diff options
Diffstat (limited to 'drivers')
-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; |