]> git.hungrycats.org Git - linux/commitdiff
[PATCH] prism54: Add avs header support
authorMargit Schubert-While <margitsw@t-online.de>
Wed, 2 Jun 2004 11:54:58 +0000 (07:54 -0400)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Wed, 2 Jun 2004 11:54:58 +0000 (07:54 -0400)
* islpci_eth.[c,h], islpci_dev.[c,h], isl_ioctl.[c,h] : added
  support for avs header in monitor mode. Based on the work of
  Antonio Eugenio Burriel <aeb@ryanstudios.com>. Unified packets
  header (rfmon_header and rx_annex) for iwspy.

drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/prism54/isl_oid.h
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/prism54/islpci_dev.h
drivers/net/wireless/prism54/islpci_eth.c
drivers/net/wireless/prism54/islpci_eth.h
drivers/net/wireless/prism54/oid_mgt.c
drivers/net/wireless/prism54/oid_mgt.h

index 9300b9c719c2fc5483d8a4ee13255903cc8a6fdb..426fc2e3e211e243367e03dff54aa2e35508d227 100644 (file)
@@ -327,34 +327,15 @@ prism54_set_freq(struct net_device *ndev, struct iw_request_info *info,
 {
        islpci_private *priv = netdev_priv(ndev);
        int rvalue;
-       u32 c = 0;
+       u32 c;
 
-       /* prepare the structure for the set object */
        if (fwrq->m < 1000)
-               /* structure value contains a channel indication */
+               /* we have a channel number */
                c = fwrq->m;
-       else {
-               /* structure contains a frequency indication and fwrq->e = 1 */
-               int f = fwrq->m / 100000;
-
-               if (fwrq->e != 1)
-                       return -EINVAL;
-               if ((f >= 2412) && (f <= 2484)) {
-                       while ((c < 14) && (f != frequency_list_bg[c]))
-                               c++;
-                       if (c >= 14)
-                               return -EINVAL;
-               } else if ((f >= (int) 5170) && (f <= (int) 5320)) {
-                       while ((c < 12) && (f != frequency_list_a[c]))
-                               c++;
-                       if (c >= 12)
-                               return -EINVAL;
-               } else
-                       return -EINVAL;
-               c++;
-       }
+       else
+               c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0;
 
-       rvalue = mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c);
+       rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL;
 
        /* Call commit handler */
        return (rvalue ? rvalue : -EINPROGRESS);
@@ -410,7 +391,7 @@ prism54_set_mode(struct net_device *ndev, struct iw_request_info *info,
 
        mgt_commit(priv);
        priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR)
-           ? ARPHRD_IEEE80211 : ARPHRD_ETHER;
+           ? priv->monitor_type : ARPHRD_ETHER;
        up_write(&priv->mib_sem);
 
        return 0;
@@ -1962,6 +1943,28 @@ prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info,
        return 0;
 }
 
+int
+prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info,
+                    __u32 * uwrq, char *extra)
+{
+       islpci_private *priv = netdev_priv(ndev);
+       priv->monitor_type =
+           (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211);
+       if (priv->iw_mode == IW_MODE_MONITOR)
+               priv->ndev->type = priv->monitor_type;
+
+       return 0;
+}
+
+int
+prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info,
+                    __u32 * uwrq, char *extra)
+{
+       islpci_private *priv = netdev_priv(ndev);
+       *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM);
+       return 0;
+}
+
 int
 prism54_set_maxframeburst(struct net_device *ndev, struct iw_request_info *info,
                          __u32 * uwrq, char *extra)
