aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Pedersen <thomas@cozybit.com>2011-11-24 20:15:25 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-11-28 14:44:07 -0500
commit0cfda8519c85eb279166fb55a8553ee66eac9b35 (patch)
tree55f917c9402c0164a76c80b4675ea173562a869f
parentdca7e9430cb3e492437a5ce891b8b3e315c147ca (diff)
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 <thomas@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/mesh.h2
-rw-r--r--net/mac80211/mesh_hwmp.c111
-rw-r--r--net/mac80211/mesh_pathtbl.c27
-rw-r--r--net/mac80211/rx.c14
-rw-r--r--net/mac80211/tx.c2
5 files changed, 79 insertions, 77 deletions
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);
233/* Mesh paths */ 233/* Mesh paths */
234int mesh_nexthop_lookup(struct sk_buff *skb, 234int mesh_nexthop_lookup(struct sk_buff *skb,
235 struct ieee80211_sub_if_data *sdata); 235 struct ieee80211_sub_if_data *sdata);
236int mesh_nexthop_resolve(struct sk_buff *skb,
237 struct ieee80211_sub_if_data *sdata);
236void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); 238void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata);
237struct mesh_path *mesh_path_lookup(u8 *dst, 239struct mesh_path *mesh_path_lookup(u8 *dst,
238 struct ieee80211_sub_if_data *sdata); 240 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:
982 kfree(preq_node); 982 kfree(preq_node);
983} 983}
984 984
985/** 985/* mesh_nexthop_resolve - lookup next hop for given skb and start path
986 * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame 986 * discovery if no forwarding information is found.
987 * 987 *
988 * @skb: 802.11 frame to be sent 988 * @skb: 802.11 frame to be sent
989 * @sdata: network subif the frame will be sent through 989 * @sdata: network subif the frame will be sent through
990 * 990 *
991 * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is 991 * Returns: 0 if the next hop was found and -ENOENT if the frame was queued.
992 * found, the function will start a path discovery and queue the frame so it is 992 * skb is freeed here if no mpath could be allocated.
993 * sent when the path is resolved. This means the caller must not free the skb
994 * in this case.
995 */ 993 */
996int mesh_nexthop_lookup(struct sk_buff *skb, 994int mesh_nexthop_resolve(struct sk_buff *skb,
997 struct ieee80211_sub_if_data *sdata) 995 struct ieee80211_sub_if_data *sdata)
998{ 996{
999 struct sk_buff *skb_to_free = NULL;
1000 struct mesh_path *mpath;
1001 struct sta_info *next_hop;
1002 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 997 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
998 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
999 struct mesh_path *mpath;
1000 struct sk_buff *skb_to_free = NULL;
1003 u8 *target_addr = hdr->addr3; 1001 u8 *target_addr = hdr->addr3;
1004 int err = 0; 1002 int err = 0;
1005 1003
1006 rcu_read_lock(); 1004 rcu_read_lock();
1007 mpath = mesh_path_lookup(target_addr, sdata); 1005 err = mesh_nexthop_lookup(skb, sdata);
1006 if (!err)
1007 goto endlookup;
1008 1008
1009 /* no nexthop found, start resolving */
1010 mpath = mesh_path_lookup(target_addr, sdata);
1009 if (!mpath) { 1011 if (!mpath) {
1010 mesh_path_add(target_addr, sdata); 1012 mesh_path_add(target_addr, sdata);
1011 mpath = mesh_path_lookup(target_addr, sdata); 1013 mpath = mesh_path_lookup(target_addr, sdata);
1012 if (!mpath) { 1014 if (!mpath) {
1013 sdata->u.mesh.mshstats.dropped_frames_no_route++; 1015 mesh_path_discard_frame(skb, sdata);
1014 err = -ENOSPC; 1016 err = -ENOSPC;
1015 goto endlookup; 1017 goto endlookup;
1016 } 1018 }
1017 } 1019 }
1018 1020
1019 if (mpath->flags & MESH_PATH_ACTIVE) { 1021 if (!(mpath->flags & MESH_PATH_RESOLVING))
1020 if (time_after(jiffies, 1022 mesh_queue_preq(mpath, PREQ_Q_F_START);
1021 mpath->exp_time - 1023
1022 msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) && 1024 if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
1023 !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) && 1025 skb_to_free = skb_dequeue(&mpath->frame_queue);
1024 !(mpath->flags & MESH_PATH_RESOLVING) && 1026
1025 !(mpath->flags & MESH_PATH_FIXED)) { 1027 info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
1026 mesh_queue_preq(mpath, 1028 ieee80211_set_qos_hdr(sdata, skb);
1027 PREQ_Q_F_START | PREQ_Q_F_REFRESH); 1029 skb_queue_tail(&mpath->frame_queue, skb);
1028 } 1030 err = -ENOENT;
1029 next_hop = rcu_dereference(mpath->next_hop); 1031 if (skb_to_free)
1030 if (next_hop) { 1032 mesh_path_discard_frame(skb_to_free, sdata);
1031 memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN); 1033
1032 memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); 1034endlookup:
1033 } else 1035 rcu_read_unlock();
1034 err = -ENOENT; 1036 return err;
1035 } else { 1037}
1036 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1038/**
1037 if (!(mpath->flags & MESH_PATH_RESOLVING)) { 1039 * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame. Calling
1038 /* Start discovery only if it is not running yet */ 1040 * this function is considered "using" the associated mpath, so preempt a path
1039 mesh_queue_preq(mpath, PREQ_Q_F_START); 1041 * refresh if this mpath expires soon.
1040 } 1042 *
1043 * @skb: 802.11 frame to be sent
1044 * @sdata: network subif the frame will be sent through
1045 *
1046 * Returns: 0 if the next hop was found. Nonzero otherwise.
1047 */
1048int mesh_nexthop_lookup(struct sk_buff *skb,
1049 struct ieee80211_sub_if_data *sdata)
1050{
1051 struct mesh_path *mpath;
1052 struct sta_info *next_hop;
1053 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1054 u8 *target_addr = hdr->addr3;
1055 int err = -ENOENT;
1041 1056
1042 if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN) 1057 rcu_read_lock();
1043 skb_to_free = skb_dequeue(&mpath->frame_queue); 1058 mpath = mesh_path_lookup(target_addr, sdata);
1059
1060 if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE))
1061 goto endlookup;
1062
1063 if (time_after(jiffies,
1064 mpath->exp_time -
1065 msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
1066 !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) &&
1067 !(mpath->flags & MESH_PATH_RESOLVING) &&
1068 !(mpath->flags & MESH_PATH_FIXED))
1069 mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
1044 1070
1045 info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; 1071 next_hop = rcu_dereference(mpath->next_hop);
1046 ieee80211_set_qos_hdr(sdata, skb); 1072 if (next_hop) {
1047 skb_queue_tail(&mpath->frame_queue, skb); 1073 memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
1048 if (skb_to_free) 1074 memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
1049 mesh_path_discard_frame(skb_to_free, sdata); 1075 err = 0;
1050 err = -ENOENT;
1051 } 1076 }
1052 1077
1053endlookup: 1078endlookup:
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)
973 * @skb: frame to discard 973 * @skb: frame to discard
974 * @sdata: network subif the frame was to be sent through 974 * @sdata: network subif the frame was to be sent through
975 * 975 *
976 * If the frame was being forwarded from another MP, a PERR frame will be sent
977 * to the precursor. The precursor's address (i.e. the previous hop) was saved
978 * in addr1 of the frame-to-be-forwarded, and would only be overwritten once
979 * the destination is successfully resolved.
980 *
981 * Locking: the function must me called within a rcu_read_lock region 976 * Locking: the function must me called within a rcu_read_lock region
982 */ 977 */
983void mesh_path_discard_frame(struct sk_buff *skb, 978void mesh_path_discard_frame(struct sk_buff *skb,
984 struct ieee80211_sub_if_data *sdata) 979 struct ieee80211_sub_if_data *sdata)
985{ 980{
986 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
987 struct mesh_path *mpath;
988 u32 sn = 0;
989 __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
990
991 if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) {
992 u8 *ra, *da;
993
994 da = hdr->addr3;
995 ra = hdr->addr2;
996 rcu_read_lock();
997 mpath = mesh_path_lookup(da, sdata);
998 if (mpath) {
999 spin_lock_bh(&mpath->state_lock);
1000 sn = ++mpath->sn;
1001 spin_unlock_bh(&mpath->state_lock);
1002 }
1003 rcu_read_unlock();
1004 mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, da,
1005 cpu_to_le32(sn), reason, ra, sdata);
1006 }
1007
1008 kfree_skb(skb); 981 kfree_skb(skb);
1009 sdata->u.mesh.mshstats.dropped_frames_no_route++; 982 sdata->u.mesh.mshstats.dropped_frames_no_route++;
1010} 983}
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)
1899 struct ieee80211_local *local = rx->local; 1899 struct ieee80211_local *local = rx->local;
1900 struct ieee80211_sub_if_data *sdata = rx->sdata; 1900 struct ieee80211_sub_if_data *sdata = rx->sdata;
1901 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 1901 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
1902 __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
1902 u16 q; 1903 u16 q;
1903 1904
1904 hdr = (struct ieee80211_hdr *) skb->data; 1905 hdr = (struct ieee80211_hdr *) skb->data;
@@ -1985,13 +1986,14 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
1985 fwded_mcast); 1986 fwded_mcast);
1986 memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); 1987 memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
1987 } else { 1988 } else {
1988 int err; 1989 if (mesh_nexthop_lookup(fwd_skb, sdata)) {
1989 err = mesh_nexthop_lookup(fwd_skb, sdata); 1990 /* can't resolve next hop, send a PERR */
1990 /* Failed to immediately resolve next hop: 1991 mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl,
1991 * fwded frame was dropped or will be added 1992 fwd_hdr->addr3, 0, reason,
1992 * later to the pending skb queue. */ 1993 fwd_hdr->addr2, sdata);
1993 if (err) 1994 sdata->u.mesh.mshstats.dropped_frames_no_route++;
1994 return RX_DROP_MONITOR; 1995 return RX_DROP_MONITOR;
1996 }
1995 1997
1996 IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, 1998 IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
1997 fwded_unicast); 1999 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)
1464 if (ieee80211_vif_is_mesh(&sdata->vif) && 1464 if (ieee80211_vif_is_mesh(&sdata->vif) &&
1465 ieee80211_is_data(hdr->frame_control) && 1465 ieee80211_is_data(hdr->frame_control) &&
1466 !is_multicast_ether_addr(hdr->addr1)) 1466 !is_multicast_ether_addr(hdr->addr1))
1467 if (mesh_nexthop_lookup(skb, sdata)) { 1467 if (mesh_nexthop_resolve(skb, sdata)) {
1468 /* skb queued: don't free */ 1468 /* skb queued: don't free */
1469 rcu_read_unlock(); 1469 rcu_read_unlock();
1470 return; 1470 return;