summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl3945-base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl3945-base.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c535
1 files changed, 263 insertions, 272 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 6027e1119c3f..4a22d3fba75b 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -102,16 +102,6 @@ MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
-static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
-{
- u16 fc = le16_to_cpu(hdr->frame_control);
- int hdr_len = ieee80211_get_hdrlen(fc);
-
- if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
- return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
- return NULL;
-}
-
static const struct ieee80211_supported_band *iwl3945_get_band(
struct iwl3945_priv *priv, enum ieee80211_band band)
{
@@ -547,10 +537,20 @@ static inline int iwl3945_is_init(struct iwl3945_priv *priv)
return test_bit(STATUS_INIT, &priv->status);
}
+static inline int iwl3945_is_rfkill_sw(struct iwl3945_priv *priv)
+{
+ return test_bit(STATUS_RF_KILL_SW, &priv->status);
+}
+
+static inline int iwl3945_is_rfkill_hw(struct iwl3945_priv *priv)
+{
+ return test_bit(STATUS_RF_KILL_HW, &priv->status);
+}
+
static inline int iwl3945_is_rfkill(struct iwl3945_priv *priv)
{
- return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
- test_bit(STATUS_RF_KILL_SW, &priv->status);
+ return iwl3945_is_rfkill_hw(priv) ||
+ iwl3945_is_rfkill_sw(priv);
}
static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv)
@@ -980,7 +980,7 @@ static int iwl3945_full_rxon_required(struct iwl3945_priv *priv)
{
/* These items are only settable from the full RXON command */
- if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ||
+ if (!(iwl3945_is_associated(priv)) ||
compare_ether_addr(priv->staging_rxon.bssid_addr,
priv->active_rxon.bssid_addr) ||
compare_ether_addr(priv->staging_rxon.node_addr,
@@ -2035,36 +2035,6 @@ static int iwl3945_send_power_mode(struct iwl3945_priv *priv, u32 mode)
return rc;
}
-int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
-{
- /* Filter incoming packets to determine if they are targeted toward
- * this network, discarding packets coming from ourselves */
- switch (priv->iw_mode) {
- case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */
- /* packets from our adapter are dropped (echo) */
- if (!compare_ether_addr(header->addr2, priv->mac_addr))
- return 0;
- /* {broad,multi}cast packets to our IBSS go through */
- if (is_multicast_ether_addr(header->addr1))
- return !compare_ether_addr(header->addr3, priv->bssid);
- /* packets to our adapter go through */
- return !compare_ether_addr(header->addr1, priv->mac_addr);
- case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
- /* packets from our adapter are dropped (echo) */
- if (!compare_ether_addr(header->addr3, priv->mac_addr))
- return 0;
- /* {broad,multi}cast packets to our BSS go through */
- if (is_multicast_ether_addr(header->addr1))
- return !compare_ether_addr(header->addr2, priv->bssid);
- /* packets to our adapter go through */
- return !compare_ether_addr(header->addr1, priv->mac_addr);
- default:
- return 1;
- }
-
- return 1;
-}
-
/**
* iwl3945_scan_cancel - Cancel any currently executing HW scan
*
@@ -2117,20 +2087,6 @@ static int iwl3945_scan_cancel_timeout(struct iwl3945_priv *priv, unsigned long
return ret;
}
-static void iwl3945_sequence_reset(struct iwl3945_priv *priv)
-{
- /* Reset ieee stats */
-
- /* We don't reset the net_device_stats (ieee->stats) on
- * re-association */
-
- priv->last_seq_num = -1;
- priv->last_frag_num = -1;
- priv->last_packet_time = 0;
-
- iwl3945_scan_cancel(priv);
-}
-
#define MAX_UCODE_BEACON_INTERVAL 1024
#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA)
@@ -2322,7 +2278,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
#endif
ch_info = iwl3945_get_channel_info(priv, priv->band,
- le16_to_cpu(priv->staging_rxon.channel));
+ le16_to_cpu(priv->active_rxon.channel));
if (!ch_info)
ch_info = &priv->channel_info[0];
@@ -2389,12 +2345,13 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode)
}
static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
- struct ieee80211_tx_control *ctl,
+ struct ieee80211_tx_info *info,
struct iwl3945_cmd *cmd,
struct sk_buff *skb_frag,
int last_frag)
{
- struct iwl3945_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+ struct iwl3945_hw_key *keyinfo =
+ &priv->stations[info->control.hw_key->hw_key_idx].keyinfo;
switch (keyinfo->alg) {
case ALG_CCMP:
@@ -2417,7 +2374,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
case ALG_WEP:
cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
- (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
+ (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
if (keyinfo->keylen == 13)
cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
@@ -2425,7 +2382,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
IWL_DEBUG_TX("Configuring packet for WEP encryption "
- "with key %d\n", ctl->key_idx);
+ "with key %d\n", info->control.hw_key->hw_key_idx);
break;
default:
@@ -2439,20 +2396,19 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
*/
static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
struct iwl3945_cmd *cmd,
- struct ieee80211_tx_control *ctrl,
+ struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr,
int is_unicast, u8 std_id)
{
- __le16 *qc;
- u16 fc = le16_to_cpu(hdr->frame_control);
+ __le16 fc = hdr->frame_control;
__le32 tx_flags = cmd->cmd.tx.tx_flags;
cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
- if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
tx_flags |= TX_CMD_FLG_ACK_MSK;
- if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+ if (ieee80211_is_mgmt(fc))
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
- if (ieee80211_is_probe_response(fc) &&
+ if (ieee80211_is_probe_resp(fc) &&
!(le16_to_cpu(hdr->seq_ctrl) & 0xf))
tx_flags |= TX_CMD_FLG_TSF_MSK;
} else {
@@ -2461,20 +2417,21 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
}
cmd->cmd.tx.sta_id = std_id;
- if (ieee80211_get_morefrag(hdr))
+ if (ieee80211_has_morefrags(fc))
tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
- qc = ieee80211_get_qos_ctrl(hdr);
- if (qc) {
- cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
+ if (ieee80211_is_data_qos(fc)) {
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
+ cmd->cmd.tx.tid_tspec = qc[0] & 0xf;
tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
- } else
+ } else {
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ }
- if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+ if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
tx_flags |= TX_CMD_FLG_RTS_MSK;
tx_flags &= ~TX_CMD_FLG_CTS_MSK;
- } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
tx_flags &= ~TX_CMD_FLG_RTS_MSK;
tx_flags |= TX_CMD_FLG_CTS_MSK;
}
@@ -2483,9 +2440,8 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
- if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
- if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
- (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
+ if (ieee80211_is_mgmt(fc)) {
+ if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3);
else
cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2);
@@ -2549,6 +2505,11 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h
iwl3945_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
return priv->hw_setting.bcast_sta_id;
}
+ /* If we are in monitor mode, use BCAST. This is required for
+ * packet injection. */
+ case IEEE80211_IF_TYPE_MNTR:
+ return priv->hw_setting.bcast_sta_id;
+
default:
IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
return priv->hw_setting.bcast_sta_id;
@@ -2558,25 +2519,27 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h
/*
* start REPLY_TX command process
*/
-static int iwl3945_tx_skb(struct iwl3945_priv *priv,
- struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl3945_tfd_frame *tfd;
u32 *control_flags;
- int txq_id = ctl->queue;
+ int txq_id = skb_get_queue_mapping(skb);
struct iwl3945_tx_queue *txq = NULL;
struct iwl3945_queue *q = NULL;
dma_addr_t phys_addr;
dma_addr_t txcmd_phys;
struct iwl3945_cmd *out_cmd = NULL;
- u16 len, idx, len_org;
- u8 id, hdr_len, unicast;
+ u16 len, idx, len_org, hdr_len;
+ u8 id;
+ u8 unicast;
u8 sta_id;
+ u8 tid = 0;
u16 seq_number = 0;
- u16 fc;
- __le16 *qc;
+ __le16 fc;
u8 wait_write_ptr = 0;
+ u8 *qc = NULL;
unsigned long flags;
int rc;
@@ -2586,12 +2549,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
goto drop_unlock;
}
- if (!priv->vif) {
- IWL_DEBUG_DROP("Dropping - !priv->vif\n");
- goto drop_unlock;
- }
-
- if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) {
+ if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) {
IWL_ERROR("ERROR: No TX rate available.\n");
goto drop_unlock;
}
@@ -2599,28 +2557,29 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
unicast = !is_multicast_ether_addr(hdr->addr1);
id = 0;
- fc = le16_to_cpu(hdr->frame_control);
+ fc = hdr->frame_control;
#ifdef CONFIG_IWL3945_DEBUG
if (ieee80211_is_auth(fc))
IWL_DEBUG_TX("Sending AUTH frame\n");
- else if (ieee80211_is_assoc_request(fc))
+ else if (ieee80211_is_assoc_req(fc))
IWL_DEBUG_TX("Sending ASSOC frame\n");
- else if (ieee80211_is_reassoc_request(fc))
+ else if (ieee80211_is_reassoc_req(fc))
IWL_DEBUG_TX("Sending REASSOC frame\n");
#endif
/* drop all data frame if we are not associated */
- if ((!iwl3945_is_associated(priv) ||
- ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id)) &&
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+ if (ieee80211_is_data(fc) &&
+ (priv->iw_mode != IEEE80211_IF_TYPE_MNTR) && /* packet injection */
+ (!iwl3945_is_associated(priv) ||
+ ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id))) {
IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n");
goto drop_unlock;
}
spin_unlock_irqrestore(&priv->lock, flags);
- hdr_len = ieee80211_get_hdrlen(fc);
+ hdr_len = ieee80211_get_hdrlen(le16_to_cpu(fc));
/* Find (or create) index into station table for destination station */
sta_id = iwl3945_get_sta_id(priv, hdr);
@@ -2634,9 +2593,9 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
IWL_DEBUG_RATE("station Id %d\n", sta_id);
- qc = ieee80211_get_qos_ctrl(hdr);
- if (qc) {
- u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+ if (ieee80211_is_data_qos(fc)) {
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = qc[0] & 0xf;
seq_number = priv->stations[sta_id].tid[tid].seq_number &
IEEE80211_SCTL_SEQ;
hdr->seq_ctrl = cpu_to_le16(seq_number) |
@@ -2660,8 +2619,6 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl3945_tx_info));
txq->txb[q->write_ptr].skb[0] = skb;
- memcpy(&(txq->txb[q->write_ptr].status.control),
- ctl, sizeof(struct ieee80211_tx_control));
/* Init first empty entry in queue's array of Tx/cmd buffers */
out_cmd = &txq->cmd[idx];
@@ -2710,8 +2667,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
* first entry */
iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
- if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
- iwl3945_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+ if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
+ iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0);
/* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */
@@ -2736,18 +2693,17 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
out_cmd->cmd.tx.len = cpu_to_le16(len);
/* TODO need this for burst mode later on */
- iwl3945_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+ iwl3945_build_tx_cmd_basic(priv, out_cmd, info, hdr, unicast, sta_id);
/* set is_hcca to 0; it probably will never be implemented */
- iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+ iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, info, hdr, sta_id, 0);
out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
- if (!ieee80211_get_morefrag(hdr)) {
+ if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
if (qc) {
- u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
priv->stations[sta_id].tid[tid].seq_number = seq_number;
}
} else {
@@ -2759,7 +2715,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
sizeof(out_cmd->cmd.tx));
iwl3945_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
- ieee80211_get_hdrlen(fc));
+ ieee80211_get_hdrlen(le16_to_cpu(fc)));
/* Tell device the write index *just past* this latest filled TFD */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
@@ -2778,7 +2734,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
spin_unlock_irqrestore(&priv->lock, flags);
}
- ieee80211_stop_queue(priv->hw, ctl->queue);
+ ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb));
}
return 0;
@@ -2888,7 +2844,8 @@ static void iwl3945_radio_kill_sw(struct iwl3945_priv *priv, int disable_radio)
return;
}
- queue_work(priv->workqueue, &priv->restart);
+ if (priv->is_open)
+ queue_work(priv->workqueue, &priv->restart);
return;
}
@@ -2924,72 +2881,6 @@ void iwl3945_set_decrypted_flag(struct iwl3945_priv *priv, struct sk_buff *skb,
}
}
-#define IWL_PACKET_RETRY_TIME HZ
-
-int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
-{
- u16 sc = le16_to_cpu(header->seq_ctrl);
- u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
- u16 frag = sc & IEEE80211_SCTL_FRAG;
- u16 *last_seq, *last_frag;
- unsigned long *last_time;
-
- switch (priv->iw_mode) {
- case IEEE80211_IF_TYPE_IBSS:{
- struct list_head *p;
- struct iwl3945_ibss_seq *entry = NULL;
- u8 *mac = header->addr2;
- int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
-
- __list_for_each(p, &priv->ibss_mac_hash[index]) {
- entry = list_entry(p, struct iwl3945_ibss_seq, list);
- if (!compare_ether_addr(entry->mac, mac))
- break;
- }
- if (p == &priv->ibss_mac_hash[index]) {
- entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
- if (!entry) {
- IWL_ERROR("Cannot malloc new mac entry\n");
- return 0;
- }
- memcpy(entry->mac, mac, ETH_ALEN);
- entry->seq_num = seq;
- entry->frag_num = frag;
- entry->packet_time = jiffies;
- list_add(&entry->list, &priv->ibss_mac_hash[index]);
- return 0;
- }
- last_seq = &entry->seq_num;
- last_frag = &entry->frag_num;
- last_time = &entry->packet_time;
- break;
- }
- case IEEE80211_IF_TYPE_STA:
- last_seq = &priv->last_seq_num;
- last_frag = &priv->last_frag_num;
- last_time = &priv->last_packet_time;
- break;
- default:
- return 0;
- }
- if ((*last_seq == seq) &&
- time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
- if (*last_frag == frag)
- goto drop;
- if (*last_frag + 1 != frag)
- /* out-of-order fragment */
- goto drop;
- } else
- *last_seq = seq;
-
- *last_frag = frag;
- *last_time = jiffies;
- return 0;
-
- drop:
- return 1;
-}
-
#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
#include "iwl-spectrum.h"
@@ -3241,7 +3132,7 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)
struct sk_buff *beacon;
/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
- beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL);
+ beacon = ieee80211_beacon_get(priv->hw, priv->vif);
if (!beacon) {
IWL_ERROR("update beacon failed\n");
@@ -4848,7 +4739,7 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv)
ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
ch_info->min_power = 0;
- IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x"
+ IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
" %ddBm): Ad-Hoc %ssupported\n",
ch_info->channel,
is_channel_a_band(ch_info) ?
@@ -4858,7 +4749,6 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv)
CHECK_AND_PRINT(ACTIVE),
CHECK_AND_PRINT(RADAR),
CHECK_AND_PRINT(WIDE),
- CHECK_AND_PRINT(NARROW),
CHECK_AND_PRINT(DFS),
eeprom_ch_info[ch].flags,
eeprom_ch_info[ch].max_power_avg,
@@ -4994,9 +4884,6 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
if (scan_ch->type & 1)
scan_ch->type |= (direct_mask << 1);
- if (is_channel_narrow(ch_info))
- scan_ch->type |= (1 << 7);
-
scan_ch->active_dwell = cpu_to_le16(active_dwell);
scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
@@ -5843,7 +5730,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
if (iwl3945_is_rfkill(priv))
return;
- ieee80211_start_queues(priv->hw);
+ ieee80211_wake_queues(priv->hw);
priv->active_rate = priv->rates_mask;
priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
@@ -5869,9 +5756,6 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
/* Configure the adapter for unassociated operation */
iwl3945_commit_rxon(priv);
- /* At this point, the NIC is initialized and operational */
- priv->notif_missed_beacons = 0;
-
iwl3945_reg_txpower_periodic(priv);
iwl3945_led_register(priv);
@@ -5938,7 +5822,9 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
STATUS_GEO_CONFIGURED |
test_bit(STATUS_IN_SUSPEND, &priv->status) <<
- STATUS_IN_SUSPEND;
+ STATUS_IN_SUSPEND |
+ test_bit(STATUS_EXIT_PENDING, &priv->status) <<
+ STATUS_EXIT_PENDING;
goto exit;
}
@@ -5953,7 +5839,9 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
test_bit(STATUS_IN_SUSPEND, &priv->status) <<
STATUS_IN_SUSPEND |
test_bit(STATUS_FW_ERROR, &priv->status) <<
- STATUS_FW_ERROR;
+ STATUS_FW_ERROR |
+ test_bit(STATUS_EXIT_PENDING, &priv->status) <<
+ STATUS_EXIT_PENDING;
spin_lock_irqsave(&priv->lock, flags);
iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
@@ -6085,6 +5973,7 @@ static int __iwl3945_up(struct iwl3945_priv *priv)
set_bit(STATUS_EXIT_PENDING, &priv->status);
__iwl3945_down(priv);
+ clear_bit(STATUS_EXIT_PENDING, &priv->status);
/* tried to restart and config the device for as long as our
* patience could withstand */
@@ -6152,6 +6041,26 @@ static void iwl3945_bg_rf_kill(struct work_struct *work)
"Kill switch must be turned off for "
"wireless networking to work.\n");
}
+
+ mutex_unlock(&priv->mutex);
+ iwl3945_rfkill_set_hw_state(priv);
+}
+
+static void iwl3945_bg_set_monitor(struct work_struct *work)
+{
+ struct iwl3945_priv *priv = container_of(work,
+ struct iwl3945_priv, set_monitor);
+
+ IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
+
+ mutex_lock(&priv->mutex);
+
+ if (!iwl3945_is_ready(priv))
+ IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
+ else
+ if (iwl3945_set_mode(priv, IEEE80211_IF_TYPE_MNTR) != 0)
+ IWL_ERROR("iwl3945_set_mode() failed\n");
+
mutex_unlock(&priv->mutex);
}
@@ -6388,6 +6297,7 @@ static void iwl3945_bg_up(struct work_struct *data)
mutex_lock(&priv->mutex);
__iwl3945_up(priv);
mutex_unlock(&priv->mutex);
+ iwl3945_rfkill_set_hw_state(priv);
}
static void iwl3945_bg_restart(struct work_struct *data)
@@ -6511,8 +6421,6 @@ static void iwl3945_bg_post_associate(struct work_struct *data)
break;
}
- iwl3945_sequence_reset(priv);
-
iwl3945_activate_qos(priv, 0);
/* we have just associated, don't start scan too early */
@@ -6608,6 +6516,8 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
mutex_unlock(&priv->mutex);
+ iwl3945_rfkill_set_hw_state(priv);
+
if (ret)
goto out_release_irq;
@@ -6678,8 +6588,7 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw)
IWL_DEBUG_MAC80211("leave\n");
}
-static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct iwl3945_priv *priv = hw->priv;
@@ -6692,9 +6601,9 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
}
IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
- ctl->tx_rate->bitrate);
+ ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
- if (iwl3945_tx_skb(priv, skb, ctl))
+ if (iwl3945_tx_skb(priv, skb))
dev_kfree_skb_any(skb);
IWL_DEBUG_MAC80211("leave\n");
@@ -6837,7 +6746,7 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv)
return;
/* The following should be done only at AP bring up */
- if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) {
+ if (!(iwl3945_is_associated(priv))) {
/* RXON - unassoc (to set timing command) */
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
@@ -6886,6 +6795,9 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv)
* clear sta table, add BCAST sta... */
}
+/* temporary */
+static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
+
static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
@@ -6903,10 +6815,21 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
return 0;
}
+ /* handle this temporarily here */
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+ conf->changed & IEEE80211_IFCC_BEACON) {
+ struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+ if (!beacon)
+ return -ENOMEM;
+ rc = iwl3945_mac_beacon_update(hw, beacon);
+ if (rc)
+ return rc;
+ }
+
/* XXX: this MUST use conf->mac_addr */
if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
- (!conf->beacon || !conf->ssid_len)) {
+ (!conf->ssid_len)) {
IWL_DEBUG_MAC80211
("Leaving in AP mode because HostAPD is not ready.\n");
return 0;
@@ -6938,7 +6861,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon);
- priv->ibss_beacon = conf->beacon;
+ priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
}
if (iwl3945_is_rfkill(priv))
@@ -6999,11 +6922,18 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
unsigned int *total_flags,
int mc_count, struct dev_addr_list *mc_list)
{
- /*
- * XXX: dummy
- * see also iwl3945_connection_init_rx_config
- */
- *total_flags = 0;
+ struct iwl3945_priv *priv = hw->priv;
+
+ if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
+ IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
+ IEEE80211_IF_TYPE_MNTR,
+ changed_flags, *total_flags);
+ /* queue work 'cuz mac80211 is holding a lock which
+ * prevents us from issuing (synchronous) f/w cmds */
+ queue_work(priv->workqueue, &priv->set_monitor);
+ }
+ *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
+ FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw,
@@ -7061,9 +6991,10 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
rc = -EAGAIN;
goto out_unlock;
}
- /* if we just finished scan ask for delay */
- if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies +
- IWL_DELAY_NEXT_SCAN, jiffies)) {
+ /* if we just finished scan ask for delay for a broadcast scan */
+ if ((len == 0) && priv->last_scan_jiffies &&
+ time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
+ jiffies)) {
rc = -EAGAIN;
goto out_unlock;
}
@@ -7150,7 +7081,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return rc;
}
-static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct iwl3945_priv *priv = hw->priv;
@@ -7224,9 +7155,9 @@ static int iwl3945_mac_get_tx_stats(struct ieee80211_hw *hw,
q = &txq->q;
avail = iwl3945_queue_space(q);
- stats->data[i].len = q->n_window - avail;
- stats->data[i].limit = q->n_window - q->high_mark;
- stats->data[i].count = q->n_window;
+ stats[i].len = q->n_window - avail;
+ stats[i].limit = q->n_window - q->high_mark;
+ stats[i].count = q->n_window;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -7315,8 +7246,7 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
}
-static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct iwl3945_priv *priv = hw->priv;
unsigned long flags;
@@ -7398,37 +7328,6 @@ static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
#endif /* CONFIG_IWL3945_DEBUG */
-static ssize_t show_rf_kill(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- /*
- * 0 - RF kill not enabled
- * 1 - SW based RF kill active (sysfs)
- * 2 - HW based RF kill active
- * 3 - Both HW and SW based RF kill active
- */
- struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
- int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
- (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
-
- return sprintf(buf, "%i\n", val);
-}
-
-static ssize_t store_rf_kill(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
-
- mutex_lock(&priv->mutex);
- iwl3945_radio_kill_sw(priv, buf[0] == '1');
- mutex_unlock(&priv->mutex);
-
- return count;
-}
-
-static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
-
static ssize_t show_temperature(struct device *d,
struct device_attribute *attr, char *buf)
{
@@ -7879,6 +7778,7 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv)
INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan);
INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill);
INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
+ INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor);
INIT_DELAYED_WORK(&priv->post_associate, iwl3945_bg_post_associate);
INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
@@ -7913,7 +7813,6 @@ static struct attribute *iwl3945_sysfs_entries[] = {
#endif
&dev_attr_power_level.attr,
&dev_attr_retry_rate.attr,
- &dev_attr_rf_kill.attr,
&dev_attr_rs_window.attr,
&dev_attr_statistics.attr,
&dev_attr_status.attr,
@@ -7943,7 +7842,6 @@ static struct ieee80211_ops iwl3945_hw_ops = {
.conf_tx = iwl3945_mac_conf_tx,
.get_tsf = iwl3945_mac_get_tsf,
.reset_tsf = iwl3945_mac_reset_tsf,
- .beacon_update = iwl3945_mac_beacon_update,
.hw_scan = iwl3945_mac_hw_scan
};
@@ -7953,7 +7851,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
struct iwl3945_priv *priv;
struct ieee80211_hw *hw;
struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
- int i;
unsigned long flags;
DECLARE_MAC_BUF(mac);
@@ -8001,17 +7898,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv->ibss_beacon = NULL;
- /* Tell mac80211 and its clients (e.g. Wireless Extensions)
- * the range of signal quality values that we'll provide.
- * Negative values for level/noise indicate that we'll provide dBm.
- * For WE, at least, non-0 values here *enable* display of values
- * in app (iwconfig). */
- hw->max_rssi = -20; /* signal level, negative indicates dBm */
- hw->max_noise = -20; /* noise level, negative indicates dBm */
- hw->max_signal = 100; /* link quality indication (%) */
-
- /* Tell mac80211 our Tx characteristics */
- hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+ /* Tell mac80211 our characteristics */
+ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_NOISE_DBM;
/* 4 EDCA QOS priorities */
hw->queues = 4;
@@ -8021,9 +7911,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
spin_lock_init(&priv->sta_lock);
spin_lock_init(&priv->hcmd_lock);
- for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
- INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
-
INIT_LIST_HEAD(&priv->free_frames);
mutex_init(&priv->mutex);
@@ -8161,6 +8048,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
pci_save_state(pdev);
pci_disable_device(pdev);
+ err = iwl3945_rfkill_init(priv);
+ if (err)
+ IWL_ERROR("Unable to initialize RFKILL system. "
+ "Ignoring error: %d\n", err);
+
return 0;
out_free_geos:
@@ -8191,8 +8083,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
{
struct iwl3945_priv *priv = pci_get_drvdata(pdev);
- struct list_head *p, *q;
- int i;
unsigned long flags;
if (!priv)
@@ -8213,16 +8103,9 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
iwl_synchronize_irq(priv);
- /* Free MAC hash list for ADHOC */
- for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
- list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
- list_del(p);
- kfree(list_entry(p, struct iwl3945_ibss_seq, list));
- }
- }
-
sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+ iwl3945_rfkill_unregister(priv);
iwl3945_dealloc_ucode_pci(priv);
if (priv->rxq.bd)
@@ -8252,7 +8135,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
iwl3945_free_channel_map(priv);
iwl3945_free_geos(priv);
-
+ kfree(priv->scan);
if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon);
@@ -8291,6 +8174,114 @@ static int iwl3945_pci_resume(struct pci_dev *pdev)
#endif /* CONFIG_PM */
+/*************** RFKILL FUNCTIONS **********/
+#ifdef CONFIG_IWL3945_RFKILL
+/* software rf-kill from user */
+static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
+{
+ struct iwl3945_priv *priv = data;
+ int err = 0;
+
+ if (!priv->rfkill)
+ return 0;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return 0;
+
+ IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state);
+ mutex_lock(&priv->mutex);
+
+ switch (state) {
+ case RFKILL_STATE_UNBLOCKED:
+ if (iwl3945_is_rfkill_hw(priv)) {
+ err = -EBUSY;
+ goto out_unlock;
+ }
+ iwl3945_radio_kill_sw(priv, 0);
+ break;
+ case RFKILL_STATE_SOFT_BLOCKED:
+ iwl3945_radio_kill_sw(priv, 1);
+ break;
+ default:
+ IWL_WARNING("we recieved unexpected RFKILL state %d\n", state);
+ break;
+ }
+out_unlock:
+ mutex_unlock(&priv->mutex);
+
+ return err;
+}
+
+int iwl3945_rfkill_init(struct iwl3945_priv *priv)
+{
+ struct device *device = wiphy_dev(priv->hw->wiphy);
+ int ret = 0;
+
+ BUG_ON(device == NULL);
+
+ IWL_DEBUG_RF_KILL("Initializing RFKILL.\n");
+ priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
+ if (!priv->rfkill) {
+ IWL_ERROR("Unable to allocate rfkill device.\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ priv->rfkill->name = priv->cfg->name;
+ priv->rfkill->data = priv;
+ priv->rfkill->state = RFKILL_STATE_UNBLOCKED;
+ priv->rfkill->toggle_radio = iwl3945_rfkill_soft_rf_kill;
+ priv->rfkill->user_claim_unsupported = 1;
+
+ priv->rfkill->dev.class->suspend = NULL;
+ priv->rfkill->dev.class->resume = NULL;
+
+ ret = rfkill_register(priv->rfkill);
+ if (ret) {
+ IWL_ERROR("Unable to register rfkill: %d\n", ret);
+ goto freed_rfkill;
+ }
+
+ IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n");
+ return ret;
+
+freed_rfkill:
+ if (priv->rfkill != NULL)
+ rfkill_free(priv->rfkill);
+ priv->rfkill = NULL;
+
+error:
+ IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n");
+ return ret;
+}
+
+void iwl3945_rfkill_unregister(struct iwl3945_priv *priv)
+{
+ if (priv->rfkill)
+ rfkill_unregister(priv->rfkill);
+
+ priv->rfkill = NULL;
+}
+
+/* set rf-kill to the right state. */
+void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv)
+{
+
+ if (!priv->rfkill)
+ return;
+
+ if (iwl3945_is_rfkill_hw(priv)) {
+ rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED);
+ return;
+ }
+
+ if (!iwl3945_is_rfkill_sw(priv))
+ rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED);
+ else
+ rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED);
+}
+#endif
+
/*****************************************************************************
*
* driver and module entry point