diff options
author | Thomas Pedersen <thomas@cozybit.com> | 2011-11-24 20:15:25 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-28 14:44:07 -0500 |
commit | 0cfda8519c85eb279166fb55a8553ee66eac9b35 (patch) | |
tree | 55f917c9402c0164a76c80b4675ea173562a869f | |
parent | dca7e9430cb3e492437a5ce891b8b3e315c147ca (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.h | 2 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 111 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 27 | ||||
-rw-r--r-- | net/mac80211/rx.c | 14 | ||||
-rw-r--r-- | net/mac80211/tx.c | 2 |
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 */ |
234 | int mesh_nexthop_lookup(struct sk_buff *skb, | 234 | int mesh_nexthop_lookup(struct sk_buff *skb, |
235 | struct ieee80211_sub_if_data *sdata); | 235 | struct ieee80211_sub_if_data *sdata); |
236 | int mesh_nexthop_resolve(struct sk_buff *skb, | ||
237 | struct ieee80211_sub_if_data *sdata); | ||
236 | void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); | 238 | void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); |
237 | struct mesh_path *mesh_path_lookup(u8 *dst, | 239 | struct 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 | */ |
996 | int mesh_nexthop_lookup(struct sk_buff *skb, | 994 | int 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); | 1034 | endlookup: |
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 | */ | ||
1048 | int 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 | ||
1053 | endlookup: | 1078 | 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) | |||
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 | */ |
983 | void mesh_path_discard_frame(struct sk_buff *skb, | 978 | void 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; |