Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Stefan Rompf and committed by
John W. Linville
15745a7d 171e7b2f

+88 -11
+84 -11
drivers/net/wireless/ipw2100.c
··· 2390 2390 IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); 2391 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 2394 if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR && 2404 2395 !(priv->status & STATUS_ASSOCIATED))) { ··· 2436 2445 /* Update the RDB entry */ 2437 2446 priv->rx_queue.drv[i].host_addr = packet->dma_addr; 2438 2447 } 2448 + 2449 + #ifdef CONFIG_IPW2100_MONITOR 2450 + 2451 + static void isr_rx_monitor(struct ipw2100_priv *priv, int i, 2452 + struct ieee80211_rx_stats *stats) 2453 + { 2454 + struct ipw2100_status *status = &priv->status_queue.drv[i]; 2455 + struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; 2456 + 2457 + IPW_DEBUG_RX("Handler...\n"); 2458 + 2459 + /* Magic struct that slots into the radiotap header -- no reason 2460 + * to build this manually element by element, we can write it much 2461 + * more efficiently than we can parse it. ORDER MATTERS HERE */ 2462 + struct ipw_rt_hdr { 2463 + struct ieee80211_radiotap_header rt_hdr; 2464 + s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ 2465 + } *ipw_rt; 2466 + 2467 + if (unlikely(status->frame_size > skb_tailroom(packet->skb) - sizeof(struct ipw_rt_hdr))) { 2468 + IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!" 2469 + " Dropping.\n", 2470 + priv->net_dev->name, 2471 + status->frame_size, skb_tailroom(packet->skb)); 2472 + priv->ieee->stats.rx_errors++; 2473 + return; 2474 + } 2475 + 2476 + if (unlikely(!netif_running(priv->net_dev))) { 2477 + priv->ieee->stats.rx_errors++; 2478 + priv->wstats.discard.misc++; 2479 + IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); 2480 + return; 2481 + } 2482 + 2483 + if (unlikely(priv->config & CFG_CRC_CHECK && 2484 + status->flags & IPW_STATUS_FLAG_CRC_ERROR)) { 2485 + IPW_DEBUG_RX("CRC error in packet. Dropping.\n"); 2486 + priv->ieee->stats.rx_errors++; 2487 + return; 2488 + } 2489 + 2490 + pci_unmap_single(priv->pci_dev, 2491 + packet->dma_addr, 2492 + sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); 2493 + memmove(packet->skb->data + sizeof(struct ipw_rt_hdr), 2494 + packet->skb->data, status->frame_size); 2495 + 2496 + ipw_rt = (struct ipw_rt_hdr *) packet->skb->data; 2497 + 2498 + ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; 2499 + ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ 2500 + ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total header+data */ 2501 + 2502 + ipw_rt->rt_hdr.it_present = 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL; 2503 + 2504 + ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM; 2505 + 2506 + skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr)); 2507 + 2508 + if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { 2509 + priv->ieee->stats.rx_errors++; 2510 + 2511 + /* ieee80211_rx failed, so it didn't free the SKB */ 2512 + dev_kfree_skb_any(packet->skb); 2513 + packet->skb = NULL; 2514 + } 2515 + 2516 + /* We need to allocate a new SKB and attach it to the RDB. */ 2517 + if (unlikely(ipw2100_alloc_skb(priv, packet))) { 2518 + IPW_DEBUG_WARNING( 2519 + "%s: Unable to allocate SKB onto RBD ring - disabling " 2520 + "adapter.\n", priv->net_dev->name); 2521 + /* TODO: schedule adapter shutdown */ 2522 + IPW_DEBUG_INFO("TODO: Shutdown adapter...\n"); 2523 + } 2524 + 2525 + /* Update the RDB entry */ 2526 + priv->rx_queue.drv[i].host_addr = packet->dma_addr; 2527 + } 2528 + 2529 + #endif 2439 2530 2440 2531 static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i) 2441 2532 { ··· 2650 2577 case P8023_DATA_VAL: 2651 2578 #ifdef CONFIG_IPW2100_MONITOR 2652 2579 if (priv->ieee->iw_mode == IW_MODE_MONITOR) { 2653 - isr_rx(priv, i, &stats); 2580 + isr_rx_monitor(priv, i, &stats); 2654 2581 break; 2655 2582 } 2656 2583 #endif ··· 3955 3882 #ifdef CONFIG_IPW2100_MONITOR 3956 3883 case IW_MODE_MONITOR: 3957 3884 priv->last_mode = priv->ieee->iw_mode; 3958 - priv->net_dev->type = ARPHRD_IEEE80211; 3885 + priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; 3959 3886 break; 3960 3887 #endif /* CONFIG_IPW2100_MONITOR */ 3961 3888 }
+4
drivers/net/wireless/ipw2100.h
··· 41 41 42 42 #include <net/ieee80211.h> 43 43 44 + #ifdef CONFIG_IPW2100_MONITOR 45 + #include <net/ieee80211_radiotap.h> 46 + #endif 47 + 44 48 #include <linux/workqueue.h> 45 49 46 50 struct ipw2100_priv;