diff options
author | Zhu Yi <yi.zhu@intel.com> | 2007-12-19 22:27:32 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:07:53 -0500 |
commit | 12342c475f5de17071eaf24ea2938ba8dfe285f2 (patch) | |
tree | a2cdfd191069397e093f2410009092e7e96c9325 /drivers/net/wireless/iwlwifi/iwl-3945.c | |
parent | 7e94041ca17685cf12c658b8edc008dd0bdb00c7 (diff) |
iwlwifi: proper monitor support
This patch changes the iwlwifi driver to properly support
monitor interfaces after the filter flags change.
The patch is originally created by Johannes Berg for iwl4965. I fixed some
of the comments and created a similar patch for iwl3945.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-3945.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-3945.c | 120 |
1 files changed, 102 insertions, 18 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7d15b33b9dcd..a793cd11f738 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -35,9 +35,9 @@ | |||
35 | #include <linux/netdevice.h> | 35 | #include <linux/netdevice.h> |
36 | #include <linux/wireless.h> | 36 | #include <linux/wireless.h> |
37 | #include <linux/firmware.h> | 37 | #include <linux/firmware.h> |
38 | #include <net/mac80211.h> | ||
39 | |||
40 | #include <linux/etherdevice.h> | 38 | #include <linux/etherdevice.h> |
39 | #include <asm/unaligned.h> | ||
40 | #include <net/mac80211.h> | ||
41 | 41 | ||
42 | #include "iwl-3945.h" | 42 | #include "iwl-3945.h" |
43 | #include "iwl-helpers.h" | 43 | #include "iwl-helpers.h" |
@@ -238,10 +238,102 @@ void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_b | |||
238 | priv->last_statistics_time = jiffies; | 238 | priv->last_statistics_time = jiffies; |
239 | } | 239 | } |
240 | 240 | ||
241 | void iwl3945_add_radiotap(struct iwl3945_priv *priv, struct sk_buff *skb, | ||
242 | struct iwl3945_rx_frame_hdr *rx_hdr, | ||
243 | struct ieee80211_rx_status *stats) | ||
244 | { | ||
245 | /* First cache any information we need before we overwrite | ||
246 | * the information provided in the skb from the hardware */ | ||
247 | s8 signal = stats->ssi; | ||
248 | s8 noise = 0; | ||
249 | int rate = stats->rate; | ||
250 | u64 tsf = stats->mactime; | ||
251 | __le16 phy_flags_hw = rx_hdr->phy_flags; | ||
252 | |||
253 | struct iwl3945_rt_rx_hdr { | ||
254 | struct ieee80211_radiotap_header rt_hdr; | ||
255 | __le64 rt_tsf; /* TSF */ | ||
256 | u8 rt_flags; /* radiotap packet flags */ | ||
257 | u8 rt_rate; /* rate in 500kb/s */ | ||
258 | __le16 rt_channelMHz; /* channel in MHz */ | ||
259 | __le16 rt_chbitmask; /* channel bitfield */ | ||
260 | s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ | ||
261 | s8 rt_dbmnoise; | ||
262 | u8 rt_antenna; /* antenna number */ | ||
263 | } __attribute__ ((packed)) *iwl3945_rt; | ||
264 | |||
265 | if (skb_headroom(skb) < sizeof(*iwl3945_rt)) { | ||
266 | if (net_ratelimit()) | ||
267 | printk(KERN_ERR "not enough headroom [%d] for " | ||
268 | "radiotap head [%d]\n", | ||
269 | skb_headroom(skb), sizeof(*iwl3945_rt)); | ||
270 | return; | ||
271 | } | ||
272 | |||
273 | /* put radiotap header in front of 802.11 header and data */ | ||
274 | iwl3945_rt = (void *)skb_push(skb, sizeof(*iwl3945_rt)); | ||
275 | |||
276 | /* initialise radiotap header */ | ||
277 | iwl3945_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; | ||
278 | iwl3945_rt->rt_hdr.it_pad = 0; | ||
279 | |||
280 | /* total header + data */ | ||
281 | put_unaligned(cpu_to_le16(sizeof(*iwl3945_rt)), | ||
282 | &iwl3945_rt->rt_hdr.it_len); | ||
283 | |||
284 | /* Indicate all the fields we add to the radiotap header */ | ||
285 | put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | | ||
286 | (1 << IEEE80211_RADIOTAP_FLAGS) | | ||
287 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
288 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
289 | (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | | ||
290 | (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | | ||
291 | (1 << IEEE80211_RADIOTAP_ANTENNA)), | ||
292 | &iwl3945_rt->rt_hdr.it_present); | ||
293 | |||
294 | /* Zero the flags, we'll add to them as we go */ | ||
295 | iwl3945_rt->rt_flags = 0; | ||
296 | |||
297 | put_unaligned(cpu_to_le64(tsf), &iwl3945_rt->rt_tsf); | ||
298 | |||
299 | iwl3945_rt->rt_dbmsignal = signal; | ||
300 | iwl3945_rt->rt_dbmnoise = noise; | ||
301 | |||
302 | /* Convert the channel frequency and set the flags */ | ||
303 | put_unaligned(cpu_to_le16(stats->freq), &iwl3945_rt->rt_channelMHz); | ||
304 | if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) | ||
305 | put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
306 | IEEE80211_CHAN_5GHZ), | ||
307 | &iwl3945_rt->rt_chbitmask); | ||
308 | else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) | ||
309 | put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | | ||
310 | IEEE80211_CHAN_2GHZ), | ||
311 | &iwl3945_rt->rt_chbitmask); | ||
312 | else /* 802.11g */ | ||
313 | put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
314 | IEEE80211_CHAN_2GHZ), | ||
315 | &iwl3945_rt->rt_chbitmask); | ||
316 | |||
317 | rate = iwl3945_rate_index_from_plcp(rate); | ||
318 | if (rate == -1) | ||
319 | iwl3945_rt->rt_rate = 0; | ||
320 | else | ||
321 | iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee; | ||
322 | |||
323 | /* antenna number */ | ||
324 | iwl3945_rt->rt_antenna = | ||
325 | le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; | ||
326 | |||
327 | /* set the preamble flag if we have it */ | ||
328 | if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) | ||
329 | iwl3945_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; | ||
330 | |||
331 | stats->flag |= RX_FLAG_RADIOTAP; | ||
332 | } | ||
333 | |||
241 | static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, | 334 | static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, |
242 | struct iwl3945_rx_mem_buffer *rxb, | 335 | struct iwl3945_rx_mem_buffer *rxb, |
243 | struct ieee80211_rx_status *stats, | 336 | struct ieee80211_rx_status *stats) |
244 | u16 phy_flags) | ||
245 | { | 337 | { |
246 | struct ieee80211_hdr *hdr; | 338 | struct ieee80211_hdr *hdr; |
247 | struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data; | 339 | struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data; |
@@ -261,15 +353,6 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, | |||
261 | ("Dropping packet while interface is not open.\n"); | 353 | ("Dropping packet while interface is not open.\n"); |
262 | return; | 354 | return; |
263 | } | 355 | } |
264 | if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { | ||
265 | if (iwl3945_param_hwcrypto) | ||
266 | iwl3945_set_decrypted_flag(priv, rxb->skb, | ||
267 | le32_to_cpu(rx_end->status), | ||
268 | stats); | ||
269 | iwl3945_handle_data_packet_monitor(priv, rxb, IWL_RX_DATA(pkt), | ||
270 | len, stats, phy_flags); | ||
271 | return; | ||
272 | } | ||
273 | 356 | ||
274 | skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt); | 357 | skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt); |
275 | /* Set the size of the skb to the size of the frame */ | 358 | /* Set the size of the skb to the size of the frame */ |
@@ -281,6 +364,9 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, | |||
281 | iwl3945_set_decrypted_flag(priv, rxb->skb, | 364 | iwl3945_set_decrypted_flag(priv, rxb->skb, |
282 | le32_to_cpu(rx_end->status), stats); | 365 | le32_to_cpu(rx_end->status), stats); |
283 | 366 | ||
367 | if (priv->add_radiotap) | ||
368 | iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats); | ||
369 | |||
284 | ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); | 370 | ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); |
285 | rxb->skb = NULL; | 371 | rxb->skb = NULL; |
286 | } | 372 | } |
@@ -295,7 +381,6 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, | |||
295 | struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); | 381 | struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); |
296 | struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); | 382 | struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); |
297 | struct ieee80211_hdr *header; | 383 | struct ieee80211_hdr *header; |
298 | u16 phy_flags = le16_to_cpu(rx_hdr->phy_flags); | ||
299 | u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg); | 384 | u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg); |
300 | u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff); | 385 | u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff); |
301 | struct ieee80211_rx_status stats = { | 386 | struct ieee80211_rx_status stats = { |
@@ -325,7 +410,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, | |||
325 | } | 410 | } |
326 | 411 | ||
327 | if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { | 412 | if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { |
328 | iwl3945_handle_data_packet(priv, 1, rxb, &stats, phy_flags); | 413 | iwl3945_handle_data_packet(priv, 1, rxb, &stats); |
329 | return; | 414 | return; |
330 | } | 415 | } |
331 | 416 | ||
@@ -479,7 +564,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, | |||
479 | } | 564 | } |
480 | } | 565 | } |
481 | 566 | ||
482 | iwl3945_handle_data_packet(priv, 0, rxb, &stats, phy_flags); | 567 | iwl3945_handle_data_packet(priv, 0, rxb, &stats); |
483 | break; | 568 | break; |
484 | 569 | ||
485 | case IEEE80211_FTYPE_CTL: | 570 | case IEEE80211_FTYPE_CTL: |
@@ -496,8 +581,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, | |||
496 | print_mac(mac2, header->addr2), | 581 | print_mac(mac2, header->addr2), |
497 | print_mac(mac3, header->addr3)); | 582 | print_mac(mac3, header->addr3)); |
498 | else | 583 | else |
499 | iwl3945_handle_data_packet(priv, 1, rxb, &stats, | 584 | iwl3945_handle_data_packet(priv, 1, rxb, &stats); |
500 | phy_flags); | ||
501 | break; | 585 | break; |
502 | } | 586 | } |
503 | } | 587 | } |