1 /*- 2 * Copyright (c) 2011-2012 Stefan Bethke. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <ctype.h> 33 #include <err.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <sysexits.h> 40 #include <unistd.h> 41 #include <sys/types.h> 42 #include <sys/ioctl.h> 43 #include <net/if.h> 44 #include <net/if_media.h> 45 #include <dev/etherswitch/etherswitch.h> 46 47 int get_media_subtype(int, const char *); 48 int get_media_mode(int, const char *); 49 int get_media_options(int, const char *); 50 int lookup_media_word(struct ifmedia_description *, const char *); 51 void print_media_word(int, int); 52 void print_media_word_ifconfig(int); 53 54 /* some constants */ 55 #define IEEE802DOT1Q_VID_MAX 4094 56 #define IFMEDIAREQ_NULISTENTRIES 256 57 58 enum cmdmode { 59 MODE_NONE = 0, 60 MODE_PORT, 61 MODE_CONFIG, 62 MODE_VLANGROUP, 63 MODE_REGISTER, 64 MODE_PHYREG 65 }; 66 67 struct cfg { 68 int fd; 69 int verbose; 70 int mediatypes; 71 const char *controlfile; 72 etherswitch_conf_t conf; 73 etherswitch_info_t info; 74 enum cmdmode mode; 75 int unit; 76 }; 77 78 struct cmds { 79 enum cmdmode mode; 80 const char *name; 81 int args; 82 void (*f)(struct cfg *, char *argv[]); 83 }; 84 static struct cmds cmds[]; 85 86 87 /* 88 * Print a value a la the %b format of the kernel's printf. 89 * Stolen from ifconfig.c. 90 */ 91 static void 92 printb(const char *s, unsigned v, const char *bits) 93 { 94 int i, any = 0; 95 char c; 96 97 if (bits && *bits == 8) 98 printf("%s=%o", s, v); 99 else 100 printf("%s=%x", s, v); 101 bits++; 102 if (bits) { 103 putchar('<'); 104 while ((i = *bits++) != '\0') { 105 if (v & (1 << (i-1))) { 106 if (any) 107 putchar(','); 108 any = 1; 109 for (; (c = *bits) > 32; bits++) 110 putchar(c); 111 } else 112 for (; *bits > 32; bits++) 113 ; 114 } 115 putchar('>'); 116 } 117 } 118 119 static int 120 read_register(struct cfg *cfg, int r) 121 { 122 struct etherswitch_reg er; 123 124 er.reg = r; 125 if (ioctl(cfg->fd, IOETHERSWITCHGETREG, &er) != 0) 126 err(EX_OSERR, "ioctl(IOETHERSWITCHGETREG)"); 127 return (er.val); 128 } 129 130 static void 131 write_register(struct cfg *cfg, int r, int v) 132 { 133 struct etherswitch_reg er; 134 135 er.reg = r; 136 er.val = v; 137 if (ioctl(cfg->fd, IOETHERSWITCHSETREG, &er) != 0) 138 err(EX_OSERR, "ioctl(IOETHERSWITCHSETREG)"); 139 } 140 141 static int 142 read_phyregister(struct cfg *cfg, int phy, int reg) 143 { 144 struct etherswitch_phyreg er; 145 146 er.phy = phy; 147 er.reg = reg; 148 if (ioctl(cfg->fd, IOETHERSWITCHGETPHYREG, &er) != 0) 149 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPHYREG)"); 150 return (er.val); 151 } 152 153 static void 154 write_phyregister(struct cfg *cfg, int phy, int reg, int val) 155 { 156 struct etherswitch_phyreg er; 157 158 er.phy = phy; 159 er.reg = reg; 160 er.val = val; 161 if (ioctl(cfg->fd, IOETHERSWITCHSETPHYREG, &er) != 0) 162 err(EX_OSERR, "ioctl(IOETHERSWITCHSETPHYREG)"); 163 } 164 165 static void 166 set_port_vid(struct cfg *cfg, char *argv[]) 167 { 168 int v; 169 etherswitch_port_t p; 170 171 v = strtol(argv[1], NULL, 0); 172 if (v < 0 || v > IEEE802DOT1Q_VID_MAX) 173 errx(EX_USAGE, "pvid must be between 0 and %d", 174 IEEE802DOT1Q_VID_MAX); 175 bzero(&p, sizeof(p)); 176 p.es_port = cfg->unit; 177 if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) 178 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); 179 p.es_pvid = v; 180 if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) 181 err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); 182 } 183 184 static void 185 set_port_flag(struct cfg *cfg, char *argv[]) 186 { 187 char *flag; 188 int n; 189 uint32_t f; 190 etherswitch_port_t p; 191 192 n = 0; 193 f = 0; 194 flag = argv[0]; 195 if (strcmp(flag, "none") != 0) { 196 if (*flag == '-') { 197 n++; 198 flag++; 199 } 200 if (strcasecmp(flag, "striptag") == 0) 201 f = ETHERSWITCH_PORT_STRIPTAG; 202 else if (strcasecmp(flag, "addtag") == 0) 203 f = ETHERSWITCH_PORT_ADDTAG; 204 else if (strcasecmp(flag, "firstlock") == 0) 205 f = ETHERSWITCH_PORT_FIRSTLOCK; 206 else if (strcasecmp(flag, "dropuntagged") == 0) 207 f = ETHERSWITCH_PORT_DROPUNTAGGED; 208 else if (strcasecmp(flag, "doubletag") == 0) 209 f = ETHERSWITCH_PORT_DOUBLE_TAG; 210 else if (strcasecmp(flag, "ingress") == 0) 211 f = ETHERSWITCH_PORT_INGRESS; 212 } 213 bzero(&p, sizeof(p)); 214 p.es_port = cfg->unit; 215 if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) 216 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); 217 if (n) 218 p.es_flags &= ~f; 219 else 220 p.es_flags |= f; 221 if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) 222 err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); 223 } 224 225 static void 226 set_port_media(struct cfg *cfg, char *argv[]) 227 { 228 etherswitch_port_t p; 229 int ifm_ulist[IFMEDIAREQ_NULISTENTRIES]; 230 int subtype; 231 232 bzero(&p, sizeof(p)); 233 p.es_port = cfg->unit; 234 p.es_ifmr.ifm_ulist = ifm_ulist; 235 p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; 236 if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) 237 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); 238 subtype = get_media_subtype(IFM_TYPE(ifm_ulist[0]), argv[1]); 239 p.es_ifr.ifr_media = (p.es_ifmr.ifm_current & IFM_IMASK) | 240 IFM_TYPE(ifm_ulist[0]) | subtype; 241 if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) 242 err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); 243 } 244 245 static void 246 set_port_mediaopt(struct cfg *cfg, char *argv[]) 247 { 248 etherswitch_port_t p; 249 int ifm_ulist[IFMEDIAREQ_NULISTENTRIES]; 250 int options; 251 252 bzero(&p, sizeof(p)); 253 p.es_port = cfg->unit; 254 p.es_ifmr.ifm_ulist = ifm_ulist; 255 p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; 256 if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) 257 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); 258 options = get_media_options(IFM_TYPE(ifm_ulist[0]), argv[1]); 259 if (options == -1) 260 errx(EX_USAGE, "invalid media options \"%s\"", argv[1]); 261 if (options & IFM_HDX) { 262 p.es_ifr.ifr_media &= ~IFM_FDX; 263 options &= ~IFM_HDX; 264 } 265 p.es_ifr.ifr_media |= options; 266 if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) 267 err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); 268 } 269 270 static void 271 set_vlangroup_vid(struct cfg *cfg, char *argv[]) 272 { 273 int v; 274 etherswitch_vlangroup_t vg; 275 276 v = strtol(argv[1], NULL, 0); 277 if (v < 0 || v > IEEE802DOT1Q_VID_MAX) 278 errx(EX_USAGE, "vlan must be between 0 and %d", IEEE802DOT1Q_VID_MAX); 279 vg.es_vlangroup = cfg->unit; 280 if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0) 281 err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)"); 282 vg.es_vid = v; 283 if (ioctl(cfg->fd, IOETHERSWITCHSETVLANGROUP, &vg) != 0) 284 err(EX_OSERR, "ioctl(IOETHERSWITCHSETVLANGROUP)"); 285 } 286 287 static void 288 set_vlangroup_members(struct cfg *cfg, char *argv[]) 289 { 290 etherswitch_vlangroup_t vg; 291 int member, untagged; 292 char *c, *d; 293 int v; 294 295 member = untagged = 0; 296 if (strcmp(argv[1], "none") != 0) { 297 for (c=argv[1]; *c; c=d) { 298 v = strtol(c, &d, 0); 299 if (d == c) 300 break; 301 if (v < 0 || v >= cfg->info.es_nports) 302 errx(EX_USAGE, "Member port must be between 0 and %d", cfg->info.es_nports-1); 303 if (d[0] == ',' || d[0] == '\0' || 304 ((d[0] == 't' || d[0] == 'T') && (d[1] == ',' || d[1] == '\0'))) { 305 if (d[0] == 't' || d[0] == 'T') { 306 untagged &= ~ETHERSWITCH_PORTMASK(v); 307 d++; 308 } else 309 untagged |= ETHERSWITCH_PORTMASK(v); 310 member |= ETHERSWITCH_PORTMASK(v); 311 d++; 312 } else 313 errx(EX_USAGE, "Invalid members specification \"%s\"", d); 314 } 315 } 316 vg.es_vlangroup = cfg->unit; 317 if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0) 318 err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)"); 319 vg.es_member_ports = member; 320 vg.es_untagged_ports = untagged; 321 if (ioctl(cfg->fd, IOETHERSWITCHSETVLANGROUP, &vg) != 0) 322 err(EX_OSERR, "ioctl(IOETHERSWITCHSETVLANGROUP)"); 323 } 324 325 static int 326 set_register(struct cfg *cfg, char *arg) 327 { 328 int a, v; 329 char *c; 330 331 a = strtol(arg, &c, 0); 332 if (c==arg) 333 return (1); 334 if (*c == '=') { 335 v = strtol(c+1, NULL, 0); 336 write_register(cfg, a, v); 337 } 338 printf("\treg 0x%04x=0x%04x\n", a, read_register(cfg, a)); 339 return (0); 340 } 341 342 static int 343 set_phyregister(struct cfg *cfg, char *arg) 344 { 345 int phy, reg, val; 346 char *c, *d; 347 348 phy = strtol(arg, &c, 0); 349 if (c==arg) 350 return (1); 351 if (*c != '.') 352 return (1); 353 d = c+1; 354 reg = strtol(d, &c, 0); 355 if (d == c) 356 return (1); 357 if (*c == '=') { 358 val = strtol(c+1, NULL, 0); 359 write_phyregister(cfg, phy, reg, val); 360 } 361 printf("\treg %d.0x%02x=0x%04x\n", phy, reg, read_phyregister(cfg, phy, reg)); 362 return (0); 363 } 364 365 static void 366 set_vlan_mode(struct cfg *cfg, char *argv[]) 367 { 368 etherswitch_conf_t conf; 369 370 bzero(&conf, sizeof(conf)); 371 conf.cmd = ETHERSWITCH_CONF_VLAN_MODE; 372 if (strcasecmp(argv[1], "isl") == 0) 373 conf.vlan_mode = ETHERSWITCH_VLAN_ISL; 374 else if (strcasecmp(argv[1], "port") == 0) 375 conf.vlan_mode = ETHERSWITCH_VLAN_PORT; 376 else if (strcasecmp(argv[1], "dot1q") == 0) 377 conf.vlan_mode = ETHERSWITCH_VLAN_DOT1Q; 378 else if (strcasecmp(argv[1], "dot1q4k") == 0) 379 conf.vlan_mode = ETHERSWITCH_VLAN_DOT1Q_4K; 380 else if (strcasecmp(argv[1], "qinq") == 0) 381 conf.vlan_mode = ETHERSWITCH_VLAN_DOUBLE_TAG; 382 else 383 conf.vlan_mode = 0; 384 if (ioctl(cfg->fd, IOETHERSWITCHSETCONF, &conf) != 0) 385 err(EX_OSERR, "ioctl(IOETHERSWITCHSETCONF)"); 386 } 387 388 static void 389 print_config(struct cfg *cfg) 390 { 391 const char *c; 392 393 /* Get the device name. */ 394 c = strrchr(cfg->controlfile, '/'); 395 if (c != NULL) 396 c = c + 1; 397 else 398 c = cfg->controlfile; 399 400 /* Print VLAN mode. */ 401 if (cfg->conf.cmd & ETHERSWITCH_CONF_VLAN_MODE) { 402 printf("%s: VLAN mode: ", c); 403 switch (cfg->conf.vlan_mode) { 404 case ETHERSWITCH_VLAN_ISL: 405 printf("ISL\n"); 406 break; 407 case ETHERSWITCH_VLAN_PORT: 408 printf("PORT\n"); 409 break; 410 case ETHERSWITCH_VLAN_DOT1Q: 411 printf("DOT1Q\n"); 412 break; 413 case ETHERSWITCH_VLAN_DOT1Q_4K: 414 printf("DOT1Q4K\n"); 415 break; 416 case ETHERSWITCH_VLAN_DOUBLE_TAG: 417 printf("QinQ\n"); 418 break; 419 default: 420 printf("none\n"); 421 } 422 } 423 } 424 425 static void 426 print_port(struct cfg *cfg, int port) 427 { 428 etherswitch_port_t p; 429 int ifm_ulist[IFMEDIAREQ_NULISTENTRIES]; 430 int i; 431 432 bzero(&p, sizeof(p)); 433 p.es_port = port; 434 p.es_ifmr.ifm_ulist = ifm_ulist; 435 p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; 436 if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) 437 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); 438 printf("port%d:\n", port); 439 if (cfg->conf.vlan_mode == ETHERSWITCH_VLAN_DOT1Q) 440 printf("\tpvid: %d\n", p.es_pvid); 441 printb("\tflags", p.es_flags, ETHERSWITCH_PORT_FLAGS_BITS); 442 printf("\n"); 443 printf("\tmedia: "); 444 print_media_word(p.es_ifmr.ifm_current, 1); 445 if (p.es_ifmr.ifm_active != p.es_ifmr.ifm_current) { 446 putchar(' '); 447 putchar('('); 448 print_media_word(p.es_ifmr.ifm_active, 0); 449 putchar(')'); 450 } 451 putchar('\n'); 452 printf("\tstatus: %s\n", (p.es_ifmr.ifm_status & IFM_ACTIVE) != 0 ? "active" : "no carrier"); 453 if (cfg->mediatypes) { 454 printf("\tsupported media:\n"); 455 if (p.es_ifmr.ifm_count > IFMEDIAREQ_NULISTENTRIES) 456 p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; 457 for (i=0; i<p.es_ifmr.ifm_count; i++) { 458 printf("\t\tmedia "); 459 print_media_word(ifm_ulist[i], 0); 460 putchar('\n'); 461 } 462 } 463 } 464 465 static void 466 print_vlangroup(struct cfg *cfg, int vlangroup) 467 { 468 etherswitch_vlangroup_t vg; 469 int i, comma; 470 471 vg.es_vlangroup = vlangroup; 472 if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0) 473 err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)"); 474 if ((vg.es_vid & ETHERSWITCH_VID_VALID) == 0) 475 return; 476 vg.es_vid &= ETHERSWITCH_VID_MASK; 477 printf("vlangroup%d:\n", vlangroup); 478 if (cfg->conf.vlan_mode == ETHERSWITCH_VLAN_PORT) 479 printf("\tport: %d\n", vg.es_vid); 480 else 481 printf("\tvlan: %d\n", vg.es_vid); 482 printf("\tmembers "); 483 comma = 0; 484 if (vg.es_member_ports != 0) 485 for (i=0; i<cfg->info.es_nports; i++) { 486 if ((vg.es_member_ports & ETHERSWITCH_PORTMASK(i)) != 0) { 487 if (comma) 488 printf(","); 489 printf("%d", i); 490 if ((vg.es_untagged_ports & ETHERSWITCH_PORTMASK(i)) == 0) 491 printf("t"); 492 comma = 1; 493 } 494 } 495 else 496 printf("none"); 497 printf("\n"); 498 } 499 500 static void 501 print_info(struct cfg *cfg) 502 { 503 const char *c; 504 int i; 505 506 c = strrchr(cfg->controlfile, '/'); 507 if (c != NULL) 508 c = c + 1; 509 else 510 c = cfg->controlfile; 511 if (cfg->verbose) { 512 printf("%s: %s with %d ports and %d VLAN groups\n", c, 513 cfg->info.es_name, cfg->info.es_nports, 514 cfg->info.es_nvlangroups); 515 printf("%s: ", c); 516 printb("VLAN capabilities", cfg->info.es_vlan_caps, 517 ETHERSWITCH_VLAN_CAPS_BITS); 518 printf("\n"); 519 } 520 print_config(cfg); 521 for (i=0; i<cfg->info.es_nports; i++) { 522 print_port(cfg, i); 523 } 524 for (i=0; i<cfg->info.es_nvlangroups; i++) { 525 print_vlangroup(cfg, i); 526 } 527 } 528 529 static void 530 usage(struct cfg *cfg __unused, char *argv[] __unused) 531 { 532 fprintf(stderr, "usage: etherswitchctl\n"); 533 fprintf(stderr, "\tetherswitchcfg [-f control file] info\n"); 534 fprintf(stderr, "\tetherswitchcfg [-f control file] config " 535 "command parameter\n"); 536 fprintf(stderr, "\t\tconfig commands: vlan_mode\n"); 537 fprintf(stderr, "\tetherswitchcfg [-f control file] phy " 538 "phy.register[=value]\n"); 539 fprintf(stderr, "\tetherswitchcfg [-f control file] portX " 540 "[flags] command parameter\n"); 541 fprintf(stderr, "\t\tport commands: pvid, media, mediaopt\n"); 542 fprintf(stderr, "\tetherswitchcfg [-f control file] reg " 543 "register[=value]\n"); 544 fprintf(stderr, "\tetherswitchcfg [-f control file] vlangroupX " 545 "command parameter\n"); 546 fprintf(stderr, "\t\tvlangroup commands: vlan, members\n"); 547 exit(EX_USAGE); 548 } 549 550 static void 551 newmode(struct cfg *cfg, enum cmdmode mode) 552 { 553 if (mode == cfg->mode) 554 return; 555 switch (cfg->mode) { 556 case MODE_NONE: 557 break; 558 case MODE_CONFIG: 559 /* 560 * Read the updated the configuration (it can be different 561 * from the last time we read it). 562 */ 563 if (ioctl(cfg->fd, IOETHERSWITCHGETCONF, &cfg->conf) != 0) 564 err(EX_OSERR, "ioctl(IOETHERSWITCHGETCONF)"); 565 print_config(cfg); 566 break; 567 case MODE_PORT: 568 print_port(cfg, cfg->unit); 569 break; 570 case MODE_VLANGROUP: 571 print_vlangroup(cfg, cfg->unit); 572 break; 573 case MODE_REGISTER: 574 case MODE_PHYREG: 575 break; 576 } 577 cfg->mode = mode; 578 } 579 580 int 581 main(int argc, char *argv[]) 582 { 583 int ch; 584 struct cfg cfg; 585 int i; 586 587 bzero(&cfg, sizeof(cfg)); 588 cfg.controlfile = "/dev/etherswitch0"; 589 while ((ch = getopt(argc, argv, "f:mv?")) != -1) 590 switch(ch) { 591 case 'f': 592 cfg.controlfile = optarg; 593 break; 594 case 'm': 595 cfg.mediatypes++; 596 break; 597 case 'v': 598 cfg.verbose++; 599 break; 600 case '?': 601 /* FALLTHROUGH */ 602 default: 603 usage(&cfg, argv); 604 } 605 argc -= optind; 606 argv += optind; 607 cfg.fd = open(cfg.controlfile, O_RDONLY); 608 if (cfg.fd < 0) 609 err(EX_UNAVAILABLE, "Can't open control file: %s", cfg.controlfile); 610 if (ioctl(cfg.fd, IOETHERSWITCHGETINFO, &cfg.info) != 0) 611 err(EX_OSERR, "ioctl(IOETHERSWITCHGETINFO)"); 612 if (ioctl(cfg.fd, IOETHERSWITCHGETCONF, &cfg.conf) != 0) 613 err(EX_OSERR, "ioctl(IOETHERSWITCHGETCONF)"); 614 if (argc == 0) { 615 print_info(&cfg); 616 return (0); 617 } 618 cfg.mode = MODE_NONE; 619 while (argc > 0) { 620 switch(cfg.mode) { 621 case MODE_NONE: 622 if (strcmp(argv[0], "info") == 0) { 623 print_info(&cfg); 624 } else if (sscanf(argv[0], "port%d", &cfg.unit) == 1) { 625 if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nports) 626 errx(EX_USAGE, "port unit must be between 0 and %d", cfg.info.es_nports - 1); 627 newmode(&cfg, MODE_PORT); 628 } else if (sscanf(argv[0], "vlangroup%d", &cfg.unit) == 1) { 629 if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nvlangroups) 630 errx(EX_USAGE, 631 "vlangroup unit must be between 0 and %d", 632 cfg.info.es_nvlangroups - 1); 633 newmode(&cfg, MODE_VLANGROUP); 634 } else if (strcmp(argv[0], "config") == 0) { 635 newmode(&cfg, MODE_CONFIG); 636 } else if (strcmp(argv[0], "phy") == 0) { 637 newmode(&cfg, MODE_PHYREG); 638 } else if (strcmp(argv[0], "reg") == 0) { 639 newmode(&cfg, MODE_REGISTER); 640 } else if (strcmp(argv[0], "help") == 0) { 641 usage(&cfg, argv); 642 } else { 643 errx(EX_USAGE, "Unknown command \"%s\"", argv[0]); 644 } 645 break; 646 case MODE_PORT: 647 case MODE_CONFIG: 648 case MODE_VLANGROUP: 649 for(i=0; cmds[i].name != NULL; i++) { 650 if (cfg.mode == cmds[i].mode && strcmp(argv[0], cmds[i].name) == 0) { 651 if (argc < (cmds[i].args + 1)) { 652 printf("%s needs an argument\n", cmds[i].name); 653 break; 654 } 655 (cmds[i].f)(&cfg, argv); 656 argc -= cmds[i].args; 657 argv += cmds[i].args; 658 break; 659 } 660 } 661 if (cmds[i].name == NULL) { 662 newmode(&cfg, MODE_NONE); 663 continue; 664 } 665 break; 666 case MODE_REGISTER: 667 if (set_register(&cfg, argv[0]) != 0) { 668 newmode(&cfg, MODE_NONE); 669 continue; 670 } 671 break; 672 case MODE_PHYREG: 673 if (set_phyregister(&cfg, argv[0]) != 0) { 674 newmode(&cfg, MODE_NONE); 675 continue; 676 } 677 break; 678 } 679 argc--; 680 argv++; 681 } 682 /* switch back to command mode to print configuration for last command */ 683 newmode(&cfg, MODE_NONE); 684 close(cfg.fd); 685 return (0); 686 } 687 688 static struct cmds cmds[] = { 689 { MODE_PORT, "pvid", 1, set_port_vid }, 690 { MODE_PORT, "media", 1, set_port_media }, 691 { MODE_PORT, "mediaopt", 1, set_port_mediaopt }, 692 { MODE_PORT, "addtag", 0, set_port_flag }, 693 { MODE_PORT, "-addtag", 0, set_port_flag }, 694 { MODE_PORT, "ingress", 0, set_port_flag }, 695 { MODE_PORT, "-ingress", 0, set_port_flag }, 696 { MODE_PORT, "striptag", 0, set_port_flag }, 697 { MODE_PORT, "-striptag", 0, set_port_flag }, 698 { MODE_PORT, "doubletag", 0, set_port_flag }, 699 { MODE_PORT, "-doubletag", 0, set_port_flag }, 700 { MODE_PORT, "firstlock", 0, set_port_flag }, 701 { MODE_PORT, "-firstlock", 0, set_port_flag }, 702 { MODE_PORT, "dropuntagged", 0, set_port_flag }, 703 { MODE_PORT, "-dropuntagged", 0, set_port_flag }, 704 { MODE_CONFIG, "vlan_mode", 1, set_vlan_mode }, 705 { MODE_VLANGROUP, "vlan", 1, set_vlangroup_vid }, 706 { MODE_VLANGROUP, "members", 1, set_vlangroup_members }, 707 { 0, NULL, 0, NULL } 708 }; 709