From d0ce1855eab098c6257f1321b02b70f916064aaa Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 3 Nov 2011 21:11:13 -0700 Subject: mac80211: simplify mesh frame queue mapping and QoS We only need to set the skb queue twice: 1. by the netdev, on local TX. 2. when forwarding a mesh frame. We only need to set the qos header twice: 1. by mac80211, on local TX. 2. when putting a frame on the mpath->frame_queue We also don't need the RA in order to set the proper queue mapping since all mesh STAs are QoS, indicate this and do it once when the frame is received. Also fixes an issue where the QoS header and queue mapping was not set for unicast forwarded frames. Signed-off-by: Javier Cardona Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net/mac80211/mesh_pathtbl.c') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 7f54c5042235..4fc23d1b9c3a 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -213,7 +213,6 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) struct ieee80211_hdr *hdr; struct sk_buff_head tmpq; unsigned long flags; - struct ieee80211_sub_if_data *sdata = mpath->sdata; rcu_assign_pointer(mpath->next_hop, sta); @@ -224,8 +223,6 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) { hdr = (struct ieee80211_hdr *) skb->data; memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); - skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb)); - ieee80211_set_qos_hdr(sdata, skb); __skb_queue_tail(&tmpq, skb); } -- cgit v1.2.3 From 30be52e44fd4276d768efffb55d424fb682e6505 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 21 Nov 2011 11:23:50 +0100 Subject: mac80211: fix RCU warnings in mesh Sparse RCU checking reports two warnings in the mesh path table code. These are due to questionable uses of rcu_dereference. To fix the first one, get rid of mesh_gate_add() and just make mesh_path_add_gate() do the correct deref. To fix the second one, simply remove rcu_dereference() in mesh_gate_del() -- it already gets a proper pointer as indicated by the prototype (no __rcu annotation) and confirmed by the code. Cc: Javier Cardona Cc: Thomas Pedersen Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) (limited to 'net/mac80211/mesh_pathtbl.c') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 4fc23d1b9c3a..7bd2a76aef0e 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -69,8 +69,6 @@ static inline struct mesh_table *resize_dereference_mpp_paths(void) lockdep_is_held(&pathtbl_resize_lock)); } -static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath); - /* * CAREFUL -- "tbl" must not be an expression, * in particular not an rcu_dereference(), since @@ -420,21 +418,18 @@ static void mesh_gate_node_reclaim(struct rcu_head *rp) } /** - * mesh_gate_add - mark mpath as path to a mesh gate and add to known_gates - * @mesh_tbl: table which contains known_gates list - * @mpath: mpath to known mesh gate - * - * Returns: 0 on success - * + * mesh_path_add_gate - add the given mpath to a mesh gate to our path table + * @mpath: gate path to add to table */ -static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath) +int mesh_path_add_gate(struct mesh_path *mpath) { + struct mesh_table *tbl; struct mpath_node *gate, *new_gate; struct hlist_node *n; int err; rcu_read_lock(); - tbl = rcu_dereference(tbl); + tbl = rcu_dereference(mesh_paths); hlist_for_each_entry_rcu(gate, n, tbl->known_gates, list) if (gate->mpath == mpath) { @@ -478,8 +473,6 @@ static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath) struct mpath_node *gate; struct hlist_node *p, *q; - tbl = rcu_dereference(tbl); - hlist_for_each_entry_safe(gate, p, q, tbl->known_gates, list) if (gate->mpath == mpath) { spin_lock_bh(&tbl->gates_lock); @@ -497,16 +490,6 @@ static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath) return 0; } -/** - * - * mesh_path_add_gate - add the given mpath to a mesh gate to our path table - * @mpath: gate path to add to table - */ -int mesh_path_add_gate(struct mesh_path *mpath) -{ - return mesh_gate_add(mesh_paths, mpath); -} - /** * mesh_gate_num - number of gates known to this interface * @sdata: subif data -- cgit v1.2.3 From 7e3c88660b5b90f437cf466b1805089ccb764ee3 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Thu, 24 Nov 2011 17:15:21 -0800 Subject: mac80211: failed forwarded mesh frame addressing Don't write the TA until next hop is actually known, since we might need the original TA for sending a PERR. Previously we would send a PERR to ourself if path resolution for a forwarded frame failed. Signed-off-by: Thomas Pedersen Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 5 +++-- net/mac80211/mesh_pathtbl.c | 6 ++++-- net/mac80211/rx.c | 8 +------- 3 files changed, 8 insertions(+), 11 deletions(-) (limited to 'net/mac80211/mesh_pathtbl.c') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index ce3db2735d7c..1b13135d7f35 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -1029,9 +1029,10 @@ int mesh_nexthop_lookup(struct sk_buff *skb, PREQ_Q_F_START | PREQ_Q_F_REFRESH); } next_hop = rcu_dereference(mpath->next_hop); - if (next_hop) + if (next_hop) { memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN); - else + memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); + } else err = -ENOENT; } else { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 7bd2a76aef0e..4c50d8ade04f 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -221,6 +221,7 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) { hdr = (struct ieee80211_hdr *) skb->data; memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); + memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN); __skb_queue_tail(&tmpq, skb); } @@ -264,6 +265,7 @@ static void prepare_for_gate(struct sk_buff *skb, char *dst_addr, next_hop = rcu_dereference(gate_mpath->next_hop)->sta.addr; memcpy(hdr->addr1, next_hop, ETH_ALEN); rcu_read_unlock(); + memcpy(hdr->addr2, gate_mpath->sdata->vif.addr, ETH_ALEN); memcpy(hdr->addr3, dst_addr, ETH_ALEN); } @@ -990,7 +992,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, u8 *ra, *da; da = hdr->addr3; - ra = hdr->addr1; + ra = hdr->addr2; rcu_read_lock(); mpath = mesh_path_lookup(da, sdata); if (mpath) { @@ -999,7 +1001,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, spin_unlock_bh(&mpath->state_lock); } rcu_read_unlock(); - mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data, + mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, da, cpu_to_le32(sn), reason, ra, sdata); } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4eafbfd891d5..60798d6d53cf 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1974,7 +1974,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) goto out; fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; - memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); info = IEEE80211_SKB_CB(fwd_skb); memset(info, 0, sizeof(*info)); info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; @@ -1983,14 +1982,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) if (is_multicast_ether_addr(fwd_hdr->addr1)) { IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, fwded_mcast); + memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); } else { int err; - /* - * Save TA to addr1 to send TA a path error if a - * suitable next hop is not found - */ - memcpy(fwd_hdr->addr1, fwd_hdr->addr2, - ETH_ALEN); err = mesh_nexthop_lookup(fwd_skb, sdata); /* Failed to immediately resolve next hop: * fwded frame was dropped or will be added -- cgit v1.2.3 From 0cfda8519c85eb279166fb55a8553ee66eac9b35 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Thu, 24 Nov 2011 17:15:25 -0800 Subject: 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: Thomas Pedersen Signed-off-by: John W. Linville --- net/mac80211/mesh.h | 2 + net/mac80211/mesh_hwmp.c | 111 +++++++++++++++++++++++++++----------------- net/mac80211/mesh_pathtbl.c | 27 ----------- net/mac80211/rx.c | 14 +++--- net/mac80211/tx.c | 2 +- 5 files changed, 79 insertions(+), 77 deletions(-) (limited to 'net/mac80211/mesh_pathtbl.c') diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 622cc96eb4de..bd14bd26a2b6 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -233,6 +233,8 @@ void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); /* Mesh paths */ int mesh_nexthop_lookup(struct sk_buff *skb, 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); struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index fe93386d6aa9..73abb7524b2c 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -982,72 +982,97 @@ enddiscovery: kfree(preq_node); } -/** - * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame +/* mesh_nexthop_resolve - lookup next hop for given skb and start path + * discovery if no forwarding information is found. * * @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. If no next hop is - * found, the function will start a path discovery and queue the frame so it is - * sent when the path is resolved. This means the caller must not free the skb - * in this case. + * Returns: 0 if the next hop was found and -ENOENT if the frame was queued. + * skb is freeed here if no mpath could be allocated. */ -int mesh_nexthop_lookup(struct sk_buff *skb, - struct ieee80211_sub_if_data *sdata) +int mesh_nexthop_resolve(struct sk_buff *skb, + 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_tx_info *info = IEEE80211_SKB_CB(skb); + struct mesh_path *mpath; + struct sk_buff *skb_to_free = NULL; u8 *target_addr = hdr->addr3; int err = 0; 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) { mesh_path_add(target_addr, sdata); mpath = mesh_path_lookup(target_addr, sdata); if (!mpath) { - sdata->u.mesh.mshstats.dropped_frames_no_route++; + mesh_path_discard_frame(skb, sdata); err = -ENOSPC; goto endlookup; } } - if (mpath->flags & MESH_PATH_ACTIVE) { - 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); - } + if (!(mpath->flags & MESH_PATH_RESOLVING)) + mesh_queue_preq(mpath, PREQ_Q_F_START); + + if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN) + skb_to_free = skb_dequeue(&mpath->frame_queue); + + info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; + ieee80211_set_qos_hdr(sdata, skb); + skb_queue_tail(&mpath->frame_queue, skb); + err = -ENOENT; + if (skb_to_free) + mesh_path_discard_frame(skb_to_free, sdata); + +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; - if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN) - skb_to_free = skb_dequeue(&mpath->frame_queue); + 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); - info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; - ieee80211_set_qos_hdr(sdata, skb); - skb_queue_tail(&mpath->frame_queue, skb); - if (skb_to_free) - mesh_path_discard_frame(skb_to_free, sdata); - err = -ENOENT; + 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: diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 4c50d8ade04f..edf167e3b8f3 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -973,38 +973,11 @@ int mesh_path_send_to_gates(struct mesh_path *mpath) * @skb: frame to discard * @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 */ void mesh_path_discard_frame(struct sk_buff *skb, 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); sdata->u.mesh.mshstats.dropped_frames_no_route++; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 92fa95741761..f842f901d179 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1899,6 +1899,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) struct ieee80211_local *local = rx->local; struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD); u16 q; hdr = (struct ieee80211_hdr *) skb->data; @@ -1985,13 +1986,14 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) fwded_mcast); memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); } else { - int err; - err = mesh_nexthop_lookup(fwd_skb, sdata); - /* Failed to immediately resolve next hop: - * fwded frame was dropped or will be added - * later to the pending skb queue. */ - if (err) + if (mesh_nexthop_lookup(fwd_skb, sdata)) { + /* can't resolve next hop, send a PERR */ + mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, + fwd_hdr->addr3, 0, reason, + fwd_hdr->addr2, sdata); + sdata->u.mesh.mshstats.dropped_frames_no_route++; return RX_DROP_MONITOR; + } IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, fwded_unicast); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 655e3a97f92e..c4cb4a536e27 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1464,7 +1464,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) if (ieee80211_vif_is_mesh(&sdata->vif) && ieee80211_is_data(hdr->frame_control) && !is_multicast_ether_addr(hdr->addr1)) - if (mesh_nexthop_lookup(skb, sdata)) { + if (mesh_nexthop_resolve(skb, sdata)) { /* skb queued: don't free */ rcu_read_unlock(); return; -- cgit v1.2.3