diff options
Diffstat (limited to 'net/wireless/util.c')
| -rw-r--r-- | net/wireless/util.c | 25 | 
1 files changed, 19 insertions, 6 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c index be2ab8c59e3..3416373a9c0 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -5,6 +5,7 @@   */  #include <linux/bitops.h>  #include <linux/etherdevice.h> +#include <linux/slab.h>  #include <net/cfg80211.h>  #include <net/ip.h>  #include "core.h" @@ -330,11 +331,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,  		if (iftype == NL80211_IFTYPE_MESH_POINT) {  			struct ieee80211s_hdr *meshdr =  				(struct ieee80211s_hdr *) (skb->data + hdrlen); -			hdrlen += ieee80211_get_mesh_hdrlen(meshdr); +			/* make sure meshdr->flags is on the linear part */ +			if (!pskb_may_pull(skb, hdrlen + 1)) +				return -1;  			if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { -				memcpy(dst, meshdr->eaddr1, ETH_ALEN); -				memcpy(src, meshdr->eaddr2, ETH_ALEN); +				skb_copy_bits(skb, hdrlen + +					offsetof(struct ieee80211s_hdr, eaddr1), +				       	dst, ETH_ALEN); +				skb_copy_bits(skb, hdrlen + +					offsetof(struct ieee80211s_hdr, eaddr2), +				        src, ETH_ALEN);  			} +			hdrlen += ieee80211_get_mesh_hdrlen(meshdr);  		}  		break;  	case cpu_to_le16(IEEE80211_FCTL_FROMDS): @@ -346,9 +354,14 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,  		if (iftype == NL80211_IFTYPE_MESH_POINT) {  			struct ieee80211s_hdr *meshdr =  				(struct ieee80211s_hdr *) (skb->data + hdrlen); -			hdrlen += ieee80211_get_mesh_hdrlen(meshdr); +			/* make sure meshdr->flags is on the linear part */ +			if (!pskb_may_pull(skb, hdrlen + 1)) +				return -1;  			if (meshdr->flags & MESH_FLAGS_AE_A4) -				memcpy(src, meshdr->eaddr1, ETH_ALEN); +				skb_copy_bits(skb, hdrlen + +					offsetof(struct ieee80211s_hdr, eaddr1), +					src, ETH_ALEN); +			hdrlen += ieee80211_get_mesh_hdrlen(meshdr);  		}  		break;  	case cpu_to_le16(0): @@ -357,7 +370,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,  		break;  	} -	if (unlikely(skb->len - hdrlen < 8)) +	if (!pskb_may_pull(skb, hdrlen + 8))  		return -1;  	payload = skb->data + hdrlen;  |