📄 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, manu.sharma@ascom.com
// 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
/* Spanning tree defaults */
#define BSTP_DEFAULT_MAX_AGE (20 * 256)
#define BSTP_DEFAULT_HELLO_TIME (2 * 256)
#define BSTP_DEFAULT_FORWARD_DELAY (15 * 256)
#define BSTP_DEFAULT_HOLD_TIME (1 * 256)
#define BSTP_DEFAULT_BRIDGE_PRIORITY 0x8000
#define BSTP_DEFAULT_PORT_PRIORITY 0x80
#define BSTP_DEFAULT_PATH_COST 55
extern int ifqmaxlen;
/* 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 *));
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 *));
int bridge_ifenqueue __P((struct bridge_softc *, struct ifnet *, struct mbuf *));
#ifdef CYGPKG_NET_BRIDGE_STP_CODE
void bridge_span (struct bridge_softc *, struct ether_header *, struct mbuf *);
#endif
#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;
bridgectl[i].sc_bridge_max_age = BSTP_DEFAULT_MAX_AGE;
bridgectl[i].sc_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME;
bridgectl[i].sc_bridge_forward_delay= BSTP_DEFAULT_FORWARD_DELAY;
bridgectl[i].sc_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
bridgectl[i].sc_hold_time = BSTP_DEFAULT_HOLD_TIME;
LIST_INIT(&bridgectl[i].sc_iflist);
LIST_INIT(&bridgectl[i].sc_spanlist);
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;
}
#ifdef CYGPKG_NET_BRIDGE_STP_CODE
/* If it's in the span list, it can't be a member. */
LIST_FOREACH(p, &sc->sc_spanlist, next) {
if (p->ifp == ifs)
break;
}
if (p != LIST_END(&sc->sc_spanlist)) {
error = EBUSY;
break;
}
#endif
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;
p->bif_priority = BSTP_DEFAULT_PORT_PRIORITY;
p->bif_path_cost = BSTP_DEFAULT_PATH_COST;
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, 0);
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;
#ifdef CYGPKG_NET_BRIDGE_STP_CODE
case SIOCBRDGADDS:
#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;
}
LIST_FOREACH(p, &sc->sc_spanlist, next) {
if (p->ifp == ifs)
break;
}
if (p != LIST_END(&sc->sc_spanlist)) {
error = EBUSY;
break;
}
p = (struct bridge_iflist *)malloc(
sizeof(struct bridge_iflist), M_DEVBUF, M_NOWAIT);
if (p == NULL) {
error = ENOMEM;
break;
}
bzero(p, sizeof(struct bridge_iflist));
p->ifp = ifs;
SIMPLEQ_INIT(&p->bif_brlin);
SIMPLEQ_INIT(&p->bif_brlout);
LIST_INSERT_HEAD(&sc->sc_spanlist, p, next);
break;
case SIOCBRDGDELS:
#ifndef __ECOS
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
#endif
LIST_FOREACH(p, &sc->sc_spanlist, next) {
if (strncmp(p->ifp->if_xname, req->ifbr_ifsname,
sizeof(p->ifp->if_xname)) == 0) {
LIST_REMOVE(p, next);
free(p, M_DEVBUF);
break;
}
}
if (p == LIST_END(&sc->sc_spanlist)) {
error = ENOENT;
break;
}
break;
#endif
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;
req->ifbr_state = p->bif_state;
req->ifbr_priority = p->bif_priority;
req->ifbr_path_cost = p->bif_path_cost;
req->ifbr_portno = p->ifp->if_index & 0xff;
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 SIOCBRDGSIFPRIO:
case SIOCBRDGSIFCOST:
#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;
}
LIST_FOREACH(p, &sc->sc_iflist, next) {
if (p->ifp == ifs)
break;
}
if (p == LIST_END(&sc->sc_iflist)) {
error = ESRCH;
break;
}
if (cmd == SIOCBRDGSIFPRIO)
p->bif_priority = req->ifbr_priority;
else {
if (req->ifbr_path_cost < 1)
error = EINVAL;
else
p->bif_path_cost = req->ifbr_path_cost;
}
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -