1 /* 2 * iplink_can.c CAN device support 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Wolfgang Grandegger <wg (at) grandegger.com> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include <linux/can/netlink.h> 17 18 #include "rt_names.h" 19 #include "utils.h" 20 #include "ip_common.h" 21 22 static void usage(void) 23 { 24 fprintf(stderr, 25 "Usage: ip link set DEVICE type can\n" 26 "\t[ bitrate BITRATE [ sample-point SAMPLE-POINT] ] | \n" 27 "\t[ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1\n " 28 "\t phase-seg2 PHASE-SEG2 [ sjw SJW ] ]\n" 29 "\n" 30 "\t[ loopback { on | off } ]\n" 31 "\t[ listen-only { on | off } ]\n" 32 "\t[ triple-sampling { on | off } ]\n" 33 "\n" 34 "\t[ restart-ms TIME-MS ]\n" 35 "\t[ restart ]\n" 36 "\n" 37 "\tWhere: BITRATE := { 1..1000000 }\n" 38 "\t SAMPLE-POINT := { 0.000..0.999 }\n" 39 "\t TQ := { NUMBER }\n" 40 "\t PROP-SEG := { 1..8 }\n" 41 "\t PHASE-SEG1 := { 1..8 }\n" 42 "\t PHASE-SEG2 := { 1..8 }\n" 43 "\t SJW := { 1..4 }\n" 44 "\t RESTART-MS := { 0 | NUMBER }\n" 45 ); 46 } 47 48 static int get_float(float *val, const char *arg) 49 { 50 float res; 51 char *ptr; 52 53 if (!arg || !*arg) 54 return -1; 55 res = strtof(arg, &ptr); 56 if (!ptr || ptr == arg || *ptr) 57 return -1; 58 *val = res; 59 return 0; 60 } 61 62 static void set_ctrlmode(char* name, char *arg, 63 struct can_ctrlmode *cm, __u32 flags) 64 { 65 if (strcmp(arg, "on") == 0) { 66 cm->flags |= flags; 67 } else if (strcmp(arg, "off") != 0) { 68 fprintf(stderr, 69 "Error: argument of \"%s\" must be \"on\" or \"off\"\n", 70 name); 71 exit(-1); 72 } 73 cm->mask |= flags; 74 } 75 76 static void print_ctrlmode(FILE *f, __u32 cm) 77 { 78 fprintf(f, "<"); 79 #define _PF(cmflag, cmname) \ 80 if (cm & cmflag) { \ 81 cm &= ~cmflag; \ 82 fprintf(f, "%s%s", cmname, cm ? "," : ""); \ 83 } 84 _PF(CAN_CTRLMODE_LOOPBACK, "LOOPBACK"); 85 _PF(CAN_CTRLMODE_LISTENONLY, "LISTEN-ONLY"); 86 _PF(CAN_CTRLMODE_3_SAMPLES, "TRIPLE-SAMPLING"); 87 #undef _PF 88 if (cm) 89 fprintf(f, "%x", cm); 90 fprintf(f, "> "); 91 } 92 93 static int can_parse_opt(struct link_util *lu, int argc, char **argv, 94 struct nlmsghdr *n) 95 { 96 struct can_bittiming bt; 97 struct can_ctrlmode cm = {0, 0}; 98 99 memset(&bt, 0, sizeof(bt)); 100 while (argc > 0) { 101 if (matches(*argv, "bitrate") == 0) { 102 NEXT_ARG(); 103 if (get_u32(&bt.bitrate, *argv, 0)) 104 invarg("invalid \"bitrate\" value\n", *argv); 105 } else if (matches(*argv, "sample-point") == 0) { 106 float sp; 107 108 NEXT_ARG(); 109 if (get_float(&sp, *argv)) 110 invarg("invalid \"sample-point\" value\n", 111 *argv); 112 bt.sample_point = (__u32)(sp * 1000); 113 } else if (matches(*argv, "tq") == 0) { 114 NEXT_ARG(); 115 if (get_u32(&bt.tq, *argv, 0)) 116 invarg("invalid \"tq\" value\n", *argv); 117 } else if (matches(*argv, "prop-seg") == 0) { 118 NEXT_ARG(); 119 if (get_u32(&bt.prop_seg, *argv, 0)) 120 invarg("invalid \"prop-seg\" value\n", *argv); 121 } else if (matches(*argv, "phase-seg1") == 0) { 122 NEXT_ARG(); 123 if (get_u32(&bt.phase_seg1, *argv, 0)) 124 invarg("invalid \"phase-seg1\" value\n", *argv); 125 } else if (matches(*argv, "phase-seg2") == 0) { 126 NEXT_ARG(); 127 if (get_u32(&bt.phase_seg2, *argv, 0)) 128 invarg("invalid \"phase-seg2\" value\n", *argv); 129 } else if (matches(*argv, "sjw") == 0) { 130 NEXT_ARG(); 131 if (get_u32(&bt.sjw, *argv, 0)) 132 invarg("invalid \"sjw\" value\n", *argv); 133 } else if (matches(*argv, "loopback") == 0) { 134 NEXT_ARG(); 135 set_ctrlmode("loopback", *argv, &cm, 136 CAN_CTRLMODE_LOOPBACK); 137 } else if (matches(*argv, "listen-only") == 0) { 138 NEXT_ARG(); 139 set_ctrlmode("listen-only", *argv, &cm, 140 CAN_CTRLMODE_LISTENONLY); 141 } else if (matches(*argv, "triple-sampling") == 0) { 142 NEXT_ARG(); 143 set_ctrlmode("triple-sampling", *argv, &cm, 144 CAN_CTRLMODE_3_SAMPLES); 145 } else if (matches(*argv, "restart") == 0) { 146 __u32 val = 1; 147 148 addattr32(n, 1024, IFLA_CAN_RESTART, val); 149 } else if (matches(*argv, "restart-ms") == 0) { 150 __u32 val; 151 152 NEXT_ARG(); 153 if (get_u32(&val, *argv, 0)) 154 invarg("invalid \"restart-ms\" value\n", *argv); 155 addattr32(n, 1024, IFLA_CAN_RESTART_MS, val); 156 } else if (matches(*argv, "help") == 0) { 157 usage(); 158 return -1; 159 } else { 160 fprintf(stderr, "can: what is \"%s\"?\n", *argv); 161 usage(); 162 return -1; 163 } 164 argc--, argv++; 165 } 166 167 if (bt.bitrate || bt.tq) 168 addattr_l(n, 1024, IFLA_CAN_BITTIMING, &bt, sizeof(bt)); 169 if (cm.mask) 170 addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm)); 171 172 return 0; 173 } 174 175 static const char *can_state_names[] = { 176 [CAN_STATE_ERROR_ACTIVE] = "ERROR-ACTIVE", 177 [CAN_STATE_ERROR_WARNING] = "ERROR-WARNING", 178 [CAN_STATE_ERROR_PASSIVE] = "ERROR-PASSIVE", 179 [CAN_STATE_BUS_OFF] = "BUS-OFF", 180 [CAN_STATE_STOPPED] = "STOPPED", 181 [CAN_STATE_SLEEPING] = "SLEEPING" 182 }; 183 184 static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 185 { 186 if (!tb) 187 return; 188 189 if (tb[IFLA_CAN_CTRLMODE]) { 190 struct can_ctrlmode *cm = RTA_DATA(tb[IFLA_CAN_CTRLMODE]); 191 192 if (cm->flags) 193 print_ctrlmode(f, cm->flags); 194 } 195 196 if (tb[IFLA_CAN_STATE]) { 197 int *state = RTA_DATA(tb[IFLA_CAN_STATE]); 198 199 fprintf(f, "state %s ", *state <= CAN_STATE_MAX ? 200 can_state_names[*state] : "UNKNOWN"); 201 } 202 203 if (tb[IFLA_CAN_RESTART_MS]) { 204 __u32 *restart_ms = RTA_DATA(tb[IFLA_CAN_RESTART_MS]); 205 206 fprintf(f, "restart-ms %d ", *restart_ms); 207 } 208 209 if (tb[IFLA_CAN_BITTIMING]) { 210 struct can_bittiming *bt = RTA_DATA(tb[IFLA_CAN_BITTIMING]); 211 212 fprintf(f, "\n " 213 "bitrate %d sample-point %.3f ", 214 bt->bitrate, (float)bt->sample_point / 1000.); 215 fprintf(f, "\n " 216 "tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d", 217 bt->tq, bt->prop_seg, bt->phase_seg1, bt->phase_seg2, 218 bt->sjw); 219 } 220 221 if (tb[IFLA_CAN_BITTIMING_CONST]) { 222 struct can_bittiming_const *btc = 223 RTA_DATA(tb[IFLA_CAN_BITTIMING_CONST]); 224 225 fprintf(f, "\n " 226 "%s: tseg1 %d..%d tseg2 %d..%d " 227 "sjw 1..%d brp %d..%d brp-inc %d", 228 btc->name, btc->tseg1_min, btc->tseg1_max, 229 btc->tseg2_min, btc->tseg2_max, btc->sjw_max, 230 btc->brp_min, btc->brp_max, btc->brp_inc); 231 } 232 233 if (tb[IFLA_CAN_CLOCK]) { 234 struct can_clock *clock = RTA_DATA(tb[IFLA_CAN_CLOCK]); 235 236 fprintf(f, "\n clock %d", clock->freq); 237 } 238 239 } 240 241 static void can_print_xstats(struct link_util *lu, 242 FILE *f, struct rtattr *xstats) 243 { 244 struct can_device_stats *stats; 245 246 if (xstats && RTA_PAYLOAD(xstats) == sizeof(*stats)) { 247 stats = RTA_DATA(xstats); 248 fprintf(f, "\n " 249 "re-started bus-errors arbit-lost " 250 "error-warn error-pass bus-off"); 251 fprintf(f, "\n %-10d %-10d %-10d %-10d %-10d %-10d", 252 stats->restarts, stats->bus_error, 253 stats->arbitration_lost, stats->error_warning, 254 stats->error_passive, stats->bus_off); 255 } 256 } 257 258 struct link_util can_link_util = { 259 .id = "can", 260 .maxattr = IFLA_CAN_MAX, 261 .parse_opt = can_parse_opt, 262 .print_opt = can_print_opt, 263 .print_xstats = can_print_xstats, 264 }; 265