if_bridge.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,353 行 · 第 1/4 页
C
2,353 行
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. */voidbridge_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; }}intbridge_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); }#endifdone: bifc->ifbic_len = i * sizeof(breq); return (error);}intbridge_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);}voidbridge_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. */voidbridge_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. */intbridge_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. */voidbridge_start(ifp) struct ifnet *ifp;{}voidbridgeintr(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. */voidbridgeintr_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 + =
减小字号Ctrl + -
显示快捷键?