diff options
| author | Stefan Rompf <stefan@loplof.de> | 2006-02-21 05:36:17 -0500 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2006-03-17 16:14:48 -0500 |
| commit | 15745a7dd1ac6bf1ef7959040f864c78a95aa35b (patch) | |
| tree | b9e95a75c83f2d1b5eba9af2a36cc9912e0188ee | |
| parent | 171e7b2f1f50f112d3ce8a829a3e79c5739b3132 (diff) | |
[PATCH] ipw2100: add radiotap headers to packtes captured in monitor mode
Signed-off-by: Stefan Rompf <stefan@loplof.de>
Signed-off-by: Andrea Merello <andreamrl at tiscali it>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
| -rw-r--r-- | drivers/net/wireless/ipw2100.c | 95 | ||||
| -rw-r--r-- | drivers/net/wireless/ipw2100.h | 4 |
2 files changed, 88 insertions, 11 deletions
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 84f63876bf75..d429fd576a66 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c | |||
| @@ -2390,15 +2390,6 @@ static void isr_rx(struct ipw2100_priv *priv, int i, | |||
| 2390 | IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); | 2390 | IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); |
| 2391 | return; | 2391 | return; |
| 2392 | } | 2392 | } |
| 2393 | #ifdef CONFIG_IPW2100_MONITOR | ||
| 2394 | if (unlikely(priv->ieee->iw_mode == IW_MODE_MONITOR && | ||
| 2395 | priv->config & CFG_CRC_CHECK && | ||
| 2396 | status->flags & IPW_STATUS_FLAG_CRC_ERROR)) { | ||
| 2397 | IPW_DEBUG_RX("CRC error in packet. Dropping.\n"); | ||
| 2398 | priv->ieee->stats.rx_errors++; | ||
| 2399 | return; | ||
| 2400 | } | ||
| 2401 | #endif | ||
| 2402 | 2393 | ||
| 2403 | if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR && | 2394 | if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR && |
| 2404 | !(priv->status & STATUS_ASSOCIATED))) { | 2395 | !(priv->status & STATUS_ASSOCIATED))) { |
| @@ -2446,6 +2437,88 @@ static void isr_rx(struct ipw2100_priv *priv, int i, | |||
| 2446 | priv->rx_queue.drv[i].host_addr = packet->dma_addr; | 2437 | priv->rx_queue.drv[i].host_addr = packet->dma_addr; |
| 2447 | } | 2438 | } |
| 2448 | 2439 | ||
| 2440 | #ifdef CONFIG_IPW2100_MONITOR | ||
| 2441 | |||
| 2442 | static void isr_rx_monitor(struct ipw2100_priv *priv, int i, | ||
| 2443 | struct ieee80211_rx_stats *stats) | ||
| 2444 | { | ||
| 2445 | struct ipw2100_status *status = &priv->status_queue.drv[i]; | ||
| 2446 | struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; | ||
| 2447 | |||
| 2448 | IPW_DEBUG_RX("Handler...\n"); | ||
| 2449 | |||
| 2450 | /* Magic struct that slots into the radiotap header -- no reason | ||
| 2451 | * to build this manually element by element, we can write it much | ||
| 2452 | * more efficiently than we can parse it. ORDER MATTERS HERE */ | ||
| 2453 | struct ipw_rt_hdr { | ||
| 2454 | struct ieee80211_radiotap_header rt_hdr; | ||
| 2455 | s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ | ||
| 2456 | } *ipw_rt; | ||
| 2457 | |||
| 2458 | if (unlikely(status->frame_size > skb_tailroom(packet->skb) - sizeof(struct ipw_rt_hdr))) { | ||
| 2459 | IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!" | ||
| 2460 | " Dropping.\n", | ||
| 2461 | priv->net_dev->name, | ||
| 2462 | status->frame_size, skb_tailroom(packet->skb)); | ||
| 2463 | priv->ieee->stats.rx_errors++; | ||
| 2464 | return; | ||
| 2465 | } | ||
| 2466 | |||
| 2467 | if (unlikely(!netif_running(priv->net_dev))) { | ||
| 2468 | priv->ieee->stats.rx_errors++; | ||
| 2469 | priv->wstats.discard.misc++; | ||
| 2470 | IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); | ||
| 2471 | return; | ||
| 2472 | } | ||
| 2473 | |||
| 2474 | if (unlikely(priv->config & CFG_CRC_CHECK && | ||
| 2475 | status->flags & IPW_STATUS_FLAG_CRC_ERROR)) { | ||
| 2476 | IPW_DEBUG_RX("CRC error in packet. Dropping.\n"); | ||
| 2477 | priv->ieee->stats.rx_errors++; | ||
| 2478 | return; | ||
| 2479 | } | ||
| 2480 | |||
| 2481 | pci_unmap_single(priv->pci_dev, | ||
| 2482 | packet->dma_addr, | ||
| 2483 | sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); | ||
| 2484 | memmove(packet->skb->data + sizeof(struct ipw_rt_hdr), | ||
| 2485 | packet->skb->data, status->frame_size); | ||
| 2486 | |||
| 2487 | ipw_rt = (struct ipw_rt_hdr *) packet->skb->data; | ||
| 2488 | |||
| 2489 | ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; | ||
| 2490 | ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ | ||
| 2491 | ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total header+data */ | ||
| 2492 | |||
| 2493 | ipw_rt->rt_hdr.it_present = 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL; | ||
| 2494 | |||
| 2495 | ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM; | ||
| 2496 | |||
| 2497 | skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr)); | ||
| 2498 | |||
| 2499 | if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { | ||
| 2500 | priv->ieee->stats.rx_errors++; | ||
| 2501 | |||
| 2502 | /* ieee80211_rx failed, so it didn't free the SKB */ | ||
| 2503 | dev_kfree_skb_any(packet->skb); | ||
| 2504 | packet->skb = NULL; | ||
| 2505 | } | ||
| 2506 | |||
| 2507 | /* We need to allocate a new SKB and attach it to the RDB. */ | ||
| 2508 | if (unlikely(ipw2100_alloc_skb(priv, packet))) { | ||
| 2509 | IPW_DEBUG_WARNING( | ||
| 2510 | "%s: Unable to allocate SKB onto RBD ring - disabling " | ||
| 2511 | "adapter.\n", priv->net_dev->name); | ||
| 2512 | /* TODO: schedule adapter shutdown */ | ||
| 2513 | IPW_DEBUG_INFO("TODO: Shutdown adapter...\n"); | ||
| 2514 | } | ||
| 2515 | |||
| 2516 | /* Update the RDB entry */ | ||
| 2517 | priv->rx_queue.drv[i].host_addr = packet->dma_addr; | ||
| 2518 | } | ||
| 2519 | |||
| 2520 | #endif | ||
| 2521 | |||
| 2449 | static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i) | 2522 | static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i) |
| 2450 | { | 2523 | { |
| 2451 | struct ipw2100_status *status = &priv->status_queue.drv[i]; | 2524 | struct ipw2100_status *status = &priv->status_queue.drv[i]; |
| @@ -2577,7 +2650,7 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) | |||
| 2577 | case P8023_DATA_VAL: | 2650 | case P8023_DATA_VAL: |
| 2578 | #ifdef CONFIG_IPW2100_MONITOR | 2651 | #ifdef CONFIG_IPW2100_MONITOR |
| 2579 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | 2652 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { |
| 2580 | isr_rx(priv, i, &stats); | 2653 | isr_rx_monitor(priv, i, &stats); |
| 2581 | break; | 2654 | break; |
| 2582 | } | 2655 | } |
| 2583 | #endif | 2656 | #endif |
| @@ -3882,7 +3955,7 @@ static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode) | |||
| 3882 | #ifdef CONFIG_IPW2100_MONITOR | 3955 | #ifdef CONFIG_IPW2100_MONITOR |
| 3883 | case IW_MODE_MONITOR: | 3956 | case IW_MODE_MONITOR: |
| 3884 | priv->last_mode = priv->ieee->iw_mode; | 3957 | priv->last_mode = priv->ieee->iw_mode; |
| 3885 | priv->net_dev->type = ARPHRD_IEEE80211; | 3958 | priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; |
| 3886 | break; | 3959 | break; |
| 3887 | #endif /* CONFIG_IPW2100_MONITOR */ | 3960 | #endif /* CONFIG_IPW2100_MONITOR */ |
| 3888 | } | 3961 | } |
diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index 948d426fcf9d..6f0b40f96abd 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h | |||
| @@ -41,6 +41,10 @@ | |||
| 41 | 41 | ||
| 42 | #include <net/ieee80211.h> | 42 | #include <net/ieee80211.h> |
| 43 | 43 | ||
| 44 | #ifdef CONFIG_IPW2100_MONITOR | ||
| 45 | #include <net/ieee80211_radiotap.h> | ||
| 46 | #endif | ||
| 47 | |||
| 44 | #include <linux/workqueue.h> | 48 | #include <linux/workqueue.h> |
| 45 | 49 | ||
| 46 | struct ipw2100_priv; | 50 | struct ipw2100_priv; |
