diff options
-rw-r--r-- | include/net/cfg80211.h | 9 | ||||
-rw-r--r-- | net/mac80211/rx.c | 32 | ||||
-rw-r--r-- | net/wireless/util.c | 3 |
3 files changed, 42 insertions, 2 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f8cd4cf3fad8..7d5b6000378b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -2652,6 +2652,15 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); | |||
2652 | unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc); | 2652 | unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc); |
2653 | 2653 | ||
2654 | /** | 2654 | /** |
2655 | * ieee80211_get_mesh_hdrlen - get mesh extension header length | ||
2656 | * @meshhdr: the mesh extension header, only the flags field | ||
2657 | * (first byte) will be accessed | ||
2658 | * Returns the length of the extension header, which is always at | ||
2659 | * least 6 bytes and at most 18 if address 5 and 6 are present. | ||
2660 | */ | ||
2661 | unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); | ||
2662 | |||
2663 | /** | ||
2655 | * DOC: Data path helpers | 2664 | * DOC: Data path helpers |
2656 | * | 2665 | * |
2657 | * In addition to generic utilities, cfg80211 also offers | 2666 | * In addition to generic utilities, cfg80211 also offers |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 99cdee16e31b..265a032dec49 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -531,6 +531,11 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
531 | 531 | ||
532 | if (ieee80211_is_action(hdr->frame_control)) { | 532 | if (ieee80211_is_action(hdr->frame_control)) { |
533 | u8 category; | 533 | u8 category; |
534 | |||
535 | /* make sure category field is present */ | ||
536 | if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE) | ||
537 | return RX_DROP_MONITOR; | ||
538 | |||
534 | mgmt = (struct ieee80211_mgmt *)hdr; | 539 | mgmt = (struct ieee80211_mgmt *)hdr; |
535 | category = mgmt->u.action.category; | 540 | category = mgmt->u.action.category; |
536 | if (category != WLAN_CATEGORY_MESH_ACTION && | 541 | if (category != WLAN_CATEGORY_MESH_ACTION && |
@@ -1892,6 +1897,20 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1892 | 1897 | ||
1893 | hdr = (struct ieee80211_hdr *) skb->data; | 1898 | hdr = (struct ieee80211_hdr *) skb->data; |
1894 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 1899 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
1900 | |||
1901 | /* make sure fixed part of mesh header is there, also checks skb len */ | ||
1902 | if (!pskb_may_pull(rx->skb, hdrlen + 6)) | ||
1903 | return RX_DROP_MONITOR; | ||
1904 | |||
1905 | mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); | ||
1906 | |||
1907 | /* make sure full mesh header is there, also checks skb len */ | ||
1908 | if (!pskb_may_pull(rx->skb, | ||
1909 | hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr))) | ||
1910 | return RX_DROP_MONITOR; | ||
1911 | |||
1912 | /* reload pointers */ | ||
1913 | hdr = (struct ieee80211_hdr *) skb->data; | ||
1895 | mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); | 1914 | mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); |
1896 | 1915 | ||
1897 | /* frame is in RMC, don't forward */ | 1916 | /* frame is in RMC, don't forward */ |
@@ -1915,9 +1934,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1915 | if (is_multicast_ether_addr(hdr->addr1)) { | 1934 | if (is_multicast_ether_addr(hdr->addr1)) { |
1916 | mpp_addr = hdr->addr3; | 1935 | mpp_addr = hdr->addr3; |
1917 | proxied_addr = mesh_hdr->eaddr1; | 1936 | proxied_addr = mesh_hdr->eaddr1; |
1918 | } else { | 1937 | } else if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6) { |
1938 | /* has_a4 already checked in ieee80211_rx_mesh_check */ | ||
1919 | mpp_addr = hdr->addr4; | 1939 | mpp_addr = hdr->addr4; |
1920 | proxied_addr = mesh_hdr->eaddr2; | 1940 | proxied_addr = mesh_hdr->eaddr2; |
1941 | } else { | ||
1942 | return RX_DROP_MONITOR; | ||
1921 | } | 1943 | } |
1922 | 1944 | ||
1923 | rcu_read_lock(); | 1945 | rcu_read_lock(); |
@@ -2354,6 +2376,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2354 | } | 2376 | } |
2355 | break; | 2377 | break; |
2356 | case WLAN_CATEGORY_SELF_PROTECTED: | 2378 | case WLAN_CATEGORY_SELF_PROTECTED: |
2379 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
2380 | sizeof(mgmt->u.action.u.self_prot.action_code))) | ||
2381 | break; | ||
2382 | |||
2357 | switch (mgmt->u.action.u.self_prot.action_code) { | 2383 | switch (mgmt->u.action.u.self_prot.action_code) { |
2358 | case WLAN_SP_MESH_PEERING_OPEN: | 2384 | case WLAN_SP_MESH_PEERING_OPEN: |
2359 | case WLAN_SP_MESH_PEERING_CLOSE: | 2385 | case WLAN_SP_MESH_PEERING_CLOSE: |
@@ -2372,6 +2398,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2372 | } | 2398 | } |
2373 | break; | 2399 | break; |
2374 | case WLAN_CATEGORY_MESH_ACTION: | 2400 | case WLAN_CATEGORY_MESH_ACTION: |
2401 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
2402 | sizeof(mgmt->u.action.u.mesh_action.action_code))) | ||
2403 | break; | ||
2404 | |||
2375 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | 2405 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
2376 | break; | 2406 | break; |
2377 | if (mesh_action_is_path_sel(mgmt) && | 2407 | if (mesh_action_is_path_sel(mgmt) && |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 45a09de1ffe3..2762e8329986 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -309,7 +309,7 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) | |||
309 | } | 309 | } |
310 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); | 310 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); |
311 | 311 | ||
312 | static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | 312 | unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) |
313 | { | 313 | { |
314 | int ae = meshhdr->flags & MESH_FLAGS_AE; | 314 | int ae = meshhdr->flags & MESH_FLAGS_AE; |
315 | /* 802.11-2012, 8.2.4.7.3 */ | 315 | /* 802.11-2012, 8.2.4.7.3 */ |
@@ -323,6 +323,7 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | |||
323 | return 18; | 323 | return 18; |
324 | } | 324 | } |
325 | } | 325 | } |
326 | EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen); | ||
326 | 327 | ||
327 | int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | 328 | int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, |
328 | enum nl80211_iftype iftype) | 329 | enum nl80211_iftype iftype) |