1 /* $NetBSD: canconfig.c,v 1.2 2017/05/27 21:02:55 bouyer Exp $ */ 2 3 /* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 40 #ifndef lint 41 __RCSID("$NetBSD: canconfig.c,v 1.2 2017/05/27 21:02:55 bouyer Exp $"); 42 #endif 43 44 45 #include <sys/param.h> 46 #include <sys/socket.h> 47 #include <sys/ioctl.h> 48 49 #include <net/if.h> 50 #include <netcan/can.h> 51 #include <netcan/can_link.h> 52 #include <ifaddrs.h> 53 54 #include <ctype.h> 55 #include <err.h> 56 #include <errno.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 62 struct command { 63 const char *cmd_keyword; 64 int cmd_argcnt; 65 int cmd_flags; 66 void (*cmd_func)(const struct command *, int, const char *, 67 char **); 68 }; 69 70 #define CMD_INVERT 0x01 /* "invert" the sense of the command */ 71 72 static void cmd_up(const struct command *, int, const char *, char **); 73 static void cmd_down(const struct command *, int, const char *, char **); 74 static void cmd_brp(const struct command *, int, const char *, char **); 75 static void cmd_prop_seg(const struct command *, int, const char *, char **); 76 static void cmd_phase_seg1(const struct command *, int, const char *, char **); 77 static void cmd_phase_seg2(const struct command *, int, const char *, char **); 78 static void cmd_sjw(const struct command *, int, const char *, char **); 79 static void cmd_3samples(const struct command *, int, const char *, char **); 80 static void cmd_listenonly(const struct command *, int, const char *, char **); 81 static void cmd_loopback(const struct command *, int, const char *, char **); 82 83 static const struct command command_table[] = { 84 { "up", 0, 0, cmd_up }, 85 { "down", 0, 0, cmd_down }, 86 87 { "brp", 1, 0, cmd_brp }, 88 { "prop_seg", 1, 0, cmd_prop_seg }, 89 { "phase_seg1", 1, 0, cmd_phase_seg1 }, 90 { "phase_seg2", 1, 0, cmd_phase_seg2 }, 91 { "sjw", 1, 0, cmd_sjw }, 92 93 { "3samples", 0, 0, cmd_3samples }, 94 { "-3samples", 0, CMD_INVERT, cmd_3samples }, 95 96 { "listenonly", 0, 0, cmd_listenonly }, 97 { "-listenonly", 0, CMD_INVERT, cmd_listenonly }, 98 99 { "loopback", 0, 0, cmd_loopback }, 100 { "-loopback", 0, CMD_INVERT, cmd_loopback }, 101 102 { NULL, 0, 0, NULL }, 103 }; 104 105 static void printall(int); 106 static void status(int, const char *); 107 static void show_timings(int, const char *, const char *); 108 static int is_can(int s, const char *); 109 static int get_val(const char *, u_long *); 110 #define do_cmd(a,b,c,d,e,f) do_cmd2((a),(b),(c),(d),(e),NULL,(f)) 111 static int do_cmd2(int, const char *, u_long, void *, size_t, size_t *, int); 112 __dead static void usage(void); 113 114 static int aflag; 115 static struct ifreq g_ifr; 116 static int g_ifr_updated = 0; 117 118 struct can_link_timecaps g_cltc; 119 struct can_link_timings g_clt; 120 static int g_clt_updated = 0; 121 122 int 123 main(int argc, char *argv[]) 124 { 125 const struct command *cmd; 126 char *canifname; 127 int sock, ch; 128 129 if (argc < 2) 130 usage(); 131 132 while ((ch = getopt(argc, argv, "a")) != -1) { 133 switch (ch) { 134 case 'a': 135 aflag = 1; 136 break; 137 138 default: 139 usage(); 140 } 141 } 142 143 argc -= optind; 144 argv += optind; 145 146 if (aflag) { 147 if (argc != 0) 148 usage(); 149 sock = socket(AF_CAN, SOCK_RAW, CAN_RAW); 150 if (sock < 0) 151 err(1, "socket"); 152 153 printall(sock); 154 exit(0); 155 } 156 157 if (argc == 0) 158 usage(); 159 160 sock = socket(AF_CAN, SOCK_RAW, CAN_RAW); 161 if (sock < 0) 162 err(1, "socket"); 163 164 canifname = argv[0]; 165 166 if (is_can(sock, canifname) == 0) 167 errx(1, "%s is not a can interface", canifname); 168 169 /* Get a copy of the interface flags. */ 170 strlcpy(g_ifr.ifr_name, canifname, sizeof(g_ifr.ifr_name)); 171 if (ioctl(sock, SIOCGIFFLAGS, &g_ifr) < 0) 172 err(1, "unable to get interface flags"); 173 174 argc--; 175 argv++; 176 177 if (argc == 0) { 178 status(sock, canifname); 179 exit(0); 180 } 181 182 if (do_cmd(sock, canifname, CANGLINKTIMECAP, &g_cltc, sizeof(g_cltc), 0) 183 < 0) 184 err(1, "unable to get can link timecaps"); 185 186 if (do_cmd(sock, canifname, CANGLINKTIMINGS, &g_clt, sizeof(g_clt), 0) < 0) 187 err(1, "unable to get can link timings"); 188 189 while (argc != 0) { 190 for (cmd = command_table; cmd->cmd_keyword != NULL; cmd++) { 191 if (strcmp(cmd->cmd_keyword, argv[0]) == 0) 192 break; 193 } 194 if (cmd->cmd_keyword == NULL) 195 errx(1, "unknown command: %s", argv[0]); 196 197 argc--; 198 argv++; 199 200 if (argc < cmd->cmd_argcnt) 201 errx(1, "command %s requires %d argument%s", 202 cmd->cmd_keyword, cmd->cmd_argcnt, 203 cmd->cmd_argcnt == 1 ? "" : "s"); 204 205 (*cmd->cmd_func)(cmd, sock, canifname, argv); 206 207 argc -= cmd->cmd_argcnt; 208 argv += cmd->cmd_argcnt; 209 } 210 211 /* If the timings changed, update them. */ 212 if (g_clt_updated && 213 do_cmd(sock, canifname, CANSLINKTIMINGS, &g_clt, sizeof(g_clt), 1) < 0) 214 err(1, "unable to set can link timings"); 215 216 /* If the flags changed, update them. */ 217 if (g_ifr_updated && ioctl(sock, SIOCSIFFLAGS, &g_ifr) < 0) 218 err(1, "unable to set interface flags"); 219 220 exit (0); 221 } 222 223 static void 224 usage(void) 225 { 226 static const char *usage_strings[] = { 227 "-a", 228 "<canif>", 229 "<canif> up|down", 230 "<canif> brp <value>", 231 "<canif> prop_seg <value>", 232 "<canif> phase_seg1 <value>", 233 "<canif> phase_seg2 <value>", 234 "<canif> sjw <value>", 235 "<canif> 3samples | -3samples", 236 "<canif> listenonly | -listenonly", 237 "<canif> loopback | -loopback", 238 NULL, 239 }; 240 extern const char *__progname; 241 int i; 242 243 for (i = 0; usage_strings[i] != NULL; i++) 244 fprintf(stderr, "%s %s %s\n", 245 i == 0 ? "usage:" : " ", 246 __progname, usage_strings[i]); 247 248 exit(1); 249 } 250 251 static int 252 is_can(int s, const char *canif) 253 { 254 uint32_t linkmode; 255 256 if (do_cmd(s, canif, CANGLINKMODE, &linkmode, sizeof(linkmode), 0) < 0) 257 return (0); 258 259 return (1); 260 } 261 262 static void 263 printb(const char *s, u_int v, const char *bits) 264 { 265 int i, any = 0; 266 char c; 267 268 if (bits && *bits == 8) 269 printf("%s=%o", s, v); 270 else 271 printf("%s=%x", s, v); 272 if (bits) { 273 bits++; 274 putchar('<'); 275 while ((i = *bits++) != 0) { 276 if (v & (1 << (i-1))) { 277 if (any) 278 putchar(','); 279 any = 1; 280 for (; (c = *bits) > 32; bits++) 281 putchar(c); 282 } else 283 for (; *bits > 32; bits++) 284 ; 285 } 286 putchar('>'); 287 } 288 } 289 290 static void 291 printall(int sock) 292 { 293 struct ifaddrs *ifap, *ifa; 294 char *p; 295 296 if (getifaddrs(&ifap) != 0) 297 err(1, "getifaddrs"); 298 p = NULL; 299 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 300 if (is_can(sock, ifa->ifa_name) == 0) 301 continue; 302 if (p != NULL && strcmp(p, ifa->ifa_name) == 0) 303 continue; 304 p = ifa->ifa_name; 305 status(sock, ifa->ifa_name); 306 } 307 308 freeifaddrs(ifap); 309 } 310 311 static void 312 status(int sock, const char *canifname) 313 { 314 struct ifreq ifr; 315 316 memset(&ifr, 0, sizeof(ifr)); 317 318 strlcpy(ifr.ifr_name, canifname, sizeof(ifr.ifr_name)); 319 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) 320 err(1, "unable to get flags"); 321 322 printf("%s: ", canifname); 323 printb("flags", ifr.ifr_flags, IFFBITS); 324 printf("\n"); 325 326 show_timings(sock, canifname, "\t"); 327 328 } 329 330 static int 331 valid_timings(struct can_link_timecaps *cltc, struct can_link_timings *clt) 332 { 333 if (clt->clt_brp < cltc->cltc_brp_min || 334 clt->clt_brp > cltc->cltc_brp_max) 335 return 0; 336 337 if (clt->clt_prop < cltc->cltc_prop_min || 338 clt->clt_prop > cltc->cltc_prop_max) 339 return 0; 340 341 if (clt->clt_ps1 < cltc->cltc_ps1_min || 342 clt->clt_ps1 > cltc->cltc_ps1_max) 343 return 0; 344 345 if (clt->clt_ps2 < cltc->cltc_ps2_min || 346 clt->clt_ps2 > cltc->cltc_ps2_max) 347 return 0; 348 349 return 1; 350 } 351 352 static void 353 show_timings(int sock, const char *canifname, const char *prefix) 354 { 355 struct can_link_timecaps cltc; 356 struct can_link_timings clt; 357 u_int32_t linkmode; 358 char hbuf[8]; 359 360 if (do_cmd(sock, canifname, CANGLINKTIMECAP, &cltc, sizeof(cltc), 0) 361 < 0) 362 err(1, "unable to get can link timecaps"); 363 364 if (do_cmd(sock, canifname, CANGLINKTIMINGS, &clt, sizeof(clt), 0) < 0) 365 err(1, "unable to get can link timings"); 366 367 if (do_cmd(sock, canifname, CANGLINKMODE, &linkmode, sizeof(linkmode), 368 0) < 0) 369 err(1, "unable to get can link mode"); 370 371 humanize_number(hbuf, sizeof(hbuf), cltc.cltc_clock_freq, "Hz", 372 HN_AUTOSCALE, HN_NOSPACE | HN_DIVISOR_1000); 373 374 printf("%stiming caps:\n", prefix); 375 printf("%s clock %s, brp [%d..%d]/%d, prop_seg [%d..%d]\n", 376 prefix, hbuf, 377 cltc.cltc_brp_min, cltc.cltc_brp_max, cltc.cltc_brp_inc, 378 cltc.cltc_prop_min, cltc.cltc_prop_max); 379 printf("%s phase_seg1 [%d..%d], phase_seg2 [%d..%d], sjw [0..%d]\n", 380 prefix, 381 cltc.cltc_ps1_min, cltc.cltc_ps1_max, 382 cltc.cltc_ps2_min, cltc.cltc_ps2_max, 383 cltc.cltc_sjw_max); 384 printf("%s ", prefix); 385 printb("capabilities", cltc.cltc_linkmode_caps, CAN_IFFBITS); 386 printf("\n"); 387 printf("%soperational timings:", prefix); 388 if (valid_timings(&cltc, &clt)) { 389 uint32_t tq, ntq, bps; 390 tq = ((uint64_t)clt.clt_brp * (uint64_t)1000000000) / 391 cltc.cltc_clock_freq; 392 ntq = 1 + clt.clt_prop + clt.clt_ps1 + clt.clt_ps2; 393 printf(" %d time quanta of %dns", 394 1 + clt.clt_prop + clt.clt_ps1 + clt.clt_ps2, tq); 395 bps = 1000000000 / (tq * ntq); 396 humanize_number(hbuf, sizeof(hbuf), bps, "bps", 397 HN_AUTOSCALE, HN_NOSPACE | HN_DIVISOR_1000); 398 printf(", %s", hbuf); 399 }; 400 printf("\n"); 401 402 printf("%s brp %d, prop_seg %d, phase_seg1 %d, phase_seg2 %d, sjw %d\n", 403 prefix, 404 clt.clt_brp, clt.clt_prop, clt.clt_ps1, clt.clt_ps2, clt.clt_sjw); 405 printf("%s ", prefix); 406 printb("mode", linkmode, CAN_IFFBITS); 407 printf("\n"); 408 } 409 410 static int 411 get_val(const char *cp, u_long *valp) 412 { 413 char *endptr; 414 u_long val; 415 416 errno = 0; 417 val = strtoul(cp, &endptr, 0); 418 if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) 419 return (-1); 420 421 *valp = val; 422 return (0); 423 } 424 425 static int 426 do_cmd2(int sock, const char *canifname, u_long op, void *arg, size_t argsize, 427 size_t *outsizep, int set) 428 { 429 struct ifdrv ifd; 430 int error; 431 432 memset(&ifd, 0, sizeof(ifd)); 433 434 strlcpy(ifd.ifd_name, canifname, sizeof(ifd.ifd_name)); 435 ifd.ifd_cmd = op; 436 ifd.ifd_len = argsize; 437 ifd.ifd_data = arg; 438 439 error = ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd); 440 441 if (outsizep) 442 *outsizep = ifd.ifd_len; 443 444 return error; 445 } 446 447 static void 448 do_ifflag(int sock, const char *canifname, int flag, int set) 449 { 450 451 if (set) 452 g_ifr.ifr_flags |= flag; 453 else 454 g_ifr.ifr_flags &= ~flag; 455 456 g_ifr_updated = 1; 457 } 458 459 static int 460 do_canflag(int sock, const char *canifname, uint32_t flag, int set) 461 { 462 int cmd; 463 if (set) 464 cmd = CANSLINKMODE; 465 else 466 cmd = CANCLINKMODE; 467 return do_cmd(sock, canifname, cmd, &flag, sizeof(flag), 1); 468 } 469 470 static void 471 cmd_up(const struct command *cmd, int sock, const char *canifname, 472 char **argv) 473 { 474 475 do_ifflag(sock, canifname, IFF_UP, 1); 476 } 477 478 static void 479 cmd_down(const struct command *cmd, int sock, const char *canifname, 480 char **argv) 481 { 482 483 do_ifflag(sock, canifname, IFF_UP, 0); 484 } 485 486 static void 487 cmd_brp(const struct command *cmd, int sock, const char *bridge, 488 char **argv) 489 { 490 u_long val; 491 492 if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0) 493 errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); 494 if (val < g_cltc.cltc_brp_min || val > g_cltc.cltc_brp_max) 495 errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]); 496 g_clt.clt_brp = val; 497 g_clt_updated=1; 498 } 499 500 static void 501 cmd_prop_seg(const struct command *cmd, int sock, const char *bridge, 502 char **argv) 503 { 504 u_long val; 505 506 if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0) 507 errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); 508 if (val < g_cltc.cltc_prop_min || val > g_cltc.cltc_prop_max) 509 errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]); 510 g_clt.clt_prop = val; 511 g_clt_updated=1; 512 } 513 514 static void 515 cmd_phase_seg1(const struct command *cmd, int sock, const char *bridge, 516 char **argv) 517 { 518 u_long val; 519 520 if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0) 521 errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); 522 if (val < g_cltc.cltc_ps1_min || val > g_cltc.cltc_ps1_max) 523 errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]); 524 g_clt.clt_ps1 = val; 525 g_clt_updated=1; 526 } 527 528 static void 529 cmd_phase_seg2(const struct command *cmd, int sock, const char *bridge, 530 char **argv) 531 { 532 u_long val; 533 534 if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0) 535 errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); 536 if (val < g_cltc.cltc_ps2_min || val > g_cltc.cltc_ps2_max) 537 errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]); 538 g_clt.clt_ps2 = val; 539 g_clt_updated=1; 540 } 541 542 static void 543 cmd_sjw(const struct command *cmd, int sock, const char *bridge, 544 char **argv) 545 { 546 u_long val; 547 548 if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0) 549 errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); 550 if (val > g_cltc.cltc_sjw_max) 551 errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]); 552 g_clt.clt_sjw = val; 553 g_clt_updated=1; 554 } 555 static void 556 cmd_3samples(const struct command *cmd, int sock, const char *canifname, 557 char **argv) 558 { 559 if (do_canflag(sock, canifname, CAN_LINKMODE_3SAMPLES, 560 (cmd->cmd_flags & CMD_INVERT) ? 0 : 1) < 0) 561 err(1, "%s", cmd->cmd_keyword); 562 563 } 564 565 static void 566 cmd_listenonly(const struct command *cmd, int sock, const char *canifname, 567 char **argv) 568 { 569 if (do_canflag(sock, canifname, CAN_LINKMODE_LISTENONLY, 570 (cmd->cmd_flags & CMD_INVERT) ? 0 : 1) < 0) 571 err(1, "%s", cmd->cmd_keyword); 572 573 } 574 575 static void 576 cmd_loopback(const struct command *cmd, int sock, const char *canifname, 577 char **argv) 578 { 579 if (do_canflag(sock, canifname, CAN_LINKMODE_LOOPBACK, 580 (cmd->cmd_flags & CMD_INVERT) ? 0 : 1) < 0) 581 err(1, "%s", cmd->cmd_keyword); 582 583 } 584