svn commit: r195784 - in head: sbin/ifconfig sys/net80211

Rui Paulo rpaulo at FreeBSD.org
Mon Jul 20 19:12:09 UTC 2009


Author: rpaulo
Date: Mon Jul 20 19:12:08 2009
New Revision: 195784
URL: http://svn.freebsd.org/changeset/base/195784

Log:
  More mesh bits, namely:
  * bridge support (sam)
  * handling of errors (sam)
  * deletion of inactive routing entries
  * more debug msgs (sam)
  * fixed some inconsistencies with the spec.
  * decap is now specific to mesh (sam)
  * print mesh seq. no. on ifconfig list mesh
  * small perf. improvements
  
  Reviewed by:	sam
  Approved by:	re (kib)

Modified:
  head/sbin/ifconfig/ifieee80211.c
  head/sys/net80211/ieee80211_hwmp.c
  head/sys/net80211/ieee80211_input.c
  head/sys/net80211/ieee80211_ioctl.h
  head/sys/net80211/ieee80211_mesh.c
  head/sys/net80211/ieee80211_mesh.h
  head/sys/net80211/ieee80211_output.c

Modified: head/sbin/ifconfig/ifieee80211.c
==============================================================================
--- head/sbin/ifconfig/ifieee80211.c	Mon Jul 20 16:19:42 2009	(r195783)
+++ head/sbin/ifconfig/ifieee80211.c	Mon Jul 20 19:12:08 2009	(r195784)
@@ -3965,21 +3965,23 @@ list_mesh(int s)
 	if (ioctl(s, SIOCG80211, &ireq) < 0)
 	 	err(1, "unable to get the Mesh routing table");
 
-	printf("%-17.17s %-17.17s %4s %4s %4s\n"
+	printf("%-17.17s %-17.17s %4s %4s %4s %6s\n"
 		, "DEST"
 		, "NEXT HOP"
 		, "HOPS"
 		, "METRIC"
-		, "LIFETIME");
+		, "LIFETIME"
+		, "MSEQ");
 
 	for (i = 0; i < ireq.i_len / sizeof(*routes); i++) {
 		printf("%s ",
 		    ether_ntoa((const struct ether_addr *)routes[i].imr_dest));
-		printf("%s %4u   %4d   %6d\n",
+		printf("%s %4u   %4u   %6u %6u\n",
 			ether_ntoa((const struct ether_addr *)
 			    routes[i].imr_nexthop),
 			routes[i].imr_nhops, routes[i].imr_metric,
-			routes[i].imr_lifetime);
+			routes[i].imr_lifetime,
+			routes[i].imr_lastmseq);
 	}
 }
 

Modified: head/sys/net80211/ieee80211_hwmp.c
==============================================================================
--- head/sys/net80211/ieee80211_hwmp.c	Mon Jul 20 16:19:42 2009	(r195783)
+++ head/sys/net80211/ieee80211_hwmp.c	Mon Jul 20 19:12:08 2009	(r195784)
@@ -121,7 +121,6 @@ static int	ieee80211_hwmp_replyforward =
 static const int ieee80211_hwmp_maxprepretries = 3;
 static const struct timeval ieee80211_hwmp_maxhopstime = { 0, 500000 };
 static const struct timeval ieee80211_hwmp_preqminint = { 0, 100000 };
-static const struct timeval ieee80211_hwmp_prepminint = { 0, 100000 };
 static const struct timeval ieee80211_hwmp_perrminint = { 0, 100000 };
 static const struct timeval ieee80211_hwmp_roottimeout = { 5, 0 };
 static const struct timeval ieee80211_hwmp_pathtimeout = { 5, 0 };
@@ -152,8 +151,6 @@ static const struct timeval ieee80211_hw
 /* NB: the Target Address set in a Proactive PREQ is the broadcast address. */
 static const uint8_t	broadcastaddr[IEEE80211_ADDR_LEN] =
 	{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-static const uint8_t	invalidaddr[IEEE80211_ADDR_LEN] =
-	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
 typedef uint32_t ieee80211_hwmp_seq;
 #define	IEEE80211_HWMP_SEQ_LEQ(a, b)	((int32_t)((a)-(b)) <= 0)
@@ -171,7 +168,6 @@ struct ieee80211_hwmp_state {
 	ieee80211_hwmp_seq	hs_seq;		/* next seq to be used */
 	ieee80211_hwmp_seq	hs_preqid;	/* next PREQ ID to be used */
 	struct timeval		hs_lastpreq;	/* last time we sent a PREQ */
-	struct timeval		hs_lastprep;	/* last time we sent a PREP */
 	struct timeval		hs_lastperr;	/* last time we sent a PERR */
 	int			hs_rootmode;	/* proactive HWMP */
 	struct callout		hs_roottimer;
@@ -201,6 +197,8 @@ static const struct ieee80211_mesh_proto
 	.mpp_vdetach	= hwmp_vdetach,
 	.mpp_newstate	= hwmp_newstate,
 	.mpp_privlen	= sizeof(struct ieee80211_hwmp_route),
+	/* ieee80211_hwmp_pathtimeout */
+	.mpp_inact	= { 5, 0 },
 };
 
 
@@ -250,8 +248,7 @@ hwmp_vdetach(struct ieee80211vap *vap)
 {
 	struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
 
-	if (callout_active(&hs->hs_roottimer))
-		callout_drain(&hs->hs_roottimer);
+	callout_drain(&hs->hs_roottimer);
 	free(vap->iv_hwmp, M_80211_VAP);
 	vap->iv_hwmp = NULL;
 } 
@@ -269,6 +266,8 @@ hwmp_newstate(struct ieee80211vap *vap, 
 	/* Flush the table on RUN -> !RUN, e.g. interface down & up */
 	if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
 		callout_drain(&hs->hs_roottimer);
+	if (nstate == IEEE80211_S_RUN)
+		hwmp_rootmode_setup(vap);
 	return 0;
 }
 
@@ -644,7 +643,7 @@ hwmp_rootmode_cb(void *arg)
 	struct ieee80211_meshpreq_ie preq;
 
 	IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
-	    "%s", "sending broadcast PREQ");
+	    "%s", "send broadcast PREQ");
 
 	/* XXX check portal role */
 	preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM;
