2 * Copyright (c) 2011-2012 Stefan Bethke.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
41 #include <sys/types.h>
42 #include <sys/ioctl.h>
44 #include <net/if_media.h>
45 #include <dev/etherswitch/etherswitch.h>
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);
55 #define IEEE802DOT1Q_VID_MAX 4094
56 #define IFMEDIAREQ_NULISTENTRIES 256
70 const char *controlfile;
71 etherswitch_info_t info;
80 void (*f)(struct cfg *, char *argv[]);
85 static void usage(void);
88 read_register(struct cfg *cfg, int r)
90 struct etherswitch_reg er;
93 if (ioctl(cfg->fd, IOETHERSWITCHGETREG, &er) != 0)
94 err(EX_OSERR, "ioctl(IOETHERSWITCHGETREG)");
99 write_register(struct cfg *cfg, int r, int v)
101 struct etherswitch_reg er;
105 if (ioctl(cfg->fd, IOETHERSWITCHSETREG, &er) != 0)
106 err(EX_OSERR, "ioctl(IOETHERSWITCHSETREG)");
110 read_phyregister(struct cfg *cfg, int phy, int reg)
112 struct etherswitch_phyreg er;
116 if (ioctl(cfg->fd, IOETHERSWITCHGETPHYREG, &er) != 0)
117 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPHYREG)");
122 write_phyregister(struct cfg *cfg, int phy, int reg, int val)
124 struct etherswitch_phyreg er;
129 if (ioctl(cfg->fd, IOETHERSWITCHSETPHYREG, &er) != 0)
130 err(EX_OSERR, "ioctl(IOETHERSWITCHSETPHYREG)");
134 set_port_vlangroup(struct cfg *cfg, char *argv[])
137 etherswitch_port_t p;
139 v = strtol(argv[1], NULL, 0);
140 if (v < 0 || v >= cfg->info.es_nvlangroups)
141 errx(EX_USAGE, "vlangroup must be between 0 and %d", cfg->info.es_nvlangroups-1);
142 p.es_port = cfg->unit;
143 if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0)
144 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)");
146 if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0)
147 err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)");
151 set_port_media(struct cfg *cfg, char *argv[])
153 etherswitch_port_t p;
154 int ifm_ulist[IFMEDIAREQ_NULISTENTRIES];
157 bzero(&p, sizeof(p));
158 p.es_port = cfg->unit;
159 p.es_ifmr.ifm_ulist = ifm_ulist;
160 p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES;
161 if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0)
162 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)");
163 subtype = get_media_subtype(IFM_TYPE(ifm_ulist[0]), argv[1]);
164 p.es_ifr.ifr_media = (p.es_ifmr.ifm_current & IFM_IMASK) |
165 IFM_TYPE(ifm_ulist[0]) | subtype;
166 if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0)
167 err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)");
171 set_port_mediaopt(struct cfg *cfg, char *argv[])
173 etherswitch_port_t p;
174 int ifm_ulist[IFMEDIAREQ_NULISTENTRIES];
177 bzero(&p, sizeof(p));
178 p.es_port = cfg->unit;
179 p.es_ifmr.ifm_ulist = ifm_ulist;
180 p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES;
181 if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0)
182 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)");
183 options = get_media_options(IFM_TYPE(ifm_ulist[0]), argv[1]);
185 errx(EX_USAGE, "invalid media options \"%s\"", argv[1]);
186 if (options & IFM_HDX) {
187 p.es_ifr.ifr_media &= ~IFM_FDX;
190 p.es_ifr.ifr_media |= options;
191 if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0)
192 err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)");
196 set_vlangroup_vid(struct cfg *cfg, char *argv[])
199 etherswitch_vlangroup_t vg;
201 v = strtol(argv[1], NULL, 0);
202 if (v < 0 || v >= IEEE802DOT1Q_VID_MAX)
203 errx(EX_USAGE, "vlan must be between 0 and %d", IEEE802DOT1Q_VID_MAX);
204 vg.es_vlangroup = cfg->unit;
205 if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0)
206 err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)");
208 if (ioctl(cfg->fd, IOETHERSWITCHSETVLANGROUP, &vg) != 0)
209 err(EX_OSERR, "ioctl(IOETHERSWITCHSETVLANGROUP)");
213 set_vlangroup_members(struct cfg *cfg, char *argv[])
215 etherswitch_vlangroup_t vg;
216 int member, untagged;
220 member = untagged = 0;
221 if (strcmp(argv[1], "none") != 0) {
222 for (c=argv[1]; *c; c=d) {
223 v = strtol(c, &d, 0);
226 if (v < 0 || v >= cfg->info.es_nports)
227 errx(EX_USAGE, "Member port must be between 0 and %d", cfg->info.es_nports-1);
228 if (d[0] == ',' || d[0] == '\0' ||
229 ((d[0] == 't' || d[0] == 'T') && (d[1] == ',' || d[1] == '\0'))) {
230 if (d[0] == 't' || d[0] == 'T') {
231 untagged &= ~ETHERSWITCH_PORTMASK(v);
234 untagged |= ETHERSWITCH_PORTMASK(v);
235 member |= ETHERSWITCH_PORTMASK(v);
238 errx(EX_USAGE, "Invalid members specification \"%s\"", d);
241 vg.es_vlangroup = cfg->unit;
242 if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0)
243 err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)");
244 vg.es_member_ports = member;
245 vg.es_untagged_ports = untagged;
246 if (ioctl(cfg->fd, IOETHERSWITCHSETVLANGROUP, &vg) != 0)
247 err(EX_OSERR, "ioctl(IOETHERSWITCHSETVLANGROUP)");
251 set_register(struct cfg *cfg, char *arg)
256 a = strtol(arg, &c, 0);
260 v = strtol(c+1, NULL, 0);
261 write_register(cfg, a, v);
263 printf("\treg 0x%04x=0x%04x\n", a, read_register(cfg, a));
268 set_phyregister(struct cfg *cfg, char *arg)
273 phy = strtol(arg, &c, 0);
279 reg = strtol(d, &c, 0);
283 val = strtol(c+1, NULL, 0);
284 write_phyregister(cfg, phy, reg, val);
286 printf("\treg %d.0x%02x=0x%04x\n", phy, reg, read_phyregister(cfg, phy, reg));
291 print_port(struct cfg *cfg, int port)
293 etherswitch_port_t p;
294 int ifm_ulist[IFMEDIAREQ_NULISTENTRIES];
297 bzero(&p, sizeof(p));
299 p.es_ifmr.ifm_ulist = ifm_ulist;
300 p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES;
301 if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0)
302 err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)");
303 printf("port%d:\n", port);
304 printf("\tvlangroup: %d\n", p.es_vlangroup);
306 print_media_word(p.es_ifmr.ifm_current, 1);
307 if (p.es_ifmr.ifm_active != p.es_ifmr.ifm_current) {
310 print_media_word(p.es_ifmr.ifm_active, 0);
314 printf("\tstatus: %s\n", (p.es_ifmr.ifm_status & IFM_ACTIVE) != 0 ? "active" : "no carrier");
315 if (cfg->mediatypes) {
316 printf("\tsupported media:\n");
317 if (p.es_ifmr.ifm_count > IFMEDIAREQ_NULISTENTRIES)
318 p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES;
319 for (i=0; i<p.es_ifmr.ifm_count; i++) {
320 printf("\t\tmedia ");
321 print_media_word(ifm_ulist[i], 0);
328 print_vlangroup(struct cfg *cfg, int vlangroup)
330 etherswitch_vlangroup_t vg;
333 vg.es_vlangroup = vlangroup;
334 if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0)
335 err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)");
336 if (cfg->verbose == 0 && vg.es_member_ports == 0)
338 printf("vlangroup%d:\n", vlangroup);
339 printf("\tvlan: %d\n", vg.es_vid);
340 printf("\tmembers ");
342 if (vg.es_member_ports != 0)
343 for (i=0; i<cfg->info.es_nports; i++) {
344 if ((vg.es_member_ports & ETHERSWITCH_PORTMASK(i)) != 0) {
348 if ((vg.es_untagged_ports & ETHERSWITCH_PORTMASK(i)) == 0)
359 print_info(struct cfg *cfg)
364 c = strrchr(cfg->controlfile, '/');
368 c = cfg->controlfile;
370 printf("%s: %s with %d ports and %d VLAN groups\n",
371 c, cfg->info.es_name, cfg->info.es_nports, cfg->info.es_nvlangroups);
372 for (i=0; i<cfg->info.es_nports; i++) {
375 for (i=0; i<cfg->info.es_nvlangroups; i++) {
376 print_vlangroup(cfg, i);
383 fprintf(stderr, "usage: etherswitchctl\n");
388 newmode(struct cfg *cfg, enum cmdmode mode)
390 if (mode == cfg->mode)
396 print_port(cfg, cfg->unit);
399 print_vlangroup(cfg, cfg->unit);
409 main(int argc, char *argv[])
415 bzero(&cfg, sizeof(cfg));
416 cfg.controlfile = "/dev/etherswitch0";
417 while ((ch = getopt(argc, argv, "f:mv?")) != -1)
420 cfg.controlfile = optarg;
435 cfg.fd = open(cfg.controlfile, O_RDONLY);
437 err(EX_UNAVAILABLE, "Can't open control file: %s", cfg.controlfile);
438 if (ioctl(cfg.fd, IOETHERSWITCHGETINFO, &cfg.info) != 0)
439 err(EX_OSERR, "ioctl(IOETHERSWITCHGETINFO)");
444 cfg.mode = MODE_NONE;
448 if (strcmp(argv[0], "info") == 0) {
450 } else if (sscanf(argv[0], "port%d", &cfg.unit) == 1) {
451 if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nports)
452 errx(EX_USAGE, "port unit must be between 0 and %d", cfg.info.es_nports);
453 newmode(&cfg, MODE_PORT);
454 } else if (sscanf(argv[0], "vlangroup%d", &cfg.unit) == 1) {
455 if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nvlangroups)
456 errx(EX_USAGE, "port unit must be between 0 and %d", cfg.info.es_nvlangroups);
457 newmode(&cfg, MODE_VLANGROUP);
458 } else if (strcmp(argv[0], "phy") == 0) {
459 newmode(&cfg, MODE_PHYREG);
460 } else if (strcmp(argv[0], "reg") == 0) {
461 newmode(&cfg, MODE_REGISTER);
463 errx(EX_USAGE, "Unknown command \"%s\"", argv[0]);
468 for(i=0; cmds[i].name != NULL; i++) {
469 if (cfg.mode == cmds[i].mode && strcmp(argv[0], cmds[i].name) == 0
470 && argc >= cmds[i].args) {
471 (cmds[i].f)(&cfg, argv);
472 argc -= cmds[i].args;
473 argv += cmds[i].args;
477 if (cmds[i].name == NULL) {
478 newmode(&cfg, MODE_NONE);
483 if (set_register(&cfg, argv[0]) != 0) {
484 newmode(&cfg, MODE_NONE);
489 if (set_phyregister(&cfg, argv[0]) != 0) {
490 newmode(&cfg, MODE_NONE);
498 /* switch back to command mode to print configuration for last command */
499 newmode(&cfg, MODE_NONE);
504 struct cmds cmds[] = {
505 { MODE_PORT, "vlangroup", 1, set_port_vlangroup },
506 { MODE_PORT, "media", 1, set_port_media },
507 { MODE_PORT, "mediaopt", 1, set_port_mediaopt },
508 { MODE_VLANGROUP, "vlan", 1, set_vlangroup_vid },
509 { MODE_VLANGROUP, "members", 1, set_vlangroup_members },