diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2008-06-30 05:23:09 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-30 17:37:40 -0400 |
commit | 1781a07fbe9cce3dc1697288a5edd260ea7edc02 (patch) | |
tree | be06e824b69af8d43edfeab2c78a353f0bf7f8ce /drivers/net/wireless | |
parent | 37deb2a0baf1bb540b723cc8a3972b42ff2daac6 (diff) |
iwlwifi: move RX handlers to iwl-rx.c
This patch moves RX handlers to iwl-rx.c
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 703 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 853 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl4965-base.c | 152 |
5 files changed, 861 insertions, 860 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1688803af58..d8e6d2e6a86 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -1929,707 +1929,6 @@ static void iwl4965_temperature_calib(struct iwl_priv *priv, | |||
1929 | queue_work(priv->workqueue, &priv->txpower_work); | 1929 | queue_work(priv->workqueue, &priv->txpower_work); |
1930 | } | 1930 | } |
1931 | 1931 | ||
1932 | static void iwl4965_add_radiotap(struct iwl_priv *priv, | ||
1933 | struct sk_buff *skb, | ||
1934 | struct iwl4965_rx_phy_res *rx_start, | ||
1935 | struct ieee80211_rx_status *stats, | ||
1936 | u32 ampdu_status) | ||
1937 | { | ||
1938 | s8 signal = stats->signal; | ||
1939 | s8 noise = 0; | ||
1940 | int rate = stats->rate_idx; | ||
1941 | u64 tsf = stats->mactime; | ||
1942 | __le16 antenna; | ||
1943 | __le16 phy_flags_hw = rx_start->phy_flags; | ||
1944 | struct iwl4965_rt_rx_hdr { | ||
1945 | struct ieee80211_radiotap_header rt_hdr; | ||
1946 | __le64 rt_tsf; /* TSF */ | ||
1947 | u8 rt_flags; /* radiotap packet flags */ | ||
1948 | u8 rt_rate; /* rate in 500kb/s */ | ||
1949 | __le16 rt_channelMHz; /* channel in MHz */ | ||
1950 | __le16 rt_chbitmask; /* channel bitfield */ | ||
1951 | s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ | ||
1952 | s8 rt_dbmnoise; | ||
1953 | u8 rt_antenna; /* antenna number */ | ||
1954 | } __attribute__ ((packed)) *iwl4965_rt; | ||
1955 | |||
1956 | /* TODO: We won't have enough headroom for HT frames. Fix it later. */ | ||
1957 | if (skb_headroom(skb) < sizeof(*iwl4965_rt)) { | ||
1958 | if (net_ratelimit()) | ||
1959 | printk(KERN_ERR "not enough headroom [%d] for " | ||
1960 | "radiotap head [%zd]\n", | ||
1961 | skb_headroom(skb), sizeof(*iwl4965_rt)); | ||
1962 | return; | ||
1963 | } | ||
1964 | |||
1965 | /* put radiotap header in front of 802.11 header and data */ | ||
1966 | iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt)); | ||
1967 | |||
1968 | /* initialise radiotap header */ | ||
1969 | iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; | ||
1970 | iwl4965_rt->rt_hdr.it_pad = 0; | ||
1971 | |||
1972 | /* total header + data */ | ||
1973 | put_unaligned(cpu_to_le16(sizeof(*iwl4965_rt)), | ||
1974 | &iwl4965_rt->rt_hdr.it_len); | ||
1975 | |||
1976 | /* Indicate all the fields we add to the radiotap header */ | ||
1977 | put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | | ||
1978 | (1 << IEEE80211_RADIOTAP_FLAGS) | | ||
1979 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
1980 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
1981 | (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | | ||
1982 | (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | | ||
1983 | (1 << IEEE80211_RADIOTAP_ANTENNA)), | ||
1984 | &iwl4965_rt->rt_hdr.it_present); | ||
1985 | |||
1986 | /* Zero the flags, we'll add to them as we go */ | ||
1987 | iwl4965_rt->rt_flags = 0; | ||
1988 | |||
1989 | put_unaligned(cpu_to_le64(tsf), &iwl4965_rt->rt_tsf); | ||
1990 | |||
1991 | iwl4965_rt->rt_dbmsignal = signal; | ||
1992 | iwl4965_rt->rt_dbmnoise = noise; | ||
1993 | |||
1994 | /* Convert the channel frequency and set the flags */ | ||
1995 | put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz); | ||
1996 | if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) | ||
1997 | put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
1998 | IEEE80211_CHAN_5GHZ), | ||
1999 | &iwl4965_rt->rt_chbitmask); | ||
2000 | else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) | ||
2001 | put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | | ||
2002 | IEEE80211_CHAN_2GHZ), | ||
2003 | &iwl4965_rt->rt_chbitmask); | ||
2004 | else /* 802.11g */ | ||
2005 | put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
2006 | IEEE80211_CHAN_2GHZ), | ||
2007 | &iwl4965_rt->rt_chbitmask); | ||
2008 | |||
2009 | if (rate == -1) | ||
2010 | iwl4965_rt->rt_rate = 0; | ||
2011 | else | ||
2012 | iwl4965_rt->rt_rate = iwl_rates[rate].ieee; | ||
2013 | |||
2014 | /* | ||
2015 | * "antenna number" | ||
2016 | * | ||
2017 | * It seems that the antenna field in the phy flags value | ||
2018 | * is actually a bitfield. This is undefined by radiotap, | ||
2019 | * it wants an actual antenna number but I always get "7" | ||
2020 | * for most legacy frames I receive indicating that the | ||
2021 | * same frame was received on all three RX chains. | ||
2022 | * | ||
2023 | * I think this field should be removed in favour of a | ||
2024 | * new 802.11n radiotap field "RX chains" that is defined | ||
2025 | * as a bitmask. | ||
2026 | */ | ||
2027 | antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; | ||
2028 | iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4; | ||
2029 | |||
2030 | /* set the preamble flag if appropriate */ | ||
2031 | if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) | ||
2032 | iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; | ||
2033 | |||
2034 | stats->flag |= RX_FLAG_RADIOTAP; | ||
2035 | } | ||
2036 | |||
2037 | static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) | ||
2038 | { | ||
2039 | /* 0 - mgmt, 1 - cnt, 2 - data */ | ||
2040 | int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; | ||
2041 | priv->rx_stats[idx].cnt++; | ||
2042 | priv->rx_stats[idx].bytes += len; | ||
2043 | } | ||
2044 | |||
2045 | /* | ||
2046 | * returns non-zero if packet should be dropped | ||
2047 | */ | ||
2048 | static int iwl4965_set_decrypted_flag(struct iwl_priv *priv, | ||
2049 | struct ieee80211_hdr *hdr, | ||
2050 | u32 decrypt_res, | ||
2051 | struct ieee80211_rx_status *stats) | ||
2052 | { | ||
2053 | u16 fc = le16_to_cpu(hdr->frame_control); | ||
2054 | |||
2055 | if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) | ||
2056 | return 0; | ||
2057 | |||
2058 | if (!(fc & IEEE80211_FCTL_PROTECTED)) | ||
2059 | return 0; | ||
2060 | |||
2061 | IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); | ||
2062 | switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { | ||
2063 | case RX_RES_STATUS_SEC_TYPE_TKIP: | ||
2064 | /* The uCode has got a bad phase 1 Key, pushes the packet. | ||
2065 | * Decryption will be done in SW. */ | ||
2066 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == | ||
2067 | RX_RES_STATUS_BAD_KEY_TTAK) | ||
2068 | break; | ||
2069 | |||
2070 | case RX_RES_STATUS_SEC_TYPE_WEP: | ||
2071 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == | ||
2072 | RX_RES_STATUS_BAD_ICV_MIC) { | ||
2073 | /* bad ICV, the packet is destroyed since the | ||
2074 | * decryption is inplace, drop it */ | ||
2075 | IWL_DEBUG_RX("Packet destroyed\n"); | ||
2076 | return -1; | ||
2077 | } | ||
2078 | case RX_RES_STATUS_SEC_TYPE_CCMP: | ||
2079 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == | ||
2080 | RX_RES_STATUS_DECRYPT_OK) { | ||
2081 | IWL_DEBUG_RX("hw decrypt successfully!!!\n"); | ||
2082 | stats->flag |= RX_FLAG_DECRYPTED; | ||
2083 | } | ||
2084 | break; | ||
2085 | |||
2086 | default: | ||
2087 | break; | ||
2088 | } | ||
2089 | return 0; | ||
2090 | } | ||
2091 | |||
2092 | static u32 iwl4965_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) | ||
2093 | { | ||
2094 | u32 decrypt_out = 0; | ||
2095 | |||
2096 | if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == | ||
2097 | RX_RES_STATUS_STATION_FOUND) | ||
2098 | decrypt_out |= (RX_RES_STATUS_STATION_FOUND | | ||
2099 | RX_RES_STATUS_NO_STATION_INFO_MISMATCH); | ||
2100 | |||
2101 | decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); | ||
2102 | |||
2103 | /* packet was not encrypted */ | ||
2104 | if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == | ||
2105 | RX_RES_STATUS_SEC_TYPE_NONE) | ||
2106 | return decrypt_out; | ||
2107 | |||
2108 | /* packet was encrypted with unknown alg */ | ||
2109 | if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == | ||
2110 | RX_RES_STATUS_SEC_TYPE_ERR) | ||
2111 | return decrypt_out; | ||
2112 | |||
2113 | /* decryption was not done in HW */ | ||
2114 | if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != | ||
2115 | RX_MPDU_RES_STATUS_DEC_DONE_MSK) | ||
2116 | return decrypt_out; | ||
2117 | |||
2118 | switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { | ||
2119 | |||
2120 | case RX_RES_STATUS_SEC_TYPE_CCMP: | ||
2121 | /* alg is CCM: check MIC only */ | ||
2122 | if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) | ||
2123 | /* Bad MIC */ | ||
2124 | decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; | ||
2125 | else | ||
2126 | decrypt_out |= RX_RES_STATUS_DECRYPT_OK; | ||
2127 | |||
2128 | break; | ||
2129 | |||
2130 | case RX_RES_STATUS_SEC_TYPE_TKIP: | ||
2131 | if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { | ||
2132 | /* Bad TTAK */ | ||
2133 | decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; | ||
2134 | break; | ||
2135 | } | ||
2136 | /* fall through if TTAK OK */ | ||
2137 | default: | ||
2138 | if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) | ||
2139 | decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; | ||
2140 | else | ||
2141 | decrypt_out |= RX_RES_STATUS_DECRYPT_OK; | ||
2142 | break; | ||
2143 | }; | ||
2144 | |||
2145 | IWL_DEBUG_RX("decrypt_in:0x%x decrypt_out = 0x%x\n", | ||
2146 | decrypt_in, decrypt_out); | ||
2147 | |||
2148 | return decrypt_out; | ||
2149 | } | ||
2150 | |||
2151 | static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, | ||
2152 | int include_phy, | ||
2153 | struct iwl_rx_mem_buffer *rxb, | ||
2154 | struct ieee80211_rx_status *stats) | ||
2155 | { | ||
2156 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
2157 | struct iwl4965_rx_phy_res *rx_start = (include_phy) ? | ||
2158 | (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; | ||
2159 | struct ieee80211_hdr *hdr; | ||
2160 | u16 len; | ||
2161 | __le32 *rx_end; | ||
2162 | unsigned int skblen; | ||
2163 | u32 ampdu_status; | ||
2164 | u32 ampdu_status_legacy; | ||
2165 | |||
2166 | if (!include_phy && priv->last_phy_res[0]) | ||
2167 | rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; | ||
2168 | |||
2169 | if (!rx_start) { | ||
2170 | IWL_ERROR("MPDU frame without a PHY data\n"); | ||
2171 | return; | ||
2172 | } | ||
2173 | if (include_phy) { | ||
2174 | hdr = (struct ieee80211_hdr *)((u8 *) & rx_start[1] + | ||
2175 | rx_start->cfg_phy_cnt); | ||
2176 | |||
2177 | len = le16_to_cpu(rx_start->byte_count); | ||
2178 | |||
2179 | rx_end = (__le32 *) ((u8 *) & pkt->u.raw[0] + | ||
2180 | sizeof(struct iwl4965_rx_phy_res) + | ||
2181 | rx_start->cfg_phy_cnt + len); | ||
2182 | |||
2183 | } else { | ||
2184 | struct iwl4965_rx_mpdu_res_start *amsdu = | ||
2185 | (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; | ||
2186 | |||
2187 | hdr = (struct ieee80211_hdr *)(pkt->u.raw + | ||
2188 | sizeof(struct iwl4965_rx_mpdu_res_start)); | ||
2189 | len = le16_to_cpu(amsdu->byte_count); | ||
2190 | rx_start->byte_count = amsdu->byte_count; | ||
2191 | rx_end = (__le32 *) (((u8 *) hdr) + len); | ||
2192 | } | ||
2193 | /* In monitor mode allow 802.11 ACk frames (10 bytes) */ | ||
2194 | if (len > priv->hw_params.max_pkt_size || | ||
2195 | len < ((priv->iw_mode == IEEE80211_IF_TYPE_MNTR) ? 10 : 16)) { | ||
2196 | IWL_WARNING("byte count out of range [16,4K] : %d\n", len); | ||
2197 | return; | ||
2198 | } | ||
2199 | |||
2200 | ampdu_status = le32_to_cpu(*rx_end); | ||
2201 | skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32); | ||
2202 | |||
2203 | if (!include_phy) { | ||
2204 | /* New status scheme, need to translate */ | ||
2205 | ampdu_status_legacy = ampdu_status; | ||
2206 | ampdu_status = iwl4965_translate_rx_status(priv, ampdu_status); | ||
2207 | } | ||
2208 | |||
2209 | /* start from MAC */ | ||
2210 | skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); | ||
2211 | skb_put(rxb->skb, len); /* end where data ends */ | ||
2212 | |||
2213 | /* We only process data packets if the interface is open */ | ||
2214 | if (unlikely(!priv->is_open)) { | ||
2215 | IWL_DEBUG_DROP_LIMIT | ||
2216 | ("Dropping packet while interface is not open.\n"); | ||
2217 | return; | ||
2218 | } | ||
2219 | |||
2220 | stats->flag = 0; | ||
2221 | hdr = (struct ieee80211_hdr *)rxb->skb->data; | ||
2222 | |||
2223 | /* in case of HW accelerated crypto and bad decryption, drop */ | ||
2224 | if (!priv->hw_params.sw_crypto && | ||
2225 | iwl4965_set_decrypted_flag(priv, hdr, ampdu_status, stats)) | ||
2226 | return; | ||
2227 | |||
2228 | if (priv->add_radiotap) | ||
2229 | iwl4965_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); | ||
2230 | |||
2231 | iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); | ||
2232 | ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); | ||
2233 | priv->alloc_rxb_skb--; | ||
2234 | rxb->skb = NULL; | ||
2235 | } | ||
2236 | |||
2237 | /* Calc max signal level (dBm) among 3 possible receivers */ | ||
2238 | static int iwl4965_calc_rssi(struct iwl_priv *priv, | ||
2239 | struct iwl4965_rx_phy_res *rx_resp) | ||
2240 | { | ||
2241 | /* data from PHY/DSP regarding signal strength, etc., | ||
2242 | * contents are always there, not configurable by host. */ | ||
2243 | struct iwl4965_rx_non_cfg_phy *ncphy = | ||
2244 | (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy; | ||
2245 | u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK) | ||
2246 | >> IWL_AGC_DB_POS; | ||
2247 | |||
2248 | u32 valid_antennae = | ||
2249 | (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK) | ||
2250 | >> RX_PHY_FLAGS_ANTENNAE_OFFSET; | ||
2251 | u8 max_rssi = 0; | ||
2252 | u32 i; | ||
2253 | |||
2254 | /* Find max rssi among 3 possible receivers. | ||
2255 | * These values are measured by the digital signal processor (DSP). | ||
2256 | * They should stay fairly constant even as the signal strength varies, | ||
2257 | * if the radio's automatic gain control (AGC) is working right. | ||
2258 | * AGC value (see below) will provide the "interesting" info. */ | ||
2259 | for (i = 0; i < 3; i++) | ||
2260 | if (valid_antennae & (1 << i)) | ||
2261 | max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); | ||
2262 | |||
2263 | IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", | ||
2264 | ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], | ||
2265 | max_rssi, agc); | ||
2266 | |||
2267 | /* dBm = max_rssi dB - agc dB - constant. | ||
2268 | * Higher AGC (higher radio gain) means lower signal. */ | ||
2269 | return (max_rssi - agc - IWL_RSSI_OFFSET); | ||
2270 | } | ||
2271 | |||
2272 | static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) | ||
2273 | { | ||
2274 | unsigned long flags; | ||
2275 | |||
2276 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
2277 | priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; | ||
2278 | priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; | ||
2279 | priv->stations[sta_id].sta.sta.modify_mask = 0; | ||
2280 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | ||
2281 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
2282 | |||
2283 | iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); | ||
2284 | } | ||
2285 | |||
2286 | static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) | ||
2287 | { | ||
2288 | /* FIXME: need locking over ps_status ??? */ | ||
2289 | u8 sta_id = iwl_find_station(priv, addr); | ||
2290 | |||
2291 | if (sta_id != IWL_INVALID_STATION) { | ||
2292 | u8 sta_awake = priv->stations[sta_id]. | ||
2293 | ps_status == STA_PS_STATUS_WAKE; | ||
2294 | |||
2295 | if (sta_awake && ps_bit) | ||
2296 | priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; | ||
2297 | else if (!sta_awake && !ps_bit) { | ||
2298 | iwl4965_sta_modify_ps_wake(priv, sta_id); | ||
2299 | priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; | ||
2300 | } | ||
2301 | } | ||
2302 | } | ||
2303 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
2304 | |||
2305 | /** | ||
2306 | * iwl4965_dbg_report_frame - dump frame to syslog during debug sessions | ||
2307 | * | ||
2308 | * You may hack this function to show different aspects of received frames, | ||
2309 | * including selective frame dumps. | ||
2310 | * group100 parameter selects whether to show 1 out of 100 good frames. | ||
2311 | * | ||
2312 | * TODO: This was originally written for 3945, need to audit for | ||
2313 | * proper operation with 4965. | ||
2314 | */ | ||
2315 | static void iwl4965_dbg_report_frame(struct iwl_priv *priv, | ||
2316 | struct iwl_rx_packet *pkt, | ||
2317 | struct ieee80211_hdr *header, int group100) | ||
2318 | { | ||
2319 | u32 to_us; | ||
2320 | u32 print_summary = 0; | ||
2321 | u32 print_dump = 0; /* set to 1 to dump all frames' contents */ | ||
2322 | u32 hundred = 0; | ||
2323 | u32 dataframe = 0; | ||
2324 | __le16 fc; | ||
2325 | u16 seq_ctl; | ||
2326 | u16 channel; | ||
2327 | u16 phy_flags; | ||
2328 | int rate_sym; | ||
2329 | u16 length; | ||
2330 | u16 status; | ||
2331 | u16 bcn_tmr; | ||
2332 | u32 tsf_low; | ||
2333 | u64 tsf; | ||
2334 | u8 rssi; | ||
2335 | u8 agc; | ||
2336 | u16 sig_avg; | ||
2337 | u16 noise_diff; | ||
2338 | struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); | ||
2339 | struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); | ||
2340 | struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); | ||
2341 | u8 *data = IWL_RX_DATA(pkt); | ||
2342 | |||
2343 | if (likely(!(priv->debug_level & IWL_DL_RX))) | ||
2344 | return; | ||
2345 | |||
2346 | /* MAC header */ | ||
2347 | fc = header->frame_control; | ||
2348 | seq_ctl = le16_to_cpu(header->seq_ctrl); | ||
2349 | |||
2350 | /* metadata */ | ||
2351 | channel = le16_to_cpu(rx_hdr->channel); | ||
2352 | phy_flags = le16_to_cpu(rx_hdr->phy_flags); | ||
2353 | rate_sym = rx_hdr->rate; | ||
2354 | length = le16_to_cpu(rx_hdr->len); | ||
2355 | |||
2356 | /* end-of-frame status and timestamp */ | ||
2357 | status = le32_to_cpu(rx_end->status); | ||
2358 | bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); | ||
2359 | tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; | ||
2360 | tsf = le64_to_cpu(rx_end->timestamp); | ||
2361 | |||
2362 | /* signal statistics */ | ||
2363 | rssi = rx_stats->rssi; | ||
2364 | agc = rx_stats->agc; | ||
2365 | sig_avg = le16_to_cpu(rx_stats->sig_avg); | ||
2366 | noise_diff = le16_to_cpu(rx_stats->noise_diff); | ||
2367 | |||
2368 | to_us = !compare_ether_addr(header->addr1, priv->mac_addr); | ||
2369 | |||
2370 | /* if data frame is to us and all is good, | ||
2371 | * (optionally) print summary for only 1 out of every 100 */ | ||
2372 | if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) == | ||
2373 | cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { | ||
2374 | dataframe = 1; | ||
2375 | if (!group100) | ||
2376 | print_summary = 1; /* print each frame */ | ||
2377 | else if (priv->framecnt_to_us < 100) { | ||
2378 | priv->framecnt_to_us++; | ||
2379 | print_summary = 0; | ||
2380 | } else { | ||
2381 | priv->framecnt_to_us = 0; | ||
2382 | print_summary = 1; | ||
2383 | hundred = 1; | ||
2384 | } | ||
2385 | } else { | ||
2386 | /* print summary for all other frames */ | ||
2387 | print_summary = 1; | ||
2388 | } | ||
2389 | |||
2390 | if (print_summary) { | ||
2391 | char *title; | ||
2392 | int rate_idx; | ||
2393 | u32 bitrate; | ||
2394 | |||
2395 | if (hundred) | ||
2396 | title = "100Frames"; | ||
2397 | else if (ieee80211_has_retry(fc)) | ||
2398 | title = "Retry"; | ||
2399 | else if (ieee80211_is_assoc_resp(fc)) | ||
2400 | title = "AscRsp"; | ||
2401 | else if (ieee80211_is_reassoc_resp(fc)) | ||
2402 | title = "RasRsp"; | ||
2403 | else if (ieee80211_is_probe_resp(fc)) { | ||
2404 | title = "PrbRsp"; | ||
2405 | print_dump = 1; /* dump frame contents */ | ||
2406 | } else if (ieee80211_is_beacon(fc)) { | ||
2407 | title = "Beacon"; | ||
2408 | print_dump = 1; /* dump frame contents */ | ||
2409 | } else if (ieee80211_is_atim(fc)) | ||
2410 | title = "ATIM"; | ||
2411 | else if (ieee80211_is_auth(fc)) | ||
2412 | title = "Auth"; | ||
2413 | else if (ieee80211_is_deauth(fc)) | ||
2414 | title = "DeAuth"; | ||
2415 | else if (ieee80211_is_disassoc(fc)) | ||
2416 | title = "DisAssoc"; | ||
2417 | else | ||
2418 | title = "Frame"; | ||
2419 | |||
2420 | rate_idx = iwl_hwrate_to_plcp_idx(rate_sym); | ||
2421 | if (unlikely(rate_idx == -1)) | ||
2422 | bitrate = 0; | ||
2423 | else | ||
2424 | bitrate = iwl_rates[rate_idx].ieee / 2; | ||
2425 | |||
2426 | /* print frame summary. | ||
2427 | * MAC addresses show just the last byte (for brevity), | ||
2428 | * but you can hack it to show more, if you'd like to. */ | ||
2429 | if (dataframe) | ||
2430 | IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " | ||
2431 | "len=%u, rssi=%d, chnl=%d, rate=%u, \n", | ||
2432 | title, le16_to_cpu(fc), header->addr1[5], | ||
2433 | length, rssi, channel, bitrate); | ||
2434 | else { | ||
2435 | /* src/dst addresses assume managed mode */ | ||
2436 | IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " | ||
2437 | "src=0x%02x, rssi=%u, tim=%lu usec, " | ||
2438 | "phy=0x%02x, chnl=%d\n", | ||
2439 | title, le16_to_cpu(fc), header->addr1[5], | ||
2440 | header->addr3[5], rssi, | ||
2441 | tsf_low - priv->scan_start_tsf, | ||
2442 | phy_flags, channel); | ||
2443 | } | ||
2444 | } | ||
2445 | if (print_dump) | ||
2446 | iwl_print_hex_dump(priv, IWL_DL_RX, data, length); | ||
2447 | } | ||
2448 | #else | ||
2449 | static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv, | ||
2450 | struct iwl_rx_packet *pkt, | ||
2451 | struct ieee80211_hdr *header, | ||
2452 | int group100) | ||
2453 | { | ||
2454 | } | ||
2455 | #endif | ||
2456 | |||
2457 | |||
2458 | |||
2459 | /* Called for REPLY_RX (legacy ABG frames), or | ||
2460 | * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ | ||
2461 | void iwl4965_rx_reply_rx(struct iwl_priv *priv, | ||
2462 | struct iwl_rx_mem_buffer *rxb) | ||
2463 | { | ||
2464 | struct ieee80211_hdr *header; | ||
2465 | struct ieee80211_rx_status rx_status; | ||
2466 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
2467 | /* Use phy data (Rx signal strength, etc.) contained within | ||
2468 | * this rx packet for legacy frames, | ||
2469 | * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ | ||
2470 | int include_phy = (pkt->hdr.cmd == REPLY_RX); | ||
2471 | struct iwl4965_rx_phy_res *rx_start = (include_phy) ? | ||
2472 | (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : | ||
2473 | (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; | ||
2474 | __le32 *rx_end; | ||
2475 | unsigned int len = 0; | ||
2476 | u16 fc; | ||
2477 | u8 network_packet; | ||
2478 | |||
2479 | rx_status.mactime = le64_to_cpu(rx_start->timestamp); | ||
2480 | rx_status.freq = | ||
2481 | ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel)); | ||
2482 | rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | ||
2483 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | ||
2484 | rx_status.rate_idx = | ||
2485 | iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); | ||
2486 | if (rx_status.band == IEEE80211_BAND_5GHZ) | ||
2487 | rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; | ||
2488 | |||
2489 | rx_status.antenna = 0; | ||
2490 | rx_status.flag = 0; | ||
2491 | |||
2492 | if ((unlikely(rx_start->cfg_phy_cnt > 20))) { | ||
2493 | IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n", | ||
2494 | rx_start->cfg_phy_cnt); | ||
2495 | return; | ||
2496 | } | ||
2497 | |||
2498 | if (!include_phy) { | ||
2499 | if (priv->last_phy_res[0]) | ||
2500 | rx_start = (struct iwl4965_rx_phy_res *) | ||
2501 | &priv->last_phy_res[1]; | ||
2502 | else | ||
2503 | rx_start = NULL; | ||
2504 | } | ||
2505 | |||
2506 | if (!rx_start) { | ||
2507 | IWL_ERROR("MPDU frame without a PHY data\n"); | ||
2508 | return; | ||
2509 | } | ||
2510 | |||
2511 | if (include_phy) { | ||
2512 | header = (struct ieee80211_hdr *)((u8 *) & rx_start[1] | ||
2513 | + rx_start->cfg_phy_cnt); | ||
2514 | |||
2515 | len = le16_to_cpu(rx_start->byte_count); | ||
2516 | rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + | ||
2517 | sizeof(struct iwl4965_rx_phy_res) + len); | ||
2518 | } else { | ||
2519 | struct iwl4965_rx_mpdu_res_start *amsdu = | ||
2520 | (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; | ||
2521 | |||
2522 | header = (void *)(pkt->u.raw + | ||
2523 | sizeof(struct iwl4965_rx_mpdu_res_start)); | ||
2524 | len = le16_to_cpu(amsdu->byte_count); | ||
2525 | rx_end = (__le32 *) (pkt->u.raw + | ||
2526 | sizeof(struct iwl4965_rx_mpdu_res_start) + len); | ||
2527 | } | ||
2528 | |||
2529 | if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || | ||
2530 | !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { | ||
2531 | IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", | ||
2532 | le32_to_cpu(*rx_end)); | ||
2533 | return; | ||
2534 | } | ||
2535 | |||
2536 | priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); | ||
2537 | |||
2538 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ | ||
2539 | rx_status.signal = iwl4965_calc_rssi(priv, rx_start); | ||
2540 | |||
2541 | /* Meaningful noise values are available only from beacon statistics, | ||
2542 | * which are gathered only when associated, and indicate noise | ||
2543 | * only for the associated network channel ... | ||
2544 | * Ignore these noise values while scanning (other channels) */ | ||
2545 | if (iwl_is_associated(priv) && | ||
2546 | !test_bit(STATUS_SCANNING, &priv->status)) { | ||
2547 | rx_status.noise = priv->last_rx_noise; | ||
2548 | rx_status.qual = iwl4965_calc_sig_qual(rx_status.signal, | ||
2549 | rx_status.noise); | ||
2550 | } else { | ||
2551 | rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||
2552 | rx_status.qual = iwl4965_calc_sig_qual(rx_status.signal, 0); | ||
2553 | } | ||
2554 | |||
2555 | /* Reset beacon noise level if not associated. */ | ||
2556 | if (!iwl_is_associated(priv)) | ||
2557 | priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||
2558 | |||
2559 | /* Set "1" to report good data frames in groups of 100 */ | ||
2560 | /* FIXME: need to optimze the call: */ | ||
2561 | iwl4965_dbg_report_frame(priv, pkt, header, 1); | ||
2562 | |||
2563 | IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", | ||
2564 | rx_status.signal, rx_status.noise, rx_status.signal, | ||
2565 | (unsigned long long)rx_status.mactime); | ||
2566 | |||
2567 | |||
2568 | if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { | ||
2569 | iwl4965_handle_data_packet(priv, 1, include_phy, | ||
2570 | rxb, &rx_status); | ||
2571 | return; | ||
2572 | } | ||
2573 | |||
2574 | network_packet = iwl4965_is_network_packet(priv, header); | ||
2575 | if (network_packet) { | ||
2576 | priv->last_rx_rssi = rx_status.signal; | ||
2577 | priv->last_beacon_time = priv->ucode_beacon_time; | ||
2578 | priv->last_tsf = le64_to_cpu(rx_start->timestamp); | ||
2579 | } | ||
2580 | |||
2581 | fc = le16_to_cpu(header->frame_control); | ||
2582 | switch (fc & IEEE80211_FCTL_FTYPE) { | ||
2583 | case IEEE80211_FTYPE_MGMT: | ||
2584 | if (priv->iw_mode == IEEE80211_IF_TYPE_AP) | ||
2585 | iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, | ||
2586 | header->addr2); | ||
2587 | iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &rx_status); | ||
2588 | break; | ||
2589 | |||
2590 | case IEEE80211_FTYPE_CTL: | ||
2591 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
2592 | case IEEE80211_STYPE_BACK_REQ: | ||
2593 | IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); | ||
2594 | iwl4965_handle_data_packet(priv, 0, include_phy, | ||
2595 | rxb, &rx_status); | ||
2596 | break; | ||
2597 | default: | ||
2598 | break; | ||
2599 | } | ||
2600 | break; | ||
2601 | |||
2602 | case IEEE80211_FTYPE_DATA: { | ||
2603 | DECLARE_MAC_BUF(mac1); | ||
2604 | DECLARE_MAC_BUF(mac2); | ||
2605 | DECLARE_MAC_BUF(mac3); | ||
2606 | |||
2607 | if (priv->iw_mode == IEEE80211_IF_TYPE_AP) | ||
2608 | iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, | ||
2609 | header->addr2); | ||
2610 | |||
2611 | if (unlikely(!network_packet)) | ||
2612 | IWL_DEBUG_DROP("Dropping (non network): " | ||
2613 | "%s, %s, %s\n", | ||
2614 | print_mac(mac1, header->addr1), | ||
2615 | print_mac(mac2, header->addr2), | ||
2616 | print_mac(mac3, header->addr3)); | ||
2617 | else if (unlikely(iwl4965_is_duplicate_packet(priv, header))) | ||
2618 | IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n", | ||
2619 | print_mac(mac1, header->addr1), | ||
2620 | print_mac(mac2, header->addr2), | ||
2621 | print_mac(mac3, header->addr3)); | ||
2622 | else | ||
2623 | iwl4965_handle_data_packet(priv, 1, include_phy, rxb, | ||
2624 | &rx_status); | ||
2625 | break; | ||
2626 | } | ||
2627 | default: | ||
2628 | break; | ||
2629 | |||
2630 | } | ||
2631 | } | ||
2632 | |||
2633 | /** | 1932 | /** |
2634 | * iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack | 1933 | * iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack |
2635 | * | 1934 | * |
@@ -3253,7 +2552,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, | |||
3253 | static void iwl4965_rx_handler_setup(struct iwl_priv *priv) | 2552 | static void iwl4965_rx_handler_setup(struct iwl_priv *priv) |
3254 | { | 2553 | { |
3255 | /* Legacy Rx frames */ | 2554 | /* Legacy Rx frames */ |
3256 | priv->rx_handlers[REPLY_RX] = iwl4965_rx_reply_rx; | 2555 | priv->rx_handlers[REPLY_RX] = iwl_rx_reply_rx; |
3257 | /* Tx response */ | 2556 | /* Tx response */ |
3258 | priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; | 2557 | priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; |
3259 | /* block ack */ | 2558 | /* block ack */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 0cff64d878e..0d8cc8c659a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -372,7 +372,11 @@ extern void iwl_rf_kill_ct_config(struct iwl_priv *priv); | |||
372 | extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags); | 372 | extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags); |
373 | extern int iwl_verify_ucode(struct iwl_priv *priv); | 373 | extern int iwl_verify_ucode(struct iwl_priv *priv); |
374 | extern int iwl_send_lq_cmd(struct iwl_priv *priv, | 374 | extern int iwl_send_lq_cmd(struct iwl_priv *priv, |
375 | struct iwl_link_quality_cmd *lq, u8 flags); | 375 | struct iwl_link_quality_cmd *lq, u8 flags); |
376 | extern void iwl_rx_reply_rx(struct iwl_priv *priv, | ||
377 | struct iwl_rx_mem_buffer *rxb); | ||
378 | extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv, | ||
379 | struct iwl_rx_mem_buffer *rxb); | ||
376 | 380 | ||
377 | static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) | 381 | static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) |
378 | { | 382 | { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index fd008ab63bd..8017e57dc14 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -591,11 +591,6 @@ extern int iwl_send_add_sta(struct iwl_priv *priv, | |||
591 | struct iwl_addsta_cmd *sta, u8 flags); | 591 | struct iwl_addsta_cmd *sta, u8 flags); |
592 | u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, | 592 | u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, |
593 | u8 flags, struct ieee80211_ht_info *ht_info); | 593 | u8 flags, struct ieee80211_ht_info *ht_info); |
594 | extern int iwl4965_is_network_packet(struct iwl_priv *priv, | ||
595 | struct ieee80211_hdr *header); | ||
596 | extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv, | ||
597 | struct ieee80211_hdr *header); | ||
598 | extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm); | ||
599 | extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, | 594 | extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, |
600 | struct ieee80211_hdr *hdr, | 595 | struct ieee80211_hdr *hdr, |
601 | const u8 *dest, int left); | 596 | const u8 *dest, int left); |
@@ -625,8 +620,6 @@ extern void iwl_txq_ctx_stop(struct iwl_priv *priv); | |||
625 | extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, | 620 | extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, |
626 | struct iwl_frame *frame, u8 rate); | 621 | struct iwl_frame *frame, u8 rate); |
627 | extern void iwl4965_disable_events(struct iwl_priv *priv); | 622 | extern void iwl4965_disable_events(struct iwl_priv *priv); |
628 | extern void iwl4965_rx_reply_rx(struct iwl_priv *priv, | ||
629 | struct iwl_rx_mem_buffer *rxb); | ||
630 | 623 | ||
631 | extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); | 624 | extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); |
632 | extern int iwl_queue_space(const struct iwl_queue *q); | 625 | extern int iwl_queue_space(const struct iwl_queue *q); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index b3ca1375c01..e0d3e2dd1d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -27,6 +27,7 @@ | |||
27 | * | 27 | * |
28 | *****************************************************************************/ | 28 | *****************************************************************************/ |
29 | 29 | ||
30 | #include <linux/etherdevice.h> | ||
30 | #include <net/mac80211.h> | 31 | #include <net/mac80211.h> |
31 | #include "iwl-eeprom.h" | 32 | #include "iwl-eeprom.h" |
32 | #include "iwl-dev.h" | 33 | #include "iwl-dev.h" |
@@ -541,3 +542,855 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
541 | priv->cfg->ops->lib->temperature(priv, &pkt->u.stats); | 542 | priv->cfg->ops->lib->temperature(priv, &pkt->u.stats); |
542 | } | 543 | } |
543 | EXPORT_SYMBOL(iwl_rx_statistics); | 544 | EXPORT_SYMBOL(iwl_rx_statistics); |
545 | |||
546 | #define PERFECT_RSSI (-20) /* dBm */ | ||
547 | #define WORST_RSSI (-95) /* dBm */ | ||
548 | #define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) | ||
549 | |||
550 | /* Calculate an indication of rx signal quality (a percentage, not dBm!). | ||
551 | * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info | ||
552 | * about formulas used below. */ | ||
553 | static int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) | ||
554 | { | ||
555 | int sig_qual; | ||
556 | int degradation = PERFECT_RSSI - rssi_dbm; | ||
557 | |||
558 | /* If we get a noise measurement, use signal-to-noise ratio (SNR) | ||
559 | * as indicator; formula is (signal dbm - noise dbm). | ||
560 | * SNR at or above 40 is a great signal (100%). | ||
561 | * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. | ||
562 | * Weakest usable signal is usually 10 - 15 dB SNR. */ | ||
563 | if (noise_dbm) { | ||
564 | if (rssi_dbm - noise_dbm >= 40) | ||
565 | return 100; | ||
566 | else if (rssi_dbm < noise_dbm) | ||
567 | return 0; | ||
568 | sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; | ||
569 | |||
570 | /* Else use just the signal level. | ||
571 | * This formula is a least squares fit of data points collected and | ||
572 | * compared with a reference system that had a percentage (%) display | ||
573 | * for signal quality. */ | ||
574 | } else | ||
575 | sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * | ||
576 | (15 * RSSI_RANGE + 62 * degradation)) / | ||
577 | (RSSI_RANGE * RSSI_RANGE); | ||
578 | |||
579 | if (sig_qual > 100) | ||
580 | sig_qual = 100; | ||
581 | else if (sig_qual < 1) | ||
582 | sig_qual = 0; | ||
583 | |||
584 | return sig_qual; | ||
585 | } | ||
586 | |||
587 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
588 | |||
589 | /** | ||
590 | * iwl_dbg_report_frame - dump frame to syslog during debug sessions | ||
591 | * | ||
592 | * You may hack this function to show different aspects of received frames, | ||
593 | * including selective frame dumps. | ||
594 | * group100 parameter selects whether to show 1 out of 100 good frames. | ||
595 | * | ||
596 | * TODO: This was originally written for 3945, need to audit for | ||
597 | * proper operation with 4965. | ||
598 | */ | ||
599 | static void iwl_dbg_report_frame(struct iwl_priv *priv, | ||
600 | struct iwl_rx_packet *pkt, | ||
601 | struct ieee80211_hdr *header, int group100) | ||
602 | { | ||
603 | u32 to_us; | ||
604 | u32 print_summary = 0; | ||
605 | u32 print_dump = 0; /* set to 1 to dump all frames' contents */ | ||
606 | u32 hundred = 0; | ||
607 | u32 dataframe = 0; | ||
608 | __le16 fc; | ||
609 | u16 seq_ctl; | ||
610 | u16 channel; | ||
611 | u16 phy_flags; | ||
612 | int rate_sym; | ||
613 | u16 length; | ||
614 | u16 status; | ||
615 | u16 bcn_tmr; | ||
616 | u32 tsf_low; | ||
617 | u64 tsf; | ||
618 | u8 rssi; | ||
619 | u8 agc; | ||
620 | u16 sig_avg; | ||
621 | u16 noise_diff; | ||
622 | struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); | ||
623 | struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); | ||
624 | struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); | ||
625 | u8 *data = IWL_RX_DATA(pkt); | ||
626 | |||
627 | if (likely(!(priv->debug_level & IWL_DL_RX))) | ||
628 | return; | ||
629 | |||
630 | /* MAC header */ | ||
631 | fc = header->frame_control; | ||
632 | seq_ctl = le16_to_cpu(header->seq_ctrl); | ||
633 | |||
634 | /* metadata */ | ||
635 | channel = le16_to_cpu(rx_hdr->channel); | ||
636 | phy_flags = le16_to_cpu(rx_hdr->phy_flags); | ||
637 | rate_sym = rx_hdr->rate; | ||
638 | length = le16_to_cpu(rx_hdr->len); | ||
639 | |||
640 | /* end-of-frame status and timestamp */ | ||
641 | status = le32_to_cpu(rx_end->status); | ||
642 | bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); | ||
643 | tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; | ||
644 | tsf = le64_to_cpu(rx_end->timestamp); | ||
645 | |||
646 | /* signal statistics */ | ||
647 | rssi = rx_stats->rssi; | ||
648 | agc = rx_stats->agc; | ||
649 | sig_avg = le16_to_cpu(rx_stats->sig_avg); | ||
650 | noise_diff = le16_to_cpu(rx_stats->noise_diff); | ||
651 | |||
652 | to_us = !compare_ether_addr(header->addr1, priv->mac_addr); | ||
653 | |||
654 | /* if data frame is to us and all is good, | ||
655 | * (optionally) print summary for only 1 out of every 100 */ | ||
656 | if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) == | ||
657 | cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { | ||
658 | dataframe = 1; | ||
659 | if (!group100) | ||
660 | print_summary = 1; /* print each frame */ | ||
661 | else if (priv->framecnt_to_us < 100) { | ||
662 | priv->framecnt_to_us++; | ||
663 | print_summary = 0; | ||
664 | } else { | ||
665 | priv->framecnt_to_us = 0; | ||
666 | print_summary = 1; | ||
667 | hundred = 1; | ||
668 | } | ||
669 | } else { | ||
670 | /* print summary for all other frames */ | ||
671 | print_summary = 1; | ||
672 | } | ||
673 | |||
674 | if (print_summary) { | ||
675 | char *title; | ||
676 | int rate_idx; | ||
677 | u32 bitrate; | ||
678 | |||
679 | if (hundred) | ||
680 | title = "100Frames"; | ||
681 | else if (ieee80211_has_retry(fc)) | ||
682 | title = "Retry"; | ||
683 | else if (ieee80211_is_assoc_resp(fc)) | ||
684 | title = "AscRsp"; | ||
685 | else if (ieee80211_is_reassoc_resp(fc)) | ||
686 | title = "RasRsp"; | ||
687 | else if (ieee80211_is_probe_resp(fc)) { | ||
688 | title = "PrbRsp"; | ||
689 | print_dump = 1; /* dump frame contents */ | ||
690 | } else if (ieee80211_is_beacon(fc)) { | ||
691 | title = "Beacon"; | ||
692 | print_dump = 1; /* dump frame contents */ | ||
693 | } else if (ieee80211_is_atim(fc)) | ||
694 | title = "ATIM"; | ||
695 | else if (ieee80211_is_auth(fc)) | ||
696 | title = "Auth"; | ||
697 | else if (ieee80211_is_deauth(fc)) | ||
698 | title = "DeAuth"; | ||
699 | else if (ieee80211_is_disassoc(fc)) | ||
700 | title = "DisAssoc"; | ||
701 | else | ||
702 | title = "Frame"; | ||
703 | |||
704 | rate_idx = iwl_hwrate_to_plcp_idx(rate_sym); | ||
705 | if (unlikely(rate_idx == -1)) | ||
706 | bitrate = 0; | ||
707 | else | ||
708 | bitrate = iwl_rates[rate_idx].ieee / 2; | ||
709 | |||
710 | /* print frame summary. | ||
711 | * MAC addresses show just the last byte (for brevity), | ||
712 | * but you can hack it to show more, if you'd like to. */ | ||
713 | if (dataframe) | ||
714 | IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " | ||
715 | "len=%u, rssi=%d, chnl=%d, rate=%u, \n", | ||
716 | title, le16_to_cpu(fc), header->addr1[5], | ||
717 | length, rssi, channel, bitrate); | ||
718 | else { | ||
719 | /* src/dst addresses assume managed mode */ | ||
720 | IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " | ||
721 | "src=0x%02x, rssi=%u, tim=%lu usec, " | ||
722 | "phy=0x%02x, chnl=%d\n", | ||
723 | title, le16_to_cpu(fc), header->addr1[5], | ||
724 | header->addr3[5], rssi, | ||
725 | tsf_low - priv->scan_start_tsf, | ||
726 | phy_flags, channel); | ||
727 | } | ||
728 | } | ||
729 | if (print_dump) | ||
730 | iwl_print_hex_dump(priv, IWL_DL_RX, data, length); | ||
731 | } | ||
732 | #else | ||
733 | static inline void iwl_dbg_report_frame(struct iwl_priv *priv, | ||
734 | struct iwl_rx_packet *pkt, | ||
735 | struct ieee80211_hdr *header, | ||
736 | int group100) | ||
737 | { | ||
738 | } | ||
739 | #endif | ||
740 | |||
741 | static void iwl_add_radiotap(struct iwl_priv *priv, | ||
742 | struct sk_buff *skb, | ||
743 | struct iwl4965_rx_phy_res *rx_start, | ||
744 | struct ieee80211_rx_status *stats, | ||
745 | u32 ampdu_status) | ||
746 | { | ||
747 | s8 signal = stats->signal; | ||
748 | s8 noise = 0; | ||
749 | int rate = stats->rate_idx; | ||
750 | u64 tsf = stats->mactime; | ||
751 | __le16 antenna; | ||
752 | __le16 phy_flags_hw = rx_start->phy_flags; | ||
753 | struct iwl4965_rt_rx_hdr { | ||
754 | struct ieee80211_radiotap_header rt_hdr; | ||
755 | __le64 rt_tsf; /* TSF */ | ||
756 | u8 rt_flags; /* radiotap packet flags */ | ||
757 | u8 rt_rate; /* rate in 500kb/s */ | ||
758 | __le16 rt_channelMHz; /* channel in MHz */ | ||
759 | __le16 rt_chbitmask; /* channel bitfield */ | ||
760 | s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ | ||
761 | s8 rt_dbmnoise; | ||
762 | u8 rt_antenna; /* antenna number */ | ||
763 | } __attribute__ ((packed)) *iwl4965_rt; | ||
764 | |||
765 | /* TODO: We won't have enough headroom for HT frames. Fix it later. */ | ||
766 | if (skb_headroom(skb) < sizeof(*iwl4965_rt)) { | ||
767 | if (net_ratelimit()) | ||
768 | printk(KERN_ERR "not enough headroom [%d] for " | ||
769 | "radiotap head [%zd]\n", | ||
770 | skb_headroom(skb), sizeof(*iwl4965_rt)); | ||
771 | return; | ||
772 | } | ||
773 | |||
774 | /* put radiotap header in front of 802.11 header and data */ | ||
775 | iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt)); | ||
776 | |||
777 | /* initialise radiotap header */ | ||
778 | iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; | ||
779 | iwl4965_rt->rt_hdr.it_pad = 0; | ||
780 | |||
781 | /* total header + data */ | ||
782 | put_unaligned(cpu_to_le16(sizeof(*iwl4965_rt)), | ||
783 | &iwl4965_rt->rt_hdr.it_len); | ||
784 | |||
785 | /* Indicate all the fields we add to the radiotap header */ | ||
786 | put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | | ||
787 | (1 << IEEE80211_RADIOTAP_FLAGS) | | ||
788 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
789 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
790 | (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | | ||
791 | (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | | ||
792 | (1 << IEEE80211_RADIOTAP_ANTENNA)), | ||
793 | &iwl4965_rt->rt_hdr.it_present); | ||
794 | |||
795 | /* Zero the flags, we'll add to them as we go */ | ||
796 | iwl4965_rt->rt_flags = 0; | ||
797 | |||
798 | put_unaligned(cpu_to_le64(tsf), &iwl4965_rt->rt_tsf); | ||
799 | |||
800 | iwl4965_rt->rt_dbmsignal = signal; | ||
801 | iwl4965_rt->rt_dbmnoise = noise; | ||
802 | |||
803 | /* Convert the channel frequency and set the flags */ | ||
804 | put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz); | ||
805 | if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) | ||
806 | put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
807 | IEEE80211_CHAN_5GHZ), | ||
808 | &iwl4965_rt->rt_chbitmask); | ||
809 | else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) | ||
810 | put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | | ||
811 | IEEE80211_CHAN_2GHZ), | ||
812 | &iwl4965_rt->rt_chbitmask); | ||
813 | else /* 802.11g */ | ||
814 | put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
815 | IEEE80211_CHAN_2GHZ), | ||
816 | &iwl4965_rt->rt_chbitmask); | ||
817 | |||
818 | if (rate == -1) | ||
819 | iwl4965_rt->rt_rate = 0; | ||
820 | else | ||
821 | iwl4965_rt->rt_rate = iwl_rates[rate].ieee; | ||
822 | |||
823 | /* | ||
824 | * "antenna number" | ||
825 | * | ||
826 | * It seems that the antenna field in the phy flags value | ||
827 | * is actually a bitfield. This is undefined by radiotap, | ||
828 | * it wants an actual antenna number but I always get "7" | ||
829 | * for most legacy frames I receive indicating that the | ||
830 | * same frame was received on all three RX chains. | ||
831 | * | ||
832 | * I think this field should be removed in favour of a | ||
833 | * new 802.11n radiotap field "RX chains" that is defined | ||
834 | * as a bitmask. | ||
835 | */ | ||
836 | antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; | ||
837 | iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4; | ||
838 | |||
839 | /* set the preamble flag if appropriate */ | ||
840 | if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) | ||
841 | iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; | ||
842 | |||
843 | stats->flag |= RX_FLAG_RADIOTAP; | ||
844 | } | ||
845 | |||
846 | static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) | ||
847 | { | ||
848 | /* 0 - mgmt, 1 - cnt, 2 - data */ | ||
849 | int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; | ||
850 | priv->rx_stats[idx].cnt++; | ||
851 | priv->rx_stats[idx].bytes += len; | ||
852 | } | ||
853 | |||
854 | /* | ||
855 | * returns non-zero if packet should be dropped | ||
856 | */ | ||
857 | static int iwl_set_decrypted_flag(struct iwl_priv *priv, | ||
858 | struct ieee80211_hdr *hdr, | ||
859 | u32 decrypt_res, | ||
860 | struct ieee80211_rx_status *stats) | ||
861 | { | ||
862 | u16 fc = le16_to_cpu(hdr->frame_control); | ||
863 | |||
864 | if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) | ||
865 | return 0; | ||
866 | |||
867 | if (!(fc & IEEE80211_FCTL_PROTECTED)) | ||
868 | return 0; | ||
869 | |||
870 | IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); | ||
871 | switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { | ||
872 | case RX_RES_STATUS_SEC_TYPE_TKIP: | ||
873 | /* The uCode has got a bad phase 1 Key, pushes the packet. | ||
874 | * Decryption will be done in SW. */ | ||
875 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == | ||
876 | RX_RES_STATUS_BAD_KEY_TTAK) | ||
877 | break; | ||
878 | |||
879 | case RX_RES_STATUS_SEC_TYPE_WEP: | ||
880 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == | ||
881 | RX_RES_STATUS_BAD_ICV_MIC) { | ||
882 | /* bad ICV, the packet is destroyed since the | ||
883 | * decryption is inplace, drop it */ | ||
884 | IWL_DEBUG_RX("Packet destroyed\n"); | ||
885 | return -1; | ||
886 | } | ||
887 | case RX_RES_STATUS_SEC_TYPE_CCMP: | ||
888 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == | ||
889 | RX_RES_STATUS_DECRYPT_OK) { | ||
890 | IWL_DEBUG_RX("hw decrypt successfully!!!\n"); | ||
891 | stats->flag |= RX_FLAG_DECRYPTED; | ||
892 | } | ||
893 | break; | ||
894 | |||
895 | default: | ||
896 | break; | ||
897 | } | ||
898 | return 0; | ||
899 | } | ||
900 | |||
901 | static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) | ||
902 | { | ||
903 | u32 decrypt_out = 0; | ||
904 | |||
905 | if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == | ||
906 | RX_RES_STATUS_STATION_FOUND) | ||
907 | decrypt_out |= (RX_RES_STATUS_STATION_FOUND | | ||
908 | RX_RES_STATUS_NO_STATION_INFO_MISMATCH); | ||
909 | |||
910 | decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); | ||
911 | |||
912 | /* packet was not encrypted */ | ||
913 | if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == | ||
914 | RX_RES_STATUS_SEC_TYPE_NONE) | ||
915 | return decrypt_out; | ||
916 | |||
917 | /* packet was encrypted with unknown alg */ | ||
918 | if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == | ||
919 | RX_RES_STATUS_SEC_TYPE_ERR) | ||
920 | return decrypt_out; | ||
921 | |||
922 | /* decryption was not done in HW */ | ||
923 | if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != | ||
924 | RX_MPDU_RES_STATUS_DEC_DONE_MSK) | ||
925 | return decrypt_out; | ||
926 | |||
927 | switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { | ||
928 | |||
929 | case RX_RES_STATUS_SEC_TYPE_CCMP: | ||
930 | /* alg is CCM: check MIC only */ | ||
931 | if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) | ||
932 | /* Bad MIC */ | ||
933 | decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; | ||
934 | else | ||
935 | decrypt_out |= RX_RES_STATUS_DECRYPT_OK; | ||
936 | |||
937 | break; | ||
938 | |||
939 | case RX_RES_STATUS_SEC_TYPE_TKIP: | ||
940 | if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { | ||
941 | /* Bad TTAK */ | ||
942 | decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; | ||
943 | break; | ||
944 | } | ||
945 | /* fall through if TTAK OK */ | ||
946 | default: | ||
947 | if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) | ||
948 | decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; | ||
949 | else | ||
950 | decrypt_out |= RX_RES_STATUS_DECRYPT_OK; | ||
951 | break; | ||
952 | }; | ||
953 | |||
954 | IWL_DEBUG_RX("decrypt_in:0x%x decrypt_out = 0x%x\n", | ||
955 | decrypt_in, decrypt_out); | ||
956 | |||
957 | return decrypt_out; | ||
958 | } | ||
959 | |||
960 | static void iwl_handle_data_packet(struct iwl_priv *priv, int is_data, | ||
961 | int include_phy, | ||
962 | struct iwl_rx_mem_buffer *rxb, | ||
963 | struct ieee80211_rx_status *stats) | ||
964 | { | ||
965 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
966 | struct iwl4965_rx_phy_res *rx_start = (include_phy) ? | ||
967 | (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; | ||
968 | struct ieee80211_hdr *hdr; | ||
969 | u16 len; | ||
970 | __le32 *rx_end; | ||
971 | unsigned int skblen; | ||
972 | u32 ampdu_status; | ||
973 | u32 ampdu_status_legacy; | ||
974 | |||
975 | if (!include_phy && priv->last_phy_res[0]) | ||
976 | rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; | ||
977 | |||
978 | if (!rx_start) { | ||
979 | IWL_ERROR("MPDU frame without a PHY data\n"); | ||
980 | return; | ||
981 | } | ||
982 | if (include_phy) { | ||
983 | hdr = (struct ieee80211_hdr *)((u8 *) &rx_start[1] + | ||
984 | rx_start->cfg_phy_cnt); | ||
985 | |||
986 | len = le16_to_cpu(rx_start->byte_count); | ||
987 | |||
988 | rx_end = (__le32 *) ((u8 *) &pkt->u.raw[0] + | ||
989 | sizeof(struct iwl4965_rx_phy_res) + | ||
990 | rx_start->cfg_phy_cnt + len); | ||
991 | |||
992 | } else { | ||
993 | struct iwl4965_rx_mpdu_res_start *amsdu = | ||
994 | (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; | ||
995 | |||
996 | hdr = (struct ieee80211_hdr *)(pkt->u.raw + | ||
997 | sizeof(struct iwl4965_rx_mpdu_res_start)); | ||
998 | len = le16_to_cpu(amsdu->byte_count); | ||
999 | rx_start->byte_count = amsdu->byte_count; | ||
1000 | rx_end = (__le32 *) (((u8 *) hdr) + len); | ||
1001 | } | ||
1002 | /* In monitor mode allow 802.11 ACk frames (10 bytes) */ | ||
1003 | if (len > priv->hw_params.max_pkt_size || | ||
1004 | len < ((priv->iw_mode == IEEE80211_IF_TYPE_MNTR) ? 10 : 16)) { | ||
1005 | IWL_WARNING("byte count out of range [16,4K] : %d\n", len); | ||
1006 | return; | ||
1007 | } | ||
1008 | |||
1009 | ampdu_status = le32_to_cpu(*rx_end); | ||
1010 | skblen = ((u8 *) rx_end - (u8 *) &pkt->u.raw[0]) + sizeof(u32); | ||
1011 | |||
1012 | if (!include_phy) { | ||
1013 | /* New status scheme, need to translate */ | ||
1014 | ampdu_status_legacy = ampdu_status; | ||
1015 | ampdu_status = iwl_translate_rx_status(priv, ampdu_status); | ||
1016 | } | ||
1017 | |||
1018 | /* start from MAC */ | ||
1019 | skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); | ||
1020 | skb_put(rxb->skb, len); /* end where data ends */ | ||
1021 | |||
1022 | /* We only process data packets if the interface is open */ | ||
1023 | if (unlikely(!priv->is_open)) { | ||
1024 | IWL_DEBUG_DROP_LIMIT | ||
1025 | ("Dropping packet while interface is not open.\n"); | ||
1026 | return; | ||
1027 | } | ||
1028 | |||
1029 | stats->flag = 0; | ||
1030 | hdr = (struct ieee80211_hdr *)rxb->skb->data; | ||
1031 | |||
1032 | /* in case of HW accelerated crypto and bad decryption, drop */ | ||
1033 | if (!priv->hw_params.sw_crypto && | ||
1034 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) | ||
1035 | return; | ||
1036 | |||
1037 | if (priv->add_radiotap) | ||
1038 | iwl_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); | ||
1039 | |||
1040 | iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); | ||
1041 | ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); | ||
1042 | priv->alloc_rxb_skb--; | ||
1043 | rxb->skb = NULL; | ||
1044 | } | ||
1045 | |||
1046 | /* Calc max signal level (dBm) among 3 possible receivers */ | ||
1047 | static int iwl_calc_rssi(struct iwl_priv *priv, | ||
1048 | struct iwl4965_rx_phy_res *rx_resp) | ||
1049 | { | ||
1050 | /* data from PHY/DSP regarding signal strength, etc., | ||
1051 | * contents are always there, not configurable by host. */ | ||
1052 | struct iwl4965_rx_non_cfg_phy *ncphy = | ||
1053 | (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy; | ||
1054 | u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK) | ||
1055 | >> IWL_AGC_DB_POS; | ||
1056 | |||
1057 | u32 valid_antennae = | ||
1058 | (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK) | ||
1059 | >> RX_PHY_FLAGS_ANTENNAE_OFFSET; | ||
1060 | u8 max_rssi = 0; | ||
1061 | u32 i; | ||
1062 | |||
1063 | /* Find max rssi among 3 possible receivers. | ||
1064 | * These values are measured by the digital signal processor (DSP). | ||
1065 | * They should stay fairly constant even as the signal strength varies, | ||
1066 | * if the radio's automatic gain control (AGC) is working right. | ||
1067 | * AGC value (see below) will provide the "interesting" info. */ | ||
1068 | for (i = 0; i < 3; i++) | ||
1069 | if (valid_antennae & (1 << i)) | ||
1070 | max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); | ||
1071 | |||
1072 | IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", | ||
1073 | ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], | ||
1074 | max_rssi, agc); | ||
1075 | |||
1076 | /* dBm = max_rssi dB - agc dB - constant. | ||
1077 | * Higher AGC (higher radio gain) means lower signal. */ | ||
1078 | return max_rssi - agc - IWL_RSSI_OFFSET; | ||
1079 | } | ||
1080 | |||
1081 | static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) | ||
1082 | { | ||
1083 | unsigned long flags; | ||
1084 | |||
1085 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
1086 | priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; | ||
1087 | priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; | ||
1088 | priv->stations[sta_id].sta.sta.modify_mask = 0; | ||
1089 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | ||
1090 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1091 | |||
1092 | iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); | ||
1093 | } | ||
1094 | |||
1095 | static void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) | ||
1096 | { | ||
1097 | /* FIXME: need locking over ps_status ??? */ | ||
1098 | u8 sta_id = iwl_find_station(priv, addr); | ||
1099 | |||
1100 | if (sta_id != IWL_INVALID_STATION) { | ||
1101 | u8 sta_awake = priv->stations[sta_id]. | ||
1102 | ps_status == STA_PS_STATUS_WAKE; | ||
1103 | |||
1104 | if (sta_awake && ps_bit) | ||
1105 | priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; | ||
1106 | else if (!sta_awake && !ps_bit) { | ||
1107 | iwl_sta_modify_ps_wake(priv, sta_id); | ||
1108 | priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; | ||
1109 | } | ||
1110 | } | ||
1111 | } | ||
1112 | |||
1113 | #define IWL_PACKET_RETRY_TIME HZ | ||
1114 | |||
1115 | static int iwl_is_duplicate_packet(struct iwl_priv *priv, | ||
1116 | struct ieee80211_hdr *header) | ||
1117 | { | ||
1118 | u16 sc = le16_to_cpu(header->seq_ctrl); | ||
1119 | u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; | ||
1120 | u16 frag = sc & IEEE80211_SCTL_FRAG; | ||
1121 | u16 *last_seq, *last_frag; | ||
1122 | unsigned long *last_time; | ||
1123 | |||
1124 | switch (priv->iw_mode) { | ||
1125 | case IEEE80211_IF_TYPE_IBSS:{ | ||
1126 | struct list_head *p; | ||
1127 | struct iwl4965_ibss_seq *entry = NULL; | ||
1128 | u8 *mac = header->addr2; | ||
1129 | int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1); | ||
1130 | |||
1131 | __list_for_each(p, &priv->ibss_mac_hash[index]) { | ||
1132 | entry = list_entry(p, struct iwl4965_ibss_seq, list); | ||
1133 | if (!compare_ether_addr(entry->mac, mac)) | ||
1134 | break; | ||
1135 | } | ||
1136 | if (p == &priv->ibss_mac_hash[index]) { | ||
1137 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
1138 | if (!entry) { | ||
1139 | IWL_ERROR("Cannot malloc new mac entry\n"); | ||
1140 | return 0; | ||
1141 | } | ||
1142 | memcpy(entry->mac, mac, ETH_ALEN); | ||
1143 | entry->seq_num = seq; | ||
1144 | entry->frag_num = frag; | ||
1145 | entry->packet_time = jiffies; | ||
1146 | list_add(&entry->list, &priv->ibss_mac_hash[index]); | ||
1147 | return 0; | ||
1148 | } | ||
1149 | last_seq = &entry->seq_num; | ||
1150 | last_frag = &entry->frag_num; | ||
1151 | last_time = &entry->packet_time; | ||
1152 | break; | ||
1153 | } | ||
1154 | case IEEE80211_IF_TYPE_STA: | ||
1155 | last_seq = &priv->last_seq_num; | ||
1156 | last_frag = &priv->last_frag_num; | ||
1157 | last_time = &priv->last_packet_time; | ||
1158 | break; | ||
1159 | default: | ||
1160 | return 0; | ||
1161 | } | ||
1162 | if ((*last_seq == seq) && | ||
1163 | time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) { | ||
1164 | if (*last_frag == frag) | ||
1165 | goto drop; | ||
1166 | if (*last_frag + 1 != frag) | ||
1167 | /* out-of-order fragment */ | ||
1168 | goto drop; | ||
1169 | } else | ||
1170 | *last_seq = seq; | ||
1171 | |||
1172 | *last_frag = frag; | ||
1173 | *last_time = jiffies; | ||
1174 | return 0; | ||
1175 | |||
1176 | drop: | ||
1177 | return 1; | ||
1178 | } | ||
1179 | |||
1180 | static int iwl_is_network_packet(struct iwl_priv *priv, | ||
1181 | struct ieee80211_hdr *header) | ||
1182 | { | ||
1183 | /* Filter incoming packets to determine if they are targeted toward | ||
1184 | * this network, discarding packets coming from ourselves */ | ||
1185 | switch (priv->iw_mode) { | ||
1186 | case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ | ||
1187 | /* packets from our adapter are dropped (echo) */ | ||
1188 | if (!compare_ether_addr(header->addr2, priv->mac_addr)) | ||
1189 | return 0; | ||
1190 | /* {broad,multi}cast packets to our IBSS go through */ | ||
1191 | if (is_multicast_ether_addr(header->addr1)) | ||
1192 | return !compare_ether_addr(header->addr3, priv->bssid); | ||
1193 | /* packets to our adapter go through */ | ||
1194 | return !compare_ether_addr(header->addr1, priv->mac_addr); | ||
1195 | case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ | ||
1196 | /* packets from our adapter are dropped (echo) */ | ||
1197 | if (!compare_ether_addr(header->addr3, priv->mac_addr)) | ||
1198 | return 0; | ||
1199 | /* {broad,multi}cast packets to our BSS go through */ | ||
1200 | if (is_multicast_ether_addr(header->addr1)) | ||
1201 | return !compare_ether_addr(header->addr2, priv->bssid); | ||
1202 | /* packets to our adapter go through */ | ||
1203 | return !compare_ether_addr(header->addr1, priv->mac_addr); | ||
1204 | default: | ||
1205 | break; | ||
1206 | } | ||
1207 | |||
1208 | return 1; | ||
1209 | } | ||
1210 | |||
1211 | /* Called for REPLY_RX (legacy ABG frames), or | ||
1212 | * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ | ||
1213 | void iwl_rx_reply_rx(struct iwl_priv *priv, | ||
1214 | struct iwl_rx_mem_buffer *rxb) | ||
1215 | { | ||
1216 | struct ieee80211_hdr *header; | ||
1217 | struct ieee80211_rx_status rx_status; | ||
1218 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
1219 | /* Use phy data (Rx signal strength, etc.) contained within | ||
1220 | * this rx packet for legacy frames, | ||
1221 | * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ | ||
1222 | int include_phy = (pkt->hdr.cmd == REPLY_RX); | ||
1223 | struct iwl4965_rx_phy_res *rx_start = (include_phy) ? | ||
1224 | (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : | ||
1225 | (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; | ||
1226 | __le32 *rx_end; | ||
1227 | unsigned int len = 0; | ||
1228 | u16 fc; | ||
1229 | u8 network_packet; | ||
1230 | |||
1231 | rx_status.mactime = le64_to_cpu(rx_start->timestamp); | ||
1232 | rx_status.freq = | ||
1233 | ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel)); | ||
1234 | rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | ||
1235 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | ||
1236 | rx_status.rate_idx = | ||
1237 | iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); | ||
1238 | if (rx_status.band == IEEE80211_BAND_5GHZ) | ||
1239 | rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; | ||
1240 | |||
1241 | rx_status.antenna = 0; | ||
1242 | rx_status.flag = 0; | ||
1243 | |||
1244 | if ((unlikely(rx_start->cfg_phy_cnt > 20))) { | ||
1245 | IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n", | ||
1246 | rx_start->cfg_phy_cnt); | ||
1247 | return; | ||
1248 | } | ||
1249 | |||
1250 | if (!include_phy) { | ||
1251 | if (priv->last_phy_res[0]) | ||
1252 | rx_start = (struct iwl4965_rx_phy_res *) | ||
1253 | &priv->last_phy_res[1]; | ||
1254 | else | ||
1255 | rx_start = NULL; | ||
1256 | } | ||
1257 | |||
1258 | if (!rx_start) { | ||
1259 | IWL_ERROR("MPDU frame without a PHY data\n"); | ||
1260 | return; | ||
1261 | } | ||
1262 | |||
1263 | if (include_phy) { | ||
1264 | header = (struct ieee80211_hdr *)((u8 *) &rx_start[1] | ||
1265 | + rx_start->cfg_phy_cnt); | ||
1266 | |||
1267 | len = le16_to_cpu(rx_start->byte_count); | ||
1268 | rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + | ||
1269 | sizeof(struct iwl4965_rx_phy_res) + len); | ||
1270 | } else { | ||
1271 | struct iwl4965_rx_mpdu_res_start *amsdu = | ||
1272 | (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; | ||
1273 | |||
1274 | header = (void *)(pkt->u.raw + | ||
1275 | sizeof(struct iwl4965_rx_mpdu_res_start)); | ||
1276 | len = le16_to_cpu(amsdu->byte_count); | ||
1277 | rx_end = (__le32 *) (pkt->u.raw + | ||
1278 | sizeof(struct iwl4965_rx_mpdu_res_start) + len); | ||
1279 | } | ||
1280 | |||
1281 | if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || | ||
1282 | !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { | ||
1283 | IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", | ||
1284 | le32_to_cpu(*rx_end)); | ||
1285 | return; | ||
1286 | } | ||
1287 | |||
1288 | priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); | ||
1289 | |||
1290 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ | ||
1291 | rx_status.signal = iwl_calc_rssi(priv, rx_start); | ||
1292 | |||
1293 | /* Meaningful noise values are available only from beacon statistics, | ||
1294 | * which are gathered only when associated, and indicate noise | ||
1295 | * only for the associated network channel ... | ||
1296 | * Ignore these noise values while scanning (other channels) */ | ||
1297 | if (iwl_is_associated(priv) && | ||
1298 | !test_bit(STATUS_SCANNING, &priv->status)) { | ||
1299 | rx_status.noise = priv->last_rx_noise; | ||
1300 | rx_status.qual = iwl_calc_sig_qual(rx_status.signal, | ||
1301 | rx_status.noise); | ||
1302 | } else { | ||
1303 | rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||
1304 | rx_status.qual = iwl_calc_sig_qual(rx_status.signal, 0); | ||
1305 | } | ||
1306 | |||
1307 | /* Reset beacon noise level if not associated. */ | ||
1308 | if (!iwl_is_associated(priv)) | ||
1309 | priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||
1310 | |||
1311 | /* Set "1" to report good data frames in groups of 100 */ | ||
1312 | /* FIXME: need to optimze the call: */ | ||
1313 | iwl_dbg_report_frame(priv, pkt, header, 1); | ||
1314 | |||
1315 | IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", | ||
1316 | rx_status.signal, rx_status.noise, rx_status.signal, | ||
1317 | (unsigned long long)rx_status.mactime); | ||
1318 | |||
1319 | |||
1320 | if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { | ||
1321 | iwl_handle_data_packet(priv, 1, include_phy, | ||
1322 | rxb, &rx_status); | ||
1323 | return; | ||
1324 | } | ||
1325 | |||
1326 | network_packet = iwl_is_network_packet(priv, header); | ||
1327 | if (network_packet) { | ||
1328 | priv->last_rx_rssi = rx_status.signal; | ||
1329 | priv->last_beacon_time = priv->ucode_beacon_time; | ||
1330 | priv->last_tsf = le64_to_cpu(rx_start->timestamp); | ||
1331 | } | ||
1332 | |||
1333 | fc = le16_to_cpu(header->frame_control); | ||
1334 | switch (fc & IEEE80211_FCTL_FTYPE) { | ||
1335 | case IEEE80211_FTYPE_MGMT: | ||
1336 | if (priv->iw_mode == IEEE80211_IF_TYPE_AP) | ||
1337 | iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, | ||
1338 | header->addr2); | ||
1339 | iwl_handle_data_packet(priv, 0, include_phy, rxb, &rx_status); | ||
1340 | break; | ||
1341 | |||
1342 | case IEEE80211_FTYPE_CTL: | ||
1343 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
1344 | case IEEE80211_STYPE_BACK_REQ: | ||
1345 | IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); | ||
1346 | iwl_handle_data_packet(priv, 0, include_phy, | ||
1347 | rxb, &rx_status); | ||
1348 | break; | ||
1349 | default: | ||
1350 | break; | ||
1351 | } | ||
1352 | break; | ||
1353 | |||
1354 | case IEEE80211_FTYPE_DATA: { | ||
1355 | DECLARE_MAC_BUF(mac1); | ||
1356 | DECLARE_MAC_BUF(mac2); | ||
1357 | DECLARE_MAC_BUF(mac3); | ||
1358 | |||
1359 | if (priv->iw_mode == IEEE80211_IF_TYPE_AP) | ||
1360 | iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, | ||
1361 | header->addr2); | ||
1362 | |||
1363 | if (unlikely(!network_packet)) | ||
1364 | IWL_DEBUG_DROP("Dropping (non network): " | ||
1365 | "%s, %s, %s\n", | ||
1366 | print_mac(mac1, header->addr1), | ||
1367 | print_mac(mac2, header->addr2), | ||
1368 | print_mac(mac3, header->addr3)); | ||
1369 | else if (unlikely(iwl_is_duplicate_packet(priv, header))) | ||
1370 | IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n", | ||
1371 | print_mac(mac1, header->addr1), | ||
1372 | print_mac(mac2, header->addr2), | ||
1373 | print_mac(mac3, header->addr3)); | ||
1374 | else | ||
1375 | iwl_handle_data_packet(priv, 1, include_phy, rxb, | ||
1376 | &rx_status); | ||
1377 | break; | ||
1378 | } | ||
1379 | default: | ||
1380 | break; | ||
1381 | |||
1382 | } | ||
1383 | } | ||
1384 | EXPORT_SYMBOL(iwl_rx_reply_rx); | ||
1385 | |||
1386 | /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). | ||
1387 | * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ | ||
1388 | void iwl_rx_reply_rx_phy(struct iwl_priv *priv, | ||
1389 | struct iwl_rx_mem_buffer *rxb) | ||
1390 | { | ||
1391 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
1392 | priv->last_phy_res[0] = 1; | ||
1393 | memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), | ||
1394 | sizeof(struct iwl4965_rx_phy_res)); | ||
1395 | } | ||
1396 | EXPORT_SYMBOL(iwl_rx_reply_rx_phy); | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index a607b39223e..499705ff888 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c | |||
@@ -613,36 +613,6 @@ static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force) | |||
613 | } | 613 | } |
614 | } | 614 | } |
615 | 615 | ||
616 | int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) | ||
617 | { | ||
618 | /* Filter incoming packets to determine if they are targeted toward | ||
619 | * this network, discarding packets coming from ourselves */ | ||
620 | switch (priv->iw_mode) { | ||
621 | case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ | ||
622 | /* packets from our adapter are dropped (echo) */ | ||
623 | if (!compare_ether_addr(header->addr2, priv->mac_addr)) | ||
624 | return 0; | ||
625 | /* {broad,multi}cast packets to our IBSS go through */ | ||
626 | if (is_multicast_ether_addr(header->addr1)) | ||
627 | return !compare_ether_addr(header->addr3, priv->bssid); | ||
628 | /* packets to our adapter go through */ | ||
629 | return !compare_ether_addr(header->addr1, priv->mac_addr); | ||
630 | case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ | ||
631 | /* packets from our adapter are dropped (echo) */ | ||
632 | if (!compare_ether_addr(header->addr3, priv->mac_addr)) | ||
633 | return 0; | ||
634 | /* {broad,multi}cast packets to our BSS go through */ | ||
635 | if (is_multicast_ether_addr(header->addr1)) | ||
636 | return !compare_ether_addr(header->addr2, priv->bssid); | ||
637 | /* packets to our adapter go through */ | ||
638 | return !compare_ether_addr(header->addr1, priv->mac_addr); | ||
639 | default: | ||
640 | break; | ||
641 | } | ||
642 | |||
643 | return 1; | ||
644 | } | ||
645 | |||
646 | static void iwl4965_sequence_reset(struct iwl_priv *priv) | 616 | static void iwl4965_sequence_reset(struct iwl_priv *priv) |
647 | { | 617 | { |
648 | /* Reset ieee stats */ | 618 | /* Reset ieee stats */ |
@@ -906,72 +876,6 @@ static void iwl4965_set_rate(struct iwl_priv *priv) | |||
906 | (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; | 876 | (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; |
907 | } | 877 | } |
908 | 878 | ||
909 | #define IWL_PACKET_RETRY_TIME HZ | ||
910 | |||
911 | int iwl4965_is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) | ||
912 | { | ||
913 | u16 sc = le16_to_cpu(header->seq_ctrl); | ||
914 | u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; | ||
915 | u16 frag = sc & IEEE80211_SCTL_FRAG; | ||
916 | u16 *last_seq, *last_frag; | ||
917 | unsigned long *last_time; | ||
918 | |||
919 | switch (priv->iw_mode) { | ||
920 | case IEEE80211_IF_TYPE_IBSS:{ | ||
921 | struct list_head *p; | ||
922 | struct iwl4965_ibss_seq *entry = NULL; | ||
923 | u8 *mac = header->addr2; | ||
924 | int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1); | ||
925 | |||
926 | __list_for_each(p, &priv->ibss_mac_hash[index]) { | ||
927 | entry = list_entry(p, struct iwl4965_ibss_seq, list); | ||
928 | if (!compare_ether_addr(entry->mac, mac)) | ||
929 | break; | ||
930 | } | ||
931 | if (p == &priv->ibss_mac_hash[index]) { | ||
932 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
933 | if (!entry) { | ||
934 | IWL_ERROR("Cannot malloc new mac entry\n"); | ||
935 | return 0; | ||
936 | } | ||
937 | memcpy(entry->mac, mac, ETH_ALEN); | ||
938 | entry->seq_num = seq; | ||
939 | entry->frag_num = frag; | ||
940 | entry->packet_time = jiffies; | ||
941 | list_add(&entry->list, &priv->ibss_mac_hash[index]); | ||
942 | return 0; | ||
943 | } | ||
944 | last_seq = &entry->seq_num; | ||
945 | last_frag = &entry->frag_num; | ||
946 | last_time = &entry->packet_time; | ||
947 | break; | ||
948 | } | ||
949 | case IEEE80211_IF_TYPE_STA: | ||
950 | last_seq = &priv->last_seq_num; | ||
951 | last_frag = &priv->last_frag_num; | ||
952 | last_time = &priv->last_packet_time; | ||
953 | break; | ||
954 | default: | ||
955 | return 0; | ||
956 | } | ||
957 | if ((*last_seq == seq) && | ||
958 | time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) { | ||
959 | if (*last_frag == frag) | ||
960 | goto drop; | ||
961 | if (*last_frag + 1 != frag) | ||
962 | /* out-of-order fragment */ | ||
963 | goto drop; | ||
964 | } else | ||
965 | *last_seq = seq; | ||
966 | |||
967 | *last_frag = frag; | ||
968 | *last_time = jiffies; | ||
969 | return 0; | ||
970 | |||
971 | drop: | ||
972 | return 1; | ||
973 | } | ||
974 | |||
975 | #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT | 879 | #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT |
976 | 880 | ||
977 | #include "iwl-spectrum.h" | 881 | #include "iwl-spectrum.h" |
@@ -1350,17 +1254,6 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, | |||
1350 | wake_up_interruptible(&priv->wait_command_queue); | 1254 | wake_up_interruptible(&priv->wait_command_queue); |
1351 | } | 1255 | } |
1352 | 1256 | ||
1353 | /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). | ||
1354 | * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ | ||
1355 | static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, | ||
1356 | struct iwl_rx_mem_buffer *rxb) | ||
1357 | { | ||
1358 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
1359 | priv->last_phy_res[0] = 1; | ||
1360 | memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), | ||
1361 | sizeof(struct iwl4965_rx_phy_res)); | ||
1362 | } | ||
1363 | |||
1364 | /** | 1257 | /** |
1365 | * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks | 1258 | * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks |
1366 | * | 1259 | * |
@@ -1398,8 +1291,8 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) | |||
1398 | priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = | 1291 | priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = |
1399 | iwl_rx_missed_beacon_notif; | 1292 | iwl_rx_missed_beacon_notif; |
1400 | /* Rx handlers */ | 1293 | /* Rx handlers */ |
1401 | priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy; | 1294 | priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy; |
1402 | priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx; | 1295 | priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx; |
1403 | /* Set up hardware specific Rx handlers */ | 1296 | /* Set up hardware specific Rx handlers */ |
1404 | priv->cfg->ops->lib->rx_handler_setup(priv); | 1297 | priv->cfg->ops->lib->rx_handler_setup(priv); |
1405 | } | 1298 | } |
@@ -1530,47 +1423,6 @@ void iwl_rx_handle(struct iwl_priv *priv) | |||
1530 | iwl_rx_queue_restock(priv); | 1423 | iwl_rx_queue_restock(priv); |
1531 | } | 1424 | } |
1532 | 1425 | ||
1533 | #define PERFECT_RSSI (-20) /* dBm */ | ||
1534 | #define WORST_RSSI (-95) /* dBm */ | ||
1535 | #define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) | ||
1536 | |||
1537 | /* Calculate an indication of rx signal quality (a percentage, not dBm!). | ||
1538 | * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info | ||
1539 | * about formulas used below. */ | ||
1540 | int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm) | ||
1541 | { | ||
1542 | int sig_qual; | ||
1543 | int degradation = PERFECT_RSSI - rssi_dbm; | ||
1544 | |||
1545 | /* If we get a noise measurement, use signal-to-noise ratio (SNR) | ||
1546 | * as indicator; formula is (signal dbm - noise dbm). | ||
1547 | * SNR at or above 40 is a great signal (100%). | ||
1548 | * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. | ||
1549 | * Weakest usable signal is usually 10 - 15 dB SNR. */ | ||
1550 | if (noise_dbm) { | ||
1551 | if (rssi_dbm - noise_dbm >= 40) | ||
1552 | return 100; | ||
1553 | else if (rssi_dbm < noise_dbm) | ||
1554 | return 0; | ||
1555 | sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; | ||
1556 | |||
1557 | /* Else use just the signal level. | ||
1558 | * This formula is a least squares fit of data points collected and | ||
1559 | * compared with a reference system that had a percentage (%) display | ||
1560 | * for signal quality. */ | ||
1561 | } else | ||
1562 | sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * | ||
1563 | (15 * RSSI_RANGE + 62 * degradation)) / | ||
1564 | (RSSI_RANGE * RSSI_RANGE); | ||
1565 | |||
1566 | if (sig_qual > 100) | ||
1567 | sig_qual = 100; | ||
1568 | else if (sig_qual < 1) | ||
1569 | sig_qual = 0; | ||
1570 | |||
1571 | return sig_qual; | ||
1572 | } | ||
1573 | |||
1574 | #ifdef CONFIG_IWLWIFI_DEBUG | 1426 | #ifdef CONFIG_IWLWIFI_DEBUG |
1575 | static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) | 1427 | static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) |
1576 | { | 1428 | { |