aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorMichael Wu <flamingice@sourmilk.net>2008-01-31 13:48:27 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-02-29 15:37:03 -0500
commit3d30d949cf3f9763393f3457721bca3ac2426e42 (patch)
treed80d1490f8a5263d74b4ed105835a7ef21eb6b80 /net/mac80211
parent8944b79fe9b1fe249c599e7e51f1bfad539aab6d (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')
-rw-r--r--net/mac80211/ieee80211.c67
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/rx.c87
3 files changed, 126 insertions, 31 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 78fd91895c80..91f06c3f4a7c 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -239,6 +239,11 @@ static int ieee80211_open(struct net_device *dev)
239 /* no need to tell driver */ 239 /* no need to tell driver */
240 break; 240 break;
241 case IEEE80211_IF_TYPE_MNTR: 241 case IEEE80211_IF_TYPE_MNTR:
242 if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
243 local->cooked_mntrs++;
244 break;
245 }
246
242 /* must be before the call to ieee80211_configure_filter */ 247 /* must be before the call to ieee80211_configure_filter */
243 local->monitors++; 248 local->monitors++;
244 if (local->monitors == 1) 249 if (local->monitors == 1)
@@ -370,6 +375,11 @@ static int ieee80211_stop(struct net_device *dev)
370 /* no need to tell driver */ 375 /* no need to tell driver */
371 break; 376 break;
372 case IEEE80211_IF_TYPE_MNTR: 377 case IEEE80211_IF_TYPE_MNTR:
378 if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
379 local->cooked_mntrs--;
380 break;
381 }
382
373 local->monitors--; 383 local->monitors--;
374 if (local->monitors == 0) 384 if (local->monitors == 0)
375 local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; 385 local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
@@ -1177,7 +1187,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
1177 u16 frag, type; 1187 u16 frag, type;
1178 struct ieee80211_tx_status_rtap_hdr *rthdr; 1188 struct ieee80211_tx_status_rtap_hdr *rthdr;
1179 struct ieee80211_sub_if_data *sdata; 1189 struct ieee80211_sub_if_data *sdata;
1180 int monitors; 1190 struct net_device *prev_dev = NULL;
1181 1191
1182 if (!status) { 1192 if (!status) {
1183 printk(KERN_ERR 1193 printk(KERN_ERR
@@ -1290,7 +1300,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
1290 /* this was a transmitted frame, but now we want to reuse it */ 1300 /* this was a transmitted frame, but now we want to reuse it */
1291 skb_orphan(skb); 1301 skb_orphan(skb);
1292 1302
1293 if (!local->monitors) { 1303 /*
1304 * This is a bit racy but we can avoid a lot of work
1305 * with this test...
1306 */
1307 if (!local->monitors && !local->cooked_mntrs) {
1294 dev_kfree_skb(skb); 1308 dev_kfree_skb(skb);
1295 return; 1309 return;
1296 } 1310 }
@@ -1324,42 +1338,37 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
1324 1338
1325 rthdr->data_retries = status->retry_count; 1339 rthdr->data_retries = status->retry_count;
1326 1340
1341 /* XXX: is this sufficient for BPF? */
1342 skb_set_mac_header(skb, 0);
1343 skb->ip_summed = CHECKSUM_UNNECESSARY;
1344 skb->pkt_type = PACKET_OTHERHOST;
1345 skb->protocol = htons(ETH_P_802_2);
1346 memset(skb->cb, 0, sizeof(skb->cb));
1347
1327 rcu_read_lock(); 1348 rcu_read_lock();
1328 monitors = local->monitors;
1329 list_for_each_entry_rcu(sdata, &local->interfaces, list) { 1349 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
1330 /*
1331 * Using the monitors counter is possibly racy, but
1332 * if the value is wrong we simply either clone the skb
1333 * once too much or forget sending it to one monitor iface
1334 * The latter case isn't nice but fixing the race is much
1335 * more complicated.
1336 */
1337 if (!monitors || !skb)
1338 goto out;
1339
1340 if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) { 1350 if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) {
1341 if (!netif_running(sdata->dev)) 1351 if (!netif_running(sdata->dev))
1342 continue; 1352 continue;
1343 monitors--; 1353
1344 if (monitors) 1354 if (prev_dev) {
1345 skb2 = skb_clone(skb, GFP_ATOMIC); 1355 skb2 = skb_clone(skb, GFP_ATOMIC);
1346 else 1356 if (skb2) {
1347 skb2 = NULL; 1357 skb2->dev = prev_dev;
1348 skb->dev = sdata->dev; 1358 netif_rx(skb2);
1349 /* XXX: is this sufficient for BPF? */ 1359 }
1350 skb_set_mac_header(skb, 0); 1360 }
1351 skb->ip_summed = CHECKSUM_UNNECESSARY; 1361
1352 skb->pkt_type = PACKET_OTHERHOST; 1362 prev_dev = sdata->dev;
1353 skb->protocol = htons(ETH_P_802_2);
1354 memset(skb->cb, 0, sizeof(skb->cb));
1355 netif_rx(skb);
1356 skb = skb2;
1357 } 1363 }
1358 } 1364 }
1359 out: 1365 if (prev_dev) {
1366 skb->dev = prev_dev;
1367 netif_rx(skb);
1368 skb = NULL;
1369 }
1360 rcu_read_unlock(); 1370 rcu_read_unlock();
1361 if (skb) 1371 dev_kfree_skb(skb);
1362 dev_kfree_skb(skb);
1363} 1372}
1364EXPORT_SYMBOL(ieee80211_tx_status); 1373EXPORT_SYMBOL(ieee80211_tx_status);
1365 1374
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 1129a4299de7..1b4a4497030d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -131,6 +131,7 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
131#define IEEE80211_TXRXD_RXRA_MATCH BIT(5) 131#define IEEE80211_TXRXD_RXRA_MATCH BIT(5)
132#define IEEE80211_TXRXD_TX_INJECTED BIT(6) 132#define IEEE80211_TXRXD_TX_INJECTED BIT(6)
133#define IEEE80211_TXRXD_RX_AMSDU BIT(7) 133#define IEEE80211_TXRXD_RX_AMSDU BIT(7)
134#define IEEE80211_TXRXD_RX_CMNTR_REPORTED BIT(8)
134struct ieee80211_txrx_data { 135struct ieee80211_txrx_data {
135 struct sk_buff *skb; 136 struct sk_buff *skb;
136 struct net_device *dev; 137 struct net_device *dev;
@@ -419,7 +420,7 @@ struct ieee80211_local {
419 420
420 struct net_device *mdev; /* wmaster# - "master" 802.11 device */ 421 struct net_device *mdev; /* wmaster# - "master" 802.11 device */
421 int open_count; 422 int open_count;
422 int monitors; 423 int monitors, cooked_mntrs;
423 /* number of interfaces with corresponding FIF_ flags */ 424 /* number of interfaces with corresponding FIF_ flags */
424 int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; 425 int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
425 unsigned int filter_flags; /* FIF_* */ 426 unsigned int filter_flags; /* FIF_* */
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
1526static 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
1523typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *); 1606typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *);
1524static ieee80211_rx_handler ieee80211_rx_handlers[] = 1607static 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 }