OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [tcpip/] [v2_0/] [src/] [sys/] [net/] [if_bridge.c] - Diff between revs 27 and 174

Only display areas with differences | Details | Blame | View Log

Rev 27 Rev 174
//==========================================================================
//==========================================================================
//
//
//      sys/net/if_bridge.c
//      sys/net/if_bridge.c
//
//
//     
//     
//
//
//==========================================================================
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//####BSDCOPYRIGHTBEGIN####
//
//
// -------------------------------------------
// -------------------------------------------
//
//
// Portions of this software may have been derived from OpenBSD or other sources,
// Portions of this software may have been derived from OpenBSD or other sources,
// and are covered by the appropriate copyright disclaimers included herein.
// and are covered by the appropriate copyright disclaimers included herein.
//
//
// -------------------------------------------
// -------------------------------------------
//
//
//####BSDCOPYRIGHTEND####
//####BSDCOPYRIGHTEND####
//==========================================================================
//==========================================================================
//#####DESCRIPTIONBEGIN####
//#####DESCRIPTIONBEGIN####
//
//
// Author(s):    Jason L. Wright (jason@thought.net)  
// Author(s):    Jason L. Wright (jason@thought.net)  
// Contributors: andrew.lunn@ascom.ch (Andrew Lunn), hmt
// Contributors: andrew.lunn@ascom.ch (Andrew Lunn), hmt
// Date:         2000-07-18
// Date:         2000-07-18
// Purpose:      Ethernet bridge
// Purpose:      Ethernet bridge
// Description:  
// Description:  
//              
//              
//
//
//####DESCRIPTIONEND####
//####DESCRIPTIONEND####
//
//
//==========================================================================
//==========================================================================
/*      $OpenBSD: if_bridge.c,v 1.33 2000/06/20 05:50:16 jason Exp $    */
/*      $OpenBSD: if_bridge.c,v 1.33 2000/06/20 05:50:16 jason Exp $    */
 
 
/*
/*
 * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
 * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
 * All rights reserved.
 * All rights reserved.
 *
 *
 * Redistribution and use in source and binary forms, with or without
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * modification, are permitted provided that the following conditions
 * are met:
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    must display the following acknowledgement:
 *      This product includes software developed by Jason L. Wright
 *      This product includes software developed by Jason L. Wright
 * 4. The name of the author may not be used to endorse or promote products
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *    derived from this software without specific prior written permission.
 *
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * POSSIBILITY OF SUCH DAMAGE.
 */
 */
 
 
#ifdef __ECOS
#ifdef __ECOS
#include <pkgconf/net.h>
#include <pkgconf/net.h>
#else
#else
#include "bridge.h"
#include "bridge.h"
#include "bpfilter.h"
#include "bpfilter.h"
#include "enc.h"
#include "enc.h"
#endif
#endif
 
 
#include <sys/param.h>
#include <sys/param.h>
#ifndef __ECOS
#ifndef __ECOS
#include <sys/proc.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/systm.h>
#endif
#endif
#include <sys/mbuf.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/errno.h>
#ifndef __ECOS
#ifndef __ECOS
#include <sys/device.h>
#include <sys/device.h>
#endif
#endif
#include <sys/kernel.h>
#include <sys/kernel.h>
#include <machine/cpu.h>
#include <machine/cpu.h>
 
 
#include <net/if.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/if_types.h>
#include <net/if_llc.h>
#include <net/if_llc.h>
#include <net/route.h>
#include <net/route.h>
#include <net/netisr.h>
#include <net/netisr.h>
 
 
#ifdef INET
#ifdef INET
#include <netinet/in.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <netinet/if_ether.h>
#include <netinet/ip_ipsp.h>
#include <netinet/ip_ipsp.h>
 
 
#ifndef __ECOS
#ifndef __ECOS
#include <net/if_enc.h>
#include <net/if_enc.h>
#endif
#endif
#ifdef IPFILTER
#ifdef IPFILTER
#include <netinet/ip_fil_compat.h>
#include <netinet/ip_fil_compat.h>
#include <netinet/ip_fil.h>
#include <netinet/ip_fil.h>
#endif
#endif
#endif
#endif
 
 
#if NBPFILTER > 0
#if NBPFILTER > 0
#include <net/bpf.h>
#include <net/bpf.h>
#endif
#endif
 
 
#include <net/if_bridge.h>
#include <net/if_bridge.h>
 
 
#ifdef __ECOS
#ifdef __ECOS
#include <stdio.h> /* for sprintf */
#include <stdio.h> /* for sprintf */
#endif 
#endif 
 
 
#ifndef BRIDGE_RTABLE_SIZE
#ifndef BRIDGE_RTABLE_SIZE
#define BRIDGE_RTABLE_SIZE      1024
#define BRIDGE_RTABLE_SIZE      1024
#endif
#endif
#define BRIDGE_RTABLE_MASK      (BRIDGE_RTABLE_SIZE - 1)
#define BRIDGE_RTABLE_MASK      (BRIDGE_RTABLE_SIZE - 1)
 
 
/*
/*
 * Maximum number of addresses to cache
 * Maximum number of addresses to cache
 */
 */
#ifndef BRIDGE_RTABLE_MAX
#ifndef BRIDGE_RTABLE_MAX
#define BRIDGE_RTABLE_MAX       100
#define BRIDGE_RTABLE_MAX       100
#endif
#endif
 
 
/*
/*
 * Timeout (in seconds) for entries learned dynamically
 * Timeout (in seconds) for entries learned dynamically
 */
 */
#ifndef BRIDGE_RTABLE_TIMEOUT
#ifndef BRIDGE_RTABLE_TIMEOUT
#define BRIDGE_RTABLE_TIMEOUT   300
#define BRIDGE_RTABLE_TIMEOUT   300
#endif
#endif
 
 
extern int ifqmaxlen;
extern int ifqmaxlen;
 
 
/*
/*
 * Bridge filtering rules
 * Bridge filtering rules
 */
 */
struct brl_node {
struct brl_node {
        SIMPLEQ_ENTRY(brl_node) brl_next;       /* next rule */
        SIMPLEQ_ENTRY(brl_node) brl_next;       /* next rule */
        struct ether_addr       brl_src;        /* source mac address */
        struct ether_addr       brl_src;        /* source mac address */
        struct ether_addr       brl_dst;        /* destination mac address */
        struct ether_addr       brl_dst;        /* destination mac address */
        u_int8_t                brl_action;     /* what to do with match */
        u_int8_t                brl_action;     /* what to do with match */
        u_int8_t                brl_flags;      /* comparision flags */
        u_int8_t                brl_flags;      /* comparision flags */
};
};
 
 
/*
/*
 * Bridge interface list
 * Bridge interface list
 */
 */
struct bridge_iflist {
struct bridge_iflist {
        LIST_ENTRY(bridge_iflist)       next;           /* next in list */
        LIST_ENTRY(bridge_iflist)       next;           /* next in list */
        SIMPLEQ_HEAD(, brl_node)        bif_brlin;      /* input rules */
        SIMPLEQ_HEAD(, brl_node)        bif_brlin;      /* input rules */
        SIMPLEQ_HEAD(, brl_node)        bif_brlout;     /* output rules */
        SIMPLEQ_HEAD(, brl_node)        bif_brlout;     /* output rules */
        struct                          ifnet *ifp;     /* member interface */
        struct                          ifnet *ifp;     /* member interface */
        u_int32_t                       bif_flags;      /* member flags */
        u_int32_t                       bif_flags;      /* member flags */
};
};
 
 
/*
/*
 * Bridge route node
 * Bridge route node
 */
 */
struct bridge_rtnode {
struct bridge_rtnode {
        LIST_ENTRY(bridge_rtnode)       brt_next;       /* next in list */
        LIST_ENTRY(bridge_rtnode)       brt_next;       /* next in list */
        struct                          ifnet *brt_if;  /* destination ifs */
        struct                          ifnet *brt_if;  /* destination ifs */
        u_int8_t                        brt_flags;      /* address flags */
        u_int8_t                        brt_flags;      /* address flags */
        u_int8_t                        brt_age;        /* age counter */
        u_int8_t                        brt_age;        /* age counter */
        struct                          ether_addr brt_addr;    /* dst addr */
        struct                          ether_addr brt_addr;    /* dst addr */
};
};
 
 
/*
/*
 * Software state for each bridge
 * Software state for each bridge
 */
 */
struct bridge_softc {
struct bridge_softc {
        struct                          ifnet sc_if;    /* the interface */
        struct                          ifnet sc_if;    /* the interface */
        u_int32_t                       sc_brtmax;      /* max # addresses */
        u_int32_t                       sc_brtmax;      /* max # addresses */
        u_int32_t                       sc_brtcnt;      /* current # addrs */
        u_int32_t                       sc_brtcnt;      /* current # addrs */
        u_int32_t                       sc_brttimeout;  /* timeout ticks */
        u_int32_t                       sc_brttimeout;  /* timeout ticks */
        LIST_HEAD(, bridge_iflist)      sc_iflist;      /* interface list */
        LIST_HEAD(, bridge_iflist)      sc_iflist;      /* interface list */
        LIST_HEAD(bridge_rthead, bridge_rtnode) *sc_rts;/* hash table */
        LIST_HEAD(bridge_rthead, bridge_rtnode) *sc_rts;/* hash table */
};
};
 
 
/* SNAP LLC header */
/* SNAP LLC header */
struct snap {
struct snap {
        u_int8_t dsap;
        u_int8_t dsap;
        u_int8_t ssap;
        u_int8_t ssap;
        u_int8_t control;
        u_int8_t control;
        u_int8_t org[3];
        u_int8_t org[3];
        u_int16_t type;
        u_int16_t type;
};
};
 
 
struct bridge_softc bridgectl[CYGNUM_NET_BRIDGES];
struct bridge_softc bridgectl[CYGNUM_NET_BRIDGES];
 
 
void    bridgeattach __P((int));
void    bridgeattach __P((int));
int     bridge_ioctl __P((struct ifnet *, u_long, caddr_t));
int     bridge_ioctl __P((struct ifnet *, u_long, caddr_t));
void    bridge_start __P((struct ifnet *));
void    bridge_start __P((struct ifnet *));
void    bridgeintr_frame __P((struct bridge_softc *, struct mbuf *));
void    bridgeintr_frame __P((struct bridge_softc *, struct mbuf *));
void    bridge_broadcast __P((struct bridge_softc *, struct ifnet *,
void    bridge_broadcast __P((struct bridge_softc *, struct ifnet *,
    struct ether_header *, struct mbuf *)) __attribute ((weak));
    struct ether_header *, struct mbuf *)) __attribute ((weak));
void    bridge_stop __P((struct bridge_softc *));
void    bridge_stop __P((struct bridge_softc *));
void    bridge_init __P((struct bridge_softc *));
void    bridge_init __P((struct bridge_softc *));
int     bridge_bifconf __P((struct bridge_softc *, struct ifbifconf *));
int     bridge_bifconf __P((struct bridge_softc *, struct ifbifconf *));
 
 
int     bridge_rtfind __P((struct bridge_softc *, struct ifbaconf *));
int     bridge_rtfind __P((struct bridge_softc *, struct ifbaconf *));
void    bridge_rtage __P((void *));
void    bridge_rtage __P((void *));
void    bridge_rttrim __P((struct bridge_softc *));
void    bridge_rttrim __P((struct bridge_softc *));
void    bridge_rtdelete __P((struct bridge_softc *, struct ifnet *));
void    bridge_rtdelete __P((struct bridge_softc *, struct ifnet *));
int     bridge_rtdaddr __P((struct bridge_softc *, struct ether_addr *));
int     bridge_rtdaddr __P((struct bridge_softc *, struct ether_addr *));
int     bridge_rtflush __P((struct bridge_softc *, int));
int     bridge_rtflush __P((struct bridge_softc *, int));
struct ifnet *  bridge_rtupdate __P((struct bridge_softc *,
struct ifnet *  bridge_rtupdate __P((struct bridge_softc *,
    struct ether_addr *, struct ifnet *ifp, int, u_int8_t));
    struct ether_addr *, struct ifnet *ifp, int, u_int8_t));
struct ifnet *  bridge_rtlookup __P((struct bridge_softc *,
struct ifnet *  bridge_rtlookup __P((struct bridge_softc *,
    struct ether_addr *));
    struct ether_addr *));
u_int32_t       bridge_hash __P((struct ether_addr *));
u_int32_t       bridge_hash __P((struct ether_addr *));
int bridge_blocknonip __P((struct ether_header *, struct mbuf *));
int bridge_blocknonip __P((struct ether_header *, struct mbuf *));
int             bridge_addrule __P((struct bridge_iflist *,
int             bridge_addrule __P((struct bridge_iflist *,
    struct ifbrlreq *, int out));
    struct ifbrlreq *, int out));
int             bridge_flushrule __P((struct bridge_iflist *));
int             bridge_flushrule __P((struct bridge_iflist *));
int     bridge_brlconf __P((struct bridge_softc *, struct ifbrlconf *));
int     bridge_brlconf __P((struct bridge_softc *, struct ifbrlconf *));
u_int8_t bridge_filterrule __P((struct brl_node *, struct ether_header *));
u_int8_t bridge_filterrule __P((struct brl_node *, struct ether_header *));
 
 
#define ETHERADDR_IS_IP_MCAST(a) \
#define ETHERADDR_IS_IP_MCAST(a) \
        /* struct etheraddr *a; */                              \
        /* struct etheraddr *a; */                              \
        ((a)->ether_addr_octet[0] == 0x01 &&                     \
        ((a)->ether_addr_octet[0] == 0x01 &&                     \
         (a)->ether_addr_octet[1] == 0x00 &&                    \
         (a)->ether_addr_octet[1] == 0x00 &&                    \
         (a)->ether_addr_octet[2] == 0x5e)
         (a)->ether_addr_octet[2] == 0x5e)
 
 
 
 
#if defined(INET) && (defined(IPFILTER) || defined(IPFILTER_LKM))
#if defined(INET) && (defined(IPFILTER) || defined(IPFILTER_LKM))
/*
/*
 * Filter hooks
 * Filter hooks
 */
 */
struct mbuf *bridge_filter __P((struct bridge_softc *, struct ifnet *,
struct mbuf *bridge_filter __P((struct bridge_softc *, struct ifnet *,
    struct ether_header *, struct mbuf *m));
    struct ether_header *, struct mbuf *m));
