|
|
|
@ -199,7 +199,6 @@ struct rx_desc {
|
|
|
|
|
u8 PreambleType;
|
|
|
|
|
u16 Duration;
|
|
|
|
|
u32 RxTime;
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define RX_DESC_FLAG_VALID 0x80
|
|
|
|
@ -218,7 +217,6 @@ struct rx_desc {
|
|
|
|
|
#define RX_DESC_DURATION_OFFSET 14
|
|
|
|
|
#define RX_DESC_RX_TIME_OFFSET 16
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct tx_desc {
|
|
|
|
|
u32 NextDescriptor;
|
|
|
|
|
u16 TxStartOfFrame;
|
|
|
|
@ -238,10 +236,8 @@ struct tx_desc {
|
|
|
|
|
u8 Reserved;
|
|
|
|
|
u8 PacketType;
|
|
|
|
|
u16 HostTxLength;
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define TX_DESC_NEXT_OFFSET 0
|
|
|
|
|
#define TX_DESC_POS_OFFSET 4
|
|
|
|
|
#define TX_DESC_SIZE_OFFSET 6
|
|
|
|
@ -255,8 +251,6 @@ struct tx_desc {
|
|
|
|
|
#define TX_DESC_PACKET_TYPE_OFFSET 17
|
|
|
|
|
#define TX_DESC_HOST_LENGTH_OFFSET 18
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
// Host-MAC interface
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
@ -266,7 +260,6 @@ struct tx_desc {
|
|
|
|
|
#define TX_FIRM_OWN 0x80
|
|
|
|
|
#define TX_DONE 0x40
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define TX_ERROR 0x01
|
|
|
|
|
|
|
|
|
|
#define TX_PACKET_TYPE_DATA 0x01
|
|
|
|
@ -282,7 +275,6 @@ struct tx_desc {
|
|
|
|
|
#define ISR_IBSS_MERGE 0x40 // (4.1.2.30): IBSS merge
|
|
|
|
|
#define ISR_GENERIC_IRQ 0x80
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define Local_Mib_Type 0x01
|
|
|
|
|
#define Mac_Address_Mib_Type 0x02
|
|
|
|
|
#define Mac_Mib_Type 0x03
|
|
|
|
@ -317,7 +309,6 @@ struct tx_desc {
|
|
|
|
|
#define LOCAL_MIB_PREAMBLE_TYPE 9
|
|
|
|
|
#define MAC_ADDR_MIB_MAC_ADDR_POS 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define CMD_Set_MIB_Vars 0x01
|
|
|
|
|
#define CMD_Get_MIB_Vars 0x02
|
|
|
|
|
#define CMD_Scan 0x03
|
|
|
|
@ -338,7 +329,6 @@ struct tx_desc {
|
|
|
|
|
#define CMD_STATUS_HOST_ERROR 0xFF
|
|
|
|
|
#define CMD_STATUS_BUSY 0xFE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define CMD_BLOCK_COMMAND_OFFSET 0
|
|
|
|
|
#define CMD_BLOCK_STATUS_OFFSET 1
|
|
|
|
|
#define CMD_BLOCK_PARAMETERS_OFFSET 4
|
|
|
|
@ -398,7 +388,6 @@ struct tx_desc {
|
|
|
|
|
#define PROM_MODE_CTRL 0x10
|
|
|
|
|
#define PROM_MODE_BAD_PROTOCOL 0x20
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define IFACE_INT_STATUS_OFFSET 0
|
|
|
|
|
#define IFACE_INT_MASK_OFFSET 1
|
|
|
|
|
#define IFACE_LOCKOUT_HOST_OFFSET 2
|
|
|
|
@ -590,7 +579,6 @@ struct atmel_private {
|
|
|
|
|
u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH];
|
|
|
|
|
u64 last_beacon_timestamp;
|
|
|
|
|
u8 rx_buf[MAX_WIRELESS_BODY];
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static u8 atmel_basic_rates[4] = {0x82,0x84,0x0b,0x16};
|
|
|
|
@ -610,27 +598,37 @@ static const struct {
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
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);
|
|
|
|
|
static void atmel_set_gcr(struct net_device *dev, u16 mask);
|
|
|
|
|
static void atmel_clear_gcr(struct net_device *dev, u16 mask);
|
|
|
|
|
static int atmel_lock_mac(struct atmel_private *priv);
|
|
|
|
|
static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data);
|
|
|
|
|
static void atmel_command_irq(struct atmel_private *priv);
|
|
|
|
|
static int atmel_validate_channel(struct atmel_private *priv, int channel);
|
|
|
|
|
static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
|
|
|
|
|
static void atmel_management_frame(struct atmel_private *priv,
|
|
|
|
|
struct ieee80211_hdr_4addr *header,
|
|
|
|
|
u16 frame_len, u8 rssi);
|
|
|
|
|
static void atmel_management_timer(u_long a);
|
|
|
|
|
static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size);
|
|
|
|
|
static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size);
|
|
|
|
|
static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
|
|
|
|
|
static void atmel_send_command(struct atmel_private *priv, int command,
|
|
|
|
|
void *cmd, int cmd_size);
|
|
|
|
|
static int atmel_send_command_wait(struct atmel_private *priv, int command,
|
|
|
|
|
void *cmd, int cmd_size);
|
|
|
|
|
static void atmel_transmit_management_frame(struct atmel_private *priv,
|
|
|
|
|
struct ieee80211_hdr_4addr *header,
|
|
|
|
|
u8 *body, int body_len);
|
|
|
|
|
|
|
|
|
|
static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index);
|
|
|
|
|
static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data);
|
|
|
|
|
static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 data);
|
|
|
|
|
static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len);
|
|
|
|
|
static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len);
|
|
|
|
|
static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index,
|
|
|
|
|
u8 data);
|
|
|
|
|
static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index,
|
|
|
|
|
u16 data);
|
|
|
|
|
static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index,
|
|
|
|
|
u8 *data, int data_len);
|
|
|
|
|
static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index,
|
|
|
|
|
u8 *data, int data_len);
|
|
|
|
|
static void atmel_scan(struct atmel_private *priv, int specific_ssid);
|
|
|
|
|
static void atmel_join_bss(struct atmel_private *priv, int bss_index);
|
|
|
|
|
static void atmel_smooth_qual(struct atmel_private *priv);
|
|
|
|
@ -714,7 +712,6 @@ static void tx_done_irq(struct atmel_private *priv)
|
|
|
|
|
atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE &&
|
|
|
|
|
i < priv->host_info.tx_desc_count;
|
|
|
|
|
i++) {
|
|
|
|
|
|
|
|
|
|
u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head));
|
|
|
|
|
u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head));
|
|
|
|
|
u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head));
|
|
|
|
@ -762,7 +759,8 @@ static u16 find_tx_buff(struct atmel_private *priv, u16 len)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, 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);
|
|
|
|
@ -776,7 +774,7 @@ static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, u16 l
|
|
|
|
|
if (is_bcast) {
|
|
|
|
|
cipher_type = priv->group_cipher_suite;
|
|
|
|
|
if (cipher_type == CIPHER_SUITE_WEP_64 ||
|
|
|
|
|
cipher_type == CIPHER_SUITE_WEP_128 )
|
|
|
|
|
cipher_type == CIPHER_SUITE_WEP_128)
|
|
|
|
|
cipher_length = 8;
|
|
|
|
|
else if (cipher_type == CIPHER_SUITE_TKIP)
|
|
|
|
|
cipher_length = 12;
|
|
|
|
@ -791,7 +789,7 @@ static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, u16 l
|
|
|
|
|
} else {
|
|
|
|
|
cipher_type = priv->pairwise_cipher_suite;
|
|
|
|
|
if (cipher_type == CIPHER_SUITE_WEP_64 ||
|
|
|
|
|
cipher_type == CIPHER_SUITE_WEP_128 )
|
|
|
|
|
cipher_type == CIPHER_SUITE_WEP_128)
|
|
|
|
|
cipher_length = 8;
|
|
|
|
|
else if (cipher_type == CIPHER_SUITE_TKIP)
|
|
|
|
|
cipher_length = 12;
|
|
|
|
@ -815,16 +813,15 @@ static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, u16 l
|
|
|
|
|
if (priv->tx_desc_previous != priv->tx_desc_tail)
|
|
|
|
|
atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0);
|
|
|
|
|
priv->tx_desc_previous = priv->tx_desc_tail;
|
|
|
|
|
if (priv->tx_desc_tail < (priv->host_info.tx_desc_count -1 ))
|
|
|
|
|
if (priv->tx_desc_tail < (priv->host_info.tx_desc_count - 1))
|
|
|
|
|
priv->tx_desc_tail++;
|
|
|
|
|
else
|
|
|
|
|
priv->tx_desc_tail = 0;
|
|
|
|
|
priv->tx_desc_free--;
|
|
|
|
|
priv->tx_free_mem -= len;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int start_tx (struct sk_buff *skb, struct net_device *dev)
|
|
|
|
|
static int start_tx(struct sk_buff *skb, struct net_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct atmel_private *priv = netdev_priv(dev);
|
|
|
|
|
struct ieee80211_hdr_4addr header;
|
|
|
|
@ -852,8 +849,9 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
|
|
|
|
|
/* nb doing the above in the opposite order will deadlock */
|
|
|
|
|
|
|
|
|
|
/* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the
|
|
|
|
|
12 first bytes (containing DA/SA) and put them in the appropriate fields of
|
|
|
|
|
the Wireless Header. Thus the packet length is then the initial + 18 (+30-12) */
|
|
|
|
|
12 first bytes (containing DA/SA) and put them in the appropriate
|
|
|
|
|
fields of the Wireless Header. Thus the packet length is then the
|
|
|
|
|
initial + 18 (+30-12) */
|
|
|
|
|
|
|
|
|
|
if (!(buff = find_tx_buff(priv, len + 18))) {
|
|
|
|
|
priv->stats.tx_dropped++;
|
|
|
|
@ -917,7 +915,8 @@ static void atmel_transmit_management_frame(struct atmel_private *priv,
|
|
|
|
|
tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
|
|
|
|
|
static void fast_rx_path(struct atmel_private *priv,
|
|
|
|
|
struct ieee80211_hdr_4addr *header,
|
|
|
|
|
u16 msdu_size, u16 rx_packet_loc, u32 crc)
|
|
|
|
|
{
|
|
|
|
|
/* fast path: unfragmented packet copy directly into skbuf */
|
|
|
|
@ -960,7 +959,7 @@ static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr
|
|
|
|
|
else
|
|
|
|
|
memcpy(&skbp[6], header->addr2, 6); /* source address */
|
|
|
|
|
|
|
|
|
|
priv->dev->last_rx=jiffies;
|
|
|
|
|
priv->dev->last_rx = jiffies;
|
|
|
|
|
skb->dev = priv->dev;
|
|
|
|
|
skb->protocol = eth_type_trans(skb, priv->dev);
|
|
|
|
|
skb->ip_summed = CHECKSUM_NONE;
|
|
|
|
@ -970,7 +969,8 @@ static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test to see if the packet in card memory at packet_loc has a valid CRC
|
|
|
|
|
It doesn't matter that this is slow: it is only used to proble the first few packets. */
|
|
|
|
|
It doesn't matter that this is slow: it is only used to proble the first few
|
|
|
|
|
packets. */
|
|
|
|
|
static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size)
|
|
|
|
|
{
|
|
|
|
|
int i = msdu_size - 4;
|
|
|
|
@ -990,8 +990,10 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size)
|
|
|
|
|
return (crc ^ 0xffffffff) == netcrc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
|
|
|
|
|
u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags)
|
|
|
|
|
static void frag_rx_path(struct atmel_private *priv,
|
|
|
|
|
struct ieee80211_hdr_4addr *header,
|
|
|
|
|
u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no,
|
|
|
|
|
u8 frag_no, int more_frags)
|
|
|
|
|
{
|
|
|
|
|
u8 mac4[6];
|
|
|
|
|
u8 source[6];
|
|
|
|
@ -1074,7 +1076,6 @@ static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr
|
|
|
|
|
priv->stats.rx_packets++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else
|
|
|
|
|
priv->wstats.discard.fragment++;
|
|
|
|
|
}
|
|
|
|
@ -1114,8 +1115,9 @@ static void rx_done_irq(struct atmel_private *priv)
|
|
|
|
|
frame_ctl = le16_to_cpu(header.frame_ctl);
|
|
|
|
|
seq_control = le16_to_cpu(header.seq_ctl);
|
|
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
|
/* 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_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED)) {
|
|
|
|
|
priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size);
|
|
|
|
@ -1138,12 +1140,11 @@ static void rx_done_irq(struct atmel_private *priv)
|
|
|
|
|
msdu_size -= 24; /* header */
|
|
|
|
|
|
|
|
|
|
if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
|
|
|
|
|
|
|
|
|
|
int more_fragments = frame_ctl & IEEE80211_FCTL_MOREFRAGS;
|
|
|
|
|
u8 packet_fragment_no = seq_control & IEEE80211_SCTL_FRAG;
|
|
|
|
|
u16 packet_sequence_no = (seq_control & IEEE80211_SCTL_SEQ) >> 4;
|
|
|
|
|
|
|
|
|
|
if (!more_fragments && packet_fragment_no == 0 ) {
|
|
|
|
|
if (!more_fragments && packet_fragment_no == 0) {
|
|
|
|
|
fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc);
|
|
|
|
|
} else {
|
|
|
|
|
frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc,
|
|
|
|
@ -1172,7 +1173,7 @@ static void rx_done_irq(struct atmel_private *priv)
|
|
|
|
|
atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next:
|
|
|
|
|
next:
|
|
|
|
|
/* release descriptor */
|
|
|
|
|
atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED);
|
|
|
|
|
|
|
|
|
@ -1200,7 +1201,6 @@ static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs
|
|
|
|
|
ISR_GENERIC_IRQ
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (priv->card && priv->present_callback &&
|
|
|
|
|
!(*priv->present_callback)(priv->card))
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
@ -1291,14 +1291,13 @@ static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct net_device_stats *atmel_get_stats (struct net_device *dev)
|
|
|
|
|
static struct net_device_stats *atmel_get_stats(struct net_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct atmel_private *priv = netdev_priv(dev);
|
|
|
|
|
return &priv->stats;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct iw_statistics *atmel_get_wireless_stats (struct net_device *dev)
|
|
|
|
|
static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct atmel_private *priv = netdev_priv(dev);
|
|
|
|
|
|
|
|
|
@ -1329,7 +1328,7 @@ static struct iw_statistics *atmel_get_wireless_stats (struct net_device *dev)
|
|
|
|
|
priv->wstats.miss.beacon = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (&priv->wstats);
|
|
|
|
|
return &priv->wstats;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int atmel_change_mtu(struct net_device *dev, int new_mtu)
|
|
|
|
@ -1350,7 +1349,7 @@ static int atmel_set_mac_address(struct net_device *dev, void *p)
|
|
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(atmel_open);
|
|
|
|
|
|
|
|
|
|
int atmel_open (struct net_device *dev)
|
|
|
|
|
int atmel_open(struct net_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct atmel_private *priv = netdev_priv(dev);
|
|
|
|
|
int i, channel;
|
|
|
|
@ -1404,7 +1403,7 @@ int atmel_open (struct net_device *dev)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int atmel_close (struct net_device *dev)
|
|
|
|
|
static int atmel_close(struct net_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct atmel_private *priv = netdev_priv(dev);
|
|
|
|
|
|
|
|
|
@ -1439,10 +1438,12 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
|
|
|
|
|
char *p = buf;
|
|
|
|
|
char *s, *r, *c;
|
|
|
|
|
|
|
|
|
|
p += sprintf(p, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR);
|
|
|
|
|
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\nFirmware location:\t",
|
|
|
|
|
p += sprintf(p, "Firmware version:\t%d.%d build %d\n"
|
|
|
|
|
"Firmware location:\t",
|
|
|
|
|
priv->host_info.major_version,
|
|
|
|
|
priv->host_info.minor_version,
|
|
|
|
|
priv->host_info.build_version);
|
|
|
|
@ -1450,18 +1451,19 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
|
|
|
|
|
if (priv->card_type != CARD_TYPE_EEPROM)
|
|
|
|
|
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) {
|
|
|
|
|
switch (priv->card_type) {
|
|
|
|
|
case CARD_TYPE_PARALLEL_FLASH: c = "Parallel flash"; break;
|
|
|
|
|
case CARD_TYPE_SPI_FLASH: c = "SPI flash\n"; break;
|
|
|
|
|
case CARD_TYPE_EEPROM: c = "EEPROM"; break;
|
|
|
|
|
default: c = "<unknown>";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r = "<unknown>";
|
|
|
|
|
for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++)
|
|
|
|
|
if (priv->reg_domain == channel_table[i].reg_domain)
|
|
|
|
@ -1504,9 +1506,12 @@ static int atmel_read_proc(char *page, char **start, off_t off,
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct net_device *init_atmel_card( unsigned short irq, unsigned long port, const AtmelFWType fw_type,
|
|
|
|
|
struct device *sys_dev, int (*card_present)(void *), void *card)
|
|
|
|
|
struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
|
|
|
|
|
const AtmelFWType fw_type,
|
|
|
|
|
struct device *sys_dev,
|
|
|
|
|
int (*card_present)(void *), void *card)
|
|
|
|
|
{
|
|
|
|
|
struct proc_dir_entry *ent;
|
|
|
|
|
struct net_device *dev;
|
|
|
|
|
struct atmel_private *priv;
|
|
|
|
|
int rc;
|
|
|
|
@ -1601,7 +1606,7 @@ struct net_device *init_atmel_card( unsigned short irq, unsigned long port, cons
|
|
|
|
|
SET_NETDEV_DEV(dev, sys_dev);
|
|
|
|
|
|
|
|
|
|
if ((rc = request_irq(dev->irq, service_interrupt, SA_SHIRQ, dev->name, dev))) {
|
|
|
|
|
printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc );
|
|
|
|
|
printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc);
|
|
|
|
|
goto err_out_free;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1620,7 +1625,9 @@ struct net_device *init_atmel_card( unsigned short irq, unsigned long port, cons
|
|
|
|
|
|
|
|
|
|
netif_carrier_off(dev);
|
|
|
|
|
|
|
|
|
|
create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv);
|
|
|
|
|
ent = create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv);
|
|
|
|
|
if (!ent)
|
|
|
|
|
printk(KERN_WARNING "atmel: unable to create /proc entry.\n");
|
|
|
|
|
|
|
|
|
|
printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
|
|
|
|
|
dev->name, DRIVER_MAJOR, DRIVER_MINOR,
|
|
|
|
@ -1630,11 +1637,11 @@ struct net_device *init_atmel_card( unsigned short irq, unsigned long port, cons
|
|
|
|
|
SET_MODULE_OWNER(dev);
|
|
|
|
|
return dev;
|
|
|
|
|
|
|
|
|
|
err_out_res:
|
|
|
|
|
err_out_res:
|
|
|
|
|
release_region( dev->base_addr, 32);
|
|
|
|
|
err_out_irq:
|
|
|
|
|
err_out_irq:
|
|
|
|
|
free_irq(dev->irq, dev);
|
|
|
|
|
err_out_free:
|
|
|
|
|
err_out_free:
|
|
|
|
|
free_netdev(dev);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
@ -1678,7 +1685,7 @@ static int atmel_set_essid(struct net_device *dev,
|
|
|
|
|
|
|
|
|
|
/* Check the size of the string */
|
|
|
|
|
if (dwrq->length > MAX_SSID_LENGTH + 1)
|
|
|
|
|
return -E2BIG ;
|
|
|
|
|
return -E2BIG;
|
|
|
|
|
if (index != 0)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
@ -1783,16 +1790,16 @@ static int atmel_set_encode(struct net_device *dev,
|
|
|
|
|
} else {
|
|
|
|
|
/* Do we want to just set the transmit key index ? */
|
|
|
|
|
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
|
|
|
|
|
if ( index>=0 && index < 4 ) {
|
|
|
|
|
if (index >= 0 && index < 4) {
|
|
|
|
|
priv->default_key = index;
|
|
|
|
|
} else
|
|
|
|
|
/* Don't complain if only change the mode */
|
|
|
|
|
if(!dwrq->flags & IW_ENCODE_MODE) {
|
|
|
|
|
if (!dwrq->flags & IW_ENCODE_MODE) {
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Read the flags */
|
|
|
|
|
if(dwrq->flags & IW_ENCODE_DISABLED) {
|
|
|
|
|
if (dwrq->flags & IW_ENCODE_DISABLED) {
|
|
|
|
|
priv->wep_is_on = 0;
|
|
|
|
|
priv->encryption_level = 0;
|
|
|
|
|
priv->pairwise_cipher_suite = CIPHER_SUITE_NONE;
|
|
|
|
@ -1806,7 +1813,7 @@ static int atmel_set_encode(struct net_device *dev,
|
|
|
|
|
priv->encryption_level = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(dwrq->flags & IW_ENCODE_RESTRICTED)
|
|
|
|
|
if (dwrq->flags & IW_ENCODE_RESTRICTED)
|
|
|
|
|
priv->exclude_unencrypted = 1;
|
|
|
|
|
if(dwrq->flags & IW_ENCODE_OPEN)
|
|
|
|
|
priv->exclude_unencrypted = 0;
|
|
|
|
@ -1814,7 +1821,6 @@ static int atmel_set_encode(struct net_device *dev,
|
|
|
|
|
return -EINPROGRESS; /* Call commit handler */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int atmel_get_encode(struct net_device *dev,
|
|
|
|
|
struct iw_request_info *info,
|
|
|
|
|
struct iw_point *dwrq,
|
|
|
|
@ -1870,7 +1876,7 @@ static int atmel_set_rate(struct net_device *dev,
|
|
|
|
|
priv->auto_tx_rate = 0;
|
|
|
|
|
|
|
|
|
|
/* Which type of value ? */
|
|
|
|
|
if((vwrq->value < 4) && (vwrq->value >= 0)) {
|
|
|
|
|
if ((vwrq->value < 4) && (vwrq->value >= 0)) {
|
|
|
|
|
/* Setting by rate index */
|
|
|
|
|
priv->tx_rate = vwrq->value;
|
|
|
|
|
} else {
|
|
|
|
@ -1963,8 +1969,8 @@ static int atmel_set_retry(struct net_device *dev,
|
|
|
|
|
{
|
|
|
|
|
struct atmel_private *priv = netdev_priv(dev);
|
|
|
|
|
|
|
|
|
|
if(!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) {
|
|
|
|
|
if(vwrq->flags & IW_RETRY_MAX)
|
|
|
|
|
if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) {
|
|
|
|
|
if (vwrq->flags & IW_RETRY_MAX)
|
|
|
|
|
priv->long_retry = vwrq->value;
|
|
|
|
|
else if (vwrq->flags & IW_RETRY_MIN)
|
|
|
|
|
priv->short_retry = vwrq->value;
|
|
|
|
@ -1989,13 +1995,13 @@ static int atmel_get_retry(struct net_device *dev,
|
|
|
|
|
vwrq->disabled = 0; /* Can't be disabled */
|
|
|
|
|
|
|
|
|
|
/* Note : by default, display the min retry number */
|
|
|
|
|
if((vwrq->flags & IW_RETRY_MAX)) {
|
|
|
|
|
if (vwrq->flags & IW_RETRY_MAX) {
|
|
|
|
|
vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
|
|
|
|
|
vwrq->value = priv->long_retry;
|
|
|
|
|
} else {
|
|
|
|
|
vwrq->flags = IW_RETRY_LIMIT;
|
|
|
|
|
vwrq->value = priv->short_retry;
|
|
|
|
|
if(priv->long_retry != priv->short_retry)
|
|
|
|
|
if (priv->long_retry != priv->short_retry)
|
|
|
|
|
vwrq->flags |= IW_RETRY_MIN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2010,9 +2016,9 @@ static int atmel_set_rts(struct net_device *dev,
|
|
|
|
|
struct atmel_private *priv = netdev_priv(dev);
|
|
|
|
|
int rthr = vwrq->value;
|
|
|
|
|
|
|
|
|
|
if(vwrq->disabled)
|
|
|
|
|
if (vwrq->disabled)
|
|
|
|
|
rthr = 2347;
|
|
|
|
|
if((rthr < 0) || (rthr > 2347)) {
|
|
|
|
|
if ((rthr < 0) || (rthr > 2347)) {
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
priv->rts_threshold = rthr;
|
|
|
|
@ -2042,9 +2048,9 @@ static int atmel_set_frag(struct net_device *dev,
|
|
|
|
|
struct atmel_private *priv = netdev_priv(dev);
|
|
|
|
|
int fthr = vwrq->value;
|
|
|
|
|
|
|
|
|
|
if(vwrq->disabled)
|
|
|
|
|
if (vwrq->disabled)
|
|
|
|
|
fthr = 2346;
|
|
|
|
|
if((fthr < 256) || (fthr > 2346)) {
|
|
|
|
|
if ((fthr < 256) || (fthr > 2346)) {
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
fthr &= ~0x1; /* Get an even value - is it really needed ??? */
|
|
|
|
@ -2079,19 +2085,19 @@ static int atmel_set_freq(struct net_device *dev,
|
|
|
|
|
int rc = -EINPROGRESS; /* Call commit handler */
|
|
|
|
|
|
|
|
|
|
/* If setting by frequency, convert to a channel */
|
|
|
|
|
if((fwrq->e == 1) &&
|
|
|
|
|
if ((fwrq->e == 1) &&
|
|
|
|
|
(fwrq->m >= (int) 241200000) &&
|
|
|
|
|
(fwrq->m <= (int) 248700000)) {
|
|
|
|
|
int f = fwrq->m / 100000;
|
|
|
|
|
int c = 0;
|
|
|
|
|
while((c < 14) && (f != frequency_list[c]))
|
|
|
|
|
while ((c < 14) && (f != frequency_list[c]))
|
|
|
|
|
c++;
|
|
|
|
|
/* Hack to fall through... */
|
|
|
|
|
fwrq->e = 0;
|
|
|
|
|
fwrq->m = c + 1;
|
|
|
|
|
}
|
|
|
|
|
/* Setting by channel number */
|
|
|
|
|
if((fwrq->m > 1000) || (fwrq->e > 0))
|
|
|
|
|
if ((fwrq->m > 1000) || (fwrq->e > 0))
|
|
|
|
|
rc = -EOPNOTSUPP;
|
|
|
|
|
else {
|
|
|
|
|
int channel = fwrq->m;
|
|
|
|
@ -2167,7 +2173,7 @@ static int atmel_get_scan(struct net_device *dev,
|
|
|
|
|
if (priv->site_survey_state != SITE_SURVEY_COMPLETED)
|
|
|
|
|
return -EAGAIN;
|
|
|
|
|
|
|
|
|
|
for(i=0; i<priv->BSS_list_entries; i++) {
|
|
|
|
|
for (i = 0; i < priv->BSS_list_entries; i++) {
|
|
|
|
|
iwe.cmd = SIOCGIWAP;
|
|
|
|
|
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
|
|
|
|
memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6);
|
|
|
|
@ -2196,7 +2202,6 @@ static int atmel_get_scan(struct net_device *dev,
|
|
|
|
|
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
|
|
|
|
iwe.u.data.length = 0;
|
|
|
|
|
current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, NULL);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Length of data */
|
|
|
|
@ -2213,7 +2218,7 @@ static int atmel_get_range(struct net_device *dev,
|
|
|
|
|
{
|
|
|
|
|
struct atmel_private *priv = netdev_priv(dev);
|
|
|
|
|
struct iw_range *range = (struct iw_range *) extra;
|
|
|
|
|
int k,i,j;
|
|
|
|
|
int k, i, j;
|
|
|
|
|
|
|
|
|
|
dwrq->length = sizeof(struct iw_range);
|
|
|
|
|
memset(range, 0, sizeof(struct iw_range));
|
|
|
|
@ -2226,9 +2231,9 @@ static int atmel_get_range(struct net_device *dev,
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (range->num_channels != 0) {
|
|
|
|
|
for(k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) {
|
|
|
|
|
for (k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) {
|
|
|
|
|
range->freq[k].i = i; /* List index */
|
|
|
|
|
range->freq[k].m = frequency_list[i-1] * 100000;
|
|
|
|
|
range->freq[k].m = frequency_list[i - 1] * 100000;
|
|
|
|
|
range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */
|
|
|
|
|
}
|
|
|
|
|
range->num_frequency = k;
|
|
|
|
@ -2298,7 +2303,7 @@ static int atmel_set_wap(struct net_device *dev,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(i=0; i<priv->BSS_list_entries; i++) {
|
|
|
|
|
for (i = 0; i < priv->BSS_list_entries; i++) {
|
|
|
|
|
if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) {
|
|
|
|
|
if (!priv->wep_is_on && priv->BSSinfo[i].UsingWEP) {
|
|
|
|
|
return -EINVAL;
|
|
|
|
@ -2375,7 +2380,6 @@ static const iw_handler atmel_handler[] =
|
|
|
|
|
(iw_handler) atmel_get_power, /* SIOCGIWPOWER */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const iw_handler atmel_private_handler[] =
|
|
|
|
|
{
|
|
|
|
|
NULL, /* SIOCIWFIRSTPRIV */
|
|
|
|
@ -2387,7 +2391,6 @@ typedef struct atmel_priv_ioctl {
|
|
|
|
|
unsigned short len;
|
|
|
|
|
} atmel_priv_ioctl;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define ATMELFWL SIOCIWFIRSTPRIV
|
|
|
|
|
#define ATMELIDIFC ATMELFWL + 1
|
|
|
|
|
#define ATMELRD ATMELFWL + 2
|
|
|
|
@ -2395,10 +2398,24 @@ typedef struct atmel_priv_ioctl {
|
|
|
|
|
#define REGDOMAINSZ 20
|
|
|
|
|
|
|
|
|
|
static const struct iw_priv_args atmel_private_args[] = {
|
|
|
|
|
/*{ cmd, set_args, get_args, name } */
|
|
|
|
|
{ ATMELFWL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (atmel_priv_ioctl), IW_PRIV_TYPE_NONE, "atmelfwl" },
|
|
|
|
|
{ ATMELIDIFC, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "atmelidifc" },
|
|
|
|
|
{ ATMELRD, IW_PRIV_TYPE_CHAR | REGDOMAINSZ, IW_PRIV_TYPE_NONE, "regdomain" },
|
|
|
|
|
{
|
|
|
|
|
.cmd = ATMELFWL,
|
|
|
|
|
.set_args = IW_PRIV_TYPE_BYTE
|
|
|
|
|
| IW_PRIV_SIZE_FIXED
|
|
|
|
|
| sizeof (atmel_priv_ioctl),
|
|
|
|
|
.get_args = IW_PRIV_TYPE_NONE,
|
|
|
|
|
.name = "atmelfwl"
|
|
|
|
|
}, {
|
|
|
|
|
.cmd = ATMELIDIFC,
|
|
|
|
|
.set_args = IW_PRIV_TYPE_NONE,
|
|
|
|
|
.get_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
|
|
|
|
|
.name = "atmelidifc"
|
|
|
|
|
}, {
|
|
|
|
|
.cmd = ATMELRD,
|
|
|
|
|
.set_args = IW_PRIV_TYPE_CHAR | REGDOMAINSZ,
|
|
|
|
|
.get_args = IW_PRIV_TYPE_NONE,
|
|
|
|
|
.name = "regdomain"
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct iw_handler_def atmel_handler_def =
|
|
|
|
@ -2419,7 +2436,7 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
|
|
|
|
atmel_priv_ioctl com;
|
|
|
|
|
struct iwreq *wrq = (struct iwreq *) rq;
|
|
|
|
|
unsigned char *new_firmware;
|
|
|
|
|
char domain[REGDOMAINSZ+1];
|
|
|
|
|
char domain[REGDOMAINSZ + 1];
|
|
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case ATMELIDIFC:
|
|
|
|
@ -2594,7 +2611,6 @@ static void join(struct atmel_private *priv, int type)
|
|
|
|
|
atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void start(struct atmel_private *priv, int type)
|
|
|
|
|
{
|
|
|
|
|
struct {
|
|
|
|
@ -2615,7 +2631,8 @@ static void start(struct atmel_private *priv, int type)
|
|
|
|
|
atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 channel)
|
|
|
|
|
static void handle_beacon_probe(struct atmel_private *priv, u16 capability,
|
|
|
|
|
u8 channel)
|
|
|
|
|
{
|
|
|
|
|
int rejoin = 0;
|
|
|
|
|
int new = capability & C80211_MGMT_CAPABILITY_ShortPreamble ?
|
|
|
|
@ -2644,8 +2661,8 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 c
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void send_authentication_request(struct atmel_private *priv, u16 system, u8 *challenge, int challenge_len)
|
|
|
|
|
static void send_authentication_request(struct atmel_private *priv, u16 system,
|
|
|
|
|
u8 *challenge, int challenge_len)
|
|
|
|
|
{
|
|
|
|
|
struct ieee80211_hdr_4addr header;
|
|
|
|
|
struct auth_body auth;
|
|
|
|
@ -2722,7 +2739,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
|
|
|
|
|
bodysize = 12 + priv->SSID_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssid_el_p[0]= C80211_MGMT_ElementID_SSID;
|
|
|
|
|
ssid_el_p[0] = C80211_MGMT_ElementID_SSID;
|
|
|
|
|
ssid_el_p[1] = priv->SSID_size;
|
|
|
|
|
memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size);
|
|
|
|
|
ssid_el_p[2 + priv->SSID_size] = C80211_MGMT_ElementID_SupportedRates;
|
|
|
|
@ -2732,7 +2749,8 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
|
|
|
|
|
atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr_4addr *header)
|
|
|
|
|
static int is_frame_from_current_bss(struct atmel_private *priv,
|
|
|
|
|
struct ieee80211_hdr_4addr *header)
|
|
|
|
|
{
|
|
|
|
|
if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
|
|
|
|
|
return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0;
|
|
|
|
@ -2750,11 +2768,12 @@ static int retrieve_bss(struct atmel_private *priv)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if (priv->connect_to_any_BSS) {
|
|
|
|
|
/* Select a BSS with the max-RSSI but of the same type and of the same WEP mode
|
|
|
|
|
and that it is not marked as 'bad' (i.e. we had previously failed to connect to
|
|
|
|
|
this BSS with the settings that we currently use) */
|
|
|
|
|
/* Select a BSS with the max-RSSI but of the same type and of
|
|
|
|
|
the same WEP mode and that it is not marked as 'bad' (i.e.
|
|
|
|
|
we had previously failed to connect to this BSS with the
|
|
|
|
|
settings that we currently use) */
|
|
|
|
|
priv->current_BSS = 0;
|
|
|
|
|
for(i=0; i<priv->BSS_list_entries; i++) {
|
|
|
|
|
for (i = 0; i < priv->BSS_list_entries; i++) {
|
|
|
|
|
if (priv->operating_mode == priv->BSSinfo[i].BSStype &&
|
|
|
|
|
((!priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) ||
|
|
|
|
|
(priv->wep_is_on && priv->BSSinfo[i].UsingWEP)) &&
|
|
|
|
@ -2762,12 +2781,11 @@ static int retrieve_bss(struct atmel_private *priv)
|
|
|
|
|
max_rssi = priv->BSSinfo[i].RSSI;
|
|
|
|
|
priv->current_BSS = max_index = i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return max_index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(i=0; i<priv->BSS_list_entries; i++) {
|
|
|
|
|
for (i = 0; i < priv->BSS_list_entries; i++) {
|
|
|
|
|
if (priv->SSID_size == priv->BSSinfo[i].SSIDsize &&
|
|
|
|
|
memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 &&
|
|
|
|
|
priv->operating_mode == priv->BSSinfo[i].BSStype &&
|
|
|
|
@ -2781,10 +2799,10 @@ static int retrieve_bss(struct atmel_private *priv)
|
|
|
|
|
return max_index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
|
|
|
|
|
u16 capability, u16 beacon_period, u8 channel, u8 rssi,
|
|
|
|
|
u8 ssid_len, u8 *ssid, int is_beacon)
|
|
|
|
|
static void store_bss_info(struct atmel_private *priv,
|
|
|
|
|
struct ieee80211_hdr_4addr *header, u16 capability,
|
|
|
|
|
u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len,
|
|
|
|
|
u8 *ssid, int is_beacon)
|
|
|
|
|
{
|
|
|
|
|
u8 *bss = capability & C80211_MGMT_CAPABILITY_ESS ? header->addr2 : header->addr3;
|
|
|
|
|
int i, index;
|
|
|
|
@ -2886,7 +2904,6 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
priv->AuthenticationRequestRetryCnt = 0;
|
|
|
|
|
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
|
|
|
|
|
priv->station_is_associated = 0;
|
|
|
|
@ -2916,16 +2933,22 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype)
|
|
|
|
|
else
|
|
|
|
|
priv->ReAssociationRequestRetryCnt = 0;
|
|
|
|
|
|
|
|
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff);
|
|
|
|
|
atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len);
|
|
|
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type,
|
|
|
|
|
MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff);
|
|
|
|
|
atmel_set_mib(priv, Phy_Mib_Type,
|
|
|
|
|
PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len);
|
|
|
|
|
if (priv->power_mode == 0) {
|
|
|
|
|
priv->listen_interval = 1;
|
|
|
|
|
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE);
|
|
|
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1);
|
|
|
|
|
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type,
|
|
|
|
|
MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE);
|
|
|
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type,
|
|
|
|
|
MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1);
|
|
|
|
|
} else {
|
|
|
|
|
priv->listen_interval = 2;
|
|
|
|
|
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, PS_MODE);
|
|
|
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2);
|
|
|
|
|
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type,
|
|
|
|
|
MAC_MGMT_MIB_PS_MODE_POS, PS_MODE);
|
|
|
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type,
|
|
|
|
|
MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
priv->station_is_associated = 1;
|
|
|
|
@ -2957,13 +2980,12 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype)
|
|
|
|
|
atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
|
|
|
|
|
priv->station_is_associated = 0;
|
|
|
|
|
|
|
|
|
|
if(priv->connect_to_any_BSS) {
|
|
|
|
|
if (priv->connect_to_any_BSS) {
|
|
|
|
|
int bss_index;
|
|
|
|
|
priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
|
|
|
|
|
|
|
|
|
|
if ((bss_index = retrieve_bss(priv)) != -1)
|
|
|
|
|
atmel_join_bss(priv, bss_index);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2985,8 +3007,10 @@ void atmel_join_bss(struct atmel_private *priv, int bss_index)
|
|
|
|
|
priv->power_mode) {
|
|
|
|
|
priv->power_mode = 0;
|
|
|
|
|
priv->listen_interval = 1;
|
|
|
|
|
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE);
|
|
|
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1);
|
|
|
|
|
atmel_set_mib8(priv, Mac_Mgmt_Mib_Type,
|
|
|
|
|
MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE);
|
|
|
|
|
atmel_set_mib16(priv, Mac_Mgmt_Mib_Type,
|
|
|
|
|
MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
priv->operating_mode = bss->BSStype;
|
|
|
|
@ -2995,7 +3019,8 @@ void atmel_join_bss(struct atmel_private *priv, int bss_index)
|
|
|
|
|
|
|
|
|
|
if (priv->preamble != bss->preamble) {
|
|
|
|
|
priv->preamble = bss->preamble;
|
|
|
|
|
atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, bss->preamble);
|
|
|
|
|
atmel_set_mib8(priv, Local_Mib_Type,
|
|
|
|
|
LOCAL_MIB_PREAMBLE_TYPE, bss->preamble);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!priv->wep_is_on && bss->UsingWEP) {
|
|
|
|
@ -3018,7 +3043,6 @@ void atmel_join_bss(struct atmel_private *priv, int bss_index)
|
|
|
|
|
join(priv, BSS_TYPE_AD_HOC);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void restart_search(struct atmel_private *priv)
|
|
|
|
|
{
|
|
|
|
|
int bss_index;
|
|
|
|
@ -3032,7 +3056,6 @@ static void restart_search(struct atmel_private *priv)
|
|
|
|
|
atmel_join_bss(priv, bss_index);
|
|
|
|
|
else
|
|
|
|
|
atmel_scan(priv, 0);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3050,20 +3073,20 @@ static void smooth_rssi(struct atmel_private *priv, u8 rssi)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rssi = rssi * 100 / max_rssi;
|
|
|
|
|
if((rssi + old) % 2)
|
|
|
|
|
priv->wstats.qual.level = ((rssi + old)/2) + 1;
|
|
|
|
|
if ((rssi + old) % 2)
|
|
|
|
|
priv->wstats.qual.level = (rssi + old) / 2 + 1;
|
|
|
|
|
else
|
|
|
|
|
priv->wstats.qual.level = ((rssi + old)/2);
|
|
|
|
|
priv->wstats.qual.level = (rssi + old) / 2;
|
|
|
|
|
priv->wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
|
|
|
|
|
priv->wstats.qual.updated &= ~IW_QUAL_LEVEL_INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void atmel_smooth_qual(struct atmel_private *priv)
|
|
|
|
|
{
|
|
|
|
|
unsigned long time_diff = (jiffies - priv->last_qual)/HZ;
|
|
|
|
|
unsigned long time_diff = (jiffies - priv->last_qual) / HZ;
|
|
|
|
|
while (time_diff--) {
|
|
|
|
|
priv->last_qual += HZ;
|
|
|
|
|
priv->wstats.qual.qual = priv->wstats.qual.qual/2;
|
|
|
|
|
priv->wstats.qual.qual = priv->wstats.qual.qual / 2;
|
|
|
|
|
priv->wstats.qual.qual +=
|
|
|
|
|
priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000;
|
|
|
|
|
priv->beacons_this_sec = 0;
|
|
|
|
@ -3073,13 +3096,15 @@ static void atmel_smooth_qual(struct atmel_private *priv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* deals with incoming managment frames. */
|
|
|
|
|
static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
|
|
|
|
|
static void atmel_management_frame(struct atmel_private *priv,
|
|
|
|
|
struct ieee80211_hdr_4addr *header,
|
|
|
|
|
u16 frame_len, u8 rssi)
|
|
|
|
|
{
|
|
|
|
|
u16 subtype;
|
|
|
|
|
|
|
|
|
|
switch (subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE) {
|
|
|
|
|
case C80211_SUBTYPE_MGMT_BEACON :
|
|
|
|
|
subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE;
|
|
|
|
|
switch (subtype) {
|
|
|
|
|
case C80211_SUBTYPE_MGMT_BEACON:
|
|
|
|
|
case C80211_SUBTYPE_MGMT_ProbeResponse:
|
|
|
|
|
|
|
|
|
|
/* beacon frame has multiple variable-length fields -
|
|
|
|
@ -3133,10 +3158,12 @@ static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (priv->station_state == STATION_STATE_SCANNING )
|
|
|
|
|
store_bss_info(priv, header, capability, beacon_interval, channel,
|
|
|
|
|
rssi, ssid_length, &beacon->rates_el_id,
|
|
|
|
|
subtype == C80211_SUBTYPE_MGMT_BEACON) ;
|
|
|
|
|
if (priv->station_state == STATION_STATE_SCANNING)
|
|
|
|
|
store_bss_info(priv, header, capability,
|
|
|
|
|
beacon_interval, channel, rssi,
|
|
|
|
|
ssid_length,
|
|
|
|
|
&beacon->rates_el_id,
|
|
|
|
|
subtype == C80211_SUBTYPE_MGMT_BEACON);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
@ -3210,7 +3237,6 @@ static void atmel_management_timer(u_long a)
|
|
|
|
|
mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
|
|
|
|
|
send_authentication_request(priv, C80211_MGMT_AAN_OPENSYSTEM, NULL, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case STATION_STATE_ASSOCIATING:
|
|
|
|
@ -3224,7 +3250,6 @@ static void atmel_management_timer(u_long a)
|
|
|
|
|
mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
|
|
|
|
|
send_association_request(priv, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case STATION_STATE_REASSOCIATING:
|
|
|
|
@ -3238,7 +3263,6 @@ static void atmel_management_timer(u_long a)
|
|
|
|
|
mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
|
|
|
|
|
send_association_request(priv, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
@ -3321,7 +3345,6 @@ static void atmel_command_irq(struct atmel_private *priv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
atmel_scan(priv, 1);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3382,7 +3405,8 @@ static int atmel_wakeup_firmware(struct atmel_private *priv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
printk(KERN_ALERT "%s: MAC failed to initialise.\n", priv->dev->name);
|
|
|
|
|
printk(KERN_ALERT "%s: MAC failed to initialise.\n",
|
|
|
|
|
priv->dev->name);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3490,10 +3514,10 @@ 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. */
|
|
|
|
|
static void build_wep_mib(struct atmel_private *priv)
|
|
|
|
|
{
|
|
|
|
|
struct { /* NB this is matched to the hardware, don't change. */
|
|
|
|
|
u8 wep_is_on;
|
|
|
|
@ -3523,7 +3547,7 @@ static void build_wep_mib(struct atmel_private *priv)
|
|
|
|
|
mib.default_key = priv->default_key;
|
|
|
|
|
mib.exclude_unencrypted = priv->exclude_unencrypted;
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < MAX_ENCRYPTION_KEYS; i++)
|
|
|
|
|
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));
|
|
|
|
@ -3559,8 +3583,9 @@ static void build_wpa_mib(struct atmel_private *priv)
|
|
|
|
|
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 */
|
|
|
|
|
/* 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;
|
|
|
|
@ -3770,7 +3795,8 @@ static int reset_atmel_card(struct net_device *dev)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size)
|
|
|
|
|
static void atmel_send_command(struct atmel_private *priv, int command,
|
|
|
|
|
void *cmd, int cmd_size)
|
|
|
|
|
{
|
|
|
|
|
if (cmd)
|
|
|
|
|
atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET),
|
|
|
|
@ -3780,7 +3806,8 @@ static void atmel_send_command(struct atmel_private *priv, int command, void *cm
|
|
|
|
|
atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size)
|
|
|
|
|
static int atmel_send_command_wait(struct atmel_private *priv, int command,
|
|
|
|
|
void *cmd, int cmd_size)
|
|
|
|
|
{
|
|
|
|
|
int i, status;
|
|
|
|
|
|
|
|
|
@ -3827,7 +3854,8 @@ static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 dat
|
|
|
|
|
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)
|
|
|
|
|
static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index,
|
|
|
|
|
u16 data)
|
|
|
|
|
{
|
|
|
|
|
struct get_set_mib m;
|
|
|
|
|
m.type = type;
|
|
|
|
@ -3839,7 +3867,8 @@ static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 d
|
|
|
|
|
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)
|
|
|
|
|
static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index,
|
|
|
|
|
u8 *data, int data_len)
|
|
|
|
|
{
|
|
|
|
|
struct get_set_mib m;
|
|
|
|
|
m.type = type;
|
|
|
|
@ -3853,7 +3882,8 @@ static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *dat
|
|
|
|
|
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)
|
|
|
|
|
static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index,
|
|
|
|
|
u8 *data, int data_len)
|
|
|
|
|
{
|
|
|
|
|
struct get_set_mib m;
|
|
|
|
|
m.type = type;
|
|
|
|
@ -3873,11 +3903,12 @@ static void atmel_writeAR(struct net_device *dev, u16 data)
|
|
|
|
|
int i;
|
|
|
|
|
outw(data, dev->base_addr + AR);
|
|
|
|
|
/* Address register appears to need some convincing..... */
|
|
|
|
|
for (i = 0; data != inw(dev->base_addr + AR) && i<10; i++)
|
|
|
|
|
for (i = 0; data != inw(dev->base_addr + AR) && i < 10; i++)
|
|
|
|
|
outw(data, dev->base_addr + AR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *src, u16 len)
|
|
|
|
|
static void atmel_copy_to_card(struct net_device *dev, u16 dest,
|
|
|
|
|
unsigned char *src, u16 len)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
atmel_writeAR(dev, dest);
|
|
|
|
@ -3894,7 +3925,8 @@ static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *
|
|
|
|
|
atmel_write8(dev, DR, *src);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, u16 src, u16 len)
|
|
|
|
|
static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest,
|
|
|
|
|
u16 src, u16 len)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
atmel_writeAR(dev, src);
|
|
|
|
@ -3931,12 +3963,14 @@ static int atmel_lock_mac(struct atmel_private *priv)
|
|
|
|
|
udelay(20);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!i) return 0; /* timed out */
|
|
|
|
|
if (!i)
|
|
|
|
|
return 0; /* timed out */
|
|
|
|
|
|
|
|
|
|
atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1);
|
|
|
|
|
if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) {
|
|
|
|
|
atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0);
|
|
|
|
|
if (!j--) return 0; /* timed out */
|
|
|
|
|
if (!j--)
|
|
|
|
|
return 0; /* timed out */
|
|
|
|
|
goto retry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|