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 == 0 && vg.es_member_ports == 0) 475 return; 476 printf("vlangroup%d:\n", vlangroup); 477 if (cfg->conf.vlan_mode == ETHERSWITCH_VLAN_PORT) 478 printf("\tport: %d\n", vg.es_vid); 479 else 480 printf("\tvlan: %d\n", vg.es_vid); 481 printf("\tmembers "); 482 comma = 0; 483 if (vg.es_member_ports != 0) 484 for (i=0; i<cfg->info.es_nports; i++) { 485 if ((vg.es_member_ports & ETHERSWITCH_PORTMASK(i)) != 0) { 486 if (comma) 487 printf(","); 488 printf("%d", i); 489 if ((vg.es_untagged_ports & ETHERSWITCH_PORTMASK(i)) == 0) 490 printf("t"); 491 comma = 1; 492 } 493 } 494 else 495 printf("none"); 496 printf("\n"); 497 } 498 499 static void 500 print_info(struct cfg *cfg) 501 { 502 const char *c; 503 int i; 504 505 c = strrchr(cfg->controlfile, '/'); 506 if (c != NULL) 507 c = c + 1; 508 else 509 c = cfg->controlfile; 510 if (cfg->verbose) { 511 printf("%s: %s with %d ports and %d VLAN groups\n", c, 512 cfg->info.es_name, cfg->info.es_nports, 513 cfg->info.es_nvlangroups); 514 printf("%s: ", c); 515 printb("VLAN capabilities", cfg->info.es_vlan_caps, 516 ETHERSWITCH_VLAN_CAPS_BITS); 517 printf("\n"); 518 } 519 print_config(cfg); 520 for (i=0; i<cfg->info.es_nports; i++) { 521 print_port(cfg, i); 522 } 523 for (i=0; i<cfg->info.es_nvlangroups; i++) { 524 print_vlangroup(cfg, i); 525 } 526 } 527 528 static void 529 usage(struct cfg *cfg __unused, char *argv[] __unused) 530 { 531 fprintf(stderr, "usage: etherswitchctl\n"); 532 fprintf(stderr, "\tetherswitchcfg [-f control file] info\n"); 533 fprintf(stderr, "\tetherswitchcfg [-f control file] config " 534 "command parameter\n"); 535 fprintf(stderr, "\t\tconfig commands: vlan_mode\n"); 536 fprintf(stderr, "\tetherswitchcfg [-f control file] phy " 537 "phy.register[=value]\n"); 538 fprintf(stderr, "\tetherswitchcfg [-f control file] portX " 539 "[flags] command parameter\n"); 540 fprintf(stderr, "\t\tport commands: pvid, media, mediaopt\n"); 541 fprintf(stderr, "\tetherswitchcfg [-f control file] reg " 542 "register[=value]\n"); 543 fprintf(stderr, "\tetherswitchcfg [-f control file] vlangroupX " 544 "command parameter\n"); 545 fprintf(stderr, "\t\tvlangroup commands: vlan, members\n"); 546 exit(EX_USAGE); 547 } 548 549 static void 550 newmode(struct cfg *cfg, enum cmdmode mode) 551 { 552 if (mode == cfg->mode) 553 return; 554 switch (cfg->mode) { 555 case MODE_NONE: 556 break; 557 case MODE_CONFIG: 558 /* 559 * Read the updated the configuration (it can be different 560 * from the last time we read it). 561 */ 562 if (ioctl(cfg->fd, IOETHERSWITCHGETCONF, &cfg->conf) != 0) 563 err(EX_OSERR, "ioctl(IOETHERSWITCHGETCONF)"); 564 print_config(cfg); 565 break; 566 case MODE_PORT: 567 print_port(cfg, cfg->unit); 568 break; 569 case MODE_VLANGROUP: 570 print_vlangroup(cfg, cfg->unit); 571 break; 572 case MODE_REGISTER: 573 case MODE_PHYREG: 574 break; 575 } 576 cfg->mode = mode; 577 } 578 579 int 580 main(int argc, char *argv[]) 581 { 582 int ch; 583 struct cfg cfg; 584 int i; 585 586 bzero(&cfg, sizeof(cfg)); 587 cfg.controlfile = "/dev/etherswitch0"; 588 while ((ch = getopt(argc, argv, "f:mv?")) != -1) 589 switch(ch) { 590 case 'f': 591 cfg.controlfile = optarg; 592 break; 593 case 'm': 594 cfg.mediatypes++; 595 break; 596 case 'v': 597 cfg.verbose++; 598 break; 599 case '?': 600 /* FALLTHROUGH */ 601 default: 602 usage(&cfg, argv); 603 } 604 argc -= optind; 605 argv += optind; 606 cfg.fd = open(cfg.controlfile, O_RDONLY); 607 if (cfg.fd < 0) 608 err(EX_UNAVAILABLE, "Can't open control file: %s", cfg.controlfile); 609 if (ioctl(cfg.fd, IOETHERSWITCHGETINFO, &cfg.info) != 0) 610 err(EX_OSERR, "ioctl(IOETHERSWITCHGETINFO)"); 611 if (ioctl(cfg.fd, IOETHERSWITCHGETCONF, &cfg.conf) != 0) 612 err(EX_OSERR, "ioctl(IOETHERSWITCHGETCONF)"); 613 if (argc == 0) { 614 print_info(&cfg); 615 return (0); 616 } 617 cfg.mode = MODE_NONE; 618 while (argc > 0) { 619 switch(cfg.mode) { 620 case MODE_NONE: 621 if (strcmp(argv[0], "info") == 0) { 622 print_info(&cfg); 623 } else if (sscanf(argv[0], "port%d", &cfg.unit) == 1) { 624 if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nports) 625 errx(EX_USAGE, "port unit must be between 0 and %d", cfg.info.es_nports); 626 newmode(&cfg, MODE_PORT); 627 } else if (sscanf(argv[0], "vlangroup%d", &cfg.unit) == 1) { 628 if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nvlangroups) 629 errx(EX_USAGE, "port unit must be between 0 and %d", cfg.info.es_nvlangroups); 630 newmode(&cfg, MODE_VLANGROUP); 631 } else if (strcmp(argv[0], "config") == 0) { 632 newmode(&cfg, MODE_CONFIG); 633 } else if (strcmp(argv[0], "phy") == 0) { 634 newmode(&cfg, MODE_PHYREG); 635 } else if (strcmp(argv[0], "reg") == 0) { 636 newmode(&cfg, MODE_REGISTER); 637 } else if (strcmp(argv[0], "help") == 0) { 638 usage(&cfg, argv); 639 } else { 640 errx(EX_USAGE, "Unknown command \"%s\"", argv[0]); 641 } 642 break; 643 case MODE_PORT: 644 case MODE_CONFIG: 645 case MODE_VLANGROUP: 646 for(i=0; cmds[i].name != NULL; i++) { 647 if (cfg.mode == cmds[i].mode && strcmp(argv[0], cmds[i].name) == 0) { 648 if (argc < (cmds[i].args + 1)) { 649 printf("%s needs an argument\n", cmds[i].name); 650 break; 651 } 652 (cmds[i].f)(&cfg, argv); 653 argc -= cmds[i].args; 654 argv += cmds[i].args; 655 break; 656 } 657 } 658 if (cmds[i].name == NULL) { 659 newmode(&cfg, MODE_NONE); 660 continue; 661 } 662 break; 663 case MODE_REGISTER: 664 if (set_register(&cfg, argv[0]) != 0) { 665 newmode(&cfg, MODE_NONE); 666 continue; 667 } 668 break; 669 case MODE_PHYREG: 670 if (set_phyregister(&cfg, argv[0]) != 0) { 671 newmode(&cfg, MODE_NONE); 672 continue; 673 } 674 break; 675 } 676 argc--; 677 argv++; 678 } 679 /* switch back to command mode to print configuration for last command */ 680 newmode(&cfg, MODE_NONE); 681 close(cfg.fd); 682 return (0); 683 } 684 685 static struct cmds cmds[] = { 686 { MODE_PORT, "pvid", 1, set_port_vid }, 687 { MODE_PORT, "media", 1, set_port_media }, 688 { MODE_PORT, "mediaopt", 1, set_port_mediaopt }, 689 { MODE_PORT, "addtag", 0, set_port_flag }, 690 { MODE_PORT, "-addtag", 0, set_port_flag }, 691 { MODE_PORT, "ingress", 0, set_port_flag }, 692 { MODE_PORT, "-ingress", 0, set_port_flag }, 693 { MODE_PORT, "striptag", 0, set_port_flag }, 694 { MODE_PORT, "-striptag", 0, set_port_flag }, 695 { MODE_PORT, "doubletag", 0, set_port_flag }, 696 { MODE_PORT, "-doubletag", 0, set_port_flag }, 697 { MODE_PORT, "firstlock", 0, set_port_flag }, 698 { MODE_PORT, "-firstlock", 0, set_port_flag }, 699 { MODE_PORT, "dropuntagged", 0, set_port_flag }, 700 { MODE_PORT, "-dropuntagged", 0, set_port_flag }, 701 { MODE_CONFIG, "vlan_mode", 1, set_vlan_mode }, 702 { MODE_VLANGROUP, "vlan", 1, set_vlangroup_vid }, 703 { MODE_VLANGROUP, "members", 1, set_vlangroup_members }, 704 { 0, NULL, 0, NULL } 705 }; 706