diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-10-07 08:01:23 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-10-11 16:41:17 -0400 |
commit | 5d9cf4a5d7d46e412bc43b20c79743d81a0328cb (patch) | |
tree | 5481f798c9407c16ee7958b24559f23d8808a888 /net/mac80211/tx.c | |
parent | d9cd48f95c5ba9e5f1d5287ed74630607471031c (diff) |
mac80211: optimise monitor xmit
Since the only way the interface can be a monitor
interface in ieee80211_xmit() is because the frame
came from ieee80211_monitor_start_xmit() we can
move all the code there.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 108 |
1 files changed, 49 insertions, 59 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ad2ee4a90ec4..84ebc3f89123 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1539,55 +1539,11 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
1539 | struct ieee80211_local *local = sdata->local; | 1539 | struct ieee80211_local *local = sdata->local; |
1540 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1540 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1541 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 1541 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
1542 | struct ieee80211_sub_if_data *tmp_sdata; | ||
1543 | int headroom; | 1542 | int headroom; |
1544 | bool may_encrypt; | 1543 | bool may_encrypt; |
1545 | 1544 | ||
1546 | rcu_read_lock(); | 1545 | rcu_read_lock(); |
1547 | 1546 | ||
1548 | if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { | ||
1549 | int hdrlen; | ||
1550 | u16 len_rthdr; | ||
1551 | |||
1552 | info->flags |= IEEE80211_TX_CTL_INJECTED | | ||
1553 | IEEE80211_TX_INTFL_HAS_RADIOTAP; | ||
1554 | |||
1555 | len_rthdr = ieee80211_get_radiotap_len(skb->data); | ||
1556 | hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); | ||
1557 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
1558 | |||
1559 | /* check the header is complete in the frame */ | ||
1560 | if (likely(skb->len >= len_rthdr + hdrlen)) { | ||
1561 | /* | ||
1562 | * We process outgoing injected frames that have a | ||
1563 | * local address we handle as though they are our | ||
1564 | * own frames. | ||
1565 | * This code here isn't entirely correct, the local | ||
1566 | * MAC address is not necessarily enough to find | ||
1567 | * the interface to use; for that proper VLAN/WDS | ||
1568 | * support we will need a different mechanism. | ||
1569 | */ | ||
1570 | |||
1571 | list_for_each_entry_rcu(tmp_sdata, &local->interfaces, | ||
1572 | list) { | ||
1573 | if (!ieee80211_sdata_running(tmp_sdata)) | ||
1574 | continue; | ||
1575 | if (tmp_sdata->vif.type == | ||
1576 | NL80211_IFTYPE_MONITOR || | ||
1577 | tmp_sdata->vif.type == | ||
1578 | NL80211_IFTYPE_AP_VLAN || | ||
1579 | tmp_sdata->vif.type == | ||
1580 | NL80211_IFTYPE_WDS) | ||
1581 | continue; | ||
1582 | if (compare_ether_addr(tmp_sdata->vif.addr, | ||
1583 | hdr->addr2) == 0) { | ||
1584 | sdata = tmp_sdata; | ||
1585 | break; | ||
1586 | } | ||
1587 | } | ||
1588 | } | ||
1589 | } | ||
1590 | |||
1591 | may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT); | 1547 | may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT); |
1592 | 1548 | ||
1593 | headroom = local->tx_headroom; | 1549 | headroom = local->tx_headroom; |
@@ -1628,8 +1584,9 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1628 | (struct ieee80211_radiotap_header *)skb->data; | 1584 | (struct ieee80211_radiotap_header *)skb->data; |
1629 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1585 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1630 | struct ieee80211_hdr *hdr; | 1586 | struct ieee80211_hdr *hdr; |
1587 | struct ieee80211_sub_if_data *tmp_sdata, *sdata; | ||
1631 | u16 len_rthdr; | 1588 | u16 len_rthdr; |
1632 | u8 *payload; | 1589 | int hdrlen; |
1633 | 1590 | ||
1634 | /* | 1591 | /* |
1635 | * Frame injection is not allowed if beaconing is not allowed | 1592 | * Frame injection is not allowed if beaconing is not allowed |
@@ -1680,30 +1637,63 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1680 | skb_set_network_header(skb, len_rthdr); | 1637 | skb_set_network_header(skb, len_rthdr); |
1681 | skb_set_transport_header(skb, len_rthdr); | 1638 | skb_set_transport_header(skb, len_rthdr); |
1682 | 1639 | ||
1640 | if (skb->len < len_rthdr + 2) | ||
1641 | goto fail; | ||
1642 | |||
1643 | hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); | ||
1644 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
1645 | |||
1646 | if (skb->len < len_rthdr + hdrlen) | ||
1647 | goto fail; | ||
1648 | |||
1683 | /* | 1649 | /* |
1684 | * Initialize skb->protocol if the injected frame is a data frame | 1650 | * Initialize skb->protocol if the injected frame is a data frame |
1685 | * carrying a rfc1042 header | 1651 | * carrying a rfc1042 header |
1686 | */ | 1652 | */ |
1687 | if (skb->len > len_rthdr + 2) { | 1653 | if (ieee80211_is_data(hdr->frame_control) && |
1688 | hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); | 1654 | skb->len >= len_rthdr + hdrlen + sizeof(rfc1042_header) + 2) { |
1689 | if (ieee80211_is_data(hdr->frame_control) && | 1655 | u8 *payload = (u8 *)hdr + hdrlen; |
1690 | skb->len >= len_rthdr + | 1656 | |
1691 | ieee80211_hdrlen(hdr->frame_control) + | 1657 | if (compare_ether_addr(payload, rfc1042_header) == 0) |
1692 | sizeof(rfc1042_header) + 2) { | 1658 | skb->protocol = cpu_to_be16((payload[6] << 8) | |
1693 | payload = (u8 *)hdr + | 1659 | payload[7]); |
1694 | ieee80211_hdrlen(hdr->frame_control); | ||
1695 | if (compare_ether_addr(payload, rfc1042_header) == 0) | ||
1696 | skb->protocol = cpu_to_be16((payload[6] << 8) | | ||
1697 | payload[7]); | ||
1698 | } | ||
1699 | } | 1660 | } |
1700 | 1661 | ||
1701 | memset(info, 0, sizeof(*info)); | 1662 | memset(info, 0, sizeof(*info)); |
1702 | 1663 | ||
1703 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | 1664 | info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS | |
1665 | IEEE80211_TX_CTL_INJECTED | | ||
1666 | IEEE80211_TX_INTFL_HAS_RADIOTAP; | ||
1667 | |||
1668 | rcu_read_lock(); | ||
1669 | |||
1670 | /* | ||
1671 | * We process outgoing injected frames that have a local address | ||
1672 | * we handle as though they are non-injected frames. | ||
1673 | * This code here isn't entirely correct, the local MAC address | ||
1674 | * isn't always enough to find the interface to use; for proper | ||
1675 | * VLAN/WDS support we will need a different mechanism (which | ||
1676 | * likely isn't going to be monitor interfaces). | ||
1677 | */ | ||
1678 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1679 | |||
1680 | list_for_each_entry_rcu(tmp_sdata, &local->interfaces, list) { | ||
1681 | if (!ieee80211_sdata_running(tmp_sdata)) | ||
1682 | continue; | ||
1683 | if (tmp_sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||
1684 | tmp_sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | ||
1685 | tmp_sdata->vif.type == NL80211_IFTYPE_WDS) | ||
1686 | continue; | ||
1687 | if (compare_ether_addr(tmp_sdata->vif.addr, hdr->addr2) == 0) { | ||
1688 | sdata = tmp_sdata; | ||
1689 | break; | ||
1690 | } | ||
1691 | } | ||
1704 | 1692 | ||
1705 | /* pass the radiotap header up to xmit */ | 1693 | /* pass the radiotap header up to xmit */ |
1706 | ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb); | 1694 | ieee80211_xmit(sdata, skb); |
1695 | rcu_read_unlock(); | ||
1696 | |||
1707 | return NETDEV_TX_OK; | 1697 | return NETDEV_TX_OK; |
1708 | 1698 | ||
1709 | fail: | 1699 | fail: |