📄 if_bridge.c
字号:
//==========================================================================
//
// sys/net/if_bridge.c
//
//
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD or other sources,
// and are covered by the appropriate copyright disclaimers included herein.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): Jason L. Wright (jason@thought.net)
// Contributors: andrew.lunn@ascom.ch (Andrew Lunn), hmt
// Date: 2000-07-18
// Purpose: Ethernet bridge
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
/* $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)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Jason L. Wright
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef __ECOS
#include <pkgconf/net.h>
#else
#include "bridge.h"
#include "bpfilter.h"
#include "enc.h"
#endif
#include <sys/param.h>
#ifndef __ECOS
#include <sys/proc.h>
#include <sys/systm.h>
#endif
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#ifndef __ECOS
#include <sys/device.h>
#endif
#include <sys/kernel.h>
#include <machine/cpu.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/if_llc.h>
#include <net/route.h>
#include <net/netisr.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <netinet/ip_ipsp.h>
#ifndef __ECOS
#include <net/if_enc.h>
#endif
#ifdef IPFILTER
#include <netinet/ip_fil_compat.h>
#include <netinet/ip_fil.h>
#endif
#endif
#if NBPFILTER > 0
#include <net/bpf.h>
#endif
#include <net/if_bridge.h>
#ifdef __ECOS
#include <stdio.h> /* for sprintf */
#endif
#ifndef BRIDGE_RTABLE_SIZE
#define BRIDGE_RTABLE_SIZE 1024
#endif
#define BRIDGE_RTABLE_MASK (BRIDGE_RTABLE_SIZE - 1)
/*
* Maximum number of addresses to cache
*/
#ifndef BRIDGE_RTABLE_MAX
#define BRIDGE_RTABLE_MAX 100
#endif
/*
* Timeout (in seconds) for entries learned dynamically
*/
#ifndef BRIDGE_RTABLE_TIMEOUT
#define BRIDGE_RTABLE_TIMEOUT 300
#endif
extern int ifqmaxlen;
/*
* Bridge filtering rules
*/
struct brl_node {
SIMPLEQ_ENTRY(brl_node) brl_next; /* next rule */
struct ether_addr brl_src; /* source mac address */
struct ether_addr brl_dst; /* destination mac address */
u_int8_t brl_action; /* what to do with match */
u_int8_t brl_flags; /* comparision flags */
};
/*
* Bridge interface list
*/
struct bridge_iflist {
LIST_ENTRY(bridge_iflist) next; /* next in list */
SIMPLEQ_HEAD(, brl_node) bif_brlin; /* input rules */
SIMPLEQ_HEAD(, brl_node) bif_brlout; /* output rules */
struct ifnet *ifp; /* member interface */
u_int32_t bif_flags; /* member flags */
};
/*
* Bridge route node
*/
struct bridge_rtnode {
LIST_ENTRY(bridge_rtnode) brt_next; /* next in list */
struct ifnet *brt_if; /* destination ifs */
u_int8_t brt_flags; /* address flags */
u_int8_t brt_age; /* age counter */
struct ether_addr brt_addr; /* dst addr */
};
/*
* Software state for each bridge
*/
struct bridge_softc {
struct ifnet sc_if; /* the interface */
u_int32_t sc_brtmax; /* max # addresses */
u_int32_t sc_brtcnt; /* current # addrs */
u_int32_t sc_brttimeout; /* timeout ticks */
LIST_HEAD(, bridge_iflist) sc_iflist; /* interface list */
LIST_HEAD(bridge_rthead, bridge_rtnode) *sc_rts;/* hash table */
};
/* SNAP LLC header */
struct snap {
u_int8_t dsap;
u_int8_t ssap;
u_int8_t control;
u_int8_t org[3];
u_int16_t type;
};
struct bridge_softc bridgectl[CYGNUM_NET_BRIDGES];
void bridgeattach __P((int));
int bridge_ioctl __P((struct ifnet *, u_long, caddr_t));
void bridge_start __P((struct ifnet *));
void bridgeintr_frame __P((struct bridge_softc *, struct mbuf *));
void bridge_broadcast __P((struct bridge_softc *, struct ifnet *,
struct ether_header *, struct mbuf *)) __attribute ((weak));
void bridge_stop __P((struct bridge_softc *));
void bridge_init __P((struct bridge_softc *));
int bridge_bifconf __P((struct bridge_softc *, struct ifbifconf *));
int bridge_rtfind __P((struct bridge_softc *, struct ifbaconf *));
void bridge_rtage __P((void *));
void bridge_rttrim __P((struct bridge_softc *));
void bridge_rtdelete __P((struct bridge_softc *, struct ifnet *));
int bridge_rtdaddr __P((struct bridge_softc *, struct ether_addr *));
int bridge_rtflush __P((struct bridge_softc *, int));
struct ifnet * bridge_rtupdate __P((struct bridge_softc *,
struct ether_addr *, struct ifnet *ifp, int, u_int8_t));
struct ifnet * bridge_rtlookup __P((struct bridge_softc *,
struct ether_addr *));
u_int32_t bridge_hash __P((struct ether_addr *));
int bridge_blocknonip __P((struct ether_header *, struct mbuf *));
int bridge_addrule __P((struct bridge_iflist *,
struct ifbrlreq *, int out));
int bridge_flushrule __P((struct bridge_iflist *));
int bridge_brlconf __P((struct bridge_softc *, struct ifbrlconf *));
u_int8_t bridge_filterrule __P((struct brl_node *, struct ether_header *));
#define ETHERADDR_IS_IP_MCAST(a) \
/* struct etheraddr *a; */ \
((a)->ether_addr_octet[0] == 0x01 && \
(a)->ether_addr_octet[1] == 0x00 && \
(a)->ether_addr_octet[2] == 0x5e)
#if defined(INET) && (defined(IPFILTER) || defined(IPFILTER_LKM))
/*
* Filter hooks
*/
struct mbuf *bridge_filter __P((struct bridge_softc *, struct ifnet *,
struct ether_header *, struct mbuf *m));
#endif
void
bridgeattach(unused)
int unused;
{
int i;
struct ifnet *ifp;
for (i = 0; i < CYGNUM_NET_BRIDGES; i++) {
bridgectl[i].sc_brtmax = BRIDGE_RTABLE_MAX;
bridgectl[i].sc_brttimeout = (BRIDGE_RTABLE_TIMEOUT * hz) / 2;
LIST_INIT(&bridgectl[i].sc_iflist);
ifp = &bridgectl[i].sc_if;
sprintf(ifp->if_xname, "bridge%d", i);
ifp->if_softc = &bridgectl[i];
ifp->if_mtu = ETHERMTU;
ifp->if_ioctl = bridge_ioctl;
ifp->if_output = bridge_output;
ifp->if_start = bridge_start;
ifp->if_type = IFT_PROPVIRTUAL;
ifp->if_snd.ifq_maxlen = ifqmaxlen;
ifp->if_hdrlen = sizeof(struct ether_header);
if_attach(ifp);
#if NBPFILTER > 0
bpfattach(&bridgectl[i].sc_if.if_bpf, ifp,
DLT_EN10MB, sizeof(struct ether_header));
#endif
}
}
int
bridge_ioctl(ifp, cmd, data)
struct ifnet *ifp;
u_long cmd;
caddr_t data;
{
#ifndef __ECOS
struct proc *prc = curproc; /* XXX */
#endif
struct ifnet *ifs;
struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
struct ifbreq *req = (struct ifbreq *)data;
struct ifbaconf *baconf = (struct ifbaconf *)data;
struct ifbareq *bareq = (struct ifbareq *)data;
struct ifbcachereq *bcachereq = (struct ifbcachereq *)data;
struct ifbifconf *bifconf = (struct ifbifconf *)data;
struct ifbcachetoreq *bcacheto = (struct ifbcachetoreq *)data;
struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
struct ifbrlconf *brlconf = (struct ifbrlconf *)data;
struct ifreq ifreq;
int error = 0, s;
struct bridge_iflist *p;
s = splimp();
switch (cmd) {
case SIOCBRDGADD:
#ifndef __ECOS
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
#endif
ifs = ifunit(req->ifbr_ifsname);
if (ifs == NULL) { /* no such interface */
error = ENOENT;
break;
}
if (ifs->if_bridge == (caddr_t)sc) {
error = EEXIST;
break;
}
if (ifs->if_bridge != NULL) {
error = EBUSY;
break;
}
if (ifs->if_type == IFT_ETHER) {
if ((ifs->if_flags & IFF_UP) == 0) {
/*
* Bring interface up long enough to set
* promiscuous flag, then shut it down again.
*/
strncpy(ifreq.ifr_name, req->ifbr_ifsname,
sizeof(ifreq.ifr_name) - 1);
ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0';
ifs->if_flags |= IFF_UP;
ifreq.ifr_flags = ifs->if_flags;
error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS,
(caddr_t)&ifreq);
if (error != 0)
break;
error = ifpromisc(ifs, 1);
if (error != 0)
break;
strncpy(ifreq.ifr_name, req->ifbr_ifsname,
sizeof(ifreq.ifr_name) - 1);
ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0';
ifs->if_flags &= ~IFF_UP;
ifreq.ifr_flags = ifs->if_flags;
error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS,
(caddr_t)&ifreq);
if (error != 0) {
ifpromisc(ifs, 0);
break;
}
} else {
error = ifpromisc(ifs, 1);
if (error != 0)
break;
}
}
#ifndef __ECOS
#if NENC > 0
else if (ifs->if_type == IFT_ENC) {
/* Can't bind enc0 to a bridge */
if (ifs->if_softc == &encif[0]) {
error = EINVAL;
break;
}
}
#endif /* NENC */
#endif
else {
error = EINVAL;
break;
}
p = (struct bridge_iflist *) malloc(
sizeof(struct bridge_iflist), M_DEVBUF, M_NOWAIT);
if (p == NULL && ifs->if_type == IFT_ETHER) {
error = ENOMEM;
ifpromisc(ifs, 0);
break;
}
p->ifp = ifs;
p->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
SIMPLEQ_INIT(&p->bif_brlin);
SIMPLEQ_INIT(&p->bif_brlout);
LIST_INSERT_HEAD(&sc->sc_iflist, p, next);
ifs->if_bridge = (caddr_t)sc;
break;
case SIOCBRDGDEL:
#ifndef __ECOS
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
#endif
p = LIST_FIRST(&sc->sc_iflist);
while (p != NULL) {
if (strncmp(p->ifp->if_xname, req->ifbr_ifsname,
sizeof(p->ifp->if_xname)) == 0) {
p->ifp->if_bridge = NULL;
error = ifpromisc(p->ifp, 0);
LIST_REMOVE(p, next);
bridge_rtdelete(sc, p->ifp);
bridge_flushrule(p);
free(p, M_DEVBUF);
break;
}
p = LIST_NEXT(p, next);
}
if (p == NULL) {
error = ENOENT;
break;
}
break;
case SIOCBRDGIFS:
error = bridge_bifconf(sc, bifconf);
break;
case SIOCBRDGGIFFLGS:
ifs = ifunit(req->ifbr_ifsname);
if (ifs == NULL) {
error = ENOENT;
break;
}
if ((caddr_t)sc != ifs->if_bridge) {
error = ESRCH;
break;
}
p = LIST_FIRST(&sc->sc_iflist);
while (p != NULL && p->ifp != ifs) {
p = LIST_NEXT(p, next);
}
if (p == NULL) {
error = ESRCH;
break;
}
req->ifbr_ifsflags = p->bif_flags;
break;
case SIOCBRDGSIFFLGS:
#ifndef __ECOS
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
#endif
ifs = ifunit(req->ifbr_ifsname);
if (ifs == NULL) {
error = ENOENT;
break;
}
if ((caddr_t)sc != ifs->if_bridge) {
error = ESRCH;
break;
}
p = LIST_FIRST(&sc->sc_iflist);
while (p != NULL && p->ifp != ifs) {
p = LIST_NEXT(p, next);
}
if (p == NULL) {
error = ESRCH;
break;
}
p->bif_flags = req->ifbr_ifsflags;
break;
case SIOCBRDGRTS:
error = bridge_rtfind(sc, baconf);
break;
case SIOCBRDGFLUSH:
#ifndef __ECOS
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
#endif
error = bridge_rtflush(sc, req->ifbr_ifsflags);
break;
case SIOCBRDGSADDR:
#ifndef __ECOS
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
#endif
ifs = ifunit(bareq->ifba_ifsname);
if (ifs == NULL) { /* no such interface */
error = ENOENT;
break;
}
if (ifs->if_bridge == NULL ||
ifs->if_bridge != (caddr_t)sc) {
error = ESRCH;
break;
}
ifs = bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,
bareq->ifba_flags);
if (ifs == NULL)
error = ENOMEM;
break;
case SIOCBRDGDADDR:
#ifndef __ECOS
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
#endif
error = bridge_rtdaddr(sc, &bareq->ifba_dst);
break;
case SIOCBRDGGCACHE:
bcachereq->ifbc_size = sc->sc_brtmax;
break;
case SIOCBRDGSCACHE:
#ifndef __ECOS
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
#endif
sc->sc_brtmax = bcachereq->ifbc_size;
bridge_rttrim(sc);
break;
case SIOCBRDGSTO:
#ifndef __ECOS
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -