linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / net / wireless / orinoco.c
index 317ace7..6fd0bf7 100644 (file)
@@ -76,6 +76,7 @@
 
 #define DRIVER_NAME "orinoco"
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -200,12 +201,41 @@ static struct {
 /* Data types                                                       */
 /********************************************************************/
 
-/* Beginning of the Tx descriptor, used in TxExc handling */
-struct hermes_txexc_data {
-       struct hermes_tx_descriptor desc;
+/* Used in Event handling.
+ * We avoid nested structures as they break on ARM -- Moustafa */
+struct hermes_tx_descriptor_802_11 {
+       /* hermes_tx_descriptor */
+       __le16 status;
+       __le16 reserved1;
+       __le16 reserved2;
+       __le32 sw_support;
+       u8 retry_count;
+       u8 tx_rate;
+       __le16 tx_control;
+
+       /* ieee80211_hdr */
        __le16 frame_ctl;
        __le16 duration_id;
        u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+       u8 addr3[ETH_ALEN];
+       __le16 seq_ctl;
+       u8 addr4[ETH_ALEN];
+
+       __le16 data_len;
+
+       /* ethhdr */
+       u8 h_dest[ETH_ALEN];    /* destination eth addr */
+       u8 h_source[ETH_ALEN];  /* source ether addr    */
+       __be16 h_proto;         /* packet type ID field */
+
+       /* p8022_hdr */
+       u8 dsap;
+       u8 ssap;
+       u8 ctrl;
+       u8 oui[3];
+
+       __be16 ethertype;
 } __attribute__ ((packed));
 
 /* Rx frame header except compatibility 802.3 header */
@@ -360,7 +390,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
                }
        } else {
                struct {
-                       __le16 qual, signal, noise, unused;
+                       __le16 qual, signal, noise;
                } __attribute__ ((packed)) cq;
 
                err = HERMES_READ_RECORD(hw, USER_BAP,
@@ -420,39 +450,53 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
        hermes_t *hw = &priv->hw;
        int err = 0;
        u16 txfid = priv->txfid;
+       char *p;
        struct ethhdr *eh;
-       int data_off;
+       int len, data_len, data_off;
        struct hermes_tx_descriptor desc;
        unsigned long flags;
 
+       TRACE_ENTER(dev->name);
+
        if (! netif_running(dev)) {
                printk(KERN_ERR "%s: Tx on stopped device!\n",
                       dev->name);
-               return NETDEV_TX_BUSY;
+               TRACE_EXIT(dev->name);
+               return 1;
        }
        
        if (netif_queue_stopped(dev)) {
                printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", 
                       dev->name);
-               return NETDEV_TX_BUSY;
+               TRACE_EXIT(dev->name);
+               return 1;
        }
        
        if (orinoco_lock(priv, &flags) != 0) {
                printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
                       dev->name);
-               return NETDEV_TX_BUSY;
+               TRACE_EXIT(dev->name);
+               return 1;
        }
 
        if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
                /* Oops, the firmware hasn't established a connection,
                    silently drop the packet (this seems to be the
                    safest approach). */
-               goto drop;
+               stats->tx_errors++;
+               orinoco_unlock(priv, &flags);
+               dev_kfree_skb(skb);
+               TRACE_EXIT(dev->name);
+               return 0;
        }
 
-       /* Check packet length */
-       if (skb->len < ETH_HLEN)
-               goto drop;
+       /* Length of the packet body */
+       /* FIXME: what if the skb is smaller than this? */
+       len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN);
+       skb = skb_padto(skb, len);
+       if (skb == NULL)
+               goto fail;
+       len -= ETH_HLEN;
 
        eh = (struct ethhdr *)skb->data;
 
@@ -463,7 +507,8 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                if (net_ratelimit())
                        printk(KERN_ERR "%s: Error %d writing Tx descriptor "
                               "to BAP\n", dev->name, err);
-               goto busy;
+               stats->tx_errors++;
+               goto fail;
        }
 
        /* Clear the 802.11 header and data length fields - some
@@ -474,38 +519,50 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Encapsulate Ethernet-II frames */
        if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