#endif
#endif
 
 
void
void
bridgeattach(unused)
bridgeattach(unused)
        int unused;
        int unused;
{
{
        int i;
        int i;
        struct ifnet *ifp;
        struct ifnet *ifp;
 
 
        for (i = 0; i < CYGNUM_NET_BRIDGES; i++) {
        for (i = 0; i < CYGNUM_NET_BRIDGES; i++) {
                bridgectl[i].sc_brtmax = BRIDGE_RTABLE_MAX;
                bridgectl[i].sc_brtmax = BRIDGE_RTABLE_MAX;
                bridgectl[i].sc_brttimeout = (BRIDGE_RTABLE_TIMEOUT * hz) / 2;
                bridgectl[i].sc_brttimeout = (BRIDGE_RTABLE_TIMEOUT * hz) / 2;
                LIST_INIT(&bridgectl[i].sc_iflist);
                LIST_INIT(&bridgectl[i].sc_iflist);
                ifp = &bridgectl[i].sc_if;
                ifp = &bridgectl[i].sc_if;
                sprintf(ifp->if_xname, "bridge%d", i);
                sprintf(ifp->if_xname, "bridge%d", i);
                ifp->if_softc = &bridgectl[i];
                ifp->if_softc = &bridgectl[i];
                ifp->if_mtu = ETHERMTU;
                ifp->if_mtu = ETHERMTU;
                ifp->if_ioctl = bridge_ioctl;
                ifp->if_ioctl = bridge_ioctl;
                ifp->if_output = bridge_output;
                ifp->if_output = bridge_output;
                ifp->if_start = bridge_start;
                ifp->if_start = bridge_start;
                ifp->if_type = IFT_PROPVIRTUAL;
                ifp->if_type = IFT_PROPVIRTUAL;
                ifp->if_snd.ifq_maxlen = ifqmaxlen;
                ifp->if_snd.ifq_maxlen = ifqmaxlen;
                ifp->if_hdrlen = sizeof(struct ether_header);
                ifp->if_hdrlen = sizeof(struct ether_header);
                if_attach(ifp);
                if_attach(ifp);
#if NBPFILTER > 0
#if NBPFILTER > 0
                bpfattach(&bridgectl[i].sc_if.if_bpf, ifp,
                bpfattach(&bridgectl[i].sc_if.if_bpf, ifp,
                    DLT_EN10MB, sizeof(struct ether_header));
                    DLT_EN10MB, sizeof(struct ether_header));
#endif
#endif
        }
        }
}
}
 
 
int
int
bridge_ioctl(ifp, cmd, data)
bridge_ioctl(ifp, cmd, data)
        struct ifnet *ifp;
        struct ifnet *ifp;
        u_long cmd;
        u_long cmd;
        caddr_t data;
        caddr_t data;
{
{
#ifndef __ECOS
#ifndef __ECOS
        struct proc *prc = curproc;             /* XXX */
        struct proc *prc = curproc;             /* XXX */
#endif
#endif
        struct ifnet *ifs;
        struct ifnet *ifs;
        struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
        struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
        struct ifbreq *req = (struct ifbreq *)data;
        struct ifbreq *req = (struct ifbreq *)data;
        struct ifbaconf *baconf = (struct ifbaconf *)data;
        struct ifbaconf *baconf = (struct ifbaconf *)data;
        struct ifbareq *bareq = (struct ifbareq *)data;
        struct ifbareq *bareq = (struct ifbareq *)data;
        struct ifbcachereq *bcachereq = (struct ifbcachereq *)data;
        struct ifbcachereq *bcachereq = (struct ifbcachereq *)data;
        struct ifbifconf *bifconf = (struct ifbifconf *)data;
        struct ifbifconf *bifconf = (struct ifbifconf *)data;
        struct ifbcachetoreq *bcacheto = (struct ifbcachetoreq *)data;
        struct ifbcachetoreq *bcacheto = (struct ifbcachetoreq *)data;
        struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
        struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
        struct ifbrlconf *brlconf = (struct ifbrlconf *)data;
        struct ifbrlconf *brlconf = (struct ifbrlconf *)data;
        struct ifreq ifreq;
        struct ifreq ifreq;
        int error = 0, s;
        int error = 0, s;
        struct bridge_iflist *p;
        struct bridge_iflist *p;
 
 
        s = splimp();
        s = splimp();
        switch (cmd) {
        switch (cmd) {
        case SIOCBRDGADD:
        case SIOCBRDGADD:
#ifndef __ECOS
#ifndef __ECOS
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                        break;
                        break;
#endif
#endif
                ifs = ifunit(req->ifbr_ifsname);
                ifs = ifunit(req->ifbr_ifsname);
                if (ifs == NULL) {                      /* no such interface */
                if (ifs == NULL) {                      /* no such interface */
                        error = ENOENT;
                        error = ENOENT;
                        break;
                        break;
                }
                }
                if (ifs->if_bridge == (caddr_t)sc) {
                if (ifs->if_bridge == (caddr_t)sc) {
                        error = EEXIST;
                        error = EEXIST;
                        break;
                        break;
                }
                }
                if (ifs->if_bridge != NULL) {
                if (ifs->if_bridge != NULL) {
                        error = EBUSY;
                        error = EBUSY;
                        break;
                        break;
                }
                }
 
 
                if (ifs->if_type == IFT_ETHER) {
                if (ifs->if_type == IFT_ETHER) {
                        if ((ifs->if_flags & IFF_UP) == 0) {
                        if ((ifs->if_flags & IFF_UP) == 0) {
                                /*
                                /*
                                 * Bring interface up long enough to set
                                 * Bring interface up long enough to set
                                 * promiscuous flag, then shut it down again.
                                 * promiscuous flag, then shut it down again.
                                 */
                                 */
                                strncpy(ifreq.ifr_name, req->ifbr_ifsname,
                                strncpy(ifreq.ifr_name, req->ifbr_ifsname,
                                    sizeof(ifreq.ifr_name) - 1);
                                    sizeof(ifreq.ifr_name) - 1);
                                ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0';
                                ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0';
                                ifs->if_flags |= IFF_UP;
                                ifs->if_flags |= IFF_UP;
                                ifreq.ifr_flags = ifs->if_flags;
                                ifreq.ifr_flags = ifs->if_flags;
                                error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS,
                                error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS,
                                    (caddr_t)&ifreq);
                                    (caddr_t)&ifreq);
                                if (error != 0)
                                if (error != 0)
                                        break;
                                        break;
 
 
                                error = ifpromisc(ifs, 1);
                                error = ifpromisc(ifs, 1);
                                if (error != 0)
                                if (error != 0)
                                        break;
                                        break;
 
 
                                strncpy(ifreq.ifr_name, req->ifbr_ifsname,
                                strncpy(ifreq.ifr_name, req->ifbr_ifsname,
                                    sizeof(ifreq.ifr_name) - 1);
                                    sizeof(ifreq.ifr_name) - 1);
                                ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0';
                                ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0';
                                ifs->if_flags &= ~IFF_UP;
                                ifs->if_flags &= ~IFF_UP;
                                ifreq.ifr_flags = ifs->if_flags;
                                ifreq.ifr_flags = ifs->if_flags;
                                error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS,
                                error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS,
                                    (caddr_t)&ifreq);
                                    (caddr_t)&ifreq);
                                if (error != 0) {
                                if (error != 0) {
                                        ifpromisc(ifs, 0);
                                        ifpromisc(ifs, 0);
                                        break;
                                        break;
                                }
                                }
                        } else {
                        } else {
                                error = ifpromisc(ifs, 1);
                                error = ifpromisc(ifs, 1);
                                if (error != 0)
                                if (error != 0)
                                        break;
                                        break;
                        }
                        }
                }
                }
#ifndef __ECOS
#ifndef __ECOS
#if NENC > 0
#if NENC > 0
                else if (ifs->if_type == IFT_ENC) {
                else if (ifs->if_type == IFT_ENC) {
                        /* Can't bind enc0 to a bridge */
                        /* Can't bind enc0 to a bridge */
                        if (ifs->if_softc == &encif[0]) {
                        if (ifs->if_softc == &encif[0]) {
                                error = EINVAL;
                                error = EINVAL;
                                break;
                                break;
                        }
                        }
                }
                }
#endif /* NENC */
#endif /* NENC */
#endif
#endif
                else {
                else {
                        error = EINVAL;
                        error = EINVAL;
                        break;
                        break;
                }
                }
 
 
                p = (struct bridge_iflist *) malloc(
                p = (struct bridge_iflist *) malloc(
                    sizeof(struct bridge_iflist), M_DEVBUF, M_NOWAIT);
                    sizeof(struct bridge_iflist), M_DEVBUF, M_NOWAIT);
                if (p == NULL && ifs->if_type == IFT_ETHER) {
                if (p == NULL && ifs->if_type == IFT_ETHER) {
                        error = ENOMEM;
                        error = ENOMEM;
                        ifpromisc(ifs, 0);
                        ifpromisc(ifs, 0);
                        break;
                        break;
                }
                }
 
 
                p->ifp = ifs;
                p->ifp = ifs;
                p->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
                p->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
                SIMPLEQ_INIT(&p->bif_brlin);
                SIMPLEQ_INIT(&p->bif_brlin);
                SIMPLEQ_INIT(&p->bif_brlout);
                SIMPLEQ_INIT(&p->bif_brlout);
                LIST_INSERT_HEAD(&sc->sc_iflist, p, next);
                LIST_INSERT_HEAD(&sc->sc_iflist, p, next);
                ifs->if_bridge = (caddr_t)sc;
                ifs->if_bridge = (caddr_t)sc;
                break;
                break;
        case SIOCBRDGDEL:
        case SIOCBRDGDEL:
#ifndef __ECOS
#ifndef __ECOS
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                        break;
                        break;
#endif
#endif
                p = LIST_FIRST(&sc->sc_iflist);
                p = LIST_FIRST(&sc->sc_iflist);
                while (p != NULL) {
                while (p != NULL) {
                        if (strncmp(p->ifp->if_xname, req->ifbr_ifsname,
                        if (strncmp(p->ifp->if_xname, req->ifbr_ifsname,
                            sizeof(p->ifp->if_xname)) == 0) {
                            sizeof(p->ifp->if_xname)) == 0) {
                                p->ifp->if_bridge = NULL;
                                p->ifp->if_bridge = NULL;
 
 
                                error = ifpromisc(p->ifp, 0);
                                error = ifpromisc(p->ifp, 0);
 
 
                                LIST_REMOVE(p, next);
                                LIST_REMOVE(p, next);
                                bridge_rtdelete(sc, p->ifp);
                                bridge_rtdelete(sc, p->ifp);
                                bridge_flushrule(p);
                                bridge_flushrule(p);
                                free(p, M_DEVBUF);
                                free(p, M_DEVBUF);
                                break;
                                break;
                        }
                        }
                        p = LIST_NEXT(p, next);
                        p = LIST_NEXT(p, next);
                }
                }
                if (p == NULL) {
                if (p == NULL) {
                        error = ENOENT;
                        error = ENOENT;
                        break;
                        break;
                }
                }
                break;
                break;
        case SIOCBRDGIFS:
        case SIOCBRDGIFS:
                error = bridge_bifconf(sc, bifconf);
                error = bridge_bifconf(sc, bifconf);
                break;
                break;
        case SIOCBRDGGIFFLGS:
        case SIOCBRDGGIFFLGS:
                ifs = ifunit(req->ifbr_ifsname);
                ifs = ifunit(req->ifbr_ifsname);
                if (ifs == NULL) {
                if (ifs == NULL) {
                        error = ENOENT;
                        error = ENOENT;
                        break;
                        break;
                }
                }
                if ((caddr_t)sc != ifs->if_bridge) {
                if ((caddr_t)sc != ifs->if_bridge) {
                        error = ESRCH;
                        error = ESRCH;
                        break;
                        break;
                }
                }
                p = LIST_FIRST(&sc->sc_iflist);
                p = LIST_FIRST(&sc->sc_iflist);
                while (p != NULL && p->ifp != ifs) {
                while (p != NULL && p->ifp != ifs) {
                        p = LIST_NEXT(p, next);
                        p = LIST_NEXT(p, next);
                }
                }
                if (p == NULL) {
                if (p == NULL) {
                        error = ESRCH;
                        error = ESRCH;
                        break;
                        break;
                }
                }
                req->ifbr_ifsflags = p->bif_flags;
                req->ifbr_ifsflags = p->bif_flags;
                break;
                break;
        case SIOCBRDGSIFFLGS:
        case SIOCBRDGSIFFLGS:
#ifndef __ECOS
#ifndef __ECOS
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                        break;
                        break;
#endif
#endif
                ifs = ifunit(req->ifbr_ifsname);
                ifs = ifunit(req->ifbr_ifsname);
                if (ifs == NULL) {
                if (ifs == NULL) {
                        error = ENOENT;
                        error = ENOENT;
                        break;
                        break;
                }
                }
                if ((caddr_t)sc != ifs->if_bridge) {
                if ((caddr_t)sc != ifs->if_bridge) {
                        error = ESRCH;
                        error = ESRCH;
                        break;
                        break;
                }
                }
                p = LIST_FIRST(&sc->sc_iflist);
                p = LIST_FIRST(&sc->sc_iflist);
                while (p != NULL && p->ifp != ifs) {
                while (p != NULL && p->ifp != ifs) {
                        p = LIST_NEXT(p, next);
                        p = LIST_NEXT(p, next);
                }
                }
                if (p == NULL) {
                if (p == NULL) {
                        error = ESRCH;
                        error = ESRCH;
                        break;
                        break;
                }
                }
                p->bif_flags = req->ifbr_ifsflags;
                p->bif_flags = req->ifbr_ifsflags;
                break;
                break;
        case SIOCBRDGRTS:
        case SIOCBRDGRTS:
                error = bridge_rtfind(sc, baconf);
                error = bridge_rtfind(sc, baconf);
                break;
                break;
        case SIOCBRDGFLUSH:
        case SIOCBRDGFLUSH:
#ifndef __ECOS
#ifndef __ECOS
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                        break;
                        break;
#endif
#endif
                error = bridge_rtflush(sc, req->ifbr_ifsflags);
                error = bridge_rtflush(sc, req->ifbr_ifsflags);
                break;
                break;
        case SIOCBRDGSADDR:
        case SIOCBRDGSADDR:
#ifndef __ECOS
#ifndef __ECOS
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                        break;
                        break;
#endif
#endif
                ifs = ifunit(bareq->ifba_ifsname);
                ifs = ifunit(bareq->ifba_ifsname);
                if (ifs == NULL) {                      /* no such interface */
                if (ifs == NULL) {                      /* no such interface */
                        error = ENOENT;
                        error = ENOENT;
                        break;
                        break;
                }
                }
 
 
                if (ifs->if_bridge == NULL ||
                if (ifs->if_bridge == NULL ||
                    ifs->if_bridge != (caddr_t)sc) {
                    ifs->if_bridge != (caddr_t)sc) {
                        error = ESRCH;
                        error = ESRCH;
                        break;
                        break;
                }
                }
 
 
                ifs = bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,
                ifs = bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,
                    bareq->ifba_flags);
                    bareq->ifba_flags);
                if (ifs == NULL)
                if (ifs == NULL)
                        error = ENOMEM;
                        error = ENOMEM;
                break;
                break;
        case SIOCBRDGDADDR:
        case SIOCBRDGDADDR:
#ifndef __ECOS
#ifndef __ECOS
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                        break;
                        break;
#endif
#endif
                error = bridge_rtdaddr(sc, &bareq->ifba_dst);
                error = bridge_rtdaddr(sc, &bareq->ifba_dst);
                break;
                break;
        case SIOCBRDGGCACHE:
        case SIOCBRDGGCACHE:
                bcachereq->ifbc_size = sc->sc_brtmax;
                bcachereq->ifbc_size = sc->sc_brtmax;
                break;
                break;
        case SIOCBRDGSCACHE:
        case SIOCBRDGSCACHE:
#ifndef __ECOS
#ifndef __ECOS
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                        break;
                        break;