@@ -683,7 +682,7 @@ hwmp_rootmode_rann_cb(void *arg)
 	struct ieee80211_meshrann_ie rann;
 
 	IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
-	    "%s", "sending broadcast RANN");
+	    "%s", "send broadcast RANN");
 
 	/* XXX check portal role */
 	rann.rann_flags = 0;
@@ -740,7 +739,7 @@ hwmp_recv_preq(struct ieee80211vap *vap,
 	 */
 	if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
 		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-		    "replying to %s", ether_sprintf(preq->preq_origaddr));
+		    "reply to %s", ether_sprintf(preq->preq_origaddr));
 		/*
 		 * Build and send a PREP frame.
 		 */
@@ -760,7 +759,7 @@ hwmp_recv_preq(struct ieee80211vap *vap,
 		rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
 		if (rt == NULL)
 			hwmp_discover(vap, preq->preq_origaddr, NULL);
-		else if (IEEE80211_ADDR_EQ(rt->rt_nexthop, invalidaddr))
+		else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
 			hwmp_discover(vap, rt->rt_dest, NULL);
 		return;
 	}
@@ -774,30 +773,36 @@ hwmp_recv_preq(struct ieee80211vap *vap,
 	    (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) {
 		uint8_t rootmac[IEEE80211_ADDR_LEN];
 
-		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-		    "root mesh station @ %s",
-		    ether_sprintf(preq->preq_origaddr));
 		IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr);
 		rt = ieee80211_mesh_rt_find(vap, rootmac);
-		if (rt == NULL)
+		if (rt == NULL) {
 			rt = ieee80211_mesh_rt_add(vap, rootmac);
+			if (rt == NULL) {
+				IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+				    "unable to add root mesh path to %s",
+				    ether_sprintf(rootmac));
+				vap->iv_stats.is_mesh_rtaddfailed++;
+				return;
+			}
+		}
+		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+		    "root mesh station @ %s", ether_sprintf(rootmac));
+
 		/*
 		 * Reply with a PREP if we don't have a path to the root
 		 * or if the root sent us a proactive PREQ.
 		 */
-		if (IEEE80211_ADDR_EQ(rt->rt_nexthop, invalidaddr) ||
+		if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
 		    (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) {
 			prep.prep_flags = 0;
 			prep.prep_hopcount = 0;
 			prep.prep_ttl = ms->ms_ttl;
-			IEEE80211_ADDR_COPY(prep.prep_origaddr,
-			    vap->iv_myaddr);
+			IEEE80211_ADDR_COPY(prep.prep_origaddr, vap->iv_myaddr);
 			prep.prep_origseq = preq->preq_origseq;
 			prep.prep_targetseq = ++hs->hs_seq;
 			prep.prep_lifetime = preq->preq_lifetime;
 			prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
-			IEEE80211_ADDR_COPY(prep.prep_targetaddr,
-			    rootmac);
+			IEEE80211_ADDR_COPY(prep.prep_targetaddr, rootmac);
 			prep.prep_targetseq = PREQ_TSEQ(0);
 			hwmp_send_prep(vap->iv_bss, vap->iv_myaddr,
 			    broadcastaddr, &prep);
@@ -820,7 +825,7 @@ hwmp_recv_preq(struct ieee80211vap *vap,
 		 * We have a valid route to this node.
 		 */
 		if (rt != NULL &&
-		    !IEEE80211_ADDR_EQ(rt->rt_nexthop, invalidaddr)) {
+		    (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
 
 			hr = IEEE80211_MESH_ROUTE_PRIV(rt,
 			    struct ieee80211_hwmp_route);
@@ -829,7 +834,7 @@ hwmp_recv_preq(struct ieee80211vap *vap,
 			if (preq->preq_ttl > 1 &&
 			    preq->preq_hopcount < hs->hs_maxhops) {
 				IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-				    "forwarding PREQ from %s",
+				    "forward PREQ from %s",
 				    ether_sprintf(preq->preq_origaddr));
 				/*
 				 * Propagate the original PREQ.
@@ -880,8 +885,16 @@ hwmp_recv_preq(struct ieee80211vap *vap,
 		 */
 		} else if (preq->preq_ttl > 1 &&
 		    preq->preq_hopcount < hs->hs_maxhops) {
-			if (rt == NULL)
+			if (rt == NULL) {
 				rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0));
+				if (rt == NULL) {
+					IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
+					    ni, "unable to add PREQ path to %s",
+					    ether_sprintf(PREQ_TADDR(0)));
+					vap->iv_stats.is_mesh_rtaddfailed++;
+					return;
+				}
+			}
 			hr = IEEE80211_MESH_ROUTE_PRIV(rt,
 			    struct ieee80211_hwmp_route);
 			rt->rt_metric = preq->preq_metric;
@@ -890,7 +903,7 @@ hwmp_recv_preq(struct ieee80211vap *vap,
 			hr->hr_preqid = preq->preq_id;
 
 			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-			    "forwarding PREQ from %s",
+			    "forward PREQ from %s",
 			    ether_sprintf(preq->preq_origaddr));
 			ppreq.preq_hopcount += 1;
 			ppreq.preq_ttl -= 1;
@@ -968,7 +981,7 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 		struct ieee80211_meshprep_ie pprep; /* propagated PREP */
 
 		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-		    "propagating PREP from %s",
+		    "propagate PREP from %s",
 		    ether_sprintf(prep->prep_origaddr));
 
 		memcpy(&pprep, prep, sizeof(pprep));
@@ -986,10 +999,18 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 		 */
 		if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) {
 			rt = ieee80211_mesh_rt_add(vap, prep->prep_origaddr);
+			if (rt == NULL) {
+				IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
+				    ni, "unable to add PREP path to %s",
+				    ether_sprintf(prep->prep_origaddr));
+				vap->iv_stats.is_mesh_rtaddfailed++;
+				return;
+			}
 			IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
 			rt->rt_nhops = prep->prep_hopcount;
 			rt->rt_lifetime = prep->prep_lifetime;
 			rt->rt_metric = prep->prep_metric;
+			rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
 			return;
 		} 
 		return;
