From owner-svn-src-all@FreeBSD.ORG Fri May 11 20:56:04 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id ECEAD1065670; Fri, 11 May 2012 20:56:04 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id D63A38FC08; Fri, 11 May 2012 20:56:04 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q4BKu4Ej000209; Fri, 11 May 2012 20:56:04 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q4BKu4x2000203; Fri, 11 May 2012 20:56:04 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201205112056.q4BKu4x2000203@svn.freebsd.org> From: Adrian Chadd Date: Fri, 11 May 2012 20:56:04 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r235289 - in head/sbin: . etherswitchcfg X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 11 May 2012 20:56:05 -0000 Author: adrian Date: Fri May 11 20:56:04 2012 New Revision: 235289 URL: http://svn.freebsd.org/changeset/base/235289 Log: Add etherswitchcfg. Submitted by: Stefan Bethke Added: head/sbin/etherswitchcfg/ head/sbin/etherswitchcfg/Makefile (contents, props changed) head/sbin/etherswitchcfg/etherswitchcfg.8 (contents, props changed) head/sbin/etherswitchcfg/etherswitchcfg.c (contents, props changed) head/sbin/etherswitchcfg/ifmedia.c (contents, props changed) Modified: head/sbin/Makefile Modified: head/sbin/Makefile ============================================================================== --- head/sbin/Makefile Fri May 11 20:53:20 2012 (r235288) +++ head/sbin/Makefile Fri May 11 20:56:04 2012 (r235289) @@ -20,6 +20,7 @@ SUBDIR=adjkerntz \ dump \ dumpfs \ dumpon \ + etherswitchcfg \ ffsinfo \ fsck \ fsck_ffs \ Added: head/sbin/etherswitchcfg/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sbin/etherswitchcfg/Makefile Fri May 11 20:56:04 2012 (r235289) @@ -0,0 +1,9 @@ +# @(#)Makefile 5.4 (Berkeley) 6/5/91 +# $FreeBSD$ + +PROG= etherswitchcfg +MAN= etherswitchcfg.8 +SRCS= etherswitchcfg.c ifmedia.c +CFLAGS+= -I${.CURDIR}/../../sys + +.include Added: head/sbin/etherswitchcfg/etherswitchcfg.8 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sbin/etherswitchcfg/etherswitchcfg.8 Fri May 11 20:56:04 2012 (r235289) @@ -0,0 +1,114 @@ +.\" $FreeBSD$ +.Dd December 15, 2011 +.Dt ETHERSWITCHCFG 8 +.Os +.Sh NAME +.Nm etherswitchcfg +.Nd configure a built-in Ethernet switch +.Sh SYNOPSIS +.Nm +.Op Fl "f control file" +.Ar info +.Nm +.Op Fl "f control file" +.Ar phy +.Ar phy.register[=value] +.Nm +.Op Fl "f control file" +.Ar port%d +.Ar command parameter +.Nm +.Op Fl "f control file" +.Ar reg +.Ar register[=value] +.Nm +.Op Fl "f control file" +.Ar vlangroup%d +.Ar command parameter +.Sh DESCRIPTION +The +.Nm +utility is used to configure an Ethernet switch built into the system. +.Nm +accepts a number of options: +.Bl -tag -width ".Fl f" -compact +.It Fl "f control file" +Specifies the +.Xr etherswitch 4 +control file that represents the switch to be configured. +It defaults to +.Li /dev/etherswitch0 . +.It Fl m +When reporting port information, also list available media options for +that port. +.It Fl v +Produce more verbose output. +Without this flag, lines that represent inactive or empty configuration +options are omitted. +.El +.Ss phy +The phy command provides access to the registers of the PHYs attached +to or integrated into the switch controller. +PHY registers are specified as phy.register, +where +.Ar phy +is usually the port number, and +.Ar register +is the register number. +Both can be provided as decimal, octal or hexadecimal numbers in any of the formats +understood by +.Xr strtol 4 . +To set the register value, use the form instance.register=value. +.Ss port +The port command selects one of the ports of the switch. +It supports the following commands: +.Bl -tag -width ".Ar vlangroup number" -compact +.It Ar vlangroup number +Sets the VLAN group number that is used to process incoming frames that are not tagged. +.It Ar media mediaspec +Specifies the physical media configuration to be configured for a port. +.It Ar mediaopt mediaoption +Specifies a list of media options for a port. See +.Xr ifconfig 8 +for details on +.Ar media and +.Ar mediaopt . +.El +.Ss reg +The reg command provides access to the registers of the switch controller. +.Ss vlangroup +The vlangroup command selects one of the VLAN groups for configuration. +It supports the following commands: +.Bl -tag -width ".Ar vlangroup" -compact +.It Ar vlan VID +Sets the VLAN ID (802.1q VID) for this VLAN group. +Frames transmitted on tagged member ports of this group will be tagged +with this VID. +Incoming frames carrying this tag will be forwarded according to the +configuration of this VLAN group. +.It Ar members port,... +Configures which ports are to be a member of this VLAN group. +The port numbers are given as a comma-separated list. +Each port can optionally be followed by +.Dq t +to indicate that frames on this port are tagged. +.El +.Sh FILES +.Bl -tag -width /dev/etherswitch? -compact +.It Pa /dev/etherswitch? +Control file for the ethernet switch driver. +.El +.Sh EXAMPLES +Configure VLAN group 1 with a VID of 2 and makes ports 0 and 5 members, +while excluding all other ports. +Port 5 will send and receive tagged frames, while port 0 will be untagged. +Incoming untagged frames on port 0 are assigned to vlangroup1. +.Dl # etherswitchcfg vlangroup1 vlan 2 members 0,5t port0 vlangroup 1 +.Sh SEE ALSO +.Xr etherswitch 4 +.Sh HISTORY +.Nm +first appeared in +.Fx 10.0 . +.Sh AUTHORS +.An Stefan Bethke Added: head/sbin/etherswitchcfg/etherswitchcfg.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sbin/etherswitchcfg/etherswitchcfg.c Fri May 11 20:56:04 2012 (r235289) @@ -0,0 +1,511 @@ +/*- + * Copyright (c) 2011-2012 Stefan Bethke. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int get_media_subtype(int, const char *); +int get_media_mode(int, const char *); +int get_media_options(int, const char *); +int lookup_media_word(struct ifmedia_description *, const char *); +void print_media_word(int, int); +void print_media_word_ifconfig(int); + +/* some constants */ +#define IEEE802DOT1Q_VID_MAX 4094 +#define IFMEDIAREQ_NULISTENTRIES 256 + +enum cmdmode { + MODE_NONE = 0, + MODE_PORT, + MODE_VLANGROUP, + MODE_REGISTER, + MODE_PHYREG +}; + +struct cfg { + int fd; + int verbose; + int mediatypes; + const char *controlfile; + etherswitch_info_t info; + enum cmdmode mode; + int unit; +}; + +struct cmds { + enum cmdmode mode; + const char *name; + int args; + void (*f)(struct cfg *, char *argv[]); +}; +struct cmds cmds[]; + + +static void usage(void); + +static int +read_register(struct cfg *cfg, int r) +{ + struct etherswitch_reg er; + + er.reg = r; + if (ioctl(cfg->fd, IOETHERSWITCHGETREG, &er) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHGETREG)"); + return (er.val); +} + +static void +write_register(struct cfg *cfg, int r, int v) +{ + struct etherswitch_reg er; + + er.reg = r; + er.val = v; + if (ioctl(cfg->fd, IOETHERSWITCHSETREG, &er) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHSETREG)"); +} + +static int +read_phyregister(struct cfg *cfg, int phy, int reg) +{ + struct etherswitch_phyreg er; + + er.phy = phy; + er.reg = reg; + if (ioctl(cfg->fd, IOETHERSWITCHGETPHYREG, &er) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHGETPHYREG)"); + return (er.val); +} + +static void +write_phyregister(struct cfg *cfg, int phy, int reg, int val) +{ + struct etherswitch_phyreg er; + + er.phy = phy; + er.reg = reg; + er.val = val; + if (ioctl(cfg->fd, IOETHERSWITCHSETPHYREG, &er) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHSETPHYREG)"); +} + +static void +set_port_vlangroup(struct cfg *cfg, char *argv[]) +{ + int v; + etherswitch_port_t p; + + v = strtol(argv[1], NULL, 0); + if (v < 0 || v >= cfg->info.es_nvlangroups) + errx(EX_USAGE, "vlangroup must be between 0 and %d", cfg->info.es_nvlangroups-1); + p.es_port = cfg->unit; + if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); + p.es_vlangroup = v; + if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); +} + +static void +set_port_media(struct cfg *cfg, char *argv[]) +{ + etherswitch_port_t p; + int ifm_ulist[IFMEDIAREQ_NULISTENTRIES]; + int subtype; + + bzero(&p, sizeof(p)); + p.es_port = cfg->unit; + p.es_ifmr.ifm_ulist = ifm_ulist; + p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; + if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); + subtype = get_media_subtype(IFM_TYPE(ifm_ulist[0]), argv[1]); + p.es_ifr.ifr_media = (p.es_ifmr.ifm_current & IFM_IMASK) | + IFM_TYPE(ifm_ulist[0]) | subtype; + if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); +} + +static void +set_port_mediaopt(struct cfg *cfg, char *argv[]) +{ + etherswitch_port_t p; + int ifm_ulist[IFMEDIAREQ_NULISTENTRIES]; + int options; + + bzero(&p, sizeof(p)); + p.es_port = cfg->unit; + p.es_ifmr.ifm_ulist = ifm_ulist; + p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; + if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); + options = get_media_options(IFM_TYPE(ifm_ulist[0]), argv[1]); + if (options == -1) + errx(EX_USAGE, "invalid media options \"%s\"", argv[1]); + if (options & IFM_HDX) { + p.es_ifr.ifr_media &= ~IFM_FDX; + options &= ~IFM_HDX; + } + p.es_ifr.ifr_media |= options; + if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)"); +} + +static void +set_vlangroup_vid(struct cfg *cfg, char *argv[]) +{ + int v; + etherswitch_vlangroup_t vg; + + v = strtol(argv[1], NULL, 0); + if (v < 0 || v >= IEEE802DOT1Q_VID_MAX) + errx(EX_USAGE, "vlan must be between 0 and %d", IEEE802DOT1Q_VID_MAX); + vg.es_vlangroup = cfg->unit; + if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)"); + vg.es_vid = v; + if (ioctl(cfg->fd, IOETHERSWITCHSETVLANGROUP, &vg) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHSETVLANGROUP)"); +} + +static void +set_vlangroup_members(struct cfg *cfg, char *argv[]) +{ + etherswitch_vlangroup_t vg; + int member, untagged; + char *c, *d; + int v; + + member = untagged = 0; + if (strcmp(argv[1], "none") != 0) { + for (c=argv[1]; *c; c=d) { + v = strtol(c, &d, 0); + if (d == c) + break; + if (v < 0 || v >= cfg->info.es_nports) + errx(EX_USAGE, "Member port must be between 0 and %d", cfg->info.es_nports-1); + if (d[0] == ',' || d[0] == '\0' || + ((d[0] == 't' || d[0] == 'T') && (d[1] == ',' || d[1] == '\0'))) { + if (d[0] == 't' || d[0] == 'T') { + untagged &= ~ETHERSWITCH_PORTMASK(v); + d++; + } else + untagged |= ETHERSWITCH_PORTMASK(v); + member |= ETHERSWITCH_PORTMASK(v); + d++; + } else + errx(EX_USAGE, "Invalid members specification \"%s\"", d); + } + } + vg.es_vlangroup = cfg->unit; + if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)"); + vg.es_member_ports = member; + vg.es_untagged_ports = untagged; + if (ioctl(cfg->fd, IOETHERSWITCHSETVLANGROUP, &vg) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHSETVLANGROUP)"); +} + +static int +set_register(struct cfg *cfg, char *arg) +{ + int a, v; + char *c; + + a = strtol(arg, &c, 0); + if (c==arg) + return (1); + if (*c == '=') { + v = strtol(c+1, NULL, 0); + write_register(cfg, a, v); + } + printf("\treg 0x%04x=0x%04x\n", a, read_register(cfg, a)); + return (0); +} + +static int +set_phyregister(struct cfg *cfg, char *arg) +{ + int phy, reg, val; + char *c, *d; + + phy = strtol(arg, &c, 0); + if (c==arg) + return (1); + if (*c != '.') + return (1); + d = c+1; + reg = strtol(d, &c, 0); + if (d == c) + return (1); + if (*c == '=') { + val = strtol(c+1, NULL, 0); + write_phyregister(cfg, phy, reg, val); + } + printf("\treg %d.0x%02x=0x%04x\n", phy, reg, read_phyregister(cfg, phy, reg)); + return (0); +} + +static void +print_port(struct cfg *cfg, int port) +{ + etherswitch_port_t p; + int ifm_ulist[IFMEDIAREQ_NULISTENTRIES]; + int i; + + bzero(&p, sizeof(p)); + p.es_port = port; + p.es_ifmr.ifm_ulist = ifm_ulist; + p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; + if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)"); + printf("port%d:\n", port); + printf("\tvlangroup: %d\n", p.es_vlangroup); + printf("\tmedia: "); + print_media_word(p.es_ifmr.ifm_current, 1); + if (p.es_ifmr.ifm_active != p.es_ifmr.ifm_current) { + putchar(' '); + putchar('('); + print_media_word(p.es_ifmr.ifm_active, 0); + putchar(')'); + } + putchar('\n'); + printf("\tstatus: %s\n", (p.es_ifmr.ifm_status & IFM_ACTIVE) != 0 ? "active" : "no carrier"); + if (cfg->mediatypes) { + printf("\tsupported media:\n"); + if (p.es_ifmr.ifm_count > IFMEDIAREQ_NULISTENTRIES) + p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES; + for (i=0; ifd, IOETHERSWITCHGETVLANGROUP, &vg) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)"); + if (cfg->verbose == 0 && vg.es_member_ports == 0) + return; + printf("vlangroup%d:\n", vlangroup); + printf("\tvlan: %d\n", vg.es_vid); + printf("\tmembers "); + comma = 0; + if (vg.es_member_ports != 0) + for (i=0; iinfo.es_nports; i++) { + if ((vg.es_member_ports & ETHERSWITCH_PORTMASK(i)) != 0) { + if (comma) + printf(","); + printf("%d", i); + if ((vg.es_untagged_ports & ETHERSWITCH_PORTMASK(i)) == 0) + printf("t"); + comma = 1; + } + } + else + printf("none"); + printf("\n"); +} + +static void +print_info(struct cfg *cfg) +{ + const char *c; + int i; + + c = strrchr(cfg->controlfile, '/'); + if (c != NULL) + c = c + 1; + else + c = cfg->controlfile; + if (cfg->verbose) + printf("%s: %s with %d ports and %d VLAN groups\n", + c, cfg->info.es_name, cfg->info.es_nports, cfg->info.es_nvlangroups); + for (i=0; iinfo.es_nports; i++) { + print_port(cfg, i); + } + for (i=0; iinfo.es_nvlangroups; i++) { + print_vlangroup(cfg, i); + } +} + +static void +usage(void) +{ + fprintf(stderr, "usage: etherswitchctl\n"); + exit(EX_USAGE); +} + +static void +newmode(struct cfg *cfg, enum cmdmode mode) +{ + if (mode == cfg->mode) + return; + switch (cfg->mode) { + case MODE_NONE: + break; + case MODE_PORT: + print_port(cfg, cfg->unit); + break; + case MODE_VLANGROUP: + print_vlangroup(cfg, cfg->unit); + break; + case MODE_REGISTER: + case MODE_PHYREG: + break; + } + cfg->mode = mode; +} + +int +main(int argc, char *argv[]) +{ + int ch; + struct cfg cfg; + int i; + + bzero(&cfg, sizeof(cfg)); + cfg.controlfile = "/dev/etherswitch0"; + while ((ch = getopt(argc, argv, "f:mv?")) != -1) + switch(ch) { + case 'f': + cfg.controlfile = optarg; + break; + case 'm': + cfg.mediatypes++; + break; + case 'v': + cfg.verbose++; + break; + case '?': + /* FALLTHROUGH */ + default: + usage(); + } + argc -= optind; + argv += optind; + cfg.fd = open(cfg.controlfile, O_RDONLY); + if (cfg.fd < 0) + err(EX_UNAVAILABLE, "Can't open control file: %s", cfg.controlfile); + if (ioctl(cfg.fd, IOETHERSWITCHGETINFO, &cfg.info) != 0) + err(EX_OSERR, "ioctl(IOETHERSWITCHGETINFO)"); + if (argc == 0) { + print_info(&cfg); + return (0); + } + cfg.mode = MODE_NONE; + while (argc > 0) { + switch(cfg.mode) { + case MODE_NONE: + if (strcmp(argv[0], "info") == 0) { + print_info(&cfg); + } else if (sscanf(argv[0], "port%d", &cfg.unit) == 1) { + if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nports) + errx(EX_USAGE, "port unit must be between 0 and %d", cfg.info.es_nports); + newmode(&cfg, MODE_PORT); + } else if (sscanf(argv[0], "vlangroup%d", &cfg.unit) == 1) { + if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nvlangroups) + errx(EX_USAGE, "port unit must be between 0 and %d", cfg.info.es_nvlangroups); + newmode(&cfg, MODE_VLANGROUP); + } else if (strcmp(argv[0], "phy") == 0) { + newmode(&cfg, MODE_PHYREG); + } else if (strcmp(argv[0], "reg") == 0) { + newmode(&cfg, MODE_REGISTER); + } else { + errx(EX_USAGE, "Unknown command \"%s\"", argv[0]); + } + break; + case MODE_PORT: + case MODE_VLANGROUP: + for(i=0; cmds[i].name != NULL; i++) { + if (cfg.mode == cmds[i].mode && strcmp(argv[0], cmds[i].name) == 0 + && argc >= cmds[i].args) { + (cmds[i].f)(&cfg, argv); + argc -= cmds[i].args; + argv += cmds[i].args; + break; + } + } + if (cmds[i].name == NULL) { + newmode(&cfg, MODE_NONE); + continue; + } + break; + case MODE_REGISTER: + if (set_register(&cfg, argv[0]) != 0) { + newmode(&cfg, MODE_NONE); + continue; + } + break; + case MODE_PHYREG: + if (set_phyregister(&cfg, argv[0]) != 0) { + newmode(&cfg, MODE_NONE); + continue; + } + break; + } + argc--; + argv++; + } + /* switch back to command mode to print configuration for last command */ + newmode(&cfg, MODE_NONE); + close(cfg.fd); + return (0); +} + +struct cmds cmds[] = { + { MODE_PORT, "vlangroup", 1, set_port_vlangroup }, + { MODE_PORT, "media", 1, set_port_media }, + { MODE_PORT, "mediaopt", 1, set_port_mediaopt }, + { MODE_VLANGROUP, "vlan", 1, set_vlangroup_vid }, + { MODE_VLANGROUP, "members", 1, set_vlangroup_members }, + { 0, NULL, 0, NULL } +}; Added: head/sbin/etherswitchcfg/ifmedia.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sbin/etherswitchcfg/ifmedia.c Fri May 11 20:56:04 2012 (r235289) @@ -0,0 +1,812 @@ +/* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (c) 1997 Jason R. Thorpe. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project + * by Jason R. Thorpe. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * based on sbin/ifconfig/ifmedia.c r221954 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +void domediaopt(const char *, int, int); +int get_media_subtype(int, const char *); +int get_media_mode(int, const char *); +int get_media_options(int, const char *); +int lookup_media_word(struct ifmedia_description *, const char *); +void print_media_word(int, int); +void print_media_word_ifconfig(int); + +#if 0 +static struct ifmedia_description *get_toptype_desc(int); +static struct ifmedia_type_to_subtype *get_toptype_ttos(int); +static struct ifmedia_description *get_subtype_desc(int, + struct ifmedia_type_to_subtype *ttos); + +#define IFM_OPMODE(x) \ + ((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \ + IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \ + IFM_IEEE80211_MBSS)) +#define IFM_IEEE80211_STA 0 + +static void +media_status(int s) +{ + struct ifmediareq ifmr; + int *media_list, i; + + (void) memset(&ifmr, 0, sizeof(ifmr)); + (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); + + if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { + /* + * Interface doesn't support SIOC{G,S}IFMEDIA. + */ + return; + } + + if (ifmr.ifm_count == 0) { + warnx("%s: no media types?", name); + return; + } + + media_list = (int *)malloc(ifmr.ifm_count * sizeof(int)); + if (media_list == NULL) + err(1, "malloc"); + ifmr.ifm_ulist = media_list; + + if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) + err(1, "SIOCGIFMEDIA"); + + printf("\tmedia: "); + print_media_word(ifmr.ifm_current, 1); + if (ifmr.ifm_active != ifmr.ifm_current) { + putchar(' '); + putchar('('); + print_media_word(ifmr.ifm_active, 0); + putchar(')'); + } + + putchar('\n'); + + if (ifmr.ifm_status & IFM_AVALID) { + printf("\tstatus: "); + switch (IFM_TYPE(ifmr.ifm_active)) { + case IFM_ETHER: + case IFM_ATM: + if (ifmr.ifm_status & IFM_ACTIVE) + printf("active"); + else + printf("no carrier"); + break; + + case IFM_FDDI: + case IFM_TOKEN: + if (ifmr.ifm_status & IFM_ACTIVE) + printf("inserted"); + else + printf("no ring"); + break; + + case IFM_IEEE80211: + if (ifmr.ifm_status & IFM_ACTIVE) { + /* NB: only sta mode associates */ + if (IFM_OPMODE(ifmr.ifm_active) == IFM_IEEE80211_STA) + printf("associated"); + else + printf("running"); + } else + printf("no carrier"); + break; + } + putchar('\n'); + } + + if (ifmr.ifm_count > 0 && supmedia) { + printf("\tsupported media:\n"); + for (i = 0; i < ifmr.ifm_count; i++) { + printf("\t\t"); + print_media_word_ifconfig(media_list[i]); + putchar('\n'); + } + } + + free(media_list); +} + +struct ifmediareq * +ifmedia_getstate(int s) +{ + static struct ifmediareq *ifmr = NULL; + int *mwords; + + if (ifmr == NULL) { + ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq)); + if (ifmr == NULL) + err(1, "malloc"); + + (void) memset(ifmr, 0, sizeof(struct ifmediareq)); + (void) strncpy(ifmr->ifm_name, name, + sizeof(ifmr->ifm_name)); + + ifmr->ifm_count = 0; + ifmr->ifm_ulist = NULL; + + /* + * We must go through the motions of reading all + * supported media because we need to know both + * the current media type and the top-level type. + */ + + if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) { + err(1, "SIOCGIFMEDIA"); + } + + if (ifmr->ifm_count == 0) + errx(1, "%s: no media types?", name); + + mwords = (int *)malloc(ifmr->ifm_count * sizeof(int)); + if (mwords == NULL) + err(1, "malloc"); + + ifmr->ifm_ulist = mwords; + if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) + err(1, "SIOCGIFMEDIA"); + } + + return ifmr; +} + +static void +setifmediacallback(int s, void *arg) +{ + struct ifmediareq *ifmr = (struct ifmediareq *)arg; + static int did_it = 0; + + if (!did_it) { + ifr.ifr_media = ifmr->ifm_current; + if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) + err(1, "SIOCSIFMEDIA (media)"); + free(ifmr->ifm_ulist); + free(ifmr); + did_it = 1; + } +} + +static void +setmedia(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifmediareq *ifmr; + int subtype; + + ifmr = ifmedia_getstate(s); + + /* + * We are primarily concerned with the top-level type. + * However, "current" may be only IFM_NONE, so we just look + * for the top-level type in the first "supported type" + * entry. + * + * (I'm assuming that all supported media types for a given + * interface will be the same top-level type..) + */ + subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val); + + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) | + IFM_TYPE(ifmr->ifm_ulist[0]) | subtype; + + ifmr->ifm_current = ifr.ifr_media; + callback_register(setifmediacallback, (void *)ifmr); +} + +static void +setmediaopt(const char *val, int d, int s, const struct afswtch *afp) +{ + + domediaopt(val, 0, s); +} + +static void +unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp) +{ + + domediaopt(val, 1, s); +} + +static void +domediaopt(const char *val, int clear, int s) +{ + struct ifmediareq *ifmr; + int options; + + ifmr = ifmedia_getstate(s); + + options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val); + + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_media = ifmr->ifm_current; + if (clear) + ifr.ifr_media &= ~options; + else { + if (options & IFM_HDX) { + ifr.ifr_media &= ~IFM_FDX; + options &= ~IFM_HDX; + } + ifr.ifr_media |= options; + } + ifmr->ifm_current = ifr.ifr_media; + callback_register(setifmediacallback, (void *)ifmr); +} + +static void +setmediainst(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifmediareq *ifmr; + int inst; + + ifmr = ifmedia_getstate(s); + + inst = atoi(val); + if (inst < 0 || inst > (int)IFM_INST_MAX) + errx(1, "invalid media instance: %s", val); + + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT; + + ifmr->ifm_current = ifr.ifr_media; + callback_register(setifmediacallback, (void *)ifmr); +} + +static void +setmediamode(const char *val, int d, int s, const struct afswtch *afp) +{ + struct ifmediareq *ifmr; + int mode; + + ifmr = ifmedia_getstate(s); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***