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 "\t[ one-shot { on | off } ]\n" 34 "\t[ berr-reporting { on | off } ]\n" 35 "\n" 36 "\t[ restart-ms TIME-MS ]\n" 37 "\t[ restart ]\n" 38 "\n" 39 "\tWhere: BITRATE := { 1..1000000 }\n" 40 "\t SAMPLE-POINT := { 0.000..0.999 }\n" 41 "\t TQ := { NUMBER }\n" 42 "\t PROP-SEG := { 1..8 }\n" 43 "\t PHASE-SEG1 := { 1..8 }\n" 44 "\t PHASE-SEG2 := { 1..8 }\n" 45 "\t SJW := { 1..4 }\n" 46 "\t RESTART-MS := { 0 | NUMBER }\n" 47 ); 48 } 49 50 static int get_float(float *val, const char *arg) 51 { 52 float res; 53 char *ptr; 54 55 if (!arg || !*arg) 56 return -1; 57 res = strtof(arg, &ptr); 58 if (!ptr || ptr == arg || *ptr) 59 return -1; 60 *val = res; 61 return 0; 62 } 63 64 static void set_ctrlmode(char* name, char *arg, 65 struct can_ctrlmode *cm, __u32 flags) 66 { 67 if (strcmp(arg, "on") == 0) { 68 cm->flags |= flags; 69 } else if (strcmp(arg, "off") != 0) { 70 fprintf(stderr, 71 "Error: argument of \"%s\" must be \"on\" or \"off\"\n", 72 name); 73 exit(-1); 74 } 75 cm->mask |= flags; 76 } 77 78 static void print_ctrlmode(FILE *f, __u32 cm) 79 { 80 fprintf(f, "<"); 81 #define _PF(cmflag, cmname) \ 82 if (cm & cmflag) { \ 83 cm &= ~cmflag; \ 84 fprintf(f, "%s%s", cmname, cm ? "," : ""); \ 85 } 86 _PF(CAN_CTRLMODE_LOOPBACK, "LOOPBACK"); 87 _PF(CAN_CTRLMODE_LISTENONLY, "LISTEN-ONLY"); 88 _PF(CAN_CTRLMODE_3_SAMPLES, "TRIPLE-SAMPLING"); 89 _PF(CAN_CTRLMODE_ONE_SHOT, "ONE-SHOT"); 90 _PF(CAN_CTRLMODE_BERR_REPORTING, "BERR-REPORTING"); 91 #undef _PF 92 if (cm) 93 fprintf(f, "%x", cm); 94 fprintf(f, "> "); 95 } 96 97 static int can_parse_opt(struct link_util *lu, int argc, char **argv, 98 struct nlmsghdr *n) 99 { 100 struct can_bittiming bt; 101 struct can_ctrlmode cm = {0, 0}; 102 103 memset(&bt, 0, sizeof(bt)); 104 while (argc > 0) { 105 if (matches(*argv, "bitrate") == 0) { 106 NEXT_ARG(); 107 if (get_u32(&bt.bitrate, *argv, 0)) 108 invarg("invalid \"bitrate\" value\n", *argv); 109 } else if (matches(*argv, "sample-point") == 0) { 110 float sp; 111 112 NEXT_ARG(); 113 if (get_float(&sp, *argv)) 114 invarg("invalid \"sample-point\" value\n", 115 *argv); 116 bt.sample_point = (__u32)(sp * 1000); 117 } else if (matches(*argv, "tq") == 0) { 118 NEXT_ARG(); 119 if (get_u32(&bt.tq, *argv, 0)) 120 invarg("invalid \"tq\" value\n", *argv); 121 } else if (matches(*argv, "prop-seg") == 0) { 122 NEXT_ARG(); 123 if (get_u32(&bt.prop_seg, *argv, 0)) 124 invarg("invalid \"prop-seg\" value\n", *argv); 125 } else if (matches(*argv, "phase-seg1") == 0) { 126 NEXT_ARG(); 127 if (get_u32(&bt.phase_seg1, *argv, 0)) 128 invarg("invalid \"phase-seg1\" value\n", *argv); 129 } else if (matches(*argv, "phase-seg2") == 0) { 130 NEXT_ARG(); 131 if (get_u32(&bt.phase_seg2, *argv, 0)) 132 invarg("invalid \"phase-seg2\" value\n", *argv); 133 } else if (matches(*argv, "sjw") == 0) { 134 NEXT_ARG(); 135 if (get_u32(&bt.sjw, *argv, 0)) 136 invarg("invalid \"sjw\" value\n", *argv); 137 } else if (matches(*argv, "loopback") == 0) { 138 NEXT_ARG(); 139 set_ctrlmode("loopback", *argv, &cm, 140 CAN_CTRLMODE_LOOPBACK); 141 } else if (matches(*argv, "listen-only") == 0) { 142 NEXT_ARG(); 143 set_ctrlmode("listen-only", *argv, &cm, 144 CAN_CTRLMODE_LISTENONLY); 145 } else if (matches(*argv, "triple-sampling") == 0) { 146 NEXT_ARG(); 147 set_ctrlmode("triple-sampling", *argv, &cm, 148 CAN_CTRLMODE_3_SAMPLES); 149 } else if (matches(*argv, "one-shot") == 0) { 150 NEXT_ARG(); 151 set_ctrlmode("one-shot", *argv, &cm, 152 CAN_CTRLMODE_ONE_SHOT); 153 } else if (matches(*argv, "berr-reporting") == 0) { 154 NEXT_ARG(); 155 set_ctrlmode("berr-reporting", *argv, &cm, 156 CAN_CTRLMODE_BERR_REPORTING); 157 } else if (matches(*argv, "restart") == 0) { 158 __u32 val = 1; 159 160 addattr32(n, 1024, IFLA_CAN_RESTART, val); 161 } else if (matches(*argv, "restart-ms") == 0) { 162 __u32 val; 163 164 NEXT_ARG(); 165 if (get_u32(&val, *argv, 0)) 166 invarg("invalid \"restart-ms\" value\n", *argv); 167 addattr32(n, 1024, IFLA_CAN_RESTART_MS, val); 168 } else if (matches(*argv, "help") == 0) { 169 usage(); 170 return -1; 171 } else { 172 fprintf(stderr, "can: what is \"%s\"?\n", *argv); 173 usage(); 174 return -1; 175 } 176 argc--, argv++; 177 } 178 179 if (bt.bitrate || bt.tq) 180 addattr_l(n, 1024, IFLA_CAN_BITTIMING, &bt, sizeof(bt)); 181 if (cm.mask) 182 addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm)); 183 184 return 0; 185 } 186 187 static const char *can_state_names[] = { 188 [CAN_STATE_ERROR_ACTIVE] = "ERROR-ACTIVE", 189 [CAN_STATE_ERROR_WARNING] = "ERROR-WARNING", 190 [CAN_STATE_ERROR_PASSIVE] = "ERROR-PASSIVE", 191 [CAN_STATE_BUS_OFF] = "BUS-OFF", 192 [CAN_STATE_STOPPED] = "STOPPED", 193 [CAN_STATE_SLEEPING] = "SLEEPING" 194 }; 195 196 static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 197 { 198 if (!tb) 199 return; 200 201 if (tb[IFLA_CAN_CTRLMODE]) { 202 struct can_ctrlmode *cm = RTA_DATA(tb[IFLA_CAN_CTRLMODE]); 203 204 if (cm->flags) 205 print_ctrlmode(f, cm->flags); 206 } 207 208 if (tb[IFLA_CAN_STATE]) { 209 int *state = RTA_DATA(tb[IFLA_CAN_STATE]); 210 211 fprintf(f, "state %s ", *state <= CAN_STATE_MAX ? 212 can_state_names[*state] : "UNKNOWN"); 213 } 214 215 if (tb[IFLA_CAN_BERR_COUNTER]) { 216 struct can_berr_counter *bc = 217 RTA_DATA(tb[IFLA_CAN_BERR_COUNTER]); 218 219 fprintf(f, "(berr-counter tx %d rx %d) ", bc->txerr, bc->rxerr); 220 } 221 222 if (tb[IFLA_CAN_RESTART_MS]) { 223 __u32 *restart_ms = RTA_DATA(tb[IFLA_CAN_RESTART_MS]); 224 225 fprintf(f, "restart-ms %d ", *restart_ms); 226 } 227 228 if (tb[IFLA_CAN_BITTIMING]) { 229 struct can_bittiming *bt = RTA_DATA(tb[IFLA_CAN_BITTIMING]); 230 231 fprintf(f, "\n " 232 "bitrate %d sample-point %.3f ", 233 bt->bitrate, (float)bt->sample_point / 1000.); 234 fprintf(f, "\n " 235 "tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d", 236 bt->tq, bt->prop_seg, bt->phase_seg1, bt->phase_seg2, 237 bt->sjw); 238 } 239 240 if (tb[IFLA_CAN_BITTIMING_CONST]) { 241 struct can_bittiming_const *btc = 242 RTA_DATA(tb[IFLA_CAN_BITTIMING_CONST]); 243 244 fprintf(f, "\n " 245 "%s: tseg1 %d..%d tseg2 %d..%d " 246 "sjw 1..%d brp %d..%d brp-inc %d", 247 btc->name, btc->tseg1_min, btc->tseg1_max, 248 btc->tseg2_min, btc->tseg2_max, btc->sjw_max, 249 btc->brp_min, btc->brp_max, btc->brp_inc); 250 } 251 252 if (tb[IFLA_CAN_CLOCK]) { 253 struct can_clock *clock = RTA_DATA(tb[IFLA_CAN_CLOCK]); 254 255 fprintf(f, "\n clock %d", clock->freq); 256 } 257 258 } 259 260 static void can_print_xstats(struct link_util *lu, 261 FILE *f, struct rtattr *xstats) 262 { 263 struct can_device_stats *stats; 264 265 if (xstats && RTA_PAYLOAD(xstats) == sizeof(*stats)) { 266 stats = RTA_DATA(xstats); 267 fprintf(f, "\n " 268 "re-started bus-errors arbit-lost " 269 "error-warn error-pass bus-off"); 270 fprintf(f, "\n %-10d %-10d %-10d %-10d %-10d %-10d", 271 stats->restarts, stats->bus_error, 272 stats->arbitration_lost, stats->error_warning, 273 stats->error_passive, stats->bus_off); 274 } 275 } 276 277 struct link_util can_link_util = { 278 .id = "can", 279 .maxattr = IFLA_CAN_MAX, 280 .parse_opt = can_parse_opt, 281 .print_opt = can_print_opt, 282 .print_xstats = can_print_xstats, 283 }; 284