-               struct header_struct {
-                       struct ethhdr eth;      /* 802.3 header */
-                       u8 encap[6];            /* 802.2 header */
-               } __attribute__ ((packed)) hdr;
-
-               /* Strip destination and source from the data */
-               skb_pull(skb, 2 * ETH_ALEN);
-               data_off = HERMES_802_2_OFFSET + sizeof(encaps_hdr);
-
-               /* And move them to a separate header */
-               memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
-               hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
-               memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
-
-               err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
-                                       txfid, HERMES_802_3_OFFSET);
+               struct header_struct hdr;
+               data_len = len;
+               data_off = HERMES_802_3_OFFSET + sizeof(hdr);
+               p = skb->data + ETH_HLEN;
+
+               /* 802.3 header */
+               memcpy(hdr.dest, eh->h_dest, ETH_ALEN);
+               memcpy(hdr.src, eh->h_source, ETH_ALEN);
+               hdr.len = htons(data_len + ENCAPS_OVERHEAD);
+               
+               /* 802.2 header */
+               memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr));
+                       
+               hdr.ethertype = eh->h_proto;
+               err  = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
+                                        txfid, HERMES_802_3_OFFSET);
                if (err) {
                        if (net_ratelimit())
                                printk(KERN_ERR "%s: Error %d writing packet "
                                       "header to BAP\n", dev->name, err);
-                       goto busy;
+                       stats->tx_errors++;
+                       goto fail;
                }
+               /* Actual xfer length - allow for padding */
+               len = ALIGN(data_len, 2);
+               if (len < ETH_ZLEN - ETH_HLEN)
+                       len = ETH_ZLEN - ETH_HLEN;
        } else { /* IEEE 802.3 frame */
+               data_len = len + ETH_HLEN;
                data_off = HERMES_802_3_OFFSET;
+               p = skb->data;
+               /* Actual xfer length - round up for odd length packets */
+               len = ALIGN(data_len, 2);
+               if (len < ETH_ZLEN)
+                       len = ETH_ZLEN;
        }
 
-       err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len,
+       err = hermes_bap_pwrite_pad(hw, USER_BAP, p, data_len, len,
                                txfid, data_off);
        if (err) {
                printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
                       dev->name, err);
-               goto busy;
+               stats->tx_errors++;
+               goto fail;
        }
 
        /* Finally, we actually initiate the send */
@@ -518,27 +575,25 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                if (net_ratelimit())
                        printk(KERN_ERR "%s: Error %d transmitting packet\n",
                                dev->name, err);
-               goto busy;
+               stats->tx_errors++;
+               goto fail;
        }
 
        dev->trans_start = jiffies;
-       stats->tx_bytes += data_off + skb->len;
-       goto ok;
+       stats->tx_bytes += data_off + data_len;
 
- drop:
-       stats->tx_errors++;
-       stats->tx_dropped++;
-
- ok:
        orinoco_unlock(priv, &flags);
+
        dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
 
- busy:
-       if (err == -EIO)
-               schedule_work(&priv->reset_work);
+       TRACE_EXIT(dev->name);
+
+       return 0;
+ fail:
+       TRACE_EXIT(dev->name);
+
        orinoco_unlock(priv, &flags);
-       return NETDEV_TX_BUSY;
+       return err;
 }
 
 static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
@@ -574,7 +629,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
        struct net_device_stats *stats = &priv->stats;
        u16 fid = hermes_read_regn(hw, TXCOMPLFID);
        u16 status;
-       struct hermes_txexc_data hdr;
+       struct hermes_tx_descriptor_802_11 hdr;
        int err = 0;
 
        if (fid == DUMMY_FID)
@@ -582,7 +637,8 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
 
        /* Read part of the frame header - we need status and addr1 */
        err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
-                              sizeof(struct hermes_txexc_data),
+                              offsetof(struct hermes_tx_descriptor_802_11,
+                                       addr2),
                               fid, 0);
 
        hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
@@ -602,7 +658,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
         * exceeded, because that's the only status that really mean
         * that this particular node went away.
         * Other errors means that *we* screwed up. - Jean II */
-       status = le16_to_cpu(hdr.desc.status);
+       status = le16_to_cpu(hdr.status);
        if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
                union iwreq_data        wrqu;
 
@@ -756,6 +812,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
        if (datalen > IEEE80211_DATA_LEN + 12) {
                printk(KERN_DEBUG "%s: oversized monitor frame, "
                       "data length = %d\n", dev->name, datalen);
+               err = -EIO;
                stats->rx_length_errors++;
                goto update_stats;
        }
@@ -764,7 +821,8 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
        if (!skb) {
                printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
                       dev->name);