@@ -1002,7 +1023,7 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 		 * If we do, check if this path reply contains a
 		 * better route.
 		 */
-		if (IEEE80211_ADDR_EQ(rt->rt_nexthop, invalidaddr))
+		if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
 			useprep = 1;
 		else if (prep->prep_hopcount < rt->rt_nhops ||
 		    prep->prep_metric < rt->rt_metric)
@@ -1012,6 +1033,7 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 			rt->rt_nhops = prep->prep_hopcount;
 			rt->rt_lifetime = prep->prep_lifetime;
 			rt->rt_metric = prep->prep_metric;
+			rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
 		}
 	} else {
 		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
@@ -1044,6 +1066,8 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 	for (; m != NULL; m = next) {
 		next = m->m_nextpkt;
 		m->m_nextpkt = NULL;
+		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+		    "flush queued frame %p len %d", m, m->m_pkthdr.len);
 		ifp->if_transmit(ifp, m);
 	}
 }
@@ -1054,14 +1078,7 @@ hwmp_send_prep(struct ieee80211_node *ni
     const uint8_t da[IEEE80211_ADDR_LEN],
     struct ieee80211_meshprep_ie *prep)
 {
-	struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
-
-	/*
-	 * Enforce PREP interval.
-	 */
-	if (ratecheck(&hs->hs_lastprep, &ieee80211_hwmp_prepminint) == 0)
-		return EALREADY;
-	getmicrouptime(&hs->hs_lastprep);
+	/* NB: there's no PREP minimum interval. */
 
 	/*
 	 * mesh prep action frame format
@@ -1092,7 +1109,7 @@ hwmp_peerdown(struct ieee80211_node *ni)
 		return;
 	hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
 	IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-	    "%s", "deleting route entry");
+	    "%s", "delete route entry");
 	perr.perr_mode = 0;
 	perr.perr_ndests = 1;
 	IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
@@ -1144,7 +1161,7 @@ hwmp_recv_perr(struct ieee80211vap *vap,
 	 */
 	if (forward) {
 		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-		    "propagating PERR from %s", ether_sprintf(wh->i_addr2));
+		    "propagate PERR from %s", ether_sprintf(wh->i_addr2));
 		memcpy(&pperr, perr, sizeof(*perr));
 		hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &pperr);
 	}
@@ -1264,13 +1281,16 @@ hwmp_discover(struct ieee80211vap *vap,
 		if (rt == NULL) {
 			rt = ieee80211_mesh_rt_add(vap, dest);
 			if (rt == NULL) {
-				/* XXX stat+msg */
+				IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
+				    ni, "unable to add discovery path to %s",
+				    ether_sprintf(dest));
+				vap->iv_stats.is_mesh_rtaddfailed++;
 				goto done;
 			}
 		}
 		hr = IEEE80211_MESH_ROUTE_PRIV(rt,
 		    struct ieee80211_hwmp_route);
-		if (IEEE80211_ADDR_EQ(rt->rt_nexthop, invalidaddr)) {
+		if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
 			if (hr->hr_preqid == 0) {
 				hr->hr_seq = ++hs->hs_seq;
 				hr->hr_preqid = ++hs->hs_preqid;
@@ -1281,7 +1301,9 @@ hwmp_discover(struct ieee80211vap *vap,
 			/* XXX check preq retries */
 			sendpreq = 1;
 			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
-			    "%s", "initiating path discovery");
+			    "start path discovery (src %s)",
+			    m == NULL ? "<none>" : ether_sprintf(
+				mtod(m, struct ether_header *)->ether_shost));
 			/*
 			 * Try to discover the path for this node.
 			 */
@@ -1306,16 +1328,16 @@ hwmp_discover(struct ieee80211vap *vap,
 			hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
 			    broadcastaddr, &preq);
 		}
-		if (!IEEE80211_ADDR_EQ(rt->rt_nexthop, invalidaddr))
+		if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)
 			ni = ieee80211_find_txnode(vap, rt->rt_nexthop);
 	} else {
 		ni = ieee80211_find_txnode(vap, dest);
+		/* NB: if null then we leak mbuf */
+		KASSERT(ni != NULL, ("leak mcast frame"));
 		return ni;
 	}
 done:
 	if (ni == NULL && m != NULL) {
-		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
-		    dest, NULL, "%s", "no valid path to this node");
 		if (sendpreq) {
 			struct ieee80211com *ic = vap->iv_ic;
 			/*
@@ -1323,13 +1345,18 @@ done:
 			 * completes.  If discovery never completes the
 			 * frame will be flushed by way of the aging timer.
 			 */
+			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
+			    "%s", "queue frame until path found");
 			m->m_pkthdr.rcvif = (void *)(uintptr_t)
 			    ieee80211_mac_hash(ic, dest);
 			/* XXX age chosen randomly */
 			ieee80211_ageq_append(&ic->ic_stageq, m,
 			    IEEE80211_INACT_WAIT);
