Home | History | Annotate | Line # | Download | only in canconfig
      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