-               goto update_stats;
+               err = -ENOMEM;
+               goto drop;
        }
 
        /* Copy the 802.11 header to the skb */
@@ -1342,12 +1400,16 @@ int __orinoco_down(struct net_device *dev)
        return 0;
 }
 
-static int orinoco_allocate_fid(struct net_device *dev)
+int orinoco_reinit_firmware(struct net_device *dev)
 {
        struct orinoco_private *priv = netdev_priv(dev);
        struct hermes *hw = &priv->hw;
        int err;
 
+       err = hermes_init(hw);
+       if (err)
+               return err;
+
        err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
        if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
                /* Try workaround for old Symbol firmware bug */
@@ -1366,19 +1428,6 @@ static int orinoco_allocate_fid(struct net_device *dev)
        return err;
 }
 
-int orinoco_reinit_firmware(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct hermes *hw = &priv->hw;
-       int err;
-
-       err = hermes_init(hw);
-       if (!err)
-               err = orinoco_allocate_fid(dev);
-
-       return err;
-}
-
 static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
 {
        hermes_t *hw = &priv->hw;
@@ -1786,9 +1835,7 @@ static int __orinoco_program_rids(struct net_device *dev)
        /* Set promiscuity / multicast*/
        priv->promiscuous = 0;
        priv->mc_count = 0;
-
-       /* FIXME: what about netif_tx_lock */
-       __orinoco_set_multicast_list(dev);
+       __orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */
 
        return 0;
 }
@@ -2227,12 +2274,14 @@ static int orinoco_init(struct net_device *dev)
        u16 reclen;
        int len;
 
+       TRACE_ENTER(dev->name);
+
        /* No need to lock, the hw_unavailable flag is already set in
         * alloc_orinocodev() */
        priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN;
 
        /* Initialize the firmware */
-       err = hermes_init(hw);
+       err = orinoco_reinit_firmware(dev);
        if (err != 0) {
                printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
                       dev->name, err);
@@ -2290,13 +2339,6 @@ static int orinoco_init(struct net_device *dev)
 
        printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
 
-       err = orinoco_allocate_fid(dev);
-       if (err) {
-               printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
-                      dev->name);
-               goto out;
-       }
-
        /* Get allowed channels */
        err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
                                  &priv->channel_mask);
@@ -2387,6 +2429,7 @@ static int orinoco_init(struct net_device *dev)
        printk(KERN_DEBUG "%s: ready\n", dev->name);
 
  out:
+       TRACE_EXIT(dev->name);
        return err;
 }
 
@@ -2754,6 +2797,8 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev,
        int numrates;
        int i, k;
 
+       TRACE_ENTER(dev->name);
+
        rrq->length = sizeof(struct iw_range);
        memset(range, 0, sizeof(struct iw_range));
 
@@ -2843,6 +2888,8 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev,
        IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
        IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
 
+       TRACE_EXIT(dev->name);
+
        return 0;
 }
 