-		} else
+		} else {
+			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
+			    dest, NULL, "%s", "no valid path to this node");
 			m_freem(m);
+		}
 	}
 	return ni;
 }

Modified: head/sys/net80211/ieee80211_input.c
==============================================================================
--- head/sys/net80211/ieee80211_input.c	Mon Jul 20 16:19:42 2009	(r195783)
+++ head/sys/net80211/ieee80211_input.c	Mon Jul 20 19:12:08 2009	(r195784)
@@ -233,22 +233,17 @@ ieee80211_deliver_data(struct ieee80211v
 struct mbuf *
 ieee80211_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen)
 {
-#ifdef IEEE80211_SUPPORT_MESH
-	union {
-		struct ieee80211_qosframe_addr4 wh4;
-		uint8_t b[sizeof(struct ieee80211_qosframe_addr4) +
-			  sizeof(struct ieee80211_meshcntl_ae11)];
-	} whu;
-#define	wh	whu.wh4
-#else
 	struct ieee80211_qosframe_addr4 wh;
-#endif
 	struct ether_header *eh;
 	struct llc *llc;
 
+	KASSERT(hdrlen <= sizeof(wh),
+	    ("hdrlen %d > max %zd", hdrlen, sizeof(wh)));
+
 	if (m->m_len < hdrlen + sizeof(*llc) &&
 	    (m = m_pullup(m, hdrlen + sizeof(*llc))) == NULL) {
-		/* XXX stat, msg */
+		vap->iv_stats.is_rx_tooshort++;
+		/* XXX msg */
 		return NULL;
 	}
 	memcpy(&wh, mtod(m, caddr_t), hdrlen);
@@ -295,7 +290,6 @@ ieee80211_decap(struct ieee80211vap *vap
 		eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
 	}
 	return m;
-#undef	wh
 }
 
 /*

Modified: head/sys/net80211/ieee80211_ioctl.h
==============================================================================
--- head/sys/net80211/ieee80211_ioctl.h	Mon Jul 20 16:19:42 2009	(r195783)
+++ head/sys/net80211/ieee80211_ioctl.h	Mon Jul 20 19:12:08 2009	(r195784)
@@ -235,9 +235,13 @@ struct ieee80211_stats {
 	uint32_t	is_hwmp_wrongseq;	/* wrong hwmp seq no. */
 	uint32_t	is_hwmp_rootreqs;	/* root PREQs sent */
 	uint32_t	is_hwmp_rootrann;	/* root RANNs sent */
-	uint32_t	is_rx_badalign;		/* dropped 'cuz misaligned */
 
-	uint32_t	is_spare[15];
+	uint32_t	is_mesh_badae;		/* dropped 'cuz invalid AE */
+	uint32_t	is_mesh_rtaddfailed;	/* route add failed */
+	uint32_t	is_mesh_notproxy;	/* dropped 'cuz not proxying */
+	uint32_t	is_rx_badalign;		/* dropped 'cuz misaligned */
+	
+	uint32_t	is_spare[12];
 };
 
 /*
@@ -328,6 +332,16 @@ enum {
 	IEEE80211_MESH_RTCMD_DELETE = 3, /* delete an entry from the table */
 };
 
+struct ieee80211req_mesh_route {
+	uint8_t		imr_dest[IEEE80211_ADDR_LEN];
+	uint8_t		imr_nexthop[IEEE80211_ADDR_LEN];
+	uint16_t	imr_nhops;
+	uint16_t	imr_pad;
+	uint32_t	imr_metric;
+	uint32_t	imr_lifetime;
+	uint32_t	imr_lastmseq;
+};
+
 /*
  * HWMP root modes
  */

Modified: head/sys/net80211/ieee80211_mesh.c
==============================================================================
--- head/sys/net80211/ieee80211_mesh.c	Mon Jul 20 16:19:42 2009	(r195783)
+++ head/sys/net80211/ieee80211_mesh.c	Mon Jul 20 19:12:08 2009	(r195784)
@@ -62,10 +62,12 @@ __FBSDID("$FreeBSD$");
 #include <net80211/ieee80211_input.h>
 #include <net80211/ieee80211_mesh.h>
 
+static void	mesh_rt_flush_invalid(struct ieee80211vap *);
 static int	mesh_select_proto_path(struct ieee80211vap *, const char *);
 static int	mesh_select_proto_metric(struct ieee80211vap *, const char *);
 static void	mesh_vattach(struct ieee80211vap *);
 static int	mesh_newstate(struct ieee80211vap *, enum ieee80211_state, int);
+static void	mesh_rt_cleanup_cb(void *);
 static void	mesh_linkchange(struct ieee80211_node *,
 		    enum ieee80211_mesh_mlstate);
 static void	mesh_checkid(void *, struct ieee80211_node *);
@@ -138,6 +140,7 @@ static struct ieee80211_mesh_proto_path	
 static struct ieee80211_mesh_proto_metric	mesh_proto_metrics[4];
 
 #define	MESH_RT_LOCK(ms)	mtx_lock(&(ms)->ms_rt_lock)
+#define	MESH_RT_LOCK_ASSERT(ms)	mtx_assert(&(ms)->ms_rt_lock, MA_OWNED)
 #define	MESH_RT_UNLOCK(ms)	mtx_unlock(&(ms)->ms_rt_lock)
 
 MALLOC_DEFINE(M_80211_MESH_RT, "80211mesh", "802.11s routing table");
