diff options
author | Mike Kershaw <dragorn@kismetwireless.net> | 2005-08-26 01:41:54 -0400 |
---|---|---|
committer | James Ketrenos <jketreno@linux.intel.com> | 2005-11-07 18:51:22 -0500 |
commit | 24a47dbd89a2738bc149de4685ae5a2a97193ae1 (patch) | |
tree | 8f51a610a39581d48b6b9a6e7a0e4ba8420df8a3 /drivers/net | |
parent | a4f6bbb305123c2c42322a10a770be64089a17ca (diff) |
Adds radiotap support to ipw2200 in monitor mode..
Signed-off-by: Mike Kershaw <dragorn@kismetwireless.net>
Signed-off-by: James Ketrenos <jketreno@linux.intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ipw2200.c | 185 | ||||
-rw-r--r-- | drivers/net/wireless/ipw2200.h | 1 |
2 files changed, 186 insertions, 0 deletions
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 79697e8e8d96..86a4c2358f9d 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -7918,6 +7918,173 @@ static void ipw_handle_data_packet(struct ipw_priv *priv, | |||
7918 | } | 7918 | } |
7919 | } | 7919 | } |
7920 | 7920 | ||
7921 | #ifdef CONFIG_IEEE80211_RADIOTAP | ||
7922 | static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, | ||
7923 | struct ipw_rx_mem_buffer *rxb, | ||
7924 | struct ieee80211_rx_stats *stats) | ||
7925 | { | ||
7926 | struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; | ||
7927 | struct ipw_rx_frame *frame = &pkt->u.frame; | ||
7928 | |||
7929 | /* initial pull of some data */ | ||
7930 | u16 received_channel = frame->received_channel; | ||
7931 | u8 antennaAndPhy = frame->antennaAndPhy; | ||
7932 | s8 antsignal = frame->rssi_dbm - IPW_RSSI_TO_DBM; /* call it signed anyhow */ | ||
7933 | u16 pktrate = frame->rate; | ||
7934 | |||
7935 | /* Magic struct that slots into the radiotap header -- no reason | ||
7936 | * to build this manually element by element, we can write it much | ||
7937 | * more efficiently than we can parse it. ORDER MATTERS HERE */ | ||
7938 | struct ipw_rt_hdr { | ||
7939 | struct ieee80211_radiotap_header rt_hdr; | ||
7940 | u8 rt_flags; /* radiotap packet flags */ | ||
7941 | u8 rt_rate; /* rate in 500kb/s */ | ||
7942 | u16 rt_channel; /* channel in mhz */ | ||
7943 | u16 rt_chbitmask; /* channel bitfield */ | ||
7944 | s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ | ||
7945 | u8 rt_antenna; /* antenna number */ | ||
7946 | } *ipw_rt; | ||
7947 | |||
7948 | short len = le16_to_cpu(pkt->u.frame.length); | ||
7949 | |||
7950 | /* We received data from the HW, so stop the watchdog */ | ||
7951 | priv->net_dev->trans_start = jiffies; | ||
7952 | |||
7953 | /* We only process data packets if the | ||
7954 | * interface is open */ | ||
7955 | if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) > | ||
7956 | skb_tailroom(rxb->skb))) { | ||
7957 | priv->ieee->stats.rx_errors++; | ||
7958 | priv->wstats.discard.misc++; | ||
7959 | IPW_DEBUG_DROP("Corruption detected! Oh no!\n"); | ||
7960 | return; | ||
7961 | } else if (unlikely(!netif_running(priv->net_dev))) { | ||
7962 | priv->ieee->stats.rx_dropped++; | ||
7963 | priv->wstats.discard.misc++; | ||
7964 | IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); | ||
7965 | return; | ||
7966 | } | ||
7967 | |||
7968 | /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use | ||
7969 | * that now */ | ||
7970 | if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) { | ||
7971 | /* FIXME: Should alloc bigger skb instead */ | ||
7972 | priv->ieee->stats.rx_dropped++; | ||
7973 | priv->wstats.discard.misc++; | ||
7974 | IPW_DEBUG_DROP("Dropping too large packet in monitor\n"); | ||
7975 | return; | ||
7976 | } | ||
7977 | |||
7978 | /* copy the frame itself */ | ||
7979 | memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr), | ||
7980 | rxb->skb->data + IPW_RX_FRAME_SIZE, len); | ||
7981 | |||
7982 | /* Zero the radiotap static buffer ... We only need to zero the bytes NOT | ||
7983 | * part of our real header, saves a little time. | ||
7984 | * | ||
7985 | * No longer necessary since we fill in all our data. Purge before merging | ||
7986 | * patch officially. | ||
7987 | * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, | ||
7988 | * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); | ||
7989 | */ | ||
7990 | |||
7991 | ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data; | ||
7992 | |||
7993 | ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; | ||
7994 | ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ | ||
7995 | ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total header+data */ | ||
7996 | |||
7997 | /* Big bitfield of all the fields we provide in radiotap */ | ||
7998 | ipw_rt->rt_hdr.it_present = | ||
7999 | ((1 << IEEE80211_RADIOTAP_FLAGS) | | ||
8000 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
8001 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
8002 | (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | | ||
8003 | (1 << IEEE80211_RADIOTAP_ANTENNA)); | ||
8004 | |||
8005 | /* Zero the flags, we'll add to them as we go */ | ||
8006 | ipw_rt->rt_flags = 0; | ||
8007 | |||
8008 | /* Convert signal to DBM */ | ||
8009 | ipw_rt->rt_dbmsignal = antsignal; | ||
8010 | |||
8011 | /* Convert the channel data and set the flags */ | ||
8012 | ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel)); | ||
8013 | if (received_channel > 14) { /* 802.11a */ | ||
8014 | ipw_rt->rt_chbitmask = | ||
8015 | cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); | ||
8016 | } else if (antennaAndPhy & 32) { /* 802.11b */ | ||
8017 | ipw_rt->rt_chbitmask = | ||
8018 | cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); | ||
8019 | } else { /* 802.11g */ | ||
8020 | ipw_rt->rt_chbitmask = | ||
8021 | (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); | ||
8022 | } | ||
8023 | |||
8024 | /* set the rate in multiples of 500k/s */ | ||
8025 | switch (pktrate) { | ||
8026 | case IPW_TX_RATE_1MB: | ||
8027 | ipw_rt->rt_rate = 2; | ||
8028 | break; | ||
8029 | case IPW_TX_RATE_2MB: | ||
8030 | ipw_rt->rt_rate = 4; | ||
8031 | break; | ||
8032 | case IPW_TX_RATE_5MB: | ||
8033 | ipw_rt->rt_rate = 10; | ||
8034 | break; | ||
8035 | case IPW_TX_RATE_6MB: | ||
8036 | ipw_rt->rt_rate = 12; | ||
8037 | break; | ||
8038 | case IPW_TX_RATE_9MB: | ||
8039 | ipw_rt->rt_rate = 18; | ||
8040 | break; | ||
8041 | case IPW_TX_RATE_11MB: | ||
8042 | ipw_rt->rt_rate = 22; | ||
8043 | break; | ||
8044 | case IPW_TX_RATE_12MB: | ||
8045 | ipw_rt->rt_rate = 24; | ||
8046 | break; | ||
8047 | case IPW_TX_RATE_18MB: | ||
8048 | ipw_rt->rt_rate = 36; | ||
8049 | break; | ||
8050 | case IPW_TX_RATE_24MB: | ||
8051 | ipw_rt->rt_rate = 48; | ||
8052 | break; | ||
8053 | case IPW_TX_RATE_36MB: | ||
8054 | ipw_rt->rt_rate = 72; | ||
8055 | break; | ||
8056 | case IPW_TX_RATE_48MB: | ||
8057 | ipw_rt->rt_rate = 96; | ||
8058 | break; | ||
8059 | case IPW_TX_RATE_54MB: | ||
8060 | ipw_rt->rt_rate = 108; | ||
8061 | break; | ||
8062 | default: | ||
8063 | ipw_rt->rt_rate = 0; | ||
8064 | break; | ||
8065 | } | ||
8066 | |||
8067 | /* antenna number */ | ||
8068 | ipw_rt->rt_antenna = (antennaAndPhy & 3); /* Is this right? */ | ||
8069 | |||
8070 | /* set the preamble flag if we have it */ | ||
8071 | if ((antennaAndPhy & 64)) | ||
8072 | ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; | ||
8073 | |||
8074 | /* Set the size of the skb to the size of the frame */ | ||
8075 | skb_put(rxb->skb, len + sizeof(struct ipw_rt_hdr)); | ||
8076 | |||
8077 | IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); | ||
8078 | |||
8079 | if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) | ||
8080 | priv->ieee->stats.rx_errors++; | ||
8081 | else { /* ieee80211_rx succeeded, so it now owns the SKB */ | ||
8082 | rxb->skb = NULL; | ||
8083 | /* no LED during capture */ | ||
8084 | } | ||
8085 | } | ||
8086 | #endif | ||
8087 | |||
7921 | static inline int is_network_packet(struct ipw_priv *priv, | 8088 | static inline int is_network_packet(struct ipw_priv *priv, |
7922 | struct ieee80211_hdr_4addr *header) | 8089 | struct ieee80211_hdr_4addr *header) |
7923 | { | 8090 | { |
@@ -8147,8 +8314,14 @@ static void ipw_rx(struct ipw_priv *priv) | |||
8147 | 8314 | ||
8148 | #ifdef CONFIG_IPW2200_MONITOR | 8315 | #ifdef CONFIG_IPW2200_MONITOR |
8149 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | 8316 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { |
8317 | #ifdef CONFIG_IEEE80211_RADIOTAP | ||
8318 | ipw_handle_data_packet_monitor(priv, | ||
8319 | rxb, | ||
8320 | &stats); | ||
8321 | #else | ||
8150 | ipw_handle_data_packet(priv, rxb, | 8322 | ipw_handle_data_packet(priv, rxb, |
8151 | &stats); | 8323 | &stats); |
8324 | #endif | ||
8152 | break; | 8325 | break; |
8153 | } | 8326 | } |
8154 | #endif | 8327 | #endif |
@@ -8315,7 +8488,11 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) | |||
8315 | #ifdef CONFIG_IPW2200_MONITOR | 8488 | #ifdef CONFIG_IPW2200_MONITOR |
8316 | case 2: | 8489 | case 2: |
8317 | priv->ieee->iw_mode = IW_MODE_MONITOR; | 8490 | priv->ieee->iw_mode = IW_MODE_MONITOR; |
8491 | #ifdef CONFIG_IEEE80211_RADIOTAP | ||
8492 | priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; | ||
8493 | #else | ||
8318 | priv->net_dev->type = ARPHRD_IEEE80211; | 8494 | priv->net_dev->type = ARPHRD_IEEE80211; |
8495 | #endif | ||
8319 | break; | 8496 | break; |
8320 | #endif | 8497 | #endif |
8321 | default: | 8498 | default: |
@@ -8565,7 +8742,11 @@ static int ipw_wx_set_mode(struct net_device *dev, | |||
8565 | priv->net_dev->type = ARPHRD_ETHER; | 8742 | priv->net_dev->type = ARPHRD_ETHER; |
8566 | 8743 | ||
8567 | if (wrqu->mode == IW_MODE_MONITOR) | 8744 | if (wrqu->mode == IW_MODE_MONITOR) |
8745 | #ifdef CONFIG_IEEE80211_RADIOTAP | ||
8746 | priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; | ||
8747 | #else | ||
8568 | priv->net_dev->type = ARPHRD_IEEE80211; | 8748 | priv->net_dev->type = ARPHRD_IEEE80211; |
8749 | #endif | ||
8569 | #endif /* CONFIG_IPW2200_MONITOR */ | 8750 | #endif /* CONFIG_IPW2200_MONITOR */ |
8570 | 8751 | ||
8571 | /* Free the existing firmware and reset the fw_loaded | 8752 | /* Free the existing firmware and reset the fw_loaded |
@@ -9598,7 +9779,11 @@ static int ipw_wx_set_monitor(struct net_device *dev, | |||
9598 | IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); | 9779 | IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); |
9599 | if (enable) { | 9780 | if (enable) { |
9600 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) { | 9781 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) { |
9782 | #ifdef CONFIG_IEEE80211_RADIOTAP | ||
9783 | priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; | ||
9784 | #else | ||
9601 | priv->net_dev->type = ARPHRD_IEEE80211; | 9785 | priv->net_dev->type = ARPHRD_IEEE80211; |
9786 | #endif | ||
9602 | queue_work(priv->workqueue, &priv->adapter_restart); | 9787 | queue_work(priv->workqueue, &priv->adapter_restart); |
9603 | } | 9788 | } |
9604 | 9789 | ||
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index f2056b62254e..28f1216f8ea4 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <asm/io.h> | 50 | #include <asm/io.h> |
51 | 51 | ||
52 | #include <net/ieee80211.h> | 52 | #include <net/ieee80211.h> |
53 | #include <net/ieee80211_radiotap.h> | ||
53 | 54 | ||
54 | #define DRV_NAME "ipw2200" | 55 | #define DRV_NAME "ipw2200" |
55 | 56 | ||