summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ed/if_ed.c4
-rw-r--r--sys/net/bridge.c261
-rw-r--r--sys/net/bridge.h50
-rw-r--r--sys/net/if_ethersubr.c14
-rw-r--r--sys/netinet/ip_dummynet.c62
-rw-r--r--sys/netinet/ip_dummynet.h5
-rw-r--r--sys/netinet/ip_fw.c171
-rw-r--r--sys/netinet/ip_fw.h1
-rw-r--r--sys/netinet/ip_input.c9
-rw-r--r--sys/netinet/ip_output.c6
-rw-r--r--sys/netinet/raw_ip.c29
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:
OpenPOWER on IntegriCloud