#endif
#endif
                sc->sc_brtmax = bcachereq->ifbc_size;
                sc->sc_brtmax = bcachereq->ifbc_size;
                bridge_rttrim(sc);
                bridge_rttrim(sc);
                break;
                break;
        case SIOCBRDGSTO:
        case SIOCBRDGSTO:
#ifndef __ECOS
#ifndef __ECOS
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                        break;
                        break;
#endif
#endif
                sc->sc_brttimeout = (bcacheto->ifbct_time * hz) / 2;
                sc->sc_brttimeout = (bcacheto->ifbct_time * hz) / 2;
                untimeout(bridge_rtage, sc);
                untimeout(bridge_rtage, sc);
                if (bcacheto->ifbct_time != 0)
                if (bcacheto->ifbct_time != 0)
                        timeout(bridge_rtage, sc, sc->sc_brttimeout);
                        timeout(bridge_rtage, sc, sc->sc_brttimeout);
                break;
                break;
        case SIOCBRDGGTO:
        case SIOCBRDGGTO:
                bcacheto->ifbct_time = (2 * sc->sc_brttimeout) / hz;
                bcacheto->ifbct_time = (2 * sc->sc_brttimeout) / hz;
                break;
                break;
        case SIOCSIFFLAGS:
        case SIOCSIFFLAGS:
                if ((ifp->if_flags & IFF_UP) == IFF_UP)
                if ((ifp->if_flags & IFF_UP) == IFF_UP)
                        bridge_init(sc);
                        bridge_init(sc);
 
 
                if ((ifp->if_flags & IFF_UP) == 0)
                if ((ifp->if_flags & IFF_UP) == 0)
                        bridge_stop(sc);
                        bridge_stop(sc);
 
 
                break;
                break;
        case SIOCBRDGARL:
        case SIOCBRDGARL:
#ifndef __ECOS
#ifndef __ECOS
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                        break;
                        break;
#endif
#endif
                ifs = ifunit(brlreq->ifbr_ifsname);
                ifs = ifunit(brlreq->ifbr_ifsname);
                if (ifs == NULL) {
                if (ifs == NULL) {
                        error = ENOENT;
                        error = ENOENT;
                        break;
                        break;
                }
                }
                if (ifs->if_bridge == NULL ||
                if (ifs->if_bridge == NULL ||
                    ifs->if_bridge != (caddr_t)sc) {
                    ifs->if_bridge != (caddr_t)sc) {
                        error = ESRCH;
                        error = ESRCH;
                        break;
                        break;
                }
                }
                p = LIST_FIRST(&sc->sc_iflist);
                p = LIST_FIRST(&sc->sc_iflist);
                while (p != NULL && p->ifp != ifs) {
                while (p != NULL && p->ifp != ifs) {
                        p = LIST_NEXT(p, next);
                        p = LIST_NEXT(p, next);
                }
                }
                if (p == NULL) {
                if (p == NULL) {
                        error = ESRCH;
                        error = ESRCH;
                        break;
                        break;
                }
                }
                if ((brlreq->ifbr_action != BRL_ACTION_BLOCK &&
                if ((brlreq->ifbr_action != BRL_ACTION_BLOCK &&
                    brlreq->ifbr_action != BRL_ACTION_PASS) ||
                    brlreq->ifbr_action != BRL_ACTION_PASS) ||
                    (brlreq->ifbr_flags & (BRL_FLAG_IN|BRL_FLAG_OUT)) == 0) {
                    (brlreq->ifbr_flags & (BRL_FLAG_IN|BRL_FLAG_OUT)) == 0) {
                        error = EINVAL;
                        error = EINVAL;
                        break;
                        break;
                }
                }
                if (brlreq->ifbr_flags & BRL_FLAG_IN) {
                if (brlreq->ifbr_flags & BRL_FLAG_IN) {
                        error = bridge_addrule(p, brlreq, 0);
                        error = bridge_addrule(p, brlreq, 0);
                        if (error)
                        if (error)
                                break;
                                break;
                }
                }
                if (brlreq->ifbr_flags & BRL_FLAG_OUT) {
                if (brlreq->ifbr_flags & BRL_FLAG_OUT) {
                        error = bridge_addrule(p, brlreq, 1);
                        error = bridge_addrule(p, brlreq, 1);
                        if (error)
                        if (error)
                                break;
                                break;
                }
                }
                break;
                break;
        case SIOCBRDGFRL:
        case SIOCBRDGFRL:
#ifndef __ECOS
#ifndef __ECOS
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
                        break;
                        break;
