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) |
