Commit 435417ab authored by Simon Kelley's avatar Simon Kelley Committed by Jeff Garzik

[wireless atmel] various updates

Below is a patch against 2.6.1-rc1 which has that fix and
quite a few other components. viz:

* Bumped version to 0.9

* Dmitry Torokhov's skb-leak and netif_carrier patches.

* Added a couple of fields to /proc/driver/atmel

* Fixed failure to call unregister_netdev in a couple of error-unwind
  paths. I think this fixes the 
  unregister_netdevice: waiting for eth1 to become free.
  bugs, but I don't have definative proof.

* Remove floating-point constants just in case the compiler doesn't.

* Fixed bug in scanning.

* Added firmware versioning, driver will search through different
  available versions of firmware 'till it finds an available one.

* Changed firmware URL in configure help to a directory rather than a
  file, so I can release new named versions.

* Added support for later releases of the firmware, which are WPA aware.
  Firmware verion is automatically detected, so users who upgrade their
  kernel but not their firmware won't have problems.


The PCI support and possible WPA support will have to wait for another day.
parent 4576b4fa
......@@ -282,7 +282,7 @@ config PCMCIA_ATMEL
one of these, you will need to provide a firmware image
to be loaded into the card by the driver. The Atmel
firmware package can be downloaded from
http://www.thekelleys.org.uk/atmel/atmel_firmware.tar.gz
http://www.thekelleys.org.uk/atmel
config PCMCIA_WL3501
tristate "Planet WL3501 PCMCIA cards"
......
......@@ -67,7 +67,7 @@
#include "ieee802_11.h"
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 8
#define DRIVER_MINOR 9
MODULE_AUTHOR("Simon Kelley");
MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
......@@ -153,12 +153,15 @@ module_param(firmware, charp, 0);
#define C80211_MGMT_ElementID_ChallengeText 16
#define C80211_MGMT_CAPABILITY_ShortPreamble 0x0020
#define MIB_MAX_DATA_BYTES 212
#define MIB_HEADER_SIZE 4 /* first four fields */
struct get_set_mib {
u8 type;
u8 size;
u8 index;
u8 reserved;
u8 data[72];
u8 data[MIB_MAX_DATA_BYTES];
};
struct rx_desc {
......@@ -195,32 +198,40 @@ struct rx_desc {
struct tx_desc {
u32 NextDescriptor;
u16 TxStartOfFrame;
u16 TxLength;
u8 TxState;
u8 TxStatus;
u8 RetryCount;
u8 TxRate;
u32 TxTime;
u8 Reserved;
u8 PacketType;
u16 HostTxLength;
u32 NextDescriptor;
u16 TxStartOfFrame;
u16 TxLength;
u8 TxState;
u8 TxStatus;
u8 RetryCount;
u8 TxRate;
u8 KeyIndex;
u8 ChiperType;
u8 ChipreLength;
u8 Reserved1;
u8 Reserved;
u8 PacketType;
u16 HostTxLength;
};
#define TX_DESC_NEXT_OFFSET 0
#define TX_DESC_POS_OFFSET 4
#define TX_DESC_SIZE_OFFSET 6
#define TX_DESC_FLAGS_OFFSET 8
#define TX_DESC_STATUS_OFFSET 9
#define TX_DESC_RETRY_OFFSET 10
#define TX_DESC_RATE_OFFSET 11
#define TX_DESC_PACKET_TYPE_OFFSET 17
#define TX_DESC_HOST_LENGTH_OFFSET 18
#define TX_DESC_NEXT_OFFSET 0
#define TX_DESC_POS_OFFSET 4
#define TX_DESC_SIZE_OFFSET 6
#define TX_DESC_FLAGS_OFFSET 8
#define TX_DESC_STATUS_OFFSET 9
#define TX_DESC_RETRY_OFFSET 10
#define TX_DESC_RATE_OFFSET 11
#define TX_DESC_KEY_INDEX_OFFSET 12
#define TX_DESC_CIPHER_TYPE_OFFSET 13
#define TX_DESC_CIPHER_LENGTH_OFFSET 14
#define TX_DESC_PACKET_TYPE_OFFSET 17
#define TX_DESC_HOST_LENGTH_OFFSET 18
......@@ -324,6 +335,9 @@ struct tx_desc {
#define ACTIVE_MODE 1
#define PS_MODE 2
#define MAX_ENCRYPTION_KEYS 4
#define MAX_ENCRYPTION_KEY_SIZE 40
///////////////////////////////////////////////////////////////////////////
// 802.11 related definitions
///////////////////////////////////////////////////////////////////////////
......@@ -370,6 +384,14 @@ struct tx_desc {
#define IFACE_FUNC_CTRL_OFFSET 28
#define IFACE_MAC_STAT_OFFSET 30
#define IFACE_GENERIC_INT_TYPE_OFFSET 32
#define CIPHER_SUITE_NONE 0
#define CIPHER_SUITE_WEP_64 1
#define CIPHER_SUITE_TKIP 2
#define CIPHER_SUITE_AES 3
#define CIPHER_SUITE_CCX 4
#define CIPHER_SUITE_WEP_128 5
//
// IFACE MACROS & definitions
//
......@@ -432,6 +454,7 @@ struct atmel_private {
void *card; /* Bus dependent stucture varies for PCcard */
int (*present_callback)(void *); /* And callback which uses it */
char firmware_id[32];
char firmware_template[32];
unsigned char *firmware;
int firmware_length;
struct timer_list management_timer;
......@@ -457,20 +480,11 @@ struct atmel_private {
u16 frag_seq, frag_len, frag_no;
u8 frag_source[6];
int wep_key_len[4]; /* need to know these and not stored in Mib. */
struct { /* NB this is matched to the hardware, don't change. */
u8 wep_is_on;
u8 default_key; /* 0..3 */
u8 reserved;
u8 exclude_unencrypted;
u32 WEPICV_error_count;
u32 WEP_excluded_count;
u8 wep_keys[4][13];
u8 encryption_level; /* 0, 1, 2 */
u8 reserved2[3];
} wep;
u8 wep_is_on, default_key, exclude_unencrypted, encryption_level;
u8 group_cipher_suite, pairwise_cipher_suite;
u8 wep_keys[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE];
int wep_key_len[MAX_ENCRYPTION_KEYS];
int use_wpa;
u16 host_info_base;
struct host_info_struct {
......@@ -510,8 +524,6 @@ struct atmel_private {
STATION_STATE_ASSOCIATING,
STATION_STATE_READY,
STATION_STATE_REASSOCIATING,
STATION_STATE_FORCED_JOINNING,
STATION_STATE_FORCED_JOIN_FAILURE,
STATION_STATE_DOWN,
STATION_STATE_NO_CARD,
STATION_STATE_MGMT_ERROR
......@@ -564,6 +576,7 @@ struct atmel_private {
static u8 atmel_basic_rates[4] = {0x82,0x84,0x0b,0x16};
static void build_wpa_mib(struct atmel_private *priv);
static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *src, u16 len);
static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, u16 src, u16 len);
......@@ -717,14 +730,54 @@ static u16 find_tx_buff(struct atmel_private *priv, u16 len)
return 0;
}
static void tx_update_descriptor(struct atmel_private *priv, u16 len, u16 buff, u8 type)
static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, u16 len, u16 buff, u8 type)
{
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff);
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len);
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len);
if (!priv->use_wpa)
atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0);
if (priv->use_wpa) {
int cipher_type, cipher_length;
if (is_bcast) {
cipher_type = priv->group_cipher_suite;
if (cipher_type == CIPHER_SUITE_WEP_64 ||
cipher_type == CIPHER_SUITE_WEP_128 )
cipher_length = 8;
else if (cipher_type == CIPHER_SUITE_TKIP)
cipher_length = 12;
else if (priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_64 ||
priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_128) {
cipher_type = priv->pairwise_cipher_suite;
cipher_length = 8;
} else {
cipher_type = CIPHER_SUITE_NONE;
cipher_length = 0;
}
} else {
cipher_type = priv->pairwise_cipher_suite;
if (cipher_type == CIPHER_SUITE_WEP_64 ||
cipher_type == CIPHER_SUITE_WEP_128 )
cipher_length = 8;
else if (cipher_type == CIPHER_SUITE_TKIP)
cipher_length = 12;
else if (priv->group_cipher_suite == CIPHER_SUITE_WEP_64 ||
priv->group_cipher_suite == CIPHER_SUITE_WEP_128) {
cipher_type = priv->group_cipher_suite;
cipher_length = 8;
} else {
cipher_type = CIPHER_SUITE_NONE;
cipher_length = 0;
}
}
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_TYPE_OFFSET, priv->tx_desc_tail),
cipher_type);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_LENGTH_OFFSET, priv->tx_desc_tail),
cipher_length);
}
atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L);
atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN);
if (priv->tx_desc_previous != priv->tx_desc_tail)
......@@ -745,16 +798,19 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
struct ieee802_11_hdr header;
unsigned long flags;
u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
if(priv->station_state != STATION_STATE_READY) {
u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
if (priv->station_state != STATION_STATE_READY) {
priv->stats.tx_errors++;
goto done;
dev_kfree_skb(skb);
return 0;
}
if (priv->card && priv->present_callback &&
!(*priv->present_callback)(priv->card)) {
priv->stats.tx_errors++;
goto done;
dev_kfree_skb(skb);
return 0;
}
/* first ensure the timer func cannot run */
......@@ -778,7 +834,7 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
frame_ctl = IEEE802_11_FTYPE_DATA;
header.duration_id = 0;
header.seq_ctl = 0;
if (priv->wep.wep_is_on)
if (priv->wep_is_on)
frame_ctl |= IEEE802_11_FCTL_WEP;
if (priv->operating_mode == IW_MODE_ADHOC) {
memcpy(&header.addr1, skb->data, 6);
......@@ -791,6 +847,9 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
memcpy(&header.addr3, skb->data, 6);
}
if (priv->use_wpa)
memcpy(&header.addr4, SNAP_RFC1024, 6);
header.frame_ctl = cpu_to_le16(frame_ctl);
/* Copy the wireless header into the card */
atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE);
......@@ -798,14 +857,13 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12);
priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE;
tx_update_descriptor(priv, len + 18, buff, TX_PACKET_TYPE_DATA);
/* low bit of first byte of destination tells us if broadcast */
tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA);
dev->trans_start = jiffies;
priv->stats.tx_bytes += len;
spin_unlock_irqrestore(&priv->irqlock, flags);
spin_unlock_bh(&priv->timerlock);
done:
dev_kfree_skb(skb);
return 0;
......@@ -824,7 +882,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv,
atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET);
atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len);
priv->tx_buff_tail += len;
tx_update_descriptor(priv, len, buff, TX_PACKET_TYPE_MGMT);
tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT);
}
static void fast_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header,
......@@ -1027,7 +1085,7 @@ static void rx_done_irq(struct atmel_private *priv)
/* probe for CRC use here if needed once five packets have arrived with
the same crc status, we assume we know what's happening and stop probing */
if (priv->probe_crc) {
if (!priv->wep.wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP)) {
if (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP)) {
priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size);
} else {
priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24);
......@@ -1042,7 +1100,7 @@ static void rx_done_irq(struct atmel_private *priv)
}
/* don't CRC header when WEP in use */
if (priv->do_rx_crc && (!priv->wep.wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP))) {
if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP))) {
crc = crc32_le(0xffffffff, (unsigned char *)&header, 24);
}
msdu_size -= 24; /* header */
......@@ -1158,6 +1216,9 @@ static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs
reset_irq_status(priv, ISR_IBSS_MERGE);
atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS,
priv->CurrentBSSID, 6);
/* The WPA stuff cares about the current AP address */
if (priv->use_wpa)
build_wpa_mib(priv);
} else if (isr & ISR_GENERIC_IRQ) {
reset_irq_status(priv, ISR_GENERIC_IRQ);
printk(KERN_INFO "%s: Generic_irq recieved.\n", dev->name);
......@@ -1237,6 +1298,7 @@ static int atmel_close (struct net_device *dev)
{
struct atmel_private *priv = (struct atmel_private *) dev->priv;
netif_carrier_off(dev);
if (netif_running(dev))
netif_stop_queue(dev);
......@@ -1255,17 +1317,17 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
p += sprintf(p, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR);
if (priv->station_state != STATION_STATE_DOWN) {
p += sprintf(p, "Firmware version:\t%d.%d build %d ",
p += sprintf(p, "Firmware version:\t%d.%d build %d\nFirmware location:\t",
priv->host_info.major_version,
priv->host_info.minor_version,
priv->host_info.build_version);
if (priv->card_type != CARD_TYPE_EEPROM)
p += sprintf(p, "[built-in]\n");
p += sprintf(p, "on card\n");
else if (priv->firmware)
p += sprintf(p, "[%s loaded by host]\n", priv->firmware_id);
p += sprintf(p, "%s loaded by host\n", priv->firmware_id);
else
p += sprintf(p, "[%s loaded by hotplug]\n", priv->firmware_id);
p += sprintf(p, "%s loaded by hotplug\n", priv->firmware_id);
switch(priv->card_type) {
case CARD_TYPE_PARALLEL_FLASH: c = "Parallel flash"; break;
......@@ -1289,6 +1351,8 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
p += sprintf(p, "Regulatory domain:\t%s\n", r);
p += sprintf(p, "Host CRC checking:\t%s\n",
priv->do_rx_crc ? "On" : "Off");
p += sprintf(p, "WPA-capable firmware:\t%s\n",
priv->use_wpa ? "Yes" : "No");
}
switch(priv->station_state) {
......@@ -1299,8 +1363,6 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
case STATION_STATE_ASSOCIATING: s = "Associating"; break;
case STATION_STATE_READY: s = "Ready"; break;
case STATION_STATE_REASSOCIATING: s = "Reassociating"; break;
case STATION_STATE_FORCED_JOINNING: s = "Forced joining"; break;
case STATION_STATE_FORCED_JOIN_FAILURE: s = "Forced join failure"; break;
case STATION_STATE_NO_CARD: s = "No card"; break;
case STATION_STATE_MGMT_ERROR: s = "Management error"; break;
case STATION_STATE_DOWN: s = "Down"; break;
......@@ -1348,12 +1410,12 @@ struct net_device *init_atmel_card( unsigned short irq, int port, char *firmware
priv->present_callback = card_present;
priv->card = card;
priv->firmware = NULL;
priv->firmware_id[0] = '\0';
priv->firmware_template[0] = '\0';
if (firmware) /* module parameter */
strcpy(priv->firmware_id, firmware);
else if (firmware_id) /* from PCMCIA card-matching or PCI */
strcpy(priv->firmware_id, firmware_id);
else
priv->firmware_id[0] = '\0';
strcpy(priv->firmware_template, firmware_id);
priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI;
priv->station_state = STATION_STATE_DOWN;
priv->is3com = is3com;
......@@ -1389,9 +1451,16 @@ struct net_device *init_atmel_card( unsigned short irq, int port, char *firmware
priv->rts_threshold = 2347;
priv->short_retry = 7;
priv->long_retry = 4;
priv->wep.wep_is_on = 0;
priv->wep.default_key = 0;
priv->wep.encryption_level = 0;
priv->wep_is_on = 0;
priv->default_key = 0;
priv->encryption_level = 0;
priv->exclude_unencrypted = 0;
priv->group_cipher_suite = priv->pairwise_cipher_suite = CIPHER_SUITE_NONE;
priv->use_wpa = 0;
memset(priv->wep_keys, 0, sizeof(priv->wep_keys));
memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
priv->default_beacon_period = priv->beacon_period = 100;
priv->listen_interval = 1;
......@@ -1426,8 +1495,12 @@ struct net_device *init_atmel_card( unsigned short irq, int port, char *firmware
if (register_netdev(dev))
goto err_out_res;
if (!probe_atmel_card(dev))
if (!probe_atmel_card(dev)){
unregister_netdev(dev);
goto err_out_res;
}
netif_carrier_off(dev);
create_proc_read_entry ("driver/atmel", 0, 0, atmel_read_proc, priv);
......@@ -1443,7 +1516,7 @@ struct net_device *init_atmel_card( unsigned short irq, int port, char *firmware
err_out_irq:
free_irq(dev->irq, dev);
err_out_free:
kfree(dev);
free_netdev(dev);
return NULL;
}
......@@ -1582,7 +1655,7 @@ static int atmel_set_encode(struct net_device *dev,
* don't do it. - Jean II */
if (dwrq->length > 0) {
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
int current_index = priv->wep.default_key;
int current_index = priv->default_key;
/* Check the size of the key */
if (dwrq->length > 13) {
return -EINVAL;
......@@ -1591,7 +1664,7 @@ static int atmel_set_encode(struct net_device *dev,
if (index < 0 || index >= 4)
index = current_index;
else
priv->wep.default_key = index;
priv->default_key = index;
/* Set the length */
if (dwrq->length > 5)
priv->wep_key_len[index] = 13;
......@@ -1604,27 +1677,30 @@ static int atmel_set_encode(struct net_device *dev,
/* Check if the key is not marked as invalid */
if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
/* Cleanup */
memset(priv->wep.wep_keys[index], 0, 13);
memset(priv->wep_keys[index], 0, 13);
/* Copy the key in the driver */
memcpy(priv->wep.wep_keys[index], extra, dwrq->length);
memcpy(priv->wep_keys[index], extra, dwrq->length);
}
/* WE specify that if a valid key is set, encryption
* should be enabled (user may turn it off later)
* This is also how "iwconfig ethX key on" works */
if (index == current_index &&
priv->wep_key_len[index] > 0) {
priv->wep.wep_is_on = 1;
priv->wep.exclude_unencrypted = 1;
if (priv->wep_key_len[index] > 5)
priv->wep.encryption_level = 2;
else
priv->wep.encryption_level = 1;
priv->wep_is_on = 1;
priv->exclude_unencrypted = 1;
if (priv->wep_key_len[index] > 5) {
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
priv->encryption_level = 2;
} else {
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
priv->encryption_level = 1;
}
}
} else {
/* Do we want to just set the transmit key index ? */
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
if ( index>=0 && index < 4 ) {
priv->wep.default_key = index;
priv->default_key = index;
} else
/* Don't complain if only change the mode */
if(!dwrq->flags & IW_ENCODE_MODE) {
......@@ -1633,19 +1709,23 @@ static int atmel_set_encode(struct net_device *dev,
}
/* Read the flags */
if(dwrq->flags & IW_ENCODE_DISABLED) {
priv->wep.wep_is_on = 0;
priv->wep.encryption_level = 0;
priv->wep_is_on = 0;
priv->encryption_level = 0;
priv->pairwise_cipher_suite = CIPHER_SUITE_NONE;
} else {
priv->wep.wep_is_on = 1;
if (priv->wep_key_len[priv->wep.default_key] > 5)
priv->wep.encryption_level = 2;
else
priv->wep.encryption_level = 1;
priv->wep_is_on = 1;
if (priv->wep_key_len[priv->default_key] > 5) {
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
priv->encryption_level = 2;
} else {
priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
priv->encryption_level = 1;
}
}
if(dwrq->flags & IW_ENCODE_RESTRICTED)
priv->wep.exclude_unencrypted = 1;
priv->exclude_unencrypted = 1;
if(dwrq->flags & IW_ENCODE_OPEN)
priv->wep.exclude_unencrypted = 0;
priv->exclude_unencrypted = 0;
return -EINPROGRESS; /* Call commit handler */
}
......@@ -1659,16 +1739,16 @@ static int atmel_get_encode(struct net_device *dev,
struct atmel_private *priv = dev->priv;
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
if (!priv->wep.wep_is_on)
if (!priv->wep_is_on)
dwrq->flags = IW_ENCODE_DISABLED;
else if (priv->wep.exclude_unencrypted)
else if (priv->exclude_unencrypted)
dwrq->flags = IW_ENCODE_RESTRICTED;
else
dwrq->flags = IW_ENCODE_OPEN;
/* Which key do we want ? -1 -> tx index */
if (index < 0 || index >= 4)
index = priv->wep.default_key;
index = priv->default_key;
dwrq->flags |= index + 1;
/* Copy the key to the user buffer */
dwrq->length = priv->wep_key_len[index];
......@@ -1676,7 +1756,7 @@ static int atmel_get_encode(struct net_device *dev,
dwrq->length=0;
} else {
memset(extra, 0, 16);
memcpy(extra, priv->wep.wep_keys[index], dwrq->length);
memcpy(extra, priv->wep_keys[index], dwrq->length);
}
return 0;
......@@ -1711,10 +1791,10 @@ static int atmel_set_rate(struct net_device *dev,
} else {
/* Setting by frequency value */
switch (vwrq->value) {
case (int)1e6: priv->tx_rate = 0; break;
case (int)2e6: priv->tx_rate = 1; break;
case (int)5.5e6: priv->tx_rate = 2; break;
case (int)11e6: priv->tx_rate = 3; break;
case 1000000: priv->tx_rate = 0; break;
case 2000000: priv->tx_rate = 1; break;
case 5500000: priv->tx_rate = 2; break;
case 11000000: priv->tx_rate = 3; break;
default: return -EINVAL;
}
}
......@@ -1757,14 +1837,14 @@ static int atmel_get_rate(struct net_device *dev,
if (priv->auto_tx_rate) {
vwrq->fixed = 0;
vwrq->value = 11e6;
vwrq->value = 11000000;
} else {
vwrq->fixed = 1;
switch(priv->tx_rate) {
case 0: vwrq->value = 1e6; break;
case 1: vwrq->value = 2e6; break;
case 2: vwrq->value = 5.5e6; break;
case 3: vwrq->value = 11e6; break;
case 0: vwrq->value = 1000000; break;
case 1: vwrq->value = 2000000; break;
case 2: vwrq->value = 5500000; break;
case 3: vwrq->value = 11000000; break;
}
}
return 0;
......@@ -1982,6 +2062,7 @@ static int atmel_set_scan(struct net_device *dev,
atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */
del_timer_sync(&priv->management_timer);
priv->fast_scan = 0;
atmel_scan(priv, 0);
atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */
......@@ -2073,10 +2154,10 @@ static int atmel_get_range(struct net_device *dev,
range->max_qual.noise = 0;
range->sensitivity = 0;
range->bitrate[0] = 1e6;
range->bitrate[1] = 2e6;
range->bitrate[2] = 5.5e6;
range->bitrate[3] = 11e6;
range->bitrate[0] = 1000000;
range->bitrate[1] = 2000000;
range->bitrate[2] = 5500000;
range->bitrate[3] = 11000000;
range->num_bitrates = 4;
range->min_rts = 0;
......@@ -2129,9 +2210,9 @@ static int atmel_set_wap(struct net_device *dev,
for(i=0; i<priv->BSS_list_entries; i++) {
if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) {
if (!priv->wep.wep_is_on && priv->BSSinfo[i].UsingWEP) {
if (!priv->wep_is_on && priv->BSSinfo[i].UsingWEP) {
return -EINVAL;
} else if (priv->wep.wep_is_on && !priv->BSSinfo[i].UsingWEP) {
} else if (priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) {
return -EINVAL;
} else
atmel_join_bss(priv, i);
......@@ -2313,10 +2394,13 @@ static void atmel_enter_state(struct atmel_private *priv, int new_state)
if (new_state == old_state)
return;
if (new_state == STATION_STATE_READY)
if (new_state == STATION_STATE_READY) {
netif_start_queue(priv->dev);
netif_carrier_on(priv->dev);
}
if (old_state == STATION_STATE_READY) {
netif_carrier_off(priv->dev);
netif_stop_queue(priv->dev);
priv->last_beacon_timestamp = 0;
}
......@@ -2453,7 +2537,7 @@ static void send_authentication_request(struct atmel_private *priv, u8 *challeng
memcpy(header.addr2, priv->dev->dev_addr, 6);
memcpy(header.addr3, priv->CurrentBSSID, 6);
if (priv->wep.wep_is_on) {
if (priv->wep_is_on) {
auth.alg = C80211_MGMT_AAN_SHAREDKEY;
/* no WEP for authentication frames with TrSeqNo 1 */
if (priv->CurrentAuthentTransactionSeqNum != 1)
......@@ -2504,7 +2588,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
memcpy(header.addr3, priv->CurrentBSSID, 6);
body.capability = cpu_to_le16(C80211_MGMT_CAPABILITY_ESS);
if (priv->wep.wep_is_on)
if (priv->wep_is_on)
body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_Privacy);
if (priv->preamble == SHORT_PREAMBLE)
body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_ShortPreamble);
......@@ -2555,8 +2639,8 @@ static int retrieve_bss(struct atmel_private *priv)
priv->current_BSS = 0;
for(i=0; i<priv->BSS_list_entries; i++) {
if (priv->operating_mode == priv->BSSinfo[i].BSStype &&
((!priv->wep.wep_is_on && !priv->BSSinfo[i].UsingWEP) ||
(priv->wep.wep_is_on && priv->BSSinfo[i].UsingWEP)) &&
((!priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) ||
(priv->wep_is_on && priv->BSSinfo[i].UsingWEP)) &&
!(priv->BSSinfo[i].channel & 0x80)) {
max_rssi = priv->BSSinfo[i].RSSI;
priv->current_BSS = max_index = i;
......@@ -2630,7 +2714,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
u16 status = le16_to_cpu(auth->status);
u16 trans_seq_no = le16_to_cpu(auth->trans_seq);
if (status == C80211_MGMT_SC_Success && !priv->wep.wep_is_on) {
if (status == C80211_MGMT_SC_Success && !priv->wep_is_on) {
/* no WEP */
if (priv->station_was_associated) {
atmel_enter_state(priv, STATION_STATE_REASSOCIATING);
......@@ -2643,7 +2727,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
}
}
if (status == C80211_MGMT_SC_Success && priv->wep.wep_is_on) {
if (status == C80211_MGMT_SC_Success && priv->wep_is_on) {
/* WEP */
if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum)
return;
......@@ -2765,6 +2849,10 @@ void atmel_join_bss(struct atmel_private *priv, int bss_index)
memcpy(priv->CurrentBSSID, bss->BSSID, 6);
memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize);
/* The WPA stuff cares about the current AP address */
if (priv->use_wpa)
build_wpa_mib(priv);
/* When switching to AdHoc turn OFF Power Save if needed */
......@@ -2786,13 +2874,13 @@ void atmel_join_bss(struct atmel_private *priv, int bss_index)
atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, bss->preamble);
}
if (!priv->wep.wep_is_on && bss->UsingWEP) {
if (!priv->wep_is_on && bss->UsingWEP) {
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
priv->station_is_associated = 0;
return;
}
if (priv->wep.wep_is_on && !bss->UsingWEP) {
if (priv->wep_is_on && !bss->UsingWEP) {
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
priv->station_is_associated = 0;
return;
......@@ -3071,6 +3159,7 @@ static void atmel_command_irq(struct atmel_private *priv)
priv->fast_scan = !fast_scan;
atmel_scan(priv, 1);
}
priv->site_survey_state = SITE_SURVEY_COMPLETED;
}
break;
......@@ -3104,12 +3193,8 @@ static void atmel_command_irq(struct atmel_private *priv)
return;
}
if (priv->station_state == STATION_STATE_FORCED_JOINNING) {
atmel_enter_state(priv, STATION_STATE_FORCED_JOIN_FAILURE);
} else {
atmel_scan(priv, 1);
}
atmel_scan(priv, 1);
}
}
......@@ -3275,7 +3360,7 @@ static int probe_atmel_card(struct net_device *dev)
printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name);
memcpy(dev->dev_addr, default_mac, 6);
}
printk(KERN_INFO "%s: MAC address %x:%x:%x:%x:%x:%x\n",
printk(KERN_INFO "%s: MAC address %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
dev->name,
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
......@@ -3285,6 +3370,105 @@ static int probe_atmel_card(struct net_device *dev)
return rc;
}
static void build_wep_mib(struct atmel_private *priv)
/* Move the encyption information on the MIB structure.
This routine is for the pre-WPA firmware: later firmware has
a different format MIB and a different routine. */
{
struct { /* NB this is matched to the hardware, don't change. */
u8 wep_is_on;
u8 default_key; /* 0..3 */
u8 reserved;
u8 exclude_unencrypted;
u32 WEPICV_error_count;
u32 WEP_excluded_count;
u8 wep_keys[MAX_ENCRYPTION_KEYS][13];
u8 encryption_level; /* 0, 1, 2 */
u8 reserved2[3];
} mib;
int i;
mib.wep_is_on = priv->wep_is_on;
if (priv->wep_is_on) {
if (priv->wep_key_len[priv->default_key] > 5)
mib.encryption_level = 2;
else
mib.encryption_level = 1;
} else {
mib.encryption_level = 0;
}
mib.default_key = priv->default_key;
mib.exclude_unencrypted = priv->exclude_unencrypted;
for(i = 0; i < MAX_ENCRYPTION_KEYS; i++)
memcpy(mib.wep_keys[i], priv->wep_keys[i], 13);
atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib));
}
static void build_wpa_mib(struct atmel_private *priv)
{
/* This is for the later (WPA enabled) firmware. */
struct { /* NB this is matched to the hardware, don't change. */
u8 cipher_default_key_value[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE];
u8 receiver_address[6];
u8 wep_is_on;
u8 default_key; /* 0..3 */
u8 group_key;
u8 exclude_unencrypted;
u8 encryption_type;
u8 reserved;
u32 WEPICV_error_count;
u32 WEP_excluded_count;
u8 key_RSC[4][8];
} mib;
int i;
mib.wep_is_on = priv->wep_is_on;
mib.exclude_unencrypted = priv->exclude_unencrypted;
memcpy(mib.receiver_address, priv->CurrentBSSID, 6);
/* zero all the keys before adding in valid ones. */
memset(mib.cipher_default_key_value, 0, sizeof(mib.cipher_default_key_value));
if (priv->wep_is_on) {
/* There's a comment in the Atmel code to the effect that this is only valid
when still using WEP, it may need to be set to something to use WPA */
memset(mib.key_RSC, 0, sizeof(mib.key_RSC));
mib.default_key = mib.group_key = 255;
for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) {
if (priv->wep_key_len[i] > 0) {
memcpy(mib.cipher_default_key_value[i], priv->wep_keys[i], MAX_ENCRYPTION_KEY_SIZE);
if (i == priv->default_key) {
mib.default_key = i;
mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 7;
mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->pairwise_cipher_suite;
} else {
mib.group_key = i;
priv->group_cipher_suite = priv->pairwise_cipher_suite;
mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1;
mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->group_cipher_suite;
}
}
}
if (mib.default_key == 255)
mib.default_key = mib.group_key != 255 ? mib.group_key : 0;
if (mib.group_key == 255)
mib.group_key = mib.default_key;
}
atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib));
}
int reset_atmel_card(struct net_device *dev)
{
/* do everything necessary to wake up the hardware, including
......@@ -3305,6 +3489,15 @@ int reset_atmel_card(struct net_device *dev)
struct atmel_private *priv = dev->priv;
u8 configuration;
/* data to add to the firmware names, in priority order
this implemenents firmware versioning */
static char *firmware_modifier[] = {
"-wpa",
"",
NULL
};
if (priv->station_state == STATION_STATE_NO_CARD ||
priv->station_state == STATION_STATE_DOWN)
return 0;
......@@ -3341,21 +3534,41 @@ int reset_atmel_card(struct net_device *dev)
unsigned char *fw;
int len = priv->firmware_length;
if (!(fw = priv->firmware)) {
if (strlen(priv->firmware_id) == 0) {
printk(KERN_INFO
"%s: card type is unknown: assuming at76c502 firmware is OK.\n",
dev->name);
printk(KERN_INFO
"%s: if not, use the firmware= module parameter.\n",
dev->name);
strcpy(priv->firmware_id, "atmel_at76c502.bin");
}
if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) != 0) {
printk(KERN_ALERT
"%s: firmware %s is missing, cannot start.\n",
dev->name, priv->firmware_id);
return 0;
if (strlen(priv->firmware_template) == 0) {
if (strlen(priv->firmware_id) == 0) {
printk(KERN_INFO
"%s: card type is unknown: assuming at76c502 firmware is OK.\n",
dev->name);
printk(KERN_INFO
"%s: if not, use the firmware= module parameter.\n",
dev->name);
strcpy(priv->firmware_id, "atmel_at76c502.bin");
}
if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) != 0) {
printk(KERN_ALERT
"%s: firmware %s is missing, cannot continue.\n",
dev->name, priv->firmware_id);
return 0;
}
} else {
int i;
for (i = 0; firmware_modifier[i]; i++) {
sprintf(priv->firmware_id, priv->firmware_template, firmware_modifier[i]);
if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0)
break;
}
if (!firmware_modifier[i]) {
printk(KERN_ALERT
"%s: firmware %s is missing, cannot start.\n",
dev->name, priv->firmware_id);
priv->firmware_id[0] = '\0';
return 0;
}
priv->firmware_template[0] = '\0';
}
fw = fw_entry->data;
len = fw_entry->size;
}
......@@ -3379,6 +3592,10 @@ int reset_atmel_card(struct net_device *dev)
if (!atmel_wakeup_firmware(priv))
return 0;
/* Check the version and set the correct flag for wpa stuff,
old and new firmware is incompatible. */
priv->use_wpa = (priv->host_info.major_version >= 4);
/* unmask all irq sources */
atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff);
......@@ -3447,9 +3664,12 @@ int reset_atmel_card(struct net_device *dev)
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1);
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period);
atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4);
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep.wep_is_on);
atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&priv->wep, sizeof(priv->wep));
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep_is_on);
if (priv->use_wpa)
build_wpa_mib(priv);
else
build_wep_mib(priv);
atmel_scan(priv, 1);
atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */
......@@ -3500,8 +3720,8 @@ static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index)
m.size = 1;
m.index = index;
atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, sizeof(m));
return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + 4));
atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + 1);
return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE));
}
static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data)
......@@ -3512,7 +3732,7 @@ static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 dat
m.index = index;
m.data[0] = data;
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m));
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 1);
}
static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 data)
......@@ -3524,7 +3744,7 @@ static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 d
m.data[0] = data;
m.data[1] = data >> 8;
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m));
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 2);
}
static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len)
......@@ -3534,8 +3754,11 @@ static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *dat
m.size = data_len;
m.index = index;
if (data_len > MIB_MAX_DATA_BYTES)
printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name);
memcpy(m.data, data, data_len);
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m));
atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + data_len);
}
static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len)
......@@ -3545,10 +3768,14 @@ static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *dat
m.size = data_len;
m.index = index;
atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, sizeof(m));
atmel_copy_to_host(priv->dev, data, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + 4), data_len);
}
if (data_len > MIB_MAX_DATA_BYTES)
printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name);
atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + data_len);
atmel_copy_to_host(priv->dev, data,
atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE), data_len);
}
static void atmel_writeAR(struct net_device *dev, u16 data)
{
int i;
......
......@@ -330,20 +330,20 @@ static struct {
char *firmware;
char *name;
} card_table[] = {
{ 0, 0, "WLAN/802.11b PC CARD", "atmel_at76c502d.bin", "Actiontec 802CAT1" },
{ 0, 0, "ATMEL/AT76C502AR", "atmel_at76c502.bin", "NoName-RFMD" },
{ 0, 0, "ATMEL/AT76C502AR_D", "atmel_at76c502d.bin", "NoName-revD" },
{ 0, 0, "ATMEL/AT76C502AR_E", "atmel_at76c502e.bin", "NoName-revE" },
{ 0, 0, "ATMEL/AT76C504", "atmel_at76c504.bin", "NoName-504" },
{ MANFID_3COM, 0x0620, NULL, "atmel_at76c502_3com.bin", "3com 3CRWE62092B" },
{ MANFID_3COM, 0x0696, NULL, "atmel_at76c502_3com.bin", "3com 3CRSHPW_96" },
{ 0, 0, "SMC/2632W-V2", "atmel_at76c502.bin", "SMC 2632W-V2" },
{ 0, 0, "SMC/2632W", "atmel_at76c502d.bin", "SMC 2632W-V3" },
{ 0xd601, 0x0007, NULL, "atmel_at76c502.bin", "Sitecom WLAN-011"}, /* suspect - from a usenet posting. */
{ 0x01bf, 0x3302, NULL, "atmel_at76c502d.bin", "Belkin F5D6060u"}, /* " " " " " */
{ 0, 0, "BT/Voyager 1020 Laptop Adapter", "atmel_at76c502.bin", "BT Voyager 1020"},
{ 0, 0, "IEEE 802.11b/Wireless LAN PC Card", "atmel_at76c502.bin", "Siemens Gigaset PC Card II" },
{ 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", "atmel_at76c502e.bin", "CNet CNWLC-811ARL" }
{ 0, 0, "WLAN/802.11b PC CARD", "atmel_at76c502d%s.bin", "Actiontec 802CAT1" },
{ 0, 0, "ATMEL/AT76C502AR", "atmel_at76c502%s.bin", "NoName-RFMD" },
{ 0, 0, "ATMEL/AT76C502AR_D", "atmel_at76c502d%s.bin", "NoName-revD" },
{ 0, 0, "ATMEL/AT76C502AR_E", "atmel_at76c502e%s.bin", "NoName-revE" },
{ 0, 0, "ATMEL/AT76C504", "atmel_at76c504%s.bin", "NoName-504" },
{ MANFID_3COM, 0x0620, NULL, "atmel_at76c502_3com%s.bin", "3com 3CRWE62092B" },
{ MANFID_3COM, 0x0696, NULL, "atmel_at76c502_3com%s.bin", "3com 3CRSHPW_96" },
{ 0, 0, "SMC/2632W-V2", "atmel_at76c502%s.bin", "SMC 2632W-V2" },
{ 0, 0, "SMC/2632W", "atmel_at76c502d%s.bin", "SMC 2632W-V3" },
{ 0xd601, 0x0007, NULL, "atmel_at76c502%s.bin", "Sitecom WLAN-011"}, /* suspect - from a usenet posting. */
{ 0x01bf, 0x3302, NULL, "atmel_at76c502d%s.bin", "Belkin F5D6060u"}, /* " " " " " */
{ 0, 0, "BT/Voyager 1020 Laptop Adapter", "atmel_at76c502%s.bin", "BT Voyager 1020"},
{ 0, 0, "IEEE 802.11b/Wireless LAN PC Card", "atmel_at76c502%s.bin", "Siemens Gigaset PC Card II" },
{ 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", "atmel_at76c502e%s.bin", "CNet CNWLC-811ARL" }
};
/* This is strictly temporary, until PCMCIA devices get integrated into the device model. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment