#define DRIVER_NAME "orinoco"
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
/* 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 */
}
} else {
struct {
- __le16 qual, signal, noise, unused;
+ __le16 qual, signal, noise;
} __attribute__ ((packed)) cq;
err = HERMES_READ_RECORD(hw, USER_BAP,
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;
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
/* 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 */
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)
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)
/* 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);
* 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;
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;
}
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 */
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 */
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;
/* 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;
}
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);
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);
printk(KERN_DEBUG "%s: ready\n", dev->name);
out:
+ TRACE_EXIT(dev->name);
return err;
}
int numrates;
int i, k;
+ TRACE_ENTER(dev->name);
+
rrq->length = sizeof(struct iw_range);
memset(range, 0, sizeof(struct iw_range));
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
+ TRACE_EXIT(dev->name);
+
return 0;
}
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;
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));
int err = 0;
unsigned long flags;
+ TRACE_ENTER(dev->name);
+
if (netif_running(dev)) {
err = orinoco_hw_get_essid(priv, &active, essidbuf);
if (err)
erq->flags = 1;
erq->length = strlen(essidbuf) + 1;
+ TRACE_EXIT(dev->name);
+
return 0;
}
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...
.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 */
/********************************************************************/