@@ -2875,7 +2922,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       if (erq->length > 0) {
+       if (erq->pointer) {
                if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
                        index = priv->tx_key;
 
@@ -2918,7 +2965,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
        if (erq->flags & IW_ENCODE_RESTRICTED)
                restricted = 1;
 
-       if (erq->pointer && erq->length > 0) {
+       if (erq->pointer) {
                priv->keys[index].len = cpu_to_le16(xlen);
                memset(priv->keys[index].data, 0,
                       sizeof(priv->keys[index].data));
@@ -3024,6 +3071,8 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
        int err = 0;
        unsigned long flags;
 
+       TRACE_ENTER(dev->name);
+
        if (netif_running(dev)) {
                err = orinoco_hw_get_essid(priv, &active, essidbuf);
                if (err)
@@ -3038,6 +3087,8 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
        erq->flags = 1;
        erq->length = strlen(essidbuf) + 1;
 
+       TRACE_EXIT(dev->name);
+       
        return 0;
 }
 
@@ -3807,7 +3858,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
        unsigned long flags;
 
        /* Note : you may have realised that, as this is a SET operation,
-        * this is privileged and therefore a normal user can't
+        * this is priviledged and therefore a normal user can't
         * perform scanning.
         * This is not an error, while the device perform scanning,
         * traffic doesn't flow, so it's a perfect DoS...
@@ -4297,6 +4348,69 @@ static struct ethtool_ops orinoco_ethtool_ops = {
        .get_link = ethtool_op_get_link,
 };
 
+/********************************************************************/
+/* Debugging                                                        */
+/********************************************************************/
+
+#if 0
+static void show_rx_frame(struct orinoco_rxframe_hdr *frame)
+{
+       printk(KERN_DEBUG "RX descriptor:\n");
+       printk(KERN_DEBUG "  status      = 0x%04x\n", frame->desc.status);
+       printk(KERN_DEBUG "  time        = 0x%08x\n", frame->desc.time);
+       printk(KERN_DEBUG "  silence     = 0x%02x\n", frame->desc.silence);
+       printk(KERN_DEBUG "  signal      = 0x%02x\n", frame->desc.signal);
+       printk(KERN_DEBUG "  rate        = 0x%02x\n", frame->desc.rate);
+       printk(KERN_DEBUG "  rxflow      = 0x%02x\n", frame->desc.rxflow);
+       printk(KERN_DEBUG "  reserved    = 0x%08x\n", frame->desc.reserved);
+
+       printk(KERN_DEBUG "IEEE 802.11 header:\n");
+       printk(KERN_DEBUG "  frame_ctl   = 0x%04x\n",
+              frame->p80211.frame_ctl);
+       printk(KERN_DEBUG "  duration_id = 0x%04x\n",
+              frame->p80211.duration_id);
+       printk(KERN_DEBUG "  addr1       = %02x:%02x:%02x:%02x:%02x:%02x\n",
+              frame->p80211.addr1[0], frame->p80211.addr1[1],
+              frame->p80211.addr1[2], frame->p80211.addr1[3],
+              frame->p80211.addr1[4], frame->p80211.addr1[5]);
+       printk(KERN_DEBUG "  addr2       = %02x:%02x:%02x:%02x:%02x:%02x\n",
+              frame->p80211.addr2[0], frame->p80211.addr2[1],
+              frame->p80211.addr2[2], frame->p80211.addr2[3],
+              frame->p80211.addr2[4], frame->p80211.addr2[5]);
+       printk(KERN_DEBUG "  addr3       = %02x:%02x:%02x:%02x:%02x:%02x\n",
+              frame->p80211.addr3[0], frame->p80211.addr3[1],
+              frame->p80211.addr3[2], frame->p80211.addr3[3],
+              frame->p80211.addr3[4], frame->p80211.addr3[5]);
+       printk(KERN_DEBUG "  seq_ctl     = 0x%04x\n",
+              frame->p80211.seq_ctl);
+       printk(KERN_DEBUG "  addr4       = %02x:%02x:%02x:%02x:%02x:%02x\n",
+              frame->p80211.addr4[0], frame->p80211.addr4[1],
+              frame->p80211.addr4[2], frame->p80211.addr4[3],
+              frame->p80211.addr4[4], frame->p80211.addr4[5]);
+       printk(KERN_DEBUG "  data_len    = 0x%04x\n",
+              frame->p80211.data_len);
+
+       printk(KERN_DEBUG "IEEE 802.3 header:\n");
+       printk(KERN_DEBUG "  dest        = %02x:%02x:%02x:%02x:%02x:%02x\n",
+              frame->p8023.h_dest[0], frame->p8023.h_dest[1],
+              frame->p8023.h_dest[2], frame->p8023.h_dest[3],
+              frame->p8023.h_dest[4], frame->p8023.h_dest[5]);
+       printk(KERN_DEBUG "  src         = %02x:%02x:%02x:%02x:%02x:%02x\n",
+              frame->p8023.h_source[0], frame->p8023.h_source[1],
+              frame->p8023.h_source[2], frame->p8023.h_source[3],
+              frame->p8023.h_source[4], frame->p8023.h_source[5]);
+       printk(KERN_DEBUG "  len         = 0x%04x\n", frame->p8023.h_proto);
+
+       printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n");
+       printk(KERN_DEBUG "  DSAP        = 0x%02x\n", frame->p8022.dsap);
+       printk(KERN_DEBUG "  SSAP        = 0x%02x\n", frame->p8022.ssap);
+       printk(KERN_DEBUG "  ctrl        = 0x%02x\n", frame->p8022.ctrl);
+       printk(KERN_DEBUG "  OUI         = %02x:%02x:%02x\n",
+              frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]);
+       printk(KERN_DEBUG "  ethertype  = 0x%04x\n", frame->ethertype);
+}
+#endif /* 0 */
+
 /********************************************************************/
 /* Module initialization                                            */
 /********************************************************************/