xref: /netbsd-src/sbin/canconfig/canconfig.c (revision 6e4cb2b9ab4107b5ab560c348a691ae05ac595a5)
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
main(int argc,char * argv[])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
usage(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
is_can(int s,const char * canif)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
printb(const char * s,u_int v,const char * bits)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
printall(int sock)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
status(int sock,const char * canifname)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
valid_timings(struct can_link_timecaps * cltc,struct can_link_timings * clt)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
show_timings(int sock,const char * canifname,const char * prefix)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
get_val(const char * cp,u_long * valp)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
do_cmd2(int sock,const char * canifname,u_long op,void * arg,size_t argsize,size_t * outsizep,int set)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
do_ifflag(int sock,const char * canifname,int flag,int set)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
do_canflag(int sock,const char * canifname,uint32_t flag,int set)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
cmd_up(const struct command * cmd,int sock,const char * canifname,char ** argv)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
cmd_down(const struct command * cmd,int sock,const char * canifname,char ** argv)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
cmd_brp(const struct command * cmd,int sock,const char * bridge,char ** argv)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
cmd_prop_seg(const struct command * cmd,int sock,const char * bridge,char ** argv)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
cmd_phase_seg1(const struct command * cmd,int sock,const char * bridge,char ** argv)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
cmd_phase_seg2(const struct command * cmd,int sock,const char * bridge,char ** argv)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
cmd_sjw(const struct command * cmd,int sock,const char * bridge,char ** argv)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
cmd_3samples(const struct command * cmd,int sock,const char * canifname,char ** argv)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
cmd_listenonly(const struct command * cmd,int sock,const char * canifname,char ** argv)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
cmd_loopback(const struct command * cmd,int sock,const char * canifname,char ** argv)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