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