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