diff options
-rw-r--r-- | net/mac80211/tx.c | 48 |
1 files changed, 28 insertions, 20 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 36761c7139b..457166889cc 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1270,46 +1270,54 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct ieee80211_tx_packet_data *pkt_data; struct ieee80211_radiotap_header *prthdr = (struct ieee80211_radiotap_header *)skb->data; - u16 len; + u16 len_rthdr; - /* - * there must be a radiotap header at the - * start in this case - */ - if (unlikely(prthdr->it_version)) { - /* only version 0 is supported */ - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } + /* check for not even having the fixed radiotap header part */ + if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) + goto fail; /* too short to be possibly valid */ + + /* is it a header version we can trust to find length from? */ + if (unlikely(prthdr->it_version)) + goto fail; /* only version 0 is supported */ + + /* then there must be a radiotap header with a length we can use */ + len_rthdr = ieee80211_get_radiotap_len(skb->data); + + /* does the skb contain enough to deliver on the alleged length? */ + if (unlikely(skb->len < len_rthdr)) + goto fail; /* skb too short for claimed rt header extent */ skb->dev = local->mdev; pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; memset(pkt_data, 0, sizeof(*pkt_data)); + /* needed because we set skb device to master */ pkt_data->ifindex = dev->ifindex; + pkt_data->mgmt_iface = 0; pkt_data->do_not_encrypt = 1; - /* above needed because we set skb device to master */ - /* * fix up the pointers accounting for the radiotap * header still being in there. We are being given * a precooked IEEE80211 header so no need for * normal processing */ - len = le16_to_cpu(get_unaligned(&prthdr->it_len)); - skb_set_mac_header(skb, len); - skb_set_network_header(skb, len + sizeof(struct ieee80211_hdr)); - skb_set_transport_header(skb, len + sizeof(struct ieee80211_hdr)); - + skb_set_mac_header(skb, len_rthdr); /* - * pass the radiotap header up to - * the next stage intact + * these are just fixed to the end of the rt area since we + * don't have any better information and at this point, nobody cares */ - dev_queue_xmit(skb); + skb_set_network_header(skb, len_rthdr); + skb_set_transport_header(skb, len_rthdr); + /* pass the radiotap header up to the next stage intact */ + dev_queue_xmit(skb); return NETDEV_TX_OK; + +fail: + dev_kfree_skb(skb); + return NETDEV_TX_OK; /* meaning, we dealt with the skb */ } /** |