1 /* 2 * iplink_can.c CAN device support 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Wolfgang Grandegger <wg (at) grandegger.com> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include <linux/can/netlink.h> 17 18 #include "rt_names.h" 19 #include "utils.h" 20 #include "ip_common.h" 21 22 static void print_usage(FILE *f) 23 { 24 fprintf(f, 25 "Usage: ip link set DEVICE type can\n" 26 "\t[ bitrate BITRATE [ sample-point SAMPLE-POINT] ] |\n" 27 "\t[ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1\n \t phase-seg2 PHASE-SEG2 [ sjw SJW ] ]\n" 28 "\n" 29 "\t[ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] |\n" 30 "\t[ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1\n \t dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ]\n" 31 "\n" 32 "\t[ loopback { on | off } ]\n" 33 "\t[ listen-only { on | off } ]\n" 34 "\t[ triple-sampling { on | off } ]\n" 35 "\t[ one-shot { on | off } ]\n" 36 "\t[ berr-reporting { on | off } ]\n" 37 "\t[ fd { on | off } ]\n" 38 "\t[ fd-non-iso { on | off } ]\n" 39 "\t[ presume-ack { on | off } ]\n" 40 "\n" 41 "\t[ restart-ms TIME-MS ]\n" 42 "\t[ restart ]\n" 43 "\n" 44 "\t[ termination { 0..65535 } ]\n" 45 "\n" 46 "\tWhere: BITRATE := { 1..1000000 }\n" 47 "\t SAMPLE-POINT := { 0.000..0.999 }\n" 48 "\t TQ := { NUMBER }\n" 49 "\t PROP-SEG := { 1..8 }\n" 50 "\t PHASE-SEG1 := { 1..8 }\n" 51 "\t PHASE-SEG2 := { 1..8 }\n" 52 "\t SJW := { 1..4 }\n" 53 "\t RESTART-MS := { 0 | NUMBER }\n" 54 ); 55 } 56 57 static void usage(void) 58 { 59 print_usage(stderr); 60 } 61 62 static int get_float(float *val, const char *arg) 63 { 64 float res; 65 char *ptr; 66 67 if (!arg || !*arg) 68 return -1; 69 res = strtof(arg, &ptr); 70 if (!ptr || ptr == arg || *ptr) 71 return -1; 72 *val = res; 73 return 0; 74 } 75 76 static void set_ctrlmode(char *name, char *arg, 77 struct can_ctrlmode *cm, __u32 flags) 78 { 79 if (strcmp(arg, "on") == 0) { 80 cm->flags |= flags; 81 } else if (strcmp(arg, "off") != 0) { 82 fprintf(stderr, 83 "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n", 84 name, arg); 85 exit(-1); 86 } 87 cm->mask |= flags; 88 } 89 90 static void print_ctrlmode(FILE *f, __u32 cm) 91 { 92 open_json_array(PRINT_ANY, is_json_context() ? "ctrlmode" : "<"); 93 #define _PF(cmflag, cmname) \ 94 if (cm & cmflag) { \ 95 cm &= ~cmflag; \ 96 print_string(PRINT_ANY, NULL, cm ? "%s," : "%s", cmname); \ 97 } 98 _PF(CAN_CTRLMODE_LOOPBACK, "LOOPBACK"); 99 _PF(CAN_CTRLMODE_LISTENONLY, "LISTEN-ONLY"); 100 _PF(CAN_CTRLMODE_3_SAMPLES, "TRIPLE-SAMPLING"); 101 _PF(CAN_CTRLMODE_ONE_SHOT, "ONE-SHOT"); 102 _PF(CAN_CTRLMODE_BERR_REPORTING, "BERR-REPORTING"); 103 _PF(CAN_CTRLMODE_FD, "FD"); 104 _PF(CAN_CTRLMODE_FD_NON_ISO, "FD-NON-ISO"); 105 _PF(CAN_CTRLMODE_PRESUME_ACK, "PRESUME-ACK"); 106 #undef _PF 107 if (cm) 108 print_hex(PRINT_ANY, NULL, "%x", cm); 109 close_json_array(PRINT_ANY, "> "); 110 } 111 112 static int can_parse_opt(struct link_util *lu, int argc, char **argv, 113 struct nlmsghdr *n) 114 { 115 struct can_bittiming bt = {}, dbt = {}; 116 struct can_ctrlmode cm = {0, 0}; 117 118 while (argc > 0) { 119 if (matches(*argv, "bitrate") == 0) { 120 NEXT_ARG(); 121 if (get_u32(&bt.bitrate, *argv, 0)) 122 invarg("invalid \"bitrate\" value\n", *argv); 123 } else if (matches(*argv, "sample-point") == 0) { 124 float sp; 125 126 NEXT_ARG(); 127 if (get_float(&sp, *argv)) 128 invarg("invalid \"sample-point\" value\n", 129 *argv); 130 bt.sample_point = (__u32)(sp * 1000); 131 } else if (matches(*argv, "tq") == 0) { 132 NEXT_ARG(); 133 if (get_u32(&bt.tq, *argv, 0)) 134 invarg("invalid \"tq\" value\n", *argv); 135 } else if (matches(*argv, "prop-seg") == 0) { 136 NEXT_ARG(); 137 if (get_u32(&bt.prop_seg, *argv, 0)) 138 invarg("invalid \"prop-seg\" value\n", *argv); 139 } else if (matches(*argv, "phase-seg1") == 0) { 140 NEXT_ARG(); 141 if (get_u32(&bt.phase_seg1, *argv, 0)) 142 invarg("invalid \"phase-seg1\" value\n", *argv); 143 } else if (matches(*argv, "phase-seg2") == 0) { 144 NEXT_ARG(); 145 if (get_u32(&bt.phase_seg2, *argv, 0)) 146 invarg("invalid \"phase-seg2\" value\n", *argv); 147 } else if (matches(*argv, "sjw") == 0) { 148 NEXT_ARG(); 149 if (get_u32(&bt.sjw, *argv, 0)) 150 invarg("invalid \"sjw\" value\n", *argv); 151 } else if (matches(*argv, "dbitrate") == 0) { 152 NEXT_ARG(); 153 if (get_u32(&dbt.bitrate, *argv, 0)) 154 invarg("invalid \"dbitrate\" value\n", *argv); 155 } else if (matches(*argv, "dsample-point") == 0) { 156 float sp; 157 158 NEXT_ARG(); 159 if (get_float(&sp, *argv)) 160 invarg("invalid \"dsample-point\" value\n", *argv); 161 dbt.sample_point = (__u32)(sp * 1000); 162 } else if (matches(*argv, "dtq") == 0) { 163 NEXT_ARG(); 164 if (get_u32(&dbt.tq, *argv, 0)) 165 invarg("invalid \"dtq\" value\n", *argv); 166 } else if (matches(*argv, "dprop-seg") == 0) { 167 NEXT_ARG(); 168 if (get_u32(&dbt.prop_seg, *argv, 0)) 169 invarg("invalid \"dprop-seg\" value\n", *argv); 170 } else if (matches(*argv, "dphase-seg1") == 0) { 171 NEXT_ARG(); 172 if (get_u32(&dbt.phase_seg1, *argv, 0)) 173 invarg("invalid \"dphase-seg1\" value\n", *argv); 174 } else if (matches(*argv, "dphase-seg2") == 0) { 175 NEXT_ARG(); 176 if (get_u32(&dbt.phase_seg2, *argv, 0)) 177 invarg("invalid \"dphase-seg2\" value\n", *argv); 178 } else if (matches(*argv, "dsjw") == 0) { 179 NEXT_ARG(); 180 if (get_u32(&dbt.sjw, *argv, 0)) 181 invarg("invalid \"dsjw\" value\n", *argv); 182 } else if (matches(*argv, "loopback") == 0) { 183 NEXT_ARG(); 184 set_ctrlmode("loopback", *argv, &cm, 185 CAN_CTRLMODE_LOOPBACK); 186 } else if (matches(*argv, "listen-only") == 0) { 187 NEXT_ARG(); 188 set_ctrlmode("listen-only", *argv, &cm, 189 CAN_CTRLMODE_LISTENONLY); 190 } else if (matches(*argv, "triple-sampling") == 0) { 191 NEXT_ARG(); 192 set_ctrlmode("triple-sampling", *argv, &cm, 193 CAN_CTRLMODE_3_SAMPLES); 194 } else if (matches(*argv, "one-shot") == 0) { 195 NEXT_ARG(); 196 set_ctrlmode("one-shot", *argv, &cm, 197 CAN_CTRLMODE_ONE_SHOT); 198 } else if (matches(*argv, "berr-reporting") == 0) { 199 NEXT_ARG(); 200 set_ctrlmode("berr-reporting", *argv, &cm, 201 CAN_CTRLMODE_BERR_REPORTING); 202 } else if (matches(*argv, "fd") == 0) { 203 NEXT_ARG(); 204 set_ctrlmode("fd", *argv, &cm, 205 CAN_CTRLMODE_FD); 206 } else if (matches(*argv, "fd-non-iso") == 0) { 207 NEXT_ARG(); 208 set_ctrlmode("fd-non-iso", *argv, &cm, 209 CAN_CTRLMODE_FD_NON_ISO); 210 } else if (matches(*argv, "presume-ack") == 0) { 211 NEXT_ARG(); 212 set_ctrlmode("presume-ack", *argv, &cm, 213 CAN_CTRLMODE_PRESUME_ACK); 214 } else if (matches(*argv, "restart") == 0) { 215 __u32 val = 1; 216 217 addattr32(n, 1024, IFLA_CAN_RESTART, val); 218 } else if (matches(*argv, "restart-ms") == 0) { 219 __u32 val; 220 221 NEXT_ARG(); 222 if (get_u32(&val, *argv, 0)) 223 invarg("invalid \"restart-ms\" value\n", *argv); 224 addattr32(n, 1024, IFLA_CAN_RESTART_MS, val); 225 } else if (matches(*argv, "termination") == 0) { 226 __u16 val; 227 228 NEXT_ARG(); 229 if (get_u16(&val, *argv, 0)) 230 invarg("invalid \"termination\" value\n", 231 *argv); 232 addattr16(n, 1024, IFLA_CAN_TERMINATION, val); 233 } else if (matches(*argv, "help") == 0) { 234 usage(); 235 return -1; 236 } else { 237 fprintf(stderr, "can: unknown option \"%s\"\n", *argv); 238 usage(); 239 return -1; 240 } 241 argc--, argv++; 242 } 243 244 if (bt.bitrate || bt.tq) 245 addattr_l(n, 1024, IFLA_CAN_BITTIMING, &bt, sizeof(bt)); 246 if (dbt.bitrate || dbt.tq) 247 addattr_l(n, 1024, IFLA_CAN_DATA_BITTIMING, &dbt, sizeof(dbt)); 248 if (cm.mask) 249 addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm)); 250 251 return 0; 252 } 253 254 static const char *can_state_names[CAN_STATE_MAX] = { 255 [CAN_STATE_ERROR_ACTIVE] = "ERROR-ACTIVE", 256 [CAN_STATE_ERROR_WARNING] = "ERROR-WARNING", 257 [CAN_STATE_ERROR_PASSIVE] = "ERROR-PASSIVE", 258 [CAN_STATE_BUS_OFF] = "BUS-OFF", 259 [CAN_STATE_STOPPED] = "STOPPED", 260 [CAN_STATE_SLEEPING] = "SLEEPING" 261 }; 262 263 static void can_print_json_timing_min_max(const char *attr, int min, int max) 264 { 265 open_json_object(attr); 266 print_int(PRINT_JSON, "min", NULL, min); 267 print_int(PRINT_JSON, "max", NULL, max); 268 close_json_object(); 269 } 270 271 static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 272 { 273 if (!tb) 274 return; 275 276 if (tb[IFLA_CAN_CTRLMODE]) { 277 struct can_ctrlmode *cm = RTA_DATA(tb[IFLA_CAN_CTRLMODE]); 278 279 if (cm->flags) 280 print_ctrlmode(f, cm->flags); 281 } 282 283 if (tb[IFLA_CAN_STATE]) { 284 uint32_t state = rta_getattr_u32(tb[IFLA_CAN_STATE]); 285 286 fprintf(f, "state %s ", state < CAN_STATE_MAX ? 287 can_state_names[state] : "UNKNOWN"); 288 } 289 290 if (tb[IFLA_CAN_BERR_COUNTER]) { 291 struct can_berr_counter *bc = 292 RTA_DATA(tb[IFLA_CAN_BERR_COUNTER]); 293 294 if (is_json_context()) { 295 open_json_object("berr_counter"); 296 print_int(PRINT_JSON, "tx", NULL, bc->txerr); 297 print_int(PRINT_JSON, "rx", NULL, bc->rxerr); 298 close_json_object(); 299 } else { 300 fprintf(f, "(berr-counter tx %d rx %d) ", 301 bc->txerr, bc->rxerr); 302 } 303 } 304 305 if (tb[IFLA_CAN_RESTART_MS]) { 306 __u32 *restart_ms = RTA_DATA(tb[IFLA_CAN_RESTART_MS]); 307 308 print_int(PRINT_ANY, 309 "restart_ms", 310 "restart-ms %d ", 311 *restart_ms); 312 } 313 314 /* bittiming is irrelevant if fixed bitrate is defined */ 315 if (tb[IFLA_CAN_BITTIMING] && !tb[IFLA_CAN_BITRATE_CONST]) { 316 struct can_bittiming *bt = RTA_DATA(tb[IFLA_CAN_BITTIMING]); 317 318 if (is_json_context()) { 319 open_json_object("bittiming"); 320 print_int(PRINT_ANY, "bitrate", NULL, bt->bitrate); 321 jsonw_float_field_fmt(get_json_writer(), 322 "sample_point", "%.3f", 323 (float) bt->sample_point / 1000.); 324 print_int(PRINT_ANY, "tq", NULL, bt->tq); 325 print_int(PRINT_ANY, "prop_seg", NULL, bt->prop_seg); 326 print_int(PRINT_ANY, "phase_seg1", 327 NULL, bt->phase_seg1); 328 print_int(PRINT_ANY, "phase_seg2", 329 NULL, bt->phase_seg2); 330 print_int(PRINT_ANY, "sjw", NULL, bt->sjw); 331 close_json_object(); 332 } else { 333 fprintf(f, "\n bitrate %d sample-point %.3f ", 334 bt->bitrate, (float) bt->sample_point / 1000.); 335 fprintf(f, 336 "\n tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d", 337 bt->tq, bt->prop_seg, 338 bt->phase_seg1, bt->phase_seg2, 339 bt->sjw); 340 } 341 } 342 343 /* bittiming const is irrelevant if fixed bitrate is defined */ 344 if (tb[IFLA_CAN_BITTIMING_CONST] && !tb[IFLA_CAN_BITRATE_CONST]) { 345 struct can_bittiming_const *btc = 346 RTA_DATA(tb[IFLA_CAN_BITTIMING_CONST]); 347 348 if (is_json_context()) { 349 open_json_object("bittiming_const"); 350 print_string(PRINT_JSON, "name", NULL, btc->name); 351 can_print_json_timing_min_max("tseg1", 352 btc->tseg1_min, 353 btc->tseg1_max); 354 can_print_json_timing_min_max("tseg2", 355 btc->tseg2_min, 356 btc->tseg2_max); 357 can_print_json_timing_min_max("sjw", 1, btc->sjw_max); 358 can_print_json_timing_min_max("brp", 359 btc->brp_min, 360 btc->brp_max); 361 print_int(PRINT_JSON, "brp_inc", NULL, btc->brp_inc); 362 close_json_object(); 363 } else { 364 fprintf(f, "\n %s: tseg1 %d..%d tseg2 %d..%d " 365 "sjw 1..%d brp %d..%d brp-inc %d", 366 btc->name, btc->tseg1_min, btc->tseg1_max, 367 btc->tseg2_min, btc->tseg2_max, btc->sjw_max, 368 btc->brp_min, btc->brp_max, btc->brp_inc); 369 } 370 } 371 372 if (tb[IFLA_CAN_BITRATE_CONST]) { 373 __u32 *bitrate_const = RTA_DATA(tb[IFLA_CAN_BITRATE_CONST]); 374 int bitrate_cnt = RTA_PAYLOAD(tb[IFLA_CAN_BITRATE_CONST]) / 375 sizeof(*bitrate_const); 376 int i; 377 __u32 bitrate = 0; 378 379 if (tb[IFLA_CAN_BITTIMING]) { 380 struct can_bittiming *bt = 381 RTA_DATA(tb[IFLA_CAN_BITTIMING]); 382 bitrate = bt->bitrate; 383 } 384 385 if (is_json_context()) { 386 print_uint(PRINT_JSON, 387 "bittiming_bitrate", 388 NULL, bitrate); 389 open_json_array(PRINT_JSON, "bitrate_const"); 390 for (i = 0; i < bitrate_cnt; ++i) 391 print_uint(PRINT_JSON, NULL, NULL, 392 bitrate_const[i]); 393 close_json_array(PRINT_JSON, NULL); 394 } else { 395 fprintf(f, "\n bitrate %u", bitrate); 396 fprintf(f, "\n ["); 397 398 for (i = 0; i < bitrate_cnt - 1; ++i) { 399 /* This will keep lines below 80 signs */ 400 if (!(i % 6) && i) 401 fprintf(f, "\n "); 402 403 fprintf(f, "%8u, ", bitrate_const[i]); 404 } 405 406 if (!(i % 6) && i) 407 fprintf(f, "\n "); 408 fprintf(f, "%8u ]", bitrate_const[i]); 409 } 410 } 411 412 /* data bittiming is irrelevant if fixed bitrate is defined */ 413 if (tb[IFLA_CAN_DATA_BITTIMING] && !tb[IFLA_CAN_DATA_BITRATE_CONST]) { 414 struct can_bittiming *dbt = 415 RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]); 416 417 if (is_json_context()) { 418 open_json_object("data_bittiming"); 419 print_int(PRINT_JSON, "bitrate", NULL, dbt->bitrate); 420 jsonw_float_field_fmt(get_json_writer(), 421 "sample_point", 422 "%.3f", 423 (float) dbt->sample_point / 1000.); 424 print_int(PRINT_JSON, "tq", NULL, dbt->tq); 425 print_int(PRINT_JSON, "prop_seg", NULL, dbt->prop_seg); 426 print_int(PRINT_JSON, "phase_seg1", 427 NULL, dbt->phase_seg1); 428 print_int(PRINT_JSON, "phase_seg2", 429 NULL, dbt->phase_seg2); 430 print_int(PRINT_JSON, "sjw", NULL, dbt->sjw); 431 close_json_object(); 432 } else { 433 fprintf(f, "\n dbitrate %d dsample-point %.3f ", 434 dbt->bitrate, 435 (float) dbt->sample_point / 1000.); 436 fprintf(f, "\n dtq %d dprop-seg %d dphase-seg1 %d " 437 "dphase-seg2 %d dsjw %d", 438 dbt->tq, dbt->prop_seg, dbt->phase_seg1, 439 dbt->phase_seg2, dbt->sjw); 440 } 441 } 442 443 /* data bittiming const is irrelevant if fixed bitrate is defined */ 444 if (tb[IFLA_CAN_DATA_BITTIMING_CONST] && 445 !tb[IFLA_CAN_DATA_BITRATE_CONST]) { 446 struct can_bittiming_const *dbtc = 447 RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING_CONST]); 448 449 if (is_json_context()) { 450 open_json_object("data_bittiming_const"); 451 print_string(PRINT_JSON, "name", NULL, dbtc->name); 452 can_print_json_timing_min_max("tseg1", 453 dbtc->tseg1_min, 454 dbtc->tseg1_max); 455 can_print_json_timing_min_max("tseg2", 456 dbtc->tseg2_min, 457 dbtc->tseg2_max); 458 can_print_json_timing_min_max("sjw", 1, dbtc->sjw_max); 459 can_print_json_timing_min_max("brp", 460 dbtc->brp_min, 461 dbtc->brp_max); 462 463 print_int(PRINT_JSON, "brp_inc", NULL, dbtc->brp_inc); 464 close_json_object(); 465 } else { 466 fprintf(f, "\n %s: dtseg1 %d..%d dtseg2 %d..%d " 467 "dsjw 1..%d dbrp %d..%d dbrp-inc %d", 468 dbtc->name, dbtc->tseg1_min, dbtc->tseg1_max, 469 dbtc->tseg2_min, dbtc->tseg2_max, dbtc->sjw_max, 470 dbtc->brp_min, dbtc->brp_max, dbtc->brp_inc); 471 } 472 } 473 474 if (tb[IFLA_CAN_DATA_BITRATE_CONST]) { 475 __u32 *dbitrate_const = 476 RTA_DATA(tb[IFLA_CAN_DATA_BITRATE_CONST]); 477 int dbitrate_cnt = 478 RTA_PAYLOAD(tb[IFLA_CAN_DATA_BITRATE_CONST]) / 479 sizeof(*dbitrate_const); 480 int i; 481 __u32 dbitrate = 0; 482 483 if (tb[IFLA_CAN_DATA_BITTIMING]) { 484 struct can_bittiming *dbt = 485 RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]); 486 dbitrate = dbt->bitrate; 487 } 488 489 if (is_json_context()) { 490 print_uint(PRINT_JSON, "data_bittiming_bitrate", 491 NULL, dbitrate); 492 open_json_array(PRINT_JSON, "data_bitrate_const"); 493 for (i = 0; i < dbitrate_cnt; ++i) 494 print_uint(PRINT_JSON, NULL, NULL, 495 dbitrate_const[i]); 496 close_json_array(PRINT_JSON, NULL); 497 } else { 498 fprintf(f, "\n dbitrate %u", dbitrate); 499 fprintf(f, "\n ["); 500 501 for (i = 0; i < dbitrate_cnt - 1; ++i) { 502 /* This will keep lines below 80 signs */ 503 if (!(i % 6) && i) 504 fprintf(f, "\n "); 505 506 fprintf(f, "%8u, ", dbitrate_const[i]); 507 } 508 509 if (!(i % 6) && i) 510 fprintf(f, "\n "); 511 fprintf(f, "%8u ]", dbitrate_const[i]); 512 } 513 } 514 515 if (tb[IFLA_CAN_TERMINATION_CONST] && tb[IFLA_CAN_TERMINATION]) { 516 __u16 *trm = RTA_DATA(tb[IFLA_CAN_TERMINATION]); 517 __u16 *trm_const = RTA_DATA(tb[IFLA_CAN_TERMINATION_CONST]); 518 int trm_cnt = RTA_PAYLOAD(tb[IFLA_CAN_TERMINATION_CONST]) / 519 sizeof(*trm_const); 520 int i; 521 522 if (is_json_context()) { 523 print_hu(PRINT_JSON, "termination", NULL, *trm); 524 open_json_array(PRINT_JSON, "termination_const"); 525 for (i = 0; i < trm_cnt; ++i) 526 print_hu(PRINT_JSON, NULL, NULL, trm_const[i]); 527 close_json_array(PRINT_JSON, NULL); 528 } else { 529 fprintf(f, "\n termination %hu [ ", *trm); 530 531 for (i = 0; i < trm_cnt - 1; ++i) 532 fprintf(f, "%hu, ", trm_const[i]); 533 534 fprintf(f, "%hu ]", trm_const[i]); 535 } 536 } 537 538 if (tb[IFLA_CAN_CLOCK]) { 539 struct can_clock *clock = RTA_DATA(tb[IFLA_CAN_CLOCK]); 540 541 print_int(PRINT_ANY, 542 "clock", 543 "\n clock %d", 544 clock->freq); 545 } 546 547 } 548 549 static void can_print_xstats(struct link_util *lu, 550 FILE *f, struct rtattr *xstats) 551 { 552 struct can_device_stats *stats; 553 554 if (xstats && RTA_PAYLOAD(xstats) == sizeof(*stats)) { 555 stats = RTA_DATA(xstats); 556 557 if (is_json_context()) { 558 print_int(PRINT_JSON, "restarts", 559 NULL, stats->restarts); 560 print_int(PRINT_JSON, "bus_error", 561 NULL, stats->bus_error); 562 print_int(PRINT_JSON, "arbitration_lost", 563 NULL, stats->arbitration_lost); 564 print_int(PRINT_JSON, "error_warning", 565 NULL, stats->error_warning); 566 print_int(PRINT_JSON, "error_passive", 567 NULL, stats->error_passive); 568 print_int(PRINT_JSON, "bus_off", NULL, stats->bus_off); 569 } else { 570 fprintf(f, "\n re-started bus-errors arbit-lost " 571 "error-warn error-pass bus-off"); 572 fprintf(f, "\n %-10d %-10d %-10d %-10d %-10d %-10d", 573 stats->restarts, stats->bus_error, 574 stats->arbitration_lost, stats->error_warning, 575 stats->error_passive, stats->bus_off); 576 } 577 } 578 } 579 580 static void can_print_help(struct link_util *lu, int argc, char **argv, 581 FILE *f) 582 { 583 print_usage(f); 584 } 585 586 struct link_util can_link_util = { 587 .id = "can", 588 .maxattr = IFLA_CAN_MAX, 589 .parse_opt = can_parse_opt, 590 .print_opt = can_print_opt, 591 .print_xstats = can_print_xstats, 592 .print_help = can_print_help, 593 }; 594