📄 if_bridge.c
字号:
return (c & BRIDGE_RTABLE_MASK);
}
/*
* Trim the routing table so that we've got a number of routes
* less than or equal to the maximum.
*/
void
bridge_rttrim(sc)
struct bridge_softc *sc;
{
struct bridge_rtnode *n, *p;
int s, i;
s = splhigh();
if (sc->sc_rts == NULL)
goto done;
/*
* Make sure we have to trim the address table
*/
if (sc->sc_brtcnt <= sc->sc_brtmax)
goto done;
/*
* Force an aging cycle, this might trim enough addresses.
*/
splx(s);
bridge_rtage(sc);
s = splhigh();
if (sc->sc_brtcnt <= sc->sc_brtmax)
goto done;
for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
n = LIST_FIRST(&sc->sc_rts[i]);
while (n != NULL) {
p = LIST_NEXT(n, brt_next);
if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
LIST_REMOVE(n, brt_next);
sc->sc_brtcnt--;
free(n, M_DEVBUF);
n = p;
if (sc->sc_brtcnt <= sc->sc_brtmax)
goto done;
}
}
}
done:
if (sc->sc_rts != NULL && sc->sc_brtcnt == 0 &&
(sc->sc_if.if_flags & IFF_UP) == 0) {
free(sc->sc_rts, M_DEVBUF);
sc->sc_rts = NULL;
}
splx(s);
}
/*
* Perform an aging cycle
*/
void
bridge_rtage(vsc)
void *vsc;
{
struct bridge_softc *sc = (struct bridge_softc *)vsc;
struct bridge_rtnode *n, *p;
int s, i;
s = splhigh();
if (sc->sc_rts == NULL) {
splx(s);
return;
}
for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
n = LIST_FIRST(&sc->sc_rts[i]);
while (n != NULL) {
if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
n->brt_age = !n->brt_age;
if (n->brt_age)
n->brt_age = 0;
n = LIST_NEXT(n, brt_next);
} else if (n->brt_age) {
n->brt_age = 0;
n = LIST_NEXT(n, brt_next);
} else {
p = LIST_NEXT(n, brt_next);
LIST_REMOVE(n, brt_next);
sc->sc_brtcnt--;
free(n, M_DEVBUF);
n = p;
}
}
}
splx(s);
if (sc->sc_brttimeout != 0)
timeout(bridge_rtage, sc, sc->sc_brttimeout);
}
/*
* Remove all dynamic addresses from the cache
*/
int
bridge_rtflush(sc, full)
struct bridge_softc *sc;
int full;
{
int s, i;
struct bridge_rtnode *p, *n;
s = splhigh();
if (sc->sc_rts == NULL)
goto done;
for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
n = LIST_FIRST(&sc->sc_rts[i]);
while (n != NULL) {
if (full ||
(n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
p = LIST_NEXT(n, brt_next);
LIST_REMOVE(n, brt_next);
sc->sc_brtcnt--;
free(n, M_DEVBUF);
n = p;
} else
n = LIST_NEXT(n, brt_next);
}
}
if (sc->sc_brtcnt == 0 && (sc->sc_if.if_flags & IFF_UP) == 0) {
free(sc->sc_rts, M_DEVBUF);
sc->sc_rts = NULL;
}
done:
splx(s);
return (0);
}
/*
* Remove an address from the cache
*/
int
bridge_rtdaddr(sc, ea)
struct bridge_softc *sc;
struct ether_addr *ea;
{
int h, s;
struct bridge_rtnode *p;
s = splhigh();
if (sc->sc_rts == NULL)
goto done;
h = bridge_hash(ea);
p = LIST_FIRST(&sc->sc_rts[h]);
while (p != NULL) {
if (bcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
LIST_REMOVE(p, brt_next);
sc->sc_brtcnt--;
free(p, M_DEVBUF);
if (sc->sc_brtcnt == 0 &&
(sc->sc_if.if_flags & IFF_UP) == 0) {
free(sc->sc_rts, M_DEVBUF);
sc->sc_rts = NULL;
}
splx(s);
return (0);
}
p = LIST_NEXT(p, brt_next);
}
done:
splx(s);
return (ENOENT);
}
/*
* Delete routes to a specific interface member.
*/
void
bridge_rtdelete(sc, ifp, dynonly)
struct bridge_softc *sc;
struct ifnet *ifp;
{
int i, s;
struct bridge_rtnode *n, *p;
s = splhigh();
if (sc->sc_rts == NULL)
goto done;
/*
* Loop through all of the hash buckets and traverse each
* chain looking for routes to this interface.
*/
for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
n = LIST_FIRST(&sc->sc_rts[i]);
while (n != NULL) {
if (n->brt_if == ifp) { /* found one */
p = LIST_NEXT(n, brt_next);
LIST_REMOVE(n, brt_next);
sc->sc_brtcnt--;
free(n, M_DEVBUF);
n = p;
} else
n = LIST_NEXT(n, brt_next);
}
}
if (sc->sc_brtcnt == 0 && (sc->sc_if.if_flags & IFF_UP) == 0) {
free(sc->sc_rts, M_DEVBUF);
sc->sc_rts = NULL;
}
done:
splx(s);
}
/*
* Gather all of the routes for this interface.
*/
int
bridge_rtfind(sc, baconf)
struct bridge_softc *sc;
struct ifbaconf *baconf;
{
int i, s, error = 0;
u_int32_t cnt = 0;
struct bridge_rtnode *n;
struct ifbareq bareq;
s = splhigh();
if (sc->sc_rts == NULL || baconf->ifbac_len == 0)
goto done;
for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
n = LIST_FIRST(&sc->sc_rts[i]);
while (n != NULL) {
if (baconf->ifbac_len <
(cnt + 1) * sizeof(struct ifbareq))
goto done;
bcopy(sc->sc_if.if_xname, bareq.ifba_name,
sizeof(bareq.ifba_name));
bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
sizeof(bareq.ifba_ifsname));
bcopy(&n->brt_addr, &bareq.ifba_dst,
sizeof(bareq.ifba_dst));
bareq.ifba_age = n->brt_age;
bareq.ifba_flags = n->brt_flags;
error = copyout((caddr_t)&bareq,
(caddr_t)(baconf->ifbac_req + cnt), sizeof(bareq));
if (error)
goto done;
n = LIST_NEXT(n, brt_next);
cnt++;
}
}
done:
baconf->ifbac_len = cnt * sizeof(struct ifbareq);
splx(s);
return (error);
}
/*
* Block non-ip frames:
* Returns 0 if frame is ip, and 1 if it should be dropped.
*/
int
bridge_blocknonip(eh, m)
struct ether_header *eh;
struct mbuf *m;
{
struct snap snap;
u_int16_t etype;
if (m->m_pkthdr.len < sizeof(struct ether_header))
return (1);
etype = ntohs(eh->ether_type);
switch (etype) {
case ETHERTYPE_ARP:
case ETHERTYPE_REVARP:
case ETHERTYPE_IP:
case ETHERTYPE_IPV6:
return (0);
}
if (etype > ETHERMTU)
return (1);
if (m->m_pkthdr.len <
(sizeof(struct ether_header) + sizeof(struct snap)))
return (1);
m_copydata(m, sizeof(struct ether_header), sizeof(struct snap),
(caddr_t)&snap);
etype = ntohs(snap.type);
if (snap.dsap == LLC_SNAP_LSAP && snap.ssap == LLC_SNAP_LSAP &&
snap.control == LLC_UI &&
snap.org[0] == 0 && snap.org[1] == 0 && snap.org[2] == 0 &&
(etype == ETHERTYPE_ARP ||
etype == ETHERTYPE_REVARP ||
etype == ETHERTYPE_IP ||
etype == ETHERTYPE_IPV6)) {
return (0);
}
return (1);
}
u_int8_t
bridge_filterrule(n, eh)
struct brl_node *n;
struct ether_header *eh;
{
u_int8_t flags;
for (; n != NULL; n = SIMPLEQ_NEXT(n, brl_next)) {
flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
if (flags == 0)
return (n->brl_action);
if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) {
if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
continue;
if (bcmp(eh->ether_dhost, &n->brl_src, ETHER_ADDR_LEN))
continue;
return (n->brl_action);
}
if (flags == BRL_FLAG_SRCVALID) {
if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
continue;
return (n->brl_action);
}
if (flags == BRL_FLAG_DSTVALID) {
if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
continue;
return (n->brl_action);
}
}
return (BRL_ACTION_PASS);
}
int
bridge_addrule(bif, req, out)
struct bridge_iflist *bif;
struct ifbrlreq *req;
int out;
{
struct brl_node *n;
n = (struct brl_node *)malloc(sizeof(struct brl_node), M_DEVBUF, M_NOWAIT);
if (n == NULL)
return (ENOMEM);
bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr));
bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr));
n->brl_action = req->ifbr_action;
n->brl_flags = req->ifbr_flags;
if (out) {
n->brl_flags &= ~BRL_FLAG_IN;
n->brl_flags |= BRL_FLAG_OUT;
SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next);
} else {
n->brl_flags &= ~BRL_FLAG_OUT;
n->brl_flags |= BRL_FLAG_IN;
SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next);
}
return (0);
}
int
bridge_flushrule(bif)
struct bridge_iflist *bif;
{
struct brl_node *p, *q;
p = SIMPLEQ_FIRST(&bif->bif_brlin);
while (p != NULL) {
q = SIMPLEQ_NEXT(p, brl_next);
SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, p, brl_next);
free(p, M_DEVBUF);
p = q;
}
p = SIMPLEQ_FIRST(&bif->bif_brlout);
while (p != NULL) {
q = SIMPLEQ_NEXT(p, brl_next);
SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, p, brl_next);
free(p, M_DEVBUF);
p = q;
}
return (0);
}
#if defined(INET) && (defined(IPFILTER) || defined(IPFILTER_LKM))
/*
* Maximum sized IP header
*/
union maxip {
struct ip ip;
u_int32_t _padding[16];
};
/*
* 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
* 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
*/
struct mbuf *
bridge_filter(sc, ifp, eh, m)
struct bridge_softc *sc;
struct ifnet *ifp;
struct ether_header *eh;
struct mbuf *m;
{
struct snap snap;
int hassnap = 0;
struct ip *ip;
int hlen;
if (fr_checkp == NULL)
return (m);
if (eh->ether_type != htons(ETHERTYPE_IP)) {
if (eh->ether_type > ETHERMTU ||
m->m_pkthdr.len < (sizeof(struct snap) +
sizeof(struct ether_header)))
return (m);
m_copydata(m, sizeof(struct ether_header),
sizeof(struct snap), (caddr_t)&snap);
if (snap.dsap != LLC_SNAP_LSAP || snap.ssap != LLC_SNAP_LSAP ||
snap.control != LLC_UI ||
snap.org[0] != 0 || snap.org[1] != 0 || snap.org[2] ||
snap.type != htons(ETHERTYPE_IP))
return (m);
hassnap = 1;
}
m_adj(m, sizeof(struct ether_header));
if (hassnap)
m_adj(m, sizeof(struct snap));
if (m->m_pkthdr.len < sizeof(struct ip))
goto dropit;
/* Copy minimal header, and drop invalids */
if (m->m_len < sizeof(struct ip) &&
(m = m_pullup(m, sizeof(struct ip))) == NULL)
return (NULL);
ip = mtod(m, struct ip *);
if (ip->ip_v != IPVERSION)
goto dropit;
hlen = ip->ip_hl << 2; /* get whole header length */
if (hlen < sizeof(struct ip))
goto dropit;
if (hlen > m->m_len) {
if ((m = m_pullup(m, sizeof(struct ip))) == NULL)
return (NULL);
ip = mtod(m, struct ip *);
}
if ((ip->ip_sum = in_cksum(m, hlen)) != 0)
goto dropit;
NTOHS(ip->ip_len);
if (ip->ip_len < hlen)
goto dropit;
NTOHS(ip->ip_id);
NTOHS(ip->ip_off);
if (m->m_pkthdr.len < ip->ip_len)
goto dropit;
if (m->m_pkthdr.len > ip->ip_len) {
if (m->m_len == m->m_pkthdr.len) {
m->m_len = ip->ip_len;
m->m_pkthdr.len = ip->ip_len;
} else
m_adj(m, ip->ip_len - m->m_pkthdr.len);
}
/* Finally, we get to filter the packet! */
if (fr_checkp && (*fr_checkp)(ip, hlen, ifp, 0, &m))
return (NULL);
/* Rebuild the IP header */
if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL))
return (NULL);
if (m->m_len < sizeof(struct ip))
goto dropit;
ip = mtod(m, struct ip *);
HTONS(ip->ip_len);
HTONS(ip->ip_id);
HTONS(ip->ip_off);
ip->ip_sum = in_cksum(m, hlen);
/* Reattach SNAP header */
if (hassnap) {
M_PREPEND(m, sizeof(snap), M_DONTWAIT);
if (m == NULL)
goto dropit;
bcopy(&snap, mtod(m, caddr_t), sizeof(snap));
}
/* Reattach ethernet header */
M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
if (m == NULL)
goto dropit;
bcopy(eh, mtod(m, caddr_t), sizeof(*eh));
return (m);
dropit:
if (m != NULL)
m_freem(m);
return (NULL);
}
#endif
int
ifpromisc(ifp, pswitch)
struct ifnet *ifp;
int pswitch;
{
struct ifreq ifr;
if (pswitch) {
/*
* If the device is not configured up, we cannot put it in
* promiscuous mode.
*/
if ((ifp->if_flags & IFF_UP) == 0)
return (ENETDOWN);
if (ifp->if_pcount++ != 0)
return (0);
ifp->if_flags |= IFF_PROMISC;
} else {
if (--ifp->if_pcount > 0)
return (0);
ifp->if_flags &= ~IFF_PROMISC;
/*
* If the device is not configured up, we should not need to
* turn off promiscuous mode (device should have turned it
* off when interface went down; and will look at IFF_PROMISC
* again next time interface comes up).
*/
if ((ifp->if_flags & IFF_UP) == 0)
return (0);
}
ifr.ifr_flags = ifp->if_flags;
return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
}
int
bridge_ifenqueue(sc, ifp, m)
struct bridge_softc *sc;
struct ifnet *ifp;
struct mbuf *m;
{
int error, len;
short mflags;
len = m->m_pkthdr.len;
mflags = m->m_flags;
IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
if (error) {
sc->sc_if.if_oerrors++;
return (error);
}
sc->sc_if.if_opackets++;
sc->sc_if.if_obytes += len;
ifp->if_obytes += len;
if (mflags & M_MCAST)
ifp->if_omcasts++;
if ((ifp->if_flags & IFF_OACTIVE) == 0)
(*ifp->if_start)(ifp);
return (0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -