diff options
-rw-r--r-- | drivers/net/wireless/Kconfig | 24 | ||||
-rw-r--r-- | drivers/net/wireless/ipw2200.c | 599 | ||||
-rw-r--r-- | drivers/net/wireless/ipw2200.h | 77 |
3 files changed, 673 insertions, 27 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index e0874cbfefea..c04971a8e4a8 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -263,6 +263,30 @@ config IPW2200_DEBUG | |||
263 | If you are not trying to debug or develop the IPW2200 driver, you | 263 | If you are not trying to debug or develop the IPW2200 driver, you |
264 | most likely want to say N here. | 264 | most likely want to say N here. |
265 | 265 | ||
266 | config IPW2200_PROMISCUOUS | ||
267 | bool "Enable creation of a RF radiotap promiscuous interface." | ||
268 | depends on IPW2200 | ||
269 | select IEEE80211_RADIOTAP | ||
270 | ---help--- | ||
271 | Enables the creation of a second interface prefixed 'rtap'. | ||
272 | This second interface will provide every received in radiotap | ||
273 | format. | ||
274 | |||
275 | This is useful for performing wireless network analysis while | ||
276 | maintaining an active association. | ||
277 | |||
278 | Example usage: | ||
279 | |||
280 | % modprobe ipw2200 rtap_iface=1 | ||
281 | % ifconfig rtap0 up | ||
282 | % tethereal -i rtap0 | ||
283 | |||
284 | If you do not specify 'rtap_iface=1' as a module parameter then | ||
285 | the rtap interface will not be created and you will need to turn | ||
286 | it on via sysfs: | ||
287 | |||
288 | % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface | ||
289 | |||
266 | config AIRO | 290 | config AIRO |
267 | tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" | 291 | tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" |
268 | depends on NET_RADIO && ISA_DMA_API && (PCI || BROKEN) | 292 | depends on NET_RADIO && ISA_DMA_API && (PCI || BROKEN) |
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 11730448a821..94172558cd03 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -65,6 +65,11 @@ static const char ipw_modes[] = { | |||
65 | }; | 65 | }; |
66 | static int antenna = CFG_SYS_ANTENNA_BOTH; | 66 | static int antenna = CFG_SYS_ANTENNA_BOTH; |
67 | 67 | ||
68 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
69 | static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */ | ||
70 | #endif | ||
71 | |||
72 | |||
68 | #ifdef CONFIG_IPW_QOS | 73 | #ifdef CONFIG_IPW_QOS |
69 | static int qos_enable = 0; | 74 | static int qos_enable = 0; |
70 | static int qos_burst_enable = 0; | 75 | static int qos_burst_enable = 0; |
@@ -1272,6 +1277,105 @@ static ssize_t show_cmd_log(struct device *d, | |||
1272 | 1277 | ||
1273 | static DEVICE_ATTR(cmd_log, S_IRUGO, show_cmd_log, NULL); | 1278 | static DEVICE_ATTR(cmd_log, S_IRUGO, show_cmd_log, NULL); |
1274 | 1279 | ||
1280 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
1281 | static void ipw_prom_free(struct ipw_priv *priv); | ||
1282 | static int ipw_prom_alloc(struct ipw_priv *priv); | ||
1283 | static ssize_t store_rtap_iface(struct device *d, | ||
1284 | struct device_attribute *attr, | ||
1285 | const char *buf, size_t count) | ||
1286 | { | ||
1287 | struct ipw_priv *priv = dev_get_drvdata(d); | ||
1288 | int rc = 0; | ||
1289 | |||
1290 | if (count < 1) | ||
1291 | return -EINVAL; | ||
1292 | |||
1293 | switch (buf[0]) { | ||
1294 | case '0': | ||
1295 | if (!rtap_iface) | ||
1296 | return count; | ||
1297 | |||
1298 | if (netif_running(priv->prom_net_dev)) { | ||
1299 | IPW_WARNING("Interface is up. Cannot unregister.\n"); | ||
1300 | return count; | ||
1301 | } | ||
1302 | |||
1303 | ipw_prom_free(priv); | ||
1304 | rtap_iface = 0; | ||
1305 | break; | ||
1306 | |||
1307 | case '1': | ||
1308 | if (rtap_iface) | ||
1309 | return count; | ||
1310 | |||
1311 | rc = ipw_prom_alloc(priv); | ||
1312 | if (!rc) | ||
1313 | rtap_iface = 1; | ||
1314 | break; | ||
1315 | |||
1316 | default: | ||
1317 | return -EINVAL; | ||
1318 | } | ||
1319 | |||
1320 | if (rc) { | ||
1321 | IPW_ERROR("Failed to register promiscuous network " | ||
1322 | "device (error %d).\n", rc); | ||
1323 | } | ||
1324 | |||
1325 | return count; | ||
1326 | } | ||
1327 | |||
1328 | static ssize_t show_rtap_iface(struct device *d, | ||
1329 | struct device_attribute *attr, | ||
1330 | char *buf) | ||
1331 | { | ||
1332 | struct ipw_priv *priv = dev_get_drvdata(d); | ||
1333 | if (rtap_iface) | ||
1334 | return sprintf(buf, "%s", priv->prom_net_dev->name); | ||
1335 | else { | ||
1336 | buf[0] = '-'; | ||
1337 | buf[1] = '1'; | ||
1338 | buf[2] = '\0'; | ||
1339 | return 3; | ||
1340 | } | ||
1341 | } | ||
1342 | |||
1343 | static DEVICE_ATTR(rtap_iface, S_IWUSR | S_IRUSR, show_rtap_iface, | ||
1344 | store_rtap_iface); | ||
1345 | |||
1346 | static ssize_t store_rtap_filter(struct device *d, | ||
1347 | struct device_attribute *attr, | ||
1348 | const char *buf, size_t count) | ||
1349 | { | ||
1350 | struct ipw_priv *priv = dev_get_drvdata(d); | ||
1351 | |||
1352 | if (!priv->prom_priv) { | ||
1353 | IPW_ERROR("Attempting to set filter without " | ||
1354 | "rtap_iface enabled.\n"); | ||
1355 | return -EPERM; | ||
1356 | } | ||
1357 | |||
1358 | priv->prom_priv->filter = simple_strtol(buf, NULL, 0); | ||
1359 | |||
1360 | IPW_DEBUG_INFO("Setting rtap filter to " BIT_FMT16 "\n", | ||
1361 | BIT_ARG16(priv->prom_priv->filter)); | ||
1362 | |||
1363 | return count; | ||
1364 | } | ||
1365 | |||
1366 | static ssize_t show_rtap_filter(struct device *d, | ||
1367 | struct device_attribute *attr, | ||
1368 | char *buf) | ||
1369 | { | ||
1370 | struct ipw_priv *priv = dev_get_drvdata(d); | ||
1371 | return sprintf(buf, "0x%04X", | ||
1372 | priv->prom_priv ? priv->prom_priv->filter : 0); | ||
1373 | } | ||
1374 | |||
1375 | static DEVICE_ATTR(rtap_filter, S_IWUSR | S_IRUSR, show_rtap_filter, | ||
1376 | store_rtap_filter); | ||
1377 | #endif | ||
1378 | |||
1275 | static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, | 1379 | static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, |
1276 | char *buf) | 1380 | char *buf) |
1277 | { | 1381 | { |
@@ -2028,16 +2132,11 @@ static int ipw_send_host_complete(struct ipw_priv *priv) | |||
2028 | return ipw_send_cmd_simple(priv, IPW_CMD_HOST_COMPLETE); | 2132 | return ipw_send_cmd_simple(priv, IPW_CMD_HOST_COMPLETE); |
2029 | } | 2133 | } |
2030 | 2134 | ||
2031 | static int ipw_send_system_config(struct ipw_priv *priv, | 2135 | static int ipw_send_system_config(struct ipw_priv *priv) |
2032 | struct ipw_sys_config *config) | ||
2033 | { | 2136 | { |
2034 | if (!priv || !config) { | 2137 | return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG, |
2035 | IPW_ERROR("Invalid args\n"); | 2138 | sizeof(priv->sys_config), |
2036 | return -1; | 2139 | &priv->sys_config); |
2037 | } | ||
2038 | |||
2039 | return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG, sizeof(*config), | ||
2040 | config); | ||
2041 | } | 2140 | } |
2042 | 2141 | ||
2043 | static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) | 2142 | static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) |
@@ -3704,7 +3803,17 @@ static void ipw_bg_disassociate(void *data) | |||
3704 | static void ipw_system_config(void *data) | 3803 | static void ipw_system_config(void *data) |
3705 | { | 3804 | { |
3706 | struct ipw_priv *priv = data; | 3805 | struct ipw_priv *priv = data; |
3707 | ipw_send_system_config(priv, &priv->sys_config); | 3806 | |
3807 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
3808 | if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) { | ||
3809 | priv->sys_config.accept_all_data_frames = 1; | ||
3810 | priv->sys_config.accept_non_directed_frames = 1; | ||
3811 | priv->sys_config.accept_all_mgmt_bcpr = 1; | ||
3812 | priv->sys_config.accept_all_mgmt_frames = 1; | ||
3813 | } | ||
3814 | #endif | ||
3815 | |||
3816 | ipw_send_system_config(priv); | ||
3708 | } | 3817 | } |
3709 | 3818 | ||
3710 | struct ipw_status_code { | 3819 | struct ipw_status_code { |
@@ -7138,7 +7247,7 @@ static int ipw_associate_network(struct ipw_priv *priv, | |||
7138 | else | 7247 | else |
7139 | priv->sys_config.answer_broadcast_ssid_probe = 0; | 7248 | priv->sys_config.answer_broadcast_ssid_probe = 0; |
7140 | 7249 | ||
7141 | err = ipw_send_system_config(priv, &priv->sys_config); | 7250 | err = ipw_send_system_config(priv); |
7142 | if (err) { | 7251 | if (err) { |
7143 | IPW_DEBUG_HC("Attempt to send sys config command failed.\n"); | 7252 | IPW_DEBUG_HC("Attempt to send sys config command failed.\n"); |
7144 | return err; | 7253 | return err; |
@@ -7454,15 +7563,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, | |||
7454 | /* Magic struct that slots into the radiotap header -- no reason | 7563 | /* Magic struct that slots into the radiotap header -- no reason |
7455 | * to build this manually element by element, we can write it much | 7564 | * to build this manually element by element, we can write it much |
7456 | * more efficiently than we can parse it. ORDER MATTERS HERE */ | 7565 | * more efficiently than we can parse it. ORDER MATTERS HERE */ |
7457 | struct ipw_rt_hdr { | 7566 | struct ipw_rt_hdr *ipw_rt; |
7458 | struct ieee80211_radiotap_header rt_hdr; | ||
7459 | u8 rt_flags; /* radiotap packet flags */ | ||
7460 | u8 rt_rate; /* rate in 500kb/s */ | ||
7461 | u16 rt_channel; /* channel in mhz */ | ||
7462 | u16 rt_chbitmask; /* channel bitfield */ | ||
7463 | s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ | ||
7464 | u8 rt_antenna; /* antenna number */ | ||
7465 | } *ipw_rt; | ||
7466 | 7567 | ||
7467 | short len = le16_to_cpu(pkt->u.frame.length); | 7568 | short len = le16_to_cpu(pkt->u.frame.length); |
7468 | 7569 | ||
@@ -7516,9 +7617,11 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, | |||
7516 | /* Big bitfield of all the fields we provide in radiotap */ | 7617 | /* Big bitfield of all the fields we provide in radiotap */ |
7517 | ipw_rt->rt_hdr.it_present = | 7618 | ipw_rt->rt_hdr.it_present = |
7518 | ((1 << IEEE80211_RADIOTAP_FLAGS) | | 7619 | ((1 << IEEE80211_RADIOTAP_FLAGS) | |
7620 | (1 << IEEE80211_RADIOTAP_TSFT) | | ||
7519 | (1 << IEEE80211_RADIOTAP_RATE) | | 7621 | (1 << IEEE80211_RADIOTAP_RATE) | |
7520 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | 7622 | (1 << IEEE80211_RADIOTAP_CHANNEL) | |
7521 | (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | | 7623 | (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | |
7624 | (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | | ||
7522 | (1 << IEEE80211_RADIOTAP_ANTENNA)); | 7625 | (1 << IEEE80211_RADIOTAP_ANTENNA)); |
7523 | 7626 | ||
7524 | /* Zero the flags, we'll add to them as we go */ | 7627 | /* Zero the flags, we'll add to them as we go */ |
@@ -7604,6 +7707,220 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, | |||
7604 | } | 7707 | } |
7605 | #endif | 7708 | #endif |
7606 | 7709 | ||
7710 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
7711 | #define ieee80211_is_probe_response(fc) \ | ||
7712 | ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && \ | ||
7713 | (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP ) | ||
7714 | |||
7715 | #define ieee80211_is_management(fc) \ | ||
7716 | ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) | ||
7717 | |||
7718 | #define ieee80211_is_control(fc) \ | ||
7719 | ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) | ||
7720 | |||
7721 | #define ieee80211_is_data(fc) \ | ||
7722 | ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) | ||
7723 | |||
7724 | #define ieee80211_is_assoc_request(fc) \ | ||
7725 | ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ) | ||
7726 | |||
7727 | #define ieee80211_is_reassoc_request(fc) \ | ||
7728 | ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) | ||
7729 | |||
7730 | static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, | ||
7731 | struct ipw_rx_mem_buffer *rxb, | ||
7732 | struct ieee80211_rx_stats *stats) | ||
7733 | { | ||
7734 | struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; | ||
7735 | struct ipw_rx_frame *frame = &pkt->u.frame; | ||
7736 | struct ipw_rt_hdr *ipw_rt; | ||
7737 | |||
7738 | /* First cache any information we need before we overwrite | ||
7739 | * the information provided in the skb from the hardware */ | ||
7740 | struct ieee80211_hdr *hdr; | ||
7741 | u16 channel = frame->received_channel; | ||
7742 | u8 phy_flags = frame->antennaAndPhy; | ||
7743 | s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM; | ||
7744 | s8 noise = frame->noise; | ||
7745 | u8 rate = frame->rate; | ||
7746 | short len = le16_to_cpu(pkt->u.frame.length); | ||
7747 | u64 tsf = 0; | ||
7748 | struct sk_buff *skb; | ||
7749 | int hdr_only = 0; | ||
7750 | u16 filter = priv->prom_priv->filter; | ||
7751 | |||
7752 | /* If the filter is set to not include Rx frames then return */ | ||
7753 | if (filter & IPW_PROM_NO_RX) | ||
7754 | return; | ||
7755 | |||
7756 | if (!noise) | ||
7757 | noise = priv->last_noise; | ||
7758 | |||
7759 | /* We received data from the HW, so stop the watchdog */ | ||
7760 | priv->prom_net_dev->trans_start = jiffies; | ||
7761 | |||
7762 | if (unlikely((len + IPW_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) { | ||
7763 | priv->prom_priv->ieee->stats.rx_errors++; | ||
7764 | IPW_DEBUG_DROP("Corruption detected! Oh no!\n"); | ||
7765 | return; | ||
7766 | } | ||
7767 | |||
7768 | /* We only process data packets if the interface is open */ | ||
7769 | if (unlikely(!netif_running(priv->prom_net_dev))) { | ||
7770 | priv->prom_priv->ieee->stats.rx_dropped++; | ||
7771 | IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); | ||
7772 | return; | ||
7773 | } | ||
7774 | |||
7775 | /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use | ||
7776 | * that now */ | ||
7777 | if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) { | ||
7778 | /* FIXME: Should alloc bigger skb instead */ | ||
7779 | priv->prom_priv->ieee->stats.rx_dropped++; | ||
7780 | IPW_DEBUG_DROP("Dropping too large packet in monitor\n"); | ||
7781 | return; | ||
7782 | } | ||
7783 | |||
7784 | hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE; | ||
7785 | if (ieee80211_is_management(hdr->frame_ctl)) { | ||
7786 | if (filter & IPW_PROM_NO_MGMT) | ||
7787 | return; | ||
7788 | if (filter & IPW_PROM_MGMT_HEADER_ONLY) | ||
7789 | hdr_only = 1; | ||
7790 | } else if (ieee80211_is_control(hdr->frame_ctl)) { | ||
7791 | if (filter & IPW_PROM_NO_CTL) | ||
7792 | return; | ||
7793 | if (filter & IPW_PROM_CTL_HEADER_ONLY) | ||
7794 | hdr_only = 1; | ||
7795 | } else if (ieee80211_is_data(hdr->frame_ctl)) { | ||
7796 | if (filter & IPW_PROM_NO_DATA) | ||
7797 | return; | ||
7798 | if (filter & IPW_PROM_DATA_HEADER_ONLY) | ||
7799 | hdr_only = 1; | ||
7800 | } | ||
7801 | |||
7802 | /* Copy the SKB since this is for the promiscuous side */ | ||
7803 | skb = skb_copy(rxb->skb, GFP_ATOMIC); | ||
7804 | if (skb == NULL) { | ||
7805 | IPW_ERROR("skb_clone failed for promiscuous copy.\n"); | ||
7806 | return; | ||
7807 | } | ||
7808 | |||
7809 | /* copy the frame data to write after where the radiotap header goes */ | ||
7810 | ipw_rt = (void *)skb->data; | ||
7811 | |||
7812 | if (hdr_only) | ||
7813 | len = ieee80211_get_hdrlen(hdr->frame_ctl); | ||
7814 | |||
7815 | memcpy(ipw_rt->payload, hdr, len); | ||
7816 | |||
7817 | /* Zero the radiotap static buffer ... We only need to zero the bytes | ||
7818 | * NOT part of our real header, saves a little time. | ||
7819 | * | ||
7820 | * No longer necessary since we fill in all our data. Purge before | ||
7821 | * merging patch officially. | ||
7822 | * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, | ||
7823 | * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); | ||
7824 | */ | ||
7825 | |||
7826 | ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; | ||
7827 | ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ | ||
7828 | ipw_rt->rt_hdr.it_len = sizeof(*ipw_rt); /* total header+data */ | ||
7829 | |||
7830 | /* Set the size of the skb to the size of the frame */ | ||
7831 | skb_put(skb, ipw_rt->rt_hdr.it_len + len); | ||
7832 | |||
7833 | /* Big bitfield of all the fields we provide in radiotap */ | ||
7834 | ipw_rt->rt_hdr.it_present = | ||
7835 | ((1 << IEEE80211_RADIOTAP_FLAGS) | | ||
7836 | (1 << IEEE80211_RADIOTAP_TSFT) | | ||
7837 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
7838 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
7839 | (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | | ||
7840 | (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | | ||
7841 | (1 << IEEE80211_RADIOTAP_ANTENNA)); | ||
7842 | |||
7843 | /* Zero the flags, we'll add to them as we go */ | ||
7844 | ipw_rt->rt_flags = 0; | ||
7845 | |||
7846 | ipw_rt->rt_tsf = tsf; | ||
7847 | |||
7848 | /* Convert to DBM */ | ||
7849 | ipw_rt->rt_dbmsignal = signal; | ||
7850 | ipw_rt->rt_dbmnoise = noise; | ||
7851 | |||
7852 | /* Convert the channel data and set the flags */ | ||
7853 | ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(channel)); | ||
7854 | if (channel > 14) { /* 802.11a */ | ||
7855 | ipw_rt->rt_chbitmask = | ||
7856 | cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); | ||
7857 | } else if (phy_flags & (1 << 5)) { /* 802.11b */ | ||
7858 | ipw_rt->rt_chbitmask = | ||
7859 | cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); | ||
7860 | } else { /* 802.11g */ | ||
7861 | ipw_rt->rt_chbitmask = | ||
7862 | (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); | ||
7863 | } | ||
7864 | |||
7865 | /* set the rate in multiples of 500k/s */ | ||
7866 | switch (rate) { | ||
7867 | case IPW_TX_RATE_1MB: | ||
7868 | ipw_rt->rt_rate = 2; | ||
7869 | break; | ||
7870 | case IPW_TX_RATE_2MB: | ||
7871 | ipw_rt->rt_rate = 4; | ||
7872 | break; | ||
7873 | case IPW_TX_RATE_5MB: | ||
7874 | ipw_rt->rt_rate = 10; | ||
7875 | break; | ||
7876 | case IPW_TX_RATE_6MB: | ||
7877 | ipw_rt->rt_rate = 12; | ||
7878 | break; | ||
7879 | case IPW_TX_RATE_9MB: | ||
7880 | ipw_rt->rt_rate = 18; | ||
7881 | break; | ||
7882 | case IPW_TX_RATE_11MB: | ||
7883 | ipw_rt->rt_rate = 22; | ||
7884 | break; | ||
7885 | case IPW_TX_RATE_12MB: | ||
7886 | ipw_rt->rt_rate = 24; | ||
7887 | break; | ||
7888 | case IPW_TX_RATE_18MB: | ||
7889 | ipw_rt->rt_rate = 36; | ||
7890 | break; | ||
7891 | case IPW_TX_RATE_24MB: | ||
7892 | ipw_rt->rt_rate = 48; | ||
7893 | break; | ||
7894 | case IPW_TX_RATE_36MB: | ||
7895 | ipw_rt->rt_rate = 72; | ||
7896 | break; | ||
7897 | case IPW_TX_RATE_48MB: | ||
7898 | ipw_rt->rt_rate = 96; | ||
7899 | break; | ||
7900 | case IPW_TX_RATE_54MB: | ||
7901 | ipw_rt->rt_rate = 108; | ||
7902 | break; | ||
7903 | default: | ||
7904 | ipw_rt->rt_rate = 0; | ||
7905 | break; | ||
7906 | } | ||
7907 | |||
7908 | /* antenna number */ | ||
7909 | ipw_rt->rt_antenna = (phy_flags & 3); | ||
7910 | |||
7911 | /* set the preamble flag if we have it */ | ||
7912 | if (phy_flags & (1 << 6)) | ||
7913 | ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; | ||
7914 | |||
7915 | IPW_DEBUG_RX("Rx packet of %d bytes.\n", skb->len); | ||
7916 | |||
7917 | if (!ieee80211_rx(priv->prom_priv->ieee, skb, stats)) { | ||
7918 | priv->prom_priv->ieee->stats.rx_errors++; | ||
7919 | dev_kfree_skb_any(skb); | ||
7920 | } | ||
7921 | } | ||
7922 | #endif | ||
7923 | |||
7607 | static int is_network_packet(struct ipw_priv *priv, | 7924 | static int is_network_packet(struct ipw_priv *priv, |
7608 | struct ieee80211_hdr_4addr *header) | 7925 | struct ieee80211_hdr_4addr *header) |
7609 | { | 7926 | { |
@@ -7830,15 +8147,21 @@ static void ipw_rx(struct ipw_priv *priv) | |||
7830 | 8147 | ||
7831 | priv->rx_packets++; | 8148 | priv->rx_packets++; |
7832 | 8149 | ||
8150 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
8151 | if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) | ||
8152 | ipw_handle_promiscuous_rx(priv, rxb, &stats); | ||
8153 | #endif | ||
8154 | |||
7833 | #ifdef CONFIG_IPW2200_MONITOR | 8155 | #ifdef CONFIG_IPW2200_MONITOR |
7834 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | 8156 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { |
7835 | #ifdef CONFIG_IEEE80211_RADIOTAP | 8157 | #ifdef CONFIG_IEEE80211_RADIOTAP |
7836 | ipw_handle_data_packet_monitor(priv, | 8158 | |
7837 | rxb, | 8159 | ipw_handle_data_packet_monitor(priv, |
7838 | &stats); | 8160 | rxb, |
8161 | &stats); | ||
7839 | #else | 8162 | #else |
7840 | ipw_handle_data_packet(priv, rxb, | 8163 | ipw_handle_data_packet(priv, rxb, |
7841 | &stats); | 8164 | &stats); |
7842 | #endif | 8165 | #endif |
7843 | break; | 8166 | break; |
7844 | } | 8167 | } |
@@ -9880,6 +10203,88 @@ static int ipw_net_is_queue_full(struct net_device *dev, int pri) | |||
9880 | return 0; | 10203 | return 0; |
9881 | } | 10204 | } |
9882 | 10205 | ||
10206 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
10207 | static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, | ||
10208 | struct ieee80211_txb *txb) | ||
10209 | { | ||
10210 | struct ieee80211_rx_stats dummystats; | ||
10211 | struct ieee80211_hdr *hdr; | ||
10212 | u8 n; | ||
10213 | u16 filter = priv->prom_priv->filter; | ||
10214 | int hdr_only = 0; | ||
10215 | |||
10216 | if (filter & IPW_PROM_NO_TX) | ||
10217 | return; | ||
10218 | |||
10219 | memset(&dummystats, 0, sizeof(dummystats)); | ||
10220 | |||
10221 | /* Filtering of fragment chains is done agains the first fragment */ | ||
10222 | hdr = (void *)txb->fragments[0]->data; | ||
10223 | if (ieee80211_is_management(hdr->frame_ctl)) { | ||
10224 | if (filter & IPW_PROM_NO_MGMT) | ||
10225 | return; | ||
10226 | if (filter & IPW_PROM_MGMT_HEADER_ONLY) | ||
10227 | hdr_only = 1; | ||
10228 | } else if (ieee80211_is_control(hdr->frame_ctl)) { | ||
10229 | if (filter & IPW_PROM_NO_CTL) | ||
10230 | return; | ||
10231 | if (filter & IPW_PROM_CTL_HEADER_ONLY) | ||
10232 | hdr_only = 1; | ||
10233 | } else if (ieee80211_is_data(hdr->frame_ctl)) { | ||
10234 | if (filter & IPW_PROM_NO_DATA) | ||
10235 | return; | ||
10236 | if (filter & IPW_PROM_DATA_HEADER_ONLY) | ||
10237 | hdr_only = 1; | ||
10238 | } | ||
10239 | |||
10240 | for(n=0; n<txb->nr_frags; ++n) { | ||
10241 | struct sk_buff *src = txb->fragments[n]; | ||
10242 | struct sk_buff *dst; | ||
10243 | struct ieee80211_radiotap_header *rt_hdr; | ||
10244 | int len; | ||
10245 | |||
10246 | if (hdr_only) { | ||
10247 | hdr = (void *)src->data; | ||
10248 | len = ieee80211_get_hdrlen(hdr->frame_ctl); | ||
10249 | } else | ||
10250 | len = src->len; | ||
10251 | |||
10252 | dst = alloc_skb( | ||
10253 | len + IEEE80211_RADIOTAP_HDRLEN, GFP_ATOMIC); | ||
10254 | if (!dst) continue; | ||
10255 | |||
10256 | rt_hdr = (void *)skb_put(dst, sizeof(*rt_hdr)); | ||
10257 | |||
10258 | rt_hdr->it_version = PKTHDR_RADIOTAP_VERSION; | ||
10259 | rt_hdr->it_pad = 0; | ||
10260 | rt_hdr->it_present = 0; /* after all, it's just an idea */ | ||
10261 | rt_hdr->it_present |= (1 << IEEE80211_RADIOTAP_CHANNEL); | ||
10262 | |||
10263 | *(u16*)skb_put(dst, sizeof(u16)) = cpu_to_le16( | ||
10264 | ieee80211chan2mhz(priv->channel)); | ||
10265 | if (priv->channel > 14) /* 802.11a */ | ||
10266 | *(u16*)skb_put(dst, sizeof(u16)) = | ||
10267 | cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
10268 | IEEE80211_CHAN_5GHZ); | ||
10269 | else if (priv->ieee->mode == IEEE_B) /* 802.11b */ | ||
10270 | *(u16*)skb_put(dst, sizeof(u16)) = | ||
10271 | cpu_to_le16(IEEE80211_CHAN_CCK | | ||
10272 | IEEE80211_CHAN_2GHZ); | ||
10273 | else /* 802.11g */ | ||
10274 | *(u16*)skb_put(dst, sizeof(u16)) = | ||
10275 | cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
10276 | IEEE80211_CHAN_2GHZ); | ||
10277 | |||
10278 | rt_hdr->it_len = dst->len; | ||
10279 | |||
10280 | memcpy(skb_put(dst, len), src->data, len); | ||
10281 | |||
10282 | if (!ieee80211_rx(priv->prom_priv->ieee, dst, &dummystats)) | ||
10283 | dev_kfree_skb_any(dst); | ||
10284 | } | ||
10285 | } | ||
10286 | #endif | ||
10287 | |||
9883 | static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, | 10288 | static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, |
9884 | struct net_device *dev, int pri) | 10289 | struct net_device *dev, int pri) |
9885 | { | 10290 | { |
@@ -9897,6 +10302,11 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, | |||
9897 | goto fail_unlock; | 10302 | goto fail_unlock; |
9898 | } | 10303 | } |
9899 | 10304 | ||
10305 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
10306 | if (rtap_iface && netif_running(priv->prom_net_dev)) | ||
10307 | ipw_handle_promiscuous_tx(priv, txb); | ||
10308 | #endif | ||
10309 | |||
9900 | ret = ipw_tx_skb(priv, txb, pri); | 10310 | ret = ipw_tx_skb(priv, txb, pri); |
9901 | if (ret == NETDEV_TX_OK) | 10311 | if (ret == NETDEV_TX_OK) |
9902 | __ipw_led_activity_on(priv); | 10312 | __ipw_led_activity_on(priv); |
@@ -10344,12 +10754,21 @@ static int ipw_config(struct ipw_priv *priv) | |||
10344 | |= CFG_BT_COEXISTENCE_OOB; | 10754 | |= CFG_BT_COEXISTENCE_OOB; |
10345 | } | 10755 | } |
10346 | 10756 | ||
10757 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
10758 | if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) { | ||
10759 | priv->sys_config.accept_all_data_frames = 1; | ||
10760 | priv->sys_config.accept_non_directed_frames = 1; | ||
10761 | priv->sys_config.accept_all_mgmt_bcpr = 1; | ||
10762 | priv->sys_config.accept_all_mgmt_frames = 1; | ||
10763 | } | ||
10764 | #endif | ||
10765 | |||
10347 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) | 10766 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) |
10348 | priv->sys_config.answer_broadcast_ssid_probe = 1; | 10767 | priv->sys_config.answer_broadcast_ssid_probe = 1; |
10349 | else | 10768 | else |
10350 | priv->sys_config.answer_broadcast_ssid_probe = 0; | 10769 | priv->sys_config.answer_broadcast_ssid_probe = 0; |
10351 | 10770 | ||
10352 | if (ipw_send_system_config(priv, &priv->sys_config)) | 10771 | if (ipw_send_system_config(priv)) |
10353 | goto error; | 10772 | goto error; |
10354 | 10773 | ||
10355 | init_supported_rates(priv, &priv->rates); | 10774 | init_supported_rates(priv, &priv->rates); |
@@ -10887,6 +11306,10 @@ static struct attribute *ipw_sysfs_entries[] = { | |||
10887 | &dev_attr_led.attr, | 11306 | &dev_attr_led.attr, |
10888 | &dev_attr_speed_scan.attr, | 11307 | &dev_attr_speed_scan.attr, |
10889 | &dev_attr_net_stats.attr, | 11308 | &dev_attr_net_stats.attr, |
11309 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
11310 | &dev_attr_rtap_iface.attr, | ||
11311 | &dev_attr_rtap_filter.attr, | ||
11312 | #endif | ||
10890 | NULL | 11313 | NULL |
10891 | }; | 11314 | }; |
10892 | 11315 | ||
@@ -10895,6 +11318,109 @@ static struct attribute_group ipw_attribute_group = { | |||
10895 | .attrs = ipw_sysfs_entries, | 11318 | .attrs = ipw_sysfs_entries, |
10896 | }; | 11319 | }; |
10897 | 11320 | ||
11321 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
11322 | static int ipw_prom_open(struct net_device *dev) | ||
11323 | { | ||
11324 | struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); | ||
11325 | struct ipw_priv *priv = prom_priv->priv; | ||
11326 | |||
11327 | IPW_DEBUG_INFO("prom dev->open\n"); | ||
11328 | netif_carrier_off(dev); | ||
11329 | netif_stop_queue(dev); | ||
11330 | |||
11331 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) { | ||
11332 | priv->sys_config.accept_all_data_frames = 1; | ||
11333 | priv->sys_config.accept_non_directed_frames = 1; | ||
11334 | priv->sys_config.accept_all_mgmt_bcpr = 1; | ||
11335 | priv->sys_config.accept_all_mgmt_frames = 1; | ||
11336 | |||
11337 | ipw_send_system_config(priv); | ||
11338 | } | ||
11339 | |||
11340 | return 0; | ||
11341 | } | ||
11342 | |||
11343 | static int ipw_prom_stop(struct net_device *dev) | ||
11344 | { | ||
11345 | struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); | ||
11346 | struct ipw_priv *priv = prom_priv->priv; | ||
11347 | |||
11348 | IPW_DEBUG_INFO("prom dev->stop\n"); | ||
11349 | |||
11350 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) { | ||
11351 | priv->sys_config.accept_all_data_frames = 0; | ||
11352 | priv->sys_config.accept_non_directed_frames = 0; | ||
11353 | priv->sys_config.accept_all_mgmt_bcpr = 0; | ||
11354 | priv->sys_config.accept_all_mgmt_frames = 0; | ||
11355 | |||
11356 | ipw_send_system_config(priv); | ||
11357 | } | ||
11358 | |||
11359 | return 0; | ||
11360 | } | ||
11361 | |||
11362 | static int ipw_prom_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
11363 | { | ||
11364 | IPW_DEBUG_INFO("prom dev->xmit\n"); | ||
11365 | netif_stop_queue(dev); | ||
11366 | return -EOPNOTSUPP; | ||
11367 | } | ||
11368 | |||
11369 | static struct net_device_stats *ipw_prom_get_stats(struct net_device *dev) | ||
11370 | { | ||
11371 | struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); | ||
11372 | return &prom_priv->ieee->stats; | ||
11373 | } | ||
11374 | |||
11375 | static int ipw_prom_alloc(struct ipw_priv *priv) | ||
11376 | { | ||
11377 | int rc = 0; | ||
11378 | |||
11379 | if (priv->prom_net_dev) | ||
11380 | return -EPERM; | ||
11381 | |||
11382 | priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv)); | ||
11383 | if (priv->prom_net_dev == NULL) | ||
11384 | return -ENOMEM; | ||
11385 | |||
11386 | priv->prom_priv = ieee80211_priv(priv->prom_net_dev); | ||
11387 | priv->prom_priv->ieee = netdev_priv(priv->prom_net_dev); | ||
11388 | priv->prom_priv->priv = priv; | ||
11389 | |||
11390 | strcpy(priv->prom_net_dev->name, "rtap%d"); | ||
11391 | |||
11392 | priv->prom_net_dev->type = ARPHRD_IEEE80211_RADIOTAP; | ||
11393 | priv->prom_net_dev->open = ipw_prom_open; | ||
11394 | priv->prom_net_dev->stop = ipw_prom_stop; | ||
11395 | priv->prom_net_dev->get_stats = ipw_prom_get_stats; | ||
11396 | priv->prom_net_dev->hard_start_xmit = ipw_prom_hard_start_xmit; | ||
11397 | |||
11398 | priv->prom_priv->ieee->iw_mode = IW_MODE_MONITOR; | ||
11399 | |||
11400 | rc = register_netdev(priv->prom_net_dev); | ||
11401 | if (rc) { | ||
11402 | free_ieee80211(priv->prom_net_dev); | ||
11403 | priv->prom_net_dev = NULL; | ||
11404 | return rc; | ||
11405 | } | ||
11406 | |||
11407 | return 0; | ||
11408 | } | ||
11409 | |||
11410 | static void ipw_prom_free(struct ipw_priv *priv) | ||
11411 | { | ||
11412 | if (!priv->prom_net_dev) | ||
11413 | return; | ||
11414 | |||
11415 | unregister_netdev(priv->prom_net_dev); | ||
11416 | free_ieee80211(priv->prom_net_dev); | ||
11417 | |||
11418 | priv->prom_net_dev = NULL; | ||
11419 | } | ||
11420 | |||
11421 | #endif | ||
11422 | |||
11423 | |||
10898 | static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 11424 | static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
10899 | { | 11425 | { |
10900 | int err = 0; | 11426 | int err = 0; |
@@ -11025,6 +11551,18 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
11025 | goto out_remove_sysfs; | 11551 | goto out_remove_sysfs; |
11026 | } | 11552 | } |
11027 | 11553 | ||
11554 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
11555 | if (rtap_iface) { | ||
11556 | err = ipw_prom_alloc(priv); | ||
11557 | if (err) { | ||
11558 | IPW_ERROR("Failed to register promiscuous network " | ||
11559 | "device (error %d).\n", err); | ||
11560 | unregister_netdev(priv->net_dev); | ||
11561 | goto out_remove_sysfs; | ||
11562 | } | ||
11563 | } | ||
11564 | #endif | ||
11565 | |||
11028 | printk(KERN_INFO DRV_NAME ": Detected geography %s (%d 802.11bg " | 11566 | printk(KERN_INFO DRV_NAME ": Detected geography %s (%d 802.11bg " |
11029 | "channels, %d 802.11a channels)\n", | 11567 | "channels, %d 802.11a channels)\n", |
11030 | priv->ieee->geo.name, priv->ieee->geo.bg_channels, | 11568 | priv->ieee->geo.name, priv->ieee->geo.bg_channels, |
@@ -11104,6 +11642,10 @@ static void ipw_pci_remove(struct pci_dev *pdev) | |||
11104 | priv->error = NULL; | 11642 | priv->error = NULL; |
11105 | } | 11643 | } |
11106 | 11644 | ||
11645 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
11646 | ipw_prom_free(priv); | ||
11647 | #endif | ||
11648 | |||
11107 | free_irq(pdev->irq, priv); | 11649 | free_irq(pdev->irq, priv); |
11108 | iounmap(priv->hw_base); | 11650 | iounmap(priv->hw_base); |
11109 | pci_release_regions(pdev); | 11651 | pci_release_regions(pdev); |
@@ -11228,6 +11770,11 @@ MODULE_PARM_DESC(debug, "debug output mask"); | |||
11228 | module_param(channel, int, 0444); | 11770 | module_param(channel, int, 0444); |
11229 | MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); | 11771 | MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); |
11230 | 11772 | ||
11773 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
11774 | module_param(rtap_iface, int, 0444); | ||
11775 | MODULE_PARM_DESC(rtap_iface, "create the rtap interface (1 - create, default 0)"); | ||
11776 | #endif | ||
11777 | |||
11231 | #ifdef CONFIG_IPW_QOS | 11778 | #ifdef CONFIG_IPW_QOS |
11232 | module_param(qos_enable, int, 0444); | 11779 | module_param(qos_enable, int, 0444); |
11233 | MODULE_PARM_DESC(qos_enable, "enable all QoS functionalitis"); | 11780 | MODULE_PARM_DESC(qos_enable, "enable all QoS functionalitis"); |
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 1f2cab3f9944..14fe79abca67 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h | |||
@@ -789,7 +789,7 @@ struct ipw_sys_config { | |||
789 | u8 bt_coexist_collision_thr; | 789 | u8 bt_coexist_collision_thr; |
790 | u8 silence_threshold; | 790 | u8 silence_threshold; |
791 | u8 accept_all_mgmt_bcpr; | 791 | u8 accept_all_mgmt_bcpr; |
792 | u8 accept_all_mgtm_frames; | 792 | u8 accept_all_mgmt_frames; |
793 | u8 pass_noise_stats_to_host; | 793 | u8 pass_noise_stats_to_host; |
794 | u8 reserved3; | 794 | u8 reserved3; |
795 | } __attribute__ ((packed)); | 795 | } __attribute__ ((packed)); |
@@ -1122,6 +1122,52 @@ struct ipw_fw_error { | |||
1122 | u8 payload[0]; | 1122 | u8 payload[0]; |
1123 | } __attribute__ ((packed)); | 1123 | } __attribute__ ((packed)); |
1124 | 1124 | ||
1125 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
1126 | |||
1127 | enum ipw_prom_filter { | ||
1128 | IPW_PROM_CTL_HEADER_ONLY = (1 << 0), | ||
1129 | IPW_PROM_MGMT_HEADER_ONLY = (1 << 1), | ||
1130 | IPW_PROM_DATA_HEADER_ONLY = (1 << 2), | ||
1131 | IPW_PROM_ALL_HEADER_ONLY = 0xf, /* bits 0..3 */ | ||
1132 | IPW_PROM_NO_TX = (1 << 4), | ||
1133 | IPW_PROM_NO_RX = (1 << 5), | ||
1134 | IPW_PROM_NO_CTL = (1 << 6), | ||
1135 | IPW_PROM_NO_MGMT = (1 << 7), | ||
1136 | IPW_PROM_NO_DATA = (1 << 8), | ||
1137 | }; | ||
1138 | |||
1139 | struct ipw_priv; | ||
1140 | struct ipw_prom_priv { | ||
1141 | struct ipw_priv *priv; | ||
1142 | struct ieee80211_device *ieee; | ||
1143 | enum ipw_prom_filter filter; | ||
1144 | int tx_packets; | ||
1145 | int rx_packets; | ||
1146 | }; | ||
1147 | #endif | ||
1148 | |||
1149 | #if defined(CONFIG_IEEE80211_RADIOTAP) || defined(CONFIG_IPW2200_PROMISCUOUS) | ||
1150 | /* Magic struct that slots into the radiotap header -- no reason | ||
1151 | * to build this manually element by element, we can write it much | ||
1152 | * more efficiently than we can parse it. ORDER MATTERS HERE | ||
1153 | * | ||
1154 | * When sent to us via the simulated Rx interface in sysfs, the entire | ||
1155 | * structure is provided regardless of any bits unset. | ||
1156 | */ | ||
1157 | struct ipw_rt_hdr { | ||
1158 | struct ieee80211_radiotap_header rt_hdr; | ||
1159 | u64 rt_tsf; /* TSF */ | ||
1160 | u8 rt_flags; /* radiotap packet flags */ | ||
1161 | u8 rt_rate; /* rate in 500kb/s */ | ||
1162 | u16 rt_channel; /* channel in mhz */ | ||
1163 | u16 rt_chbitmask; /* channel bitfield */ | ||
1164 | s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ | ||
1165 | s8 rt_dbmnoise; | ||
1166 | u8 rt_antenna; /* antenna number */ | ||
1167 | u8 payload[0]; /* payload... */ | ||
1168 | } __attribute__ ((packed)); | ||
1169 | #endif | ||
1170 | |||
1125 | struct ipw_priv { | 1171 | struct ipw_priv { |
1126 | /* ieee device used by generic ieee processing code */ | 1172 | /* ieee device used by generic ieee processing code */ |
1127 | struct ieee80211_device *ieee; | 1173 | struct ieee80211_device *ieee; |
@@ -1133,6 +1179,12 @@ struct ipw_priv { | |||
1133 | struct pci_dev *pci_dev; | 1179 | struct pci_dev *pci_dev; |
1134 | struct net_device *net_dev; | 1180 | struct net_device *net_dev; |
1135 | 1181 | ||
1182 | #ifdef CONFIG_IPW2200_PROMISCUOUS | ||
1183 | /* Promiscuous mode */ | ||
1184 | struct ipw_prom_priv *prom_priv; | ||
1185 | struct net_device *prom_net_dev; | ||
1186 | #endif | ||
1187 | |||
1136 | /* pci hardware address support */ | 1188 | /* pci hardware address support */ |
1137 | void __iomem *hw_base; | 1189 | void __iomem *hw_base; |
1138 | unsigned long hw_len; | 1190 | unsigned long hw_len; |
@@ -1306,6 +1358,29 @@ struct ipw_priv { | |||
1306 | 1358 | ||
1307 | /* debug macros */ | 1359 | /* debug macros */ |
1308 | 1360 | ||
1361 | /* Debug and printf string expansion helpers for printing bitfields */ | ||
1362 | #define BIT_FMT8 "%c%c%c%c-%c%c%c%c" | ||
1363 | #define BIT_FMT16 BIT_FMT8 ":" BIT_FMT8 | ||
1364 | #define BIT_FMT32 BIT_FMT16 " " BIT_FMT16 | ||
1365 | |||
1366 | #define BITC(x,y) (((x>>y)&1)?'1':'0') | ||
1367 | #define BIT_ARG8(x) \ | ||
1368 | BITC(x,7),BITC(x,6),BITC(x,5),BITC(x,4),\ | ||
1369 | BITC(x,3),BITC(x,2),BITC(x,1),BITC(x,0) | ||
1370 | |||
1371 | #define BIT_ARG16(x) \ | ||
1372 | BITC(x,15),BITC(x,14),BITC(x,13),BITC(x,12),\ | ||
1373 | BITC(x,11),BITC(x,10),BITC(x,9),BITC(x,8),\ | ||
1374 | BIT_ARG8(x) | ||
1375 | |||
1376 | #define BIT_ARG32(x) \ | ||
1377 | BITC(x,31),BITC(x,30),BITC(x,29),BITC(x,28),\ | ||
1378 | BITC(x,27),BITC(x,26),BITC(x,25),BITC(x,24),\ | ||
1379 | BITC(x,23),BITC(x,22),BITC(x,21),BITC(x,20),\ | ||
1380 | BITC(x,19),BITC(x,18),BITC(x,17),BITC(x,16),\ | ||
1381 | BIT_ARG16(x) | ||
1382 | |||
1383 | |||
1309 | #ifdef CONFIG_IPW2200_DEBUG | 1384 | #ifdef CONFIG_IPW2200_DEBUG |
1310 | #define IPW_DEBUG(level, fmt, args...) \ | 1385 | #define IPW_DEBUG(level, fmt, args...) \ |
1311 | do { if (ipw_debug_level & (level)) \ | 1386 | do { if (ipw_debug_level & (level)) \ |