aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-3945.c
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2007-12-19 22:27:32 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:07:53 -0500
commit12342c475f5de17071eaf24ea2938ba8dfe285f2 (patch)
treea2cdfd191069397e093f2410009092e7e96c9325 /drivers/net/wireless/iwlwifi/iwl-3945.c
parent7e94041ca17685cf12c658b8edc008dd0bdb00c7 (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.c120
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
241void 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
241static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, 334static 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 }