@@ -145,6 +148,44 @@ MALLOC_DEFINE(M_80211_MESH_RT, "80211mes
 /*
  * Helper functions to manipulate the Mesh routing table.
  */
+
+static struct ieee80211_mesh_route *
+mesh_rt_find_locked(struct ieee80211_mesh_state *ms,
+    const uint8_t dest[IEEE80211_ADDR_LEN])
+{
+	struct ieee80211_mesh_route *rt;
+
+	MESH_RT_LOCK_ASSERT(ms);
+
+	TAILQ_FOREACH(rt, &ms->ms_routes, rt_next) {
+		if (IEEE80211_ADDR_EQ(dest, rt->rt_dest))
+			return rt;
+	}
+	return NULL;
+}
+
+static struct ieee80211_mesh_route *
+mesh_rt_add_locked(struct ieee80211_mesh_state *ms,
+    const uint8_t dest[IEEE80211_ADDR_LEN])
+{
+	struct ieee80211_mesh_route *rt;
+
+	KASSERT(!IEEE80211_ADDR_EQ(broadcastaddr, dest),
+	    ("%s: adding broadcast to the routing table", __func__));
+
+	MESH_RT_LOCK_ASSERT(ms);
+
+	rt = malloc(ALIGN(sizeof(struct ieee80211_mesh_route)) +
+	    ms->ms_ppath->mpp_privlen, M_80211_MESH_RT, M_NOWAIT | M_ZERO);
+	if (rt != NULL) {
+		IEEE80211_ADDR_COPY(rt->rt_dest, dest);
+		rt->rt_priv = (void *)ALIGN(&rt[1]);
+		getmicrouptime(&rt->rt_crtime);
+		TAILQ_INSERT_TAIL(&ms->ms_routes, rt, rt_next);
+	}
+	return rt;
+}
+
 struct ieee80211_mesh_route *
 ieee80211_mesh_rt_find(struct ieee80211vap *vap,
     const uint8_t dest[IEEE80211_ADDR_LEN])
@@ -153,14 +194,9 @@ ieee80211_mesh_rt_find(struct ieee80211v
 	struct ieee80211_mesh_route *rt;
 
 	MESH_RT_LOCK(ms);
-	TAILQ_FOREACH(rt, &ms->ms_routes, rt_next) {
-		if (IEEE80211_ADDR_EQ(dest, rt->rt_dest)) {
-			MESH_RT_UNLOCK(ms);
-			return rt;
-		}
-	}
+	rt = mesh_rt_find_locked(ms, dest);
 	MESH_RT_UNLOCK(ms);
-	return NULL;
+	return rt;
 }
 
 struct ieee80211_mesh_route *
@@ -174,20 +210,65 @@ ieee80211_mesh_rt_add(struct ieee80211va
 	    ("%s: duplicate entry in the routing table", __func__));
 	KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
 	    ("%s: adding self to the routing table", __func__));
-	KASSERT(!IEEE80211_ADDR_EQ(broadcastaddr, dest),
-	    ("%s: adding broadcast to the routing table", __func__));
 
-	rt = malloc(sizeof(struct ieee80211_mesh_route), M_80211_MESH_RT,
-	    M_NOWAIT | M_ZERO);
-	IEEE80211_ADDR_COPY(rt->rt_dest, dest);
-	rt->rt_priv = malloc(ms->ms_ppath->mpp_privlen, M_80211_MESH_RT,
-	    M_NOWAIT | M_ZERO);
 	MESH_RT_LOCK(ms);
-	TAILQ_INSERT_TAIL(&ms->ms_routes, rt, rt_next);
+	rt = mesh_rt_add_locked(ms, dest);
 	MESH_RT_UNLOCK(ms);
 	return rt;
 }
 
+/*
+ * Add a proxy route (as needed) for the specified destination.
+ */
+void
+ieee80211_mesh_proxy_check(struct ieee80211vap *vap,
+    const uint8_t dest[IEEE80211_ADDR_LEN])
+{
+	struct ieee80211_mesh_state *ms = vap->iv_mesh;
+	struct ieee80211_mesh_route *rt;
+
+	MESH_RT_LOCK(ms);
+	rt = mesh_rt_find_locked(ms, dest);
+	if (rt == NULL) {
+		rt = mesh_rt_add_locked(ms, dest);
+		if (rt == NULL) {
+			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
+			    "%s", "unable to add proxy entry");
+			vap->iv_stats.is_mesh_rtaddfailed++;
+		} else {
+			IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
+			rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
+				     |  IEEE80211_MESHRT_FLAGS_PROXY;
+		}
+	/* XXX assert PROXY? */
+	} else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
+		struct ieee80211com *ic = vap->iv_ic;
+		/*
+		 * Fix existing entry created by received frames from
+		 * stations that have some memory of dest.  We also
+		 * flush any frames held on the staging queue; delivering
+		 * them is too much trouble right now.
+		 */
+		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
+		    "%s", "fix proxy entry");
+		IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
+		rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
+			     |  IEEE80211_MESHRT_FLAGS_PROXY;
+		/* XXX belongs in hwmp */
+		ieee80211_ageq_drain_node(&ic->ic_stageq,
+		   (void *)(uintptr_t) ieee80211_mac_hash(ic, dest));
+		/* XXX stat? */
+	}
+	MESH_RT_UNLOCK(ms);
+}
+
+static __inline void
+mesh_rt_del(struct ieee80211_mesh_state *ms, struct ieee80211_mesh_route *rt)
+{
+	TAILQ_REMOVE(&ms->ms_routes, rt, rt_next);
+	free(rt, M_80211_MESH_RT);
+}
+
 void
 ieee80211_mesh_rt_del(struct ieee80211vap *vap,
     const uint8_t dest[IEEE80211_ADDR_LEN])
