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 if (p.es_ifmr.ifm_count == 0) 239 return; 240 subtype = get_media_subtype(IFM_TYPE(ifm_ulist[0]), argv[1]); 241 p.es_ifr.ifr_media = (p.es_ifmr.ifm_current & IFM_IMASK) | 242 IFM_TYPE(ifm_ulist[0]) | subtype; 243 if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) 244 err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); 245 } 246 247 static void 248 set_port_mediaopt(struct cfg *cfg, char *argv[]) 249 { 250 etherswitch_port_t p; 251 int ifm_ulist[IFMEDIAREQ_NULISTENTRIES]; 252 int options; 253 254 bzero(&p, sizeof(p)); 255 p.es_port = cfg->unit; 256 p.es_ifmr.ifm_ulist = ifm_ulist; 257 p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; 258 if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) 259 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); 260 options = get_media_options(IFM_TYPE(ifm_ulist[0]), argv[1]); 261 if (options == -1) 262 errx(EX_USAGE, "invalid media options \"%s\"", argv[1]); 263 if (options & IFM_HDX) { 264 p.es_ifr.ifr_media &= ~IFM_FDX; 265 options &= ~IFM_HDX; 266 } 267 p.es_ifr.ifr_media |= options; 268 if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) 269 err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); 270 } 271 272 static void 273 set_vlangroup_vid(struct cfg *cfg, char *argv[]) 274 { 275 int v; 276 etherswitch_vlangroup_t vg; 277 278 v = strtol(argv[1], NULL, 0); 279 if (v < 0 || v > IEEE802DOT1Q_VID_MAX) 280 errx(EX_USAGE, "vlan must be between 0 and %d", IEEE802DOT1Q_VID_MAX); 281 vg.es_vlangroup = cfg->unit; 282 if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0) 283 err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)"); 284 vg.es_vid = v; 285 if (ioctl(cfg->fd, IOETHERSWITCHSETVLANGROUP, &vg) != 0) 286 err(EX_OSERR, "ioctl(IOETHERSWITCHSETVLANGROUP)"); 287 } 288 289 static void 290 set_vlangroup_members(struct cfg *cfg, char *argv[]) 291 { 292 etherswitch_vlangroup_t vg; 293 int member, untagged; 294 char *c, *d; 295 int v; 296 297 member = untagged = 0; 298 if (strcmp(argv[1], "none") != 0) { 299 for (c=argv[1]; *c; c=d) { 300 v = strtol(c, &d, 0); 301 if (d == c) 302 break; 303 if (v < 0 || v >= cfg->info.es_nports) 304 errx(EX_USAGE, "Member port must be between 0 and %d", cfg->info.es_nports-1); 305 if (d[0] == ',' || d[0] == '\0' || 306 ((d[0] == 't' || d[0] == 'T') && (d[1] == ',' || d[1] == '\0'))) { 307 if (d[0] == 't' || d[0] == 'T') { 308 untagged &= ~ETHERSWITCH_PORTMASK(v); 309 d++; 310 } else 311 untagged |= ETHERSWITCH_PORTMASK(v); 312 member |= ETHERSWITCH_PORTMASK(v); 313 d++; 314 } else 315 errx(EX_USAGE, "Invalid members specification \"%s\"", d); 316 } 317 } 318 vg.es_vlangroup = cfg->unit; 319 if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0) 320 err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)"); 321 vg.es_member_ports = member; 322 vg.es_untagged_ports = untagged; 323 if (ioctl(cfg->fd, IOETHERSWITCHSETVLANGROUP, &vg) != 0) 324 err(EX_OSERR, "ioctl(IOETHERSWITCHSETVLANGROUP)"); 325 } 326 327 static int 328 set_register(struct cfg *cfg, char *arg) 329 { 330 int a, v; 331 char *c; 332 333 a = strtol(arg, &c, 0); 334 if (c==arg) 335 return (1); 336 if (*c == '=') { 337 v = strtol(c+1, NULL, 0); 338 write_register(cfg, a, v); 339 } 340 printf("\treg 0x%04x=0x%04x\n", a, read_register(cfg, a)); 341 return (0); 342 } 343 344 static int 345 set_phyregister(struct cfg *cfg, char *arg) 346 { 347 int phy, reg, val; 348 char *c, *d; 349 350 phy = strtol(arg, &c, 0); 351 if (c==arg) 352 return (1); 353 if (*c != '.') 354 return (1); 355 d = c+1; 356 reg = strtol(d, &c, 0); 357 if (d == c) 358 return (1); 359 if (*c == '=') { 360 val = strtol(c+1, NULL, 0); 361 write_phyregister(cfg, phy, reg, val); 362 } 363 printf("\treg %d.0x%02x=0x%04x\n", phy, reg, read_phyregister(cfg, phy, reg)); 364 return (0); 365 } 366 367 static void 368 set_vlan_mode(struct cfg *cfg, char *argv[]) 369 { 370 etherswitch_conf_t conf; 371 372 bzero(&conf, sizeof(conf)); 373 conf.cmd = ETHERSWITCH_CONF_VLAN_MODE; 374 if (strcasecmp(argv[1], "isl") == 0) 375 conf.vlan_mode = ETHERSWITCH_VLAN_ISL; 376 else if (strcasecmp(argv[1], "port") == 0) 377 conf.vlan_mode = ETHERSWITCH_VLAN_PORT; 378 else if (strcasecmp(argv[1], "dot1q") == 0) 379 conf.vlan_mode = ETHERSWITCH_VLAN_DOT1Q; 380 else if (strcasecmp(argv[1], "dot1q4k") == 0) 381 conf.vlan_mode = ETHERSWITCH_VLAN_DOT1Q_4K; 382 else if (strcasecmp(argv[1], "qinq") == 0) 383 conf.vlan_mode = ETHERSWITCH_VLAN_DOUBLE_TAG; 384 else 385 conf.vlan_mode = 0; 386 if (ioctl(cfg->fd, IOETHERSWITCHSETCONF, &conf) != 0) 387 err(EX_OSERR, "ioctl(IOETHERSWITCHSETCONF)"); 388 } 389 390 static void 391 print_config(struct cfg *cfg) 392 { 393 const char *c; 394 395 /* Get the device name. */ 396 c = strrchr(cfg->controlfile, '/'); 397 if (c != NULL) 398 c = c + 1; 399 else 400 c = cfg->controlfile; 401 402 /* Print VLAN mode. */ 403 if (cfg->conf.cmd & ETHERSWITCH_CONF_VLAN_MODE) { 404 printf("%s: VLAN mode: ", c); 405 switch (cfg->conf.vlan_mode) { 406 case ETHERSWITCH_VLAN_ISL: 407 printf("ISL\n"); 408 break; 409 case ETHERSWITCH_VLAN_PORT: 410 printf("PORT\n"); 411 break; 412 case ETHERSWITCH_VLAN_DOT1Q: 413 printf("DOT1Q\n"); 414 break; 415 case ETHERSWITCH_VLAN_DOT1Q_4K: 416 printf("DOT1Q4K\n"); 417 break; 418 case ETHERSWITCH_VLAN_DOUBLE_TAG: 419 printf("QinQ\n"); 420 break; 421 default: 422 printf("none\n"); 423 } 424 } 425 } 426 427 static void 428 print_port(struct cfg *cfg, int port) 429 { 430 etherswitch_port_t p; 431 int ifm_ulist[IFMEDIAREQ_NULISTENTRIES]; 432 int i; 433 434 bzero(&p, sizeof(p)); 435 p.es_port = port; 436 p.es_ifmr.ifm_ulist = ifm_ulist; 437 p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; 438 if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) 439 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); 440 printf("port%d:\n", port); 441 if (cfg->conf.vlan_mode == ETHERSWITCH_VLAN_DOT1Q) 442 printf("\tpvid: %d\n", p.es_pvid); 443 printb("\tflags", p.es_flags, ETHERSWITCH_PORT_FLAGS_BITS); 444 printf("\n"); 445 printf("\tmedia: "); 446 print_media_word(p.es_ifmr.ifm_current, 1); 447 if (p.es_ifmr.ifm_active != p.es_ifmr.ifm_current) { 448 putchar(' '); 449 putchar('('); 450 print_media_word(p.es_ifmr.ifm_active, 0); 451 putchar(')'); 452 } 453 putchar('\n'); 454 printf("\tstatus: %s\n", (p.es_ifmr.ifm_status & IFM_ACTIVE) != 0 ? "active" : "no carrier"); 455 if (cfg->mediatypes) { 456 printf("\tsupported media:\n"); 457 if (p.es_ifmr.ifm_count > IFMEDIAREQ_NULISTENTRIES) 458 p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; 459 for (i=0; i<p.es_ifmr.ifm_count; i++) { 460 printf("\t\tmedia "); 461 print_media_word(ifm_ulist[i], 0); 462 putchar('\n'); 463 } 464 } 465 } 466 467 static void 468 print_vlangroup(struct cfg *cfg, int vlangroup) 469 { 470 etherswitch_vlangroup_t vg; 471 int i, comma; 472 473 vg.es_vlangroup = vlangroup; 474 if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0) 475 err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)"); 476 if ((vg.es_vid & ETHERSWITCH_VID_VALID) == 0) 477 return; 478 vg.es_vid &= ETHERSWITCH_VID_MASK; 479 printf("vlangroup%d:\n", vlangroup); 480 if (cfg->conf.vlan_mode == ETHERSWITCH_VLAN_PORT) 481 printf("\tport: %d\n", vg.es_vid); 482 else 483 printf("\tvlan: %d\n", vg.es_vid); 484 printf("\tmembers "); 485 comma = 0; 486 if (vg.es_member_ports != 0) 487 for (i=0; i<cfg->info.es_nports; i++) { 488 if ((vg.es_member_ports & ETHERSWITCH_PORTMASK(i)) != 0) { 489 if (comma) 490 printf(","); 491 printf("%d", i); 492 if ((vg.es_untagged_ports & ETHERSWITCH_PORTMASK(i)) == 0) 493 printf("t"); 494 comma = 1; 495 } 496 } 497 else 498 printf("none"); 499 printf("\n"); 500 } 501 502 static void 503 print_info(struct cfg *cfg) 504 { 505 const char *c; 506 int i; 507 508 c = strrchr(cfg->controlfile, '/'); 509 if (c != NULL) 510 c = c + 1; 511 else 512 c = cfg->controlfile; 513 if (cfg->verbose) { 514 printf("%s: %s with %d ports and %d VLAN groups\n", c, 515 cfg->info.es_name, cfg->info.es_nports, 516 cfg->info.es_nvlangroups); 517 printf("%s: ", c); 518 printb("VLAN capabilities", cfg->info.es_vlan_caps, 519 ETHERSWITCH_VLAN_CAPS_BITS); 520 printf("\n"); 521 } 522 print_config(cfg); 523 for (i=0; i<cfg->info.es_nports; i++) { 524 print_port(cfg, i); 525 } 526 for (i=0; i<cfg->info.es_nvlangroups; i++) { 527 print_vlangroup(cfg, i); 528 } 529 } 530 531 static void 532 usage(struct cfg *cfg __unused, char *argv[] __unused) 533 { 534 fprintf(stderr, "usage: etherswitchctl\n"); 535 fprintf(stderr, "\tetherswitchcfg [-f control file] info\n"); 536 fprintf(stderr, "\tetherswitchcfg [-f control file] config " 537 "command parameter\n"); 538 fprintf(stderr, "\t\tconfig commands: vlan_mode\n"); 539 fprintf(stderr, "\tetherswitchcfg [-f control file] phy " 540 "phy.register[=value]\n"); 541 fprintf(stderr, "\tetherswitchcfg [-f control file] portX " 542 "[flags] command parameter\n"); 543 fprintf(stderr, "\t\tport commands: pvid, media, mediaopt\n"); 544 fprintf(stderr, "\tetherswitchcfg [-f control file] reg " 545 "register[=value]\n"); 546 fprintf(stderr, "\tetherswitchcfg [-f control file] vlangroupX " 547 "command parameter\n"); 548 fprintf(stderr, "\t\tvlangroup commands: vlan, members\n"); 549 exit(EX_USAGE); 550 } 551 552 static void 553 newmode(struct cfg *cfg, enum cmdmode mode) 554 { 555 if (mode == cfg->mode) 556 return; 557 switch (cfg->mode) { 558 case MODE_NONE: 559 break; 560 case MODE_CONFIG: 561 /* 562 * Read the updated the configuration (it can be different 563 * from the last time we read it). 564 */ 565 if (ioctl(cfg->fd, IOETHERSWITCHGETCONF, &cfg->conf) != 0) 566 err(EX_OSERR, "ioctl(IOETHERSWITCHGETCONF)"); 567 print_config(cfg); 568 break; 569 case MODE_PORT: 570 print_port(cfg, cfg->unit); 571 break; 572 case MODE_VLANGROUP: 573 print_vlangroup(cfg, cfg->unit); 574 break; 575 case MODE_REGISTER: 576 case MODE_PHYREG: 577 break; 578 } 579 cfg->mode = mode; 580 } 581 582 int 583 main(int argc, char *argv[]) 584 { 585 int ch; 586 struct cfg cfg; 587 int i; 588 589 bzero(&cfg, sizeof(cfg)); 590 cfg.controlfile = "/dev/etherswitch0"; 591 while ((ch = getopt(argc, argv, "f:mv?")) != -1) 592 switch(ch) { 593 case 'f': 594 cfg.controlfile = optarg; 595 break; 596 case 'm': 597 cfg.mediatypes++; 598 break; 599 case 'v': 600 cfg.verbose++; 601 break; 602 case '?': 603 /* FALLTHROUGH */ 604 default: 605 usage(&cfg, argv); 606 } 607 argc -= optind; 608 argv += optind; 609 cfg.fd = open(cfg.controlfile, O_RDONLY); 610 if (cfg.fd < 0) 611 err(EX_UNAVAILABLE, "Can't open control file: %s", cfg.controlfile); 612 if (ioctl(cfg.fd, IOETHERSWITCHGETINFO, &cfg.info) != 0) 613 err(EX_OSERR, "ioctl(IOETHERSWITCHGETINFO)"); 614 if (ioctl(cfg.fd, IOETHERSWITCHGETCONF, &cfg.conf) != 0) 615 err(EX_OSERR, "ioctl(IOETHERSWITCHGETCONF)"); 616 if (argc == 0) { 617 print_info(&cfg); 618 return (0); 619 } 620 cfg.mode = MODE_NONE; 621 while (argc > 0) { 622 switch(cfg.mode) { 623 case MODE_NONE: 624 if (strcmp(argv[0], "info") == 0) { 625 print_info(&cfg); 626 } else if (sscanf(argv[0], "port%d", &cfg.unit) == 1) { 627 if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nports) 628 errx(EX_USAGE, "port unit must be between 0 and %d", cfg.info.es_nports - 1); 629 newmode(&cfg, MODE_PORT); 630 } else if (sscanf(argv[0], "vlangroup%d", &cfg.unit) == 1) { 631 if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nvlangroups) 632 errx(EX_USAGE, 633 "vlangroup unit must be between 0 and %d", 634 cfg.info.es_nvlangroups - 1); 635 newmode(&cfg, MODE_VLANGROUP); 636 } else if (strcmp(argv[0], "config") == 0) { 637 newmode(&cfg, MODE_CONFIG); 638 } else if (strcmp(argv[0], "phy") == 0) { 639 newmode(&cfg, MODE_PHYREG); 640 } else if (strcmp(argv[0], "reg") == 0) { 641 newmode(&cfg, MODE_REGISTER); 642 } else if (strcmp(argv[0], "help") == 0) { 643 usage(&cfg, argv); 644 } else { 645 errx(EX_USAGE, "Unknown command \"%s\"", argv[0]); 646 } 647 break; 648 case MODE_PORT: 649 case MODE_CONFIG: 650 case MODE_VLANGROUP: 651 for(i=0; cmds[i].name != NULL; i++) { 652 if (cfg.mode == cmds[i].mode && strcmp(argv[0], cmds[i].name) == 0) { 653 if (argc < (cmds[i].args + 1)) { 654 printf("%s needs an argument\n", cmds[i].name); 655 break; 656 } 657 (cmds[i].f)(&cfg, argv); 658 argc -= cmds[i].args; 659 argv += cmds[i].args; 660 break; 661 } 662 } 663 if (cmds[i].name == NULL) { 664 newmode(&cfg, MODE_NONE); 665 continue; 666 } 667 break; 668 case MODE_REGISTER: 669 if (set_register(&cfg, argv[0]) != 0) { 670 newmode(&cfg, MODE_NONE); 671 continue; 672 } 673 break; 674 case MODE_PHYREG: 675 if (set_phyregister(&cfg, argv[0]) != 0) { 676 newmode(&cfg, MODE_NONE); 677 continue; 678 } 679 break; 680 } 681 argc--; 682 argv++; 683 } 684 /* switch back to command mode to print configuration for last command */ 685 newmode(&cfg, MODE_NONE); 686 close(cfg.fd); 687 return (0); 688 } 689 690 static struct cmds cmds[] = { 691 { MODE_PORT, "pvid", 1, set_port_vid }, 692 { MODE_PORT, "media", 1, set_port_media }, 693 { MODE_PORT, "mediaopt", 1, set_port_mediaopt }, 694 { MODE_PORT, "addtag", 0, set_port_flag }, 695 { MODE_PORT, "-addtag", 0, set_port_flag }, 696 { MODE_PORT, "ingress", 0, set_port_flag }, 697 { MODE_PORT, "-ingress", 0, set_port_flag }, 698 { MODE_PORT, "striptag", 0, set_port_flag }, 699 { MODE_PORT, "-striptag", 0, set_port_flag }, 700 { MODE_PORT, "doubletag", 0, set_port_flag }, 701 { MODE_PORT, "-doubletag", 0, set_port_flag }, 702 { MODE_PORT, "firstlock", 0, set_port_flag }, 703 { MODE_PORT, "-firstlock", 0, set_port_flag }, 704 { MODE_PORT, "dropuntagged", 0, set_port_flag }, 705 { MODE_PORT, "-dropuntagged", 0, set_port_flag }, 706 { MODE_CONFIG, "vlan_mode", 1, set_vlan_mode }, 707 { MODE_VLANGROUP, "vlan", 1, set_vlangroup_vid }, 708 { MODE_VLANGROUP, "members", 1, set_vlangroup_members }, 709 { 0, NULL, 0, NULL } 710 }; 711