📄 if_bridge.c
字号:
break;
case SIOCBRDGSTO:
#ifndef __ECOS
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
#endif
sc->sc_brttimeout = (bcacheto->ifbct_time * hz) / 2;
untimeout(bridge_rtage, sc);
if (bcacheto->ifbct_time != 0)
timeout(bridge_rtage, sc, sc->sc_brttimeout);
break;
case SIOCBRDGGTO:
bcacheto->ifbct_time = (2 * sc->sc_brttimeout) / hz;
break;
case SIOCSIFFLAGS:
if ((ifp->if_flags & IFF_UP) == IFF_UP)
bridge_init(sc);
if ((ifp->if_flags & IFF_UP) == 0)
bridge_stop(sc);
break;
case SIOCBRDGARL:
#ifndef __ECOS
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
#endif
ifs = ifunit(brlreq->ifbr_ifsname);
if (ifs == NULL) {
error = ENOENT;
break;
}
if (ifs->if_bridge == NULL ||
ifs->if_bridge != (caddr_t)sc) {
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;
}
if ((brlreq->ifbr_action != BRL_ACTION_BLOCK &&
brlreq->ifbr_action != BRL_ACTION_PASS) ||
(brlreq->ifbr_flags & (BRL_FLAG_IN|BRL_FLAG_OUT)) == 0) {
error = EINVAL;
break;
}
if (brlreq->ifbr_flags & BRL_FLAG_IN) {
error = bridge_addrule(p, brlreq, 0);
if (error)
break;
}
if (brlreq->ifbr_flags & BRL_FLAG_OUT) {
error = bridge_addrule(p, brlreq, 1);
if (error)
break;
}
break;
case SIOCBRDGFRL:
#ifndef __ECOS
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
#endif
ifs = ifunit(brlreq->ifbr_ifsname);
if (ifs == NULL) {
error = ENOENT;
break;
}
if (ifs->if_bridge == NULL ||
ifs->if_bridge != (caddr_t)sc) {
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;
}
error = bridge_flushrule(p);
break;
case SIOCBRDGGRL:
error = bridge_brlconf(sc, brlconf);
break;
case SIOCBRDGGPRI:
case SIOCBRDGGMA:
case SIOCBRDGGHT:
case SIOCBRDGGFD:
break;
case SIOCBRDGSPRI:
case SIOCBRDGSFD:
case SIOCBRDGSMA:
case SIOCBRDGSHT:
#ifndef __ECOS
error = suser(prc->p_ucred, &prc->p_acflag);
#endif
break;
default:
error = EINVAL;
}
#ifdef CYGPKG_NET_BRIDGE_STP_CODE
if (!error)
error = bstp_ioctl(ifp, cmd, data);
#endif
splx(s);
return (error);
}
/* Detach an interface from a bridge. */
void
bridge_ifdetach(ifp)
struct ifnet *ifp;
{
struct bridge_softc *bsc = (struct bridge_softc *)ifp->if_bridge;
struct bridge_iflist *bif;
for (bif = LIST_FIRST(&bsc->sc_iflist); bif;
bif = LIST_NEXT(bif, next))
if (bif->ifp == ifp) {
LIST_REMOVE(bif, next);
bridge_rtdelete(bsc, ifp, 0);
bridge_flushrule(bif);
free(bif, M_DEVBUF);
ifp->if_bridge = NULL;
break;
}
}
int
bridge_bifconf(sc, bifc)
struct bridge_softc *sc;
struct ifbifconf *bifc;
{
struct bridge_iflist *p;
u_int32_t total = 0, i;
#ifdef CYGPKG_NET_BRIDGE_STP_CODE
u_int32_t j;
#endif
int error = 0;
struct ifbreq breq;
p = LIST_FIRST(&sc->sc_iflist);
while (p != NULL) {
total++;
p = LIST_NEXT(p, next);
}
#ifdef CYGPKG_NET_BRIDGE_STP_CODE
p = LIST_FIRST(&sc->sc_spanlist);
while (p != NULL) {
total++;
p = LIST_NEXT(p, next);
}
#endif
if (bifc->ifbic_len == 0) {
i = total;
goto done;
}
p = LIST_FIRST(&sc->sc_iflist);
i = 0;
while (p != NULL && bifc->ifbic_len > i * sizeof(breq)) {
strncpy(breq.ifbr_name, sc->sc_if.if_xname,
sizeof(breq.ifbr_name)-1);
breq.ifbr_name[sizeof(breq.ifbr_name) - 1] = '\0';
strncpy(breq.ifbr_ifsname, p->ifp->if_xname,
sizeof(breq.ifbr_ifsname)-1);
breq.ifbr_ifsname[sizeof(breq.ifbr_ifsname) - 1] = '\0';
breq.ifbr_ifsflags = p->bif_flags;
breq.ifbr_state = p->bif_state;
breq.ifbr_priority = p->bif_priority;
breq.ifbr_path_cost = p->bif_path_cost;
breq.ifbr_portno = p->ifp->if_index & 0xff;
error = copyout((caddr_t)&breq,
(caddr_t)(bifc->ifbic_req + i), sizeof(breq));
if (error)
goto done;
p = LIST_NEXT(p, next);
i++;
bifc->ifbic_len -= sizeof(breq);
}
#ifdef CYGPKG_NET_BRIDGE_STP_CODE
p = LIST_FIRST(&sc->sc_spanlist);
j = 0;
while (p != NULL && bifc->ifbic_len > j * sizeof(breq)) {
strncpy(breq.ifbr_name, sc->sc_if.if_xname,
sizeof(breq.ifbr_name)-1);
breq.ifbr_name[sizeof(breq.ifbr_name) - 1] = '\0';
strncpy(breq.ifbr_ifsname, p->ifp->if_xname,
sizeof(breq.ifbr_ifsname)-1);
breq.ifbr_ifsname[sizeof(breq.ifbr_ifsname) - 1] = '\0';
breq.ifbr_ifsflags = p->bif_flags | IFBIF_SPAN;
breq.ifbr_state = p->bif_state;
breq.ifbr_priority = p->bif_priority;
breq.ifbr_path_cost = p->bif_path_cost;
breq.ifbr_portno = p->ifp->if_index & 0xff;
error = copyout((caddr_t)&breq,
(caddr_t)(bifc->ifbic_req + j), sizeof(breq));
if (error)
goto done;
p = LIST_NEXT(p, next);
j++;
bifc->ifbic_len -= sizeof(breq);
}
#endif
done:
bifc->ifbic_len = i * sizeof(breq);
return (error);
}
int
bridge_brlconf(sc, bc)
struct bridge_softc *sc;
struct ifbrlconf *bc;
{
struct ifnet *ifp;
struct bridge_iflist *ifl;
struct brl_node *n;
struct ifbrlreq req;
int error = 0;
u_int32_t i, total=0;
ifp = ifunit(bc->ifbrl_ifsname);
if (ifp == NULL)
return (ENOENT);
if (ifp->if_bridge == NULL || ifp->if_bridge != (caddr_t)sc)
return (ESRCH);
ifl = LIST_FIRST(&sc->sc_iflist);
while (ifl != NULL && ifl->ifp != ifp)
ifl = LIST_NEXT(ifl, next);
if (ifl == NULL)
return (ESRCH);
n = SIMPLEQ_FIRST(&ifl->bif_brlin);
while (n != NULL) {
total++;
n = SIMPLEQ_NEXT(n, brl_next);
}
n = SIMPLEQ_FIRST(&ifl->bif_brlout);
while (n != NULL) {
total++;
n = SIMPLEQ_NEXT(n, brl_next);
}
if (bc->ifbrl_len == 0) {
i = total;
goto done;
}
i = 0;
n = SIMPLEQ_FIRST(&ifl->bif_brlin);
while (n != NULL && bc->ifbrl_len > i * sizeof(req)) {
strncpy(req.ifbr_name, sc->sc_if.if_xname,
sizeof(req.ifbr_name) - 1);
req.ifbr_name[sizeof(req.ifbr_name) - 1] = '\0';
strncpy(req.ifbr_ifsname, ifl->ifp->if_xname,
sizeof(req.ifbr_ifsname) - 1);
req.ifbr_ifsname[sizeof(req.ifbr_ifsname) - 1] = '\0';
req.ifbr_action = n->brl_action;
req.ifbr_flags = n->brl_flags;
req.ifbr_src = n->brl_src;
req.ifbr_dst = n->brl_dst;
error = copyout((caddr_t)&req,
(caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
if (error)
goto done;
n = SIMPLEQ_NEXT(n, brl_next);
i++;
bc->ifbrl_len -= sizeof(req);
}
n = SIMPLEQ_FIRST(&ifl->bif_brlout);
while (n != NULL && bc->ifbrl_len > i * sizeof(req)) {
strncpy(req.ifbr_name, sc->sc_if.if_xname,
sizeof(req.ifbr_name) - 1);
req.ifbr_name[sizeof(req.ifbr_name) - 1] = '\0';
strncpy(req.ifbr_ifsname, ifl->ifp->if_xname,
sizeof(req.ifbr_ifsname) - 1);
req.ifbr_ifsname[sizeof(req.ifbr_ifsname) - 1] = '\0';
req.ifbr_action = n->brl_action;
req.ifbr_flags = n->brl_flags;
req.ifbr_src = n->brl_src;
req.ifbr_dst = n->brl_dst;
error = copyout((caddr_t)&req,
(caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
if (error)
goto done;
n = SIMPLEQ_NEXT(n, brl_next);
i++;
bc->ifbrl_len -= sizeof(req);
}
done:
bc->ifbrl_len = i * sizeof(req);
return (error);
}
void
bridge_init(sc)
struct bridge_softc *sc;
{
struct ifnet *ifp = &sc->sc_if;
int i, s;
if ((ifp->if_flags & IFF_RUNNING) == IFF_RUNNING)
return;
s = splhigh();
if (sc->sc_rts == NULL) {
sc->sc_rts = (struct bridge_rthead *)malloc(
BRIDGE_RTABLE_SIZE * (sizeof(struct bridge_rthead)),
M_DEVBUF, M_NOWAIT);
if (sc->sc_rts == NULL) {
splx(s);
return;
}
for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
LIST_INIT(&sc->sc_rts[i]);
}
}
ifp->if_flags |= IFF_RUNNING;
splx(s);
if (sc->sc_brttimeout != 0)
timeout(bridge_rtage, sc, sc->sc_brttimeout);
}
/*
* Stop the bridge and deallocate the routing table.
*/
void
bridge_stop(sc)
struct bridge_softc *sc;
{
struct ifnet *ifp = &sc->sc_if;
/*
* If we're not running, there's nothing to do.
*/
if ((ifp->if_flags & IFF_RUNNING) == 0)
return;
untimeout(bridge_rtage, sc);
bridge_rtflush(sc, IFBF_FLUSHDYN);
ifp->if_flags &= ~IFF_RUNNING;
}
/*
* Send output from the bridge. The mbuf has the ethernet header
* already attached. We must enqueue or free the mbuf before exiting.
*/
int
bridge_output(ifp, m, sa, rt)
struct ifnet *ifp;
struct mbuf *m;
struct sockaddr *sa;
struct rtentry *rt;
{
struct ether_header *eh;
struct ifnet *dst_if;
struct ether_addr *src, *dst;
struct bridge_softc *sc;
int s;
if (m->m_len < sizeof(*eh)) {
m = m_pullup(m, sizeof(*eh));
if (m == NULL)
return (0);
}
eh = mtod(m, struct ether_header *);
dst = (struct ether_addr *)&eh->ether_dhost[0];
src = (struct ether_addr *)&eh->ether_shost[0];
sc = (struct bridge_softc *)ifp->if_bridge;
s = splimp();
/*
* If bridge is down, but original output interface is up,
* go ahead and send out that interface. Otherwise the packet
* is dropped below.
*/
if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
dst_if = ifp;
goto sendunicast;
}
/*
* If the packet is a broadcast or we don't know a better way to
* get there, send to all interfaces.
*/
dst_if = bridge_rtlookup(sc, dst);
if (dst_if == NULL || eh->ether_dhost[0] & 1) {
struct bridge_iflist *p;
struct mbuf *mc;
int used = 0;
#ifdef CYGPKG_NET_BRIDGE_STP_CODE
bridge_span(sc, NULL, m);
#endif
for (p = LIST_FIRST(&sc->sc_iflist); p != NULL;
p = LIST_NEXT(p, next)) {
if ((p->ifp->if_flags & IFF_RUNNING) == 0)
continue;
if (IF_QFULL(&p->ifp->if_snd)) {
sc->sc_if.if_oerrors++;
continue;
}
if (LIST_NEXT(p, next) == NULL) {
used = 1;
mc = m;
} else {
mc = m_copym(m, 0, M_COPYALL, M_NOWAIT);
if (mc == NULL) {
sc->sc_if.if_oerrors++;
continue;
}
}
sc->sc_if.if_opackets++;
sc->sc_if.if_obytes += m->m_pkthdr.len;
// Also count the bytes in the outgoing interface; normally
// done in if_ethersubr.c but here we bypass that route.
p->ifp->if_obytes += m->m_pkthdr.len;
IF_ENQUEUE(&p->ifp->if_snd, mc);
if ((p->ifp->if_flags & IFF_OACTIVE) == 0)
(*p->ifp->if_start)(p->ifp);
}
if (!used)
m_freem(m);
splx(s);
return (0);
}
sendunicast:
if ((dst_if->if_flags & IFF_RUNNING) == 0) {
m_freem(m);
splx(s);
return (0);
}
if (IF_QFULL(&dst_if->if_snd)) {
sc->sc_if.if_oerrors++;
m_freem(m);
splx(s);
return (0);
}
sc->sc_if.if_opackets++;
sc->sc_if.if_obytes += m->m_pkthdr.len;
// Also count the bytes in the outgoing interface; normally
// done in if_ethersubr.c but here we bypass that route.
dst_if->if_obytes += m->m_pkthdr.len;
IF_ENQUEUE(&dst_if->if_snd, m);
if ((dst_if->if_flags & IFF_OACTIVE) == 0)
(*dst_if->if_start)(dst_if);
splx(s);
return (0);
}
/*
* Start output on the bridge. This function should never be called.
*/
void
bridge_start(ifp)
struct ifnet *ifp;
{
}
void
bridgeintr(void)
{
struct bridge_softc *sc;
struct mbuf *m;
int i, s;
for (i = 0; i < CYGNUM_NET_BRIDGES; i++) {
sc = &bridgectl[i];
for (;;) {
s = splimp();
IF_DEQUEUE(&sc->sc_if.if_snd, m);
splx(s);
if (m == NULL)
break;
bridgeintr_frame(sc, m);
}
}
}
/*
* Loop through each bridge interface and process their input queues.
*/
void
bridgeintr_frame(sc, m)
struct bridge_softc *sc;
struct mbuf *m;
{
int s;
struct ifnet *src_if, *dst_if;
struct bridge_iflist *ifl;
struct ether_addr *dst, *src;
struct ether_header eh;
if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
m_freem(m);
return;
}
src_if = m->m_pkthdr.rcvif;
/*
* Pick out 802.1D packets.
* */
#ifdef CYGPKG_NET_BRIDGE_STP_CODE
#ifdef __ECOS
if (m->m_flags & (M_BCAST | M_MCAST)) {
if (bcmp (mtod(m,struct ether_header *), bstp_etheraddr, ETHER_ADDR_LEN) == 0) {
m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&eh);
m_adj (m, sizeof(struct ether_header));
m = bstp_input(sc, src_if, &eh, m);
if (m == NULL)
return;
}
}
#endif // __ECOS
#endif
#if NBPFILTER > 0
if (sc->sc_if.if_bpf)
bpf_mtap(sc->sc_if.if_bpf, m);
#endif
sc->sc_if.if_lastchange = time;
sc->sc_if.if_ipackets++;
sc->sc_if.if_ibytes += m->m_pkthdr.len;
ifl = LIST_FIRST(&sc->sc_iflist);
while (ifl != NULL && ifl->ifp != src_if) {
ifl = LIST_NEXT(ifl, next);
}
if (ifl == NULL) {
m_freem(m);
return;
}
#ifdef CYGPKG_NET_BRIDGE_STP_CODE
if ((ifl->bif_flags & IFBIF_STP) &&
(ifl->bif_state == BSTP_IFSTATE_BLOCKING ||
ifl->bif_state == BSTP_IFSTATE_LISTENING ||
ifl->bif_state == BSTP_IFSTATE_DISABLED)) {
m_freem(m);
return;
}
#endif
if (m->m_pkthdr.len < sizeof(eh)) {
m_freem(m);
return;
}
m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&eh);
dst = (struct ether_addr *)&eh.ether_dhost[0];
src = (struct ether_addr *)&eh.ether_shost[0];
/*
* If interface is learning, and if source address
* is not broadcast or multicast, record it's address.
*/
if ((ifl->bif_flags & IFBIF_LEARNING) &&
(eh.ether_shost[0] & 1) == 0 &&
!(eh.ether_shost[0] == 0 &&
eh.ether_shost[1] == 0 &&
eh.ether_shost[2] == 0 &&
eh.ether_shost[3] == 0 &&
eh.ether_shost[4] == 0 &&
eh.ether_shost[5] == 0))
bridge_rtupdate(sc, src, src_if, 0, IFBAF_DYNAMIC);
#ifdef CYGPKG_NET_BRIDGE_STP_CODE
if ((ifl->bif_flags & IFBIF_STP) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -