Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0cfda851 authored by Thomas Pedersen's avatar Thomas Pedersen Committed by John W. Linville
Browse files

mac80211: don't initiate path discovery when forwarding frame with unknown DA



We used to initiate a path discovery when receiving a frame for which
there is no forwarding information. To cut down on PREQ spam, just send
a (gated) PERR in response.

Also separate path discovery logic from nexthop querying. This patch
means we no longer queue frames when forwarding, so kill the PERR TX
stuff in discard_frame().

Signed-off-by: default avatarThomas Pedersen <thomas@cozybit.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent dca7e943
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -233,6 +233,8 @@ void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh);
/* Mesh paths */
/* Mesh paths */
int mesh_nexthop_lookup(struct sk_buff *skb,
int mesh_nexthop_lookup(struct sk_buff *skb,
		struct ieee80211_sub_if_data *sdata);
		struct ieee80211_sub_if_data *sdata);
int mesh_nexthop_resolve(struct sk_buff *skb,
			 struct ieee80211_sub_if_data *sdata);
void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata);
void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata);
struct mesh_path *mesh_path_lookup(u8 *dst,
struct mesh_path *mesh_path_lookup(u8 *dst,
		struct ieee80211_sub_if_data *sdata);
		struct ieee80211_sub_if_data *sdata);
+68 −43
Original line number Original line Diff line number Diff line
@@ -982,62 +982,44 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
	kfree(preq_node);
	kfree(preq_node);
}
}


/**
/* mesh_nexthop_resolve - lookup next hop for given skb and start path
 * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame
 * discovery if no forwarding information is found.
 *
 *
 * @skb: 802.11 frame to be sent
 * @skb: 802.11 frame to be sent
 * @sdata: network subif the frame will be sent through
 * @sdata: network subif the frame will be sent through
 *
 *
 * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is
 * Returns: 0 if the next hop was found and -ENOENT if the frame was queued.
 * found, the function will start a path discovery and queue the frame so it is
 * skb is freeed here if no mpath could be allocated.
 * sent when the path is resolved. This means the caller must not free the skb
 * in this case.
 */
 */
int mesh_nexthop_lookup(struct sk_buff *skb,
int mesh_nexthop_resolve(struct sk_buff *skb,
			 struct ieee80211_sub_if_data *sdata)
			 struct ieee80211_sub_if_data *sdata)
{
{
	struct sk_buff *skb_to_free = NULL;
	struct mesh_path *mpath;
	struct sta_info *next_hop;
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct mesh_path *mpath;
	struct sk_buff *skb_to_free = NULL;
	u8 *target_addr = hdr->addr3;
	u8 *target_addr = hdr->addr3;
	int err = 0;
	int err = 0;


	rcu_read_lock();
	rcu_read_lock();
	mpath = mesh_path_lookup(target_addr, sdata);
	err = mesh_nexthop_lookup(skb, sdata);
	if (!err)
		goto endlookup;


	/* no nexthop found, start resolving */
	mpath = mesh_path_lookup(target_addr, sdata);
	if (!mpath) {
	if (!mpath) {
		mesh_path_add(target_addr, sdata);
		mesh_path_add(target_addr, sdata);
		mpath = mesh_path_lookup(target_addr, sdata);
		mpath = mesh_path_lookup(target_addr, sdata);
		if (!mpath) {
		if (!mpath) {
			sdata->u.mesh.mshstats.dropped_frames_no_route++;
			mesh_path_discard_frame(skb, sdata);
			err = -ENOSPC;
			err = -ENOSPC;
			goto endlookup;
			goto endlookup;
		}
		}
	}
	}


	if (mpath->flags & MESH_PATH_ACTIVE) {
	if (!(mpath->flags & MESH_PATH_RESOLVING))
		if (time_after(jiffies,
			       mpath->exp_time -
			       msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
		    !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) &&
		    !(mpath->flags & MESH_PATH_RESOLVING) &&
		    !(mpath->flags & MESH_PATH_FIXED)) {
			mesh_queue_preq(mpath,
					PREQ_Q_F_START | PREQ_Q_F_REFRESH);
		}
		next_hop = rcu_dereference(mpath->next_hop);
		if (next_hop) {
			memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
			memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
		} else
			err = -ENOENT;
	} else {
		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
		if (!(mpath->flags & MESH_PATH_RESOLVING)) {
			/* Start discovery only if it is not running yet */
		mesh_queue_preq(mpath, PREQ_Q_F_START);
		mesh_queue_preq(mpath, PREQ_Q_F_START);
		}


	if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
	if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
		skb_to_free = skb_dequeue(&mpath->frame_queue);
		skb_to_free = skb_dequeue(&mpath->frame_queue);
@@ -1045,9 +1027,52 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
	info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
	info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
	ieee80211_set_qos_hdr(sdata, skb);
	ieee80211_set_qos_hdr(sdata, skb);
	skb_queue_tail(&mpath->frame_queue, skb);
	skb_queue_tail(&mpath->frame_queue, skb);
	err = -ENOENT;
	if (skb_to_free)
	if (skb_to_free)
		mesh_path_discard_frame(skb_to_free, sdata);
		mesh_path_discard_frame(skb_to_free, sdata);
		err = -ENOENT;

endlookup:
	rcu_read_unlock();
	return err;
}
/**
 * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame. Calling
 * this function is considered "using" the associated mpath, so preempt a path
 * refresh if this mpath expires soon.
 *
 * @skb: 802.11 frame to be sent
 * @sdata: network subif the frame will be sent through
 *
 * Returns: 0 if the next hop was found. Nonzero otherwise.
 */
int mesh_nexthop_lookup(struct sk_buff *skb,
			struct ieee80211_sub_if_data *sdata)
{
	struct mesh_path *mpath;
	struct sta_info *next_hop;
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	u8 *target_addr = hdr->addr3;
	int err = -ENOENT;

	rcu_read_lock();
	mpath = mesh_path_lookup(target_addr, sdata);

	if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE))
		goto endlookup;

	if (time_after(jiffies,
		       mpath->exp_time -
		       msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
	    !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) &&
	    !(mpath->flags & MESH_PATH_RESOLVING) &&
	    !(mpath->flags & MESH_PATH_FIXED))
		mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);

	next_hop = rcu_dereference(mpath->next_hop);
	if (next_hop) {
		memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
		memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
		err = 0;
	}
	}


endlookup:
endlookup:
+0 −27
Original line number Original line Diff line number Diff line
@@ -973,38 +973,11 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
 * @skb: frame to discard
 * @skb: frame to discard
 * @sdata: network subif the frame was to be sent through
 * @sdata: network subif the frame was to be sent through
 *
 *
 * If the frame was being forwarded from another MP, a PERR frame will be sent
 * to the precursor.  The precursor's address (i.e. the previous hop) was saved
 * in addr1 of the frame-to-be-forwarded, and would only be overwritten once
 * the destination is successfully resolved.
 *
 * Locking: the function must me called within a rcu_read_lock region
 * Locking: the function must me called within a rcu_read_lock region
 */
 */
void mesh_path_discard_frame(struct sk_buff *skb,
void mesh_path_discard_frame(struct sk_buff *skb,
			     struct ieee80211_sub_if_data *sdata)
			     struct ieee80211_sub_if_data *sdata)
{
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	struct mesh_path *mpath;
	u32 sn = 0;
	__le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);

	if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) {
		u8 *ra, *da;

		da = hdr->addr3;
		ra = hdr->addr2;
		rcu_read_lock();
		mpath = mesh_path_lookup(da, sdata);
		if (mpath) {
			spin_lock_bh(&mpath->state_lock);
			sn = ++mpath->sn;
			spin_unlock_bh(&mpath->state_lock);
		}
		rcu_read_unlock();
		mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, da,
				   cpu_to_le32(sn), reason, ra, sdata);
	}

	kfree_skb(skb);
	kfree_skb(skb);
	sdata->u.mesh.mshstats.dropped_frames_no_route++;
	sdata->u.mesh.mshstats.dropped_frames_no_route++;
}
}
+8 −6
Original line number Original line Diff line number Diff line
@@ -1899,6 +1899,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
	struct ieee80211_local *local = rx->local;
	struct ieee80211_local *local = rx->local;
	struct ieee80211_sub_if_data *sdata = rx->sdata;
	struct ieee80211_sub_if_data *sdata = rx->sdata;
	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
	__le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
	u16 q;
	u16 q;


	hdr = (struct ieee80211_hdr *) skb->data;
	hdr = (struct ieee80211_hdr *) skb->data;
@@ -1985,13 +1986,14 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
								fwded_mcast);
								fwded_mcast);
				memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
				memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
			} else {
			} else {
				int err;
				if (mesh_nexthop_lookup(fwd_skb, sdata)) {
				err = mesh_nexthop_lookup(fwd_skb, sdata);
				/* can't resolve next hop, send a PERR */
				/* Failed to immediately resolve next hop:
					mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl,
				 * fwded frame was dropped or will be added
							   fwd_hdr->addr3, 0, reason,
				 * later to the pending skb queue.  */
							   fwd_hdr->addr2, sdata);
				if (err)
					sdata->u.mesh.mshstats.dropped_frames_no_route++;
					return RX_DROP_MONITOR;
					return RX_DROP_MONITOR;
				}


				IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
				IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
								fwded_unicast);
								fwded_unicast);
+1 −1
Original line number Original line Diff line number Diff line
@@ -1464,7 +1464,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
	if (ieee80211_vif_is_mesh(&sdata->vif) &&
	if (ieee80211_vif_is_mesh(&sdata->vif) &&
	    ieee80211_is_data(hdr->frame_control) &&
	    ieee80211_is_data(hdr->frame_control) &&
		!is_multicast_ether_addr(hdr->addr1))
		!is_multicast_ether_addr(hdr->addr1))
			if (mesh_nexthop_lookup(skb, sdata)) {
			if (mesh_nexthop_resolve(skb, sdata)) {
				/* skb queued: don't free */
				/* skb queued: don't free */
				rcu_read_unlock();
				rcu_read_unlock();
				return;
				return;