diff options
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 64 |
1 files changed, 60 insertions, 4 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 | ||