aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ieee80211.c
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/ieee80211.c
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/ieee80211.c')
-rw-r--r--net/mac80211/ieee80211.c67
1 files changed, 38 insertions, 29 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