aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMike Kershaw <dragorn@kismetwireless.net>2005-08-26 01:41:54 -0400
committerJames Ketrenos <jketreno@linux.intel.com>2005-11-07 18:51:22 -0500
commit24a47dbd89a2738bc149de4685ae5a2a97193ae1 (patch)
tree8f51a610a39581d48b6b9a6e7a0e4ba8420df8a3 /drivers
parenta4f6bbb305123c2c42322a10a770be64089a17ca (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')
-rw-r--r--drivers/net/wireless/ipw2200.c185
-rw-r--r--drivers/net/wireless/ipw2200.h1
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
7922static 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
7921static inline int is_network_packet(struct ipw_priv *priv, 8088static 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