diff options
| author | Luigi Rizzo <luigi@FreeBSD.org> | 2002-07-09 09:11:43 +0000 |
|---|---|---|
| committer | Luigi Rizzo <luigi@FreeBSD.org> | 2002-07-09 09:11:43 +0000 |
| commit | 539f5f9799c74500b284aca343f10e381c31cc89 (patch) | |
| tree | 65b54fcf6ff748e8032791ecef0bb5465f510be8 /sys/net | |
| parent | bb71e47610a9702cf4fea7af80f9fda65499ae30 (diff) | |
Notes
Diffstat (limited to 'sys/net')
| -rw-r--r-- | sys/net/bridge.c | 194 | ||||
| -rw-r--r-- | sys/net/if_ethersubr.c | 214 |
2 files changed, 289 insertions, 119 deletions
diff --git a/sys/net/bridge.c b/sys/net/bridge.c index 2a011de7fcab..565413c8b97a 100644 --- a/sys/net/bridge.c +++ b/sys/net/bridge.c @@ -1,6 +1,8 @@ /* * Copyright (c) 1998-2002 Luigi Rizzo * + * Work partly supported by: Cisco Systems, Inc. - NSITE lab, RTP, NC + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -89,14 +91,19 @@ #include <sys/param.h> #include <sys/mbuf.h> #include <sys/malloc.h> +#include <sys/protosw.h> #include <sys/systm.h> #include <sys/socket.h> /* for net/if.h */ #include <sys/ctype.h> /* string functions */ #include <sys/kernel.h> #include <sys/sysctl.h> +#if 0 /* XXX does not work yet */ +#include <net/pfil.h> /* for ipfilter */ +#endif #include <net/if.h> #include <net/if_types.h> +#include <net/if_var.h> #include <netinet/in.h> /* for struct arpcom */ #include <netinet/in_systm.h> @@ -151,6 +158,9 @@ struct cluster_softc { }; +extern struct protosw inetsw[]; /* from netinet/ip_input.c */ +extern u_char ip_protox[]; /* from netinet/ip_input.c */ + static int n_clusters; /* number of clusters */ static struct cluster_softc *clusters; @@ -193,7 +203,8 @@ static struct cluster_softc *clusters; static int bdginit(void); static void parse_bdg_cfg(void); -static int bdg_ipfw = 0 ; +static int bdg_ipf; /* IPFilter enabled in bridge */ +static int bdg_ipfw; #if 0 /* debugging only */ static char *bdg_dst_names[] = { @@ -387,7 +398,7 @@ reconfigure_bridge(void) } } -static char bridge_cfg[1024] = { "" } ; +static char bridge_cfg[1024]; /* in BSS so initialized to all NULs */ /* * parse the config string, set IFF_USED, name and cluster_id @@ -427,10 +438,10 @@ parse_bdg_cfg() * now search in interface list for a matching name */ TAILQ_FOREACH(ifp, &ifnet, if_link) { - char buf[32]; + char buf[IFNAMSIZ]; - sprintf(buf, "%s%d", ifp->if_name, ifp->if_unit); - if (!strncmp(beg, buf, l)) { + snprintf(buf, sizeof(buf), "%s%d", ifp->if_name, ifp->if_unit); + if (!strncmp(beg, buf, max(l, strlen(buf)))) { struct bdg_softc *b = &ifp2sc[ifp->if_index]; if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_L2VLAN) { printf("%s is not an ethernet, continue\n", buf); @@ -522,6 +533,9 @@ SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge, CTLTYPE_INT|CTLFLAG_RW, SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw, CTLFLAG_RW, &bdg_ipfw,0,"Pass bridged pkts through firewall"); +SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipf, CTLFLAG_RW, + &bdg_ipf, 0,"Pass bridged pkts through IPFilter"); + /* * The follow macro declares a variable, and maps it to * a SYSCTL_INT entry with the same name. @@ -569,7 +583,7 @@ static int bdg_loops ; static void bdg_timeout(void *dummy) { - static int slowtimer = 0 ; + static int slowtimer; /* in BSS so initialized to 0 */ if (do_bridge) { static int age_index = 0 ; /* index of table position to age */ @@ -781,13 +795,16 @@ bridge_in(struct ifnet *ifp, struct ether_header *eh) static struct mbuf * bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst) { - struct ifnet *src = m0->m_pkthdr.rcvif; /* NULL when called by *_output */ - struct ifnet *ifp, *last = NULL ; - int s ; + struct ifnet *src; + struct ifnet *ifp, *last; int shared = bdg_copy ; /* someone else is using the mbuf */ int once = 0; /* loop only once */ struct ifnet *real_dst = dst ; /* real dst from ether_output */ - struct ip_fw *rule = NULL ; /* did we match a firewall rule ? */ + struct ip_fw_args args; +#ifdef PFIL_HOOKS + struct packet_filter_hook *pfh; + int rv; +#endif /* PFIL_HOOKS */ /* * XXX eh is usually a pointer within the mbuf (some ethernet drivers @@ -798,16 +815,18 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst) DEB(quad_t ticks; ticks = rdtsc();) - if (m0->m_type == MT_DUMMYNET) { - /* extract info from dummynet header */ - rule = (struct ip_fw *)(m0->m_data) ; - m0 = m0->m_next ; - src = m0->m_pkthdr.rcvif; - shared = 0 ; /* For sure this is our own mbuf. */ - } else - bdg_thru++; /* count packet, only once */ + args.rule = NULL; /* did we match a firewall rule ? */ + /* Fetch state from dummynet tag, ignore others */ + for (;m0->m_type == MT_TAG; m0 = m0->m_next) + if (m0->m_tag_id == PACKET_TAG_DUMMYNET) { + args.rule = ((struct dn_pkt *)m0)->rule; + shared = 0; /* For sure this is our own mbuf. */ + } + if (args.rule == NULL) + bdg_thru++; /* first time through bdg_forward, count packet */ - if (src == NULL) /* packet from ether_output */ + src = m0->m_pkthdr.rcvif; + if (src == NULL) /* packet from ether_output */ dst = bridge_dst_lookup(eh, ifp2sc[real_dst->if_index].cluster); if (dst == BDG_DROP) { /* this should not happen */ @@ -838,16 +857,16 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst) * Additional restrictions may apply e.g. non-IP, short packets, * and pkts already gone through a pipe. */ - if (IPFW_LOADED && bdg_ipfw != 0 && src != NULL) { - struct ip *ip ; + if (src != NULL && ( +#ifdef PFIL_HOOKS + ((pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh)) != NULL && bdg_ipf !=0) || +#endif + (IPFW_LOADED && bdg_ipfw != 0))) { + int i; - if (rule != NULL) /* dummynet packet, already partially processed */ + if (args.rule != NULL) /* packet already partially processed */ goto forward; /* HACK! I should obey the fw_one_pass */ - if (ntohs(save_eh.ether_type) != ETHERTYPE_IP) - goto forward ; /* not an IP packet, ipfw is not appropriate */ - if (m0->m_pkthdr.len < sizeof(struct ip) ) - goto forward ; /* header too short for an IP pkt, cannot filter */ /* * i need some amt of data to be contiguous, and in case others need * the packet (shared==1) also better be in the first mbuf. @@ -861,30 +880,60 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst) } } +#ifdef PFIL_HOOKS /* - * before calling the firewall, swap fields the same as IP does. - * here we assume the pkt is an IP one and the header is contiguous + * NetBSD-style generic packet filter, pfil(9), hooks. + * Enables ipf(8) in bridging. */ - ip = mtod(m0, struct ip *); - NTOHS(ip->ip_len); - NTOHS(ip->ip_off); + if (m0->m_pkthdr.len >= sizeof(struct ip) && + ntohs(save_eh.ether_type) == ETHERTYPE_IP) { + /* + * before calling the firewall, swap fields the same as IP does. + * here we assume the pkt is an IP one and the header is contiguous + */ + struct ip *ip = mtod(m0, struct ip *); + + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); + + for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link)) + if (pfh->pfil_func) { + rv = pfh->pfil_func(ip, ip->ip_hl << 2, src, 0, &m0); + if (rv != 0 || m0 == NULL) + return m0; + ip = mtod(m0, struct ip *); + } + /* + * If we get here, the firewall has passed the pkt, but the mbuf + * pointer might have changed. Restore ip and the fields ntohs()'d. + */ + ip = mtod(m0, struct ip *); + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); + } +#endif /* PFIL_HOOKS */ /* - * The third parameter to the firewall code is the dst. interface. - * Since we apply checks only on input pkts we use NULL. - * The firewall knows this is a bridged packet as the cookie ptr - * is NULL. + * Prepare arguments and call the firewall. */ - i = ip_fw_chk_ptr(&ip, 0, NULL, NULL /* cookie */, &m0, &rule, NULL); - if ( (i & IP_FW_PORT_DENY_FLAG) || m0 == NULL) /* drop */ - return m0 ; + if (!IPFW_LOADED || bdg_ipfw == 0) + goto forward; /* not using ipfw, accept the packet */ + /* - * If we get here, the firewall has passed the pkt, but the mbuf - * pointer might have changed. Restore ip and the fields NTOHS()'d. + * XXX The following code is very similar to the one in + * if_ethersubr.c:ether_ipfw_chk() */ - ip = mtod(m0, struct ip *); - HTONS(ip->ip_len); - HTONS(ip->ip_off); + + args.m = m0; /* the packet we are looking at */ + args.oif = NULL; /* this is an input packet */ + args.divert_rule = 0; /* we do not support divert yet */ + args.next_hop = NULL; /* we do not support forward yet */ + args.eh = &save_eh; /* MAC header for bridged/MAC packets */ + i = ip_fw_chk_ptr(&args); + m0 = args.m; /* in case the firewall used the mbuf */ + + if ( (i & IP_FW_PORT_DENY_FLAG) || m0 == NULL) /* drop */ + return m0 ; if (i == 0) /* a PASS rule. */ goto forward ; @@ -892,20 +941,21 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst) /* * Pass the pkt to dummynet, which consumes it. * If shared, make a copy and keep the original. - * Need to prepend the ethernet header, optimize the common - * case of eh pointing already into the original mbuf. */ struct mbuf *m ; + if (shared) { m = m_copypacket(m0, M_DONTWAIT); - if (m == NULL) { - printf("bdg_fwd: copy(1) failed\n"); + if (m == NULL) /* copy failed, give up */ return m0; - } } else { m = m0 ; /* pass the original to dummynet */ m0 = NULL ; /* and nothing back to the caller */ } + /* + * Prepend the header, optimize for the common case of + * eh pointing into the mbuf. + */ if ( (void *)(eh + 1) == (void *)m->m_data) { m->m_data -= ETHER_HDR_LEN ; m->m_len += ETHER_HDR_LEN ; @@ -913,21 +963,20 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst) bdg_predict++; } else { M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT); - if (!m && verbose) - printf("M_PREPEND failed\n"); if (m == NULL) /* nope... */ return m0 ; bcopy(&save_eh, mtod(m, struct ether_header *), ETHER_HDR_LEN); } - ip_dn_io_ptr((i & 0xffff),DN_TO_BDG_FWD,m,real_dst,NULL,0,rule,0); + + args.oif = real_dst; + ip_dn_io_ptr(m, (i & 0xffff),DN_TO_BDG_FWD, &args); return m0 ; } /* - * XXX add divert/forward actions... + * XXX at some point, add support for divert/forward actions. + * If none of the above matches, we have to drop the packet. */ - /* if none of the above matches, we have to drop the pkt */ bdg_ipfw_drops++ ; - printf("bdg_forward: No rules match, so dropping packet!\n"); return m0 ; } forward: @@ -939,14 +988,20 @@ forward: int i = min(m0->m_pkthdr.len, max_protohdr) ; m0 = m_pullup(m0, i) ; - if (m0 == NULL) { - printf("-- bdg: pullup2 failed.\n") ; + if (m0 == NULL) return NULL ; - } } - /* now real_dst is used to determine the cluster where to forward */ - if (src != NULL) /* pkt comes from ether_input */ + /* + * now real_dst is used to determine the cluster where to forward. + * For packets coming from ether_input, this is the one of the 'src' + * interface, whereas for locally generated packets (src==NULL) it + * is the cluster of the original destination interface, which + * was already saved into real_dst. + */ + if (src != NULL) real_dst = src ; + + last = NULL; for (;;) { if (last) { /* need to forward packet leftover from previous loop */ struct mbuf *m ; @@ -972,31 +1027,16 @@ forward: bdg_predict++; } else { M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT); - if (!m && verbose) + if (!m && verbose) printf("M_PREPEND failed\n"); if (m == NULL) return m0; bcopy(&save_eh, mtod(m, struct ether_header *), ETHER_HDR_LEN); } - s = splimp(); - if (IF_QFULL(&last->if_snd)) { - IF_DROP(&last->if_snd); + if (!IF_HANDOFF(&last->if_snd, m, last)) { #if 0 BDG_MUTE(last); /* should I also mute ? */ #endif - splx(s); - m_freem(m); /* consume the pkt anyways */ - } else { - last->if_obytes += m->m_pkthdr.len ; - if (m->m_flags & M_MCAST) - last->if_omcasts++; - if (m->m_pkthdr.len != m->m_len) /* this pkt is on >1 bufs */ - bdg_split_pkts++; - - IF_ENQUEUE(&last->if_snd, m); - if ((last->if_flags & IFF_OACTIVE) == 0) - (*last->if_start)(last); - splx(s); } BDG_STAT(last, BDG_OUT); last = NULL ; @@ -1010,7 +1050,7 @@ forward: * up and running, is not the source interface, and belongs to * the same cluster as the 'real_dst', then send here. */ - if ( BDG_USED(ifp) && !BDG_MUTED(ifp) && !IF_QFULL(&ifp->if_snd) && + if ( BDG_USED(ifp) && !BDG_MUTED(ifp) && !_IF_QFULL(&ifp->if_snd) && (ifp->if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING) && ifp != src && BDG_SAMECLUSTER(ifp, real_dst) ) last = ifp ; diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 33a695854b1f..02931af121af 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -64,6 +64,8 @@ #include <netinet/in.h> #include <netinet/in_var.h> #include <netinet/if_ether.h> +#include <netinet/ip_fw.h> +#include <netinet/ip_dummynet.h> #endif #ifdef INET6 #include <netinet6/nd6.h> @@ -106,23 +108,28 @@ int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp); void (*ng_ether_attach_p)(struct ifnet *ifp); void (*ng_ether_detach_p)(struct ifnet *ifp); +int (*vlan_input_p)(struct ether_header *eh, struct mbuf *m); +int (*vlan_input_tag_p)(struct ether_header *eh, struct mbuf *m, + u_int16_t t); + /* bridge support */ -int do_bridge = 0; +int do_bridge; bridge_in_t *bridge_in_ptr; bdg_forward_t *bdg_forward_ptr; bdgtakeifaces_t *bdgtakeifaces_ptr; -struct bdg_softc *ifp2sc = NULL; - -int (*vlan_input_p)(struct ether_header *eh, struct mbuf *m); -int (*vlan_input_tag_p)(struct ether_header *eh, struct mbuf *m, - u_int16_t t); +struct bdg_softc *ifp2sc; -static int ether_resolvemulti __P((struct ifnet *, struct sockaddr **, - struct sockaddr *)); +static int ether_resolvemulti(struct ifnet *, struct sockaddr **, + struct sockaddr *); u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; #define senderr(e) do { error = (e); goto bad;} while (0) #define IFP2AC(IFP) ((struct arpcom *)IFP) +int +ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, + struct ip_fw **rule, struct ether_header *eh, int shared); +static int ether_ipfw; + /* * Ethernet output routine. * Encapsulate a packet of type family for the local net. @@ -142,7 +149,7 @@ ether_output(ifp, m, dst, rt0) u_char esrc[6], edst[6]; register struct rtentry *rt; register struct ether_header *eh; - int off, loop_copy = 0; + int loop_copy = 0; int hlen; /* link layer header lenght */ struct arpcom *ac = IFP2AC(ifp); @@ -179,7 +186,6 @@ ether_output(ifp, m, dst, rt0) case AF_INET: if (!arpresolve(ifp, rt, m, dst, edst, rt0)) return (0); /* if not yet resolved */ - off = m->m_pkthdr.len - m->m_len; type = htons(ETHERTYPE_IP); break; #endif @@ -189,7 +195,6 @@ ether_output(ifp, m, dst, rt0) /* Something bad happened */ return(0); } - off = m->m_pkthdr.len - m->m_len; type = htons(ETHERTYPE_IPV6); break; #endif @@ -236,7 +241,7 @@ ether_output(ifp, m, dst, rt0) } break; } -#endif NETATALK +#endif /* NETATALK */ #ifdef NS case AF_NS: switch(ns_nettype){ @@ -266,15 +271,9 @@ ether_output(ifp, m, dst, rt0) */ if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))){ m->m_pkthdr.rcvif = ifp; - schednetisr(NETISR_NS); inq = &nsintrq; - s = splimp(); - if (IF_QFULL(inq)) { - IF_DROP(inq); - m_freem(m); - } else - IF_ENQUEUE(inq, m); - splx(s); + if (IF_HANDOFF(inq, m, NULL)) + schednetisr(NETISR_NS); return (error); } if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof(edst))){ @@ -380,7 +379,17 @@ ether_output_frame(ifp, m) struct ifnet *ifp; struct mbuf *m; { - int s, error = 0; + int error = 0; + int s; + struct ip_fw *rule = NULL; + + /* Extract info from dummynet tag, ignore others */ + for (; m->m_type == MT_TAG; m = m->m_next) + if (m->m_flags == PACKET_TAG_DUMMYNET) + rule = ((struct dn_pkt *)m)->rule; + + if (rule) /* packet was already bridged */ + goto no_bridge; if (BDG_ACTIVE(ifp) ) { struct ether_header *eh; /* a ptr suffices */ @@ -394,28 +403,132 @@ ether_output_frame(ifp, m) return (0); } +no_bridge: s = splimp(); + if (IPFW_LOADED && ether_ipfw != 0) { + struct ether_header save_eh, *eh; + + eh = mtod(m, struct ether_header *); + save_eh = *eh; + m_adj(m, ETHER_HDR_LEN); + if (ether_ipfw_chk(&m, ifp, &rule, eh, 0) == 0) { + if (m) { + m_freem(m); + return ENOBUFS; /* pkt dropped */ + } else + return 0; /* consumed e.g. in a pipe */ + } + /* packet was ok, restore the ethernet header */ + if ( (void *)(eh + 1) == (void *)m->m_data) { + m->m_data -= ETHER_HDR_LEN ; + m->m_len += ETHER_HDR_LEN ; + m->m_pkthdr.len += ETHER_HDR_LEN ; + } else { + M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT); + if (m == NULL) /* nope... */ + return ENOBUFS; + bcopy(&save_eh, mtod(m, struct ether_header *), + ETHER_HDR_LEN); + } + } + /* * Queue message on interface, update output statistics if * successful, and start output if interface not yet active. */ - if (IF_QFULL(&ifp->if_snd)) { - IF_DROP(&ifp->if_snd); - splx(s); - m_freem(m); - return (ENOBUFS); - } - ifp->if_obytes += m->m_pkthdr.len; - if (m->m_flags & M_MCAST) - ifp->if_omcasts++; - IF_ENQUEUE(&ifp->if_snd, m); - if ((ifp->if_flags & IFF_OACTIVE) == 0) - (*ifp->if_start)(ifp); + if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) + error = ENOBUFS; splx(s); return (error); } /* + * ipfw processing for ethernet packets (in and out). + * The second parameter is NULL from ether_demux, and ifp from + * ether_output_frame. This section of code could be used from + * bridge.c as well as long as we use some extra info + * to distinguish that case from ether_output_frame(); + */ +int +ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, + struct ip_fw **rule, struct ether_header *eh, int shared) +{ + struct ether_header save_eh = *eh; /* might be a ptr in m */ + int i; + struct ip_fw_args args; + + if (*rule != NULL) /* dummynet packet, already partially processed */ + return 1; /* HACK! I should obey the fw_one_pass */ + + /* + * I need some amt of data to be contiguous, and in case others need + * the packet (shared==1) also better be in the first mbuf. + */ + i = min( (*m0)->m_pkthdr.len, max_protohdr); + if ( shared || (*m0)->m_len < i) { + *m0 = m_pullup(*m0, i); + if (*m0 == NULL) + return 0; + } + + args.m = *m0; /* the packet we are looking at */ + args.oif = dst; /* destination, if any */ + args.divert_rule = 0; /* we do not support divert yet */ + args.rule = *rule; /* matching rule to restart */ + args.next_hop = NULL; /* we do not support forward yet */ + args.eh = &save_eh; /* MAC header for bridged/MAC packets */ + i = ip_fw_chk_ptr(&args); + *m0 = args.m; + *rule = args.rule; + + if ( (i & IP_FW_PORT_DENY_FLAG) || *m0 == NULL) /* drop */ + return 0; + + if (i == 0) /* a PASS rule. */ + return 1; + + if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG)) { + /* + * Pass the pkt to dummynet, which consumes it. + * If shared, make a copy and keep the original. + */ + struct mbuf *m ; + + if (shared) { + m = m_copypacket(*m0, M_DONTWAIT); + if (m == NULL) + return 0; + } else { + m = *m0 ; /* pass the original to dummynet */ + *m0 = NULL ; /* and nothing back to the caller */ + } + /* + * Prepend the header, optimize for the common case of + * eh pointing into the mbuf. + */ + if ( (void *)(eh + 1) == (void *)m->m_data) { + m->m_data -= ETHER_HDR_LEN ; + m->m_len += ETHER_HDR_LEN ; + m->m_pkthdr.len += ETHER_HDR_LEN ; + } else { + M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT); + if (m == NULL) /* nope... */ + return 0; + bcopy(&save_eh, mtod(m, struct ether_header *), + ETHER_HDR_LEN); + } + ip_dn_io_ptr(m, (i & 0xffff), + dst ? DN_TO_ETH_OUT: DN_TO_ETH_DEMUX, &args); + return 0; + } + /* + * XXX at some point add support for divert/forward actions. + * If none of the above matches, we have to drop the pkt. + */ + return 0; +} + +/* * Process a received Ethernet packet; * the packet is in the mbuf chain m without * the ether header, which is provided separately. @@ -514,10 +627,20 @@ ether_demux(ifp, eh, m) { struct ifqueue *inq; u_short ether_type; - int s; #if defined(NETATALK) register struct llc *l; #endif + struct ip_fw *rule = NULL; + + /* Extract info from dummynet tag, ignore others */ + for (;m->m_type == MT_TAG; m = m->m_next) + if (m->m_flags == PACKET_TAG_DUMMYNET) { + rule = ((struct dn_pkt *)m)->rule; + ifp = m->m_next->m_pkthdr.rcvif; + } + + if (rule) /* packet was already bridged */ + goto post_stats; if (! (BDG_ACTIVE(ifp) ) ) /* Discard packet if upper layers shouldn't see it because it was @@ -547,6 +670,15 @@ ether_demux(ifp, eh, m) if (m->m_flags & (M_BCAST|M_MCAST)) ifp->if_imcasts++; +post_stats: + if (IPFW_LOADED && ether_ipfw != 0) { + if (ether_ipfw_chk(&m, NULL, &rule, eh, 0 ) == 0) { + if (m) + m_freem(m); + return; + } + } + ether_type = ntohs(eh->ether_type); switch (ether_type) { @@ -598,14 +730,16 @@ ether_demux(ifp, eh, m) /* probably this should be done with a NETISR as well */ aarpinput(IFP2AC(ifp), m); /* XXX */ return; -#endif NETATALK +#endif /* NETATALK */ case ETHERTYPE_VLAN: + /* XXX lock ? */ if (vlan_input_p != NULL) (*vlan_input_p)(eh, m); else { m->m_pkthdr.rcvif->if_noproto++; m_freem(m); } + /* XXX unlock ? */ return; default: #ifdef IPX @@ -676,13 +810,7 @@ ether_demux(ifp, eh, m) #endif /* NETATALK */ } - s = splimp(); - if (IF_QFULL(inq)) { - IF_DROP(inq); - m_freem(m); - } else - IF_ENQUEUE(inq, m); - splx(s); + (void) IF_HANDOFF(inq, m, NULL); } /* @@ -737,6 +865,8 @@ ether_ifdetach(ifp, bpf) SYSCTL_DECL(_net_link); SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet"); +SYSCTL_INT(_net_link_ether, OID_AUTO, ipfw, CTLFLAG_RD, + ðer_ipfw,0,"Pass ether pkts through firewall"); int ether_ioctl(ifp, command, data) |
