Module Name: src Committed By: bouyer Date: Mon Apr 17 20:48:36 UTC 2017
Modified Files: src/distrib/sets/lists/base [bouyer-socketcan]: mi src/distrib/sets/lists/debug [bouyer-socketcan]: mi src/distrib/sets/lists/man [bouyer-socketcan]: mi src/sbin [bouyer-socketcan]: Makefile Added Files: src/sbin/canconfig [bouyer-socketcan]: Makefile canconfig.8 canconfig.c Log Message: Add canconfig(8), an utility to configure CAN interfaces. Compile-tested only. To generate a diff of this commit: cvs rdiff -u -r1.1150.2.1 -r1.1150.2.2 src/distrib/sets/lists/base/mi cvs rdiff -u -r1.191.2.1 -r1.191.2.2 src/distrib/sets/lists/debug/mi cvs rdiff -u -r1.1545 -r1.1545.2.1 src/distrib/sets/lists/man/mi cvs rdiff -u -r1.129 -r1.129.4.1 src/sbin/Makefile cvs rdiff -u -r0 -r1.1.2.1 src/sbin/canconfig/Makefile \ src/sbin/canconfig/canconfig.8 src/sbin/canconfig/canconfig.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/base/mi diff -u src/distrib/sets/lists/base/mi:1.1150.2.1 src/distrib/sets/lists/base/mi:1.1150.2.2 --- src/distrib/sets/lists/base/mi:1.1150.2.1 Mon Apr 17 20:35:00 2017 +++ src/distrib/sets/lists/base/mi Mon Apr 17 20:48:36 2017 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.1150.2.1 2017/04/17 20:35:00 bouyer Exp $ +# $NetBSD: mi,v 1.1150.2.2 2017/04/17 20:48:36 bouyer Exp $ # # Note: Don't delete entries from here - mark them as "obsolete" instead, # unless otherwise stated below. @@ -445,6 +445,7 @@ ./sbin/blacklistctl base-sysutil-root ./sbin/blacklistd base-sysutil-root ./sbin/brconfig base-netutil-root +./sbin/canconfig base-netutil-root ./sbin/ccdconfig base-sysutil-root ./sbin/cgdconfig base-sysutil-root ./sbin/chown base-sysutil-root Index: src/distrib/sets/lists/debug/mi diff -u src/distrib/sets/lists/debug/mi:1.191.2.1 src/distrib/sets/lists/debug/mi:1.191.2.2 --- src/distrib/sets/lists/debug/mi:1.191.2.1 Mon Apr 17 20:35:00 2017 +++ src/distrib/sets/lists/debug/mi Mon Apr 17 20:48:36 2017 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.191.2.1 2017/04/17 20:35:00 bouyer Exp $ +# $NetBSD: mi,v 1.191.2.2 2017/04/17 20:48:36 bouyer Exp $ ./etc/mtree/set.debug comp-sys-root ./usr/lib comp-sys-usr compatdir ./usr/lib/i18n/libBIG5_g.a comp-c-debuglib debuglib,compatfile @@ -307,6 +307,7 @@ ./usr/libdata/debug/sbin/blacklistctl.debug comp-sysutil-debug debug ./usr/libdata/debug/sbin/blacklistd.debug comp-sysutil-debug debug ./usr/libdata/debug/sbin/brconfig.debug comp-netutil-debug debug +./usr/libdata/debug/sbin/canconfig.debug comp-netutil-debug debug ./usr/libdata/debug/sbin/ccdconfig.debug comp-sysutil-debug debug ./usr/libdata/debug/sbin/cgdconfig.debug comp-sysutil-debug debug ./usr/libdata/debug/sbin/chown.debug comp-sysutil-debug debug Index: src/distrib/sets/lists/man/mi diff -u src/distrib/sets/lists/man/mi:1.1545 src/distrib/sets/lists/man/mi:1.1545.2.1 --- src/distrib/sets/lists/man/mi:1.1545 Sat Jan 7 20:49:23 2017 +++ src/distrib/sets/lists/man/mi Mon Apr 17 20:48:36 2017 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.1545 2017/01/07 20:49:23 christos Exp $ +# $NetBSD: mi,v 1.1545.2.1 2017/04/17 20:48:36 bouyer Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -2365,6 +2365,7 @@ ./usr/share/man/cat8/bounce.0 man-postfix-catman postfix,.cat ./usr/share/man/cat8/bozohttpd.0 man-netutil-catman .cat ./usr/share/man/cat8/brconfig.0 man-netutil-catman .cat +./usr/share/man/cat8/canconfig.0 man-netutil-catman .cat ./usr/share/man/cat8/btattach.0 man-sysutil-catman .cat ./usr/share/man/cat8/btconfig.0 man-sysutil-catman .cat ./usr/share/man/cat8/btcontrol.0 man-obsolete obsolete @@ -5337,6 +5338,7 @@ ./usr/share/man/html8/bounce.html man-postfix-htmlman postfix,html ./usr/share/man/html8/bozohttpd.html man-netutil-htmlman html ./usr/share/man/html8/brconfig.html man-netutil-htmlman html +./usr/share/man/html8/canconfig.html man-netutil-htmlman html ./usr/share/man/html8/btattach.html man-sysutil-htmlman html ./usr/share/man/html8/btconfig.html man-sysutil-htmlman html ./usr/share/man/html8/btdevctl.html man-sysutil-htmlman html @@ -8344,6 +8346,7 @@ ./usr/share/man/man8/bounce.8 man-postfix-man postfix,.man ./usr/share/man/man8/bozohttpd.8 man-netutil-man .man ./usr/share/man/man8/brconfig.8 man-netutil-man .man +./usr/share/man/man8/canconfig.8 man-netutil-man .man ./usr/share/man/man8/btattach.8 man-sysutil-man .man ./usr/share/man/man8/btconfig.8 man-sysutil-man .man ./usr/share/man/man8/btcontrol.8 man-obsolete obsolete Index: src/sbin/Makefile diff -u src/sbin/Makefile:1.129 src/sbin/Makefile:1.129.4.1 --- src/sbin/Makefile:1.129 Fri Jul 1 22:50:50 2016 +++ src/sbin/Makefile Mon Apr 17 20:48:35 2017 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.129 2016/07/01 22:50:50 christos Exp $ +# $NetBSD: Makefile,v 1.129.4.1 2017/04/17 20:48:35 bouyer Exp $ # @(#)Makefile 8.5 (Berkeley) 3/31/94 # Not ported: XNSrouted enpload scsiformat startslip @@ -6,8 +6,9 @@ .include <bsd.own.mk> -SUBDIR= amrctl apmlabel atactl badsect bioctl brconfig ccdconfig cgdconfig \ - chown devpubd disklabel dkctl dkscan_bsdlabel dmesg dmctl \ +SUBDIR= amrctl apmlabel atactl badsect bioctl brconfig \ + canconfig ccdconfig cgdconfig chown \ + devpubd disklabel dkctl dkscan_bsdlabel dmesg dmctl \ drvctl fastboot fdisk fsck fsirand gpt ifconfig init ldconfig luactl \ mbrlabel mknod modload modstat modunload mount \ newbtconf nologin nvmectl \ Added files: Index: src/sbin/canconfig/Makefile diff -u /dev/null src/sbin/canconfig/Makefile:1.1.2.1 --- /dev/null Mon Apr 17 20:48:36 2017 +++ src/sbin/canconfig/Makefile Mon Apr 17 20:48:36 2017 @@ -0,0 +1,6 @@ +# $NetBSD: Makefile,v 1.1.2.1 2017/04/17 20:48:36 bouyer Exp $ + +PROG= canconfig +MAN= canconfig.8 + +.include <bsd.prog.mk> Index: src/sbin/canconfig/canconfig.8 diff -u /dev/null src/sbin/canconfig/canconfig.8:1.1.2.1 --- /dev/null Mon Apr 17 20:48:36 2017 +++ src/sbin/canconfig/canconfig.8 Mon Apr 17 20:48:36 2017 @@ -0,0 +1,118 @@ +.\" $NetBSD: canconfig.8,v 1.1.2.1 2017/04/17 20:48:36 bouyer Exp $ +.\" +.\" Copyright (c) 2017 Manuel Bouyer. + * +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. + * +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd Apris 15, 2017 +.Dt CANCONFIG 8 +.Os +.Sh NAME +.Nm canconfig +.Nd configure CAN network interface parameters +.Sh SYNOPSIS +.Nm +.Fl a +.Nm +.Ar canif +.Nm +.Ar can +.Ar command +.Op Ar args ... +.Sh DESCRIPTION +The +.Nm +utility is used to configure CAN network interface parameters and retrieve +CAN network interface parameters and status from the kernel. +.Ss Timing +.Pp +The base time unit used to define the network bit rate is the time quanta (tq), +its value is defined by the input clock freqency and the prescaler value +as (1/ freq * prescaler). +.Pp +The network bit time is split in 4 segments: +.Bl -tag -width "phase_seg1" -offset indent -compact +.It sync_seg +fixed to 1 tq +.It prop_seg +.It phase_seg1 +.It phase_seg2 +.El +The network bit time is (1 + prop_seg + phase_seg1 + phase_seg2), in tq. +The sample point is between phase_seg1 and phase_seg2. +.Pp +The receiver hardware is allowed to shorten prop_seg or phase_seg2 to +resynchronise with the sender. The swj (Synchronisation Jump Width) parameter +defines by how much the hardware can shorten these segments. +.Pp +Some hardware can use 3 sample points instead of one, and keep the majority as +the final value. +.Ss Options +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl a +Display the status of all CAN devices present on the system. +This flag is mutually exclusive with all other sub-commands. +.El +.Pp +All other operations require that a CAN interface be specified. +If a CAN interface is specified with no sub-commands, +the status of that interface is displayed. +.Pp +The following sub-commands are available: +.Pp +.Bl -tag -width indent +.It Cm up +Start network operations on the interface. Requires that all timing parameters +have been set. +.It Cm down +Stop network operations on the interface. +.It Cm brp Ar value +Set the value of the baud rate prescaler. +.It Cm prop_seg Ar value +set the number of tq for the propagation segment. +.It Cm phase_seg1 Ar value +set the number of tq for the phase segment 1. +.It Cm phase_seg2 Ar value +set the number of tq for the phase segment 2. +.It Cm sjw Ar value +set the number of tq for the Synchronisation Jump Width. +.It Cm 3samples +enables triple-sampling. +.It Cm -3samples +disables triple-sampling. +.El +.Sh EXAMPLES +TODO +.Sh SEE ALSO +.Xr ifconfig.if 5 , +.Xr ifconfig 8 , +.Sh HISTORY +The +.Nm +utility first appeared in +.Nx 8.0 . +.Sh AUTHORS +This version of the +.Nm +utility was written by +.An Manuel Bouyer . Index: src/sbin/canconfig/canconfig.c diff -u /dev/null src/sbin/canconfig/canconfig.c:1.1.2.1 --- /dev/null Mon Apr 17 20:48:36 2017 +++ src/sbin/canconfig/canconfig.c Mon Apr 17 20:48:36 2017 @@ -0,0 +1,517 @@ +/* $NetBSD: canconfig.c,v 1.1.2.1 2017/04/17 20:48:36 bouyer Exp $ */ + +/* + * Copyright 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Jason R. Thorpe for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#ifndef lint +__RCSID("$NetBSD: canconfig.c,v 1.1.2.1 2017/04/17 20:48:36 bouyer Exp $"); +#endif + + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <netcan/can.h> +#include <netcan/can_link.h> +#include <ifaddrs.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +struct command { + const char *cmd_keyword; + int cmd_argcnt; + int cmd_flags; + void (*cmd_func)(const struct command *, int, const char *, + char **); +}; + +#define CMD_INVERT 0x01 /* "invert" the sense of the command */ + +static void cmd_up(const struct command *, int, const char *, char **); +static void cmd_down(const struct command *, int, const char *, char **); +static void cmd_brp(const struct command *, int, const char *, char **); +static void cmd_prop_seg(const struct command *, int, const char *, char **); +static void cmd_phase_seg1(const struct command *, int, const char *, char **); +static void cmd_phase_seg2(const struct command *, int, const char *, char **); +static void cmd_sjw(const struct command *, int, const char *, char **); +static void cmd_3samples(const struct command *, int, const char *, char **); + +static const struct command command_table[] = { + { "up", 0, 0, cmd_up }, + { "down", 0, 0, cmd_down }, + + { "brp", 1, 0, cmd_brp }, + { "prop_seg", 1, 0, cmd_prop_seg }, + { "phase_seg1", 1, 0, cmd_phase_seg1 }, + { "phase_seg2", 1, 0, cmd_phase_seg2 }, + { "sjw", 1, 0, cmd_sjw }, + + { "3samples", 0, 0, cmd_3samples }, + { "-3samples", 0, CMD_INVERT, cmd_3samples }, + + { NULL, 0, 0, NULL }, +}; + +static void printall(int); +static void status(int, const char *); +static void show_timings(int, const char *, const char *); +static int is_can(int s, const char *); +static int get_val(const char *, u_long *); +#define do_cmd(a,b,c,d,e,f) do_cmd2((a),(b),(c),(d),(e),NULL,(f)) +static int do_cmd2(int, const char *, u_long, void *, size_t, size_t *, int); +__dead static void usage(void); + +static int aflag; +static struct ifreq g_ifr; +static int g_ifr_updated = 0; + +struct can_link_timecaps g_cltc; +struct can_link_timings g_clt; +static int g_clt_updated = 0; + +int +main(int argc, char *argv[]) +{ + const struct command *cmd; + char *canifname; + int sock, ch; + + if (argc < 2) + usage(); + + while ((ch = getopt(argc, argv, "a")) != -1) { + switch (ch) { + case 'a': + aflag = 1; + break; + + default: + usage(); + } + } + + argc -= optind; + argv += optind; + + if (aflag) { + if (argc != 0) + usage(); + sock = socket(AF_CAN, SOCK_RAW, CAN_RAW); + if (sock < 0) + err(1, "socket"); + + printall(sock); + exit(0); + } + + if (argc == 0) + usage(); + + sock = socket(AF_CAN, SOCK_RAW, CAN_RAW); + if (sock < 0) + err(1, "socket"); + + canifname = argv[0]; + + if (is_can(sock, canifname) == 0) + errx(1, "%s is not a can interface", canifname); + + /* Get a copy of the interface flags. */ + strlcpy(g_ifr.ifr_name, canifname, sizeof(g_ifr.ifr_name)); + if (ioctl(sock, SIOCGIFFLAGS, &g_ifr) < 0) + err(1, "unable to get interface flags"); + + argc--; + argv++; + + if (argc == 0) { + status(sock, canifname); + exit(0); + } + + if (do_cmd(sock, canifname, CANGLINKTIMECAP, &g_cltc, sizeof(g_cltc), 0) + < 0) + err(1, "unable to get can link timecaps"); + + if (do_cmd(sock, canifname, CANGLINKTIMINGS, &g_clt, sizeof(g_clt), 0) < 0) + err(1, "unable to get can link timings"); + + while (argc != 0) { + for (cmd = command_table; cmd->cmd_keyword != NULL; cmd++) { + if (strcmp(cmd->cmd_keyword, argv[0]) == 0) + break; + } + if (cmd->cmd_keyword == NULL) + errx(1, "unknown command: %s", argv[0]); + + argc--; + argv++; + + if (argc < cmd->cmd_argcnt) + errx(1, "command %s requires %d argument%s", + cmd->cmd_keyword, cmd->cmd_argcnt, + cmd->cmd_argcnt == 1 ? "" : "s"); + + (*cmd->cmd_func)(cmd, sock, canifname, argv); + + argc -= cmd->cmd_argcnt; + argv += cmd->cmd_argcnt; + } + + /* If the timings changed, update them. */ + if (g_clt_updated && + do_cmd(sock, canifname, CANGLINKTIMINGS, &g_clt, sizeof(g_clt), 1) < 0) + err(1, "unable to set can link timings"); + + /* If the flags changed, update them. */ + if (g_ifr_updated && ioctl(sock, SIOCSIFFLAGS, &g_ifr) < 0) + err(1, "unable to set interface flags"); + + exit (0); +} + +static void +usage(void) +{ + static const char *usage_strings[] = { + "-a", + "<canif>", + "<canif> up|down", + "<canif> brp <value>", + "<canif> prop_seg <value>", + "<canif> phase_seg1 <value>", + "<canif> phase_seg2 <value>", + "<canif> sjw <value>", + "<canif> 3samples | -3samples", + NULL, + }; + extern const char *__progname; + int i; + + for (i = 0; usage_strings[i] != NULL; i++) + fprintf(stderr, "%s %s %s\n", + i == 0 ? "usage:" : " ", + __progname, usage_strings[i]); + + exit(1); +} + +static int +is_can(int s, const char *canif) +{ + uint32_t linkmode; + + if (do_cmd(s, canif, CANGLINKMODE, &linkmode, sizeof(linkmode), 0) < 0) + return (0); + + return (1); +} + +static void +printb(const char *s, u_int v, const char *bits) +{ + int i, any = 0; + char c; + + if (bits && *bits == 8) + printf("%s=%o", s, v); + else + printf("%s=%x", s, v); + if (bits) { + bits++; + putchar('<'); + while ((i = *bits++) != 0) { + if (v & (1 << (i-1))) { + if (any) + putchar(','); + any = 1; + for (; (c = *bits) > 32; bits++) + putchar(c); + } else + for (; *bits > 32; bits++) + ; + } + putchar('>'); + } +} + +static void +printall(int sock) +{ + struct ifaddrs *ifap, *ifa; + char *p; + + if (getifaddrs(&ifap) != 0) + err(1, "getifaddrs"); + p = NULL; + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { + if (is_can(sock, ifa->ifa_name) == 0) + continue; + if (p != NULL && strcmp(p, ifa->ifa_name) == 0) + continue; + p = ifa->ifa_name; + status(sock, ifa->ifa_name); + } + + freeifaddrs(ifap); +} + +static void +status(int sock, const char *canifname) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + + strlcpy(ifr.ifr_name, canifname, sizeof(ifr.ifr_name)); + if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) + err(1, "unable to get flags"); + + printf("%s: ", canifname); + printb("flags", ifr.ifr_flags, IFFBITS); + printf("\n"); + + printf("\tTimings:\n"); + show_timings(sock, canifname, "\t\t"); + +} + +static void +show_timings(int sock, const char *canifname, const char *prefix) +{ + struct can_link_timecaps cltc; + struct can_link_timings clt; + u_int32_t linkmode; + char hbuf[8]; + + if (do_cmd(sock, canifname, CANGLINKTIMECAP, &cltc, sizeof(cltc), 0) + < 0) + err(1, "unable to get can link timecaps"); + + if (do_cmd(sock, canifname, CANGLINKTIMINGS, &clt, sizeof(clt), 0) < 0) + err(1, "unable to get can link timings"); + + if (do_cmd(sock, canifname, CANGLINKMODE, &linkmode, sizeof(linkmode), + 0) < 0) + err(1, "unable to get can link mode"); + + humanize_number(hbuf, sizeof(hbuf), cltc.cltc_clock_freq, "Hz", 0, + HN_AUTOSCALE | HN_NOSPACE | HN_DIVISOR_1000); + + printf("%scaps:\n", prefix); + printf("%s clock %s, brp [%d..%d]/%d, prop_seg [%d..%d]\n", + prefix, hbuf, + cltc.cltc_brp_min, cltc.cltc_brp_max, cltc.cltc_brp_inc, + cltc.cltc_prop_min, cltc.cltc_prop_max); + printf("%s phase_seg1 [%d..%d], phase_seg2 [%d..%d], sjw [0..%d]\n", + prefix, + cltc.cltc_ps1_min, cltc.cltc_ps1_max, + cltc.cltc_ps2_min, cltc.cltc_ps2_max, + cltc.cltc_sjw_max); + printf("%s ", prefix); + printb("capabilities", cltc.cltc_linkmode_caps, CAN_IFFBITS); + printf("%soperational:\n", prefix); + printf("%s brp %d prop_seg %d, phase_seg1 %d, phase_seg2 %d, sjw %d\n", + prefix, + clt.clt_brp, clt.clt_prop, clt.clt_ps1, clt.clt_ps2, clt.clt_sjw); + printf("%s ", prefix); + printb("mode", linkmode, CAN_IFFBITS); +} + +static int +get_val(const char *cp, u_long *valp) +{ + char *endptr; + u_long val; + + errno = 0; + val = strtoul(cp, &endptr, 0); + if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) + return (-1); + + *valp = val; + return (0); +} + +static int +do_cmd2(int sock, const char *canifname, u_long op, void *arg, size_t argsize, + size_t *outsizep, int set) +{ + struct ifdrv ifd; + int error; + + memset(&ifd, 0, sizeof(ifd)); + + strlcpy(ifd.ifd_name, canifname, sizeof(ifd.ifd_name)); + ifd.ifd_cmd = op; + ifd.ifd_len = argsize; + ifd.ifd_data = arg; + + error = ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd); + + if (outsizep) + *outsizep = ifd.ifd_len; + + return error; +} + +static void +do_ifflag(int sock, const char *canifname, int flag, int set) +{ + + if (set) + g_ifr.ifr_flags |= flag; + else + g_ifr.ifr_flags &= ~flag; + + g_ifr_updated = 1; +} + +static int +do_canflag(int sock, const char *canifname, uint32_t flag, int set) +{ + int cmd; + if (set) + cmd = CANSLINKMODE; + else + cmd = CANCLINKMODE; + return do_cmd(sock, canifname, cmd, &flag, sizeof(flag), 1); +} + +static void +cmd_up(const struct command *cmd, int sock, const char *canifname, + char **argv) +{ + + do_ifflag(sock, canifname, IFF_UP, 1); +} + +static void +cmd_down(const struct command *cmd, int sock, const char *canifname, + char **argv) +{ + + do_ifflag(sock, canifname, IFF_UP, 0); +} + +static void +cmd_brp(const struct command *cmd, int sock, const char *bridge, + char **argv) +{ + u_long val; + + if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0) + errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); + if (val < g_cltc.cltc_brp_min || val > g_cltc.cltc_brp_max) + errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]); + g_clt.clt_brp = val; + g_clt_updated=1; +} + +static void +cmd_prop_seg(const struct command *cmd, int sock, const char *bridge, + char **argv) +{ + u_long val; + + if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0) + errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); + if (val < g_cltc.cltc_prop_min || val > g_cltc.cltc_prop_max) + errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]); + g_clt.clt_prop = val; + g_clt_updated=1; +} + +static void +cmd_phase_seg1(const struct command *cmd, int sock, const char *bridge, + char **argv) +{ + u_long val; + + if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0) + errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); + if (val < g_cltc.cltc_ps1_min || val > g_cltc.cltc_ps1_max) + errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]); + g_clt.clt_ps1 = val; + g_clt_updated=1; +} + +static void +cmd_phase_seg2(const struct command *cmd, int sock, const char *bridge, + char **argv) +{ + u_long val; + + if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0) + errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); + if (val < g_cltc.cltc_ps2_min || val > g_cltc.cltc_ps2_max) + errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]); + g_clt.clt_ps2 = val; + g_clt_updated=1; +} + +static void +cmd_sjw(const struct command *cmd, int sock, const char *bridge, + char **argv) +{ + u_long val; + + if (get_val(argv[0], &val) < 0 || (val & ~0xffffffff) != 0) + errx(1, "%s: invalid value: %s", cmd->cmd_keyword, argv[0]); + if (val > g_cltc.cltc_sjw_max) + errx(1, "%s: out of range value: %s", cmd->cmd_keyword, argv[0]); + g_clt.clt_sjw = val; + g_clt_updated=1; +} + +static void +cmd_3samples(const struct command *cmd, int sock, const char *canifname, + char **argv) +{ + if (do_canflag(sock, canifname, CAN_LINKMODE_3SAMPLES, + (cmd->cmd_flags & CMD_INVERT) ? 0 : 1) < 0) + err(1, "%s", cmd->cmd_keyword); + +}