diff options
author | Michael Wu <flamingice@sourmilk.net> | 2008-01-31 13:48:27 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-02-29 15:37:03 -0500 |
commit | 3d30d949cf3f9763393f3457721bca3ac2426e42 (patch) | |
tree | d80d1490f8a5263d74b4ed105835a7ef21eb6b80 /net/mac80211/rx.c | |
parent | 8944b79fe9b1fe249c599e7e51f1bfad539aab6d (diff) |
mac80211: Add cooked monitor mode support
This adds "cooked" monitor mode to mac80211. A monitor interface
in "cooked" mode will see all frames that mac80211 has not used
internally.
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 87 |
1 files changed, 86 insertions, 1 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3a3112f17832..b1fc112152c9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -223,6 +223,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
223 | if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR) | 223 | if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR) |
224 | continue; | 224 | continue; |
225 | 225 | ||
226 | if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) | ||
227 | continue; | ||
228 | |||
226 | if (prev_dev) { | 229 | if (prev_dev) { |
227 | skb2 = skb_clone(skb, GFP_ATOMIC); | 230 | skb2 = skb_clone(skb, GFP_ATOMIC); |
228 | if (skb2) { | 231 | if (skb2) { |
@@ -1520,6 +1523,86 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, | |||
1520 | rx->skb = NULL; | 1523 | rx->skb = NULL; |
1521 | } | 1524 | } |
1522 | 1525 | ||
1526 | static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx) | ||
1527 | { | ||
1528 | struct ieee80211_sub_if_data *sdata; | ||
1529 | struct ieee80211_local *local = rx->local; | ||
1530 | struct ieee80211_rtap_hdr { | ||
1531 | struct ieee80211_radiotap_header hdr; | ||
1532 | u8 flags; | ||
1533 | u8 rate; | ||
1534 | __le16 chan_freq; | ||
1535 | __le16 chan_flags; | ||
1536 | } __attribute__ ((packed)) *rthdr; | ||
1537 | struct sk_buff *skb = rx->skb, *skb2; | ||
1538 | struct net_device *prev_dev = NULL; | ||
1539 | struct ieee80211_rx_status *status = rx->u.rx.status; | ||
1540 | |||
1541 | if (rx->flags & IEEE80211_TXRXD_RX_CMNTR_REPORTED) | ||
1542 | goto out_free_skb; | ||
1543 | |||
1544 | if (skb_headroom(skb) < sizeof(*rthdr) && | ||
1545 | pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) | ||
1546 | goto out_free_skb; | ||
1547 | |||
1548 | rthdr = (void *)skb_push(skb, sizeof(*rthdr)); | ||
1549 | memset(rthdr, 0, sizeof(*rthdr)); | ||
1550 | rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); | ||
1551 | rthdr->hdr.it_present = | ||
1552 | cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | | ||
1553 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
1554 | (1 << IEEE80211_RADIOTAP_CHANNEL)); | ||
1555 | |||
1556 | rthdr->rate = rx->u.rx.rate->bitrate / 5; | ||
1557 | rthdr->chan_freq = cpu_to_le16(status->freq); | ||
1558 | |||
1559 | if (status->band == IEEE80211_BAND_5GHZ) | ||
1560 | rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
1561 | IEEE80211_CHAN_5GHZ); | ||
1562 | else | ||
1563 | rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_DYN | | ||
1564 | IEEE80211_CHAN_2GHZ); | ||
1565 | |||
1566 | skb_set_mac_header(skb, 0); | ||
1567 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1568 | skb->pkt_type = PACKET_OTHERHOST; | ||
1569 | skb->protocol = htons(ETH_P_802_2); | ||
1570 | |||
1571 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
1572 | if (!netif_running(sdata->dev)) | ||
1573 | continue; | ||
1574 | |||
1575 | if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || | ||
1576 | !(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)) | ||
1577 | continue; | ||
1578 | |||
1579 | if (prev_dev) { | ||
1580 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
1581 | if (skb2) { | ||
1582 | skb2->dev = prev_dev; | ||
1583 | netif_rx(skb2); | ||
1584 | } | ||
1585 | } | ||
1586 | |||
1587 | prev_dev = sdata->dev; | ||
1588 | sdata->dev->stats.rx_packets++; | ||
1589 | sdata->dev->stats.rx_bytes += skb->len; | ||
1590 | } | ||
1591 | |||
1592 | if (prev_dev) { | ||
1593 | skb->dev = prev_dev; | ||
1594 | netif_rx(skb); | ||
1595 | skb = NULL; | ||
1596 | } else | ||
1597 | goto out_free_skb; | ||
1598 | |||
1599 | rx->flags |= IEEE80211_TXRXD_RX_CMNTR_REPORTED; | ||
1600 | return; | ||
1601 | |||
1602 | out_free_skb: | ||
1603 | dev_kfree_skb(skb); | ||
1604 | } | ||
1605 | |||
1523 | typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *); | 1606 | typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *); |
1524 | static ieee80211_rx_handler ieee80211_rx_handlers[] = | 1607 | static ieee80211_rx_handler ieee80211_rx_handlers[] = |
1525 | { | 1608 | { |
@@ -1574,9 +1657,11 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, | |||
1574 | } | 1657 | } |
1575 | 1658 | ||
1576 | switch (res) { | 1659 | switch (res) { |
1660 | case RX_CONTINUE: | ||
1577 | case RX_DROP_MONITOR: | 1661 | case RX_DROP_MONITOR: |
1662 | ieee80211_rx_cooked_monitor(rx); | ||
1663 | break; | ||
1578 | case RX_DROP_UNUSABLE: | 1664 | case RX_DROP_UNUSABLE: |
1579 | case RX_CONTINUE: | ||
1580 | dev_kfree_skb(rx->skb); | 1665 | dev_kfree_skb(rx->skb); |
1581 | break; | 1666 | break; |
1582 | } | 1667 | } |