diff options
author | luigi <luigi@FreeBSD.org> | 2001-11-04 22:56:25 +0000 |
---|---|---|
committer | luigi <luigi@FreeBSD.org> | 2001-11-04 22:56:25 +0000 |
commit | f565e0a1dff9f306dcf2a7ce69991a22170dfa34 (patch) | |
tree | c941161cecb4fb744bf3988da945ddfd0a75a240 | |
parent | 473a686e79edeaa4c5a1b0e1fced3d7dcc9ef444 (diff) | |
download | FreeBSD-src-f565e0a1dff9f306dcf2a7ce69991a22170dfa34.zip FreeBSD-src-f565e0a1dff9f306dcf2a7ce69991a22170dfa34.tar.gz |
MFS: sync the ipfw/dummynet/bridge code with the one recently merged
into stable (mostly , but not only, formatting and comments changes).
-rw-r--r-- | sys/dev/ed/if_ed.c | 4 | ||||
-rw-r--r-- | sys/net/bridge.c | 261 | ||||
-rw-r--r-- | sys/net/bridge.h | 50 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 14 | ||||
-rw-r--r-- | sys/netinet/ip_dummynet.c | 62 | ||||
-rw-r--r-- | sys/netinet/ip_dummynet.h | 5 | ||||
-rw-r--r-- | sys/netinet/ip_fw.c | 171 | ||||
-rw-r--r-- | sys/netinet/ip_fw.h | 1 | ||||
-rw-r--r-- | sys/netinet/ip_input.c | 9 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 6 | ||||
-rw-r--r-- | sys/netinet/raw_ip.c | 29 |
11 files changed, 346 insertions, 266 deletions
diff --git a/sys/dev/ed/if_ed.c b/sys/dev/ed/if_ed.c index 3d9714c..43099ef 100644 --- a/sys/dev/ed/if_ed.c +++ b/sys/dev/ed/if_ed.c @@ -66,7 +66,6 @@ #endif #include <net/bpf.h> -#include "opt_bdg.h" #include <net/bridge.h> #include <machine/md_var.h> @@ -2710,8 +2709,7 @@ ed_get_packet(sc, buf, len) * Don't read in the entire packet if we know we're going to drop it * and no bpf is active. */ - if (!sc->arpcom.ac_if.if_bpf && do_bridge && bdg_forward_ptr != NULL && - BDG_USED( (&sc->arpcom.ac_if) ) ) { + if (!sc->arpcom.ac_if.if_bpf && BDG_ACTIVE( (&sc->arpcom.ac_if) ) ) { struct ifnet *bif; ed_ring_copy(sc, buf, (char *)eh, ETHER_HDR_LEN); diff --git a/sys/net/bridge.c b/sys/net/bridge.c index 5feecbc..abc998a 100644 --- a/sys/net/bridge.c +++ b/sys/net/bridge.c @@ -74,12 +74,12 @@ #include <sys/malloc.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> #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> @@ -87,18 +87,14 @@ #include <netinet/ip.h> #include <netinet/if_ether.h> /* for struct arpcom */ -#if !defined(KLD_MODULE) -#include "opt_ipfw.h" -#include "opt_ipdn.h" -#endif - #include <net/route.h> #include <netinet/ip_fw.h> #include <netinet/ip_dummynet.h> #include <net/bridge.h> static struct ifnet *bridge_in(struct ifnet *, struct ether_header *); -static struct mbuf *bdg_forward(struct mbuf *, struct ether_header *const, struct ifnet *); +static struct mbuf *bdg_forward(struct mbuf *, + struct ether_header *const, struct ifnet *); static void bdgtakeifaces(void); /* @@ -116,15 +112,24 @@ static void bdgtakeifaces(void); #define DDB(x) x #define DEB(x) -static void bdginit(void *); +static int bdginit(void); static void flush_table(void); static void bdg_promisc_on(void); static void parse_bdg_cfg(void); -static int bdg_initialized = 0; - static int bdg_ipfw = 0 ; -bdg_hash_table *bdg_table = NULL ; +static bdg_hash_table *bdg_table = NULL ; + +static char *bdg_dst_names[] = { + "BDG_NULL ", + "BDG_BCAST ", + "BDG_MCAST ", + "BDG_LOCAL ", + "BDG_DROP ", + "BDG_UNKNOWN ", + "BDG_IN ", + "BDG_OUT ", + "BDG_FORWARD " }; /* * System initialization @@ -137,6 +142,45 @@ static struct callout_handle bdg_timeout_h ; if (ifp2sc[ifp->if_index].magic != 0xDEADBEEF) { x ; } /* + * Find the right pkt destination: + * BDG_BCAST is a broadcast + * BDG_MCAST is a multicast + * BDG_LOCAL is for a local address + * BDG_DROP must be dropped + * other ifp of the dest. interface (incl.self) + * + * We assume this is only called for interfaces for which bridging + * is enabled, i.e. BDG_USED(ifp) is true. + */ +static __inline +struct ifnet * +bridge_dst_lookup(struct ether_header *eh) +{ + struct ifnet *dst ; + int index ; + bdg_addr *p ; + + if (IS_ETHER_BROADCAST(eh->ether_dhost)) + return BDG_BCAST ; + if (eh->ether_dhost[0] & 1) + return BDG_MCAST ; + /* + * Lookup local addresses in case one matches. + */ + for (index = bdg_ports, p = bdg_addresses ; index ; index--, p++ ) + if (BDG_MATCH(p->etheraddr, eh->ether_dhost) ) + return BDG_LOCAL ; + /* + * Look for a possible destination in table + */ + index= HASH_FN( eh->ether_dhost ); + dst = bdg_table[index].name; + if ( dst && BDG_MATCH( bdg_table[index].etheraddr, eh->ether_dhost) ) + return dst ; + else + return BDG_UNKNOWN ; +} +/* * turn off promisc mode, optionally clear the IFF_USED flag. * The flag is turned on by parse_bdg_config */ @@ -207,8 +251,6 @@ sysctl_bdg(SYSCTL_HANDLER_ARGS) oidp->oid_name, oidp->oid_arg2, oldval, do_bridge); ) - if (bdg_table == NULL) - do_bridge = 0 ; if (oldval != do_bridge) { bdg_promisc_off( 1 ); /* reset previously used interfaces */ flush_table(); @@ -225,6 +267,8 @@ static char bridge_cfg[256] = { "" } ; /* * parse the config string, set IFF_USED, name and cluster_id * for all interfaces found. + * The config string is a list of "if[:cluster]" with + * a number of possible separators (see "sep"). */ static void parse_bdg_cfg() @@ -232,20 +276,21 @@ parse_bdg_cfg() char *p, *beg ; int i, l, cluster; struct bdg_softc *b; + static char *sep = ", \t"; - for (p= bridge_cfg; *p ; p++) { - /* interface names begin with [a-z] and continue up to ':' */ - if (*p < 'a' || *p > 'z') + for (p = bridge_cfg; *p ; p++) { + if (index(sep, *p)) /* skip separators */ continue ; - for ( beg = p ; *p && *p != ':' ; p++ ) + /* names are lowercase and digits */ + for ( beg = p ; islower(*p) || isdigit(*p) ; p++ ) ; - if (*p == 0) /* end of string, ':' not found */ - return ; - l = p - beg ; /* length of name string */ - p++ ; - DEB(printf("-- match beg(%d) <%s> p <%s>\n", l, beg, p);) - for (cluster = 0 ; *p && *p >= '0' && *p <= '9' ; p++) - cluster = cluster*10 + (*p -'0'); + l = p - beg ; /* length of name string */ + if (l == 0) /* invalid name */ + break ; + if ( *p != ':' ) /* no ':', assume default cluster 1 */ + cluster = 1 ; + else /* fetch cluster */ + cluster = strtoul( p+1, &p, 10); /* * now search in bridge strings */ @@ -256,7 +301,7 @@ parse_bdg_cfg() if (ifp == NULL) continue; sprintf(buf, "%s%d", ifp->if_name, ifp->if_unit); - if (!strncmp(beg, buf, l)) { /* XXX not correct for >10 if! */ + if (!strncmp(beg, buf, l)) { b->cluster_id = htons(cluster) ; b->flags |= IFF_USED ; sprintf(bdg_stats.s[ifp->if_index].name, @@ -267,8 +312,6 @@ parse_bdg_cfg() break ; } } - if (*p == '\0') - break ; } } @@ -319,6 +362,10 @@ 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"); +/* + * The follow macro declares a variable, and maps it to + * a SYSCTL_INT entry with the same name. + */ #define SY(parent, var, comment) \ static int var ; \ SYSCTL_INT(parent, OID_AUTO, var, CTLFLAG_RW, &(var), 0, comment); @@ -334,6 +381,7 @@ SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw_collisions, SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge_refresh, CTLTYPE_INT|CTLFLAG_WR, NULL, 0, &sysctl_refresh, "I", "iface refresh"); +#if 1 /* diagnostic vars */ SY(_net_link_ether, verbose, "Be verbose"); SY(_net_link_ether, bdg_split_pkts, "Packets split in bdg_forward"); @@ -348,6 +396,7 @@ SY(_net_link_ether, bdg_predict, "Correctly predicted header location"); SY(_net_link_ether, bdg_fw_avg, "Cycle counter avg"); SY(_net_link_ether, bdg_fw_ticks, "Cycle counter item"); SY(_net_link_ether, bdg_fw_count, "Cycle counter count"); +#endif SYSCTL_STRUCT(_net_link_ether, PF_BDG, bdgstats, CTLFLAG_RD, &bdg_stats , bdg_stats, "bridge statistics"); @@ -362,8 +411,6 @@ flush_table() { int s,i; - if (bdg_table == NULL) - return ; s = splimp(); for (i=0; i< HASH_SIZE; i++) bdg_table[i].name= NULL; /* clear table */ @@ -411,32 +458,46 @@ bdg_timeout(void *dummy) * much faster. */ bdg_addr bdg_addresses[BDG_MAX_PORTS]; -int bdg_ports ; +static int bdg_ports ; +static int bdg_max_ports = BDG_MAX_PORTS ; /* * initialization of bridge code. This needs to be done after all * interfaces have been configured. */ -static void -bdginit(void *dummy) +static int +bdginit(void) { - - bdg_initialized++; + bdg_table = (struct hash_table *) + malloc(HASH_SIZE * sizeof(struct hash_table), + M_IFADDR, M_WAITOK | M_ZERO); if (bdg_table == NULL) - bdg_table = (struct hash_table *) - malloc(HASH_SIZE * sizeof(struct hash_table), - M_IFADDR, M_WAITOK); - flush_table(); - + return ENOMEM; ifp2sc = malloc(BDG_MAX_PORTS * sizeof(struct bdg_softc), - M_IFADDR, M_WAITOK | M_ZERO); + M_IFADDR, M_WAITOK | M_ZERO ); + if (ifp2sc == NULL) { + free(bdg_table, M_IFADDR); + bdg_table = NULL ; + return ENOMEM ; + } + + bridge_in_ptr = bridge_in; + bdg_forward_ptr = bdg_forward; + bdgtakeifaces_ptr = bdgtakeifaces; + + flush_table(); bzero(&bdg_stats, sizeof(bdg_stats) ); bdgtakeifaces(); bdg_timeout(0); do_bridge=0; + return 0 ; } - + +/** + * fetch interfaces that can do bridging. + * This is re-done every time we attach or detach an interface. + */ static void bdgtakeifaces(void) { @@ -445,15 +506,14 @@ bdgtakeifaces(void) bdg_addr *p = bdg_addresses ; struct bdg_softc *bp; - if (!bdg_initialized) - return; - bdg_ports = 0 ; *bridge_cfg = '\0'; - - printf("BRIDGE 011004, have %d interfaces\n", if_index); + printf("BRIDGE 011031, have %d interfaces\n", if_index); TAILQ_FOREACH(ifp, &ifnet, if_link) if (ifp->if_type == IFT_ETHER) { /* ethernet ? */ + /* + * XXX should try to grow the arrays as needed. + */ bp = &ifp2sc[ifp->if_index] ; ac = (struct arpcom *)ifp; sprintf(bridge_cfg + strlen(bridge_cfg), @@ -479,11 +539,11 @@ bdgtakeifaces(void) } -/* +/** * bridge_in() is invoked to perform bridging decision on input packets. * * On Input: - * eh Ethernet header of the incoming packet. + * eh Ethernet header of the incoming packet. We only need this. * * On Return: destination of packet, one of * BDG_BCAST broadcast @@ -517,7 +577,7 @@ bridge_in(struct ifnet *ifp, struct ether_header *eh) bdg_table[index].name = NULL ; } else if (old != ifp) { /* - * found a loop. Either a machine has moved, or there + * Found a loop. Either a machine has moved, or there * is a misconfiguration/reconfiguration of the network. * First, do not forward this packet! * Record the relocation anyways; then, if loops persist, @@ -548,12 +608,14 @@ bridge_in(struct ifnet *ifp, struct ether_header *eh) bdg_table[index].name = ifp ; } dst = bridge_dst_lookup(eh); - /* Return values: + /* + * bridge_dst_lookup can return the following values: * BDG_BCAST, BDG_MCAST, BDG_LOCAL, BDG_UNKNOWN, BDG_DROP, ifp. - * For muted interfaces, the first 3 are changed in BDG_LOCAL, - * and others to BDG_DROP. Also, for incoming packets, ifp is changed - * to BDG_DROP in case ifp == src . These mods are not necessary - * for outgoing packets from ether_output(). + * For muted interfaces, or when we detect a loop, the first 3 are + * changed in BDG_LOCAL (we still listen to incoming traffic), + * and others to BDG_DROP (no use for the local host). + * Also, for incoming packets, ifp is changed to BDG_DROP if ifp == src. + * These changes are not necessary for outgoing packets from ether_output(). */ BDG_STAT(ifp, BDG_IN); switch ((uintptr_t)dst) { @@ -574,36 +636,44 @@ bridge_in(struct ifnet *ifp, struct ether_header *eh) if ( dropit ) { if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_LOCAL) - return BDG_LOCAL ; + dst = BDG_LOCAL ; else - return BDG_DROP ; + dst = BDG_DROP ; } else { - return (dst == ifp ? BDG_DROP : dst ) ; + if (dst == ifp) + dst = BDG_DROP; } + DEB(printf("bridge_in %6D ->%6D ty 0x%04x dst %s%d\n", + eh->ether_shost, ".", + eh->ether_dhost, ".", + ntohs(eh->ether_type), + (dst <= BDG_FORWARD) ? bdg_dst_names[(int)dst] : + dst->if_name, + (dst <= BDG_FORWARD) ? 0 : dst->if_unit); ) + + return dst ; } /* - * Forward to dst, excluding src port and muted interfaces. - * If src == NULL, the pkt comes from ether_output, and dst is the real - * interface the packet is originally sent to. In this case we must forward - * it to the whole cluster. We never call bdg_forward ether_output on - * interfaces which are not part of a cluster. + * Forward a packet to dst -- which can be a single interface or + * an entire cluster. The src port and muted interfaces are excluded. * - * The packet is freed if possible (i.e. surely not of interest for - * the upper layer), otherwise a copy is left for use by the caller - * (pointer in m0). + * If src == NULL, the pkt comes from ether_output, and dst is the real + * interface the packet is originally sent to. In this case, we must forward + * it to the whole cluster. + * We never call bdg_forward from ether_output on interfaces which are + * not part of a cluster. * - * It would be more efficient to make bdg_forward() always consume - * the packet, leaving to the caller the task to check if it needs a copy - * and get one in case. As it is now, bdg_forward() can sometimes make - * a copy whereas it is not necessary. + * If possible (i.e. we can determine that the caller does not need + * a copy), the packet is consumed here, and bdg_forward returns NULL. + * Otherwise, a pointer to a copy of the packet is returned. * - * XXX be careful about eh, it can be a pointer into *m + * XXX be careful with eh, it can be a pointer into *m */ static struct mbuf * bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst) { - struct ifnet *src = m0->m_pkthdr.rcvif; /* could be NULL in output */ + struct ifnet *src = m0->m_pkthdr.rcvif; /* NULL when called by *_output */ struct ifnet *ifp, *last = NULL ; int shared = bdg_copy ; /* someone else is using the mbuf */ int once = 0; /* loop only once */ @@ -626,7 +696,7 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst) src = m0->m_pkthdr.rcvif; shared = 0 ; /* For sure this is our own mbuf. */ } else - bdg_thru++; /* only count once */ + bdg_thru++; /* count packet, only once */ if (src == NULL) /* packet from ether_output */ dst = bridge_dst_lookup(eh); @@ -659,7 +729,7 @@ 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 (ip_fw_chk_ptr && bdg_ipfw != 0 && src != NULL) { + if (IPFW_LOADED && bdg_ipfw != 0 && src != NULL) { struct ip *ip ; int i; @@ -696,7 +766,7 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst) * The firewall knows this is a bridged packet as the cookie ptr * is NULL. */ - i = (*ip_fw_chk_ptr)(&ip, 0, NULL, NULL /* cookie */, &m0, &rule, NULL); + 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 ; /* @@ -709,7 +779,7 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst) if (i == 0) /* a PASS rule. */ goto forward ; - if (do_bridge && ip_dn_io_ptr != NULL && (i & IP_FW_PORT_DYNT_FLAG)) { + 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. @@ -734,7 +804,8 @@ 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 && verbose) + printf("M_PREPEND failed\n"); if (m == NULL) /* nope... */ return m0 ; bcopy(&save_eh, mtod(m, struct ether_header *), ETHER_HDR_LEN); @@ -792,7 +863,8 @@ forward: bdg_predict++; } else { M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT); - if (!m && verbose) printf("M_PREPEND failed\n"); + if (!m && verbose) + printf("M_PREPEND failed\n"); if (m == NULL) return m0; bcopy(&save_eh, mtod(m, struct ether_header *), ETHER_HDR_LEN); @@ -827,35 +899,48 @@ forward: return m0 ; } +/* + * initialization code, both for static and dynamic loading. + */ static int bridge_modevent(module_t mod, int type, void *unused) { int s; + int err; - s = splimp(); switch (type) { case MOD_LOAD: - bridge_in_ptr = bridge_in; - bdg_forward_ptr = bdg_forward; - bdgtakeifaces_ptr = bdgtakeifaces; - bdginit(NULL); + if (BDG_LOADED) { + err = EEXIST; + break ; + } + s = splimp(); + err = bdginit(); + splx(s); break; case MOD_UNLOAD: +#if !defined(KLD_MODULE) + printf("bridge statically compiled, cannot unload\n"); + err = EINVAL ; +#else + s = splimp(); do_bridge = 0; bridge_in_ptr = NULL; bdg_forward_ptr = NULL; bdgtakeifaces_ptr = NULL; untimeout(bdg_timeout, NULL, bdg_timeout_h); - if (bdg_table != NULL) - free(bdg_table, M_IFADDR); - if (ifp2sc != NULL) - free(ifp2sc, M_IFADDR); + free(bdg_table, M_IFADDR); + bdg_table = NULL ; + free(ifp2sc, M_IFADDR); + ifp2sc = NULL ; + splx(s); +#endif break; default: + err = EINVAL ; break; } - splx(s); - return 0; + return err; } static moduledata_t bridge_mod = { diff --git a/sys/net/bridge.h b/sys/net/bridge.h index be71d86..33b9cda 100644 --- a/sys/net/bridge.h +++ b/sys/net/bridge.h @@ -67,6 +67,11 @@ extern struct bdg_softc *ifp2sc; #define BDG_SAMECLUSTER(ifp,src) \ (src == NULL || BDG_CLUSTER(ifp) == BDG_CLUSTER(src) ) +/* + * BDG_ACTIVE(ifp) does all checks to see if bridging is loaded, + * activated and used on a given interface. + */ +#define BDG_ACTIVE(ifp) (do_bridge && BDG_LOADED && BDG_USED(ifp)) #define BDG_MAX_PORTS 128 typedef struct _bdg_addr { @@ -92,7 +97,7 @@ extern int bdg_ports ; *((unsigned int *)(a)) == 0xffffffff && \ ((unsigned short *)(a))[2] == 0xffff ) #else -/* Unaligned access versions. */ +/* for machines that do not support unaligned access */ #define BDG_MATCH(a,b) (!bcmp(a, b, ETHER_ADDR_LEN) ) #define IS_ETHER_BROADCAST(a) (!bcmp(a, "\377\377\377\377\377\377", 6)) #endif @@ -135,49 +140,10 @@ typedef struct ifnet *bridge_in_t(struct ifnet *, struct ether_header *); /* bdg_forward frees the mbuf if necessary, returning null */ typedef struct mbuf *bdg_forward_t(struct mbuf *, struct ether_header *const, struct ifnet *); -typedef void bdgtakeifaces_t(void); +typedef void bdgtakeifaces_t(void); extern bridge_in_t *bridge_in_ptr; extern bdg_forward_t *bdg_forward_ptr; extern bdgtakeifaces_t *bdgtakeifaces_ptr; -/* - * Find the right pkt destination: - * BDG_BCAST is a broadcast - * BDG_MCAST is a multicast - * BDG_LOCAL is for a local address - * BDG_DROP must be dropped - * other ifp of the dest. interface (incl.self) - * - * We assume this is only called for interfaces for which bridging - * is enabled, i.e. BDG_USED(ifp) is true. - */ -static __inline -struct ifnet * -bridge_dst_lookup(struct ether_header *eh) -{ - struct ifnet *dst ; - int index ; - bdg_addr *p ; - - if (IS_ETHER_BROADCAST(eh->ether_dhost)) - return BDG_BCAST ; - if (eh->ether_dhost[0] & 1) - return BDG_MCAST ; - /* - * Lookup local addresses in case one matches. - */ - for (index = bdg_ports, p = bdg_addresses ; index ; index--, p++ ) - if (BDG_MATCH(p->etheraddr, eh->ether_dhost) ) - return BDG_LOCAL ; - /* - * Look for a possible destination in table - */ - index= HASH_FN( eh->ether_dhost ); - dst = bdg_table[index].name; - if ( dst && BDG_MATCH( bdg_table[index].etheraddr, eh->ether_dhost) ) - return dst ; - else - return BDG_UNKNOWN ; -} - +#define BDG_LOADED (bdgtakeifaces_ptr != NULL) #endif /* KERNEL */ diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index fe2cb63..4f445d2 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -364,7 +364,7 @@ ether_output_frame(ifp, m) { int error = 0; - if (do_bridge && bdg_forward_ptr != NULL && BDG_USED(ifp) ) { + if (BDG_ACTIVE(ifp) ) { struct ether_header *eh; /* a ptr suffices */ m->m_pkthdr.rcvif = NULL; @@ -429,7 +429,7 @@ ether_input(ifp, eh, m) } /* Check for bridging mode */ - if (do_bridge && bdg_forward_ptr != NULL && BDG_USED(ifp) ) { + if (BDG_ACTIVE(ifp) ) { struct ifnet *bif; /* Check with bridging code */ @@ -441,7 +441,7 @@ ether_input(ifp, eh, m) struct mbuf *oldm = m ; save_eh = *eh ; /* because it might change */ - m = bdg_forward_ptr(m, eh, bif); /* needs forwarding */ + m = bdg_forward_ptr(m, eh, bif); /* needs forwarding */ /* * Do not continue if bdg_forward_ptr() processed our * packet (and cleared the mbuf pointer m) or if @@ -462,7 +462,7 @@ ether_input(ifp, eh, m) /* If not local and not multicast, just drop it */ if (m != NULL) - m_freem(m); + m_freem(m); return; } @@ -488,7 +488,7 @@ ether_demux(ifp, eh, m) #if defined(NETATALK) register struct llc *l; #endif - + if (! (BDG_ACTIVE(ifp) ) ) /* Discard packet if upper layers shouldn't see it because it was unicast to a different Ethernet address. If the driver is working properly, then this situation can only happen when the interface @@ -674,7 +674,7 @@ ether_ifattach(ifp, bpf) bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); if (ng_ether_attach_p != NULL) (*ng_ether_attach_p)(ifp); - if (bdgtakeifaces_ptr != NULL) + if (BDG_LOADED) bdgtakeifaces_ptr(); } @@ -691,7 +691,7 @@ ether_ifdetach(ifp, bpf) if (bpf) bpfdetach(ifp); if_detach(ifp); - if (bdgtakeifaces_ptr != NULL) + if (BDG_LOADED) bdgtakeifaces_ptr(); } diff --git a/sys/netinet/ip_dummynet.c b/sys/netinet/ip_dummynet.c index a1a61ca..bb3c409 100644 --- a/sys/netinet/ip_dummynet.c +++ b/sys/netinet/ip_dummynet.c @@ -79,9 +79,6 @@ #include <netinet/ip_dummynet.h> #include <netinet/ip_var.h> -#if !defined(KLD_MODULE) -#include "opt_bdg.h" -#endif #include <netinet/if_ether.h> /* for struct arpcom */ #include <net/bridge.h> @@ -165,9 +162,9 @@ static void dummynet(void *); static void dummynet_flush(void); void dummynet_drain(void); static int dummynet_io(int pipe, int dir, struct mbuf *m, struct ifnet *ifp, - struct route *ro, struct sockaddr_in * dst, - struct ip_fw *rule, int flags); -void dn_rule_delete(void *); + struct route *ro, struct sockaddr_in * dst, + struct ip_fw *rule, int flags); +static void dn_rule_delete(void *); int if_tx_rdy(struct ifnet *ifp); @@ -249,7 +246,7 @@ heap_init(struct dn_heap *h, int new_size) */ #define RESET_OFFSET(heap, node) \ if (heap->offset > 0) \ - *((int *)((char *)(heap->p[node].object) + heap->offset)) = -1 ; + *((int *)((char *)(heap->p[node].object) + heap->offset)) = -1 ; static int heap_insert(struct dn_heap *h, dn_key key1, void *p) { @@ -444,8 +441,12 @@ transmit_event(struct dn_pipe *pipe) break ; case DN_TO_BDG_FWD : - if (bdg_forward_ptr != NULL) { - struct mbuf *m = (struct mbuf *)pkt; + if (!BDG_LOADED) { + /* somebody unloaded the bridge module. Drop pkt */ + printf("-- dropping bridged packet trapped in pipe--\n"); + m_freem(pkt->dn_m); + } else { + struct mbuf *m = (struct mbuf *)pkt ; struct ether_header *eh; if (pkt->dn_m->m_len < ETHER_HDR_LEN && @@ -459,8 +460,8 @@ transmit_event(struct dn_pipe *pipe) eh = mtod(pkt->dn_m, struct ether_header *); m_adj(pkt->dn_m, ETHER_HDR_LEN); /* - * bdg_forward_ptr() wants a pointer to the pseudo-mbuf-header, - * but on return it will supply the pointer to the actual packet + * bdg_forward() wants a pointer to the pseudo-mbuf-header, but + * on return it will supply the pointer to the actual packet * (originally pkt->dn_m, but could be something else now) if * it has not consumed it. */ @@ -474,7 +475,7 @@ transmit_event(struct dn_pipe *pipe) m_freem(pkt->dn_m); break ; } - FREE(pkt, M_DUMMYNET); + free(pkt, M_DUMMYNET); } /* if there are leftover packets, put into the heap for next event */ if ( (pkt = pipe->head) ) @@ -831,7 +832,7 @@ create_queue(struct dn_flow_set *fs, int i) if ( fs->rq[i] != NULL ) return fs->rq[i] ; } - q = malloc(sizeof(*q), M_DUMMYNET, M_DONTWAIT | M_ZERO); /* M_ZERO needed */ + q = malloc(sizeof(*q), M_DUMMYNET, M_DONTWAIT | M_ZERO); if (q == NULL) { printf("sorry, cannot allocate queue for new flow\n"); return NULL ; @@ -1092,7 +1093,7 @@ dummynet_io(int pipe_nr, int dir, /* pipe_nr can also be a fs_nr */ goto dropit ; /* XXX expensive to zero, see if we can remove it*/ - pkt = (struct dn_pkt *)malloc(sizeof (*pkt), M_DUMMYNET, M_NOWAIT | M_ZERO); + pkt = (struct dn_pkt *)malloc(sizeof (*pkt), M_DUMMYNET, M_NOWAIT|M_ZERO); if ( pkt == NULL ) goto dropit ; /* cannot allocate packet header */ /* ok, i can handle the pkt now... */ @@ -1383,8 +1384,10 @@ config_red(struct dn_flow_set *p, struct dn_flow_set * x) } /* if the lookup table already exist, free and create it again */ - if (x->w_q_lookup) + if (x->w_q_lookup) { free(x->w_q_lookup, M_DUMMYNET); + x->w_q_lookup = NULL ; + } if (red_lookup_depth == 0) { printf("\nnet.inet.ip.dummynet.red_lookup_depth must be > 0"); free(x, M_DUMMYNET); @@ -1470,13 +1473,13 @@ config_pipe(struct dn_pipe *p) int s ; struct dn_flow_set *pfs = &(p->fs); - /* - * The config program passes parameters as follows: + /* + * The config program passes parameters as follows: * bw = bits/second (0 means no limits), * delay = ms, must be translated into ticks. * qsize = slots/bytes - */ - p->delay = ( p->delay * hz ) / 1000 ; + */ + p->delay = ( p->delay * hz ) / 1000 ; /* We need either a pipe number or a flow_set number */ if (p->pipe_nr == 0 && pfs->fs_nr == 0) return EINVAL ; @@ -1535,7 +1538,7 @@ config_pipe(struct dn_pipe *p) if (b == NULL || b->fs_nr != pfs->fs_nr) { /* new */ if (pfs->parent_nr == 0) /* need link to a pipe */ return EINVAL ; - x = malloc(sizeof(struct dn_flow_set), M_DUMMYNET, M_DONTWAIT | M_ZERO); + x = malloc(sizeof(struct dn_flow_set),M_DUMMYNET,M_DONTWAIT|M_ZERO); if (x == NULL) { printf("ip_dummynet.c: no memory for new flow_set\n"); return ENOSPC; @@ -1812,7 +1815,7 @@ dummynet_get(struct sockopt *sopt) } splx(s); error = sooptcopyout(sopt, buf, size); - FREE(buf, M_TEMP); + free(buf, M_TEMP); return error ; } @@ -1868,7 +1871,7 @@ ip_dn_ctl(struct sockopt *sopt) static void ip_dn_init(void) { - printf("DUMMYNET initialized (011004)\n"); + printf("DUMMYNET initialized (011031)\n"); all_pipes = NULL ; all_flow_sets = NULL ; ready_heap.size = ready_heap.elements = 0 ; @@ -1880,8 +1883,8 @@ ip_dn_init(void) extract_heap.size = extract_heap.elements = 0 ; extract_heap.offset = 0 ; ip_dn_ctl_ptr = ip_dn_ctl; - ip_dn_ruledel_ptr = dn_rule_delete; ip_dn_io_ptr = dummynet_io; + ip_dn_ruledel_ptr = dn_rule_delete; bzero(&dn_timeout, sizeof(struct callout_handle)); dn_timeout = timeout(dummynet, NULL, 1); } @@ -1893,17 +1896,28 @@ dummynet_modevent(module_t mod, int type, void *data) switch (type) { case MOD_LOAD: s = splimp(); + if (DUMMYNET_LOADED) { + splx(s); + printf("DUMMYNET already loaded\n"); + return EEXIST ; + } ip_dn_init(); splx(s); break; + case MOD_UNLOAD: +#if !defined(KLD_MODULE) + printf("dummynet statically compiled, cannot unload\n"); + return EINVAL ; +#else + s = splimp(); untimeout(dummynet, NULL, dn_timeout); dummynet_flush(); - s = splimp(); ip_dn_ctl_ptr = NULL; ip_dn_io_ptr = NULL; ip_dn_ruledel_ptr = NULL; splx(s); +#endif break ; default: break ; diff --git a/sys/netinet/ip_dummynet.h b/sys/netinet/ip_dummynet.h index 16cff51..85c5b5e 100644 --- a/sys/netinet/ip_dummynet.h +++ b/sys/netinet/ip_dummynet.h @@ -343,11 +343,12 @@ struct dn_pipe { /* a pipe */ typedef int ip_dn_ctl_t(struct sockopt *); /* raw_ip.c */ typedef void ip_dn_ruledel_t(void *); /* ip_fw.c */ typedef int ip_dn_io_t(int pipe, int dir, struct mbuf *m, - struct ifnet *ifp, struct route *ro, struct sockaddr_in * dst, - struct ip_fw *rule, int flags); /* ip_{in,out}put.c, bridge.c */ + struct ifnet *ifp, struct route *ro, struct sockaddr_in * dst, + struct ip_fw *rule, int flags); /* ip_{in,out}put.c, bridge.c */ extern ip_dn_ctl_t *ip_dn_ctl_ptr; extern ip_dn_ruledel_t *ip_dn_ruledel_ptr; extern ip_dn_io_t *ip_dn_io_ptr; +#define DUMMYNET_LOADED (ip_dn_io_ptr != NULL) #endif #endif /* _IP_DUMMYNET_H */ diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index 320672c..5a26121 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -155,7 +155,8 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, permanent_rules, CTLFLAG_RW, static struct ipfw_dyn_rule **ipfw_dyn_v = NULL ; static u_int32_t dyn_buckets = 256 ; /* must be power of 2 */ static u_int32_t curr_dyn_buckets = 256 ; /* must be power of 2 */ -/** + +/* * timeouts for various events in handing dynamic rules. */ static u_int32_t dyn_ack_lifetime = 300 ; @@ -200,8 +201,7 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime, CTLFLAG_RW, SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_grace_time, CTLFLAG_RD, &dyn_grace_time, 0, "Grace time for dyn. rules"); - -#endif +#endif /* SYSCTL_NODE */ #define dprintf(a) do { \ if (fw_debug) \ @@ -674,22 +674,21 @@ hash_packet(struct ipfw_flow_id *id) * head is a pointer to the head of the queue. * Modifies q and potentially also head. */ -#define UNLINK_DYN_RULE(prev, head, q) { \ - struct ipfw_dyn_rule *old_q = q; \ - \ - /* remove a refcount to the parent */ \ - if (q->dyn_type == DYN_LIMIT) \ - q->parent->count--; \ - DEB(printf("-- unlink entry 0x%08x %d -> 0x%08x %d, %d left\n", \ - (q->id.src_ip), (q->id.src_port), \ - (q->id.dst_ip), (q->id.dst_port), dyn_count-1 ); ) \ - if (prev != NULL) \ - prev->next = q = q->next ; \ - else \ - ipfw_dyn_v[i] = q = q->next ; \ - dyn_count-- ; \ - free(old_q, M_IPFW); } - +#define UNLINK_DYN_RULE(prev, head, q) { \ + struct ipfw_dyn_rule *old_q = q; \ + \ + /* remove a refcount to the parent */ \ + if (q->dyn_type == DYN_LIMIT) \ + q->parent->count--; \ + DEB(printf("-- unlink entry 0x%08x %d -> 0x%08x %d, %d left\n", \ + (q->id.src_ip), (q->id.src_port), \ + (q->id.dst_ip), (q->id.dst_port), dyn_count-1 ); ) \ + if (prev != NULL) \ + prev->next = q = q->next ; \ + else \ + ipfw_dyn_v[i] = q = q->next ; \ + dyn_count-- ; \ + free(old_q, M_IPFW); } #define TIME_LEQ(a,b) ((int)((a)-(b)) <= 0) /** @@ -733,8 +732,9 @@ remove_dyn_rule(struct ip_fw *rule, int force) max_pass = 1; /* we need a second pass */ if (zap == 1 && (pass == 0 || q->count != 0) ) { zap = 0 ; - if (q->count != 0) - printf("cannot remove parent, count %d\n", q->count); + if (pass == 1) /* should not happen */ + printf("OUCH! cannot remove rule, count %d\n", + q->count); } } if (zap) { @@ -775,7 +775,7 @@ lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction) goto next; if (TIME_LEQ( q->expire , time_second ) ) { /* expire entry */ UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q); - continue ; + continue; } if ( pkt->proto == q->id.proto) { if (pkt->src_ip == q->id.src_ip && @@ -789,8 +789,8 @@ lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction) pkt->dst_ip == q->id.src_ip && pkt->src_port == q->id.dst_port && pkt->dst_port == q->id.src_port ) { - dir = 0 ; /* reverse match */ - goto found ; + dir = 0 ; /* reverse match */ + goto found ; } } next: @@ -876,9 +876,9 @@ add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule) dyn_buckets = curr_dyn_buckets ; /* reset */ else { curr_dyn_buckets = dyn_buckets ; - if (ipfw_dyn_v != NULL) + if (ipfw_dyn_v != NULL) free(ipfw_dyn_v, M_IPFW); - ipfw_dyn_v = malloc(curr_dyn_buckets * sizeof r, + ipfw_dyn_v = malloc(curr_dyn_buckets * sizeof r, M_IPFW, M_DONTWAIT | M_ZERO); if (ipfw_dyn_v == NULL) return NULL; /* failed ! */ @@ -888,8 +888,8 @@ add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule) r = malloc(sizeof *r, M_IPFW, M_DONTWAIT | M_ZERO); if (r == NULL) { - printf ("sorry cannot allocate state\n"); - return NULL ; + printf ("sorry cannot allocate state\n"); + return NULL ; } /* increase refcount on parent, and set pointer */ @@ -921,7 +921,7 @@ add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule) } /** - * lookup dynamic parent rule using pkt and chain as search keys. + * lookup dynamic parent rule using pkt and rule as search keys. * If the lookup fails, then install one. */ static struct ipfw_dyn_rule * @@ -986,10 +986,11 @@ install_state(struct ip_fw *rule) } return 1; /* cannot install, notify caller */ } + switch (type) { case DYN_KEEP_STATE: /* bidir rule */ - add_dyn_rule(&last_pkt, DYN_KEEP_STATE, rule); - break ; + add_dyn_rule(&last_pkt, DYN_KEEP_STATE, rule); + break ; case DYN_LIMIT: /* limit number of sessions */ { u_int16_t limit_mask = rule->limit_mask ; @@ -1014,7 +1015,7 @@ install_state(struct ip_fw *rule) parent = lookup_dyn_parent(&id, rule); if (parent == NULL) { printf("add parent failed\n"); - return 1; + return 1; } if (parent->count >= conn_limit) { EXPIRE_DYN_CHAIN(rule); /* try to expire some */ @@ -1037,7 +1038,7 @@ install_state(struct ip_fw *rule) /* * given an ip_fw *, lookup_next_rule will return a pointer * of the same type to the next one. This can be either the jump - * target (for skipto instructions) or the next one in the chain (in + * target (for skipto instructions) or the next one in the list (in * all other cases including a missing jump target). * Backward jumps are not allowed, so start looking from the next * rule... @@ -1053,7 +1054,7 @@ lookup_next_rule(struct ip_fw *me) if ( (me->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_SKIPTO ) for (rule = LIST_NEXT(me,next); rule ; rule = LIST_NEXT(rule,next)) if (rule->fw_number >= rulenum) - return rule ; + return rule ; return LIST_NEXT(me,next) ; /* failure or not a skipto */ } @@ -1198,7 +1199,7 @@ ip_fw_chk(struct ip **pip, int hlen, goto dropit; } else { /* - * Go down the chain, looking for enlightment. + * Go down the list, looking for enlightment. * If we've been asked to start at a given rule, do so. */ f = LIST_FIRST(&ip_fw_chain_head); @@ -1212,7 +1213,6 @@ ip_fw_chk(struct ip **pip, int hlen, } } - for (; f; f = LIST_NEXT(f, next)) { again: if (f->fw_number == IPFW_DEFAULT_RULE) @@ -1516,7 +1516,7 @@ got_match: goto again ; case IP_FW_F_PIPE: case IP_FW_F_QUEUE: - *flow_id = f; + *flow_id = f; /* XXX set flow id */ return(f->fw_pipe_nr | IP_FW_PORT_DYNT_FLAG); #ifdef IPFIREWALL_FORWARD case IP_FW_F_FWD: @@ -1608,7 +1608,7 @@ dropit: * when a rule is added/deleted, zero the direct pointers within * all firewall rules. These will be reconstructed on the fly * as packets are matched. - * Must be called at splnet(). + * Must be called at splimp(). */ static void flush_rule_ptrs() @@ -1630,7 +1630,6 @@ add_entry(struct ip_fw_head *head, struct ip_fw *rule) ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT | M_ZERO); if (!ftmp) return (ENOSPC); - bcopy(rule, ftmp, sizeof(*ftmp)); ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0'; @@ -1639,7 +1638,7 @@ add_entry(struct ip_fw_head *head, struct ip_fw *rule) ftmp->next_rule_ptr = NULL ; ftmp->pipe_ptr = NULL ; - s = splnet(); + s = splimp(); if (LIST_FIRST(head) == 0) { LIST_INSERT_HEAD(head, ftmp, next); @@ -1683,11 +1682,11 @@ done: } /** - * free storage associated with a static chain entry (including + * free storage associated with a static rule entry (including * dependent dynamic rules), and zeroes rule pointers to avoid * dangling pointer dereferences. * @return a pointer to the next entry. - * Must be called at splnet() and with a non-null argument. + * Must be called at splimp() and with a non-null argument. */ static struct ip_fw * free_chain(struct ip_fw *fcp) @@ -1698,7 +1697,7 @@ free_chain(struct ip_fw *fcp) DELETE_DYN_CHAIN(fcp); LIST_REMOVE(fcp, next); static_count--; - if (ip_dn_ruledel_ptr != NULL) + if (DUMMYNET_LOADED) ip_dn_ruledel_ptr(fcp) ; flush_rule_ptrs(); /* more efficient to do outside the loop */ free(fcp, M_IPFW); @@ -1718,7 +1717,7 @@ del_entry(struct ip_fw_head *chainptr, u_short number) if (rule->fw_number == number) { int s ; - s = splnet(); /* prevent access to rules while removing */ + s = splimp(); /* prevent access to rules while removing */ while (rule && rule->fw_number == number) rule = free_chain(rule); /* XXX could move flush_rule_ptrs() here */ @@ -1746,7 +1745,7 @@ zero_entry(struct ip_fw *frwl, int log_only) char *msg ; if (frwl == 0) { - s = splnet(); + s = splimp(); LIST_FOREACH(rule, &ip_fw_chain_head, next) { if (log_only == 0) { rule->fw_bcnt = rule->fw_pcnt = 0; @@ -1756,19 +1755,18 @@ zero_entry(struct ip_fw *frwl, int log_only) } splx(s); msg = log_only ? "ipfw: All logging counts cleared.\n" : - "ipfw: Accounting cleared.\n"; + "ipfw: Accounting cleared.\n"; } else { int cleared = 0; number = frwl->fw_number ; - /* - * It's possible to insert multiple chain entries with the + * It is possible to insert multiple chain entries with the * same number, so we don't stop after finding the first * match if zeroing a specific entry. */ LIST_FOREACH(rule, &ip_fw_chain_head, next) if (number == rule->fw_number) { - s = splnet(); + s = splimp(); while (rule && number == rule->fw_number) { if (log_only == 0) { rule->fw_bcnt = rule->fw_pcnt = 0; @@ -1781,10 +1779,10 @@ zero_entry(struct ip_fw *frwl, int log_only) cleared = 1; break; } - if (!cleared) /* we didn't find any matching rules */ + if (!cleared) /* we did not find any matching rules */ return (EINVAL); msg = log_only ? "Entry %d logging count reset.\n" : - "ipfw: Entry %d cleared.\n"; + "ipfw: Entry %d cleared.\n"; } if (fw_verbose) log(LOG_SECURITY | LOG_NOTICE, msg, number); @@ -1946,7 +1944,13 @@ ip_fw_ctl(struct sockopt *sopt) switch (sopt->sopt_name) { case IP_FW_GET: - s = splnet(); + /* + * pass up a copy of the current rules. Static rules + * come first (the last of which has number 65535), + * followed by a possibly empty list of dynamic rule. + * The last dynamic rule has NULL in the "next" field. + */ + s = splimp(); /* size of static rules */ size = static_count * sizeof(struct ip_fw) ; if (ipfw_dyn_v) /* add size of dyn.rules */ @@ -1960,9 +1964,9 @@ ip_fw_ctl(struct sockopt *sopt) */ buf = malloc(size, M_TEMP, M_WAITOK); if (buf == 0) { - splx(s); - error = ENOBUFS; - break; + splx(s); + error = ENOBUFS; + break; } bp = buf ; @@ -1979,7 +1983,12 @@ ip_fw_ctl(struct sockopt *sopt) for ( p = ipfw_dyn_v[i] ; p != NULL ; p = p->next, dst++ ) { bcopy(p, dst, sizeof *p); (int)dst->rule = p->rule->fw_number ; - dst->next = dst ; /* fake non-null pointer... */ + /* + * store a non-null value in "next". The userland + * code will interpret a NULL here as a marker + * for the last dynamic rule. + */ + dst->next = dst ; last = dst ; if (TIME_LEQ(dst->expire, time_second) ) dst->expire = 0 ; @@ -1987,12 +1996,12 @@ ip_fw_ctl(struct sockopt *sopt) dst->expire -= time_second ; } if (last != NULL) - last->next = NULL ; + last->next = NULL ; /* mark last dynamic rule */ } splx(s); error = sooptcopyout(sopt, buf, size); - FREE(buf, M_TEMP); + free(buf, M_TEMP); break; case IP_FW_FLUSH: @@ -2009,7 +2018,7 @@ ip_fw_ctl(struct sockopt *sopt) * the old list without the need for a lock. */ - s = splnet(); + s = splimp(); while ( (fcp = LIST_FIRST(&ip_fw_chain_head)) && fcp->fw_number != IPFW_DEFAULT_RULE ) free_chain(fcp); @@ -2055,7 +2064,7 @@ ip_fw_ctl(struct sockopt *sopt) if (sopt->sopt_val != 0) { error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl); if (error) - break ; + break; arg = &frwl ; } error = zero_entry(arg, cmd); @@ -2130,38 +2139,48 @@ ip_fw_init(void) #endif } -static ip_fw_chk_t *old_chk_ptr; -static ip_fw_ctl_t *old_ctl_ptr; - static int ipfw_modevent(module_t mod, int type, void *unused) { int s; + int err = 0 ; struct ip_fw *fcp; switch (type) { case MOD_LOAD: - s = splnet(); - - old_chk_ptr = ip_fw_chk_ptr; - old_ctl_ptr = ip_fw_ctl_ptr; - - ip_fw_init(); - splx(s); - return 0; + printf("IPFW: MOD_LOAD\n"); + s = splimp(); + if (IPFW_LOADED) { + splx(s); + printf("IP firewall already loaded\n"); + err = EEXIST ; + } else { + ip_fw_init(); + splx(s); + } + break ; case MOD_UNLOAD: - s = splnet(); - ip_fw_chk_ptr = old_chk_ptr; - ip_fw_ctl_ptr = old_ctl_ptr; + printf("IPFW: MOD_UNLOAD\n"); +#if !defined(KLD_MODULE) + printf("ipfw statically compiled, cannot unload\n"); + err = EBUSY; +#else + s = splimp(); + ip_fw_chk_ptr = NULL ; + ip_fw_ctl_ptr = NULL ; + { + struct ip_fw *fcp; while ( (fcp = LIST_FIRST(&ip_fw_chain_head)) != NULL) free_chain(fcp); + } splx(s); printf("IP firewall unloaded\n"); - return 0; +#endif + break; default: break; } - return 0; + return err; } static moduledata_t ipfwmod = { diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 12fc4fc..07d659f 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -327,6 +327,7 @@ extern ip_fw_ctl_t *ip_fw_ctl_ptr; extern int fw_one_pass; extern int fw_enable; extern struct ipfw_flow_id last_pkt; +#define IPFW_LOADED (ip_fw_chk_ptr != NULL) #endif /* _KERNEL */ #endif /* _IP_FW_H */ diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index f529a7e..17e3103 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -81,7 +81,6 @@ #include <netinet/ip_fw.h> #include <netinet/ip_dummynet.h> - #ifdef IPSEC #include <netinet6/ipsec.h> #include <netkey/key.h> @@ -439,7 +438,7 @@ iphack: } #endif /* PFIL_HOOKS */ - if (fw_enable && ip_fw_chk_ptr) { + if (fw_enable && IPFW_LOADED) { #ifdef IPFIREWALL_FORWARD /* * If we've been forwarded from the output side, then @@ -452,7 +451,7 @@ iphack: * See the comment in ip_output for the return values * produced by the firewall. */ - i = (*ip_fw_chk_ptr)(&ip, + i = ip_fw_chk_ptr(&ip, hlen, NULL, &divert_cookie, &m, &rule, &ip_fw_fwd_addr); if (i & IP_FW_PORT_DENY_FLAG) { /* XXX new interface-denied */ if (m) @@ -469,7 +468,7 @@ iphack: } if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */ goto pass; - if (ip_dn_io_ptr != NULL && (i & IP_FW_PORT_DYNT_FLAG) != 0) { + if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) { /* Send packet to the appropriate pipe */ ip_dn_io_ptr(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule, 0); @@ -541,7 +540,7 @@ pass: * is not locally generated and the packet is not subject to * 'ipfw fwd'. * - * XXX - Checking also should be disabled if the destination + * XXX - Checking also should be disabled if the destination * address is ipnat'ed to a different interface. * * XXX - Checking is incompatible with IP aliases added diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 060c4c0..304aa4d 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -586,10 +586,10 @@ skip_ipsec: /* * Check with the firewall... */ - if (fw_enable && ip_fw_chk_ptr) { + if (fw_enable && IPFW_LOADED) { struct sockaddr_in *old = dst; - off = (*ip_fw_chk_ptr)(&ip, + off = ip_fw_chk_ptr(&ip, hlen, ifp, &divert_cookie, &m, &rule, &dst); /* * On return we must do the following: @@ -623,7 +623,7 @@ skip_ipsec: } if (off == 0 && dst == old) /* common case */ goto pass ; - if (ip_dn_io_ptr != NULL && (off & IP_FW_PORT_DYNT_FLAG) != 0) { + if (DUMMYNET_LOADED && (off & IP_FW_PORT_DYNT_FLAG) != 0) { /* * pass the pkt to dummynet. Need to include * pipe number, m, ifp, ro, dst because these are diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 1bad6dd..b31be39 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -70,8 +70,6 @@ #include <netinet6/ipsec.h> #endif /*IPSEC*/ -#include "opt_ipdn.h" - struct inpcbhead ripcb; struct inpcbinfo ripcbinfo; @@ -288,19 +286,19 @@ rip_ctloutput(so, sopt) error = sooptcopyout(sopt, &optval, sizeof optval); break; - case IP_FW_ADD: + case IP_FW_ADD: /* ADD actually returns the body... */ case IP_FW_GET: - if (ip_fw_ctl_ptr == NULL) - error = ENOPROTOOPT; - else + if (IPFW_LOADED) error = ip_fw_ctl_ptr(sopt); + else + error = ENOPROTOOPT; break; case IP_DUMMYNET_GET: - if (ip_dn_ctl_ptr == NULL) - error = ENOPROTOOPT; - else + if (DUMMYNET_LOADED) error = ip_dn_ctl_ptr(sopt); + else + error = ENOPROTOOPT; break ; case MRT_INIT: @@ -333,24 +331,23 @@ rip_ctloutput(so, sopt) inp->inp_flags &= ~INP_HDRINCL; break; - case IP_FW_ADD: case IP_FW_DEL: case IP_FW_FLUSH: case IP_FW_ZERO: case IP_FW_RESETLOG: - if (ip_fw_ctl_ptr == 0) - error = ENOPROTOOPT; - else + if (IPFW_LOADED) error = ip_fw_ctl_ptr(sopt); + else + error = ENOPROTOOPT; break; case IP_DUMMYNET_CONFIGURE: case IP_DUMMYNET_DEL: case IP_DUMMYNET_FLUSH: - if (ip_dn_ctl_ptr == NULL) - error = ENOPROTOOPT ; - else + if (DUMMYNET_LOADED) error = ip_dn_ctl_ptr(sopt); + else + error = ENOPROTOOPT ; break ; case IP_RSVP_ON: |