@@ -198,9 +279,7 @@ ieee80211_mesh_rt_del(struct ieee80211va
 	MESH_RT_LOCK(ms);
 	TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) {
 		if (IEEE80211_ADDR_EQ(rt->rt_dest, dest)) {
-			TAILQ_REMOVE(&ms->ms_routes, rt, rt_next);
-			free(rt->rt_priv, M_80211_MESH_RT);
-			free(rt, M_80211_MESH_RT);
+			mesh_rt_del(ms, rt);
 			MESH_RT_UNLOCK(ms);
 			return;
 		}
@@ -217,10 +296,32 @@ ieee80211_mesh_rt_flush(struct ieee80211
 	if (ms == NULL)
 		return;
 	MESH_RT_LOCK(ms);
+	TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next)
+		mesh_rt_del(ms, rt);
+	MESH_RT_UNLOCK(ms);
+}
+
+/*
+ * Flush expired routing entries, i.e. those in invalid state for
+ * some time.
+ */
+static void
+mesh_rt_flush_invalid(struct ieee80211vap *vap)
+{
+	struct ieee80211_mesh_state *ms = vap->iv_mesh;
+	struct ieee80211_mesh_route *rt, *next;
+	struct timeval tv, delta;
+
+	if (ms == NULL)
+		return;
+	getmicrouptime(&tv);
+	MESH_RT_LOCK(ms);
 	TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) {
-		TAILQ_REMOVE(&ms->ms_routes, rt, rt_next);
-		free(rt->rt_priv, M_80211_MESH_RT);
-		free(rt, M_80211_MESH_RT);
+		delta = tv;
+		timevalsub(&delta, &rt->rt_crtime);
+		if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 &&
+		    timevalcmp(&delta, &ms->ms_ppath->mpp_inact, >=))
+			mesh_rt_del(ms, rt);
 	}
 	MESH_RT_UNLOCK(ms);
 }
@@ -381,7 +482,7 @@ mesh_vdetach_peers(void *arg, struct iee
 		    IEEE80211_ACTION_MESHPEERING_CLOSE,
 		    args);
 	}
-	callout_stop(&ni->ni_mltimer);
+	callout_drain(&ni->ni_mltimer);
 	/* XXX belongs in hwmp */
 	ieee80211_ageq_drain_node(&ic->ic_stageq,
 	   (void *)(uintptr_t) ieee80211_mac_hash(ic, ni->ni_macaddr));
@@ -392,6 +493,7 @@ mesh_vdetach(struct ieee80211vap *vap)
 {
 	struct ieee80211_mesh_state *ms = vap->iv_mesh;
 
+	callout_drain(&ms->ms_cleantimer);
 	ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, mesh_vdetach_peers,
 	    NULL);
 	ieee80211_mesh_rt_flush(vap);
@@ -413,7 +515,7 @@ mesh_vattach(struct ieee80211vap *vap)
 	    M_NOWAIT | M_ZERO);
 	if (ms == NULL) {
 		printf("%s: couldn't alloc MBSS state\n", __func__);
-	return;
+		return;
 	}
 	vap->iv_mesh = ms;
 	ms->ms_seq = 0;
@@ -421,6 +523,7 @@ mesh_vattach(struct ieee80211vap *vap)
 	ms->ms_ttl = IEEE80211_MESH_DEFAULT_TTL;
 	TAILQ_INIT(&ms->ms_routes);
 	mtx_init(&ms->ms_rt_lock, "MBSS", "802.11s routing table", MTX_DEF);
+	callout_init(&ms->ms_cleantimer, CALLOUT_MPSAFE);
 	mesh_select_proto_metric(vap, "AIRTIME");
 	KASSERT(ms->ms_pmetric, ("ms_pmetric == NULL"));
 	mesh_select_proto_path(vap, "HWMP");
@@ -449,9 +552,8 @@ mesh_newstate(struct ieee80211vap *vap, 
 	if (ostate != IEEE80211_S_SCAN)
 		ieee80211_cancel_scan(vap);	/* background scan */
 	ni = vap->iv_bss;			/* NB: no reference held */
-	/* Flush the routing table */
-	if (nstate != IEEE80211_S_INIT && ostate == IEEE80211_S_INIT)
-		ieee80211_mesh_rt_flush(vap);
+	if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
+		callout_drain(&ms->ms_cleantimer);
 	switch (nstate) {
 	case IEEE80211_S_INIT:
 		switch (ostate) {
@@ -471,6 +573,7 @@ mesh_newstate(struct ieee80211vap *vap, 
 		if (ostate != IEEE80211_S_INIT) {
 			/* NB: optimize INIT -> INIT case */
 			ieee80211_reset_bss(vap);
+			ieee80211_mesh_rt_flush(vap);
 		}
 		break;
 	case IEEE80211_S_SCAN:
@@ -573,17 +676,33 @@ mesh_newstate(struct ieee80211vap *vap, 
 			break;
 		}
 		ieee80211_node_authorize(vap->iv_bss);
+		callout_reset(&ms->ms_cleantimer,
+		    msecs_to_ticks(ms->ms_ppath->mpp_inact.tv_sec * 1000 +
+		        ms->ms_ppath->mpp_inact.tv_usec / 1000),
+                    mesh_rt_cleanup_cb, vap);
 		break;
 	default:
 		break;
 	}
-
 	/* NB: ostate not nstate */
 	ms->ms_ppath->mpp_newstate(vap, ostate, arg);
-
 	return 0;
 }
 
+static void
+mesh_rt_cleanup_cb(void *arg)
+{
+	struct ieee80211vap *vap = arg;
+	struct ieee80211_mesh_state *ms = vap->iv_mesh;
+
+	mesh_rt_flush_invalid(vap);
+	callout_reset(&ms->ms_cleantimer,
+	    msecs_to_ticks(ms->ms_ppath->mpp_inact.tv_sec * 1000 +
+	        ms->ms_ppath->mpp_inact.tv_usec / 1000),
+	    mesh_rt_cleanup_cb, vap);
+}
+
+
 /*
  * Helper function to note the Mesh Peer Link FSM change.
  */
@@ -617,8 +736,16 @@ mesh_linkchange(struct ieee80211_node *n
 		ms->ms_neighbors--;
 	}
 	ni->ni_mlstate = state;
-	if (state == IEEE80211_NODE_MESH_HOLDING)
+	switch (state) {
+	case IEEE80211_NODE_MESH_HOLDING:
 		ms->ms_ppath->mpp_peerdown(ni);
+		break;
+	case IEEE80211_NODE_MESH_ESTABLISHED:
+		ieee80211_mesh_discover(vap, ni->ni_macaddr, NULL);
+		break;
+	default:
+		break;
+	}
 }
 
 /*
@@ -660,8 +787,11 @@ mesh_checkpseq(struct ieee80211vap *vap,
 
 	rt = ieee80211_mesh_rt_find(vap, source);
 	if (rt == NULL) {
+		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, source,
+		    "add mcast route, mesh seqno %d", seq);
 		rt = ieee80211_mesh_rt_add(vap, source);
-		rt->rt_lastmseq = seq;
+		if (rt != NULL)
+			rt->rt_lastmseq = seq;
 		return 0;
 	}
 	if (IEEE80211_MESH_SEQ_GEQ(rt->rt_lastmseq, seq)) {
@@ -684,6 +814,13 @@ mesh_find_txnode(struct ieee80211vap *va
 	rt = ieee80211_mesh_rt_find(vap, dest);
 	if (rt == NULL)
 		return NULL;
+	if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
+	    (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)) {
+		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
+		    "%s: !valid or proxy, flags 0x%x", __func__, rt->rt_flags);
+		/* XXX stat */
+		return NULL;
+	}
 	return ieee80211_find_txnode(vap, rt->rt_nexthop);
 }
 
