]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/orinoco.c
Pull 1024-cpu into release branch
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / orinoco.c
index 9c2d07cde0101a311c298bedba42d318861a9d34..15ceaf615756a2ceb397993c384b81ef117354a5 100644 (file)
@@ -94,6 +94,8 @@
 #include <net/iw_handler.h>
 #include <net/ieee80211.h>
 
+#include <net/ieee80211.h>
+
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include "hermes.h"
 #include "hermes_rid.h"
 #include "orinoco.h"
-#include "ieee802_11.h"
 
 /********************************************************************/
 /* Module information                                               */
@@ -150,7 +151,7 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
 #define ENCAPS_OVERHEAD                (sizeof(encaps_hdr) + 2)
 
 #define ORINOCO_MIN_MTU                256
-#define ORINOCO_MAX_MTU                (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
+#define ORINOCO_MAX_MTU                (IEEE80211_DATA_LEN - ENCAPS_OVERHEAD)
 
 #define SYMBOL_MAX_VER_LEN     (14)
 #define USER_BAP               0
@@ -442,7 +443,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
        if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
                return -EINVAL;
 
-       if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) >
+       if ( (new_mtu + ENCAPS_OVERHEAD + IEEE80211_HLEN) >
             (priv->nicbuf_size - ETH_HLEN) )
                return -EINVAL;
 
@@ -502,9 +503,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                return 0;
        }
 
-       /* Length of the packet body */
-       /* FIXME: what if the skb is smaller than this? */
-       len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN);
+       /* Check packet length, pad short packets, round up odd length */
+       len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN);
+       if (skb->len < len) {
+               skb = skb_padto(skb, len);
+               if (skb == NULL)
+                       goto fail;
+       }
+       len -= ETH_HLEN;
 
        eh = (struct ethhdr *)skb->data;
 
@@ -556,8 +562,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                p = skb->data;
        }
 
-       /* Round up for odd length packets */
-       err = hermes_bap_pwrite(hw, USER_BAP, p, ALIGN(data_len, 2),
+       err = hermes_bap_pwrite(hw, USER_BAP, p, data_len,
                                txfid, data_off);
        if (err) {
                printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
@@ -573,8 +578,9 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                                txfid, NULL);
        if (err) {
                netif_start_queue(dev);
-               printk(KERN_ERR "%s: Error %d transmitting packet\n",
-                      dev->name, err);
+               if (net_ratelimit())
+                       printk(KERN_ERR "%s: Error %d transmitting packet\n",
+                               dev->name, err);
                stats->tx_errors++;
                goto fail;
        }
@@ -918,7 +924,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
                    data. */
                return;
        }
-       if (length > IEEE802_11_DATA_LEN) {
+       if (length > IEEE80211_DATA_LEN) {
                printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
                       dev->name, length);
                stats->rx_length_errors++;
@@ -1052,8 +1058,9 @@ static void orinoco_join_ap(struct net_device *dev)
                u16 channel;
        } __attribute__ ((packed)) req;
        const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
-       struct prism2_scan_apinfo *atom;
+       struct prism2_scan_apinfo *atom = NULL;
        int offset = 4;
+       int found = 0;
        u8 *buf;
        u16 len;
 
@@ -1088,15 +1095,18 @@ static void orinoco_join_ap(struct net_device *dev)
         * we were requested to join */
        for (; offset + atom_len <= len; offset += atom_len) {
                atom = (struct prism2_scan_apinfo *) (buf + offset);
-               if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0)
-                       goto found;
+               if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
+                       found = 1;
+                       break;
+               }
        }
 
-       DEBUG(1, "%s: Requested AP not found in scan results\n",
-             dev->name);
-       goto out;
+       if (! found) {
+               DEBUG(1, "%s: Requested AP not found in scan results\n",
+                     dev->name);
+               goto out;
+       }
 
- found:
        memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
        req.channel = atom->channel;    /* both are little-endian */
        err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
@@ -1283,8 +1293,10 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                /* Read scan data */
                err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
                                       infofid, sizeof(info));