#endif
#endif
                ifs = ifunit(brlreq->ifbr_ifsname);
                ifs = ifunit(brlreq->ifbr_ifsname);
                if (ifs == NULL) {
                if (ifs == NULL) {
                        error = ENOENT;
                        error = ENOENT;
                        break;
                        break;
                }
                }
                if (ifs->if_bridge == NULL ||
                if (ifs->if_bridge == NULL ||
                    ifs->if_bridge != (caddr_t)sc) {
                    ifs->if_bridge != (caddr_t)sc) {
                        error = ESRCH;
                        error = ESRCH;
                        break;
                        break;
                }
                }
                p = LIST_FIRST(&sc->sc_iflist);
                p = LIST_FIRST(&sc->sc_iflist);
                while (p != NULL && p->ifp != ifs) {
                while (p != NULL && p->ifp != ifs) {
                        p = LIST_NEXT(p, next);
                        p = LIST_NEXT(p, next);
                }
                }
                if (p == NULL) {
                if (p == NULL) {
                        error = ESRCH;
                        error = ESRCH;
                        break;
                        break;
                }
                }
                error = bridge_flushrule(p);
                error = bridge_flushrule(p);
                break;
                break;
        case SIOCBRDGGRL:
        case SIOCBRDGGRL:
                error = bridge_brlconf(sc, brlconf);
                error = bridge_brlconf(sc, brlconf);
                break;
                break;
        default:
        default:
                error = EINVAL;
                error = EINVAL;
        }
        }
        splx(s);
        splx(s);
        return (error);
        return (error);
}
}
 
 
/* Detach an interface from a bridge.  */
/* Detach an interface from a bridge.  */
void
void
bridge_ifdetach(ifp)
bridge_ifdetach(ifp)
        struct ifnet *ifp;
        struct ifnet *ifp;
{
{
        struct bridge_softc *bsc = (struct bridge_softc *)ifp->if_bridge;
        struct bridge_softc *bsc = (struct bridge_softc *)ifp->if_bridge;
        struct bridge_iflist *bif;
        struct bridge_iflist *bif;
 
 
        for (bif = LIST_FIRST(&bsc->sc_iflist); bif;
        for (bif = LIST_FIRST(&bsc->sc_iflist); bif;
            bif = LIST_NEXT(bif, next))
            bif = LIST_NEXT(bif, next))
                if (bif->ifp == ifp) {
                if (bif->ifp == ifp) {
                        LIST_REMOVE(bif, next);
                        LIST_REMOVE(bif, next);
                        bridge_rtdelete(bsc, ifp);
                        bridge_rtdelete(bsc, ifp);
                        bridge_flushrule(bif);
                        bridge_flushrule(bif);
                        free(bif, M_DEVBUF);
                        free(bif, M_DEVBUF);
                        ifp->if_bridge = NULL;
                        ifp->if_bridge = NULL;
                        break;
                        break;
                }
                }
}
}
 
 
int
int
bridge_bifconf(sc, bifc)
bridge_bifconf(sc, bifc)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        struct ifbifconf *bifc;
        struct ifbifconf *bifc;
{
{
        struct bridge_iflist *p;
        struct bridge_iflist *p;
        u_int32_t total = 0, i;
        u_int32_t total = 0, i;
        int error = 0;
        int error = 0;
        struct ifbreq breq;
        struct ifbreq breq;
 
 
        p = LIST_FIRST(&sc->sc_iflist);
        p = LIST_FIRST(&sc->sc_iflist);
        while (p != NULL) {
        while (p != NULL) {
                total++;
                total++;
                p = LIST_NEXT(p, next);
                p = LIST_NEXT(p, next);
        }
        }
 
 
        if (bifc->ifbic_len == 0) {
        if (bifc->ifbic_len == 0) {
                i = total;
                i = total;
                goto done;
                goto done;
        }
        }
 
 
        p = LIST_FIRST(&sc->sc_iflist);
        p = LIST_FIRST(&sc->sc_iflist);
        i = 0;
        i = 0;
        while (p != NULL && bifc->ifbic_len > i * sizeof(breq)) {
        while (p != NULL && bifc->ifbic_len > i * sizeof(breq)) {
                strncpy(breq.ifbr_name, sc->sc_if.if_xname,
                strncpy(breq.ifbr_name, sc->sc_if.if_xname,
                    sizeof(breq.ifbr_name)-1);
                    sizeof(breq.ifbr_name)-1);
                breq.ifbr_name[sizeof(breq.ifbr_name) - 1] = '\0';
                breq.ifbr_name[sizeof(breq.ifbr_name) - 1] = '\0';
                strncpy(breq.ifbr_ifsname, p->ifp->if_xname,
                strncpy(breq.ifbr_ifsname, p->ifp->if_xname,
                    sizeof(breq.ifbr_ifsname)-1);
                    sizeof(breq.ifbr_ifsname)-1);
                breq.ifbr_ifsname[sizeof(breq.ifbr_ifsname) - 1] = '\0';
                breq.ifbr_ifsname[sizeof(breq.ifbr_ifsname) - 1] = '\0';
                breq.ifbr_ifsflags = p->bif_flags;
                breq.ifbr_ifsflags = p->bif_flags;
                error = copyout((caddr_t)&breq,
                error = copyout((caddr_t)&breq,
                    (caddr_t)(bifc->ifbic_req + i), sizeof(breq));
                    (caddr_t)(bifc->ifbic_req + i), sizeof(breq));
                if (error)
                if (error)
                        goto done;
                        goto done;
                p = LIST_NEXT(p, next);
                p = LIST_NEXT(p, next);
                i++;
                i++;
                bifc->ifbic_len -= sizeof(breq);
                bifc->ifbic_len -= sizeof(breq);
        }
        }
done:
done:
        bifc->ifbic_len = i * sizeof(breq);
        bifc->ifbic_len = i * sizeof(breq);
        return (error);
        return (error);
}
}
 
 
int
int
bridge_brlconf(sc, bc)
bridge_brlconf(sc, bc)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        struct ifbrlconf *bc;
        struct ifbrlconf *bc;
{
{
        struct ifnet *ifp;
        struct ifnet *ifp;
        struct bridge_iflist *ifl;
        struct bridge_iflist *ifl;
        struct brl_node *n;
        struct brl_node *n;
        struct ifbrlreq req;
        struct ifbrlreq req;
        int error = 0;
        int error = 0;
        u_int32_t i, total=0;
        u_int32_t i, total=0;
 
 
        ifp = ifunit(bc->ifbrl_ifsname);
        ifp = ifunit(bc->ifbrl_ifsname);
        if (ifp == NULL)
        if (ifp == NULL)
                return (ENOENT);
                return (ENOENT);
        if (ifp->if_bridge == NULL || ifp->if_bridge != (caddr_t)sc)
        if (ifp->if_bridge == NULL || ifp->if_bridge != (caddr_t)sc)
                return (ESRCH);
                return (ESRCH);
        ifl = LIST_FIRST(&sc->sc_iflist);
        ifl = LIST_FIRST(&sc->sc_iflist);
        while (ifl != NULL && ifl->ifp != ifp)
        while (ifl != NULL && ifl->ifp != ifp)
                ifl = LIST_NEXT(ifl, next);
                ifl = LIST_NEXT(ifl, next);
        if (ifl == NULL)
        if (ifl == NULL)
                return (ESRCH);
                return (ESRCH);
 
 
        n = SIMPLEQ_FIRST(&ifl->bif_brlin);
        n = SIMPLEQ_FIRST(&ifl->bif_brlin);
        while (n != NULL) {
        while (n != NULL) {
                total++;
                total++;
                n = SIMPLEQ_NEXT(n, brl_next);
                n = SIMPLEQ_NEXT(n, brl_next);
        }
        }
        n = SIMPLEQ_FIRST(&ifl->bif_brlout);
        n = SIMPLEQ_FIRST(&ifl->bif_brlout);
        while (n != NULL) {
        while (n != NULL) {
                total++;
                total++;
                n = SIMPLEQ_NEXT(n, brl_next);
                n = SIMPLEQ_NEXT(n, brl_next);
        }
        }
 
 
        if (bc->ifbrl_len == 0) {
        if (bc->ifbrl_len == 0) {
                i = total;
                i = total;
                goto done;
                goto done;
        }
        }
 
 
        i = 0;
        i = 0;
        n = SIMPLEQ_FIRST(&ifl->bif_brlin);
        n = SIMPLEQ_FIRST(&ifl->bif_brlin);
        while (n != NULL && bc->ifbrl_len > i * sizeof(req)) {
        while (n != NULL && bc->ifbrl_len > i * sizeof(req)) {
                strncpy(req.ifbr_name, sc->sc_if.if_xname,
                strncpy(req.ifbr_name, sc->sc_if.if_xname,
                    sizeof(req.ifbr_name) - 1);
                    sizeof(req.ifbr_name) - 1);
                req.ifbr_name[sizeof(req.ifbr_name) - 1] = '\0';
                req.ifbr_name[sizeof(req.ifbr_name) - 1] = '\0';
                strncpy(req.ifbr_ifsname, ifl->ifp->if_xname,
                strncpy(req.ifbr_ifsname, ifl->ifp->if_xname,
                    sizeof(req.ifbr_ifsname) - 1);
                    sizeof(req.ifbr_ifsname) - 1);
                req.ifbr_ifsname[sizeof(req.ifbr_ifsname) - 1] = '\0';
                req.ifbr_ifsname[sizeof(req.ifbr_ifsname) - 1] = '\0';
                req.ifbr_action = n->brl_action;
                req.ifbr_action = n->brl_action;
                req.ifbr_flags = n->brl_flags;
                req.ifbr_flags = n->brl_flags;
                req.ifbr_src = n->brl_src;
                req.ifbr_src = n->brl_src;
                req.ifbr_dst = n->brl_dst;
                req.ifbr_dst = n->brl_dst;
                error = copyout((caddr_t)&req,
                error = copyout((caddr_t)&req,
                    (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
                    (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
                if (error)
                if (error)
                        goto done;
                        goto done;
                n = SIMPLEQ_NEXT(n, brl_next);
                n = SIMPLEQ_NEXT(n, brl_next);
                i++;
                i++;
                bc->ifbrl_len -= sizeof(req);
                bc->ifbrl_len -= sizeof(req);
        }
        }
 
 
        n = SIMPLEQ_FIRST(&ifl->bif_brlout);
        n = SIMPLEQ_FIRST(&ifl->bif_brlout);
        while (n != NULL && bc->ifbrl_len > i * sizeof(req)) {
        while (n != NULL && bc->ifbrl_len > i * sizeof(req)) {
                strncpy(req.ifbr_name, sc->sc_if.if_xname,
                strncpy(req.ifbr_name, sc->sc_if.if_xname,
                    sizeof(req.ifbr_name) - 1);
                    sizeof(req.ifbr_name) - 1);
                req.ifbr_name[sizeof(req.ifbr_name) - 1] = '\0';
                req.ifbr_name[sizeof(req.ifbr_name) - 1] = '\0';
                strncpy(req.ifbr_ifsname, ifl->ifp->if_xname,
                strncpy(req.ifbr_ifsname, ifl->ifp->if_xname,
                    sizeof(req.ifbr_ifsname) - 1);
                    sizeof(req.ifbr_ifsname) - 1);
                req.ifbr_ifsname[sizeof(req.ifbr_ifsname) - 1] = '\0';
                req.ifbr_ifsname[sizeof(req.ifbr_ifsname) - 1] = '\0';
                req.ifbr_action = n->brl_action;
                req.ifbr_action = n->brl_action;
                req.ifbr_flags = n->brl_flags;
                req.ifbr_flags = n->brl_flags;
                req.ifbr_src = n->brl_src;
                req.ifbr_src = n->brl_src;
                req.ifbr_dst = n->brl_dst;
                req.ifbr_dst = n->brl_dst;
                error = copyout((caddr_t)&req,
                error = copyout((caddr_t)&req,
                    (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
                    (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
                if (error)
                if (error)
                        goto done;
                        goto done;
                n = SIMPLEQ_NEXT(n, brl_next);
                n = SIMPLEQ_NEXT(n, brl_next);
                i++;
                i++;
                bc->ifbrl_len -= sizeof(req);
                bc->ifbrl_len -= sizeof(req);
        }
        }
 
 
done:
done:
        bc->ifbrl_len = i * sizeof(req);
        bc->ifbrl_len = i * sizeof(req);
        return (error);
        return (error);
}
}
 
 
void
void
bridge_init(sc)
bridge_init(sc)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
{
{
        struct ifnet *ifp = &sc->sc_if;
        struct ifnet *ifp = &sc->sc_if;
        int i, s;
        int i, s;
 
 
        if ((ifp->if_flags & IFF_RUNNING) == IFF_RUNNING)
        if ((ifp->if_flags & IFF_RUNNING) == IFF_RUNNING)
                return;
                return;
 
 
        s = splhigh();
        s = splhigh();
        if (sc->sc_rts == NULL) {
        if (sc->sc_rts == NULL) {
                sc->sc_rts = (struct bridge_rthead *)malloc(
                sc->sc_rts = (struct bridge_rthead *)malloc(
                    BRIDGE_RTABLE_SIZE * (sizeof(struct bridge_rthead)),
                    BRIDGE_RTABLE_SIZE * (sizeof(struct bridge_rthead)),
                    M_DEVBUF, M_NOWAIT);
                    M_DEVBUF, M_NOWAIT);
                if (sc->sc_rts == NULL) {
                if (sc->sc_rts == NULL) {
                        splx(s);
                        splx(s);
                        return;
                        return;
                }
                }
                for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
                for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
                        LIST_INIT(&sc->sc_rts[i]);
                        LIST_INIT(&sc->sc_rts[i]);
                }
                }
        }
        }
        ifp->if_flags |= IFF_RUNNING;
        ifp->if_flags |= IFF_RUNNING;
        splx(s);
        splx(s);
 
 
        if (sc->sc_brttimeout != 0)
        if (sc->sc_brttimeout != 0)
                timeout(bridge_rtage, sc, sc->sc_brttimeout);
                timeout(bridge_rtage, sc, sc->sc_brttimeout);
}
}
 
 
/*
/*
 * Stop the bridge and deallocate the routing table.
 * Stop the bridge and deallocate the routing table.
 */
 */
void
void
bridge_stop(sc)
bridge_stop(sc)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
{
{
        struct ifnet *ifp = &sc->sc_if;
        struct ifnet *ifp = &sc->sc_if;
 
 
        /*
        /*
         * If we're not running, there's nothing to do.
         * If we're not running, there's nothing to do.
         */
         */
        if ((ifp->if_flags & IFF_RUNNING) == 0)
        if ((ifp->if_flags & IFF_RUNNING) == 0)
                return;
                return;
 
 
        untimeout(bridge_rtage, sc);
        untimeout(bridge_rtage, sc);
 
 
        bridge_rtflush(sc, IFBF_FLUSHDYN);
        bridge_rtflush(sc, IFBF_FLUSHDYN);
 
 
        ifp->if_flags &= ~IFF_RUNNING;
        ifp->if_flags &= ~IFF_RUNNING;
}
}
 
 
/*
/*
 * Send output from the bridge.  The mbuf has the ethernet header
 * Send output from the bridge.  The mbuf has the ethernet header
 * already attached.  We must enqueue or free the mbuf before exiting.
 * already attached.  We must enqueue or free the mbuf before exiting.
 */
 */
int
int
bridge_output(ifp, m, sa, rt)
bridge_output(ifp, m, sa, rt)
        struct ifnet *ifp;
        struct ifnet *ifp;
        struct mbuf *m;
        struct mbuf *m;
        struct sockaddr *sa;
        struct sockaddr *sa;
        struct rtentry *rt;
        struct rtentry *rt;
{
{
        struct ether_header *eh;
        struct ether_header *eh;
        struct ifnet *dst_if;
        struct ifnet *dst_if;
        struct ether_addr *src, *dst;
        struct ether_addr *src, *dst;
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        int s;
        int s;
 
 
        if (m->m_len < sizeof(*eh)) {
        if (m->m_len < sizeof(*eh)) {
                m = m_pullup(m, sizeof(*eh));
                m = m_pullup(m, sizeof(*eh));
                if (m == NULL)
                if (m == NULL)
                        return (0);
                        return (0);
        }
        }
        eh = mtod(m, struct ether_header *);
        eh = mtod(m, struct ether_header *);
        dst = (struct ether_addr *)&eh->ether_dhost[0];
        dst = (struct ether_addr *)&eh->ether_dhost[0];
        src = (struct ether_addr *)&eh->ether_shost[0];
        src = (struct ether_addr *)&eh->ether_shost[0];
        sc = (struct bridge_softc *)ifp->if_bridge;
        sc = (struct bridge_softc *)ifp->if_bridge;
 
 
        s = splimp();
        s = splimp();
 
 
        /*
        /*
         * If bridge is down, but original output interface is up,
         * If bridge is down, but original output interface is up,
         * go ahead and send out that interface.  Otherwise the packet
         * go ahead and send out that interface.  Otherwise the packet
         * is dropped below.
         * is dropped below.
         */
         */
        if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
        if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
                dst_if = ifp;
                dst_if = ifp;
                goto sendunicast;
                goto sendunicast;
        }
        }
 
 
        /*
        /*
         * If the packet is a broadcast or we don't know a better way to
         * If the packet is a broadcast or we don't know a better way to
         * get there, send to all interfaces.
         * get there, send to all interfaces.
         */
         */
        dst_if = bridge_rtlookup(sc, dst);
        dst_if = bridge_rtlookup(sc, dst);
        if (dst_if == NULL || eh->ether_dhost[0] & 1) {
        if (dst_if == NULL || eh->ether_dhost[0] & 1) {
                struct bridge_iflist *p;
                struct bridge_iflist *p;
                struct mbuf *mc;
                struct mbuf *mc;
                int used = 0;
                int used = 0;
 
 
                for (p = LIST_FIRST(&sc->sc_iflist); p != NULL;
                for (p = LIST_FIRST(&sc->sc_iflist); p != NULL;
                     p = LIST_NEXT(p, next)) {
                     p = LIST_NEXT(p, next)) {
                        if ((p->ifp->if_flags & IFF_RUNNING) == 0)
                        if ((p->ifp->if_flags & IFF_RUNNING) == 0)
                                continue;
                                continue;
                        if (IF_QFULL(&p->ifp->if_snd)) {
                        if (IF_QFULL(&p->ifp->if_snd)) {
                                sc->sc_if.if_oerrors++;
                                sc->sc_if.if_oerrors++;
                                continue;
                                continue;
                        }
                        }
 
 
                        if (LIST_NEXT(p, next) == NULL) {
                        if (LIST_NEXT(p, next) == NULL) {
                                used = 1;
                                used = 1;
                                mc = m;
                                mc = m;
                        } else {
                        } else {
                                mc = m_copym(m, 0, M_COPYALL, M_NOWAIT);
                                mc = m_copym(m, 0, M_COPYALL, M_NOWAIT);
                                if (mc == NULL) {
                                if (mc == NULL) {
                                        sc->sc_if.if_oerrors++;
                                        sc->sc_if.if_oerrors++;
                                        continue;
                                        continue;
                                }
                                }
                        }
                        }
 
 
                        sc->sc_if.if_opackets++;
                        sc->sc_if.if_opackets++;
                        sc->sc_if.if_obytes += m->m_pkthdr.len;
                        sc->sc_if.if_obytes += m->m_pkthdr.len;
                        // Also count the bytes in the outgoing interface; normally
                        // Also count the bytes in the outgoing interface; normally
                        // done in if_ethersubr.c but here we bypass that route.
                        // done in if_ethersubr.c but here we bypass that route.
                        p->ifp->if_obytes += m->m_pkthdr.len;
                        p->ifp->if_obytes += m->m_pkthdr.len;
                        IF_ENQUEUE(&p->ifp->if_snd, mc);
                        IF_ENQUEUE(&p->ifp->if_snd, mc);
                        if ((p->ifp->if_flags & IFF_OACTIVE) == 0)
                        if ((p->ifp->if_flags & IFF_OACTIVE) == 0)
                                (*p->ifp->if_start)(p->ifp);
                                (*p->ifp->if_start)(p->ifp);
                }
                }
                if (!used)
                if (!used)
                        m_freem(m);
                        m_freem(m);
                splx(s);
                splx(s);
                return (0);
                return (0);
        }
        }
 
 
sendunicast:
sendunicast:
        if ((dst_if->if_flags & IFF_RUNNING) == 0) {
        if ((dst_if->if_flags & IFF_RUNNING) == 0) {
                m_freem(m);
                m_freem(m);
                splx(s);
                splx(s);
                return (0);
                return (0);
        }
        }
        if (IF_QFULL(&dst_if->if_snd)) {
        if (IF_QFULL(&dst_if->if_snd)) {
                sc->sc_if.if_oerrors++;
                sc->sc_if.if_oerrors++;
                m_freem(m);
                m_freem(m);
                splx(s);
                splx(s);
                return (0);
                return (0);
        }
        }
        sc->sc_if.if_opackets++;
        sc->sc_if.if_opackets++;
        sc->sc_if.if_obytes += m->m_pkthdr.len;
        sc->sc_if.if_obytes += m->m_pkthdr.len;
        // Also count the bytes in the outgoing interface; normally
        // Also count the bytes in the outgoing interface; normally
        // done in if_ethersubr.c but here we bypass that route.
        // done in if_ethersubr.c but here we bypass that route.
        dst_if->if_obytes += m->m_pkthdr.len;
        dst_if->if_obytes += m->m_pkthdr.len;
        IF_ENQUEUE(&dst_if->if_snd, m);
        IF_ENQUEUE(&dst_if->if_snd, m);
        if ((dst_if->if_flags & IFF_OACTIVE) == 0)
        if ((dst_if->if_flags & IFF_OACTIVE) == 0)
                (*dst_if->if_start)(dst_if);
                (*dst_if->if_start)(dst_if);
        splx(s);
        splx(s);
        return (0);
        return (0);
}
}
 
 
/*
/*
 * Start output on the bridge.  This function should never be called.
 * Start output on the bridge.  This function should never be called.
 */
 */
void
void
bridge_start(ifp)
bridge_start(ifp)
        struct ifnet *ifp;
        struct ifnet *ifp;
{
{
}
}
 
 
void
void
bridgeintr(void)
bridgeintr(void)
{
{
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        struct mbuf *m;
        struct mbuf *m;
        int i, s;
        int i, s;
 
 
        for (i = 0; i < CYGNUM_NET_BRIDGES; i++) {
        for (i = 0; i < CYGNUM_NET_BRIDGES; i++) {
                sc = &bridgectl[i];
                sc = &bridgectl[i];
                for (;;) {
                for (;;) {
                        s = splimp();
                        s = splimp();
                        IF_DEQUEUE(&sc->sc_if.if_snd, m);
                        IF_DEQUEUE(&sc->sc_if.if_snd, m);
                        splx(s);
                        splx(s);
                        if (m == NULL)
                        if (m == NULL)
                                break;
                                break;
                        bridgeintr_frame(sc, m);
                        bridgeintr_frame(sc, m);
                }
                }
        }
        }
}
}
 
 
/*
/*
 * Loop through each bridge interface and process their input queues.
 * Loop through each bridge interface and process their input queues.
 */
 */
void
void
bridgeintr_frame(sc, m)
bridgeintr_frame(sc, m)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        struct mbuf *m;
        struct mbuf *m;
{
{
        int s;
        int s;
        struct ifnet *src_if, *dst_if;
        struct ifnet *src_if, *dst_if;
        struct bridge_iflist *ifl;
        struct bridge_iflist *ifl;
        struct ether_addr *dst, *src;
        struct ether_addr *dst, *src;
        struct ether_header eh;
        struct ether_header eh;
 
 
        if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
        if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
                m_freem(m);
                m_freem(m);
                return;
                return;
        }
        }
 
 
        src_if = m->m_pkthdr.rcvif;
        src_if = m->m_pkthdr.rcvif;
 
 
#if NBPFILTER > 0
#if NBPFILTER > 0
        if (sc->sc_if.if_bpf)
        if (sc->sc_if.if_bpf)
                bpf_mtap(sc->sc_if.if_bpf, m);
                bpf_mtap(sc->sc_if.if_bpf, m);
#endif
#endif
 
 
        sc->sc_if.if_lastchange = time;
        sc->sc_if.if_lastchange = time;
        sc->sc_if.if_ipackets++;
        sc->sc_if.if_ipackets++;
        sc->sc_if.if_ibytes += m->m_pkthdr.len;
        sc->sc_if.if_ibytes += m->m_pkthdr.len;
 
 
        ifl = LIST_FIRST(&sc->sc_iflist);
        ifl = LIST_FIRST(&sc->sc_iflist);
        while (ifl != NULL && ifl->ifp != src_if) {
        while (ifl != NULL && ifl->ifp != src_if) {
                ifl = LIST_NEXT(ifl, next);
                ifl = LIST_NEXT(ifl, next);
        }
        }
        if (ifl == NULL) {
        if (ifl == NULL) {
                m_freem(m);
                m_freem(m);
                return;
                return;
        }
        }
 
 
        if (m->m_pkthdr.len < sizeof(eh)) {
        if (m->m_pkthdr.len < sizeof(eh)) {
                m_freem(m);
                m_freem(m);
                return;
                return;
        }
        }
        m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&eh);
        m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&eh);
        dst = (struct ether_addr *)&eh.ether_dhost[0];
        dst = (struct ether_addr *)&eh.ether_dhost[0];
        src = (struct ether_addr *)&eh.ether_shost[0];
        src = (struct ether_addr *)&eh.ether_shost[0];
 
 
        /*
        /*
         * If interface is learning, and if source address
         * If interface is learning, and if source address
         * is not broadcast or multicast, record it's address.
         * is not broadcast or multicast, record it's address.
         */
         */
        if ((ifl->bif_flags & IFBIF_LEARNING) &&
        if ((ifl->bif_flags & IFBIF_LEARNING) &&
            (eh.ether_shost[0] & 1) == 0 &&
            (eh.ether_shost[0] & 1) == 0 &&
            !(eh.ether_shost[0] == 0 &&
            !(eh.ether_shost[0] == 0 &&
              eh.ether_shost[1] == 0 &&
              eh.ether_shost[1] == 0 &&
              eh.ether_shost[2] == 0 &&
              eh.ether_shost[2] == 0 &&
              eh.ether_shost[3] == 0 &&
              eh.ether_shost[3] == 0 &&
              eh.ether_shost[4] == 0 &&
              eh.ether_shost[4] == 0 &&
              eh.ether_shost[5] == 0))
              eh.ether_shost[5] == 0))
                bridge_rtupdate(sc, src, src_if, 0, IFBAF_DYNAMIC);
                bridge_rtupdate(sc, src, src_if, 0, IFBAF_DYNAMIC);
 
 
        /*
        /*
         * If packet is unicast, destined for someone on "this"
         * If packet is unicast, destined for someone on "this"
         * side of the bridge, drop it.
         * side of the bridge, drop it.
         */
         */
        if ((m->m_flags & (M_BCAST | M_MCAST)) == 0) {
        if ((m->m_flags & (M_BCAST | M_MCAST)) == 0) {
                dst_if = bridge_rtlookup(sc, dst);
                dst_if = bridge_rtlookup(sc, dst);
                if (dst_if == src_if) {
                if (dst_if == src_if) {
                        m_freem(m);
                        m_freem(m);
                        return;
                        return;
                }
                }
        } else
        } else
                dst_if = NULL;
                dst_if = NULL;
 
 
        /*
        /*
         * Multicast packets get handled a little differently:
         * Multicast packets get handled a little differently:
         * If interface is:
         * If interface is:
         *      -link0,-link1   (default) Forward all multicast
         *      -link0,-link1   (default) Forward all multicast
         *                      as broadcast.
         *                      as broadcast.
         *      -link0,link1    Drop non-IP multicast, forward
         *      -link0,link1    Drop non-IP multicast, forward
         *                      as broadcast IP multicast.
         *                      as broadcast IP multicast.
         *      link0,-link1    Drop IP multicast, forward as
         *      link0,-link1    Drop IP multicast, forward as
         *                      broadcast non-IP multicast.
         *                      broadcast non-IP multicast.
         *      link0,link1     Drop all multicast.
         *      link0,link1     Drop all multicast.
         */
         */
        if (m->m_flags & M_MCAST) {
        if (m->m_flags & M_MCAST) {
                if ((sc->sc_if.if_flags &
                if ((sc->sc_if.if_flags &
                    (IFF_LINK0 | IFF_LINK1)) ==
                    (IFF_LINK0 | IFF_LINK1)) ==
                    (IFF_LINK0 | IFF_LINK1)) {
                    (IFF_LINK0 | IFF_LINK1)) {
                        m_freem(m);
                        m_freem(m);
                        return;
                        return;
                }
                }
                if (sc->sc_if.if_flags & IFF_LINK0 &&
                if (sc->sc_if.if_flags & IFF_LINK0 &&
                    ETHERADDR_IS_IP_MCAST(dst)) {
                    ETHERADDR_IS_IP_MCAST(dst)) {
                        m_freem(m);
                        m_freem(m);
                        return;
                        return;
                }
                }
                if (sc->sc_if.if_flags & IFF_LINK1 &&
                if (sc->sc_if.if_flags & IFF_LINK1 &&
                    !ETHERADDR_IS_IP_MCAST(dst)) {
                    !ETHERADDR_IS_IP_MCAST(dst)) {
                        m_freem(m);
                        m_freem(m);
                        return;
                        return;
                }
                }
        }
        }
 
 
        if (ifl->bif_flags & IFBIF_BLOCKNONIP && bridge_blocknonip(&eh, m)) {
        if (ifl->bif_flags & IFBIF_BLOCKNONIP && bridge_blocknonip(&eh, m)) {
                m_freem(m);
                m_freem(m);
                return;
                return;
        }
        }
 
 
        if (SIMPLEQ_FIRST(&ifl->bif_brlin) &&
        if (SIMPLEQ_FIRST(&ifl->bif_brlin) &&
            bridge_filterrule(SIMPLEQ_FIRST(&ifl->bif_brlin), &eh) ==
            bridge_filterrule(SIMPLEQ_FIRST(&ifl->bif_brlin), &eh) ==
            BRL_ACTION_BLOCK) {
            BRL_ACTION_BLOCK) {
                m_freem(m);
                m_freem(m);
                return;
                return;
        }
        }
 
 
#if defined(INET) && (defined(IPFILTER) || defined(IPFILTER_LKM))
#if defined(INET) && (defined(IPFILTER) || defined(IPFILTER_LKM))
        m = bridge_filter(sc, src_if, &eh, m);
        m = bridge_filter(sc, src_if, &eh, m);
        if (m == NULL)
        if (m == NULL)
                return;
                return;
#endif
#endif
 
 
        /*
        /*
         * If the packet is a multicast or broadcast OR if we don't
         * If the packet is a multicast or broadcast OR if we don't
         * know any better, forward it to all interfaces.
         * know any better, forward it to all interfaces.
         */
         */
        if ((m->m_flags & (M_BCAST | M_MCAST)) || dst_if == NULL) {
        if ((m->m_flags & (M_BCAST | M_MCAST)) || dst_if == NULL) {
                sc->sc_if.if_imcasts++;
                sc->sc_if.if_imcasts++;
                s = splimp();
                s = splimp();
                bridge_broadcast(sc, src_if, &eh, m);
                bridge_broadcast(sc, src_if, &eh, m);
                splx(s);
                splx(s);
                return;
                return;
        }
        }
 
 
        /*
        /*
         * At this point, we're dealing with a unicast frame going to a
         * At this point, we're dealing with a unicast frame going to a
         * different interface
         * different interface
         */
         */
        if ((dst_if->if_flags & IFF_RUNNING) == 0) {
        if ((dst_if->if_flags & IFF_RUNNING) == 0) {
                m_freem(m);
                m_freem(m);
                return;
                return;
        }
        }
        ifl = LIST_FIRST(&sc->sc_iflist);
        ifl = LIST_FIRST(&sc->sc_iflist);
        while (ifl != NULL && ifl->ifp != dst_if)
        while (ifl != NULL && ifl->ifp != dst_if)
                ifl = LIST_NEXT(ifl, next);
                ifl = LIST_NEXT(ifl, next);
        if (SIMPLEQ_FIRST(&ifl->bif_brlout) &&
        if (SIMPLEQ_FIRST(&ifl->bif_brlout) &&
            bridge_filterrule(SIMPLEQ_FIRST(&ifl->bif_brlout), &eh) ==
            bridge_filterrule(SIMPLEQ_FIRST(&ifl->bif_brlout), &eh) ==
            BRL_ACTION_BLOCK) {
            BRL_ACTION_BLOCK) {
                m_freem(m);
                m_freem(m);
                return;
                return;
        }
        }
        s = splimp();
        s = splimp();
        if (IF_QFULL(&dst_if->if_snd)) {
        if (IF_QFULL(&dst_if->if_snd)) {
                sc->sc_if.if_oerrors++;
                sc->sc_if.if_oerrors++;
                m_freem(m);
                m_freem(m);
                splx(s);
                splx(s);
                return;
                return;
        }
        }
        sc->sc_if.if_opackets++;
        sc->sc_if.if_opackets++;
        sc->sc_if.if_obytes += m->m_pkthdr.len;
        sc->sc_if.if_obytes += m->m_pkthdr.len;
        // Also count the bytes in the outgoing interface; normally
        // Also count the bytes in the outgoing interface; normally
        // done in if_ethersubr.c but here we bypass that route.
        // done in if_ethersubr.c but here we bypass that route.
        dst_if->if_obytes += m->m_pkthdr.len;
        dst_if->if_obytes += m->m_pkthdr.len;
        IF_ENQUEUE(&dst_if->if_snd, m);
        IF_ENQUEUE(&dst_if->if_snd, m);
        if ((dst_if->if_flags & IFF_OACTIVE) == 0)
        if ((dst_if->if_flags & IFF_OACTIVE) == 0)
                (*dst_if->if_start)(dst_if);
                (*dst_if->if_start)(dst_if);
        splx(s);
        splx(s);
}
}
 
 
/*
/*
 * Receive input from an interface.  Queue the packet for bridging if its
 * Receive input from an interface.  Queue the packet for bridging if its
 * not for us, and schedule an interrupt.
 * not for us, and schedule an interrupt.
 */
 */
