|
|
|
@ -531,6 +531,11 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) |
|
|
|
|
|
|
|
|
|
if (ieee80211_is_action(hdr->frame_control)) { |
|
|
|
|
u8 category; |
|
|
|
|
|
|
|
|
|
/* make sure category field is present */ |
|
|
|
|
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE) |
|
|
|
|
return RX_DROP_MONITOR; |
|
|
|
|
|
|
|
|
|
mgmt = (struct ieee80211_mgmt *)hdr; |
|
|
|
|
category = mgmt->u.action.category; |
|
|
|
|
if (category != WLAN_CATEGORY_MESH_ACTION && |
|
|
|
@ -883,14 +888,16 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) |
|
|
|
|
*/ |
|
|
|
|
if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION && |
|
|
|
|
ieee80211_is_data_present(hdr->frame_control)) { |
|
|
|
|
u16 ethertype; |
|
|
|
|
u8 *payload; |
|
|
|
|
|
|
|
|
|
payload = rx->skb->data + |
|
|
|
|
ieee80211_hdrlen(hdr->frame_control); |
|
|
|
|
ethertype = (payload[6] << 8) | payload[7]; |
|
|
|
|
if (cpu_to_be16(ethertype) == |
|
|
|
|
rx->sdata->control_port_protocol) |
|
|
|
|
unsigned int hdrlen; |
|
|
|
|
__be16 ethertype; |
|
|
|
|
|
|
|
|
|
hdrlen = ieee80211_hdrlen(hdr->frame_control); |
|
|
|
|
|
|
|
|
|
if (rx->skb->len < hdrlen + 8) |
|
|
|
|
return RX_DROP_MONITOR; |
|
|
|
|
|
|
|
|
|
skb_copy_bits(rx->skb, hdrlen + 6, ðertype, 2); |
|
|
|
|
if (ethertype == rx->sdata->control_port_protocol) |
|
|
|
|
return RX_CONTINUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1462,11 +1469,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) |
|
|
|
|
|
|
|
|
|
hdr = (struct ieee80211_hdr *)rx->skb->data; |
|
|
|
|
fc = hdr->frame_control; |
|
|
|
|
|
|
|
|
|
if (ieee80211_is_ctl(fc)) |
|
|
|
|
return RX_CONTINUE; |
|
|
|
|
|
|
|
|
|
sc = le16_to_cpu(hdr->seq_ctrl); |
|
|
|
|
frag = sc & IEEE80211_SCTL_FRAG; |
|
|
|
|
|
|
|
|
|
if (likely((!ieee80211_has_morefrags(fc) && frag == 0) || |
|
|
|
|
(rx->skb)->len < 24 || |
|
|
|
|
is_multicast_ether_addr(hdr->addr1))) { |
|
|
|
|
/* not fragmented */ |
|
|
|
|
goto out; |
|
|
|
@ -1889,6 +1899,20 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) |
|
|
|
|
|
|
|
|
|
hdr = (struct ieee80211_hdr *) skb->data; |
|
|
|
|
hdrlen = ieee80211_hdrlen(hdr->frame_control); |
|
|
|
|
|
|
|
|
|
/* make sure fixed part of mesh header is there, also checks skb len */ |
|
|
|
|
if (!pskb_may_pull(rx->skb, hdrlen + 6)) |
|
|
|
|
return RX_DROP_MONITOR; |
|
|
|
|
|
|
|
|
|
mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); |
|
|
|
|
|
|
|
|
|
/* make sure full mesh header is there, also checks skb len */ |
|
|
|
|
if (!pskb_may_pull(rx->skb, |
|
|
|
|
hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr))) |
|
|
|
|
return RX_DROP_MONITOR; |
|
|
|
|
|
|
|
|
|
/* reload pointers */ |
|
|
|
|
hdr = (struct ieee80211_hdr *) skb->data; |
|
|
|
|
mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); |
|
|
|
|
|
|
|
|
|
/* frame is in RMC, don't forward */ |
|
|
|
@ -1897,7 +1921,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) |
|
|
|
|
mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata)) |
|
|
|
|
return RX_DROP_MONITOR; |
|
|
|
|
|
|
|
|
|
if (!ieee80211_is_data(hdr->frame_control)) |
|
|
|
|
if (!ieee80211_is_data(hdr->frame_control) || |
|
|
|
|
!(status->rx_flags & IEEE80211_RX_RA_MATCH)) |
|
|
|
|
return RX_CONTINUE; |
|
|
|
|
|
|
|
|
|
if (!mesh_hdr->ttl) |
|
|
|
@ -1911,9 +1936,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) |
|
|
|
|
if (is_multicast_ether_addr(hdr->addr1)) { |
|
|
|
|
mpp_addr = hdr->addr3; |
|
|
|
|
proxied_addr = mesh_hdr->eaddr1; |
|
|
|
|
} else { |
|
|
|
|
} else if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6) { |
|
|
|
|
/* has_a4 already checked in ieee80211_rx_mesh_check */ |
|
|
|
|
mpp_addr = hdr->addr4; |
|
|
|
|
proxied_addr = mesh_hdr->eaddr2; |
|
|
|
|
} else { |
|
|
|
|
return RX_DROP_MONITOR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
rcu_read_lock(); |
|
|
|
@ -1941,12 +1969,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) |
|
|
|
|
} |
|
|
|
|
skb_set_queue_mapping(skb, q); |
|
|
|
|
|
|
|
|
|
if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) |
|
|
|
|
goto out; |
|
|
|
|
|
|
|
|
|
if (!--mesh_hdr->ttl) { |
|
|
|
|
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); |
|
|
|
|
return RX_DROP_MONITOR; |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!ifmsh->mshcfg.dot11MeshForwarding) |
|
|
|
@ -2353,6 +2378,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case WLAN_CATEGORY_SELF_PROTECTED: |
|
|
|
|
if (len < (IEEE80211_MIN_ACTION_SIZE + |
|
|
|
|
sizeof(mgmt->u.action.u.self_prot.action_code))) |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
switch (mgmt->u.action.u.self_prot.action_code) { |
|
|
|
|
case WLAN_SP_MESH_PEERING_OPEN: |
|
|
|
|
case WLAN_SP_MESH_PEERING_CLOSE: |
|
|
|
@ -2371,6 +2400,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case WLAN_CATEGORY_MESH_ACTION: |
|
|
|
|
if (len < (IEEE80211_MIN_ACTION_SIZE + |
|
|
|
|
sizeof(mgmt->u.action.u.mesh_action.action_code))) |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
if (!ieee80211_vif_is_mesh(&sdata->vif)) |
|
|
|
|
break; |
|
|
|
|
if (mesh_action_is_path_sel(mgmt) && |
|
|
|
@ -2913,10 +2946,15 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, |
|
|
|
|
if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) |
|
|
|
|
local->dot11ReceivedFragmentCount++; |
|
|
|
|
|
|
|
|
|
if (ieee80211_is_mgmt(fc)) |
|
|
|
|
err = skb_linearize(skb); |
|
|
|
|
else |
|
|
|
|
if (ieee80211_is_mgmt(fc)) { |
|
|
|
|
/* drop frame if too short for header */ |
|
|
|
|
if (skb->len < ieee80211_hdrlen(fc)) |
|
|
|
|
err = -ENOBUFS; |
|
|
|
|
else |
|
|
|
|
err = skb_linearize(skb); |
|
|
|
|
} else { |
|
|
|
|
err = !pskb_may_pull(skb, ieee80211_hdrlen(fc)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (err) { |
|
|
|
|
dev_kfree_skb(skb); |
|
|
|
|