-               if (err)
+               if (err) {
+                       kfree(buf);
                        break;
+               }
 
 #ifdef ORINOCO_DEBUG
                {
@@ -2272,7 +2284,7 @@ static int orinoco_init(struct net_device *dev)
 
        /* No need to lock, the hw_unavailable flag is already set in
         * alloc_orinocodev() */
-       priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
+       priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN;
 
        /* Initialize the firmware */
        err = orinoco_reinit_firmware(dev);
@@ -2451,7 +2463,6 @@ struct net_device *alloc_orinocodev(int sizeof_card,
        dev->watchdog_timeo = HZ; /* 1 second timeout */
        dev->get_stats = orinoco_get_stats;
        dev->ethtool_ops = &orinoco_ethtool_ops;
-       dev->get_wireless_stats = orinoco_get_wireless_stats;
        dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def;
        dev->change_mtu = orinoco_change_mtu;
        dev->set_multicast_list = orinoco_set_multicast_list;
@@ -4020,7 +4031,8 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
 }
 
 /* Translate scan data returned from the card to a card independant
- * format that the Wireless Tools will understand - Jean II */
+ * format that the Wireless Tools will understand - Jean II
+ * Return message length or -errno for fatal errors */
 static inline int orinoco_translate_scan(struct net_device *dev,
                                         char *buffer,
                                         char *scan,
@@ -4060,13 +4072,19 @@ static inline int orinoco_translate_scan(struct net_device *dev,
                break;
        case FIRMWARE_TYPE_INTERSIL:
                offset = 4;
-               if (priv->has_hostscan)
-                       atom_len = scan[0] + (scan[1] << 8);
-               else
+               if (priv->has_hostscan) {
+                       atom_len = le16_to_cpup((u16 *)scan);
+                       /* Sanity check for atom_len */
+                       if (atom_len < sizeof(struct prism2_scan_apinfo)) {
+                               printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n",
+                               dev->name, atom_len);
+                               return -EIO;
+                       }
+               } else
                        atom_len = offsetof(struct prism2_scan_apinfo, atim);
                break;
        default:
-               return 0;
+               return -EOPNOTSUPP;
        }
 
        /* Check that we got an whole number of atoms */
@@ -4074,7 +4092,7 @@ static inline int orinoco_translate_scan(struct net_device *dev,
                printk(KERN_ERR "%s: Unexpected scan data length %d, "
                       "atom_len %d, offset %d\n", dev->name, scan_len,
                       atom_len, offset);
-               return 0;
+               return -EIO;
        }
 
        /* Read the entries one by one */
@@ -4209,33 +4227,41 @@ static int orinoco_ioctl_getscan(struct net_device *dev,
                /* We have some results to push back to user space */
 
                /* Translate to WE format */
-               srq->length = orinoco_translate_scan(dev, extra,
-                                                    priv->scan_result,
-                                                    priv->scan_len);
-
-               /* Return flags */
-               srq->flags = (__u16) priv->scan_mode;
+               int ret = orinoco_translate_scan(dev, extra,
+                                                priv->scan_result,
+                                                priv->scan_len);
+
+               if (ret < 0) {
+                       err = ret;
+                       kfree(priv->scan_result);
+                       priv->scan_result = NULL;
+               } else {
+                       srq->length = ret;
 
-               /* Results are here, so scan no longer in progress */
-               priv->scan_inprogress = 0;
+                       /* Return flags */
+                       srq->flags = (__u16) priv->scan_mode;
 
-               /* In any case, Scan results will be cleaned up in the
-                * reset function and when exiting the driver.
-                * The person triggering the scanning may never come to
-                * pick the results, so we need to do it in those places.
-                * Jean II */
+                       /* In any case, Scan results will be cleaned up in the
+                        * reset function and when exiting the driver.
+                        * The person triggering the scanning may never come to
+                        * pick the results, so we need to do it in those places.
+                        * Jean II */
 
 #ifdef SCAN_SINGLE_READ
-               /* If you enable this option, only one client (the first
-                * one) will be able to read the result (and only one
-                * time). If there is multiple concurent clients that
-                * want to read scan results, this behavior is not
-                * advisable - Jean II */
-               kfree(priv->scan_result);
-               priv->scan_result = NULL;
+                       /* If you enable this option, only one client (the first
+                        * one) will be able to read the result (and only one
+                        * time). If there is multiple concurent clients that
+                        * want to read scan results, this behavior is not
+                        * advisable - Jean II */
+                       kfree(priv->scan_result);
+                       priv->scan_result = NULL;
 #endif /* SCAN_SINGLE_READ */
-               /* Here, if too much time has elapsed since last scan,
-                * we may want to clean up scan results... - Jean II */
+                       /* Here, if too much time has elapsed since last scan,
+                        * we may want to clean up scan results... - Jean II */
+               }
+
+               /* Scan is no longer in progress */
+               priv->scan_inprogress = 0;
        }
          
        orinoco_unlock(priv, &flags);
@@ -4377,6 +4403,7 @@ static const struct iw_handler_def orinoco_handler_def = {
        .standard = orinoco_handler,
        .private = orinoco_private_handler,
        .private_args = orinoco_privtab,
+       .get_wireless_stats = orinoco_get_wireless_stats,
 };
 
 static void orinoco_get_drvinfo(struct net_device *dev,