struct mbuf *
struct mbuf *
bridge_input(ifp, eh, m)
bridge_input(ifp, eh, m)
        struct ifnet *ifp;
        struct ifnet *ifp;
        struct ether_header *eh;
        struct ether_header *eh;
        struct mbuf *m;
        struct mbuf *m;
{
{
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        int s;
        int s;
        struct bridge_iflist *ifl;
        struct bridge_iflist *ifl;
        struct arpcom *ac;
        struct arpcom *ac;
        struct mbuf *mc;
        struct mbuf *mc;
 
 
        /*
        /*
         * Make sure this interface is a bridge member.
         * Make sure this interface is a bridge member.
         */
         */
        if (ifp == NULL || ifp->if_bridge == NULL || m == NULL)
        if (ifp == NULL || ifp->if_bridge == NULL || m == NULL)
                return (m);
                return (m);
 
 
        if ((m->m_flags & M_PKTHDR) == 0)
        if ((m->m_flags & M_PKTHDR) == 0)
                panic("bridge_input(): no HDR");
                panic("bridge_input(): no HDR");
 
 
        sc = (struct bridge_softc *)ifp->if_bridge;
        sc = (struct bridge_softc *)ifp->if_bridge;
        if ((sc->sc_if.if_flags & IFF_RUNNING) == 0)
        if ((sc->sc_if.if_flags & IFF_RUNNING) == 0)
                return (m);
                return (m);
 
 
        if (m->m_flags & (M_BCAST | M_MCAST)) {
        if (m->m_flags & (M_BCAST | M_MCAST)) {
                /*
                /*
                 * make a copy of 'm' with 'eh' tacked on to the
                 * make a copy of 'm' with 'eh' tacked on to the
                 * beginning.  Return 'm' for local processing
                 * beginning.  Return 'm' for local processing
                 * and enqueue the copy.  Schedule netisr.
                 * and enqueue the copy.  Schedule netisr.
                 */
                 */
                mc = m_copym2(m, 0, M_COPYALL, M_NOWAIT);
                mc = m_copym2(m, 0, M_COPYALL, M_NOWAIT);
                if (mc == NULL)
                if (mc == NULL)
                        return (m);
                        return (m);
                M_PREPEND(mc, sizeof(struct ether_header), M_DONTWAIT);
                M_PREPEND(mc, sizeof(struct ether_header), M_DONTWAIT);
                if (mc == NULL)
                if (mc == NULL)
                        return (m);
                        return (m);
                bcopy(eh, mtod(mc, caddr_t), sizeof(struct ether_header));
                bcopy(eh, mtod(mc, caddr_t), sizeof(struct ether_header));
                s = splimp();
                s = splimp();
                if (IF_QFULL(&sc->sc_if.if_snd)) {
                if (IF_QFULL(&sc->sc_if.if_snd)) {
                        m_freem(mc);
                        m_freem(mc);
                        splx(s);
                        splx(s);
                        return (m);
                        return (m);
                }
                }
                IF_ENQUEUE(&sc->sc_if.if_snd, mc);
                IF_ENQUEUE(&sc->sc_if.if_snd, mc);
                splx(s);
                splx(s);
                schednetisr(NETISR_BRIDGE);
                schednetisr(NETISR_BRIDGE);
                return (m);
                return (m);
        }
        }
 
 
        /*
        /*
         * Unicast, make sure it's not for us.
         * Unicast, make sure it's not for us.
         */
         */
        for (ifl = LIST_FIRST(&sc->sc_iflist);ifl; ifl = LIST_NEXT(ifl,next)) {
        for (ifl = LIST_FIRST(&sc->sc_iflist);ifl; ifl = LIST_NEXT(ifl,next)) {
                if (ifl->ifp->if_type != IFT_ETHER)
                if (ifl->ifp->if_type != IFT_ETHER)
                        continue;
                        continue;
                ac = (struct arpcom *)ifl->ifp;
                ac = (struct arpcom *)ifl->ifp;
                if (bcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN) == 0) {
                if (bcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN) == 0) {
                        if (ifl->bif_flags & IFBIF_LEARNING)
                        if (ifl->bif_flags & IFBIF_LEARNING)
                                bridge_rtupdate(sc,
                                bridge_rtupdate(sc,
                                    (struct ether_addr *)&eh->ether_shost,
                                    (struct ether_addr *)&eh->ether_shost,
                                    ifp, 0, IFBAF_DYNAMIC);
                                    ifp, 0, IFBAF_DYNAMIC);
                        m->m_pkthdr.rcvif = ifl->ifp;
                        m->m_pkthdr.rcvif = ifl->ifp;
                        return (m);
                        return (m);
                }
                }
                if (bcmp(ac->ac_enaddr, eh->ether_shost, ETHER_ADDR_LEN) == 0) {
                if (bcmp(ac->ac_enaddr, eh->ether_shost, ETHER_ADDR_LEN) == 0) {
                        m_freem(m);
                        m_freem(m);
                        return (NULL);
                        return (NULL);
                }
                }
        }
        }
        M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT);
        M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT);
        if (m == NULL)
        if (m == NULL)
                return (NULL);
                return (NULL);
        bcopy(eh, mtod(m, caddr_t), sizeof(struct ether_header));
        bcopy(eh, mtod(m, caddr_t), sizeof(struct ether_header));
        s = splimp();
        s = splimp();
        if (IF_QFULL(&sc->sc_if.if_snd)) {
        if (IF_QFULL(&sc->sc_if.if_snd)) {
                m_freem(m);
                m_freem(m);
                splx(s);
                splx(s);
                return (NULL);
                return (NULL);
        }
        }
        IF_ENQUEUE(&sc->sc_if.if_snd, m);
        IF_ENQUEUE(&sc->sc_if.if_snd, m);
        splx(s);
        splx(s);
        schednetisr(NETISR_BRIDGE);
        schednetisr(NETISR_BRIDGE);
        return (NULL);
        return (NULL);
}
}
 
 
/*
/*
 * Send a frame to all interfaces that are members of the bridge
 * Send a frame to all interfaces that are members of the bridge
 * (except the one it came in on).  This code assumes that it is
 * (except the one it came in on).  This code assumes that it is
 * running at splnet or higher.
 * running at splnet or higher.
 */
 */
