1235289Sadrian/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4235289Sadrian * Copyright (c) 2011-2012 Stefan Bethke. 5235289Sadrian * All rights reserved. 6235289Sadrian * 7235289Sadrian * Redistribution and use in source and binary forms, with or without 8235289Sadrian * modification, are permitted provided that the following conditions 9235289Sadrian * are met: 10235289Sadrian * 1. Redistributions of source code must retain the above copyright 11235289Sadrian * notice, this list of conditions and the following disclaimer. 12235289Sadrian * 2. Redistributions in binary form must reproduce the above copyright 13235289Sadrian * notice, this list of conditions and the following disclaimer in the 14235289Sadrian * documentation and/or other materials provided with the distribution. 15235289Sadrian * 16235289Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17235289Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18235289Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19235289Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20235289Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21235289Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22235289Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23235289Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24235289Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25235289Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26235289Sadrian * SUCH DAMAGE. 27235289Sadrian * 28235289Sadrian * $FreeBSD: stable/11/sbin/etherswitchcfg/etherswitchcfg.c 330449 2018-03-05 07:26:05Z eadler $ 29235289Sadrian */ 30235289Sadrian 31235289Sadrian#include <sys/cdefs.h> 32235289Sadrian__FBSDID("$FreeBSD: stable/11/sbin/etherswitchcfg/etherswitchcfg.c 330449 2018-03-05 07:26:05Z eadler $"); 33235289Sadrian 34235289Sadrian#include <ctype.h> 35235289Sadrian#include <err.h> 36235289Sadrian#include <errno.h> 37235289Sadrian#include <fcntl.h> 38235289Sadrian#include <stdio.h> 39235289Sadrian#include <stdlib.h> 40235289Sadrian#include <string.h> 41235289Sadrian#include <sysexits.h> 42235289Sadrian#include <unistd.h> 43235289Sadrian#include <sys/types.h> 44235289Sadrian#include <sys/ioctl.h> 45235289Sadrian#include <net/if.h> 46235289Sadrian#include <net/if_media.h> 47235289Sadrian#include <dev/etherswitch/etherswitch.h> 48235289Sadrian 49235289Sadrianint get_media_subtype(int, const char *); 50235289Sadrianint get_media_mode(int, const char *); 51235289Sadrianint get_media_options(int, const char *); 52235289Sadrianint lookup_media_word(struct ifmedia_description *, const char *); 53235289Sadrianvoid print_media_word(int, int); 54235289Sadrianvoid print_media_word_ifconfig(int); 55235289Sadrian 56235289Sadrian/* some constants */ 57235289Sadrian#define IEEE802DOT1Q_VID_MAX 4094 58235289Sadrian#define IFMEDIAREQ_NULISTENTRIES 256 59235289Sadrian 60235289Sadrianenum cmdmode { 61235289Sadrian MODE_NONE = 0, 62235289Sadrian MODE_PORT, 63250382Sadrian MODE_CONFIG, 64235289Sadrian MODE_VLANGROUP, 65235289Sadrian MODE_REGISTER, 66235289Sadrian MODE_PHYREG 67235289Sadrian}; 68235289Sadrian 69235289Sadrianstruct cfg { 70235289Sadrian int fd; 71235289Sadrian int verbose; 72235289Sadrian int mediatypes; 73235289Sadrian const char *controlfile; 74250382Sadrian etherswitch_conf_t conf; 75235289Sadrian etherswitch_info_t info; 76235289Sadrian enum cmdmode mode; 77235289Sadrian int unit; 78235289Sadrian}; 79235289Sadrian 80235289Sadrianstruct cmds { 81235289Sadrian enum cmdmode mode; 82235289Sadrian const char *name; 83235289Sadrian int args; 84235289Sadrian void (*f)(struct cfg *, char *argv[]); 85235289Sadrian}; 86241720Sedstatic struct cmds cmds[]; 87235289Sadrian 88235289Sadrian 89250382Sadrian/* 90250382Sadrian * Print a value a la the %b format of the kernel's printf. 91250382Sadrian * Stolen from ifconfig.c. 92250382Sadrian */ 93250382Sadrianstatic void 94250382Sadrianprintb(const char *s, unsigned v, const char *bits) 95250382Sadrian{ 96250382Sadrian int i, any = 0; 97250382Sadrian char c; 98235289Sadrian 99250382Sadrian if (bits && *bits == 8) 100250382Sadrian printf("%s=%o", s, v); 101250382Sadrian else 102250382Sadrian printf("%s=%x", s, v); 103250382Sadrian bits++; 104250382Sadrian if (bits) { 105250382Sadrian putchar('<'); 106250382Sadrian while ((i = *bits++) != '\0') { 107250382Sadrian if (v & (1 << (i-1))) { 108250382Sadrian if (any) 109250382Sadrian putchar(','); 110250382Sadrian any = 1; 111250382Sadrian for (; (c = *bits) > 32; bits++) 112250382Sadrian putchar(c); 113250382Sadrian } else 114250382Sadrian for (; *bits > 32; bits++) 115250382Sadrian ; 116250382Sadrian } 117250382Sadrian putchar('>'); 118250382Sadrian } 119250382Sadrian} 120250382Sadrian 121235289Sadrianstatic int 122235289Sadrianread_register(struct cfg *cfg, int r) 123235289Sadrian{ 124235289Sadrian struct etherswitch_reg er; 125235289Sadrian 126235289Sadrian er.reg = r; 127235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHGETREG, &er) != 0) 128235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETREG)"); 129235289Sadrian return (er.val); 130235289Sadrian} 131235289Sadrian 132235289Sadrianstatic void 133235289Sadrianwrite_register(struct cfg *cfg, int r, int v) 134235289Sadrian{ 135235289Sadrian struct etherswitch_reg er; 136235289Sadrian 137235289Sadrian er.reg = r; 138235289Sadrian er.val = v; 139235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHSETREG, &er) != 0) 140235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHSETREG)"); 141235289Sadrian} 142235289Sadrian 143235289Sadrianstatic int 144235289Sadrianread_phyregister(struct cfg *cfg, int phy, int reg) 145235289Sadrian{ 146235289Sadrian struct etherswitch_phyreg er; 147235289Sadrian 148235289Sadrian er.phy = phy; 149235289Sadrian er.reg = reg; 150235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHGETPHYREG, &er) != 0) 151235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETPHYREG)"); 152235289Sadrian return (er.val); 153235289Sadrian} 154235289Sadrian 155235289Sadrianstatic void 156235289Sadrianwrite_phyregister(struct cfg *cfg, int phy, int reg, int val) 157235289Sadrian{ 158235289Sadrian struct etherswitch_phyreg er; 159235289Sadrian 160235289Sadrian er.phy = phy; 161235289Sadrian er.reg = reg; 162235289Sadrian er.val = val; 163235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHSETPHYREG, &er) != 0) 164235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHSETPHYREG)"); 165235289Sadrian} 166235289Sadrian 167235289Sadrianstatic void 168249752Sadrianset_port_vid(struct cfg *cfg, char *argv[]) 169235289Sadrian{ 170235289Sadrian int v; 171235289Sadrian etherswitch_port_t p; 172235289Sadrian 173235289Sadrian v = strtol(argv[1], NULL, 0); 174249752Sadrian if (v < 0 || v > IEEE802DOT1Q_VID_MAX) 175249752Sadrian errx(EX_USAGE, "pvid must be between 0 and %d", 176249752Sadrian IEEE802DOT1Q_VID_MAX); 177249747Sadrian bzero(&p, sizeof(p)); 178235289Sadrian p.es_port = cfg->unit; 179235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) 180235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); 181249752Sadrian p.es_pvid = v; 182235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) 183235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); 184235289Sadrian} 185235289Sadrian 186235289Sadrianstatic void 187250382Sadrianset_port_flag(struct cfg *cfg, char *argv[]) 188250382Sadrian{ 189250382Sadrian char *flag; 190250382Sadrian int n; 191250382Sadrian uint32_t f; 192250382Sadrian etherswitch_port_t p; 193250382Sadrian 194250382Sadrian n = 0; 195250382Sadrian f = 0; 196250382Sadrian flag = argv[0]; 197250382Sadrian if (strcmp(flag, "none") != 0) { 198250382Sadrian if (*flag == '-') { 199250382Sadrian n++; 200250382Sadrian flag++; 201250382Sadrian } 202250382Sadrian if (strcasecmp(flag, "striptag") == 0) 203250382Sadrian f = ETHERSWITCH_PORT_STRIPTAG; 204250382Sadrian else if (strcasecmp(flag, "addtag") == 0) 205250382Sadrian f = ETHERSWITCH_PORT_ADDTAG; 206250382Sadrian else if (strcasecmp(flag, "firstlock") == 0) 207250382Sadrian f = ETHERSWITCH_PORT_FIRSTLOCK; 208250382Sadrian else if (strcasecmp(flag, "dropuntagged") == 0) 209250382Sadrian f = ETHERSWITCH_PORT_DROPUNTAGGED; 210250382Sadrian else if (strcasecmp(flag, "doubletag") == 0) 211250382Sadrian f = ETHERSWITCH_PORT_DOUBLE_TAG; 212250382Sadrian else if (strcasecmp(flag, "ingress") == 0) 213250382Sadrian f = ETHERSWITCH_PORT_INGRESS; 214250382Sadrian } 215250382Sadrian bzero(&p, sizeof(p)); 216250382Sadrian p.es_port = cfg->unit; 217250382Sadrian if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) 218250382Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); 219250382Sadrian if (n) 220250382Sadrian p.es_flags &= ~f; 221250382Sadrian else 222250382Sadrian p.es_flags |= f; 223250382Sadrian if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) 224250382Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); 225250382Sadrian} 226250382Sadrian 227250382Sadrianstatic void 228235289Sadrianset_port_media(struct cfg *cfg, char *argv[]) 229235289Sadrian{ 230235289Sadrian etherswitch_port_t p; 231235289Sadrian int ifm_ulist[IFMEDIAREQ_NULISTENTRIES]; 232235289Sadrian int subtype; 233235289Sadrian 234235289Sadrian bzero(&p, sizeof(p)); 235235289Sadrian p.es_port = cfg->unit; 236235289Sadrian p.es_ifmr.ifm_ulist = ifm_ulist; 237235289Sadrian p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; 238235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) 239235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); 240268301Sloos if (p.es_ifmr.ifm_count == 0) 241268301Sloos return; 242235289Sadrian subtype = get_media_subtype(IFM_TYPE(ifm_ulist[0]), argv[1]); 243235289Sadrian p.es_ifr.ifr_media = (p.es_ifmr.ifm_current & IFM_IMASK) | 244235289Sadrian IFM_TYPE(ifm_ulist[0]) | subtype; 245235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) 246235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); 247235289Sadrian} 248235289Sadrian 249235289Sadrianstatic void 250235289Sadrianset_port_mediaopt(struct cfg *cfg, char *argv[]) 251235289Sadrian{ 252235289Sadrian etherswitch_port_t p; 253235289Sadrian int ifm_ulist[IFMEDIAREQ_NULISTENTRIES]; 254235289Sadrian int options; 255235289Sadrian 256235289Sadrian bzero(&p, sizeof(p)); 257235289Sadrian p.es_port = cfg->unit; 258235289Sadrian p.es_ifmr.ifm_ulist = ifm_ulist; 259235289Sadrian p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; 260235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) 261235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); 262235289Sadrian options = get_media_options(IFM_TYPE(ifm_ulist[0]), argv[1]); 263235289Sadrian if (options == -1) 264235289Sadrian errx(EX_USAGE, "invalid media options \"%s\"", argv[1]); 265235289Sadrian if (options & IFM_HDX) { 266235289Sadrian p.es_ifr.ifr_media &= ~IFM_FDX; 267235289Sadrian options &= ~IFM_HDX; 268235289Sadrian } 269235289Sadrian p.es_ifr.ifr_media |= options; 270235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) 271235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); 272235289Sadrian} 273235289Sadrian 274235289Sadrianstatic void 275235289Sadrianset_vlangroup_vid(struct cfg *cfg, char *argv[]) 276235289Sadrian{ 277235289Sadrian int v; 278235289Sadrian etherswitch_vlangroup_t vg; 279308891Sloos 280308891Sloos memset(&vg, 0, sizeof(vg)); 281235289Sadrian v = strtol(argv[1], NULL, 0); 282255730Shiren if (v < 0 || v > IEEE802DOT1Q_VID_MAX) 283235289Sadrian errx(EX_USAGE, "vlan must be between 0 and %d", IEEE802DOT1Q_VID_MAX); 284235289Sadrian vg.es_vlangroup = cfg->unit; 285235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0) 286235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)"); 287235289Sadrian vg.es_vid = v; 288235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHSETVLANGROUP, &vg) != 0) 289235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHSETVLANGROUP)"); 290235289Sadrian} 291235289Sadrian 292235289Sadrianstatic void 293235289Sadrianset_vlangroup_members(struct cfg *cfg, char *argv[]) 294235289Sadrian{ 295235289Sadrian etherswitch_vlangroup_t vg; 296235289Sadrian int member, untagged; 297235289Sadrian char *c, *d; 298235289Sadrian int v; 299308891Sloos 300235289Sadrian member = untagged = 0; 301308891Sloos memset(&vg, 0, sizeof(vg)); 302235289Sadrian if (strcmp(argv[1], "none") != 0) { 303235289Sadrian for (c=argv[1]; *c; c=d) { 304235289Sadrian v = strtol(c, &d, 0); 305235289Sadrian if (d == c) 306235289Sadrian break; 307235289Sadrian if (v < 0 || v >= cfg->info.es_nports) 308235289Sadrian errx(EX_USAGE, "Member port must be between 0 and %d", cfg->info.es_nports-1); 309235289Sadrian if (d[0] == ',' || d[0] == '\0' || 310235289Sadrian ((d[0] == 't' || d[0] == 'T') && (d[1] == ',' || d[1] == '\0'))) { 311235289Sadrian if (d[0] == 't' || d[0] == 'T') { 312235289Sadrian untagged &= ~ETHERSWITCH_PORTMASK(v); 313235289Sadrian d++; 314235289Sadrian } else 315235289Sadrian untagged |= ETHERSWITCH_PORTMASK(v); 316235289Sadrian member |= ETHERSWITCH_PORTMASK(v); 317235289Sadrian d++; 318235289Sadrian } else 319235289Sadrian errx(EX_USAGE, "Invalid members specification \"%s\"", d); 320235289Sadrian } 321235289Sadrian } 322235289Sadrian vg.es_vlangroup = cfg->unit; 323235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0) 324235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)"); 325235289Sadrian vg.es_member_ports = member; 326235289Sadrian vg.es_untagged_ports = untagged; 327235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHSETVLANGROUP, &vg) != 0) 328235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHSETVLANGROUP)"); 329235289Sadrian} 330235289Sadrian 331235289Sadrianstatic int 332235289Sadrianset_register(struct cfg *cfg, char *arg) 333235289Sadrian{ 334235289Sadrian int a, v; 335235289Sadrian char *c; 336235289Sadrian 337235289Sadrian a = strtol(arg, &c, 0); 338235289Sadrian if (c==arg) 339235289Sadrian return (1); 340235289Sadrian if (*c == '=') { 341235289Sadrian v = strtol(c+1, NULL, 0); 342235289Sadrian write_register(cfg, a, v); 343235289Sadrian } 344235289Sadrian printf("\treg 0x%04x=0x%04x\n", a, read_register(cfg, a)); 345235289Sadrian return (0); 346235289Sadrian} 347235289Sadrian 348235289Sadrianstatic int 349235289Sadrianset_phyregister(struct cfg *cfg, char *arg) 350235289Sadrian{ 351235289Sadrian int phy, reg, val; 352235289Sadrian char *c, *d; 353235289Sadrian 354235289Sadrian phy = strtol(arg, &c, 0); 355235289Sadrian if (c==arg) 356235289Sadrian return (1); 357235289Sadrian if (*c != '.') 358235289Sadrian return (1); 359235289Sadrian d = c+1; 360235289Sadrian reg = strtol(d, &c, 0); 361235289Sadrian if (d == c) 362235289Sadrian return (1); 363235289Sadrian if (*c == '=') { 364235289Sadrian val = strtol(c+1, NULL, 0); 365235289Sadrian write_phyregister(cfg, phy, reg, val); 366235289Sadrian } 367235289Sadrian printf("\treg %d.0x%02x=0x%04x\n", phy, reg, read_phyregister(cfg, phy, reg)); 368235289Sadrian return (0); 369235289Sadrian} 370235289Sadrian 371235289Sadrianstatic void 372250382Sadrianset_vlan_mode(struct cfg *cfg, char *argv[]) 373250382Sadrian{ 374250382Sadrian etherswitch_conf_t conf; 375250382Sadrian 376250382Sadrian bzero(&conf, sizeof(conf)); 377250382Sadrian conf.cmd = ETHERSWITCH_CONF_VLAN_MODE; 378250382Sadrian if (strcasecmp(argv[1], "isl") == 0) 379250382Sadrian conf.vlan_mode = ETHERSWITCH_VLAN_ISL; 380250382Sadrian else if (strcasecmp(argv[1], "port") == 0) 381250382Sadrian conf.vlan_mode = ETHERSWITCH_VLAN_PORT; 382250382Sadrian else if (strcasecmp(argv[1], "dot1q") == 0) 383250382Sadrian conf.vlan_mode = ETHERSWITCH_VLAN_DOT1Q; 384250382Sadrian else if (strcasecmp(argv[1], "dot1q4k") == 0) 385250382Sadrian conf.vlan_mode = ETHERSWITCH_VLAN_DOT1Q_4K; 386250382Sadrian else if (strcasecmp(argv[1], "qinq") == 0) 387250382Sadrian conf.vlan_mode = ETHERSWITCH_VLAN_DOUBLE_TAG; 388250382Sadrian else 389250382Sadrian conf.vlan_mode = 0; 390250382Sadrian if (ioctl(cfg->fd, IOETHERSWITCHSETCONF, &conf) != 0) 391250382Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHSETCONF)"); 392250382Sadrian} 393250382Sadrian 394250382Sadrianstatic void 395250382Sadrianprint_config(struct cfg *cfg) 396250382Sadrian{ 397250382Sadrian const char *c; 398250382Sadrian 399250382Sadrian /* Get the device name. */ 400250382Sadrian c = strrchr(cfg->controlfile, '/'); 401250382Sadrian if (c != NULL) 402250382Sadrian c = c + 1; 403250382Sadrian else 404250382Sadrian c = cfg->controlfile; 405250382Sadrian 406250382Sadrian /* Print VLAN mode. */ 407250382Sadrian if (cfg->conf.cmd & ETHERSWITCH_CONF_VLAN_MODE) { 408250382Sadrian printf("%s: VLAN mode: ", c); 409250382Sadrian switch (cfg->conf.vlan_mode) { 410250382Sadrian case ETHERSWITCH_VLAN_ISL: 411250382Sadrian printf("ISL\n"); 412250382Sadrian break; 413250382Sadrian case ETHERSWITCH_VLAN_PORT: 414250382Sadrian printf("PORT\n"); 415250382Sadrian break; 416250382Sadrian case ETHERSWITCH_VLAN_DOT1Q: 417250382Sadrian printf("DOT1Q\n"); 418250382Sadrian break; 419250382Sadrian case ETHERSWITCH_VLAN_DOT1Q_4K: 420250382Sadrian printf("DOT1Q4K\n"); 421250382Sadrian break; 422250382Sadrian case ETHERSWITCH_VLAN_DOUBLE_TAG: 423250382Sadrian printf("QinQ\n"); 424250382Sadrian break; 425250382Sadrian default: 426250382Sadrian printf("none\n"); 427250382Sadrian } 428250382Sadrian } 429250382Sadrian} 430250382Sadrian 431250382Sadrianstatic void 432235289Sadrianprint_port(struct cfg *cfg, int port) 433235289Sadrian{ 434235289Sadrian etherswitch_port_t p; 435235289Sadrian int ifm_ulist[IFMEDIAREQ_NULISTENTRIES]; 436235289Sadrian int i; 437235289Sadrian 438235289Sadrian bzero(&p, sizeof(p)); 439235289Sadrian p.es_port = port; 440235289Sadrian p.es_ifmr.ifm_ulist = ifm_ulist; 441235289Sadrian p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; 442235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) 443235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); 444235289Sadrian printf("port%d:\n", port); 445250382Sadrian if (cfg->conf.vlan_mode == ETHERSWITCH_VLAN_DOT1Q) 446250382Sadrian printf("\tpvid: %d\n", p.es_pvid); 447250382Sadrian printb("\tflags", p.es_flags, ETHERSWITCH_PORT_FLAGS_BITS); 448250382Sadrian printf("\n"); 449235289Sadrian printf("\tmedia: "); 450235289Sadrian print_media_word(p.es_ifmr.ifm_current, 1); 451235289Sadrian if (p.es_ifmr.ifm_active != p.es_ifmr.ifm_current) { 452235289Sadrian putchar(' '); 453235289Sadrian putchar('('); 454235289Sadrian print_media_word(p.es_ifmr.ifm_active, 0); 455235289Sadrian putchar(')'); 456235289Sadrian } 457235289Sadrian putchar('\n'); 458235289Sadrian printf("\tstatus: %s\n", (p.es_ifmr.ifm_status & IFM_ACTIVE) != 0 ? "active" : "no carrier"); 459235289Sadrian if (cfg->mediatypes) { 460235289Sadrian printf("\tsupported media:\n"); 461235289Sadrian if (p.es_ifmr.ifm_count > IFMEDIAREQ_NULISTENTRIES) 462235289Sadrian p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; 463235289Sadrian for (i=0; i<p.es_ifmr.ifm_count; i++) { 464235289Sadrian printf("\t\tmedia "); 465235289Sadrian print_media_word(ifm_ulist[i], 0); 466235289Sadrian putchar('\n'); 467235289Sadrian } 468235289Sadrian } 469235289Sadrian} 470235289Sadrian 471235289Sadrianstatic void 472235289Sadrianprint_vlangroup(struct cfg *cfg, int vlangroup) 473235289Sadrian{ 474235289Sadrian etherswitch_vlangroup_t vg; 475235289Sadrian int i, comma; 476235289Sadrian 477235289Sadrian vg.es_vlangroup = vlangroup; 478235289Sadrian if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0) 479235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)"); 480253569Sloos if ((vg.es_vid & ETHERSWITCH_VID_VALID) == 0) 481235289Sadrian return; 482253569Sloos vg.es_vid &= ETHERSWITCH_VID_MASK; 483235289Sadrian printf("vlangroup%d:\n", vlangroup); 484250382Sadrian if (cfg->conf.vlan_mode == ETHERSWITCH_VLAN_PORT) 485250382Sadrian printf("\tport: %d\n", vg.es_vid); 486250382Sadrian else 487250382Sadrian printf("\tvlan: %d\n", vg.es_vid); 488235289Sadrian printf("\tmembers "); 489235289Sadrian comma = 0; 490235289Sadrian if (vg.es_member_ports != 0) 491235289Sadrian for (i=0; i<cfg->info.es_nports; i++) { 492235289Sadrian if ((vg.es_member_ports & ETHERSWITCH_PORTMASK(i)) != 0) { 493235289Sadrian if (comma) 494235289Sadrian printf(","); 495235289Sadrian printf("%d", i); 496235289Sadrian if ((vg.es_untagged_ports & ETHERSWITCH_PORTMASK(i)) == 0) 497235289Sadrian printf("t"); 498235289Sadrian comma = 1; 499235289Sadrian } 500235289Sadrian } 501235289Sadrian else 502235289Sadrian printf("none"); 503235289Sadrian printf("\n"); 504235289Sadrian} 505235289Sadrian 506235289Sadrianstatic void 507235289Sadrianprint_info(struct cfg *cfg) 508235289Sadrian{ 509235289Sadrian const char *c; 510235289Sadrian int i; 511235289Sadrian 512235289Sadrian c = strrchr(cfg->controlfile, '/'); 513235289Sadrian if (c != NULL) 514235289Sadrian c = c + 1; 515235289Sadrian else 516235289Sadrian c = cfg->controlfile; 517250382Sadrian if (cfg->verbose) { 518250382Sadrian printf("%s: %s with %d ports and %d VLAN groups\n", c, 519250382Sadrian cfg->info.es_name, cfg->info.es_nports, 520250382Sadrian cfg->info.es_nvlangroups); 521250382Sadrian printf("%s: ", c); 522250382Sadrian printb("VLAN capabilities", cfg->info.es_vlan_caps, 523250382Sadrian ETHERSWITCH_VLAN_CAPS_BITS); 524250382Sadrian printf("\n"); 525250382Sadrian } 526250382Sadrian print_config(cfg); 527235289Sadrian for (i=0; i<cfg->info.es_nports; i++) { 528235289Sadrian print_port(cfg, i); 529235289Sadrian } 530235289Sadrian for (i=0; i<cfg->info.es_nvlangroups; i++) { 531235289Sadrian print_vlangroup(cfg, i); 532235289Sadrian } 533235289Sadrian} 534235289Sadrian 535235289Sadrianstatic void 536250382Sadrianusage(struct cfg *cfg __unused, char *argv[] __unused) 537235289Sadrian{ 538235289Sadrian fprintf(stderr, "usage: etherswitchctl\n"); 539250382Sadrian fprintf(stderr, "\tetherswitchcfg [-f control file] info\n"); 540250382Sadrian fprintf(stderr, "\tetherswitchcfg [-f control file] config " 541250382Sadrian "command parameter\n"); 542250382Sadrian fprintf(stderr, "\t\tconfig commands: vlan_mode\n"); 543250382Sadrian fprintf(stderr, "\tetherswitchcfg [-f control file] phy " 544250382Sadrian "phy.register[=value]\n"); 545250382Sadrian fprintf(stderr, "\tetherswitchcfg [-f control file] portX " 546250382Sadrian "[flags] command parameter\n"); 547250382Sadrian fprintf(stderr, "\t\tport commands: pvid, media, mediaopt\n"); 548250382Sadrian fprintf(stderr, "\tetherswitchcfg [-f control file] reg " 549250382Sadrian "register[=value]\n"); 550250382Sadrian fprintf(stderr, "\tetherswitchcfg [-f control file] vlangroupX " 551250382Sadrian "command parameter\n"); 552250382Sadrian fprintf(stderr, "\t\tvlangroup commands: vlan, members\n"); 553235289Sadrian exit(EX_USAGE); 554235289Sadrian} 555235289Sadrian 556235289Sadrianstatic void 557235289Sadriannewmode(struct cfg *cfg, enum cmdmode mode) 558235289Sadrian{ 559235289Sadrian if (mode == cfg->mode) 560235289Sadrian return; 561235289Sadrian switch (cfg->mode) { 562235289Sadrian case MODE_NONE: 563235289Sadrian break; 564250382Sadrian case MODE_CONFIG: 565250382Sadrian /* 566250382Sadrian * Read the updated the configuration (it can be different 567250382Sadrian * from the last time we read it). 568250382Sadrian */ 569250382Sadrian if (ioctl(cfg->fd, IOETHERSWITCHGETCONF, &cfg->conf) != 0) 570250382Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETCONF)"); 571250382Sadrian print_config(cfg); 572250382Sadrian break; 573235289Sadrian case MODE_PORT: 574235289Sadrian print_port(cfg, cfg->unit); 575235289Sadrian break; 576235289Sadrian case MODE_VLANGROUP: 577235289Sadrian print_vlangroup(cfg, cfg->unit); 578235289Sadrian break; 579235289Sadrian case MODE_REGISTER: 580235289Sadrian case MODE_PHYREG: 581235289Sadrian break; 582235289Sadrian } 583235289Sadrian cfg->mode = mode; 584235289Sadrian} 585235289Sadrian 586235289Sadrianint 587235289Sadrianmain(int argc, char *argv[]) 588235289Sadrian{ 589235289Sadrian int ch; 590235289Sadrian struct cfg cfg; 591235289Sadrian int i; 592235289Sadrian 593235289Sadrian bzero(&cfg, sizeof(cfg)); 594235289Sadrian cfg.controlfile = "/dev/etherswitch0"; 595235289Sadrian while ((ch = getopt(argc, argv, "f:mv?")) != -1) 596235289Sadrian switch(ch) { 597235289Sadrian case 'f': 598235289Sadrian cfg.controlfile = optarg; 599235289Sadrian break; 600235289Sadrian case 'm': 601235289Sadrian cfg.mediatypes++; 602235289Sadrian break; 603235289Sadrian case 'v': 604235289Sadrian cfg.verbose++; 605235289Sadrian break; 606235289Sadrian case '?': 607235289Sadrian /* FALLTHROUGH */ 608235289Sadrian default: 609250382Sadrian usage(&cfg, argv); 610235289Sadrian } 611235289Sadrian argc -= optind; 612235289Sadrian argv += optind; 613235289Sadrian cfg.fd = open(cfg.controlfile, O_RDONLY); 614235289Sadrian if (cfg.fd < 0) 615235289Sadrian err(EX_UNAVAILABLE, "Can't open control file: %s", cfg.controlfile); 616235289Sadrian if (ioctl(cfg.fd, IOETHERSWITCHGETINFO, &cfg.info) != 0) 617235289Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETINFO)"); 618250382Sadrian if (ioctl(cfg.fd, IOETHERSWITCHGETCONF, &cfg.conf) != 0) 619250382Sadrian err(EX_OSERR, "ioctl(IOETHERSWITCHGETCONF)"); 620235289Sadrian if (argc == 0) { 621235289Sadrian print_info(&cfg); 622235289Sadrian return (0); 623235289Sadrian } 624235289Sadrian cfg.mode = MODE_NONE; 625235289Sadrian while (argc > 0) { 626235289Sadrian switch(cfg.mode) { 627235289Sadrian case MODE_NONE: 628235289Sadrian if (strcmp(argv[0], "info") == 0) { 629235289Sadrian print_info(&cfg); 630235289Sadrian } else if (sscanf(argv[0], "port%d", &cfg.unit) == 1) { 631235289Sadrian if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nports) 632255730Shiren errx(EX_USAGE, "port unit must be between 0 and %d", cfg.info.es_nports - 1); 633235289Sadrian newmode(&cfg, MODE_PORT); 634235289Sadrian } else if (sscanf(argv[0], "vlangroup%d", &cfg.unit) == 1) { 635235289Sadrian if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nvlangroups) 636253568Sloos errx(EX_USAGE, 637253568Sloos "vlangroup unit must be between 0 and %d", 638253568Sloos cfg.info.es_nvlangroups - 1); 639235289Sadrian newmode(&cfg, MODE_VLANGROUP); 640250382Sadrian } else if (strcmp(argv[0], "config") == 0) { 641250382Sadrian newmode(&cfg, MODE_CONFIG); 642235289Sadrian } else if (strcmp(argv[0], "phy") == 0) { 643235289Sadrian newmode(&cfg, MODE_PHYREG); 644235289Sadrian } else if (strcmp(argv[0], "reg") == 0) { 645235289Sadrian newmode(&cfg, MODE_REGISTER); 646250382Sadrian } else if (strcmp(argv[0], "help") == 0) { 647250382Sadrian usage(&cfg, argv); 648235289Sadrian } else { 649235289Sadrian errx(EX_USAGE, "Unknown command \"%s\"", argv[0]); 650235289Sadrian } 651235289Sadrian break; 652235289Sadrian case MODE_PORT: 653250382Sadrian case MODE_CONFIG: 654235289Sadrian case MODE_VLANGROUP: 655235289Sadrian for(i=0; cmds[i].name != NULL; i++) { 656249748Sadrian if (cfg.mode == cmds[i].mode && strcmp(argv[0], cmds[i].name) == 0) { 657249748Sadrian if (argc < (cmds[i].args + 1)) { 658249748Sadrian printf("%s needs an argument\n", cmds[i].name); 659249748Sadrian break; 660249748Sadrian } 661235289Sadrian (cmds[i].f)(&cfg, argv); 662235289Sadrian argc -= cmds[i].args; 663235289Sadrian argv += cmds[i].args; 664235289Sadrian break; 665235289Sadrian } 666235289Sadrian } 667235289Sadrian if (cmds[i].name == NULL) { 668235289Sadrian newmode(&cfg, MODE_NONE); 669235289Sadrian continue; 670235289Sadrian } 671235289Sadrian break; 672235289Sadrian case MODE_REGISTER: 673235289Sadrian if (set_register(&cfg, argv[0]) != 0) { 674235289Sadrian newmode(&cfg, MODE_NONE); 675235289Sadrian continue; 676235289Sadrian } 677235289Sadrian break; 678235289Sadrian case MODE_PHYREG: 679235289Sadrian if (set_phyregister(&cfg, argv[0]) != 0) { 680235289Sadrian newmode(&cfg, MODE_NONE); 681235289Sadrian continue; 682235289Sadrian } 683235289Sadrian break; 684235289Sadrian } 685235289Sadrian argc--; 686235289Sadrian argv++; 687235289Sadrian } 688235289Sadrian /* switch back to command mode to print configuration for last command */ 689235289Sadrian newmode(&cfg, MODE_NONE); 690235289Sadrian close(cfg.fd); 691235289Sadrian return (0); 692235289Sadrian} 693235289Sadrian 694241720Sedstatic struct cmds cmds[] = { 695249752Sadrian { MODE_PORT, "pvid", 1, set_port_vid }, 696235289Sadrian { MODE_PORT, "media", 1, set_port_media }, 697235289Sadrian { MODE_PORT, "mediaopt", 1, set_port_mediaopt }, 698250382Sadrian { MODE_PORT, "addtag", 0, set_port_flag }, 699250382Sadrian { MODE_PORT, "-addtag", 0, set_port_flag }, 700250382Sadrian { MODE_PORT, "ingress", 0, set_port_flag }, 701250382Sadrian { MODE_PORT, "-ingress", 0, set_port_flag }, 702250382Sadrian { MODE_PORT, "striptag", 0, set_port_flag }, 703250382Sadrian { MODE_PORT, "-striptag", 0, set_port_flag }, 704250382Sadrian { MODE_PORT, "doubletag", 0, set_port_flag }, 705250382Sadrian { MODE_PORT, "-doubletag", 0, set_port_flag }, 706250382Sadrian { MODE_PORT, "firstlock", 0, set_port_flag }, 707250382Sadrian { MODE_PORT, "-firstlock", 0, set_port_flag }, 708250382Sadrian { MODE_PORT, "dropuntagged", 0, set_port_flag }, 709250382Sadrian { MODE_PORT, "-dropuntagged", 0, set_port_flag }, 710250382Sadrian { MODE_CONFIG, "vlan_mode", 1, set_vlan_mode }, 711235289Sadrian { MODE_VLANGROUP, "vlan", 1, set_vlangroup_vid }, 712235289Sadrian { MODE_VLANGROUP, "members", 1, set_vlangroup_members }, 713235289Sadrian { 0, NULL, 0, NULL } 714235289Sadrian}; 715