summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2015-02-02 14:27:13 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2015-02-13 10:34:19 +0100
commit7eeb079d84bc4abe9897be0047fc28a754e46ecd (patch)
tree9b47ac7055ce0cb1e2d86c684a2a7a1cd20c0c4d /freebsd/sys/net
parentfreebsd-to-rtems.py: Fix revert includes (diff)
downloadrtems-libbsd-7eeb079d84bc4abe9897be0047fc28a754e46ecd.tar.bz2
Update to FreeBSD 9.3
Diffstat (limited to 'freebsd/sys/net')
-rw-r--r--freebsd/sys/net/ieee8023ad_lacp.c41
-rw-r--r--freebsd/sys/net/if.c4
-rw-r--r--freebsd/sys/net/if_lagg.c19
-rw-r--r--freebsd/sys/net/if_media.h5
-rw-r--r--freebsd/sys/net/if_spppsubr.c2
-rw-r--r--freebsd/sys/net/if_tap.c6
-rw-r--r--freebsd/sys/net/if_tun.c1
-rw-r--r--freebsd/sys/net/if_vlan.c2
-rw-r--r--freebsd/sys/net/radix.c415
-rw-r--r--freebsd/sys/net/radix.h6
-rw-r--r--freebsd/sys/net/radix_mpath.c86
-rw-r--r--freebsd/sys/net/route.c167
-rw-r--r--freebsd/sys/net/route.h9
-rw-r--r--freebsd/sys/net/rtsock.c198
14 files changed, 568 insertions, 393 deletions
diff --git a/freebsd/sys/net/ieee8023ad_lacp.c b/freebsd/sys/net/ieee8023ad_lacp.c
index a1c1e49e..20288926 100644
--- a/freebsd/sys/net/ieee8023ad_lacp.c
+++ b/freebsd/sys/net/ieee8023ad_lacp.c
@@ -1030,8 +1030,45 @@ lacp_compose_key(struct lacp_port *lp)
KASSERT(IFM_TYPE(media) == IFM_ETHER, ("invalid media type"));
KASSERT((media & IFM_FDX) != 0, ("aggregating HDX interface"));
- /* bit 0..4: IFM_SUBTYPE */
- key = subtype;
+ /* bit 0..4: IFM_SUBTYPE modulo speed */
+ switch (subtype) {
+ case IFM_10_T:
+ case IFM_10_2:
+ case IFM_10_5:
+ case IFM_10_STP:
+ case IFM_10_FL:
+ key = IFM_10_T;
+ break;
+ case IFM_100_TX:
+ case IFM_100_FX:
+ case IFM_100_T4:
+ case IFM_100_VG:
+ case IFM_100_T2:
+ key = IFM_100_TX;
+ break;
+ case IFM_1000_SX:
+ case IFM_1000_LX:
+ case IFM_1000_CX:
+ case IFM_1000_T:
+ key = IFM_1000_SX;
+ break;
+ case IFM_10G_LR:
+ case IFM_10G_SR:
+ case IFM_10G_CX4:
+ case IFM_10G_TWINAX:
+ case IFM_10G_TWINAX_LONG:
+ case IFM_10G_LRM:
+ case IFM_10G_T:
+ key = IFM_10G_LR;
+ break;
+ case IFM_40G_CR4:
+ case IFM_40G_SR4:
+ case IFM_40G_LR4:
+ key = IFM_40G_CR4;
+ break;
+ default:
+ key = subtype;
+ }
/* bit 5..14: (some bits of) if_index of lagg device */
key |= 0x7fe0 & ((sc->sc_ifp->if_index) << 5);
/* bit 15: 0 */
diff --git a/freebsd/sys/net/if.c b/freebsd/sys/net/if.c
index ea4a8a46..0bd72e44 100644
--- a/freebsd/sys/net/if.c
+++ b/freebsd/sys/net/if.c
@@ -76,6 +76,7 @@
#include <net/vnet.h>
#if defined(INET) || defined(INET6)
+#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
@@ -676,7 +677,8 @@ if_attach_internal(struct ifnet *ifp, int vmove)
#if defined(INET) || defined(INET6)
/* Initialize to max value. */
if (ifp->if_hw_tsomax == 0)
- ifp->if_hw_tsomax = IP_MAXPACKET;
+ ifp->if_hw_tsomax = min(IP_MAXPACKET, 32 * MCLBYTES -
+ (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN));
KASSERT(ifp->if_hw_tsomax <= IP_MAXPACKET &&
ifp->if_hw_tsomax >= IP_MAXPACKET / 8,
("%s: tsomax outside of range", __func__));
diff --git a/freebsd/sys/net/if_lagg.c b/freebsd/sys/net/if_lagg.c
index 4dee2afe..b0be3643 100644
--- a/freebsd/sys/net/if_lagg.c
+++ b/freebsd/sys/net/if_lagg.c
@@ -56,11 +56,11 @@ __FBSDID("$FreeBSD$");
#if defined(INET) || defined(INET6)
#include <netinet/in.h>
+#include <netinet/ip.h>
#endif
#ifdef INET
#include <netinet/in_systm.h>
#include <netinet/if_ether.h>
-#include <netinet/ip.h>
#endif
#ifdef INET6
@@ -408,6 +408,11 @@ lagg_capabilities(struct lagg_softc *sc)
struct lagg_port *lp;
int cap = ~0, ena = ~0;
u_long hwa = ~0UL;
+#if defined(INET) || defined(INET6)
+ u_int hw_tsomax = IP_MAXPACKET; /* Initialize to the maximum value. */
+#else
+ u_int hw_tsomax = ~0; /* if_hw_tsomax is only for INET/INET6, but.. */
+#endif
LAGG_WLOCK_ASSERT(sc);
@@ -416,6 +421,10 @@ lagg_capabilities(struct lagg_softc *sc)
cap &= lp->lp_ifp->if_capabilities;
ena &= lp->lp_ifp->if_capenable;
hwa &= lp->lp_ifp->if_hwassist;
+ /* Set to the minimum value of the lagg ports. */
+ if (lp->lp_ifp->if_hw_tsomax < hw_tsomax &&
+ lp->lp_ifp->if_hw_tsomax > 0)
+ hw_tsomax = lp->lp_ifp->if_hw_tsomax;
}
cap = (cap == ~0 ? 0 : cap);
ena = (ena == ~0 ? 0 : ena);
@@ -423,10 +432,12 @@ lagg_capabilities(struct lagg_softc *sc)
if (sc->sc_ifp->if_capabilities != cap ||
sc->sc_ifp->if_capenable != ena ||
- sc->sc_ifp->if_hwassist != hwa) {
+ sc->sc_ifp->if_hwassist != hwa ||
+ sc->sc_ifp->if_hw_tsomax != hw_tsomax) {
sc->sc_ifp->if_capabilities = cap;
sc->sc_ifp->if_capenable = ena;
sc->sc_ifp->if_hwassist = hwa;
+ sc->sc_ifp->if_hw_tsomax = hw_tsomax;
getmicrotime(&sc->sc_ifp->if_lastchange);
if (sc->sc_ifflags & IFF_DEBUG)
@@ -822,7 +833,7 @@ lagg_port_output(struct ifnet *ifp, struct mbuf *m,
/* drop any other frames */
m_freem(m);
- return (EBUSY);
+ return (ENETDOWN);
}
static void
@@ -1895,7 +1906,7 @@ lagg_lacp_start(struct lagg_softc *sc, struct mbuf *m)
lp = lacp_select_tx_port(sc, m);
if (lp == NULL) {
m_freem(m);
- return (EBUSY);
+ return (ENETDOWN);
}
/* Send mbuf */
diff --git a/freebsd/sys/net/if_media.h b/freebsd/sys/net/if_media.h
index 6424d662..12585095 100644
--- a/freebsd/sys/net/if_media.h
+++ b/freebsd/sys/net/if_media.h
@@ -153,7 +153,10 @@ uint64_t ifmedia_baudrate(int);
#define IFM_40G_CR4 27 /* 40GBase-CR4 */
#define IFM_40G_SR4 28 /* 40GBase-SR4 */
#define IFM_40G_LR4 29 /* 40GBase-LR4 */
-
+/*
+ * Please update ieee8023ad_lacp.c:lacp_compose_key()
+ * after adding new Ethernet media types.
+ */
/* note 31 is the max! */
#define IFM_ETH_MASTER 0x00000100 /* master mode (1000baseT) */
diff --git a/freebsd/sys/net/if_spppsubr.c b/freebsd/sys/net/if_spppsubr.c
index 4f2f6d05..fa6a7c1b 100644
--- a/freebsd/sys/net/if_spppsubr.c
+++ b/freebsd/sys/net/if_spppsubr.c
@@ -3621,7 +3621,7 @@ sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len)
continue;
}
- bzero(&suggestaddr, sizeof(&suggestaddr));
+ bzero(&suggestaddr, sizeof(suggestaddr));
if (collision && nohisaddr) {
/* collision, hisaddr unknown - Conf-Rej */
type = CONF_REJ;
diff --git a/freebsd/sys/net/if_tap.c b/freebsd/sys/net/if_tap.c
index 9c501f16..599905e8 100644
--- a/freebsd/sys/net/if_tap.c
+++ b/freebsd/sys/net/if_tap.c
@@ -215,14 +215,10 @@ tap_destroy(struct tap_softc *tp)
{
struct ifnet *ifp = tp->tap_ifp;
- /* Unlocked read. */
- KASSERT(!(tp->tap_flags & TAP_OPEN),
- ("%s flags is out of sync", ifp->if_xname));
-
CURVNET_SET(ifp->if_vnet);
+ destroy_dev(tp->tap_dev);
seldrain(&tp->tap_rsel);
knlist_destroy(&tp->tap_rsel.si_note);
- destroy_dev(tp->tap_dev);
ether_ifdetach(ifp);
if_free_type(ifp, IFT_ETHER);
diff --git a/freebsd/sys/net/if_tun.c b/freebsd/sys/net/if_tun.c
index 25b73294..556a4860 100644
--- a/freebsd/sys/net/if_tun.c
+++ b/freebsd/sys/net/if_tun.c
@@ -324,6 +324,7 @@ static moduledata_t tun_mod = {
};
DECLARE_MODULE(if_tun, tun_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
+MODULE_VERSION(if_tun, 1);
static void
tunstart(struct ifnet *ifp)
diff --git a/freebsd/sys/net/if_vlan.c b/freebsd/sys/net/if_vlan.c
index f31b9be2..accfbbb6 100644
--- a/freebsd/sys/net/if_vlan.c
+++ b/freebsd/sys/net/if_vlan.c
@@ -1503,6 +1503,8 @@ vlan_capabilities(struct ifvlan *ifv)
* propagate the hardware-assisted flag. TSO on VLANs
* does not necessarily require hardware VLAN tagging.
*/
+ if (p->if_hw_tsomax > 0)
+ ifp->if_hw_tsomax = p->if_hw_tsomax;
if (p->if_capabilities & IFCAP_VLAN_HWTSO)
ifp->if_capabilities |= p->if_capabilities & IFCAP_TSO;
if (p->if_capenable & IFCAP_VLAN_HWTSO) {
diff --git a/freebsd/sys/net/radix.c b/freebsd/sys/net/radix.c
index 875a482c..ba15eb51 100644
--- a/freebsd/sys/net/radix.c
+++ b/freebsd/sys/net/radix.c
@@ -68,27 +68,27 @@ static struct radix_node
*rn_search(void *, struct radix_node *),
*rn_search_m(void *, struct radix_node *, void *);
-static int max_keylen;
-static struct radix_mask *rn_mkfreelist;
-static struct radix_node_head *mask_rnhead;
+static void rn_detachhead_internal(void **head);
+static int rn_inithead_internal(void **head, int off);
+
+#define RADIX_MAX_KEY_LEN 32
+
+static char rn_zeros[RADIX_MAX_KEY_LEN];
+static char rn_ones[RADIX_MAX_KEY_LEN] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
/*
- * Work area -- the following point to 3 buffers of size max_keylen,
- * allocated in this order in a block of memory malloc'ed by rn_init.
- * rn_zeros, rn_ones are set in rn_init and used in readonly afterwards.
- * addmask_key is used in rn_addmask in rw mode and not thread-safe.
+ * XXX: Compat stuff for old rn_addmask() users
*/
-static char *rn_zeros, *rn_ones, *addmask_key;
-
-#define MKGet(m) { \
- if (rn_mkfreelist) { \
- m = rn_mkfreelist; \
- rn_mkfreelist = (m)->rm_mklist; \
- } else \
- R_Malloc(m, struct radix_mask *, sizeof (struct radix_mask)); }
-
-#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);}
+static struct radix_node_head *mask_rnhead_compat;
+#ifdef _KERNEL
+static struct mtx mask_mtx;
+#endif
-#define rn_masktop (mask_rnhead->rnh_treetop)
static int rn_lexobetter(void *m_arg, void *n_arg);
static struct radix_mask *
@@ -158,12 +158,10 @@ static int rn_satisfies_leaf(char *trial, struct radix_node *leaf,
* Search a node in the tree matching the key.
*/
static struct radix_node *
-rn_search(v_arg, head)
- void *v_arg;
- struct radix_node *head;
+rn_search(void *v_arg, struct radix_node *head)
{
- register struct radix_node *x;
- register caddr_t v;
+ struct radix_node *x;
+ caddr_t v;
for (x = head, v = v_arg; x->rn_bit >= 0;) {
if (x->rn_bmask & v[x->rn_offset])
@@ -179,12 +177,10 @@ rn_search(v_arg, head)
* XXX note this function is used only once.
*/
static struct radix_node *
-rn_search_m(v_arg, head, m_arg)
- struct radix_node *head;
- void *v_arg, *m_arg;
+rn_search_m(void *v_arg, struct radix_node *head, void *m_arg)
{
- register struct radix_node *x;
- register caddr_t v = v_arg, m = m_arg;
+ struct radix_node *x;
+ caddr_t v = v_arg, m = m_arg;
for (x = head; x->rn_bit >= 0;) {
if ((x->rn_bmask & m[x->rn_offset]) &&
@@ -193,15 +189,14 @@ rn_search_m(v_arg, head, m_arg)
else
x = x->rn_left;
}
- return x;
+ return (x);
}
int
-rn_refines(m_arg, n_arg)
- void *m_arg, *n_arg;
+rn_refines(void *m_arg, void *n_arg)
{
- register caddr_t m = m_arg, n = n_arg;
- register caddr_t lim, lim2 = lim = n + LEN(n);
+ caddr_t m = m_arg, n = n_arg;
+ caddr_t lim, lim2 = lim = n + LEN(n);
int longer = LEN(n++) - LEN(m++);
int masks_are_equal = 1;
@@ -209,49 +204,71 @@ rn_refines(m_arg, n_arg)
lim -= longer;
while (n < lim) {
if (*n & ~(*m))
- return 0;
+ return (0);
if (*n++ != *m++)
masks_are_equal = 0;
}
while (n < lim2)
if (*n++)
- return 0;
+ return (0);
if (masks_are_equal && (longer < 0))
for (lim2 = m - longer; m < lim2; )
if (*m++)
- return 1;
+ return (1);
return (!masks_are_equal);
}
+/*
+ * Search for exact match in given @head.
+ * Assume host bits are cleared in @v_arg if @m_arg is not NULL
+ * Note that prefixes with /32 or /128 masks are treated differently
+ * from host routes.
+ */
struct radix_node *
-rn_lookup(v_arg, m_arg, head)
- void *v_arg, *m_arg;
- struct radix_node_head *head;
+rn_lookup(void *v_arg, void *m_arg, struct radix_node_head *head)
{
- register struct radix_node *x;
- caddr_t netmask = 0;
+ struct radix_node *x;
+ caddr_t netmask;
- if (m_arg) {
- x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_offset);
- if (x == 0)
- return (0);
+ if (m_arg != NULL) {
+ /*
+ * Most common case: search exact prefix/mask
+ */
+ x = rn_addmask_r(m_arg, head->rnh_masks, 1,
+ head->rnh_treetop->rn_offset);
+ if (x == NULL)
+ return (NULL);
netmask = x->rn_key;
- }
- x = rn_match(v_arg, head);
- if (x && netmask) {
- while (x && x->rn_mask != netmask)
+
+ x = rn_match(v_arg, head);
+
+ while (x != NULL && x->rn_mask != netmask)
x = x->rn_dupedkey;
+
+ return (x);
}
- return x;
+
+ /*
+ * Search for host address.
+ */
+ if ((x = rn_match(v_arg, head)) == NULL)
+ return (NULL);
+
+ /* Check if found key is the same */
+ if (LEN(x->rn_key) != LEN(v_arg) || bcmp(x->rn_key, v_arg, LEN(v_arg)))
+ return (NULL);
+
+ /* Check if this is not host route */
+ if (x->rn_mask != NULL)
+ return (NULL);
+
+ return (x);
}
static int
-rn_satisfies_leaf(trial, leaf, skip)
- char *trial;
- register struct radix_node *leaf;
- int skip;
+rn_satisfies_leaf(char *trial, struct radix_node *leaf, int skip)
{
- register char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask;
+ char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask;
char *cplim;
int length = min(LEN(cp), LEN(cp2));
@@ -262,22 +279,23 @@ rn_satisfies_leaf(trial, leaf, skip)
cplim = cp + length; cp3 += skip; cp2 += skip;
for (cp += skip; cp < cplim; cp++, cp2++, cp3++)
if ((*cp ^ *cp2) & *cp3)
- return 0;
- return 1;
+ return (0);
+ return (1);
}
+/*
+ * Search for longest-prefix match in given @head
+ */
struct radix_node *
-rn_match(v_arg, head)
- void *v_arg;
- struct radix_node_head *head;
+rn_match(void *v_arg, struct radix_node_head *head)
{
caddr_t v = v_arg;
- register struct radix_node *t = head->rnh_treetop, *x;
- register caddr_t cp = v, cp2;
+ struct radix_node *t = head->rnh_treetop, *x;
+ caddr_t cp = v, cp2;
caddr_t cplim;
struct radix_node *saved_t, *top = t;
int off = t->rn_offset, vlen = LEN(cp), matched_off;
- register int test, b, rn_bit;
+ int test, b, rn_bit;
/*
* Open code rn_search(v, top) to avoid overhead of extra
@@ -315,7 +333,7 @@ rn_match(v_arg, head)
*/
if (t->rn_flags & RNF_ROOT)
t = t->rn_dupedkey;
- return t;
+ return (t);
on1:
test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */
for (b = 7; (test >>= 1) > 0;)
@@ -336,13 +354,13 @@ on1:
*/
if (t->rn_flags & RNF_NORMAL) {
if (rn_bit <= t->rn_bit)
- return t;
+ return (t);
} else if (rn_satisfies_leaf(v, t, matched_off))
- return t;
+ return (t);
t = saved_t;
/* start searching up the tree */
do {
- register struct radix_mask *m;
+ struct radix_mask *m;
t = t->rn_parent;
m = t->rn_mklist;
/*
@@ -361,12 +379,12 @@ on1:
while (x && x->rn_mask != m->rm_mask)
x = x->rn_dupedkey;
if (x && rn_satisfies_leaf(v, x, off))
- return x;
+ return (x);
}
m = m->rm_mklist;
}
} while (t != top);
- return 0;
+ return (0);
}
#ifdef RN_DEBUG
@@ -388,12 +406,9 @@ int rn_debug = 1;
*/
static struct radix_node *
-rn_newpair(v, b, nodes)
- void *v;
- int b;
- struct radix_node nodes[2];
+rn_newpair(void *v, int b, struct radix_node nodes[2])
{
- register struct radix_node *tt = nodes, *t = tt + 1;
+ struct radix_node *tt = nodes, *t = tt + 1;
t->rn_bit = b;
t->rn_bmask = 0x80 >> (b & 7);
t->rn_left = tt;
@@ -417,44 +432,39 @@ rn_newpair(v, b, nodes)
tt->rn_ybro = rn_clist;
rn_clist = tt;
#endif
- return t;
+ return (t);
}
static struct radix_node *
-rn_insert(v_arg, head, dupentry, nodes)
- void *v_arg;
- struct radix_node_head *head;
- int *dupentry;
- struct radix_node nodes[2];
+rn_insert(void *v_arg, struct radix_node_head *head, int *dupentry,
+ struct radix_node nodes[2])
{
caddr_t v = v_arg;
struct radix_node *top = head->rnh_treetop;
int head_off = top->rn_offset, vlen = LEN(v);
- register struct radix_node *t = rn_search(v_arg, top);
- register caddr_t cp = v + head_off;
- register int b;
- struct radix_node *tt;
+ struct radix_node *t = rn_search(v_arg, top);
+ caddr_t cp = v + head_off;
+ int b;
+ struct radix_node *p, *tt, *x;
/*
* Find first bit at which v and t->rn_key differ
*/
- {
- register caddr_t cp2 = t->rn_key + head_off;
- register int cmp_res;
+ caddr_t cp2 = t->rn_key + head_off;
+ int cmp_res;
caddr_t cplim = v + vlen;
while (cp < cplim)
if (*cp2++ != *cp++)
goto on1;
*dupentry = 1;
- return t;
+ return (t);
on1:
*dupentry = 0;
cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
for (b = (cp - v) << 3; cmp_res; b--)
cmp_res >>= 1;
- }
- {
- register struct radix_node *p, *x = top;
+
+ x = top;
cp = v;
do {
p = x;
@@ -486,58 +496,51 @@ on1:
if (rn_debug)
log(LOG_DEBUG, "rn_insert: Coming Out:\n"), traverse(p);
#endif
- }
return (tt);
}
struct radix_node *
-rn_addmask(n_arg, search, skip)
- int search, skip;
- void *n_arg;
+rn_addmask_r(void *arg, struct radix_node_head *maskhead, int search, int skip)
{
- caddr_t netmask = (caddr_t)n_arg;
- register struct radix_node *x;
- register caddr_t cp, cplim;
- register int b = 0, mlen, j;
- int maskduplicated, m0, isnormal;
+ unsigned char *netmask = arg;
+ unsigned char *cp, *cplim;
+ struct radix_node *x;
+ int b = 0, mlen, j;
+ int maskduplicated, isnormal;
struct radix_node *saved_x;
- static int last_zeroed = 0;
+ unsigned char addmask_key[RADIX_MAX_KEY_LEN];
- if ((mlen = LEN(netmask)) > max_keylen)
- mlen = max_keylen;
+ if ((mlen = LEN(netmask)) > RADIX_MAX_KEY_LEN)
+ mlen = RADIX_MAX_KEY_LEN;
if (skip == 0)
skip = 1;
if (mlen <= skip)
- return (mask_rnhead->rnh_nodes);
+ return (maskhead->rnh_nodes);
+
+ bzero(addmask_key, RADIX_MAX_KEY_LEN);
if (skip > 1)
bcopy(rn_ones + 1, addmask_key + 1, skip - 1);
- if ((m0 = mlen) > skip)
- bcopy(netmask + skip, addmask_key + skip, mlen - skip);
+ bcopy(netmask + skip, addmask_key + skip, mlen - skip);
/*
* Trim trailing zeroes.
*/
for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;)
cp--;
mlen = cp - addmask_key;
- if (mlen <= skip) {
- if (m0 >= last_zeroed)
- last_zeroed = mlen;
- return (mask_rnhead->rnh_nodes);
- }
- if (m0 < last_zeroed)
- bzero(addmask_key + m0, last_zeroed - m0);
- *addmask_key = last_zeroed = mlen;
- x = rn_search(addmask_key, rn_masktop);
+ if (mlen <= skip)
+ return (maskhead->rnh_nodes);
+ *addmask_key = mlen;
+ x = rn_search(addmask_key, maskhead->rnh_treetop);
if (bcmp(addmask_key, x->rn_key, mlen) != 0)
x = 0;
if (x || search)
return (x);
- R_Zalloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x));
+ R_Zalloc(x, struct radix_node *, RADIX_MAX_KEY_LEN + 2 * sizeof (*x));
if ((saved_x = x) == 0)
return (0);
netmask = cp = (caddr_t)(x + 2);
bcopy(addmask_key, cp, mlen);
- x = rn_insert(cp, mask_rnhead, &maskduplicated, x);
+ x = rn_insert(cp, maskhead, &maskduplicated, x);
if (maskduplicated) {
log(LOG_ERR, "rn_addmask: mask impossibly already in tree");
Free(saved_x);
@@ -547,20 +550,18 @@ rn_addmask(n_arg, search, skip)
* Calculate index of mask, and check for normalcy.
* First find the first byte with a 0 bit, then if there are
* more bits left (remember we already trimmed the trailing 0's),
- * the pattern must be one of those in normal_chars[], or we have
+ * the bits should be contiguous, otherwise we have got
* a non-contiguous mask.
*/
+#define CONTIG(_c) (((~(_c) + 1) & (_c)) == (unsigned char)(~(_c) + 1))
cplim = netmask + mlen;
isnormal = 1;
for (cp = netmask + skip; (cp < cplim) && *(u_char *)cp == 0xff;)
cp++;
if (cp != cplim) {
- static char normal_chars[] = {
- 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
-
for (j = 0x80; (j & *cp) != 0; j >>= 1)
b++;
- if (*cp != normal_chars[b] || cp != (cplim - 1))
+ if (!CONTIG(*cp) || cp != (cplim - 1))
isnormal = 0;
}
b += (cp - netmask) << 3;
@@ -570,34 +571,48 @@ rn_addmask(n_arg, search, skip)
return (x);
}
+struct radix_node *
+rn_addmask(void *n_arg, int search, int skip)
+{
+ struct radix_node *tt;
+
+#ifdef _KERNEL
+ mtx_lock(&mask_mtx);
+#endif
+ tt = rn_addmask_r(&mask_rnhead_compat, n_arg, search, skip);
+
+#ifdef _KERNEL
+ mtx_unlock(&mask_mtx);
+#endif
+
+ return (tt);
+}
+
static int /* XXX: arbitrary ordering for non-contiguous masks */
-rn_lexobetter(m_arg, n_arg)
- void *m_arg, *n_arg;
+rn_lexobetter(void *m_arg, void *n_arg)
{
- register u_char *mp = m_arg, *np = n_arg, *lim;
+ u_char *mp = m_arg, *np = n_arg, *lim;
if (LEN(mp) > LEN(np))
- return 1; /* not really, but need to check longer one first */
+ return (1); /* not really, but need to check longer one first */
if (LEN(mp) == LEN(np))
for (lim = mp + LEN(mp); mp < lim;)
if (*mp++ > *np++)
- return 1;
- return 0;
+ return (1);
+ return (0);
}
static struct radix_mask *
-rn_new_radix_mask(tt, next)
- register struct radix_node *tt;
- register struct radix_mask *next;
+rn_new_radix_mask(struct radix_node *tt, struct radix_mask *next)
{
- register struct radix_mask *m;
+ struct radix_mask *m;
- MKGet(m);
- if (m == 0) {
- log(LOG_ERR, "Mask for route not entered\n");
+ R_Malloc(m, struct radix_mask *, sizeof (struct radix_mask));
+ if (m == NULL) {
+ log(LOG_ERR, "Failed to allocate route mask\n");
return (0);
}
- bzero(m, sizeof *m);
+ bzero(m, sizeof(*m));
m->rm_bit = tt->rn_bit;
m->rm_flags = tt->rn_flags;
if (tt->rn_flags & RNF_NORMAL)
@@ -606,17 +621,15 @@ rn_new_radix_mask(tt, next)
m->rm_mask = tt->rn_mask;
m->rm_mklist = next;
tt->rn_mklist = m;
- return m;
+ return (m);
}
struct radix_node *
-rn_addroute(v_arg, n_arg, head, treenodes)
- void *v_arg, *n_arg;
- struct radix_node_head *head;
- struct radix_node treenodes[2];
+rn_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
+ struct radix_node treenodes[2])
{
caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;
- register struct radix_node *t, *x = 0, *tt;
+ struct radix_node *t, *x = 0, *tt;
struct radix_node *saved_tt, *top = head->rnh_treetop;
short b = 0, b_leaf = 0;
int keyduplicated;
@@ -631,7 +644,8 @@ rn_addroute(v_arg, n_arg, head, treenodes)
* nodes and possibly save time in calculating indices.
*/
if (netmask) {
- if ((x = rn_addmask(netmask, 0, top->rn_offset)) == 0)
+ x = rn_addmask_r(netmask, head->rnh_masks, 0, top->rn_offset);
+ if (x == NULL)
return (0);
b_leaf = x->rn_bit;
b = -1 - x->rn_bit;
@@ -743,7 +757,7 @@ rn_addroute(v_arg, n_arg, head, treenodes)
on2:
/* Add new route to highest possible ancestor's list */
if ((netmask == 0) || (b > t->rn_bit ))
- return tt; /* can't lift at all */
+ return (tt); /* can't lift at all */
b_leaf = tt->rn_bit;
do {
x = t;
@@ -767,29 +781,27 @@ on2:
log(LOG_ERR,
"Non-unique normal route, mask not entered\n");
#endif
- return tt;
+ return (tt);
}
} else
mmask = m->rm_mask;
if (mmask == netmask) {
m->rm_refs++;
tt->rn_mklist = m;
- return tt;
+ return (tt);
}
if (rn_refines(netmask, mmask)
|| rn_lexobetter(netmask, mmask))
break;
}
*mp = rn_new_radix_mask(tt, *mp);
- return tt;
+ return (tt);
}
struct radix_node *
-rn_delete(v_arg, netmask_arg, head)
- void *v_arg, *netmask_arg;
- struct radix_node_head *head;
+rn_delete(void *v_arg, void *netmask_arg, struct radix_node_head *head)
{
- register struct radix_node *t, *p, *x, *tt;
+ struct radix_node *t, *p, *x, *tt;
struct radix_mask *m, *saved_m, **mp;
struct radix_node *dupedkey, *saved_tt, *top;
caddr_t v, netmask;
@@ -810,7 +822,8 @@ rn_delete(v_arg, netmask_arg, head)
* Delete our route from mask lists.
*/
if (netmask) {
- if ((x = rn_addmask(netmask, 1, head_off)) == 0)
+ x = rn_addmask_r(netmask, head->rnh_masks, 1, head_off);
+ if (x == NULL)
return (0);
netmask = x->rn_key;
while (tt->rn_mask != netmask)
@@ -822,7 +835,7 @@ rn_delete(v_arg, netmask_arg, head)
if (tt->rn_flags & RNF_NORMAL) {
if (m->rm_leaf != tt || m->rm_refs > 0) {
log(LOG_ERR, "rn_delete: inconsistent annotation\n");
- return 0; /* dangling ref could cause disaster */
+ return (0); /* dangling ref could cause disaster */
}
} else {
if (m->rm_mask != tt->rn_mask) {
@@ -843,7 +856,7 @@ rn_delete(v_arg, netmask_arg, head)
for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
if (m == saved_m) {
*mp = m->rm_mklist;
- MKFree(m);
+ Free(m);
break;
}
if (m == 0) {
@@ -934,7 +947,7 @@ on1:
struct radix_mask *mm = m->rm_mklist;
x->rn_mklist = 0;
if (--(m->rm_refs) < 0)
- MKFree(m);
+ Free(m);
m = mm;
}
if (m)
@@ -974,17 +987,14 @@ out:
* exit.
*/
static int
-rn_walktree_from(h, a, m, f, w)
- struct radix_node_head *h;
- void *a, *m;
- walktree_f_t *f;
- void *w;
+rn_walktree_from(struct radix_node_head *h, void *a, void *m,
+ walktree_f_t *f, void *w)
{
int error;
struct radix_node *base, *next;
u_char *xa = (u_char *)a;
u_char *xm = (u_char *)m;
- register struct radix_node *rn, *last = 0 /* shut up gcc */;
+ struct radix_node *rn, *last = NULL; /* shut up gcc */
int stopping = 0;
int lastb;
@@ -1077,18 +1087,15 @@ rn_walktree_from(h, a, m, f, w)
}
}
- return 0;
+ return (0);
}
static int
-rn_walktree(h, f, w)
- struct radix_node_head *h;
- walktree_f_t *f;
- void *w;
+rn_walktree(struct radix_node_head *h, walktree_f_t *f, void *w)
{
int error;
struct radix_node *base, *next;
- register struct radix_node *rn = h->rnh_treetop;
+ struct radix_node *rn = h->rnh_treetop;
/*
* This gets complicated because we may delete the node
* while applying the function f to it, so we need to calculate
@@ -1130,13 +1137,11 @@ rn_walktree(h, f, w)
* bits starting at 'off'.
* Return 1 on success, 0 on error.
*/
-int
-rn_inithead(head, off)
- void **head;
- int off;
+static int
+rn_inithead_internal(void **head, int off)
{
- register struct radix_node_head *rnh;
- register struct radix_node *t, *tt, *ttt;
+ struct radix_node_head *rnh;
+ struct radix_node *t, *tt, *ttt;
if (*head)
return (1);
R_Zalloc(rnh, struct radix_node_head *, sizeof (*rnh));
@@ -1165,8 +1170,8 @@ rn_inithead(head, off)
return (1);
}
-int
-rn_detachhead(void **head)
+static void
+rn_detachhead_internal(void **head)
{
struct radix_node_head *rnh;
@@ -1178,28 +1183,60 @@ rn_detachhead(void **head)
Free(rnh);
*head = NULL;
+}
+
+int
+rn_inithead(void **head, int off)
+{
+ struct radix_node_head *rnh;
+
+ if (*head != NULL)
+ return (1);
+
+ if (rn_inithead_internal(head, off) == 0)
+ return (0);
+
+ rnh = (struct radix_node_head *)(*head);
+
+ if (rn_inithead_internal((void **)&rnh->rnh_masks, 0) == 0) {
+ rn_detachhead_internal(head);
+ return (0);
+ }
+
+ return (1);
+}
+
+int
+rn_detachhead(void **head)
+{
+ struct radix_node_head *rnh;
+
+ KASSERT((head != NULL && *head != NULL),
+ ("%s: head already freed", __func__));
+
+ rnh = *head;
+
+ rn_detachhead_internal((void **)&rnh->rnh_masks);
+ rn_detachhead_internal(head);
return (1);
}
void
rn_init(int maxk)
{
- char *cp, *cplim;
-
- max_keylen = maxk;
- if (max_keylen == 0) {
+ if ((maxk <= 0) || (maxk > RADIX_MAX_KEY_LEN)) {
log(LOG_ERR,
- "rn_init: radix functions require max_keylen be set\n");
+ "rn_init: max_keylen must be within 1..%d\n",
+ RADIX_MAX_KEY_LEN);
return;
}
- R_Malloc(rn_zeros, char *, 3 * max_keylen);
- if (rn_zeros == NULL)
- panic("rn_init");
- bzero(rn_zeros, 3 * max_keylen);
- rn_ones = cp = rn_zeros + max_keylen;
- addmask_key = cplim = rn_ones + max_keylen;
- while (cp < cplim)
- *cp++ = -1;
- if (rn_inithead((void **)(void *)&mask_rnhead, 0) == 0)
+
+ /*
+ * XXX: Compat for old rn_addmask() users
+ */
+ if (rn_inithead((void **)(void *)&mask_rnhead_compat, 0) == 0)
panic("rn_init 2");
+#ifdef _KERNEL
+ mtx_init(&mask_mtx, "radix_mask", NULL, MTX_DEF);
+#endif
}
diff --git a/freebsd/sys/net/radix.h b/freebsd/sys/net/radix.h
index 5bacaa3a..3554c77c 100644
--- a/freebsd/sys/net/radix.h
+++ b/freebsd/sys/net/radix.h
@@ -119,9 +119,9 @@ struct radix_node_head {
(void *v, void *mask, struct radix_node_head *head);
struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */
(void *v, void *mask, struct radix_node_head *head);
- struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */
+ struct radix_node *(*rnh_matchaddr) /* longest match for sockaddr */
(void *v, struct radix_node_head *head);
- struct radix_node *(*rnh_lookup) /* locate based on sockaddr */
+ struct radix_node *(*rnh_lookup) /*exact match for sockaddr*/
(void *v, void *mask, struct radix_node_head *head);
struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */
(void *v, struct radix_node_head *head);
@@ -136,6 +136,7 @@ struct radix_node_head {
#ifdef _KERNEL
struct rwlock rnh_lock; /* locks entire radix tree */
#endif
+ struct radix_node_head *rnh_masks; /* Storage for our masks */
};
#ifndef _KERNEL
@@ -167,6 +168,7 @@ int rn_detachhead(void **);
int rn_refines(void *, void *);
struct radix_node
*rn_addmask(void *, int, int),
+ *rn_addmask_r(void *, struct radix_node_head *, int, int),
*rn_addroute (void *, void *, struct radix_node_head *,
struct radix_node [2]),
*rn_delete(void *, void *, struct radix_node_head *),
diff --git a/freebsd/sys/net/radix_mpath.c b/freebsd/sys/net/radix_mpath.c
index 0f89bf5e..1bce388e 100644
--- a/freebsd/sys/net/radix_mpath.c
+++ b/freebsd/sys/net/radix_mpath.c
@@ -118,11 +118,16 @@ rt_mpath_matchgate(struct rtentry *rt, struct sockaddr *gate)
if (rt->rt_gateway->sa_family == AF_LINK) {
if (!memcmp(rt->rt_ifa->ifa_addr, gate, gate->sa_len))
break;
- } else {
- if (rt->rt_gateway->sa_len == gate->sa_len &&
- !memcmp(rt->rt_gateway, gate, gate->sa_len))
- break;
}
+
+ /*
+ * Check for other options:
+ * 1) Routes with 'real' IPv4/IPv6 gateway
+ * 2) Loopback host routes (another AF_LINK/sockadd_dl check)
+ * */
+ if (rt->rt_gateway->sa_len == gate->sa_len &&
+ !memcmp(rt->rt_gateway, gate, gate->sa_len))
+ break;
} while ((rn = rn_mpath_next(rn)) != NULL);
return (struct rtentry *)rn;
@@ -157,6 +162,7 @@ rt_mpath_deldup(struct rtentry *headrt, struct rtentry *rt)
/*
* check if we have the same key/mask/gateway on the table already.
+ * Assume @rt rt_key host bits are cleared according to @netmask
*/
int
rt_mpath_conflict(struct radix_node_head *rnh, struct rtentry *rt,
@@ -164,76 +170,13 @@ rt_mpath_conflict(struct radix_node_head *rnh, struct rtentry *rt,
{
struct radix_node *rn, *rn1;
struct rtentry *rt1;
- char *p, *q, *eq;
- int same, l, skip;
rn = (struct radix_node *)rt;
rn1 = rnh->rnh_lookup(rt_key(rt), netmask, rnh);
if (!rn1 || rn1->rn_flags & RNF_ROOT)
- return 0;
-
- /*
- * unlike other functions we have in this file, we have to check
- * all key/mask/gateway as rnh_lookup can match less specific entry.
- */
- rt1 = (struct rtentry *)rn1;
-
- /* compare key. */
- if (rt_key(rt1)->sa_len != rt_key(rt)->sa_len ||
- bcmp(rt_key(rt1), rt_key(rt), rt_key(rt1)->sa_len))
- goto different;
-
- /* key was the same. compare netmask. hairy... */
- if (rt_mask(rt1) && netmask) {
- skip = rnh->rnh_treetop->rn_offset;
- if (rt_mask(rt1)->sa_len > netmask->sa_len) {
- /*
- * as rt_mask(rt1) is made optimal by radix.c,
- * there must be some 1-bits on rt_mask(rt1)
- * after netmask->sa_len. therefore, in
- * this case, the entries are different.
- */
- if (rt_mask(rt1)->sa_len > skip)
- goto different;
- else {
- /* no bits to compare, i.e. same*/
- goto maskmatched;
- }
- }
-
- l = rt_mask(rt1)->sa_len;
- if (skip > l) {
- /* no bits to compare, i.e. same */
- goto maskmatched;
- }
- p = (char *)rt_mask(rt1);
- q = (char *)netmask;
- if (bcmp(p + skip, q + skip, l - skip))
- goto different;
- /*
- * need to go through all the bit, as netmask is not
- * optimal and can contain trailing 0s
- */
- eq = (char *)netmask + netmask->sa_len;
- q += l;
- same = 1;
- while (eq > q)
- if (*q++) {
- same = 0;
- break;
- }
- if (!same)
- goto different;
- } else if (!rt_mask(rt1) && !netmask)
- ; /* no mask to compare, i.e. same */
- else {
- /* one has mask and the other does not, different */
- goto different;
- }
-
-maskmatched:
+ return (0);
- /* key/mask were the same. compare gateway for all multipaths */
+ /* key/mask are the same. compare gateway for all multipaths */
do {
rt1 = (struct rtentry *)rn1;
@@ -254,11 +197,10 @@ maskmatched:
}
/* all key/mask/gateway are the same. conflicting entry. */
- return EEXIST;
+ return (EEXIST);
} while ((rn1 = rn_mpath_next(rn1)) != NULL);
-different:
- return 0;
+ return (0);
}
void
diff --git a/freebsd/sys/net/route.c b/freebsd/sys/net/route.c
index fdd8a12c..b444b740 100644
--- a/freebsd/sys/net/route.c
+++ b/freebsd/sys/net/route.c
@@ -39,6 +39,7 @@
#include <rtems/bsd/local/opt_inet.h>
#include <rtems/bsd/local/opt_inet6.h>
#include <rtems/bsd/local/opt_route.h>
+#include <rtems/bsd/local/opt_sctp.h>
#include <rtems/bsd/local/opt_mrouting.h>
#include <rtems/bsd/local/opt_mpath.h>
@@ -92,6 +93,14 @@
#define RT_NUMFIBS 1
#endif
+#if defined(INET) || defined(INET6)
+#ifdef SCTP
+extern void sctp_addr_change(struct ifaddr *ifa, int cmd);
+#endif /* SCTP */
+#endif
+
+
+/* This is read-only.. */
u_int rt_numfibs = RT_NUMFIBS;
SYSCTL_UINT(_net, OID_AUTO, fibs, CTLFLAG_RD, &rt_numfibs, 0, "");
/*
@@ -131,7 +140,8 @@ VNET_DEFINE(int, rttrash); /* routes not in table but not freed */
/* compare two sockaddr structures */
-#define sa_equal(a1, a2) (bcmp((a1), (a2), (a1)->sa_len) == 0)
+#define sa_equal(a1, a2) (((a1)->sa_len == (a2)->sa_len) && \
+ (bcmp((a1), (a2), (a1)->sa_len) == 0))
/*
* Convert a 'struct radix_node *' to a 'struct rtentry *'.
@@ -974,6 +984,57 @@ bad:
return (error);
}
+#if 0
+int p_sockaddr(char *buf, int buflen, struct sockaddr *s);
+int rt_print(char *buf, int buflen, struct rtentry *rt);
+
+int
+p_sockaddr(char *buf, int buflen, struct sockaddr *s)
+{
+ void *paddr = NULL;
+
+ switch (s->sa_family) {
+ case AF_INET:
+ paddr = &((struct sockaddr_in *)s)->sin_addr;
+ break;
+ case AF_INET6:
+ paddr = &((struct sockaddr_in6 *)s)->sin6_addr;
+ break;
+ }
+
+ if (paddr == NULL)
+ return (0);
+
+ if (inet_ntop(s->sa_family, paddr, buf, buflen) == NULL)
+ return (0);
+
+ return (strlen(buf));
+}
+
+int
+rt_print(char *buf, int buflen, struct rtentry *rt)
+{
+ struct sockaddr *addr, *mask;
+ int i = 0;
+
+ addr = rt_key(rt);
+ mask = rt_mask(rt);
+
+ i = p_sockaddr(buf, buflen, addr);
+ if (!(rt->rt_flags & RTF_HOST)) {
+ buf[i++] = '/';
+ i += p_sockaddr(buf + i, buflen - i, mask);
+ }
+
+ if (rt->rt_flags & RTF_GATEWAY) {
+ buf[i++] = '>';
+ i += p_sockaddr(buf + i, buflen - i, rt->rt_gateway);
+ }
+
+ return (i);
+}
+#endif
+
#ifdef RADIX_MPATH
static int
rn_mpath_update(int req, struct rt_addrinfo *info,
@@ -987,10 +1048,11 @@ rn_mpath_update(int req, struct rt_addrinfo *info,
register struct radix_node *rn;
int error = 0;
- rn = rnh->rnh_matchaddr(dst, rnh);
+ rn = rnh->rnh_lookup(dst, netmask, rnh);
if (rn == NULL)
return (ESRCH);
rto = rt = RNTORT(rn);
+
rt = rt_mpath_matchgate(rt, gateway);
if (rt == NULL)
return (ESRCH);
@@ -1495,7 +1557,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum)
fibnum = RT_DEFAULT_FIB;
break;
}
- if (fibnum == -1) {
+ if (fibnum == RT_ALL_FIBS) {
if (rt_add_addr_allfibs == 0 && cmd == (int)RTM_ADD) {
#ifndef __rtems__
startfib = endfib = curthread->td_proc->p_fibnum;
@@ -1548,10 +1610,10 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum)
/* this table doesn't exist but others might */
continue;
RADIX_NODE_HEAD_RLOCK(rnh);
+ rn = rnh->rnh_lookup(dst, netmask, rnh);
#ifdef RADIX_MPATH
if (rn_mpath_capable(rnh)) {
- rn = rnh->rnh_matchaddr(dst, rnh);
if (rn == NULL)
error = ESRCH;
else {
@@ -1565,17 +1627,14 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum)
*/
rt = rt_mpath_matchgate(rt,
ifa->ifa_addr);
- if (!rt)
+ if (rt == NULL)
error = ESRCH;
}
}
- else
#endif
- rn = rnh->rnh_lookup(dst, netmask, rnh);
error = (rn == NULL ||
(rn->rn_flags & RNF_ROOT) ||
- RNTORT(rn)->rt_ifa != ifa ||
- !sa_equal((struct sockaddr *)rn->rn_key, dst));
+ RNTORT(rn)->rt_ifa != ifa);
RADIX_NODE_HEAD_RUNLOCK(rnh);
if (error) {
/* this is only an error if bad on ALL tables */
@@ -1706,7 +1765,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum)
int
rtinit_fib(struct ifaddr *ifa, int cmd, int flags)
{
- return (rtinit1(ifa, cmd, flags, -1));
+ return (rtinit1(ifa, cmd, flags, RT_ALL_FIBS));
}
#endif
@@ -1730,8 +1789,94 @@ rtinit(struct ifaddr *ifa, int cmd, int flags)
case AF_INET6:
case AF_INET:
/* We do support multiple FIBs. */
- fib = -1;
+ fib = RT_ALL_FIBS;
break;
}
return (rtinit1(ifa, cmd, flags, fib));
}
+
+/*
+ * Announce interface address arrival/withdraw
+ * Returns 0 on success.
+ */
+int
+rt_addrmsg(int cmd, struct ifaddr *ifa, int fibnum)
+{
+
+ KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
+ ("unexpected cmd %d", cmd));
+
+ KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs),
+ ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs));
+
+#if defined(INET) || defined(INET6)
+#ifdef SCTP
+ /*
+ * notify the SCTP stack
+ * this will only get called when an address is added/deleted
+ * XXX pass the ifaddr struct instead if ifa->ifa_addr...
+ */
+ sctp_addr_change(ifa, cmd);
+#endif /* SCTP */
+#endif
+ return (rtsock_addrmsg(cmd, ifa, fibnum));
+}
+
+/*
+ * Announce route addition/removal.
+ * Users of this function MUST validate input data BEFORE calling.
+ * However we have to be able to handle invalid data:
+ * if some userland app sends us "invalid" route message (invalid mask,
+ * no dst, wrong address families, etc...) we need to pass it back
+ * to app (and any other rtsock consumers) with rtm_errno field set to
+ * non-zero value.
+ * Returns 0 on success.
+ */
+int
+rt_routemsg(int cmd, struct ifnet *ifp, int error, struct rtentry *rt,
+ int fibnum)
+{
+
+ KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
+ ("unexpected cmd %d", cmd));
+
+ KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs),
+ ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs));
+
+ KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__));
+
+ return (rtsock_routemsg(cmd, ifp, error, rt, fibnum));
+}
+
+void
+rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
+{
+
+ rt_newaddrmsg_fib(cmd, ifa, error, rt, RT_ALL_FIBS);
+}
+
+/*
+ * This is called to generate messages from the routing socket
+ * indicating a network interface has had addresses associated with it.
+ */
+void
+rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt,
+ int fibnum)
+{
+
+ KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
+ ("unexpected cmd %u", cmd));
+ KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs),
+ ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs));
+
+ if (cmd == RTM_ADD) {
+ rt_addrmsg(cmd, ifa, fibnum);
+ if (rt != NULL)
+ rt_routemsg(cmd, ifa->ifa_ifp, error, rt, fibnum);
+ } else {
+ if (rt != NULL)
+ rt_routemsg(cmd, ifa->ifa_ifp, error, rt, fibnum);
+ rt_addrmsg(cmd, ifa, fibnum);
+ }
+}
+
diff --git a/freebsd/sys/net/route.h b/freebsd/sys/net/route.h
index 997f3cd6..0baa9a4c 100644
--- a/freebsd/sys/net/route.h
+++ b/freebsd/sys/net/route.h
@@ -92,7 +92,9 @@ struct rt_metrics {
#define RTTTOPRHZ(r) ((r) / (RTM_RTTUNIT / PR_SLOWHZ))
#define RT_DEFAULT_FIB 0 /* Explicitly mark fib=0 restricted cases */
-extern u_int rt_numfibs; /* number fo usable routing tables */
+#define RT_ALL_FIBS -1 /* Announce event for every fib */
+extern u_int rt_numfibs; /* number of usable routing tables */
+extern u_int rt_add_addr_allfibs; /* Announce interfaces to all fibs */
/*
* XXX kernel function pointer `rt_output' is visible to applications.
*/
@@ -365,10 +367,15 @@ void rt_missmsg(int, struct rt_addrinfo *, int, int);
void rt_missmsg_fib(int, struct rt_addrinfo *, int, int, int);
void rt_newaddrmsg(int, struct ifaddr *, int, struct rtentry *);
void rt_newaddrmsg_fib(int, struct ifaddr *, int, struct rtentry *, int);
+int rt_addrmsg(int, struct ifaddr *, int);
+int rt_routemsg(int, struct ifnet *ifp, int, struct rtentry *, int);
void rt_newmaddrmsg(int, struct ifmultiaddr *);
int rt_setgate(struct rtentry *, struct sockaddr *, struct sockaddr *);
void rt_maskedcopy(struct sockaddr *, struct sockaddr *, struct sockaddr *);
+int rtsock_addrmsg(int, struct ifaddr *, int);
+int rtsock_routemsg(int, struct ifnet *ifp, int, struct rtentry *, int);
+
/*
* Note the following locking behavior:
*
diff --git a/freebsd/sys/net/rtsock.c b/freebsd/sys/net/rtsock.c
index 1eebe095..e768e17b 100644
--- a/freebsd/sys/net/rtsock.c
+++ b/freebsd/sys/net/rtsock.c
@@ -32,7 +32,6 @@
* $FreeBSD$
*/
#include <rtems/bsd/local/opt_compat.h>
-#include <rtems/bsd/local/opt_sctp.h>
#include <rtems/bsd/local/opt_mpath.h>
#include <rtems/bsd/local/opt_inet.h>
#include <rtems/bsd/local/opt_inet6.h>
@@ -69,12 +68,6 @@
#include <netinet6/scope6_var.h>
#endif
-#if defined(INET) || defined(INET6)
-#ifdef SCTP
-extern void sctp_addr_change(struct ifaddr *ifa, int cmd);
-#endif /* SCTP */
-#endif
-
#ifdef COMPAT_FREEBSD32
#include <sys/mount.h>
#include <compat/freebsd32/freebsd32.h>
@@ -156,7 +149,6 @@ static struct sockaddr sa_zero = { sizeof(sa_zero), AF_INET, };
* notification to a socket bound to a particular FIB.
*/
#define RTS_FILTER_FIB M_PROTO8
-#define RTS_ALLFIBS -1
static struct {
int ip_count; /* attached w/ AF_INET */
@@ -716,10 +708,24 @@ route_output(struct mbuf *m, struct socket *so)
info.rti_info[RTAX_DST]->sa_family);
if (rnh == NULL)
senderr(EAFNOSUPPORT);
+
RADIX_NODE_HEAD_RLOCK(rnh);
- rt = (struct rtentry *) rnh->rnh_lookup(info.rti_info[RTAX_DST],
- info.rti_info[RTAX_NETMASK], rnh);
- if (rt == NULL) { /* XXX looks bogus */
+
+ if (info.rti_info[RTAX_NETMASK] == NULL &&
+ rtm->rtm_type == RTM_GET) {
+ /*
+ * Provide logest prefix match for
+ * address lookup (no mask).
+ * 'route -n get addr'
+ */
+ rt = (struct rtentry *) rnh->rnh_matchaddr(
+ info.rti_info[RTAX_DST], rnh);
+ } else
+ rt = (struct rtentry *) rnh->rnh_lookup(
+ info.rti_info[RTAX_DST],
+ info.rti_info[RTAX_NETMASK], rnh);
+
+ if (rt == NULL) {
RADIX_NODE_HEAD_RUNLOCK(rnh);
senderr(ESRCH);
}
@@ -776,25 +782,6 @@ route_output(struct mbuf *m, struct socket *so)
RT_ADDREF(rt);
RADIX_NODE_HEAD_RUNLOCK(rnh);
- /*
- * Fix for PR: 82974
- *
- * RTM_CHANGE/LOCK need a perfect match, rn_lookup()
- * returns a perfect match in case a netmask is
- * specified. For host routes only a longest prefix
- * match is returned so it is necessary to compare the
- * existence of the netmask. If both have a netmask
- * rnh_lookup() did a perfect match and if none of them
- * have a netmask both are host routes which is also a
- * perfect match.
- */
-
- if (rtm->rtm_type != RTM_GET &&
- (!rt_mask(rt) != !info.rti_info[RTAX_NETMASK])) {
- RT_UNLOCK(rt);
- senderr(ESRCH);
- }
-
switch(rtm->rtm_type) {
case RTM_GET:
@@ -1235,7 +1222,7 @@ rt_missmsg_fib(int type, struct rt_addrinfo *rtinfo, int flags, int error,
if (m == NULL)
return;
- if (fibnum != RTS_ALLFIBS) {
+ if (fibnum != RT_ALL_FIBS) {
KASSERT(fibnum >= 0 && fibnum < rt_numfibs, ("%s: fibnum out "
"of range 0 <= %d < %d", __func__, fibnum, rt_numfibs));
M_SETFIB(m, fibnum);
@@ -1253,7 +1240,7 @@ void
rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error)
{
- rt_missmsg_fib(type, rtinfo, flags, error, RTS_ALLFIBS);
+ rt_missmsg_fib(type, rtinfo, flags, error, RT_ALL_FIBS);
}
/*
@@ -1282,89 +1269,92 @@ rt_ifmsg(struct ifnet *ifp)
}
/*
- * This is called to generate messages from the routing socket
- * indicating a network interface has had addresses associated with it.
- * if we ever reverse the logic and replace messages TO the routing
- * socket indicate a request to configure interfaces, then it will
- * be unnecessary as the routing socket will automatically generate
- * copies of it.
+ * Announce interface address arrival/withdraw.
+ * Please do not call directly, use rt_addrmsg().
+ * Assume input data to be valid.
+ * Returns 0 on success.
*/
-void
-rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt,
- int fibnum)
+int
+rtsock_addrmsg(int cmd, struct ifaddr *ifa, int fibnum)
{
struct rt_addrinfo info;
- struct sockaddr *sa = NULL;
- int pass;
- struct mbuf *m = NULL;
+ struct sockaddr *sa;
+ int ncmd;
+ struct mbuf *m;
+ struct ifa_msghdr *ifam;
struct ifnet *ifp = ifa->ifa_ifp;
- KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
- ("unexpected cmd %u", cmd));
-#if defined(INET) || defined(INET6)
-#ifdef SCTP
- /*
- * notify the SCTP stack
- * this will only get called when an address is added/deleted
- * XXX pass the ifaddr struct instead if ifa->ifa_addr...
- */
- sctp_addr_change(ifa, cmd);
-#endif /* SCTP */
-#endif
if (route_cb.any_count == 0)
- return;
- for (pass = 1; pass < 3; pass++) {
- bzero((caddr_t)&info, sizeof(info));
- if ((cmd == RTM_ADD && pass == 1) ||
- (cmd == RTM_DELETE && pass == 2)) {
- struct ifa_msghdr *ifam;
- int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR;
-
- info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr;
- info.rti_info[RTAX_IFP] = ifp->if_addr->ifa_addr;
- info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
- info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
- if ((m = rt_msg1(ncmd, &info)) == NULL)
- continue;
- ifam = mtod(m, struct ifa_msghdr *);
- ifam->ifam_index = ifp->if_index;
- ifam->ifam_metric = ifa->ifa_metric;
- ifam->ifam_flags = ifa->ifa_flags;
- ifam->ifam_addrs = info.rti_addrs;
- }
- if ((cmd == RTM_ADD && pass == 2) ||
- (cmd == RTM_DELETE && pass == 1)) {
- struct rt_msghdr *rtm;
+ return (0);
- if (rt == NULL)
- continue;
- info.rti_info[RTAX_NETMASK] = rt_mask(rt);
- info.rti_info[RTAX_DST] = sa = rt_key(rt);
- info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
- if ((m = rt_msg1(cmd, &info)) == NULL)
- continue;
- rtm = mtod(m, struct rt_msghdr *);
- rtm->rtm_index = ifp->if_index;
- rtm->rtm_flags |= rt->rt_flags;
- rtm->rtm_errno = error;
- rtm->rtm_addrs = info.rti_addrs;
- }
- if (fibnum != RTS_ALLFIBS) {
- KASSERT(fibnum >= 0 && fibnum < rt_numfibs, ("%s: "
- "fibnum out of range 0 <= %d < %d", __func__,
- fibnum, rt_numfibs));
- M_SETFIB(m, fibnum);
- m->m_flags |= RTS_FILTER_FIB;
- }
- rt_dispatch(m, sa ? sa->sa_family : AF_UNSPEC);
+ ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR;
+
+ bzero((caddr_t)&info, sizeof(info));
+ info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr;
+ info.rti_info[RTAX_IFP] = ifp->if_addr->ifa_addr;
+ info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
+ info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
+ if ((m = rt_msg1(ncmd, &info)) == NULL)
+ return (ENOBUFS);
+ ifam = mtod(m, struct ifa_msghdr *);
+ ifam->ifam_index = ifp->if_index;
+ ifam->ifam_metric = ifa->ifa_metric;
+ ifam->ifam_flags = ifa->ifa_flags;
+ ifam->ifam_addrs = info.rti_addrs;
+
+ if (fibnum != RT_ALL_FIBS) {
+ M_SETFIB(m, fibnum);
+ m->m_flags |= RTS_FILTER_FIB;
}
+
+ rt_dispatch(m, sa ? sa->sa_family : AF_UNSPEC);
+
+ return (0);
}
-void
-rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
+/*
+ * Announce route addition/removal.
+ * Please do not call directly, use rt_routemsg().
+ * Note that @rt data MAY be inconsistent/invalid:
+ * if some userland app sends us "invalid" route message (invalid mask,
+ * no dst, wrong address families, etc...) we need to pass it back
+ * to app (and any other rtsock consumers) with rtm_errno field set to
+ * non-zero value.
+ *
+ * Returns 0 on success.
+ */
+int
+rtsock_routemsg(int cmd, struct ifnet *ifp, int error, struct rtentry *rt,
+ int fibnum)
{
+ struct rt_addrinfo info;
+ struct sockaddr *sa;
+ struct mbuf *m;
+ struct rt_msghdr *rtm;
+
+ if (route_cb.any_count == 0)
+ return (0);
- rt_newaddrmsg_fib(cmd, ifa, error, rt, RTS_ALLFIBS);
+ bzero((caddr_t)&info, sizeof(info));
+ info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+ info.rti_info[RTAX_DST] = sa = rt_key(rt);
+ info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
+ if ((m = rt_msg1(cmd, &info)) == NULL)
+ return (ENOBUFS);
+ rtm = mtod(m, struct rt_msghdr *);
+ rtm->rtm_index = ifp->if_index;
+ rtm->rtm_flags |= rt->rt_flags;
+ rtm->rtm_errno = error;
+ rtm->rtm_addrs = info.rti_addrs;
+
+ if (fibnum != RT_ALL_FIBS) {
+ M_SETFIB(m, fibnum);
+ m->m_flags |= RTS_FILTER_FIB;
+ }
+
+ rt_dispatch(m, sa ? sa->sa_family : AF_UNSPEC);
+
+ return (0);
}
/*
@@ -1839,7 +1829,7 @@ sysctl_rtsock(SYSCTL_HANDLER_ARGS)
fib = BSD_DEFAULT_FIB;
#endif /* __rtems__ */
else if (namelen == 4)
- fib = (name[3] == -1) ?
+ fib = (name[3] == RT_ALL_FIBS) ?
#ifndef __rtems__
req->td->td_proc->p_fibnum : name[3];
#else /* __rtems__ */