void
void
bridge_broadcast(sc, ifp, eh, m)
bridge_broadcast(sc, ifp, eh, m)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        struct ifnet *ifp;
        struct ifnet *ifp;
        struct ether_header *eh;
        struct ether_header *eh;
        struct mbuf *m;
        struct mbuf *m;
{
{
        struct bridge_iflist *p;
        struct bridge_iflist *p;
        struct mbuf *mc;
        struct mbuf *mc;
        int used = 0;
        int used = 0;
 
 
        for (p = LIST_FIRST(&sc->sc_iflist); p; p = LIST_NEXT(p, next)) {
        for (p = LIST_FIRST(&sc->sc_iflist); p; p = LIST_NEXT(p, next)) {
                /*
                /*
                 * Don't retransmit out of the same interface where
                 * Don't retransmit out of the same interface where
                 * the packet was received from.
                 * the packet was received from.
                 */
                 */
                if (p->ifp->if_index == ifp->if_index)
                if (p->ifp->if_index == ifp->if_index)
                        continue;
                        continue;
 
 
                if ((p->bif_flags & IFBIF_DISCOVER) == 0 &&
                if ((p->bif_flags & IFBIF_DISCOVER) == 0 &&
                    (m->m_flags & (M_BCAST | M_MCAST)) == 0)
                    (m->m_flags & (M_BCAST | M_MCAST)) == 0)
                        continue;
                        continue;
 
 
                if ((p->ifp->if_flags & IFF_RUNNING) == 0)
                if ((p->ifp->if_flags & IFF_RUNNING) == 0)
                        continue;
                        continue;
 
 
                if (IF_QFULL(&p->ifp->if_snd)) {
                if (IF_QFULL(&p->ifp->if_snd)) {
                        sc->sc_if.if_oerrors++;
                        sc->sc_if.if_oerrors++;
                        continue;
                        continue;
                }
                }
 
 
                if (SIMPLEQ_FIRST(&p->bif_brlout) &&
                if (SIMPLEQ_FIRST(&p->bif_brlout) &&
                    bridge_filterrule(SIMPLEQ_FIRST(&p->bif_brlout), eh) ==
                    bridge_filterrule(SIMPLEQ_FIRST(&p->bif_brlout), eh) ==
                    BRL_ACTION_BLOCK)
                    BRL_ACTION_BLOCK)
                        continue;
                        continue;
 
 
                /* If last one, reuse the passed-in mbuf */
                /* If last one, reuse the passed-in mbuf */
                if (LIST_NEXT(p, next) == NULL) {
                if (LIST_NEXT(p, next) == NULL) {
                        mc = m;
                        mc = m;
                        used = 1;
                        used = 1;
                } else {
                } else {
                        mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
                        mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
                        if (mc == NULL) {
                        if (mc == NULL) {
                                sc->sc_if.if_oerrors++;
                                sc->sc_if.if_oerrors++;
                                continue;
                                continue;
                        }
                        }
                }
                }
 
 
                if (p->bif_flags & IFBIF_BLOCKNONIP &&
                if (p->bif_flags & IFBIF_BLOCKNONIP &&
                    bridge_blocknonip(eh, mc)) {
                    bridge_blocknonip(eh, mc)) {
                        m_freem(mc);
                        m_freem(mc);
                        continue;
                        continue;
                }
                }
 
 
                sc->sc_if.if_opackets++;
                sc->sc_if.if_opackets++;
                sc->sc_if.if_obytes += mc->m_pkthdr.len;
                sc->sc_if.if_obytes += mc->m_pkthdr.len;
                if (ifp && ((eh->ether_shost[0] & 1) == 0) )
                if (ifp && ((eh->ether_shost[0] & 1) == 0) )
                        ifp->if_omcasts++;
                        ifp->if_omcasts++;
                // Also count the bytes in the outgoing interface; normally
                // Also count the bytes in the outgoing interface; normally
                // done in if_ethersubr.c but here we bypass that route.
                // done in if_ethersubr.c but here we bypass that route.
                p->ifp->if_obytes += m->m_pkthdr.len;
                p->ifp->if_obytes += m->m_pkthdr.len;
                IF_ENQUEUE(&p->ifp->if_snd, mc);
                IF_ENQUEUE(&p->ifp->if_snd, mc);
                if ((p->ifp->if_flags & IFF_OACTIVE) == 0)
                if ((p->ifp->if_flags & IFF_OACTIVE) == 0)
                        (*p->ifp->if_start)(p->ifp);
                        (*p->ifp->if_start)(p->ifp);
        }
        }
 
 
        if (!used)
        if (!used)
                m_freem(m);
                m_freem(m);
}
}
 
 
struct ifnet *
struct ifnet *
bridge_rtupdate(sc, ea, ifp, setflags, flags)
bridge_rtupdate(sc, ea, ifp, setflags, flags)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        struct ether_addr *ea;
        struct ether_addr *ea;
        struct ifnet *ifp;
        struct ifnet *ifp;
        int setflags;
        int setflags;
        u_int8_t flags;
        u_int8_t flags;
{
{
        struct bridge_rtnode *p, *q;
        struct bridge_rtnode *p, *q;
        u_int32_t h;
        u_int32_t h;
        int s, dir;
        int s, dir;
 
 
        s = splhigh();
        s = splhigh();
        if (sc->sc_rts == NULL) {
        if (sc->sc_rts == NULL) {
                if (setflags && flags == IFBAF_STATIC) {
                if (setflags && flags == IFBAF_STATIC) {
                        sc->sc_rts = (struct bridge_rthead *)malloc(
                        sc->sc_rts = (struct bridge_rthead *)malloc(
                            BRIDGE_RTABLE_SIZE *
                            BRIDGE_RTABLE_SIZE *
                            (sizeof(struct bridge_rthead)),M_DEVBUF,M_NOWAIT);
                            (sizeof(struct bridge_rthead)),M_DEVBUF,M_NOWAIT);
 
 
                        if (sc->sc_rts == NULL)
                        if (sc->sc_rts == NULL)
                                goto done;
                                goto done;
 
 
                        for (h = 0; h < BRIDGE_RTABLE_SIZE; h++)
                        for (h = 0; h < BRIDGE_RTABLE_SIZE; h++)
                                LIST_INIT(&sc->sc_rts[h]);
                                LIST_INIT(&sc->sc_rts[h]);
                } else
                } else
                        goto done;
                        goto done;
        }
        }
 
 
        h = bridge_hash(ea);
        h = bridge_hash(ea);
        p = LIST_FIRST(&sc->sc_rts[h]);
        p = LIST_FIRST(&sc->sc_rts[h]);
        if (p == NULL) {
        if (p == NULL) {
                if (sc->sc_brtcnt >= sc->sc_brtmax)
                if (sc->sc_brtcnt >= sc->sc_brtmax)
                        goto done;
                        goto done;
                p = (struct bridge_rtnode *)malloc(
                p = (struct bridge_rtnode *)malloc(
                    sizeof(struct bridge_rtnode), M_DEVBUF, M_NOWAIT);
                    sizeof(struct bridge_rtnode), M_DEVBUF, M_NOWAIT);
                if (p == NULL)
                if (p == NULL)
                        goto done;
                        goto done;
 
 
                bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
                bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
                p->brt_if = ifp;
                p->brt_if = ifp;
                p->brt_age = 1;
                p->brt_age = 1;
 
 
                if (setflags)
                if (setflags)
                        p->brt_flags = flags;
                        p->brt_flags = flags;
                else
                else
                        p->brt_flags = IFBAF_DYNAMIC;
                        p->brt_flags = IFBAF_DYNAMIC;
 
 
                LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next);
                LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next);
                sc->sc_brtcnt++;
                sc->sc_brtcnt++;
                goto want;
                goto want;
        }
        }
 
 
        do {
        do {
                q = p;
                q = p;
                p = LIST_NEXT(p, brt_next);
                p = LIST_NEXT(p, brt_next);
 
 
                dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
                dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
                if (dir == 0) {
                if (dir == 0) {
                        if (setflags) {
                        if (setflags) {
                                q->brt_if = ifp;
                                q->brt_if = ifp;
                                q->brt_flags = flags;
                                q->brt_flags = flags;
                        }
                        }
 
 
                        if (q->brt_if == ifp)
                        if (q->brt_if == ifp)
                                q->brt_age = 1;
                                q->brt_age = 1;
                        ifp = q->brt_if;
                        ifp = q->brt_if;
                        goto want;
                        goto want;
                }
                }
 
 
                if (dir > 0) {
                if (dir > 0) {
                        if (sc->sc_brtcnt >= sc->sc_brtmax)
                        if (sc->sc_brtcnt >= sc->sc_brtmax)
                                goto done;
                                goto done;
                        p = (struct bridge_rtnode *)malloc(
                        p = (struct bridge_rtnode *)malloc(
                            sizeof(struct bridge_rtnode), M_DEVBUF, M_NOWAIT);
                            sizeof(struct bridge_rtnode), M_DEVBUF, M_NOWAIT);
                        if (p == NULL)
                        if (p == NULL)
                                goto done;
                                goto done;
 
 
                        bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
                        bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
                        p->brt_if = ifp;
                        p->brt_if = ifp;
                        p->brt_age = 1;
                        p->brt_age = 1;
 
 
                        if (setflags)
                        if (setflags)
                                p->brt_flags = flags;
                                p->brt_flags = flags;
                        else
                        else
                                p->brt_flags = IFBAF_DYNAMIC;
                                p->brt_flags = IFBAF_DYNAMIC;
 
 
                        LIST_INSERT_BEFORE(q, p, brt_next);
                        LIST_INSERT_BEFORE(q, p, brt_next);
                        sc->sc_brtcnt++;
                        sc->sc_brtcnt++;
                        goto want;
                        goto want;
                }
                }
 
 
                if (p == NULL) {
                if (p == NULL) {
                        if (sc->sc_brtcnt >= sc->sc_brtmax)
                        if (sc->sc_brtcnt >= sc->sc_brtmax)
                                goto done;
                                goto done;
                        p = (struct bridge_rtnode *)malloc(
                        p = (struct bridge_rtnode *)malloc(
                            sizeof(struct bridge_rtnode), M_DEVBUF, M_NOWAIT);
                            sizeof(struct bridge_rtnode), M_DEVBUF, M_NOWAIT);
                        if (p == NULL)
                        if (p == NULL)
                                goto done;
                                goto done;
 
 
                        bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
                        bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
                        p->brt_if = ifp;
                        p->brt_if = ifp;
                        p->brt_age = 1;
                        p->brt_age = 1;
 
 
                        if (setflags)
                        if (setflags)
                                p->brt_flags = flags;
                                p->brt_flags = flags;
                        else
                        else
                                p->brt_flags = IFBAF_DYNAMIC;
                                p->brt_flags = IFBAF_DYNAMIC;
                        LIST_INSERT_AFTER(q, p, brt_next);
                        LIST_INSERT_AFTER(q, p, brt_next);
                        sc->sc_brtcnt++;
                        sc->sc_brtcnt++;
                        goto want;
                        goto want;
                }
                }
        } while (p != NULL);
        } while (p != NULL);
 
 
done:
done:
        ifp = NULL;
        ifp = NULL;
want:
want:
        splx(s);
        splx(s);
        return (ifp);
        return (ifp);
}
}
 
 
struct ifnet *
struct ifnet *
bridge_rtlookup(sc, ea)
bridge_rtlookup(sc, ea)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        struct ether_addr *ea;
        struct ether_addr *ea;
{
{
        struct bridge_rtnode *p;
        struct bridge_rtnode *p;
        u_int32_t h;
        u_int32_t h;
        int s, dir;
        int s, dir;
 
 
        /*
        /*
         * Lock out everything else
         * Lock out everything else
         */
         */
        s = splhigh();
        s = splhigh();
 
 
        if (sc->sc_rts == NULL)
        if (sc->sc_rts == NULL)
                goto fail;
                goto fail;
 
 
        h = bridge_hash(ea);
        h = bridge_hash(ea);
        p = LIST_FIRST(&sc->sc_rts[h]);
        p = LIST_FIRST(&sc->sc_rts[h]);
        while (p != NULL) {
        while (p != NULL) {
                dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr));
                dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr));
                if (dir == 0) {
                if (dir == 0) {
                        splx(s);
                        splx(s);
                        return (p->brt_if);
                        return (p->brt_if);
                }
                }
                if (dir > 0)
                if (dir > 0)
                        goto fail;
                        goto fail;
                p = LIST_NEXT(p, brt_next);
                p = LIST_NEXT(p, brt_next);
        }
        }
fail:
fail:
        splx(s);
        splx(s);
        return (NULL);
        return (NULL);
}
}
 
 
/*
/*
 * The following hash function is adapted from 'Hash Functions' by Bob Jenkins
 * The following hash function is adapted from 'Hash Functions' by Bob Jenkins
 * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
 * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
 * "You may use this code any way you wish, private, educational, or
 * "You may use this code any way you wish, private, educational, or
 *  commercial.  It's free."
 *  commercial.  It's free."
 */
 */
#define mix(a,b,c) \
#define mix(a,b,c) \
        do {                                            \
        do {                                            \
                a -= b; a -= c; a ^= (c >> 13);         \
                a -= b; a -= c; a ^= (c >> 13);         \
                b -= c; b -= a; b ^= (a << 8);          \
                b -= c; b -= a; b ^= (a << 8);          \
                c -= a; c -= b; c ^= (b >> 13);         \
                c -= a; c -= b; c ^= (b >> 13);         \
                a -= b; a -= c; a ^= (c >> 12);         \
                a -= b; a -= c; a ^= (c >> 12);         \
                b -= c; b -= a; b ^= (a << 16);         \
                b -= c; b -= a; b ^= (a << 16);         \
                c -= a; c -= b; c ^= (b >> 5);          \
                c -= a; c -= b; c ^= (b >> 5);          \
                a -= b; a -= c; a ^= (c >> 3);          \
                a -= b; a -= c; a ^= (c >> 3);          \
                b -= c; b -= a; b ^= (a << 10);         \
                b -= c; b -= a; b ^= (a << 10);         \
                c -= a; c -= b; c ^= (b >> 15);         \
                c -= a; c -= b; c ^= (b >> 15);         \
        } while(0)
        } while(0)
 
 
u_int32_t
u_int32_t
bridge_hash(addr)
bridge_hash(addr)
        struct ether_addr *addr;
        struct ether_addr *addr;
{
{
        u_int32_t a = 0x9e3779b9, b = 0x9e3779b9, c = 0xdeadbeef;
        u_int32_t a = 0x9e3779b9, b = 0x9e3779b9, c = 0xdeadbeef;
 
 
        b += addr->ether_addr_octet[5] << 8;
        b += addr->ether_addr_octet[5] << 8;
        b += addr->ether_addr_octet[4];
        b += addr->ether_addr_octet[4];
        a += addr->ether_addr_octet[3] << 24;
        a += addr->ether_addr_octet[3] << 24;
        a += addr->ether_addr_octet[2] << 16;
        a += addr->ether_addr_octet[2] << 16;
        a += addr->ether_addr_octet[1] << 8;
        a += addr->ether_addr_octet[1] << 8;
        a += addr->ether_addr_octet[0];
        a += addr->ether_addr_octet[0];
 
 
        mix(a, b, c);
        mix(a, b, c);
        return (c & BRIDGE_RTABLE_MASK);
        return (c & BRIDGE_RTABLE_MASK);
}
}
 
 
/*
/*
 * Trim the routing table so that we've got a number of routes
 * Trim the routing table so that we've got a number of routes
 * less than or equal to the maximum.
 * less than or equal to the maximum.
 */
 */