@@ -757,11 +894,6 @@ mesh_forward(struct ieee80211vap *vap, s
 		}
 		IEEE80211_ADDR_COPY(whcopy->i_addr1, ni->ni_macaddr);
 	}
-	IEEE80211_NOTE(vap, IEEE80211_MSG_MESH, ni,
-	    "fwd %s frame from %s ttl %d",
-	    IEEE80211_IS_MULTICAST(wh->i_addr1) ?  "mcast" : "ucast",
-	    ether_sprintf(wh->i_addr3), mccopy->mc_ttl);
-
 	KASSERT(mccopy->mc_ttl > 0, ("%s called with wrong ttl", __func__));
 	mccopy->mc_ttl--;
 
@@ -779,6 +911,117 @@ mesh_forward(struct ieee80211vap *vap, s
 	}
 }
 
+static struct mbuf *
+mesh_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen, int meshdrlen)
+{
+#define	WHDIR(wh) ((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK)
+	uint8_t b[sizeof(struct ieee80211_qosframe_addr4) +
+		  sizeof(struct ieee80211_meshcntl_ae11)];
+	const struct ieee80211_qosframe_addr4 *wh;
+	const struct ieee80211_meshcntl_ae10 *mc;
+	struct ether_header *eh;
+	struct llc *llc;
+	int ae;
+
+	if (m->m_len < hdrlen + sizeof(*llc) &&
+	    (m = m_pullup(m, hdrlen + sizeof(*llc))) == NULL) {
+		IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY,
+		    "discard data frame: %s", "m_pullup failed");
+		vap->iv_stats.is_rx_tooshort++;
+		return NULL;
+	}
+	memcpy(b, mtod(m, caddr_t), hdrlen);
+	wh = (const struct ieee80211_qosframe_addr4 *)&b[0];
+	mc = (const struct ieee80211_meshcntl_ae10 *)&b[hdrlen - meshdrlen];
+	KASSERT(WHDIR(wh) == IEEE80211_FC1_DIR_FROMDS ||
+		WHDIR(wh) == IEEE80211_FC1_DIR_DSTODS,
+	    ("bogus dir, fc 0x%x:0x%x", wh->i_fc[0], wh->i_fc[1]));
+
+	llc = (struct llc *)(mtod(m, caddr_t) + hdrlen);
+	if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP &&
+	    llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 &&
+	    llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0 &&
+	    /* NB: preserve AppleTalk frames that have a native SNAP hdr */
+	    !(llc->llc_snap.ether_type == htons(ETHERTYPE_AARP) ||
+	      llc->llc_snap.ether_type == htons(ETHERTYPE_IPX))) {
+		m_adj(m, hdrlen + sizeof(struct llc) - sizeof(*eh));
+		llc = NULL;
+	} else {
+		m_adj(m, hdrlen - sizeof(*eh));
+	}
+	eh = mtod(m, struct ether_header *);
+	ae = mc->mc_flags & 3;
+	if (WHDIR(wh) == IEEE80211_FC1_DIR_FROMDS) {
+		IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr1);
+		if (ae == 0) {
+			IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr3);
+		} else if (ae == 1) {
+			IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr4);
+		} else {
+			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
+			    (const struct ieee80211_frame *)wh, NULL,
+			    "bad AE %d", ae);
+			vap->iv_stats.is_mesh_badae++;
+			m_freem(m);
+			return NULL;
+		}
+	} else {
+		if (ae == 0) {
+			IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr3);
+			IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr4);
+		} else if (ae == 2) {
+			IEEE80211_ADDR_COPY(eh->ether_dhost, mc->mc_addr4);
+			IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr5);
+		} else {
+			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
+			    (const struct ieee80211_frame *)wh, NULL,
+			    "bad AE %d", ae);
+			vap->iv_stats.is_mesh_badae++;
+			m_freem(m);
+			return NULL;
+		}
+	}
+#ifdef ALIGNED_POINTER
+	if (!ALIGNED_POINTER(mtod(m, caddr_t) + sizeof(*eh), uint32_t)) {
+		m = ieee80211_realign(vap, m, sizeof(*eh));
+		if (m == NULL)
+			return NULL;
+	}
+#endif /* ALIGNED_POINTER */
+	if (llc != NULL) {
+		eh = mtod(m, struct ether_header *);
+		eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
+	}
+	return m;
+#undef WDIR
+}
+
+/*
+ * Return non-zero if the unicast mesh data frame should be processed
+ * locally.  Frames that are not proxy'd have our address, otherwise
+ * we need to consult the routing table to look for a proxy entry.
+ */
+static __inline int
+mesh_isucastforme(struct ieee80211vap *vap, const struct ieee80211_frame *wh,
+    const struct ieee80211_meshcntl *mc)
+{
+	int ae = mc->mc_flags & 3;
+
+	KASSERT((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS,
+	    ("bad dir 0x%x:0x%x", wh->i_fc[0], wh->i_fc[1]));
+	KASSERT(ae == 0 || ae == 2, ("bad AE %d", ae));
+	if (ae == 2) {				/* ucast w/ proxy */
+		const struct ieee80211_meshcntl_ae10 *mc10 =
+		    (const struct ieee80211_meshcntl_ae10 *) mc;
+		struct ieee80211_mesh_route *rt =
+		    ieee80211_mesh_rt_find(vap, mc10->mc_addr4);
+		/* check for proxy route to ourself */
+		return (rt != NULL &&
+		    (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY));
+	} else					/* ucast w/o proxy */
+		return IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr);
+}
+
 static int
 mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
 {
@@ -789,7 +1032,7 @@ mesh_input(struct ieee80211_node *ni, st
 	struct ifnet *ifp = vap->iv_ifp;
 	struct ieee80211_frame *wh;
 	const struct ieee80211_meshcntl *mc;
-	int hdrspace, need_tap;
+	int hdrspace, meshdrlen, need_tap;
 	uint8_t dir, type, subtype, qos;
 	uint32_t seq;
 	uint8_t *addr;
@@ -904,13 +1147,14 @@ mesh_input(struct ieee80211_node *ni, st
 		}
 		/*
 		 * Now calculate the full extent of the headers. Note
-		 * ieee80211_decap will pull up anything we didn't get
+		 * mesh_decap will pull up anything we didn't get
 		 * above when it strips the 802.11 headers.
 		 */
 		mc = (const struct ieee80211_meshcntl *)
 		    (mtod(m, const uint8_t *) + hdrspace);
-		hdrspace += sizeof(struct ieee80211_meshcntl) +
+		meshdrlen = sizeof(struct ieee80211_meshcntl) +
 		    (mc->mc_flags & 3) * IEEE80211_ADDR_LEN;
+		hdrspace += meshdrlen;
 		seq = LE_READ_4(mc->mc_seq);
 		if (IEEE80211_IS_MULTICAST(wh->i_addr1))
 			addr = wh->i_addr3;
@@ -935,7 +1179,7 @@ mesh_input(struct ieee80211_node *ni, st
 		 * for the rules.  XXX tap fwd'd packets not for us?
 		 */
 		if (dir == IEEE80211_FC1_DIR_FROMDS ||
-		    !IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr)) {
+		    !mesh_isucastforme(vap, wh, mc)) {
 			mesh_forward(vap, m, mc);
 			if (dir == IEEE80211_FC1_DIR_DSTODS)
 				goto out;
@@ -970,7 +1214,7 @@ mesh_input(struct ieee80211_node *ni, st
 		/*
 		 * Finally, strip the 802.11 header.
 		 */
-		m = ieee80211_decap(vap, m, hdrspace);
+		m = mesh_decap(vap, m, hdrspace, meshdrlen);
 		if (m == NULL) {
 			/* XXX mask bit to check for both */
 			/* don't count Null data frames as errors */
@@ -987,13 +1231,7 @@ mesh_input(struct ieee80211_node *ni, st
 			m = ieee80211_decap_amsdu(ni, m);
 			if (m == NULL)
 				return IEEE80211_FC0_TYPE_DATA;
-		} else {
-#ifdef IEEE80211_SUPPORT_SUPERG
-			m = ieee80211_decap_fastframe(vap, ni, m);
-			if (m == NULL)
-				return IEEE80211_FC0_TYPE_DATA;
-#endif
-		}		
+		}
 		ieee80211_deliver_data(vap, ni, m);
 		return type;
 	case IEEE80211_FC0_TYPE_MGT:
@@ -1967,7 +2205,7 @@ mesh_peer_timeout_backoff(struct ieee802
 static __inline void
 mesh_peer_timeout_stop(struct ieee80211_node *ni)
 {
-	callout_stop(&ni->ni_mltimer);
+	callout_drain(&ni->ni_mltimer);
 }
 
 /*
@@ -2401,6 +2639,7 @@ mesh_ioctl_get80211(struct ieee80211vap 
 				return ENOMEM;
 			}
 			ireq->i_len = len;
+			/* XXX M_WAIT? */
 			p = malloc(len, M_TEMP, M_NOWAIT | M_ZERO);
 			if (p == NULL)
 				return ENOMEM;
@@ -2418,6 +2657,7 @@ mesh_ioctl_get80211(struct ieee80211vap 
 				imr->imr_metric = rt->rt_metric;
 				imr->imr_nhops = rt->rt_nhops;
 				imr->imr_lifetime = rt->rt_lifetime;
+				imr->imr_lastmseq = rt->rt_lastmseq;
 				off += sizeof(*imr);
 			}
 			MESH_RT_UNLOCK(ms);
@@ -2475,17 +2715,19 @@ mesh_ioctl_set80211(struct ieee80211vap 
 		if (ireq->i_val != 0 || ireq->i_len > IEEE80211_MESHID_LEN)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list