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)) \ |