void
void
bridge_rttrim(sc)
bridge_rttrim(sc)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
{
{
        struct bridge_rtnode *n, *p;
        struct bridge_rtnode *n, *p;
        int s, i;
        int s, i;
 
 
        s = splhigh();
        s = splhigh();
        if (sc->sc_rts == NULL)
        if (sc->sc_rts == NULL)
                goto done;
                goto done;
 
 
        /*
        /*
         * Make sure we have to trim the address table
         * Make sure we have to trim the address table
         */
         */
        if (sc->sc_brtcnt <= sc->sc_brtmax)
        if (sc->sc_brtcnt <= sc->sc_brtmax)
                goto done;
                goto done;
 
 
        /*
        /*
         * Force an aging cycle, this might trim enough addresses.
         * Force an aging cycle, this might trim enough addresses.
         */
         */
        splx(s);
        splx(s);
        bridge_rtage(sc);
        bridge_rtage(sc);
        s = splhigh();
        s = splhigh();
 
 
        if (sc->sc_brtcnt <= sc->sc_brtmax)
        if (sc->sc_brtcnt <= sc->sc_brtmax)
                goto done;
                goto done;
 
 
        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
                n = LIST_FIRST(&sc->sc_rts[i]);
                n = LIST_FIRST(&sc->sc_rts[i]);
                while (n != NULL) {
                while (n != NULL) {
                        p = LIST_NEXT(n, brt_next);
                        p = LIST_NEXT(n, brt_next);
                        if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
                        if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
                                LIST_REMOVE(n, brt_next);
                                LIST_REMOVE(n, brt_next);
                                sc->sc_brtcnt--;
                                sc->sc_brtcnt--;
                                free(n, M_DEVBUF);
                                free(n, M_DEVBUF);
                                n = p;
                                n = p;
                                if (sc->sc_brtcnt <= sc->sc_brtmax)
                                if (sc->sc_brtcnt <= sc->sc_brtmax)
                                        goto done;
                                        goto done;
                        }
                        }
                }
                }
        }
        }
 
 
done:
done:
        if (sc->sc_rts != NULL && sc->sc_brtcnt == 0 &&
        if (sc->sc_rts != NULL && sc->sc_brtcnt == 0 &&
            (sc->sc_if.if_flags & IFF_UP) == 0) {
            (sc->sc_if.if_flags & IFF_UP) == 0) {
                free(sc->sc_rts, M_DEVBUF);
                free(sc->sc_rts, M_DEVBUF);
                sc->sc_rts = NULL;
                sc->sc_rts = NULL;
        }
        }
 
 
        splx(s);
        splx(s);
}
}
 
 
/*
/*
 * Perform an aging cycle
 * Perform an aging cycle
 */
 */
void
void
bridge_rtage(vsc)
bridge_rtage(vsc)
        void *vsc;
        void *vsc;
{
{
        struct bridge_softc *sc = (struct bridge_softc *)vsc;
        struct bridge_softc *sc = (struct bridge_softc *)vsc;
        struct bridge_rtnode *n, *p;
        struct bridge_rtnode *n, *p;
        int s, i;
        int s, i;
 
 
        s = splhigh();
        s = splhigh();
        if (sc->sc_rts == NULL) {
        if (sc->sc_rts == NULL) {
                splx(s);
                splx(s);
                return;
                return;
        }
        }
 
 
        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
                n = LIST_FIRST(&sc->sc_rts[i]);
                n = LIST_FIRST(&sc->sc_rts[i]);
                while (n != NULL) {
                while (n != NULL) {
                        if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
                        if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
                                n->brt_age = !n->brt_age;
                                n->brt_age = !n->brt_age;
                                if (n->brt_age)
                                if (n->brt_age)
                                        n->brt_age = 0;
                                        n->brt_age = 0;
                                n = LIST_NEXT(n, brt_next);
                                n = LIST_NEXT(n, brt_next);
                        } else if (n->brt_age) {
                        } else if (n->brt_age) {
                                n->brt_age = 0;
                                n->brt_age = 0;
                                n = LIST_NEXT(n, brt_next);
                                n = LIST_NEXT(n, brt_next);
                        } else {
                        } else {
                                p = LIST_NEXT(n, brt_next);
                                p = LIST_NEXT(n, brt_next);
                                LIST_REMOVE(n, brt_next);
                                LIST_REMOVE(n, brt_next);
                                sc->sc_brtcnt--;
                                sc->sc_brtcnt--;
                                free(n, M_DEVBUF);
                                free(n, M_DEVBUF);
                                n = p;
                                n = p;
                        }
                        }
                }
                }
        }
        }
        splx(s);
        splx(s);
 
 
        if (sc->sc_brttimeout != 0)
        if (sc->sc_brttimeout != 0)
                timeout(bridge_rtage, sc, sc->sc_brttimeout);
                timeout(bridge_rtage, sc, sc->sc_brttimeout);
}
}
 
 
/*
/*
 * Remove all dynamic addresses from the cache
 * Remove all dynamic addresses from the cache
 */
 */
int
int
bridge_rtflush(sc, full)
bridge_rtflush(sc, full)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        int full;
        int full;
{
{
        int s, i;
        int s, i;
        struct bridge_rtnode *p, *n;
        struct bridge_rtnode *p, *n;
 
 
        s = splhigh();
        s = splhigh();
        if (sc->sc_rts == NULL)
        if (sc->sc_rts == NULL)
                goto done;
                goto done;
 
 
        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
                n = LIST_FIRST(&sc->sc_rts[i]);
                n = LIST_FIRST(&sc->sc_rts[i]);
                while (n != NULL) {
                while (n != NULL) {
                        if (full ||
                        if (full ||
                            (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
                            (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
                                p = LIST_NEXT(n, brt_next);
                                p = LIST_NEXT(n, brt_next);
                                LIST_REMOVE(n, brt_next);
                                LIST_REMOVE(n, brt_next);
                                sc->sc_brtcnt--;
                                sc->sc_brtcnt--;
                                free(n, M_DEVBUF);
                                free(n, M_DEVBUF);
                                n = p;
                                n = p;
                        } else
                        } else
                                n = LIST_NEXT(n, brt_next);
                                n = LIST_NEXT(n, brt_next);
                }
                }
        }
        }
 
 
        if (sc->sc_brtcnt == 0 && (sc->sc_if.if_flags & IFF_UP) == 0) {
        if (sc->sc_brtcnt == 0 && (sc->sc_if.if_flags & IFF_UP) == 0) {
                free(sc->sc_rts, M_DEVBUF);
                free(sc->sc_rts, M_DEVBUF);
                sc->sc_rts = NULL;
                sc->sc_rts = NULL;
        }
        }
 
 
done:
done:
        splx(s);
        splx(s);
        return (0);
        return (0);
}
}
 
 
/*
/*
 * Remove an address from the cache
 * Remove an address from the cache
 */
 */
int
int
bridge_rtdaddr(sc, ea)
bridge_rtdaddr(sc, ea)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        struct ether_addr *ea;
        struct ether_addr *ea;
{
{
        int h, s;
        int h, s;
        struct bridge_rtnode *p;
        struct bridge_rtnode *p;
 
 
        s = splhigh();
        s = splhigh();
        if (sc->sc_rts == NULL)
        if (sc->sc_rts == NULL)
                goto done;
                goto done;
 
 
        h = bridge_hash(ea);
        h = bridge_hash(ea);
        p = LIST_FIRST(&sc->sc_rts[h]);
        p = LIST_FIRST(&sc->sc_rts[h]);
        while (p != NULL) {
        while (p != NULL) {
                if (bcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
                if (bcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
                        LIST_REMOVE(p, brt_next);
                        LIST_REMOVE(p, brt_next);
                        sc->sc_brtcnt--;
                        sc->sc_brtcnt--;
                        free(p, M_DEVBUF);
                        free(p, M_DEVBUF);
                        if (sc->sc_brtcnt == 0 &&
                        if (sc->sc_brtcnt == 0 &&
                            (sc->sc_if.if_flags & IFF_UP) == 0) {
                            (sc->sc_if.if_flags & IFF_UP) == 0) {
                                free(sc->sc_rts, M_DEVBUF);
                                free(sc->sc_rts, M_DEVBUF);
                                sc->sc_rts = NULL;
                                sc->sc_rts = NULL;
                        }
                        }
                        splx(s);
                        splx(s);
                        return (0);
                        return (0);
                }
                }
                p = LIST_NEXT(p, brt_next);
                p = LIST_NEXT(p, brt_next);
        }
        }
 
 
done:
done:
        splx(s);
        splx(s);
        return (ENOENT);
        return (ENOENT);
}
}
/*
/*
 * Delete routes to a specific interface member.
 * Delete routes to a specific interface member.
 */
 */
void
void
bridge_rtdelete(sc, ifp)
bridge_rtdelete(sc, ifp)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        struct ifnet *ifp;
        struct ifnet *ifp;
{
{
        int i, s;
        int i, s;
        struct bridge_rtnode *n, *p;
        struct bridge_rtnode *n, *p;
 
 
        s = splhigh();
        s = splhigh();
        if (sc->sc_rts == NULL)
        if (sc->sc_rts == NULL)
                goto done;
                goto done;
 
 
        /*
        /*
         * Loop through all of the hash buckets and traverse each
         * Loop through all of the hash buckets and traverse each
         * chain looking for routes to this interface.
         * chain looking for routes to this interface.
         */
         */
        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
                n = LIST_FIRST(&sc->sc_rts[i]);
                n = LIST_FIRST(&sc->sc_rts[i]);
                while (n != NULL) {
                while (n != NULL) {
                        if (n->brt_if == ifp) {         /* found one */
                        if (n->brt_if == ifp) {         /* found one */
                                p = LIST_NEXT(n, brt_next);
                                p = LIST_NEXT(n, brt_next);
                                LIST_REMOVE(n, brt_next);
                                LIST_REMOVE(n, brt_next);
                                sc->sc_brtcnt--;
                                sc->sc_brtcnt--;
                                free(n, M_DEVBUF);
                                free(n, M_DEVBUF);
                                n = p;
                                n = p;
                        } else
                        } else
                                n = LIST_NEXT(n, brt_next);
                                n = LIST_NEXT(n, brt_next);
                }
                }
        }
        }
        if (sc->sc_brtcnt == 0 && (sc->sc_if.if_flags & IFF_UP) == 0) {
        if (sc->sc_brtcnt == 0 && (sc->sc_if.if_flags & IFF_UP) == 0) {
                free(sc->sc_rts, M_DEVBUF);
                free(sc->sc_rts, M_DEVBUF);
                sc->sc_rts = NULL;
                sc->sc_rts = NULL;
        }
        }
 
 
done:
done:
        splx(s);
        splx(s);
}
}
 
 
/*
/*
 * Gather all of the routes for this interface.
 * Gather all of the routes for this interface.
 */
 */
int
int
bridge_rtfind(sc, baconf)
bridge_rtfind(sc, baconf)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        struct ifbaconf *baconf;
        struct ifbaconf *baconf;
{
{
        int i, s, error = 0;
        int i, s, error = 0;
        u_int32_t cnt = 0;
        u_int32_t cnt = 0;
        struct bridge_rtnode *n;
        struct bridge_rtnode *n;
        struct ifbareq bareq;
        struct ifbareq bareq;
 
 
        s = splhigh();
        s = splhigh();
 
 
        if (sc->sc_rts == NULL || baconf->ifbac_len == 0)
        if (sc->sc_rts == NULL || baconf->ifbac_len == 0)
                goto done;
                goto done;
 
 
        for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
        for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
                n = LIST_FIRST(&sc->sc_rts[i]);
                n = LIST_FIRST(&sc->sc_rts[i]);
                while (n != NULL) {
                while (n != NULL) {
                        if (baconf->ifbac_len <
                        if (baconf->ifbac_len <
                            (cnt + 1) * sizeof(struct ifbareq))
                            (cnt + 1) * sizeof(struct ifbareq))
                                goto done;
                                goto done;
                        bcopy(sc->sc_if.if_xname, bareq.ifba_name,
                        bcopy(sc->sc_if.if_xname, bareq.ifba_name,
                            sizeof(bareq.ifba_name));
                            sizeof(bareq.ifba_name));
                        bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
                        bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
                            sizeof(bareq.ifba_ifsname));
                            sizeof(bareq.ifba_ifsname));
                        bcopy(&n->brt_addr, &bareq.ifba_dst,
                        bcopy(&n->brt_addr, &bareq.ifba_dst,
                            sizeof(bareq.ifba_dst));
                            sizeof(bareq.ifba_dst));
                        bareq.ifba_age = n->brt_age;
                        bareq.ifba_age = n->brt_age;
                        bareq.ifba_flags = n->brt_flags;
                        bareq.ifba_flags = n->brt_flags;
                        error = copyout((caddr_t)&bareq,
                        error = copyout((caddr_t)&bareq,
                            (caddr_t)(baconf->ifbac_req + cnt), sizeof(bareq));
                            (caddr_t)(baconf->ifbac_req + cnt), sizeof(bareq));
                        if (error)
                        if (error)
                                goto done;
                                goto done;
                        n = LIST_NEXT(n, brt_next);
                        n = LIST_NEXT(n, brt_next);
                        cnt++;
                        cnt++;
                }
                }
        }
        }
done:
done:
        baconf->ifbac_len = cnt * sizeof(struct ifbareq);
        baconf->ifbac_len = cnt * sizeof(struct ifbareq);
        splx(s);
        splx(s);
        return (error);
        return (error);
}
}
 
 
/*
/*
 * Block non-ip frames:
 * Block non-ip frames:
 * Returns 0 if frame is ip, and 1 if it should be dropped.
 * Returns 0 if frame is ip, and 1 if it should be dropped.
 */
 */
