diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/tx.c | 64 | ||||
-rw-r--r-- | net/mac80211/util.c | 37 |
2 files changed, 85 insertions, 16 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 698c8233e6b3..c12f361d7185 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -624,7 +624,14 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | |||
624 | u8 *qc; | 624 | u8 *qc; |
625 | int tid; | 625 | int tid; |
626 | 626 | ||
627 | /* only for injected frames */ | 627 | /* |
628 | * Packet injection may want to control the sequence | ||
629 | * number, if we have no matching interface then we | ||
630 | * neither assign one ourselves nor ask the driver to. | ||
631 | */ | ||
632 | if (unlikely(!info->control.vif)) | ||
633 | return TX_CONTINUE; | ||
634 | |||
628 | if (unlikely(ieee80211_is_ctl(hdr->frame_control))) | 635 | if (unlikely(ieee80211_is_ctl(hdr->frame_control))) |
629 | return TX_CONTINUE; | 636 | return TX_CONTINUE; |
630 | 637 | ||
@@ -849,7 +856,6 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
849 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; | 856 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; |
850 | 857 | ||
851 | skb->do_not_encrypt = 1; | 858 | skb->do_not_encrypt = 1; |
852 | info->flags |= IEEE80211_TX_CTL_INJECTED; | ||
853 | tx->flags &= ~IEEE80211_TX_FRAGMENTED; | 859 | tx->flags &= ~IEEE80211_TX_FRAGMENTED; |
854 | 860 | ||
855 | /* | 861 | /* |
@@ -981,7 +987,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, | |||
981 | 987 | ||
982 | /* process and remove the injection radiotap header */ | 988 | /* process and remove the injection radiotap header */ |
983 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 989 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
984 | if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { | 990 | if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) { |
985 | if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP) | 991 | if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP) |
986 | return TX_DROP; | 992 | return TX_DROP; |
987 | 993 | ||
@@ -1300,6 +1306,11 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, | |||
1300 | struct ieee80211_sub_if_data *osdata; | 1306 | struct ieee80211_sub_if_data *osdata; |
1301 | int headroom; | 1307 | int headroom; |
1302 | bool may_encrypt; | 1308 | bool may_encrypt; |
1309 | enum { | ||
1310 | NOT_MONITOR, | ||
1311 | FOUND_SDATA, | ||
1312 | UNKNOWN_ADDRESS, | ||
1313 | } monitor_iface = NOT_MONITOR; | ||
1303 | int ret; | 1314 | int ret; |
1304 | 1315 | ||
1305 | if (skb->iif) | 1316 | if (skb->iif) |
@@ -1335,6 +1346,50 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, | |||
1335 | IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh, | 1346 | IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh, |
1336 | fwded_frames); | 1347 | fwded_frames); |
1337 | } | 1348 | } |
1349 | } else if (unlikely(osdata->vif.type == NL80211_IFTYPE_MONITOR)) { | ||
1350 | struct ieee80211_sub_if_data *sdata; | ||
1351 | struct ieee80211_local *local = osdata->local; | ||
1352 | struct ieee80211_hdr *hdr; | ||
1353 | int hdrlen; | ||
1354 | u16 len_rthdr; | ||
1355 | |||
1356 | info->flags |= IEEE80211_TX_CTL_INJECTED; | ||
1357 | monitor_iface = UNKNOWN_ADDRESS; | ||
1358 | |||
1359 | len_rthdr = ieee80211_get_radiotap_len(skb->data); | ||
1360 | hdr = (struct ieee80211_hdr *)skb->data + len_rthdr; | ||
1361 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
1362 | |||
1363 | /* check the header is complete in the frame */ | ||
1364 | if (likely(skb->len >= len_rthdr + hdrlen)) { | ||
1365 | /* | ||
1366 | * We process outgoing injected frames that have a | ||
1367 | * local address we handle as though they are our | ||
1368 | * own frames. | ||
1369 | * This code here isn't entirely correct, the local | ||
1370 | * MAC address is not necessarily enough to find | ||
1371 | * the interface to use; for that proper VLAN/WDS | ||
1372 | * support we will need a different mechanism. | ||
1373 | */ | ||
1374 | |||
1375 | rcu_read_lock(); | ||
1376 | list_for_each_entry_rcu(sdata, &local->interfaces, | ||
1377 | list) { | ||
1378 | if (!netif_running(sdata->dev)) | ||
1379 | continue; | ||
1380 | if (compare_ether_addr(sdata->dev->dev_addr, | ||
1381 | hdr->addr2)) { | ||
1382 | dev_hold(sdata->dev); | ||
1383 | dev_put(odev); | ||
1384 | osdata = sdata; | ||
1385 | odev = osdata->dev; | ||
1386 | skb->iif = sdata->dev->ifindex; | ||
1387 | monitor_iface = FOUND_SDATA; | ||
1388 | break; | ||
1389 | } | ||
1390 | } | ||
1391 | rcu_read_unlock(); | ||
1392 | } | ||
1338 | } | 1393 | } |
1339 | 1394 | ||
1340 | may_encrypt = !skb->do_not_encrypt; | 1395 | may_encrypt = !skb->do_not_encrypt; |
@@ -1355,7 +1410,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, | |||
1355 | osdata = container_of(osdata->bss, | 1410 | osdata = container_of(osdata->bss, |
1356 | struct ieee80211_sub_if_data, | 1411 | struct ieee80211_sub_if_data, |
1357 | u.ap); | 1412 | u.ap); |
1358 | info->control.vif = &osdata->vif; | 1413 | if (likely(monitor_iface != UNKNOWN_ADDRESS)) |
1414 | info->control.vif = &osdata->vif; | ||
1359 | ret = ieee80211_tx(odev, skb); | 1415 | ret = ieee80211_tx(odev, skb); |
1360 | dev_put(odev); | 1416 | dev_put(odev); |
1361 | 1417 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 6eb222369bcb..f32561ec224c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -231,16 +231,21 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, | |||
231 | struct ieee80211_rate *rate) | 231 | struct ieee80211_rate *rate) |
232 | { | 232 | { |
233 | struct ieee80211_local *local = hw_to_local(hw); | 233 | struct ieee80211_local *local = hw_to_local(hw); |
234 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 234 | struct ieee80211_sub_if_data *sdata; |
235 | u16 dur; | 235 | u16 dur; |
236 | int erp; | 236 | int erp; |
237 | bool short_preamble = false; | ||
237 | 238 | ||
238 | erp = 0; | 239 | erp = 0; |
239 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) | 240 | if (vif) { |
240 | erp = rate->flags & IEEE80211_RATE_ERP_G; | 241 | sdata = vif_to_sdata(vif); |
242 | short_preamble = sdata->bss_conf.use_short_preamble; | ||
243 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) | ||
244 | erp = rate->flags & IEEE80211_RATE_ERP_G; | ||
245 | } | ||
241 | 246 | ||
242 | dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, | 247 | dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, |
243 | sdata->bss_conf.use_short_preamble); | 248 | short_preamble); |
244 | 249 | ||
245 | return cpu_to_le16(dur); | 250 | return cpu_to_le16(dur); |
246 | } | 251 | } |
@@ -252,7 +257,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, | |||
252 | { | 257 | { |
253 | struct ieee80211_local *local = hw_to_local(hw); | 258 | struct ieee80211_local *local = hw_to_local(hw); |
254 | struct ieee80211_rate *rate; | 259 | struct ieee80211_rate *rate; |
255 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 260 | struct ieee80211_sub_if_data *sdata; |
256 | bool short_preamble; | 261 | bool short_preamble; |
257 | int erp; | 262 | int erp; |
258 | u16 dur; | 263 | u16 dur; |
@@ -260,13 +265,17 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, | |||
260 | 265 | ||
261 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 266 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
262 | 267 | ||
263 | short_preamble = sdata->bss_conf.use_short_preamble; | 268 | short_preamble = false; |
264 | 269 | ||
265 | rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; | 270 | rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; |
266 | 271 | ||
267 | erp = 0; | 272 | erp = 0; |
268 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) | 273 | if (vif) { |
269 | erp = rate->flags & IEEE80211_RATE_ERP_G; | 274 | sdata = vif_to_sdata(vif); |
275 | short_preamble = sdata->bss_conf.use_short_preamble; | ||
276 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) | ||
277 | erp = rate->flags & IEEE80211_RATE_ERP_G; | ||
278 | } | ||
270 | 279 | ||
271 | /* CTS duration */ | 280 | /* CTS duration */ |
272 | dur = ieee80211_frame_duration(local, 10, rate->bitrate, | 281 | dur = ieee80211_frame_duration(local, 10, rate->bitrate, |
@@ -289,7 +298,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, | |||
289 | { | 298 | { |
290 | struct ieee80211_local *local = hw_to_local(hw); | 299 | struct ieee80211_local *local = hw_to_local(hw); |
291 | struct ieee80211_rate *rate; | 300 | struct ieee80211_rate *rate; |
292 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 301 | struct ieee80211_sub_if_data *sdata; |
293 | bool short_preamble; | 302 | bool short_preamble; |
294 | int erp; | 303 | int erp; |
295 | u16 dur; | 304 | u16 dur; |
@@ -297,12 +306,16 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, | |||
297 | 306 | ||
298 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 307 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
299 | 308 | ||
300 | short_preamble = sdata->bss_conf.use_short_preamble; | 309 | short_preamble = false; |
301 | 310 | ||
302 | rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; | 311 | rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx]; |
303 | erp = 0; | 312 | erp = 0; |
304 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) | 313 | if (vif) { |
305 | erp = rate->flags & IEEE80211_RATE_ERP_G; | 314 | sdata = vif_to_sdata(vif); |
315 | short_preamble = sdata->bss_conf.use_short_preamble; | ||
316 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) | ||
317 | erp = rate->flags & IEEE80211_RATE_ERP_G; | ||
318 | } | ||
306 | 319 | ||
307 | /* Data frame duration */ | 320 | /* Data frame duration */ |
308 | dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, | 321 | dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, |