@@ -2198,6 +2201,9 @@ static const iw_handler prism54_handler[] = {
 #define        PRISM54_SET_OID_STR     SIOCIWFIRSTPRIV+20
 #define        PRISM54_SET_OID_ADDR    SIOCIWFIRSTPRIV+22
 
+#define PRISM54_GET_PRISMHDR   SIOCIWFIRSTPRIV+23
+#define PRISM54_SET_PRISMHDR   SIOCIWFIRSTPRIV+24
+
 #define IWPRIV_SET_U32(n,x)    { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_"x }
 #define IWPRIV_SET_SSID(n,x)   { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "set_"x }
 #define IWPRIV_SET_ADDR(n,x)   { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "set_"x }
@@ -2212,6 +2218,10 @@ static const iw_handler prism54_handler[] = {
 static const struct iw_priv_args prism54_private_args[] = {
 /*{ cmd, set_args, get_args, name } */
        {PRISM54_RESET, 0, 0, "reset"},
+       {PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        "get_prismhdr"},
+       {PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+        "set_prismhdr"},
        {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
         "getPolicy"},
        {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
@@ -2321,7 +2331,8 @@ static const iw_handler prism54_private_handler[] = {
        (iw_handler) prism54_set_raw,
        (iw_handler) NULL,
        (iw_handler) prism54_set_raw,
-
+       (iw_handler) prism54_get_prismhdr,
+       (iw_handler) prism54_set_prismhdr,
 };
 
 const struct iw_handler_def prism54_handler_def = {
index 986073b477c8ce1feec4cf9fb54790997c9de4c5..c4b27d24d4c63cf111aca9e484fe1da4f8007572 100644 (file)
@@ -91,19 +91,6 @@ struct obj_frequencies {
        u16 mhz[0];
 } __attribute__ ((packed));
 
-struct obj_rx_annex {
-       u8 addr1[ETH_ALEN];
-       u8 addr2[ETH_ALEN];
-       u32 something0;
-       u32 time;
-       u16 something1;
-       u16 rate;
-       u16 freq;
-       u16 something2;
-       u8 rssi;
-       u8 pad[3];
-} __attribute__ ((packed));
-
 /* 
  * in case everything's ok, the inlined function below will be
  * optimized away by the compiler...
index acc5fbd87b3eed951d166ae312953cf8159b3436..1571939180dfa15ebeb5115393c48a92c0495b4d 100644 (file)
@@ -715,9 +715,9 @@ islpci_setup(struct pci_dev *pdev)
        priv = netdev_priv(ndev);
        priv->ndev = ndev;
        priv->pdev = pdev;
-
+       priv->monitor_type = ARPHRD_IEEE80211;
        priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ?
-               ARPHRD_IEEE80211: ARPHRD_ETHER;
+               priv->monitor_type : ARPHRD_ETHER;
 
        /* save the start and end address of the PCI memory area */
        ndev->mem_start = (unsigned long) priv->device_base;
index 9178da54c8e4226b3f28963caeed349fbc06c37a..de92b4ea6a76648deadf83fe530448684158c117 100644 (file)
@@ -114,6 +114,8 @@ typedef struct {
 
        struct iw_spy_data spy_data; /* iwspy support */
 
+       int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */
+
        struct islpci_acl acl;
 
        /* PCI bus allocation & configuration members */
index 2a3e30ccbf0cb25acc4eced10186d3ff6a599764..c18c42d0c2aa9c9db49f6b092ed0aee979d0277f 100644 (file)
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/if_arp.h>
 
 #include "isl_38xx.h"
 #include "islpci_eth.h"
 #include "islpci_mgt.h"
+#include "oid_mgt.h"
 
 /******************************************************************************
     Network Interface functions
@@ -246,6 +248,69 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
        return err;
 }
 
+static inline int
+islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb)
+{
+       /* The card reports full 802.11 packets but with a 20 bytes
+        * header and without the FCS. But there a is a bit that
+        * indicates if the packet is corrupted :-) */
+       struct rfmon_header *hdr = (struct rfmon_header *) (*skb)->data;
+       if (hdr->flags & 0x01)
+               /* This one is bad. Drop it ! */
+               return -1;
+       if (priv->ndev->type == ARPHRD_IEEE80211_PRISM) {
+               struct avs_80211_1_header *avs;
+               /* extract the relevant data from the header */
+               u32 clock = hdr->clock;
+               u8 rate = hdr->rate;
+               u16 freq = be16_to_cpu(hdr->freq);
+               u8 rssi = hdr->rssi;
+
+               skb_pull(*skb, sizeof (struct rfmon_header));
+
+               if (skb_headroom(*skb) < sizeof (struct avs_80211_1_header)) {
+                       struct sk_buff *newskb = skb_copy_expand(*skb,
+                                                                sizeof (struct
+                                                                        avs_80211_1_header),
+                                                                0, GFP_ATOMIC);
+                       if (newskb) {
+                               kfree_skb(*skb);
+                               *skb = newskb;
+                       } else
+                               return -1;
+                       /* This behavior is not very subtile... */
+               }
+
+               /* make room for the new header and fill it. */
+               avs =
+                   (struct avs_80211_1_header *) skb_push(*skb,
+                                                          sizeof (struct
+                                                                  avs_80211_1_header));
+
+               avs->version = htonl(P80211CAPTURE_VERSION);
+               avs->length = htonl(sizeof (struct avs_80211_1_header));
+               avs->mactime = __cpu_to_be64(clock);
+               avs->hosttime = __cpu_to_be64(jiffies);
+               avs->phytype = htonl(6);        /*OFDM: 6 for (g), 8 for (a) */
+               avs->channel = htonl(channel_of_freq(freq));
+               avs->datarate = htonl(rate * 5);
+               avs->antenna = htonl(0);        /*unknown */
+               avs->priority = htonl(0);       /*unknown */
+               avs->ssi_type = htonl(2);       /*2: dBm, 3: raw RSSI */
+               avs->ssi_signal = htonl(rssi);
+               avs->ssi_noise = htonl(priv->local_iwstatistics.qual.noise);    /*better than 'undefined', I assume */
+               avs->preamble = htonl(0);       /*unknown */
+               avs->encoding = htonl(0);       /*unknown */
+       } else
+               skb_pull(*skb, sizeof (struct rfmon_header));
+
+       (*skb)->protocol = htons(ETH_P_802_2);
+       (*skb)->mac.raw = (*skb)->data;
+       (*skb)->pkt_type = PACKET_OTHERHOST;
+
+       return 0;
+}
+
 int
 islpci_eth_receive(islpci_private *priv)
 {
@@ -315,37 +380,29 @@ islpci_eth_receive(islpci_private *priv)
        /* do some additional sk_buff and network layer parameters */
        skb->dev = ndev;
 
-       /* take care of monitor mode */
-       if (priv->iw_mode == IW_MODE_MONITOR) {
-               /* The card reports full 802.11 packets but with a 20 bytes
-                * header and without the FCS. But there a is a bit that
-                * indicates if the packet is corrupted :-) */
-               if (skb->data[8] & 0x01)
-                       /* This one is bad. Drop it ! */
-                       discard = 1;
-               skb_pull(skb, 20);
-               skb->protocol = htons(ETH_P_802_2);
-               skb->mac.raw = skb->data;
-               skb->pkt_type = PACKET_OTHERHOST;
-       } else {
+       /* take care of monitor mode and spy monitoring. */
+       if (priv->iw_mode == IW_MODE_MONITOR)
+               discard = islpci_monitor_rx(priv, &skb);
+       else {
                if (skb->data[2 * ETH_ALEN] == 0) {
                        /* The packet has a rx_annex. Read it for spy monitoring, Then
                         * remove it, while keeping the 2 leading MAC addr.
                         */
                        struct iw_quality wstats;
-                       struct obj_rx_annex *annex =
-                           (struct obj_rx_annex *) skb->data;
-                       wstats.level = annex->rssi;
+                       struct rx_annex_header *annex =
+                           (struct rx_annex_header *) skb->data;
+                       wstats.level = annex->rfmon.rssi;
                        /* The noise value can be a bit outdated if nobody's 
                         * reading wireless stats... */
-                       wstats.noise = priv->iwstatistics.qual.noise;
+                       wstats.noise = priv->local_iwstatistics.qual.noise;
                        wstats.qual = wstats.level - wstats.noise;
                        wstats.updated = 0x07;
                        /* Update spy records */
                        wireless_spy_update(ndev, annex->addr2, &wstats);
-                       /* 20 = sizeof(struct obj_rx_annex) - 2*ETH_ALEN */
-                       memcpy(skb->data + 20, skb->data, 2 * ETH_ALEN);
-                       skb_pull(skb, 20);
+
+                       memcpy(skb->data + sizeof (struct rfmon_header),
+                              skb->data, 2 * ETH_ALEN);
+                       skb_pull(skb, sizeof (struct rfmon_header));
                }
                skb->protocol = eth_type_trans(skb, ndev);
        }
index c99bb2bb623a514dce449ee1db3c41fd0f3b8426..bc9d7a60b8d607e4642e7efa325dc04534e73c4b 100644 (file)
 #include "isl_38xx.h"
 #include "islpci_dev.h"
 
+struct rfmon_header {
+       u16 unk0;               /* = 0x0000 */
+       u16 length;             /* = 0x1400 */
+       u32 clock;              /* 1MHz clock */
+       u8 flags;
+       u8 unk1;
+       u8 rate;
+       u8 unk2;
+       u16 freq;
+       u16 unk3;
+       u8 rssi;
+       u8 padding[3];
+} __attribute__ ((packed));
+
+struct rx_annex_header {
+       u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+       struct rfmon_header rfmon;
+} __attribute__ ((packed));
+
+/* wlan-ng (and hopefully others) AVS header, version one.  Fields in
+ * network byte order. */
+#define P80211CAPTURE_VERSION 0x80211001
+
+struct avs_80211_1_header {
+       uint32_t version;
+       uint32_t length;
+       uint64_t mactime;
+       uint64_t hosttime;
+       uint32_t phytype;
+       uint32_t channel;
+       uint32_t datarate;
+       uint32_t antenna;
+       uint32_t priority;
+       uint32_t ssi_type;
+       int32_t ssi_signal;
+       int32_t ssi_noise;
+       uint32_t preamble;
+       uint32_t encoding;
+};
+
 void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *);
 int islpci_eth_transmit(struct sk_buff *, struct net_device *);
 int islpci_eth_receive(islpci_private *);
index b1aee22928c9c63648d7315e06ea5766da8380af..cfa541ca28385d0887891278f3658b4a3f284a14 100644 (file)
@@ -31,6 +31,27 @@ const int frequency_list_a[] = { 5170, 5180, 5190, 5200, 5210, 5220, 5230,
        5240, 5260, 5280, 5300, 5320
 };
 
+int
+channel_of_freq(int f)
+{
+       int c = 0;
+
+       if ((f >= 2412) && (f <= 2484)) {
+               while ((c < 14) && (f != frequency_list_bg[c]))
+                       c++;
+               if (c >= 14)
+                       return 0;
+       } else if ((f >= (int) 5170) && (f <= (int) 5320)) {
+               while ((c < 12) && (f != frequency_list_a[c]))
+                       c++;
+               if (c >= 12)
+                       return 0;
+       } else
+               return 0;
+
+       return ++c;
+}
+
 #define OID_STRUCT(name,oid,s,t) [name] = {oid, 0, sizeof(s), t}
 #define OID_STRUCT_C(name,oid,s,t) OID_STRUCT(name,oid,s,t | OID_FLAG_CACHED)
 #define OID_U32(name,oid) OID_STRUCT(name,oid,u32,OID_TYPE_U32)
index 670e4fbbc6a4ab546411b801122bf001a90d9ee9..cd8167e29eebb28c4879161ff3b86a28363f5b40 100644 (file)
@@ -28,9 +28,10 @@ int mgt_init(islpci_private *);
 
 void mgt_clean(islpci_private *);
 
+/* I don't know where to put these 3 */
 extern const int frequency_list_bg[];
-
 extern const int frequency_list_a[];
+int channel_of_freq(int);
 
 void mgt_le_to_cpu(int, void *);