int
int
bridge_blocknonip(eh, m)
bridge_blocknonip(eh, m)
        struct ether_header *eh;
        struct ether_header *eh;
        struct mbuf *m;
        struct mbuf *m;
{
{
        struct snap snap;
        struct snap snap;
        u_int16_t etype;
        u_int16_t etype;
 
 
        if (m->m_pkthdr.len < sizeof(struct ether_header))
        if (m->m_pkthdr.len < sizeof(struct ether_header))
                return (1);
                return (1);
 
 
        etype = ntohs(eh->ether_type);
        etype = ntohs(eh->ether_type);
        switch (etype) {
        switch (etype) {
        case ETHERTYPE_ARP:
        case ETHERTYPE_ARP:
        case ETHERTYPE_REVARP:
        case ETHERTYPE_REVARP:
        case ETHERTYPE_IP:
        case ETHERTYPE_IP:
        case ETHERTYPE_IPV6:
        case ETHERTYPE_IPV6:
                return (0);
                return (0);
        }
        }
 
 
        if (etype > ETHERMTU)
        if (etype > ETHERMTU)
                return (1);
                return (1);
 
 
        if (m->m_pkthdr.len <
        if (m->m_pkthdr.len <
            (sizeof(struct ether_header) + sizeof(struct snap)))
            (sizeof(struct ether_header) + sizeof(struct snap)))
                return (1);
                return (1);
 
 
        m_copydata(m, sizeof(struct ether_header), sizeof(struct snap),
        m_copydata(m, sizeof(struct ether_header), sizeof(struct snap),
            (caddr_t)&snap);
            (caddr_t)&snap);
 
 
        etype = ntohs(snap.type);
        etype = ntohs(snap.type);
        if (snap.dsap == LLC_SNAP_LSAP && snap.ssap == LLC_SNAP_LSAP &&
        if (snap.dsap == LLC_SNAP_LSAP && snap.ssap == LLC_SNAP_LSAP &&
            snap.control == LLC_UI &&
            snap.control == LLC_UI &&
            snap.org[0] == 0 && snap.org[1] == 0 && snap.org[2] == 0 &&
            snap.org[0] == 0 && snap.org[1] == 0 && snap.org[2] == 0 &&
            (etype == ETHERTYPE_ARP ||
            (etype == ETHERTYPE_ARP ||
             etype == ETHERTYPE_REVARP ||
             etype == ETHERTYPE_REVARP ||
             etype == ETHERTYPE_IP ||
             etype == ETHERTYPE_IP ||
             etype == ETHERTYPE_IPV6)) {
             etype == ETHERTYPE_IPV6)) {
                return (0);
                return (0);
        }
        }
 
 
        return (1);
        return (1);
}
}
 
 
u_int8_t
u_int8_t
bridge_filterrule(n, eh)
bridge_filterrule(n, eh)
        struct brl_node *n;
        struct brl_node *n;
        struct ether_header *eh;
        struct ether_header *eh;
{
{
        u_int8_t flags;
        u_int8_t flags;
 
 
        for (; n != NULL; n = SIMPLEQ_NEXT(n, brl_next)) {
        for (; n != NULL; n = SIMPLEQ_NEXT(n, brl_next)) {
                flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
                flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
                if (flags == 0)
                if (flags == 0)
                        return (n->brl_action);
                        return (n->brl_action);
                if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) {
                if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) {
                        if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
                        if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
                                continue;
                                continue;
                        if (bcmp(eh->ether_dhost, &n->brl_src, ETHER_ADDR_LEN))
                        if (bcmp(eh->ether_dhost, &n->brl_src, ETHER_ADDR_LEN))
                                continue;
                                continue;
                        return (n->brl_action);
                        return (n->brl_action);
                }
                }
                if (flags == BRL_FLAG_SRCVALID) {
                if (flags == BRL_FLAG_SRCVALID) {
                        if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
                        if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
                                continue;
                                continue;
                        return (n->brl_action);
                        return (n->brl_action);
                }
                }
                if (flags == BRL_FLAG_DSTVALID) {
                if (flags == BRL_FLAG_DSTVALID) {
                        if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
                        if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
                                continue;
                                continue;
                        return (n->brl_action);
                        return (n->brl_action);
                }
                }
        }
        }
        return (BRL_ACTION_PASS);
        return (BRL_ACTION_PASS);
}
}
 
 
int
int
bridge_addrule(bif, req, out)
bridge_addrule(bif, req, out)
        struct bridge_iflist *bif;
        struct bridge_iflist *bif;
        struct ifbrlreq *req;
        struct ifbrlreq *req;
        int out;
        int out;
{
{
        struct brl_node *n;
        struct brl_node *n;
 
 
        n = (struct brl_node *)malloc(sizeof(struct brl_node), M_DEVBUF, M_NOWAIT);
        n = (struct brl_node *)malloc(sizeof(struct brl_node), M_DEVBUF, M_NOWAIT);
        if (n == NULL)
        if (n == NULL)
                return (ENOMEM);
                return (ENOMEM);
        bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr));
        bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr));
        bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr));
        bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr));
        n->brl_action = req->ifbr_action;
        n->brl_action = req->ifbr_action;
        n->brl_flags = req->ifbr_flags;
        n->brl_flags = req->ifbr_flags;
        if (out) {
        if (out) {
                n->brl_flags &= ~BRL_FLAG_IN;
                n->brl_flags &= ~BRL_FLAG_IN;
                n->brl_flags |= BRL_FLAG_OUT;
                n->brl_flags |= BRL_FLAG_OUT;
                SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next);
                SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next);
        } else {
        } else {
                n->brl_flags &= ~BRL_FLAG_OUT;
                n->brl_flags &= ~BRL_FLAG_OUT;
                n->brl_flags |= BRL_FLAG_IN;
                n->brl_flags |= BRL_FLAG_IN;
                SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next);
                SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next);
        }
        }
        return (0);
        return (0);
}
}
 
 
int
int
bridge_flushrule(bif)
bridge_flushrule(bif)
        struct bridge_iflist *bif;
        struct bridge_iflist *bif;
{
{
        struct brl_node *p, *q;
        struct brl_node *p, *q;
 
 
        p = SIMPLEQ_FIRST(&bif->bif_brlin);
        p = SIMPLEQ_FIRST(&bif->bif_brlin);
        while (p != NULL) {
        while (p != NULL) {
                q = SIMPLEQ_NEXT(p, brl_next);
                q = SIMPLEQ_NEXT(p, brl_next);
                SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, p, brl_next);
                SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, p, brl_next);
                free(p, M_DEVBUF);
                free(p, M_DEVBUF);
                p = q;
                p = q;
        }
        }
        p = SIMPLEQ_FIRST(&bif->bif_brlout);
        p = SIMPLEQ_FIRST(&bif->bif_brlout);
        while (p != NULL) {
        while (p != NULL) {
                q = SIMPLEQ_NEXT(p, brl_next);
                q = SIMPLEQ_NEXT(p, brl_next);
                SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, p, brl_next);
                SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, p, brl_next);
                free(p, M_DEVBUF);
                free(p, M_DEVBUF);
                p = q;
                p = q;
        }
        }
        return (0);
        return (0);
}
}
 
 
#if defined(INET) && (defined(IPFILTER) || defined(IPFILTER_LKM))
#if defined(INET) && (defined(IPFILTER) || defined(IPFILTER_LKM))
 
 
/*
/*
 * Maximum sized IP header
 * Maximum sized IP header
 */
 */
union maxip {
union maxip {
        struct ip ip;
        struct ip ip;
        u_int32_t _padding[16];
        u_int32_t _padding[16];
};
};
 
 
/*
/*
 * Filter IP packets by peeking into the ethernet frame.  This violates
 * Filter IP packets by peeking into the ethernet frame.  This violates
 * the ISO model, but allows us to act as a IP filter at the data link
 * the ISO model, but allows us to act as a IP filter at the data link
 * layer.  As a result, most of this code will look familiar to those
 * layer.  As a result, most of this code will look familiar to those
 * who've read net/if_ethersubr.c and netinet/ip_input.c
 * who've read net/if_ethersubr.c and netinet/ip_input.c
 */
 */
struct mbuf *
struct mbuf *
bridge_filter(sc, ifp, eh, m)
bridge_filter(sc, ifp, eh, m)
        struct bridge_softc *sc;
        struct bridge_softc *sc;
        struct ifnet *ifp;
        struct ifnet *ifp;
        struct ether_header *eh;
        struct ether_header *eh;
        struct mbuf *m;
        struct mbuf *m;
{
{
        struct snap snap;
        struct snap snap;
        int hassnap = 0;
        int hassnap = 0;
        struct ip *ip;
        struct ip *ip;
        int hlen;
        int hlen;
 
 
        if (fr_checkp == NULL)
        if (fr_checkp == NULL)
                return (m);
                return (m);
 
 
        if (eh->ether_type != htons(ETHERTYPE_IP)) {
        if (eh->ether_type != htons(ETHERTYPE_IP)) {
                if (eh->ether_type > ETHERMTU ||
                if (eh->ether_type > ETHERMTU ||
                    m->m_pkthdr.len < (sizeof(struct snap) +
                    m->m_pkthdr.len < (sizeof(struct snap) +
                    sizeof(struct ether_header)))
                    sizeof(struct ether_header)))
                        return (m);
                        return (m);
 
 
                m_copydata(m, sizeof(struct ether_header),
                m_copydata(m, sizeof(struct ether_header),
                    sizeof(struct snap), (caddr_t)&snap);
                    sizeof(struct snap), (caddr_t)&snap);
 
 
                if (snap.dsap != LLC_SNAP_LSAP || snap.ssap != LLC_SNAP_LSAP ||
                if (snap.dsap != LLC_SNAP_LSAP || snap.ssap != LLC_SNAP_LSAP ||
                    snap.control != LLC_UI ||
                    snap.control != LLC_UI ||
                    snap.org[0] != 0 || snap.org[1] != 0 || snap.org[2] ||
                    snap.org[0] != 0 || snap.org[1] != 0 || snap.org[2] ||
                    snap.type != htons(ETHERTYPE_IP))
                    snap.type != htons(ETHERTYPE_IP))
                        return (m);
                        return (m);
                hassnap = 1;
                hassnap = 1;
        }
        }
 
 
        m_adj(m, sizeof(struct ether_header));
        m_adj(m, sizeof(struct ether_header));
        if (hassnap)
        if (hassnap)
                m_adj(m, sizeof(struct snap));
                m_adj(m, sizeof(struct snap));
 
 
        if (m->m_pkthdr.len < sizeof(struct ip))
        if (m->m_pkthdr.len < sizeof(struct ip))
                goto dropit;
                goto dropit;
 
 
        /* Copy minimal header, and drop invalids */
        /* Copy minimal header, and drop invalids */
        if (m->m_len < sizeof(struct ip) &&
        if (m->m_len < sizeof(struct ip) &&
            (m = m_pullup(m, sizeof(struct ip))) == NULL)
            (m = m_pullup(m, sizeof(struct ip))) == NULL)
                return (NULL);
                return (NULL);
        ip = mtod(m, struct ip *);
        ip = mtod(m, struct ip *);
 
 
        if (ip->ip_v != IPVERSION)
        if (ip->ip_v != IPVERSION)
                goto dropit;
                goto dropit;
 
 
        hlen = ip->ip_hl << 2;  /* get whole header length */
        hlen = ip->ip_hl << 2;  /* get whole header length */
        if (hlen < sizeof(struct ip))
        if (hlen < sizeof(struct ip))
                goto dropit;
                goto dropit;
        if (hlen > m->m_len) {
        if (hlen > m->m_len) {
                if ((m = m_pullup(m, sizeof(struct ip))) == NULL)
                if ((m = m_pullup(m, sizeof(struct ip))) == NULL)
                        return (NULL);
                        return (NULL);
                ip = mtod(m, struct ip *);
                ip = mtod(m, struct ip *);
        }
        }
 
 
        if ((ip->ip_sum = in_cksum(m, hlen)) != 0)
        if ((ip->ip_sum = in_cksum(m, hlen)) != 0)
                goto dropit;
                goto dropit;
 
 
        NTOHS(ip->ip_len);
        NTOHS(ip->ip_len);
        if (ip->ip_len < hlen)
        if (ip->ip_len < hlen)
                goto dropit;
                goto dropit;
        NTOHS(ip->ip_id);
        NTOHS(ip->ip_id);
        NTOHS(ip->ip_off);
        NTOHS(ip->ip_off);
 
 
        if (m->m_pkthdr.len < ip->ip_len)
        if (m->m_pkthdr.len < ip->ip_len)
                goto dropit;
                goto dropit;
        if (m->m_pkthdr.len > ip->ip_len) {
        if (m->m_pkthdr.len > ip->ip_len) {
                if (m->m_len == m->m_pkthdr.len) {
                if (m->m_len == m->m_pkthdr.len) {
                        m->m_len = ip->ip_len;
                        m->m_len = ip->ip_len;
                        m->m_pkthdr.len = ip->ip_len;
                        m->m_pkthdr.len = ip->ip_len;
                } else
                } else
                        m_adj(m, ip->ip_len - m->m_pkthdr.len);
                        m_adj(m, ip->ip_len - m->m_pkthdr.len);
        }
        }
 
 
        /* Finally, we get to filter the packet! */
        /* Finally, we get to filter the packet! */
        if (fr_checkp && (*fr_checkp)(ip, hlen, ifp, 0, &m))
        if (fr_checkp && (*fr_checkp)(ip, hlen, ifp, 0, &m))
                return (NULL);
                return (NULL);
 
 
        /* Rebuild the IP header */
        /* Rebuild the IP header */
        if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL))
        if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL))
                return (NULL);
                return (NULL);
        if (m->m_len < sizeof(struct ip))
        if (m->m_len < sizeof(struct ip))
                goto dropit;
                goto dropit;
        ip = mtod(m, struct ip *);
        ip = mtod(m, struct ip *);
        HTONS(ip->ip_len);
        HTONS(ip->ip_len);
        HTONS(ip->ip_id);
        HTONS(ip->ip_id);
        HTONS(ip->ip_off);
        HTONS(ip->ip_off);
        ip->ip_sum = in_cksum(m, hlen);
        ip->ip_sum = in_cksum(m, hlen);
 
 
        /* Reattach SNAP header */
        /* Reattach SNAP header */
        if (hassnap) {
        if (hassnap) {
                M_PREPEND(m, sizeof(snap), M_DONTWAIT);
                M_PREPEND(m, sizeof(snap), M_DONTWAIT);
                if (m == NULL)
                if (m == NULL)
                        goto dropit;
                        goto dropit;
                bcopy(&snap, mtod(m, caddr_t), sizeof(snap));
                bcopy(&snap, mtod(m, caddr_t), sizeof(snap));
        }
        }
 
 
        /* Reattach ethernet header */
        /* Reattach ethernet header */
        M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
        M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
        if (m == NULL)
        if (m == NULL)
                goto dropit;
                goto dropit;
        bcopy(eh, mtod(m, caddr_t), sizeof(*eh));
        bcopy(eh, mtod(m, caddr_t), sizeof(*eh));
 
 
        return (m);
        return (m);
 
 
dropit:
dropit:
        if (m != NULL)
        if (m != NULL)
                m_freem(m);
                m_freem(m);
        return (NULL);
        return (NULL);
}
}
#endif
#endif
 
 
int
int
ifpromisc(ifp, pswitch)
ifpromisc(ifp, pswitch)
        struct ifnet *ifp;
        struct ifnet *ifp;
        int pswitch;
        int pswitch;
{
{
        struct ifreq ifr;
        struct ifreq ifr;
 
 
        if (pswitch) {
        if (pswitch) {
                /*
                /*
                 * If the device is not configured up, we cannot put it in
                 * If the device is not configured up, we cannot put it in
                 * promiscuous mode.
                 * promiscuous mode.
                 */
                 */
                if ((ifp->if_flags & IFF_UP) == 0)
                if ((ifp->if_flags & IFF_UP) == 0)
                        return (ENETDOWN);
                        return (ENETDOWN);
                if (ifp->if_pcount++ != 0)
                if (ifp->if_pcount++ != 0)
                        return (0);
                        return (0);
                ifp->if_flags |= IFF_PROMISC;
                ifp->if_flags |= IFF_PROMISC;
        } else {
        } else {
                if (--ifp->if_pcount > 0)
                if (--ifp->if_pcount > 0)
                        return (0);
                        return (0);
                ifp->if_flags &= ~IFF_PROMISC;
                ifp->if_flags &= ~IFF_PROMISC;
                /*
                /*
                 * If the device is not configured up, we should not need to
                 * If the device is not configured up, we should not need to
                 * turn off promiscuous mode (device should have turned it
                 * turn off promiscuous mode (device should have turned it
                 * off when interface went down; and will look at IFF_PROMISC
                 * off when interface went down; and will look at IFF_PROMISC
                 * again next time interface comes up).
                 * again next time interface comes up).
                 */
                 */
                if ((ifp->if_flags & IFF_UP) == 0)
                if ((ifp->if_flags & IFF_UP) == 0)
                        return (0);
                        return (0);
        }
        }
        ifr.ifr_flags = ifp->if_flags;
        ifr.ifr_flags = ifp->if_flags;
        return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
        return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
}
}
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.