Index: head/sys/dev/etherswitch/etherswitch.c =================================================================== --- head/sys/dev/etherswitch/etherswitch.c (revision 328765) +++ head/sys/dev/etherswitch/etherswitch.c (revision 328766) @@ -1,212 +1,230 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "etherswitch_if.h" struct etherswitch_softc { device_t sc_dev; struct cdev *sc_devnode; }; static int etherswitch_probe(device_t); static int etherswitch_attach(device_t); static int etherswitch_detach(device_t); static void etherswitch_identify(driver_t *driver, device_t parent); devclass_t etherswitch_devclass; static device_method_t etherswitch_methods[] = { /* device interface */ DEVMETHOD(device_identify, etherswitch_identify), DEVMETHOD(device_probe, etherswitch_probe), DEVMETHOD(device_attach, etherswitch_attach), DEVMETHOD(device_detach, etherswitch_detach), DEVMETHOD_END }; driver_t etherswitch_driver = { "etherswitch", etherswitch_methods, sizeof(struct etherswitch_softc), }; static d_ioctl_t etherswitchioctl; static struct cdevsw etherswitch_cdevsw = { .d_version = D_VERSION, .d_flags = D_TRACKCLOSE, .d_ioctl = etherswitchioctl, .d_name = "etherswitch", }; static void etherswitch_identify(driver_t *driver, device_t parent) { if (device_find_child(parent, "etherswitch", -1) == NULL) BUS_ADD_CHILD(parent, 0, "etherswitch", -1); } static int etherswitch_probe(device_t dev) { device_set_desc(dev, "Switch controller"); return (0); } static int etherswitch_attach(device_t dev) { int err; struct etherswitch_softc *sc; struct make_dev_args devargs; sc = device_get_softc(dev); sc->sc_dev = dev; make_dev_args_init(&devargs); devargs.mda_devsw = ðerswitch_cdevsw; devargs.mda_uid = UID_ROOT; devargs.mda_gid = GID_WHEEL; devargs.mda_mode = 0600; devargs.mda_si_drv1 = sc; err = make_dev_s(&devargs, &sc->sc_devnode, "etherswitch%d", device_get_unit(dev)); if (err != 0) { device_printf(dev, "failed to create character device\n"); return (ENXIO); } return (0); } static int etherswitch_detach(device_t dev) { struct etherswitch_softc *sc = (struct etherswitch_softc *)device_get_softc(dev); if (sc->sc_devnode) destroy_dev(sc->sc_devnode); return (0); } static int etherswitchioctl(struct cdev *cdev, u_long cmd, caddr_t data, int flags, struct thread *td) { struct etherswitch_softc *sc = cdev->si_drv1; device_t dev = sc->sc_dev; device_t etherswitch = device_get_parent(dev); etherswitch_conf_t conf; etherswitch_info_t *info; etherswitch_reg_t *reg; etherswitch_phyreg_t *phyreg; + etherswitch_portid_t *portid; int error = 0; switch (cmd) { case IOETHERSWITCHGETINFO: info = ETHERSWITCH_GETINFO(etherswitch); bcopy(info, data, sizeof(etherswitch_info_t)); break; case IOETHERSWITCHGETREG: reg = (etherswitch_reg_t *)data; ETHERSWITCH_LOCK(etherswitch); reg->val = ETHERSWITCH_READREG(etherswitch, reg->reg); ETHERSWITCH_UNLOCK(etherswitch); break; case IOETHERSWITCHSETREG: reg = (etherswitch_reg_t *)data; ETHERSWITCH_LOCK(etherswitch); error = ETHERSWITCH_WRITEREG(etherswitch, reg->reg, reg->val); ETHERSWITCH_UNLOCK(etherswitch); break; case IOETHERSWITCHGETPORT: error = ETHERSWITCH_GETPORT(etherswitch, (etherswitch_port_t *)data); break; case IOETHERSWITCHSETPORT: error = ETHERSWITCH_SETPORT(etherswitch, (etherswitch_port_t *)data); break; case IOETHERSWITCHGETVLANGROUP: error = ETHERSWITCH_GETVGROUP(etherswitch, (etherswitch_vlangroup_t *)data); break; case IOETHERSWITCHSETVLANGROUP: error = ETHERSWITCH_SETVGROUP(etherswitch, (etherswitch_vlangroup_t *)data); break; case IOETHERSWITCHGETPHYREG: phyreg = (etherswitch_phyreg_t *)data; phyreg->val = ETHERSWITCH_READPHYREG(etherswitch, phyreg->phy, phyreg->reg); break; case IOETHERSWITCHSETPHYREG: phyreg = (etherswitch_phyreg_t *)data; error = ETHERSWITCH_WRITEPHYREG(etherswitch, phyreg->phy, phyreg->reg, phyreg->val); break; case IOETHERSWITCHGETCONF: bzero(&conf, sizeof(etherswitch_conf_t)); error = ETHERSWITCH_GETCONF(etherswitch, &conf); bcopy(&conf, data, sizeof(etherswitch_conf_t)); break; case IOETHERSWITCHSETCONF: error = ETHERSWITCH_SETCONF(etherswitch, (etherswitch_conf_t *)data); + break; + + case IOETHERSWITCHFLUSHALL: + error = ETHERSWITCH_FLUSH_ALL(etherswitch); + break; + + case IOETHERSWITCHFLUSHPORT: + portid = (etherswitch_portid_t *)data; + error = ETHERSWITCH_FLUSH_PORT(etherswitch, portid->es_port); + break; + + case IOETHERSWITCHGETTABLE: + error = ETHERSWITCH_FETCH_TABLE(etherswitch, (void *) data); + break; + + case IOETHERSWITCHGETTABLEENTRY: + error = ETHERSWITCH_FETCH_TABLE_ENTRY(etherswitch, (void *) data); break; default: error = ENOTTY; } return (error); } MODULE_VERSION(etherswitch, 1); Index: head/sys/dev/etherswitch/etherswitch.h =================================================================== --- head/sys/dev/etherswitch/etherswitch.h (revision 328765) +++ head/sys/dev/etherswitch/etherswitch.h (revision 328766) @@ -1,116 +1,144 @@ /* * $FreeBSD$ */ #ifndef __SYS_DEV_ETHERSWITCH_ETHERSWITCH_H #define __SYS_DEV_ETHERSWITCH_ETHERSWITCH_H #include +#include #ifdef _KERNEL extern devclass_t etherswitch_devclass; extern driver_t etherswitch_driver; #endif /* _KERNEL */ struct etherswitch_reg { uint16_t reg; uint32_t val; }; typedef struct etherswitch_reg etherswitch_reg_t; struct etherswitch_phyreg { uint16_t phy; uint16_t reg; uint16_t val; }; typedef struct etherswitch_phyreg etherswitch_phyreg_t; #define ETHERSWITCH_NAMEMAX 64 #define ETHERSWITCH_VID_MASK 0xfff #define ETHERSWITCH_VID_VALID (1 << 12) #define ETHERSWITCH_VLAN_ISL (1 << 0) /* ISL */ #define ETHERSWITCH_VLAN_PORT (1 << 1) /* Port based vlan */ #define ETHERSWITCH_VLAN_DOT1Q (1 << 2) /* 802.1q */ #define ETHERSWITCH_VLAN_DOT1Q_4K (1 << 3) /* 4k support on 802.1q */ #define ETHERSWITCH_VLAN_DOUBLE_TAG (1 << 4) /* Q-in-Q */ #define ETHERSWITCH_VLAN_CAPS_BITS \ "\020\1ISL\2PORT\3DOT1Q\4DOT1Q4K\5QinQ" struct etherswitch_info { int es_nports; int es_nvlangroups; char es_name[ETHERSWITCH_NAMEMAX]; uint32_t es_vlan_caps; }; typedef struct etherswitch_info etherswitch_info_t; #define ETHERSWITCH_CONF_FLAGS (1 << 0) #define ETHERSWITCH_CONF_MIRROR (1 << 1) #define ETHERSWITCH_CONF_VLAN_MODE (1 << 2) struct etherswitch_conf { uint32_t cmd; /* What to configure */ uint32_t vlan_mode; /* Switch VLAN mode */ }; typedef struct etherswitch_conf etherswitch_conf_t; #define ETHERSWITCH_PORT_CPU (1 << 0) #define ETHERSWITCH_PORT_STRIPTAG (1 << 1) #define ETHERSWITCH_PORT_ADDTAG (1 << 2) #define ETHERSWITCH_PORT_FIRSTLOCK (1 << 3) #define ETHERSWITCH_PORT_DROPUNTAGGED (1 << 4) #define ETHERSWITCH_PORT_DOUBLE_TAG (1 << 5) #define ETHERSWITCH_PORT_INGRESS (1 << 6) #define ETHERSWITCH_PORT_FLAGS_BITS \ "\020\1CPUPORT\2STRIPTAG\3ADDTAG\4FIRSTLOCK\5DROPUNTAGGED\6QinQ\7INGRESS" #define ETHERSWITCH_PORT_MAX_LEDS 3 enum etherswitch_port_led { ETHERSWITCH_PORT_LED_DEFAULT, ETHERSWITCH_PORT_LED_ON, ETHERSWITCH_PORT_LED_OFF, ETHERSWITCH_PORT_LED_BLINK, ETHERSWITCH_PORT_LED_MAX }; typedef enum etherswitch_port_led etherswitch_port_led_t; struct etherswitch_port { int es_port; int es_pvid; int es_nleds; uint32_t es_flags; etherswitch_port_led_t es_led[ETHERSWITCH_PORT_MAX_LEDS]; union { struct ifreq es_uifr; struct ifmediareq es_uifmr; } es_ifu; #define es_ifr es_ifu.es_uifr #define es_ifmr es_ifu.es_uifmr }; typedef struct etherswitch_port etherswitch_port_t; struct etherswitch_vlangroup { int es_vlangroup; int es_vid; int es_member_ports; int es_untagged_ports; int es_fid; }; typedef struct etherswitch_vlangroup etherswitch_vlangroup_t; #define ETHERSWITCH_PORTMASK(_port) (1 << (_port)) +struct etherswitch_portid { + int es_port; +}; +typedef struct etherswitch_portid etherswitch_portid_t; + +struct etherswitch_atu_entry { + int id; + int es_portmask; + uint8_t es_macaddr[ETHER_ADDR_LEN]; +}; +typedef struct etherswitch_atu_entry etherswitch_atu_entry_t; + +struct etherswitch_atu_table { + uint32_t es_nitems; +}; +typedef struct etherswitch_atu_table etherswitch_atu_table_t; + +struct etherswitch_atu_flush_macentry { + uint8_t es_macaddr[ETHER_ADDR_LEN]; +}; +typedef struct etherswitch_atu_flush_macentry etherswitch_atu_flush_macentry_t; + #define IOETHERSWITCHGETINFO _IOR('i', 1, etherswitch_info_t) #define IOETHERSWITCHGETREG _IOWR('i', 2, etherswitch_reg_t) #define IOETHERSWITCHSETREG _IOW('i', 3, etherswitch_reg_t) #define IOETHERSWITCHGETPORT _IOWR('i', 4, etherswitch_port_t) #define IOETHERSWITCHSETPORT _IOW('i', 5, etherswitch_port_t) #define IOETHERSWITCHGETVLANGROUP _IOWR('i', 6, etherswitch_vlangroup_t) #define IOETHERSWITCHSETVLANGROUP _IOW('i', 7, etherswitch_vlangroup_t) #define IOETHERSWITCHGETPHYREG _IOWR('i', 8, etherswitch_phyreg_t) #define IOETHERSWITCHSETPHYREG _IOW('i', 9, etherswitch_phyreg_t) #define IOETHERSWITCHGETCONF _IOR('i', 10, etherswitch_conf_t) #define IOETHERSWITCHSETCONF _IOW('i', 11, etherswitch_conf_t) +#define IOETHERSWITCHFLUSHALL _IOW('i', 12, etherswitch_portid_t) /* Dummy */ +#define IOETHERSWITCHFLUSHPORT _IOW('i', 13, etherswitch_portid_t) +#define IOETHERSWITCHFLUSHMAC _IOW('i', 14, etherswitch_atu_flush_macentry_t) +#define IOETHERSWITCHGETTABLE _IOWR('i', 15, etherswitch_atu_table_t) +#define IOETHERSWITCHGETTABLEENTRY _IOWR('i', 16, etherswitch_atu_entry_t) #endif Index: head/sys/dev/etherswitch/etherswitch_if.m =================================================================== --- head/sys/dev/etherswitch/etherswitch_if.m (revision 328765) +++ head/sys/dev/etherswitch/etherswitch_if.m (revision 328766) @@ -1,143 +1,221 @@ # $FreeBSD$ #include # Needed for ifreq/ifmediareq #include #include #include INTERFACE etherswitch; # # Default implementation # CODE { static void null_etherswitch_lock(device_t dev) { } static void null_etherswitch_unlock(device_t dev) { } static int null_etherswitch_getconf(device_t dev, etherswitch_conf_t *conf) { return (0); } static int null_etherswitch_setconf(device_t dev, etherswitch_conf_t *conf) { return (0); } + + static int + null_etherswitch_flush_all(device_t dev) + { + + return (ENXIO); + } + + static int + null_etherswitch_flush_port(device_t dev, int port) + { + + return (ENXIO); + } + + static int + null_etherswitch_flush_mac(device_t dev, + etherswitch_atu_flush_macentry_t *e) + { + + return (ENXIO); + } + + static int + null_etherswitch_fetch_table(device_t dev, + etherswitch_atu_table_t *table) + { + + table->es_nitems = 0; + return (ENXIO); + } + + static int + null_etherswitch_fetch_entry(device_t dev, + etherswitch_atu_entry_t *e) + { + + return (ENXIO); + } }; # # Return device info # METHOD etherswitch_info_t* getinfo { device_t dev; } # # Lock access to switch registers # METHOD void lock { device_t dev; } DEFAULT null_etherswitch_lock; # # Unlock access to switch registers # METHOD void unlock { device_t dev; } DEFAULT null_etherswitch_unlock; # # Read switch register # METHOD int readreg { device_t dev; int reg; }; # # Write switch register # METHOD int writereg { device_t dev; int reg; int value; }; # # Read PHY register # METHOD int readphyreg { device_t dev; int phy; int reg; }; # # Write PHY register # METHOD int writephyreg { device_t dev; int phy; int reg; int value; }; # # Get port configuration # METHOD int getport { device_t dev; etherswitch_port_t *vg; } # # Set port configuration # METHOD int setport { device_t dev; etherswitch_port_t *vg; } # # Get VLAN group configuration # METHOD int getvgroup { device_t dev; etherswitch_vlangroup_t *vg; } # # Set VLAN group configuration # METHOD int setvgroup { device_t dev; etherswitch_vlangroup_t *vg; } # # Get the Switch configuration # METHOD int getconf { device_t dev; etherswitch_conf_t *conf; } DEFAULT null_etherswitch_getconf; # # Set the Switch configuration # METHOD int setconf { device_t dev; etherswitch_conf_t *conf; } DEFAULT null_etherswitch_setconf; + +# +# Flush all of the programmed/learnt MAC addresses +# +METHOD int flush_all { + device_t dev; +} DEFAULT null_etherswitch_flush_all; + +# +# Flush a single MAC address entry +# +METHOD int flush_mac { + device_t dev; + etherswitch_atu_flush_macentry_t *entry; +} DEFAULT null_etherswitch_flush_mac; + +# +# Flush all of the dynamic MAC addresses on a given port +# +METHOD int flush_port { + device_t dev; + int port; +} DEFAULT null_etherswitch_flush_port; + +# +# Fetch the address table from the ethernet switch. +# +METHOD int fetch_table { + device_t dev; + etherswitch_atu_table_t *table; +} DEFAULT null_etherswitch_fetch_table; + +# +# Fetch a single entry from the ethernet switch table. +# +METHOD int fetch_table_entry { + device_t dev; + etherswitch_atu_entry_t *entry; +} DEFAULT null_etherswitch_fetch_entry;