diff options
author | David S. Miller <davem@davemloft.net> | 2008-07-05 21:41:53 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-05 21:41:53 -0700 |
commit | f3032be921cd126615ce3bfd7084e3d319f3f892 (patch) | |
tree | c2ce874f2ab7f107dddf7b854772e0f3b64d35a1 /drivers | |
parent | 70c03b49b80ba3634958acc31853771019c0ebd3 (diff) | |
parent | 18d7260527ce7c0d0a177afdf92d8f868f50b067 (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers')
29 files changed, 1614 insertions, 1564 deletions
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 4cca203992e..fec5645944a 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -43,6 +43,23 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) return 0; } +/* Update the rfkill state */ +static void b43_rfkill_update_state(struct b43_wldev *dev) +{ + struct b43_rfkill *rfk = &(dev->wl->rfkill); + + if (!dev->radio_hw_enable) { + rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED; + return; + } + + if (!dev->phy.radio_on) + rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED; + else + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; + +} + /* The poll callback for the hardware button. */ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) { @@ -60,6 +77,7 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; report_change = 1; + b43_rfkill_update_state(dev); b43info(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); } @@ -135,7 +153,7 @@ void b43_rfkill_init(struct b43_wldev *dev) snprintf(rfk->name, sizeof(rfk->name), "b43-%s", wiphy_name(wl->hw->wiphy)); rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; rfk->rfkill->data = dev; rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; rfk->rfkill->user_claim_unsupported = 1; diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index 8935a302b22..476add97e97 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -44,6 +44,23 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) return 0; } +/* Update the rfkill state */ +static void b43legacy_rfkill_update_state(struct b43legacy_wldev *dev) +{ + struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); + + if (!dev->radio_hw_enable) { + rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED; + return; + } + + if (!dev->phy.radio_on) + rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED; + else + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; + +} + /* The poll callback for the hardware button. */ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) { @@ -61,6 +78,7 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; report_change = 1; + b43legacy_rfkill_update_state(dev); b43legacyinfo(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); } @@ -139,7 +157,7 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev) snprintf(rfk->name, sizeof(rfk->name), "b43legacy-%s", wiphy_name(wl->hw->wiphy)); rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; rfk->rfkill->data = dev; rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; rfk->rfkill->user_claim_unsupported = 1; diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index 4fd73809602..d669e5956ce 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -78,6 +78,9 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, prism_header = 2; phdrlen = sizeof(struct linux_wlan_ng_cap_hdr); } + } else if (dev->type == ARPHRD_IEEE80211_RADIOTAP) { + prism_header = 3; + phdrlen = sizeof(struct hostap_radiotap_rx); } else { prism_header = 0; phdrlen = 0; @@ -165,6 +168,24 @@ hdr->f.status = s; hdr->f.len = l; hdr->f.data = d hdr->ssi_noise = htonl(rx_stats->noise); hdr->preamble = htonl(0); /* unknown */ hdr->encoding = htonl(1); /* cck */ + } else if (prism_header == 3) { + struct hostap_radiotap_rx *hdr; + hdr = (struct hostap_radiotap_rx *)skb_push(skb, phdrlen); + memset(hdr, 0, phdrlen); + hdr->hdr.it_len = cpu_to_le16(phdrlen); + hdr->hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)); + hdr->tsft = cpu_to_le64(rx_stats->mac_time); + hdr->chan_freq = cpu_to_le16(freq_list[local->channel - 1]); + hdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_CCK | + IEEE80211_CHAN_2GHZ); + hdr->rate = rx_stats->rate / 5; + hdr->dbm_antsignal = rx_stats->signal; + hdr->dbm_antnoise = rx_stats->noise; } ret = skb->len - phdrlen; diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index cdf90c40f11..79a9bc95d2a 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -3204,6 +3204,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY; local->sram_type = -1; local->scan_channel_mask = 0xffff; + local->monitor_type = PRISM2_MONITOR_RADIOTAP; /* Initialize task queue structures */ INIT_WORK(&local->reset_queue, handle_reset_queue); diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index ed52d98317c..3f8b1d7036e 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -897,6 +897,8 @@ static void hostap_monitor_set_type(local_info_t *local) if (local->monitor_type == PRISM2_MONITOR_PRISM || local->monitor_type == PRISM2_MONITOR_CAPHDR) { dev->type = ARPHRD_IEEE80211_PRISM; + } else if (local->monitor_type == PRISM2_MONITOR_RADIOTAP) { + dev->type = ARPHRD_IEEE80211_RADIOTAP; } else { dev->type = ARPHRD_IEEE80211; } @@ -2520,7 +2522,8 @@ static int prism2_ioctl_priv_prism2_param(struct net_device *dev, case PRISM2_PARAM_MONITOR_TYPE: if (value != PRISM2_MONITOR_80211 && value != PRISM2_MONITOR_CAPHDR && - value != PRISM2_MONITOR_PRISM) { + value != PRISM2_MONITOR_PRISM && + value != PRISM2_MONITOR_RADIOTAP) { ret = -EINVAL; break; } diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index f7aec9309d0..b5213f61fb0 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -596,25 +596,7 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) int hostap_80211_header_parse(const struct sk_buff *skb, unsigned char *haddr) { - struct hostap_interface *iface = netdev_priv(skb->dev); - local_info_t *local = iface->local; - - if (local->monitor_type == PRISM2_MONITOR_PRISM || - local->monitor_type == PRISM2_MONITOR_CAPHDR) { - const unsigned char *mac = skb_mac_header(skb); - - if (*(u32 *)mac == LWNG_CAP_DID_BASE) { - memcpy(haddr, - mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10, - ETH_ALEN); /* addr2 */ - } else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */ - memcpy(haddr, - mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10, - ETH_ALEN); /* addr2 */ - } - } else - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - + memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ return ETH_ALEN; } diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index 15445bce2ac..ffdf4876121 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -5,6 +5,7 @@ #include <linux/netdevice.h> #include <linux/mutex.h> #include <net/iw_handler.h> +#include <net/ieee80211_radiotap.h> #include "hostap_config.h" #include "hostap_common.h" @@ -55,6 +56,17 @@ struct linux_wlan_ng_cap_hdr { __be32 encoding; } __attribute__ ((packed)); +struct hostap_radiotap_rx { + struct ieee80211_radiotap_header hdr; + __le64 tsft; + u8 rate; + u8 padding; + __le16 chan_freq; + __le16 chan_flags; + s8 dbm_antsignal; + s8 dbm_antnoise; +} __attribute__ ((packed)); + #define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */ #define LWNG_CAPHDR_VERSION 0x80211001 @@ -734,7 +746,7 @@ struct local_info { unsigned long scan_timestamp; /* Time started to scan */ enum { PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1, - PRISM2_MONITOR_CAPHDR = 2 + PRISM2_MONITOR_CAPHDR = 2, PRISM2_MONITOR_RADIOTAP = 3 } monitor_type; int monitor_allow_fcserr; diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index d7ea32f3969..b628a44057f 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -8,7 +8,6 @@ config IWLCORE select MAC80211_LEDS if IWLWIFI_LEDS select LEDS_CLASS if IWLWIFI_LEDS select RFKILL if IWLWIFI_RFKILL - select RFKILL_INPUT if (IWLWIFI_RFKILL && INPUT) config IWLWIFI_LEDS bool diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index a9b3edad386..a77497809d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -36,6 +36,10 @@ #include <linux/kernel.h> #include <net/ieee80211_radiotap.h> +/*used for rfkill*/ +#include <linux/rfkill.h> +#include <linux/input.h> + /* Hardware specific file defines the PCI IDs table for that hardware module */ extern struct pci_device_id iwl3945_hw_card_ids[]; @@ -686,6 +690,23 @@ enum { #endif +#ifdef CONFIG_IWLWIFI_RFKILL +struct iwl3945_priv; + +struct iwl3945_rfkill_mngr { + struct rfkill *rfkill; + struct input_dev *input_dev; +}; + +void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv); +void iwl3945_rfkill_unregister(struct iwl3945_priv *priv); +int iwl3945_rfkill_init(struct iwl3945_priv *priv); +#else +static inline void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv) {} +static inline void iwl3945_rfkill_unregister(struct iwl3945_priv *priv) {} +static inline int iwl3945_rfkill_init(struct iwl3945_priv *priv) { return 0; } +#endif + #define IWL_MAX_NUM_QUEUES IWL39_MAX_NUM_QUEUES struct iwl3945_priv { @@ -779,6 +800,10 @@ struct iwl3945_priv { struct iwl3945_init_alive_resp card_alive_init; struct iwl3945_alive_resp card_alive; +#ifdef CONFIG_IWLWIFI_RFKILL + struct iwl3945_rfkill_mngr rfkill_mngr; +#endif + #ifdef CONFIG_IWL3945_LEDS struct iwl3945_led led[IWL_LED_TRG_MAX]; unsigned long last_blink_time; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 20230311728..c7ebb3bf06f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -822,9 +822,6 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; - if (!priv->lq_mngr.lq_ready) - goto out; - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq_sta->ibss_sta_added) goto out; @@ -1678,10 +1675,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (!sta || !sta->rate_ctrl_priv) return; - if (!priv->lq_mngr.lq_ready) { - IWL_DEBUG_RATE("still rate scaling not ready\n"); - return; - } lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; tid = rs_tl_add_packet(lq_sta, hdr); @@ -2140,11 +2133,8 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, lq_sta->ibss_sta_added = 1; rs_initialize_lq(priv, conf, sta); } - if (!lq_sta->ibss_sta_added) - goto done; } -done: if ((i < 0) || (i > IWL_RATE_COUNT)) { sel->rate_idx = rate_lowest_index(local, sband, sta); goto out; @@ -2279,9 +2269,6 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->drv = priv; #endif - if (priv->assoc_station_added) - priv->lq_mngr.lq_ready = 1; - rs_initialize_lq(priv, conf, sta); } @@ -2421,7 +2408,7 @@ static void rs_clear(void *priv_rate) IWL_DEBUG_RATE("enter\n"); - priv->lq_mngr.lq_ready = 0; + /* TODO - add rate scale state reset */ IWL_DEBUG_RATE("leave\n"); } @@ -2716,13 +2703,6 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) return cnt; } -void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) -{ - struct iwl_priv *priv = hw->priv; - - priv->lq_mngr.lq_ready = 1; -} - int iwl4965_rate_control_register(void) { return ieee80211_rate_control_register(&rs_ops); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h index cbd12641849..9b9972885aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h @@ -296,14 +296,6 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) extern int iwl4965_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id); /** - * iwl4965_rate_scale_init - Initialize the rate scale table based on assoc info - * - * The specific throughput table used is based on the type of network - * the associated with, including A, B, G, and G w/ TGG protection - */ -extern void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); - -/** * iwl4965_rate_control_register - Register the rate control algorithm callbacks * * Since the rate control algorithm is hardware specific, there is no need diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index ab5027345a0..8c93f8d56a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -555,8 +555,6 @@ out: return ret; } -#define REG_RECALIB_PERIOD (60) - /* Reset differential Rx gains in NIC to prepare for chain noise calibration. * Called after every association, but this runs only once! * ... once chain noise is calibrated the first time, it's good forever. */ @@ -839,17 +837,8 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; priv->hw_params.first_ampdu_q = IWL49_FIRST_AMPDU_QUEUE; - priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; - priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; - priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; - if (priv->cfg->mod_params->amsdu_size_8K) - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K; - else - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; - priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; priv->hw_params.max_stations = IWL4965_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; - priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE; priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; @@ -1890,87 +1879,10 @@ static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv) return 1; } -/* Calculate noise level, based on measurements during network silence just - * before arriving beacon. This measurement can be done only if we know - * exactly when to expect beacons, therefore only when we're associated. */ -static void iwl4965_rx_calc_noise(struct iwl_priv *priv) -{ - struct statistics_rx_non_phy *rx_info - = &(priv->statistics.rx.general); - int num_active_rx = 0; - int total_silence = 0; - int bcn_silence_a = - le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; - int bcn_silence_b = - le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; - int bcn_silence_c = - le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; - - if (bcn_silence_a) { - total_silence += bcn_silence_a; - num_active_rx++; - } - if (bcn_silence_b) { - total_silence += bcn_silence_b; - num_active_rx++; - } - if (bcn_silence_c) { - total_silence += bcn_silence_c; - num_active_rx++; - } - - /* Average among active antennas */ - if (num_active_rx) - priv->last_rx_noise = (total_silence / num_active_rx) - 107; - else - priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - - IWL_DEBUG_CALIB("inband silence a %u, b %u, c %u, dBm %d\n", - bcn_silence_a, bcn_silence_b, bcn_silence_c, - priv->last_rx_noise); -} - -void iwl4965_hw_rx_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_temperature_calib(struct iwl_priv *priv) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - int change; s32 temp; - IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n", - (int)sizeof(priv->statistics), pkt->len); - - change = ((priv->statistics.general.temperature != - pkt->u.stats.general.temperature) || - ((priv->statistics.flag & - STATISTICS_REPLY_FLG_FAT_MODE_MSK) != - (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK))); - - memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); - - set_bit(STATUS_STATISTICS, &priv->status); - - /* Reschedule the statistics timer to occur in - * REG_RECALIB_PERIOD seconds to ensure we get a - * thermal update even if the uCode doesn't give - * us one */ - mod_timer(&priv->statistics_periodic, jiffies + - msecs_to_jiffies(REG_RECALIB_PERIOD * 1000)); - - if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && - (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { - iwl4965_rx_calc_noise(priv); - queue_work(priv->workqueue, &priv->run_time_calib_work); - } - - iwl_leds_background(priv); - - /* If the hardware hasn't reported a change in - * temperature then don't bother computing a - * calibrated temperature value */ - if (!change) - return; - temp = iwl4965_hw_get_temperature(priv); if (temp < 0) return; @@ -1996,775 +1908,6 @@ void iwl4965_hw_rx_statistics(struct iwl_priv *priv, queue_work(priv->workqueue, &priv->txpower_work); } -static void iwl4965_add_radiotap(struct iwl_priv *priv, - struct sk_buff *skb, - struct iwl4965_rx_phy_res *rx_start, - struct ieee80211_rx_status *stats, - u32 ampdu_status) -{ - s8 signal = stats->signal; - s8 noise = 0; - int rate = stats->rate_idx; - u64 tsf = stats->mactime; - __le16 antenna; - __le16 phy_flags_hw = rx_start->phy_flags; - struct iwl4965_rt_rx_hdr { - struct ieee80211_radiotap_header rt_hdr; - __le64 rt_tsf; /* TSF */ - u8 rt_flags; /* radiotap packet flags */ - u8 rt_rate; /* rate in 500kb/s */ - __le16 rt_channelMHz; /* channel in MHz */ - __le16 rt_chbitmask; /* channel bitfield */ - s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ - s8 rt_dbmnoise; - u8 rt_antenna; /* antenna number */ - } __attribute__ ((packed)) *iwl4965_rt; - - /* TODO: We won't have enough headroom for HT frames. Fix it later. */ - if (skb_headroom(skb) < sizeof(*iwl4965_rt)) { - if (net_ratelimit()) - printk(KERN_ERR "not enough headroom [%d] for " - "radiotap head [%zd]\n", - skb_headroom(skb), sizeof(*iwl4965_rt)); - return; - } - - /* put radiotap header in front of 802.11 header and data */ - iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt)); - - /* initialise radiotap header */ - iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - iwl4965_rt->rt_hdr.it_pad = 0; - - /* total header + data */ - put_unaligned(cpu_to_le16(sizeof(*iwl4965_rt)), - &iwl4965_rt->rt_hdr.it_len); - - /* Indicate all the fields we add to the radiotap header */ - put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA)), - &iwl4965_rt->rt_hdr.it_present); - - /* Zero the flags, we'll add to them as we go */ - iwl4965_rt->rt_flags = 0; - - put_unaligned(cpu_to_le64(tsf), &iwl4965_rt->rt_tsf); - - iwl4965_rt->rt_dbmsignal = signal; - iwl4965_rt->rt_dbmnoise = noise; - - /* Convert the channel frequency and set the flags */ - put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz); - if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_5GHZ), - &iwl4965_rt->rt_chbitmask); - else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | - IEEE80211_CHAN_2GHZ), - &iwl4965_rt->rt_chbitmask); - else /* 802.11g */ - put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_2GHZ), - &iwl4965_rt->rt_chbitmask); - - if (rate == -1) - iwl4965_rt->rt_rate = 0; - else - iwl4965_rt->rt_rate = iwl_rates[rate].ieee; - - /* - * "antenna number" - * - * It seems that the antenna field in the phy flags value - * is actually a bitfield. This is undefined by radiotap, - * it wants an actual antenna number but I always get "7" - * for most legacy frames I receive indicating that the - * same frame was received on all three RX chains. - * - * I think this field should be removed in favour of a - * new 802.11n radiotap field "RX chains" that is defined - * as a bitmask. - */ - antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; - iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4; - - /* set the preamble flag if appropriate */ - if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) - iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - - stats->flag |= RX_FLAG_RADIOTAP; -} - -static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) -{ - /* 0 - mgmt, 1 - cnt, 2 - data */ - int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; - priv->rx_stats[idx].cnt++; - priv->rx_stats[idx].bytes += len; -} - -/* - * returns non-zero if packet should be dropped - */ -static int iwl4965_set_decrypted_flag(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - u32 decrypt_res, - struct ieee80211_rx_status *stats) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - - if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) - return 0; - - if (!(fc & IEEE80211_FCTL_PROTECTED)) - return 0; - - IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); - switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { - case RX_RES_STATUS_SEC_TYPE_TKIP: - /* The uCode has got a bad phase 1 Key, pushes the packet. - * Decryption will be done in SW. */ - if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == - RX_RES_STATUS_BAD_KEY_TTAK) - break; - - case RX_RES_STATUS_SEC_TYPE_WEP: - if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == - RX_RES_STATUS_BAD_ICV_MIC) { - /* bad ICV, the packet is destroyed since the - * decryption is inplace, drop it */ - IWL_DEBUG_RX("Packet destroyed\n"); - return -1; - } - case RX_RES_STATUS_SEC_TYPE_CCMP: - if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == - RX_RES_STATUS_DECRYPT_OK) { - IWL_DEBUG_RX("hw decrypt successfully!!!\n"); - stats->flag |= RX_FLAG_DECRYPTED; - } - break; - - default: - break; - } - return 0; -} - -static u32 iwl4965_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) -{ - u32 decrypt_out = 0; - - if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == - RX_RES_STATUS_STATION_FOUND) - decrypt_out |= (RX_RES_STATUS_STATION_FOUND | - RX_RES_STATUS_NO_STATION_INFO_MISMATCH); - - decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); - - /* packet was not encrypted */ - if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == - RX_RES_STATUS_SEC_TYPE_NONE) - return decrypt_out; - - /* packet was encrypted with unknown alg */ - if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == - RX_RES_STATUS_SEC_TYPE_ERR) - return decrypt_out; - - /* decryption was not done in HW */ - if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != - RX_MPDU_RES_STATUS_DEC_DONE_MSK) - return decrypt_out; - - switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { - - case RX_RES_STATUS_SEC_TYPE_CCMP: - /* alg is CCM: check MIC only */ - if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) - /* Bad MIC */ - decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; - else - decrypt_out |= RX_RES_STATUS_DECRYPT_OK; - - break; - - case RX_RES_STATUS_SEC_TYPE_TKIP: - if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { - /* Bad TTAK */ - decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; - break; - } - /* fall through if TTAK OK */ - default: - if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) - decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; - else - decrypt_out |= RX_RES_STATUS_DECRYPT_OK; - break; - }; - - IWL_DEBUG_RX("decrypt_in:0x%x decrypt_out = 0x%x\n", - decrypt_in, decrypt_out); - - return decrypt_out; -} - -static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, - int include_phy, - struct iwl_rx_mem_buffer *rxb, - struct ieee80211_rx_status *stats) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_rx_phy_res *rx_start = (include_phy) ? - (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; - struct ieee80211_hdr *hdr; - u16 len; - __le32 *rx_end; - unsigned int skblen; - u32 ampdu_status; - u32 ampdu_status_legacy; - - if (!include_phy && priv->last_phy_res[0]) - rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; - - if (!rx_start) { - IWL_ERROR("MPDU frame without a PHY data\n"); - return; - } - if (include_phy) { - hdr = (struct ieee80211_hdr *)((u8 *) & rx_start[1] + - rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - - rx_end = (__le32 *) ((u8 *) & pkt->u.raw[0] + - sizeof(struct iwl4965_rx_phy_res) + - rx_start->cfg_phy_cnt + len); - - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; - - hdr = (struct ieee80211_hdr *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_start->byte_count = am |