MFS: sync the ipfw/dummynet/bridge code with the one recently merged
into stable (mostly , but not only, formatting and comments changes).
This commit is contained in:
parent
473a686e79
commit
f565e0a1df
@ -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);
|
||||
|
263
sys/net/bridge.c
263
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
|
||||
@ -136,6 +141,45 @@ static struct callout_handle bdg_timeout_h ;
|
||||
#define IFP_CHK(ifp, x) \
|
||||
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++;
|
||||
if (bdg_table == NULL)
|
||||
bdg_table = (struct hash_table *)
|
||||
malloc(HASH_SIZE * sizeof(struct hash_table),
|
||||
M_IFADDR, M_WAITOK);
|
||||
flush_table();
|
||||
|
||||
ifp2sc = malloc(BDG_MAX_PORTS * sizeof(struct bdg_softc),
|
||||
bdg_table = (struct hash_table *)
|
||||
malloc(HASH_SIZE * sizeof(struct hash_table),
|
||||
M_IFADDR, M_WAITOK | M_ZERO);
|
||||
if (bdg_table == NULL)
|
||||
return ENOMEM;
|
||||
ifp2sc = malloc(BDG_MAX_PORTS * sizeof(struct bdg_softc),
|
||||
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.
|
||||
* Forward a packet to dst -- which can be a single interface or
|
||||
* an entire cluster. The src port and muted interfaces are excluded.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* 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 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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 = {
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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 ;
|
||||
|
@ -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 */
|
||||
|
@ -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 = {
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user