diff options
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 158 |
1 files changed, 83 insertions, 75 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7cffaa046b33..0c08d1e60cb5 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -317,30 +317,30 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
317 | if (!atomic_read(&tx->sdata->bss->num_sta_ps)) | 317 | if (!atomic_read(&tx->sdata->bss->num_sta_ps)) |
318 | return TX_CONTINUE; | 318 | return TX_CONTINUE; |
319 | 319 | ||
320 | /* buffered in hardware */ | ||
321 | if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) { | ||
322 | info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; | ||
323 | |||
324 | return TX_CONTINUE; | ||
325 | } | ||
326 | |||
320 | /* buffered in mac80211 */ | 327 | /* buffered in mac80211 */ |
321 | if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) { | 328 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) |
322 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) | 329 | purge_old_ps_buffers(tx->local); |
323 | purge_old_ps_buffers(tx->local); | 330 | |
324 | if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= | 331 | if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) { |
325 | AP_MAX_BC_BUFFER) { | ||
326 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 332 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
327 | if (net_ratelimit()) { | 333 | if (net_ratelimit()) |
328 | printk(KERN_DEBUG "%s: BC TX buffer full - " | 334 | printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n", |
329 | "dropping the oldest frame\n", | 335 | tx->dev->name); |
330 | tx->dev->name); | ||
331 | } | ||
332 | #endif | 336 | #endif |
333 | dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); | 337 | dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); |
334 | } else | 338 | } else |
335 | tx->local->total_ps_buffered++; | 339 | tx->local->total_ps_buffered++; |
336 | skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); | ||
337 | return TX_QUEUED; | ||
338 | } | ||
339 | 340 | ||
340 | /* buffered in hardware */ | 341 | skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); |
341 | info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; | ||
342 | 342 | ||
343 | return TX_CONTINUE; | 343 | return TX_QUEUED; |
344 | } | 344 | } |
345 | 345 | ||
346 | static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, | 346 | static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, |
@@ -700,7 +700,6 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | |||
700 | /* for pure STA mode without beacons, we can do it */ | 700 | /* for pure STA mode without beacons, we can do it */ |
701 | hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); | 701 | hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); |
702 | tx->sdata->sequence_number += 0x10; | 702 | tx->sdata->sequence_number += 0x10; |
703 | tx->sdata->sequence_number &= IEEE80211_SCTL_SEQ; | ||
704 | return TX_CONTINUE; | 703 | return TX_CONTINUE; |
705 | } | 704 | } |
706 | 705 | ||
@@ -844,6 +843,23 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
844 | } | 843 | } |
845 | 844 | ||
846 | static ieee80211_tx_result debug_noinline | 845 | static ieee80211_tx_result debug_noinline |
846 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | ||
847 | { | ||
848 | struct sk_buff *skb = tx->skb; | ||
849 | |||
850 | if (!tx->sta) | ||
851 | return TX_CONTINUE; | ||
852 | |||
853 | tx->sta->tx_packets++; | ||
854 | do { | ||
855 | tx->sta->tx_fragments++; | ||
856 | tx->sta->tx_bytes += skb->len; | ||
857 | } while ((skb = skb->next)); | ||
858 | |||
859 | return TX_CONTINUE; | ||
860 | } | ||
861 | |||
862 | static ieee80211_tx_result debug_noinline | ||
847 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | 863 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) |
848 | { | 864 | { |
849 | if (!tx->key) | 865 | if (!tx->key) |
@@ -887,23 +903,6 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) | |||
887 | return TX_CONTINUE; | 903 | return TX_CONTINUE; |
888 | } | 904 | } |
889 | 905 | ||
890 | static ieee80211_tx_result debug_noinline | ||
891 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | ||
892 | { | ||
893 | struct sk_buff *skb = tx->skb; | ||
894 | |||
895 | if (!tx->sta) | ||
896 | return TX_CONTINUE; | ||
897 | |||
898 | tx->sta->tx_packets++; | ||
899 | do { | ||
900 | tx->sta->tx_fragments++; | ||
901 | tx->sta->tx_bytes += skb->len; | ||
902 | } while ((skb = skb->next)); | ||
903 | |||
904 | return TX_CONTINUE; | ||
905 | } | ||
906 | |||
907 | /* actual transmit path */ | 906 | /* actual transmit path */ |
908 | 907 | ||
909 | /* | 908 | /* |
@@ -1154,6 +1153,9 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1154 | next = skb->next; | 1153 | next = skb->next; |
1155 | len = skb->len; | 1154 | len = skb->len; |
1156 | 1155 | ||
1156 | if (next) | ||
1157 | info->flags |= IEEE80211_TX_CTL_MORE_FRAMES; | ||
1158 | |||
1157 | sdata = vif_to_sdata(info->control.vif); | 1159 | sdata = vif_to_sdata(info->control.vif); |
1158 | 1160 | ||
1159 | switch (sdata->vif.type) { | 1161 | switch (sdata->vif.type) { |
@@ -1210,9 +1212,9 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1210 | CALL_TXH(ieee80211_tx_h_sequence) | 1212 | CALL_TXH(ieee80211_tx_h_sequence) |
1211 | CALL_TXH(ieee80211_tx_h_fragment) | 1213 | CALL_TXH(ieee80211_tx_h_fragment) |
1212 | /* handlers after fragment must be aware of tx info fragmentation! */ | 1214 | /* handlers after fragment must be aware of tx info fragmentation! */ |
1215 | CALL_TXH(ieee80211_tx_h_stats) | ||
1213 | CALL_TXH(ieee80211_tx_h_encrypt) | 1216 | CALL_TXH(ieee80211_tx_h_encrypt) |
1214 | CALL_TXH(ieee80211_tx_h_calculate_duration) | 1217 | CALL_TXH(ieee80211_tx_h_calculate_duration) |
1215 | CALL_TXH(ieee80211_tx_h_stats) | ||
1216 | #undef CALL_TXH | 1218 | #undef CALL_TXH |
1217 | 1219 | ||
1218 | txh_done: | 1220 | txh_done: |
@@ -1410,16 +1412,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1410 | 1412 | ||
1411 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | 1413 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; |
1412 | 1414 | ||
1413 | if (ieee80211_vif_is_mesh(&sdata->vif) && | 1415 | if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { |
1414 | ieee80211_is_data(hdr->frame_control)) { | ||
1415 | if (is_multicast_ether_addr(hdr->addr3)) | ||
1416 | memcpy(hdr->addr1, hdr->addr3, ETH_ALEN); | ||
1417 | else | ||
1418 | if (mesh_nexthop_lookup(skb, sdata)) { | ||
1419 | dev_put(sdata->dev); | ||
1420 | return; | ||
1421 | } | ||
1422 | } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { | ||
1423 | int hdrlen; | 1416 | int hdrlen; |
1424 | u16 len_rthdr; | 1417 | u16 len_rthdr; |
1425 | 1418 | ||
@@ -1476,6 +1469,15 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1476 | 1469 | ||
1477 | info->control.vif = &sdata->vif; | 1470 | info->control.vif = &sdata->vif; |
1478 | 1471 | ||
1472 | if (ieee80211_vif_is_mesh(&sdata->vif) && | ||
1473 | ieee80211_is_data(hdr->frame_control) && | ||
1474 | !is_multicast_ether_addr(hdr->addr1)) | ||
1475 | if (mesh_nexthop_lookup(skb, sdata)) { | ||
1476 | /* skb queued: don't free */ | ||
1477 | dev_put(sdata->dev); | ||
1478 | return; | ||
1479 | } | ||
1480 | |||
1479 | ieee80211_select_queue(local, skb); | 1481 | ieee80211_select_queue(local, skb); |
1480 | ieee80211_tx(sdata, skb, false); | 1482 | ieee80211_tx(sdata, skb, false); |
1481 | dev_put(sdata->dev); | 1483 | dev_put(sdata->dev); |
@@ -1617,52 +1619,58 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1617 | break; | 1619 | break; |
1618 | #ifdef CONFIG_MAC80211_MESH | 1620 | #ifdef CONFIG_MAC80211_MESH |
1619 | case NL80211_IFTYPE_MESH_POINT: | 1621 | case NL80211_IFTYPE_MESH_POINT: |
1620 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | ||
1621 | if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { | 1622 | if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { |
1622 | /* Do not send frames with mesh_ttl == 0 */ | 1623 | /* Do not send frames with mesh_ttl == 0 */ |
1623 | sdata->u.mesh.mshstats.dropped_frames_ttl++; | 1624 | sdata->u.mesh.mshstats.dropped_frames_ttl++; |
1624 | ret = NETDEV_TX_OK; | 1625 | ret = NETDEV_TX_OK; |
1625 | goto fail; | 1626 | goto fail; |
1626 | } | 1627 | } |
1627 | memset(&mesh_hdr, 0, sizeof(mesh_hdr)); | ||
1628 | 1628 | ||
1629 | if (compare_ether_addr(dev->dev_addr, | 1629 | if (compare_ether_addr(dev->dev_addr, |
1630 | skb->data + ETH_ALEN) == 0) { | 1630 | skb->data + ETH_ALEN) == 0) { |
1631 | /* RA TA DA SA */ | 1631 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, |
1632 | memset(hdr.addr1, 0, ETH_ALEN); | 1632 | skb->data, skb->data + ETH_ALEN); |
1633 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | 1633 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, |
1634 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1634 | sdata, NULL, NULL, NULL); |
1635 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
1636 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata); | ||
1637 | } else { | 1635 | } else { |
1638 | /* packet from other interface */ | 1636 | /* packet from other interface */ |
1639 | struct mesh_path *mppath; | 1637 | struct mesh_path *mppath; |
1638 | int is_mesh_mcast = 1; | ||
1639 | char *mesh_da; | ||
1640 | 1640 | ||
1641 | memset(hdr.addr1, 0, ETH_ALEN); | 1641 | rcu_read_lock(); |
1642 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
1643 | memcpy(hdr.addr4, dev->dev_addr, ETH_ALEN); | ||
1644 | |||
1645 | if (is_multicast_ether_addr(skb->data)) | 1642 | if (is_multicast_ether_addr(skb->data)) |
1646 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1643 | /* DA TA mSA AE:SA */ |
1644 | mesh_da = skb->data; | ||
1647 | else { | 1645 | else { |
1648 | rcu_read_lock(); | ||
1649 | mppath = mpp_path_lookup(skb->data, sdata); | 1646 | mppath = mpp_path_lookup(skb->data, sdata); |
1650 | if (mppath) | 1647 | if (mppath) { |
1651 | memcpy(hdr.addr3, mppath->mpp, ETH_ALEN); | 1648 | /* RA TA mDA mSA AE:DA SA */ |
1652 | else | 1649 | mesh_da = mppath->mpp; |
1653 | memset(hdr.addr3, 0xff, ETH_ALEN); | 1650 | is_mesh_mcast = 0; |
1654 | rcu_read_unlock(); | 1651 | } else |
1652 | /* DA TA mSA AE:SA */ | ||
1653 | mesh_da = dev->broadcast; | ||
1655 | } | 1654 | } |
1655 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, | ||
1656 | mesh_da, dev->dev_addr); | ||
1657 | rcu_read_unlock(); | ||
1658 | if (is_mesh_mcast) | ||
1659 | meshhdrlen = | ||
1660 | ieee80211_new_mesh_header(&mesh_hdr, | ||
1661 | sdata, | ||
1662 | skb->data + ETH_ALEN, | ||
1663 | NULL, | ||
1664 | NULL); | ||
1665 | else | ||
1666 | meshhdrlen = | ||
1667 | ieee80211_new_mesh_header(&mesh_hdr, | ||
1668 | sdata, | ||
1669 | NULL, | ||
1670 | skb->data, | ||
1671 | skb->data + ETH_ALEN); | ||
1656 | 1672 | ||
1657 | mesh_hdr.flags |= MESH_FLAGS_AE_A5_A6; | ||
1658 | mesh_hdr.ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; | ||
1659 | put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &mesh_hdr.seqnum); | ||
1660 | memcpy(mesh_hdr.eaddr1, skb->data, ETH_ALEN); | ||
1661 | memcpy(mesh_hdr.eaddr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
1662 | sdata->u.mesh.mesh_seqnum++; | ||
1663 | meshhdrlen = 18; | ||
1664 | } | 1673 | } |
1665 | hdrlen = 30; | ||
1666 | break; | 1674 | break; |
1667 | #endif | 1675 | #endif |
1668 | case NL80211_IFTYPE_STATION: | 1676 | case NL80211_IFTYPE_STATION: |