diff options
128 files changed, 6629 insertions, 2696 deletions
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index 445289cd0e65..2014155c899d 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl | |||
@@ -433,8 +433,18 @@ | |||
433 | Insert notes about VLAN interfaces with hw crypto here or | 433 | Insert notes about VLAN interfaces with hw crypto here or |
434 | in the hw crypto chapter. | 434 | in the hw crypto chapter. |
435 | </para> | 435 | </para> |
436 | <section id="ps-client"> | ||
437 | <title>support for powersaving clients</title> | ||
438 | !Pinclude/net/mac80211.h AP support for powersaving clients | ||
439 | </section> | ||
436 | !Finclude/net/mac80211.h ieee80211_get_buffered_bc | 440 | !Finclude/net/mac80211.h ieee80211_get_buffered_bc |
437 | !Finclude/net/mac80211.h ieee80211_beacon_get | 441 | !Finclude/net/mac80211.h ieee80211_beacon_get |
442 | !Finclude/net/mac80211.h ieee80211_sta_eosp_irqsafe | ||
443 | !Finclude/net/mac80211.h ieee80211_frame_release_type | ||
444 | !Finclude/net/mac80211.h ieee80211_sta_ps_transition | ||
445 | !Finclude/net/mac80211.h ieee80211_sta_ps_transition_ni | ||
446 | !Finclude/net/mac80211.h ieee80211_sta_set_buffered | ||
447 | !Finclude/net/mac80211.h ieee80211_sta_block_awake | ||
438 | </chapter> | 448 | </chapter> |
439 | 449 | ||
440 | <chapter id="multi-iface"> | 450 | <chapter id="multi-iface"> |
@@ -460,7 +470,6 @@ | |||
460 | !Finclude/net/mac80211.h sta_notify_cmd | 470 | !Finclude/net/mac80211.h sta_notify_cmd |
461 | !Finclude/net/mac80211.h ieee80211_find_sta | 471 | !Finclude/net/mac80211.h ieee80211_find_sta |
462 | !Finclude/net/mac80211.h ieee80211_find_sta_by_ifaddr | 472 | !Finclude/net/mac80211.h ieee80211_find_sta_by_ifaddr |
463 | !Finclude/net/mac80211.h ieee80211_sta_block_awake | ||
464 | </chapter> | 473 | </chapter> |
465 | 474 | ||
466 | <chapter id="hardware-scan-offload"> | 475 | <chapter id="hardware-scan-offload"> |
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 4dc465477665..d5ac362daef5 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -594,9 +594,18 @@ Why: In 3.0, we can now autodetect internal 3G device and already have | |||
594 | Who: Lee, Chun-Yi <jlee@novell.com> | 594 | Who: Lee, Chun-Yi <jlee@novell.com> |
595 | 595 | ||
596 | ---------------------------- | 596 | ---------------------------- |
597 | |||
597 | What: The XFS nodelaylog mount option | 598 | What: The XFS nodelaylog mount option |
598 | When: 3.3 | 599 | When: 3.3 |
599 | Why: The delaylog mode that has been the default since 2.6.39 has proven | 600 | Why: The delaylog mode that has been the default since 2.6.39 has proven |
600 | stable, and the old code is in the way of additional improvements in | 601 | stable, and the old code is in the way of additional improvements in |
601 | the log code. | 602 | the log code. |
602 | Who: Christoph Hellwig <hch@lst.de> | 603 | Who: Christoph Hellwig <hch@lst.de> |
604 | |||
605 | ---------------------------- | ||
606 | |||
607 | What: iwlagn alias support | ||
608 | When: 3.5 | ||
609 | Why: The iwlagn module has been renamed iwlwifi. The alias will be around | ||
610 | for backward compatibility for several cycles and then dropped. | ||
611 | Who: Don Fry <donald.h.fry@intel.com> | ||
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 9cbac6b445e1..675246a6f7ef 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c | |||
@@ -60,6 +60,9 @@ static struct usb_device_id btusb_table[] = { | |||
60 | /* Generic Bluetooth USB device */ | 60 | /* Generic Bluetooth USB device */ |
61 | { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, | 61 | { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, |
62 | 62 | ||
63 | /* Broadcom SoftSailing reporting vendor specific */ | ||
64 | { USB_DEVICE(0x05ac, 0x21e1) }, | ||
65 | |||
63 | /* Apple MacBookPro 7,1 */ | 66 | /* Apple MacBookPro 7,1 */ |
64 | { USB_DEVICE(0x05ac, 0x8213) }, | 67 | { USB_DEVICE(0x05ac, 0x8213) }, |
65 | 68 | ||
@@ -708,8 +711,7 @@ static int btusb_send_frame(struct sk_buff *skb) | |||
708 | break; | 711 | break; |
709 | 712 | ||
710 | case HCI_ACLDATA_PKT: | 713 | case HCI_ACLDATA_PKT: |
711 | if (!data->bulk_tx_ep || (hdev->conn_hash.acl_num < 1 && | 714 | if (!data->bulk_tx_ep) |
712 | hdev->conn_hash.le_num < 1)) | ||
713 | return -ENODEV; | 715 | return -ENODEV; |
714 | 716 | ||
715 | urb = usb_alloc_urb(0, GFP_ATOMIC); | 717 | urb = usb_alloc_urb(0, GFP_ATOMIC); |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 7bba6a82b875..4cf0ad312da1 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
@@ -41,7 +41,7 @@ obj-$(CONFIG_ADM8211) += adm8211.o | |||
41 | 41 | ||
42 | obj-$(CONFIG_MWL8K) += mwl8k.o | 42 | obj-$(CONFIG_MWL8K) += mwl8k.o |
43 | 43 | ||
44 | obj-$(CONFIG_IWLAGN) += iwlwifi/ | 44 | obj-$(CONFIG_IWLWIFI) += iwlwifi/ |
45 | obj-$(CONFIG_IWLWIFI_LEGACY) += iwlegacy/ | 45 | obj-$(CONFIG_IWLWIFI_LEGACY) += iwlegacy/ |
46 | obj-$(CONFIG_RT2X00) += rt2x00/ | 46 | obj-$(CONFIG_RT2X00) += rt2x00/ |
47 | 47 | ||
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 298601436ee2..39322d4121b7 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c | |||
@@ -500,10 +500,9 @@ exit: | |||
500 | 500 | ||
501 | #define HEX2STR_BUFFERS 4 | 501 | #define HEX2STR_BUFFERS 4 |
502 | #define HEX2STR_MAX_LEN 64 | 502 | #define HEX2STR_MAX_LEN 64 |
503 | #define BIN2HEX(x) ((x) < 10 ? '0' + (x) : (x) + 'A' - 10) | ||
504 | 503 | ||
505 | /* Convert binary data into hex string */ | 504 | /* Convert binary data into hex string */ |
506 | static char *hex2str(void *buf, int len) | 505 | static char *hex2str(void *buf, size_t len) |
507 | { | 506 | { |
508 | static atomic_t a = ATOMIC_INIT(0); | 507 | static atomic_t a = ATOMIC_INIT(0); |
509 | static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1]; | 508 | static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1]; |
@@ -514,18 +513,17 @@ static char *hex2str(void *buf, int len) | |||
514 | if (len > HEX2STR_MAX_LEN) | 513 | if (len > HEX2STR_MAX_LEN) |
515 | len = HEX2STR_MAX_LEN; | 514 | len = HEX2STR_MAX_LEN; |
516 | 515 | ||
517 | if (len <= 0) { | 516 | if (len == 0) |
518 | ret[0] = '\0'; | 517 | goto exit; |
519 | return ret; | ||
520 | } | ||
521 | 518 | ||
522 | while (len--) { | 519 | while (len--) { |
523 | *obuf++ = BIN2HEX(*ibuf >> 4); | 520 | obuf = pack_hex_byte(obuf, *ibuf++); |
524 | *obuf++ = BIN2HEX(*ibuf & 0xf); | ||
525 | *obuf++ = '-'; | 521 | *obuf++ = '-'; |
526 | ibuf++; | ||
527 | } | 522 | } |
528 | *(--obuf) = '\0'; | 523 | obuf--; |
524 | |||
525 | exit: | ||
526 | *obuf = '\0'; | ||
529 | 527 | ||
530 | return ret; | 528 | return ret; |
531 | } | 529 | } |
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index bba4f6fcf7e2..6ed4c0717e3e 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c | |||
@@ -563,7 +563,7 @@ ath5k_get_stats(struct ieee80211_hw *hw, | |||
563 | 563 | ||
564 | 564 | ||
565 | static int | 565 | static int |
566 | ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue, | 566 | ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, |
567 | const struct ieee80211_tx_queue_params *params) | 567 | const struct ieee80211_tx_queue_params *params) |
568 | { | 568 | { |
569 | struct ath5k_hw *ah = hw->priv; | 569 | struct ath5k_hw *ah = hw->priv; |
diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index e1bb07ea8e80..8f7a0d1c290c 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile | |||
@@ -31,5 +31,7 @@ ath6kl-y += init.o | |||
31 | ath6kl-y += main.o | 31 | ath6kl-y += main.o |
32 | ath6kl-y += txrx.o | 32 | ath6kl-y += txrx.o |
33 | ath6kl-y += wmi.o | 33 | ath6kl-y += wmi.o |
34 | ath6kl-y += node.o | ||
35 | ath6kl-y += sdio.o | 34 | ath6kl-y += sdio.o |
35 | ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o | ||
36 | |||
37 | ccflags-y += -D__CHECK_ENDIAN__ | ||
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c index 84676697d7eb..c5d11cc536e0 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.c +++ b/drivers/net/wireless/ath/ath6kl/bmi.c | |||
@@ -62,14 +62,14 @@ static int ath6kl_get_bmi_cmd_credits(struct ath6kl *ar) | |||
62 | return 0; | 62 | return 0; |
63 | } | 63 | } |
64 | 64 | ||
65 | static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar, bool need_timeout) | 65 | static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar) |
66 | { | 66 | { |
67 | unsigned long timeout; | 67 | unsigned long timeout; |
68 | u32 rx_word = 0; | 68 | u32 rx_word = 0; |
69 | int ret = 0; | 69 | int ret = 0; |
70 | 70 | ||
71 | timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); | 71 | timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); |
72 | while ((!need_timeout || time_before(jiffies, timeout)) && !rx_word) { | 72 | while (time_before(jiffies, timeout) && !rx_word) { |
73 | ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS, | 73 | ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS, |
74 | (u8 *)&rx_word, sizeof(rx_word), | 74 | (u8 *)&rx_word, sizeof(rx_word), |
75 | HIF_RD_SYNC_BYTE_INC); | 75 | HIF_RD_SYNC_BYTE_INC); |
@@ -109,8 +109,7 @@ static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len) | |||
109 | return ret; | 109 | return ret; |
110 | } | 110 | } |
111 | 111 | ||
112 | static int ath6kl_bmi_recv_buf(struct ath6kl *ar, | 112 | static int ath6kl_bmi_recv_buf(struct ath6kl *ar, u8 *buf, u32 len) |
113 | u8 *buf, u32 len, bool want_timeout) | ||
114 | { | 113 | { |
115 | int ret; | 114 | int ret; |
116 | u32 addr; | 115 | u32 addr; |
@@ -162,7 +161,7 @@ static int ath6kl_bmi_recv_buf(struct ath6kl *ar, | |||
162 | * a function of Host processor speed. | 161 | * a function of Host processor speed. |
163 | */ | 162 | */ |
164 | if (len >= 4) { /* NB: Currently, always true */ | 163 | if (len >= 4) { /* NB: Currently, always true */ |
165 | ret = ath6kl_bmi_get_rx_lkahd(ar, want_timeout); | 164 | ret = ath6kl_bmi_get_rx_lkahd(ar); |
166 | if (ret) | 165 | if (ret) |
167 | return ret; | 166 | return ret; |
168 | } | 167 | } |
@@ -220,7 +219,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, | |||
220 | } | 219 | } |
221 | 220 | ||
222 | ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version, | 221 | ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version, |
223 | sizeof(targ_info->version), true); | 222 | sizeof(targ_info->version)); |
224 | if (ret) { | 223 | if (ret) { |
225 | ath6kl_err("Unable to recv target info: %d\n", ret); | 224 | ath6kl_err("Unable to recv target info: %d\n", ret); |
226 | return ret; | 225 | return ret; |
@@ -230,8 +229,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, | |||
230 | /* Determine how many bytes are in the Target's targ_info */ | 229 | /* Determine how many bytes are in the Target's targ_info */ |
231 | ret = ath6kl_bmi_recv_buf(ar, | 230 | ret = ath6kl_bmi_recv_buf(ar, |
232 | (u8 *)&targ_info->byte_count, | 231 | (u8 *)&targ_info->byte_count, |
233 | sizeof(targ_info->byte_count), | 232 | sizeof(targ_info->byte_count)); |
234 | true); | ||
235 | if (ret) { | 233 | if (ret) { |
236 | ath6kl_err("unable to read target info byte count: %d\n", | 234 | ath6kl_err("unable to read target info byte count: %d\n", |
237 | ret); | 235 | ret); |
@@ -252,8 +250,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, | |||
252 | ((u8 *)targ_info) + | 250 | ((u8 *)targ_info) + |
253 | sizeof(targ_info->byte_count), | 251 | sizeof(targ_info->byte_count), |
254 | sizeof(*targ_info) - | 252 | sizeof(*targ_info) - |
255 | sizeof(targ_info->byte_count), | 253 | sizeof(targ_info->byte_count)); |
256 | true); | ||
257 | 254 | ||
258 | if (ret) { | 255 | if (ret) { |
259 | ath6kl_err("Unable to read target info (%d bytes): %d\n", | 256 | ath6kl_err("Unable to read target info (%d bytes): %d\n", |
@@ -311,7 +308,7 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) | |||
311 | ret); | 308 | ret); |
312 | return ret; | 309 | return ret; |
313 | } | 310 | } |
314 | ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len, true); | 311 | ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len); |
315 | if (ret) { | 312 | if (ret) { |
316 | ath6kl_err("Unable to read from the device: %d\n", | 313 | ath6kl_err("Unable to read from the device: %d\n", |
317 | ret); | 314 | ret); |
@@ -424,7 +421,7 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param) | |||
424 | return ret; | 421 | return ret; |
425 | } | 422 | } |
426 | 423 | ||
427 | ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param), false); | 424 | ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param)); |
428 | if (ret) { | 425 | if (ret) { |
429 | ath6kl_err("Unable to read from the device: %d\n", ret); | 426 | ath6kl_err("Unable to read from the device: %d\n", ret); |
430 | return ret; | 427 | return ret; |
@@ -504,7 +501,7 @@ int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param) | |||
504 | return ret; | 501 | return ret; |
505 | } | 502 | } |
506 | 503 | ||
507 | ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param), true); | 504 | ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param)); |
508 | if (ret) { | 505 | if (ret) { |
509 | ath6kl_err("Unable to read from the device: %d\n", ret); | 506 | ath6kl_err("Unable to read from the device: %d\n", ret); |
510 | return ret; | 507 | return ret; |
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h index 83546d76d979..96851d5df24b 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.h +++ b/drivers/net/wireless/ath/ath6kl/bmi.h | |||
@@ -139,8 +139,8 @@ | |||
139 | */ | 139 | */ |
140 | 140 | ||
141 | #define TARGET_VERSION_SENTINAL 0xffffffff | 141 | #define TARGET_VERSION_SENTINAL 0xffffffff |
142 | #define TARGET_TYPE_AR6003 3 | 142 | #define TARGET_TYPE_AR6003 3 |
143 | 143 | #define TARGET_TYPE_AR6004 5 | |
144 | #define BMI_ROMPATCH_INSTALL 9 | 144 | #define BMI_ROMPATCH_INSTALL 9 |
145 | /* | 145 | /* |
146 | * Semantics: Install a ROM Patch. | 146 | * Semantics: Install a ROM Patch. |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 14559ffb1453..3aff36bad5d3 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -17,6 +17,12 @@ | |||
17 | #include "core.h" | 17 | #include "core.h" |
18 | #include "cfg80211.h" | 18 | #include "cfg80211.h" |
19 | #include "debug.h" | 19 | #include "debug.h" |
20 | #include "hif-ops.h" | ||
21 | #include "testmode.h" | ||
22 | |||
23 | static unsigned int ath6kl_p2p; | ||
24 | |||
25 | module_param(ath6kl_p2p, uint, 0644); | ||
20 | 26 | ||
21 | #define RATETAB_ENT(_rate, _rateid, _flags) { \ | 27 | #define RATETAB_ENT(_rate, _rateid, _flags) { \ |
22 | .bitrate = (_rate), \ | 28 | .bitrate = (_rate), \ |
@@ -152,8 +158,7 @@ static int ath6kl_set_auth_type(struct ath6kl *ar, | |||
152 | break; | 158 | break; |
153 | 159 | ||
154 | case NL80211_AUTHTYPE_AUTOMATIC: | 160 | case NL80211_AUTHTYPE_AUTOMATIC: |
155 | ar->dot11_auth_mode = OPEN_AUTH; | 161 | ar->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH; |
156 | ar->auto_auth_stage = AUTH_OPEN_IN_PROGRESS; | ||
157 | break; | 162 | break; |
158 | 163 | ||
159 | default: | 164 | default: |
@@ -167,7 +172,8 @@ static int ath6kl_set_auth_type(struct ath6kl *ar, | |||
167 | static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast) | 172 | static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast) |
168 | { | 173 | { |
169 | u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto; | 174 | u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto; |
170 | u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len : &ar->grp_crpto_len; | 175 | u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len : |
176 | &ar->grp_crypto_len; | ||
171 | 177 | ||
172 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n", | 178 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n", |
173 | __func__, cipher, ucast); | 179 | __func__, cipher, ucast); |
@@ -354,6 +360,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
354 | } | 360 | } |
355 | 361 | ||
356 | if (!ar->usr_bss_filter) { | 362 | if (!ar->usr_bss_filter) { |
363 | clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); | ||
357 | if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) { | 364 | if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) { |
358 | ath6kl_err("couldn't set bss filtering\n"); | 365 | ath6kl_err("couldn't set bss filtering\n"); |
359 | up(&ar->sem); | 366 | up(&ar->sem); |
@@ -370,14 +377,14 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
370 | __func__, | 377 | __func__, |
371 | ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto, | 378 | ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto, |
372 | ar->prwise_crypto_len, ar->grp_crypto, | 379 | ar->prwise_crypto_len, ar->grp_crypto, |
373 | ar->grp_crpto_len, ar->ch_hint); | 380 | ar->grp_crypto_len, ar->ch_hint); |
374 | 381 | ||
375 | ar->reconnect_flag = 0; | 382 | ar->reconnect_flag = 0; |
376 | status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type, | 383 | status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type, |
377 | ar->dot11_auth_mode, ar->auth_mode, | 384 | ar->dot11_auth_mode, ar->auth_mode, |
378 | ar->prwise_crypto, | 385 | ar->prwise_crypto, |
379 | ar->prwise_crypto_len, | 386 | ar->prwise_crypto_len, |
380 | ar->grp_crypto, ar->grp_crpto_len, | 387 | ar->grp_crypto, ar->grp_crypto_len, |
381 | ar->ssid_len, ar->ssid, | 388 | ar->ssid_len, ar->ssid, |
382 | ar->req_bssid, ar->ch_hint, | 389 | ar->req_bssid, ar->ch_hint, |
383 | ar->connect_ctrl_flags); | 390 | ar->connect_ctrl_flags); |
@@ -407,6 +414,53 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
407 | return 0; | 414 | return 0; |
408 | } | 415 | } |
409 | 416 | ||
417 | static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid, | ||
418 | struct ieee80211_channel *chan, | ||
419 | const u8 *beacon_ie, size_t beacon_ie_len) | ||
420 | { | ||
421 | struct cfg80211_bss *bss; | ||
422 | u8 *ie; | ||
423 | |||
424 | bss = cfg80211_get_bss(ar->wdev->wiphy, chan, bssid, | ||
425 | ar->ssid, ar->ssid_len, WLAN_CAPABILITY_ESS, | ||
426 | WLAN_CAPABILITY_ESS); | ||
427 | if (bss == NULL) { | ||
428 | /* | ||
429 | * Since cfg80211 may not yet know about the BSS, | ||
430 | * generate a partial entry until the first BSS info | ||
431 | * event becomes available. | ||
432 | * | ||
433 | * Prepend SSID element since it is not included in the Beacon | ||
434 | * IEs from the target. | ||
435 | */ | ||
436 | ie = kmalloc(2 + ar->ssid_len + beacon_ie_len, GFP_KERNEL); | ||
437 | if (ie == NULL) | ||
438 | return -ENOMEM; | ||
439 | ie[0] = WLAN_EID_SSID; | ||
440 | ie[1] = ar->ssid_len; | ||
441 | memcpy(ie + 2, ar->ssid, ar->ssid_len); | ||
442 | memcpy(ie + 2 + ar->ssid_len, beacon_ie, beacon_ie_len); | ||
443 | bss = cfg80211_inform_bss(ar->wdev->wiphy, chan, | ||
444 | bssid, 0, WLAN_CAPABILITY_ESS, 100, | ||
445 | ie, 2 + ar->ssid_len + beacon_ie_len, | ||
446 | 0, GFP_KERNEL); | ||
447 | if (bss) | ||
448 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for " | ||
449 | "%pM prior to indicating connect/roamed " | ||
450 | "event\n", bssid); | ||
451 | kfree(ie); | ||
452 | } else | ||
453 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss " | ||
454 | "entry\n"); | ||
455 | |||
456 | if (bss == NULL) | ||
457 | return -ENOMEM; | ||
458 | |||
459 | cfg80211_put_bss(bss); | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
410 | void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | 464 | void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, |
411 | u8 *bssid, u16 listen_intvl, | 465 | u8 *bssid, u16 listen_intvl, |
412 | u16 beacon_intvl, | 466 | u16 beacon_intvl, |
@@ -414,19 +468,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | |||
414 | u8 beacon_ie_len, u8 assoc_req_len, | 468 | u8 beacon_ie_len, u8 assoc_req_len, |
415 | u8 assoc_resp_len, u8 *assoc_info) | 469 | u8 assoc_resp_len, u8 *assoc_info) |
416 | { | 470 | { |
417 | u16 size = 0; | 471 | struct ieee80211_channel *chan; |
418 | u16 capability = 0; | ||
419 | struct cfg80211_bss *bss = NULL; | ||
420 | struct ieee80211_mgmt *mgmt = NULL; | ||
421 | struct ieee80211_channel *ibss_ch = NULL; | ||
422 | s32 signal = 50 * 100; | ||
423 | u8 ie_buf_len = 0; | ||
424 | unsigned char ie_buf[256]; | ||
425 | unsigned char *ptr_ie_buf = ie_buf; | ||
426 | unsigned char *ieeemgmtbuf = NULL; | ||
427 | u8 source_mac[ETH_ALEN]; | ||
428 | u16 capa_mask; | ||
429 | u16 capa_val; | ||
430 | 472 | ||
431 | /* capinfo + listen interval */ | 473 | /* capinfo + listen interval */ |
432 | u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); | 474 | u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); |
@@ -441,7 +483,12 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | |||
441 | assoc_req_len -= assoc_req_ie_offset; | 483 | assoc_req_len -= assoc_req_ie_offset; |
442 | assoc_resp_len -= assoc_resp_ie_offset; | 484 | assoc_resp_len -= assoc_resp_ie_offset; |
443 | 485 | ||
444 | ar->auto_auth_stage = AUTH_IDLE; | 486 | /* |
487 | * Store Beacon interval here; DTIM period will be available only once | ||
488 | * a Beacon frame from the AP is seen. | ||
489 | */ | ||
490 | ar->assoc_bss_beacon_int = beacon_intvl; | ||
491 | clear_bit(DTIM_PERIOD_AVAIL, &ar->flag); | ||
445 | 492 | ||
446 | if (nw_type & ADHOC_NETWORK) { | 493 | if (nw_type & ADHOC_NETWORK) { |
447 | if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) { | 494 | if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) { |
@@ -452,110 +499,26 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | |||
452 | } | 499 | } |
453 | 500 | ||
454 | if (nw_type & INFRA_NETWORK) { | 501 | if (nw_type & INFRA_NETWORK) { |
455 | if (ar->wdev->iftype != NL80211_IFTYPE_STATION) { | 502 | if (ar->wdev->iftype != NL80211_IFTYPE_STATION && |
503 | ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { | ||
456 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | 504 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
457 | "%s: ath6k not in station mode\n", __func__); | 505 | "%s: ath6k not in station mode\n", __func__); |
458 | return; | 506 | return; |
459 | } | 507 | } |
460 | } | 508 | } |
461 | 509 | ||
462 | if (nw_type & ADHOC_NETWORK) { | 510 | chan = ieee80211_get_channel(ar->wdev->wiphy, (int) channel); |
463 | capa_mask = WLAN_CAPABILITY_IBSS; | ||
464 | capa_val = WLAN_CAPABILITY_IBSS; | ||
465 | } else { | ||
466 | capa_mask = WLAN_CAPABILITY_ESS; | ||
467 | capa_val = WLAN_CAPABILITY_ESS; | ||
468 | } | ||
469 | 511 | ||
470 | /* Before informing the join/connect event, make sure that | ||
471 | * bss entry is present in scan list, if it not present | ||
472 | * construct and insert into scan list, otherwise that | ||
473 | * event will be dropped on the way by cfg80211, due to | ||
474 | * this keys will not be plumbed in case of WEP and | ||
475 | * application will not be aware of join/connect status. */ | ||
476 | bss = cfg80211_get_bss(ar->wdev->wiphy, NULL, bssid, | ||
477 | ar->wdev->ssid, ar->wdev->ssid_len, | ||
478 | capa_mask, capa_val); | ||
479 | |||
480 | /* | ||
481 | * Earlier we were updating the cfg about bss by making a beacon frame | ||
482 | * only if the entry for bss is not there. This can have some issue if | ||
483 | * ROAM event is generated and a heavy traffic is ongoing. The ROAM | ||
484 | * event is handled through a work queue and by the time it really gets | ||
485 | * handled, BSS would have been aged out. So it is better to update the | ||
486 | * cfg about BSS irrespective of its entry being present right now or | ||
487 | * not. | ||
488 | */ | ||
489 | 512 | ||
490 | if (nw_type & ADHOC_NETWORK) { | 513 | if (nw_type & ADHOC_NETWORK) { |
491 | /* construct 802.11 mgmt beacon */ | 514 | cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); |
492 | if (ptr_ie_buf) { | ||
493 | *ptr_ie_buf++ = WLAN_EID_SSID; | ||
494 | *ptr_ie_buf++ = ar->ssid_len; | ||
495 | memcpy(ptr_ie_buf, ar->ssid, ar->ssid_len); | ||
496 | ptr_ie_buf += ar->ssid_len; | ||
497 | |||
498 | *ptr_ie_buf++ = WLAN_EID_IBSS_PARAMS; | ||
499 | *ptr_ie_buf++ = 2; /* length */ | ||
500 | *ptr_ie_buf++ = 0; /* ATIM window */ | ||
501 | *ptr_ie_buf++ = 0; /* ATIM window */ | ||
502 | |||
503 | /* TODO: update ibss params and include supported rates, | ||
504 | * DS param set, extened support rates, wmm. */ | ||
505 | |||
506 | ie_buf_len = ptr_ie_buf - ie_buf; | ||
507 | } | ||
508 | |||
509 | capability |= WLAN_CAPABILITY_IBSS; | ||
510 | |||
511 | if (ar->prwise_crypto == WEP_CRYPT) | ||
512 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
513 | |||
514 | memcpy(source_mac, ar->net_dev->dev_addr, ETH_ALEN); | ||
515 | ptr_ie_buf = ie_buf; | ||
516 | } else { | ||
517 | capability = *(u16 *) (&assoc_info[beacon_ie_len]); | ||
518 | memcpy(source_mac, bssid, ETH_ALEN); | ||
519 | ptr_ie_buf = assoc_req_ie; | ||
520 | ie_buf_len = assoc_req_len; | ||
521 | } | ||
522 | |||
523 | size = offsetof(struct ieee80211_mgmt, u) | ||
524 | + sizeof(mgmt->u.beacon) | ||
525 | + ie_buf_len; | ||
526 | |||
527 | ieeemgmtbuf = kzalloc(size, GFP_ATOMIC); | ||
528 | if (!ieeemgmtbuf) { | ||
529 | ath6kl_err("ieee mgmt buf alloc error\n"); | ||
530 | cfg80211_put_bss(bss); | ||
531 | return; | 515 | return; |
532 | } | 516 | } |
533 | 517 | ||
534 | mgmt = (struct ieee80211_mgmt *)ieeemgmtbuf; | 518 | if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info, |
535 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 519 | beacon_ie_len) < 0) { |
536 | IEEE80211_STYPE_BEACON); | 520 | ath6kl_err("could not add cfg80211 bss entry for " |
537 | memset(mgmt->da, 0xff, ETH_ALEN); /* broadcast addr */ | 521 | "connect/roamed notification\n"); |
538 | memcpy(mgmt->sa, source_mac, ETH_ALEN); | ||
539 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
540 | mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_intvl); | ||
541 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); | ||
542 | memcpy(mgmt->u.beacon.variable, ptr_ie_buf, ie_buf_len); | ||
543 | |||
544 | ibss_ch = ieee80211_get_channel(ar->wdev->wiphy, (int)channel); | ||
545 | |||
546 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
547 | "%s: inform bss with bssid %pM channel %d beacon_intvl %d capability 0x%x\n", | ||
548 | __func__, mgmt->bssid, ibss_ch->hw_value, | ||
549 | beacon_intvl, capability); | ||
550 | |||
551 | bss = cfg80211_inform_bss_frame(ar->wdev->wiphy, | ||
552 | ibss_ch, mgmt, | ||
553 | size, signal, GFP_KERNEL); | ||
554 | kfree(ieeemgmtbuf); | ||
555 | cfg80211_put_bss(bss); | ||
556 | |||
557 | if (nw_type & ADHOC_NETWORK) { | ||
558 | cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); | ||
559 | return; | 522 | return; |
560 | } | 523 | } |
561 | 524 | ||
@@ -568,7 +531,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | |||
568 | WLAN_STATUS_SUCCESS, GFP_KERNEL); | 531 | WLAN_STATUS_SUCCESS, GFP_KERNEL); |
569 | } else if (ar->sme_state == SME_CONNECTED) { | 532 | } else if (ar->sme_state == SME_CONNECTED) { |
570 | /* inform roam event to cfg80211 */ | 533 | /* inform roam event to cfg80211 */ |
571 | cfg80211_roamed(ar->net_dev, ibss_ch, bssid, | 534 | cfg80211_roamed(ar->net_dev, chan, bssid, |
572 | assoc_req_ie, assoc_req_len, | 535 | assoc_req_ie, assoc_req_len, |
573 | assoc_resp_ie, assoc_resp_len, GFP_KERNEL); | 536 | assoc_resp_ie, assoc_resp_len, GFP_KERNEL); |
574 | } | 537 | } |
@@ -605,6 +568,8 @@ static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy, | |||
605 | 568 | ||
606 | up(&ar->sem); | 569 | up(&ar->sem); |
607 | 570 | ||
571 | ar->sme_state = SME_DISCONNECTED; | ||
572 | |||
608 | return 0; | 573 | return 0; |
609 | } | 574 | } |
610 | 575 | ||
@@ -612,9 +577,6 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason, | |||
612 | u8 *bssid, u8 assoc_resp_len, | 577 | u8 *bssid, u8 assoc_resp_len, |
613 | u8 *assoc_info, u16 proto_reason) | 578 | u8 *assoc_info, u16 proto_reason) |
614 | { | 579 | { |
615 | struct ath6kl_key *key = NULL; | ||
616 | u16 status; | ||
617 | |||
618 | if (ar->scan_req) { | 580 | if (ar->scan_req) { |
619 | cfg80211_scan_done(ar->scan_req, true); | 581 | cfg80211_scan_done(ar->scan_req, true); |
620 | ar->scan_req = NULL; | 582 | ar->scan_req = NULL; |
@@ -632,164 +594,64 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason, | |||
632 | } | 594 | } |
633 | 595 | ||
634 | if (ar->nw_type & INFRA_NETWORK) { | 596 | if (ar->nw_type & INFRA_NETWORK) { |
635 | if (ar->wdev->iftype != NL80211_IFTYPE_STATION) { | 597 | if (ar->wdev->iftype != NL80211_IFTYPE_STATION && |
598 | ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { | ||
636 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | 599 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
637 | "%s: ath6k not in station mode\n", __func__); | 600 | "%s: ath6k not in station mode\n", __func__); |
638 | return; | 601 | return; |
639 | } | 602 | } |
640 | } | 603 | } |
641 | 604 | ||
642 | if (!test_bit(CONNECT_PEND, &ar->flag)) { | ||
643 | if (reason != DISCONNECT_CMD) | ||
644 | ath6kl_wmi_disconnect_cmd(ar->wmi); | ||
645 | |||
646 | return; | ||
647 | } | ||
648 | |||
649 | if (reason == NO_NETWORK_AVAIL) { | ||
650 | /* connect cmd failed */ | ||
651 | ath6kl_wmi_disconnect_cmd(ar->wmi); | ||
652 | return; | ||
653 | } | ||
654 | |||
655 | if (reason != DISCONNECT_CMD) | ||
656 | return; | ||
657 | |||
658 | if (!ar->auto_auth_stage) { | ||
659 | clear_bit(CONNECT_PEND, &ar->flag); | ||
660 | |||
661 | if (ar->sme_state == SME_CONNECTING) { | ||
662 | cfg80211_connect_result(ar->net_dev, | ||
663 | bssid, NULL, 0, | ||
664 | NULL, 0, | ||
665 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
666 | GFP_KERNEL); | ||
667 | } else { | ||
668 | cfg80211_disconnected(ar->net_dev, reason, | ||
669 | NULL, 0, GFP_KERNEL); | ||
670 | } | ||
671 | |||
672 | ar->sme_state = SME_DISCONNECTED; | ||
673 | return; | ||
674 | } | ||
675 | |||
676 | if (ar->dot11_auth_mode != OPEN_AUTH) | ||
677 | return; | ||
678 | |||
679 | /* | 605 | /* |
680 | * If the current auth algorithm is open, try shared and | 606 | * Send a disconnect command to target when a disconnect event is |
681 | * make autoAuthStage idle. We do not make it leap for now | 607 | * received with reason code other than 3 (DISCONNECT_CMD - disconnect |
682 | * being. | 608 | * request from host) to make the firmware stop trying to connect even |
609 | * after giving disconnect event. There will be one more disconnect | ||
610 | * event for this disconnect command with reason code DISCONNECT_CMD | ||
611 | * which will be notified to cfg80211. | ||
683 | */ | 612 | */ |
684 | key = &ar->keys[ar->def_txkey_index]; | ||
685 | if (down_interruptible(&ar->sem)) { | ||
686 | ath6kl_err("busy, couldn't get access\n"); | ||
687 | return; | ||
688 | } | ||
689 | |||
690 | ar->dot11_auth_mode = SHARED_AUTH; | ||
691 | ar->auto_auth_stage = AUTH_IDLE; | ||
692 | 613 | ||
693 | ath6kl_wmi_addkey_cmd(ar->wmi, | 614 | if (reason != DISCONNECT_CMD) { |
694 | ar->def_txkey_index, | 615 | ath6kl_wmi_disconnect_cmd(ar->wmi); |
695 | ar->prwise_crypto, | ||
696 | GROUP_USAGE | TX_USAGE, | ||
697 | key->key_len, NULL, | ||
698 | key->key, | ||
699 | KEY_OP_INIT_VAL, NULL, | ||
700 | NO_SYNC_WMIFLAG); | ||
701 | |||
702 | status = ath6kl_wmi_connect_cmd(ar->wmi, | ||
703 | ar->nw_type, | ||
704 | ar->dot11_auth_mode, | ||
705 | ar->auth_mode, | ||
706 | ar->prwise_crypto, | ||
707 | ar->prwise_crypto_len, | ||
708 | ar->grp_crypto, | ||
709 | ar->grp_crpto_len, | ||
710 | ar->ssid_len, | ||
711 | ar->ssid, | ||
712 | ar->req_bssid, | ||
713 | ar->ch_hint, | ||
714 | ar->connect_ctrl_flags); | ||
715 | up(&ar->sem); | ||
716 | } | ||
717 | |||
718 | static inline bool is_ch_11a(u16 ch) | ||
719 | { | ||
720 | return (!((ch >= 2412) && (ch <= 2484))); | ||
721 | } | ||
722 | |||
723 | /* struct ath6kl_node_table::nt_nodelock is locked when calling this */ | ||
724 | void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni) | ||
725 | { | ||
726 | u16 size; | ||
727 | unsigned char *ieeemgmtbuf = NULL; | ||
728 | struct ieee80211_mgmt *mgmt; | ||
729 | struct ieee80211_channel *channel; | ||
730 | struct ieee80211_supported_band *band; | ||
731 | struct ath6kl_common_ie *cie; | ||
732 | s32 signal; | ||
733 | int freq; | ||
734 | |||
735 | cie = &ni->ni_cie; | ||
736 | |||
737 | if (is_ch_11a(cie->ie_chan)) | ||
738 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; /* 11a */ | ||
739 | else if ((cie->ie_erp) || (cie->ie_xrates)) | ||
740 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11g */ | ||
741 | else | ||
742 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11b */ | ||
743 | |||
744 | size = ni->ni_framelen + offsetof(struct ieee80211_mgmt, u); | ||
745 | ieeemgmtbuf = kmalloc(size, GFP_ATOMIC); | ||
746 | if (!ieeemgmtbuf) { | ||
747 | ath6kl_err("ieee mgmt buf alloc error\n"); | ||
748 | return; | 616 | return; |
749 | } | 617 | } |
750 | 618 | ||
751 | /* | 619 | clear_bit(CONNECT_PEND, &ar->flag); |
752 | * TODO: Update target to include 802.11 mac header while sending | ||
753 | * bss info. Target removes 802.11 mac header while sending the bss | ||
754 | * info to host, cfg80211 needs it, for time being just filling the | ||
755 | * da, sa and bssid fields alone. | ||
756 | */ | ||
757 | mgmt = (struct ieee80211_mgmt *)ieeemgmtbuf; | ||
758 | memset(mgmt->da, 0xff, ETH_ALEN); /*broadcast addr */ | ||
759 | memcpy(mgmt->sa, ni->ni_macaddr, ETH_ALEN); | ||
760 | memcpy(mgmt->bssid, ni->ni_macaddr, ETH_ALEN); | ||
761 | memcpy(ieeemgmtbuf + offsetof(struct ieee80211_mgmt, u), | ||
762 | ni->ni_buf, ni->ni_framelen); | ||
763 | |||
764 | freq = cie->ie_chan; | ||
765 | channel = ieee80211_get_channel(wiphy, freq); | ||
766 | signal = ni->ni_snr * 100; | ||
767 | 620 | ||
768 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | 621 | if (ar->sme_state == SME_CONNECTING) { |
769 | "%s: bssid %pM ch %d freq %d size %d\n", __func__, | 622 | cfg80211_connect_result(ar->net_dev, |
770 | mgmt->bssid, channel->hw_value, freq, size); | 623 | bssid, NULL, 0, |
771 | cfg80211_inform_bss_frame(wiphy, channel, mgmt, | 624 | NULL, 0, |
772 | size, signal, GFP_ATOMIC); | 625 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
626 | GFP_KERNEL); | ||
627 | } else if (ar->sme_state == SME_CONNECTED) { | ||
628 | cfg80211_disconnected(ar->net_dev, reason, | ||
629 | NULL, 0, GFP_KERNEL); | ||
630 | } | ||
773 | 631 | ||
774 | kfree(ieeemgmtbuf); | 632 | ar->sme_state = SME_DISCONNECTED; |
775 | } | 633 | } |
776 | 634 | ||
777 | static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | 635 | static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, |
778 | struct cfg80211_scan_request *request) | 636 | struct cfg80211_scan_request *request) |
779 | { | 637 | { |
780 | struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); | 638 | struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); |
639 | s8 n_channels = 0; | ||
640 | u16 *channels = NULL; | ||
781 | int ret = 0; | 641 | int ret = 0; |
782 | 642 | ||
783 | if (!ath6kl_cfg80211_ready(ar)) | 643 | if (!ath6kl_cfg80211_ready(ar)) |
784 | return -EIO; | 644 | return -EIO; |
785 | 645 | ||
786 | if (!ar->usr_bss_filter) { | 646 | if (!ar->usr_bss_filter) { |
787 | if (ath6kl_wmi_bssfilter_cmd(ar->wmi, | 647 | clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); |
788 | (test_bit(CONNECTED, &ar->flag) ? | 648 | ret = ath6kl_wmi_bssfilter_cmd( |
789 | ALL_BUT_BSS_FILTER : | 649 | ar->wmi, |
790 | ALL_BSS_FILTER), 0) != 0) { | 650 | (test_bit(CONNECTED, &ar->flag) ? |
651 | ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0); | ||
652 | if (ret) { | ||
791 | ath6kl_err("couldn't set bss filtering\n"); | 653 | ath6kl_err("couldn't set bss filtering\n"); |
792 | return -EIO; | 654 | return ret; |
793 | } | 655 | } |
794 | } | 656 | } |
795 | 657 | ||
@@ -806,13 +668,46 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | |||
806 | request->ssids[i].ssid); | 668 | request->ssids[i].ssid); |
807 | } | 669 | } |
808 | 670 | ||
809 | if (ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0, | 671 | if (request->ie) { |
810 | false, 0, 0, 0, NULL) != 0) { | 672 | ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ, |
811 | ath6kl_err("wmi_startscan_cmd failed\n"); | 673 | request->ie, request->ie_len); |
812 | ret = -EIO; | 674 | if (ret) { |
675 | ath6kl_err("failed to set Probe Request appie for " | ||
676 | "scan"); | ||
677 | return ret; | ||
678 | } | ||
813 | } | 679 | } |
814 | 680 | ||
815 | ar->scan_req = request; | 681 | /* |
682 | * Scan only the requested channels if the request specifies a set of | ||
683 | * channels. If the list is longer than the target supports, do not | ||
684 | * configure the list and instead, scan all available channels. | ||
685 | */ | ||
686 | if (request->n_channels > 0 && | ||
687 | request->n_channels <= WMI_MAX_CHANNELS) { | ||
688 | u8 i; | ||
689 | |||
690 | n_channels = request->n_channels; | ||
691 | |||
692 | channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL); | ||
693 | if (channels == NULL) { | ||
694 | ath6kl_warn("failed to set scan channels, " | ||
695 | "scan all channels"); | ||
696 | n_channels = 0; | ||
697 | } | ||
698 | |||
699 | for (i = 0; i < n_channels; i++) | ||
700 | channels[i] = request->channels[i]->center_freq; | ||
701 | } | ||
702 | |||
703 | ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0, | ||
704 | false, 0, 0, n_channels, channels); | ||
705 | if (ret) | ||
706 | ath6kl_err("wmi_startscan_cmd failed\n"); | ||
707 | else | ||
708 | ar->scan_req = request; | ||
709 | |||
710 | kfree(channels); | ||
816 | 711 | ||
817 | return ret; | 712 | return ret; |
818 | } | 713 | } |
@@ -831,9 +726,6 @@ void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status) | |||
831 | goto out; | 726 | goto out; |
832 | } | 727 | } |
833 | 728 | ||
834 | /* Translate data to cfg80211 mgmt format */ | ||
835 | wlan_iterate_nodes(&ar->scan_table, ar->wdev->wiphy); | ||
836 | |||
837 | cfg80211_scan_done(ar->scan_req, false); | 729 | cfg80211_scan_done(ar->scan_req, false); |
838 | 730 | ||
839 | if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) { | 731 | if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) { |
@@ -918,6 +810,40 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
918 | key_usage, key->seq_len); | 810 | key_usage, key->seq_len); |
919 | 811 | ||
920 | ar->def_txkey_index = key_index; | 812 | ar->def_txkey_index = key_index; |
813 | |||
814 | if (ar->nw_type == AP_NETWORK && !pairwise && | ||
815 | (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) { | ||
816 | ar->ap_mode_bkey.valid = true; | ||
817 | ar->ap_mode_bkey.key_index = key_index; | ||
818 | ar->ap_mode_bkey.key_type = key_type; | ||
819 | ar->ap_mode_bkey.key_len = key->key_len; | ||
820 | memcpy(ar->ap_mode_bkey.key, key->key, key->key_len); | ||
821 | if (!test_bit(CONNECTED, &ar->flag)) { | ||
822 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group " | ||
823 | "key configuration until AP mode has been " | ||
824 | "started\n"); | ||
825 | /* | ||
826 | * The key will be set in ath6kl_connect_ap_mode() once | ||
827 | * the connected event is received from the target. | ||
828 | */ | ||
829 | return 0; | ||
830 | } | ||
831 | } | ||
832 | |||
833 | if (ar->next_mode == AP_NETWORK && key_type == WEP_CRYPT && | ||
834 | !test_bit(CONNECTED, &ar->flag)) { | ||
835 | /* | ||
836 | * Store the key locally so that it can be re-configured after | ||
837 | * the AP mode has properly started | ||
838 | * (ath6kl_install_statioc_wep_keys). | ||
839 | */ | ||
840 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration " | ||
841 | "until AP mode has been started\n"); | ||
842 | ar->wep_key_list[key_index].key_len = key->key_len; | ||
843 | memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len); | ||
844 | return 0; | ||
845 | } | ||
846 | |||
921 | status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, | 847 | status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, |
922 | key_type, key_usage, key->key_len, | 848 | key_type, key_usage, key->key_len, |
923 | key->seq, key->key, KEY_OP_INIT_VAL, | 849 | key->seq, key->key, KEY_OP_INIT_VAL, |
@@ -1002,6 +928,7 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy, | |||
1002 | struct ath6kl_key *key = NULL; | 928 | struct ath6kl_key *key = NULL; |
1003 | int status = 0; | 929 | int status = 0; |
1004 | u8 key_usage; | 930 | u8 key_usage; |
931 | enum crypto_type key_type = NONE_CRYPT; | ||
1005 | 932 | ||
1006 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index); | 933 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index); |
1007 | 934 | ||
@@ -1026,9 +953,16 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy, | |||
1026 | key_usage = GROUP_USAGE; | 953 | key_usage = GROUP_USAGE; |
1027 | if (ar->prwise_crypto == WEP_CRYPT) | 954 | if (ar->prwise_crypto == WEP_CRYPT) |
1028 | key_usage |= TX_USAGE; | 955 | key_usage |= TX_USAGE; |
956 | if (unicast) | ||
957 | key_type = ar->prwise_crypto; | ||
958 | if (multicast) | ||
959 | key_type = ar->grp_crypto; | ||
960 | |||
961 | if (ar->next_mode == AP_NETWORK && !test_bit(CONNECTED, &ar->flag)) | ||
962 | return 0; /* Delay until AP mode has been started */ | ||
1029 | 963 | ||
1030 | status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, | 964 | status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, |
1031 | ar->prwise_crypto, key_usage, | 965 | key_type, key_usage, |
1032 | key->key_len, key->seq, key->key, | 966 | key->key_len, key->seq, key->key, |
1033 | KEY_OP_INIT_VAL, NULL, | 967 | KEY_OP_INIT_VAL, NULL, |
1034 | SYNC_BOTH_WMIFLAG); | 968 | SYNC_BOTH_WMIFLAG); |
@@ -1183,6 +1117,15 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, | |||
1183 | case NL80211_IFTYPE_ADHOC: | 1117 | case NL80211_IFTYPE_ADHOC: |
1184 | ar->next_mode = ADHOC_NETWORK; | 1118 | ar->next_mode = ADHOC_NETWORK; |
1185 | break; | 1119 | break; |
1120 | case NL80211_IFTYPE_AP: | ||
1121 | ar->next_mode = AP_NETWORK; | ||
1122 | break; | ||
1123 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1124 | ar->next_mode = INFRA_NETWORK; | ||
1125 | break; | ||
1126 | case NL80211_IFTYPE_P2P_GO: | ||
1127 | ar->next_mode = AP_NETWORK; | ||
1128 | break; | ||
1186 | default: | 1129 | default: |
1187 | ath6kl_err("invalid interface type %u\n", type); | 1130 | ath6kl_err("invalid interface type %u\n", type); |
1188 | return -EOPNOTSUPP; | 1131 | return -EOPNOTSUPP; |
@@ -1246,13 +1189,13 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy, | |||
1246 | __func__, | 1189 | __func__, |
1247 | ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto, | 1190 | ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto, |
1248 | ar->prwise_crypto_len, ar->grp_crypto, | 1191 | ar->prwise_crypto_len, ar->grp_crypto, |
1249 | ar->grp_crpto_len, ar->ch_hint); | 1192 | ar->grp_crypto_len, ar->ch_hint); |
1250 | 1193 | ||
1251 | status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type, | 1194 | status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type, |
1252 | ar->dot11_auth_mode, ar->auth_mode, | 1195 | ar->dot11_auth_mode, ar->auth_mode, |
1253 | ar->prwise_crypto, | 1196 | ar->prwise_crypto, |
1254 | ar->prwise_crypto_len, | 1197 | ar->prwise_crypto_len, |
1255 | ar->grp_crypto, ar->grp_crpto_len, | 1198 | ar->grp_crypto, ar->grp_crypto_len, |
1256 | ar->ssid_len, ar->ssid, | 1199 | ar->ssid_len, ar->ssid, |
1257 | ar->req_bssid, ar->ch_hint, | 1200 | ar->req_bssid, ar->ch_hint, |
1258 | ar->connect_ctrl_flags); | 1201 | ar->connect_ctrl_flags); |
@@ -1422,12 +1365,23 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
1422 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 1365 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
1423 | sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; | 1366 | sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; |
1424 | } else { | 1367 | } else { |
1425 | ath6kl_warn("invalid rate: %d\n", rate); | 1368 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
1369 | "invalid rate from stats: %d\n", rate); | ||
1370 | ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE); | ||
1426 | return 0; | 1371 | return 0; |
1427 | } | 1372 | } |
1428 | 1373 | ||
1429 | sinfo->filled |= STATION_INFO_TX_BITRATE; | 1374 | sinfo->filled |= STATION_INFO_TX_BITRATE; |
1430 | 1375 | ||
1376 | if (test_bit(CONNECTED, &ar->flag) && | ||
1377 | test_bit(DTIM_PERIOD_AVAIL, &ar->flag) && | ||
1378 | ar->nw_type == INFRA_NETWORK) { | ||
1379 | sinfo->filled |= STATION_INFO_BSS_PARAM; | ||
1380 | sinfo->bss_param.flags = 0; | ||
1381 | sinfo->bss_param.dtim_period = ar->assoc_bss_dtim_period; | ||
1382 | sinfo->bss_param.beacon_interval = ar->assoc_bss_beacon_int; | ||
1383 | } | ||
1384 | |||
1431 | return 0; | 1385 | return 0; |
1432 | } | 1386 | } |
1433 | 1387 | ||
@@ -1455,6 +1409,402 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) | |||
1455 | return 0; | 1409 | return 0; |
1456 | } | 1410 | } |
1457 | 1411 | ||
1412 | #ifdef CONFIG_PM | ||
1413 | static int ar6k_cfg80211_suspend(struct wiphy *wiphy, | ||
1414 | struct cfg80211_wowlan *wow) | ||
1415 | { | ||
1416 | struct ath6kl *ar = wiphy_priv(wiphy); | ||
1417 | |||
1418 | return ath6kl_hif_suspend(ar); | ||
1419 | } | ||
1420 | #endif | ||
1421 | |||
1422 | static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, | ||
1423 | struct ieee80211_channel *chan, | ||
1424 | enum nl80211_channel_type channel_type) | ||
1425 | { | ||
1426 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1427 | |||
1428 | if (!ath6kl_cfg80211_ready(ar)) | ||
1429 | return -EIO; | ||
1430 | |||
1431 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", | ||
1432 | __func__, chan->center_freq, chan->hw_value); | ||
1433 | ar->next_chan = chan->center_freq; | ||
1434 | |||
1435 | return 0; | ||
1436 | } | ||
1437 | |||
1438 | static bool ath6kl_is_p2p_ie(const u8 *pos) | ||
1439 | { | ||
1440 | return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && | ||
1441 | pos[2] == 0x50 && pos[3] == 0x6f && | ||
1442 | pos[4] == 0x9a && pos[5] == 0x09; | ||
1443 | } | ||
1444 | |||
1445 | static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies, | ||
1446 | size_t ies_len) | ||
1447 | { | ||
1448 | const u8 *pos; | ||
1449 | u8 *buf = NULL; | ||
1450 | size_t len = 0; | ||
1451 | int ret; | ||
1452 | |||
1453 | /* | ||
1454 | * Filter out P2P IE(s) since they will be included depending on | ||
1455 | * the Probe Request frame in ath6kl_send_go_probe_resp(). | ||
1456 | */ | ||
1457 | |||
1458 | if (ies && ies_len) { | ||
1459 | buf = kmalloc(ies_len, GFP_KERNEL); | ||
1460 | if (buf == NULL) | ||
1461 | return -ENOMEM; | ||
1462 | pos = ies; | ||
1463 | while (pos + 1 < ies + ies_len) { | ||
1464 | if (pos + 2 + pos[1] > ies + ies_len) | ||
1465 | break; | ||
1466 | if (!ath6kl_is_p2p_ie(pos)) { | ||
1467 | memcpy(buf + len, pos, 2 + pos[1]); | ||
1468 | len += 2 + pos[1]; | ||
1469 | } | ||
1470 | pos += 2 + pos[1]; | ||
1471 | } | ||
1472 | } | ||
1473 | |||
1474 | ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP, | ||
1475 | buf, len); | ||
1476 | kfree(buf); | ||
1477 | return ret; | ||
1478 | } | ||
1479 | |||
1480 | static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, | ||
1481 | struct beacon_parameters *info, bool add) | ||
1482 | { | ||
1483 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1484 | struct ieee80211_mgmt *mgmt; | ||
1485 | u8 *ies; | ||
1486 | int ies_len; | ||
1487 | struct wmi_connect_cmd p; | ||
1488 | int res; | ||
1489 | int i; | ||
1490 | |||
1491 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add); | ||
1492 | |||
1493 | if (!ath6kl_cfg80211_ready(ar)) | ||
1494 | return -EIO; | ||
1495 | |||
1496 | if (ar->next_mode != AP_NETWORK) | ||
1497 | return -EOPNOTSUPP; | ||
1498 | |||
1499 | if (info->beacon_ies) { | ||
1500 | res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON, | ||
1501 | info->beacon_ies, | ||
1502 | info->beacon_ies_len); | ||
1503 | if (res) | ||
1504 | return res; | ||
1505 | } | ||
1506 | if (info->proberesp_ies) { | ||
1507 | res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies, | ||
1508 | info->proberesp_ies_len); | ||
1509 | if (res) | ||
1510 | return res; | ||
1511 | } | ||
1512 | if (info->assocresp_ies) { | ||
1513 | res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP, | ||
1514 | info->assocresp_ies, | ||
1515 | info->assocresp_ies_len); | ||
1516 | if (res) | ||
1517 | return res; | ||
1518 | } | ||
1519 | |||
1520 | if (!add) | ||
1521 | return 0; | ||
1522 | |||
1523 | ar->ap_mode_bkey.valid = false; | ||
1524 | |||
1525 | /* TODO: | ||
1526 | * info->interval | ||
1527 | * info->dtim_period | ||
1528 | */ | ||
1529 | |||
1530 | if (info->head == NULL) | ||
1531 | return -EINVAL; | ||
1532 | mgmt = (struct ieee80211_mgmt *) info->head; | ||
1533 | ies = mgmt->u.beacon.variable; | ||
1534 | if (ies > info->head + info->head_len) | ||
1535 | return -EINVAL; | ||
1536 | ies_len = info->head + info->head_len - ies; | ||
1537 | |||
1538 | if (info->ssid == NULL) | ||
1539 | return -EINVAL; | ||
1540 | memcpy(ar->ssid, info->ssid, info->ssid_len); | ||
1541 | ar->ssid_len = info->ssid_len; | ||
1542 | if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) | ||
1543 | return -EOPNOTSUPP; /* TODO */ | ||
1544 | |||
1545 | ar->dot11_auth_mode = OPEN_AUTH; | ||
1546 | |||
1547 | memset(&p, 0, sizeof(p)); | ||
1548 | |||
1549 | for (i = 0; i < info->crypto.n_akm_suites; i++) { | ||
1550 | switch (info->crypto.akm_suites[i]) { | ||
1551 | case WLAN_AKM_SUITE_8021X: | ||
1552 | if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1) | ||
1553 | p.auth_mode |= WPA_AUTH; | ||
1554 | if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2) | ||
1555 | p.auth_mode |= WPA2_AUTH; | ||
1556 | break; | ||
1557 | case WLAN_AKM_SUITE_PSK: | ||
1558 | if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1) | ||
1559 | p.auth_mode |= WPA_PSK_AUTH; | ||
1560 | if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2) | ||
1561 | p.auth_mode |= WPA2_PSK_AUTH; | ||
1562 | break; | ||
1563 | } | ||
1564 | } | ||
1565 | if (p.auth_mode == 0) | ||
1566 | p.auth_mode = NONE_AUTH; | ||
1567 | ar->auth_mode = p.auth_mode; | ||
1568 | |||
1569 | for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) { | ||
1570 | switch (info->crypto.ciphers_pairwise[i]) { | ||
1571 | case WLAN_CIPHER_SUITE_WEP40: | ||
1572 | case WLAN_CIPHER_SUITE_WEP104: | ||
1573 | p.prwise_crypto_type |= WEP_CRYPT; | ||
1574 | break; | ||
1575 | case WLAN_CIPHER_SUITE_TKIP: | ||
1576 | p.prwise_crypto_type |= TKIP_CRYPT; | ||
1577 | break; | ||
1578 | case WLAN_CIPHER_SUITE_CCMP: | ||
1579 | p.prwise_crypto_type |= AES_CRYPT; | ||
1580 | break; | ||
1581 | } | ||
1582 | } | ||
1583 | if (p.prwise_crypto_type == 0) { | ||
1584 | p.prwise_crypto_type = NONE_CRYPT; | ||
1585 | ath6kl_set_cipher(ar, 0, true); | ||
1586 | } else if (info->crypto.n_ciphers_pairwise == 1) | ||
1587 | ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true); | ||
1588 | |||
1589 | switch (info->crypto.cipher_group) { | ||
1590 | case WLAN_CIPHER_SUITE_WEP40: | ||
1591 | case WLAN_CIPHER_SUITE_WEP104: | ||
1592 | p.grp_crypto_type = WEP_CRYPT; | ||
1593 | break; | ||
1594 | case WLAN_CIPHER_SUITE_TKIP: | ||
1595 | p.grp_crypto_type = TKIP_CRYPT; | ||
1596 | break; | ||
1597 | case WLAN_CIPHER_SUITE_CCMP: | ||
1598 | p.grp_crypto_type = AES_CRYPT; | ||
1599 | break; | ||
1600 | default: | ||
1601 | p.grp_crypto_type = NONE_CRYPT; | ||
1602 | break; | ||
1603 | } | ||
1604 | ath6kl_set_cipher(ar, info->crypto.cipher_group, false); | ||
1605 | |||
1606 | p.nw_type = AP_NETWORK; | ||
1607 | ar->nw_type = ar->next_mode; | ||
1608 | |||
1609 | p.ssid_len = ar->ssid_len; | ||
1610 | memcpy(p.ssid, ar->ssid, ar->ssid_len); | ||
1611 | p.dot11_auth_mode = ar->dot11_auth_mode; | ||
1612 | p.ch = cpu_to_le16(ar->next_chan); | ||
1613 | |||
1614 | res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p); | ||
1615 | if (res < 0) | ||
1616 | return res; | ||
1617 | |||
1618 | return 0; | ||
1619 | } | ||
1620 | |||
1621 | static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev, | ||
1622 | struct beacon_parameters *info) | ||
1623 | { | ||
1624 | return ath6kl_ap_beacon(wiphy, dev, info, true); | ||
1625 | } | ||
1626 | |||
1627 | static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev, | ||
1628 | struct beacon_parameters *info) | ||
1629 | { | ||
1630 | return ath6kl_ap_beacon(wiphy, dev, info, false); | ||
1631 | } | ||
1632 | |||
1633 | static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) | ||
1634 | { | ||
1635 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1636 | |||
1637 | if (ar->nw_type != AP_NETWORK) | ||
1638 | return -EOPNOTSUPP; | ||
1639 | if (!test_bit(CONNECTED, &ar->flag)) | ||
1640 | return -ENOTCONN; | ||
1641 | |||
1642 | ath6kl_wmi_disconnect_cmd(ar->wmi); | ||
1643 | clear_bit(CONNECTED, &ar->flag); | ||
1644 | |||
1645 | return 0; | ||
1646 | } | ||
1647 | |||
1648 | static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, | ||
1649 | u8 *mac, struct station_parameters *params) | ||
1650 | { | ||
1651 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1652 | |||
1653 | if (ar->nw_type != AP_NETWORK) | ||
1654 | return -EOPNOTSUPP; | ||
1655 | |||
1656 | /* Use this only for authorizing/unauthorizing a station */ | ||
1657 | if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) | ||
1658 | return -EOPNOTSUPP; | ||
1659 | |||
1660 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
1661 | return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE, | ||
1662 | mac, 0); | ||
1663 | return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac, | ||
1664 | 0); | ||
1665 | } | ||
1666 | |||
1667 | static int ath6kl_remain_on_channel(struct wiphy *wiphy, | ||
1668 | struct net_device *dev, | ||
1669 | struct ieee80211_channel *chan, | ||
1670 | enum nl80211_channel_type channel_type, | ||
1671 | unsigned int duration, | ||
1672 | u64 *cookie) | ||
1673 | { | ||
1674 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1675 | |||
1676 | /* TODO: if already pending or ongoing remain-on-channel, | ||
1677 | * return -EBUSY */ | ||
1678 | *cookie = 1; /* only a single pending request is supported */ | ||
1679 | |||
1680 | return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq, | ||
1681 | duration); | ||
1682 | } | ||
1683 | |||
1684 | static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy, | ||
1685 | struct net_device *dev, | ||
1686 | u64 cookie) | ||
1687 | { | ||
1688 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1689 | |||
1690 | if (cookie != 1) | ||
1691 | return -ENOENT; | ||
1692 | |||
1693 | return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi); | ||
1694 | } | ||
1695 | |||
1696 | static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf, | ||
1697 | size_t len, unsigned int freq) | ||
1698 | { | ||
1699 | const u8 *pos; | ||
1700 | u8 *p2p; | ||
1701 | int p2p_len; | ||
1702 | int ret; | ||
1703 | const struct ieee80211_mgmt *mgmt; | ||
1704 | |||
1705 | mgmt = (const struct ieee80211_mgmt *) buf; | ||
1706 | |||
1707 | /* Include P2P IE(s) from the frame generated in user space. */ | ||
1708 | |||
1709 | p2p = kmalloc(len, GFP_KERNEL); | ||
1710 | if (p2p == NULL) | ||
1711 | return -ENOMEM; | ||
1712 | p2p_len = 0; | ||
1713 | |||
1714 | pos = mgmt->u.probe_resp.variable; | ||
1715 | while (pos + 1 < buf + len) { | ||
1716 | if (pos + 2 + pos[1] > buf + len) | ||
1717 | break; | ||
1718 | if (ath6kl_is_p2p_ie(pos)) { | ||
1719 | memcpy(p2p + p2p_len, pos, 2 + pos[1]); | ||
1720 | p2p_len += 2 + pos[1]; | ||
1721 | } | ||
1722 | pos += 2 + pos[1]; | ||
1723 | } | ||
1724 | |||
1725 | ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da, | ||
1726 | p2p, p2p_len); | ||
1727 | kfree(p2p); | ||
1728 | return ret; | ||
1729 | } | ||
1730 | |||
1731 | static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | ||
1732 | struct ieee80211_channel *chan, bool offchan, | ||
1733 | enum nl80211_channel_type channel_type, | ||
1734 | bool channel_type_valid, unsigned int wait, | ||
1735 | const u8 *buf, size_t len, bool no_cck, u64 *cookie) | ||
1736 | { | ||
1737 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1738 | u32 id; | ||
1739 | const struct ieee80211_mgmt *mgmt; | ||
1740 | |||
1741 | mgmt = (const struct ieee80211_mgmt *) buf; | ||
1742 | if (buf + len >= mgmt->u.probe_resp.variable && | ||
1743 | ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) && | ||
1744 | ieee80211_is_probe_resp(mgmt->frame_control)) { | ||
1745 | /* | ||
1746 | * Send Probe Response frame in AP mode using a separate WMI | ||
1747 | * command to allow the target to fill in the generic IEs. | ||
1748 | */ | ||
1749 | *cookie = 0; /* TX status not supported */ | ||
1750 | return ath6kl_send_go_probe_resp(ar, buf, len, | ||
1751 | chan->center_freq); | ||
1752 | } | ||
1753 | |||
1754 | id = ar->send_action_id++; | ||
1755 | if (id == 0) { | ||
1756 | /* | ||
1757 | * 0 is a reserved value in the WMI command and shall not be | ||
1758 | * used for the command. | ||
1759 | */ | ||
1760 | id = ar->send_action_id++; | ||
1761 | } | ||
1762 | |||
1763 | *cookie = id; | ||
1764 | return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait, | ||
1765 | buf, len); | ||
1766 | } | ||
1767 | |||
1768 | static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, | ||
1769 | struct net_device *dev, | ||
1770 | u16 frame_type, bool reg) | ||
1771 | { | ||
1772 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1773 | |||
1774 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n", | ||
1775 | __func__, frame_type, reg); | ||
1776 | if (frame_type == IEEE80211_STYPE_PROBE_REQ) { | ||
1777 | /* | ||
1778 | * Note: This notification callback is not allowed to sleep, so | ||
1779 | * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we | ||
1780 | * hardcode target to report Probe Request frames all the time. | ||
1781 | */ | ||
1782 | ar->probe_req_report = reg; | ||
1783 | } | ||
1784 | } | ||
1785 | |||
1786 | static const struct ieee80211_txrx_stypes | ||
1787 | ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { | ||
1788 | [NL80211_IFTYPE_STATION] = { | ||
1789 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
1790 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
1791 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
1792 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
1793 | }, | ||
1794 | [NL80211_IFTYPE_P2P_CLIENT] = { | ||
1795 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
1796 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
1797 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
1798 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
1799 | }, | ||
1800 | [NL80211_IFTYPE_P2P_GO] = { | ||
1801 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
1802 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
1803 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
1804 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
1805 | }, | ||
1806 | }; | ||
1807 | |||
1458 | static struct cfg80211_ops ath6kl_cfg80211_ops = { | 1808 | static struct cfg80211_ops ath6kl_cfg80211_ops = { |
1459 | .change_virtual_intf = ath6kl_cfg80211_change_iface, | 1809 | .change_virtual_intf = ath6kl_cfg80211_change_iface, |
1460 | .scan = ath6kl_cfg80211_scan, | 1810 | .scan = ath6kl_cfg80211_scan, |
@@ -1474,12 +1824,26 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { | |||
1474 | .set_pmksa = ath6kl_set_pmksa, | 1824 | .set_pmksa = ath6kl_set_pmksa, |
1475 | .del_pmksa = ath6kl_del_pmksa, | 1825 | .del_pmksa = ath6kl_del_pmksa, |
1476 | .flush_pmksa = ath6kl_flush_pmksa, | 1826 | .flush_pmksa = ath6kl_flush_pmksa, |
1827 | CFG80211_TESTMODE_CMD(ath6kl_tm_cmd) | ||
1828 | #ifdef CONFIG_PM | ||
1829 | .suspend = ar6k_cfg80211_suspend, | ||
1830 | #endif | ||
1831 | .set_channel = ath6kl_set_channel, | ||
1832 | .add_beacon = ath6kl_add_beacon, | ||
1833 | .set_beacon = ath6kl_set_beacon, | ||
1834 | .del_beacon = ath6kl_del_beacon, | ||
1835 | .change_station = ath6kl_change_station, | ||
1836 | .remain_on_channel = ath6kl_remain_on_channel, | ||
1837 | .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel, | ||
1838 | .mgmt_tx = ath6kl_mgmt_tx, | ||
1839 | .mgmt_frame_register = ath6kl_mgmt_frame_register, | ||
1477 | }; | 1840 | }; |
1478 | 1841 | ||
1479 | struct wireless_dev *ath6kl_cfg80211_init(struct device *dev) | 1842 | struct wireless_dev *ath6kl_cfg80211_init(struct device *dev) |
1480 | { | 1843 | { |
1481 | int ret = 0; | 1844 | int ret = 0; |
1482 | struct wireless_dev *wdev; | 1845 | struct wireless_dev *wdev; |
1846 | struct ath6kl *ar; | ||
1483 | 1847 | ||
1484 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | 1848 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); |
1485 | if (!wdev) { | 1849 | if (!wdev) { |
@@ -1495,13 +1859,25 @@ struct wireless_dev *ath6kl_cfg80211_init(struct device *dev) | |||
1495 | return NULL; | 1859 | return NULL; |
1496 | } | 1860 | } |
1497 | 1861 | ||
1862 | ar = wiphy_priv(wdev->wiphy); | ||
1863 | ar->p2p = !!ath6kl_p2p; | ||
1864 | |||
1865 | wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes; | ||
1866 | |||
1867 | wdev->wiphy->max_remain_on_channel_duration = 5000; | ||
1868 | |||
1498 | /* set device pointer for wiphy */ | 1869 | /* set device pointer for wiphy */ |
1499 | set_wiphy_dev(wdev->wiphy, dev); | 1870 | set_wiphy_dev(wdev->wiphy, dev); |
1500 | 1871 | ||
1501 | wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | 1872 | wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
1502 | BIT(NL80211_IFTYPE_ADHOC); | 1873 | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); |
1874 | if (ar->p2p) { | ||
1875 | wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) | | ||
1876 | BIT(NL80211_IFTYPE_P2P_CLIENT); | ||
1877 | } | ||
1503 | /* max num of ssids that can be probed during scanning */ | 1878 | /* max num of ssids that can be probed during scanning */ |
1504 | wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; | 1879 | wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; |
1880 | wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ | ||
1505 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; | 1881 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; |
1506 | wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; | 1882 | wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; |
1507 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 1883 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h index 6b0d45642fe3..b92f0e5d2336 100644 --- a/drivers/net/wireless/ath/ath6kl/common.h +++ b/drivers/net/wireless/ath/ath6kl/common.h | |||
@@ -75,94 +75,11 @@ enum crypto_type { | |||
75 | AES_CRYPT = 0x08, | 75 | AES_CRYPT = 0x08, |
76 | }; | 76 | }; |
77 | 77 | ||
78 | #define ATH6KL_NODE_HASHSIZE 32 | ||
79 | /* simple hash is enough for variation of macaddr */ | ||
80 | #define ATH6KL_NODE_HASH(addr) \ | ||
81 | (((const u8 *)(addr))[ETH_ALEN - 1] % \ | ||
82 | ATH6KL_NODE_HASHSIZE) | ||
83 | |||
84 | /* | ||
85 | * Table of ath6kl_node instances. Each ieee80211com | ||
86 | * has at least one for holding the scan candidates. | ||
87 | * When operating as an access point or in ibss mode there | ||
88 | * is a second table for associated stations or neighbors. | ||
89 | */ | ||
90 | struct ath6kl_node_table { | ||
91 | spinlock_t nt_nodelock; /* on node table */ | ||
92 | struct bss *nt_node_first; /* information of all nodes */ | ||
93 | struct bss *nt_node_last; /* information of all nodes */ | ||
94 | struct bss *nt_hash[ATH6KL_NODE_HASHSIZE]; | ||
95 | const char *nt_name; /* for debugging */ | ||
96 | u32 nt_node_age; /* node aging time */ | ||
97 | }; | ||
98 | |||
99 | #define WLAN_NODE_INACT_TIMEOUT_MSEC 120000 | ||
100 | #define WLAN_NODE_INACT_CNT 4 | ||
101 | |||
102 | struct ath6kl_common_ie { | ||
103 | u16 ie_chan; | ||
104 | u8 *ie_tstamp; | ||
105 | u8 *ie_ssid; | ||
106 | u8 *ie_rates; | ||
107 | u8 *ie_xrates; | ||
108 | u8 *ie_country; | ||
109 | u8 *ie_wpa; | ||
110 | u8 *ie_rsn; | ||
111 | u8 *ie_wmm; | ||
112 | u8 *ie_ath; | ||
113 | u16 ie_capInfo; | ||
114 | u16 ie_beaconInt; | ||
115 | u8 *ie_tim; | ||
116 | u8 *ie_chswitch; | ||
117 | u8 ie_erp; | ||
118 | u8 *ie_wsc; | ||
119 | u8 *ie_htcap; | ||
120 | u8 *ie_htop; | ||
121 | }; | ||
122 | |||
123 | struct bss { | ||
124 | u8 ni_macaddr[ETH_ALEN]; | ||
125 | u8 ni_snr; | ||
126 | s16 ni_rssi; | ||
127 | struct bss *ni_list_next; | ||
128 | struct bss *ni_list_prev; | ||
129 | struct bss *ni_hash_next; | ||
130 | struct bss *ni_hash_prev; | ||
131 | struct ath6kl_common_ie ni_cie; | ||
132 | u8 *ni_buf; | ||
133 | u16 ni_framelen; | ||
134 | struct ath6kl_node_table *ni_table; | ||
135 | u32 ni_refcnt; | ||
136 | |||
137 | u32 ni_tstamp; | ||
138 | u32 ni_actcnt; | ||
139 | }; | ||
140 | |||
141 | struct htc_endpoint_credit_dist; | 78 | struct htc_endpoint_credit_dist; |
142 | struct ath6kl; | 79 | struct ath6kl; |
143 | enum htc_credit_dist_reason; | 80 | enum htc_credit_dist_reason; |
144 | struct htc_credit_state_info; | 81 | struct htc_credit_state_info; |
145 | 82 | ||
146 | struct bss *wlan_node_alloc(int wh_size); | ||
147 | void wlan_node_free(struct bss *ni); | ||
148 | void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni, | ||
149 | const u8 *mac_addr); | ||
150 | struct bss *wlan_find_node(struct ath6kl_node_table *nt, | ||
151 | const u8 *mac_addr); | ||
152 | void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni); | ||
153 | void wlan_free_allnodes(struct ath6kl_node_table *nt); | ||
154 | void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg); | ||
155 | |||
156 | void wlan_node_table_init(struct ath6kl_node_table *nt); | ||
157 | void wlan_node_table_cleanup(struct ath6kl_node_table *nt); | ||
158 | |||
159 | void wlan_refresh_inactive_nodes(struct ath6kl *ar); | ||
160 | |||
161 | struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 *ssid, | ||
162 | u32 ssid_len, bool is_wpa2, bool match_ssid); | ||
163 | |||
164 | void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni); | ||
165 | |||
166 | int ath6k_setup_credit_dist(void *htc_handle, | 83 | int ath6k_setup_credit_dist(void *htc_handle, |
167 | struct htc_credit_state_info *cred_info); | 84 | struct htc_credit_state_info *cred_info); |
168 | void ath6k_credit_distribute(struct htc_credit_state_info *cred_inf, | 85 | void ath6k_credit_distribute(struct htc_credit_state_info *cred_inf, |
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 74170229523f..6d8a4845baaf 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h | |||
@@ -21,10 +21,12 @@ | |||
21 | #include <linux/rtnetlink.h> | 21 | #include <linux/rtnetlink.h> |
22 | #include <linux/firmware.h> | 22 | #include <linux/firmware.h> |
23 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
24 | #include <linux/circ_buf.h> | ||
24 | #include <net/cfg80211.h> | 25 | #include <net/cfg80211.h> |
25 | #include "htc.h" | 26 | #include "htc.h" |
26 | #include "wmi.h" | 27 | #include "wmi.h" |
27 | #include "bmi.h" | 28 | #include "bmi.h" |
29 | #include "target.h" | ||
28 | 30 | ||
29 | #define MAX_ATH6KL 1 | 31 | #define MAX_ATH6KL 1 |
30 | #define ATH6KL_MAX_RX_BUFFERS 16 | 32 | #define ATH6KL_MAX_RX_BUFFERS 16 |
@@ -42,6 +44,9 @@ | |||
42 | #define ATH6KL_MAX_ENDPOINTS 4 | 44 | #define ATH6KL_MAX_ENDPOINTS 4 |
43 | #define MAX_NODE_NUM 15 | 45 | #define MAX_NODE_NUM 15 |
44 | 46 | ||
47 | /* Extra bytes for htc header alignment */ | ||
48 | #define ATH6KL_HTC_ALIGN_BYTES 3 | ||
49 | |||
45 | /* MAX_HI_COOKIE_NUM are reserved for high priority traffic */ | 50 | /* MAX_HI_COOKIE_NUM are reserved for high priority traffic */ |
46 | #define MAX_DEF_COOKIE_NUM 180 | 51 | #define MAX_DEF_COOKIE_NUM 180 |
47 | #define MAX_HI_COOKIE_NUM 18 /* 10% of MAX_COOKIE_NUM */ | 52 | #define MAX_HI_COOKIE_NUM 18 /* 10% of MAX_COOKIE_NUM */ |
@@ -53,6 +58,35 @@ | |||
53 | #define A_DEFAULT_LISTEN_INTERVAL 100 | 58 | #define A_DEFAULT_LISTEN_INTERVAL 100 |
54 | #define A_MAX_WOW_LISTEN_INTERVAL 1000 | 59 | #define A_MAX_WOW_LISTEN_INTERVAL 1000 |
55 | 60 | ||
61 | /* includes also the null byte */ | ||
62 | #define ATH6KL_FIRMWARE_MAGIC "QCA-ATH6KL" | ||
63 | |||
64 | enum ath6kl_fw_ie_type { | ||
65 | ATH6KL_FW_IE_FW_VERSION = 0, | ||
66 | ATH6KL_FW_IE_TIMESTAMP = 1, | ||
67 | ATH6KL_FW_IE_OTP_IMAGE = 2, | ||
68 | ATH6KL_FW_IE_FW_IMAGE = 3, | ||
69 | ATH6KL_FW_IE_PATCH_IMAGE = 4, | ||
70 | ATH6KL_FW_IE_RESERVED_RAM_SIZE = 5, | ||
71 | ATH6KL_FW_IE_CAPABILITIES = 6, | ||
72 | ATH6KL_FW_IE_PATCH_ADDR = 7, | ||
73 | }; | ||
74 | |||
75 | enum ath6kl_fw_capability { | ||
76 | ATH6KL_FW_CAPABILITY_HOST_P2P = 0, | ||
77 | |||
78 | /* this needs to be last */ | ||
79 | ATH6KL_FW_CAPABILITY_MAX, | ||
80 | }; | ||
81 | |||
82 | #define ATH6KL_CAPABILITY_LEN (ALIGN(ATH6KL_FW_CAPABILITY_MAX, 32) / 32) | ||
83 | |||
84 | struct ath6kl_fw_ie { | ||
85 | __le32 id; | ||
86 | __le32 len; | ||
87 | u8 data[0]; | ||
88 | }; | ||
89 | |||
56 | /* AR6003 1.0 definitions */ | 90 | /* AR6003 1.0 definitions */ |
57 | #define AR6003_REV1_VERSION 0x300002ba | 91 | #define AR6003_REV1_VERSION 0x300002ba |
58 | 92 | ||
@@ -61,7 +95,9 @@ | |||
61 | #define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910 | 95 | #define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910 |
62 | #define AR6003_REV2_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77" | 96 | #define AR6003_REV2_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77" |
63 | #define AR6003_REV2_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77" | 97 | #define AR6003_REV2_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77" |
98 | #define AR6003_REV2_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin" | ||
64 | #define AR6003_REV2_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin" | 99 | #define AR6003_REV2_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin" |
100 | #define AR6003_REV2_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin" | ||
65 | #define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin" | 101 | #define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin" |
66 | #define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin" | 102 | #define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin" |
67 | 103 | ||
@@ -69,11 +105,21 @@ | |||
69 | #define AR6003_REV3_VERSION 0x30000582 | 105 | #define AR6003_REV3_VERSION 0x30000582 |
70 | #define AR6003_REV3_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin" | 106 | #define AR6003_REV3_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin" |
71 | #define AR6003_REV3_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin" | 107 | #define AR6003_REV3_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin" |
108 | #define AR6003_REV3_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin" | ||
72 | #define AR6003_REV3_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin" | 109 | #define AR6003_REV3_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin" |
110 | #define AR6003_REV3_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin" | ||
73 | #define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin" | 111 | #define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin" |
74 | #define AR6003_REV3_DEFAULT_BOARD_DATA_FILE \ | 112 | #define AR6003_REV3_DEFAULT_BOARD_DATA_FILE \ |
75 | "ath6k/AR6003/hw2.1.1/bdata.SD31.bin" | 113 | "ath6k/AR6003/hw2.1.1/bdata.SD31.bin" |
76 | 114 | ||
115 | /* AR6004 1.0 definitions */ | ||
116 | #define AR6004_REV1_VERSION 0x30000623 | ||
117 | #define AR6004_REV1_FIRMWARE_FILE "ath6k/AR6004/hw6.1/fw.ram.bin" | ||
118 | #define AR6004_REV1_FIRMWARE_2_FILE "ath6k/AR6004/hw6.1/fw-2.bin" | ||
119 | #define AR6004_REV1_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.bin" | ||
120 | #define AR6004_REV1_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.DB132.bin" | ||
121 | #define AR6004_REV1_EPPING_FIRMWARE_FILE "ath6k/AR6004/hw6.1/endpointping.bin" | ||
122 | |||
77 | /* Per STA data, used in AP mode */ | 123 | /* Per STA data, used in AP mode */ |
78 | #define STA_PS_AWAKE BIT(0) | 124 | #define STA_PS_AWAKE BIT(0) |
79 | #define STA_PS_SLEEP BIT(1) | 125 | #define STA_PS_SLEEP BIT(1) |
@@ -325,26 +371,13 @@ struct ath6kl_mbox_info { | |||
325 | #define ATH6KL_KEY_RECV 0x02 | 371 | #define ATH6KL_KEY_RECV 0x02 |
326 | #define ATH6KL_KEY_DEFAULT 0x80 /* default xmit key */ | 372 | #define ATH6KL_KEY_DEFAULT 0x80 /* default xmit key */ |
327 | 373 | ||
328 | /* | 374 | /* Initial group key for AP mode */ |
329 | * WPA/RSN get/set key request. Specify the key/cipher | ||
330 | * type and whether the key is to be used for sending and/or | ||
331 | * receiving. The key index should be set only when working | ||
332 | * with global keys (use IEEE80211_KEYIX_NONE for ``no index''). | ||
333 | * Otherwise a unicast/pairwise key is specified by the bssid | ||
334 | * (on a station) or mac address (on an ap). They key length | ||
335 | * must include any MIC key data; otherwise it should be no | ||
336 | * more than ATH6KL_KEYBUF_SIZE. | ||
337 | */ | ||
338 | struct ath6kl_req_key { | 375 | struct ath6kl_req_key { |
339 | u8 ik_type; /* key/cipher type */ | 376 | bool valid; |
340 | u8 ik_pad; | 377 | u8 key_index; |
341 | u16 ik_keyix; /* key index */ | 378 | int key_type; |
342 | u8 ik_keylen; /* key length in bytes */ | 379 | u8 key[WLAN_MAX_KEY_LEN]; |
343 | u8 ik_flags; | 380 | u8 key_len; |
344 | u8 ik_macaddr[ETH_ALEN]; | ||
345 | u64 ik_keyrsc; /* key receive sequence counter */ | ||
346 | u64 ik_keytsc; /* key transmit sequence counter */ | ||
347 | u8 ik_keydata[ATH6KL_KEYBUF_SIZE + ATH6KL_MICBUF_SIZE]; | ||
348 | }; | 381 | }; |
349 | 382 | ||
350 | /* Flag info */ | 383 | /* Flag info */ |
@@ -361,6 +394,9 @@ struct ath6kl_req_key { | |||
361 | #define NETDEV_REGISTERED 10 | 394 | #define NETDEV_REGISTERED 10 |
362 | #define SKIP_SCAN 11 | 395 | #define SKIP_SCAN 11 |
363 | #define WLAN_ENABLED 12 | 396 | #define WLAN_ENABLED 12 |
397 | #define TESTMODE 13 | ||
398 | #define CLEAR_BSSFILTER_ON_BEACON 14 | ||
399 | #define DTIM_PERIOD_AVAIL 15 | ||
364 | 400 | ||
365 | struct ath6kl { | 401 | struct ath6kl { |
366 | struct device *dev; | 402 | struct device *dev; |
@@ -383,7 +419,7 @@ struct ath6kl { | |||
383 | u8 prwise_crypto; | 419 | u8 prwise_crypto; |
384 | u8 prwise_crypto_len; | 420 | u8 prwise_crypto_len; |
385 | u8 grp_crypto; | 421 | u8 grp_crypto; |
386 | u8 grp_crpto_len; | 422 | u8 grp_crypto_len; |
387 | u8 def_txkey_index; | 423 | u8 def_txkey_index; |
388 | struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1]; | 424 | struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1]; |
389 | u8 bssid[ETH_ALEN]; | 425 | u8 bssid[ETH_ALEN]; |
@@ -392,6 +428,7 @@ struct ath6kl { | |||
392 | u16 bss_ch; | 428 | u16 bss_ch; |
393 | u16 listen_intvl_b; | 429 | u16 listen_intvl_b; |
394 | u16 listen_intvl_t; | 430 | u16 listen_intvl_t; |
431 | u8 lrssi_roam_threshold; | ||
395 | struct ath6kl_version version; | 432 | struct ath6kl_version version; |
396 | u32 target_type; | 433 | u32 target_type; |
397 | u8 tx_pwr; | 434 | u8 tx_pwr; |
@@ -432,7 +469,18 @@ struct ath6kl { | |||
432 | enum wlan_low_pwr_state wlan_pwr_state; | 469 | enum wlan_low_pwr_state wlan_pwr_state; |
433 | struct wmi_scan_params_cmd sc_params; | 470 | struct wmi_scan_params_cmd sc_params; |
434 | #define AR_MCAST_FILTER_MAC_ADDR_SIZE 4 | 471 | #define AR_MCAST_FILTER_MAC_ADDR_SIZE 4 |
435 | u8 auto_auth_stage; | 472 | struct { |
473 | void *rx_report; | ||
474 | size_t rx_report_len; | ||
475 | } tm; | ||
476 | |||
477 | struct { | ||
478 | u32 dataset_patch_addr; | ||
479 | u32 app_load_addr; | ||
480 | u32 app_start_override_addr; | ||
481 | u32 board_ext_data_addr; | ||
482 | u32 reserved_ram_size; | ||
483 | } hw; | ||
436 | 484 | ||
437 | u16 conf_flags; | 485 | u16 conf_flags; |
438 | wait_queue_head_t event_wq; | 486 | wait_queue_head_t event_wq; |
@@ -454,9 +502,35 @@ struct ath6kl { | |||
454 | u8 *fw_patch; | 502 | u8 *fw_patch; |
455 | size_t fw_patch_len; | 503 | size_t fw_patch_len; |
456 | 504 | ||
505 | unsigned long fw_capabilities[ATH6KL_CAPABILITY_LEN]; | ||
506 | |||
457 | struct workqueue_struct *ath6kl_wq; | 507 | struct workqueue_struct *ath6kl_wq; |
458 | 508 | ||
459 | struct ath6kl_node_table scan_table; | 509 | struct dentry *debugfs_phy; |
510 | |||
511 | u32 send_action_id; | ||
512 | bool probe_req_report; | ||
513 | u16 next_chan; | ||
514 | |||
515 | bool p2p; | ||
516 | u16 assoc_bss_beacon_int; | ||
517 | u8 assoc_bss_dtim_period; | ||
518 | |||
519 | #ifdef CONFIG_ATH6KL_DEBUG | ||
520 | struct { | ||
521 | struct circ_buf fwlog_buf; | ||
522 | spinlock_t fwlog_lock; | ||
523 | void *fwlog_tmp; | ||
524 | u32 fwlog_mask; | ||
525 | unsigned int dbgfs_diag_reg; | ||
526 | u32 diag_reg_addr_wr; | ||
527 | u32 diag_reg_val_wr; | ||
528 | |||
529 | struct { | ||
530 | unsigned int invalid_rate; | ||
531 | } war_stats; | ||
532 | } debug; | ||
533 | #endif /* CONFIG_ATH6KL_DEBUG */ | ||
460 | }; | 534 | }; |
461 | 535 | ||
462 | static inline void *ath6kl_priv(struct net_device *dev) | 536 | static inline void *ath6kl_priv(struct net_device *dev) |
@@ -474,6 +548,19 @@ static inline void ath6kl_deposit_credit_to_ep(struct htc_credit_state_info | |||
474 | cred_info->cur_free_credits -= credits; | 548 | cred_info->cur_free_credits -= credits; |
475 | } | 549 | } |
476 | 550 | ||
551 | static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar, | ||
552 | u32 item_offset) | ||
553 | { | ||
554 | u32 addr = 0; | ||
555 | |||
556 | if (ar->target_type == TARGET_TYPE_AR6003) | ||
557 | addr = ATH6KL_AR6003_HI_START_ADDR + item_offset; | ||
558 | else if (ar->target_type == TARGET_TYPE_AR6004) | ||
559 | addr = ATH6KL_AR6004_HI_START_ADDR + item_offset; | ||
560 | |||
561 | return addr; | ||
562 | } | ||
563 | |||
477 | void ath6kl_destroy(struct net_device *dev, unsigned int unregister); | 564 | void ath6kl_destroy(struct net_device *dev, unsigned int unregister); |
478 | int ath6kl_configure_target(struct ath6kl *ar); | 565 | int ath6kl_configure_target(struct ath6kl *ar); |
479 | void ath6kl_detect_error(unsigned long ptr); | 566 | void ath6kl_detect_error(unsigned long ptr); |
@@ -487,9 +574,11 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, | |||
487 | struct htc_packet *packet); | 574 | struct htc_packet *packet); |
488 | void ath6kl_stop_txrx(struct ath6kl *ar); | 575 | void ath6kl_stop_txrx(struct ath6kl *ar); |
489 | void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar); | 576 | void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar); |
490 | int ath6kl_access_datadiag(struct ath6kl *ar, u32 address, | 577 | int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value); |
491 | u8 *data, u32 length, bool read); | 578 | int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length); |
492 | int ath6kl_read_reg_diag(struct ath6kl *ar, u32 *address, u32 *data); | 579 | int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value); |
580 | int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length); | ||
581 | int ath6kl_read_fwlogs(struct ath6kl *ar); | ||
493 | void ath6kl_init_profile_info(struct ath6kl *ar); | 582 | void ath6kl_init_profile_info(struct ath6kl *ar); |
494 | void ath6kl_tx_data_cleanup(struct ath6kl *ar); | 583 | void ath6kl_tx_data_cleanup(struct ath6kl *ar); |
495 | void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile, | 584 | void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile, |
@@ -520,6 +609,10 @@ void ath6kl_connect_event(struct ath6kl *ar, u16 channel, | |||
520 | u16 beacon_int, enum network_type net_type, | 609 | u16 beacon_int, enum network_type net_type, |
521 | u8 beacon_ie_len, u8 assoc_req_len, | 610 | u8 beacon_ie_len, u8 assoc_req_len, |
522 | u8 assoc_resp_len, u8 *assoc_info); | 611 | u8 assoc_resp_len, u8 *assoc_info); |
612 | void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel); | ||
613 | void ath6kl_connect_ap_mode_sta(struct ath6kl *ar, u16 aid, u8 *mac_addr, | ||
614 | u8 keymgmt, u8 ucipher, u8 auth, | ||
615 | u8 assoc_req_len, u8 *assoc_info); | ||
523 | void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, | 616 | void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, |
524 | u8 *bssid, u8 assoc_resp_len, | 617 | u8 *bssid, u8 assoc_resp_len, |
525 | u8 *assoc_info, u16 prot_reason_status); | 618 | u8 *assoc_info, u16 prot_reason_status); |
@@ -534,11 +627,11 @@ void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid); | |||
534 | 627 | ||
535 | void ath6kl_dtimexpiry_event(struct ath6kl *ar); | 628 | void ath6kl_dtimexpiry_event(struct ath6kl *ar); |
536 | void ath6kl_disconnect(struct ath6kl *ar); | 629 | void ath6kl_disconnect(struct ath6kl *ar); |
630 | void ath6kl_deep_sleep_enable(struct ath6kl *ar); | ||
537 | void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid); | 631 | void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid); |
538 | void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no, | 632 | void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no, |
539 | u8 win_sz); | 633 | u8 win_sz); |
540 | void ath6kl_wakeup_event(void *dev); | 634 | void ath6kl_wakeup_event(void *dev); |
541 | void ath6kl_target_failure(struct ath6kl *ar); | 635 | void ath6kl_target_failure(struct ath6kl *ar); |
542 | 636 | ||
543 | void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni); | ||
544 | #endif /* CORE_H */ | 637 | #endif /* CORE_H */ |
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index 316136c8b903..ba3f23d71150 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c | |||
@@ -15,7 +15,26 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "core.h" | 17 | #include "core.h" |
18 | |||
19 | #include <linux/circ_buf.h> | ||
20 | #include <linux/fs.h> | ||
21 | #include <linux/vmalloc.h> | ||
22 | |||
18 | #include "debug.h" | 23 | #include "debug.h" |
24 | #include "target.h" | ||
25 | |||
26 | struct ath6kl_fwlog_slot { | ||
27 | __le32 timestamp; | ||
28 | __le32 length; | ||
29 | |||
30 | /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */ | ||
31 | u8 payload[0]; | ||
32 | }; | ||
33 | |||
34 | #define ATH6KL_FWLOG_SIZE 32768 | ||
35 | #define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \ | ||
36 | ATH6KL_FWLOG_PAYLOAD_SIZE) | ||
37 | #define ATH6KL_FWLOG_VALID_MASK 0x1ffff | ||
19 | 38 | ||
20 | int ath6kl_printk(const char *level, const char *fmt, ...) | 39 | int ath6kl_printk(const char *level, const char *fmt, ...) |
21 | { | 40 | { |
@@ -36,6 +55,27 @@ int ath6kl_printk(const char *level, const char *fmt, ...) | |||
36 | } | 55 | } |
37 | 56 | ||
38 | #ifdef CONFIG_ATH6KL_DEBUG | 57 | #ifdef CONFIG_ATH6KL_DEBUG |
58 | |||
59 | #define REG_OUTPUT_LEN_PER_LINE 25 | ||
60 | #define REGTYPE_STR_LEN 100 | ||
61 | |||
62 | struct ath6kl_diag_reg_info { | ||
63 | u32 reg_start; | ||
64 | u32 reg_end; | ||
65 | const char *reg_info; | ||
66 | }; | ||
67 | |||
68 | static const struct ath6kl_diag_reg_info diag_reg[] = { | ||
69 | { 0x20000, 0x200fc, "General DMA and Rx registers" }, | ||
70 | { 0x28000, 0x28900, "MAC PCU register & keycache" }, | ||
71 | { 0x20800, 0x20a40, "QCU" }, | ||
72 | { 0x21000, 0x212f0, "DCU" }, | ||
73 | { 0x4000, 0x42e4, "RTC" }, | ||
74 | { 0x540000, 0x540000 + (256 * 1024), "RAM" }, | ||
75 | { 0x29800, 0x2B210, "Base Band" }, | ||
76 | { 0x1C000, 0x1C748, "Analog" }, | ||
77 | }; | ||
78 | |||
39 | void ath6kl_dump_registers(struct ath6kl_device *dev, | 79 | void ath6kl_dump_registers(struct ath6kl_device *dev, |
40 | struct ath6kl_irq_proc_registers *irq_proc_reg, | 80 | struct ath6kl_irq_proc_registers *irq_proc_reg, |
41 | struct ath6kl_irq_enable_reg *irq_enable_reg) | 81 | struct ath6kl_irq_enable_reg *irq_enable_reg) |
@@ -147,4 +187,748 @@ void dump_cred_dist_stats(struct htc_target *target) | |||
147 | target->cred_dist_cntxt->cur_free_credits); | 187 | target->cred_dist_cntxt->cur_free_credits); |
148 | } | 188 | } |
149 | 189 | ||
190 | static int ath6kl_debugfs_open(struct inode *inode, struct file *file) | ||
191 | { | ||
192 | file->private_data = inode->i_private; | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war) | ||
197 | { | ||
198 | switch (war) { | ||
199 | case ATH6KL_WAR_INVALID_RATE: | ||
200 | ar->debug.war_stats.invalid_rate++; | ||
201 | break; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | static ssize_t read_file_war_stats(struct file *file, char __user *user_buf, | ||
206 | size_t count, loff_t *ppos) | ||
207 | { | ||
208 | struct ath6kl *ar = file->private_data; | ||
209 | char *buf; | ||
210 | unsigned int len = 0, buf_len = 1500; | ||
211 | ssize_t ret_cnt; | ||
212 | |||
213 | buf = kzalloc(buf_len, GFP_KERNEL); | ||
214 | if (!buf) | ||
215 | return -ENOMEM; | ||
216 | |||
217 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
218 | len += scnprintf(buf + len, buf_len - len, "%25s\n", | ||
219 | "Workaround stats"); | ||
220 | len += scnprintf(buf + len, buf_len - len, "%25s\n\n", | ||
221 | "================="); | ||
222 | len += scnprintf(buf + len, buf_len - len, "%20s %10u\n", | ||
223 | "Invalid rates", ar->debug.war_stats.invalid_rate); | ||
224 | |||
225 | if (WARN_ON(len > buf_len)) | ||
226 | len = buf_len; | ||
227 | |||
228 | ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
229 | |||
230 | kfree(buf); | ||
231 | return ret_cnt; | ||
232 | } | ||
233 | |||
234 | static const struct file_operations fops_war_stats = { | ||
235 | .read = read_file_war_stats, | ||
236 | .open = ath6kl_debugfs_open, | ||
237 | .owner = THIS_MODULE, | ||
238 | .llseek = default_llseek, | ||
239 | }; | ||
240 | |||
241 | static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf, | ||
242 | size_t buf_len) | ||
243 | { | ||
244 | struct circ_buf *fwlog = &ar->debug.fwlog_buf; | ||
245 | size_t space; | ||
246 | int i; | ||
247 | |||
248 | /* entries must all be equal size */ | ||
249 | if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE)) | ||
250 | return; | ||
251 | |||
252 | space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE); | ||
253 | if (space < buf_len) | ||
254 | /* discard oldest slot */ | ||
255 | fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) & | ||
256 | (ATH6KL_FWLOG_SIZE - 1); | ||
257 | |||
258 | for (i = 0; i < buf_len; i += space) { | ||
259 | space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail, | ||
260 | ATH6KL_FWLOG_SIZE); | ||
261 | |||
262 | if ((size_t) space > buf_len - i) | ||
263 | space = buf_len - i; | ||
264 | |||
265 | memcpy(&fwlog->buf[fwlog->head], buf, space); | ||
266 | fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1); | ||
267 | } | ||
268 | |||
269 | } | ||
270 | |||
271 | void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) | ||
272 | { | ||
273 | struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp; | ||
274 | size_t slot_len; | ||
275 | |||
276 | if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) | ||
277 | return; | ||
278 | |||
279 | spin_lock_bh(&ar->debug.fwlog_lock); | ||
280 | |||
281 | slot->timestamp = cpu_to_le32(jiffies); | ||
282 | slot->length = cpu_to_le32(len); | ||
283 | memcpy(slot->payload, buf, len); | ||
284 | |||
285 | slot_len = sizeof(*slot) + len; | ||
286 | |||
287 | if (slot_len < ATH6KL_FWLOG_SLOT_SIZE) | ||
288 | memset(slot->payload + len, 0, | ||
289 | ATH6KL_FWLOG_SLOT_SIZE - slot_len); | ||
290 | |||
291 | ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE); | ||
292 | |||
293 | spin_unlock_bh(&ar->debug.fwlog_lock); | ||
294 | } | ||
295 | |||
296 | static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar) | ||
297 | { | ||
298 | return CIRC_CNT(ar->debug.fwlog_buf.head, | ||
299 | ar->debug.fwlog_buf.tail, | ||
300 | ATH6KL_FWLOG_SLOT_SIZE) == 0; | ||
301 | } | ||
302 | |||
303 | static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, | ||
304 | size_t count, loff_t *ppos) | ||
305 | { | ||
306 | struct ath6kl *ar = file->private_data; | ||
307 | struct circ_buf *fwlog = &ar->debug.fwlog_buf; | ||
308 | size_t len = 0, buf_len = count; | ||
309 | ssize_t ret_cnt; | ||
310 | char *buf; | ||
311 | int ccnt; | ||
312 | |||
313 | buf = vmalloc(buf_len); | ||
314 | if (!buf) | ||
315 | return -ENOMEM; | ||
316 | |||
317 | /* read undelivered logs from firmware */ | ||
318 | ath6kl_read_fwlogs(ar); | ||
319 | |||
320 | spin_lock_bh(&ar->debug.fwlog_lock); | ||
321 | |||
322 | while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) { | ||
323 | ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail, | ||
324 | ATH6KL_FWLOG_SIZE); | ||
325 | |||
326 | if ((size_t) ccnt > buf_len - len) | ||
327 | ccnt = buf_len - len; | ||
328 | |||
329 | memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt); | ||
330 | len += ccnt; | ||
331 | |||
332 | fwlog->tail = (fwlog->tail + ccnt) & | ||
333 | (ATH6KL_FWLOG_SIZE - 1); | ||
334 | } | ||
335 | |||
336 | spin_unlock_bh(&ar->debug.fwlog_lock); | ||
337 | |||
338 | if (WARN_ON(len > buf_len)) | ||
339 | len = buf_len; | ||
340 | |||
341 | ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
342 | |||
343 | vfree(buf); | ||
344 | |||
345 | return ret_cnt; | ||
346 | } | ||
347 | |||
348 | static const struct file_operations fops_fwlog = { | ||
349 | .open = ath6kl_debugfs_open, | ||
350 | .read = ath6kl_fwlog_read, | ||
351 | .owner = THIS_MODULE, | ||
352 | .llseek = default_llseek, | ||
353 | }; | ||
354 | |||
355 | static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, | ||
356 | size_t count, loff_t *ppos) | ||
357 | { | ||
358 | struct ath6kl *ar = file->private_data; | ||
359 | char buf[16]; | ||
360 | int len; | ||
361 | |||
362 | len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask); | ||
363 | |||
364 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
365 | } | ||
366 | |||
367 | static ssize_t ath6kl_fwlog_mask_write(struct file *file, | ||
368 | const char __user *user_buf, | ||
369 | size_t count, loff_t *ppos) | ||
370 | { | ||
371 | struct ath6kl *ar = file->private_data; | ||
372 | int ret; | ||
373 | |||
374 | ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask); | ||
375 | if (ret) | ||
376 | return ret; | ||
377 | |||
378 | ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi, | ||
379 | ATH6KL_FWLOG_VALID_MASK, | ||
380 | ar->debug.fwlog_mask); | ||
381 | if (ret) | ||
382 | return ret; | ||
383 | |||
384 | return count; | ||
385 | } | ||
386 | |||
387 | static const struct file_operations fops_fwlog_mask = { | ||
388 | .open = ath6kl_debugfs_open, | ||
389 | .read = ath6kl_fwlog_mask_read, | ||
390 | .write = ath6kl_fwlog_mask_write, | ||
391 | .owner = THIS_MODULE, | ||
392 | .llseek = default_llseek, | ||
393 | }; | ||
394 | |||
395 | static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, | ||
396 | size_t count, loff_t *ppos) | ||
397 | { | ||
398 | struct ath6kl *ar = file->private_data; | ||
399 | struct target_stats *tgt_stats = &ar->target_stats; | ||
400 | char *buf; | ||
401 | unsigned int len = 0, buf_len = 1500; | ||
402 | int i; | ||
403 | long left; | ||
404 | ssize_t ret_cnt; | ||
405 | |||
406 | buf = kzalloc(buf_len, GFP_KERNEL); | ||
407 | if (!buf) | ||
408 | return -ENOMEM; | ||
409 | |||
410 | if (down_interruptible(&ar->sem)) { | ||
411 | kfree(buf); | ||
412 | return -EBUSY; | ||
413 | } | ||
414 | |||
415 | set_bit(STATS_UPDATE_PEND, &ar->flag); | ||
416 | |||
417 | if (ath6kl_wmi_get_stats_cmd(ar->wmi)) { | ||
418 | up(&ar->sem); | ||
419 | kfree(buf); | ||
420 | return -EIO; | ||
421 | } | ||
422 | |||
423 | left = wait_event_interruptible_timeout(ar->event_wq, | ||
424 | !test_bit(STATS_UPDATE_PEND, | ||
425 | &ar->flag), WMI_TIMEOUT); | ||
426 | |||
427 | up(&ar->sem); | ||
428 | |||
429 | if (left <= 0) { | ||
430 | kfree(buf); | ||
431 | return -ETIMEDOUT; | ||
432 | } | ||
433 | |||
434 | len += scnprintf(buf + len, buf_len - len, "\n"); | ||
435 | len += scnprintf(buf + len, buf_len - len, "%25s\n", | ||
436 | "Target Tx stats"); | ||
437 | len += scnprintf(buf + len, buf_len - len, "%25s\n\n", | ||
438 | "================="); | ||
439 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
440 | "Ucast packets", tgt_stats->tx_ucast_pkt); | ||
441 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
442 | "Bcast packets", tgt_stats->tx_bcast_pkt); | ||
443 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
444 | "Ucast byte", tgt_stats->tx_ucast_byte); | ||
445 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
446 | "Bcast byte", tgt_stats->tx_bcast_byte); | ||
447 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
448 | "Rts success cnt", tgt_stats->tx_rts_success_cnt); | ||
449 | for (i = 0; i < 4; i++) | ||
450 | len += scnprintf(buf + len, buf_len - len, | ||
451 | "%18s %d %10llu\n", "PER on ac", | ||
452 | i, tgt_stats->tx_pkt_per_ac[i]); | ||
453 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
454 | "Error", tgt_stats->tx_err); | ||
455 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
456 | "Fail count", tgt_stats->tx_fail_cnt); | ||
457 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
458 | "Retry count", tgt_stats->tx_retry_cnt); | ||
459 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
460 | "Multi retry cnt", tgt_stats->tx_mult_retry_cnt); | ||
461 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
462 | "Rts fail cnt", tgt_stats->tx_rts_fail_cnt); | ||
463 | len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n", | ||
464 | "TKIP counter measure used", | ||
465 | tgt_stats->tkip_cnter_measures_invoked); | ||
466 | |||
467 | len += scnprintf(buf + len, buf_len - len, "%25s\n", | ||
468 | "Target Rx stats"); | ||
469 | len += scnprintf(buf + len, buf_len - len, "%25s\n", | ||
470 | "================="); | ||
471 | |||
472 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
473 | "Ucast packets", tgt_stats->rx_ucast_pkt); | ||
474 | len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", | ||
475 | "Ucast Rate", tgt_stats->rx_ucast_rate); | ||
476 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
477 | "Bcast packets", tgt_stats->rx_bcast_pkt); | ||
478 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
479 | "Ucast byte", tgt_stats->rx_ucast_byte); | ||
480 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
481 | "Bcast byte", tgt_stats->rx_bcast_byte); | ||
482 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
483 | "Fragmented pkt", tgt_stats->rx_frgment_pkt); | ||
484 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
485 | "Error", tgt_stats->rx_err); | ||
486 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
487 | "CRC Err", tgt_stats->rx_crc_err); | ||
488 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
489 | "Key chache miss", tgt_stats->rx_key_cache_miss); | ||
490 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
491 | "Decrypt Err", tgt_stats->rx_decrypt_err); | ||
492 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
493 | "Duplicate frame", tgt_stats->rx_dupl_frame); | ||
494 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
495 | "Tkip Mic failure", tgt_stats->tkip_local_mic_fail); | ||
496 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
497 | "TKIP format err", tgt_stats->tkip_fmt_err); | ||
498 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
499 | "CCMP format Err", tgt_stats->ccmp_fmt_err); | ||
500 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n", | ||
501 | "CCMP Replay Err", tgt_stats->ccmp_replays); | ||
502 | |||
503 | len += scnprintf(buf + len, buf_len - len, "%25s\n", | ||
504 | "Misc Target stats"); | ||
505 | len += scnprintf(buf + len, buf_len - len, "%25s\n", | ||
506 | "================="); | ||
507 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
508 | "Beacon Miss count", tgt_stats->cs_bmiss_cnt); | ||
509 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
510 | "Num Connects", tgt_stats->cs_connect_cnt); | ||
511 | len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", | ||
512 | "Num disconnects", tgt_stats->cs_discon_cnt); | ||
513 | len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", | ||
514 | "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi); | ||
515 | |||
516 | if (len > buf_len) | ||
517 | len = buf_len; | ||
518 | |||
519 | ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
520 | |||
521 | kfree(buf); | ||
522 | return ret_cnt; | ||
523 | } | ||
524 | |||
525 | static const struct file_operations fops_tgt_stats = { | ||
526 | .read = read_file_tgt_stats, | ||
527 | .open = ath6kl_debugfs_open, | ||
528 | .owner = THIS_MODULE, | ||
529 | .llseek = default_llseek, | ||
530 | }; | ||
531 | |||
532 | #define print_credit_info(fmt_str, ep_list_field) \ | ||
533 | (len += scnprintf(buf + len, buf_len - len, fmt_str, \ | ||
534 | ep_list->ep_list_field)) | ||
535 | #define CREDIT_INFO_DISPLAY_STRING_LEN 200 | ||
536 | #define CREDIT_INFO_LEN 128 | ||
537 | |||
538 | static ssize_t read_file_credit_dist_stats(struct file *file, | ||
539 | char __user *user_buf, | ||
540 | size_t count, loff_t *ppos) | ||
541 | { | ||
542 | struct ath6kl *ar = file->private_data; | ||
543 | struct htc_target *target = ar->htc_target; | ||
544 | struct htc_endpoint_credit_dist *ep_list; | ||
545 | char *buf; | ||
546 | unsigned int buf_len, len = 0; | ||
547 | ssize_t ret_cnt; | ||
548 | |||
549 | buf_len = CREDIT_INFO_DISPLAY_STRING_LEN + | ||
550 | get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN; | ||
551 | buf = kzalloc(buf_len, GFP_KERNEL); | ||
552 | if (!buf) | ||
553 | return -ENOMEM; | ||
554 | |||
555 | len += scnprintf(buf + len, buf_len - len, "%25s%5d\n", | ||
556 | "Total Avail Credits: ", | ||
557 | target->cred_dist_cntxt->total_avail_credits); | ||
558 | len += scnprintf(buf + len, buf_len - len, "%25s%5d\n", | ||
559 | "Free credits :", | ||
560 | target->cred_dist_cntxt->cur_free_credits); | ||
561 | |||
562 | len += scnprintf(buf + len, buf_len - len, | ||
563 | " Epid Flags Cred_norm Cred_min Credits Cred_assngd" | ||
564 | " Seek_cred Cred_sz Cred_per_msg Cred_to_dist" | ||
565 | " qdepth\n"); | ||
566 | |||
567 | list_for_each_entry(ep_list, &target->cred_dist_list, list) { | ||
568 | print_credit_info(" %2d", endpoint); | ||
569 | print_credit_info("%10x", dist_flags); | ||
570 | print_credit_info("%8d", cred_norm); | ||
571 | print_credit_info("%9d", cred_min); | ||
572 | print_credit_info("%9d", credits); | ||
573 | print_credit_info("%10d", cred_assngd); | ||
574 | print_credit_info("%13d", seek_cred); | ||
575 | print_credit_info("%12d", cred_sz); | ||
576 | print_credit_info("%9d", cred_per_msg); | ||
577 | print_credit_info("%14d", cred_to_dist); | ||
578 | len += scnprintf(buf + len, buf_len - len, "%12d\n", | ||
579 | get_queue_depth(&((struct htc_endpoint *) | ||
580 | ep_list->htc_rsvd)->txq)); | ||
581 | } | ||
582 | |||
583 | if (len > buf_len) | ||
584 | len = buf_len; | ||
585 | |||
586 | ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
587 | kfree(buf); | ||
588 | return ret_cnt; | ||
589 | } | ||
590 | |||
591 | static const struct file_operations fops_credit_dist_stats = { | ||
592 | .read = read_file_credit_dist_stats, | ||
593 | .open = ath6kl_debugfs_open, | ||
594 | .owner = THIS_MODULE, | ||
595 | .llseek = default_llseek, | ||
596 | }; | ||
597 | |||
598 | static unsigned long ath6kl_get_num_reg(void) | ||
599 | { | ||
600 | int i; | ||
601 | unsigned long n_reg = 0; | ||
602 | |||
603 | for (i = 0; i < ARRAY_SIZE(diag_reg); i++) | ||
604 | n_reg = n_reg + | ||
605 | (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1; | ||
606 | |||
607 | return n_reg; | ||
608 | } | ||
609 | |||
610 | static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr) | ||
611 | { | ||
612 | int i; | ||
613 | |||
614 | for (i = 0; i < ARRAY_SIZE(diag_reg); i++) { | ||
615 | if (reg_addr >= diag_reg[i].reg_start && | ||
616 | reg_addr <= diag_reg[i].reg_end) | ||
617 | return true; | ||
618 | } | ||
619 | |||
620 | return false; | ||
621 | } | ||
622 | |||
623 | static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf, | ||
624 | size_t count, loff_t *ppos) | ||
625 | { | ||
626 | struct ath6kl *ar = file->private_data; | ||
627 | u8 buf[50]; | ||
628 | unsigned int len = 0; | ||
629 | |||
630 | if (ar->debug.dbgfs_diag_reg) | ||
631 | len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", | ||
632 | ar->debug.dbgfs_diag_reg); | ||
633 | else | ||
634 | len += scnprintf(buf + len, sizeof(buf) - len, | ||
635 | "All diag registers\n"); | ||
636 | |||
637 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
638 | } | ||
639 | |||
640 | static ssize_t ath6kl_regread_write(struct file *file, | ||
641 | const char __user *user_buf, | ||
642 | size_t count, loff_t *ppos) | ||
643 | { | ||
644 | struct ath6kl *ar = file->private_data; | ||
645 | u8 buf[50]; | ||
646 | unsigned int len; | ||
647 | unsigned long reg_addr; | ||
648 | |||
649 | len = min(count, sizeof(buf) - 1); | ||
650 | if (copy_from_user(buf, user_buf, len)) | ||
651 | return -EFAULT; | ||
652 | |||
653 | buf[len] = '\0'; | ||
654 | |||
655 | if (strict_strtoul(buf, 0, ®_addr)) | ||
656 | return -EINVAL; | ||
657 | |||
658 | if ((reg_addr % 4) != 0) | ||
659 | return -EINVAL; | ||
660 | |||
661 | if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr)) | ||
662 | return -EINVAL; | ||
663 | |||
664 | ar->debug.dbgfs_diag_reg = reg_addr; | ||
665 | |||
666 | return count; | ||
667 | } | ||
668 | |||
669 | static const struct file_operations fops_diag_reg_read = { | ||
670 | .read = ath6kl_regread_read, | ||
671 | .write = ath6kl_regread_write, | ||
672 | .open = ath6kl_debugfs_open, | ||
673 | .owner = THIS_MODULE, | ||
674 | .llseek = default_llseek, | ||
675 | }; | ||
676 | |||
677 | static int ath6kl_regdump_open(struct inode *inode, struct file *file) | ||
678 | { | ||
679 | struct ath6kl *ar = inode->i_private; | ||
680 | u8 *buf; | ||
681 | unsigned long int reg_len; | ||
682 | unsigned int len = 0, n_reg; | ||
683 | u32 addr; | ||
684 | __le32 reg_val; | ||
685 | int i, status; | ||
686 | |||
687 | /* Dump all the registers if no register is specified */ | ||
688 | if (!ar->debug.dbgfs_diag_reg) | ||
689 | n_reg = ath6kl_get_num_reg(); | ||
690 | else | ||
691 | n_reg = 1; | ||
692 | |||
693 | reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE; | ||
694 | if (n_reg > 1) | ||
695 | reg_len += REGTYPE_STR_LEN; | ||
696 | |||
697 | buf = vmalloc(reg_len); | ||
698 | if (!buf) | ||
699 | return -ENOMEM; | ||
700 | |||
701 | if (n_reg == 1) { | ||
702 | addr = ar->debug.dbgfs_diag_reg; | ||
703 | |||
704 | status = ath6kl_diag_read32(ar, | ||
705 | TARG_VTOP(ar->target_type, addr), | ||
706 | (u32 *)®_val); | ||
707 | if (status) | ||
708 | goto fail_reg_read; | ||
709 | |||
710 | len += scnprintf(buf + len, reg_len - len, | ||
711 | "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val)); | ||
712 | goto done; | ||
713 | } | ||
714 | |||
715 | for (i = 0; i < ARRAY_SIZE(diag_reg); i++) { | ||
716 | len += scnprintf(buf + len, reg_len - len, | ||
717 | "%s\n", diag_reg[i].reg_info); | ||
718 | for (addr = diag_reg[i].reg_start; | ||
719 | addr <= diag_reg[i].reg_end; addr += 4) { | ||
720 | status = ath6kl_diag_read32(ar, | ||
721 | TARG_VTOP(ar->target_type, addr), | ||
722 | (u32 *)®_val); | ||
723 | if (status) | ||
724 | goto fail_reg_read; | ||
725 | |||
726 | len += scnprintf(buf + len, reg_len - len, | ||
727 | "0x%06x 0x%08x\n", | ||
728 | addr, le32_to_cpu(reg_val)); | ||
729 | } | ||
730 | } | ||
731 | |||
732 | done: | ||
733 | file->private_data = buf; | ||
734 | return 0; | ||
735 | |||
736 | fail_reg_read: | ||
737 | ath6kl_warn("Unable to read memory:%u\n", addr); | ||
738 | vfree(buf); | ||
739 | return -EIO; | ||
740 | } | ||
741 | |||
742 | static ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf, | ||
743 | size_t count, loff_t *ppos) | ||
744 | { | ||
745 | u8 *buf = file->private_data; | ||
746 | return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); | ||
747 | } | ||
748 | |||
749 | static int ath6kl_regdump_release(struct inode *inode, struct file *file) | ||
750 | { | ||
751 | vfree(file->private_data); | ||
752 | return 0; | ||
753 | } | ||
754 | |||
755 | static const struct file_operations fops_reg_dump = { | ||
756 | .open = ath6kl_regdump_open, | ||
757 | .read = ath6kl_regdump_read, | ||
758 | .release = ath6kl_regdump_release, | ||
759 | .owner = THIS_MODULE, | ||
760 | .llseek = default_llseek, | ||
761 | }; | ||
762 | |||
763 | static ssize_t ath6kl_lrssi_roam_write(struct file *file, | ||
764 | const char __user *user_buf, | ||
765 | size_t count, loff_t *ppos) | ||
766 | { | ||
767 | struct ath6kl *ar = file->private_data; | ||
768 | unsigned long lrssi_roam_threshold; | ||
769 | char buf[32]; | ||
770 | ssize_t len; | ||
771 | |||
772 | len = min(count, sizeof(buf) - 1); | ||
773 | if (copy_from_user(buf, user_buf, len)) | ||
774 | return -EFAULT; | ||
775 | |||
776 | buf[len] = '\0'; | ||
777 | if (strict_strtoul(buf, 0, &lrssi_roam_threshold)) | ||
778 | return -EINVAL; | ||
779 | |||
780 | ar->lrssi_roam_threshold = lrssi_roam_threshold; | ||
781 | |||
782 | ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold); | ||
783 | |||
784 | return count; | ||
785 | } | ||
786 | |||
787 | static ssize_t ath6kl_lrssi_roam_read(struct file *file, | ||
788 | char __user *user_buf, | ||
789 | size_t count, loff_t *ppos) | ||
790 | { | ||
791 | struct ath6kl *ar = file->private_data; | ||
792 | char buf[32]; | ||
793 | unsigned int len; | ||
794 | |||
795 | len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold); | ||
796 | |||
797 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
798 | } | ||
799 | |||
800 | static const struct file_operations fops_lrssi_roam_threshold = { | ||
801 | .read = ath6kl_lrssi_roam_read, | ||
802 | .write = ath6kl_lrssi_roam_write, | ||
803 | .open = ath6kl_debugfs_open, | ||
804 | .owner = THIS_MODULE, | ||
805 | .llseek = default_llseek, | ||
806 | }; | ||
807 | |||
808 | static ssize_t ath6kl_regwrite_read(struct file *file, | ||
809 | char __user *user_buf, | ||
810 | size_t count, loff_t *ppos) | ||
811 | { | ||
812 | struct ath6kl *ar = file->private_data; | ||
813 | u8 buf[32]; | ||
814 | unsigned int len = 0; | ||
815 | |||
816 | len = scnprintf(buf, sizeof(buf), "Addr: 0x%x Val: 0x%x\n", | ||
817 | ar->debug.diag_reg_addr_wr, ar->debug.diag_reg_val_wr); | ||
818 | |||
819 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
820 | } | ||
821 | |||
822 | static ssize_t ath6kl_regwrite_write(struct file *file, | ||
823 | const char __user *user_buf, | ||
824 | size_t count, loff_t *ppos) | ||
825 | { | ||
826 | struct ath6kl *ar = file->private_data; | ||
827 | char buf[32]; | ||
828 | char *sptr, *token; | ||
829 | unsigned int len = 0; | ||
830 | u32 reg_addr, reg_val; | ||
831 | |||
832 | len = min(count, sizeof(buf) - 1); | ||
833 | if (copy_from_user(buf, user_buf, len)) | ||
834 | return -EFAULT; | ||
835 | |||
836 | buf[len] = '\0'; | ||
837 | sptr = buf; | ||
838 | |||
839 | token = strsep(&sptr, "="); | ||
840 | if (!token) | ||
841 | return -EINVAL; | ||
842 | |||
843 | if (kstrtou32(token, 0, ®_addr)) | ||
844 | return -EINVAL; | ||
845 | |||
846 | if (!ath6kl_dbg_is_diag_reg_valid(reg_addr)) | ||
847 | return -EINVAL; | ||
848 | |||
849 | if (kstrtou32(sptr, 0, ®_val)) | ||
850 | return -EINVAL; | ||
851 | |||
852 | ar->debug.diag_reg_addr_wr = reg_addr; | ||
853 | ar->debug.diag_reg_val_wr = reg_val; | ||
854 | |||
855 | if (ath6kl_diag_write32(ar, ar->debug.diag_reg_addr_wr, | ||
856 | cpu_to_le32(ar->debug.diag_reg_val_wr))) | ||
857 | return -EIO; | ||
858 | |||
859 | return count; | ||
860 | } | ||
861 | |||
862 | static const struct file_operations fops_diag_reg_write = { | ||
863 | .read = ath6kl_regwrite_read, | ||
864 | .write = ath6kl_regwrite_write, | ||
865 | .open = ath6kl_debugfs_open, | ||
866 | .owner = THIS_MODULE, | ||
867 | .llseek = default_llseek, | ||
868 | }; | ||
869 | |||
870 | int ath6kl_debug_init(struct ath6kl *ar) | ||
871 | { | ||
872 | ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE); | ||
873 | if (ar->debug.fwlog_buf.buf == NULL) | ||
874 | return -ENOMEM; | ||
875 | |||
876 | ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL); | ||
877 | if (ar->debug.fwlog_tmp == NULL) { | ||
878 | vfree(ar->debug.fwlog_buf.buf); | ||
879 | return -ENOMEM; | ||
880 | } | ||
881 | |||
882 | spin_lock_init(&ar->debug.fwlog_lock); | ||
883 | |||
884 | /* | ||
885 | * Actually we are lying here but don't know how to read the mask | ||
886 | * value from the firmware. | ||
887 | */ | ||
888 | ar->debug.fwlog_mask = 0; | ||
889 | |||
890 | ar->debugfs_phy = debugfs_create_dir("ath6kl", | ||
891 | ar->wdev->wiphy->debugfsdir); | ||
892 | if (!ar->debugfs_phy) { | ||
893 | vfree(ar->debug.fwlog_buf.buf); | ||
894 | kfree(ar->debug.fwlog_tmp); | ||
895 | return -ENOMEM; | ||
896 | } | ||
897 | |||
898 | debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, | ||
899 | &fops_tgt_stats); | ||
900 | |||
901 | debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar, | ||
902 | &fops_credit_dist_stats); | ||
903 | |||
904 | debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, | ||
905 | &fops_fwlog); | ||
906 | |||
907 | debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, | ||
908 | ar, &fops_fwlog_mask); | ||
909 | |||
910 | debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar, | ||
911 | &fops_diag_reg_read); | ||
912 | |||
913 | debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar, | ||
914 | &fops_reg_dump); | ||
915 | |||
916 | debugfs_create_file("lrssi_roam_threshold", S_IRUSR | S_IWUSR, | ||
917 | ar->debugfs_phy, ar, &fops_lrssi_roam_threshold); | ||
918 | |||
919 | debugfs_create_file("reg_write", S_IRUSR | S_IWUSR, | ||
920 | ar->debugfs_phy, ar, &fops_diag_reg_write); | ||
921 | |||
922 | debugfs_create_file("war_stats", S_IRUSR, ar->debugfs_phy, ar, | ||
923 | &fops_war_stats); | ||
924 | |||
925 | return 0; | ||
926 | } | ||
927 | |||
928 | void ath6kl_debug_cleanup(struct ath6kl *ar) | ||
929 | { | ||
930 | vfree(ar->debug.fwlog_buf.buf); | ||
931 | kfree(ar->debug.fwlog_tmp); | ||
932 | } | ||
933 | |||
150 | #endif | 934 | #endif |
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index 66b399962f01..9288a3ce1e39 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h | |||
@@ -34,8 +34,12 @@ enum ATH6K_DEBUG_MASK { | |||
34 | ATH6KL_DBG_TRC = BIT(11), /* generic func tracing */ | 34 | ATH6KL_DBG_TRC = BIT(11), /* generic func tracing */ |
35 | ATH6KL_DBG_SCATTER = BIT(12), /* hif scatter tracing */ | 35 | ATH6KL_DBG_SCATTER = BIT(12), /* hif scatter tracing */ |
36 | ATH6KL_DBG_WLAN_CFG = BIT(13), /* cfg80211 i/f file tracing */ | 36 | ATH6KL_DBG_WLAN_CFG = BIT(13), /* cfg80211 i/f file tracing */ |
37 | ATH6KL_DBG_RAW_BYTES = BIT(14), /* dump tx/rx and wmi frames */ | 37 | ATH6KL_DBG_RAW_BYTES = BIT(14), /* dump tx/rx frames */ |
38 | ATH6KL_DBG_AGGR = BIT(15), /* aggregation */ | 38 | ATH6KL_DBG_AGGR = BIT(15), /* aggregation */ |
39 | ATH6KL_DBG_SDIO = BIT(16), | ||
40 | ATH6KL_DBG_SDIO_DUMP = BIT(17), | ||
41 | ATH6KL_DBG_BOOT = BIT(18), /* driver init and fw boot */ | ||
42 | ATH6KL_DBG_WMI_DUMP = BIT(19), | ||
39 | ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ | 43 | ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ |
40 | }; | 44 | }; |
41 | 45 | ||
@@ -52,6 +56,10 @@ extern int ath6kl_printk(const char *level, const char *fmt, ...) | |||
52 | 56 | ||
53 | #define AR_DBG_LVL_CHECK(mask) (debug_mask & mask) | 57 | #define AR_DBG_LVL_CHECK(mask) (debug_mask & mask) |
54 | 58 | ||
59 | enum ath6kl_war { | ||
60 | ATH6KL_WAR_INVALID_RATE, | ||
61 | }; | ||
62 | |||
55 | #ifdef CONFIG_ATH6KL_DEBUG | 63 | #ifdef CONFIG_ATH6KL_DEBUG |
56 | #define ath6kl_dbg(mask, fmt, ...) \ | 64 | #define ath6kl_dbg(mask, fmt, ...) \ |
57 | ({ \ | 65 | ({ \ |
@@ -65,12 +73,14 @@ extern int ath6kl_printk(const char *level, const char *fmt, ...) | |||
65 | }) | 73 | }) |
66 | 74 | ||
67 | static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, | 75 | static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, |
68 | const char *msg, const void *buf, | 76 | const char *msg, const char *prefix, |
69 | size_t len) | 77 | const void *buf, size_t len) |
70 | { | 78 | { |
71 | if (debug_mask & mask) { | 79 | if (debug_mask & mask) { |
72 | ath6kl_dbg(mask, "%s\n", msg); | 80 | if (msg) |
73 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len); | 81 | ath6kl_dbg(mask, "%s\n", msg); |
82 | |||
83 | print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); | ||
74 | } | 84 | } |
75 | } | 85 | } |
76 | 86 | ||
@@ -78,6 +88,11 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, | |||
78 | struct ath6kl_irq_proc_registers *irq_proc_reg, | 88 | struct ath6kl_irq_proc_registers *irq_proc_reg, |
79 | struct ath6kl_irq_enable_reg *irq_en_reg); | 89 | struct ath6kl_irq_enable_reg *irq_en_reg); |
80 | void dump_cred_dist_stats(struct htc_target *target); | 90 | void dump_cred_dist_stats(struct htc_target *target); |
91 | void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len); | ||
92 | void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war); | ||
93 | int ath6kl_debug_init(struct ath6kl *ar); | ||
94 | void ath6kl_debug_cleanup(struct ath6kl *ar); | ||
95 | |||
81 | #else | 96 | #else |
82 | static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask, | 97 | static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask, |
83 | const char *fmt, ...) | 98 | const char *fmt, ...) |
@@ -86,8 +101,8 @@ static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask, | |||
86 | } | 101 | } |
87 | 102 | ||
88 | static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, | 103 | static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, |
89 | const char *msg, const void *buf, | 104 | const char *msg, const char *prefix, |
90 | size_t len) | 105 | const void *buf, size_t len) |
91 | { | 106 | { |
92 | } | 107 | } |
93 | 108 | ||
@@ -100,6 +115,24 @@ static inline void ath6kl_dump_registers(struct ath6kl_device *dev, | |||
100 | static inline void dump_cred_dist_stats(struct htc_target *target) | 115 | static inline void dump_cred_dist_stats(struct htc_target *target) |
101 | { | 116 | { |
102 | } | 117 | } |
103 | #endif | ||
104 | 118 | ||
119 | static inline void ath6kl_debug_fwlog_event(struct ath6kl *ar, | ||
120 | const void *buf, size_t len) | ||
121 | { | ||
122 | } | ||
123 | |||
124 | static inline void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war) | ||
125 | { | ||
126 | } | ||
127 | |||
128 | static inline int ath6kl_debug_init(struct ath6kl *ar) | ||
129 | { | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static inline void ath6kl_debug_cleanup(struct ath6kl *ar) | ||
134 | { | ||
135 | } | ||
136 | |||
137 | #endif | ||
105 | #endif | 138 | #endif |
diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h index c923979776a0..d6c898f3d0b3 100644 --- a/drivers/net/wireless/ath/ath6kl/hif-ops.h +++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h | |||
@@ -69,4 +69,9 @@ static inline void ath6kl_hif_cleanup_scatter(struct ath6kl *ar) | |||
69 | return ar->hif_ops->cleanup_scatter(ar); | 69 | return ar->hif_ops->cleanup_scatter(ar); |
70 | } | 70 | } |
71 | 71 | ||
72 | static inline int ath6kl_hif_suspend(struct ath6kl *ar) | ||
73 | { | ||
74 | return ar->hif_ops->suspend(ar); | ||
75 | } | ||
76 | |||
72 | #endif | 77 | #endif |
diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h index 5ceff54775a1..797e2d1d9bf9 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.h +++ b/drivers/net/wireless/ath/ath6kl/hif.h | |||
@@ -202,6 +202,7 @@ struct ath6kl_hif_ops { | |||
202 | int (*scat_req_rw) (struct ath6kl *ar, | 202 | int (*scat_req_rw) (struct ath6kl *ar, |
203 | struct hif_scatter_req *scat_req); | 203 | struct hif_scatter_req *scat_req); |
204 | void (*cleanup_scatter)(struct ath6kl *ar); | 204 | void (*cleanup_scatter)(struct ath6kl *ar); |
205 | int (*suspend)(struct ath6kl *ar); | ||
205 | }; | 206 | }; |
206 | 207 | ||
207 | #endif | 208 | #endif |
diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c index a8dc5c3ea567..f88a7c9e4148 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.c +++ b/drivers/net/wireless/ath/ath6kl/htc.c | |||
@@ -22,8 +22,19 @@ | |||
22 | 22 | ||
23 | #define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) | 23 | #define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) |
24 | 24 | ||
25 | static void htc_prep_send_pkt(struct htc_packet *packet, u8 flags, int ctrl0, | 25 | static void ath6kl_htc_tx_buf_align(u8 **buf, unsigned long len) |
26 | int ctrl1) | 26 | { |
27 | u8 *align_addr; | ||
28 | |||
29 | if (!IS_ALIGNED((unsigned long) *buf, 4)) { | ||
30 | align_addr = PTR_ALIGN(*buf - 4, 4); | ||
31 | memmove(align_addr, *buf, len); | ||
32 | *buf = align_addr; | ||
33 | } | ||
34 | } | ||
35 | |||
36 | static void ath6kl_htc_tx_prep_pkt(struct htc_packet *packet, u8 flags, | ||
37 | int ctrl0, int ctrl1) | ||
27 | { | 38 | { |
28 | struct htc_frame_hdr *hdr; | 39 | struct htc_frame_hdr *hdr; |
29 | 40 | ||
@@ -167,7 +178,8 @@ static void htc_async_tx_scat_complete(struct htc_target *target, | |||
167 | htc_tx_complete(endpoint, &tx_compq); | 178 | htc_tx_complete(endpoint, &tx_compq); |
168 | } | 179 | } |
169 | 180 | ||
170 | static int htc_issue_send(struct htc_target *target, struct htc_packet *packet) | 181 | static int ath6kl_htc_tx_issue(struct htc_target *target, |
182 | struct htc_packet *packet) | ||
171 | { | 183 | { |
172 | int status; | 184 | int status; |
173 | bool sync = false; | 185 | bool sync = false; |
@@ -196,7 +208,7 @@ static int htc_issue_send(struct htc_target *target, struct htc_packet *packet) | |||
196 | HIF_WR_SYNC_BLOCK_INC); | 208 | HIF_WR_SYNC_BLOCK_INC); |
197 | 209 | ||
198 | packet->status = status; | 210 | packet->status = status; |
199 | packet->buf += HTC_HDR_LENGTH; | 211 | packet->buf += HTC_HDR_LENGTH; |
200 | } else | 212 | } else |
201 | status = hif_write_async(target->dev->ar, | 213 | status = hif_write_async(target->dev->ar, |
202 | target->dev->ar->mbox_info.htc_addr, | 214 | target->dev->ar->mbox_info.htc_addr, |
@@ -265,9 +277,9 @@ static int htc_check_credits(struct htc_target *target, | |||
265 | return 0; | 277 | return 0; |
266 | } | 278 | } |
267 | 279 | ||
268 | static void htc_tx_pkts_get(struct htc_target *target, | 280 | static void ath6kl_htc_tx_pkts_get(struct htc_target *target, |
269 | struct htc_endpoint *endpoint, | 281 | struct htc_endpoint *endpoint, |
270 | struct list_head *queue) | 282 | struct list_head *queue) |
271 | { | 283 | { |
272 | int req_cred; | 284 | int req_cred; |
273 | u8 flags; | 285 | u8 flags; |
@@ -346,11 +358,11 @@ static int htc_get_credit_padding(unsigned int cred_sz, int *len, | |||
346 | return cred_pad; | 358 | return cred_pad; |
347 | } | 359 | } |
348 | 360 | ||
349 | static int htc_setup_send_scat_list(struct htc_target *target, | 361 | static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target, |
350 | struct htc_endpoint *endpoint, | 362 | struct htc_endpoint *endpoint, |
351 | struct hif_scatter_req *scat_req, | 363 | struct hif_scatter_req *scat_req, |
352 | int n_scat, | 364 | int n_scat, |
353 | struct list_head *queue) | 365 | struct list_head *queue) |
354 | { | 366 | { |
355 | struct htc_packet *packet; | 367 | struct htc_packet *packet; |
356 | int i, len, rem_scat, cred_pad; | 368 | int i, len, rem_scat, cred_pad; |
@@ -370,27 +382,23 @@ static int htc_setup_send_scat_list(struct htc_target *target, | |||
370 | 382 | ||
371 | cred_pad = htc_get_credit_padding(target->tgt_cred_sz, | 383 | cred_pad = htc_get_credit_padding(target->tgt_cred_sz, |
372 | &len, endpoint); | 384 | &len, endpoint); |
373 | if (cred_pad < 0) { | 385 | if (cred_pad < 0 || rem_scat < len) { |
374 | status = -EINVAL; | ||
375 | break; | ||
376 | } | ||
377 | |||
378 | if (rem_scat < len) { | ||
379 | /* exceeds what we can transfer */ | ||
380 | status = -ENOSPC; | 386 | status = -ENOSPC; |
381 | break; | 387 | break; |
382 | } | 388 | } |
383 | 389 | ||
384 | rem_scat -= len; | 390 | rem_scat -= len; |
385 | /* now remove it from the queue */ | 391 | /* now remove it from the queue */ |
386 | packet = list_first_entry(queue, struct htc_packet, list); | ||
387 | list_del(&packet->list); | 392 | list_del(&packet->list); |
388 | 393 | ||
389 | scat_req->scat_list[i].packet = packet; | 394 | scat_req->scat_list[i].packet = packet; |
390 | /* prepare packet and flag message as part of a send bundle */ | 395 | /* prepare packet and flag message as part of a send bundle */ |
391 | htc_prep_send_pkt(packet, | 396 | ath6kl_htc_tx_prep_pkt(packet, |
392 | packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE, | 397 | packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE, |
393 | cred_pad, packet->info.tx.seqno); | 398 | cred_pad, packet->info.tx.seqno); |
399 | /* Make sure the buffer is 4-byte aligned */ | ||
400 | ath6kl_htc_tx_buf_align(&packet->buf, | ||
401 | packet->act_len + HTC_HDR_LENGTH); | ||
394 | scat_req->scat_list[i].buf = packet->buf; | 402 | scat_req->scat_list[i].buf = packet->buf; |
395 | scat_req->scat_list[i].len = len; | 403 | scat_req->scat_list[i].len = len; |
396 | 404 | ||
@@ -402,7 +410,7 @@ static int htc_setup_send_scat_list(struct htc_target *target, | |||
402 | } | 410 | } |
403 | 411 | ||
404 | /* Roll back scatter setup in case of any failure */ | 412 | /* Roll back scatter setup in case of any failure */ |
405 | if (status || (scat_req->scat_entries < HTC_MIN_HTC_MSGS_TO_BUNDLE)) { | 413 | if (scat_req->scat_entries < HTC_MIN_HTC_MSGS_TO_BUNDLE) { |
406 | for (i = scat_req->scat_entries - 1; i >= 0; i--) { | 414 | for (i = scat_req->scat_entries - 1; i >= 0; i--) { |
407 | packet = scat_req->scat_list[i].packet; | 415 | packet = scat_req->scat_list[i].packet; |
408 | if (packet) { | 416 | if (packet) { |
@@ -410,31 +418,32 @@ static int htc_setup_send_scat_list(struct htc_target *target, | |||
410 | list_add(&packet->list, queue); | 418 | list_add(&packet->list, queue); |
411 | } | 419 | } |
412 | } | 420 | } |
413 | return -EINVAL; | 421 | return -EAGAIN; |
414 | } | 422 | } |
415 | 423 | ||
416 | return 0; | 424 | return status; |
417 | } | 425 | } |
418 | 426 | ||
419 | /* | 427 | /* |
420 | * htc_issue_send_bundle: drain a queue and send as bundles | 428 | * Drain a queue and send as bundles this function may return without fully |
421 | * this function may return without fully draining the queue | 429 | * draining the queue when |
422 | * when | ||
423 | * | 430 | * |
424 | * 1. scatter resources are exhausted | 431 | * 1. scatter resources are exhausted |
425 | * 2. a message that will consume a partial credit will stop the | 432 | * 2. a message that will consume a partial credit will stop the |
426 | * bundling process early | 433 | * bundling process early |
427 | * 3. we drop below the minimum number of messages for a bundle | 434 | * 3. we drop below the minimum number of messages for a bundle |
428 | */ | 435 | */ |
429 | static void htc_issue_send_bundle(struct htc_endpoint *endpoint, | 436 | static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, |
430 | struct list_head *queue, | 437 | struct list_head *queue, |
431 | int *sent_bundle, int *n_bundle_pkts) | 438 | int *sent_bundle, int *n_bundle_pkts) |
432 | { | 439 | { |
433 | struct htc_target *target = endpoint->target; | 440 | struct htc_target *target = endpoint->target; |
434 | struct hif_scatter_req *scat_req = NULL; | 441 | struct hif_scatter_req *scat_req = NULL; |
435 | int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0; | 442 | int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0; |
443 | int status; | ||
436 | 444 | ||
437 | while (true) { | 445 | while (true) { |
446 | status = 0; | ||
438 | n_scat = get_queue_depth(queue); | 447 | n_scat = get_queue_depth(queue); |
439 | n_scat = min(n_scat, target->msg_per_bndl_max); | 448 | n_scat = min(n_scat, target->msg_per_bndl_max); |
440 | 449 | ||
@@ -457,8 +466,10 @@ static void htc_issue_send_bundle(struct htc_endpoint *endpoint, | |||
457 | scat_req->len = 0; | 466 | scat_req->len = 0; |
458 | scat_req->scat_entries = 0; | 467 | scat_req->scat_entries = 0; |
459 | 468 | ||
460 | if (htc_setup_send_scat_list(target, endpoint, scat_req, | 469 | status = ath6kl_htc_tx_setup_scat_list(target, endpoint, |
461 | n_scat, queue)) { | 470 | scat_req, n_scat, |
471 | queue); | ||
472 | if (status == -EAGAIN) { | ||
462 | hif_scatter_req_add(target->dev->ar, scat_req); | 473 | hif_scatter_req_add(target->dev->ar, scat_req); |
463 | break; | 474 | break; |
464 | } | 475 | } |
@@ -472,18 +483,21 @@ static void htc_issue_send_bundle(struct htc_endpoint *endpoint, | |||
472 | "send scatter total bytes: %d , entries: %d\n", | 483 | "send scatter total bytes: %d , entries: %d\n", |
473 | scat_req->len, scat_req->scat_entries); | 484 | scat_req->len, scat_req->scat_entries); |
474 | ath6kldev_submit_scat_req(target->dev, scat_req, false); | 485 | ath6kldev_submit_scat_req(target->dev, scat_req, false); |
486 | |||
487 | if (status) | ||
488 | break; | ||
475 | } | 489 | } |
476 | 490 | ||
477 | *sent_bundle = n_sent_bundle; | 491 | *sent_bundle = n_sent_bundle; |
478 | *n_bundle_pkts = tot_pkts_bundle; | 492 | *n_bundle_pkts = tot_pkts_bundle; |
479 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "htc_issue_send_bundle (sent:%d)\n", | 493 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "%s (sent:%d)\n", |
480 | n_sent_bundle); | 494 | __func__, n_sent_bundle); |
481 | 495 | ||
482 | return; | 496 | return; |
483 | } | 497 | } |
484 | 498 | ||
485 | static void htc_tx_from_ep_txq(struct htc_target *target, | 499 | static void ath6kl_htc_tx_from_queue(struct htc_target *target, |
486 | struct htc_endpoint *endpoint) | 500 | struct htc_endpoint *endpoint) |
487 | { | 501 | { |
488 | struct list_head txq; | 502 | struct list_head txq; |
489 | struct htc_packet *packet; | 503 | struct htc_packet *packet; |
@@ -511,7 +525,7 @@ static void htc_tx_from_ep_txq(struct htc_target *target, | |||
511 | if (list_empty(&endpoint->txq)) | 525 | if (list_empty(&endpoint->txq)) |
512 | break; | 526 | break; |
513 | 527 | ||
514 | htc_tx_pkts_get(target, endpoint, &txq); | 528 | ath6kl_htc_tx_pkts_get(target, endpoint, &txq); |
515 | 529 | ||
516 | if (list_empty(&txq)) | 530 | if (list_empty(&txq)) |
517 | break; | 531 | break; |
@@ -528,8 +542,8 @@ static void htc_tx_from_ep_txq(struct htc_target *target, | |||
528 | HTC_MIN_HTC_MSGS_TO_BUNDLE)) { | 542 | HTC_MIN_HTC_MSGS_TO_BUNDLE)) { |
529 | int temp1 = 0, temp2 = 0; | 543 | int temp1 = 0, temp2 = 0; |
530 | 544 | ||
531 | htc_issue_send_bundle(endpoint, &txq, | 545 | ath6kl_htc_tx_bundle(endpoint, &txq, |
532 | &temp1, &temp2); | 546 | &temp1, &temp2); |
533 | bundle_sent += temp1; | 547 | bundle_sent += temp1; |
534 | n_pkts_bundle += temp2; | 548 | n_pkts_bundle += temp2; |
535 | } | 549 | } |
@@ -541,9 +555,9 @@ static void htc_tx_from_ep_txq(struct htc_target *target, | |||
541 | list); | 555 | list); |
542 | list_del(&packet->list); | 556 | list_del(&packet->list); |
543 | 557 | ||
544 | htc_prep_send_pkt(packet, packet->info.tx.flags, | 558 | ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags, |
545 | 0, packet->info.tx.seqno); | 559 | 0, packet->info.tx.seqno); |
546 | htc_issue_send(target, packet); | 560 | ath6kl_htc_tx_issue(target, packet); |
547 | } | 561 | } |
548 | 562 | ||
549 | spin_lock_bh(&target->tx_lock); | 563 | spin_lock_bh(&target->tx_lock); |
@@ -556,9 +570,9 @@ static void htc_tx_from_ep_txq(struct htc_target *target, | |||
556 | spin_unlock_bh(&target->tx_lock); | 570 | spin_unlock_bh(&target->tx_lock); |
557 | } | 571 | } |
558 | 572 | ||
559 | static bool htc_try_send(struct htc_target *target, | 573 | static bool ath6kl_htc_tx_try(struct htc_target *target, |
560 | struct htc_endpoint *endpoint, | 574 | struct htc_endpoint *endpoint, |
561 | struct htc_packet *tx_pkt) | 575 | struct htc_packet *tx_pkt) |
562 | { | 576 | { |
563 | struct htc_ep_callbacks ep_cb; | 577 | struct htc_ep_callbacks ep_cb; |
564 | int txq_depth; | 578 | int txq_depth; |
@@ -594,7 +608,7 @@ static bool htc_try_send(struct htc_target *target, | |||
594 | list_add_tail(&tx_pkt->list, &endpoint->txq); | 608 | list_add_tail(&tx_pkt->list, &endpoint->txq); |
595 | spin_unlock_bh(&target->tx_lock); | 609 | spin_unlock_bh(&target->tx_lock); |
596 | 610 | ||
597 | htc_tx_from_ep_txq(target, endpoint); | 611 | ath6kl_htc_tx_from_queue(target, endpoint); |
598 | 612 | ||
599 | return true; | 613 | return true; |
600 | } | 614 | } |
@@ -628,7 +642,7 @@ static void htc_chk_ep_txq(struct htc_target *target) | |||
628 | * chance to reclaim credits from lower priority | 642 | * chance to reclaim credits from lower priority |
629 | * ones. | 643 | * ones. |
630 | */ | 644 | */ |
631 | htc_tx_from_ep_txq(target, endpoint); | 645 | ath6kl_htc_tx_from_queue(target, endpoint); |
632 | spin_lock_bh(&target->tx_lock); | 646 | spin_lock_bh(&target->tx_lock); |
633 | } | 647 | } |
634 | spin_unlock_bh(&target->tx_lock); | 648 | spin_unlock_bh(&target->tx_lock); |
@@ -680,8 +694,8 @@ static int htc_setup_tx_complete(struct htc_target *target) | |||
680 | 694 | ||
681 | /* we want synchronous operation */ | 695 | /* we want synchronous operation */ |
682 | send_pkt->completion = NULL; | 696 | send_pkt->completion = NULL; |
683 | htc_prep_send_pkt(send_pkt, 0, 0, 0); | 697 | ath6kl_htc_tx_prep_pkt(send_pkt, 0, 0, 0); |
684 | status = htc_issue_send(target, send_pkt); | 698 | status = ath6kl_htc_tx_issue(target, send_pkt); |
685 | 699 | ||
686 | if (send_pkt != NULL) | 700 | if (send_pkt != NULL) |
687 | htc_reclaim_txctrl_buf(target, send_pkt); | 701 | htc_reclaim_txctrl_buf(target, send_pkt); |
@@ -733,7 +747,7 @@ int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet) | |||
733 | 747 | ||
734 | endpoint = &target->endpoint[packet->endpoint]; | 748 | endpoint = &target->endpoint[packet->endpoint]; |
735 | 749 | ||
736 | if (!htc_try_send(target, endpoint, packet)) { | 750 | if (!ath6kl_htc_tx_try(target, endpoint, packet)) { |
737 | packet->status = (target->htc_flags & HTC_OP_STATE_STOPPING) ? | 751 | packet->status = (target->htc_flags & HTC_OP_STATE_STOPPING) ? |
738 | -ECANCELED : -ENOSPC; | 752 | -ECANCELED : -ENOSPC; |
739 | INIT_LIST_HEAD(&queue); | 753 | INIT_LIST_HEAD(&queue); |
@@ -846,8 +860,8 @@ void ath6kl_htc_indicate_activity_change(struct htc_target *target, | |||
846 | 860 | ||
847 | /* HTC Rx */ | 861 | /* HTC Rx */ |
848 | 862 | ||
849 | static inline void htc_update_rx_stats(struct htc_endpoint *endpoint, | 863 | static inline void ath6kl_htc_rx_update_stats(struct htc_endpoint *endpoint, |
850 | int n_look_ahds) | 864 | int n_look_ahds) |
851 | { | 865 | { |
852 | endpoint->ep_st.rx_pkts++; | 866 | endpoint->ep_st.rx_pkts++; |
853 | if (n_look_ahds == 1) | 867 | if (n_look_ahds == 1) |
@@ -894,8 +908,9 @@ static void reclaim_rx_ctrl_buf(struct htc_target *target, | |||
894 | spin_unlock_bh(&target->htc_lock); | 908 | spin_unlock_bh(&target->htc_lock); |
895 | } | 909 | } |
896 | 910 | ||
897 | static int dev_rx_pkt(struct htc_target *target, struct htc_packet *packet, | 911 | static int ath6kl_htc_rx_packet(struct htc_target *target, |
898 | u32 rx_len) | 912 | struct htc_packet *packet, |
913 | u32 rx_len) | ||
899 | { | 914 | { |
900 | struct ath6kl_device *dev = target->dev; | 915 | struct ath6kl_device *dev = target->dev; |
901 | u32 padded_len; | 916 | u32 padded_len; |
@@ -929,9 +944,9 @@ static int dev_rx_pkt(struct htc_target *target, struct htc_packet *packet, | |||
929 | * "hint" that there are more single-packets to fetch | 944 | * "hint" that there are more single-packets to fetch |
930 | * on this endpoint. | 945 | * on this endpoint. |
931 | */ | 946 | */ |
932 | static void set_rxpkt_indication_flag(u32 lk_ahd, | 947 | static void ath6kl_htc_rx_set_indicate(u32 lk_ahd, |
933 | struct htc_endpoint *endpoint, | 948 | struct htc_endpoint *endpoint, |
934 | struct htc_packet *packet) | 949 | struct htc_packet *packet) |
935 | { | 950 | { |
936 | struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)&lk_ahd; | 951 | struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)&lk_ahd; |
937 | 952 | ||
@@ -942,7 +957,7 @@ static void set_rxpkt_indication_flag(u32 lk_ahd, | |||
942 | } | 957 | } |
943 | } | 958 | } |
944 | 959 | ||
945 | static void chk_rx_water_mark(struct htc_endpoint *endpoint) | 960 | static void ath6kl_htc_rx_chk_water_mark(struct htc_endpoint *endpoint) |
946 | { | 961 | { |
947 | struct htc_ep_callbacks ep_cb = endpoint->ep_cb; | 962 | struct htc_ep_callbacks ep_cb = endpoint->ep_cb; |
948 | 963 | ||
@@ -959,8 +974,9 @@ static void chk_rx_water_mark(struct htc_endpoint *endpoint) | |||
959 | } | 974 | } |
960 | 975 | ||
961 | /* This function is called with rx_lock held */ | 976 | /* This function is called with rx_lock held */ |
962 | static int htc_setup_rxpkts(struct htc_target *target, struct htc_endpoint *ep, | 977 | static int ath6kl_htc_rx_setup(struct htc_target *target, |
963 | u32 *lk_ahds, struct list_head *queue, int n_msg) | 978 | struct htc_endpoint *ep, |
979 | u32 *lk_ahds, struct list_head *queue, int n_msg) | ||
964 | { | 980 | { |
965 | struct htc_packet *packet; | 981 | struct htc_packet *packet; |
966 | /* FIXME: type of lk_ahds can't be right */ | 982 | /* FIXME: type of lk_ahds can't be right */ |
@@ -1060,10 +1076,10 @@ static int htc_setup_rxpkts(struct htc_target *target, struct htc_endpoint *ep, | |||
1060 | return status; | 1076 | return status; |
1061 | } | 1077 | } |
1062 | 1078 | ||
1063 | static int alloc_and_prep_rxpkts(struct htc_target *target, | 1079 | static int ath6kl_htc_rx_alloc(struct htc_target *target, |
1064 | u32 lk_ahds[], int msg, | 1080 | u32 lk_ahds[], int msg, |
1065 | struct htc_endpoint *endpoint, | 1081 | struct htc_endpoint *endpoint, |
1066 | struct list_head *queue) | 1082 | struct list_head *queue) |
1067 | { | 1083 | { |
1068 | int status = 0; | 1084 | int status = 0; |
1069 | struct htc_packet *packet, *tmp_pkt; | 1085 | struct htc_packet *packet, *tmp_pkt; |
@@ -1129,8 +1145,8 @@ static int alloc_and_prep_rxpkts(struct htc_target *target, | |||
1129 | n_msg = 1; | 1145 | n_msg = 1; |
1130 | 1146 | ||
1131 | /* Setup packet buffers for each message */ | 1147 | /* Setup packet buffers for each message */ |
1132 | status = htc_setup_rxpkts(target, endpoint, &lk_ahds[i], queue, | 1148 | status = ath6kl_htc_rx_setup(target, endpoint, &lk_ahds[i], |
1133 | n_msg); | 1149 | queue, n_msg); |
1134 | 1150 | ||
1135 | /* | 1151 | /* |
1136 | * This is due to unavailabilty of buffers to rx entire data. | 1152 | * This is due to unavailabilty of buffers to rx entire data. |
@@ -1176,9 +1192,9 @@ static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets) | |||
1176 | packets->act_len + HTC_HDR_LENGTH); | 1192 | packets->act_len + HTC_HDR_LENGTH); |
1177 | 1193 | ||
1178 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, | 1194 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, |
1179 | "Unexpected ENDPOINT 0 Message", | 1195 | "Unexpected ENDPOINT 0 Message", "", |
1180 | packets->buf - HTC_HDR_LENGTH, | 1196 | packets->buf - HTC_HDR_LENGTH, |
1181 | packets->act_len + HTC_HDR_LENGTH); | 1197 | packets->act_len + HTC_HDR_LENGTH); |
1182 | } | 1198 | } |
1183 | 1199 | ||
1184 | htc_reclaim_rxbuf(context, packets, &context->endpoint[0]); | 1200 | htc_reclaim_rxbuf(context, packets, &context->endpoint[0]); |
@@ -1312,7 +1328,7 @@ static int htc_parse_trailer(struct htc_target *target, | |||
1312 | memcpy((u8 *)&next_lk_ahds[0], lk_ahd->lk_ahd, 4); | 1328 | memcpy((u8 *)&next_lk_ahds[0], lk_ahd->lk_ahd, 4); |
1313 | 1329 | ||
1314 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Next Look Ahead", | 1330 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Next Look Ahead", |
1315 | next_lk_ahds, 4); | 1331 | "", next_lk_ahds, 4); |
1316 | 1332 | ||
1317 | *n_lk_ahds = 1; | 1333 | *n_lk_ahds = 1; |
1318 | } | 1334 | } |
@@ -1331,7 +1347,7 @@ static int htc_parse_trailer(struct htc_target *target, | |||
1331 | (struct htc_bundle_lkahd_rpt *) record_buf; | 1347 | (struct htc_bundle_lkahd_rpt *) record_buf; |
1332 | 1348 | ||
1333 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Bundle lk_ahd", | 1349 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Bundle lk_ahd", |
1334 | record_buf, record->len); | 1350 | "", record_buf, record->len); |
1335 | 1351 | ||
1336 | for (i = 0; i < len; i++) { | 1352 | for (i = 0; i < len; i++) { |
1337 | memcpy((u8 *)&next_lk_ahds[i], | 1353 | memcpy((u8 *)&next_lk_ahds[i], |
@@ -1364,7 +1380,8 @@ static int htc_proc_trailer(struct htc_target *target, | |||
1364 | 1380 | ||
1365 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "+htc_proc_trailer (len:%d)\n", len); | 1381 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "+htc_proc_trailer (len:%d)\n", len); |
1366 | 1382 | ||
1367 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Recv Trailer", buf, len); | 1383 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Recv Trailer", "", |
1384 | buf, len); | ||
1368 | 1385 | ||
1369 | orig_buf = buf; | 1386 | orig_buf = buf; |
1370 | orig_len = len; | 1387 | orig_len = len; |
@@ -1402,14 +1419,14 @@ static int htc_proc_trailer(struct htc_target *target, | |||
1402 | 1419 | ||
1403 | if (status) | 1420 | if (status) |
1404 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD Recv Trailer", | 1421 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD Recv Trailer", |
1405 | orig_buf, orig_len); | 1422 | "", orig_buf, orig_len); |
1406 | 1423 | ||
1407 | return status; | 1424 | return status; |
1408 | } | 1425 | } |
1409 | 1426 | ||
1410 | static int htc_proc_rxhdr(struct htc_target *target, | 1427 | static int ath6kl_htc_rx_process_hdr(struct htc_target *target, |
1411 | struct htc_packet *packet, | 1428 | struct htc_packet *packet, |
1412 | u32 *next_lkahds, int *n_lkahds) | 1429 | u32 *next_lkahds, int *n_lkahds) |
1413 | { | 1430 | { |
1414 | int status = 0; | 1431 | int status = 0; |
1415 | u16 payload_len; | 1432 | u16 payload_len; |
@@ -1419,8 +1436,8 @@ static int htc_proc_rxhdr(struct htc_target *target, | |||
1419 | if (n_lkahds != NULL) | 1436 | if (n_lkahds != NULL) |
1420 | *n_lkahds = 0; | 1437 | *n_lkahds = 0; |
1421 | 1438 | ||
1422 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "HTC Recv PKT", packet->buf, | 1439 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "HTC Recv PKT", "htc ", |
1423 | packet->act_len); | 1440 | packet->buf, packet->act_len); |
1424 | 1441 | ||
1425 | /* | 1442 | /* |
1426 | * NOTE: we cannot assume the alignment of buf, so we use the safe | 1443 | * NOTE: we cannot assume the alignment of buf, so we use the safe |
@@ -1461,12 +1478,12 @@ static int htc_proc_rxhdr(struct htc_target *target, | |||
1461 | } | 1478 | } |
1462 | 1479 | ||
1463 | if (lk_ahd != packet->info.rx.exp_hdr) { | 1480 | if (lk_ahd != packet->info.rx.exp_hdr) { |
1464 | ath6kl_err("htc_proc_rxhdr, lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n", | 1481 | ath6kl_err("%s(): lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n", |
1465 | packet, packet->info.rx.rx_flags); | 1482 | __func__, packet, packet->info.rx.rx_flags); |
1466 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Expected Message lk_ahd", | 1483 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Expected Message lk_ahd", |
1467 | &packet->info.rx.exp_hdr, 4); | 1484 | "", &packet->info.rx.exp_hdr, 4); |
1468 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Current Frame Header", | 1485 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Current Frame Header", |
1469 | (u8 *)&lk_ahd, sizeof(lk_ahd)); | 1486 | "", (u8 *)&lk_ahd, sizeof(lk_ahd)); |
1470 | status = -ENOMEM; | 1487 | status = -ENOMEM; |
1471 | goto fail_rx; | 1488 | goto fail_rx; |
1472 | } | 1489 | } |
@@ -1474,8 +1491,8 @@ static int htc_proc_rxhdr(struct htc_target *target, | |||
1474 | if (htc_hdr->flags & HTC_FLG_RX_TRAILER) { | 1491 | if (htc_hdr->flags & HTC_FLG_RX_TRAILER) { |
1475 | if (htc_hdr->ctrl[0] < sizeof(struct htc_record_hdr) || | 1492 | if (htc_hdr->ctrl[0] < sizeof(struct htc_record_hdr) || |
1476 | htc_hdr->ctrl[0] > payload_len) { | 1493 | htc_hdr->ctrl[0] > payload_len) { |
1477 | ath6kl_err("htc_proc_rxhdr, invalid hdr (payload len should be :%d, CB[0] is:%d)\n", | 1494 | ath6kl_err("%s(): invalid hdr (payload len should be :%d, CB[0] is:%d)\n", |
1478 | payload_len, htc_hdr->ctrl[0]); | 1495 | __func__, payload_len, htc_hdr->ctrl[0]); |
1479 | status = -ENOMEM; | 1496 | status = -ENOMEM; |
1480 | goto fail_rx; | 1497 | goto fail_rx; |
1481 | } | 1498 | } |
@@ -1502,20 +1519,20 @@ static int htc_proc_rxhdr(struct htc_target *target, | |||
1502 | fail_rx: | 1519 | fail_rx: |
1503 | if (status) | 1520 | if (status) |
1504 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD HTC Recv PKT", | 1521 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD HTC Recv PKT", |
1505 | packet->buf, | 1522 | "", packet->buf, |
1506 | packet->act_len < 256 ? packet->act_len : 256); | 1523 | packet->act_len < 256 ? packet->act_len : 256); |
1507 | else { | 1524 | else { |
1508 | if (packet->act_len > 0) | 1525 | if (packet->act_len > 0) |
1509 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, | 1526 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, |
1510 | "HTC - Application Msg", | 1527 | "HTC - Application Msg", "", |
1511 | packet->buf, packet->act_len); | 1528 | packet->buf, packet->act_len); |
1512 | } | 1529 | } |
1513 | 1530 | ||
1514 | return status; | 1531 | return status; |
1515 | } | 1532 | } |
1516 | 1533 | ||
1517 | static void do_rx_completion(struct htc_endpoint *endpoint, | 1534 | static void ath6kl_htc_rx_complete(struct htc_endpoint *endpoint, |
1518 | struct htc_packet *packet) | 1535 | struct htc_packet *packet) |
1519 | { | 1536 | { |
1520 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | 1537 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, |
1521 | "htc calling ep %d recv callback on packet 0x%p\n", | 1538 | "htc calling ep %d recv callback on packet 0x%p\n", |
@@ -1523,10 +1540,10 @@ static void do_rx_completion(struct htc_endpoint *endpoint, | |||
1523 | endpoint->ep_cb.rx(endpoint->target, packet); | 1540 | endpoint->ep_cb.rx(endpoint->target, packet); |
1524 | } | 1541 | } |
1525 | 1542 | ||
1526 | static int htc_issue_rxpkt_bundle(struct htc_target *target, | 1543 | static int ath6kl_htc_rx_bundle(struct htc_target *target, |
1527 | struct list_head *rxq, | 1544 | struct list_head *rxq, |
1528 | struct list_head *sync_compq, | 1545 | struct list_head *sync_compq, |
1529 | int *n_pkt_fetched, bool part_bundle) | 1546 | int *n_pkt_fetched, bool part_bundle) |
1530 | { | 1547 | { |
1531 | struct hif_scatter_req *scat_req; | 1548 | struct hif_scatter_req *scat_req; |
1532 | struct htc_packet *packet; | 1549 | struct htc_packet *packet; |
@@ -1548,15 +1565,15 @@ static int htc_issue_rxpkt_bundle(struct htc_target *target, | |||
1548 | * This would only happen if the target ignored our max | 1565 | * This would only happen if the target ignored our max |
1549 | * bundle limit. | 1566 | * bundle limit. |
1550 | */ | 1567 | */ |
1551 | ath6kl_warn("htc_issue_rxpkt_bundle : partial bundle detected num:%d , %d\n", | 1568 | ath6kl_warn("%s(): partial bundle detected num:%d , %d\n", |
1552 | get_queue_depth(rxq), n_scat_pkt); | 1569 | __func__, get_queue_depth(rxq), n_scat_pkt); |
1553 | } | 1570 | } |
1554 | 1571 | ||
1555 | len = 0; | 1572 | len = 0; |
1556 | 1573 | ||
1557 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | 1574 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, |
1558 | "htc_issue_rxpkt_bundle (numpackets: %d , actual : %d)\n", | 1575 | "%s(): (numpackets: %d , actual : %d)\n", |
1559 | get_queue_depth(rxq), n_scat_pkt); | 1576 | __func__, get_queue_depth(rxq), n_scat_pkt); |
1560 | 1577 | ||
1561 | scat_req = hif_scatter_req_get(target->dev->ar); | 1578 | scat_req = hif_scatter_req_get(target->dev->ar); |
1562 | 1579 | ||
@@ -1616,9 +1633,10 @@ fail_rx_pkt: | |||
1616 | return status; | 1633 | return status; |
1617 | } | 1634 | } |
1618 | 1635 | ||
1619 | static int htc_proc_fetched_rxpkts(struct htc_target *target, | 1636 | static int ath6kl_htc_rx_process_packets(struct htc_target *target, |
1620 | struct list_head *comp_pktq, u32 lk_ahds[], | 1637 | struct list_head *comp_pktq, |
1621 | int *n_lk_ahd) | 1638 | u32 lk_ahds[], |
1639 | int *n_lk_ahd) | ||
1622 | { | 1640 | { |
1623 | struct htc_packet *packet, *tmp_pkt; | 1641 | struct htc_packet *packet, *tmp_pkt; |
1624 | struct htc_endpoint *ep; | 1642 | struct htc_endpoint *ep; |
@@ -1629,7 +1647,8 @@ static int htc_proc_fetched_rxpkts(struct htc_target *target, | |||
1629 | ep = &target->endpoint[packet->endpoint]; | 1647 | ep = &target->endpoint[packet->endpoint]; |
1630 | 1648 | ||
1631 | /* process header for each of the recv packet */ | 1649 | /* process header for each of the recv packet */ |
1632 | status = htc_proc_rxhdr(target, packet, lk_ahds, n_lk_ahd); | 1650 | status = ath6kl_htc_rx_process_hdr(target, packet, lk_ahds, |
1651 | n_lk_ahd); | ||
1633 | if (status) | 1652 | if (status) |
1634 | return status; | 1653 | return status; |
1635 | 1654 | ||
@@ -1639,8 +1658,8 @@ static int htc_proc_fetched_rxpkts(struct htc_target *target, | |||
1639 | * based on the lookahead. | 1658 | * based on the lookahead. |
1640 | */ | 1659 | */ |
1641 | if (*n_lk_ahd > 0) | 1660 | if (*n_lk_ahd > 0) |
1642 | set_rxpkt_indication_flag(lk_ahds[0], | 1661 | ath6kl_htc_rx_set_indicate(lk_ahds[0], |
1643 | ep, packet); | 1662 | ep, packet); |
1644 | } else | 1663 | } else |
1645 | /* | 1664 | /* |
1646 | * Packets in a bundle automatically have | 1665 | * Packets in a bundle automatically have |
@@ -1649,20 +1668,20 @@ static int htc_proc_fetched_rxpkts(struct htc_target *target, | |||
1649 | packet->info.rx.indicat_flags |= | 1668 | packet->info.rx.indicat_flags |= |
1650 | HTC_RX_FLAGS_INDICATE_MORE_PKTS; | 1669 | HTC_RX_FLAGS_INDICATE_MORE_PKTS; |
1651 | 1670 | ||
1652 | htc_update_rx_stats(ep, *n_lk_ahd); | 1671 | ath6kl_htc_rx_update_stats(ep, *n_lk_ahd); |
1653 | 1672 | ||
1654 | if (packet->info.rx.rx_flags & HTC_RX_PKT_PART_OF_BUNDLE) | 1673 | if (packet->info.rx.rx_flags & HTC_RX_PKT_PART_OF_BUNDLE) |
1655 | ep->ep_st.rx_bundl += 1; | 1674 | ep->ep_st.rx_bundl += 1; |
1656 | 1675 | ||
1657 | do_rx_completion(ep, packet); | 1676 | ath6kl_htc_rx_complete(ep, packet); |
1658 | } | 1677 | } |
1659 | 1678 | ||
1660 | return status; | 1679 | return status; |
1661 | } | 1680 | } |
1662 | 1681 | ||
1663 | static int htc_fetch_rxpkts(struct htc_target *target, | 1682 | static int ath6kl_htc_rx_fetch(struct htc_target *target, |
1664 | struct list_head *rx_pktq, | 1683 | struct list_head *rx_pktq, |
1665 | struct list_head *comp_pktq) | 1684 | struct list_head *comp_pktq) |
1666 | { | 1685 | { |
1667 | int fetched_pkts; | 1686 | int fetched_pkts; |
1668 | bool part_bundle = false; | 1687 | bool part_bundle = false; |
@@ -1678,10 +1697,10 @@ static int htc_fetch_rxpkts(struct htc_target *target, | |||
1678 | * bundle transfer and recv bundling is | 1697 | * bundle transfer and recv bundling is |
1679 | * allowed. | 1698 | * allowed. |
1680 | */ | 1699 | */ |
1681 | status = htc_issue_rxpkt_bundle(target, rx_pktq, | 1700 | status = ath6kl_htc_rx_bundle(target, rx_pktq, |
1682 | comp_pktq, | 1701 | comp_pktq, |
1683 | &fetched_pkts, | 1702 | &fetched_pkts, |
1684 | part_bundle); | 1703 | part_bundle); |
1685 | if (status) | 1704 | if (status) |
1686 | return status; | 1705 | return status; |
1687 | 1706 | ||
@@ -1710,7 +1729,8 @@ static int htc_fetch_rxpkts(struct htc_target *target, | |||
1710 | HTC_RX_PKT_IGNORE_LOOKAHEAD; | 1729 | HTC_RX_PKT_IGNORE_LOOKAHEAD; |
1711 | 1730 | ||
1712 | /* go fetch the packet */ | 1731 | /* go fetch the packet */ |
1713 | status = dev_rx_pkt(target, packet, packet->act_len); | 1732 | status = ath6kl_htc_rx_packet(target, packet, |
1733 | packet->act_len); | ||
1714 | if (status) | 1734 | if (status) |
1715 | return status; | 1735 | return status; |
1716 | 1736 | ||
@@ -1764,9 +1784,9 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, | |||
1764 | * Try to allocate as many HTC RX packets indicated by the | 1784 | * Try to allocate as many HTC RX packets indicated by the |
1765 | * look_aheads. | 1785 | * look_aheads. |
1766 | */ | 1786 | */ |
1767 | status = alloc_and_prep_rxpkts(target, look_aheads, | 1787 | status = ath6kl_htc_rx_alloc(target, look_aheads, |
1768 | num_look_ahead, endpoint, | 1788 | num_look_ahead, endpoint, |
1769 | &rx_pktq); | 1789 | &rx_pktq); |
1770 | if (status) | 1790 | if (status) |
1771 | break; | 1791 | break; |
1772 | 1792 | ||
@@ -1781,14 +1801,15 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, | |||
1781 | 1801 | ||
1782 | num_look_ahead = 0; | 1802 | num_look_ahead = 0; |
1783 | 1803 | ||
1784 | status = htc_fetch_rxpkts(target, &rx_pktq, &comp_pktq); | 1804 | status = ath6kl_htc_rx_fetch(target, &rx_pktq, &comp_pktq); |
1785 | 1805 | ||
1786 | if (!status) | 1806 | if (!status) |
1787 | chk_rx_water_mark(endpoint); | 1807 | ath6kl_htc_rx_chk_water_mark(endpoint); |
1788 | 1808 | ||
1789 | /* Process fetched packets */ | 1809 | /* Process fetched packets */ |
1790 | status = htc_proc_fetched_rxpkts(target, &comp_pktq, | 1810 | status = ath6kl_htc_rx_process_packets(target, &comp_pktq, |
1791 | look_aheads, &num_look_ahead); | 1811 | look_aheads, |
1812 | &num_look_ahead); | ||
1792 | 1813 | ||
1793 | if (!num_look_ahead || status) | 1814 | if (!num_look_ahead || status) |
1794 | break; | 1815 | break; |
@@ -1881,14 +1902,14 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target) | |||
1881 | packet->completion = NULL; | 1902 | packet->completion = NULL; |
1882 | 1903 | ||
1883 | /* get the message from the device, this will block */ | 1904 | /* get the message from the device, this will block */ |
1884 | if (dev_rx_pkt(target, packet, packet->act_len)) | 1905 | if (ath6kl_htc_rx_packet(target, packet, packet->act_len)) |
1885 | goto fail_ctrl_rx; | 1906 | goto fail_ctrl_rx; |
1886 | 1907 | ||
1887 | /* process receive header */ | 1908 | /* process receive header */ |
1888 | packet->status = htc_proc_rxhdr(target, packet, NULL, NULL); | 1909 | packet->status = ath6kl_htc_rx_process_hdr(target, packet, NULL, NULL); |
1889 | 1910 | ||
1890 | if (packet->status) { | 1911 | if (packet->status) { |
1891 | ath6kl_err("htc_wait_for_ctrl_msg, htc_proc_rxhdr failed (status = %d)\n", | 1912 | ath6kl_err("htc_wait_for_ctrl_msg, ath6kl_htc_rx_process_hdr failed (status = %d)\n", |
1892 | packet->status); | 1913 | packet->status); |
1893 | goto fail_ctrl_rx; | 1914 | goto fail_ctrl_rx; |
1894 | } | 1915 | } |
@@ -1935,7 +1956,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, | |||
1935 | list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) { | 1956 | list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) { |
1936 | packet->status = -ECANCELED; | 1957 | packet->status = -ECANCELED; |
1937 | list_del(&packet->list); | 1958 | list_del(&packet->list); |
1938 | do_rx_completion(endpoint, packet); | 1959 | ath6kl_htc_rx_complete(endpoint, packet); |
1939 | } | 1960 | } |
1940 | 1961 | ||
1941 | return status; | 1962 | return status; |
@@ -2034,8 +2055,8 @@ int ath6kl_htc_conn_service(struct htc_target *target, | |||
2034 | 2055 | ||
2035 | /* we want synchronous operation */ | 2056 | /* we want synchronous operation */ |
2036 | tx_pkt->completion = NULL; | 2057 | tx_pkt->completion = NULL; |
2037 | htc_prep_send_pkt(tx_pkt, 0, 0, 0); | 2058 | ath6kl_htc_tx_prep_pkt(tx_pkt, 0, 0, 0); |
2038 | status = htc_issue_send(target, tx_pkt); | 2059 | status = ath6kl_htc_tx_issue(target, tx_pkt); |
2039 | 2060 | ||
2040 | if (status) | 2061 | if (status) |
2041 | goto fail_tx; | 2062 | goto fail_tx; |
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 9d10322eac41..c1d2366704b5 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c | |||
@@ -15,6 +15,8 @@ | |||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/moduleparam.h> | ||
19 | #include <linux/of.h> | ||
18 | #include <linux/mmc/sdio_func.h> | 20 | #include <linux/mmc/sdio_func.h> |
19 | #include "core.h" | 21 | #include "core.h" |
20 | #include "cfg80211.h" | 22 | #include "cfg80211.h" |
@@ -23,8 +25,10 @@ | |||
23 | #include "hif-ops.h" | 25 | #include "hif-ops.h" |
24 | 26 | ||
25 | unsigned int debug_mask; | 27 | unsigned int debug_mask; |
28 | static unsigned int testmode; | ||
26 | 29 | ||
27 | module_param(debug_mask, uint, 0644); | 30 | module_param(debug_mask, uint, 0644); |
31 | module_param(testmode, uint, 0644); | ||
28 | 32 | ||
29 | /* | 33 | /* |
30 | * Include definitions here that can be used to tune the WLAN module | 34 | * Include definitions here that can be used to tune the WLAN module |
@@ -53,12 +57,6 @@ module_param(debug_mask, uint, 0644); | |||
53 | 57 | ||
54 | #define CONFIG_AR600x_DEBUG_UART_TX_PIN 8 | 58 | #define CONFIG_AR600x_DEBUG_UART_TX_PIN 8 |
55 | 59 | ||
56 | enum addr_type { | ||
57 | DATASET_PATCH_ADDR, | ||
58 | APP_LOAD_ADDR, | ||
59 | APP_START_OVERRIDE_ADDR, | ||
60 | }; | ||
61 | |||
62 | #define ATH6KL_DATA_OFFSET 64 | 60 | #define ATH6KL_DATA_OFFSET 64 |
63 | struct sk_buff *ath6kl_buf_alloc(int size) | 61 | struct sk_buff *ath6kl_buf_alloc(int size) |
64 | { | 62 | { |
@@ -67,7 +65,7 @@ struct sk_buff *ath6kl_buf_alloc(int size) | |||
67 | 65 | ||
68 | /* Add chacheline space at front and back of buffer */ | 66 | /* Add chacheline space at front and back of buffer */ |
69 | reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET + | 67 | reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET + |
70 | sizeof(struct htc_packet); | 68 | sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES; |
71 | skb = dev_alloc_skb(size + reserved); | 69 | skb = dev_alloc_skb(size + reserved); |
72 | 70 | ||
73 | if (skb) | 71 | if (skb) |
@@ -85,7 +83,7 @@ void ath6kl_init_profile_info(struct ath6kl *ar) | |||
85 | ar->prwise_crypto = NONE_CRYPT; | 83 | ar->prwise_crypto = NONE_CRYPT; |
86 | ar->prwise_crypto_len = 0; | 84 | ar->prwise_crypto_len = 0; |
87 | ar->grp_crypto = NONE_CRYPT; | 85 | ar->grp_crypto = NONE_CRYPT; |
88 | ar->grp_crpto_len = 0; | 86 | ar->grp_crypto_len = 0; |
89 | memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list)); | 87 | memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list)); |
90 | memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); | 88 | memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); |
91 | memset(ar->bssid, 0, sizeof(ar->bssid)); | 89 | memset(ar->bssid, 0, sizeof(ar->bssid)); |
@@ -108,17 +106,6 @@ static u8 ath6kl_get_fw_iftype(struct ath6kl *ar) | |||
108 | } | 106 | } |
109 | } | 107 | } |
110 | 108 | ||
111 | static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar, | ||
112 | u32 item_offset) | ||
113 | { | ||
114 | u32 addr = 0; | ||
115 | |||
116 | if (ar->target_type == TARGET_TYPE_AR6003) | ||
117 | addr = ATH6KL_HI_START_ADDR + item_offset; | ||
118 | |||
119 | return addr; | ||
120 | } | ||
121 | |||
122 | static int ath6kl_set_host_app_area(struct ath6kl *ar) | 109 | static int ath6kl_set_host_app_area(struct ath6kl *ar) |
123 | { | 110 | { |
124 | u32 address, data; | 111 | u32 address, data; |
@@ -127,16 +114,15 @@ static int ath6kl_set_host_app_area(struct ath6kl *ar) | |||
127 | /* Fetch the address of the host_app_area_s | 114 | /* Fetch the address of the host_app_area_s |
128 | * instance in the host interest area */ | 115 | * instance in the host interest area */ |
129 | address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest)); | 116 | address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest)); |
130 | address = TARG_VTOP(address); | 117 | address = TARG_VTOP(ar->target_type, address); |
131 | 118 | ||
132 | if (ath6kl_read_reg_diag(ar, &address, &data)) | 119 | if (ath6kl_diag_read32(ar, address, &data)) |
133 | return -EIO; | 120 | return -EIO; |
134 | 121 | ||
135 | address = TARG_VTOP(data); | 122 | address = TARG_VTOP(ar->target_type, data); |
136 | host_app_area.wmi_protocol_ver = WMI_PROTOCOL_VERSION; | 123 | host_app_area.wmi_protocol_ver = WMI_PROTOCOL_VERSION; |
137 | if (ath6kl_access_datadiag(ar, address, | 124 | if (ath6kl_diag_write(ar, address, (u8 *) &host_app_area, |
138 | (u8 *)&host_app_area, | 125 | sizeof(struct host_app_area))) |
139 | sizeof(struct host_app_area), false)) | ||
140 | return -EIO; | 126 | return -EIO; |
141 | 127 | ||
142 | return 0; | 128 | return 0; |
@@ -290,6 +276,7 @@ static void ath6kl_init_control_info(struct ath6kl *ar) | |||
290 | memset(&ar->sc_params, 0, sizeof(ar->sc_params)); | 276 | memset(&ar->sc_params, 0, sizeof(ar->sc_params)); |
291 | ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT; | 277 | ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT; |
292 | ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS; | 278 | ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS; |
279 | ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; | ||
293 | 280 | ||
294 | memset((u8 *)ar->sta_list, 0, | 281 | memset((u8 *)ar->sta_list, 0, |
295 | AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); | 282 | AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); |
@@ -370,10 +357,10 @@ static void ath6kl_dump_target_assert_info(struct ath6kl *ar) | |||
370 | 357 | ||
371 | /* the reg dump pointer is copied to the host interest area */ | 358 | /* the reg dump pointer is copied to the host interest area */ |
372 | address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state)); | 359 | address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state)); |
373 | address = TARG_VTOP(address); | 360 | address = TARG_VTOP(ar->target_type, address); |
374 | 361 | ||
375 | /* read RAM location through diagnostic window */ | 362 | /* read RAM location through diagnostic window */ |
376 | status = ath6kl_read_reg_diag(ar, &address, ®dump_loc); | 363 | status = ath6kl_diag_read32(ar, address, ®dump_loc); |
377 | 364 | ||
378 | if (status || !regdump_loc) { | 365 | if (status || !regdump_loc) { |
379 | ath6kl_err("failed to get ptr to register dump area\n"); | 366 | ath6kl_err("failed to get ptr to register dump area\n"); |
@@ -382,15 +369,11 @@ static void ath6kl_dump_target_assert_info(struct ath6kl *ar) | |||
382 | 369 | ||
383 | ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n", | 370 | ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n", |
384 | regdump_loc); | 371 | regdump_loc); |
385 | 372 | regdump_loc = TARG_VTOP(ar->target_type, regdump_loc); | |
386 | regdump_loc = TARG_VTOP(regdump_loc); | ||
387 | 373 | ||
388 | /* fetch register dump data */ | 374 | /* fetch register dump data */ |
389 | status = ath6kl_access_datadiag(ar, | 375 | status = ath6kl_diag_read(ar, regdump_loc, (u8 *)®dump_val[0], |
390 | regdump_loc, | 376 | REG_DUMP_COUNT_AR6003 * (sizeof(u32))); |
391 | (u8 *)®dump_val[0], | ||
392 | REG_DUMP_COUNT_AR6003 * (sizeof(u32)), | ||
393 | true); | ||
394 | 377 | ||
395 | if (status) { | 378 | if (status) { |
396 | ath6kl_err("failed to get register dump\n"); | 379 | ath6kl_err("failed to get register dump\n"); |
@@ -416,6 +399,7 @@ void ath6kl_target_failure(struct ath6kl *ar) | |||
416 | static int ath6kl_target_config_wlan_params(struct ath6kl *ar) | 399 | static int ath6kl_target_config_wlan_params(struct ath6kl *ar) |
417 | { | 400 | { |
418 | int status = 0; | 401 | int status = 0; |
402 | int ret; | ||
419 | 403 | ||
420 | /* | 404 | /* |
421 | * Configure the device for rx dot11 header rules. "0,0" are the | 405 | * Configure the device for rx dot11 header rules. "0,0" are the |
@@ -460,6 +444,28 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar) | |||
460 | status = -EIO; | 444 | status = -EIO; |
461 | } | 445 | } |
462 | 446 | ||
447 | if (ar->p2p) { | ||
448 | ret = ath6kl_wmi_info_req_cmd(ar->wmi, | ||
449 | P2P_FLAG_CAPABILITIES_REQ | | ||
450 | P2P_FLAG_MACADDR_REQ | | ||
451 | P2P_FLAG_HMODEL_REQ); | ||
452 | if (ret) { | ||
453 | ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P " | ||
454 | "capabilities (%d) - assuming P2P not " | ||
455 | "supported\n", ret); | ||
456 | ar->p2p = 0; | ||
457 | } | ||
458 | } | ||
459 | |||
460 | if (ar->p2p) { | ||
461 | /* Enable Probe Request reporting for P2P */ | ||
462 | ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, true); | ||
463 | if (ret) { | ||
464 | ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe " | ||
465 | "Request reporting (%d)\n", ret); | ||
466 | } | ||
467 | } | ||
468 | |||
463 | return status; | 469 | return status; |
464 | } | 470 | } |
465 | 471 | ||
@@ -495,6 +501,10 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
495 | 501 | ||
496 | param |= (1 << HI_OPTION_NUM_DEV_SHIFT); | 502 | param |= (1 << HI_OPTION_NUM_DEV_SHIFT); |
497 | param |= (fw_iftype << HI_OPTION_FW_MODE_SHIFT); | 503 | param |= (fw_iftype << HI_OPTION_FW_MODE_SHIFT); |
504 | if (ar->p2p && fw_iftype == HI_OPTION_FW_MODE_BSS_STA) { | ||
505 | param |= HI_OPTION_FW_SUBMODE_P2PDEV << | ||
506 | HI_OPTION_FW_SUBMODE_SHIFT; | ||
507 | } | ||
498 | param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); | 508 | param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); |
499 | param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); | 509 | param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); |
500 | 510 | ||
@@ -518,29 +528,21 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
518 | * but possible in theory. | 528 | * but possible in theory. |
519 | */ | 529 | */ |
520 | 530 | ||
521 | if (ar->target_type == TARGET_TYPE_AR6003) { | 531 | param = ar->hw.board_ext_data_addr; |
522 | if (ar->version.target_ver == AR6003_REV2_VERSION) { | 532 | ram_reserved_size = ar->hw.reserved_ram_size; |
523 | param = AR6003_REV2_BOARD_EXT_DATA_ADDRESS; | ||
524 | ram_reserved_size = AR6003_REV2_RAM_RESERVE_SIZE; | ||
525 | } else { | ||
526 | param = AR6003_REV3_BOARD_EXT_DATA_ADDRESS; | ||
527 | ram_reserved_size = AR6003_REV3_RAM_RESERVE_SIZE; | ||
528 | } | ||
529 | 533 | ||
530 | if (ath6kl_bmi_write(ar, | 534 | if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, |
531 | ath6kl_get_hi_item_addr(ar, | 535 | HI_ITEM(hi_board_ext_data)), |
532 | HI_ITEM(hi_board_ext_data)), | 536 | (u8 *)¶m, 4) != 0) { |
533 | (u8 *)¶m, 4) != 0) { | 537 | ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); |
534 | ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); | 538 | return -EIO; |
535 | return -EIO; | 539 | } |
536 | } | 540 | |
537 | if (ath6kl_bmi_write(ar, | 541 | if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, |
538 | ath6kl_get_hi_item_addr(ar, | 542 | HI_ITEM(hi_end_ram_reserve_sz)), |
539 | HI_ITEM(hi_end_ram_reserve_sz)), | 543 | (u8 *)&ram_reserved_size, 4) != 0) { |
540 | (u8 *)&ram_reserved_size, 4) != 0) { | 544 | ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); |
541 | ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); | 545 | return -EIO; |
542 | return -EIO; | ||
543 | } | ||
544 | } | 546 | } |
545 | 547 | ||
546 | /* set the block size for the target */ | 548 | /* set the block size for the target */ |
@@ -568,6 +570,12 @@ struct ath6kl *ath6kl_core_alloc(struct device *sdev) | |||
568 | ar->wdev = wdev; | 570 | ar->wdev = wdev; |
569 | wdev->iftype = NL80211_IFTYPE_STATION; | 571 | wdev->iftype = NL80211_IFTYPE_STATION; |
570 | 572 | ||
573 | if (ath6kl_debug_init(ar)) { | ||
574 | ath6kl_err("Failed to initialize debugfs\n"); | ||
575 | ath6kl_cfg80211_deinit(ar); | ||
576 | return NULL; | ||
577 | } | ||
578 | |||
571 | dev = alloc_netdev(0, "wlan%d", ether_setup); | 579 | dev = alloc_netdev(0, "wlan%d", ether_setup); |
572 | if (!dev) { | 580 | if (!dev) { |
573 | ath6kl_err("no memory for network device instance\n"); | 581 | ath6kl_err("no memory for network device instance\n"); |
@@ -579,7 +587,6 @@ struct ath6kl *ath6kl_core_alloc(struct device *sdev) | |||
579 | SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); | 587 | SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); |
580 | wdev->netdev = dev; | 588 | wdev->netdev = dev; |
581 | ar->sme_state = SME_DISCONNECTED; | 589 | ar->sme_state = SME_DISCONNECTED; |
582 | ar->auto_auth_stage = AUTH_IDLE; | ||
583 | 590 | ||
584 | init_netdev(dev); | 591 | init_netdev(dev); |
585 | 592 | ||
@@ -611,29 +618,6 @@ int ath6kl_unavail_ev(struct ath6kl *ar) | |||
611 | } | 618 | } |
612 | 619 | ||
613 | /* firmware upload */ | 620 | /* firmware upload */ |
614 | static u32 ath6kl_get_load_address(u32 target_ver, enum addr_type type) | ||
615 | { | ||
616 | WARN_ON(target_ver != AR6003_REV2_VERSION && | ||
617 | target_ver != AR6003_REV3_VERSION); | ||
618 | |||
619 | switch (type) { | ||
620 | case DATASET_PATCH_ADDR: | ||
621 | return (target_ver == AR6003_REV2_VERSION) ? | ||
622 | AR6003_REV2_DATASET_PATCH_ADDRESS : | ||
623 | AR6003_REV3_DATASET_PATCH_ADDRESS; | ||
624 | case APP_LOAD_ADDR: | ||
625 | return (target_ver == AR6003_REV2_VERSION) ? | ||
626 | AR6003_REV2_APP_LOAD_ADDRESS : | ||
627 | 0x1234; | ||
628 | case APP_START_OVERRIDE_ADDR: | ||
629 | return (target_ver == AR6003_REV2_VERSION) ? | ||
630 | AR6003_REV2_APP_START_OVERRIDE : | ||
631 | AR6003_REV3_APP_START_OVERRIDE; | ||
632 | default: | ||
633 | return 0; | ||
634 | } | ||
635 | } | ||
636 | |||
637 | static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, | 621 | static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, |
638 | u8 **fw, size_t *fw_len) | 622 | u8 **fw, size_t *fw_len) |
639 | { | 623 | { |
@@ -655,15 +639,79 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, | |||
655 | return ret; | 639 | return ret; |
656 | } | 640 | } |
657 | 641 | ||
642 | #ifdef CONFIG_OF | ||
643 | static const char *get_target_ver_dir(const struct ath6kl *ar) | ||
644 | { | ||
645 | switch (ar->version.target_ver) { | ||
646 | case AR6003_REV1_VERSION: | ||
647 | return "ath6k/AR6003/hw1.0"; | ||
648 | case AR6003_REV2_VERSION: | ||
649 | return "ath6k/AR6003/hw2.0"; | ||
650 | case AR6003_REV3_VERSION: | ||
651 | return "ath6k/AR6003/hw2.1.1"; | ||
652 | } | ||
653 | ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__, | ||
654 | ar->version.target_ver); | ||
655 | return NULL; | ||
656 | } | ||
657 | |||
658 | /* | ||
659 | * Check the device tree for a board-id and use it to construct | ||
660 | * the pathname to the firmware file. Used (for now) to find a | ||
661 | * fallback to the "bdata.bin" file--typically a symlink to the | ||
662 | * appropriate board-specific file. | ||
663 | */ | ||
664 | static bool check_device_tree(struct ath6kl *ar) | ||
665 | { | ||
666 | static const char *board_id_prop = "atheros,board-id"; | ||
667 | struct device_node *node; | ||
668 | char board_filename[64]; | ||
669 | const char *board_id; | ||
670 | int ret; | ||
671 | |||
672 | for_each_compatible_node(node, NULL, "atheros,ath6kl") { | ||
673 | board_id = of_get_property(node, board_id_prop, NULL); | ||
674 | if (board_id == NULL) { | ||
675 | ath6kl_warn("No \"%s\" property on %s node.\n", | ||
676 | board_id_prop, node->name); | ||
677 | continue; | ||
678 | } | ||
679 | snprintf(board_filename, sizeof(board_filename), | ||
680 | "%s/bdata.%s.bin", get_target_ver_dir(ar), board_id); | ||
681 | |||
682 | ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board, | ||
683 | &ar->fw_board_len); | ||
684 | if (ret) { | ||
685 | ath6kl_err("Failed to get DT board file %s: %d\n", | ||
686 | board_filename, ret); | ||
687 | continue; | ||
688 | } | ||
689 | return true; | ||
690 | } | ||
691 | return false; | ||
692 | } | ||
693 | #else | ||
694 | static bool check_device_tree(struct ath6kl *ar) | ||
695 | { | ||
696 | return false; | ||
697 | } | ||
698 | #endif /* CONFIG_OF */ | ||
699 | |||
658 | static int ath6kl_fetch_board_file(struct ath6kl *ar) | 700 | static int ath6kl_fetch_board_file(struct ath6kl *ar) |
659 | { | 701 | { |
660 | const char *filename; | 702 | const char *filename; |
661 | int ret; | 703 | int ret; |
662 | 704 | ||
705 | if (ar->fw_board != NULL) | ||
706 | return 0; | ||
707 | |||
663 | switch (ar->version.target_ver) { | 708 | switch (ar->version.target_ver) { |
664 | case AR6003_REV2_VERSION: | 709 | case AR6003_REV2_VERSION: |
665 | filename = AR6003_REV2_BOARD_DATA_FILE; | 710 | filename = AR6003_REV2_BOARD_DATA_FILE; |
666 | break; | 711 | break; |
712 | case AR6004_REV1_VERSION: | ||
713 | filename = AR6004_REV1_BOARD_DATA_FILE; | ||
714 | break; | ||
667 | default: | 715 | default: |
668 | filename = AR6003_REV3_BOARD_DATA_FILE; | 716 | filename = AR6003_REV3_BOARD_DATA_FILE; |
669 | break; | 717 | break; |
@@ -676,6 +724,11 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar) | |||
676 | return 0; | 724 | return 0; |
677 | } | 725 | } |
678 | 726 | ||
727 | if (check_device_tree(ar)) { | ||
728 | /* got board file from device tree */ | ||
729 | return 0; | ||
730 | } | ||
731 | |||
679 | /* there was no proper board file, try to use default instead */ | 732 | /* there was no proper board file, try to use default instead */ |
680 | ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n", | 733 | ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n", |
681 | filename, ret); | 734 | filename, ret); |
@@ -684,6 +737,9 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar) | |||
684 | case AR6003_REV2_VERSION: | 737 | case AR6003_REV2_VERSION: |
685 | filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE; | 738 | filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE; |
686 | break; | 739 | break; |
740 | case AR6004_REV1_VERSION: | ||
741 | filename = AR6004_REV1_DEFAULT_BOARD_DATA_FILE; | ||
742 | break; | ||
687 | default: | 743 | default: |
688 | filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE; | 744 | filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE; |
689 | break; | 745 | break; |
@@ -703,25 +759,346 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar) | |||
703 | return 0; | 759 | return 0; |
704 | } | 760 | } |
705 | 761 | ||
762 | static int ath6kl_fetch_otp_file(struct ath6kl *ar) | ||
763 | { | ||
764 | const char *filename; | ||
765 | int ret; | ||
706 | 766 | ||
707 | static int ath6kl_upload_board_file(struct ath6kl *ar) | 767 | if (ar->fw_otp != NULL) |
768 | return 0; | ||
769 | |||
770 | switch (ar->version.target_ver) { | ||
771 | case AR6003_REV2_VERSION: | ||
772 | filename = AR6003_REV2_OTP_FILE; | ||
773 | break; | ||
774 | case AR6004_REV1_VERSION: | ||
775 | ath6kl_dbg(ATH6KL_DBG_TRC, "AR6004 doesn't need OTP file\n"); | ||
776 | return 0; | ||
777 | break; | ||
778 | default: | ||
779 | filename = AR6003_REV3_OTP_FILE; | ||
780 | break; | ||
781 | } | ||
782 | |||
783 | ret = ath6kl_get_fw(ar, filename, &ar->fw_otp, | ||
784 | &ar->fw_otp_len); | ||
785 | if (ret) { | ||
786 | ath6kl_err("Failed to get OTP file %s: %d\n", | ||
787 | filename, ret); | ||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | static int ath6kl_fetch_fw_file(struct ath6kl *ar) | ||
708 | { | 795 | { |
709 | u32 board_address, board_ext_address, param; | 796 | const char *filename; |
797 | int ret; | ||
798 | |||
799 | if (ar->fw != NULL) | ||
800 | return 0; | ||
801 | |||
802 | if (testmode) { | ||
803 | switch (ar->version.target_ver) { | ||
804 | case AR6003_REV2_VERSION: | ||
805 | filename = AR6003_REV2_TCMD_FIRMWARE_FILE; | ||
806 | break; | ||
807 | case AR6003_REV3_VERSION: | ||
808 | filename = AR6003_REV3_TCMD_FIRMWARE_FILE; | ||
809 | break; | ||
810 | case AR6004_REV1_VERSION: | ||
811 | ath6kl_warn("testmode not supported with ar6004\n"); | ||
812 | return -EOPNOTSUPP; | ||
813 | default: | ||
814 | ath6kl_warn("unknown target version: 0x%x\n", | ||
815 | ar->version.target_ver); | ||
816 | return -EINVAL; | ||
817 | } | ||
818 | |||
819 | set_bit(TESTMODE, &ar->flag); | ||
820 | |||
821 | goto get_fw; | ||
822 | } | ||
823 | |||
824 | switch (ar->version.target_ver) { | ||
825 | case AR6003_REV2_VERSION: | ||
826 | filename = AR6003_REV2_FIRMWARE_FILE; | ||
827 | break; | ||
828 | case AR6004_REV1_VERSION: | ||
829 | filename = AR6004_REV1_FIRMWARE_FILE; | ||
830 | break; | ||
831 | default: | ||
832 | filename = AR6003_REV3_FIRMWARE_FILE; | ||
833 | break; | ||
834 | } | ||
835 | |||
836 | get_fw: | ||
837 | ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); | ||
838 | if (ret) { | ||
839 | ath6kl_err("Failed to get firmware file %s: %d\n", | ||
840 | filename, ret); | ||
841 | return ret; | ||
842 | } | ||
843 | |||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | static int ath6kl_fetch_patch_file(struct ath6kl *ar) | ||
848 | { | ||
849 | const char *filename; | ||
710 | int ret; | 850 | int ret; |
711 | 851 | ||
712 | if (ar->fw_board == NULL) { | 852 | switch (ar->version.target_ver) { |
713 | ret = ath6kl_fetch_board_file(ar); | 853 | case AR6003_REV2_VERSION: |
714 | if (ret) | 854 | filename = AR6003_REV2_PATCH_FILE; |
855 | break; | ||
856 | case AR6004_REV1_VERSION: | ||
857 | /* FIXME: implement for AR6004 */ | ||
858 | return 0; | ||
859 | break; | ||
860 | default: | ||
861 | filename = AR6003_REV3_PATCH_FILE; | ||
862 | break; | ||
863 | } | ||
864 | |||
865 | if (ar->fw_patch == NULL) { | ||
866 | ret = ath6kl_get_fw(ar, filename, &ar->fw_patch, | ||
867 | &ar->fw_patch_len); | ||
868 | if (ret) { | ||
869 | ath6kl_err("Failed to get patch file %s: %d\n", | ||
870 | filename, ret); | ||
715 | return ret; | 871 | return ret; |
872 | } | ||
716 | } | 873 | } |
717 | 874 | ||
718 | /* Determine where in Target RAM to write Board Data */ | 875 | return 0; |
719 | ath6kl_bmi_read(ar, | 876 | } |
720 | ath6kl_get_hi_item_addr(ar, | 877 | |
721 | HI_ITEM(hi_board_data)), | 878 | static int ath6kl_fetch_fw_api1(struct ath6kl *ar) |
722 | (u8 *) &board_address, 4); | 879 | { |
723 | ath6kl_dbg(ATH6KL_DBG_TRC, "board data download addr: 0x%x\n", | 880 | int ret; |
724 | board_address); | 881 | |
882 | ret = ath6kl_fetch_otp_file(ar); | ||
883 | if (ret) | ||
884 | return ret; | ||
885 | |||
886 | ret = ath6kl_fetch_fw_file(ar); | ||
887 | if (ret) | ||
888 | return ret; | ||
889 | |||
890 | ret = ath6kl_fetch_patch_file(ar); | ||
891 | if (ret) | ||
892 | return ret; | ||
893 | |||
894 | return 0; | ||
895 | } | ||
896 | |||
897 | static int ath6kl_fetch_fw_api2(struct ath6kl *ar) | ||
898 | { | ||
899 | size_t magic_len, len, ie_len; | ||
900 | const struct firmware *fw; | ||
901 | struct ath6kl_fw_ie *hdr; | ||
902 | const char *filename; | ||
903 | const u8 *data; | ||
904 | int ret, ie_id, i, index, bit; | ||
905 | __le32 *val; | ||
906 | |||
907 | switch (ar->version.target_ver) { | ||
908 | case AR6003_REV2_VERSION: | ||
909 | filename = AR6003_REV2_FIRMWARE_2_FILE; | ||
910 | break; | ||
911 | case AR6003_REV3_VERSION: | ||
912 | filename = AR6003_REV3_FIRMWARE_2_FILE; | ||
913 | break; | ||
914 | case AR6004_REV1_VERSION: | ||
915 | filename = AR6004_REV1_FIRMWARE_2_FILE; | ||
916 | break; | ||
917 | default: | ||
918 | return -EOPNOTSUPP; | ||
919 | } | ||
920 | |||
921 | ret = request_firmware(&fw, filename, ar->dev); | ||
922 | if (ret) | ||
923 | return ret; | ||
924 | |||
925 | data = fw->data; | ||
926 | len = fw->size; | ||
927 | |||
928 | /* magic also includes the null byte, check that as well */ | ||
929 | magic_len = strlen(ATH6KL_FIRMWARE_MAGIC) + 1; | ||
930 | |||
931 | if (len < magic_len) { | ||
932 | ret = -EINVAL; | ||
933 | goto out; | ||
934 | } | ||
935 | |||
936 | if (memcmp(data, ATH6KL_FIRMWARE_MAGIC, magic_len) != 0) { | ||
937 | ret = -EINVAL; | ||
938 | goto out; | ||
939 | } | ||
940 | |||
941 | len -= magic_len; | ||
942 | data += magic_len; | ||
943 | |||
944 | /* loop elements */ | ||
945 | while (len > sizeof(struct ath6kl_fw_ie)) { | ||
946 | /* hdr is unaligned! */ | ||
947 | hdr = (struct ath6kl_fw_ie *) data; | ||
948 | |||
949 | ie_id = le32_to_cpup(&hdr->id); | ||
950 | ie_len = le32_to_cpup(&hdr->len); | ||
951 | |||
952 | len -= sizeof(*hdr); | ||
953 | data += sizeof(*hdr); | ||
954 | |||
955 | if (len < ie_len) { | ||
956 | ret = -EINVAL; | ||
957 | goto out; | ||
958 | } | ||
959 | |||
960 | switch (ie_id) { | ||
961 | case ATH6KL_FW_IE_OTP_IMAGE: | ||
962 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n", | ||
963 | ie_len); | ||
964 | |||
965 | ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL); | ||
966 | |||
967 | if (ar->fw_otp == NULL) { | ||
968 | ret = -ENOMEM; | ||
969 | goto out; | ||
970 | } | ||
971 | |||
972 | ar->fw_otp_len = ie_len; | ||
973 | break; | ||
974 | case ATH6KL_FW_IE_FW_IMAGE: | ||
975 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n", | ||
976 | ie_len); | ||
977 | |||
978 | ar->fw = kmemdup(data, ie_len, GFP_KERNEL); | ||
979 | |||
980 | if (ar->fw == NULL) { | ||
981 | ret = -ENOMEM; | ||
982 | goto out; | ||
983 | } | ||
984 | |||
985 | ar->fw_len = ie_len; | ||
986 | break; | ||
987 | case ATH6KL_FW_IE_PATCH_IMAGE: | ||
988 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n", | ||
989 | ie_len); | ||
990 | |||
991 | ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL); | ||
992 | |||
993 | if (ar->fw_patch == NULL) { | ||
994 | ret = -ENOMEM; | ||
995 | goto out; | ||
996 | } | ||
997 | |||
998 | ar->fw_patch_len = ie_len; | ||
999 | break; | ||
1000 | case ATH6KL_FW_IE_RESERVED_RAM_SIZE: | ||
1001 | val = (__le32 *) data; | ||
1002 | ar->hw.reserved_ram_size = le32_to_cpup(val); | ||
1003 | |||
1004 | ath6kl_dbg(ATH6KL_DBG_BOOT, | ||
1005 | "found reserved ram size ie 0x%d\n", | ||
1006 | ar->hw.reserved_ram_size); | ||
1007 | break; | ||
1008 | case ATH6KL_FW_IE_CAPABILITIES: | ||
1009 | ath6kl_dbg(ATH6KL_DBG_BOOT, | ||
1010 | "found firmware capabilities ie (%zd B)\n", | ||
1011 | ie_len); | ||
1012 | |||
1013 | for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) { | ||
1014 | index = ALIGN(i, 8) / 8; | ||
1015 | bit = i % 8; | ||
1016 | |||
1017 | if (data[index] & (1 << bit)) | ||
1018 | __set_bit(i, ar->fw_capabilities); | ||
1019 | } | ||
1020 | |||
1021 | ath6kl_dbg_dump(ATH6KL_DBG_BOOT, "capabilities", "", | ||
1022 | ar->fw_capabilities, | ||
1023 | sizeof(ar->fw_capabilities)); | ||
1024 | break; | ||
1025 | case ATH6KL_FW_IE_PATCH_ADDR: | ||
1026 | if (ie_len != sizeof(*val)) | ||
1027 | break; | ||
1028 | |||
1029 | val = (__le32 *) data; | ||
1030 | ar->hw.dataset_patch_addr = le32_to_cpup(val); | ||
1031 | |||
1032 | ath6kl_dbg(ATH6KL_DBG_BOOT, | ||
1033 | "found patch address ie 0x%d\n", | ||
1034 | ar->hw.dataset_patch_addr); | ||
1035 | break; | ||
1036 | default: | ||
1037 | ath6kl_dbg(ATH6KL_DBG_BOOT, "Unknown fw ie: %u\n", | ||
1038 | le32_to_cpup(&hdr->id)); | ||
1039 | break; | ||
1040 | } | ||
1041 | |||
1042 | len -= ie_len; | ||
1043 | data += ie_len; | ||
1044 | }; | ||
1045 | |||
1046 | ret = 0; | ||
1047 | out: | ||
1048 | release_firmware(fw); | ||
1049 | |||
1050 | return ret; | ||
1051 | } | ||
1052 | |||
1053 | static int ath6kl_fetch_firmwares(struct ath6kl *ar) | ||
1054 | { | ||
1055 | int ret; | ||
1056 | |||
1057 | ret = ath6kl_fetch_board_file(ar); | ||
1058 | if (ret) | ||
1059 | return ret; | ||
1060 | |||
1061 | ret = ath6kl_fetch_fw_api2(ar); | ||
1062 | if (ret == 0) { | ||
1063 | ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 2\n"); | ||
1064 | return 0; | ||
1065 | } | ||
1066 | |||
1067 | ret = ath6kl_fetch_fw_api1(ar); | ||
1068 | if (ret) | ||
1069 | return ret; | ||
1070 | |||
1071 | ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 1\n"); | ||
1072 | |||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | static int ath6kl_upload_board_file(struct ath6kl *ar) | ||
1077 | { | ||
1078 | u32 board_address, board_ext_address, param; | ||
1079 | u32 board_data_size, board_ext_data_size; | ||
1080 | int ret; | ||
1081 | |||
1082 | if (WARN_ON(ar->fw_board == NULL)) | ||
1083 | return -ENOENT; | ||
1084 | |||
1085 | /* | ||
1086 | * Determine where in Target RAM to write Board Data. | ||
1087 | * For AR6004, host determine Target RAM address for | ||
1088 | * writing board data. | ||
1089 | */ | ||
1090 | if (ar->target_type == TARGET_TYPE_AR6004) { | ||
1091 | board_address = AR6004_REV1_BOARD_DATA_ADDRESS; | ||
1092 | ath6kl_bmi_write(ar, | ||
1093 | ath6kl_get_hi_item_addr(ar, | ||
1094 | HI_ITEM(hi_board_data)), | ||
1095 | (u8 *) &board_address, 4); | ||
1096 | } else { | ||
1097 | ath6kl_bmi_read(ar, | ||
1098 | ath6kl_get_hi_item_addr(ar, | ||
1099 | HI_ITEM(hi_board_data)), | ||
1100 | (u8 *) &board_address, 4); | ||
1101 | } | ||
725 | 1102 | ||
726 | /* determine where in target ram to write extended board data */ | 1103 | /* determine where in target ram to write extended board data */ |
727 | ath6kl_bmi_read(ar, | 1104 | ath6kl_bmi_read(ar, |
@@ -729,21 +1106,37 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
729 | HI_ITEM(hi_board_ext_data)), | 1106 | HI_ITEM(hi_board_ext_data)), |
730 | (u8 *) &board_ext_address, 4); | 1107 | (u8 *) &board_ext_address, 4); |
731 | 1108 | ||
732 | ath6kl_dbg(ATH6KL_DBG_TRC, "board file download addr: 0x%x\n", | ||
733 | board_ext_address); | ||
734 | |||
735 | if (board_ext_address == 0) { | 1109 | if (board_ext_address == 0) { |
736 | ath6kl_err("Failed to get board file target address.\n"); | 1110 | ath6kl_err("Failed to get board file target address.\n"); |
737 | return -EINVAL; | 1111 | return -EINVAL; |
738 | } | 1112 | } |
739 | 1113 | ||
740 | if (ar->fw_board_len == (AR6003_BOARD_DATA_SZ + | 1114 | switch (ar->target_type) { |
741 | AR6003_BOARD_EXT_DATA_SZ)) { | 1115 | case TARGET_TYPE_AR6003: |
1116 | board_data_size = AR6003_BOARD_DATA_SZ; | ||
1117 | board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ; | ||
1118 | break; | ||
1119 | case TARGET_TYPE_AR6004: | ||
1120 | board_data_size = AR6004_BOARD_DATA_SZ; | ||
1121 | board_ext_data_size = AR6004_BOARD_EXT_DATA_SZ; | ||
1122 | break; | ||
1123 | default: | ||
1124 | WARN_ON(1); | ||
1125 | return -EINVAL; | ||
1126 | break; | ||
1127 | } | ||
1128 | |||
1129 | if (ar->fw_board_len == (board_data_size + | ||
1130 | board_ext_data_size)) { | ||
1131 | |||
742 | /* write extended board data */ | 1132 | /* write extended board data */ |
743 | ret = ath6kl_bmi_write(ar, board_ext_address, | 1133 | ath6kl_dbg(ATH6KL_DBG_BOOT, |
744 | ar->fw_board + AR6003_BOARD_DATA_SZ, | 1134 | "writing extended board data to 0x%x (%d B)\n", |
745 | AR6003_BOARD_EXT_DATA_SZ); | 1135 | board_ext_address, board_ext_data_size); |
746 | 1136 | ||
1137 | ret = ath6kl_bmi_write(ar, board_ext_address, | ||
1138 | ar->fw_board + board_data_size, | ||
1139 | board_ext_data_size); | ||
747 | if (ret) { | 1140 | if (ret) { |
748 | ath6kl_err("Failed to write extended board data: %d\n", | 1141 | ath6kl_err("Failed to write extended board data: %d\n", |
749 | ret); | 1142 | ret); |
@@ -751,21 +1144,25 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
751 | } | 1144 | } |
752 | 1145 | ||
753 | /* record that extended board data is initialized */ | 1146 | /* record that extended board data is initialized */ |
754 | param = (AR6003_BOARD_EXT_DATA_SZ << 16) | 1; | 1147 | param = (board_ext_data_size << 16) | 1; |
1148 | |||
755 | ath6kl_bmi_write(ar, | 1149 | ath6kl_bmi_write(ar, |
756 | ath6kl_get_hi_item_addr(ar, | 1150 | ath6kl_get_hi_item_addr(ar, |
757 | HI_ITEM(hi_board_ext_data_config)), | 1151 | HI_ITEM(hi_board_ext_data_config)), |
758 | (unsigned char *) ¶m, 4); | 1152 | (unsigned char *) ¶m, 4); |
759 | } | 1153 | } |
760 | 1154 | ||
761 | if (ar->fw_board_len < AR6003_BOARD_DATA_SZ) { | 1155 | if (ar->fw_board_len < board_data_size) { |
762 | ath6kl_err("Too small board file: %zu\n", ar->fw_board_len); | 1156 | ath6kl_err("Too small board file: %zu\n", ar->fw_board_len); |
763 | ret = -EINVAL; | 1157 | ret = -EINVAL; |
764 | return ret; | 1158 | return ret; |
765 | } | 1159 | } |
766 | 1160 | ||
1161 | ath6kl_dbg(ATH6KL_DBG_BOOT, "writing board file to 0x%x (%d B)\n", | ||
1162 | board_address, board_data_size); | ||
1163 | |||
767 | ret = ath6kl_bmi_write(ar, board_address, ar->fw_board, | 1164 | ret = ath6kl_bmi_write(ar, board_address, ar->fw_board, |
768 | AR6003_BOARD_DATA_SZ); | 1165 | board_data_size); |
769 | 1166 | ||
770 | if (ret) { | 1167 | if (ret) { |
771 | ath6kl_err("Board file bmi write failed: %d\n", ret); | 1168 | ath6kl_err("Board file bmi write failed: %d\n", ret); |
@@ -784,31 +1181,16 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
784 | 1181 | ||
785 | static int ath6kl_upload_otp(struct ath6kl *ar) | 1182 | static int ath6kl_upload_otp(struct ath6kl *ar) |
786 | { | 1183 | { |
787 | const char *filename; | ||
788 | u32 address, param; | 1184 | u32 address, param; |
789 | int ret; | 1185 | int ret; |
790 | 1186 | ||
791 | switch (ar->version.target_ver) { | 1187 | if (WARN_ON(ar->fw_otp == NULL)) |
792 | case AR6003_REV2_VERSION: | 1188 | return -ENOENT; |
793 | filename = AR6003_REV2_OTP_FILE; | ||
794 | break; | ||
795 | default: | ||
796 | filename = AR6003_REV3_OTP_FILE; | ||
797 | break; | ||
798 | } | ||
799 | 1189 | ||
800 | if (ar->fw_otp == NULL) { | 1190 | address = ar->hw.app_load_addr; |
801 | ret = ath6kl_get_fw(ar, filename, &ar->fw_otp, | ||
802 | &ar->fw_otp_len); | ||
803 | if (ret) { | ||
804 | ath6kl_err("Failed to get OTP file %s: %d\n", | ||
805 | filename, ret); | ||
806 | return ret; | ||
807 | } | ||
808 | } | ||
809 | 1191 | ||
810 | address = ath6kl_get_load_address(ar->version.target_ver, | 1192 | ath6kl_dbg(ATH6KL_DBG_BOOT, "writing otp to 0x%x (%zd B)\n", address, |
811 | APP_LOAD_ADDR); | 1193 | ar->fw_otp_len); |
812 | 1194 | ||
813 | ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp, | 1195 | ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp, |
814 | ar->fw_otp_len); | 1196 | ar->fw_otp_len); |
@@ -817,10 +1199,25 @@ static int ath6kl_upload_otp(struct ath6kl *ar) | |||
817 | return ret; | 1199 | return ret; |
818 | } | 1200 | } |
819 | 1201 | ||
1202 | /* read firmware start address */ | ||
1203 | ret = ath6kl_bmi_read(ar, | ||
1204 | ath6kl_get_hi_item_addr(ar, | ||
1205 | HI_ITEM(hi_app_start)), | ||
1206 | (u8 *) &address, sizeof(address)); | ||
1207 | |||
1208 | if (ret) { | ||
1209 | ath6kl_err("Failed to read hi_app_start: %d\n", ret); | ||
1210 | return ret; | ||
1211 | } | ||
1212 | |||
1213 | ar->hw.app_start_override_addr = address; | ||
1214 | |||
1215 | ath6kl_dbg(ATH6KL_DBG_BOOT, "app_start_override_addr 0x%x\n", | ||
1216 | ar->hw.app_start_override_addr); | ||
1217 | |||
820 | /* execute the OTP code */ | 1218 | /* execute the OTP code */ |
1219 | ath6kl_dbg(ATH6KL_DBG_BOOT, "executing OTP at 0x%x\n", address); | ||
821 | param = 0; | 1220 | param = 0; |
822 | address = ath6kl_get_load_address(ar->version.target_ver, | ||
823 | APP_START_OVERRIDE_ADDR); | ||
824 | ath6kl_bmi_execute(ar, address, ¶m); | 1221 | ath6kl_bmi_execute(ar, address, ¶m); |
825 | 1222 | ||
826 | return ret; | 1223 | return ret; |
@@ -828,30 +1225,16 @@ static int ath6kl_upload_otp(struct ath6kl *ar) | |||
828 | 1225 | ||
829 | static int ath6kl_upload_firmware(struct ath6kl *ar) | 1226 | static int ath6kl_upload_firmware(struct ath6kl *ar) |
830 | { | 1227 | { |
831 | const char *filename; | ||
832 | u32 address; | 1228 | u32 address; |
833 | int ret; | 1229 | int ret; |
834 | 1230 | ||
835 | switch (ar->version.target_ver) { | 1231 | if (WARN_ON(ar->fw == NULL)) |
836 | case AR6003_REV2_VERSION: | 1232 | return -ENOENT; |
837 | filename = AR6003_REV2_FIRMWARE_FILE; | ||
838 | break; | ||
839 | default: | ||
840 | filename = AR6003_REV3_FIRMWARE_FILE; | ||
841 | break; | ||
842 | } | ||
843 | 1233 | ||
844 | if (ar->fw == NULL) { | 1234 | address = ar->hw.app_load_addr; |
845 | ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); | ||
846 | if (ret) { | ||
847 | ath6kl_err("Failed to get firmware file %s: %d\n", | ||
848 | filename, ret); | ||
849 | return ret; | ||
850 | } | ||
851 | } | ||
852 | 1235 | ||
853 | address = ath6kl_get_load_address(ar->version.target_ver, | 1236 | ath6kl_dbg(ATH6KL_DBG_BOOT, "writing firmware to 0x%x (%zd B)\n", |
854 | APP_LOAD_ADDR); | 1237 | address, ar->fw_len); |
855 | 1238 | ||
856 | ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len); | 1239 | ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len); |
857 | 1240 | ||
@@ -860,41 +1243,29 @@ static int ath6kl_upload_firmware(struct ath6kl *ar) | |||
860 | return ret; | 1243 | return ret; |
861 | } | 1244 | } |
862 | 1245 | ||
863 | /* Set starting address for firmware */ | 1246 | /* |
864 | address = ath6kl_get_load_address(ar->version.target_ver, | 1247 | * Set starting address for firmware |
865 | APP_START_OVERRIDE_ADDR); | 1248 | * Don't need to setup app_start override addr on AR6004 |
866 | ath6kl_bmi_set_app_start(ar, address); | 1249 | */ |
867 | 1250 | if (ar->target_type != TARGET_TYPE_AR6004) { | |
1251 | address = ar->hw.app_start_override_addr; | ||
1252 | ath6kl_bmi_set_app_start(ar, address); | ||
1253 | } | ||
868 | return ret; | 1254 | return ret; |
869 | } | 1255 | } |
870 | 1256 | ||
871 | static int ath6kl_upload_patch(struct ath6kl *ar) | 1257 | static int ath6kl_upload_patch(struct ath6kl *ar) |
872 | { | 1258 | { |
873 | const char *filename; | ||
874 | u32 address, param; | 1259 | u32 address, param; |
875 | int ret; | 1260 | int ret; |
876 | 1261 | ||
877 | switch (ar->version.target_ver) { | 1262 | if (WARN_ON(ar->fw_patch == NULL)) |
878 | case AR6003_REV2_VERSION: | 1263 | return -ENOENT; |
879 | filename = AR6003_REV2_PATCH_FILE; | ||
880 | break; | ||
881 | default: | ||
882 | filename = AR6003_REV3_PATCH_FILE; | ||
883 | break; | ||
884 | } | ||
885 | 1264 | ||
886 | if (ar->fw_patch == NULL) { | 1265 | address = ar->hw.dataset_patch_addr; |
887 | ret = ath6kl_get_fw(ar, filename, &ar->fw_patch, | ||
888 | &ar->fw_patch_len); | ||
889 | if (ret) { | ||
890 | ath6kl_err("Failed to get patch file %s: %d\n", | ||
891 | filename, ret); | ||
892 | return ret; | ||
893 | } | ||
894 | } | ||
895 | 1266 | ||
896 | address = ath6kl_get_load_address(ar->version.target_ver, | 1267 | ath6kl_dbg(ATH6KL_DBG_BOOT, "writing patch to 0x%x (%zd B)\n", |
897 | DATASET_PATCH_ADDR); | 1268 | address, ar->fw_patch_len); |
898 | 1269 | ||
899 | ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len); | 1270 | ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len); |
900 | if (ret) { | 1271 | if (ret) { |
@@ -916,7 +1287,8 @@ static int ath6kl_init_upload(struct ath6kl *ar) | |||
916 | u32 param, options, sleep, address; | 1287 | u32 param, options, sleep, address; |
917 | int status = 0; | 1288 | int status = 0; |
918 | 1289 | ||
919 | if (ar->target_type != TARGET_TYPE_AR6003) | 1290 | if (ar->target_type != TARGET_TYPE_AR6003 && |
1291 | ar->target_type != TARGET_TYPE_AR6004) | ||
920 | return -EINVAL; | 1292 | return -EINVAL; |
921 | 1293 | ||
922 | /* temporarily disable system sleep */ | 1294 | /* temporarily disable system sleep */ |
@@ -948,18 +1320,22 @@ static int ath6kl_init_upload(struct ath6kl *ar) | |||
948 | options, sleep); | 1320 | options, sleep); |
949 | 1321 | ||
950 | /* program analog PLL register */ | 1322 | /* program analog PLL register */ |
951 | status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER, | 1323 | /* no need to control 40/44MHz clock on AR6004 */ |
952 | 0xF9104001); | 1324 | if (ar->target_type != TARGET_TYPE_AR6004) { |
953 | if (status) | 1325 | status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER, |
954 | return status; | 1326 | 0xF9104001); |
955 | 1327 | ||
956 | /* Run at 80/88MHz by default */ | 1328 | if (status) |
957 | param = SM(CPU_CLOCK_STANDARD, 1); | 1329 | return status; |
958 | 1330 | ||
959 | address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS; | 1331 | /* Run at 80/88MHz by default */ |
960 | status = ath6kl_bmi_reg_write(ar, address, param); | 1332 | param = SM(CPU_CLOCK_STANDARD, 1); |
961 | if (status) | 1333 | |
962 | return status; | 1334 | address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS; |
1335 | status = ath6kl_bmi_reg_write(ar, address, param); | ||
1336 | if (status) | ||
1337 | return status; | ||
1338 | } | ||
963 | 1339 | ||
964 | param = 0; | 1340 | param = 0; |
965 | address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS; | 1341 | address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS; |
@@ -1036,6 +1412,45 @@ static int ath6kl_init_upload(struct ath6kl *ar) | |||
1036 | return status; | 1412 | return status; |
1037 | } | 1413 | } |
1038 | 1414 | ||
1415 | static int ath6kl_init_hw_params(struct ath6kl *ar) | ||
1416 | { | ||
1417 | switch (ar->version.target_ver) { | ||
1418 | case AR6003_REV2_VERSION: | ||
1419 | ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS; | ||
1420 | ar->hw.app_load_addr = AR6003_REV2_APP_LOAD_ADDRESS; | ||
1421 | ar->hw.board_ext_data_addr = AR6003_REV2_BOARD_EXT_DATA_ADDRESS; | ||
1422 | ar->hw.reserved_ram_size = AR6003_REV2_RAM_RESERVE_SIZE; | ||
1423 | break; | ||
1424 | case AR6003_REV3_VERSION: | ||
1425 | ar->hw.dataset_patch_addr = AR6003_REV3_DATASET_PATCH_ADDRESS; | ||
1426 | ar->hw.app_load_addr = 0x1234; | ||
1427 | ar->hw.board_ext_data_addr = AR6003_REV3_BOARD_EXT_DATA_ADDRESS; | ||
1428 | ar->hw.reserved_ram_size = AR6003_REV3_RAM_RESERVE_SIZE; | ||
1429 | break; | ||
1430 | case AR6004_REV1_VERSION: | ||
1431 | ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS; | ||
1432 | ar->hw.app_load_addr = AR6003_REV3_APP_LOAD_ADDRESS; | ||
1433 | ar->hw.board_ext_data_addr = AR6004_REV1_BOARD_EXT_DATA_ADDRESS; | ||
1434 | ar->hw.reserved_ram_size = AR6004_REV1_RAM_RESERVE_SIZE; | ||
1435 | break; | ||
1436 | default: | ||
1437 | ath6kl_err("Unsupported hardware version: 0x%x\n", | ||
1438 | ar->version.target_ver); | ||
1439 | return -EINVAL; | ||
1440 | } | ||
1441 | |||
1442 | ath6kl_dbg(ATH6KL_DBG_BOOT, | ||
1443 | "target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x\n", | ||
1444 | ar->version.target_ver, ar->target_type, | ||
1445 | ar->hw.dataset_patch_addr, ar->hw.app_load_addr); | ||
1446 | ath6kl_dbg(ATH6KL_DBG_BOOT, | ||
1447 | "app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x", | ||
1448 | ar->hw.app_start_override_addr, ar->hw.board_ext_data_addr, | ||
1449 | ar->hw.reserved_ram_size); | ||
1450 | |||
1451 | return 0; | ||
1452 | } | ||
1453 | |||
1039 | static int ath6kl_init(struct net_device *dev) | 1454 | static int ath6kl_init(struct net_device *dev) |
1040 | { | 1455 | { |
1041 | struct ath6kl *ar = ath6kl_priv(dev); | 1456 | struct ath6kl *ar = ath6kl_priv(dev); |
@@ -1062,8 +1477,6 @@ static int ath6kl_init(struct net_device *dev) | |||
1062 | 1477 | ||
1063 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); | 1478 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); |
1064 | 1479 | ||
1065 | wlan_node_table_init(&ar->scan_table); | ||
1066 | |||
1067 | /* | 1480 | /* |
1068 | * The reason we have to wait for the target here is that the | 1481 | * The reason we have to wait for the target here is that the |
1069 | * driver layer has to init BMI in order to set the host block | 1482 | * driver layer has to init BMI in order to set the host block |
@@ -1111,6 +1524,8 @@ static int ath6kl_init(struct net_device *dev) | |||
1111 | &ar->flag), | 1524 | &ar->flag), |
1112 | WMI_TIMEOUT); | 1525 | WMI_TIMEOUT); |
1113 | 1526 | ||
1527 | ath6kl_dbg(ATH6KL_DBG_BOOT, "firmware booted\n"); | ||
1528 | |||
1114 | if (ar->version.abi_ver != ATH6KL_ABI_VERSION) { | 1529 | if (ar->version.abi_ver != ATH6KL_ABI_VERSION) { |
1115 | ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n", | 1530 | ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n", |
1116 | ATH6KL_ABI_VERSION, ar->version.abi_ver); | 1531 | ATH6KL_ABI_VERSION, ar->version.abi_ver); |
@@ -1133,6 +1548,8 @@ static int ath6kl_init(struct net_device *dev) | |||
1133 | ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | | 1548 | ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | |
1134 | ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; | 1549 | ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; |
1135 | 1550 | ||
1551 | ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; | ||
1552 | |||
1136 | status = ath6kl_target_config_wlan_params(ar); | 1553 | status = ath6kl_target_config_wlan_params(ar); |
1137 | if (!status) | 1554 | if (!status) |
1138 | goto ath6kl_init_done; | 1555 | goto ath6kl_init_done; |
@@ -1145,7 +1562,6 @@ err_rxbuf_cleanup: | |||
1145 | err_cleanup_scatter: | 1562 | err_cleanup_scatter: |
1146 | ath6kl_hif_cleanup_scatter(ar); | 1563 | ath6kl_hif_cleanup_scatter(ar); |
1147 | err_node_cleanup: | 1564 | err_node_cleanup: |
1148 | wlan_node_table_cleanup(&ar->scan_table); | ||
1149 | ath6kl_wmi_shutdown(ar->wmi); | 1565 | ath6kl_wmi_shutdown(ar->wmi); |
1150 | clear_bit(WMI_ENABLED, &ar->flag); | 1566 | clear_bit(WMI_ENABLED, &ar->flag); |
1151 | ar->wmi = NULL; | 1567 | ar->wmi = NULL; |
@@ -1175,6 +1591,10 @@ int ath6kl_core_init(struct ath6kl *ar) | |||
1175 | ar->target_type = le32_to_cpu(targ_info.type); | 1591 | ar->target_type = le32_to_cpu(targ_info.type); |
1176 | ar->wdev->wiphy->hw_version = le32_to_cpu(targ_info.version); | 1592 | ar->wdev->wiphy->hw_version = le32_to_cpu(targ_info.version); |
1177 | 1593 | ||
1594 | ret = ath6kl_init_hw_params(ar); | ||
1595 | if (ret) | ||
1596 | goto err_bmi_cleanup; | ||
1597 | |||
1178 | ret = ath6kl_configure_target(ar); | 1598 | ret = ath6kl_configure_target(ar); |
1179 | if (ret) | 1599 | if (ret) |
1180 | goto err_bmi_cleanup; | 1600 | goto err_bmi_cleanup; |
@@ -1193,6 +1613,10 @@ int ath6kl_core_init(struct ath6kl *ar) | |||
1193 | goto err_htc_cleanup; | 1613 | goto err_htc_cleanup; |
1194 | } | 1614 | } |
1195 | 1615 | ||
1616 | ret = ath6kl_fetch_firmwares(ar); | ||
1617 | if (ret) | ||
1618 | goto err_htc_cleanup; | ||
1619 | |||
1196 | ret = ath6kl_init_upload(ar); | 1620 | ret = ath6kl_init_upload(ar); |
1197 | if (ret) | 1621 | if (ret) |
1198 | goto err_htc_cleanup; | 1622 | goto err_htc_cleanup; |
@@ -1285,6 +1709,8 @@ void ath6kl_destroy(struct net_device *dev, unsigned int unregister) | |||
1285 | 1709 | ||
1286 | ath6kl_bmi_cleanup(ar); | 1710 | ath6kl_bmi_cleanup(ar); |
1287 | 1711 | ||
1712 | ath6kl_debug_cleanup(ar); | ||
1713 | |||
1288 | if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) { | 1714 | if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) { |
1289 | unregister_netdev(dev); | 1715 | unregister_netdev(dev); |
1290 | clear_bit(NETDEV_REGISTERED, &ar->flag); | 1716 | clear_bit(NETDEV_REGISTERED, &ar->flag); |
@@ -1292,8 +1718,6 @@ void ath6kl_destroy(struct net_device *dev, unsigned int unregister) | |||
1292 | 1718 | ||
1293 | free_netdev(dev); | 1719 | free_netdev(dev); |
1294 | 1720 | ||
1295 | wlan_node_table_cleanup(&ar->scan_table); | ||
1296 | |||
1297 | kfree(ar->fw_board); | 1721 | kfree(ar->fw_board); |
1298 | kfree(ar->fw_otp); | 1722 | kfree(ar->fw_otp); |
1299 | kfree(ar->fw); | 1723 | kfree(ar->fw); |
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index c336eae0cf48..30b5a53db9ed 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c | |||
@@ -61,7 +61,8 @@ static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie, | |||
61 | 61 | ||
62 | sta = &ar->sta_list[free_slot]; | 62 | sta = &ar->sta_list[free_slot]; |
63 | memcpy(sta->mac, mac, ETH_ALEN); | 63 | memcpy(sta->mac, mac, ETH_ALEN); |
64 | memcpy(sta->wpa_ie, wpaie, ielen); | 64 | if (ielen <= ATH6KL_MAX_IE) |
65 | memcpy(sta->wpa_ie, wpaie, ielen); | ||
65 | sta->aid = aid; | 66 | sta->aid = aid; |
66 | sta->keymgmt = keymgmt; | 67 | sta->keymgmt = keymgmt; |
67 | sta->ucipher = ucipher; | 68 | sta->ucipher = ucipher; |
@@ -177,8 +178,8 @@ void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie) | |||
177 | static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr) | 178 | static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr) |
178 | { | 179 | { |
179 | int status; | 180 | int status; |
180 | u8 addr_val[4]; | ||
181 | s32 i; | 181 | s32 i; |
182 | __le32 addr_val; | ||
182 | 183 | ||
183 | /* | 184 | /* |
184 | * Write bytes 1,2,3 of the register to set the upper address bytes, | 185 | * Write bytes 1,2,3 of the register to set the upper address bytes, |
@@ -188,16 +189,18 @@ static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr) | |||
188 | for (i = 1; i <= 3; i++) { | 189 | for (i = 1; i <= 3; i++) { |
189 | /* | 190 | /* |
190 | * Fill the buffer with the address byte value we want to | 191 | * Fill the buffer with the address byte value we want to |
191 | * hit 4 times. | 192 | * hit 4 times. No need to worry about endianness as the |
193 | * same byte is copied to all four bytes of addr_val at | ||
194 | * any time. | ||
192 | */ | 195 | */ |
193 | memset(addr_val, ((u8 *)&addr)[i], 4); | 196 | memset((u8 *)&addr_val, ((u8 *)&addr)[i], 4); |
194 | 197 | ||
195 | /* | 198 | /* |
196 | * Hit each byte of the register address with a 4-byte | 199 | * Hit each byte of the register address with a 4-byte |
197 | * write operation to the same address, this is a harmless | 200 | * write operation to the same address, this is a harmless |
198 | * operation. | 201 | * operation. |
199 | */ | 202 | */ |
200 | status = hif_read_write_sync(ar, reg_addr + i, addr_val, | 203 | status = hif_read_write_sync(ar, reg_addr + i, (u8 *)&addr_val, |
201 | 4, HIF_WR_SYNC_BYTE_FIX); | 204 | 4, HIF_WR_SYNC_BYTE_FIX); |
202 | if (status) | 205 | if (status) |
203 | break; | 206 | break; |
@@ -215,7 +218,9 @@ static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr) | |||
215 | * cycle to start, the extra 3 byte write to bytes 1,2,3 has no | 218 | * cycle to start, the extra 3 byte write to bytes 1,2,3 has no |
216 | * effect since we are writing the same values again | 219 | * effect since we are writing the same values again |
217 | */ | 220 | */ |
218 | status = hif_read_write_sync(ar, reg_addr, (u8 *)(&addr), | 221 | addr_val = cpu_to_le32(addr); |
222 | status = hif_read_write_sync(ar, reg_addr, | ||
223 | (u8 *)&(addr_val), | ||
219 | 4, HIF_WR_SYNC_BYTE_INC); | 224 | 4, HIF_WR_SYNC_BYTE_INC); |
220 | 225 | ||
221 | if (status) { | 226 | if (status) { |
@@ -228,90 +233,193 @@ static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr) | |||
228 | } | 233 | } |
229 | 234 | ||
230 | /* | 235 | /* |
231 | * Read from the ATH6KL through its diagnostic window. No cooperation from | 236 | * Read from the hardware through its diagnostic window. No cooperation |
232 | * the Target is required for this. | 237 | * from the firmware is required for this. |
233 | */ | 238 | */ |
234 | int ath6kl_read_reg_diag(struct ath6kl *ar, u32 *address, u32 *data) | 239 | int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value) |
235 | { | 240 | { |
236 | int status; | 241 | int ret; |
237 | 242 | ||
238 | /* set window register to start read cycle */ | 243 | /* set window register to start read cycle */ |
239 | status = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, | 244 | ret = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, address); |
240 | *address); | 245 | if (ret) |
241 | 246 | return ret; | |
242 | if (status) | ||
243 | return status; | ||
244 | 247 | ||
245 | /* read the data */ | 248 | /* read the data */ |
246 | status = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *)data, | 249 | ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) value, |
247 | sizeof(u32), HIF_RD_SYNC_BYTE_INC); | 250 | sizeof(*value), HIF_RD_SYNC_BYTE_INC); |
248 | if (status) { | 251 | if (ret) { |
249 | ath6kl_err("failed to read from window data addr\n"); | 252 | ath6kl_warn("failed to read32 through diagnose window: %d\n", |
250 | return status; | 253 | ret); |
254 | return ret; | ||
251 | } | 255 | } |
252 | 256 | ||
253 | return status; | 257 | return 0; |
254 | } | 258 | } |
255 | 259 | ||
256 | |||
257 | /* | 260 | /* |
258 | * Write to the ATH6KL through its diagnostic window. No cooperation from | 261 | * Write to the ATH6KL through its diagnostic window. No cooperation from |
259 | * the Target is required for this. | 262 | * the Target is required for this. |
260 | */ | 263 | */ |
261 | static int ath6kl_write_reg_diag(struct ath6kl *ar, u32 *address, u32 *data) | 264 | int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value) |
262 | { | 265 | { |
263 | int status; | 266 | int ret; |
264 | 267 | ||
265 | /* set write data */ | 268 | /* set write data */ |
266 | status = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *)data, | 269 | ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) &value, |
267 | sizeof(u32), HIF_WR_SYNC_BYTE_INC); | 270 | sizeof(value), HIF_WR_SYNC_BYTE_INC); |
268 | if (status) { | 271 | if (ret) { |
269 | ath6kl_err("failed to write 0x%x to window data addr\n", *data); | 272 | ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n", |
270 | return status; | 273 | address, value); |
274 | return ret; | ||
271 | } | 275 | } |
272 | 276 | ||
273 | /* set window register, which starts the write cycle */ | 277 | /* set window register, which starts the write cycle */ |
274 | return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS, | 278 | return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS, |
275 | *address); | 279 | address); |
276 | } | 280 | } |
277 | 281 | ||
278 | int ath6kl_access_datadiag(struct ath6kl *ar, u32 address, | 282 | int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length) |
279 | u8 *data, u32 length, bool read) | 283 | { |
284 | u32 count, *buf = data; | ||
285 | int ret; | ||
286 | |||
287 | if (WARN_ON(length % 4)) | ||
288 | return -EINVAL; | ||
289 | |||
290 | for (count = 0; count < length / 4; count++, address += 4) { | ||
291 | ret = ath6kl_diag_read32(ar, address, &buf[count]); | ||
292 | if (ret) | ||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length) | ||
280 | { | 300 | { |
281 | u32 count; | 301 | u32 count; |
282 | int status = 0; | 302 | __le32 *buf = data; |
303 | int ret; | ||
283 | 304 | ||
284 | for (count = 0; count < length; count += 4, address += 4) { | 305 | if (WARN_ON(length % 4)) |
285 | if (read) { | 306 | return -EINVAL; |
286 | status = ath6kl_read_reg_diag(ar, &address, | 307 | |
287 | (u32 *) &data[count]); | 308 | for (count = 0; count < length / 4; count++, address += 4) { |
288 | if (status) | 309 | ret = ath6kl_diag_write32(ar, address, buf[count]); |
289 | break; | 310 | if (ret) |
290 | } else { | 311 | return ret; |
291 | status = ath6kl_write_reg_diag(ar, &address, | 312 | } |
292 | (u32 *) &data[count]); | 313 | |
293 | if (status) | 314 | return 0; |
294 | break; | 315 | } |
295 | } | 316 | |
317 | int ath6kl_read_fwlogs(struct ath6kl *ar) | ||
318 | { | ||
319 | struct ath6kl_dbglog_hdr debug_hdr; | ||
320 | struct ath6kl_dbglog_buf debug_buf; | ||
321 | u32 address, length, dropped, firstbuf, debug_hdr_addr; | ||
322 | int ret = 0, loop; | ||
323 | u8 *buf; | ||
324 | |||
325 | buf = kmalloc(ATH6KL_FWLOG_PAYLOAD_SIZE, GFP_KERNEL); | ||
326 | if (!buf) | ||
327 | return -ENOMEM; | ||
328 | |||
329 | address = TARG_VTOP(ar->target_type, | ||
330 | ath6kl_get_hi_item_addr(ar, | ||
331 | HI_ITEM(hi_dbglog_hdr))); | ||
332 | |||
333 | ret = ath6kl_diag_read32(ar, address, &debug_hdr_addr); | ||
334 | if (ret) | ||
335 | goto out; | ||
336 | |||
337 | /* Get the contents of the ring buffer */ | ||
338 | if (debug_hdr_addr == 0) { | ||
339 | ath6kl_warn("Invalid address for debug_hdr_addr\n"); | ||
340 | ret = -EINVAL; | ||
341 | goto out; | ||
296 | } | 342 | } |
297 | 343 | ||
298 | return status; | 344 | address = TARG_VTOP(ar->target_type, debug_hdr_addr); |
345 | ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); | ||
346 | |||
347 | address = TARG_VTOP(ar->target_type, | ||
348 | le32_to_cpu(debug_hdr.dbuf_addr)); | ||
349 | firstbuf = address; | ||
350 | dropped = le32_to_cpu(debug_hdr.dropped); | ||
351 | ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); | ||
352 | |||
353 | loop = 100; | ||
354 | |||
355 | do { | ||
356 | address = TARG_VTOP(ar->target_type, | ||
357 | le32_to_cpu(debug_buf.buffer_addr)); | ||
358 | length = le32_to_cpu(debug_buf.length); | ||
359 | |||
360 | if (length != 0 && (le32_to_cpu(debug_buf.length) <= | ||
361 | le32_to_cpu(debug_buf.bufsize))) { | ||
362 | length = ALIGN(length, 4); | ||
363 | |||
364 | ret = ath6kl_diag_read(ar, address, | ||
365 | buf, length); | ||
366 | if (ret) | ||
367 | goto out; | ||
368 | |||
369 | ath6kl_debug_fwlog_event(ar, buf, length); | ||
370 | } | ||
371 | |||
372 | address = TARG_VTOP(ar->target_type, | ||
373 | le32_to_cpu(debug_buf.next)); | ||
374 | ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); | ||
375 | if (ret) | ||
376 | goto out; | ||
377 | |||
378 | loop--; | ||
379 | |||
380 | if (WARN_ON(loop == 0)) { | ||
381 | ret = -ETIMEDOUT; | ||
382 | goto out; | ||
383 | } | ||
384 | } while (address != firstbuf); | ||
385 | |||
386 | out: | ||
387 | kfree(buf); | ||
388 | |||
389 | return ret; | ||
299 | } | 390 | } |
300 | 391 | ||
392 | /* FIXME: move to a better place, target.h? */ | ||
393 | #define AR6003_RESET_CONTROL_ADDRESS 0x00004000 | ||
394 | #define AR6004_RESET_CONTROL_ADDRESS 0x00004000 | ||
395 | |||
301 | static void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, | 396 | static void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, |
302 | bool wait_fot_compltn, bool cold_reset) | 397 | bool wait_fot_compltn, bool cold_reset) |
303 | { | 398 | { |
304 | int status = 0; | 399 | int status = 0; |
305 | u32 address; | 400 | u32 address; |
306 | u32 data; | 401 | __le32 data; |
307 | 402 | ||
308 | if (target_type != TARGET_TYPE_AR6003) | 403 | if (target_type != TARGET_TYPE_AR6003 && |
404 | target_type != TARGET_TYPE_AR6004) | ||
309 | return; | 405 | return; |
310 | 406 | ||
311 | data = cold_reset ? RESET_CONTROL_COLD_RST : RESET_CONTROL_MBOX_RST; | 407 | data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) : |
408 | cpu_to_le32(RESET_CONTROL_MBOX_RST); | ||
312 | 409 | ||
313 | address = RTC_BASE_ADDRESS; | 410 | switch (target_type) { |
314 | status = ath6kl_write_reg_diag(ar, &address, &data); | 411 | case TARGET_TYPE_AR6003: |
412 | address = AR6003_RESET_CONTROL_ADDRESS; | ||
413 | break; | ||
414 | case TARGET_TYPE_AR6004: | ||
415 | address = AR6004_RESET_CONTROL_ADDRESS; | ||
416 | break; | ||
417 | default: | ||
418 | address = AR6003_RESET_CONTROL_ADDRESS; | ||
419 | break; | ||
420 | } | ||
421 | |||
422 | status = ath6kl_diag_write32(ar, address, data); | ||
315 | 423 | ||
316 | if (status) | 424 | if (status) |
317 | ath6kl_err("failed to reset target\n"); | 425 | ath6kl_err("failed to reset target\n"); |
@@ -411,68 +519,107 @@ static void ath6kl_install_static_wep_keys(struct ath6kl *ar) | |||
411 | } | 519 | } |
412 | } | 520 | } |
413 | 521 | ||
414 | static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid, | 522 | void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel) |
415 | u16 listen_int, u16 beacon_int, | ||
416 | u8 assoc_resp_len, u8 *assoc_info) | ||
417 | { | 523 | { |
418 | struct net_device *dev = ar->net_dev; | ||
419 | struct station_info sinfo; | ||
420 | struct ath6kl_req_key *ik; | 524 | struct ath6kl_req_key *ik; |
421 | enum crypto_type keyType = NONE_CRYPT; | 525 | int res; |
526 | u8 key_rsc[ATH6KL_KEY_SEQ_LEN]; | ||
422 | 527 | ||
423 | if (memcmp(dev->dev_addr, bssid, ETH_ALEN) == 0) { | 528 | ik = &ar->ap_mode_bkey; |
424 | ik = &ar->ap_mode_bkey; | ||
425 | 529 | ||
426 | switch (ar->auth_mode) { | 530 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "AP mode started on %u MHz\n", channel); |
427 | case NONE_AUTH: | 531 | |
428 | if (ar->prwise_crypto == WEP_CRYPT) | 532 | switch (ar->auth_mode) { |
429 | ath6kl_install_static_wep_keys(ar); | 533 | case NONE_AUTH: |
430 | break; | 534 | if (ar->prwise_crypto == WEP_CRYPT) |
431 | case WPA_PSK_AUTH: | 535 | ath6kl_install_static_wep_keys(ar); |
432 | case WPA2_PSK_AUTH: | 536 | break; |
433 | case (WPA_PSK_AUTH|WPA2_PSK_AUTH): | 537 | case WPA_PSK_AUTH: |
434 | switch (ik->ik_type) { | 538 | case WPA2_PSK_AUTH: |
435 | case ATH6KL_CIPHER_TKIP: | 539 | case (WPA_PSK_AUTH | WPA2_PSK_AUTH): |
436 | keyType = TKIP_CRYPT; | 540 | if (!ik->valid) |
437 | break; | ||
438 | case ATH6KL_CIPHER_AES_CCM: | ||
439 | keyType = AES_CRYPT; | ||
440 | break; | ||
441 | default: | ||
442 | goto skip_key; | ||
443 | } | ||
444 | ath6kl_wmi_addkey_cmd(ar->wmi, ik->ik_keyix, keyType, | ||
445 | GROUP_USAGE, ik->ik_keylen, | ||
446 | (u8 *)&ik->ik_keyrsc, | ||
447 | ik->ik_keydata, | ||
448 | KEY_OP_INIT_VAL, ik->ik_macaddr, | ||
449 | SYNC_BOTH_WMIFLAG); | ||
450 | break; | 541 | break; |
542 | |||
543 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for " | ||
544 | "the initial group key for AP mode\n"); | ||
545 | memset(key_rsc, 0, sizeof(key_rsc)); | ||
546 | res = ath6kl_wmi_addkey_cmd( | ||
547 | ar->wmi, ik->key_index, ik->key_type, | ||
548 | GROUP_USAGE, ik->key_len, key_rsc, ik->key, | ||
549 | KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG); | ||
550 | if (res) { | ||
551 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed " | ||
552 | "addkey failed: %d\n", res); | ||
451 | } | 553 | } |
452 | skip_key: | 554 | break; |
453 | set_bit(CONNECTED, &ar->flag); | ||
454 | return; | ||
455 | } | 555 | } |
456 | 556 | ||
457 | ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", | 557 | ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); |
458 | bssid, channel); | 558 | set_bit(CONNECTED, &ar->flag); |
559 | netif_carrier_on(ar->net_dev); | ||
560 | } | ||
561 | |||
562 | void ath6kl_connect_ap_mode_sta(struct ath6kl *ar, u16 aid, u8 *mac_addr, | ||
563 | u8 keymgmt, u8 ucipher, u8 auth, | ||
564 | u8 assoc_req_len, u8 *assoc_info) | ||
565 | { | ||
566 | u8 *ies = NULL, *wpa_ie = NULL, *pos; | ||
567 | size_t ies_len = 0; | ||
568 | struct station_info sinfo; | ||
459 | 569 | ||
460 | ath6kl_add_new_sta(ar, bssid, channel, assoc_info, assoc_resp_len, | 570 | ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", mac_addr, aid); |
461 | listen_int & 0xFF, beacon_int, | 571 | |
462 | (listen_int >> 8) & 0xFF); | 572 | if (assoc_req_len > sizeof(struct ieee80211_hdr_3addr)) { |
573 | struct ieee80211_mgmt *mgmt = | ||
574 | (struct ieee80211_mgmt *) assoc_info; | ||
575 | if (ieee80211_is_assoc_req(mgmt->frame_control) && | ||
576 | assoc_req_len >= sizeof(struct ieee80211_hdr_3addr) + | ||
577 | sizeof(mgmt->u.assoc_req)) { | ||
578 | ies = mgmt->u.assoc_req.variable; | ||
579 | ies_len = assoc_info + assoc_req_len - ies; | ||
580 | } else if (ieee80211_is_reassoc_req(mgmt->frame_control) && | ||
581 | assoc_req_len >= sizeof(struct ieee80211_hdr_3addr) | ||
582 | + sizeof(mgmt->u.reassoc_req)) { | ||
583 | ies = mgmt->u.reassoc_req.variable; | ||
584 | ies_len = assoc_info + assoc_req_len - ies; | ||
585 | } | ||
586 | } | ||
587 | |||
588 | pos = ies; | ||
589 | while (pos && pos + 1 < ies + ies_len) { | ||
590 | if (pos + 2 + pos[1] > ies + ies_len) | ||
591 | break; | ||
592 | if (pos[0] == WLAN_EID_RSN) | ||
593 | wpa_ie = pos; /* RSN IE */ | ||
594 | else if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && | ||
595 | pos[1] >= 4 && | ||
596 | pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2) { | ||
597 | if (pos[5] == 0x01) | ||
598 | wpa_ie = pos; /* WPA IE */ | ||
599 | else if (pos[5] == 0x04) { | ||
600 | wpa_ie = pos; /* WPS IE */ | ||
601 | break; /* overrides WPA/RSN IE */ | ||
602 | } | ||
603 | } | ||
604 | pos += 2 + pos[1]; | ||
605 | } | ||
606 | |||
607 | ath6kl_add_new_sta(ar, mac_addr, aid, wpa_ie, | ||
608 | wpa_ie ? 2 + wpa_ie[1] : 0, | ||
609 | keymgmt, ucipher, auth); | ||
463 | 610 | ||
464 | /* send event to application */ | 611 | /* send event to application */ |
465 | memset(&sinfo, 0, sizeof(sinfo)); | 612 | memset(&sinfo, 0, sizeof(sinfo)); |
466 | 613 | ||
467 | /* TODO: sinfo.generation */ | 614 | /* TODO: sinfo.generation */ |
468 | /* TODO: need to deliver (Re)AssocReq IEs somehow.. change in | ||
469 | * cfg80211 needed, e.g., by adding those into sinfo | ||
470 | */ | ||
471 | cfg80211_new_sta(ar->net_dev, bssid, &sinfo, GFP_KERNEL); | ||
472 | 615 | ||
473 | netif_wake_queue(ar->net_dev); | 616 | sinfo.assoc_req_ies = ies; |
617 | sinfo.assoc_req_ies_len = ies_len; | ||
618 | sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; | ||
474 | 619 | ||
475 | return; | 620 | cfg80211_new_sta(ar->net_dev, mac_addr, &sinfo, GFP_KERNEL); |
621 | |||
622 | netif_wake_queue(ar->net_dev); | ||
476 | } | 623 | } |
477 | 624 | ||
478 | /* Functions for Tx credit handling */ | 625 | /* Functions for Tx credit handling */ |
@@ -779,6 +926,41 @@ void ath6kl_disconnect(struct ath6kl *ar) | |||
779 | } | 926 | } |
780 | } | 927 | } |
781 | 928 | ||
929 | void ath6kl_deep_sleep_enable(struct ath6kl *ar) | ||
930 | { | ||
931 | switch (ar->sme_state) { | ||
932 | case SME_CONNECTING: | ||
933 | cfg80211_connect_result(ar->net_dev, ar->bssid, NULL, 0, | ||
934 | NULL, 0, | ||
935 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
936 | GFP_KERNEL); | ||
937 | break; | ||
938 | case SME_CONNECTED: | ||
939 | default: | ||
940 | /* | ||
941 | * FIXME: oddly enough smeState is in DISCONNECTED during | ||
942 | * suspend, why? Need to send disconnected event in that | ||
943 | * state. | ||
944 | */ | ||
945 | cfg80211_disconnected(ar->net_dev, 0, NULL, 0, GFP_KERNEL); | ||
946 | break; | ||
947 | } | ||
948 | |||
949 | if (test_bit(CONNECTED, &ar->flag) || | ||
950 | test_bit(CONNECT_PEND, &ar->flag)) | ||
951 | ath6kl_wmi_disconnect_cmd(ar->wmi); | ||
952 | |||
953 | ar->sme_state = SME_DISCONNECTED; | ||
954 | |||
955 | /* disable scanning */ | ||
956 | if (ath6kl_wmi_scanparams_cmd(ar->wmi, 0xFFFF, 0, 0, 0, 0, 0, 0, 0, | ||
957 | 0, 0) != 0) | ||
958 | printk(KERN_WARNING "ath6kl: failed to disable scan " | ||
959 | "during suspend\n"); | ||
960 | |||
961 | ath6kl_cfg80211_scan_complete_event(ar, -ECANCELED); | ||
962 | } | ||
963 | |||
782 | /* WMI Event handlers */ | 964 | /* WMI Event handlers */ |
783 | 965 | ||
784 | static const char *get_hw_id_string(u32 id) | 966 | static const char *get_hw_id_string(u32 id) |
@@ -819,17 +1001,20 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver) | |||
819 | set_bit(WMI_READY, &ar->flag); | 1001 | set_bit(WMI_READY, &ar->flag); |
820 | wake_up(&ar->event_wq); | 1002 | wake_up(&ar->event_wq); |
821 | 1003 | ||
822 | ath6kl_info("hw %s fw %s\n", | 1004 | ath6kl_info("hw %s fw %s%s\n", |
823 | get_hw_id_string(ar->wdev->wiphy->hw_version), | 1005 | get_hw_id_string(ar->wdev->wiphy->hw_version), |
824 | ar->wdev->wiphy->fw_version); | 1006 | ar->wdev->wiphy->fw_version, |
1007 | test_bit(TESTMODE, &ar->flag) ? " testmode" : ""); | ||
825 | } | 1008 | } |
826 | 1009 | ||
827 | void ath6kl_scan_complete_evt(struct ath6kl *ar, int status) | 1010 | void ath6kl_scan_complete_evt(struct ath6kl *ar, int status) |
828 | { | 1011 | { |
829 | ath6kl_cfg80211_scan_complete_event(ar, status); | 1012 | ath6kl_cfg80211_scan_complete_event(ar, status); |
830 | 1013 | ||
831 | if (!ar->usr_bss_filter) | 1014 | if (!ar->usr_bss_filter) { |
1015 | clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); | ||
832 | ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); | 1016 | ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); |
1017 | } | ||
833 | 1018 | ||
834 | ath6kl_dbg(ATH6KL_DBG_WLAN_SCAN, "scan complete: %d\n", status); | 1019 | ath6kl_dbg(ATH6KL_DBG_WLAN_SCAN, "scan complete: %d\n", status); |
835 | } | 1020 | } |
@@ -842,13 +1027,6 @@ void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid, | |||
842 | { | 1027 | { |
843 | unsigned long flags; | 1028 | unsigned long flags; |
844 | 1029 | ||
845 | if (ar->nw_type == AP_NETWORK) { | ||
846 | ath6kl_connect_ap_mode(ar, channel, bssid, listen_int, | ||
847 | beacon_int, assoc_resp_len, | ||
848 | assoc_info); | ||
849 | return; | ||
850 | } | ||
851 | |||
852 | ath6kl_cfg80211_connect_event(ar, channel, bssid, | 1030 | ath6kl_cfg80211_connect_event(ar, channel, bssid, |
853 | listen_int, beacon_int, | 1031 | listen_int, beacon_int, |
854 | net_type, beacon_ie_len, | 1032 | net_type, beacon_ie_len, |
@@ -880,8 +1058,10 @@ void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid, | |||
880 | ar->next_ep_id = ENDPOINT_2; | 1058 | ar->next_ep_id = ENDPOINT_2; |
881 | } | 1059 | } |
882 | 1060 | ||
883 | if (!ar->usr_bss_filter) | 1061 | if (!ar->usr_bss_filter) { |
884 | ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); | 1062 | set_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); |
1063 | ath6kl_wmi_bssfilter_cmd(ar->wmi, CURRENT_BSS_FILTER, 0); | ||
1064 | } | ||
885 | } | 1065 | } |
886 | 1066 | ||
887 | void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast) | 1067 | void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast) |
@@ -915,26 +1095,11 @@ static void ath6kl_update_target_stats(struct ath6kl *ar, u8 *ptr, u32 len) | |||
915 | (struct wmi_target_stats *) ptr; | 1095 | (struct wmi_target_stats *) ptr; |
916 | struct target_stats *stats = &ar->target_stats; | 1096 | struct target_stats *stats = &ar->target_stats; |
917 | struct tkip_ccmp_stats *ccmp_stats; | 1097 | struct tkip_ccmp_stats *ccmp_stats; |
918 | struct bss *conn_bss = NULL; | ||
919 | struct cserv_stats *c_stats; | ||
920 | u8 ac; | 1098 | u8 ac; |
921 | 1099 | ||
922 | if (len < sizeof(*tgt_stats)) | 1100 | if (len < sizeof(*tgt_stats)) |
923 | return; | 1101 | return; |
924 | 1102 | ||
925 | /* update the RSSI of the connected bss */ | ||
926 | if (test_bit(CONNECTED, &ar->flag)) { | ||
927 | conn_bss = ath6kl_wmi_find_node(ar->wmi, ar->bssid); | ||
928 | if (conn_bss) { | ||
929 | c_stats = &tgt_stats->cserv_stats; | ||
930 | conn_bss->ni_rssi = | ||
931 | a_sle16_to_cpu(c_stats->cs_ave_beacon_rssi); | ||
932 | conn_bss->ni_snr = | ||
933 | tgt_stats->cserv_stats.cs_ave_beacon_snr; | ||
934 | ath6kl_wmi_node_return(ar->wmi, conn_bss); | ||
935 | } | ||
936 | } | ||
937 | |||
938 | ath6kl_dbg(ATH6KL_DBG_TRC, "updating target stats\n"); | 1103 | ath6kl_dbg(ATH6KL_DBG_TRC, "updating target stats\n"); |
939 | 1104 | ||
940 | stats->tx_pkt += le32_to_cpu(tgt_stats->stats.tx.pkt); | 1105 | stats->tx_pkt += le32_to_cpu(tgt_stats->stats.tx.pkt); |
@@ -1165,7 +1330,6 @@ void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid, | |||
1165 | u8 assoc_resp_len, u8 *assoc_info, | 1330 | u8 assoc_resp_len, u8 *assoc_info, |
1166 | u16 prot_reason_status) | 1331 | u16 prot_reason_status) |
1167 | { | 1332 | { |
1168 | struct bss *wmi_ssid_node = NULL; | ||
1169 | unsigned long flags; | 1333 | unsigned long flags; |
1170 | 1334 | ||
1171 | if (ar->nw_type == AP_NETWORK) { | 1335 | if (ar->nw_type == AP_NETWORK) { |
@@ -1188,7 +1352,10 @@ void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid, | |||
1188 | cfg80211_del_sta(ar->net_dev, bssid, GFP_KERNEL); | 1352 | cfg80211_del_sta(ar->net_dev, bssid, GFP_KERNEL); |
1189 | } | 1353 | } |
1190 | 1354 | ||
1191 | clear_bit(CONNECTED, &ar->flag); | 1355 | if (memcmp(ar->net_dev->dev_addr, bssid, ETH_ALEN) == 0) { |
1356 | memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list)); | ||
1357 | clear_bit(CONNECTED, &ar->flag); | ||
1358 | } | ||
1192 | return; | 1359 | return; |
1193 | } | 1360 | } |
1194 | 1361 | ||
@@ -1222,33 +1389,6 @@ void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid, | |||
1222 | } | 1389 | } |
1223 | } | 1390 | } |
1224 | 1391 | ||
1225 | if ((reason == NO_NETWORK_AVAIL) && test_bit(WMI_READY, &ar->flag)) { | ||
1226 | ath6kl_wmi_node_free(ar->wmi, bssid); | ||
1227 | |||
1228 | /* | ||
1229 | * In case any other same SSID nodes are present remove it, | ||
1230 | * since those nodes also not available now. | ||
1231 | */ | ||
1232 | do { | ||
1233 | /* | ||
1234 | * Find the nodes based on SSID and remove it | ||
1235 | * | ||
1236 | * Note: This case will not work out for | ||
1237 | * Hidden-SSID | ||
1238 | */ | ||
1239 | wmi_ssid_node = ath6kl_wmi_find_ssid_node(ar->wmi, | ||
1240 | ar->ssid, | ||
1241 | ar->ssid_len, | ||
1242 | false, | ||
1243 | true); | ||
1244 | |||
1245 | if (wmi_ssid_node) | ||
1246 | ath6kl_wmi_node_free(ar->wmi, | ||
1247 | wmi_ssid_node->ni_macaddr); | ||
1248 | |||
1249 | } while (wmi_ssid_node); | ||
1250 | } | ||
1251 | |||
1252 | /* update connect & link status atomically */ | 1392 | /* update connect & link status atomically */ |
1253 | spin_lock_irqsave(&ar->lock, flags); | 1393 | spin_lock_irqsave(&ar->lock, flags); |
1254 | clear_bit(CONNECTED, &ar->flag); | 1394 | clear_bit(CONNECTED, &ar->flag); |
@@ -1331,7 +1471,7 @@ void init_netdev(struct net_device *dev) | |||
1331 | dev->needed_headroom = ETH_HLEN; | 1471 | dev->needed_headroom = ETH_HLEN; |
1332 | dev->needed_headroom += sizeof(struct ath6kl_llc_snap_hdr) + | 1472 | dev->needed_headroom += sizeof(struct ath6kl_llc_snap_hdr) + |
1333 | sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH | 1473 | sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH |
1334 | + WMI_MAX_TX_META_SZ; | 1474 | + WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES; |
1335 | 1475 | ||
1336 | return; | 1476 | return; |
1337 | } | 1477 | } |
diff --git a/drivers/net/wireless/ath/ath6kl/node.c b/drivers/net/wireless/ath/ath6kl/node.c deleted file mode 100644 index 131205c610b9..000000000000 --- a/drivers/net/wireless/ath/ath6kl/node.c +++ /dev/null | |||
@@ -1,234 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "htc.h" | ||
18 | #include "wmi.h" | ||
19 | #include "debug.h" | ||
20 | |||
21 | struct bss *wlan_node_alloc(int wh_size) | ||
22 | { | ||
23 | struct bss *ni; | ||
24 | |||
25 | ni = kzalloc(sizeof(struct bss), GFP_ATOMIC); | ||
26 | |||
27 | if ((ni != NULL) && wh_size) { | ||
28 | ni->ni_buf = kmalloc(wh_size, GFP_ATOMIC); | ||
29 | if (ni->ni_buf == NULL) { | ||
30 | kfree(ni); | ||
31 | return NULL; | ||
32 | } | ||
33 | } | ||
34 | |||
35 | return ni; | ||
36 | } | ||
37 | |||
38 | void wlan_node_free(struct bss *ni) | ||
39 | { | ||
40 | kfree(ni->ni_buf); | ||
41 | kfree(ni); | ||
42 | } | ||
43 | |||
44 | void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni, | ||
45 | const u8 *mac_addr) | ||
46 | { | ||
47 | int hash; | ||
48 | |||
49 | memcpy(ni->ni_macaddr, mac_addr, ETH_ALEN); | ||
50 | hash = ATH6KL_NODE_HASH(mac_addr); | ||
51 | ni->ni_refcnt = 1; | ||
52 | |||
53 | ni->ni_tstamp = jiffies_to_msecs(jiffies); | ||
54 | ni->ni_actcnt = WLAN_NODE_INACT_CNT; | ||
55 | |||
56 | spin_lock_bh(&nt->nt_nodelock); | ||
57 | |||
58 | /* insert at the end of the node list */ | ||
59 | ni->ni_list_next = NULL; | ||
60 | ni->ni_list_prev = nt->nt_node_last; | ||
61 | if (nt->nt_node_last != NULL) | ||
62 | nt->nt_node_last->ni_list_next = ni; | ||
63 | |||
64 | nt->nt_node_last = ni; | ||
65 | if (nt->nt_node_first == NULL) | ||
66 | nt->nt_node_first = ni; | ||
67 | |||
68 | /* insert into the hash list */ | ||
69 | ni->ni_hash_next = nt->nt_hash[hash]; | ||
70 | if (ni->ni_hash_next != NULL) | ||
71 | nt->nt_hash[hash]->ni_hash_prev = ni; | ||
72 | |||
73 | ni->ni_hash_prev = NULL; | ||
74 | nt->nt_hash[hash] = ni; | ||
75 | |||
76 | spin_unlock_bh(&nt->nt_nodelock); | ||
77 | } | ||
78 | |||
79 | struct bss *wlan_find_node(struct ath6kl_node_table *nt, | ||
80 | const u8 *mac_addr) | ||
81 | { | ||
82 | struct bss *ni, *found_ni = NULL; | ||
83 | int hash; | ||
84 | |||
85 | spin_lock_bh(&nt->nt_nodelock); | ||
86 | |||
87 | hash = ATH6KL_NODE_HASH(mac_addr); | ||
88 | for (ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) { | ||
89 | if (memcmp(ni->ni_macaddr, mac_addr, ETH_ALEN) == 0) { | ||
90 | ni->ni_refcnt++; | ||
91 | found_ni = ni; | ||
92 | break; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | spin_unlock_bh(&nt->nt_nodelock); | ||
97 | |||
98 | return found_ni; | ||
99 | } | ||
100 | |||
101 | void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni) | ||
102 | { | ||
103 | int hash; | ||
104 | |||
105 | spin_lock_bh(&nt->nt_nodelock); | ||
106 | |||
107 | if (ni->ni_list_prev == NULL) | ||
108 | /* fix list head */ | ||
109 | nt->nt_node_first = ni->ni_list_next; | ||
110 | else | ||
111 | ni->ni_list_prev->ni_list_next = ni->ni_list_next; | ||
112 | |||
113 | if (ni->ni_list_next == NULL) | ||
114 | /* fix list tail */ | ||
115 | nt->nt_node_last = ni->ni_list_prev; | ||
116 | else | ||
117 | ni->ni_list_next->ni_list_prev = ni->ni_list_prev; | ||
118 | |||
119 | if (ni->ni_hash_prev == NULL) { | ||
120 | /* first in list so fix the list head */ | ||
121 | hash = ATH6KL_NODE_HASH(ni->ni_macaddr); | ||
122 | nt->nt_hash[hash] = ni->ni_hash_next; | ||
123 | } else { | ||
124 | ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next; | ||
125 | } | ||
126 | |||
127 | if (ni->ni_hash_next != NULL) | ||
128 | ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev; | ||
129 | |||
130 | wlan_node_free(ni); | ||
131 | |||
132 | spin_unlock_bh(&nt->nt_nodelock); | ||
133 | } | ||
134 | |||
135 | static void wlan_node_dec_free(struct bss *ni) | ||
136 | { | ||
137 | if ((ni->ni_refcnt--) == 1) | ||
138 | wlan_node_free(ni); | ||
139 | } | ||
140 | |||
141 | void wlan_free_allnodes(struct ath6kl_node_table *nt) | ||
142 | { | ||
143 | struct bss *ni; | ||
144 | |||
145 | while ((ni = nt->nt_node_first) != NULL) | ||
146 | wlan_node_reclaim(nt, ni); | ||
147 | } | ||
148 | |||
149 | void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg) | ||
150 | { | ||
151 | struct bss *ni; | ||
152 | |||
153 | spin_lock_bh(&nt->nt_nodelock); | ||
154 | for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) { | ||
155 | ni->ni_refcnt++; | ||
156 | ath6kl_cfg80211_scan_node(arg, ni); | ||
157 | wlan_node_dec_free(ni); | ||
158 | } | ||
159 | spin_unlock_bh(&nt->nt_nodelock); | ||
160 | } | ||
161 | |||
162 | void wlan_node_table_init(struct ath6kl_node_table *nt) | ||
163 | { | ||
164 | ath6kl_dbg(ATH6KL_DBG_WLAN_NODE, "node table = 0x%lx\n", | ||
165 | (unsigned long)nt); | ||
166 | |||
167 | memset(nt, 0, sizeof(struct ath6kl_node_table)); | ||
168 | |||
169 | spin_lock_init(&nt->nt_nodelock); | ||
170 | |||
171 | nt->nt_node_age = WLAN_NODE_INACT_TIMEOUT_MSEC; | ||
172 | } | ||
173 | |||
174 | void wlan_refresh_inactive_nodes(struct ath6kl *ar) | ||
175 | { | ||
176 | struct ath6kl_node_table *nt = &ar->scan_table; | ||
177 | struct bss *bss; | ||
178 | u32 now; | ||
179 | |||
180 | now = jiffies_to_msecs(jiffies); | ||
181 | bss = nt->nt_node_first; | ||
182 | while (bss != NULL) { | ||
183 | /* refresh all nodes except the current bss */ | ||
184 | if (memcmp(ar->bssid, bss->ni_macaddr, ETH_ALEN) != 0) { | ||
185 | if (((now - bss->ni_tstamp) > nt->nt_node_age) | ||
186 | || --bss->ni_actcnt == 0) { | ||
187 | wlan_node_reclaim(nt, bss); | ||
188 | } | ||
189 | } | ||
190 | bss = bss->ni_list_next; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | void wlan_node_table_cleanup(struct ath6kl_node_table *nt) | ||
195 | { | ||
196 | wlan_free_allnodes(nt); | ||
197 | } | ||
198 | |||
199 | struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 * ssid, | ||
200 | u32 ssid_len, bool is_wpa2, bool match_ssid) | ||
201 | { | ||
202 | struct bss *ni, *found_ni = NULL; | ||
203 | u8 *ie_ssid; | ||
204 | |||
205 | spin_lock_bh(&nt->nt_nodelock); | ||
206 | |||
207 | for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) { | ||
208 | |||
209 | ie_ssid = ni->ni_cie.ie_ssid; | ||
210 | |||
211 | if ((ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) && | ||
212 | (memcmp(ssid, &ie_ssid[2], ssid_len) == 0)) { | ||
213 | |||
214 | if (match_ssid || | ||
215 | (is_wpa2 && ni->ni_cie.ie_rsn != NULL) || | ||
216 | (!is_wpa2 && ni->ni_cie.ie_wpa != NULL)) { | ||
217 | ni->ni_refcnt++; | ||
218 | found_ni = ni; | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | spin_unlock_bh(&nt->nt_nodelock); | ||
225 | |||
226 | return found_ni; | ||
227 | } | ||
228 | |||
229 | void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni) | ||
230 | { | ||
231 | spin_lock_bh(&nt->nt_nodelock); | ||
232 | wlan_node_dec_free(ni); | ||
233 | spin_unlock_bh(&nt->nt_nodelock); | ||
234 | } | ||
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 34171604cbe4..f1dc311ee0c7 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "hif-ops.h" | 25 | #include "hif-ops.h" |
26 | #include "target.h" | 26 | #include "target.h" |
27 | #include "debug.h" | 27 | #include "debug.h" |
28 | #include "cfg80211.h" | ||
28 | 29 | ||
29 | struct ath6kl_sdio { | 30 | struct ath6kl_sdio { |
30 | struct sdio_func *func; | 31 | struct sdio_func *func; |
@@ -134,10 +135,12 @@ static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr, | |||
134 | int ret = 0; | 135 | int ret = 0; |
135 | 136 | ||
136 | if (request & HIF_WRITE) { | 137 | if (request & HIF_WRITE) { |
138 | /* FIXME: looks like ugly workaround for something */ | ||
137 | if (addr >= HIF_MBOX_BASE_ADDR && | 139 | if (addr >= HIF_MBOX_BASE_ADDR && |
138 | addr <= HIF_MBOX_END_ADDR) | 140 | addr <= HIF_MBOX_END_ADDR) |
139 | addr += (HIF_MBOX_WIDTH - len); | 141 | addr += (HIF_MBOX_WIDTH - len); |
140 | 142 | ||
143 | /* FIXME: this also looks like ugly workaround */ | ||
141 | if (addr == HIF_MBOX0_EXT_BASE_ADDR) | 144 | if (addr == HIF_MBOX0_EXT_BASE_ADDR) |
142 | addr += HIF_MBOX0_EXT_WIDTH - len; | 145 | addr += HIF_MBOX0_EXT_WIDTH - len; |
143 | 146 | ||
@@ -152,6 +155,11 @@ static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr, | |||
152 | ret = sdio_memcpy_fromio(func, buf, addr, len); | 155 | ret = sdio_memcpy_fromio(func, buf, addr, len); |
153 | } | 156 | } |
154 | 157 | ||
158 | ath6kl_dbg(ATH6KL_DBG_SDIO, "%s addr 0x%x%s buf 0x%p len %d\n", | ||
159 | request & HIF_WRITE ? "wr" : "rd", addr, | ||
160 | request & HIF_FIXED_ADDRESS ? " (fixed)" : "", buf, len); | ||
161 | ath6kl_dbg_dump(ATH6KL_DBG_SDIO_DUMP, NULL, "sdio ", buf, len); | ||
162 | |||
155 | return ret; | 163 | return ret; |
156 | } | 164 | } |
157 | 165 | ||
@@ -172,7 +180,8 @@ static struct bus_request *ath6kl_sdio_alloc_busreq(struct ath6kl_sdio *ar_sdio) | |||
172 | list_del(&bus_req->list); | 180 | list_del(&bus_req->list); |
173 | 181 | ||
174 | spin_unlock_irqrestore(&ar_sdio->lock, flag); | 182 | spin_unlock_irqrestore(&ar_sdio->lock, flag); |
175 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: bus request 0x%p\n", __func__, bus_req); | 183 | ath6kl_dbg(ATH6KL_DBG_SCATTER, "%s: bus request 0x%p\n", |
184 | __func__, bus_req); | ||
176 | 185 | ||
177 | return bus_req; | 186 | return bus_req; |
178 | } | 187 | } |
@@ -182,7 +191,8 @@ static void ath6kl_sdio_free_bus_req(struct ath6kl_sdio *ar_sdio, | |||
182 | { | 191 | { |
183 | unsigned long flag; | 192 | unsigned long flag; |
184 | 193 | ||
185 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: bus request 0x%p\n", __func__, bus_req); | 194 | ath6kl_dbg(ATH6KL_DBG_SCATTER, "%s: bus request 0x%p\n", |
195 | __func__, bus_req); | ||
186 | 196 | ||
187 | spin_lock_irqsave(&ar_sdio->lock, flag); | 197 | spin_lock_irqsave(&ar_sdio->lock, flag); |
188 | list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq); | 198 | list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq); |
@@ -213,16 +223,6 @@ static void ath6kl_sdio_setup_scat_data(struct hif_scatter_req *scat_req, | |||
213 | 223 | ||
214 | /* assemble SG list */ | 224 | /* assemble SG list */ |
215 | for (i = 0; i < scat_req->scat_entries; i++, sg++) { | 225 | for (i = 0; i < scat_req->scat_entries; i++, sg++) { |
216 | if ((unsigned long)scat_req->scat_list[i].buf & 0x3) | ||
217 | /* | ||
218 | * Some scatter engines can handle unaligned | ||
219 | * buffers, print this as informational only. | ||
220 | */ | ||
221 | ath6kl_dbg(ATH6KL_DBG_SCATTER, | ||
222 | "(%s) scatter buffer is unaligned 0x%p\n", | ||
223 | scat_req->req & HIF_WRITE ? "WR" : "RD", | ||
224 | scat_req->scat_list[i].buf); | ||
225 | |||
226 | ath6kl_dbg(ATH6KL_DBG_SCATTER, "%d: addr:0x%p, len:%d\n", | 226 | ath6kl_dbg(ATH6KL_DBG_SCATTER, "%d: addr:0x%p, len:%d\n", |
227 | i, scat_req->scat_list[i].buf, | 227 | i, scat_req->scat_list[i].buf, |
228 | scat_req->scat_list[i].len); | 228 | scat_req->scat_list[i].len); |
@@ -447,6 +447,8 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func) | |||
447 | int status; | 447 | int status; |
448 | struct ath6kl_sdio *ar_sdio; | 448 | struct ath6kl_sdio *ar_sdio; |
449 | 449 | ||
450 | ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n"); | ||
451 | |||
450 | ar_sdio = sdio_get_drvdata(func); | 452 | ar_sdio = sdio_get_drvdata(func); |
451 | atomic_set(&ar_sdio->irq_handling, 1); | 453 | atomic_set(&ar_sdio->irq_handling, 1); |
452 | 454 | ||
@@ -684,7 +686,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar) | |||
684 | MAX_SCATTER_REQUESTS, virt_scat); | 686 | MAX_SCATTER_REQUESTS, virt_scat); |
685 | 687 | ||
686 | if (!ret) { | 688 | if (!ret) { |
687 | ath6kl_dbg(ATH6KL_DBG_ANY, | 689 | ath6kl_dbg(ATH6KL_DBG_SCATTER, |
688 | "hif-scatter enabled: max scatter req : %d entries: %d\n", | 690 | "hif-scatter enabled: max scatter req : %d entries: %d\n", |
689 | MAX_SCATTER_REQUESTS, | 691 | MAX_SCATTER_REQUESTS, |
690 | MAX_SCATTER_ENTRIES_PER_REQ); | 692 | MAX_SCATTER_ENTRIES_PER_REQ); |
@@ -709,7 +711,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar) | |||
709 | return ret; | 711 | return ret; |
710 | } | 712 | } |
711 | 713 | ||
712 | ath6kl_dbg(ATH6KL_DBG_ANY, | 714 | ath6kl_dbg(ATH6KL_DBG_SCATTER, |
713 | "Vitual scatter enabled, max_scat_req:%d, entries:%d\n", | 715 | "Vitual scatter enabled, max_scat_req:%d, entries:%d\n", |
714 | ATH6KL_SCATTER_REQS, ATH6KL_SCATTER_ENTRIES_PER_REQ); | 716 | ATH6KL_SCATTER_REQS, ATH6KL_SCATTER_ENTRIES_PER_REQ); |
715 | 717 | ||
@@ -721,6 +723,34 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar) | |||
721 | return 0; | 723 | return 0; |
722 | } | 724 | } |
723 | 725 | ||
726 | static int ath6kl_sdio_suspend(struct ath6kl *ar) | ||
727 | { | ||
728 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | ||
729 | struct sdio_func *func = ar_sdio->func; | ||
730 | mmc_pm_flag_t flags; | ||
731 | int ret; | ||
732 | |||
733 | flags = sdio_get_host_pm_caps(func); | ||
734 | |||
735 | if (!(flags & MMC_PM_KEEP_POWER)) | ||
736 | /* as host doesn't support keep power we need to bail out */ | ||
737 | ath6kl_dbg(ATH6KL_DBG_SDIO, | ||
738 | "func %d doesn't support MMC_PM_KEEP_POWER\n", | ||
739 | func->num); | ||
740 | return -EINVAL; | ||
741 | |||
742 | ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); | ||
743 | if (ret) { | ||
744 | printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n", | ||
745 | ret); | ||
746 | return ret; | ||
747 | } | ||
748 | |||
749 | ath6kl_deep_sleep_enable(ar); | ||
750 | |||
751 | return 0; | ||
752 | } | ||
753 | |||
724 | static const struct ath6kl_hif_ops ath6kl_sdio_ops = { | 754 | static const struct ath6kl_hif_ops ath6kl_sdio_ops = { |
725 | .read_write_sync = ath6kl_sdio_read_write_sync, | 755 | .read_write_sync = ath6kl_sdio_read_write_sync, |
726 | .write_async = ath6kl_sdio_write_async, | 756 | .write_async = ath6kl_sdio_write_async, |
@@ -731,6 +761,7 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = { | |||
731 | .enable_scatter = ath6kl_sdio_enable_scatter, | 761 | .enable_scatter = ath6kl_sdio_enable_scatter, |
732 | .scat_req_rw = ath6kl_sdio_async_rw_scatter, | 762 | .scat_req_rw = ath6kl_sdio_async_rw_scatter, |
733 | .cleanup_scatter = ath6kl_sdio_cleanup_scatter, | 763 | .cleanup_scatter = ath6kl_sdio_cleanup_scatter, |
764 | .suspend = ath6kl_sdio_suspend, | ||
734 | }; | 765 | }; |
735 | 766 | ||
736 | static int ath6kl_sdio_probe(struct sdio_func *func, | 767 | static int ath6kl_sdio_probe(struct sdio_func *func, |
@@ -741,10 +772,10 @@ static int ath6kl_sdio_probe(struct sdio_func *func, | |||
741 | struct ath6kl *ar; | 772 | struct ath6kl *ar; |
742 | int count; | 773 | int count; |
743 | 774 | ||
744 | ath6kl_dbg(ATH6KL_DBG_TRC, | 775 | ath6kl_dbg(ATH6KL_DBG_SDIO, |
745 | "%s: func: 0x%X, vendor id: 0x%X, dev id: 0x%X, block size: 0x%X/0x%X\n", | 776 | "new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n", |
746 | __func__, func->num, func->vendor, | 777 | func->num, func->vendor, func->device, |
747 | func->device, func->max_blksize, func->cur_blksize); | 778 | func->max_blksize, func->cur_blksize); |
748 | 779 | ||
749 | ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL); | 780 | ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL); |
750 | if (!ar_sdio) | 781 | if (!ar_sdio) |
@@ -800,10 +831,10 @@ static int ath6kl_sdio_probe(struct sdio_func *func, | |||
800 | ath6kl_err("Failed to enable 4-bit async irq mode %d\n", | 831 | ath6kl_err("Failed to enable 4-bit async irq mode %d\n", |
801 | ret); | 832 | ret); |
802 | sdio_release_host(func); | 833 | sdio_release_host(func); |
803 | goto err_dma; | 834 | goto err_cfg80211; |
804 | } | 835 | } |
805 | 836 | ||
806 | ath6kl_dbg(ATH6KL_DBG_TRC, "4-bit async irq mode enabled\n"); | 837 | ath6kl_dbg(ATH6KL_DBG_SDIO, "4-bit async irq mode enabled\n"); |
807 | } | 838 | } |
808 | 839 | ||
809 | /* give us some time to enable, in ms */ | 840 | /* give us some time to enable, in ms */ |
@@ -813,7 +844,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func, | |||
813 | 844 | ||
814 | ret = ath6kl_sdio_power_on(ar_sdio); | 845 | ret = ath6kl_sdio_power_on(ar_sdio); |
815 | if (ret) | 846 | if (ret) |
816 | goto err_dma; | 847 | goto err_cfg80211; |
817 | 848 | ||
818 | sdio_claim_host(func); | 849 | sdio_claim_host(func); |
819 | 850 | ||
@@ -837,6 +868,8 @@ static int ath6kl_sdio_probe(struct sdio_func *func, | |||
837 | 868 | ||
838 | err_off: | 869 | err_off: |
839 | ath6kl_sdio_power_off(ar_sdio); | 870 | ath6kl_sdio_power_off(ar_sdio); |
871 | err_cfg80211: | ||
872 | ath6kl_cfg80211_deinit(ar_sdio->ar); | ||
840 | err_dma: | 873 | err_dma: |
841 | kfree(ar_sdio->dma_buffer); | 874 | kfree(ar_sdio->dma_buffer); |
842 | err_hif: | 875 | err_hif: |
@@ -849,6 +882,10 @@ static void ath6kl_sdio_remove(struct sdio_func *func) | |||
849 | { | 882 | { |
850 | struct ath6kl_sdio *ar_sdio; | 883 | struct ath6kl_sdio *ar_sdio; |
851 | 884 | ||
885 | ath6kl_dbg(ATH6KL_DBG_SDIO, | ||
886 | "removed func %d vendor 0x%x device 0x%x\n", | ||
887 | func->num, func->vendor, func->device); | ||
888 | |||
852 | ar_sdio = sdio_get_drvdata(func); | 889 | ar_sdio = sdio_get_drvdata(func); |
853 | 890 | ||
854 | ath6kl_stop_txrx(ar_sdio->ar); | 891 | ath6kl_stop_txrx(ar_sdio->ar); |
diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h index 519a013c9991..c9a76051f042 100644 --- a/drivers/net/wireless/ath/ath6kl/target.h +++ b/drivers/net/wireless/ath/ath6kl/target.h | |||
@@ -20,6 +20,9 @@ | |||
20 | #define AR6003_BOARD_DATA_SZ 1024 | 20 | #define AR6003_BOARD_DATA_SZ 1024 |
21 | #define AR6003_BOARD_EXT_DATA_SZ 768 | 21 | #define AR6003_BOARD_EXT_DATA_SZ 768 |
22 | 22 | ||
23 | #define AR6004_BOARD_DATA_SZ 7168 | ||
24 | #define AR6004_BOARD_EXT_DATA_SZ 0 | ||
25 | |||
23 | #define RESET_CONTROL_ADDRESS 0x00000000 | 26 | #define RESET_CONTROL_ADDRESS 0x00000000 |
24 | #define RESET_CONTROL_COLD_RST 0x00000100 | 27 | #define RESET_CONTROL_COLD_RST 0x00000100 |
25 | #define RESET_CONTROL_MBOX_RST 0x00000004 | 28 | #define RESET_CONTROL_MBOX_RST 0x00000004 |
@@ -135,7 +138,8 @@ | |||
135 | * between the two, and is intended to remain constant (with additions only | 138 | * between the two, and is intended to remain constant (with additions only |
136 | * at the end). | 139 | * at the end). |
137 | */ | 140 | */ |
138 | #define ATH6KL_HI_START_ADDR 0x00540600 | 141 | #define ATH6KL_AR6003_HI_START_ADDR 0x00540600 |
142 | #define ATH6KL_AR6004_HI_START_ADDR 0x00400800 | ||
139 | 143 | ||
140 | /* | 144 | /* |
141 | * These are items that the Host may need to access | 145 | * These are items that the Host may need to access |
@@ -300,6 +304,11 @@ struct host_interest { | |||
300 | #define HI_OPTION_FW_MODE_BSS_STA 0x1 | 304 | #define HI_OPTION_FW_MODE_BSS_STA 0x1 |
301 | #define HI_OPTION_FW_MODE_AP 0x2 | 305 | #define HI_OPTION_FW_MODE_AP 0x2 |
302 | 306 | ||
307 | #define HI_OPTION_FW_SUBMODE_NONE 0x0 | ||
308 | #define HI_OPTION_FW_SUBMODE_P2PDEV 0x1 | ||
309 | #define HI_OPTION_FW_SUBMODE_P2PCLIENT 0x2 | ||
310 | #define HI_OPTION_FW_SUBMODE_P2PGO 0x3 | ||
311 | |||
303 | #define HI_OPTION_NUM_DEV_SHIFT 0x9 | 312 | #define HI_OPTION_NUM_DEV_SHIFT 0x9 |
304 | 313 | ||
305 | #define HI_OPTION_FW_BRIDGE_SHIFT 0x04 | 314 | #define HI_OPTION_FW_BRIDGE_SHIFT 0x04 |
@@ -312,20 +321,44 @@ struct host_interest { | |||
312 | |------------------------------------------------------------------------------| | 321 | |------------------------------------------------------------------------------| |
313 | */ | 322 | */ |
314 | #define HI_OPTION_FW_MODE_SHIFT 0xC | 323 | #define HI_OPTION_FW_MODE_SHIFT 0xC |
324 | #define HI_OPTION_FW_SUBMODE_SHIFT 0x14 | ||
315 | 325 | ||
316 | /* Convert a Target virtual address into a Target physical address */ | 326 | /* Convert a Target virtual address into a Target physical address */ |
317 | #define TARG_VTOP(vaddr) (vaddr & 0x001fffff) | 327 | #define AR6003_VTOP(vaddr) ((vaddr) & 0x001fffff) |
328 | #define AR6004_VTOP(vaddr) (vaddr) | ||
329 | |||
330 | #define TARG_VTOP(target_type, vaddr) \ | ||
331 | (((target_type) == TARGET_TYPE_AR6003) ? AR6003_VTOP(vaddr) : \ | ||
332 | (((target_type) == TARGET_TYPE_AR6004) ? AR6004_VTOP(vaddr) : 0)) | ||
318 | 333 | ||
319 | #define AR6003_REV2_APP_START_OVERRIDE 0x944C00 | ||
320 | #define AR6003_REV2_APP_LOAD_ADDRESS 0x543180 | 334 | #define AR6003_REV2_APP_LOAD_ADDRESS 0x543180 |
321 | #define AR6003_REV2_BOARD_EXT_DATA_ADDRESS 0x57E500 | 335 | #define AR6003_REV2_BOARD_EXT_DATA_ADDRESS 0x57E500 |
322 | #define AR6003_REV2_DATASET_PATCH_ADDRESS 0x57e884 | 336 | #define AR6003_REV2_DATASET_PATCH_ADDRESS 0x57e884 |
323 | #define AR6003_REV2_RAM_RESERVE_SIZE 6912 | 337 | #define AR6003_REV2_RAM_RESERVE_SIZE 6912 |
324 | 338 | ||
325 | #define AR6003_REV3_APP_START_OVERRIDE 0x945d00 | ||
326 | #define AR6003_REV3_APP_LOAD_ADDRESS 0x545000 | 339 | #define AR6003_REV3_APP_LOAD_ADDRESS 0x545000 |
327 | #define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330 | 340 | #define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330 |
328 | #define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74 | 341 | #define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74 |
329 | #define AR6003_REV3_RAM_RESERVE_SIZE 512 | 342 | #define AR6003_REV3_RAM_RESERVE_SIZE 512 |
330 | 343 | ||
344 | #define AR6004_REV1_BOARD_DATA_ADDRESS 0x435400 | ||
345 | #define AR6004_REV1_BOARD_EXT_DATA_ADDRESS 0x437000 | ||
346 | #define AR6004_REV1_RAM_RESERVE_SIZE 11264 | ||
347 | |||
348 | #define ATH6KL_FWLOG_PAYLOAD_SIZE 1500 | ||
349 | |||
350 | struct ath6kl_dbglog_buf { | ||
351 | __le32 next; | ||
352 | __le32 buffer_addr; | ||
353 | __le32 bufsize; | ||
354 | __le32 length; | ||
355 | __le32 count; | ||
356 | __le32 free; | ||
357 | } __packed; | ||
358 | |||
359 | struct ath6kl_dbglog_hdr { | ||
360 | __le32 dbuf_addr; | ||
361 | __le32 dropped; | ||
362 | } __packed; | ||
363 | |||
331 | #endif | 364 | #endif |
diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c new file mode 100644 index 000000000000..381eb66a605f --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/testmode.c | |||
@@ -0,0 +1,167 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010-2011 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "testmode.h" | ||
18 | |||
19 | #include <net/netlink.h> | ||
20 | |||
21 | enum ath6kl_tm_attr { | ||
22 | __ATH6KL_TM_ATTR_INVALID = 0, | ||
23 | ATH6KL_TM_ATTR_CMD = 1, | ||
24 | ATH6KL_TM_ATTR_DATA = 2, | ||
25 | |||
26 | /* keep last */ | ||
27 | __ATH6KL_TM_ATTR_AFTER_LAST, | ||
28 | ATH6KL_TM_ATTR_MAX = __ATH6KL_TM_ATTR_AFTER_LAST - 1, | ||
29 | }; | ||
30 | |||
31 | enum ath6kl_tm_cmd { | ||
32 | ATH6KL_TM_CMD_TCMD = 0, | ||
33 | ATH6KL_TM_CMD_RX_REPORT = 1, | ||
34 | }; | ||
35 | |||
36 | #define ATH6KL_TM_DATA_MAX_LEN 5000 | ||
37 | |||
38 | static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = { | ||
39 | [ATH6KL_TM_ATTR_CMD] = { .type = NLA_U32 }, | ||
40 | [ATH6KL_TM_ATTR_DATA] = { .type = NLA_BINARY, | ||
41 | .len = ATH6KL_TM_DATA_MAX_LEN }, | ||
42 | }; | ||
43 | |||
44 | void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len) | ||
45 | { | ||
46 | if (down_interruptible(&ar->sem)) | ||
47 | return; | ||
48 | |||
49 | kfree(ar->tm.rx_report); | ||
50 | |||
51 | ar->tm.rx_report = kmemdup(buf, buf_len, GFP_KERNEL); | ||
52 | ar->tm.rx_report_len = buf_len; | ||
53 | |||
54 | up(&ar->sem); | ||
55 | |||
56 | wake_up(&ar->event_wq); | ||
57 | } | ||
58 | |||
59 | static int ath6kl_tm_rx_report(struct ath6kl *ar, void *buf, size_t buf_len, | ||
60 | struct sk_buff *skb) | ||
61 | { | ||
62 | int ret = 0; | ||
63 | long left; | ||
64 | |||
65 | if (down_interruptible(&ar->sem)) | ||
66 | return -ERESTARTSYS; | ||
67 | |||
68 | if (!test_bit(WMI_READY, &ar->flag)) { | ||
69 | ret = -EIO; | ||
70 | goto out; | ||
71 | } | ||
72 | |||
73 | if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) { | ||
74 | ret = -EBUSY; | ||
75 | goto out; | ||
76 | } | ||
77 | |||
78 | if (ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len) < 0) { | ||
79 | up(&ar->sem); | ||
80 | return -EIO; | ||
81 | } | ||
82 | |||
83 | left = wait_event_interruptible_timeout(ar->event_wq, | ||
84 | ar->tm.rx_report != NULL, | ||
85 | WMI_TIMEOUT); | ||
86 | |||
87 | if (left == 0) { | ||
88 | ret = -ETIMEDOUT; | ||
89 | goto out; | ||
90 | } else if (left < 0) { | ||
91 | ret = left; | ||
92 | goto out; | ||
93 | } | ||
94 | |||
95 | if (ar->tm.rx_report == NULL || ar->tm.rx_report_len == 0) { | ||
96 | ret = -EINVAL; | ||
97 | goto out; | ||
98 | } | ||
99 | |||
100 | NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, ar->tm.rx_report_len, | ||
101 | ar->tm.rx_report); | ||
102 | |||
103 | kfree(ar->tm.rx_report); | ||
104 | ar->tm.rx_report = NULL; | ||
105 | |||
106 | out: | ||
107 | up(&ar->sem); | ||
108 | |||
109 | return ret; | ||
110 | |||
111 | nla_put_failure: | ||
112 | ret = -ENOBUFS; | ||
113 | goto out; | ||
114 | } | ||
115 | |||
116 | int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) | ||
117 | { | ||
118 | struct ath6kl *ar = wiphy_priv(wiphy); | ||
119 | struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1]; | ||
120 | int err, buf_len, reply_len; | ||
121 | struct sk_buff *skb; | ||
122 | void *buf; | ||
123 | |||
124 | err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len, | ||
125 | ath6kl_tm_policy); | ||
126 | if (err) | ||
127 | return err; | ||
128 | |||
129 | if (!tb[ATH6KL_TM_ATTR_CMD]) | ||
130 | return -EINVAL; | ||
131 | |||
132 | switch (nla_get_u32(tb[ATH6KL_TM_ATTR_CMD])) { | ||
133 | case ATH6KL_TM_CMD_TCMD: | ||
134 | if (!tb[ATH6KL_TM_ATTR_DATA]) | ||
135 | return -EINVAL; | ||
136 | |||
137 | buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); | ||
138 | buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); | ||
139 | |||
140 | ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len); | ||
141 | |||
142 | return 0; | ||
143 | |||
144 | break; | ||
145 | case ATH6KL_TM_CMD_RX_REPORT: | ||
146 | if (!tb[ATH6KL_TM_ATTR_DATA]) | ||
147 | return -EINVAL; | ||
148 | |||
149 | buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); | ||
150 | buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); | ||
151 | |||
152 | reply_len = nla_total_size(ATH6KL_TM_DATA_MAX_LEN); | ||
153 | skb = cfg80211_testmode_alloc_reply_skb(wiphy, reply_len); | ||
154 | if (!skb) | ||
155 | return -ENOMEM; | ||
156 | |||
157 | err = ath6kl_tm_rx_report(ar, buf, buf_len, skb); | ||
158 | if (err < 0) { | ||
159 | kfree_skb(skb); | ||
160 | return err; | ||
161 | } | ||
162 | |||
163 | return cfg80211_testmode_reply(skb); | ||
164 | default: | ||
165 | return -EOPNOTSUPP; | ||
166 | } | ||
167 | } | ||
diff --git a/drivers/net/wireless/ath/ath6kl/testmode.h b/drivers/net/wireless/ath/ath6kl/testmode.h new file mode 100644 index 000000000000..43dffcc11fb1 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/testmode.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010-2011 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "core.h" | ||
18 | |||
19 | #ifdef CONFIG_NL80211_TESTMODE | ||
20 | |||
21 | void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len); | ||
22 | int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len); | ||
23 | |||
24 | #else | ||
25 | |||
26 | static inline void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, | ||
27 | size_t buf_len) | ||
28 | { | ||
29 | } | ||
30 | |||
31 | static inline int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | #endif | ||
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 167bdb9cf68d..a7117074f81c 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c | |||
@@ -239,7 +239,6 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) | |||
239 | u16 htc_tag = ATH6KL_DATA_PKT_TAG; | 239 | u16 htc_tag = ATH6KL_DATA_PKT_TAG; |
240 | u8 ac = 99 ; /* initialize to unmapped ac */ | 240 | u8 ac = 99 ; /* initialize to unmapped ac */ |
241 | bool chk_adhoc_ps_mapping = false, more_data = false; | 241 | bool chk_adhoc_ps_mapping = false, more_data = false; |
242 | struct wmi_tx_meta_v2 meta_v2; | ||
243 | int ret; | 242 | int ret; |
244 | 243 | ||
245 | ath6kl_dbg(ATH6KL_DBG_WLAN_TX, | 244 | ath6kl_dbg(ATH6KL_DBG_WLAN_TX, |
@@ -262,8 +261,6 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) | |||
262 | } | 261 | } |
263 | 262 | ||
264 | if (test_bit(WMI_ENABLED, &ar->flag)) { | 263 | if (test_bit(WMI_ENABLED, &ar->flag)) { |
265 | memset(&meta_v2, 0, sizeof(meta_v2)); | ||
266 | |||
267 | if (skb_headroom(skb) < dev->needed_headroom) { | 264 | if (skb_headroom(skb) < dev->needed_headroom) { |
268 | WARN_ON(1); | 265 | WARN_ON(1); |
269 | goto fail_tx; | 266 | goto fail_tx; |
@@ -320,12 +317,31 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) | |||
320 | 317 | ||
321 | spin_unlock_bh(&ar->lock); | 318 | spin_unlock_bh(&ar->lock); |
322 | 319 | ||
320 | if (!IS_ALIGNED((unsigned long) skb->data - HTC_HDR_LENGTH, 4) && | ||
321 | skb_cloned(skb)) { | ||
322 | /* | ||
323 | * We will touch (move the buffer data to align it. Since the | ||
324 | * skb buffer is cloned and not only the header is changed, we | ||
325 | * have to copy it to allow the changes. Since we are copying | ||
326 | * the data here, we may as well align it by reserving suitable | ||
327 | * headroom to avoid the memmove in ath6kl_htc_tx_buf_align(). | ||
328 | */ | ||
329 | struct sk_buff *nskb; | ||
330 | |||
331 | nskb = skb_copy_expand(skb, HTC_HDR_LENGTH, 0, GFP_ATOMIC); | ||
332 | if (nskb == NULL) | ||
333 | goto fail_tx; | ||
334 | kfree_skb(skb); | ||
335 | skb = nskb; | ||
336 | } | ||
337 | |||
323 | cookie->skb = skb; | 338 | cookie->skb = skb; |
324 | cookie->map_no = map_no; | 339 | cookie->map_no = map_no; |
325 | set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, | 340 | set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, |
326 | eid, htc_tag); | 341 | eid, htc_tag); |
327 | 342 | ||
328 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, skb->data, skb->len); | 343 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "tx ", |
344 | skb->data, skb->len); | ||
329 | 345 | ||
330 | /* | 346 | /* |
331 | * HTC interface is asynchronous, if this fails, cleanup will | 347 | * HTC interface is asynchronous, if this fails, cleanup will |
@@ -689,6 +705,8 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) | |||
689 | break; | 705 | break; |
690 | 706 | ||
691 | packet = (struct htc_packet *) skb->head; | 707 | packet = (struct htc_packet *) skb->head; |
708 | if (!IS_ALIGNED((unsigned long) skb->data, 4)) | ||
709 | skb->data = PTR_ALIGN(skb->data - 4, 4); | ||
692 | set_htc_rxpkt_info(packet, skb, skb->data, | 710 | set_htc_rxpkt_info(packet, skb, skb->data, |
693 | ATH6KL_BUFFER_SIZE, endpoint); | 711 | ATH6KL_BUFFER_SIZE, endpoint); |
694 | list_add_tail(&packet->list, &queue); | 712 | list_add_tail(&packet->list, &queue); |
@@ -709,6 +727,8 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count) | |||
709 | return; | 727 | return; |
710 | 728 | ||
711 | packet = (struct htc_packet *) skb->head; | 729 | packet = (struct htc_packet *) skb->head; |
730 | if (!IS_ALIGNED((unsigned long) skb->data, 4)) | ||
731 | skb->data = PTR_ALIGN(skb->data - 4, 4); | ||
712 | set_htc_rxpkt_info(packet, skb, skb->data, | 732 | set_htc_rxpkt_info(packet, skb, skb->data, |
713 | ATH6KL_AMSDU_BUFFER_SIZE, 0); | 733 | ATH6KL_AMSDU_BUFFER_SIZE, 0); |
714 | spin_lock_bh(&ar->lock); | 734 | spin_lock_bh(&ar->lock); |
@@ -812,7 +832,7 @@ static void aggr_slice_amsdu(struct aggr_info *p_aggr, | |||
812 | /* Add the length of A-MSDU subframe padding bytes - | 832 | /* Add the length of A-MSDU subframe padding bytes - |
813 | * Round to nearest word. | 833 | * Round to nearest word. |
814 | */ | 834 | */ |
815 | frame_8023_len = ALIGN(frame_8023_len + 3, 3); | 835 | frame_8023_len = ALIGN(frame_8023_len, 4); |
816 | 836 | ||
817 | framep += frame_8023_len; | 837 | framep += frame_8023_len; |
818 | amsdu_len -= frame_8023_len; | 838 | amsdu_len -= frame_8023_len; |
@@ -1044,12 +1064,13 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1044 | ar->net_stats.rx_packets++; | 1064 | ar->net_stats.rx_packets++; |
1045 | ar->net_stats.rx_bytes += packet->act_len; | 1065 | ar->net_stats.rx_bytes += packet->act_len; |
1046 | 1066 | ||
1067 | spin_unlock_bh(&ar->lock); | ||
1068 | |||
1047 | skb_put(skb, packet->act_len + HTC_HDR_LENGTH); | 1069 | skb_put(skb, packet->act_len + HTC_HDR_LENGTH); |
1048 | skb_pull(skb, HTC_HDR_LENGTH); | 1070 | skb_pull(skb, HTC_HDR_LENGTH); |
1049 | 1071 | ||
1050 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, skb->data, skb->len); | 1072 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ", |
1051 | 1073 | skb->data, skb->len); | |
1052 | spin_unlock_bh(&ar->lock); | ||
1053 | 1074 | ||
1054 | skb->dev = ar->net_dev; | 1075 | skb->dev = ar->net_dev; |
1055 | 1076 | ||
@@ -1065,9 +1086,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1065 | return; | 1086 | return; |
1066 | } | 1087 | } |
1067 | 1088 | ||
1068 | min_hdr_len = sizeof(struct ethhdr); | 1089 | min_hdr_len = sizeof(struct ethhdr) + sizeof(struct wmi_data_hdr) + |
1069 | min_hdr_len += sizeof(struct wmi_data_hdr) + | 1090 | sizeof(struct ath6kl_llc_snap_hdr); |
1070 | sizeof(struct ath6kl_llc_snap_hdr); | ||
1071 | 1091 | ||
1072 | dhdr = (struct wmi_data_hdr *) skb->data; | 1092 | dhdr = (struct wmi_data_hdr *) skb->data; |
1073 | 1093 | ||
@@ -1163,8 +1183,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1163 | seq_no = wmi_data_hdr_get_seqno(dhdr); | 1183 | seq_no = wmi_data_hdr_get_seqno(dhdr); |
1164 | meta_type = wmi_data_hdr_get_meta(dhdr); | 1184 | meta_type = wmi_data_hdr_get_meta(dhdr); |
1165 | dot11_hdr = wmi_data_hdr_get_dot11(dhdr); | 1185 | dot11_hdr = wmi_data_hdr_get_dot11(dhdr); |
1166 | 1186 | skb_pull(skb, sizeof(struct wmi_data_hdr)); | |
1167 | ath6kl_wmi_data_hdr_remove(ar->wmi, skb); | ||
1168 | 1187 | ||
1169 | switch (meta_type) { | 1188 | switch (meta_type) { |
1170 | case WMI_META_VERSION_1: | 1189 | case WMI_META_VERSION_1: |
@@ -1231,9 +1250,15 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1231 | ath6kl_data_tx(skb1, ar->net_dev); | 1250 | ath6kl_data_tx(skb1, ar->net_dev); |
1232 | } | 1251 | } |
1233 | 1252 | ||
1234 | if (!aggr_process_recv_frm(ar->aggr_cntxt, tid, seq_no, | 1253 | datap = (struct ethhdr *) skb->data; |
1235 | is_amsdu, skb)) | 1254 | |
1236 | ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb); | 1255 | if (is_unicast_ether_addr(datap->h_dest) && |
1256 | aggr_process_recv_frm(ar->aggr_cntxt, tid, seq_no, | ||
1257 | is_amsdu, skb)) | ||
1258 | /* aggregation code will handle the skb */ | ||
1259 | return; | ||
1260 | |||
1261 | ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb); | ||
1237 | } | 1262 | } |
1238 | 1263 | ||
1239 | static void aggr_timeout(unsigned long arg) | 1264 | static void aggr_timeout(unsigned long arg) |
@@ -1250,10 +1275,6 @@ static void aggr_timeout(unsigned long arg) | |||
1250 | if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress) | 1275 | if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress) |
1251 | continue; | 1276 | continue; |
1252 | 1277 | ||
1253 | /* | ||
1254 | * FIXME: these timeouts happen quite fruently, something | ||
1255 | * line once within 60 seconds. Investigate why. | ||
1256 | */ | ||
1257 | stats->num_timeouts++; | 1278 | stats->num_timeouts++; |
1258 | ath6kl_dbg(ATH6KL_DBG_AGGR, | 1279 | ath6kl_dbg(ATH6KL_DBG_AGGR, |
1259 | "aggr timeout (st %d end %d)\n", | 1280 | "aggr timeout (st %d end %d)\n", |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index f5aa33dd4c42..a7de23cbd2c7 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c | |||
@@ -17,6 +17,9 @@ | |||
17 | #include <linux/ip.h> | 17 | #include <linux/ip.h> |
18 | #include "core.h" | 18 | #include "core.h" |
19 | #include "debug.h" | 19 | #include "debug.h" |
20 | #include "testmode.h" | ||
21 | #include "../regd.h" | ||
22 | #include "../regd_common.h" | ||
20 | 23 | ||
21 | static int ath6kl_wmi_sync_point(struct wmi *wmi); | 24 | static int ath6kl_wmi_sync_point(struct wmi *wmi); |
22 | 25 | ||
@@ -167,9 +170,11 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, | |||
167 | if (WARN_ON(skb == NULL)) | 170 | if (WARN_ON(skb == NULL)) |
168 | return -EINVAL; | 171 | return -EINVAL; |
169 | 172 | ||
170 | ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info); | 173 | if (tx_meta_info) { |
171 | if (ret) | 174 | ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info); |
172 | return ret; | 175 | if (ret) |
176 | return ret; | ||
177 | } | ||
173 | 178 | ||
174 | skb_push(skb, sizeof(struct wmi_data_hdr)); | 179 | skb_push(skb, sizeof(struct wmi_data_hdr)); |
175 | 180 | ||
@@ -376,35 +381,6 @@ int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb) | |||
376 | return 0; | 381 | return 0; |
377 | } | 382 | } |
378 | 383 | ||
379 | int ath6kl_wmi_data_hdr_remove(struct wmi *wmi, struct sk_buff *skb) | ||
380 | { | ||
381 | if (WARN_ON(skb == NULL)) | ||
382 | return -EINVAL; | ||
383 | |||
384 | skb_pull(skb, sizeof(struct wmi_data_hdr)); | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static void ath6kl_wmi_convert_bssinfo_hdr2_to_hdr(struct sk_buff *skb, | ||
390 | u8 *datap) | ||
391 | { | ||
392 | struct wmi_bss_info_hdr2 bih2; | ||
393 | struct wmi_bss_info_hdr *bih; | ||
394 | |||
395 | memcpy(&bih2, datap, sizeof(struct wmi_bss_info_hdr2)); | ||
396 | |||
397 | skb_push(skb, 4); | ||
398 | bih = (struct wmi_bss_info_hdr *) skb->data; | ||
399 | |||
400 | bih->ch = bih2.ch; | ||
401 | bih->frame_type = bih2.frame_type; | ||
402 | bih->snr = bih2.snr; | ||
403 | bih->rssi = a_cpu_to_sle16(bih2.snr - 95); | ||
404 | bih->ie_mask = cpu_to_le32(le16_to_cpu(bih2.ie_mask)); | ||
405 | memcpy(bih->bssid, bih2.bssid, ETH_ALEN); | ||
406 | } | ||
407 | |||
408 | static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) | 384 | static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) |
409 | { | 385 | { |
410 | struct tx_complete_msg_v1 *msg_v1; | 386 | struct tx_complete_msg_v1 *msg_v1; |
@@ -433,6 +409,201 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) | |||
433 | return 0; | 409 | return 0; |
434 | } | 410 | } |
435 | 411 | ||
412 | static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap, | ||
413 | int len) | ||
414 | { | ||
415 | struct wmi_remain_on_chnl_event *ev; | ||
416 | u32 freq; | ||
417 | u32 dur; | ||
418 | struct ieee80211_channel *chan; | ||
419 | struct ath6kl *ar = wmi->parent_dev; | ||
420 | |||
421 | if (len < sizeof(*ev)) | ||
422 | return -EINVAL; | ||
423 | |||
424 | ev = (struct wmi_remain_on_chnl_event *) datap; | ||
425 | freq = le32_to_cpu(ev->freq); | ||
426 | dur = le32_to_cpu(ev->duration); | ||
427 | ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: freq=%u dur=%u\n", | ||
428 | freq, dur); | ||
429 | chan = ieee80211_get_channel(ar->wdev->wiphy, freq); | ||
430 | if (!chan) { | ||
431 | ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: Unknown channel " | ||
432 | "(freq=%u)\n", freq); | ||
433 | return -EINVAL; | ||
434 | } | ||
435 | cfg80211_ready_on_channel(ar->net_dev, 1, chan, NL80211_CHAN_NO_HT, | ||
436 | dur, GFP_ATOMIC); | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi, | ||
442 | u8 *datap, int len) | ||
443 | { | ||
444 | struct wmi_cancel_remain_on_chnl_event *ev; | ||
445 | u32 freq; | ||
446 | u32 dur; | ||
447 | struct ieee80211_channel *chan; | ||
448 | struct ath6kl *ar = wmi->parent_dev; | ||
449 | |||
450 | if (len < sizeof(*ev)) | ||
451 | return -EINVAL; | ||
452 | |||
453 | ev = (struct wmi_cancel_remain_on_chnl_event *) datap; | ||
454 | freq = le32_to_cpu(ev->freq); | ||
455 | dur = le32_to_cpu(ev->duration); | ||
456 | ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: freq=%u dur=%u " | ||
457 | "status=%u\n", freq, dur, ev->status); | ||
458 | chan = ieee80211_get_channel(ar->wdev->wiphy, freq); | ||
459 | if (!chan) { | ||
460 | ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: Unknown " | ||
461 | "channel (freq=%u)\n", freq); | ||
462 | return -EINVAL; | ||
463 | } | ||
464 | cfg80211_remain_on_channel_expired(ar->net_dev, 1, chan, | ||
465 | NL80211_CHAN_NO_HT, GFP_ATOMIC); | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
471 | { | ||
472 | struct wmi_tx_status_event *ev; | ||
473 | u32 id; | ||
474 | struct ath6kl *ar = wmi->parent_dev; | ||
475 | |||
476 | if (len < sizeof(*ev)) | ||
477 | return -EINVAL; | ||
478 | |||
479 | ev = (struct wmi_tx_status_event *) datap; | ||
480 | id = le32_to_cpu(ev->id); | ||
481 | ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n", | ||
482 | id, ev->ack_status); | ||
483 | if (wmi->last_mgmt_tx_frame) { | ||
484 | cfg80211_mgmt_tx_status(ar->net_dev, id, | ||
485 | wmi->last_mgmt_tx_frame, | ||
486 | wmi->last_mgmt_tx_frame_len, | ||
487 | !!ev->ack_status, GFP_ATOMIC); | ||
488 | kfree(wmi->last_mgmt_tx_frame); | ||
489 | wmi->last_mgmt_tx_frame = NULL; | ||
490 | wmi->last_mgmt_tx_frame_len = 0; | ||
491 | } | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
497 | { | ||
498 | struct wmi_p2p_rx_probe_req_event *ev; | ||
499 | u32 freq; | ||
500 | u16 dlen; | ||
501 | struct ath6kl *ar = wmi->parent_dev; | ||
502 | |||
503 | if (len < sizeof(*ev)) | ||
504 | return -EINVAL; | ||
505 | |||
506 | ev = (struct wmi_p2p_rx_probe_req_event *) datap; | ||
507 | freq = le32_to_cpu(ev->freq); | ||
508 | dlen = le16_to_cpu(ev->len); | ||
509 | if (datap + len < ev->data + dlen) { | ||
510 | ath6kl_err("invalid wmi_p2p_rx_probe_req_event: " | ||
511 | "len=%d dlen=%u\n", len, dlen); | ||
512 | return -EINVAL; | ||
513 | } | ||
514 | ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u freq=%u " | ||
515 | "probe_req_report=%d\n", | ||
516 | dlen, freq, ar->probe_req_report); | ||
517 | |||
518 | if (ar->probe_req_report || ar->nw_type == AP_NETWORK) | ||
519 | cfg80211_rx_mgmt(ar->net_dev, freq, ev->data, dlen, GFP_ATOMIC); | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static int ath6kl_wmi_p2p_capabilities_event_rx(u8 *datap, int len) | ||
525 | { | ||
526 | struct wmi_p2p_capabilities_event *ev; | ||
527 | u16 dlen; | ||
528 | |||
529 | if (len < sizeof(*ev)) | ||
530 | return -EINVAL; | ||
531 | |||
532 | ev = (struct wmi_p2p_capabilities_event *) datap; | ||
533 | dlen = le16_to_cpu(ev->len); | ||
534 | ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_capab: len=%u\n", dlen); | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
540 | { | ||
541 | struct wmi_rx_action_event *ev; | ||
542 | u32 freq; | ||
543 | u16 dlen; | ||
544 | struct ath6kl *ar = wmi->parent_dev; | ||
545 | |||
546 | if (len < sizeof(*ev)) | ||
547 | return -EINVAL; | ||
548 | |||
549 | ev = (struct wmi_rx_action_event *) datap; | ||
550 | freq = le32_to_cpu(ev->freq); | ||
551 | dlen = le16_to_cpu(ev->len); | ||
552 | if (datap + len < ev->data + dlen) { | ||
553 | ath6kl_err("invalid wmi_rx_action_event: " | ||
554 | "len=%d dlen=%u\n", len, dlen); | ||
555 | return -EINVAL; | ||
556 | } | ||
557 | ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); | ||
558 | cfg80211_rx_mgmt(ar->net_dev, freq, ev->data, dlen, GFP_ATOMIC); | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | static int ath6kl_wmi_p2p_info_event_rx(u8 *datap, int len) | ||
564 | { | ||
565 | struct wmi_p2p_info_event *ev; | ||
566 | u32 flags; | ||
567 | u16 dlen; | ||
568 | |||
569 | if (len < sizeof(*ev)) | ||
570 | return -EINVAL; | ||
571 | |||
572 | ev = (struct wmi_p2p_info_event *) datap; | ||
573 | flags = le32_to_cpu(ev->info_req_flags); | ||
574 | dlen = le16_to_cpu(ev->len); | ||
575 | ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: flags=%x len=%d\n", flags, dlen); | ||
576 | |||
577 | if (flags & P2P_FLAG_CAPABILITIES_REQ) { | ||
578 | struct wmi_p2p_capabilities *cap; | ||
579 | if (dlen < sizeof(*cap)) | ||
580 | return -EINVAL; | ||
581 | cap = (struct wmi_p2p_capabilities *) ev->data; | ||
582 | ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: GO Power Save = %d\n", | ||
583 | cap->go_power_save); | ||
584 | } | ||
585 | |||
586 | if (flags & P2P_FLAG_MACADDR_REQ) { | ||
587 | struct wmi_p2p_macaddr *mac; | ||
588 | if (dlen < sizeof(*mac)) | ||
589 | return -EINVAL; | ||
590 | mac = (struct wmi_p2p_macaddr *) ev->data; | ||
591 | ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: MAC Address = %pM\n", | ||
592 | mac->mac_addr); | ||
593 | } | ||
594 | |||
595 | if (flags & P2P_FLAG_HMODEL_REQ) { | ||
596 | struct wmi_p2p_hmodel *mod; | ||
597 | if (dlen < sizeof(*mod)) | ||
598 | return -EINVAL; | ||
599 | mod = (struct wmi_p2p_hmodel *) ev->data; | ||
600 | ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: P2P Model = %d (%s)\n", | ||
601 | mod->p2p_model, | ||
602 | mod->p2p_model ? "host" : "firmware"); | ||
603 | } | ||
604 | return 0; | ||
605 | } | ||
606 | |||
436 | static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size) | 607 | static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size) |
437 | { | 608 | { |
438 | struct sk_buff *skb; | 609 | struct sk_buff *skb; |
@@ -478,18 +649,84 @@ static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len) | |||
478 | return 0; | 649 | return 0; |
479 | } | 650 | } |
480 | 651 | ||
652 | /* | ||
653 | * Mechanism to modify the roaming behavior in the firmware. The lower rssi | ||
654 | * at which the station has to roam can be passed with | ||
655 | * WMI_SET_LRSSI_SCAN_PARAMS. Subtract 96 from RSSI to get the signal level | ||
656 | * in dBm. | ||
657 | */ | ||
658 | int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi) | ||
659 | { | ||
660 | struct sk_buff *skb; | ||
661 | struct roam_ctrl_cmd *cmd; | ||
662 | |||
663 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
664 | if (!skb) | ||
665 | return -ENOMEM; | ||
666 | |||
667 | cmd = (struct roam_ctrl_cmd *) skb->data; | ||
668 | |||
669 | cmd->info.params.lrssi_scan_period = cpu_to_le16(DEF_LRSSI_SCAN_PERIOD); | ||
670 | cmd->info.params.lrssi_scan_threshold = a_cpu_to_sle16(lrssi + | ||
671 | DEF_SCAN_FOR_ROAM_INTVL); | ||
672 | cmd->info.params.lrssi_roam_threshold = a_cpu_to_sle16(lrssi); | ||
673 | cmd->info.params.roam_rssi_floor = DEF_LRSSI_ROAM_FLOOR; | ||
674 | cmd->roam_ctrl = WMI_SET_LRSSI_SCAN_PARAMS; | ||
675 | |||
676 | ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_ROAM_CTRL_CMDID, NO_SYNC_WMIFLAG); | ||
677 | |||
678 | return 0; | ||
679 | } | ||
680 | |||
481 | static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len) | 681 | static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len) |
482 | { | 682 | { |
483 | struct wmi_connect_event *ev; | 683 | struct wmi_connect_event *ev; |
484 | u8 *pie, *peie; | 684 | u8 *pie, *peie; |
685 | struct ath6kl *ar = wmi->parent_dev; | ||
485 | 686 | ||
486 | if (len < sizeof(struct wmi_connect_event)) | 687 | if (len < sizeof(struct wmi_connect_event)) |
487 | return -EINVAL; | 688 | return -EINVAL; |
488 | 689 | ||
489 | ev = (struct wmi_connect_event *) datap; | 690 | ev = (struct wmi_connect_event *) datap; |
490 | 691 | ||
491 | ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM\n", | 692 | if (ar->nw_type == AP_NETWORK) { |
492 | __func__, ev->ch, ev->bssid); | 693 | /* AP mode start/STA connected event */ |
694 | struct net_device *dev = ar->net_dev; | ||
695 | if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) { | ||
696 | ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM " | ||
697 | "(AP started)\n", | ||
698 | __func__, le16_to_cpu(ev->u.ap_bss.ch), | ||
699 | ev->u.ap_bss.bssid); | ||
700 | ath6kl_connect_ap_mode_bss( | ||
701 | ar, le16_to_cpu(ev->u.ap_bss.ch)); | ||
702 | } else { | ||
703 | ath6kl_dbg(ATH6KL_DBG_WMI, "%s: aid %u mac_addr %pM " | ||
704 | "auth=%u keymgmt=%u cipher=%u apsd_info=%u " | ||
705 | "(STA connected)\n", | ||
706 | __func__, ev->u.ap_sta.aid, | ||
707 | ev->u.ap_sta.mac_addr, | ||
708 | ev->u.ap_sta.auth, | ||
709 | ev->u.ap_sta.keymgmt, | ||
710 | le16_to_cpu(ev->u.ap_sta.cipher), | ||
711 | ev->u.ap_sta.apsd_info); | ||
712 | ath6kl_connect_ap_mode_sta( | ||
713 | ar, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr, | ||
714 | ev->u.ap_sta.keymgmt, | ||
715 | le16_to_cpu(ev->u.ap_sta.cipher), | ||
716 | ev->u.ap_sta.auth, ev->assoc_req_len, | ||
717 | ev->assoc_info + ev->beacon_ie_len); | ||
718 | } | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | /* STA/IBSS mode connection event */ | ||
723 | |||
724 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
725 | "wmi event connect freq %d bssid %pM listen_intvl %d beacon_intvl %d type %d\n", | ||
726 | le16_to_cpu(ev->u.sta.ch), ev->u.sta.bssid, | ||
727 | le16_to_cpu(ev->u.sta.listen_intvl), | ||
728 | le16_to_cpu(ev->u.sta.beacon_intvl), | ||
729 | le32_to_cpu(ev->u.sta.nw_type)); | ||
493 | 730 | ||
494 | /* Start of assoc rsp IEs */ | 731 | /* Start of assoc rsp IEs */ |
495 | pie = ev->assoc_info + ev->beacon_ie_len + | 732 | pie = ev->assoc_info + ev->beacon_ie_len + |
@@ -518,16 +755,92 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len) | |||
518 | pie += pie[1] + 2; | 755 | pie += pie[1] + 2; |
519 | } | 756 | } |
520 | 757 | ||
521 | ath6kl_connect_event(wmi->parent_dev, le16_to_cpu(ev->ch), ev->bssid, | 758 | ath6kl_connect_event(wmi->parent_dev, le16_to_cpu(ev->u.sta.ch), |
522 | le16_to_cpu(ev->listen_intvl), | 759 | ev->u.sta.bssid, |
523 | le16_to_cpu(ev->beacon_intvl), | 760 | le16_to_cpu(ev->u.sta.listen_intvl), |
524 | le32_to_cpu(ev->nw_type), | 761 | le16_to_cpu(ev->u.sta.beacon_intvl), |
762 | le32_to_cpu(ev->u.sta.nw_type), | ||
525 | ev->beacon_ie_len, ev->assoc_req_len, | 763 | ev->beacon_ie_len, ev->assoc_req_len, |
526 | ev->assoc_resp_len, ev->assoc_info); | 764 | ev->assoc_resp_len, ev->assoc_info); |
527 | 765 | ||
528 | return 0; | 766 | return 0; |
529 | } | 767 | } |
530 | 768 | ||
769 | static struct country_code_to_enum_rd * | ||
770 | ath6kl_regd_find_country(u16 countryCode) | ||
771 | { | ||
772 | int i; | ||
773 | |||
774 | for (i = 0; i < ARRAY_SIZE(allCountries); i++) { | ||
775 | if (allCountries[i].countryCode == countryCode) | ||
776 | return &allCountries[i]; | ||
777 | } | ||
778 | |||
779 | return NULL; | ||
780 | } | ||
781 | |||
782 | static struct reg_dmn_pair_mapping * | ||
783 | ath6kl_get_regpair(u16 regdmn) | ||
784 | { | ||
785 | int i; | ||
786 | |||
787 | if (regdmn == NO_ENUMRD) | ||
788 | return NULL; | ||
789 | |||
790 | for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { | ||
791 | if (regDomainPairs[i].regDmnEnum == regdmn) | ||
792 | return ®DomainPairs[i]; | ||
793 | } | ||
794 | |||
795 | return NULL; | ||
796 | } | ||
797 | |||
798 | static struct country_code_to_enum_rd * | ||
799 | ath6kl_regd_find_country_by_rd(u16 regdmn) | ||
800 | { | ||
801 | int i; | ||
802 | |||
803 | for (i = 0; i < ARRAY_SIZE(allCountries); i++) { | ||
804 | if (allCountries[i].regDmnEnum == regdmn) | ||
805 | return &allCountries[i]; | ||
806 | } | ||
807 | |||
808 | return NULL; | ||
809 | } | ||
810 | |||
811 | static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) | ||
812 | { | ||
813 | |||
814 | struct ath6kl_wmi_regdomain *ev; | ||
815 | struct country_code_to_enum_rd *country = NULL; | ||
816 | struct reg_dmn_pair_mapping *regpair = NULL; | ||
817 | char alpha2[2]; | ||
818 | u32 reg_code; | ||
819 | |||
820 | ev = (struct ath6kl_wmi_regdomain *) datap; | ||
821 | reg_code = le32_to_cpu(ev->reg_code); | ||
822 | |||
823 | if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) | ||
824 | country = ath6kl_regd_find_country((u16) reg_code); | ||
825 | else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) { | ||
826 | |||
827 | regpair = ath6kl_get_regpair((u16) reg_code); | ||
828 | country = ath6kl_regd_find_country_by_rd((u16) reg_code); | ||
829 | ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", | ||
830 | regpair->regDmnEnum); | ||
831 | } | ||
832 | |||
833 | if (country) { | ||
834 | alpha2[0] = country->isoName[0]; | ||
835 | alpha2[1] = country->isoName[1]; | ||
836 | |||
837 | regulatory_hint(wmi->parent_dev->wdev->wiphy, alpha2); | ||
838 | |||
839 | ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n", | ||
840 | alpha2[0], alpha2[1]); | ||
841 | } | ||
842 | } | ||
843 | |||
531 | static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len) | 844 | static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len) |
532 | { | 845 | { |
533 | struct wmi_disconnect_event *ev; | 846 | struct wmi_disconnect_event *ev; |
@@ -538,6 +851,11 @@ static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len) | |||
538 | 851 | ||
539 | ev = (struct wmi_disconnect_event *) datap; | 852 | ev = (struct wmi_disconnect_event *) datap; |
540 | 853 | ||
854 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
855 | "wmi event disconnect proto_reason %d bssid %pM wmi_reason %d assoc_resp_len %d\n", | ||
856 | le16_to_cpu(ev->proto_reason_status), ev->bssid, | ||
857 | ev->disconn_reason, ev->assoc_resp_len); | ||
858 | |||
541 | wmi->is_wmm_enabled = false; | 859 | wmi->is_wmm_enabled = false; |
542 | wmi->pair_crypto_type = NONE_CRYPT; | 860 | wmi->pair_crypto_type = NONE_CRYPT; |
543 | wmi->grp_crypto_type = NONE_CRYPT; | 861 | wmi->grp_crypto_type = NONE_CRYPT; |
@@ -582,315 +900,92 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len) | |||
582 | return 0; | 900 | return 0; |
583 | } | 901 | } |
584 | 902 | ||
585 | static int ath6kl_wlan_parse_beacon(u8 *buf, int frame_len, | ||
586 | struct ath6kl_common_ie *cie) | ||
587 | { | ||
588 | u8 *frm, *efrm; | ||
589 | u8 elemid_ssid = false; | ||
590 | |||
591 | frm = buf; | ||
592 | efrm = (u8 *) (frm + frame_len); | ||
593 | |||
594 | /* | ||
595 | * beacon/probe response frame format | ||
596 | * [8] time stamp | ||
597 | * [2] beacon interval | ||
598 | * [2] capability information | ||
599 | * [tlv] ssid | ||
600 | * [tlv] supported rates | ||
601 | * [tlv] country information | ||
602 | * [tlv] parameter set (FH/DS) | ||
603 | * [tlv] erp information | ||
604 | * [tlv] extended supported rates | ||
605 | * [tlv] WMM | ||
606 | * [tlv] WPA or RSN | ||
607 | * [tlv] Atheros Advanced Capabilities | ||
608 | */ | ||
609 | if ((efrm - frm) < 12) | ||
610 | return -EINVAL; | ||
611 | |||
612 | memset(cie, 0, sizeof(*cie)); | ||
613 | |||
614 | cie->ie_tstamp = frm; | ||
615 | frm += 8; | ||
616 | cie->ie_beaconInt = *(u16 *) frm; | ||
617 | frm += 2; | ||
618 | cie->ie_capInfo = *(u16 *) frm; | ||
619 | frm += 2; | ||
620 | cie->ie_chan = 0; | ||
621 | |||
622 | while (frm < efrm) { | ||
623 | switch (*frm) { | ||
624 | case WLAN_EID_SSID: | ||
625 | if (!elemid_ssid) { | ||
626 | cie->ie_ssid = frm; | ||
627 | elemid_ssid = true; | ||
628 | } | ||
629 | break; | ||
630 | case WLAN_EID_SUPP_RATES: | ||
631 | cie->ie_rates = frm; | ||
632 | break; | ||
633 | case WLAN_EID_COUNTRY: | ||
634 | cie->ie_country = frm; | ||
635 | break; | ||
636 | case WLAN_EID_FH_PARAMS: | ||
637 | break; | ||
638 | case WLAN_EID_DS_PARAMS: | ||
639 | cie->ie_chan = frm[2]; | ||
640 | break; | ||
641 | case WLAN_EID_TIM: | ||
642 | cie->ie_tim = frm; | ||
643 | break; | ||
644 | case WLAN_EID_IBSS_PARAMS: | ||
645 | break; | ||
646 | case WLAN_EID_EXT_SUPP_RATES: | ||
647 | cie->ie_xrates = frm; | ||
648 | break; | ||
649 | case WLAN_EID_ERP_INFO: | ||
650 | if (frm[1] != 1) | ||
651 | return -EINVAL; | ||
652 | |||
653 | cie->ie_erp = frm[2]; | ||
654 | break; | ||
655 | case WLAN_EID_RSN: | ||
656 | cie->ie_rsn = frm; | ||
657 | break; | ||
658 | case WLAN_EID_HT_CAPABILITY: | ||
659 | cie->ie_htcap = frm; | ||
660 | break; | ||
661 | case WLAN_EID_HT_INFORMATION: | ||
662 | cie->ie_htop = frm; | ||
663 | break; | ||
664 | case WLAN_EID_VENDOR_SPECIFIC: | ||
665 | if (frm[1] > 3 && frm[2] == 0x00 && frm[3] == 0x50 && | ||
666 | frm[4] == 0xf2) { | ||
667 | /* OUT Type (00:50:F2) */ | ||
668 | |||
669 | if (frm[5] == WPA_OUI_TYPE) { | ||
670 | /* WPA OUT */ | ||
671 | cie->ie_wpa = frm; | ||
672 | } else if (frm[5] == WMM_OUI_TYPE) { | ||
673 | /* WMM OUT */ | ||
674 | cie->ie_wmm = frm; | ||
675 | } else if (frm[5] == WSC_OUT_TYPE) { | ||
676 | /* WSC OUT */ | ||
677 | cie->ie_wsc = frm; | ||
678 | } | ||
679 | |||
680 | } else if (frm[1] > 3 && frm[2] == 0x00 | ||
681 | && frm[3] == 0x03 && frm[4] == 0x7f | ||
682 | && frm[5] == ATH_OUI_TYPE) { | ||
683 | /* Atheros OUI (00:03:7f) */ | ||
684 | cie->ie_ath = frm; | ||
685 | } | ||
686 | break; | ||
687 | default: | ||
688 | break; | ||
689 | } | ||
690 | frm += frm[1] + 2; | ||
691 | } | ||
692 | |||
693 | if ((cie->ie_rates == NULL) | ||
694 | || (cie->ie_rates[1] > ATH6KL_RATE_MAXSIZE)) | ||
695 | return -EINVAL; | ||
696 | |||
697 | if ((cie->ie_ssid == NULL) | ||
698 | || (cie->ie_ssid[1] > IEEE80211_MAX_SSID_LEN)) | ||
699 | return -EINVAL; | ||
700 | |||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len) | 903 | static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len) |
705 | { | 904 | { |
706 | struct bss *bss = NULL; | 905 | struct wmi_bss_info_hdr2 *bih; |
707 | struct wmi_bss_info_hdr *bih; | 906 | u8 *buf; |
708 | u8 cached_ssid_len = 0; | 907 | struct ieee80211_channel *channel; |
709 | u8 cached_ssid[IEEE80211_MAX_SSID_LEN] = { 0 }; | 908 | struct ath6kl *ar = wmi->parent_dev; |
710 | u8 beacon_ssid_len = 0; | 909 | struct ieee80211_mgmt *mgmt; |
711 | u8 *buf, *ie_ssid; | 910 | struct cfg80211_bss *bss; |
712 | u8 *ni_buf; | ||
713 | int buf_len; | ||
714 | |||
715 | int ret; | ||
716 | 911 | ||
717 | if (len <= sizeof(struct wmi_bss_info_hdr)) | 912 | if (len <= sizeof(struct wmi_bss_info_hdr2)) |
718 | return -EINVAL; | 913 | return -EINVAL; |
719 | 914 | ||
720 | bih = (struct wmi_bss_info_hdr *) datap; | 915 | bih = (struct wmi_bss_info_hdr2 *) datap; |
721 | bss = wlan_find_node(&wmi->parent_dev->scan_table, bih->bssid); | 916 | buf = datap + sizeof(struct wmi_bss_info_hdr2); |
722 | 917 | len -= sizeof(struct wmi_bss_info_hdr2); | |
723 | if (a_sle16_to_cpu(bih->rssi) > 0) { | ||
724 | if (bss == NULL) | ||
725 | return 0; | ||
726 | else | ||
727 | bih->rssi = a_cpu_to_sle16(bss->ni_rssi); | ||
728 | } | ||
729 | |||
730 | buf = datap + sizeof(struct wmi_bss_info_hdr); | ||
731 | len -= sizeof(struct wmi_bss_info_hdr); | ||
732 | 918 | ||
733 | ath6kl_dbg(ATH6KL_DBG_WMI, | 919 | ath6kl_dbg(ATH6KL_DBG_WMI, |
734 | "bss info evt - ch %u, rssi %02x, bssid \"%pM\"\n", | 920 | "bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" " |
735 | bih->ch, a_sle16_to_cpu(bih->rssi), bih->bssid); | 921 | "frame_type=%d\n", |
736 | 922 | bih->ch, bih->snr, bih->snr - 95, bih->bssid, | |
737 | if (bss != NULL) { | 923 | bih->frame_type); |
738 | /* | 924 | |
739 | * Free up the node. We are about to allocate a new node. | 925 | if (bih->frame_type != BEACON_FTYPE && |
740 | * In case of hidden AP, beacon will not have ssid, | 926 | bih->frame_type != PROBERESP_FTYPE) |
741 | * but a directed probe response will have it, | 927 | return 0; /* Only update BSS table for now */ |
742 | * so cache the probe-resp-ssid if already present. | 928 | |
743 | */ | 929 | if (bih->frame_type == BEACON_FTYPE && |
744 | if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE)) { | 930 | test_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag)) { |
745 | ie_ssid = bss->ni_cie.ie_ssid; | 931 | clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); |
746 | if (ie_ssid && (ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) && | 932 | ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); |
747 | (ie_ssid[2] != 0)) { | ||
748 | cached_ssid_len = ie_ssid[1]; | ||
749 | memcpy(cached_ssid, ie_ssid + 2, | ||
750 | cached_ssid_len); | ||
751 | } | ||
752 | } | ||
753 | |||
754 | /* | ||
755 | * Use the current average rssi of associated AP base on | ||
756 | * assumption | ||
757 | * 1. Most os with GUI will update RSSI by | ||
758 | * ath6kl_wmi_get_stats_cmd() periodically. | ||
759 | * 2. ath6kl_wmi_get_stats_cmd(..) will be called when calling | ||
760 | * ath6kl_wmi_startscan_cmd(...) | ||
761 | * The average value of RSSI give end-user better feeling for | ||
762 | * instance value of scan result. It also sync up RSSI info | ||
763 | * in GUI between scan result and RSSI signal icon. | ||
764 | */ | ||
765 | if (memcmp(wmi->parent_dev->bssid, bih->bssid, ETH_ALEN) == 0) { | ||
766 | bih->rssi = a_cpu_to_sle16(bss->ni_rssi); | ||
767 | bih->snr = bss->ni_snr; | ||
768 | } | ||
769 | |||
770 | wlan_node_reclaim(&wmi->parent_dev->scan_table, bss); | ||
771 | } | 933 | } |
772 | 934 | ||
773 | /* | 935 | channel = ieee80211_get_channel(ar->wdev->wiphy, le16_to_cpu(bih->ch)); |
774 | * beacon/probe response frame format | 936 | if (channel == NULL) |
775 | * [8] time stamp | ||
776 | * [2] beacon interval | ||
777 | * [2] capability information | ||
778 | * [tlv] ssid | ||
779 | */ | ||
780 | beacon_ssid_len = buf[SSID_IE_LEN_INDEX]; | ||
781 | |||
782 | /* | ||
783 | * If ssid is cached for this hidden AP, then change | ||
784 | * buffer len accordingly. | ||
785 | */ | ||
786 | if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) && | ||
787 | (cached_ssid_len != 0) && | ||
788 | (beacon_ssid_len == 0 || (cached_ssid_len > beacon_ssid_len && | ||
789 | buf[SSID_IE_LEN_INDEX + 1] == 0))) { | ||
790 | |||
791 | len += (cached_ssid_len - beacon_ssid_len); | ||
792 | } | ||
793 | |||
794 | bss = wlan_node_alloc(len); | ||
795 | if (!bss) | ||
796 | return -ENOMEM; | ||
797 | |||
798 | bss->ni_snr = bih->snr; | ||
799 | bss->ni_rssi = a_sle16_to_cpu(bih->rssi); | ||
800 | |||
801 | if (WARN_ON(!bss->ni_buf)) | ||
802 | return -EINVAL; | 937 | return -EINVAL; |
803 | 938 | ||
804 | /* | 939 | if (len < 8 + 2 + 2) |
805 | * In case of hidden AP, beacon will not have ssid, | ||
806 | * but a directed probe response will have it, | ||
807 | * so place the cached-ssid(probe-resp) in the bss info. | ||
808 | */ | ||
809 | if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) && | ||
810 | (cached_ssid_len != 0) && | ||
811 | (beacon_ssid_len == 0 || (beacon_ssid_len && | ||
812 | buf[SSID_IE_LEN_INDEX + 1] == 0))) { | ||
813 | ni_buf = bss->ni_buf; | ||
814 | buf_len = len; | ||
815 | |||
816 | /* | ||
817 | * Copy the first 14 bytes: | ||
818 | * time-stamp(8), beacon-interval(2), | ||
819 | * cap-info(2), ssid-id(1), ssid-len(1). | ||
820 | */ | ||
821 | memcpy(ni_buf, buf, SSID_IE_LEN_INDEX + 1); | ||
822 | |||
823 | ni_buf[SSID_IE_LEN_INDEX] = cached_ssid_len; | ||
824 | ni_buf += (SSID_IE_LEN_INDEX + 1); | ||
825 | |||
826 | buf += (SSID_IE_LEN_INDEX + 1); | ||
827 | buf_len -= (SSID_IE_LEN_INDEX + 1); | ||
828 | |||
829 | memcpy(ni_buf, cached_ssid, cached_ssid_len); | ||
830 | ni_buf += cached_ssid_len; | ||
831 | |||
832 | buf += beacon_ssid_len; | ||
833 | buf_len -= beacon_ssid_len; | ||
834 | |||
835 | if (cached_ssid_len > beacon_ssid_len) | ||
836 | buf_len -= (cached_ssid_len - beacon_ssid_len); | ||
837 | |||
838 | memcpy(ni_buf, buf, buf_len); | ||
839 | } else | ||
840 | memcpy(bss->ni_buf, buf, len); | ||
841 | |||
842 | bss->ni_framelen = len; | ||
843 | |||
844 | ret = ath6kl_wlan_parse_beacon(bss->ni_buf, len, &bss->ni_cie); | ||
845 | if (ret) { | ||
846 | wlan_node_free(bss); | ||
847 | return -EINVAL; | 940 | return -EINVAL; |
941 | |||
942 | if (bih->frame_type == BEACON_FTYPE && test_bit(CONNECTED, &ar->flag) && | ||
943 | memcmp(bih->bssid, ar->bssid, ETH_ALEN) == 0) { | ||
944 | const u8 *tim; | ||
945 | tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2, | ||
946 | len - 8 - 2 - 2); | ||
947 | if (tim && tim[1] >= 2) { | ||
948 | ar->assoc_bss_dtim_period = tim[3]; | ||
949 | set_bit(DTIM_PERIOD_AVAIL, &ar->flag); | ||
950 | } | ||
848 | } | 951 | } |
849 | 952 | ||
850 | /* | 953 | /* |
851 | * Update the frequency in ie_chan, overwriting of channel number | 954 | * In theory, use of cfg80211_inform_bss() would be more natural here |
852 | * which is done in ath6kl_wlan_parse_beacon | 955 | * since we do not have the full frame. However, at least for now, |
956 | * cfg80211 can only distinguish Beacon and Probe Response frames from | ||
957 | * each other when using cfg80211_inform_bss_frame(), so let's build a | ||
958 | * fake IEEE 802.11 header to be able to take benefit of this. | ||
853 | */ | 959 | */ |
854 | bss->ni_cie.ie_chan = le16_to_cpu(bih->ch); | 960 | mgmt = kmalloc(24 + len, GFP_ATOMIC); |
855 | wlan_setup_node(&wmi->parent_dev->scan_table, bss, bih->bssid); | 961 | if (mgmt == NULL) |
856 | |||
857 | return 0; | ||
858 | } | ||
859 | |||
860 | static int ath6kl_wmi_opt_frame_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
861 | { | ||
862 | struct bss *bss; | ||
863 | struct wmi_opt_rx_info_hdr *bih; | ||
864 | u8 *buf; | ||
865 | |||
866 | if (len <= sizeof(struct wmi_opt_rx_info_hdr)) | ||
867 | return -EINVAL; | 962 | return -EINVAL; |
868 | 963 | ||
869 | bih = (struct wmi_opt_rx_info_hdr *) datap; | 964 | if (bih->frame_type == BEACON_FTYPE) { |
870 | buf = datap + sizeof(struct wmi_opt_rx_info_hdr); | 965 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
871 | len -= sizeof(struct wmi_opt_rx_info_hdr); | 966 | IEEE80211_STYPE_BEACON); |
872 | 967 | memset(mgmt->da, 0xff, ETH_ALEN); | |
873 | ath6kl_dbg(ATH6KL_DBG_WMI, "opt frame event %2.2x:%2.2x\n", | 968 | } else { |
874 | bih->bssid[4], bih->bssid[5]); | 969 | struct net_device *dev = ar->net_dev; |
875 | 970 | ||
876 | bss = wlan_find_node(&wmi->parent_dev->scan_table, bih->bssid); | 971 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
877 | if (bss != NULL) { | 972 | IEEE80211_STYPE_PROBE_RESP); |
878 | /* Free up the node. We are about to allocate a new node. */ | 973 | memcpy(mgmt->da, dev->dev_addr, ETH_ALEN); |
879 | wlan_node_reclaim(&wmi->parent_dev->scan_table, bss); | ||
880 | } | 974 | } |
881 | 975 | mgmt->duration = cpu_to_le16(0); | |
882 | bss = wlan_node_alloc(len); | 976 | memcpy(mgmt->sa, bih->bssid, ETH_ALEN); |
883 | if (!bss) | 977 | memcpy(mgmt->bssid, bih->bssid, ETH_ALEN); |
978 | mgmt->seq_ctrl = cpu_to_le16(0); | ||
979 | |||
980 | memcpy(&mgmt->u.beacon, buf, len); | ||
981 | |||
982 | bss = cfg80211_inform_bss_frame(ar->wdev->wiphy, channel, mgmt, | ||
983 | 24 + len, (bih->snr - 95) * 100, | ||
984 | GFP_ATOMIC); | ||
985 | kfree(mgmt); | ||
986 | if (bss == NULL) | ||
884 | return -ENOMEM; | 987 | return -ENOMEM; |
885 | 988 | cfg80211_put_bss(bss); | |
886 | bss->ni_snr = bih->snr; | ||
887 | bss->ni_cie.ie_chan = le16_to_cpu(bih->ch); | ||
888 | |||
889 | if (WARN_ON(!bss->ni_buf)) | ||
890 | return -EINVAL; | ||
891 | |||
892 | memcpy(bss->ni_buf, buf, len); | ||
893 | wlan_setup_node(&wmi->parent_dev->scan_table, bss, bih->bssid); | ||
894 | 989 | ||
895 | return 0; | 990 | return 0; |
896 | } | 991 | } |
@@ -949,6 +1044,13 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len) | |||
949 | return 0; | 1044 | return 0; |
950 | } | 1045 | } |
951 | 1046 | ||
1047 | static int ath6kl_wmi_tcmd_test_report_rx(struct wmi *wmi, u8 *datap, int len) | ||
1048 | { | ||
1049 | ath6kl_tm_rx_report_event(wmi->parent_dev, datap, len); | ||
1050 | |||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
952 | static int ath6kl_wmi_ratemask_reply_rx(struct wmi *wmi, u8 *datap, int len) | 1054 | static int ath6kl_wmi_ratemask_reply_rx(struct wmi *wmi, u8 *datap, int len) |
953 | { | 1055 | { |
954 | if (len < sizeof(struct wmi_fix_rates_reply)) | 1056 | if (len < sizeof(struct wmi_fix_rates_reply)) |
@@ -998,15 +1100,41 @@ static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len) | |||
998 | 1100 | ||
999 | ev = (struct wmi_scan_complete_event *) datap; | 1101 | ev = (struct wmi_scan_complete_event *) datap; |
1000 | 1102 | ||
1001 | if (a_sle32_to_cpu(ev->status) == 0) | ||
1002 | wlan_refresh_inactive_nodes(wmi->parent_dev); | ||
1003 | |||
1004 | ath6kl_scan_complete_evt(wmi->parent_dev, a_sle32_to_cpu(ev->status)); | 1103 | ath6kl_scan_complete_evt(wmi->parent_dev, a_sle32_to_cpu(ev->status)); |
1005 | wmi->is_probe_ssid = false; | 1104 | wmi->is_probe_ssid = false; |
1006 | 1105 | ||
1007 | return 0; | 1106 | return 0; |
1008 | } | 1107 | } |
1009 | 1108 | ||
1109 | static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap, | ||
1110 | int len) | ||
1111 | { | ||
1112 | struct wmi_neighbor_report_event *ev; | ||
1113 | u8 i; | ||
1114 | |||
1115 | if (len < sizeof(*ev)) | ||
1116 | return -EINVAL; | ||
1117 | ev = (struct wmi_neighbor_report_event *) datap; | ||
1118 | if (sizeof(*ev) + ev->num_neighbors * sizeof(struct wmi_neighbor_info) | ||
1119 | > len) { | ||
1120 | ath6kl_dbg(ATH6KL_DBG_WMI, "truncated neighbor event " | ||
1121 | "(num=%d len=%d)\n", ev->num_neighbors, len); | ||
1122 | return -EINVAL; | ||
1123 | } | ||
1124 | for (i = 0; i < ev->num_neighbors; i++) { | ||
1125 | ath6kl_dbg(ATH6KL_DBG_WMI, "neighbor %d/%d - %pM 0x%x\n", | ||
1126 | i + 1, ev->num_neighbors, ev->neighbor[i].bssid, | ||
1127 | ev->neighbor[i].bss_flags); | ||
1128 | cfg80211_pmksa_candidate_notify(wmi->parent_dev->net_dev, i, | ||
1129 | ev->neighbor[i].bssid, | ||
1130 | !!(ev->neighbor[i].bss_flags & | ||
1131 | WMI_PREAUTH_CAPABLE_BSS), | ||
1132 | GFP_ATOMIC); | ||
1133 | } | ||
1134 | |||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1010 | /* | 1138 | /* |
1011 | * Target is reporting a programming error. This is for | 1139 | * Target is reporting a programming error. This is for |
1012 | * developer aid only. Target only checks a few common violations | 1140 | * developer aid only. Target only checks a few common violations |
@@ -1410,6 +1538,11 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb, | |||
1410 | if (WARN_ON(skb == NULL)) | 1538 | if (WARN_ON(skb == NULL)) |
1411 | return -EINVAL; | 1539 | return -EINVAL; |
1412 | 1540 | ||
1541 | ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n", | ||
1542 | cmd_id, skb->len, sync_flag); | ||
1543 | ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi tx ", | ||
1544 | skb->data, skb->len); | ||
1545 | |||
1413 | if (sync_flag >= END_WMIFLAG) { | 1546 | if (sync_flag >= END_WMIFLAG) { |
1414 | dev_kfree_skb(skb); | 1547 | dev_kfree_skb(skb); |
1415 | return -EINVAL; | 1548 | return -EINVAL; |
@@ -1468,6 +1601,13 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type, | |||
1468 | struct wmi_connect_cmd *cc; | 1601 | struct wmi_connect_cmd *cc; |
1469 | int ret; | 1602 | int ret; |
1470 | 1603 | ||
1604 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
1605 | "wmi connect bssid %pM freq %d flags 0x%x ssid_len %d " | ||
1606 | "type %d dot11_auth %d auth %d pairwise %d group %d\n", | ||
1607 | bssid, channel, ctrl_flags, ssid_len, nw_type, | ||
1608 | dot11_auth_mode, auth_mode, pairwise_crypto, group_crypto); | ||
1609 | ath6kl_dbg_dump(ATH6KL_DBG_WMI, NULL, "ssid ", ssid, ssid_len); | ||
1610 | |||
1471 | wmi->traffic_class = 100; | 1611 | wmi->traffic_class = 100; |
1472 | 1612 | ||
1473 | if ((pairwise_crypto == NONE_CRYPT) && (group_crypto != NONE_CRYPT)) | 1613 | if ((pairwise_crypto == NONE_CRYPT) && (group_crypto != NONE_CRYPT)) |
@@ -1513,6 +1653,9 @@ int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel) | |||
1513 | struct wmi_reconnect_cmd *cc; | 1653 | struct wmi_reconnect_cmd *cc; |
1514 | int ret; | 1654 | int ret; |
1515 | 1655 | ||
1656 | ath6kl_dbg(ATH6KL_DBG_WMI, "wmi reconnect bssid %pM freq %d\n", | ||
1657 | bssid, channel); | ||
1658 | |||
1516 | wmi->traffic_class = 100; | 1659 | wmi->traffic_class = 100; |
1517 | 1660 | ||
1518 | skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_reconnect_cmd)); | 1661 | skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_reconnect_cmd)); |
@@ -1535,6 +1678,8 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi) | |||
1535 | { | 1678 | { |
1536 | int ret; | 1679 | int ret; |
1537 | 1680 | ||
1681 | ath6kl_dbg(ATH6KL_DBG_WMI, "wmi disconnect\n"); | ||
1682 | |||
1538 | wmi->traffic_class = 100; | 1683 | wmi->traffic_class = 100; |
1539 | 1684 | ||
1540 | /* Disconnect command does not need to do a SYNC before. */ | 1685 | /* Disconnect command does not need to do a SYNC before. */ |
@@ -1551,7 +1696,7 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type, | |||
1551 | struct sk_buff *skb; | 1696 | struct sk_buff *skb; |
1552 | struct wmi_start_scan_cmd *sc; | 1697 | struct wmi_start_scan_cmd *sc; |
1553 | s8 size; | 1698 | s8 size; |
1554 | int ret; | 1699 | int i, ret; |
1555 | 1700 | ||
1556 | size = sizeof(struct wmi_start_scan_cmd); | 1701 | size = sizeof(struct wmi_start_scan_cmd); |
1557 | 1702 | ||
@@ -1576,8 +1721,8 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type, | |||
1576 | sc->force_scan_intvl = cpu_to_le32(force_scan_interval); | 1721 | sc->force_scan_intvl = cpu_to_le32(force_scan_interval); |
1577 | sc->num_ch = num_chan; | 1722 | sc->num_ch = num_chan; |
1578 | 1723 | ||
1579 | if (num_chan) | 1724 | for (i = 0; i < num_chan; i++) |
1580 | memcpy(sc->ch_list, ch_list, num_chan * sizeof(u16)); | 1725 | sc->ch_list[i] = cpu_to_le16(ch_list[i]); |
1581 | 1726 | ||
1582 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID, | 1727 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID, |
1583 | NO_SYNC_WMIFLAG); | 1728 | NO_SYNC_WMIFLAG); |
@@ -1770,6 +1915,10 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index, | |||
1770 | struct wmi_add_cipher_key_cmd *cmd; | 1915 | struct wmi_add_cipher_key_cmd *cmd; |
1771 | int ret; | 1916 | int ret; |
1772 | 1917 | ||
1918 | ath6kl_dbg(ATH6KL_DBG_WMI, "addkey cmd: key_index=%u key_type=%d " | ||
1919 | "key_usage=%d key_len=%d key_op_ctrl=%d\n", | ||
1920 | key_index, key_type, key_usage, key_len, key_op_ctrl); | ||
1921 | |||
1773 | if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) || | 1922 | if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) || |
1774 | (key_material == NULL)) | 1923 | (key_material == NULL)) |
1775 | return -EINVAL; | 1924 | return -EINVAL; |
@@ -2211,6 +2360,25 @@ int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source) | |||
2211 | return ret; | 2360 | return ret; |
2212 | } | 2361 | } |
2213 | 2362 | ||
2363 | int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config) | ||
2364 | { | ||
2365 | struct ath6kl_wmix_dbglog_cfg_module_cmd *cmd; | ||
2366 | struct sk_buff *skb; | ||
2367 | int ret; | ||
2368 | |||
2369 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
2370 | if (!skb) | ||
2371 | return -ENOMEM; | ||
2372 | |||
2373 | cmd = (struct ath6kl_wmix_dbglog_cfg_module_cmd *) skb->data; | ||
2374 | cmd->valid = cpu_to_le32(valid); | ||
2375 | cmd->config = cpu_to_le32(config); | ||
2376 | |||
2377 | ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_DBGLOG_CFG_MODULE_CMDID, | ||
2378 | NO_SYNC_WMIFLAG); | ||
2379 | return ret; | ||
2380 | } | ||
2381 | |||
2214 | int ath6kl_wmi_get_stats_cmd(struct wmi *wmi) | 2382 | int ath6kl_wmi_get_stats_cmd(struct wmi *wmi) |
2215 | { | 2383 | { |
2216 | return ath6kl_wmi_simple_cmd(wmi, WMI_GET_STATISTICS_CMDID); | 2384 | return ath6kl_wmi_simple_cmd(wmi, WMI_GET_STATISTICS_CMDID); |
@@ -2316,49 +2484,29 @@ int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl) | |||
2316 | return ret; | 2484 | return ret; |
2317 | } | 2485 | } |
2318 | 2486 | ||
2319 | s32 ath6kl_wmi_get_rate(s8 rate_index) | 2487 | int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len) |
2320 | { | 2488 | { |
2321 | if (rate_index == RATE_AUTO) | 2489 | struct sk_buff *skb; |
2322 | return 0; | 2490 | int ret; |
2323 | 2491 | ||
2324 | return wmi_rate_tbl[(u32) rate_index][0]; | 2492 | skb = ath6kl_wmi_get_new_buf(len); |
2325 | } | 2493 | if (!skb) |
2494 | return -ENOMEM; | ||
2326 | 2495 | ||
2327 | void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss) | 2496 | memcpy(skb->data, buf, len); |
2328 | { | ||
2329 | if (bss) | ||
2330 | wlan_node_return(&wmi->parent_dev->scan_table, bss); | ||
2331 | } | ||
2332 | 2497 | ||
2333 | struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 * ssid, | 2498 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_TEST_CMDID, NO_SYNC_WMIFLAG); |
2334 | u32 ssid_len, bool is_wpa2, | ||
2335 | bool match_ssid) | ||
2336 | { | ||
2337 | struct bss *node = NULL; | ||
2338 | 2499 | ||
2339 | node = wlan_find_ssid_node(&wmi->parent_dev->scan_table, ssid, | 2500 | return ret; |
2340 | ssid_len, is_wpa2, match_ssid); | ||
2341 | return node; | ||
2342 | } | 2501 | } |
2343 | 2502 | ||
2344 | struct bss *ath6kl_wmi_find_node(struct wmi *wmi, const u8 * mac_addr) | ||
2345 | { | ||
2346 | struct bss *ni = NULL; | ||
2347 | |||
2348 | ni = wlan_find_node(&wmi->parent_dev->scan_table, mac_addr); | ||
2349 | |||
2350 | return ni; | ||
2351 | } | ||
2352 | 2503 | ||
2353 | void ath6kl_wmi_node_free(struct wmi *wmi, const u8 * mac_addr) | 2504 | s32 ath6kl_wmi_get_rate(s8 rate_index) |
2354 | { | 2505 | { |
2355 | struct bss *ni = NULL; | 2506 | if (rate_index == RATE_AUTO) |
2356 | 2507 | return 0; | |
2357 | ni = wlan_find_node(&wmi->parent_dev->scan_table, mac_addr); | ||
2358 | if (ni != NULL) | ||
2359 | wlan_node_reclaim(&wmi->parent_dev->scan_table, ni); | ||
2360 | 2508 | ||
2361 | return; | 2509 | return wmi_rate_tbl[(u32) rate_index][0]; |
2362 | } | 2510 | } |
2363 | 2511 | ||
2364 | static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, | 2512 | static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, |
@@ -2400,6 +2548,47 @@ static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len) | |||
2400 | } | 2548 | } |
2401 | 2549 | ||
2402 | /* AP mode functions */ | 2550 | /* AP mode functions */ |
2551 | |||
2552 | int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p) | ||
2553 | { | ||
2554 | struct sk_buff *skb; | ||
2555 | struct wmi_connect_cmd *cm; | ||
2556 | int res; | ||
2557 | |||
2558 | skb = ath6kl_wmi_get_new_buf(sizeof(*cm)); | ||
2559 | if (!skb) | ||
2560 | return -ENOMEM; | ||
2561 | |||
2562 | cm = (struct wmi_connect_cmd *) skb->data; | ||
2563 | memcpy(cm, p, sizeof(*cm)); | ||
2564 | |||
2565 | res = ath6kl_wmi_cmd_send(wmip, skb, WMI_AP_CONFIG_COMMIT_CMDID, | ||
2566 | NO_SYNC_WMIFLAG); | ||
2567 | ath6kl_dbg(ATH6KL_DBG_WMI, "%s: nw_type=%u auth_mode=%u ch=%u " | ||
2568 | "ctrl_flags=0x%x-> res=%d\n", | ||
2569 | __func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch), | ||
2570 | le32_to_cpu(p->ctrl_flags), res); | ||
2571 | return res; | ||
2572 | } | ||
2573 | |||
2574 | int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 cmd, const u8 *mac, u16 reason) | ||
2575 | { | ||
2576 | struct sk_buff *skb; | ||
2577 | struct wmi_ap_set_mlme_cmd *cm; | ||
2578 | |||
2579 | skb = ath6kl_wmi_get_new_buf(sizeof(*cm)); | ||
2580 | if (!skb) | ||
2581 | return -ENOMEM; | ||
2582 | |||
2583 | cm = (struct wmi_ap_set_mlme_cmd *) skb->data; | ||
2584 | memcpy(cm->mac, mac, ETH_ALEN); | ||
2585 | cm->reason = cpu_to_le16(reason); | ||
2586 | cm->cmd = cmd; | ||
2587 | |||
2588 | return ath6kl_wmi_cmd_send(wmip, skb, WMI_AP_SET_MLME_CMDID, | ||
2589 | NO_SYNC_WMIFLAG); | ||
2590 | } | ||
2591 | |||
2403 | static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len) | 2592 | static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len) |
2404 | { | 2593 | { |
2405 | struct wmi_pspoll_event *ev; | 2594 | struct wmi_pspoll_event *ev; |
@@ -2433,6 +2622,7 @@ int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag) | |||
2433 | 2622 | ||
2434 | cmd = (struct wmi_ap_set_pvb_cmd *) skb->data; | 2623 | cmd = (struct wmi_ap_set_pvb_cmd *) skb->data; |
2435 | cmd->aid = cpu_to_le16(aid); | 2624 | cmd->aid = cpu_to_le16(aid); |
2625 | cmd->rsvd = cpu_to_le16(0); | ||
2436 | cmd->flag = cpu_to_le32(flag); | 2626 | cmd->flag = cpu_to_le32(flag); |
2437 | 2627 | ||
2438 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_AP_SET_PVB_CMDID, | 2628 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_AP_SET_PVB_CMDID, |
@@ -2464,6 +2654,160 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_ver, | |||
2464 | return ret; | 2654 | return ret; |
2465 | } | 2655 | } |
2466 | 2656 | ||
2657 | int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie, | ||
2658 | u8 ie_len) | ||
2659 | { | ||
2660 | struct sk_buff *skb; | ||
2661 | struct wmi_set_appie_cmd *p; | ||
2662 | |||
2663 | skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len); | ||
2664 | if (!skb) | ||
2665 | return -ENOMEM; | ||
2666 | |||
2667 | ath6kl_dbg(ATH6KL_DBG_WMI, "set_appie_cmd: mgmt_frm_type=%u " | ||
2668 | "ie_len=%u\n", mgmt_frm_type, ie_len); | ||
2669 | p = (struct wmi_set_appie_cmd *) skb->data; | ||
2670 | p->mgmt_frm_type = mgmt_frm_type; | ||
2671 | p->ie_len = ie_len; | ||
2672 | memcpy(p->ie_info, ie, ie_len); | ||
2673 | return ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_APPIE_CMDID, | ||
2674 | NO_SYNC_WMIFLAG); | ||
2675 | } | ||
2676 | |||
2677 | int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable) | ||
2678 | { | ||
2679 | struct sk_buff *skb; | ||
2680 | struct wmi_disable_11b_rates_cmd *cmd; | ||
2681 | |||
2682 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
2683 | if (!skb) | ||
2684 | return -ENOMEM; | ||
2685 | |||
2686 | ath6kl_dbg(ATH6KL_DBG_WMI, "disable_11b_rates_cmd: disable=%u\n", | ||
2687 | disable); | ||
2688 | cmd = (struct wmi_disable_11b_rates_cmd *) skb->data; | ||
2689 | cmd->disable = disable ? 1 : 0; | ||
2690 | |||
2691 | return ath6kl_wmi_cmd_send(wmi, skb, WMI_DISABLE_11B_RATES_CMDID, | ||
2692 | NO_SYNC_WMIFLAG); | ||
2693 | } | ||
2694 | |||
2695 | int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u32 freq, u32 dur) | ||
2696 | { | ||
2697 | struct sk_buff *skb; | ||
2698 | struct wmi_remain_on_chnl_cmd *p; | ||
2699 | |||
2700 | skb = ath6kl_wmi_get_new_buf(sizeof(*p)); | ||
2701 | if (!skb) | ||
2702 | return -ENOMEM; | ||
2703 | |||
2704 | ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl_cmd: freq=%u dur=%u\n", | ||
2705 | freq, dur); | ||
2706 | p = (struct wmi_remain_on_chnl_cmd *) skb->data; | ||
2707 | p->freq = cpu_to_le32(freq); | ||
2708 | p->duration = cpu_to_le32(dur); | ||
2709 | return ath6kl_wmi_cmd_send(wmi, skb, WMI_REMAIN_ON_CHNL_CMDID, | ||
2710 | NO_SYNC_WMIFLAG); | ||
2711 | } | ||
2712 | |||
2713 | int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait, | ||
2714 | const u8 *data, u16 data_len) | ||
2715 | { | ||
2716 | struct sk_buff *skb; | ||
2717 | struct wmi_send_action_cmd *p; | ||
2718 | u8 *buf; | ||
2719 | |||
2720 | if (wait) | ||
2721 | return -EINVAL; /* Offload for wait not supported */ | ||
2722 | |||
2723 | buf = kmalloc(data_len, GFP_KERNEL); | ||
2724 | if (!buf) | ||
2725 | return -ENOMEM; | ||
2726 | |||
2727 | skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len); | ||
2728 | if (!skb) { | ||
2729 | kfree(buf); | ||
2730 | return -ENOMEM; | ||
2731 | } | ||
2732 | |||
2733 | kfree(wmi->last_mgmt_tx_frame); | ||
2734 | wmi->last_mgmt_tx_frame = buf; | ||
2735 | wmi->last_mgmt_tx_frame_len = data_len; | ||
2736 | |||
2737 | ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u " | ||
2738 | "len=%u\n", id, freq, wait, data_len); | ||
2739 | p = (struct wmi_send_action_cmd *) skb->data; | ||
2740 | p->id = cpu_to_le32(id); | ||
2741 | p->freq = cpu_to_le32(freq); | ||
2742 | p->wait = cpu_to_le32(wait); | ||
2743 | p->len = cpu_to_le16(data_len); | ||
2744 | memcpy(p->data, data, data_len); | ||
2745 | return ath6kl_wmi_cmd_send(wmi, skb, WMI_SEND_ACTION_CMDID, | ||
2746 | NO_SYNC_WMIFLAG); | ||
2747 | } | ||
2748 | |||
2749 | int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u32 freq, | ||
2750 | const u8 *dst, | ||
2751 | const u8 *data, u16 data_len) | ||
2752 | { | ||
2753 | struct sk_buff *skb; | ||
2754 | struct wmi_p2p_probe_response_cmd *p; | ||
2755 | |||
2756 | skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len); | ||
2757 | if (!skb) | ||
2758 | return -ENOMEM; | ||
2759 | |||
2760 | ath6kl_dbg(ATH6KL_DBG_WMI, "send_probe_response_cmd: freq=%u dst=%pM " | ||
2761 | "len=%u\n", freq, dst, data_len); | ||
2762 | p = (struct wmi_p2p_probe_response_cmd *) skb->data; | ||
2763 | p->freq = cpu_to_le32(freq); | ||
2764 | memcpy(p->destination_addr, dst, ETH_ALEN); | ||
2765 | p->len = cpu_to_le16(data_len); | ||
2766 | memcpy(p->data, data, data_len); | ||
2767 | return ath6kl_wmi_cmd_send(wmi, skb, WMI_SEND_PROBE_RESPONSE_CMDID, | ||
2768 | NO_SYNC_WMIFLAG); | ||
2769 | } | ||
2770 | |||
2771 | int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, bool enable) | ||
2772 | { | ||
2773 | struct sk_buff *skb; | ||
2774 | struct wmi_probe_req_report_cmd *p; | ||
2775 | |||
2776 | skb = ath6kl_wmi_get_new_buf(sizeof(*p)); | ||
2777 | if (!skb) | ||
2778 | return -ENOMEM; | ||
2779 | |||
2780 | ath6kl_dbg(ATH6KL_DBG_WMI, "probe_report_req_cmd: enable=%u\n", | ||
2781 | enable); | ||
2782 | p = (struct wmi_probe_req_report_cmd *) skb->data; | ||
2783 | p->enable = enable ? 1 : 0; | ||
2784 | return ath6kl_wmi_cmd_send(wmi, skb, WMI_PROBE_REQ_REPORT_CMDID, | ||
2785 | NO_SYNC_WMIFLAG); | ||
2786 | } | ||
2787 | |||
2788 | int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags) | ||
2789 | { | ||
2790 | struct sk_buff *skb; | ||
2791 | struct wmi_get_p2p_info *p; | ||
2792 | |||
2793 | skb = ath6kl_wmi_get_new_buf(sizeof(*p)); | ||
2794 | if (!skb) | ||
2795 | return -ENOMEM; | ||
2796 | |||
2797 | ath6kl_dbg(ATH6KL_DBG_WMI, "info_req_cmd: flags=%x\n", | ||
2798 | info_req_flags); | ||
2799 | p = (struct wmi_get_p2p_info *) skb->data; | ||
2800 | p->info_req_flags = cpu_to_le32(info_req_flags); | ||
2801 | return ath6kl_wmi_cmd_send(wmi, skb, WMI_GET_P2P_INFO_CMDID, | ||
2802 | NO_SYNC_WMIFLAG); | ||
2803 | } | ||
2804 | |||
2805 | int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi) | ||
2806 | { | ||
2807 | ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl_cmd\n"); | ||
2808 | return ath6kl_wmi_simple_cmd(wmi, WMI_CANCEL_REMAIN_ON_CHNL_CMDID); | ||
2809 | } | ||
2810 | |||
2467 | static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) | 2811 | static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) |
2468 | { | 2812 | { |
2469 | struct wmix_cmd_hdr *cmd; | 2813 | struct wmix_cmd_hdr *cmd; |
@@ -2488,11 +2832,14 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) | |||
2488 | 2832 | ||
2489 | switch (id) { | 2833 | switch (id) { |
2490 | case WMIX_HB_CHALLENGE_RESP_EVENTID: | 2834 | case WMIX_HB_CHALLENGE_RESP_EVENTID: |
2835 | ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n"); | ||
2491 | break; | 2836 | break; |
2492 | case WMIX_DBGLOG_EVENTID: | 2837 | case WMIX_DBGLOG_EVENTID: |
2838 | ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len); | ||
2839 | ath6kl_debug_fwlog_event(wmi->parent_dev, datap, len); | ||
2493 | break; | 2840 | break; |
2494 | default: | 2841 | default: |
2495 | ath6kl_err("unknown cmd id 0x%x\n", id); | 2842 | ath6kl_warn("unknown cmd id 0x%x\n", id); |
2496 | wmi->stat.cmd_id_err++; | 2843 | wmi->stat.cmd_id_err++; |
2497 | ret = -EINVAL; | 2844 | ret = -EINVAL; |
2498 | break; | 2845 | break; |
@@ -2528,8 +2875,9 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
2528 | datap = skb->data; | 2875 | datap = skb->data; |
2529 | len = skb->len; | 2876 | len = skb->len; |
2530 | 2877 | ||
2531 | ath6kl_dbg(ATH6KL_DBG_WMI, "%s: wmi id: %d\n", __func__, id); | 2878 | ath6kl_dbg(ATH6KL_DBG_WMI, "wmi rx id %d len %d\n", id, len); |
2532 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "msg payload ", datap, len); | 2879 | ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ", |
2880 | datap, len); | ||
2533 | 2881 | ||
2534 | switch (id) { | 2882 | switch (id) { |
2535 | case WMI_GET_BITRATE_CMDID: | 2883 | case WMI_GET_BITRATE_CMDID: |
@@ -2566,11 +2914,11 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
2566 | break; | 2914 | break; |
2567 | case WMI_BSSINFO_EVENTID: | 2915 | case WMI_BSSINFO_EVENTID: |
2568 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n"); | 2916 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n"); |
2569 | ath6kl_wmi_convert_bssinfo_hdr2_to_hdr(skb, datap); | 2917 | ret = ath6kl_wmi_bssinfo_event_rx(wmi, datap, len); |
2570 | ret = ath6kl_wmi_bssinfo_event_rx(wmi, skb->data, skb->len); | ||
2571 | break; | 2918 | break; |
2572 | case WMI_REGDOMAIN_EVENTID: | 2919 | case WMI_REGDOMAIN_EVENTID: |
2573 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n"); | 2920 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n"); |
2921 | ath6kl_wmi_regdomain_event(wmi, datap, len); | ||
2574 | break; | 2922 | break; |
2575 | case WMI_PSTREAM_TIMEOUT_EVENTID: | 2923 | case WMI_PSTREAM_TIMEOUT_EVENTID: |
2576 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n"); | 2924 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n"); |
@@ -2578,6 +2926,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
2578 | break; | 2926 | break; |
2579 | case WMI_NEIGHBOR_REPORT_EVENTID: | 2927 | case WMI_NEIGHBOR_REPORT_EVENTID: |
2580 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n"); | 2928 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n"); |
2929 | ret = ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len); | ||
2581 | break; | 2930 | break; |
2582 | case WMI_SCAN_COMPLETE_EVENTID: | 2931 | case WMI_SCAN_COMPLETE_EVENTID: |
2583 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n"); | 2932 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n"); |
@@ -2600,7 +2949,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
2600 | break; | 2949 | break; |
2601 | case WMI_OPT_RX_FRAME_EVENTID: | 2950 | case WMI_OPT_RX_FRAME_EVENTID: |
2602 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_OPT_RX_FRAME_EVENTID\n"); | 2951 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_OPT_RX_FRAME_EVENTID\n"); |
2603 | ret = ath6kl_wmi_opt_frame_event_rx(wmi, datap, len); | 2952 | /* this event has been deprecated */ |
2604 | break; | 2953 | break; |
2605 | case WMI_REPORT_ROAM_TBL_EVENTID: | 2954 | case WMI_REPORT_ROAM_TBL_EVENTID: |
2606 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_TBL_EVENTID\n"); | 2955 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_TBL_EVENTID\n"); |
@@ -2619,6 +2968,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
2619 | case WMI_REPORT_ROAM_DATA_EVENTID: | 2968 | case WMI_REPORT_ROAM_DATA_EVENTID: |
2620 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_DATA_EVENTID\n"); | 2969 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_DATA_EVENTID\n"); |
2621 | break; | 2970 | break; |
2971 | case WMI_TEST_EVENTID: | ||
2972 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TEST_EVENTID\n"); | ||
2973 | ret = ath6kl_wmi_tcmd_test_report_rx(wmi, datap, len); | ||
2974 | break; | ||
2622 | case WMI_GET_FIXRATES_CMDID: | 2975 | case WMI_GET_FIXRATES_CMDID: |
2623 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n"); | 2976 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n"); |
2624 | ret = ath6kl_wmi_ratemask_reply_rx(wmi, datap, len); | 2977 | ret = ath6kl_wmi_ratemask_reply_rx(wmi, datap, len); |
@@ -2683,6 +3036,36 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
2683 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n"); | 3036 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n"); |
2684 | ret = ath6kl_wmi_tx_complete_event_rx(datap, len); | 3037 | ret = ath6kl_wmi_tx_complete_event_rx(datap, len); |
2685 | break; | 3038 | break; |
3039 | case WMI_REMAIN_ON_CHNL_EVENTID: | ||
3040 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n"); | ||
3041 | ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len); | ||
3042 | break; | ||
3043 | case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID: | ||
3044 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
3045 | "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n"); | ||
3046 | ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap, | ||
3047 | len); | ||
3048 | break; | ||
3049 | case WMI_TX_STATUS_EVENTID: | ||
3050 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n"); | ||
3051 | ret = ath6kl_wmi_tx_status_event_rx(wmi, datap, len); | ||
3052 | break; | ||
3053 | case WMI_RX_PROBE_REQ_EVENTID: | ||
3054 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n"); | ||
3055 | ret = ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len); | ||
3056 | break; | ||
3057 | case WMI_P2P_CAPABILITIES_EVENTID: | ||
3058 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n"); | ||
3059 | ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len); | ||
3060 | break; | ||
3061 | case WMI_RX_ACTION_EVENTID: | ||
3062 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); | ||
3063 | ret = ath6kl_wmi_rx_action_event_rx(wmi, datap, len); | ||
3064 | break; | ||
3065 | case WMI_P2P_INFO_EVENTID: | ||
3066 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n"); | ||
3067 | ret = ath6kl_wmi_p2p_info_event_rx(datap, len); | ||
3068 | break; | ||
2686 | default: | 3069 | default: |
2687 | ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id); | 3070 | ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id); |
2688 | wmi->stat.cmd_id_err++; | 3071 | wmi->stat.cmd_id_err++; |
@@ -2739,5 +3122,6 @@ void ath6kl_wmi_shutdown(struct wmi *wmi) | |||
2739 | if (!wmi) | 3122 | if (!wmi) |
2740 | return; | 3123 | return; |
2741 | 3124 | ||
3125 | kfree(wmi->last_mgmt_tx_frame); | ||
2742 | kfree(wmi); | 3126 | kfree(wmi); |
2743 | } | 3127 | } |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index fe3ddce64087..f8e644d54aa7 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h | |||
@@ -129,6 +129,9 @@ struct wmi { | |||
129 | u8 ht_allowed[A_NUM_BANDS]; | 129 | u8 ht_allowed[A_NUM_BANDS]; |
130 | u8 traffic_class; | 130 | u8 traffic_class; |
131 | bool is_probe_ssid; | 131 | bool is_probe_ssid; |
132 | |||
133 | u8 *last_mgmt_tx_frame; | ||
134 | size_t last_mgmt_tx_frame_len; | ||
132 | }; | 135 | }; |
133 | 136 | ||
134 | struct host_app_area { | 137 | struct host_app_area { |
@@ -490,17 +493,61 @@ enum wmi_cmd_id { | |||
490 | WMI_SET_PASSPHRASE_CMDID, | 493 | WMI_SET_PASSPHRASE_CMDID, |
491 | WMI_SEND_ASSOC_RES_CMDID, | 494 | WMI_SEND_ASSOC_RES_CMDID, |
492 | WMI_SET_ASSOC_REQ_RELAY_CMDID, | 495 | WMI_SET_ASSOC_REQ_RELAY_CMDID, |
493 | WMI_GET_RFKILL_MODE_CMDID, | ||
494 | 496 | ||
495 | /* ACS command, consists of sub-commands */ | 497 | /* ACS command, consists of sub-commands */ |
496 | WMI_ACS_CTRL_CMDID, | 498 | WMI_ACS_CTRL_CMDID, |
499 | WMI_SET_EXCESS_TX_RETRY_THRES_CMDID, | ||
500 | WMI_SET_TBD_TIME_CMDID, /*added for wmiconfig command for TBD */ | ||
501 | |||
502 | /* Pktlog cmds */ | ||
503 | WMI_PKTLOG_ENABLE_CMDID, | ||
504 | WMI_PKTLOG_DISABLE_CMDID, | ||
505 | |||
506 | /* More P2P Cmds */ | ||
507 | WMI_P2P_GO_NEG_REQ_RSP_CMDID, | ||
508 | WMI_P2P_GRP_INIT_CMDID, | ||
509 | WMI_P2P_GRP_FORMATION_DONE_CMDID, | ||
510 | WMI_P2P_INVITE_CMDID, | ||
511 | WMI_P2P_INVITE_REQ_RSP_CMDID, | ||
512 | WMI_P2P_PROV_DISC_REQ_CMDID, | ||
513 | WMI_P2P_SET_CMDID, | ||
514 | |||
515 | WMI_GET_RFKILL_MODE_CMDID, | ||
516 | WMI_SET_RFKILL_MODE_CMDID, | ||
517 | WMI_AP_SET_APSD_CMDID, | ||
518 | WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID, | ||
497 | 519 | ||
520 | WMI_P2P_SDPD_TX_CMDID, /* F05C */ | ||
521 | WMI_P2P_STOP_SDPD_CMDID, | ||
522 | WMI_P2P_CANCEL_CMDID, | ||
498 | /* Ultra low power store / recall commands */ | 523 | /* Ultra low power store / recall commands */ |
499 | WMI_STORERECALL_CONFIGURE_CMDID, | 524 | WMI_STORERECALL_CONFIGURE_CMDID, |
500 | WMI_STORERECALL_RECALL_CMDID, | 525 | WMI_STORERECALL_RECALL_CMDID, |
501 | WMI_STORERECALL_HOST_READY_CMDID, | 526 | WMI_STORERECALL_HOST_READY_CMDID, |
502 | WMI_FORCE_TARGET_ASSERT_CMDID, | 527 | WMI_FORCE_TARGET_ASSERT_CMDID, |
503 | WMI_SET_EXCESS_TX_RETRY_THRES_CMDID, | 528 | |
529 | WMI_SET_PROBED_SSID_EX_CMDID, | ||
530 | WMI_SET_NETWORK_LIST_OFFLOAD_CMDID, | ||
531 | WMI_SET_ARP_NS_OFFLOAD_CMDID, | ||
532 | WMI_ADD_WOW_EXT_PATTERN_CMDID, | ||
533 | WMI_GTK_OFFLOAD_OP_CMDID, | ||
534 | WMI_REMAIN_ON_CHNL_CMDID, | ||
535 | WMI_CANCEL_REMAIN_ON_CHNL_CMDID, | ||
536 | WMI_SEND_ACTION_CMDID, | ||
537 | WMI_PROBE_REQ_REPORT_CMDID, | ||
538 | WMI_DISABLE_11B_RATES_CMDID, | ||
539 | WMI_SEND_PROBE_RESPONSE_CMDID, | ||
540 | WMI_GET_P2P_INFO_CMDID, | ||
541 | WMI_AP_JOIN_BSS_CMDID, | ||
542 | }; | ||
543 | |||
544 | enum wmi_mgmt_frame_type { | ||
545 | WMI_FRAME_BEACON = 0, | ||
546 | WMI_FRAME_PROBE_REQ, | ||
547 | WMI_FRAME_PROBE_RESP, | ||
548 | WMI_FRAME_ASSOC_REQ, | ||
549 | WMI_FRAME_ASSOC_RESP, | ||
550 | WMI_NUM_MGMT_FRAME | ||
504 | }; | 551 | }; |
505 | 552 | ||
506 | /* WMI_CONNECT_CMDID */ | 553 | /* WMI_CONNECT_CMDID */ |
@@ -519,11 +566,6 @@ enum dot11_auth_mode { | |||
519 | LEAP_AUTH = 0x04, | 566 | LEAP_AUTH = 0x04, |
520 | }; | 567 | }; |
521 | 568 | ||
522 | enum { | ||
523 | AUTH_IDLE, | ||
524 | AUTH_OPEN_IN_PROGRESS, | ||
525 | }; | ||
526 | |||
527 | enum auth_mode { | 569 | enum auth_mode { |
528 | NONE_AUTH = 0x01, | 570 | NONE_AUTH = 0x01, |
529 | WPA_AUTH = 0x02, | 571 | WPA_AUTH = 0x02, |
@@ -1179,15 +1221,26 @@ enum wmi_event_id { | |||
1179 | WMI_WAC_START_WPS_EVENTID, | 1221 | WMI_WAC_START_WPS_EVENTID, |
1180 | WMI_WAC_CTRL_REQ_REPLY_EVENTID, | 1222 | WMI_WAC_CTRL_REQ_REPLY_EVENTID, |
1181 | 1223 | ||
1224 | WMI_REPORT_WMM_PARAMS_EVENTID, | ||
1225 | WMI_WAC_REJECT_WPS_EVENTID, | ||
1226 | |||
1227 | /* More P2P Events */ | ||
1228 | WMI_P2P_GO_NEG_REQ_EVENTID, | ||
1229 | WMI_P2P_INVITE_REQ_EVENTID, | ||
1230 | WMI_P2P_INVITE_RCVD_RESULT_EVENTID, | ||
1231 | WMI_P2P_INVITE_SENT_RESULT_EVENTID, | ||
1232 | WMI_P2P_PROV_DISC_RESP_EVENTID, | ||
1233 | WMI_P2P_PROV_DISC_REQ_EVENTID, | ||
1234 | |||
1182 | /* RFKILL Events */ | 1235 | /* RFKILL Events */ |
1183 | WMI_RFKILL_STATE_CHANGE_EVENTID, | 1236 | WMI_RFKILL_STATE_CHANGE_EVENTID, |
1184 | WMI_RFKILL_GET_MODE_CMD_EVENTID, | 1237 | WMI_RFKILL_GET_MODE_CMD_EVENTID, |
1185 | WMI_THIN_RESERVED_START_EVENTID = 0x8000, | ||
1186 | 1238 | ||
1187 | /* | 1239 | WMI_P2P_START_SDPD_EVENTID, |
1188 | * Events in this range are reserved for thinmode | 1240 | WMI_P2P_SDPD_RX_EVENTID, |
1189 | * See wmi_thin.h for actual definitions | 1241 | |
1190 | */ | 1242 | WMI_THIN_RESERVED_START_EVENTID = 0x8000, |
1243 | /* Events in this range are reserved for thinmode */ | ||
1191 | WMI_THIN_RESERVED_END_EVENTID = 0x8fff, | 1244 | WMI_THIN_RESERVED_END_EVENTID = 0x8fff, |
1192 | 1245 | ||
1193 | WMI_SET_CHANNEL_EVENTID, | 1246 | WMI_SET_CHANNEL_EVENTID, |
@@ -1195,7 +1248,17 @@ enum wmi_event_id { | |||
1195 | 1248 | ||
1196 | /* Generic ACS event */ | 1249 | /* Generic ACS event */ |
1197 | WMI_ACS_EVENTID, | 1250 | WMI_ACS_EVENTID, |
1198 | WMI_REPORT_WMM_PARAMS_EVENTID | 1251 | WMI_STORERECALL_STORE_EVENTID, |
1252 | WMI_WOW_EXT_WAKE_EVENTID, | ||
1253 | WMI_GTK_OFFLOAD_STATUS_EVENTID, | ||
1254 | WMI_NETWORK_LIST_OFFLOAD_EVENTID, | ||
1255 | WMI_REMAIN_ON_CHNL_EVENTID, | ||
1256 | WMI_CANCEL_REMAIN_ON_CHNL_EVENTID, | ||
1257 | WMI_TX_STATUS_EVENTID, | ||
1258 | WMI_RX_PROBE_REQ_EVENTID, | ||
1259 | WMI_P2P_CAPABILITIES_EVENTID, | ||
1260 | WMI_RX_ACTION_EVENTID, | ||
1261 | WMI_P2P_INFO_EVENTID, | ||
1199 | }; | 1262 | }; |
1200 | 1263 | ||
1201 | struct wmi_ready_event_2 { | 1264 | struct wmi_ready_event_2 { |
@@ -1207,11 +1270,30 @@ struct wmi_ready_event_2 { | |||
1207 | 1270 | ||
1208 | /* Connect Event */ | 1271 | /* Connect Event */ |
1209 | struct wmi_connect_event { | 1272 | struct wmi_connect_event { |
1210 | __le16 ch; | 1273 | union { |
1211 | u8 bssid[ETH_ALEN]; | 1274 | struct { |
1212 | __le16 listen_intvl; | 1275 | __le16 ch; |
1213 | __le16 beacon_intvl; | 1276 | u8 bssid[ETH_ALEN]; |
1214 | __le32 nw_type; | 1277 | __le16 listen_intvl; |
1278 | __le16 beacon_intvl; | ||
1279 | __le32 nw_type; | ||
1280 | } sta; | ||
1281 | struct { | ||
1282 | u8 phymode; | ||
1283 | u8 aid; | ||
1284 | u8 mac_addr[ETH_ALEN]; | ||
1285 | u8 auth; | ||
1286 | u8 keymgmt; | ||
1287 | __le16 cipher; | ||
1288 | u8 apsd_info; | ||
1289 | u8 unused[3]; | ||
1290 | } ap_sta; | ||
1291 | struct { | ||
1292 | __le16 ch; | ||
1293 | u8 bssid[ETH_ALEN]; | ||
1294 | u8 unused[8]; | ||
1295 | } ap_bss; | ||
1296 | } u; | ||
1215 | u8 beacon_ie_len; | 1297 | u8 beacon_ie_len; |
1216 | u8 assoc_req_len; | 1298 | u8 assoc_req_len; |
1217 | u8 assoc_resp_len; | 1299 | u8 assoc_resp_len; |
@@ -1238,6 +1320,12 @@ enum wmi_disconnect_reason { | |||
1238 | IBSS_MERGE = 0xe, | 1320 | IBSS_MERGE = 0xe, |
1239 | }; | 1321 | }; |
1240 | 1322 | ||
1323 | #define ATH6KL_COUNTRY_RD_SHIFT 16 | ||
1324 | |||
1325 | struct ath6kl_wmi_regdomain { | ||
1326 | __le32 reg_code; | ||
1327 | }; | ||
1328 | |||
1241 | struct wmi_disconnect_event { | 1329 | struct wmi_disconnect_event { |
1242 | /* reason code, see 802.11 spec. */ | 1330 | /* reason code, see 802.11 spec. */ |
1243 | __le16 proto_reason_status; | 1331 | __le16 proto_reason_status; |
@@ -1265,33 +1353,54 @@ enum wmi_bi_ftype { | |||
1265 | PROBEREQ_FTYPE, | 1353 | PROBEREQ_FTYPE, |
1266 | }; | 1354 | }; |
1267 | 1355 | ||
1268 | struct wmi_bss_info_hdr { | 1356 | #define DEF_LRSSI_SCAN_PERIOD 5 |
1269 | __le16 ch; | 1357 | #define DEF_LRSSI_ROAM_THRESHOLD 20 |
1358 | #define DEF_LRSSI_ROAM_FLOOR 60 | ||
1359 | #define DEF_SCAN_FOR_ROAM_INTVL 2 | ||
1270 | 1360 | ||
1271 | /* see, enum wmi_bi_ftype */ | 1361 | enum wmi_roam_ctrl { |
1272 | u8 frame_type; | 1362 | WMI_FORCE_ROAM = 1, |
1363 | WMI_SET_ROAM_MODE, | ||
1364 | WMI_SET_HOST_BIAS, | ||
1365 | WMI_SET_LRSSI_SCAN_PARAMS, | ||
1366 | }; | ||
1273 | 1367 | ||
1274 | u8 snr; | 1368 | struct bss_bias { |
1275 | a_sle16 rssi; | ||
1276 | u8 bssid[ETH_ALEN]; | 1369 | u8 bssid[ETH_ALEN]; |
1277 | __le32 ie_mask; | 1370 | u8 bias; |
1278 | } __packed; | 1371 | } __packed; |
1279 | 1372 | ||
1280 | /* | 1373 | struct bss_bias_info { |
1281 | * BSS INFO HDR version 2.0 | 1374 | u8 num_bss; |
1282 | * With 6 bytes HTC header and 6 bytes of WMI header | 1375 | struct bss_bias bss_bias[1]; |
1283 | * WMI_BSS_INFO_HDR cannot be accommodated in the removed 802.11 management | 1376 | } __packed; |
1284 | * header space. | 1377 | |
1285 | * - Reduce the ie_mask to 2 bytes as only two bit flags are used | 1378 | struct low_rssi_scan_params { |
1286 | * - Remove rssi and compute it on the host. rssi = snr - 95 | 1379 | __le16 lrssi_scan_period; |
1287 | */ | 1380 | a_sle16 lrssi_scan_threshold; |
1381 | a_sle16 lrssi_roam_threshold; | ||
1382 | u8 roam_rssi_floor; | ||
1383 | u8 reserved[1]; | ||
1384 | } __packed; | ||
1385 | |||
1386 | struct roam_ctrl_cmd { | ||
1387 | union { | ||
1388 | u8 bssid[ETH_ALEN]; | ||
1389 | u8 roam_mode; | ||
1390 | struct bss_bias_info bss; | ||
1391 | struct low_rssi_scan_params params; | ||
1392 | } __packed info; | ||
1393 | u8 roam_ctrl; | ||
1394 | } __packed; | ||
1395 | |||
1396 | /* BSS INFO HDR version 2.0 */ | ||
1288 | struct wmi_bss_info_hdr2 { | 1397 | struct wmi_bss_info_hdr2 { |
1289 | __le16 ch; | 1398 | __le16 ch; /* frequency in MHz */ |
1290 | 1399 | ||
1291 | /* see, enum wmi_bi_ftype */ | 1400 | /* see, enum wmi_bi_ftype */ |
1292 | u8 frame_type; | 1401 | u8 frame_type; |
1293 | 1402 | ||
1294 | u8 snr; | 1403 | u8 snr; /* note: rssi = snr - 95 dBm */ |
1295 | u8 bssid[ETH_ALEN]; | 1404 | u8 bssid[ETH_ALEN]; |
1296 | __le16 ie_mask; | 1405 | __le16 ie_mask; |
1297 | } __packed; | 1406 | } __packed; |
@@ -1330,6 +1439,16 @@ enum wmi_bss_flags { | |||
1330 | WMI_PMKID_VALID_BSS = 0x02, | 1439 | WMI_PMKID_VALID_BSS = 0x02, |
1331 | }; | 1440 | }; |
1332 | 1441 | ||
1442 | struct wmi_neighbor_info { | ||
1443 | u8 bssid[ETH_ALEN]; | ||
1444 | u8 bss_flags; /* enum wmi_bss_flags */ | ||
1445 | } __packed; | ||
1446 | |||
1447 | struct wmi_neighbor_report_event { | ||
1448 | u8 num_neighbors; | ||
1449 | struct wmi_neighbor_info neighbor[0]; | ||
1450 | } __packed; | ||
1451 | |||
1333 | /* TKIP MIC Error Event */ | 1452 | /* TKIP MIC Error Event */ |
1334 | struct wmi_tkip_micerr_event { | 1453 | struct wmi_tkip_micerr_event { |
1335 | u8 key_id; | 1454 | u8 key_id; |
@@ -1642,6 +1761,12 @@ struct wmi_get_keepalive_cmd { | |||
1642 | u8 keep_alive_intvl; | 1761 | u8 keep_alive_intvl; |
1643 | } __packed; | 1762 | } __packed; |
1644 | 1763 | ||
1764 | struct wmi_set_appie_cmd { | ||
1765 | u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */ | ||
1766 | u8 ie_len; | ||
1767 | u8 ie_info[0]; | ||
1768 | } __packed; | ||
1769 | |||
1645 | /* Notify the WSC registration status to the target */ | 1770 | /* Notify the WSC registration status to the target */ |
1646 | #define WSC_REG_ACTIVE 1 | 1771 | #define WSC_REG_ACTIVE 1 |
1647 | #define WSC_REG_INACTIVE 0 | 1772 | #define WSC_REG_INACTIVE 0 |
@@ -1789,8 +1914,26 @@ struct wmi_tx_complete_event { | |||
1789 | 1914 | ||
1790 | /* Used with WMI_AP_SET_NUM_STA_CMDID */ | 1915 | /* Used with WMI_AP_SET_NUM_STA_CMDID */ |
1791 | 1916 | ||
1917 | /* | ||
1918 | * Used with WMI_AP_SET_MLME_CMDID | ||
1919 | */ | ||
1920 | |||
1921 | /* MLME Commands */ | ||
1922 | #define WMI_AP_MLME_ASSOC 1 /* associate station */ | ||
1923 | #define WMI_AP_DISASSOC 2 /* disassociate station */ | ||
1924 | #define WMI_AP_DEAUTH 3 /* deauthenticate station */ | ||
1925 | #define WMI_AP_MLME_AUTHORIZE 4 /* authorize station */ | ||
1926 | #define WMI_AP_MLME_UNAUTHORIZE 5 /* unauthorize station */ | ||
1927 | |||
1928 | struct wmi_ap_set_mlme_cmd { | ||
1929 | u8 mac[ETH_ALEN]; | ||
1930 | __le16 reason; /* 802.11 reason code */ | ||
1931 | u8 cmd; /* operation to perform (WMI_AP_*) */ | ||
1932 | } __packed; | ||
1933 | |||
1792 | struct wmi_ap_set_pvb_cmd { | 1934 | struct wmi_ap_set_pvb_cmd { |
1793 | __le32 flag; | 1935 | __le32 flag; |
1936 | __le16 rsvd; | ||
1794 | __le16 aid; | 1937 | __le16 aid; |
1795 | } __packed; | 1938 | } __packed; |
1796 | 1939 | ||
@@ -1840,6 +1983,100 @@ struct wmi_ap_mode_stat { | |||
1840 | 1983 | ||
1841 | /* End of AP mode definitions */ | 1984 | /* End of AP mode definitions */ |
1842 | 1985 | ||
1986 | struct wmi_remain_on_chnl_cmd { | ||
1987 | __le32 freq; | ||
1988 | __le32 duration; | ||
1989 | } __packed; | ||
1990 | |||
1991 | struct wmi_send_action_cmd { | ||
1992 | __le32 id; | ||
1993 | __le32 freq; | ||
1994 | __le32 wait; | ||
1995 | __le16 len; | ||
1996 | u8 data[0]; | ||
1997 | } __packed; | ||
1998 | |||
1999 | struct wmi_tx_status_event { | ||
2000 | __le32 id; | ||
2001 | u8 ack_status; | ||
2002 | } __packed; | ||
2003 | |||
2004 | struct wmi_probe_req_report_cmd { | ||
2005 | u8 enable; | ||
2006 | } __packed; | ||
2007 | |||
2008 | struct wmi_disable_11b_rates_cmd { | ||
2009 | u8 disable; | ||
2010 | } __packed; | ||
2011 | |||
2012 | struct wmi_set_appie_extended_cmd { | ||
2013 | u8 role_id; | ||
2014 | u8 mgmt_frm_type; | ||
2015 | u8 ie_len; | ||
2016 | u8 ie_info[0]; | ||
2017 | } __packed; | ||
2018 | |||
2019 | struct wmi_remain_on_chnl_event { | ||
2020 | __le32 freq; | ||
2021 | __le32 duration; | ||
2022 | } __packed; | ||
2023 | |||
2024 | struct wmi_cancel_remain_on_chnl_event { | ||
2025 | __le32 freq; | ||
2026 | __le32 duration; | ||
2027 | u8 status; | ||
2028 | } __packed; | ||
2029 | |||
2030 | struct wmi_rx_action_event { | ||
2031 | __le32 freq; | ||
2032 | __le16 len; | ||
2033 | u8 data[0]; | ||
2034 | } __packed; | ||
2035 | |||
2036 | struct wmi_p2p_capabilities_event { | ||
2037 | __le16 len; | ||
2038 | u8 data[0]; | ||
2039 | } __packed; | ||
2040 | |||
2041 | struct wmi_p2p_rx_probe_req_event { | ||
2042 | __le32 freq; | ||
2043 | __le16 len; | ||
2044 | u8 data[0]; | ||
2045 | } __packed; | ||
2046 | |||
2047 | #define P2P_FLAG_CAPABILITIES_REQ (0x00000001) | ||
2048 | #define P2P_FLAG_MACADDR_REQ (0x00000002) | ||
2049 | #define P2P_FLAG_HMODEL_REQ (0x00000002) | ||
2050 | |||
2051 | struct wmi_get_p2p_info { | ||
2052 | __le32 info_req_flags; | ||
2053 | } __packed; | ||
2054 | |||
2055 | struct wmi_p2p_info_event { | ||
2056 | __le32 info_req_flags; | ||
2057 | __le16 len; | ||
2058 | u8 data[0]; | ||
2059 | } __packed; | ||
2060 | |||
2061 | struct wmi_p2p_capabilities { | ||
2062 | u8 go_power_save; | ||
2063 | } __packed; | ||
2064 | |||
2065 | struct wmi_p2p_macaddr { | ||
2066 | u8 mac_addr[ETH_ALEN]; | ||
2067 | } __packed; | ||
2068 | |||
2069 | struct wmi_p2p_hmodel { | ||
2070 | u8 p2p_model; | ||
2071 | } __packed; | ||
2072 | |||
2073 | struct wmi_p2p_probe_response_cmd { | ||
2074 | __le32 freq; | ||
2075 | u8 destination_addr[ETH_ALEN]; | ||
2076 | __le16 len; | ||
2077 | u8 data[0]; | ||
2078 | } __packed; | ||
2079 | |||
1843 | /* Extended WMI (WMIX) | 2080 | /* Extended WMI (WMIX) |
1844 | * | 2081 | * |
1845 | * Extended WMIX commands are encapsulated in a WMI message with | 2082 | * Extended WMIX commands are encapsulated in a WMI message with |
@@ -1898,6 +2135,11 @@ struct wmix_hb_challenge_resp_cmd { | |||
1898 | __le32 source; | 2135 | __le32 source; |
1899 | } __packed; | 2136 | } __packed; |
1900 | 2137 | ||
2138 | struct ath6kl_wmix_dbglog_cfg_module_cmd { | ||
2139 | __le32 valid; | ||
2140 | __le32 config; | ||
2141 | } __packed; | ||
2142 | |||
1901 | /* End of Extended WMI (WMIX) */ | 2143 | /* End of Extended WMI (WMIX) */ |
1902 | 2144 | ||
1903 | enum wmi_sync_flag { | 2145 | enum wmi_sync_flag { |
@@ -1925,14 +2167,11 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, | |||
1925 | 2167 | ||
1926 | int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb); | 2168 | int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb); |
1927 | int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb); | 2169 | int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb); |
1928 | int ath6kl_wmi_data_hdr_remove(struct wmi *wmi, struct sk_buff *skb); | ||
1929 | int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb, | 2170 | int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb, |
1930 | u32 layer2_priority, bool wmm_enabled, | 2171 | u32 layer2_priority, bool wmm_enabled, |
1931 | u8 *ac); | 2172 | u8 *ac); |
1932 | 2173 | ||
1933 | int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb); | 2174 | int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb); |
1934 | struct bss *ath6kl_wmi_find_node(struct wmi *wmi, const u8 *mac_addr); | ||
1935 | void ath6kl_wmi_node_free(struct wmi *wmi, const u8 *mac_addr); | ||
1936 | 2175 | ||
1937 | int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb, | 2176 | int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb, |
1938 | enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag); | 2177 | enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag); |
@@ -1978,6 +2217,7 @@ int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status, | |||
1978 | u8 preamble_policy); | 2217 | u8 preamble_policy); |
1979 | 2218 | ||
1980 | int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source); | 2219 | int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source); |
2220 | int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config); | ||
1981 | 2221 | ||
1982 | int ath6kl_wmi_get_stats_cmd(struct wmi *wmi); | 2222 | int ath6kl_wmi_get_stats_cmd(struct wmi *wmi); |
1983 | int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index, | 2223 | int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index, |
@@ -1995,23 +2235,47 @@ int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi); | |||
1995 | 2235 | ||
1996 | int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg); | 2236 | int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg); |
1997 | int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl); | 2237 | int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl); |
2238 | int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); | ||
1998 | 2239 | ||
1999 | s32 ath6kl_wmi_get_rate(s8 rate_index); | 2240 | s32 ath6kl_wmi_get_rate(s8 rate_index); |
2000 | 2241 | ||
2001 | int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd); | 2242 | int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd); |
2243 | int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); | ||
2002 | 2244 | ||
2003 | struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 *ssid, | 2245 | /* AP mode */ |
2004 | u32 ssid_len, bool is_wpa2, | 2246 | int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p); |
2005 | bool match_ssid); | ||
2006 | 2247 | ||
2007 | void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss); | 2248 | int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 cmd, const u8 *mac, u16 reason); |
2008 | 2249 | ||
2009 | /* AP mode */ | ||
2010 | int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag); | 2250 | int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag); |
2011 | 2251 | ||
2012 | int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version, | 2252 | int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version, |
2013 | bool rx_dot11_hdr, bool defrag_on_host); | 2253 | bool rx_dot11_hdr, bool defrag_on_host); |
2014 | 2254 | ||
2255 | int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie, | ||
2256 | u8 ie_len); | ||
2257 | |||
2258 | /* P2P */ | ||
2259 | int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); | ||
2260 | |||
2261 | int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u32 freq, u32 dur); | ||
2262 | |||
2263 | int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait, | ||
2264 | const u8 *data, u16 data_len); | ||
2265 | |||
2266 | int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u32 freq, | ||
2267 | const u8 *dst, | ||
2268 | const u8 *data, u16 data_len); | ||
2269 | |||
2270 | int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, bool enable); | ||
2271 | |||
2272 | int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags); | ||
2273 | |||
2274 | int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi); | ||
2275 | |||
2276 | int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie, | ||
2277 | u8 ie_len); | ||
2278 | |||
2015 | void *ath6kl_wmi_init(struct ath6kl *devt); | 2279 | void *ath6kl_wmi_init(struct ath6kl *devt); |
2016 | void ath6kl_wmi_shutdown(struct wmi *wmi); | 2280 | void ath6kl_wmi_shutdown(struct wmi *wmi); |
2017 | 2281 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 94d887b65e69..1e8614783181 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -340,7 +340,8 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); | |||
340 | void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); | 340 | void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); |
341 | 341 | ||
342 | void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); | 342 | void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); |
343 | bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an); | 343 | void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, |
344 | struct ath_node *an); | ||
344 | 345 | ||
345 | /********/ | 346 | /********/ |
346 | /* VIFs */ | 347 | /* VIFs */ |
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index a3c7d0c247a3..5d92f96980e6 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h | |||
@@ -104,16 +104,11 @@ | |||
104 | #define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_11_OR_LATER(ah) && \ | 104 | #define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_11_OR_LATER(ah) && \ |
105 | ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) | 105 | ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) |
106 | 106 | ||
107 | #define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c | ||
108 | #define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 | ||
109 | #define AR_EEPROM_RFSILENT_POLARITY 0x0002 | ||
110 | #define AR_EEPROM_RFSILENT_POLARITY_S 1 | ||
111 | |||
112 | #define EEP_RFSILENT_ENABLED 0x0001 | 107 | #define EEP_RFSILENT_ENABLED 0x0001 |
113 | #define EEP_RFSILENT_ENABLED_S 0 | 108 | #define EEP_RFSILENT_ENABLED_S 0 |
114 | #define EEP_RFSILENT_POLARITY 0x0002 | 109 | #define EEP_RFSILENT_POLARITY 0x0002 |
115 | #define EEP_RFSILENT_POLARITY_S 1 | 110 | #define EEP_RFSILENT_POLARITY_S 1 |
116 | #define EEP_RFSILENT_GPIO_SEL 0x001c | 111 | #define EEP_RFSILENT_GPIO_SEL (AR_SREV_9480(ah) ? 0x00fc : 0x001c) |
117 | #define EEP_RFSILENT_GPIO_SEL_S 2 | 112 | #define EEP_RFSILENT_GPIO_SEL_S 2 |
118 | 113 | ||
119 | #define AR5416_OPFLAGS_11A 0x01 | 114 | #define AR5416_OPFLAGS_11A 0x01 |
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index afbf5400a52a..fd0f84ebdb51 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c | |||
@@ -84,9 +84,14 @@ void ath_init_leds(struct ath_softc *sc) | |||
84 | static bool ath_is_rfkill_set(struct ath_softc *sc) | 84 | static bool ath_is_rfkill_set(struct ath_softc *sc) |
85 | { | 85 | { |
86 | struct ath_hw *ah = sc->sc_ah; | 86 | struct ath_hw *ah = sc->sc_ah; |
87 | bool is_blocked; | ||
87 | 88 | ||
88 | return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == | 89 | ath9k_ps_wakeup(sc); |
90 | is_blocked = ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == | ||
89 | ah->rfkill_polarity; | 91 | ah->rfkill_polarity; |
92 | ath9k_ps_restore(sc); | ||
93 | |||
94 | return is_blocked; | ||
90 | } | 95 | } |
91 | 96 | ||
92 | void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) | 97 | void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) |
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index d3f4a59cd456..77c8ded8de57 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c | |||
@@ -38,6 +38,7 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { | |||
38 | { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */ | 38 | { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */ |
39 | { USB_DEVICE(0x040D, 0x3801) }, /* VIA */ | 39 | { USB_DEVICE(0x040D, 0x3801) }, /* VIA */ |
40 | { USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */ | 40 | { USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */ |
41 | { USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */ | ||
41 | 42 | ||
42 | { USB_DEVICE(0x0cf3, 0x7015), | 43 | { USB_DEVICE(0x0cf3, 0x7015), |
43 | .driver_info = AR9287_USB }, /* Atheros */ | 44 | .driver_info = AR9287_USB }, /* Atheros */ |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index db2352e5cc0d..e3a02eb8e0cc 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c | |||
@@ -228,8 +228,14 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv) | |||
228 | 228 | ||
229 | static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv) | 229 | static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv) |
230 | { | 230 | { |
231 | return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) == | 231 | bool is_blocked; |
232 | priv->ah->rfkill_polarity; | 232 | |
233 | ath9k_htc_ps_wakeup(priv); | ||
234 | is_blocked = ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) == | ||
235 | priv->ah->rfkill_polarity; | ||
236 | ath9k_htc_ps_restore(priv); | ||
237 | |||
238 | return is_blocked; | ||
233 | } | 239 | } |
234 | 240 | ||
235 | void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw) | 241 | void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw) |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 17dbbd9d2f53..0b9a0e8a4958 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -1352,7 +1352,8 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, | |||
1352 | return ret; | 1352 | return ret; |
1353 | } | 1353 | } |
1354 | 1354 | ||
1355 | static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue, | 1355 | static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, |
1356 | struct ieee80211_vif *vif, u16 queue, | ||
1356 | const struct ieee80211_tx_queue_params *params) | 1357 | const struct ieee80211_tx_queue_params *params) |
1357 | { | 1358 | { |
1358 | struct ath9k_htc_priv *priv = hw->priv; | 1359 | struct ath9k_htc_priv *priv = hw->priv; |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f2de7ee047ce..42ebe8fb053a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -284,7 +284,12 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) | |||
284 | ah->hw_version.macVersion = | 284 | ah->hw_version.macVersion = |
285 | (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; | 285 | (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; |
286 | ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); | 286 | ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); |
287 | ah->is_pciexpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; | 287 | |
288 | if (AR_SREV_9480(ah)) | ||
289 | ah->is_pciexpress = true; | ||
290 | else | ||
291 | ah->is_pciexpress = (val & | ||
292 | AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; | ||
288 | } else { | 293 | } else { |
289 | if (!AR_SREV_9100(ah)) | 294 | if (!AR_SREV_9100(ah)) |
290 | ah->hw_version.macVersion = MS(val, AR_SREV_VERSION); | 295 | ah->hw_version.macVersion = MS(val, AR_SREV_VERSION); |
@@ -2153,6 +2158,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
2153 | pCap->num_gpio_pins = AR9271_NUM_GPIO; | 2158 | pCap->num_gpio_pins = AR9271_NUM_GPIO; |
2154 | else if (AR_DEVID_7010(ah)) | 2159 | else if (AR_DEVID_7010(ah)) |
2155 | pCap->num_gpio_pins = AR7010_NUM_GPIO; | 2160 | pCap->num_gpio_pins = AR7010_NUM_GPIO; |
2161 | else if (AR_SREV_9300_20_OR_LATER(ah)) | ||
2162 | pCap->num_gpio_pins = AR9300_NUM_GPIO; | ||
2163 | else if (AR_SREV_9287_11_OR_LATER(ah)) | ||
2164 | pCap->num_gpio_pins = AR9287_NUM_GPIO; | ||
2156 | else if (AR_SREV_9285_12_OR_LATER(ah)) | 2165 | else if (AR_SREV_9285_12_OR_LATER(ah)) |
2157 | pCap->num_gpio_pins = AR9285_NUM_GPIO; | 2166 | pCap->num_gpio_pins = AR9285_NUM_GPIO; |
2158 | else if (AR_SREV_9280_20_OR_LATER(ah)) | 2167 | else if (AR_SREV_9280_20_OR_LATER(ah)) |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index edaa7843bf4c..988318665758 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1833,8 +1833,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, | |||
1833 | switch (cmd) { | 1833 | switch (cmd) { |
1834 | case STA_NOTIFY_SLEEP: | 1834 | case STA_NOTIFY_SLEEP: |
1835 | an->sleeping = true; | 1835 | an->sleeping = true; |
1836 | if (ath_tx_aggr_sleep(sc, an)) | 1836 | ath_tx_aggr_sleep(sta, sc, an); |
1837 | ieee80211_sta_set_tim(sta); | ||
1838 | break; | 1837 | break; |
1839 | case STA_NOTIFY_AWAKE: | 1838 | case STA_NOTIFY_AWAKE: |
1840 | an->sleeping = false; | 1839 | an->sleeping = false; |
@@ -1843,7 +1842,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, | |||
1843 | } | 1842 | } |
1844 | } | 1843 | } |
1845 | 1844 | ||
1846 | static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, | 1845 | static int ath9k_conf_tx(struct ieee80211_hw *hw, |
1846 | struct ieee80211_vif *vif, u16 queue, | ||
1847 | const struct ieee80211_tx_queue_params *params) | 1847 | const struct ieee80211_tx_queue_params *params) |
1848 | { | 1848 | { |
1849 | struct ath_softc *sc = hw->priv; | 1849 | struct ath_softc *sc = hw->priv; |
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 4f1301881137..8448281dd069 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c | |||
@@ -1362,12 +1362,6 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
1362 | if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) | 1362 | if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) |
1363 | return; | 1363 | return; |
1364 | 1364 | ||
1365 | if (!(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) { | ||
1366 | tx_info->status.ampdu_ack_len = | ||
1367 | (tx_info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0); | ||
1368 | tx_info->status.ampdu_len = 1; | ||
1369 | } | ||
1370 | |||
1371 | if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) | 1365 | if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) |
1372 | tx_status = 1; | 1366 | tx_status = 1; |
1373 | 1367 | ||
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 49843500fe7c..f658ec60b510 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -586,22 +586,11 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) | |||
586 | 586 | ||
587 | static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) | 587 | static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) |
588 | { | 588 | { |
589 | struct ieee80211_mgmt *mgmt; | ||
590 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 589 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
591 | 590 | ||
592 | if (skb->len < 24 + 8 + 2 + 2) | 591 | if (skb->len < 24 + 8 + 2 + 2) |
593 | return; | 592 | return; |
594 | 593 | ||
595 | mgmt = (struct ieee80211_mgmt *)skb->data; | ||
596 | if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) { | ||
597 | /* TODO: This doesn't work well if you have stations | ||
598 | * associated to two different APs because curbssid | ||
599 | * is just the last AP that any of the stations associated | ||
600 | * with. | ||
601 | */ | ||
602 | return; /* not from our current AP */ | ||
603 | } | ||
604 | |||
605 | sc->ps_flags &= ~PS_WAIT_FOR_BEACON; | 594 | sc->ps_flags &= ~PS_WAIT_FOR_BEACON; |
606 | 595 | ||
607 | if (sc->ps_flags & PS_BEACON_SYNC) { | 596 | if (sc->ps_flags & PS_BEACON_SYNC) { |
@@ -637,7 +626,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) | |||
637 | } | 626 | } |
638 | } | 627 | } |
639 | 628 | ||
640 | static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) | 629 | static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon) |
641 | { | 630 | { |
642 | struct ieee80211_hdr *hdr; | 631 | struct ieee80211_hdr *hdr; |
643 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 632 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
@@ -646,7 +635,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) | |||
646 | 635 | ||
647 | /* Process Beacon and CAB receive in PS state */ | 636 | /* Process Beacon and CAB receive in PS state */ |
648 | if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc)) | 637 | if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc)) |
649 | && ieee80211_is_beacon(hdr->frame_control)) | 638 | && mybeacon) |
650 | ath_rx_ps_beacon(sc, skb); | 639 | ath_rx_ps_beacon(sc, skb); |
651 | else if ((sc->ps_flags & PS_WAIT_FOR_CAB) && | 640 | else if ((sc->ps_flags & PS_WAIT_FOR_CAB) && |
652 | (ieee80211_is_data(hdr->frame_control) || | 641 | (ieee80211_is_data(hdr->frame_control) || |
@@ -1952,10 +1941,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) | |||
1952 | spin_lock_irqsave(&sc->sc_pm_lock, flags); | 1941 | spin_lock_irqsave(&sc->sc_pm_lock, flags); |
1953 | 1942 | ||
1954 | if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | | 1943 | if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | |
1955 | PS_WAIT_FOR_CAB | | 1944 | PS_WAIT_FOR_CAB | |
1956 | PS_WAIT_FOR_PSPOLL_DATA)) || | 1945 | PS_WAIT_FOR_PSPOLL_DATA)) || |
1957 | ath9k_check_auto_sleep(sc)) | 1946 | ath9k_check_auto_sleep(sc)) |
1958 | ath_rx_ps(sc, skb); | 1947 | ath_rx_ps(sc, skb, rs.is_mybeacon); |
1959 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | 1948 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); |
1960 | 1949 | ||
1961 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3) | 1950 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3) |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index fa3dcfdf7174..c2bfc57958d8 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -542,7 +542,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
542 | /* prepend un-acked frames to the beginning of the pending frame queue */ | 542 | /* prepend un-acked frames to the beginning of the pending frame queue */ |
543 | if (!skb_queue_empty(&bf_pending)) { | 543 | if (!skb_queue_empty(&bf_pending)) { |
544 | if (an->sleeping) | 544 | if (an->sleeping) |
545 | ieee80211_sta_set_tim(sta); | 545 | ieee80211_sta_set_buffered(sta, tid->tidno, true); |
546 | 546 | ||
547 | spin_lock_bh(&txq->axq_lock); | 547 | spin_lock_bh(&txq->axq_lock); |
548 | if (clear_filter) | 548 | if (clear_filter) |
@@ -1153,12 +1153,13 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) | |||
1153 | ath_tx_flush_tid(sc, txtid); | 1153 | ath_tx_flush_tid(sc, txtid); |
1154 | } | 1154 | } |
1155 | 1155 | ||
1156 | bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) | 1156 | void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, |
1157 | struct ath_node *an) | ||
1157 | { | 1158 | { |
1158 | struct ath_atx_tid *tid; | 1159 | struct ath_atx_tid *tid; |
1159 | struct ath_atx_ac *ac; | 1160 | struct ath_atx_ac *ac; |
1160 | struct ath_txq *txq; | 1161 | struct ath_txq *txq; |
1161 | bool buffered = false; | 1162 | bool buffered; |
1162 | int tidno; | 1163 | int tidno; |
1163 | 1164 | ||
1164 | for (tidno = 0, tid = &an->tid[tidno]; | 1165 | for (tidno = 0, tid = &an->tid[tidno]; |
@@ -1172,8 +1173,7 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) | |||
1172 | 1173 | ||
1173 | spin_lock_bh(&txq->axq_lock); | 1174 | spin_lock_bh(&txq->axq_lock); |
1174 | 1175 | ||
1175 | if (!skb_queue_empty(&tid->buf_q)) | 1176 | buffered = !skb_queue_empty(&tid->buf_q); |
1176 | buffered = true; | ||
1177 | 1177 | ||
1178 | tid->sched = false; | 1178 | tid->sched = false; |
1179 | list_del(&tid->list); | 1179 | list_del(&tid->list); |
@@ -1184,9 +1184,9 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) | |||
1184 | } | 1184 | } |
1185 | 1185 | ||
1186 | spin_unlock_bh(&txq->axq_lock); | 1186 | spin_unlock_bh(&txq->axq_lock); |
1187 | } | ||
1188 | 1187 | ||
1189 | return buffered; | 1188 | ieee80211_sta_set_buffered(sta, tidno, buffered); |
1189 | } | ||
1190 | } | 1190 | } |
1191 | 1191 | ||
1192 | void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) | 1192 | void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) |
@@ -2043,10 +2043,9 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, | |||
2043 | tx_info->flags |= IEEE80211_TX_STAT_AMPDU; | 2043 | tx_info->flags |= IEEE80211_TX_STAT_AMPDU; |
2044 | 2044 | ||
2045 | BUG_ON(nbad > nframes); | 2045 | BUG_ON(nbad > nframes); |
2046 | |||
2047 | tx_info->status.ampdu_len = nframes; | ||
2048 | tx_info->status.ampdu_ack_len = nframes - nbad; | ||
2049 | } | 2046 | } |
2047 | tx_info->status.ampdu_len = nframes; | ||
2048 | tx_info->status.ampdu_ack_len = nframes - nbad; | ||
2050 | 2049 | ||
2051 | if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && | 2050 | if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && |
2052 | (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0) { | 2051 | (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0) { |
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 8b780d6d470f..beca71073e9b 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c | |||
@@ -1305,7 +1305,8 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw, | |||
1305 | return 0; | 1305 | return 0; |
1306 | } | 1306 | } |
1307 | 1307 | ||
1308 | static int carl9170_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | 1308 | static int carl9170_op_conf_tx(struct ieee80211_hw *hw, |
1309 | struct ieee80211_vif *vif, u16 queue, | ||
1309 | const struct ieee80211_tx_queue_params *param) | 1310 | const struct ieee80211_tx_queue_params *param) |
1310 | { | 1311 | { |
1311 | struct ar9170 *ar = hw->priv; | 1312 | struct ar9170 *ar = hw->priv; |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 43400fb62e1c..7cf4125a1624 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -3559,7 +3559,8 @@ static void b43_qos_init(struct b43_wldev *dev) | |||
3559 | b43dbg(dev->wl, "QoS enabled\n"); | 3559 | b43dbg(dev->wl, "QoS enabled\n"); |
3560 | } | 3560 | } |
3561 | 3561 | ||
3562 | static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, | 3562 | static int b43_op_conf_tx(struct ieee80211_hw *hw, |
3563 | struct ieee80211_vif *vif, u16 _queue, | ||
3563 | const struct ieee80211_tx_queue_params *params) | 3564 | const struct ieee80211_tx_queue_params *params) |
3564 | { | 3565 | { |
3565 | struct b43_wl *wl = hw_to_b43_wl(hw); | 3566 | struct b43_wl *wl = hw_to_b43_wl(hw); |
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 468d1836548e..a3b72cd72c66 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c | |||
@@ -2466,7 +2466,8 @@ out: | |||
2466 | } | 2466 | } |
2467 | } | 2467 | } |
2468 | 2468 | ||
2469 | static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | 2469 | static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, |
2470 | struct ieee80211_vif *vif, u16 queue, | ||
2470 | const struct ieee80211_tx_queue_params *params) | 2471 | const struct ieee80211_tx_queue_params *params) |
2471 | { | 2472 | { |
2472 | return 0; | 2473 | return 0; |
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c index ac4f64de1363..7f12e3638bae 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c | |||
@@ -335,7 +335,7 @@ int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
335 | sta_priv = (void *)sta->drv_priv; | 335 | sta_priv = (void *)sta->drv_priv; |
336 | 336 | ||
337 | if (sta_priv && sta_priv->asleep && | 337 | if (sta_priv && sta_priv->asleep && |
338 | (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) { | 338 | (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) { |
339 | /* | 339 | /* |
340 | * This sends an asynchronous command to the device, | 340 | * This sends an asynchronous command to the device, |
341 | * but we can rely on it being processed before the | 341 | * but we can rely on it being processed before the |
diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 8928d47432df..2bd5659310d7 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c | |||
@@ -1250,7 +1250,8 @@ void iwl_legacy_clear_isr_stats(struct iwl_priv *priv) | |||
1250 | memset(&priv->isr_stats, 0, sizeof(priv->isr_stats)); | 1250 | memset(&priv->isr_stats, 0, sizeof(priv->isr_stats)); |
1251 | } | 1251 | } |
1252 | 1252 | ||
1253 | int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, | 1253 | int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, |
1254 | struct ieee80211_vif *vif, u16 queue, | ||
1254 | const struct ieee80211_tx_queue_params *params) | 1255 | const struct ieee80211_tx_queue_params *params) |
1255 | { | 1256 | { |
1256 | struct iwl_priv *priv = hw->priv; | 1257 | struct iwl_priv *priv = hw->priv; |
diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h index b2df01c8f8f5..d1271fe07d4b 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.h +++ b/drivers/net/wireless/iwlegacy/iwl-core.h | |||
@@ -286,7 +286,8 @@ struct iwl_cfg { | |||
286 | ***************************/ | 286 | ***************************/ |
287 | 287 | ||
288 | struct ieee80211_hw *iwl_legacy_alloc_all(struct iwl_cfg *cfg); | 288 | struct ieee80211_hw *iwl_legacy_alloc_all(struct iwl_cfg *cfg); |
289 | int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, | 289 | int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, |
290 | struct ieee80211_vif *vif, u16 queue, | ||
290 | const struct ieee80211_tx_queue_params *params); | 291 | const struct ieee80211_tx_queue_params *params); |
291 | int iwl_legacy_mac_tx_last_beacon(struct ieee80211_hw *hw); | 292 | int iwl_legacy_mac_tx_last_beacon(struct ieee80211_hw *hw); |
292 | void iwl_legacy_set_rxon_hwcrypto(struct iwl_priv *priv, | 293 | void iwl_legacy_set_rxon_hwcrypto(struct iwl_priv *priv, |
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 1d7572f9887f..e0441033788c 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | config IWLAGN | 1 | config IWLWIFI |
2 | tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlagn) " | 2 | tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) " |
3 | depends on PCI && MAC80211 | 3 | depends on PCI && MAC80211 |
4 | select FW_LOADER | 4 | select FW_LOADER |
5 | select NEW_LEDS | 5 | select NEW_LEDS |
@@ -39,14 +39,14 @@ config IWLAGN | |||
39 | If you want to compile the driver as a module ( = code which can be | 39 | If you want to compile the driver as a module ( = code which can be |
40 | inserted in and removed from the running kernel whenever you want), | 40 | inserted in and removed from the running kernel whenever you want), |
41 | say M here and read <file:Documentation/kbuild/modules.txt>. The | 41 | say M here and read <file:Documentation/kbuild/modules.txt>. The |
42 | module will be called iwlagn. | 42 | module will be called iwlwifi. |
43 | 43 | ||
44 | menu "Debugging Options" | 44 | menu "Debugging Options" |
45 | depends on IWLAGN | 45 | depends on IWLWIFI |
46 | 46 | ||
47 | config IWLWIFI_DEBUG | 47 | config IWLWIFI_DEBUG |
48 | bool "Enable full debugging output in the iwlagn driver" | 48 | bool "Enable full debugging output in the iwlwifi driver" |
49 | depends on IWLAGN | 49 | depends on IWLWIFI |
50 | ---help--- | 50 | ---help--- |
51 | This option will enable debug tracing output for the iwlwifi drivers | 51 | This option will enable debug tracing output for the iwlwifi drivers |
52 | 52 | ||
@@ -70,8 +70,8 @@ config IWLWIFI_DEBUG | |||
70 | any problems you may encounter. | 70 | any problems you may encounter. |
71 | 71 | ||
72 | config IWLWIFI_DEBUGFS | 72 | config IWLWIFI_DEBUGFS |
73 | bool "iwlagn debugfs support" | 73 | bool "iwlwifi debugfs support" |
74 | depends on IWLAGN && MAC80211_DEBUGFS | 74 | depends on IWLWIFI && MAC80211_DEBUGFS |
75 | ---help--- | 75 | ---help--- |
76 | Enable creation of debugfs files for the iwlwifi drivers. This | 76 | Enable creation of debugfs files for the iwlwifi drivers. This |
77 | is a low-impact option that allows getting insight into the | 77 | is a low-impact option that allows getting insight into the |
@@ -79,13 +79,13 @@ config IWLWIFI_DEBUGFS | |||
79 | 79 | ||
80 | config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE | 80 | config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE |
81 | bool "Experimental uCode support" | 81 | bool "Experimental uCode support" |
82 | depends on IWLAGN && IWLWIFI_DEBUG | 82 | depends on IWLWIFI && IWLWIFI_DEBUG |
83 | ---help--- | 83 | ---help--- |
84 | Enable use of experimental ucode for testing and debugging. | 84 | Enable use of experimental ucode for testing and debugging. |
85 | 85 | ||
86 | config IWLWIFI_DEVICE_TRACING | 86 | config IWLWIFI_DEVICE_TRACING |
87 | bool "iwlwifi device access tracing" | 87 | bool "iwlwifi device access tracing" |
88 | depends on IWLAGN | 88 | depends on IWLWIFI |
89 | depends on EVENT_TRACING | 89 | depends on EVENT_TRACING |
90 | help | 90 | help |
91 | Say Y here to trace all commands, including TX frames and IO | 91 | Say Y here to trace all commands, including TX frames and IO |
@@ -104,7 +104,7 @@ endmenu | |||
104 | 104 | ||
105 | config IWLWIFI_DEVICE_SVTOOL | 105 | config IWLWIFI_DEVICE_SVTOOL |
106 | bool "iwlwifi device svtool support" | 106 | bool "iwlwifi device svtool support" |
107 | depends on IWLAGN | 107 | depends on IWLWIFI |
108 | select NL80211_TESTMODE | 108 | select NL80211_TESTMODE |
109 | help | 109 | help |
110 | This option enables the svtool support for iwlwifi device through | 110 | This option enables the svtool support for iwlwifi device through |
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 8fa59cdb3b49..bacafa4a5f48 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile | |||
@@ -1,25 +1,25 @@ | |||
1 | # AGN | 1 | # WIFI |
2 | obj-$(CONFIG_IWLAGN) += iwlagn.o | 2 | obj-$(CONFIG_IWLWIFI) += iwlwifi.o |
3 | iwlagn-objs := iwl-agn.o iwl-agn-rs.o | 3 | iwlwifi-objs := iwl-agn.o iwl-agn-rs.o |
4 | iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o | 4 | iwlwifi-objs += iwl-agn-ucode.o iwl-agn-tx.o |
5 | iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o | 5 | iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o |
6 | iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o | 6 | iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o |
7 | 7 | ||
8 | iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-power.o | 8 | iwlwifi-objs += iwl-core.o iwl-eeprom.o iwl-power.o |
9 | iwlagn-objs += iwl-rx.o iwl-sta.o | 9 | iwlwifi-objs += iwl-rx.o iwl-sta.o |
10 | iwlagn-objs += iwl-scan.o iwl-led.o | 10 | iwlwifi-objs += iwl-scan.o iwl-led.o |
11 | iwlagn-objs += iwl-agn-rxon.o | 11 | iwlwifi-objs += iwl-agn-rxon.o |
12 | iwlagn-objs += iwl-5000.o | 12 | iwlwifi-objs += iwl-5000.o |
13 | iwlagn-objs += iwl-6000.o | 13 | iwlwifi-objs += iwl-6000.o |
14 | iwlagn-objs += iwl-1000.o | 14 | iwlwifi-objs += iwl-1000.o |
15 | iwlagn-objs += iwl-2000.o | 15 | iwlwifi-objs += iwl-2000.o |
16 | iwlagn-objs += iwl-pci.o | 16 | iwlwifi-objs += iwl-pci.o |
17 | iwlagn-objs += iwl-trans.o | 17 | iwlwifi-objs += iwl-trans.o |
18 | iwlagn-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o | 18 | iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o |
19 | 19 | ||
20 | iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o | 20 | iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o |
21 | iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o | 21 | iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o |
22 | iwlagn-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o | 22 | iwlwifi-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o |
23 | 23 | ||
24 | CFLAGS_iwl-devtrace.o := -I$(src) | 24 | CFLAGS_iwl-devtrace.o := -I$(src) |
25 | 25 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index c14f8d6fd7d8..7d6a3bf64950 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c | |||
@@ -2273,9 +2273,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, | |||
2273 | info->flags & IEEE80211_TX_CTL_NO_ACK) | 2273 | info->flags & IEEE80211_TX_CTL_NO_ACK) |
2274 | return; | 2274 | return; |
2275 | 2275 | ||
2276 | if (!sta || !lq_sta) | ||
2277 | return; | ||
2278 | |||
2279 | lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; | 2276 | lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; |
2280 | 2277 | ||
2281 | tid = rs_tl_add_packet(lq_sta, hdr); | 2278 | tid = rs_tl_add_packet(lq_sta, hdr); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 0e5d6498be21..dcb3bd67d4f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |||
@@ -300,7 +300,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
300 | sta_priv = (void *)info->control.sta->drv_priv; | 300 | sta_priv = (void *)info->control.sta->drv_priv; |
301 | 301 | ||
302 | if (sta_priv && sta_priv->asleep && | 302 | if (sta_priv && sta_priv->asleep && |
303 | (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) { | 303 | (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) { |
304 | /* | 304 | /* |
305 | * This sends an asynchronous command to the device, | 305 | * This sends an asynchronous command to the device, |
306 | * but we can rely on it being processed before the | 306 | * but we can rely on it being processed before the |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index baaf48616cc7..d0fd6f063bf8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -79,6 +79,7 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); | |||
79 | MODULE_VERSION(DRV_VERSION); | 79 | MODULE_VERSION(DRV_VERSION); |
80 | MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); | 80 | MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); |
81 | MODULE_LICENSE("GPL"); | 81 | MODULE_LICENSE("GPL"); |
82 | MODULE_ALIAS("iwlagn"); | ||
82 | 83 | ||
83 | void iwl_update_chain_flags(struct iwl_priv *priv) | 84 | void iwl_update_chain_flags(struct iwl_priv *priv) |
84 | { | 85 | { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index fc400bb2bdff..0725603dbf1d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -1123,8 +1123,9 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) | |||
1123 | &statistics_cmd); | 1123 | &statistics_cmd); |
1124 | } | 1124 | } |
1125 | 1125 | ||
1126 | int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, | 1126 | int iwl_mac_conf_tx(struct ieee80211_hw *hw, |
1127 | const struct ieee80211_tx_queue_params *params) | 1127 | struct ieee80211_vif *vif, u16 queue, |
1128 | const struct ieee80211_tx_queue_params *params) | ||
1128 | { | 1129 | { |
1129 | struct iwl_priv *priv = hw->priv; | 1130 | struct iwl_priv *priv = hw->priv; |
1130 | struct iwl_rxon_context *ctx; | 1131 | struct iwl_rxon_context *ctx; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index e55ffad83950..db50b650756c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -236,7 +236,8 @@ struct iwl_cfg { | |||
236 | * L i b * | 236 | * L i b * |
237 | ***************************/ | 237 | ***************************/ |
238 | 238 | ||
239 | int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, | 239 | int iwl_mac_conf_tx(struct ieee80211_hw *hw, |
240 | struct ieee80211_vif *vif, u16 queue, | ||
240 | const struct ieee80211_tx_queue_params *params); | 241 | const struct ieee80211_tx_queue_params *params); |
241 | int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); | 242 | int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); |
242 | void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | 243 | void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index 8747bbdf8983..3a24b477b8fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-shared.h +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h | |||
@@ -100,7 +100,7 @@ struct iwl_priv; | |||
100 | struct iwl_sensitivity_ranges; | 100 | struct iwl_sensitivity_ranges; |
101 | struct iwl_trans_ops; | 101 | struct iwl_trans_ops; |
102 | 102 | ||
103 | #define DRV_NAME "iwlagn" | 103 | #define DRV_NAME "iwlwifi" |
104 | #define IWLWIFI_VERSION "in-tree:" | 104 | #define IWLWIFI_VERSION "in-tree:" |
105 | #define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation" | 105 | #define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation" |
106 | #define DRV_AUTHOR "<ilw@linux.intel.com>" | 106 | #define DRV_AUTHOR "<ilw@linux.intel.com>" |
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index fb3e40bf5902..f3fd447131c2 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h | |||
@@ -158,6 +158,7 @@ struct lbs_private { | |||
158 | /* protected by hard_start_xmit serialization */ | 158 | /* protected by hard_start_xmit serialization */ |
159 | u8 txretrycount; | 159 | u8 txretrycount; |
160 | struct sk_buff *currenttxskb; | 160 | struct sk_buff *currenttxskb; |
161 | struct timer_list tx_lockup_timer; | ||
161 | 162 | ||
162 | /* Locks */ | 163 | /* Locks */ |
163 | struct mutex lock; | 164 | struct mutex lock; |
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index d1c1d52931f1..c50ae07e2e89 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -188,6 +188,7 @@ int lbs_stop_iface(struct lbs_private *priv) | |||
188 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 188 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
189 | 189 | ||
190 | cancel_work_sync(&priv->mcast_work); | 190 | cancel_work_sync(&priv->mcast_work); |
191 | del_timer_sync(&priv->tx_lockup_timer); | ||
191 | 192 | ||
192 | /* Disable command processing, and wait for all commands to complete */ | 193 | /* Disable command processing, and wait for all commands to complete */ |
193 | lbs_deb_main("waiting for commands to complete\n"); | 194 | lbs_deb_main("waiting for commands to complete\n"); |
@@ -243,6 +244,7 @@ void lbs_host_to_card_done(struct lbs_private *priv) | |||
243 | lbs_deb_enter(LBS_DEB_THREAD); | 244 | lbs_deb_enter(LBS_DEB_THREAD); |
244 | 245 | ||
245 | spin_lock_irqsave(&priv->driver_lock, flags); | 246 | spin_lock_irqsave(&priv->driver_lock, flags); |
247 | del_timer(&priv->tx_lockup_timer); | ||
246 | 248 | ||
247 | priv->dnld_sent = DNLD_RES_RECEIVED; | 249 | priv->dnld_sent = DNLD_RES_RECEIVED; |
248 | 250 | ||
@@ -585,6 +587,9 @@ static int lbs_thread(void *data) | |||
585 | if (ret) { | 587 | if (ret) { |
586 | lbs_deb_tx("host_to_card failed %d\n", ret); | 588 | lbs_deb_tx("host_to_card failed %d\n", ret); |
587 | priv->dnld_sent = DNLD_RES_RECEIVED; | 589 | priv->dnld_sent = DNLD_RES_RECEIVED; |
590 | } else { | ||
591 | mod_timer(&priv->tx_lockup_timer, | ||
592 | jiffies + (HZ * 5)); | ||
588 | } | 593 | } |
589 | priv->tx_pending_len = 0; | 594 | priv->tx_pending_len = 0; |
590 | if (!priv->currenttxskb) { | 595 | if (!priv->currenttxskb) { |
@@ -601,6 +606,7 @@ static int lbs_thread(void *data) | |||
601 | } | 606 | } |
602 | 607 | ||
603 | del_timer(&priv->command_timer); | 608 | del_timer(&priv->command_timer); |
609 | del_timer(&priv->tx_lockup_timer); | ||
604 | del_timer(&priv->auto_deepsleep_timer); | 610 | del_timer(&priv->auto_deepsleep_timer); |
605 | 611 | ||
606 | lbs_deb_leave(LBS_DEB_THREAD); | 612 | lbs_deb_leave(LBS_DEB_THREAD); |
@@ -735,6 +741,32 @@ out: | |||
735 | } | 741 | } |
736 | 742 | ||
737 | /** | 743 | /** |
744 | * lbs_tx_lockup_handler - handles the timeout of the passing of TX frames | ||
745 | * to the hardware. This is known to frequently happen with SD8686 when | ||
746 | * waking up after a Wake-on-WLAN-triggered resume. | ||
747 | * | ||
748 | * @data: &struct lbs_private pointer | ||
749 | */ | ||
750 | static void lbs_tx_lockup_handler(unsigned long data) | ||
751 | { | ||
752 | struct lbs_private *priv = (struct lbs_private *)data; | ||
753 | unsigned long flags; | ||
754 | |||
755 | lbs_deb_enter(LBS_DEB_TX); | ||
756 | spin_lock_irqsave(&priv->driver_lock, flags); | ||
757 | |||
758 | netdev_info(priv->dev, "TX lockup detected\n"); | ||
759 | if (priv->reset_card) | ||
760 | priv->reset_card(priv); | ||
761 | |||
762 | priv->dnld_sent = DNLD_RES_RECEIVED; | ||
763 | wake_up_interruptible(&priv->waitq); | ||
764 | |||
765 | spin_unlock_irqrestore(&priv->driver_lock, flags); | ||
766 | lbs_deb_leave(LBS_DEB_TX); | ||
767 | } | ||
768 | |||
769 | /** | ||
738 | * auto_deepsleep_timer_fn - put the device back to deep sleep mode when | 770 | * auto_deepsleep_timer_fn - put the device back to deep sleep mode when |
739 | * timer expires and no activity (command, event, data etc.) is detected. | 771 | * timer expires and no activity (command, event, data etc.) is detected. |
740 | * @data: &struct lbs_private pointer | 772 | * @data: &struct lbs_private pointer |
@@ -820,6 +852,8 @@ static int lbs_init_adapter(struct lbs_private *priv) | |||
820 | 852 | ||
821 | setup_timer(&priv->command_timer, lbs_cmd_timeout_handler, | 853 | setup_timer(&priv->command_timer, lbs_cmd_timeout_handler, |
822 | (unsigned long)priv); | 854 | (unsigned long)priv); |
855 | setup_timer(&priv->tx_lockup_timer, lbs_tx_lockup_handler, | ||
856 | (unsigned long)priv); | ||
823 | setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn, | 857 | setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn, |
824 | (unsigned long)priv); | 858 | (unsigned long)priv); |
825 | 859 | ||
@@ -857,6 +891,7 @@ static void lbs_free_adapter(struct lbs_private *priv) | |||
857 | lbs_free_cmd_buffer(priv); | 891 | lbs_free_cmd_buffer(priv); |
858 | kfifo_free(&priv->event_fifo); | 892 | kfifo_free(&priv->event_fifo); |
859 | del_timer(&priv->command_timer); | 893 | del_timer(&priv->command_timer); |
894 | del_timer(&priv->tx_lockup_timer); | ||
860 | del_timer(&priv->auto_deepsleep_timer); | 895 | del_timer(&priv->auto_deepsleep_timer); |
861 | 896 | ||
862 | lbs_deb_leave(LBS_DEB_MAIN); | 897 | lbs_deb_leave(LBS_DEB_MAIN); |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 34b79fc91e39..68455a2307cb 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -970,7 +970,8 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, | |||
970 | } | 970 | } |
971 | 971 | ||
972 | static int mac80211_hwsim_conf_tx( | 972 | static int mac80211_hwsim_conf_tx( |
973 | struct ieee80211_hw *hw, u16 queue, | 973 | struct ieee80211_hw *hw, |
974 | struct ieee80211_vif *vif, u16 queue, | ||
974 | const struct ieee80211_tx_queue_params *params) | 975 | const struct ieee80211_tx_queue_params *params) |
975 | { | 976 | { |
976 | wiphy_debug(hw->wiphy, | 977 | wiphy_debug(hw->wiphy, |
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 1a453a605b3f..9e63d16365e3 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c | |||
@@ -193,7 +193,6 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, | |||
193 | skb_src = skb_dequeue(&pra_list->skb_head); | 193 | skb_src = skb_dequeue(&pra_list->skb_head); |
194 | 194 | ||
195 | pra_list->total_pkts_size -= skb_src->len; | 195 | pra_list->total_pkts_size -= skb_src->len; |
196 | pra_list->total_pkts--; | ||
197 | 196 | ||
198 | atomic_dec(&priv->wmm.tx_pkts_queued); | 197 | atomic_dec(&priv->wmm.tx_pkts_queued); |
199 | 198 | ||
@@ -269,7 +268,6 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, | |||
269 | skb_queue_tail(&pra_list->skb_head, skb_aggr); | 268 | skb_queue_tail(&pra_list->skb_head, skb_aggr); |
270 | 269 | ||
271 | pra_list->total_pkts_size += skb_aggr->len; | 270 | pra_list->total_pkts_size += skb_aggr->len; |
272 | pra_list->total_pkts++; | ||
273 | 271 | ||
274 | atomic_inc(&priv->wmm.tx_pkts_queued); | 272 | atomic_inc(&priv->wmm.tx_pkts_queued); |
275 | 273 | ||
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.h b/drivers/net/wireless/mwifiex/11n_aggr.h index 9c6dca7ab02c..900e1c62a0cc 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.h +++ b/drivers/net/wireless/mwifiex/11n_aggr.h | |||
@@ -21,6 +21,7 @@ | |||
21 | #define _MWIFIEX_11N_AGGR_H_ | 21 | #define _MWIFIEX_11N_AGGR_H_ |
22 | 22 | ||
23 | #define PKT_TYPE_AMSDU 0xE6 | 23 | #define PKT_TYPE_AMSDU 0xE6 |
24 | #define MIN_NUM_AMSDU 2 | ||
24 | 25 | ||
25 | int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, | 26 | int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, |
26 | struct sk_buff *skb); | 27 | struct sk_buff *skb); |
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 0ddcdca63cf7..462c71067bfb 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -543,12 +543,28 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, | |||
543 | ret = -EFAULT; | 543 | ret = -EFAULT; |
544 | } | 544 | } |
545 | 545 | ||
546 | /* | ||
547 | * Bit 0 in tx_htinfo indicates that current Tx rate is 11n rate. Valid | ||
548 | * MCS index values for us are 0 to 7. | ||
549 | */ | ||
550 | if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 8)) { | ||
551 | sinfo->txrate.mcs = priv->tx_rate; | ||
552 | sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; | ||
553 | /* 40MHz rate */ | ||
554 | if (priv->tx_htinfo & BIT(1)) | ||
555 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | ||
556 | /* SGI enabled */ | ||
557 | if (priv->tx_htinfo & BIT(2)) | ||
558 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | ||
559 | } | ||
560 | |||
546 | sinfo->rx_bytes = priv->stats.rx_bytes; | 561 | sinfo->rx_bytes = priv->stats.rx_bytes; |
547 | sinfo->tx_bytes = priv->stats.tx_bytes; | 562 | sinfo->tx_bytes = priv->stats.tx_bytes; |
548 | sinfo->rx_packets = priv->stats.rx_packets; | 563 | sinfo->rx_packets = priv->stats.rx_packets; |
549 | sinfo->tx_packets = priv->stats.tx_packets; | 564 | sinfo->tx_packets = priv->stats.tx_packets; |
550 | sinfo->signal = priv->qual_level; | 565 | sinfo->signal = priv->qual_level; |
551 | sinfo->txrate.legacy = rate.rate; | 566 | /* bit rate is in 500 kb/s units. Convert it to 100kb/s units */ |
567 | sinfo->txrate.legacy = rate.rate * 5; | ||
552 | 568 | ||
553 | return ret; | 569 | return ret; |
554 | } | 570 | } |
@@ -565,8 +581,6 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
565 | { | 581 | { |
566 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | 582 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); |
567 | 583 | ||
568 | mwifiex_dump_station_info(priv, sinfo); | ||
569 | |||
570 | if (!priv->media_connected) | 584 | if (!priv->media_connected) |
571 | return -ENOENT; | 585 | return -ENOENT; |
572 | if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) | 586 | if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) |
@@ -1148,8 +1162,150 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, | |||
1148 | ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | 1162 | ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; |
1149 | } | 1163 | } |
1150 | 1164 | ||
1165 | /* | ||
1166 | * create a new virtual interface with the given name | ||
1167 | */ | ||
1168 | struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, | ||
1169 | char *name, | ||
1170 | enum nl80211_iftype type, | ||
1171 | u32 *flags, | ||
1172 | struct vif_params *params) | ||
1173 | { | ||
1174 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
1175 | struct mwifiex_adapter *adapter; | ||
1176 | struct net_device *dev; | ||
1177 | void *mdev_priv; | ||
1178 | |||
1179 | if (!priv) | ||
1180 | return NULL; | ||
1181 | |||
1182 | adapter = priv->adapter; | ||
1183 | if (!adapter) | ||
1184 | return NULL; | ||
1185 | |||
1186 | switch (type) { | ||
1187 | case NL80211_IFTYPE_UNSPECIFIED: | ||
1188 | case NL80211_IFTYPE_STATION: | ||
1189 | case NL80211_IFTYPE_ADHOC: | ||
1190 | if (priv->bss_mode) { | ||
1191 | wiphy_err(wiphy, "cannot create multiple" | ||
1192 | " station/adhoc interfaces\n"); | ||
1193 | return NULL; | ||
1194 | } | ||
1195 | |||
1196 | if (type == NL80211_IFTYPE_UNSPECIFIED) | ||
1197 | priv->bss_mode = NL80211_IFTYPE_STATION; | ||
1198 | else | ||
1199 | priv->bss_mode = type; | ||
1200 | |||
1201 | priv->bss_type = MWIFIEX_BSS_TYPE_STA; | ||
1202 | priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; | ||
1203 | priv->bss_priority = 0; | ||
1204 | priv->bss_role = MWIFIEX_BSS_ROLE_STA; | ||
1205 | priv->bss_index = 0; | ||
1206 | priv->bss_num = 0; | ||
1207 | |||
1208 | break; | ||
1209 | default: | ||
1210 | wiphy_err(wiphy, "type not supported\n"); | ||
1211 | return NULL; | ||
1212 | } | ||
1213 | |||
1214 | dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name, | ||
1215 | ether_setup, 1); | ||
1216 | if (!dev) { | ||
1217 | wiphy_err(wiphy, "no memory available for netdevice\n"); | ||
1218 | goto error; | ||
1219 | } | ||
1220 | |||
1221 | dev_net_set(dev, wiphy_net(wiphy)); | ||
1222 | dev->ieee80211_ptr = priv->wdev; | ||
1223 | dev->ieee80211_ptr->iftype = priv->bss_mode; | ||
1224 | memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); | ||
1225 | memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN); | ||
1226 | SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); | ||
1227 | |||
1228 | dev->flags |= IFF_BROADCAST | IFF_MULTICAST; | ||
1229 | dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT; | ||
1230 | dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN; | ||
1231 | |||
1232 | mdev_priv = netdev_priv(dev); | ||
1233 | *((unsigned long *) mdev_priv) = (unsigned long) priv; | ||
1234 | |||
1235 | priv->netdev = dev; | ||
1236 | mwifiex_init_priv_params(priv, dev); | ||
1237 | |||
1238 | SET_NETDEV_DEV(dev, adapter->dev); | ||
1239 | |||
1240 | /* Register network device */ | ||
1241 | if (register_netdevice(dev)) { | ||
1242 | wiphy_err(wiphy, "cannot register virtual network device\n"); | ||
1243 | goto error; | ||
1244 | } | ||
1245 | |||
1246 | sema_init(&priv->async_sem, 1); | ||
1247 | priv->scan_pending_on_block = false; | ||
1248 | |||
1249 | dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); | ||
1250 | |||
1251 | #ifdef CONFIG_DEBUG_FS | ||
1252 | mwifiex_dev_debugfs_init(priv); | ||
1253 | #endif | ||
1254 | return dev; | ||
1255 | error: | ||
1256 | if (dev && (dev->reg_state == NETREG_UNREGISTERED)) | ||
1257 | free_netdev(dev); | ||
1258 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; | ||
1259 | |||
1260 | return NULL; | ||
1261 | } | ||
1262 | EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); | ||
1263 | |||
1264 | /* | ||
1265 | * del_virtual_intf: remove the virtual interface determined by dev | ||
1266 | */ | ||
1267 | int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) | ||
1268 | { | ||
1269 | struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); | ||
1270 | |||
1271 | if (!priv || !dev) | ||
1272 | return 0; | ||
1273 | |||
1274 | #ifdef CONFIG_DEBUG_FS | ||
1275 | mwifiex_dev_debugfs_remove(priv); | ||
1276 | #endif | ||
1277 | |||
1278 | if (!netif_queue_stopped(priv->netdev)) | ||
1279 | netif_stop_queue(priv->netdev); | ||
1280 | |||
1281 | if (netif_carrier_ok(priv->netdev)) | ||
1282 | netif_carrier_off(priv->netdev); | ||
1283 | |||
1284 | if (dev->reg_state == NETREG_REGISTERED) | ||
1285 | unregister_netdevice(dev); | ||
1286 | |||
1287 | if (dev->reg_state == NETREG_UNREGISTERED) | ||
1288 | free_netdev(dev); | ||
1289 | |||
1290 | /* Clear the priv in adapter */ | ||
1291 | priv->netdev = NULL; | ||
1292 | |||
1293 | priv->media_connected = false; | ||
1294 | |||
1295 | cancel_work_sync(&priv->cfg_workqueue); | ||
1296 | flush_workqueue(priv->workqueue); | ||
1297 | destroy_workqueue(priv->workqueue); | ||
1298 | |||
1299 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; | ||
1300 | |||
1301 | return 0; | ||
1302 | } | ||
1303 | EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf); | ||
1304 | |||
1151 | /* station cfg80211 operations */ | 1305 | /* station cfg80211 operations */ |
1152 | static struct cfg80211_ops mwifiex_cfg80211_ops = { | 1306 | static struct cfg80211_ops mwifiex_cfg80211_ops = { |
1307 | .add_virtual_intf = mwifiex_add_virtual_intf, | ||
1308 | .del_virtual_intf = mwifiex_del_virtual_intf, | ||
1153 | .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf, | 1309 | .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf, |
1154 | .scan = mwifiex_cfg80211_scan, | 1310 | .scan = mwifiex_cfg80211_scan, |
1155 | .connect = mwifiex_cfg80211_connect, | 1311 | .connect = mwifiex_cfg80211_connect, |
@@ -1174,8 +1330,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { | |||
1174 | * default parameters and handler function pointers, and finally | 1330 | * default parameters and handler function pointers, and finally |
1175 | * registers the device. | 1331 | * registers the device. |
1176 | */ | 1332 | */ |
1177 | int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, | 1333 | int mwifiex_register_cfg80211(struct mwifiex_private *priv) |
1178 | struct mwifiex_private *priv) | ||
1179 | { | 1334 | { |
1180 | int ret; | 1335 | int ret; |
1181 | void *wdev_priv; | 1336 | void *wdev_priv; |
@@ -1215,7 +1370,7 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, | |||
1215 | wdev->wiphy->cipher_suites = mwifiex_cipher_suites; | 1370 | wdev->wiphy->cipher_suites = mwifiex_cipher_suites; |
1216 | wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); | 1371 | wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); |
1217 | 1372 | ||
1218 | memcpy(wdev->wiphy->perm_addr, mac, 6); | 1373 | memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN); |
1219 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 1374 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
1220 | 1375 | ||
1221 | /* We are using custom domains */ | 1376 | /* We are using custom domains */ |
@@ -1245,17 +1400,8 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, | |||
1245 | "info: successfully registered wiphy device\n"); | 1400 | "info: successfully registered wiphy device\n"); |
1246 | } | 1401 | } |
1247 | 1402 | ||
1248 | dev_net_set(dev, wiphy_net(wdev->wiphy)); | ||
1249 | dev->ieee80211_ptr = wdev; | ||
1250 | memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6); | ||
1251 | memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6); | ||
1252 | SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); | ||
1253 | priv->wdev = wdev; | 1403 | priv->wdev = wdev; |
1254 | 1404 | ||
1255 | dev->flags |= IFF_BROADCAST | IFF_MULTICAST; | ||
1256 | dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT; | ||
1257 | dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN; | ||
1258 | |||
1259 | return ret; | 1405 | return ret; |
1260 | } | 1406 | } |
1261 | 1407 | ||
diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h index c4db8f36aa16..8d010f2500c5 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.h +++ b/drivers/net/wireless/mwifiex/cfg80211.h | |||
@@ -24,8 +24,7 @@ | |||
24 | 24 | ||
25 | #include "main.h" | 25 | #include "main.h" |
26 | 26 | ||
27 | int mwifiex_register_cfg80211(struct net_device *, u8 *, | 27 | int mwifiex_register_cfg80211(struct mwifiex_private *); |
28 | struct mwifiex_private *); | ||
29 | 28 | ||
30 | void mwifiex_cfg80211_results(struct work_struct *work); | 29 | void mwifiex_cfg80211_results(struct work_struct *work); |
31 | #endif | 30 | #endif |
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 94ddc9038cb3..6ca62c809cb9 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h | |||
@@ -114,14 +114,6 @@ struct mwifiex_txinfo { | |||
114 | u8 bss_index; | 114 | u8 bss_index; |
115 | }; | 115 | }; |
116 | 116 | ||
117 | struct mwifiex_bss_attr { | ||
118 | u8 bss_type; | ||
119 | u8 frame_type; | ||
120 | u8 active; | ||
121 | u8 bss_priority; | ||
122 | u8 bss_num; | ||
123 | }; | ||
124 | |||
125 | enum mwifiex_wmm_ac_e { | 117 | enum mwifiex_wmm_ac_e { |
126 | WMM_AC_BK, | 118 | WMM_AC_BK, |
127 | WMM_AC_BE, | 119 | WMM_AC_BE, |
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 26e685a31bc0..e1076b46401e 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c | |||
@@ -76,7 +76,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv) | |||
76 | memset(priv->curr_addr, 0xff, ETH_ALEN); | 76 | memset(priv->curr_addr, 0xff, ETH_ALEN); |
77 | 77 | ||
78 | priv->pkt_tx_ctrl = 0; | 78 | priv->pkt_tx_ctrl = 0; |
79 | priv->bss_mode = NL80211_IFTYPE_STATION; | 79 | priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; |
80 | priv->data_rate = 0; /* Initially indicate the rate as auto */ | 80 | priv->data_rate = 0; /* Initially indicate the rate as auto */ |
81 | priv->is_data_rate_auto = true; | 81 | priv->is_data_rate_auto = true; |
82 | priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; | 82 | priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; |
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 48b4d95219fb..4c7491ec3f2b 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c | |||
@@ -26,21 +26,6 @@ | |||
26 | 26 | ||
27 | const char driver_version[] = "mwifiex " VERSION " (%s) "; | 27 | const char driver_version[] = "mwifiex " VERSION " (%s) "; |
28 | 28 | ||
29 | static struct mwifiex_bss_attr mwifiex_bss_sta[] = { | ||
30 | {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0}, | ||
31 | }; | ||
32 | |||
33 | static int drv_mode = DRV_MODE_STA; | ||
34 | |||
35 | /* Supported drv_mode table */ | ||
36 | static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { | ||
37 | { | ||
38 | .drv_mode = DRV_MODE_STA, | ||
39 | .intf_num = ARRAY_SIZE(mwifiex_bss_sta), | ||
40 | .bss_attr = mwifiex_bss_sta, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | /* | 29 | /* |
45 | * This function registers the device and performs all the necessary | 30 | * This function registers the device and performs all the necessary |
46 | * initializations. | 31 | * initializations. |
@@ -57,7 +42,6 @@ static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { | |||
57 | * proper cleanup before exiting. | 42 | * proper cleanup before exiting. |
58 | */ | 43 | */ |
59 | static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, | 44 | static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, |
60 | struct mwifiex_drv_mode *drv_mode_ptr, | ||
61 | void **padapter) | 45 | void **padapter) |
62 | { | 46 | { |
63 | struct mwifiex_adapter *adapter; | 47 | struct mwifiex_adapter *adapter; |
@@ -78,44 +62,20 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, | |||
78 | goto error; | 62 | goto error; |
79 | 63 | ||
80 | adapter->priv_num = 0; | 64 | adapter->priv_num = 0; |
81 | for (i = 0; i < drv_mode_ptr->intf_num; i++) { | ||
82 | adapter->priv[i] = NULL; | ||
83 | |||
84 | if (!drv_mode_ptr->bss_attr[i].active) | ||
85 | continue; | ||
86 | |||
87 | /* Allocate memory for private structure */ | ||
88 | adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private), | ||
89 | GFP_KERNEL); | ||
90 | if (!adapter->priv[i]) { | ||
91 | dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n", | ||
92 | __func__, i); | ||
93 | goto error; | ||
94 | } | ||
95 | 65 | ||
96 | adapter->priv_num++; | 66 | /* Allocate memory for private structure */ |
97 | adapter->priv[i]->adapter = adapter; | 67 | adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private), |
98 | /* Save bss_type, frame_type & bss_priority */ | 68 | GFP_KERNEL); |
99 | adapter->priv[i]->bss_type = drv_mode_ptr->bss_attr[i].bss_type; | 69 | if (!adapter->priv[0]) { |
100 | adapter->priv[i]->frame_type = | 70 | dev_err(adapter->dev, "%s: failed to alloc priv[0]\n", |
101 | drv_mode_ptr->bss_attr[i].frame_type; | 71 | __func__); |
102 | adapter->priv[i]->bss_priority = | 72 | goto error; |
103 | drv_mode_ptr->bss_attr[i].bss_priority; | ||
104 | |||
105 | if (drv_mode_ptr->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA) | ||
106 | adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA; | ||
107 | else if (drv_mode_ptr->bss_attr[i].bss_type == | ||
108 | MWIFIEX_BSS_TYPE_UAP) | ||
109 | adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP; | ||
110 | |||
111 | /* Save bss_index & bss_num */ | ||
112 | adapter->priv[i]->bss_index = i; | ||
113 | adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num; | ||
114 | } | 73 | } |
115 | adapter->drv_mode = drv_mode_ptr; | ||
116 | 74 | ||
117 | if (mwifiex_init_lock_list(adapter)) | 75 | adapter->priv_num++; |
118 | goto error; | 76 | |
77 | adapter->priv[0]->adapter = adapter; | ||
78 | mwifiex_init_lock_list(adapter); | ||
119 | 79 | ||
120 | init_timer(&adapter->cmd_timer); | 80 | init_timer(&adapter->cmd_timer); |
121 | adapter->cmd_timer.function = mwifiex_cmd_timeout_func; | 81 | adapter->cmd_timer.function = mwifiex_cmd_timeout_func; |
@@ -126,9 +86,9 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, | |||
126 | error: | 86 | error: |
127 | dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); | 87 | dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); |
128 | 88 | ||
129 | mwifiex_free_lock_list(adapter); | 89 | for (i = 0; i < adapter->priv_num; i++) |
130 | for (i = 0; i < drv_mode_ptr->intf_num; i++) | ||
131 | kfree(adapter->priv[i]); | 90 | kfree(adapter->priv[i]); |
91 | |||
132 | kfree(adapter); | 92 | kfree(adapter); |
133 | 93 | ||
134 | return -1; | 94 | return -1; |
@@ -316,38 +276,6 @@ exit_main_proc: | |||
316 | } | 276 | } |
317 | 277 | ||
318 | /* | 278 | /* |
319 | * This function initializes the software. | ||
320 | * | ||
321 | * The main work includes allocating and initializing the adapter structure | ||
322 | * and initializing the private structures. | ||
323 | */ | ||
324 | static int | ||
325 | mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **padapter) | ||
326 | { | ||
327 | int i; | ||
328 | struct mwifiex_drv_mode *drv_mode_ptr; | ||
329 | |||
330 | /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */ | ||
331 | drv_mode_ptr = NULL; | ||
332 | for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) { | ||
333 | if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) { | ||
334 | drv_mode_ptr = &mwifiex_drv_mode_tbl[i]; | ||
335 | break; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | if (!drv_mode_ptr) { | ||
340 | pr_err("invalid drv_mode=%d\n", drv_mode); | ||
341 | return -1; | ||
342 | } | ||
343 | |||
344 | if (mwifiex_register(card, if_ops, drv_mode_ptr, padapter)) | ||
345 | return -1; | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * This function frees the adapter structure. | 279 | * This function frees the adapter structure. |
352 | * | 280 | * |
353 | * Additionally, this closes the netlink socket, frees the timers | 281 | * Additionally, this closes the netlink socket, frees the timers |
@@ -649,8 +577,8 @@ static const struct net_device_ops mwifiex_netdev_ops = { | |||
649 | * | 577 | * |
650 | * In addition, the CFG80211 work queue is also created. | 578 | * In addition, the CFG80211 work queue is also created. |
651 | */ | 579 | */ |
652 | static void | 580 | void mwifiex_init_priv_params(struct mwifiex_private *priv, |
653 | mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) | 581 | struct net_device *dev) |
654 | { | 582 | { |
655 | dev->netdev_ops = &mwifiex_netdev_ops; | 583 | dev->netdev_ops = &mwifiex_netdev_ops; |
656 | /* Initialize private structure */ | 584 | /* Initialize private structure */ |
@@ -664,118 +592,6 @@ mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) | |||
664 | } | 592 | } |
665 | 593 | ||
666 | /* | 594 | /* |
667 | * This function adds a new logical interface. | ||
668 | * | ||
669 | * It allocates, initializes and registers the interface by performing | ||
670 | * the following opearations - | ||
671 | * - Allocate a new net device structure | ||
672 | * - Assign device name | ||
673 | * - Register the new device with CFG80211 subsystem | ||
674 | * - Initialize semaphore and private structure | ||
675 | * - Register the new device with kernel | ||
676 | * - Create the complete debug FS structure if configured | ||
677 | */ | ||
678 | static struct mwifiex_private *mwifiex_add_interface( | ||
679 | struct mwifiex_adapter *adapter, | ||
680 | u8 bss_index, u8 bss_type) | ||
681 | { | ||
682 | struct net_device *dev; | ||
683 | struct mwifiex_private *priv; | ||
684 | void *mdev_priv; | ||
685 | |||
686 | dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d", | ||
687 | ether_setup, 1); | ||
688 | if (!dev) { | ||
689 | dev_err(adapter->dev, "no memory available for netdevice\n"); | ||
690 | goto error; | ||
691 | } | ||
692 | |||
693 | if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr, | ||
694 | adapter->priv[bss_index]) != 0) { | ||
695 | dev_err(adapter->dev, "cannot register netdevice with cfg80211\n"); | ||
696 | goto error; | ||
697 | } | ||
698 | /* Save the priv pointer in netdev */ | ||
699 | priv = adapter->priv[bss_index]; | ||
700 | mdev_priv = netdev_priv(dev); | ||
701 | *((unsigned long *) mdev_priv) = (unsigned long) priv; | ||
702 | |||
703 | priv->netdev = dev; | ||
704 | |||
705 | sema_init(&priv->async_sem, 1); | ||
706 | priv->scan_pending_on_block = false; | ||
707 | |||
708 | mwifiex_init_priv_params(priv, dev); | ||
709 | |||
710 | SET_NETDEV_DEV(dev, adapter->dev); | ||
711 | |||
712 | /* Register network device */ | ||
713 | if (register_netdev(dev)) { | ||
714 | dev_err(adapter->dev, "cannot register virtual network device\n"); | ||
715 | goto error; | ||
716 | } | ||
717 | |||
718 | dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); | ||
719 | #ifdef CONFIG_DEBUG_FS | ||
720 | mwifiex_dev_debugfs_init(priv); | ||
721 | #endif | ||
722 | return priv; | ||
723 | error: | ||
724 | if (dev) | ||
725 | free_netdev(dev); | ||
726 | return NULL; | ||
727 | } | ||
728 | |||
729 | /* | ||
730 | * This function removes a logical interface. | ||
731 | * | ||
732 | * It deregisters, resets and frees the interface by performing | ||
733 | * the following operations - | ||
734 | * - Disconnect the device if connected, send wireless event to | ||
735 | * notify applications. | ||
736 | * - Remove the debug FS structure if configured | ||
737 | * - Unregister the device from kernel | ||
738 | * - Free the net device structure | ||
739 | * - Cancel all works and destroy work queue | ||
740 | * - Unregister and free the wireless device from CFG80211 subsystem | ||
741 | */ | ||
742 | static void | ||
743 | mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index) | ||
744 | { | ||
745 | struct net_device *dev; | ||
746 | struct mwifiex_private *priv = adapter->priv[bss_index]; | ||
747 | |||
748 | if (!priv) | ||
749 | return; | ||
750 | dev = priv->netdev; | ||
751 | |||
752 | if (priv->media_connected) | ||
753 | priv->media_connected = false; | ||
754 | |||
755 | #ifdef CONFIG_DEBUG_FS | ||
756 | mwifiex_dev_debugfs_remove(priv); | ||
757 | #endif | ||
758 | /* Last reference is our one */ | ||
759 | dev_dbg(adapter->dev, "info: %s: refcnt = %d\n", | ||
760 | dev->name, netdev_refcnt_read(dev)); | ||
761 | |||
762 | if (dev->reg_state == NETREG_REGISTERED) | ||
763 | unregister_netdev(dev); | ||
764 | |||
765 | /* Clear the priv in adapter */ | ||
766 | priv->netdev = NULL; | ||
767 | if (dev) | ||
768 | free_netdev(dev); | ||
769 | |||
770 | cancel_work_sync(&priv->cfg_workqueue); | ||
771 | flush_workqueue(priv->workqueue); | ||
772 | destroy_workqueue(priv->workqueue); | ||
773 | wiphy_unregister(priv->wdev->wiphy); | ||
774 | wiphy_free(priv->wdev->wiphy); | ||
775 | kfree(priv->wdev); | ||
776 | } | ||
777 | |||
778 | /* | ||
779 | * This function check if command is pending. | 595 | * This function check if command is pending. |
780 | */ | 596 | */ |
781 | int is_command_pending(struct mwifiex_adapter *adapter) | 597 | int is_command_pending(struct mwifiex_adapter *adapter) |
@@ -847,14 +663,14 @@ int | |||
847 | mwifiex_add_card(void *card, struct semaphore *sem, | 663 | mwifiex_add_card(void *card, struct semaphore *sem, |
848 | struct mwifiex_if_ops *if_ops) | 664 | struct mwifiex_if_ops *if_ops) |
849 | { | 665 | { |
850 | int i; | ||
851 | struct mwifiex_adapter *adapter; | 666 | struct mwifiex_adapter *adapter; |
852 | char fmt[64]; | 667 | char fmt[64]; |
668 | struct mwifiex_private *priv; | ||
853 | 669 | ||
854 | if (down_interruptible(sem)) | 670 | if (down_interruptible(sem)) |
855 | goto exit_sem_err; | 671 | goto exit_sem_err; |
856 | 672 | ||
857 | if (mwifiex_init_sw(card, if_ops, (void **)&adapter)) { | 673 | if (mwifiex_register(card, if_ops, (void **)&adapter)) { |
858 | pr_err("%s: software init failed\n", __func__); | 674 | pr_err("%s: software init failed\n", __func__); |
859 | goto err_init_sw; | 675 | goto err_init_sw; |
860 | } | 676 | } |
@@ -888,14 +704,26 @@ mwifiex_add_card(void *card, struct semaphore *sem, | |||
888 | goto err_init_fw; | 704 | goto err_init_fw; |
889 | } | 705 | } |
890 | 706 | ||
891 | /* Add interfaces */ | 707 | priv = adapter->priv[0]; |
892 | for (i = 0; i < adapter->drv_mode->intf_num; i++) { | 708 | |
893 | if (!mwifiex_add_interface(adapter, i, | 709 | if (mwifiex_register_cfg80211(priv) != 0) { |
894 | adapter->drv_mode->bss_attr[i].bss_type)) { | 710 | dev_err(adapter->dev, "cannot register netdevice" |
895 | goto err_add_intf; | 711 | " with cfg80211\n"); |
896 | } | 712 | goto err_init_fw; |
713 | } | ||
714 | |||
715 | rtnl_lock(); | ||
716 | /* Create station interface by default */ | ||
717 | if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d", | ||
718 | NL80211_IFTYPE_STATION, NULL, NULL)) { | ||
719 | rtnl_unlock(); | ||
720 | dev_err(adapter->dev, "cannot create default station" | ||
721 | " interface\n"); | ||
722 | goto err_add_intf; | ||
897 | } | 723 | } |
898 | 724 | ||
725 | rtnl_unlock(); | ||
726 | |||
899 | up(sem); | 727 | up(sem); |
900 | 728 | ||
901 | mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); | 729 | mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); |
@@ -904,8 +732,9 @@ mwifiex_add_card(void *card, struct semaphore *sem, | |||
904 | return 0; | 732 | return 0; |
905 | 733 | ||
906 | err_add_intf: | 734 | err_add_intf: |
907 | for (i = 0; i < adapter->priv_num; i++) | 735 | rtnl_lock(); |
908 | mwifiex_remove_interface(adapter, i); | 736 | mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); |
737 | rtnl_unlock(); | ||
909 | err_init_fw: | 738 | err_init_fw: |
910 | pr_debug("info: %s: unregister device\n", __func__); | 739 | pr_debug("info: %s: unregister device\n", __func__); |
911 | adapter->if_ops.unregister_dev(adapter); | 740 | adapter->if_ops.unregister_dev(adapter); |
@@ -960,7 +789,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) | |||
960 | /* Stop data */ | 789 | /* Stop data */ |
961 | for (i = 0; i < adapter->priv_num; i++) { | 790 | for (i = 0; i < adapter->priv_num; i++) { |
962 | priv = adapter->priv[i]; | 791 | priv = adapter->priv[i]; |
963 | if (priv) { | 792 | if (priv && priv->netdev) { |
964 | if (!netif_queue_stopped(priv->netdev)) | 793 | if (!netif_queue_stopped(priv->netdev)) |
965 | netif_stop_queue(priv->netdev); | 794 | netif_stop_queue(priv->netdev); |
966 | if (netif_carrier_ok(priv->netdev)) | 795 | if (netif_carrier_ok(priv->netdev)) |
@@ -985,9 +814,20 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) | |||
985 | atomic_read(&adapter->cmd_pending)); | 814 | atomic_read(&adapter->cmd_pending)); |
986 | } | 815 | } |
987 | 816 | ||
988 | /* Remove interface */ | 817 | for (i = 0; i < adapter->priv_num; i++) { |
989 | for (i = 0; i < adapter->priv_num; i++) | 818 | priv = adapter->priv[i]; |
990 | mwifiex_remove_interface(adapter, i); | 819 | |
820 | if (!priv) | ||
821 | continue; | ||
822 | |||
823 | rtnl_lock(); | ||
824 | mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); | ||
825 | rtnl_unlock(); | ||
826 | } | ||
827 | |||
828 | wiphy_unregister(priv->wdev->wiphy); | ||
829 | wiphy_free(priv->wdev->wiphy); | ||
830 | kfree(priv->wdev); | ||
991 | 831 | ||
992 | mwifiex_terminate_workqueue(adapter); | 832 | mwifiex_terminate_workqueue(adapter); |
993 | 833 | ||
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 1e801328a558..907ab746dc4b 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h | |||
@@ -45,15 +45,6 @@ enum { | |||
45 | MWIFIEX_SYNC_CMD | 45 | MWIFIEX_SYNC_CMD |
46 | }; | 46 | }; |
47 | 47 | ||
48 | #define DRV_MODE_STA 0x1 | ||
49 | |||
50 | struct mwifiex_drv_mode { | ||
51 | u16 drv_mode; | ||
52 | u16 intf_num; | ||
53 | struct mwifiex_bss_attr *bss_attr; | ||
54 | }; | ||
55 | |||
56 | |||
57 | #define MWIFIEX_MAX_AP 64 | 48 | #define MWIFIEX_MAX_AP 64 |
58 | 49 | ||
59 | #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) | 50 | #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) |
@@ -182,7 +173,6 @@ struct mwifiex_ra_list_tbl { | |||
182 | struct sk_buff_head skb_head; | 173 | struct sk_buff_head skb_head; |
183 | u8 ra[ETH_ALEN]; | 174 | u8 ra[ETH_ALEN]; |
184 | u32 total_pkts_size; | 175 | u32 total_pkts_size; |
185 | u32 total_pkts; | ||
186 | u32 is_11n_enabled; | 176 | u32 is_11n_enabled; |
187 | }; | 177 | }; |
188 | 178 | ||
@@ -546,7 +536,6 @@ struct mwifiex_if_ops { | |||
546 | struct mwifiex_adapter { | 536 | struct mwifiex_adapter { |
547 | struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM]; | 537 | struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM]; |
548 | u8 priv_num; | 538 | u8 priv_num; |
549 | struct mwifiex_drv_mode *drv_mode; | ||
550 | const struct firmware *firmware; | 539 | const struct firmware *firmware; |
551 | char fw_name[32]; | 540 | char fw_name[32]; |
552 | struct device *dev; | 541 | struct device *dev; |
@@ -792,6 +781,8 @@ int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, | |||
792 | int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, | 781 | int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, |
793 | struct host_cmd_ds_command *resp); | 782 | struct host_cmd_ds_command *resp); |
794 | int is_command_pending(struct mwifiex_adapter *adapter); | 783 | int is_command_pending(struct mwifiex_adapter *adapter); |
784 | void mwifiex_init_priv_params(struct mwifiex_private *priv, | ||
785 | struct net_device *dev); | ||
795 | 786 | ||
796 | /* | 787 | /* |
797 | * This function checks if the queuing is RA based or not. | 788 | * This function checks if the queuing is RA based or not. |
@@ -966,6 +957,12 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, | |||
966 | int mwifiex_check_network_compatibility(struct mwifiex_private *priv, | 957 | int mwifiex_check_network_compatibility(struct mwifiex_private *priv, |
967 | struct mwifiex_bssdescriptor *bss_desc); | 958 | struct mwifiex_bssdescriptor *bss_desc); |
968 | 959 | ||
960 | struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, | ||
961 | char *name, enum nl80211_iftype type, | ||
962 | u32 *flags, struct vif_params *params); | ||
963 | int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev); | ||
964 | |||
965 | |||
969 | #ifdef CONFIG_DEBUG_FS | 966 | #ifdef CONFIG_DEBUG_FS |
970 | void mwifiex_debugfs_init(void); | 967 | void mwifiex_debugfs_init(void); |
971 | void mwifiex_debugfs_remove(void); | 968 | void mwifiex_debugfs_remove(void); |
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index a9dfeb1b4ace..520800b618e7 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c | |||
@@ -720,51 +720,9 @@ done: | |||
720 | static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, | 720 | static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, |
721 | struct mwifiex_rate_cfg *rate_cfg) | 721 | struct mwifiex_rate_cfg *rate_cfg) |
722 | { | 722 | { |
723 | struct mwifiex_adapter *adapter = priv->adapter; | ||
724 | |||
725 | rate_cfg->is_rate_auto = priv->is_data_rate_auto; | 723 | rate_cfg->is_rate_auto = priv->is_data_rate_auto; |
726 | if (!priv->media_connected) { | 724 | return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, |
727 | switch (adapter->config_bands) { | 725 | HostCmd_ACT_GEN_GET, 0, NULL); |
728 | case BAND_B: | ||
729 | /* Return the lowest supported rate for B band */ | ||
730 | rate_cfg->rate = supported_rates_b[0] & 0x7f; | ||
731 | break; | ||
732 | case BAND_G: | ||
733 | case BAND_G | BAND_GN: | ||
734 | /* Return the lowest supported rate for G band */ | ||
735 | rate_cfg->rate = supported_rates_g[0] & 0x7f; | ||
736 | break; | ||
737 | case BAND_B | BAND_G: | ||
738 | case BAND_A | BAND_B | BAND_G: | ||
739 | case BAND_A | BAND_B: | ||
740 | case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN: | ||
741 | case BAND_B | BAND_G | BAND_GN: | ||
742 | /* Return the lowest supported rate for BG band */ | ||
743 | rate_cfg->rate = supported_rates_bg[0] & 0x7f; | ||
744 | break; | ||
745 | case BAND_A: | ||
746 | case BAND_A | BAND_G: | ||
747 | case BAND_A | BAND_G | BAND_AN | BAND_GN: | ||
748 | case BAND_A | BAND_AN: | ||
749 | /* Return the lowest supported rate for A band */ | ||
750 | rate_cfg->rate = supported_rates_a[0] & 0x7f; | ||
751 | break; | ||
752 | case BAND_GN: | ||
753 | /* Return the lowest supported rate for N band */ | ||
754 | rate_cfg->rate = supported_rates_n[0] & 0x7f; | ||
755 | break; | ||
756 | default: | ||
757 | dev_warn(adapter->dev, "invalid band %#x\n", | ||
758 | adapter->config_bands); | ||
759 | break; | ||
760 | } | ||
761 | } else { | ||
762 | return mwifiex_send_cmd_sync(priv, | ||
763 | HostCmd_CMD_802_11_TX_RATE_QUERY, | ||
764 | HostCmd_ACT_GEN_GET, 0, NULL); | ||
765 | } | ||
766 | |||
767 | return 0; | ||
768 | } | 726 | } |
769 | 727 | ||
770 | /* | 728 | /* |
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 69e260b41711..eda24474c1fc 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c | |||
@@ -121,7 +121,6 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra) | |||
121 | memcpy(ra_list->ra, ra, ETH_ALEN); | 121 | memcpy(ra_list->ra, ra, ETH_ALEN); |
122 | 122 | ||
123 | ra_list->total_pkts_size = 0; | 123 | ra_list->total_pkts_size = 0; |
124 | ra_list->total_pkts = 0; | ||
125 | 124 | ||
126 | dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list); | 125 | dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list); |
127 | 126 | ||
@@ -648,7 +647,6 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, | |||
648 | skb_queue_tail(&ra_list->skb_head, skb); | 647 | skb_queue_tail(&ra_list->skb_head, skb); |
649 | 648 | ||
650 | ra_list->total_pkts_size += skb->len; | 649 | ra_list->total_pkts_size += skb->len; |
651 | ra_list->total_pkts++; | ||
652 | 650 | ||
653 | atomic_inc(&priv->wmm.tx_pkts_queued); | 651 | atomic_inc(&priv->wmm.tx_pkts_queued); |
654 | 652 | ||
@@ -975,6 +973,28 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, | |||
975 | } | 973 | } |
976 | 974 | ||
977 | /* | 975 | /* |
976 | * This function checks if 11n aggregation is possible. | ||
977 | */ | ||
978 | static int | ||
979 | mwifiex_is_11n_aggragation_possible(struct mwifiex_private *priv, | ||
980 | struct mwifiex_ra_list_tbl *ptr, | ||
981 | int max_buf_size) | ||
982 | { | ||
983 | int count = 0, total_size = 0; | ||
984 | struct sk_buff *skb, *tmp; | ||
985 | |||
986 | skb_queue_walk_safe(&ptr->skb_head, skb, tmp) { | ||
987 | total_size += skb->len; | ||
988 | if (total_size >= max_buf_size) | ||
989 | break; | ||
990 | if (++count >= MIN_NUM_AMSDU) | ||
991 | return true; | ||
992 | } | ||
993 | |||
994 | return false; | ||
995 | } | ||
996 | |||
997 | /* | ||
978 | * This function sends a single packet to firmware for transmission. | 998 | * This function sends a single packet to firmware for transmission. |
979 | */ | 999 | */ |
980 | static void | 1000 | static void |
@@ -1001,7 +1021,6 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, | |||
1001 | dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb); | 1021 | dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb); |
1002 | 1022 | ||
1003 | ptr->total_pkts_size -= skb->len; | 1023 | ptr->total_pkts_size -= skb->len; |
1004 | ptr->total_pkts--; | ||
1005 | 1024 | ||
1006 | if (!skb_queue_empty(&ptr->skb_head)) | 1025 | if (!skb_queue_empty(&ptr->skb_head)) |
1007 | skb_next = skb_peek(&ptr->skb_head); | 1026 | skb_next = skb_peek(&ptr->skb_head); |
@@ -1027,7 +1046,6 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, | |||
1027 | skb_queue_tail(&ptr->skb_head, skb); | 1046 | skb_queue_tail(&ptr->skb_head, skb); |
1028 | 1047 | ||
1029 | ptr->total_pkts_size += skb->len; | 1048 | ptr->total_pkts_size += skb->len; |
1030 | ptr->total_pkts++; | ||
1031 | tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; | 1049 | tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; |
1032 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, | 1050 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, |
1033 | ra_list_flags); | 1051 | ra_list_flags); |
@@ -1213,11 +1231,9 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) | |||
1213 | mwifiex_send_delba(priv, tid_del, ra, 1); | 1231 | mwifiex_send_delba(priv, tid_del, ra, 1); |
1214 | } | 1232 | } |
1215 | } | 1233 | } |
1216 | /* Minimum number of AMSDU */ | ||
1217 | #define MIN_NUM_AMSDU 2 | ||
1218 | |||
1219 | if (mwifiex_is_amsdu_allowed(priv, tid) && | 1234 | if (mwifiex_is_amsdu_allowed(priv, tid) && |
1220 | (ptr->total_pkts >= MIN_NUM_AMSDU)) | 1235 | mwifiex_is_11n_aggragation_possible(priv, ptr, |
1236 | adapter->tx_buf_size)) | ||
1221 | mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, | 1237 | mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, |
1222 | ptr_index, flags); | 1238 | ptr_index, flags); |
1223 | /* ra_list_spinlock has been freed in | 1239 | /* ra_list_spinlock has been freed in |
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ea1395aafa39..995695c28d5c 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -4915,7 +4915,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, | |||
4915 | return ret; | 4915 | return ret; |
4916 | } | 4916 | } |
4917 | 4917 | ||
4918 | static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, | 4918 | static int mwl8k_conf_tx(struct ieee80211_hw *hw, |
4919 | struct ieee80211_vif *vif, u16 queue, | ||
4919 | const struct ieee80211_tx_queue_params *params) | 4920 | const struct ieee80211_tx_queue_params *params) |
4920 | { | 4921 | { |
4921 | struct mwl8k_priv *priv = hw->priv; | 4922 | struct mwl8k_priv *priv = hw->priv; |
@@ -5462,7 +5463,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) | |||
5462 | goto fail; | 5463 | goto fail; |
5463 | 5464 | ||
5464 | for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { | 5465 | for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { |
5465 | rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); | 5466 | rc = mwl8k_conf_tx(hw, NULL, i, &priv->wmm_params[i]); |
5466 | if (rc) | 5467 | if (rc) |
5467 | goto fail; | 5468 | goto fail; |
5468 | } | 5469 | } |
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 726a9343f514..ad9ae04d07aa 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c | |||
@@ -404,7 +404,8 @@ static void p54_configure_filter(struct ieee80211_hw *dev, | |||
404 | p54_set_groupfilter(priv); | 404 | p54_set_groupfilter(priv); |
405 | } | 405 | } |
406 | 406 | ||
407 | static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, | 407 | static int p54_conf_tx(struct ieee80211_hw *dev, |
408 | struct ieee80211_vif *vif, u16 queue, | ||
408 | const struct ieee80211_tx_queue_params *params) | 409 | const struct ieee80211_tx_queue_params *params) |
409 | { | 410 | { |
410 | struct p54_common *priv = dev->priv; | 411 | struct p54_common *priv = dev->priv; |
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 2b97a89e7ff8..f485784a60ae 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c | |||
@@ -689,7 +689,7 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, | |||
689 | if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) | 689 | if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) |
690 | *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; | 690 | *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; |
691 | 691 | ||
692 | if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE) | 692 | if (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE) |
693 | *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; | 693 | *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; |
694 | 694 | ||
695 | if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) | 695 | if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 7e9272b8f01d..3a6b40239bc1 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -1648,7 +1648,8 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
1648 | /* | 1648 | /* |
1649 | * IEEE80211 stack callback functions. | 1649 | * IEEE80211 stack callback functions. |
1650 | */ | 1650 | */ |
1651 | static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, | 1651 | static int rt2400pci_conf_tx(struct ieee80211_hw *hw, |
1652 | struct ieee80211_vif *vif, u16 queue, | ||
1652 | const struct ieee80211_tx_queue_params *params) | 1653 | const struct ieee80211_tx_queue_params *params) |
1653 | { | 1654 | { |
1654 | struct rt2x00_dev *rt2x00dev = hw->priv; | 1655 | struct rt2x00_dev *rt2x00dev = hw->priv; |
@@ -1661,7 +1662,7 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
1661 | if (queue != 0) | 1662 | if (queue != 0) |
1662 | return -EINVAL; | 1663 | return -EINVAL; |
1663 | 1664 | ||
1664 | if (rt2x00mac_conf_tx(hw, queue, params)) | 1665 | if (rt2x00mac_conf_tx(hw, vif, queue, params)) |
1665 | return -EINVAL; | 1666 | return -EINVAL; |
1666 | 1667 | ||
1667 | /* | 1668 | /* |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 9688dd0a7ebd..3f183a15186e 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -4398,7 +4398,8 @@ int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | |||
4398 | } | 4398 | } |
4399 | EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold); | 4399 | EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold); |
4400 | 4400 | ||
4401 | int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, | 4401 | int rt2800_conf_tx(struct ieee80211_hw *hw, |
4402 | struct ieee80211_vif *vif, u16 queue_idx, | ||
4402 | const struct ieee80211_tx_queue_params *params) | 4403 | const struct ieee80211_tx_queue_params *params) |
4403 | { | 4404 | { |
4404 | struct rt2x00_dev *rt2x00dev = hw->priv; | 4405 | struct rt2x00_dev *rt2x00dev = hw->priv; |
@@ -4414,7 +4415,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, | |||
4414 | * we are free to update the registers based on the value | 4415 | * we are free to update the registers based on the value |
4415 | * in the queue parameter. | 4416 | * in the queue parameter. |
4416 | */ | 4417 | */ |
4417 | retval = rt2x00mac_conf_tx(hw, queue_idx, params); | 4418 | retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); |
4418 | if (retval) | 4419 | if (retval) |
4419 | return retval; | 4420 | return retval; |
4420 | 4421 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 6de128e9c612..8c3c281904fe 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h | |||
@@ -197,7 +197,8 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev); | |||
197 | void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32, | 197 | void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32, |
198 | u16 *iv16); | 198 | u16 *iv16); |
199 | int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value); | 199 | int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value); |
200 | int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, | 200 | int rt2800_conf_tx(struct ieee80211_hw *hw, |
201 | struct ieee80211_vif *vif, u16 queue_idx, | ||
201 | const struct ieee80211_tx_queue_params *params); | 202 | const struct ieee80211_tx_queue_params *params); |
202 | u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | 203 | u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); |
203 | int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 204 | int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index cbf8eb334e96..2ec5c00235e6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -1299,7 +1299,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, | |||
1299 | struct ieee80211_vif *vif, | 1299 | struct ieee80211_vif *vif, |
1300 | struct ieee80211_bss_conf *bss_conf, | 1300 | struct ieee80211_bss_conf *bss_conf, |
1301 | u32 changes); | 1301 | u32 changes); |
1302 | int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, | 1302 | int rt2x00mac_conf_tx(struct ieee80211_hw *hw, |
1303 | struct ieee80211_vif *vif, u16 queue, | ||
1303 | const struct ieee80211_tx_queue_params *params); | 1304 | const struct ieee80211_tx_queue_params *params); |
1304 | void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); | 1305 | void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); |
1305 | void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop); | 1306 | void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index cef1c878c37e..bf0acff07807 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -713,7 +713,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, | |||
713 | } | 713 | } |
714 | EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); | 714 | EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); |
715 | 715 | ||
716 | int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, | 716 | int rt2x00mac_conf_tx(struct ieee80211_hw *hw, |
717 | struct ieee80211_vif *vif, u16 queue_idx, | ||
717 | const struct ieee80211_tx_queue_params *params) | 718 | const struct ieee80211_tx_queue_params *params) |
718 | { | 719 | { |
719 | struct rt2x00_dev *rt2x00dev = hw->priv; | 720 | struct rt2x00_dev *rt2x00dev = hw->priv; |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 6b6a8e2dcddc..bf55b4a311e3 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -2883,7 +2883,8 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
2883 | /* | 2883 | /* |
2884 | * IEEE80211 stack callback functions. | 2884 | * IEEE80211 stack callback functions. |
2885 | */ | 2885 | */ |
2886 | static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, | 2886 | static int rt61pci_conf_tx(struct ieee80211_hw *hw, |
2887 | struct ieee80211_vif *vif, u16 queue_idx, | ||
2887 | const struct ieee80211_tx_queue_params *params) | 2888 | const struct ieee80211_tx_queue_params *params) |
2888 | { | 2889 | { |
2889 | struct rt2x00_dev *rt2x00dev = hw->priv; | 2890 | struct rt2x00_dev *rt2x00dev = hw->priv; |
@@ -2899,7 +2900,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, | |||
2899 | * we are free to update the registers based on the value | 2900 | * we are free to update the registers based on the value |
2900 | * in the queue parameter. | 2901 | * in the queue parameter. |
2901 | */ | 2902 | */ |
2902 | retval = rt2x00mac_conf_tx(hw, queue_idx, params); | 2903 | retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); |
2903 | if (retval) | 2904 | if (retval) |
2904 | return retval; | 2905 | return retval; |
2905 | 2906 | ||
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 6f51e39f5595..cfb19dbb0a67 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -2222,7 +2222,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
2222 | /* | 2222 | /* |
2223 | * IEEE80211 stack callback functions. | 2223 | * IEEE80211 stack callback functions. |
2224 | */ | 2224 | */ |
2225 | static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, | 2225 | static int rt73usb_conf_tx(struct ieee80211_hw *hw, |
2226 | struct ieee80211_vif *vif, u16 queue_idx, | ||
2226 | const struct ieee80211_tx_queue_params *params) | 2227 | const struct ieee80211_tx_queue_params *params) |
2227 | { | 2228 | { |
2228 | struct rt2x00_dev *rt2x00dev = hw->priv; | 2229 | struct rt2x00_dev *rt2x00dev = hw->priv; |
@@ -2238,7 +2239,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, | |||
2238 | * we are free to update the registers based on the value | 2239 | * we are free to update the registers based on the value |
2239 | * in the queue parameter. | 2240 | * in the queue parameter. |
2240 | */ | 2241 | */ |
2241 | retval = rt2x00mac_conf_tx(hw, queue_idx, params); | 2242 | retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); |
2242 | if (retval) | 2243 | if (retval) |
2243 | return retval; | 2244 | return retval; |
2244 | 2245 | ||
diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index f5afa155ce91..24873b55b55c 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c | |||
@@ -1241,7 +1241,8 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev, | |||
1241 | rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); | 1241 | rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); |
1242 | } | 1242 | } |
1243 | 1243 | ||
1244 | static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, | 1244 | static int rtl8187_conf_tx(struct ieee80211_hw *dev, |
1245 | struct ieee80211_vif *vif, u16 queue, | ||
1245 | const struct ieee80211_tx_queue_params *params) | 1246 | const struct ieee80211_tx_queue_params *params) |
1246 | { | 1247 | { |
1247 | struct rtl8187_priv *priv = dev->priv; | 1248 | struct rtl8187_priv *priv = dev->priv; |
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 21e40f62a8d7..3f0f056fae9c 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c | |||
@@ -504,7 +504,8 @@ static int _rtl_get_hal_qnum(u16 queue) | |||
504 | *for mac80211 VO=0, VI=1, BE=2, BK=3 | 504 | *for mac80211 VO=0, VI=1, BE=2, BK=3 |
505 | *for rtl819x BE=0, BK=1, VI=2, VO=3 | 505 | *for rtl819x BE=0, BK=1, VI=2, VO=3 |
506 | */ | 506 | */ |
507 | static int rtl_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | 507 | static int rtl_op_conf_tx(struct ieee80211_hw *hw, |
508 | struct ieee80211_vif *vif, u16 queue, | ||
508 | const struct ieee80211_tx_queue_params *param) | 509 | const struct ieee80211_tx_queue_params *param) |
509 | { | 510 | { |
510 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 511 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 4bf3cf457ef0..b42c2e2b2055 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c | |||
@@ -191,44 +191,6 @@ static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val) | |||
191 | _usb_write_async(to_usb_device(dev), addr, val, 4); | 191 | _usb_write_async(to_usb_device(dev), addr, val, 4); |
192 | } | 192 | } |
193 | 193 | ||
194 | static int _usb_nbytes_read_write(struct usb_device *udev, bool read, u32 addr, | ||
195 | u16 len, u8 *pdata) | ||
196 | { | ||
197 | int status; | ||
198 | u8 request; | ||
199 | u16 wvalue; | ||
200 | u16 index; | ||
201 | |||
202 | request = REALTEK_USB_VENQT_CMD_REQ; | ||
203 | index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ | ||
204 | wvalue = (u16)addr; | ||
205 | if (read) | ||
206 | status = _usbctrl_vendorreq_sync_read(udev, request, wvalue, | ||
207 | index, pdata, len); | ||
208 | else | ||
209 | status = _usbctrl_vendorreq_async_write(udev, request, wvalue, | ||
210 | index, pdata, len); | ||
211 | return status; | ||
212 | } | ||
213 | |||
214 | static int _usb_readN_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len, | ||
215 | u8 *pdata) | ||
216 | { | ||
217 | struct device *dev = rtlpriv->io.dev; | ||
218 | |||
219 | return _usb_nbytes_read_write(to_usb_device(dev), true, addr, len, | ||
220 | pdata); | ||
221 | } | ||
222 | |||
223 | static int _usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, u16 len, | ||
224 | u8 *pdata) | ||
225 | { | ||
226 | struct device *dev = rtlpriv->io.dev; | ||
227 | |||
228 | return _usb_nbytes_read_write(to_usb_device(dev), false, addr, len, | ||
229 | pdata); | ||
230 | } | ||
231 | |||
232 | static void _rtl_usb_io_handler_init(struct device *dev, | 194 | static void _rtl_usb_io_handler_init(struct device *dev, |
233 | struct ieee80211_hw *hw) | 195 | struct ieee80211_hw *hw) |
234 | { | 196 | { |
@@ -239,11 +201,9 @@ static void _rtl_usb_io_handler_init(struct device *dev, | |||
239 | rtlpriv->io.write8_async = _usb_write8_async; | 201 | rtlpriv->io.write8_async = _usb_write8_async; |
240 | rtlpriv->io.write16_async = _usb_write16_async; | 202 | rtlpriv->io.write16_async = _usb_write16_async; |
241 | rtlpriv->io.write32_async = _usb_write32_async; | 203 | rtlpriv->io.write32_async = _usb_write32_async; |
242 | rtlpriv->io.writeN_async = _usb_writeN_async; | ||
243 | rtlpriv->io.read8_sync = _usb_read8_sync; | 204 | rtlpriv->io.read8_sync = _usb_read8_sync; |
244 | rtlpriv->io.read16_sync = _usb_read16_sync; | 205 | rtlpriv->io.read16_sync = _usb_read16_sync; |
245 | rtlpriv->io.read32_sync = _usb_read32_sync; | 206 | rtlpriv->io.read32_sync = _usb_read32_sync; |
246 | rtlpriv->io.readN_sync = _usb_readN_sync; | ||
247 | } | 207 | } |
248 | 208 | ||
249 | static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) | 209 | static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) |
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 615f6b4463e6..3126485393d9 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h | |||
@@ -942,16 +942,12 @@ struct rtl_io { | |||
942 | unsigned long pci_base_addr; /*device I/O address */ | 942 | unsigned long pci_base_addr; /*device I/O address */ |
943 | 943 | ||
944 | void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val); | 944 | void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val); |
945 | void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, u16 val); | 945 | void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, __le16 val); |
946 | void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, u32 val); | 946 | void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, __le32 val); |
947 | int (*writeN_async) (struct rtl_priv *rtlpriv, u32 addr, u16 len, | ||
948 | u8 *pdata); | ||
949 | 947 | ||
950 | u8(*read8_sync) (struct rtl_priv *rtlpriv, u32 addr); | 948 | u8(*read8_sync) (struct rtl_priv *rtlpriv, u32 addr); |
951 | u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr); | 949 | u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr); |
952 | u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr); | 950 | u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr); |
953 | int (*readN_sync) (struct rtl_priv *rtlpriv, u32 addr, u16 len, | ||
954 | u8 *pdata); | ||
955 | 951 | ||
956 | }; | 952 | }; |
957 | 953 | ||
diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index a14a48c99cdc..ba3268ea81fe 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c | |||
@@ -1158,7 +1158,8 @@ static struct ieee80211_channel wl1251_channels[] = { | |||
1158 | { .hw_value = 13, .center_freq = 2472}, | 1158 | { .hw_value = 13, .center_freq = 2472}, |
1159 | }; | 1159 | }; |
1160 | 1160 | ||
1161 | static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | 1161 | static int wl1251_op_conf_tx(struct ieee80211_hw *hw, |
1162 | struct ieee80211_vif *vif, u16 queue, | ||
1162 | const struct ieee80211_tx_queue_params *params) | 1163 | const struct ieee80211_tx_queue_params *params) |
1163 | { | 1164 | { |
1164 | enum wl1251_acx_ps_scheme ps_scheme; | 1165 | enum wl1251_acx_ps_scheme ps_scheme; |
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 7d409b0f3357..e2d6edd2fcd2 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c | |||
@@ -3744,7 +3744,8 @@ out: | |||
3744 | mutex_unlock(&wl->mutex); | 3744 | mutex_unlock(&wl->mutex); |
3745 | } | 3745 | } |
3746 | 3746 | ||
3747 | static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | 3747 | static int wl1271_op_conf_tx(struct ieee80211_hw *hw, |
3748 | struct ieee80211_vif *vif, u16 queue, | ||
3748 | const struct ieee80211_tx_queue_params *params) | 3749 | const struct ieee80211_tx_queue_params *params) |
3749 | { | 3750 | { |
3750 | struct wl1271 *wl = hw->priv; | 3751 | struct wl1271 *wl = hw->priv; |
diff --git a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c index 315dd91800b6..6d71cba3a0a5 100644 --- a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c | |||
@@ -141,8 +141,9 @@ static void brcms_ops_sta_notify(struct ieee80211_hw *hw, | |||
141 | struct ieee80211_vif *vif, | 141 | struct ieee80211_vif *vif, |
142 | enum sta_notify_cmd cmd, | 142 | enum sta_notify_cmd cmd, |
143 | struct ieee80211_sta *sta); | 143 | struct ieee80211_sta *sta); |
144 | static int brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, | 144 | static int brcms_ops_conf_tx(struct ieee80211_hw *hw, |
145 | const struct ieee80211_tx_queue_params *params); | 145 | struct ieee80211_vif *vif, u16 queue, |
146 | const struct ieee80211_tx_queue_params *params); | ||
146 | static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, | 147 | static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, |
147 | struct ieee80211_vif *vif); | 148 | struct ieee80211_vif *vif); |
148 | static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 149 | static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
@@ -556,7 +557,7 @@ brcms_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
556 | } | 557 | } |
557 | 558 | ||
558 | static int | 559 | static int |
559 | brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, | 560 | brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, |
560 | const struct ieee80211_tx_queue_params *params) | 561 | const struct ieee80211_tx_queue_params *params) |
561 | { | 562 | { |
562 | struct brcms_info *wl = hw->priv; | 563 | struct brcms_info *wl = hw->priv; |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index b5e0a5c344fd..48363c3c40f8 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -759,6 +759,12 @@ struct ieee80211_mgmt { | |||
759 | u8 action; | 759 | u8 action; |
760 | u8 smps_control; | 760 | u8 smps_control; |
761 | } __attribute__ ((packed)) ht_smps; | 761 | } __attribute__ ((packed)) ht_smps; |
762 | struct { | ||
763 | u8 action_code; | ||
764 | u8 dialog_token; | ||
765 | __le16 capability; | ||
766 | u8 variable[0]; | ||
767 | } __packed tdls_discover_resp; | ||
762 | } u; | 768 | } u; |
763 | } __attribute__ ((packed)) action; | 769 | } __attribute__ ((packed)) action; |
764 | } u; | 770 | } u; |
@@ -805,6 +811,52 @@ struct ieee80211_pspoll { | |||
805 | u8 ta[6]; | 811 | u8 ta[6]; |
806 | } __attribute__ ((packed)); | 812 | } __attribute__ ((packed)); |
807 | 813 | ||
814 | /* TDLS */ | ||
815 | |||
816 | /* Link-id information element */ | ||
817 | struct ieee80211_tdls_lnkie { | ||
818 | u8 ie_type; /* Link Identifier IE */ | ||
819 | u8 ie_len; | ||
820 | u8 bssid[6]; | ||
821 | u8 init_sta[6]; | ||
822 | u8 resp_sta[6]; | ||
823 | } __packed; | ||
824 | |||
825 | struct ieee80211_tdls_data { | ||
826 | u8 da[6]; | ||
827 | u8 sa[6]; | ||
828 | __be16 ether_type; | ||
829 | u8 payload_type; | ||
830 | u8 category; | ||
831 | u8 action_code; | ||
832 | union { | ||
833 | struct { | ||
834 | u8 dialog_token; | ||
835 | __le16 capability; | ||
836 | u8 variable[0]; | ||
837 | } __packed setup_req; | ||
838 | struct { | ||
839 | __le16 status_code; | ||
840 | u8 dialog_token; | ||
841 | __le16 capability; | ||
842 | u8 variable[0]; | ||
843 | } __packed setup_resp; | ||
844 | struct { | ||
845 | __le16 status_code; | ||
846 | u8 dialog_token; | ||
847 | u8 variable[0]; | ||
848 | } __packed setup_cfm; | ||
849 | struct { | ||
850 | __le16 reason_code; | ||
851 | u8 variable[0]; | ||
852 | } __packed teardown; | ||
853 | struct { | ||
854 | u8 dialog_token; | ||
855 | u8 variable[0]; | ||
856 | } __packed discover_req; | ||
857 | } u; | ||
858 | } __packed; | ||
859 | |||
808 | /** | 860 | /** |
809 | * struct ieee80211_bar - HT Block Ack Request | 861 | * struct ieee80211_bar - HT Block Ack Request |
810 | * | 862 | * |
@@ -1196,6 +1248,8 @@ enum ieee80211_eid { | |||
1196 | WLAN_EID_TS_DELAY = 43, | 1248 | WLAN_EID_TS_DELAY = 43, |
1197 | WLAN_EID_TCLAS_PROCESSING = 44, | 1249 | WLAN_EID_TCLAS_PROCESSING = 44, |
1198 | WLAN_EID_QOS_CAPA = 46, | 1250 | WLAN_EID_QOS_CAPA = 46, |
1251 | /* 802.11z */ | ||
1252 | WLAN_EID_LINK_ID = 101, | ||
1199 | /* 802.11s */ | 1253 | /* 802.11s */ |
1200 | WLAN_EID_MESH_CONFIG = 113, | 1254 | WLAN_EID_MESH_CONFIG = 113, |
1201 | WLAN_EID_MESH_ID = 114, | 1255 | WLAN_EID_MESH_ID = 114, |
@@ -1279,6 +1333,7 @@ enum ieee80211_category { | |||
1279 | WLAN_CATEGORY_HT = 7, | 1333 | WLAN_CATEGORY_HT = 7, |
1280 | WLAN_CATEGORY_SA_QUERY = 8, | 1334 | WLAN_CATEGORY_SA_QUERY = 8, |
1281 | WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9, | 1335 | WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9, |
1336 | WLAN_CATEGORY_TDLS = 12, | ||
1282 | WLAN_CATEGORY_MESH_ACTION = 13, | 1337 | WLAN_CATEGORY_MESH_ACTION = 13, |
1283 | WLAN_CATEGORY_MULTIHOP_ACTION = 14, | 1338 | WLAN_CATEGORY_MULTIHOP_ACTION = 14, |
1284 | WLAN_CATEGORY_SELF_PROTECTED = 15, | 1339 | WLAN_CATEGORY_SELF_PROTECTED = 15, |
@@ -1342,6 +1397,36 @@ enum ieee80211_key_len { | |||
1342 | WLAN_KEY_LEN_AES_CMAC = 16, | 1397 | WLAN_KEY_LEN_AES_CMAC = 16, |
1343 | }; | 1398 | }; |
1344 | 1399 | ||
1400 | /* Public action codes */ | ||
1401 | enum ieee80211_pub_actioncode { | ||
1402 | WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14, | ||
1403 | }; | ||
1404 | |||
1405 | /* TDLS action codes */ | ||
1406 | enum ieee80211_tdls_actioncode { | ||
1407 | WLAN_TDLS_SETUP_REQUEST = 0, | ||
1408 | WLAN_TDLS_SETUP_RESPONSE = 1, | ||
1409 | WLAN_TDLS_SETUP_CONFIRM = 2, | ||
1410 | WLAN_TDLS_TEARDOWN = 3, | ||
1411 | WLAN_TDLS_PEER_TRAFFIC_INDICATION = 4, | ||
1412 | WLAN_TDLS_CHANNEL_SWITCH_REQUEST = 5, | ||
1413 | WLAN_TDLS_CHANNEL_SWITCH_RESPONSE = 6, | ||
1414 | WLAN_TDLS_PEER_PSM_REQUEST = 7, | ||
1415 | WLAN_TDLS_PEER_PSM_RESPONSE = 8, | ||
1416 | WLAN_TDLS_PEER_TRAFFIC_RESPONSE = 9, | ||
1417 | WLAN_TDLS_DISCOVERY_REQUEST = 10, | ||
1418 | }; | ||
1419 | |||
1420 | /* | ||
1421 | * TDLS capabililites to be enabled in the 5th byte of the | ||
1422 | * @WLAN_EID_EXT_CAPABILITY information element | ||
1423 | */ | ||
1424 | #define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5) | ||
1425 | #define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6) | ||
1426 | |||
1427 | /* TDLS specific payload type in the LLC/SNAP header */ | ||
1428 | #define WLAN_TDLS_SNAP_RFTYPE 0x2 | ||
1429 | |||
1345 | /** | 1430 | /** |
1346 | * enum - mesh path selection protocol identifier | 1431 | * enum - mesh path selection protocol identifier |
1347 | * | 1432 | * |
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index c63bbd754a84..e473003e4bda 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h | |||
@@ -83,6 +83,7 @@ | |||
83 | #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ | 83 | #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ |
84 | #define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ | 84 | #define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ |
85 | #define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ | 85 | #define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ |
86 | #define ETH_P_TDLS 0x890D /* TDLS */ | ||
86 | #define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ | 87 | #define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ |
87 | #define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ | 88 | #define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ |
88 | #define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ | 89 | #define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ |
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c73582fb9d20..9d797f253d8e 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -506,6 +506,9 @@ | |||
506 | * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace | 506 | * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace |
507 | * of PMKSA caching dandidates. | 507 | * of PMKSA caching dandidates. |
508 | * | 508 | * |
509 | * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup). | ||
510 | * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. | ||
511 | * | ||
509 | * @NL80211_CMD_MAX: highest used command number | 512 | * @NL80211_CMD_MAX: highest used command number |
510 | * @__NL80211_CMD_AFTER_LAST: internal use | 513 | * @__NL80211_CMD_AFTER_LAST: internal use |
511 | */ | 514 | */ |
@@ -632,6 +635,9 @@ enum nl80211_commands { | |||
632 | 635 | ||
633 | NL80211_CMD_PMKSA_CANDIDATE, | 636 | NL80211_CMD_PMKSA_CANDIDATE, |
634 | 637 | ||
638 | NL80211_CMD_TDLS_OPER, | ||
639 | NL80211_CMD_TDLS_MGMT, | ||
640 | |||
635 | /* add new commands above here */ | 641 | /* add new commands above here */ |
636 | 642 | ||
637 | /* used to define NL80211_CMD_MAX below */ | 643 | /* used to define NL80211_CMD_MAX below */ |
@@ -1089,6 +1095,20 @@ enum nl80211_commands { | |||
1089 | * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and | 1095 | * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and |
1090 | * %NL80211_CMD_FRAME commands. | 1096 | * %NL80211_CMD_FRAME commands. |
1091 | * | 1097 | * |
1098 | * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup | ||
1099 | * request, link setup confirm, link teardown, etc.). Values are | ||
1100 | * described in the TDLS (802.11z) specification. | ||
1101 | * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a | ||
1102 | * TDLS conversation between two devices. | ||
1103 | * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see | ||
1104 | * &enum nl80211_tdls_operation, represented as a u8. | ||
1105 | * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate | ||
1106 | * as a TDLS peer sta. | ||
1107 | * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown | ||
1108 | * procedures should be performed by sending TDLS packets via | ||
1109 | * %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be | ||
1110 | * used for asking the driver to perform a TDLS operation. | ||
1111 | * | ||
1092 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1112 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
1093 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1113 | * @__NL80211_ATTR_AFTER_LAST: internal use |
1094 | */ | 1114 | */ |
@@ -1311,6 +1331,12 @@ enum nl80211_attrs { | |||
1311 | 1331 | ||
1312 | NL80211_ATTR_TX_NO_CCK_RATE, | 1332 | NL80211_ATTR_TX_NO_CCK_RATE, |
1313 | 1333 | ||
1334 | NL80211_ATTR_TDLS_ACTION, | ||
1335 | NL80211_ATTR_TDLS_DIALOG_TOKEN, | ||
1336 | NL80211_ATTR_TDLS_OPERATION, | ||
1337 | NL80211_ATTR_TDLS_SUPPORT, | ||
1338 | NL80211_ATTR_TDLS_EXTERNAL_SETUP, | ||
1339 | |||
1314 | /* add attributes here, update the policy in nl80211.c */ | 1340 | /* add attributes here, update the policy in nl80211.c */ |
1315 | 1341 | ||
1316 | __NL80211_ATTR_AFTER_LAST, | 1342 | __NL80211_ATTR_AFTER_LAST, |
@@ -1408,6 +1434,7 @@ enum nl80211_iftype { | |||
1408 | * @NL80211_STA_FLAG_WME: station is WME/QoS capable | 1434 | * @NL80211_STA_FLAG_WME: station is WME/QoS capable |
1409 | * @NL80211_STA_FLAG_MFP: station uses management frame protection | 1435 | * @NL80211_STA_FLAG_MFP: station uses management frame protection |
1410 | * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated | 1436 | * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated |
1437 | * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer | ||
1411 | * @NL80211_STA_FLAG_MAX: highest station flag number currently defined | 1438 | * @NL80211_STA_FLAG_MAX: highest station flag number currently defined |
1412 | * @__NL80211_STA_FLAG_AFTER_LAST: internal use | 1439 | * @__NL80211_STA_FLAG_AFTER_LAST: internal use |
1413 | */ | 1440 | */ |
@@ -1418,6 +1445,7 @@ enum nl80211_sta_flags { | |||
1418 | NL80211_STA_FLAG_WME, | 1445 | NL80211_STA_FLAG_WME, |
1419 | NL80211_STA_FLAG_MFP, | 1446 | NL80211_STA_FLAG_MFP, |
1420 | NL80211_STA_FLAG_AUTHENTICATED, | 1447 | NL80211_STA_FLAG_AUTHENTICATED, |
1448 | NL80211_STA_FLAG_TDLS_PEER, | ||
1421 | 1449 | ||
1422 | /* keep last */ | 1450 | /* keep last */ |
1423 | __NL80211_STA_FLAG_AFTER_LAST, | 1451 | __NL80211_STA_FLAG_AFTER_LAST, |
@@ -2604,4 +2632,20 @@ enum nl80211_pmksa_candidate_attr { | |||
2604 | MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1 | 2632 | MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1 |
2605 | }; | 2633 | }; |
2606 | 2634 | ||
2635 | /** | ||
2636 | * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION | ||
2637 | * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request | ||
2638 | * @NL80211_TDLS_SETUP: Setup TDLS link | ||
2639 | * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established | ||
2640 | * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link | ||
2641 | * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link | ||
2642 | */ | ||
2643 | enum nl80211_tdls_operation { | ||
2644 | NL80211_TDLS_DISCOVERY_REQ, | ||
2645 | NL80211_TDLS_SETUP, | ||
2646 | NL80211_TDLS_TEARDOWN, | ||
2647 | NL80211_TDLS_ENABLE_LINK, | ||
2648 | NL80211_TDLS_DISABLE_LINK, | ||
2649 | }; | ||
2650 | |||
2607 | #endif /* __LINUX_NL80211_H */ | 2651 | #endif /* __LINUX_NL80211_H */ |
diff --git a/include/linux/rfkill-gpio.h b/include/linux/rfkill-gpio.h index a175d0598033..4d09f6eab359 100644 --- a/include/linux/rfkill-gpio.h +++ b/include/linux/rfkill-gpio.h | |||
@@ -30,6 +30,8 @@ | |||
30 | * @reset_gpio: GPIO which is used for reseting rfkill switch | 30 | * @reset_gpio: GPIO which is used for reseting rfkill switch |
31 | * @shutdown_gpio: GPIO which is used for shutdown of rfkill switch | 31 | * @shutdown_gpio: GPIO which is used for shutdown of rfkill switch |
32 | * @power_clk_name: [optional] name of clk to turn off while blocked | 32 | * @power_clk_name: [optional] name of clk to turn off while blocked |
33 | * @gpio_runtime_close: clean up platform specific gpio configuration | ||
34 | * @gpio_runtime_setup: set up platform specific gpio configuration | ||
33 | */ | 35 | */ |
34 | 36 | ||
35 | struct rfkill_gpio_platform_data { | 37 | struct rfkill_gpio_platform_data { |
@@ -38,6 +40,8 @@ struct rfkill_gpio_platform_data { | |||
38 | int shutdown_gpio; | 40 | int shutdown_gpio; |
39 | const char *power_clk_name; | 41 | const char *power_clk_name; |
40 | enum rfkill_type type; | 42 | enum rfkill_type type; |
43 | void (*gpio_runtime_close)(struct platform_device *); | ||
44 | int (*gpio_runtime_setup)(struct platform_device *); | ||
41 | }; | 45 | }; |
42 | 46 | ||
43 | #endif /* __RFKILL_GPIO_H */ | 47 | #endif /* __RFKILL_GPIO_H */ |
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7f878b9d5642..ab90ae0970a6 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -354,8 +354,8 @@ struct l2cap_chan { | |||
354 | __u8 retry_count; | 354 | __u8 retry_count; |
355 | __u8 num_acked; | 355 | __u8 num_acked; |
356 | __u16 sdu_len; | 356 | __u16 sdu_len; |
357 | __u16 partial_sdu_len; | ||
358 | struct sk_buff *sdu; | 357 | struct sk_buff *sdu; |
358 | struct sk_buff *sdu_last_frag; | ||
359 | 359 | ||
360 | __u8 remote_tx_win; | 360 | __u8 remote_tx_win; |
361 | __u8 remote_max_tx; | 361 | __u8 remote_max_tx; |
@@ -448,7 +448,6 @@ enum { | |||
448 | #define L2CAP_CONF_MAX_CONF_RSP 2 | 448 | #define L2CAP_CONF_MAX_CONF_RSP 2 |
449 | 449 | ||
450 | enum { | 450 | enum { |
451 | CONN_SAR_SDU, | ||
452 | CONN_SREJ_SENT, | 451 | CONN_SREJ_SENT, |
453 | CONN_WAIT_F, | 452 | CONN_WAIT_F, |
454 | CONN_SREJ_ACT, | 453 | CONN_SREJ_ACT, |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 31d823a3092b..74f4f85be32f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -424,6 +424,17 @@ enum plink_actions { | |||
424 | }; | 424 | }; |
425 | 425 | ||
426 | /** | 426 | /** |
427 | * enum station_parameters_apply_mask - station parameter values to apply | ||
428 | * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp) | ||
429 | * | ||
430 | * Not all station parameters have in-band "no change" signalling, | ||
431 | * for those that don't these flags will are used. | ||
432 | */ | ||
433 | enum station_parameters_apply_mask { | ||
434 | STATION_PARAM_APPLY_UAPSD = BIT(0), | ||
435 | }; | ||
436 | |||
437 | /** | ||
427 | * struct station_parameters - station parameters | 438 | * struct station_parameters - station parameters |
428 | * | 439 | * |
429 | * Used to change and create a new station. | 440 | * Used to change and create a new station. |
@@ -450,6 +461,7 @@ struct station_parameters { | |||
450 | u8 *supported_rates; | 461 | u8 *supported_rates; |
451 | struct net_device *vlan; | 462 | struct net_device *vlan; |
452 | u32 sta_flags_mask, sta_flags_set; | 463 | u32 sta_flags_mask, sta_flags_set; |
464 | u32 sta_modify_mask; | ||
453 | int listen_interval; | 465 | int listen_interval; |
454 | u16 aid; | 466 | u16 aid; |
455 | u8 supported_rates_len; | 467 | u8 supported_rates_len; |
@@ -1410,6 +1422,9 @@ struct cfg80211_gtk_rekey_data { | |||
1410 | * @set_ringparam: Set tx and rx ring sizes. | 1422 | * @set_ringparam: Set tx and rx ring sizes. |
1411 | * | 1423 | * |
1412 | * @get_ringparam: Get tx and rx ring current and maximum sizes. | 1424 | * @get_ringparam: Get tx and rx ring current and maximum sizes. |
1425 | * | ||
1426 | * @tdls_mgmt: Transmit a TDLS management frame. | ||
1427 | * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup). | ||
1413 | */ | 1428 | */ |
1414 | struct cfg80211_ops { | 1429 | struct cfg80211_ops { |
1415 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | 1430 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
@@ -1593,6 +1608,12 @@ struct cfg80211_ops { | |||
1593 | 1608 | ||
1594 | int (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev, | 1609 | int (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev, |
1595 | struct cfg80211_gtk_rekey_data *data); | 1610 | struct cfg80211_gtk_rekey_data *data); |
1611 | |||
1612 | int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev, | ||
1613 | u8 *peer, u8 action_code, u8 dialog_token, | ||
1614 | u16 status_code, const u8 *buf, size_t len); | ||
1615 | int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev, | ||
1616 | u8 *peer, enum nl80211_tdls_operation oper); | ||
1596 | }; | 1617 | }; |
1597 | 1618 | ||
1598 | /* | 1619 | /* |
@@ -1645,6 +1666,12 @@ struct cfg80211_ops { | |||
1645 | * @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the | 1666 | * @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the |
1646 | * firmware. | 1667 | * firmware. |
1647 | * @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP. | 1668 | * @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP. |
1669 | * @WIPHY_FLAG_SUPPORTS_TDLS: The device supports TDLS (802.11z) operation. | ||
1670 | * @WIPHY_FLAG_TDLS_EXTERNAL_SETUP: The device does not handle TDLS (802.11z) | ||
1671 | * link setup/discovery operations internally. Setup, discovery and | ||
1672 | * teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT | ||
1673 | * command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be | ||
1674 | * used for asking the driver/firmware to perform a TDLS operation. | ||
1648 | */ | 1675 | */ |
1649 | enum wiphy_flags { | 1676 | enum wiphy_flags { |
1650 | WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), | 1677 | WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), |
@@ -1661,6 +1688,8 @@ enum wiphy_flags { | |||
1661 | WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12), | 1688 | WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12), |
1662 | WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13), | 1689 | WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13), |
1663 | WIPHY_FLAG_AP_UAPSD = BIT(14), | 1690 | WIPHY_FLAG_AP_UAPSD = BIT(14), |
1691 | WIPHY_FLAG_SUPPORTS_TDLS = BIT(15), | ||
1692 | WIPHY_FLAG_TDLS_EXTERNAL_SETUP = BIT(16), | ||
1664 | }; | 1693 | }; |
1665 | 1694 | ||
1666 | /** | 1695 | /** |
diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index b0be5fb9de19..7e2c4d483ad0 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h | |||
@@ -251,6 +251,7 @@ enum ieee80211_radiotap_type { | |||
251 | * retries */ | 251 | * retries */ |
252 | #define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ | 252 | #define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ |
253 | #define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ | 253 | #define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ |
254 | #define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* don't expect an ack */ | ||
254 | 255 | ||
255 | 256 | ||
256 | /* For IEEE80211_RADIOTAP_MCS */ | 257 | /* For IEEE80211_RADIOTAP_MCS */ |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1e83afae3c64..cd108dfa1952 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -109,6 +109,7 @@ enum ieee80211_ac_numbers { | |||
109 | IEEE80211_AC_BE = 2, | 109 | IEEE80211_AC_BE = 2, |
110 | IEEE80211_AC_BK = 3, | 110 | IEEE80211_AC_BK = 3, |
111 | }; | 111 | }; |
112 | #define IEEE80211_NUM_ACS 4 | ||
112 | 113 | ||
113 | /** | 114 | /** |
114 | * struct ieee80211_tx_queue_params - transmit queue configuration | 115 | * struct ieee80211_tx_queue_params - transmit queue configuration |
@@ -338,9 +339,9 @@ struct ieee80211_bss_conf { | |||
338 | * used to indicate that a frame was already retried due to PS | 339 | * used to indicate that a frame was already retried due to PS |
339 | * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211, | 340 | * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211, |
340 | * used to indicate frame should not be encrypted | 341 | * used to indicate frame should not be encrypted |
341 | * @IEEE80211_TX_CTL_PSPOLL_RESPONSE: (internal?) | 342 | * @IEEE80211_TX_CTL_POLL_RESPONSE: This frame is a response to a poll |
342 | * This frame is a response to a PS-poll frame and should be sent | 343 | * frame (PS-Poll or uAPSD) and should be sent although the station |
343 | * although the station is in powersave mode. | 344 | * is in powersave mode. |
344 | * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the | 345 | * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the |
345 | * transmit function after the current frame, this can be used | 346 | * transmit function after the current frame, this can be used |
346 | * by drivers to kick the DMA queue only if unset or when the | 347 | * by drivers to kick the DMA queue only if unset or when the |
@@ -366,6 +367,14 @@ struct ieee80211_bss_conf { | |||
366 | * @IEEE80211_TX_CTL_NO_CCK_RATE: This frame will be sent at non CCK rate. | 367 | * @IEEE80211_TX_CTL_NO_CCK_RATE: This frame will be sent at non CCK rate. |
367 | * This flag is actually used for management frame especially for P2P | 368 | * This flag is actually used for management frame especially for P2P |
368 | * frames not being sent at CCK rate in 2GHz band. | 369 | * frames not being sent at CCK rate in 2GHz band. |
370 | * @IEEE80211_TX_STATUS_EOSP: This packet marks the end of service period, | ||
371 | * when its status is reported the service period ends. For frames in | ||
372 | * an SP that mac80211 transmits, it is already set; for driver frames | ||
373 | * the driver may set this flag. It is also used to do the same for | ||
374 | * PS-Poll responses. | ||
375 | * @IEEE80211_TX_CTL_USE_MINRATE: This frame will be sent at lowest rate. | ||
376 | * This flag is used to send nullfunc frame at minimum rate when | ||
377 | * the nullfunc is used for connection monitoring purpose. | ||
369 | * | 378 | * |
370 | * Note: If you have to add new flags to the enumeration, then don't | 379 | * Note: If you have to add new flags to the enumeration, then don't |
371 | * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary. | 380 | * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary. |
@@ -387,7 +396,7 @@ enum mac80211_tx_control_flags { | |||
387 | IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), | 396 | IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), |
388 | IEEE80211_TX_INTFL_RETRIED = BIT(15), | 397 | IEEE80211_TX_INTFL_RETRIED = BIT(15), |
389 | IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), | 398 | IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), |
390 | IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17), | 399 | IEEE80211_TX_CTL_POLL_RESPONSE = BIT(17), |
391 | IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), | 400 | IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), |
392 | IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), | 401 | IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), |
393 | IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20), | 402 | IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20), |
@@ -397,6 +406,8 @@ enum mac80211_tx_control_flags { | |||
397 | IEEE80211_TX_CTL_TX_OFFCHAN = BIT(25), | 406 | IEEE80211_TX_CTL_TX_OFFCHAN = BIT(25), |
398 | IEEE80211_TX_INTFL_TKIP_MIC_FAILURE = BIT(26), | 407 | IEEE80211_TX_INTFL_TKIP_MIC_FAILURE = BIT(26), |
399 | IEEE80211_TX_CTL_NO_CCK_RATE = BIT(27), | 408 | IEEE80211_TX_CTL_NO_CCK_RATE = BIT(27), |
409 | IEEE80211_TX_STATUS_EOSP = BIT(28), | ||
410 | IEEE80211_TX_CTL_USE_MINRATE = BIT(29), | ||
400 | }; | 411 | }; |
401 | 412 | ||
402 | #define IEEE80211_TX_CTL_STBC_SHIFT 23 | 413 | #define IEEE80211_TX_CTL_STBC_SHIFT 23 |
@@ -410,9 +421,9 @@ enum mac80211_tx_control_flags { | |||
410 | IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU | \ | 421 | IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU | \ |
411 | IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK | \ | 422 | IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK | \ |
412 | IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK | \ | 423 | IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK | \ |
413 | IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_PSPOLL_RESPONSE | \ | 424 | IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_POLL_RESPONSE | \ |
414 | IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \ | 425 | IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \ |
415 | IEEE80211_TX_CTL_STBC) | 426 | IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP) |
416 | 427 | ||
417 | /** | 428 | /** |
418 | * enum mac80211_rate_control_flags - per-rate flags set by the | 429 | * enum mac80211_rate_control_flags - per-rate flags set by the |
@@ -1532,6 +1543,95 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, | |||
1532 | */ | 1543 | */ |
1533 | 1544 | ||
1534 | /** | 1545 | /** |
1546 | * DOC: AP support for powersaving clients | ||
1547 | * | ||
1548 | * In order to implement AP and P2P GO modes, mac80211 has support for | ||
1549 | * client powersaving, both "legacy" PS (PS-Poll/null data) and uAPSD. | ||
1550 | * There currently is no support for sAPSD. | ||
1551 | * | ||
1552 | * There is one assumption that mac80211 makes, namely that a client | ||
1553 | * will not poll with PS-Poll and trigger with uAPSD at the same time. | ||
1554 | * Both are supported, and both can be used by the same client, but | ||
1555 | * they can't be used concurrently by the same client. This simplifies | ||
1556 | * the driver code. | ||
1557 | * | ||
1558 | * The first thing to keep in mind is that there is a flag for complete | ||
1559 | * driver implementation: %IEEE80211_HW_AP_LINK_PS. If this flag is set, | ||
1560 | * mac80211 expects the driver to handle most of the state machine for | ||
1561 | * powersaving clients and will ignore the PM bit in incoming frames. | ||
1562 | * Drivers then use ieee80211_sta_ps_transition() to inform mac80211 of | ||
1563 | * stations' powersave transitions. In this mode, mac80211 also doesn't | ||
1564 | * handle PS-Poll/uAPSD. | ||
1565 | * | ||
1566 | * In the mode without %IEEE80211_HW_AP_LINK_PS, mac80211 will check the | ||
1567 | * PM bit in incoming frames for client powersave transitions. When a | ||
1568 | * station goes to sleep, we will stop transmitting to it. There is, | ||
1569 | * however, a race condition: a station might go to sleep while there is | ||
1570 | * data buffered on hardware queues. If the device has support for this | ||
1571 | * it will reject frames, and the driver should give the frames back to | ||
1572 | * mac80211 with the %IEEE80211_TX_STAT_TX_FILTERED flag set which will | ||
1573 | * cause mac80211 to retry the frame when the station wakes up. The | ||
1574 | * driver is also notified of powersave transitions by calling its | ||
1575 | * @sta_notify callback. | ||
1576 | * | ||
1577 | * When the station is asleep, it has three choices: it can wake up, | ||
1578 | * it can PS-Poll, or it can possibly start a uAPSD service period. | ||
1579 | * Waking up is implemented by simply transmitting all buffered (and | ||
1580 | * filtered) frames to the station. This is the easiest case. When | ||
1581 | * the station sends a PS-Poll or a uAPSD trigger frame, mac80211 | ||
1582 | * will inform the driver of this with the @allow_buffered_frames | ||
1583 | * callback; this callback is optional. mac80211 will then transmit | ||
1584 | * the frames as usual and set the %IEEE80211_TX_CTL_POLL_RESPONSE | ||
1585 | * on each frame. The last frame in the service period (or the only | ||
1586 | * response to a PS-Poll) also has %IEEE80211_TX_STATUS_EOSP set to | ||
1587 | * indicate that it ends the service period; as this frame must have | ||
1588 | * TX status report it also sets %IEEE80211_TX_CTL_REQ_TX_STATUS. | ||
1589 | * When TX status is reported for this frame, the service period is | ||
1590 | * marked has having ended and a new one can be started by the peer. | ||
1591 | * | ||
1592 | * Another race condition can happen on some devices like iwlwifi | ||
1593 | * when there are frames queued for the station and it wakes up | ||
1594 | * or polls; the frames that are already queued could end up being | ||
1595 | * transmitted first instead, causing reordering and/or wrong | ||
1596 | * processing of the EOSP. The cause is that allowing frames to be | ||
1597 | * transmitted to a certain station is out-of-band communication to | ||
1598 | * the device. To allow this problem to be solved, the driver can | ||
1599 | * call ieee80211_sta_block_awake() if frames are buffered when it | ||
1600 | * is notified that the station went to sleep. When all these frames | ||
1601 | * have been filtered (see above), it must call the function again | ||
1602 | * to indicate that the station is no longer blocked. | ||
1603 | * | ||
1604 | * If the driver buffers frames in the driver for aggregation in any | ||
1605 | * way, it must use the ieee80211_sta_set_buffered() call when it is | ||
1606 | * notified of the station going to sleep to inform mac80211 of any | ||
1607 | * TIDs that have frames buffered. Note that when a station wakes up | ||
1608 | * this information is reset (hence the requirement to call it when | ||
1609 | * informed of the station going to sleep). Then, when a service | ||
1610 | * period starts for any reason, @release_buffered_frames is called | ||
1611 | * with the number of frames to be released and which TIDs they are | ||
1612 | * to come from. In this case, the driver is responsible for setting | ||
1613 | * the EOSP (for uAPSD) and MORE_DATA bits in the released frames, | ||
1614 | * to help the @more_data paramter is passed to tell the driver if | ||
1615 | * there is more data on other TIDs -- the TIDs to release frames | ||
1616 | * from are ignored since mac80211 doesn't know how many frames the | ||
1617 | * buffers for those TIDs contain. | ||
1618 | * | ||
1619 | * If the driver also implement GO mode, where absence periods may | ||
1620 | * shorten service periods (or abort PS-Poll responses), it must | ||
1621 | * filter those response frames except in the case of frames that | ||
1622 | * are buffered in the driver -- those must remain buffered to avoid | ||
1623 | * reordering. Because it is possible that no frames are released | ||
1624 | * in this case, the driver must call ieee80211_sta_eosp_irqsafe() | ||
1625 | * to indicate to mac80211 that the service period ended anyway. | ||
1626 | * | ||
1627 | * Finally, if frames from multiple TIDs are released from mac80211 | ||
1628 | * but the driver might reorder them, it must clear & set the flags | ||
1629 | * appropriately (only the last frame may have %IEEE80211_TX_STATUS_EOSP) | ||
1630 | * and also take care of the EOSP and MORE_DATA bits in the frame. | ||
1631 | * The driver may also use ieee80211_sta_eosp_irqsafe() in this case. | ||
1632 | */ | ||
1633 | |||
1634 | /** | ||
1535 | * enum ieee80211_filter_flags - hardware filter flags | 1635 | * enum ieee80211_filter_flags - hardware filter flags |
1536 | * | 1636 | * |
1537 | * These flags determine what the filter in hardware should be | 1637 | * These flags determine what the filter in hardware should be |
@@ -1621,6 +1721,17 @@ enum ieee80211_tx_sync_type { | |||
1621 | }; | 1721 | }; |
1622 | 1722 | ||
1623 | /** | 1723 | /** |
1724 | * enum ieee80211_frame_release_type - frame release reason | ||
1725 | * @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll | ||
1726 | * @IEEE80211_FRAME_RELEASE_UAPSD: frame(s) released due to | ||
1727 | * frame received on trigger-enabled AC | ||
1728 | */ | ||
1729 | enum ieee80211_frame_release_type { | ||
1730 | IEEE80211_FRAME_RELEASE_PSPOLL, | ||
1731 | IEEE80211_FRAME_RELEASE_UAPSD, | ||
1732 | }; | ||
1733 | |||
1734 | /** | ||
1624 | * struct ieee80211_ops - callbacks from mac80211 to the driver | 1735 | * struct ieee80211_ops - callbacks from mac80211 to the driver |
1625 | * | 1736 | * |
1626 | * This structure contains various callbacks that the driver may | 1737 | * This structure contains various callbacks that the driver may |
@@ -1930,6 +2041,45 @@ enum ieee80211_tx_sync_type { | |||
1930 | * The callback can sleep. | 2041 | * The callback can sleep. |
1931 | * @rssi_callback: Notify driver when the average RSSI goes above/below | 2042 | * @rssi_callback: Notify driver when the average RSSI goes above/below |
1932 | * thresholds that were registered previously. The callback can sleep. | 2043 | * thresholds that were registered previously. The callback can sleep. |
2044 | * | ||
2045 | * @release_buffered_frames: Release buffered frames according to the given | ||
2046 | * parameters. In the case where the driver buffers some frames for | ||
2047 | * sleeping stations mac80211 will use this callback to tell the driver | ||
2048 | * to release some frames, either for PS-poll or uAPSD. | ||
2049 | * Note that if the @more_data paramter is %false the driver must check | ||
2050 | * if there are more frames on the given TIDs, and if there are more than | ||
2051 | * the frames being released then it must still set the more-data bit in | ||
2052 | * the frame. If the @more_data parameter is %true, then of course the | ||
2053 | * more-data bit must always be set. | ||
2054 | * The @tids parameter tells the driver which TIDs to release frames | ||
2055 | * from, for PS-poll it will always have only a single bit set. | ||
2056 | * In the case this is used for a PS-poll initiated release, the | ||
2057 | * @num_frames parameter will always be 1 so code can be shared. In | ||
2058 | * this case the driver must also set %IEEE80211_TX_STATUS_EOSP flag | ||
2059 | * on the TX status (and must report TX status) so that the PS-poll | ||
2060 | * period is properly ended. This is used to avoid sending multiple | ||
2061 | * responses for a retried PS-poll frame. | ||
2062 | * In the case this is used for uAPSD, the @num_frames parameter may be | ||
2063 | * bigger than one, but the driver may send fewer frames (it must send | ||
2064 | * at least one, however). In this case it is also responsible for | ||
2065 | * setting the EOSP flag in the QoS header of the frames. Also, when the | ||
2066 | * service period ends, the driver must set %IEEE80211_TX_STATUS_EOSP | ||
2067 | * on the last frame in the SP. Alternatively, it may call the function | ||
2068 | * ieee80211_sta_eosp_irqsafe() to inform mac80211 of the end of the SP. | ||
2069 | * This callback must be atomic. | ||
2070 | * @allow_buffered_frames: Prepare device to allow the given number of frames | ||
2071 | * to go out to the given station. The frames will be sent by mac80211 | ||
2072 | * via the usual TX path after this call. The TX information for frames | ||
2073 | * released will also have the %IEEE80211_TX_CTL_POLL_RESPONSE flag set | ||
2074 | * and the last one will also have %IEEE80211_TX_STATUS_EOSP set. In case | ||
2075 | * frames from multiple TIDs are released and the driver might reorder | ||
2076 | * them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag | ||
2077 | * on the last frame and clear it on all others and also handle the EOSP | ||
2078 | * bit in the QoS header correctly. Alternatively, it can also call the | ||
2079 | * ieee80211_sta_eosp_irqsafe() function. | ||
2080 | * The @tids parameter is a bitmap and tells the driver which TIDs the | ||
2081 | * frames will be on; it will at most have two bits set. | ||
2082 | * This callback must be atomic. | ||
1933 | */ | 2083 | */ |
1934 | struct ieee80211_ops { | 2084 | struct ieee80211_ops { |
1935 | void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); | 2085 | void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); |
@@ -2002,7 +2152,8 @@ struct ieee80211_ops { | |||
2002 | struct ieee80211_sta *sta); | 2152 | struct ieee80211_sta *sta); |
2003 | void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 2153 | void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
2004 | enum sta_notify_cmd, struct ieee80211_sta *sta); | 2154 | enum sta_notify_cmd, struct ieee80211_sta *sta); |
2005 | int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, | 2155 | int (*conf_tx)(struct ieee80211_hw *hw, |
2156 | struct ieee80211_vif *vif, u16 queue, | ||
2006 | const struct ieee80211_tx_queue_params *params); | 2157 | const struct ieee80211_tx_queue_params *params); |
2007 | u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | 2158 | u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); |
2008 | void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 2159 | void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
@@ -2044,6 +2195,17 @@ struct ieee80211_ops { | |||
2044 | const struct cfg80211_bitrate_mask *mask); | 2195 | const struct cfg80211_bitrate_mask *mask); |
2045 | void (*rssi_callback)(struct ieee80211_hw *hw, | 2196 | void (*rssi_callback)(struct ieee80211_hw *hw, |
2046 | enum ieee80211_rssi_event rssi_event); | 2197 | enum ieee80211_rssi_event rssi_event); |
2198 | |||
2199 | void (*allow_buffered_frames)(struct ieee80211_hw *hw, | ||
2200 | struct ieee80211_sta *sta, | ||
2201 | u16 tids, int num_frames, | ||
2202 | enum ieee80211_frame_release_type reason, | ||
2203 | bool more_data); | ||
2204 | void (*release_buffered_frames)(struct ieee80211_hw *hw, | ||
2205 | struct ieee80211_sta *sta, | ||
2206 | u16 tids, int num_frames, | ||
2207 | enum ieee80211_frame_release_type reason, | ||
2208 | bool more_data); | ||
2047 | }; | 2209 | }; |
2048 | 2210 | ||
2049 | /** | 2211 | /** |
@@ -2361,17 +2523,35 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta, | |||
2361 | #define IEEE80211_TX_STATUS_HEADROOM 13 | 2523 | #define IEEE80211_TX_STATUS_HEADROOM 13 |
2362 | 2524 | ||
2363 | /** | 2525 | /** |
2364 | * ieee80211_sta_set_tim - set the TIM bit for a sleeping station | 2526 | * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames |
2365 | * @sta: &struct ieee80211_sta pointer for the sleeping station | 2527 | * @sta: &struct ieee80211_sta pointer for the sleeping station |
2528 | * @tid: the TID that has buffered frames | ||
2529 | * @buffered: indicates whether or not frames are buffered for this TID | ||
2366 | * | 2530 | * |
2367 | * If a driver buffers frames for a powersave station instead of passing | 2531 | * If a driver buffers frames for a powersave station instead of passing |
2368 | * them back to mac80211 for retransmission, the station needs to be told | 2532 | * them back to mac80211 for retransmission, the station may still need |
2369 | * to wake up using the TIM bitmap in the beacon. | 2533 | * to be told that there are buffered frames via the TIM bit. |
2370 | * | 2534 | * |
2371 | * This function sets the station's TIM bit - it will be cleared when the | 2535 | * This function informs mac80211 whether or not there are frames that are |
2372 | * station wakes up. | 2536 | * buffered in the driver for a given TID; mac80211 can then use this data |
2537 | * to set the TIM bit (NOTE: This may call back into the driver's set_tim | ||
2538 | * call! Beware of the locking!) | ||
2539 | * | ||
2540 | * If all frames are released to the station (due to PS-poll or uAPSD) | ||
2541 | * then the driver needs to inform mac80211 that there no longer are | ||
2542 | * frames buffered. However, when the station wakes up mac80211 assumes | ||
2543 | * that all buffered frames will be transmitted and clears this data, | ||
2544 | * drivers need to make sure they inform mac80211 about all buffered | ||
2545 | * frames on the sleep transition (sta_notify() with %STA_NOTIFY_SLEEP). | ||
2546 | * | ||
2547 | * Note that technically mac80211 only needs to know this per AC, not per | ||
2548 | * TID, but since driver buffering will inevitably happen per TID (since | ||
2549 | * it is related to aggregation) it is easier to make mac80211 map the | ||
2550 | * TID to the AC as required instead of keeping track in all drivers that | ||
2551 | * use this API. | ||
2373 | */ | 2552 | */ |
2374 | void ieee80211_sta_set_tim(struct ieee80211_sta *sta); | 2553 | void ieee80211_sta_set_buffered(struct ieee80211_sta *sta, |
2554 | u8 tid, bool buffered); | ||
2375 | 2555 | ||
2376 | /** | 2556 | /** |
2377 | * ieee80211_tx_status - transmit status callback | 2557 | * ieee80211_tx_status - transmit status callback |
@@ -3029,6 +3209,24 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | |||
3029 | struct ieee80211_sta *pubsta, bool block); | 3209 | struct ieee80211_sta *pubsta, bool block); |
3030 | 3210 | ||
3031 | /** | 3211 | /** |
3212 | * ieee80211_sta_eosp - notify mac80211 about end of SP | ||
3213 | * @pubsta: the station | ||
3214 | * | ||
3215 | * When a device transmits frames in a way that it can't tell | ||
3216 | * mac80211 in the TX status about the EOSP, it must clear the | ||
3217 | * %IEEE80211_TX_STATUS_EOSP bit and call this function instead. | ||
3218 | * This applies for PS-Poll as well as uAPSD. | ||
3219 | * | ||
3220 | * Note that there is no non-_irqsafe version right now as | ||
3221 | * it wasn't needed, but just like _tx_status() and _rx() | ||
3222 | * must not be mixed in irqsafe/non-irqsafe versions, this | ||
3223 | * function must not be mixed with those either. Use the | ||
3224 | * all irqsafe, or all non-irqsafe, don't mix! If you need | ||
3225 | * the non-irqsafe version of this, you need to add it. | ||
3226 | */ | ||
3227 | void ieee80211_sta_eosp_irqsafe(struct ieee80211_sta *pubsta); | ||
3228 | |||
3229 | /** | ||
3032 | * ieee80211_iter_keys - iterate keys programmed into the device | 3230 | * ieee80211_iter_keys - iterate keys programmed into the device |
3033 | * @hw: pointer obtained from ieee80211_alloc_hw() | 3231 | * @hw: pointer obtained from ieee80211_alloc_hw() |
3034 | * @vif: virtual interface to iterate, may be %NULL for all | 3232 | * @vif: virtual interface to iterate, may be %NULL for all |
@@ -3444,4 +3642,9 @@ void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif, | |||
3444 | int rssi_max_thold); | 3642 | int rssi_max_thold); |
3445 | 3643 | ||
3446 | void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif); | 3644 | void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif); |
3645 | |||
3646 | int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb); | ||
3647 | |||
3648 | int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, | ||
3649 | struct sk_buff *skb); | ||
3447 | #endif /* MAC80211_H */ | 3650 | #endif /* MAC80211_H */ |
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 117e0d161780..062124cd89cf 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c | |||
@@ -349,7 +349,7 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
349 | } | 349 | } |
350 | 350 | ||
351 | chunk = min_t(unsigned int, skb->len, size); | 351 | chunk = min_t(unsigned int, skb->len, size); |
352 | if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { | 352 | if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, chunk)) { |
353 | skb_queue_head(&sk->sk_receive_queue, skb); | 353 | skb_queue_head(&sk->sk_receive_queue, skb); |
354 | if (!copied) | 354 | if (!copied) |
355 | copied = -EFAULT; | 355 | copied = -EFAULT; |
@@ -361,7 +361,33 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
361 | sock_recv_ts_and_drops(msg, sk, skb); | 361 | sock_recv_ts_and_drops(msg, sk, skb); |
362 | 362 | ||
363 | if (!(flags & MSG_PEEK)) { | 363 | if (!(flags & MSG_PEEK)) { |
364 | skb_pull(skb, chunk); | 364 | int skb_len = skb_headlen(skb); |
365 | |||
366 | if (chunk <= skb_len) { | ||
367 | __skb_pull(skb, chunk); | ||
368 | } else { | ||
369 | struct sk_buff *frag; | ||
370 | |||
371 | __skb_pull(skb, skb_len); | ||
372 | chunk -= skb_len; | ||
373 | |||
374 | skb_walk_frags(skb, frag) { | ||
375 | if (chunk <= frag->len) { | ||
376 | /* Pulling partial data */ | ||
377 | skb->len -= chunk; | ||
378 | skb->data_len -= chunk; | ||
379 | __skb_pull(frag, chunk); | ||
380 | break; | ||
381 | } else if (frag->len) { | ||
382 | /* Pulling all frag data */ | ||
383 | chunk -= frag->len; | ||
384 | skb->len -= frag->len; | ||
385 | skb->data_len -= frag->len; | ||
386 | __skb_pull(frag, frag->len); | ||
387 | } | ||
388 | } | ||
389 | } | ||
390 | |||
365 | if (skb->len) { | 391 | if (skb->len) { |
366 | skb_queue_head(&sk->sk_receive_queue, skb); | 392 | skb_queue_head(&sk->sk_receive_queue, skb); |
367 | break; | 393 | break; |
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index d9edfe8bf9d6..91bcd3a961ec 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c | |||
@@ -492,7 +492,10 @@ static int bnep_session(void *arg) | |||
492 | /* RX */ | 492 | /* RX */ |
493 | while ((skb = skb_dequeue(&sk->sk_receive_queue))) { | 493 | while ((skb = skb_dequeue(&sk->sk_receive_queue))) { |
494 | skb_orphan(skb); | 494 | skb_orphan(skb); |
495 | bnep_rx_frame(s, skb); | 495 | if (!skb_linearize(skb)) |
496 | bnep_rx_frame(s, skb); | ||
497 | else | ||
498 | kfree_skb(skb); | ||
496 | } | 499 | } |
497 | 500 | ||
498 | if (sk->sk_state != BT_CONNECTED) | 501 | if (sk->sk_state != BT_CONNECTED) |
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 521baa4fe835..7d00ddf9e9dc 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c | |||
@@ -302,7 +302,10 @@ static int cmtp_session(void *arg) | |||
302 | 302 | ||
303 | while ((skb = skb_dequeue(&sk->sk_receive_queue))) { | 303 | while ((skb = skb_dequeue(&sk->sk_receive_queue))) { |
304 | skb_orphan(skb); | 304 | skb_orphan(skb); |
305 | cmtp_recv_frame(session, skb); | 305 | if (!skb_linearize(skb)) |
306 | cmtp_recv_frame(session, skb); | ||
307 | else | ||
308 | kfree_skb(skb); | ||
306 | } | 309 | } |
307 | 310 | ||
308 | cmtp_process_transmit(session); | 311 | cmtp_process_transmit(session); |
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index c2df7bf1d374..c1c597e3e198 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -56,15 +56,15 @@ static void hci_le_connect(struct hci_conn *conn) | |||
56 | conn->sec_level = BT_SECURITY_LOW; | 56 | conn->sec_level = BT_SECURITY_LOW; |
57 | 57 | ||
58 | memset(&cp, 0, sizeof(cp)); | 58 | memset(&cp, 0, sizeof(cp)); |
59 | cp.scan_interval = cpu_to_le16(0x0004); | 59 | cp.scan_interval = cpu_to_le16(0x0060); |
60 | cp.scan_window = cpu_to_le16(0x0004); | 60 | cp.scan_window = cpu_to_le16(0x0030); |
61 | bacpy(&cp.peer_addr, &conn->dst); | 61 | bacpy(&cp.peer_addr, &conn->dst); |
62 | cp.peer_addr_type = conn->dst_type; | 62 | cp.peer_addr_type = conn->dst_type; |
63 | cp.conn_interval_min = cpu_to_le16(0x0008); | 63 | cp.conn_interval_min = cpu_to_le16(0x0028); |
64 | cp.conn_interval_max = cpu_to_le16(0x0100); | 64 | cp.conn_interval_max = cpu_to_le16(0x0038); |
65 | cp.supervision_timeout = cpu_to_le16(0x0064); | 65 | cp.supervision_timeout = cpu_to_le16(0x002a); |
66 | cp.min_ce_len = cpu_to_le16(0x0001); | 66 | cp.min_ce_len = cpu_to_le16(0x0000); |
67 | cp.max_ce_len = cpu_to_le16(0x0001); | 67 | cp.max_ce_len = cpu_to_le16(0x0000); |
68 | 68 | ||
69 | hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); | 69 | hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); |
70 | } | 70 | } |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 35083f2aa2ea..d7d96b6b1f0d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -2174,7 +2174,10 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff | |||
2174 | hci_dev_lock(hdev); | 2174 | hci_dev_lock(hdev); |
2175 | 2175 | ||
2176 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); | 2176 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); |
2177 | if (conn && conn->state == BT_CONNECTED) { | 2177 | if (!conn) |
2178 | goto unlock; | ||
2179 | |||
2180 | if (conn->state == BT_CONNECTED) { | ||
2178 | hci_conn_hold(conn); | 2181 | hci_conn_hold(conn); |
2179 | conn->disc_timeout = HCI_PAIRING_TIMEOUT; | 2182 | conn->disc_timeout = HCI_PAIRING_TIMEOUT; |
2180 | hci_conn_put(conn); | 2183 | hci_conn_put(conn); |
@@ -2194,6 +2197,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff | |||
2194 | mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure); | 2197 | mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure); |
2195 | } | 2198 | } |
2196 | 2199 | ||
2200 | unlock: | ||
2197 | hci_dev_unlock(hdev); | 2201 | hci_dev_unlock(hdev); |
2198 | } | 2202 | } |
2199 | 2203 | ||
@@ -2834,19 +2838,17 @@ unlock: | |||
2834 | static inline void hci_le_adv_report_evt(struct hci_dev *hdev, | 2838 | static inline void hci_le_adv_report_evt(struct hci_dev *hdev, |
2835 | struct sk_buff *skb) | 2839 | struct sk_buff *skb) |
2836 | { | 2840 | { |
2837 | struct hci_ev_le_advertising_info *ev; | 2841 | u8 num_reports = skb->data[0]; |
2838 | u8 num_reports; | 2842 | void *ptr = &skb->data[1]; |
2839 | |||
2840 | num_reports = skb->data[0]; | ||
2841 | ev = (void *) &skb->data[1]; | ||
2842 | 2843 | ||
2843 | hci_dev_lock(hdev); | 2844 | hci_dev_lock(hdev); |
2844 | 2845 | ||
2845 | hci_add_adv_entry(hdev, ev); | 2846 | while (num_reports--) { |
2847 | struct hci_ev_le_advertising_info *ev = ptr; | ||
2846 | 2848 | ||
2847 | while (--num_reports) { | ||
2848 | ev = (void *) (ev->data + ev->length + 1); | ||
2849 | hci_add_adv_entry(hdev, ev); | 2849 | hci_add_adv_entry(hdev, ev); |
2850 | |||
2851 | ptr += sizeof(*ev) + ev->length + 1; | ||
2850 | } | 2852 | } |
2851 | 2853 | ||
2852 | hci_dev_unlock(hdev); | 2854 | hci_dev_unlock(hdev); |
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index b83979c548b2..075a3e920caf 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c | |||
@@ -716,12 +716,18 @@ static int hidp_session(void *arg) | |||
716 | 716 | ||
717 | while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { | 717 | while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { |
718 | skb_orphan(skb); | 718 | skb_orphan(skb); |
719 | hidp_recv_ctrl_frame(session, skb); | 719 | if (!skb_linearize(skb)) |
720 | hidp_recv_ctrl_frame(session, skb); | ||
721 | else | ||
722 | kfree_skb(skb); | ||
720 | } | 723 | } |
721 | 724 | ||
722 | while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) { | 725 | while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) { |
723 | skb_orphan(skb); | 726 | skb_orphan(skb); |
724 | hidp_recv_intr_frame(session, skb); | 727 | if (!skb_linearize(skb)) |
728 | hidp_recv_intr_frame(session, skb); | ||
729 | else | ||
730 | kfree_skb(skb); | ||
725 | } | 731 | } |
726 | 732 | ||
727 | hidp_process_transmit(session); | 733 | hidp_process_transmit(session); |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 1611b3544bb1..8cd12917733b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -1245,7 +1245,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) | |||
1245 | __clear_retrans_timer(chan); | 1245 | __clear_retrans_timer(chan); |
1246 | } | 1246 | } |
1247 | 1247 | ||
1248 | void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) | 1248 | static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) |
1249 | { | 1249 | { |
1250 | struct hci_conn *hcon = chan->conn->hcon; | 1250 | struct hci_conn *hcon = chan->conn->hcon; |
1251 | u16 flags; | 1251 | u16 flags; |
@@ -1261,7 +1261,7 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) | |||
1261 | hci_send_acl(hcon, skb, flags); | 1261 | hci_send_acl(hcon, skb, flags); |
1262 | } | 1262 | } |
1263 | 1263 | ||
1264 | void l2cap_streaming_send(struct l2cap_chan *chan) | 1264 | static void l2cap_streaming_send(struct l2cap_chan *chan) |
1265 | { | 1265 | { |
1266 | struct sk_buff *skb; | 1266 | struct sk_buff *skb; |
1267 | u16 control, fcs; | 1267 | u16 control, fcs; |
@@ -1327,7 +1327,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) | |||
1327 | l2cap_do_send(chan, tx_skb); | 1327 | l2cap_do_send(chan, tx_skb); |
1328 | } | 1328 | } |
1329 | 1329 | ||
1330 | int l2cap_ertm_send(struct l2cap_chan *chan) | 1330 | static int l2cap_ertm_send(struct l2cap_chan *chan) |
1331 | { | 1331 | { |
1332 | struct sk_buff *skb, *tx_skb; | 1332 | struct sk_buff *skb, *tx_skb; |
1333 | u16 control, fcs; | 1333 | u16 control, fcs; |
@@ -1465,7 +1465,7 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in | |||
1465 | return sent; | 1465 | return sent; |
1466 | } | 1466 | } |
1467 | 1467 | ||
1468 | struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) | 1468 | static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) |
1469 | { | 1469 | { |
1470 | struct sock *sk = chan->sk; | 1470 | struct sock *sk = chan->sk; |
1471 | struct l2cap_conn *conn = chan->conn; | 1471 | struct l2cap_conn *conn = chan->conn; |
@@ -1495,7 +1495,7 @@ struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr | |||
1495 | return skb; | 1495 | return skb; |
1496 | } | 1496 | } |
1497 | 1497 | ||
1498 | struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) | 1498 | static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) |
1499 | { | 1499 | { |
1500 | struct sock *sk = chan->sk; | 1500 | struct sock *sk = chan->sk; |
1501 | struct l2cap_conn *conn = chan->conn; | 1501 | struct l2cap_conn *conn = chan->conn; |
@@ -1572,7 +1572,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, | |||
1572 | return skb; | 1572 | return skb; |
1573 | } | 1573 | } |
1574 | 1574 | ||
1575 | int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) | 1575 | static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) |
1576 | { | 1576 | { |
1577 | struct sk_buff *skb; | 1577 | struct sk_buff *skb; |
1578 | struct sk_buff_head sar_queue; | 1578 | struct sk_buff_head sar_queue; |
@@ -3128,102 +3128,104 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, | |||
3128 | return 0; | 3128 | return 0; |
3129 | } | 3129 | } |
3130 | 3130 | ||
3131 | static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) | 3131 | static void append_skb_frag(struct sk_buff *skb, |
3132 | struct sk_buff *new_frag, struct sk_buff **last_frag) | ||
3132 | { | 3133 | { |
3133 | struct sk_buff *_skb; | 3134 | /* skb->len reflects data in skb as well as all fragments |
3134 | int err; | 3135 | * skb->data_len reflects only data in fragments |
3136 | */ | ||
3137 | if (!skb_has_frag_list(skb)) | ||
3138 | skb_shinfo(skb)->frag_list = new_frag; | ||
3139 | |||
3140 | new_frag->next = NULL; | ||
3141 | |||
3142 | (*last_frag)->next = new_frag; | ||
3143 | *last_frag = new_frag; | ||
3144 | |||
3145 | skb->len += new_frag->len; | ||
3146 | skb->data_len += new_frag->len; | ||
3147 | skb->truesize += new_frag->truesize; | ||
3148 | } | ||
3149 | |||
3150 | static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) | ||
3151 | { | ||
3152 | int err = -EINVAL; | ||
3135 | 3153 | ||
3136 | switch (control & L2CAP_CTRL_SAR) { | 3154 | switch (control & L2CAP_CTRL_SAR) { |
3137 | case L2CAP_SDU_UNSEGMENTED: | 3155 | case L2CAP_SDU_UNSEGMENTED: |
3138 | if (test_bit(CONN_SAR_SDU, &chan->conn_state)) | 3156 | if (chan->sdu) |
3139 | goto drop; | 3157 | break; |
3140 | 3158 | ||
3141 | return chan->ops->recv(chan->data, skb); | 3159 | err = chan->ops->recv(chan->data, skb); |
3160 | break; | ||
3142 | 3161 | ||
3143 | case L2CAP_SDU_START: | 3162 | case L2CAP_SDU_START: |
3144 | if (test_bit(CONN_SAR_SDU, &chan->conn_state)) | 3163 | if (chan->sdu) |
3145 | goto drop; | 3164 | break; |
3146 | 3165 | ||
3147 | chan->sdu_len = get_unaligned_le16(skb->data); | 3166 | chan->sdu_len = get_unaligned_le16(skb->data); |
3167 | skb_pull(skb, 2); | ||
3148 | 3168 | ||
3149 | if (chan->sdu_len > chan->imtu) | 3169 | if (chan->sdu_len > chan->imtu) { |
3150 | goto disconnect; | 3170 | err = -EMSGSIZE; |
3151 | 3171 | break; | |
3152 | chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); | 3172 | } |
3153 | if (!chan->sdu) | ||
3154 | return -ENOMEM; | ||
3155 | 3173 | ||
3156 | /* pull sdu_len bytes only after alloc, because of Local Busy | 3174 | if (skb->len >= chan->sdu_len) |
3157 | * condition we have to be sure that this will be executed | 3175 | break; |
3158 | * only once, i.e., when alloc does not fail */ | ||
3159 | skb_pull(skb, 2); | ||
3160 | 3176 | ||
3161 | memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); | 3177 | chan->sdu = skb; |
3178 | chan->sdu_last_frag = skb; | ||
3162 | 3179 | ||
3163 | set_bit(CONN_SAR_SDU, &chan->conn_state); | 3180 | skb = NULL; |
3164 | chan->partial_sdu_len = skb->len; | 3181 | err = 0; |
3165 | break; | 3182 | break; |
3166 | 3183 | ||
3167 | case L2CAP_SDU_CONTINUE: | 3184 | case L2CAP_SDU_CONTINUE: |
3168 | if (!test_bit(CONN_SAR_SDU, &chan->conn_state)) | ||
3169 | goto disconnect; | ||
3170 | |||
3171 | if (!chan->sdu) | 3185 | if (!chan->sdu) |
3172 | goto disconnect; | 3186 | break; |
3173 | 3187 | ||
3174 | chan->partial_sdu_len += skb->len; | 3188 | append_skb_frag(chan->sdu, skb, |
3175 | if (chan->partial_sdu_len > chan->sdu_len) | 3189 | &chan->sdu_last_frag); |
3176 | goto drop; | 3190 | skb = NULL; |
3177 | 3191 | ||
3178 | memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); | 3192 | if (chan->sdu->len >= chan->sdu_len) |
3193 | break; | ||
3179 | 3194 | ||
3195 | err = 0; | ||
3180 | break; | 3196 | break; |
3181 | 3197 | ||
3182 | case L2CAP_SDU_END: | 3198 | case L2CAP_SDU_END: |
3183 | if (!test_bit(CONN_SAR_SDU, &chan->conn_state)) | ||
3184 | goto disconnect; | ||
3185 | |||
3186 | if (!chan->sdu) | 3199 | if (!chan->sdu) |
3187 | goto disconnect; | 3200 | break; |
3188 | |||
3189 | chan->partial_sdu_len += skb->len; | ||
3190 | |||
3191 | if (chan->partial_sdu_len > chan->imtu) | ||
3192 | goto drop; | ||
3193 | 3201 | ||
3194 | if (chan->partial_sdu_len != chan->sdu_len) | 3202 | append_skb_frag(chan->sdu, skb, |
3195 | goto drop; | 3203 | &chan->sdu_last_frag); |
3204 | skb = NULL; | ||
3196 | 3205 | ||
3197 | memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); | 3206 | if (chan->sdu->len != chan->sdu_len) |
3207 | break; | ||
3198 | 3208 | ||
3199 | _skb = skb_clone(chan->sdu, GFP_ATOMIC); | 3209 | err = chan->ops->recv(chan->data, chan->sdu); |
3200 | if (!_skb) { | ||
3201 | return -ENOMEM; | ||
3202 | } | ||
3203 | 3210 | ||
3204 | err = chan->ops->recv(chan->data, _skb); | 3211 | if (!err) { |
3205 | if (err < 0) { | 3212 | /* Reassembly complete */ |
3206 | kfree_skb(_skb); | 3213 | chan->sdu = NULL; |
3207 | return err; | 3214 | chan->sdu_last_frag = NULL; |
3215 | chan->sdu_len = 0; | ||
3208 | } | 3216 | } |
3209 | |||
3210 | clear_bit(CONN_SAR_SDU, &chan->conn_state); | ||
3211 | |||
3212 | kfree_skb(chan->sdu); | ||
3213 | break; | 3217 | break; |
3214 | } | 3218 | } |
3215 | 3219 | ||
3216 | kfree_skb(skb); | 3220 | if (err) { |
3217 | return 0; | 3221 | kfree_skb(skb); |
3218 | 3222 | kfree_skb(chan->sdu); | |
3219 | drop: | 3223 | chan->sdu = NULL; |
3220 | kfree_skb(chan->sdu); | 3224 | chan->sdu_last_frag = NULL; |
3221 | chan->sdu = NULL; | 3225 | chan->sdu_len = 0; |
3226 | } | ||
3222 | 3227 | ||
3223 | disconnect: | 3228 | return err; |
3224 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); | ||
3225 | kfree_skb(skb); | ||
3226 | return 0; | ||
3227 | } | 3229 | } |
3228 | 3230 | ||
3229 | static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) | 3231 | static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) |
@@ -3277,99 +3279,6 @@ void l2cap_chan_busy(struct l2cap_chan *chan, int busy) | |||
3277 | } | 3279 | } |
3278 | } | 3280 | } |
3279 | 3281 | ||
3280 | static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) | ||
3281 | { | ||
3282 | struct sk_buff *_skb; | ||
3283 | int err = -EINVAL; | ||
3284 | |||
3285 | /* | ||
3286 | * TODO: We have to notify the userland if some data is lost with the | ||
3287 | * Streaming Mode. | ||
3288 | */ | ||
3289 | |||
3290 | switch (control & L2CAP_CTRL_SAR) { | ||
3291 | case L2CAP_SDU_UNSEGMENTED: | ||
3292 | if (test_bit(CONN_SAR_SDU, &chan->conn_state)) { | ||
3293 | kfree_skb(chan->sdu); | ||
3294 | break; | ||
3295 | } | ||
3296 | |||
3297 | err = chan->ops->recv(chan->data, skb); | ||
3298 | if (!err) | ||
3299 | return 0; | ||
3300 | |||
3301 | break; | ||
3302 | |||
3303 | case L2CAP_SDU_START: | ||
3304 | if (test_bit(CONN_SAR_SDU, &chan->conn_state)) { | ||
3305 | kfree_skb(chan->sdu); | ||
3306 | break; | ||
3307 | } | ||
3308 | |||
3309 | chan->sdu_len = get_unaligned_le16(skb->data); | ||
3310 | skb_pull(skb, 2); | ||
3311 | |||
3312 | if (chan->sdu_len > chan->imtu) { | ||
3313 | err = -EMSGSIZE; | ||
3314 | break; | ||
3315 | } | ||
3316 | |||
3317 | chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); | ||
3318 | if (!chan->sdu) { | ||
3319 | err = -ENOMEM; | ||
3320 | break; | ||
3321 | } | ||
3322 | |||
3323 | memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); | ||
3324 | |||
3325 | set_bit(CONN_SAR_SDU, &chan->conn_state); | ||
3326 | chan->partial_sdu_len = skb->len; | ||
3327 | err = 0; | ||
3328 | break; | ||
3329 | |||
3330 | case L2CAP_SDU_CONTINUE: | ||
3331 | if (!test_bit(CONN_SAR_SDU, &chan->conn_state)) | ||
3332 | break; | ||
3333 | |||
3334 | memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); | ||
3335 | |||
3336 | chan->partial_sdu_len += skb->len; | ||
3337 | if (chan->partial_sdu_len > chan->sdu_len) | ||
3338 | kfree_skb(chan->sdu); | ||
3339 | else | ||
3340 | err = 0; | ||
3341 | |||
3342 | break; | ||
3343 | |||
3344 | case L2CAP_SDU_END: | ||
3345 | if (!test_bit(CONN_SAR_SDU, &chan->conn_state)) | ||
3346 | break; | ||
3347 | |||
3348 | memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); | ||
3349 | |||
3350 | clear_bit(CONN_SAR_SDU, &chan->conn_state); | ||
3351 | chan->partial_sdu_len += skb->len; | ||
3352 | |||
3353 | if (chan->partial_sdu_len > chan->imtu) | ||
3354 | goto drop; | ||
3355 | |||
3356 | if (chan->partial_sdu_len == chan->sdu_len) { | ||
3357 | _skb = skb_clone(chan->sdu, GFP_ATOMIC); | ||
3358 | err = chan->ops->recv(chan->data, _skb); | ||
3359 | if (err < 0) | ||
3360 | kfree_skb(_skb); | ||
3361 | } | ||
3362 | err = 0; | ||
3363 | |||
3364 | drop: | ||
3365 | kfree_skb(chan->sdu); | ||
3366 | break; | ||
3367 | } | ||
3368 | |||
3369 | kfree_skb(skb); | ||
3370 | return err; | ||
3371 | } | ||
3372 | |||
3373 | static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) | 3282 | static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) |
3374 | { | 3283 | { |
3375 | struct sk_buff *skb; | 3284 | struct sk_buff *skb; |
@@ -3384,7 +3293,7 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) | |||
3384 | 3293 | ||
3385 | skb = skb_dequeue(&chan->srej_q); | 3294 | skb = skb_dequeue(&chan->srej_q); |
3386 | control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; | 3295 | control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; |
3387 | err = l2cap_ertm_reassembly_sdu(chan, skb, control); | 3296 | err = l2cap_reassemble_sdu(chan, skb, control); |
3388 | 3297 | ||
3389 | if (err < 0) { | 3298 | if (err < 0) { |
3390 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); | 3299 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); |
@@ -3544,7 +3453,7 @@ expected: | |||
3544 | return 0; | 3453 | return 0; |
3545 | } | 3454 | } |
3546 | 3455 | ||
3547 | err = l2cap_ertm_reassembly_sdu(chan, skb, rx_control); | 3456 | err = l2cap_reassemble_sdu(chan, skb, rx_control); |
3548 | chan->buffer_seq = (chan->buffer_seq + 1) % 64; | 3457 | chan->buffer_seq = (chan->buffer_seq + 1) % 64; |
3549 | if (err < 0) { | 3458 | if (err < 0) { |
3550 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); | 3459 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); |
@@ -3860,12 +3769,20 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk | |||
3860 | 3769 | ||
3861 | tx_seq = __get_txseq(control); | 3770 | tx_seq = __get_txseq(control); |
3862 | 3771 | ||
3863 | if (chan->expected_tx_seq == tx_seq) | 3772 | if (chan->expected_tx_seq != tx_seq) { |
3864 | chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; | 3773 | /* Frame(s) missing - must discard partial SDU */ |
3865 | else | 3774 | kfree_skb(chan->sdu); |
3866 | chan->expected_tx_seq = (tx_seq + 1) % 64; | 3775 | chan->sdu = NULL; |
3776 | chan->sdu_last_frag = NULL; | ||
3777 | chan->sdu_len = 0; | ||
3867 | 3778 | ||
3868 | l2cap_streaming_reassembly_sdu(chan, skb, control); | 3779 | /* TODO: Notify userland of missing data */ |
3780 | } | ||
3781 | |||
3782 | chan->expected_tx_seq = (tx_seq + 1) % 64; | ||
3783 | |||
3784 | if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE) | ||
3785 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); | ||
3869 | 3786 | ||
3870 | goto done; | 3787 | goto done; |
3871 | 3788 | ||
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 5ba3f6df665c..38b618c96de6 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c | |||
@@ -1853,7 +1853,10 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s) | |||
1853 | /* Get data directly from socket receive queue without copying it. */ | 1853 | /* Get data directly from socket receive queue without copying it. */ |
1854 | while ((skb = skb_dequeue(&sk->sk_receive_queue))) { | 1854 | while ((skb = skb_dequeue(&sk->sk_receive_queue))) { |
1855 | skb_orphan(skb); | 1855 | skb_orphan(skb); |
1856 | rfcomm_recv_frame(s, skb); | 1856 | if (!skb_linearize(skb)) |
1857 | rfcomm_recv_frame(s, skb); | ||
1858 | else | ||
1859 | kfree_skb(skb); | ||
1857 | } | 1860 | } |
1858 | 1861 | ||
1859 | if (sk->sk_state == BT_CLOSED) { | 1862 | if (sk->sk_state == BT_CLOSED) { |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index d1886b59bec4..7d3b438755f0 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -225,6 +225,18 @@ config MAC80211_VERBOSE_MHWMP_DEBUG | |||
225 | 225 | ||
226 | Do not select this option. | 226 | Do not select this option. |
227 | 227 | ||
228 | config MAC80211_VERBOSE_TDLS_DEBUG | ||
229 | bool "Verbose TDLS debugging" | ||
230 | depends on MAC80211_DEBUG_MENU | ||
231 | ---help--- | ||
232 | Selecting this option causes mac80211 to print out very | ||
233 | verbose TDLS selection debugging messages (when mac80211 | ||
234 | is a TDLS STA). | ||
235 | It should not be selected on production systems as those | ||
236 | messages are remotely triggerable. | ||
237 | |||
238 | Do not select this option. | ||
239 | |||
228 | config MAC80211_DEBUG_COUNTERS | 240 | config MAC80211_DEBUG_COUNTERS |
229 | bool "Extra statistics for TX/RX debugging" | 241 | bool "Extra statistics for TX/RX debugging" |
230 | depends on MAC80211_DEBUG_MENU | 242 | depends on MAC80211_DEBUG_MENU |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 7c366dfe8da9..97f33588b65f 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -223,7 +223,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
223 | 223 | ||
224 | status = WLAN_STATUS_REQUEST_DECLINED; | 224 | status = WLAN_STATUS_REQUEST_DECLINED; |
225 | 225 | ||
226 | if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) { | 226 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { |
227 | #ifdef CONFIG_MAC80211_HT_DEBUG | 227 | #ifdef CONFIG_MAC80211_HT_DEBUG |
228 | printk(KERN_DEBUG "Suspend in progress. " | 228 | printk(KERN_DEBUG "Suspend in progress. " |
229 | "Denying ADDBA request\n"); | 229 | "Denying ADDBA request\n"); |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 3cef5a7281cb..2ac033989e01 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -382,7 +382,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
382 | sdata->vif.type != NL80211_IFTYPE_AP) | 382 | sdata->vif.type != NL80211_IFTYPE_AP) |
383 | return -EINVAL; | 383 | return -EINVAL; |
384 | 384 | ||
385 | if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) { | 385 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { |
386 | #ifdef CONFIG_MAC80211_HT_DEBUG | 386 | #ifdef CONFIG_MAC80211_HT_DEBUG |
387 | printk(KERN_DEBUG "BA sessions blocked. " | 387 | printk(KERN_DEBUG "BA sessions blocked. " |
388 | "Denying BA session request\n"); | 388 | "Denying BA session request\n"); |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9b1a95e1f56a..55ee5a31756f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <net/net_namespace.h> | 13 | #include <net/net_namespace.h> |
14 | #include <linux/rcupdate.h> | 14 | #include <linux/rcupdate.h> |
15 | #include <linux/if_ether.h> | ||
15 | #include <net/cfg80211.h> | 16 | #include <net/cfg80211.h> |
16 | #include "ieee80211_i.h" | 17 | #include "ieee80211_i.h" |
17 | #include "driver-ops.h" | 18 | #include "driver-ops.h" |
@@ -667,7 +668,6 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
667 | struct sta_info *sta, | 668 | struct sta_info *sta, |
668 | struct station_parameters *params) | 669 | struct station_parameters *params) |
669 | { | 670 | { |
670 | unsigned long flags; | ||
671 | u32 rates; | 671 | u32 rates; |
672 | int i, j; | 672 | int i, j; |
673 | struct ieee80211_supported_band *sband; | 673 | struct ieee80211_supported_band *sband; |
@@ -676,46 +676,58 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
676 | 676 | ||
677 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | 677 | sband = local->hw.wiphy->bands[local->oper_channel->band]; |
678 | 678 | ||
679 | spin_lock_irqsave(&sta->flaglock, flags); | ||
680 | mask = params->sta_flags_mask; | 679 | mask = params->sta_flags_mask; |
681 | set = params->sta_flags_set; | 680 | set = params->sta_flags_set; |
682 | 681 | ||
683 | if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { | 682 | if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { |
684 | sta->flags &= ~WLAN_STA_AUTHORIZED; | ||
685 | if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) | 683 | if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) |
686 | sta->flags |= WLAN_STA_AUTHORIZED; | 684 | set_sta_flag(sta, WLAN_STA_AUTHORIZED); |
685 | else | ||
686 | clear_sta_flag(sta, WLAN_STA_AUTHORIZED); | ||
687 | } | 687 | } |
688 | 688 | ||
689 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { | 689 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { |
690 | sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; | ||
691 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) | 690 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) |
692 | sta->flags |= WLAN_STA_SHORT_PREAMBLE; | 691 | set_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE); |
692 | else | ||
693 | clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE); | ||
693 | } | 694 | } |
694 | 695 | ||
695 | if (mask & BIT(NL80211_STA_FLAG_WME)) { | 696 | if (mask & BIT(NL80211_STA_FLAG_WME)) { |
696 | sta->flags &= ~WLAN_STA_WME; | ||
697 | sta->sta.wme = false; | ||
698 | if (set & BIT(NL80211_STA_FLAG_WME)) { | 697 | if (set & BIT(NL80211_STA_FLAG_WME)) { |
699 | sta->flags |= WLAN_STA_WME; | 698 | set_sta_flag(sta, WLAN_STA_WME); |
700 | sta->sta.wme = true; | 699 | sta->sta.wme = true; |
700 | } else { | ||
701 | clear_sta_flag(sta, WLAN_STA_WME); | ||
702 | sta->sta.wme = false; | ||
701 | } | 703 | } |
702 | } | 704 | } |
703 | 705 | ||
704 | if (mask & BIT(NL80211_STA_FLAG_MFP)) { | 706 | if (mask & BIT(NL80211_STA_FLAG_MFP)) { |
705 | sta->flags &= ~WLAN_STA_MFP; | ||
706 | if (set & BIT(NL80211_STA_FLAG_MFP)) | 707 | if (set & BIT(NL80211_STA_FLAG_MFP)) |
707 | sta->flags |= WLAN_STA_MFP; | 708 | set_sta_flag(sta, WLAN_STA_MFP); |
709 | else | ||
710 | clear_sta_flag(sta, WLAN_STA_MFP); | ||
708 | } | 711 | } |
709 | 712 | ||
710 | if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) { | 713 | if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) { |
711 | sta->flags &= ~WLAN_STA_AUTH; | ||
712 | if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) | 714 | if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) |
713 | sta->flags |= WLAN_STA_AUTH; | 715 | set_sta_flag(sta, WLAN_STA_AUTH); |
716 | else | ||
717 | clear_sta_flag(sta, WLAN_STA_AUTH); | ||
714 | } | 718 | } |
715 | spin_unlock_irqrestore(&sta->flaglock, flags); | ||
716 | 719 | ||
717 | sta->sta.uapsd_queues = params->uapsd_queues; | 720 | if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) { |
718 | sta->sta.max_sp = params->max_sp; | 721 | if (set & BIT(NL80211_STA_FLAG_TDLS_PEER)) |
722 | set_sta_flag(sta, WLAN_STA_TDLS_PEER); | ||
723 | else | ||
724 | clear_sta_flag(sta, WLAN_STA_TDLS_PEER); | ||
725 | } | ||
726 | |||
727 | if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) { | ||
728 | sta->sta.uapsd_queues = params->uapsd_queues; | ||
729 | sta->sta.max_sp = params->max_sp; | ||
730 | } | ||
719 | 731 | ||
720 | /* | 732 | /* |
721 | * cfg80211 validates this (1-2007) and allows setting the AID | 733 | * cfg80211 validates this (1-2007) and allows setting the AID |
@@ -806,10 +818,17 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
806 | if (!sta) | 818 | if (!sta) |
807 | return -ENOMEM; | 819 | return -ENOMEM; |
808 | 820 | ||
809 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | 821 | set_sta_flag(sta, WLAN_STA_AUTH); |
822 | set_sta_flag(sta, WLAN_STA_ASSOC); | ||
810 | 823 | ||
811 | sta_apply_parameters(local, sta, params); | 824 | sta_apply_parameters(local, sta, params); |
812 | 825 | ||
826 | /* Only TDLS-supporting stations can add TDLS peers */ | ||
827 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && | ||
828 | !((wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) && | ||
829 | sdata->vif.type == NL80211_IFTYPE_STATION)) | ||
830 | return -ENOTSUPP; | ||
831 | |||
813 | rate_control_rate_init(sta); | 832 | rate_control_rate_init(sta); |
814 | 833 | ||
815 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 834 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
@@ -862,6 +881,14 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
862 | return -ENOENT; | 881 | return -ENOENT; |
863 | } | 882 | } |
864 | 883 | ||
884 | /* The TDLS bit cannot be toggled after the STA was added */ | ||
885 | if ((params->sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) && | ||
886 | !!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) != | ||
887 | !!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | ||
888 | rcu_read_unlock(); | ||
889 | return -EINVAL; | ||
890 | } | ||
891 | |||
865 | if (params->vlan && params->vlan != sta->sdata->dev) { | 892 | if (params->vlan && params->vlan != sta->sdata->dev) { |
866 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 893 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
867 | 894 | ||
@@ -2126,6 +2153,323 @@ static int ieee80211_set_rekey_data(struct wiphy *wiphy, | |||
2126 | return 0; | 2153 | return 0; |
2127 | } | 2154 | } |
2128 | 2155 | ||
2156 | static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) | ||
2157 | { | ||
2158 | u8 *pos = (void *)skb_put(skb, 7); | ||
2159 | |||
2160 | *pos++ = WLAN_EID_EXT_CAPABILITY; | ||
2161 | *pos++ = 5; /* len */ | ||
2162 | *pos++ = 0x0; | ||
2163 | *pos++ = 0x0; | ||
2164 | *pos++ = 0x0; | ||
2165 | *pos++ = 0x0; | ||
2166 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; | ||
2167 | } | ||
2168 | |||
2169 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata) | ||
2170 | { | ||
2171 | struct ieee80211_local *local = sdata->local; | ||
2172 | u16 capab; | ||
2173 | |||
2174 | capab = 0; | ||
2175 | if (local->oper_channel->band != IEEE80211_BAND_2GHZ) | ||
2176 | return capab; | ||
2177 | |||
2178 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
2179 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
2180 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
2181 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
2182 | |||
2183 | return capab; | ||
2184 | } | ||
2185 | |||
2186 | static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr, | ||
2187 | u8 *peer, u8 *bssid) | ||
2188 | { | ||
2189 | struct ieee80211_tdls_lnkie *lnkid; | ||
2190 | |||
2191 | lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); | ||
2192 | |||
2193 | lnkid->ie_type = WLAN_EID_LINK_ID; | ||
2194 | lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2; | ||
2195 | |||
2196 | memcpy(lnkid->bssid, bssid, ETH_ALEN); | ||
2197 | memcpy(lnkid->init_sta, src_addr, ETH_ALEN); | ||
2198 | memcpy(lnkid->resp_sta, peer, ETH_ALEN); | ||
2199 | } | ||
2200 | |||
2201 | static int | ||
2202 | ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | ||
2203 | u8 *peer, u8 action_code, u8 dialog_token, | ||
2204 | u16 status_code, struct sk_buff *skb) | ||
2205 | { | ||
2206 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2207 | struct ieee80211_tdls_data *tf; | ||
2208 | |||
2209 | tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); | ||
2210 | |||
2211 | memcpy(tf->da, peer, ETH_ALEN); | ||
2212 | memcpy(tf->sa, sdata->vif.addr, ETH_ALEN); | ||
2213 | tf->ether_type = cpu_to_be16(ETH_P_TDLS); | ||
2214 | tf->payload_type = WLAN_TDLS_SNAP_RFTYPE; | ||
2215 | |||
2216 | switch (action_code) { | ||
2217 | case WLAN_TDLS_SETUP_REQUEST: | ||
2218 | tf->category = WLAN_CATEGORY_TDLS; | ||
2219 | tf->action_code = WLAN_TDLS_SETUP_REQUEST; | ||
2220 | |||
2221 | skb_put(skb, sizeof(tf->u.setup_req)); | ||
2222 | tf->u.setup_req.dialog_token = dialog_token; | ||
2223 | tf->u.setup_req.capability = | ||
2224 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||
2225 | |||
2226 | ieee80211_add_srates_ie(&sdata->vif, skb); | ||
2227 | ieee80211_add_ext_srates_ie(&sdata->vif, skb); | ||
2228 | ieee80211_tdls_add_ext_capab(skb); | ||
2229 | break; | ||
2230 | case WLAN_TDLS_SETUP_RESPONSE: | ||
2231 | tf->category = WLAN_CATEGORY_TDLS; | ||
2232 | tf->action_code = WLAN_TDLS_SETUP_RESPONSE; | ||
2233 | |||
2234 | skb_put(skb, sizeof(tf->u.setup_resp)); | ||
2235 | tf->u.setup_resp.status_code = cpu_to_le16(status_code); | ||
2236 | tf->u.setup_resp.dialog_token = dialog_token; | ||
2237 | tf->u.setup_resp.capability = | ||
2238 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||
2239 | |||
2240 | ieee80211_add_srates_ie(&sdata->vif, skb); | ||
2241 | ieee80211_add_ext_srates_ie(&sdata->vif, skb); | ||
2242 | ieee80211_tdls_add_ext_capab(skb); | ||
2243 | break; | ||
2244 | case WLAN_TDLS_SETUP_CONFIRM: | ||
2245 | tf->category = WLAN_CATEGORY_TDLS; | ||
2246 | tf->action_code = WLAN_TDLS_SETUP_CONFIRM; | ||
2247 | |||
2248 | skb_put(skb, sizeof(tf->u.setup_cfm)); | ||
2249 | tf->u.setup_cfm.status_code = cpu_to_le16(status_code); | ||
2250 | tf->u.setup_cfm.dialog_token = dialog_token; | ||
2251 | break; | ||
2252 | case WLAN_TDLS_TEARDOWN: | ||
2253 | tf->category = WLAN_CATEGORY_TDLS; | ||
2254 | tf->action_code = WLAN_TDLS_TEARDOWN; | ||
2255 | |||
2256 | skb_put(skb, sizeof(tf->u.teardown)); | ||
2257 | tf->u.teardown.reason_code = cpu_to_le16(status_code); | ||
2258 | break; | ||
2259 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
2260 | tf->category = WLAN_CATEGORY_TDLS; | ||
2261 | tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST; | ||
2262 | |||
2263 | skb_put(skb, sizeof(tf->u.discover_req)); | ||
2264 | tf->u.discover_req.dialog_token = dialog_token; | ||
2265 | break; | ||
2266 | default: | ||
2267 | return -EINVAL; | ||
2268 | } | ||
2269 | |||
2270 | return 0; | ||
2271 | } | ||
2272 | |||
2273 | static int | ||
2274 | ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | ||
2275 | u8 *peer, u8 action_code, u8 dialog_token, | ||
2276 | u16 status_code, struct sk_buff *skb) | ||
2277 | { | ||
2278 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2279 | struct ieee80211_mgmt *mgmt; | ||
2280 | |||
2281 | mgmt = (void *)skb_put(skb, 24); | ||
2282 | memset(mgmt, 0, 24); | ||
2283 | memcpy(mgmt->da, peer, ETH_ALEN); | ||
2284 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
2285 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); | ||
2286 | |||
2287 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
2288 | IEEE80211_STYPE_ACTION); | ||
2289 | |||
2290 | switch (action_code) { | ||
2291 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
2292 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp)); | ||
2293 | mgmt->u.action.category = WLAN_CATEGORY_PUBLIC; | ||
2294 | mgmt->u.action.u.tdls_discover_resp.action_code = | ||
2295 | WLAN_PUB_ACTION_TDLS_DISCOVER_RES; | ||
2296 | mgmt->u.action.u.tdls_discover_resp.dialog_token = | ||
2297 | dialog_token; | ||
2298 | mgmt->u.action.u.tdls_discover_resp.capability = | ||
2299 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||
2300 | |||
2301 | ieee80211_add_srates_ie(&sdata->vif, skb); | ||
2302 | ieee80211_add_ext_srates_ie(&sdata->vif, skb); | ||
2303 | ieee80211_tdls_add_ext_capab(skb); | ||
2304 | break; | ||
2305 | default: | ||
2306 | return -EINVAL; | ||
2307 | } | ||
2308 | |||
2309 | return 0; | ||
2310 | } | ||
2311 | |||
2312 | static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | ||
2313 | u8 *peer, u8 action_code, u8 dialog_token, | ||
2314 | u16 status_code, const u8 *extra_ies, | ||
2315 | size_t extra_ies_len) | ||
2316 | { | ||
2317 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2318 | struct ieee80211_local *local = sdata->local; | ||
2319 | struct ieee80211_tx_info *info; | ||
2320 | struct sk_buff *skb = NULL; | ||
2321 | bool send_direct; | ||
2322 | int ret; | ||
2323 | |||
2324 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
2325 | return -ENOTSUPP; | ||
2326 | |||
2327 | /* make sure we are in managed mode, and associated */ | ||
2328 | if (sdata->vif.type != NL80211_IFTYPE_STATION || | ||
2329 | !sdata->u.mgd.associated) | ||
2330 | return -EINVAL; | ||
2331 | |||
2332 | #ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG | ||
2333 | printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer); | ||
2334 | #endif | ||
2335 | |||
2336 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
2337 | max(sizeof(struct ieee80211_mgmt), | ||
2338 | sizeof(struct ieee80211_tdls_data)) + | ||
2339 | 50 + /* supported rates */ | ||
2340 | 7 + /* ext capab */ | ||
2341 | extra_ies_len + | ||
2342 | sizeof(struct ieee80211_tdls_lnkie)); | ||
2343 | if (!skb) | ||
2344 | return -ENOMEM; | ||
2345 | |||
2346 | info = IEEE80211_SKB_CB(skb); | ||
2347 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2348 | |||
2349 | switch (action_code) { | ||
2350 | case WLAN_TDLS_SETUP_REQUEST: | ||
2351 | case WLAN_TDLS_SETUP_RESPONSE: | ||
2352 | case WLAN_TDLS_SETUP_CONFIRM: | ||
2353 | case WLAN_TDLS_TEARDOWN: | ||
2354 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
2355 | ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer, | ||
2356 | action_code, dialog_token, | ||
2357 | status_code, skb); | ||
2358 | send_direct = false; | ||
2359 | break; | ||
2360 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
2361 | ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code, | ||
2362 | dialog_token, status_code, | ||
2363 | skb); | ||
2364 | send_direct = true; | ||
2365 | break; | ||
2366 | default: | ||
2367 | ret = -ENOTSUPP; | ||
2368 | break; | ||
2369 | } | ||
2370 | |||
2371 | if (ret < 0) | ||
2372 | goto fail; | ||
2373 | |||
2374 | if (extra_ies_len) | ||
2375 | memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); | ||
2376 | |||
2377 | /* the TDLS link IE is always added last */ | ||
2378 | switch (action_code) { | ||
2379 | case WLAN_TDLS_SETUP_REQUEST: | ||
2380 | case WLAN_TDLS_SETUP_CONFIRM: | ||
2381 | case WLAN_TDLS_TEARDOWN: | ||
2382 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
2383 | /* we are the initiator */ | ||
2384 | ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer, | ||
2385 | sdata->u.mgd.bssid); | ||
2386 | break; | ||
2387 | case WLAN_TDLS_SETUP_RESPONSE: | ||
2388 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
2389 | /* we are the responder */ | ||
2390 | ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr, | ||
2391 | sdata->u.mgd.bssid); | ||
2392 | break; | ||
2393 | default: | ||
2394 | ret = -ENOTSUPP; | ||
2395 | goto fail; | ||
2396 | } | ||
2397 | |||
2398 | if (send_direct) { | ||
2399 | ieee80211_tx_skb(sdata, skb); | ||
2400 | return 0; | ||
2401 | } | ||
2402 | |||
2403 | /* | ||
2404 | * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise | ||
2405 | * we should default to AC_VI. | ||
2406 | */ | ||
2407 | switch (action_code) { | ||
2408 | case WLAN_TDLS_SETUP_REQUEST: | ||
2409 | case WLAN_TDLS_SETUP_RESPONSE: | ||
2410 | skb_set_queue_mapping(skb, IEEE80211_AC_BK); | ||
2411 | skb->priority = 2; | ||
2412 | break; | ||
2413 | default: | ||
2414 | skb_set_queue_mapping(skb, IEEE80211_AC_VI); | ||
2415 | skb->priority = 5; | ||
2416 | break; | ||
2417 | } | ||
2418 | |||
2419 | /* disable bottom halves when entering the Tx path */ | ||
2420 | local_bh_disable(); | ||
2421 | ret = ieee80211_subif_start_xmit(skb, dev); | ||
2422 | local_bh_enable(); | ||
2423 | |||
2424 | return ret; | ||
2425 | |||
2426 | fail: | ||
2427 | dev_kfree_skb(skb); | ||
2428 | return ret; | ||
2429 | } | ||
2430 | |||
2431 | static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | ||
2432 | u8 *peer, enum nl80211_tdls_operation oper) | ||
2433 | { | ||
2434 | struct sta_info *sta; | ||
2435 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2436 | |||
2437 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
2438 | return -ENOTSUPP; | ||
2439 | |||
2440 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
2441 | return -EINVAL; | ||
2442 | |||
2443 | #ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG | ||
2444 | printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer); | ||
2445 | #endif | ||
2446 | |||
2447 | switch (oper) { | ||
2448 | case NL80211_TDLS_ENABLE_LINK: | ||
2449 | rcu_read_lock(); | ||
2450 | sta = sta_info_get(sdata, peer); | ||
2451 | if (!sta) { | ||
2452 | rcu_read_unlock(); | ||
2453 | return -ENOLINK; | ||
2454 | } | ||
2455 | |||
2456 | set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); | ||
2457 | rcu_read_unlock(); | ||
2458 | break; | ||
2459 | case NL80211_TDLS_DISABLE_LINK: | ||
2460 | return sta_info_destroy_addr(sdata, peer); | ||
2461 | case NL80211_TDLS_TEARDOWN: | ||
2462 | case NL80211_TDLS_SETUP: | ||
2463 | case NL80211_TDLS_DISCOVERY_REQ: | ||
2464 | /* We don't support in-driver setup/teardown/discovery */ | ||
2465 | return -ENOTSUPP; | ||
2466 | default: | ||
2467 | return -ENOTSUPP; | ||
2468 | } | ||
2469 | |||
2470 | return 0; | ||
2471 | } | ||
2472 | |||
2129 | struct cfg80211_ops mac80211_config_ops = { | 2473 | struct cfg80211_ops mac80211_config_ops = { |
2130 | .add_virtual_intf = ieee80211_add_iface, | 2474 | .add_virtual_intf = ieee80211_add_iface, |
2131 | .del_virtual_intf = ieee80211_del_iface, | 2475 | .del_virtual_intf = ieee80211_del_iface, |
@@ -2189,4 +2533,6 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2189 | .set_ringparam = ieee80211_set_ringparam, | 2533 | .set_ringparam = ieee80211_set_ringparam, |
2190 | .get_ringparam = ieee80211_get_ringparam, | 2534 | .get_ringparam = ieee80211_get_ringparam, |
2191 | .set_rekey_data = ieee80211_set_rekey_data, | 2535 | .set_rekey_data = ieee80211_set_rekey_data, |
2536 | .tdls_oper = ieee80211_tdls_oper, | ||
2537 | .tdls_mgmt = ieee80211_tdls_mgmt, | ||
2192 | }; | 2538 | }; |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index a01d2137fddc..c5f341798c16 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -56,19 +56,22 @@ STA_FILE(last_signal, last_signal, D); | |||
56 | static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | 56 | static ssize_t sta_flags_read(struct file *file, char __user *userbuf, |
57 | size_t count, loff_t *ppos) | 57 | size_t count, loff_t *ppos) |
58 | { | 58 | { |
59 | char buf[100]; | 59 | char buf[121]; |
60 | struct sta_info *sta = file->private_data; | 60 | struct sta_info *sta = file->private_data; |
61 | u32 staflags = get_sta_flags(sta); | 61 | |
62 | int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s", | 62 | #define TEST(flg) \ |
63 | staflags & WLAN_STA_AUTH ? "AUTH\n" : "", | 63 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" |
64 | staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "", | 64 | |
65 | staflags & WLAN_STA_PS_STA ? "PS (sta)\n" : "", | 65 | int res = scnprintf(buf, sizeof(buf), |
66 | staflags & WLAN_STA_PS_DRIVER ? "PS (driver)\n" : "", | 66 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", |
67 | staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", | 67 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), |
68 | staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", | 68 | TEST(PS_DRIVER), TEST(AUTHORIZED), |
69 | staflags & WLAN_STA_WME ? "WME\n" : "", | 69 | TEST(SHORT_PREAMBLE), TEST(ASSOC_AP), |
70 | staflags & WLAN_STA_WDS ? "WDS\n" : "", | 70 | TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT), |
71 | staflags & WLAN_STA_MFP ? "MFP\n" : ""); | 71 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), |
72 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), | ||
73 | TEST(TDLS_PEER_AUTH)); | ||
74 | #undef TEST | ||
72 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | 75 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); |
73 | } | 76 | } |
74 | STA_OPS(flags); | 77 | STA_OPS(flags); |
@@ -78,8 +81,14 @@ static ssize_t sta_num_ps_buf_frames_read(struct file *file, | |||
78 | size_t count, loff_t *ppos) | 81 | size_t count, loff_t *ppos) |
79 | { | 82 | { |
80 | struct sta_info *sta = file->private_data; | 83 | struct sta_info *sta = file->private_data; |
81 | return mac80211_format_buffer(userbuf, count, ppos, "%u\n", | 84 | char buf[17*IEEE80211_NUM_ACS], *p = buf; |
82 | skb_queue_len(&sta->ps_tx_buf)); | 85 | int ac; |
86 | |||
87 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
88 | p += scnprintf(p, sizeof(buf)+buf-p, "AC%d: %d\n", ac, | ||
89 | skb_queue_len(&sta->ps_tx_buf[ac]) + | ||
90 | skb_queue_len(&sta->tx_filtered[ac])); | ||
91 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | ||
83 | } | 92 | } |
84 | STA_OPS(num_ps_buf_frames); | 93 | STA_OPS(num_ps_buf_frames); |
85 | 94 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4f845c0845ee..5f165d7eb2db 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -423,7 +423,8 @@ static inline int drv_conf_tx(struct ieee80211_local *local, | |||
423 | 423 | ||
424 | trace_drv_conf_tx(local, sdata, queue, params); | 424 | trace_drv_conf_tx(local, sdata, queue, params); |
425 | if (local->ops->conf_tx) | 425 | if (local->ops->conf_tx) |
426 | ret = local->ops->conf_tx(&local->hw, queue, params); | 426 | ret = local->ops->conf_tx(&local->hw, &sdata->vif, |
427 | queue, params); | ||
427 | trace_drv_return_int(local, ret); | 428 | trace_drv_return_int(local, ret); |
428 | return ret; | 429 | return ret; |
429 | } | 430 | } |
@@ -670,4 +671,34 @@ static inline void drv_rssi_callback(struct ieee80211_local *local, | |||
670 | local->ops->rssi_callback(&local->hw, event); | 671 | local->ops->rssi_callback(&local->hw, event); |
671 | trace_drv_return_void(local); | 672 | trace_drv_return_void(local); |
672 | } | 673 | } |
674 | |||
675 | static inline void | ||
676 | drv_release_buffered_frames(struct ieee80211_local *local, | ||
677 | struct sta_info *sta, u16 tids, int num_frames, | ||
678 | enum ieee80211_frame_release_type reason, | ||
679 | bool more_data) | ||
680 | { | ||
681 | trace_drv_release_buffered_frames(local, &sta->sta, tids, num_frames, | ||
682 | reason, more_data); | ||
683 | if (local->ops->release_buffered_frames) | ||
684 | local->ops->release_buffered_frames(&local->hw, &sta->sta, tids, | ||
685 | num_frames, reason, | ||
686 | more_data); | ||
687 | trace_drv_return_void(local); | ||
688 | } | ||
689 | |||
690 | static inline void | ||
691 | drv_allow_buffered_frames(struct ieee80211_local *local, | ||
692 | struct sta_info *sta, u16 tids, int num_frames, | ||
693 | enum ieee80211_frame_release_type reason, | ||
694 | bool more_data) | ||
695 | { | ||
696 | trace_drv_allow_buffered_frames(local, &sta->sta, tids, num_frames, | ||
697 | reason, more_data); | ||
698 | if (local->ops->allow_buffered_frames) | ||
699 | local->ops->allow_buffered_frames(&local->hw, &sta->sta, | ||
700 | tids, num_frames, reason, | ||
701 | more_data); | ||
702 | trace_drv_return_void(local); | ||
703 | } | ||
673 | #endif /* __MAC80211_DRIVER_OPS */ | 704 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index a46b279bbbe4..2af4fca55337 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -1129,6 +1129,61 @@ TRACE_EVENT(drv_rssi_callback, | |||
1129 | ) | 1129 | ) |
1130 | ); | 1130 | ); |
1131 | 1131 | ||
1132 | DECLARE_EVENT_CLASS(release_evt, | ||
1133 | TP_PROTO(struct ieee80211_local *local, | ||
1134 | struct ieee80211_sta *sta, | ||
1135 | u16 tids, int num_frames, | ||
1136 | enum ieee80211_frame_release_type reason, | ||
1137 | bool more_data), | ||
1138 | |||
1139 | TP_ARGS(local, sta, tids, num_frames, reason, more_data), | ||
1140 | |||
1141 | TP_STRUCT__entry( | ||
1142 | LOCAL_ENTRY | ||
1143 | STA_ENTRY | ||
1144 | __field(u16, tids) | ||
1145 | __field(int, num_frames) | ||
1146 | __field(int, reason) | ||
1147 | __field(bool, more_data) | ||
1148 | ), | ||
1149 | |||
1150 | TP_fast_assign( | ||
1151 | LOCAL_ASSIGN; | ||
1152 | STA_ASSIGN; | ||
1153 | __entry->tids = tids; | ||
1154 | __entry->num_frames = num_frames; | ||
1155 | __entry->reason = reason; | ||
1156 | __entry->more_data = more_data; | ||
1157 | ), | ||
1158 | |||
1159 | TP_printk( | ||
1160 | LOCAL_PR_FMT STA_PR_FMT | ||
1161 | " TIDs:0x%.4x frames:%d reason:%d more:%d", | ||
1162 | LOCAL_PR_ARG, STA_PR_ARG, __entry->tids, __entry->num_frames, | ||
1163 | __entry->reason, __entry->more_data | ||
1164 | ) | ||
1165 | ); | ||
1166 | |||
1167 | DEFINE_EVENT(release_evt, drv_release_buffered_frames, | ||
1168 | TP_PROTO(struct ieee80211_local *local, | ||
1169 | struct ieee80211_sta *sta, | ||
1170 | u16 tids, int num_frames, | ||
1171 | enum ieee80211_frame_release_type reason, | ||
1172 | bool more_data), | ||
1173 | |||
1174 | TP_ARGS(local, sta, tids, num_frames, reason, more_data) | ||
1175 | ); | ||
1176 | |||
1177 | DEFINE_EVENT(release_evt, drv_allow_buffered_frames, | ||
1178 | TP_PROTO(struct ieee80211_local *local, | ||
1179 | struct ieee80211_sta *sta, | ||
1180 | u16 tids, int num_frames, | ||
1181 | enum ieee80211_frame_release_type reason, | ||
1182 | bool more_data), | ||
1183 | |||
1184 | TP_ARGS(local, sta, tids, num_frames, reason, more_data) | ||
1185 | ); | ||
1186 | |||
1132 | /* | 1187 | /* |
1133 | * Tracing for API calls that drivers call. | 1188 | * Tracing for API calls that drivers call. |
1134 | */ | 1189 | */ |
@@ -1443,6 +1498,28 @@ TRACE_EVENT(api_enable_rssi_reports, | |||
1443 | ) | 1498 | ) |
1444 | ); | 1499 | ); |
1445 | 1500 | ||
1501 | TRACE_EVENT(api_eosp, | ||
1502 | TP_PROTO(struct ieee80211_local *local, | ||
1503 | struct ieee80211_sta *sta), | ||
1504 | |||
1505 | TP_ARGS(local, sta), | ||
1506 | |||
1507 | TP_STRUCT__entry( | ||
1508 | LOCAL_ENTRY | ||
1509 | STA_ENTRY | ||
1510 | ), | ||
1511 | |||
1512 | TP_fast_assign( | ||
1513 | LOCAL_ASSIGN; | ||
1514 | STA_ASSIGN; | ||
1515 | ), | ||
1516 | |||
1517 | TP_printk( | ||
1518 | LOCAL_PR_FMT STA_PR_FMT, | ||
1519 | LOCAL_PR_ARG, STA_PR_FMT | ||
1520 | ) | ||
1521 | ); | ||
1522 | |||
1446 | /* | 1523 | /* |
1447 | * Tracing for internal functions | 1524 | * Tracing for internal functions |
1448 | * (which may also be called in response to driver calls) | 1525 | * (which may also be called in response to driver calls) |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 2b9b52c69569..f80a35c0d000 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -130,7 +130,7 @@ void ieee80211_ba_session_work(struct work_struct *work) | |||
130 | * down by the code that set the flag, so this | 130 | * down by the code that set the flag, so this |
131 | * need not run. | 131 | * need not run. |
132 | */ | 132 | */ |
133 | if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) | 133 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) |
134 | return; | 134 | return; |
135 | 135 | ||
136 | mutex_lock(&sta->ampdu_mlme.mtx); | 136 | mutex_lock(&sta->ampdu_mlme.mtx); |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 41f16dd1a2b0..ede9a8b341ac 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -314,7 +314,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
314 | } | 314 | } |
315 | 315 | ||
316 | if (sta && elems->wmm_info) | 316 | if (sta && elems->wmm_info) |
317 | set_sta_flags(sta, WLAN_STA_WME); | 317 | set_sta_flag(sta, WLAN_STA_WME); |
318 | 318 | ||
319 | rcu_read_unlock(); | 319 | rcu_read_unlock(); |
320 | } | 320 | } |
@@ -452,7 +452,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
452 | return NULL; | 452 | return NULL; |
453 | 453 | ||
454 | sta->last_rx = jiffies; | 454 | sta->last_rx = jiffies; |
455 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | 455 | set_sta_flag(sta, WLAN_STA_AUTHORIZED); |
456 | 456 | ||
457 | /* make sure mandatory rates are always added */ | 457 | /* make sure mandatory rates are always added */ |
458 | sta->sta.supp_rates[band] = supp_rates | | 458 | sta->sta.supp_rates[band] = supp_rates | |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 5cadcbbc9a57..9fa5f8a674bc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -664,6 +664,11 @@ enum sdata_queue_type { | |||
664 | enum { | 664 | enum { |
665 | IEEE80211_RX_MSG = 1, | 665 | IEEE80211_RX_MSG = 1, |
666 | IEEE80211_TX_STATUS_MSG = 2, | 666 | IEEE80211_TX_STATUS_MSG = 2, |
667 | IEEE80211_EOSP_MSG = 3, | ||
668 | }; | ||
669 | |||
670 | struct skb_eosp_msg_data { | ||
671 | u8 sta[ETH_ALEN], iface[ETH_ALEN]; | ||
667 | }; | 672 | }; |
668 | 673 | ||
669 | enum queue_stop_reason { | 674 | enum queue_stop_reason { |
@@ -1272,6 +1277,7 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke | |||
1272 | struct ieee80211_hdr *hdr, const u8 *tsc, | 1277 | struct ieee80211_hdr *hdr, const u8 *tsc, |
1273 | gfp_t gfp); | 1278 | gfp_t gfp); |
1274 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); | 1279 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); |
1280 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); | ||
1275 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); | 1281 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); |
1276 | void ieee802_11_parse_elems(u8 *start, size_t len, | 1282 | void ieee802_11_parse_elems(u8 *start, size_t len, |
1277 | struct ieee802_11_elems *elems); | 1283 | struct ieee802_11_elems *elems); |
@@ -1303,11 +1309,11 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | |||
1303 | enum queue_stop_reason reason); | 1309 | enum queue_stop_reason reason); |
1304 | void ieee80211_add_pending_skb(struct ieee80211_local *local, | 1310 | void ieee80211_add_pending_skb(struct ieee80211_local *local, |
1305 | struct sk_buff *skb); | 1311 | struct sk_buff *skb); |
1306 | int ieee80211_add_pending_skbs(struct ieee80211_local *local, | 1312 | void ieee80211_add_pending_skbs(struct ieee80211_local *local, |
1307 | struct sk_buff_head *skbs); | 1313 | struct sk_buff_head *skbs); |
1308 | int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | 1314 | void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, |
1309 | struct sk_buff_head *skbs, | 1315 | struct sk_buff_head *skbs, |
1310 | void (*fn)(void *data), void *data); | 1316 | void (*fn)(void *data), void *data); |
1311 | 1317 | ||
1312 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1318 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
1313 | u16 transaction, u16 auth_alg, | 1319 | u16 transaction, u16 auth_alg, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f4350262663f..30d73552e9ab 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -299,8 +299,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
299 | goto err_del_interface; | 299 | goto err_del_interface; |
300 | } | 300 | } |
301 | 301 | ||
302 | /* no locking required since STA is not live yet */ | 302 | /* no atomic bitop required since STA is not live yet */ |
303 | sta->flags |= WLAN_STA_AUTHORIZED; | 303 | set_sta_flag(sta, WLAN_STA_AUTHORIZED); |
304 | 304 | ||
305 | res = sta_info_insert(sta); | 305 | res = sta_info_insert(sta); |
306 | if (res) { | 306 | if (res) { |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 5150c6d11b57..756b157c2edd 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -464,7 +464,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
464 | * some hardware cannot handle TKIP with QoS, so | 464 | * some hardware cannot handle TKIP with QoS, so |
465 | * we indicate whether QoS could be in use. | 465 | * we indicate whether QoS could be in use. |
466 | */ | 466 | */ |
467 | if (test_sta_flags(sta, WLAN_STA_WME)) | 467 | if (test_sta_flag(sta, WLAN_STA_WME)) |
468 | key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; | 468 | key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; |
469 | } else { | 469 | } else { |
470 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 470 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
@@ -478,7 +478,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
478 | /* same here, the AP could be using QoS */ | 478 | /* same here, the AP could be using QoS */ |
479 | ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid); | 479 | ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid); |
480 | if (ap) { | 480 | if (ap) { |
481 | if (test_sta_flags(ap, WLAN_STA_WME)) | 481 | if (test_sta_flag(ap, WLAN_STA_WME)) |
482 | key->conf.flags |= | 482 | key->conf.flags |= |
483 | IEEE80211_KEY_FLAG_WMM_STA; | 483 | IEEE80211_KEY_FLAG_WMM_STA; |
484 | } | 484 | } |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index a5809a1a6239..17b038aeac9b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -325,6 +325,8 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) | |||
325 | static void ieee80211_tasklet_handler(unsigned long data) | 325 | static void ieee80211_tasklet_handler(unsigned long data) |
326 | { | 326 | { |
327 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 327 | struct ieee80211_local *local = (struct ieee80211_local *) data; |
328 | struct sta_info *sta, *tmp; | ||
329 | struct skb_eosp_msg_data *eosp_data; | ||
328 | struct sk_buff *skb; | 330 | struct sk_buff *skb; |
329 | 331 | ||
330 | while ((skb = skb_dequeue(&local->skb_queue)) || | 332 | while ((skb = skb_dequeue(&local->skb_queue)) || |
@@ -340,6 +342,18 @@ static void ieee80211_tasklet_handler(unsigned long data) | |||
340 | skb->pkt_type = 0; | 342 | skb->pkt_type = 0; |
341 | ieee80211_tx_status(local_to_hw(local), skb); | 343 | ieee80211_tx_status(local_to_hw(local), skb); |
342 | break; | 344 | break; |
345 | case IEEE80211_EOSP_MSG: | ||
346 | eosp_data = (void *)skb->cb; | ||
347 | for_each_sta_info(local, eosp_data->sta, sta, tmp) { | ||
348 | /* skip wrong virtual interface */ | ||
349 | if (memcmp(eosp_data->iface, | ||
350 | sta->sdata->vif.addr, ETH_ALEN)) | ||
351 | continue; | ||
352 | clear_sta_flag(sta, WLAN_STA_SP); | ||
353 | break; | ||
354 | } | ||
355 | dev_kfree_skb(skb); | ||
356 | break; | ||
343 | default: | 357 | default: |
344 | WARN(1, "mac80211: Packet is of unknown type %d\n", | 358 | WARN(1, "mac80211: Packet is of unknown type %d\n", |
345 | skb->pkt_type); | 359 | skb->pkt_type); |
@@ -863,6 +877,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
863 | if (local->ops->sched_scan_start) | 877 | if (local->ops->sched_scan_start) |
864 | local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | 878 | local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; |
865 | 879 | ||
880 | /* mac80211 based drivers don't support internal TDLS setup */ | ||
881 | if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) | ||
882 | local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; | ||
883 | |||
866 | result = wiphy_register(local->hw.wiphy); | 884 | result = wiphy_register(local->hw.wiphy); |
867 | if (result < 0) | 885 | if (result < 0) |
868 | goto fail_wiphy_register; | 886 | goto fail_wiphy_register; |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index a4225ae69681..a7078fdba8ca 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -320,64 +320,6 @@ mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
320 | return 0; | 320 | return 0; |
321 | } | 321 | } |
322 | 322 | ||
323 | int | ||
324 | mesh_add_srates_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | ||
325 | { | ||
326 | struct ieee80211_local *local = sdata->local; | ||
327 | struct ieee80211_supported_band *sband; | ||
328 | int rate; | ||
329 | u8 i, rates, *pos; | ||
330 | |||
331 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
332 | rates = sband->n_bitrates; | ||
333 | if (rates > 8) | ||
334 | rates = 8; | ||
335 | |||
336 | if (skb_tailroom(skb) < rates + 2) | ||
337 | return -ENOMEM; | ||
338 | |||
339 | pos = skb_put(skb, rates + 2); | ||
340 | *pos++ = WLAN_EID_SUPP_RATES; | ||
341 | *pos++ = rates; | ||
342 | for (i = 0; i < rates; i++) { | ||
343 | rate = sband->bitrates[i].bitrate; | ||
344 | *pos++ = (u8) (rate / 5); | ||
345 | } | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | int | ||
351 | mesh_add_ext_srates_ie(struct sk_buff *skb, | ||
352 | struct ieee80211_sub_if_data *sdata) | ||
353 | { | ||
354 | struct ieee80211_local *local = sdata->local; | ||
355 | struct ieee80211_supported_band *sband; | ||
356 | int rate; | ||
357 | u8 i, exrates, *pos; | ||
358 | |||
359 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
360 | exrates = sband->n_bitrates; | ||
361 | if (exrates > 8) | ||
362 | exrates -= 8; | ||
363 | else | ||
364 | exrates = 0; | ||
365 | |||
366 | if (skb_tailroom(skb) < exrates + 2) | ||
367 | return -ENOMEM; | ||
368 | |||
369 | if (exrates) { | ||
370 | pos = skb_put(skb, exrates + 2); | ||
371 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
372 | *pos++ = exrates; | ||
373 | for (i = 8; i < sband->n_bitrates; i++) { | ||
374 | rate = sband->bitrates[i].bitrate; | ||
375 | *pos++ = (u8) (rate / 5); | ||
376 | } | ||
377 | } | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | int mesh_add_ds_params_ie(struct sk_buff *skb, | 323 | int mesh_add_ds_params_ie(struct sk_buff *skb, |
382 | struct ieee80211_sub_if_data *sdata) | 324 | struct ieee80211_sub_if_data *sdata) |
383 | { | 325 | { |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 7118e8e8855c..8c00e2d1d636 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -210,10 +210,6 @@ int mesh_add_rsn_ie(struct sk_buff *skb, | |||
210 | struct ieee80211_sub_if_data *sdata); | 210 | struct ieee80211_sub_if_data *sdata); |
211 | int mesh_add_vendor_ies(struct sk_buff *skb, | 211 | int mesh_add_vendor_ies(struct sk_buff *skb, |
212 | struct ieee80211_sub_if_data *sdata); | 212 | struct ieee80211_sub_if_data *sdata); |
213 | int mesh_add_srates_ie(struct sk_buff *skb, | ||
214 | struct ieee80211_sub_if_data *sdata); | ||
215 | int mesh_add_ext_srates_ie(struct sk_buff *skb, | ||
216 | struct ieee80211_sub_if_data *sdata); | ||
217 | int mesh_add_ds_params_ie(struct sk_buff *skb, | 213 | int mesh_add_ds_params_ie(struct sk_buff *skb, |
218 | struct ieee80211_sub_if_data *sdata); | 214 | struct ieee80211_sub_if_data *sdata); |
219 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); | 215 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 1213a23ff0fa..7e57f5d07f66 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -92,7 +92,9 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
92 | if (!sta) | 92 | if (!sta) |
93 | return NULL; | 93 | return NULL; |
94 | 94 | ||
95 | sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH | WLAN_STA_WME; | 95 | set_sta_flag(sta, WLAN_STA_AUTH); |
96 | set_sta_flag(sta, WLAN_STA_AUTHORIZED); | ||
97 | set_sta_flag(sta, WLAN_STA_WME); | ||
96 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; | 98 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; |
97 | rate_control_rate_init(sta); | 99 | rate_control_rate_init(sta); |
98 | 100 | ||
@@ -185,8 +187,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
185 | pos = skb_put(skb, 2); | 187 | pos = skb_put(skb, 2); |
186 | memcpy(pos + 2, &plid, 2); | 188 | memcpy(pos + 2, &plid, 2); |
187 | } | 189 | } |
188 | if (mesh_add_srates_ie(skb, sdata) || | 190 | if (ieee80211_add_srates_ie(&sdata->vif, skb) || |
189 | mesh_add_ext_srates_ie(skb, sdata) || | 191 | ieee80211_add_ext_srates_ie(&sdata->vif, skb) || |
190 | mesh_add_rsn_ie(skb, sdata) || | 192 | mesh_add_rsn_ie(skb, sdata) || |
191 | mesh_add_meshid_ie(skb, sdata) || | 193 | mesh_add_meshid_ie(skb, sdata) || |
192 | mesh_add_meshconf_ie(skb, sdata)) | 194 | mesh_add_meshconf_ie(skb, sdata)) |
@@ -383,7 +385,7 @@ int mesh_plink_open(struct sta_info *sta) | |||
383 | __le16 llid; | 385 | __le16 llid; |
384 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 386 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
385 | 387 | ||
386 | if (!test_sta_flags(sta, WLAN_STA_AUTH)) | 388 | if (!test_sta_flag(sta, WLAN_STA_AUTH)) |
387 | return -EPERM; | 389 | return -EPERM; |
388 | 390 | ||
389 | spin_lock_bh(&sta->lock); | 391 | spin_lock_bh(&sta->lock); |
@@ -503,7 +505,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
503 | return; | 505 | return; |
504 | } | 506 | } |
505 | 507 | ||
506 | if (sta && !test_sta_flags(sta, WLAN_STA_AUTH)) { | 508 | if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) { |
507 | mpl_dbg("Mesh plink: Action frame from non-authed peer\n"); | 509 | mpl_dbg("Mesh plink: Action frame from non-authed peer\n"); |
508 | rcu_read_unlock(); | 510 | rcu_read_unlock(); |
509 | return; | 511 | return; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index cd37a4e3c0d7..0e5d8daba1ee 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -348,6 +348,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
348 | { | 348 | { |
349 | struct sk_buff *skb; | 349 | struct sk_buff *skb; |
350 | struct ieee80211_hdr_3addr *nullfunc; | 350 | struct ieee80211_hdr_3addr *nullfunc; |
351 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
351 | 352 | ||
352 | skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif); | 353 | skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif); |
353 | if (!skb) | 354 | if (!skb) |
@@ -358,6 +359,10 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
358 | nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | 359 | nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); |
359 | 360 | ||
360 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 361 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
362 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | ||
363 | IEEE80211_STA_CONNECTION_POLL)) | ||
364 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE; | ||
365 | |||
361 | ieee80211_tx_skb(sdata, skb); | 366 | ieee80211_tx_skb(sdata, skb); |
362 | } | 367 | } |
363 | 368 | ||
@@ -627,7 +632,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) | |||
627 | { | 632 | { |
628 | struct ieee80211_if_managed *mgd = &sdata->u.mgd; | 633 | struct ieee80211_if_managed *mgd = &sdata->u.mgd; |
629 | struct sta_info *sta = NULL; | 634 | struct sta_info *sta = NULL; |
630 | u32 sta_flags = 0; | 635 | bool authorized = false; |
631 | 636 | ||
632 | if (!mgd->powersave) | 637 | if (!mgd->powersave) |
633 | return false; | 638 | return false; |
@@ -645,13 +650,10 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) | |||
645 | rcu_read_lock(); | 650 | rcu_read_lock(); |
646 | sta = sta_info_get(sdata, mgd->bssid); | 651 | sta = sta_info_get(sdata, mgd->bssid); |
647 | if (sta) | 652 | if (sta) |
648 | sta_flags = get_sta_flags(sta); | 653 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); |
649 | rcu_read_unlock(); | 654 | rcu_read_unlock(); |
650 | 655 | ||
651 | if (!(sta_flags & WLAN_STA_AUTHORIZED)) | 656 | return authorized; |
652 | return false; | ||
653 | |||
654 | return true; | ||
655 | } | 657 | } |
656 | 658 | ||
657 | /* need to hold RTNL or interface lock */ | 659 | /* need to hold RTNL or interface lock */ |
@@ -1095,7 +1097,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1095 | mutex_lock(&local->sta_mtx); | 1097 | mutex_lock(&local->sta_mtx); |
1096 | sta = sta_info_get(sdata, bssid); | 1098 | sta = sta_info_get(sdata, bssid); |
1097 | if (sta) { | 1099 | if (sta) { |
1098 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | 1100 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); |
1099 | ieee80211_sta_tear_down_BA_sessions(sta, tx); | 1101 | ieee80211_sta_tear_down_BA_sessions(sta, tx); |
1100 | } | 1102 | } |
1101 | mutex_unlock(&local->sta_mtx); | 1103 | mutex_unlock(&local->sta_mtx); |
@@ -1137,8 +1139,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1137 | changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; | 1139 | changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; |
1138 | ieee80211_bss_info_change_notify(sdata, changed); | 1140 | ieee80211_bss_info_change_notify(sdata, changed); |
1139 | 1141 | ||
1142 | /* remove AP and TDLS peers */ | ||
1140 | if (remove_sta) | 1143 | if (remove_sta) |
1141 | sta_info_destroy_addr(sdata, bssid); | 1144 | sta_info_flush(local, sdata); |
1142 | 1145 | ||
1143 | del_timer_sync(&sdata->u.mgd.conn_mon_timer); | 1146 | del_timer_sync(&sdata->u.mgd.conn_mon_timer); |
1144 | del_timer_sync(&sdata->u.mgd.bcn_mon_timer); | 1147 | del_timer_sync(&sdata->u.mgd.bcn_mon_timer); |
@@ -1512,10 +1515,11 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1512 | return false; | 1515 | return false; |
1513 | } | 1516 | } |
1514 | 1517 | ||
1515 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | | 1518 | set_sta_flag(sta, WLAN_STA_AUTH); |
1516 | WLAN_STA_ASSOC_AP); | 1519 | set_sta_flag(sta, WLAN_STA_ASSOC); |
1520 | set_sta_flag(sta, WLAN_STA_ASSOC_AP); | ||
1517 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | 1521 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) |
1518 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | 1522 | set_sta_flag(sta, WLAN_STA_AUTHORIZED); |
1519 | 1523 | ||
1520 | rates = 0; | 1524 | rates = 0; |
1521 | basic_rates = 0; | 1525 | basic_rates = 0; |
@@ -1574,10 +1578,10 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1574 | rate_control_rate_init(sta); | 1578 | rate_control_rate_init(sta); |
1575 | 1579 | ||
1576 | if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) | 1580 | if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) |
1577 | set_sta_flags(sta, WLAN_STA_MFP); | 1581 | set_sta_flag(sta, WLAN_STA_MFP); |
1578 | 1582 | ||
1579 | if (elems.wmm_param) | 1583 | if (elems.wmm_param) |
1580 | set_sta_flags(sta, WLAN_STA_WME); | 1584 | set_sta_flag(sta, WLAN_STA_WME); |
1581 | 1585 | ||
1582 | /* sta_info_reinsert will also unlock the mutex lock */ | 1586 | /* sta_info_reinsert will also unlock the mutex lock */ |
1583 | err = sta_info_reinsert(sta); | 1587 | err = sta_info_reinsert(sta); |
@@ -2738,7 +2742,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2738 | req->reason_code, cookie, | 2742 | req->reason_code, cookie, |
2739 | !req->local_state_change); | 2743 | !req->local_state_change); |
2740 | if (assoc_bss) | 2744 | if (assoc_bss) |
2741 | sta_info_destroy_addr(sdata, bssid); | 2745 | sta_info_flush(sdata->local, sdata); |
2742 | 2746 | ||
2743 | mutex_lock(&sdata->local->mtx); | 2747 | mutex_lock(&sdata->local->mtx); |
2744 | ieee80211_recalc_idle(sdata->local); | 2748 | ieee80211_recalc_idle(sdata->local); |
@@ -2778,7 +2782,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2778 | ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, | 2782 | ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, |
2779 | IEEE80211_STYPE_DISASSOC, req->reason_code, | 2783 | IEEE80211_STYPE_DISASSOC, req->reason_code, |
2780 | cookie, !req->local_state_change); | 2784 | cookie, !req->local_state_change); |
2781 | sta_info_destroy_addr(sdata, bssid); | 2785 | sta_info_flush(sdata->local, sdata); |
2782 | 2786 | ||
2783 | mutex_lock(&sdata->local->mtx); | 2787 | mutex_lock(&sdata->local->mtx); |
2784 | ieee80211_recalc_idle(sdata->local); | 2788 | ieee80211_recalc_idle(sdata->local); |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 6326d3439861..9ee7164b207c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -42,7 +42,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
42 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | 42 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { |
43 | mutex_lock(&local->sta_mtx); | 43 | mutex_lock(&local->sta_mtx); |
44 | list_for_each_entry(sta, &local->sta_list, list) { | 44 | list_for_each_entry(sta, &local->sta_list, list) { |
45 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | 45 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); |
46 | ieee80211_sta_tear_down_BA_sessions(sta, true); | 46 | ieee80211_sta_tear_down_BA_sessions(sta, true); |
47 | } | 47 | } |
48 | mutex_unlock(&local->sta_mtx); | 48 | mutex_unlock(&local->sta_mtx); |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index f61244c0e0a2..ff5c3aa48a15 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -199,7 +199,7 @@ static void rate_control_release(struct kref *kref) | |||
199 | kfree(ctrl_ref); | 199 | kfree(ctrl_ref); |
200 | } | 200 | } |
201 | 201 | ||
202 | static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc) | 202 | static bool rc_no_data_or_no_ack_use_min(struct ieee80211_tx_rate_control *txrc) |
203 | { | 203 | { |
204 | struct sk_buff *skb = txrc->skb; | 204 | struct sk_buff *skb = txrc->skb; |
205 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 205 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
@@ -208,7 +208,9 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc) | |||
208 | 208 | ||
209 | fc = hdr->frame_control; | 209 | fc = hdr->frame_control; |
210 | 210 | ||
211 | return (info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc); | 211 | return (info->flags & (IEEE80211_TX_CTL_NO_ACK | |
212 | IEEE80211_TX_CTL_USE_MINRATE)) || | ||
213 | !ieee80211_is_data(fc); | ||
212 | } | 214 | } |
213 | 215 | ||
214 | static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, | 216 | static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, |
@@ -262,7 +264,7 @@ bool rate_control_send_low(struct ieee80211_sta *sta, | |||
262 | struct ieee80211_supported_band *sband = txrc->sband; | 264 | struct ieee80211_supported_band *sband = txrc->sband; |
263 | int mcast_rate; | 265 | int mcast_rate; |
264 | 266 | ||
265 | if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) { | 267 | if (!sta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) { |
266 | if ((sband->band != IEEE80211_BAND_2GHZ) || | 268 | if ((sband->band != IEEE80211_BAND_2GHZ) || |
267 | !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)) | 269 | !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)) |
268 | info->control.rates[0].idx = | 270 | info->control.rates[0].idx = |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index e19249b0f971..cdb28535716b 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -281,6 +281,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
281 | 281 | ||
282 | mr = minstrel_get_ratestats(mi, mg->max_tp_rate); | 282 | mr = minstrel_get_ratestats(mi, mg->max_tp_rate); |
283 | if (cur_tp < mr->cur_tp) { | 283 | if (cur_tp < mr->cur_tp) { |
284 | mi->max_tp_rate2 = mi->max_tp_rate; | ||
285 | cur_tp2 = cur_tp; | ||
284 | mi->max_tp_rate = mg->max_tp_rate; | 286 | mi->max_tp_rate = mg->max_tp_rate; |
285 | cur_tp = mr->cur_tp; | 287 | cur_tp = mr->cur_tp; |
286 | } | 288 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index db46601e50bf..b867bd55de7a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -841,7 +841,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
841 | ieee80211_is_pspoll(hdr->frame_control)) && | 841 | ieee80211_is_pspoll(hdr->frame_control)) && |
842 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && | 842 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && |
843 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && | 843 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && |
844 | (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) { | 844 | (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { |
845 | if (rx->sta && rx->sta->dummy && | 845 | if (rx->sta && rx->sta->dummy && |
846 | ieee80211_is_data_present(hdr->frame_control)) { | 846 | ieee80211_is_data_present(hdr->frame_control)) { |
847 | u16 ethertype; | 847 | u16 ethertype; |
@@ -1110,7 +1110,7 @@ static void ap_sta_ps_start(struct sta_info *sta) | |||
1110 | struct ieee80211_local *local = sdata->local; | 1110 | struct ieee80211_local *local = sdata->local; |
1111 | 1111 | ||
1112 | atomic_inc(&sdata->bss->num_sta_ps); | 1112 | atomic_inc(&sdata->bss->num_sta_ps); |
1113 | set_sta_flags(sta, WLAN_STA_PS_STA); | 1113 | set_sta_flag(sta, WLAN_STA_PS_STA); |
1114 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) | 1114 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
1115 | drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); | 1115 | drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); |
1116 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1116 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
@@ -1130,7 +1130,7 @@ static void ap_sta_ps_end(struct sta_info *sta) | |||
1130 | sdata->name, sta->sta.addr, sta->sta.aid); | 1130 | sdata->name, sta->sta.addr, sta->sta.aid); |
1131 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | 1131 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ |
1132 | 1132 | ||
1133 | if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) { | 1133 | if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { |
1134 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1134 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
1135 | printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n", | 1135 | printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n", |
1136 | sdata->name, sta->sta.addr, sta->sta.aid); | 1136 | sdata->name, sta->sta.addr, sta->sta.aid); |
@@ -1149,7 +1149,7 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start) | |||
1149 | WARN_ON(!(sta_inf->local->hw.flags & IEEE80211_HW_AP_LINK_PS)); | 1149 | WARN_ON(!(sta_inf->local->hw.flags & IEEE80211_HW_AP_LINK_PS)); |
1150 | 1150 | ||
1151 | /* Don't let the same PS state be set twice */ | 1151 | /* Don't let the same PS state be set twice */ |
1152 | in_ps = test_sta_flags(sta_inf, WLAN_STA_PS_STA); | 1152 | in_ps = test_sta_flag(sta_inf, WLAN_STA_PS_STA); |
1153 | if ((start && in_ps) || (!start && !in_ps)) | 1153 | if ((start && in_ps) || (!start && !in_ps)) |
1154 | return -EINVAL; | 1154 | return -EINVAL; |
1155 | 1155 | ||
@@ -1163,6 +1163,81 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start) | |||
1163 | EXPORT_SYMBOL(ieee80211_sta_ps_transition); | 1163 | EXPORT_SYMBOL(ieee80211_sta_ps_transition); |
1164 | 1164 | ||
1165 | static ieee80211_rx_result debug_noinline | 1165 | static ieee80211_rx_result debug_noinline |
1166 | ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx) | ||
1167 | { | ||
1168 | struct ieee80211_sub_if_data *sdata = rx->sdata; | ||
1169 | struct ieee80211_hdr *hdr = (void *)rx->skb->data; | ||
1170 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
1171 | int tid, ac; | ||
1172 | |||
1173 | if (!rx->sta || !(status->rx_flags & IEEE80211_RX_RA_MATCH)) | ||
1174 | return RX_CONTINUE; | ||
1175 | |||
1176 | if (sdata->vif.type != NL80211_IFTYPE_AP && | ||
1177 | sdata->vif.type != NL80211_IFTYPE_AP_VLAN) | ||
1178 | return RX_CONTINUE; | ||
1179 | |||
1180 | /* | ||
1181 | * The device handles station powersave, so don't do anything about | ||
1182 | * uAPSD and PS-Poll frames (the latter shouldn't even come up from | ||
1183 | * it to mac80211 since they're handled.) | ||
1184 | */ | ||
1185 | if (sdata->local->hw.flags & IEEE80211_HW_AP_LINK_PS) | ||
1186 | return RX_CONTINUE; | ||
1187 | |||
1188 | /* | ||
1189 | * Don't do anything if the station isn't already asleep. In | ||
1190 | * the uAPSD case, the station will probably be marked asleep, | ||
1191 | * in the PS-Poll case the station must be confused ... | ||
1192 | */ | ||
1193 | if (!test_sta_flag(rx->sta, WLAN_STA_PS_STA)) | ||
1194 | return RX_CONTINUE; | ||
1195 | |||
1196 | if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) { | ||
1197 | if (!test_sta_flag(rx->sta, WLAN_STA_SP)) { | ||
1198 | if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER)) | ||
1199 | ieee80211_sta_ps_deliver_poll_response(rx->sta); | ||
1200 | else | ||
1201 | set_sta_flag(rx->sta, WLAN_STA_PSPOLL); | ||
1202 | } | ||
1203 | |||
1204 | /* Free PS Poll skb here instead of returning RX_DROP that would | ||
1205 | * count as an dropped frame. */ | ||
1206 | dev_kfree_skb(rx->skb); | ||
1207 | |||
1208 | return RX_QUEUED; | ||
1209 | } else if (!ieee80211_has_morefrags(hdr->frame_control) && | ||
1210 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && | ||
1211 | ieee80211_has_pm(hdr->frame_control) && | ||
1212 | (ieee80211_is_data_qos(hdr->frame_control) || | ||
1213 | ieee80211_is_qos_nullfunc(hdr->frame_control))) { | ||
1214 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | ||
1215 | ac = ieee802_1d_to_ac[tid & 7]; | ||
1216 | |||
1217 | /* | ||
1218 | * If this AC is not trigger-enabled do nothing. | ||
1219 | * | ||
1220 | * NB: This could/should check a separate bitmap of trigger- | ||
1221 | * enabled queues, but for now we only implement uAPSD w/o | ||
1222 | * TSPEC changes to the ACs, so they're always the same. | ||
1223 | */ | ||
1224 | if (!(rx->sta->sta.uapsd_queues & BIT(ac))) | ||
1225 | return RX_CONTINUE; | ||
1226 | |||
1227 | /* if we are in a service period, do nothing */ | ||
1228 | if (test_sta_flag(rx->sta, WLAN_STA_SP)) | ||
1229 | return RX_CONTINUE; | ||
1230 | |||
1231 | if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER)) | ||
1232 | ieee80211_sta_ps_deliver_uapsd(rx->sta); | ||
1233 | else | ||
1234 | set_sta_flag(rx->sta, WLAN_STA_UAPSD); | ||
1235 | } | ||
1236 | |||
1237 | return RX_CONTINUE; | ||
1238 | } | ||
1239 | |||
1240 | static ieee80211_rx_result debug_noinline | ||
1166 | ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | 1241 | ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) |
1167 | { | 1242 | { |
1168 | struct sta_info *sta = rx->sta; | 1243 | struct sta_info *sta = rx->sta; |
@@ -1220,7 +1295,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1220 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && | 1295 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && |
1221 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || | 1296 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || |
1222 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { | 1297 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { |
1223 | if (test_sta_flags(sta, WLAN_STA_PS_STA)) { | 1298 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { |
1224 | /* | 1299 | /* |
1225 | * Ignore doze->wake transitions that are | 1300 | * Ignore doze->wake transitions that are |
1226 | * indicated by non-data frames, the standard | 1301 | * indicated by non-data frames, the standard |
@@ -1473,33 +1548,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1473 | } | 1548 | } |
1474 | 1549 | ||
1475 | static ieee80211_rx_result debug_noinline | 1550 | static ieee80211_rx_result debug_noinline |
1476 | ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) | ||
1477 | { | ||
1478 | struct ieee80211_sub_if_data *sdata = rx->sdata; | ||
1479 | __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control; | ||
1480 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
1481 | |||
1482 | if (likely(!rx->sta || !ieee80211_is_pspoll(fc) || | ||
1483 | !(status->rx_flags & IEEE80211_RX_RA_MATCH))) | ||
1484 | return RX_CONTINUE; | ||
1485 | |||
1486 | if ((sdata->vif.type != NL80211_IFTYPE_AP) && | ||
1487 | (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)) | ||
1488 | return RX_DROP_UNUSABLE; | ||
1489 | |||
1490 | if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER)) | ||
1491 | ieee80211_sta_ps_deliver_poll_response(rx->sta); | ||
1492 | else | ||
1493 | set_sta_flags(rx->sta, WLAN_STA_PSPOLL); | ||
1494 | |||
1495 | /* Free PS Poll skb here instead of returning RX_DROP that would | ||
1496 | * count as an dropped frame. */ | ||
1497 | dev_kfree_skb(rx->skb); | ||
1498 | |||
1499 | return RX_QUEUED; | ||
1500 | } | ||
1501 | |||
1502 | static ieee80211_rx_result debug_noinline | ||
1503 | ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx) | 1551 | ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx) |
1504 | { | 1552 | { |
1505 | u8 *data = rx->skb->data; | 1553 | u8 *data = rx->skb->data; |
@@ -1522,7 +1570,7 @@ static int | |||
1522 | ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) | 1570 | ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) |
1523 | { | 1571 | { |
1524 | if (unlikely(!rx->sta || | 1572 | if (unlikely(!rx->sta || |
1525 | !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED))) | 1573 | !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) |
1526 | return -EACCES; | 1574 | return -EACCES; |
1527 | 1575 | ||
1528 | return 0; | 1576 | return 0; |
@@ -1565,7 +1613,7 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) | |||
1565 | if (status->flag & RX_FLAG_DECRYPTED) | 1613 | if (status->flag & RX_FLAG_DECRYPTED) |
1566 | return 0; | 1614 | return 0; |
1567 | 1615 | ||
1568 | if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { | 1616 | if (rx->sta && test_sta_flag(rx->sta, WLAN_STA_MFP)) { |
1569 | if (unlikely(!ieee80211_has_protected(fc) && | 1617 | if (unlikely(!ieee80211_has_protected(fc) && |
1570 | ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && | 1618 | ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && |
1571 | rx->key)) { | 1619 | rx->key)) { |
@@ -2567,9 +2615,9 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx) | |||
2567 | 2615 | ||
2568 | CALL_RXH(ieee80211_rx_h_decrypt) | 2616 | CALL_RXH(ieee80211_rx_h_decrypt) |
2569 | CALL_RXH(ieee80211_rx_h_check_more_data) | 2617 | CALL_RXH(ieee80211_rx_h_check_more_data) |
2618 | CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll) | ||
2570 | CALL_RXH(ieee80211_rx_h_sta_process) | 2619 | CALL_RXH(ieee80211_rx_h_sta_process) |
2571 | CALL_RXH(ieee80211_rx_h_defragment) | 2620 | CALL_RXH(ieee80211_rx_h_defragment) |
2572 | CALL_RXH(ieee80211_rx_h_ps_poll) | ||
2573 | CALL_RXH(ieee80211_rx_h_michael_mic_verify) | 2621 | CALL_RXH(ieee80211_rx_h_michael_mic_verify) |
2574 | /* must be after MMIC verify so header is counted in MPDU mic */ | 2622 | /* must be after MMIC verify so header is counted in MPDU mic */ |
2575 | #ifdef CONFIG_MAC80211_MESH | 2623 | #ifdef CONFIG_MAC80211_MESH |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 0a7e0fed3251..58b1c2bb26d2 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "sta_info.h" | 24 | #include "sta_info.h" |
25 | #include "debugfs_sta.h" | 25 | #include "debugfs_sta.h" |
26 | #include "mesh.h" | 26 | #include "mesh.h" |
27 | #include "wme.h" | ||
27 | 28 | ||
28 | /** | 29 | /** |
29 | * DOC: STA information lifetime rules | 30 | * DOC: STA information lifetime rules |
@@ -243,13 +244,22 @@ static void sta_unblock(struct work_struct *wk) | |||
243 | if (sta->dead) | 244 | if (sta->dead) |
244 | return; | 245 | return; |
245 | 246 | ||
246 | if (!test_sta_flags(sta, WLAN_STA_PS_STA)) | 247 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) |
247 | ieee80211_sta_ps_deliver_wakeup(sta); | 248 | ieee80211_sta_ps_deliver_wakeup(sta); |
248 | else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) { | 249 | else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) { |
249 | clear_sta_flags(sta, WLAN_STA_PS_DRIVER); | 250 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); |
251 | |||
252 | local_bh_disable(); | ||
250 | ieee80211_sta_ps_deliver_poll_response(sta); | 253 | ieee80211_sta_ps_deliver_poll_response(sta); |
254 | local_bh_enable(); | ||
255 | } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) { | ||
256 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
257 | |||
258 | local_bh_disable(); | ||
259 | ieee80211_sta_ps_deliver_uapsd(sta); | ||
260 | local_bh_enable(); | ||
251 | } else | 261 | } else |
252 | clear_sta_flags(sta, WLAN_STA_PS_DRIVER); | 262 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); |
253 | } | 263 | } |
254 | 264 | ||
255 | static int sta_prepare_rate_control(struct ieee80211_local *local, | 265 | static int sta_prepare_rate_control(struct ieee80211_local *local, |
@@ -282,7 +292,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
282 | return NULL; | 292 | return NULL; |
283 | 293 | ||
284 | spin_lock_init(&sta->lock); | 294 | spin_lock_init(&sta->lock); |
285 | spin_lock_init(&sta->flaglock); | ||
286 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 295 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); |
287 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 296 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
288 | mutex_init(&sta->ampdu_mlme.mtx); | 297 | mutex_init(&sta->ampdu_mlme.mtx); |
@@ -309,8 +318,10 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
309 | */ | 318 | */ |
310 | sta->timer_to_tid[i] = i; | 319 | sta->timer_to_tid[i] = i; |
311 | } | 320 | } |
312 | skb_queue_head_init(&sta->ps_tx_buf); | 321 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { |
313 | skb_queue_head_init(&sta->tx_filtered); | 322 | skb_queue_head_init(&sta->ps_tx_buf[i]); |
323 | skb_queue_head_init(&sta->tx_filtered[i]); | ||
324 | } | ||
314 | 325 | ||
315 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | 326 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) |
316 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); | 327 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); |
@@ -641,54 +652,84 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) | |||
641 | bss->tim[aid / 8] &= ~(1 << (aid % 8)); | 652 | bss->tim[aid / 8] &= ~(1 << (aid % 8)); |
642 | } | 653 | } |
643 | 654 | ||
644 | static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, | 655 | static unsigned long ieee80211_tids_for_ac(int ac) |
645 | struct sta_info *sta) | ||
646 | { | 656 | { |
647 | BUG_ON(!bss); | 657 | /* If we ever support TIDs > 7, this obviously needs to be adjusted */ |
648 | 658 | switch (ac) { | |
649 | __bss_tim_set(bss, sta->sta.aid); | 659 | case IEEE80211_AC_VO: |
650 | 660 | return BIT(6) | BIT(7); | |
651 | if (sta->local->ops->set_tim) { | 661 | case IEEE80211_AC_VI: |
652 | sta->local->tim_in_locked_section = true; | 662 | return BIT(4) | BIT(5); |
653 | drv_set_tim(sta->local, &sta->sta, true); | 663 | case IEEE80211_AC_BE: |
654 | sta->local->tim_in_locked_section = false; | 664 | return BIT(0) | BIT(3); |
665 | case IEEE80211_AC_BK: | ||
666 | return BIT(1) | BIT(2); | ||
667 | default: | ||
668 | WARN_ON(1); | ||
669 | return 0; | ||
655 | } | 670 | } |
656 | } | 671 | } |
657 | 672 | ||
658 | void sta_info_set_tim_bit(struct sta_info *sta) | 673 | void sta_info_recalc_tim(struct sta_info *sta) |
659 | { | 674 | { |
675 | struct ieee80211_local *local = sta->local; | ||
676 | struct ieee80211_if_ap *bss = sta->sdata->bss; | ||
660 | unsigned long flags; | 677 | unsigned long flags; |
678 | bool indicate_tim = false; | ||
679 | u8 ignore_for_tim = sta->sta.uapsd_queues; | ||
680 | int ac; | ||
661 | 681 | ||
662 | BUG_ON(!sta->sdata->bss); | 682 | if (WARN_ON_ONCE(!sta->sdata->bss)) |
683 | return; | ||
663 | 684 | ||
664 | spin_lock_irqsave(&sta->local->sta_lock, flags); | 685 | /* No need to do anything if the driver does all */ |
665 | __sta_info_set_tim_bit(sta->sdata->bss, sta); | 686 | if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) |
666 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); | 687 | return; |
667 | } | ||
668 | 688 | ||
669 | static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, | 689 | if (sta->dead) |
670 | struct sta_info *sta) | 690 | goto done; |
671 | { | 691 | |
672 | BUG_ON(!bss); | 692 | /* |
693 | * If all ACs are delivery-enabled then we should build | ||
694 | * the TIM bit for all ACs anyway; if only some are then | ||
695 | * we ignore those and build the TIM bit using only the | ||
696 | * non-enabled ones. | ||
697 | */ | ||
698 | if (ignore_for_tim == BIT(IEEE80211_NUM_ACS) - 1) | ||
699 | ignore_for_tim = 0; | ||
700 | |||
701 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
702 | unsigned long tids; | ||
673 | 703 | ||
674 | __bss_tim_clear(bss, sta->sta.aid); | 704 | if (ignore_for_tim & BIT(ac)) |
705 | continue; | ||
706 | |||
707 | indicate_tim |= !skb_queue_empty(&sta->tx_filtered[ac]) || | ||
708 | !skb_queue_empty(&sta->ps_tx_buf[ac]); | ||
709 | if (indicate_tim) | ||
710 | break; | ||
675 | 711 | ||
676 | if (sta->local->ops->set_tim) { | 712 | tids = ieee80211_tids_for_ac(ac); |
677 | sta->local->tim_in_locked_section = true; | 713 | |
678 | drv_set_tim(sta->local, &sta->sta, false); | 714 | indicate_tim |= |
679 | sta->local->tim_in_locked_section = false; | 715 | sta->driver_buffered_tids & tids; |
680 | } | 716 | } |
681 | } | ||
682 | 717 | ||
683 | void sta_info_clear_tim_bit(struct sta_info *sta) | 718 | done: |
684 | { | 719 | spin_lock_irqsave(&local->sta_lock, flags); |
685 | unsigned long flags; | ||
686 | 720 | ||
687 | BUG_ON(!sta->sdata->bss); | 721 | if (indicate_tim) |
722 | __bss_tim_set(bss, sta->sta.aid); | ||
723 | else | ||
724 | __bss_tim_clear(bss, sta->sta.aid); | ||
725 | |||
726 | if (local->ops->set_tim) { | ||
727 | local->tim_in_locked_section = true; | ||
728 | drv_set_tim(local, &sta->sta, indicate_tim); | ||
729 | local->tim_in_locked_section = false; | ||
730 | } | ||
688 | 731 | ||
689 | spin_lock_irqsave(&sta->local->sta_lock, flags); | 732 | spin_unlock_irqrestore(&local->sta_lock, flags); |
690 | __sta_info_clear_tim_bit(sta->sdata->bss, sta); | ||
691 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); | ||
692 | } | 733 | } |
693 | 734 | ||
694 | static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) | 735 | static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) |
@@ -711,21 +752,59 @@ static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) | |||
711 | } | 752 | } |
712 | 753 | ||
713 | 754 | ||
714 | static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | 755 | static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local, |
715 | struct sta_info *sta) | 756 | struct sta_info *sta, int ac) |
716 | { | 757 | { |
717 | unsigned long flags; | 758 | unsigned long flags; |
718 | struct sk_buff *skb; | 759 | struct sk_buff *skb; |
719 | 760 | ||
761 | /* | ||
762 | * First check for frames that should expire on the filtered | ||
763 | * queue. Frames here were rejected by the driver and are on | ||
764 | * a separate queue to avoid reordering with normal PS-buffered | ||
765 | * frames. They also aren't accounted for right now in the | ||
766 | * total_ps_buffered counter. | ||
767 | */ | ||
768 | for (;;) { | ||
769 | spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags); | ||
770 | skb = skb_peek(&sta->tx_filtered[ac]); | ||
771 | if (sta_info_buffer_expired(sta, skb)) | ||
772 | skb = __skb_dequeue(&sta->tx_filtered[ac]); | ||
773 | else | ||
774 | skb = NULL; | ||
775 | spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags); | ||
776 | |||
777 | /* | ||
778 | * Frames are queued in order, so if this one | ||
779 | * hasn't expired yet we can stop testing. If | ||
780 | * we actually reached the end of the queue we | ||
781 | * also need to stop, of course. | ||
782 | */ | ||
783 | if (!skb) | ||
784 | break; | ||
785 | dev_kfree_skb(skb); | ||
786 | } | ||
787 | |||
788 | /* | ||
789 | * Now also check the normal PS-buffered queue, this will | ||
790 | * only find something if the filtered queue was emptied | ||
791 | * since the filtered frames are all before the normal PS | ||
792 | * buffered frames. | ||
793 | */ | ||
720 | for (;;) { | 794 | for (;;) { |
721 | spin_lock_irqsave(&sta->ps_tx_buf.lock, flags); | 795 | spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags); |
722 | skb = skb_peek(&sta->ps_tx_buf); | 796 | skb = skb_peek(&sta->ps_tx_buf[ac]); |
723 | if (sta_info_buffer_expired(sta, skb)) | 797 | if (sta_info_buffer_expired(sta, skb)) |
724 | skb = __skb_dequeue(&sta->ps_tx_buf); | 798 | skb = __skb_dequeue(&sta->ps_tx_buf[ac]); |
725 | else | 799 | else |
726 | skb = NULL; | 800 | skb = NULL; |
727 | spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags); | 801 | spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags); |
728 | 802 | ||
803 | /* | ||
804 | * frames are queued in order, so if this one | ||
805 | * hasn't expired yet (or we reached the end of | ||
806 | * the queue) we can stop testing | ||
807 | */ | ||
729 | if (!skb) | 808 | if (!skb) |
730 | break; | 809 | break; |
731 | 810 | ||
@@ -735,22 +814,47 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
735 | sta->sta.addr); | 814 | sta->sta.addr); |
736 | #endif | 815 | #endif |
737 | dev_kfree_skb(skb); | 816 | dev_kfree_skb(skb); |
738 | |||
739 | if (skb_queue_empty(&sta->ps_tx_buf) && | ||
740 | !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF)) | ||
741 | sta_info_clear_tim_bit(sta); | ||
742 | } | 817 | } |
743 | 818 | ||
744 | return !skb_queue_empty(&sta->ps_tx_buf); | 819 | /* |
820 | * Finally, recalculate the TIM bit for this station -- it might | ||
821 | * now be clear because the station was too slow to retrieve its | ||
822 | * frames. | ||
823 | */ | ||
824 | sta_info_recalc_tim(sta); | ||
825 | |||
826 | /* | ||
827 | * Return whether there are any frames still buffered, this is | ||
828 | * used to check whether the cleanup timer still needs to run, | ||
829 | * if there are no frames we don't need to rearm the timer. | ||
830 | */ | ||
831 | return !(skb_queue_empty(&sta->ps_tx_buf[ac]) && | ||
832 | skb_queue_empty(&sta->tx_filtered[ac])); | ||
833 | } | ||
834 | |||
835 | static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | ||
836 | struct sta_info *sta) | ||
837 | { | ||
838 | bool have_buffered = false; | ||
839 | int ac; | ||
840 | |||
841 | /* This is only necessary for stations on BSS interfaces */ | ||
842 | if (!sta->sdata->bss) | ||
843 | return false; | ||
844 | |||
845 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
846 | have_buffered |= | ||
847 | sta_info_cleanup_expire_buffered_ac(local, sta, ac); | ||
848 | |||
849 | return have_buffered; | ||
745 | } | 850 | } |
746 | 851 | ||
747 | static int __must_check __sta_info_destroy(struct sta_info *sta) | 852 | static int __must_check __sta_info_destroy(struct sta_info *sta) |
748 | { | 853 | { |
749 | struct ieee80211_local *local; | 854 | struct ieee80211_local *local; |
750 | struct ieee80211_sub_if_data *sdata; | 855 | struct ieee80211_sub_if_data *sdata; |
751 | struct sk_buff *skb; | ||
752 | unsigned long flags; | 856 | unsigned long flags; |
753 | int ret, i; | 857 | int ret, i, ac; |
754 | 858 | ||
755 | might_sleep(); | 859 | might_sleep(); |
756 | 860 | ||
@@ -766,7 +870,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
766 | * sessions -- block that to make sure the tear-down | 870 | * sessions -- block that to make sure the tear-down |
767 | * will be sufficient. | 871 | * will be sufficient. |
768 | */ | 872 | */ |
769 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); | 873 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); |
770 | ieee80211_sta_tear_down_BA_sessions(sta, true); | 874 | ieee80211_sta_tear_down_BA_sessions(sta, true); |
771 | 875 | ||
772 | spin_lock_irqsave(&local->sta_lock, flags); | 876 | spin_lock_irqsave(&local->sta_lock, flags); |
@@ -787,12 +891,15 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
787 | 891 | ||
788 | sta->dead = true; | 892 | sta->dead = true; |
789 | 893 | ||
790 | if (test_and_clear_sta_flags(sta, | 894 | if (test_sta_flag(sta, WLAN_STA_PS_STA) || |
791 | WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { | 895 | test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { |
792 | BUG_ON(!sdata->bss); | 896 | BUG_ON(!sdata->bss); |
793 | 897 | ||
898 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
899 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
900 | |||
794 | atomic_dec(&sdata->bss->num_sta_ps); | 901 | atomic_dec(&sdata->bss->num_sta_ps); |
795 | sta_info_clear_tim_bit(sta); | 902 | sta_info_recalc_tim(sta); |
796 | } | 903 | } |
797 | 904 | ||
798 | local->num_sta--; | 905 | local->num_sta--; |
@@ -818,6 +925,12 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
818 | */ | 925 | */ |
819 | synchronize_rcu(); | 926 | synchronize_rcu(); |
820 | 927 | ||
928 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
929 | local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); | ||
930 | __skb_queue_purge(&sta->ps_tx_buf[ac]); | ||
931 | __skb_queue_purge(&sta->tx_filtered[ac]); | ||
932 | } | ||
933 | |||
821 | #ifdef CONFIG_MAC80211_MESH | 934 | #ifdef CONFIG_MAC80211_MESH |
822 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 935 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
823 | mesh_accept_plinks_update(sdata); | 936 | mesh_accept_plinks_update(sdata); |
@@ -840,14 +953,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
840 | } | 953 | } |
841 | #endif | 954 | #endif |
842 | 955 | ||
843 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | ||
844 | local->total_ps_buffered--; | ||
845 | dev_kfree_skb_any(skb); | ||
846 | } | ||
847 | |||
848 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | ||
849 | dev_kfree_skb_any(skb); | ||
850 | |||
851 | __sta_info_free(local, sta); | 956 | __sta_info_free(local, sta); |
852 | 957 | ||
853 | return 0; | 958 | return 0; |
@@ -1013,7 +1118,8 @@ static void clear_sta_ps_flags(void *_sta) | |||
1013 | { | 1118 | { |
1014 | struct sta_info *sta = _sta; | 1119 | struct sta_info *sta = _sta; |
1015 | 1120 | ||
1016 | clear_sta_flags(sta, WLAN_STA_PS_DRIVER | WLAN_STA_PS_STA); | 1121 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); |
1122 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
1017 | } | 1123 | } |
1018 | 1124 | ||
1019 | /* powersave support code */ | 1125 | /* powersave support code */ |
@@ -1021,88 +1127,343 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
1021 | { | 1127 | { |
1022 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 1128 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
1023 | struct ieee80211_local *local = sdata->local; | 1129 | struct ieee80211_local *local = sdata->local; |
1024 | int sent, buffered; | 1130 | struct sk_buff_head pending; |
1131 | int filtered = 0, buffered = 0, ac; | ||
1132 | |||
1133 | clear_sta_flag(sta, WLAN_STA_SP); | ||
1134 | |||
1135 | BUILD_BUG_ON(BITS_TO_LONGS(STA_TID_NUM) > 1); | ||
1136 | sta->driver_buffered_tids = 0; | ||
1025 | 1137 | ||
1026 | clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); | ||
1027 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) | 1138 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
1028 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); | 1139 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); |
1029 | 1140 | ||
1030 | if (!skb_queue_empty(&sta->ps_tx_buf)) | 1141 | skb_queue_head_init(&pending); |
1031 | sta_info_clear_tim_bit(sta); | ||
1032 | 1142 | ||
1033 | /* Send all buffered frames to the station */ | 1143 | /* Send all buffered frames to the station */ |
1034 | sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered); | 1144 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
1035 | buffered = ieee80211_add_pending_skbs_fn(local, &sta->ps_tx_buf, | 1145 | int count = skb_queue_len(&pending), tmp; |
1036 | clear_sta_ps_flags, sta); | 1146 | |
1037 | sent += buffered; | 1147 | skb_queue_splice_tail_init(&sta->tx_filtered[ac], &pending); |
1148 | tmp = skb_queue_len(&pending); | ||
1149 | filtered += tmp - count; | ||
1150 | count = tmp; | ||
1151 | |||
1152 | skb_queue_splice_tail_init(&sta->ps_tx_buf[ac], &pending); | ||
1153 | tmp = skb_queue_len(&pending); | ||
1154 | buffered += tmp - count; | ||
1155 | } | ||
1156 | |||
1157 | ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta); | ||
1158 | |||
1038 | local->total_ps_buffered -= buffered; | 1159 | local->total_ps_buffered -= buffered; |
1039 | 1160 | ||
1161 | sta_info_recalc_tim(sta); | ||
1162 | |||
1040 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1163 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
1041 | printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " | 1164 | printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " |
1042 | "since STA not sleeping anymore\n", sdata->name, | 1165 | "since STA not sleeping anymore\n", sdata->name, |
1043 | sta->sta.addr, sta->sta.aid, sent - buffered, buffered); | 1166 | sta->sta.addr, sta->sta.aid, filtered, buffered); |
1044 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | 1167 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ |
1045 | } | 1168 | } |
1046 | 1169 | ||
1047 | void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) | 1170 | static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, |
1171 | struct sta_info *sta, int tid, | ||
1172 | enum ieee80211_frame_release_type reason) | ||
1048 | { | 1173 | { |
1049 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
1050 | struct ieee80211_local *local = sdata->local; | 1174 | struct ieee80211_local *local = sdata->local; |
1175 | struct ieee80211_qos_hdr *nullfunc; | ||
1051 | struct sk_buff *skb; | 1176 | struct sk_buff *skb; |
1052 | int no_pending_pkts; | 1177 | int size = sizeof(*nullfunc); |
1178 | __le16 fc; | ||
1179 | bool qos = test_sta_flag(sta, WLAN_STA_WME); | ||
1180 | struct ieee80211_tx_info *info; | ||
1053 | 1181 | ||
1054 | skb = skb_dequeue(&sta->tx_filtered); | 1182 | if (qos) { |
1055 | if (!skb) { | 1183 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | |
1056 | skb = skb_dequeue(&sta->ps_tx_buf); | 1184 | IEEE80211_STYPE_QOS_NULLFUNC | |
1057 | if (skb) | 1185 | IEEE80211_FCTL_FROMDS); |
1058 | local->total_ps_buffered--; | 1186 | } else { |
1187 | size -= 2; | ||
1188 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
1189 | IEEE80211_STYPE_NULLFUNC | | ||
1190 | IEEE80211_FCTL_FROMDS); | ||
1059 | } | 1191 | } |
1060 | no_pending_pkts = skb_queue_empty(&sta->tx_filtered) && | ||
1061 | skb_queue_empty(&sta->ps_tx_buf); | ||
1062 | 1192 | ||
1063 | if (skb) { | 1193 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + size); |
1064 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1194 | if (!skb) |
1065 | struct ieee80211_hdr *hdr = | 1195 | return; |
1066 | (struct ieee80211_hdr *) skb->data; | 1196 | |
1197 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1198 | |||
1199 | nullfunc = (void *) skb_put(skb, size); | ||
1200 | nullfunc->frame_control = fc; | ||
1201 | nullfunc->duration_id = 0; | ||
1202 | memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN); | ||
1203 | memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); | ||
1204 | memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN); | ||
1205 | |||
1206 | if (qos) { | ||
1207 | skb->priority = tid; | ||
1208 | |||
1209 | skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]); | ||
1210 | |||
1211 | nullfunc->qos_ctrl = cpu_to_le16(tid); | ||
1212 | |||
1213 | if (reason == IEEE80211_FRAME_RELEASE_UAPSD) | ||
1214 | nullfunc->qos_ctrl |= | ||
1215 | cpu_to_le16(IEEE80211_QOS_CTL_EOSP); | ||
1216 | } | ||
1217 | |||
1218 | info = IEEE80211_SKB_CB(skb); | ||
1219 | |||
1220 | /* | ||
1221 | * Tell TX path to send this frame even though the | ||
1222 | * STA may still remain is PS mode after this frame | ||
1223 | * exchange. Also set EOSP to indicate this packet | ||
1224 | * ends the poll/service period. | ||
1225 | */ | ||
1226 | info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE | | ||
1227 | IEEE80211_TX_STATUS_EOSP | | ||
1228 | IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
1229 | |||
1230 | drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false); | ||
1231 | |||
1232 | ieee80211_xmit(sdata, skb); | ||
1233 | } | ||
1234 | |||
1235 | static void | ||
1236 | ieee80211_sta_ps_deliver_response(struct sta_info *sta, | ||
1237 | int n_frames, u8 ignored_acs, | ||
1238 | enum ieee80211_frame_release_type reason) | ||
1239 | { | ||
1240 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
1241 | struct ieee80211_local *local = sdata->local; | ||
1242 | bool found = false; | ||
1243 | bool more_data = false; | ||
1244 | int ac; | ||
1245 | unsigned long driver_release_tids = 0; | ||
1246 | struct sk_buff_head frames; | ||
1247 | |||
1248 | /* Service or PS-Poll period starts */ | ||
1249 | set_sta_flag(sta, WLAN_STA_SP); | ||
1250 | |||
1251 | __skb_queue_head_init(&frames); | ||
1252 | |||
1253 | /* | ||
1254 | * Get response frame(s) and more data bit for it. | ||
1255 | */ | ||
1256 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
1257 | unsigned long tids; | ||
1258 | |||
1259 | if (ignored_acs & BIT(ac)) | ||
1260 | continue; | ||
1261 | |||
1262 | tids = ieee80211_tids_for_ac(ac); | ||
1263 | |||
1264 | if (!found) { | ||
1265 | driver_release_tids = sta->driver_buffered_tids & tids; | ||
1266 | if (driver_release_tids) { | ||
1267 | found = true; | ||
1268 | } else { | ||
1269 | struct sk_buff *skb; | ||
1270 | |||
1271 | while (n_frames > 0) { | ||
1272 | skb = skb_dequeue(&sta->tx_filtered[ac]); | ||
1273 | if (!skb) { | ||
1274 | skb = skb_dequeue( | ||
1275 | &sta->ps_tx_buf[ac]); | ||
1276 | if (skb) | ||
1277 | local->total_ps_buffered--; | ||
1278 | } | ||
1279 | if (!skb) | ||
1280 | break; | ||
1281 | n_frames--; | ||
1282 | found = true; | ||
1283 | __skb_queue_tail(&frames, skb); | ||
1284 | } | ||
1285 | } | ||
1286 | |||
1287 | /* | ||
1288 | * If the driver has data on more than one TID then | ||
1289 | * certainly there's more data if we release just a | ||
1290 | * single frame now (from a single TID). | ||
1291 | */ | ||
1292 | if (reason == IEEE80211_FRAME_RELEASE_PSPOLL && | ||
1293 | hweight16(driver_release_tids) > 1) { | ||
1294 | more_data = true; | ||
1295 | driver_release_tids = | ||
1296 | BIT(ffs(driver_release_tids) - 1); | ||
1297 | break; | ||
1298 | } | ||
1299 | } | ||
1300 | |||
1301 | if (!skb_queue_empty(&sta->tx_filtered[ac]) || | ||
1302 | !skb_queue_empty(&sta->ps_tx_buf[ac])) { | ||
1303 | more_data = true; | ||
1304 | break; | ||
1305 | } | ||
1306 | } | ||
1307 | |||
1308 | if (!found) { | ||
1309 | int tid; | ||
1067 | 1310 | ||
1068 | /* | 1311 | /* |
1069 | * Tell TX path to send this frame even though the STA may | 1312 | * For PS-Poll, this can only happen due to a race condition |
1070 | * still remain is PS mode after this frame exchange. | 1313 | * when we set the TIM bit and the station notices it, but |
1314 | * before it can poll for the frame we expire it. | ||
1315 | * | ||
1316 | * For uAPSD, this is said in the standard (11.2.1.5 h): | ||
1317 | * At each unscheduled SP for a non-AP STA, the AP shall | ||
1318 | * attempt to transmit at least one MSDU or MMPDU, but no | ||
1319 | * more than the value specified in the Max SP Length field | ||
1320 | * in the QoS Capability element from delivery-enabled ACs, | ||
1321 | * that are destined for the non-AP STA. | ||
1322 | * | ||
1323 | * Since we have no other MSDU/MMPDU, transmit a QoS null frame. | ||
1071 | */ | 1324 | */ |
1072 | info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE; | ||
1073 | 1325 | ||
1074 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1326 | /* This will evaluate to 1, 3, 5 or 7. */ |
1075 | printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", | 1327 | tid = 7 - ((ffs(~ignored_acs) - 1) << 1); |
1076 | sta->sta.addr, sta->sta.aid, | ||
1077 | skb_queue_len(&sta->ps_tx_buf)); | ||
1078 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | ||
1079 | 1328 | ||
1080 | /* Use MoreData flag to indicate whether there are more | 1329 | ieee80211_send_null_response(sdata, sta, tid, reason); |
1081 | * buffered frames for this STA */ | 1330 | return; |
1082 | if (no_pending_pkts) | 1331 | } |
1083 | hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA); | ||
1084 | else | ||
1085 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
1086 | 1332 | ||
1087 | ieee80211_add_pending_skb(local, skb); | 1333 | if (!driver_release_tids) { |
1334 | struct sk_buff_head pending; | ||
1335 | struct sk_buff *skb; | ||
1336 | int num = 0; | ||
1337 | u16 tids = 0; | ||
1338 | |||
1339 | skb_queue_head_init(&pending); | ||
1340 | |||
1341 | while ((skb = __skb_dequeue(&frames))) { | ||
1342 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1343 | struct ieee80211_hdr *hdr = (void *) skb->data; | ||
1344 | u8 *qoshdr = NULL; | ||
1345 | |||
1346 | num++; | ||
1347 | |||
1348 | /* | ||
1349 | * Tell TX path to send this frame even though the | ||
1350 | * STA may still remain is PS mode after this frame | ||
1351 | * exchange. | ||
1352 | */ | ||
1353 | info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE; | ||
1354 | |||
1355 | /* | ||
1356 | * Use MoreData flag to indicate whether there are | ||
1357 | * more buffered frames for this STA | ||
1358 | */ | ||
1359 | if (!more_data) | ||
1360 | hdr->frame_control &= | ||
1361 | cpu_to_le16(~IEEE80211_FCTL_MOREDATA); | ||
1362 | else | ||
1363 | hdr->frame_control |= | ||
1364 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
1365 | |||
1366 | if (ieee80211_is_data_qos(hdr->frame_control) || | ||
1367 | ieee80211_is_qos_nullfunc(hdr->frame_control)) | ||
1368 | qoshdr = ieee80211_get_qos_ctl(hdr); | ||
1369 | |||
1370 | /* set EOSP for the frame */ | ||
1371 | if (reason == IEEE80211_FRAME_RELEASE_UAPSD && | ||
1372 | qoshdr && skb_queue_empty(&frames)) | ||
1373 | *qoshdr |= IEEE80211_QOS_CTL_EOSP; | ||
1374 | |||
1375 | info->flags |= IEEE80211_TX_STATUS_EOSP | | ||
1376 | IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
1377 | |||
1378 | if (qoshdr) | ||
1379 | tids |= BIT(*qoshdr & IEEE80211_QOS_CTL_TID_MASK); | ||
1380 | else | ||
1381 | tids |= BIT(0); | ||
1382 | |||
1383 | __skb_queue_tail(&pending, skb); | ||
1384 | } | ||
1088 | 1385 | ||
1089 | if (no_pending_pkts) | 1386 | drv_allow_buffered_frames(local, sta, tids, num, |
1090 | sta_info_clear_tim_bit(sta); | 1387 | reason, more_data); |
1091 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1388 | |
1389 | ieee80211_add_pending_skbs(local, &pending); | ||
1390 | |||
1391 | sta_info_recalc_tim(sta); | ||
1092 | } else { | 1392 | } else { |
1093 | /* | 1393 | /* |
1094 | * FIXME: This can be the result of a race condition between | 1394 | * We need to release a frame that is buffered somewhere in the |
1095 | * us expiring a frame and the station polling for it. | 1395 | * driver ... it'll have to handle that. |
1096 | * Should we send it a null-func frame indicating we | 1396 | * Note that, as per the comment above, it'll also have to see |
1097 | * have nothing buffered for it? | 1397 | * if there is more than just one frame on the specific TID that |
1398 | * we're releasing from, and it needs to set the more-data bit | ||
1399 | * accordingly if we tell it that there's no more data. If we do | ||
1400 | * tell it there's more data, then of course the more-data bit | ||
1401 | * needs to be set anyway. | ||
1402 | */ | ||
1403 | drv_release_buffered_frames(local, sta, driver_release_tids, | ||
1404 | n_frames, reason, more_data); | ||
1405 | |||
1406 | /* | ||
1407 | * Note that we don't recalculate the TIM bit here as it would | ||
1408 | * most likely have no effect at all unless the driver told us | ||
1409 | * that the TID became empty before returning here from the | ||
1410 | * release function. | ||
1411 | * Either way, however, when the driver tells us that the TID | ||
1412 | * became empty we'll do the TIM recalculation. | ||
1098 | */ | 1413 | */ |
1099 | printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " | ||
1100 | "though there are no buffered frames for it\n", | ||
1101 | sdata->name, sta->sta.addr); | ||
1102 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | ||
1103 | } | 1414 | } |
1104 | } | 1415 | } |
1105 | 1416 | ||
1417 | void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) | ||
1418 | { | ||
1419 | u8 ignore_for_response = sta->sta.uapsd_queues; | ||
1420 | |||
1421 | /* | ||
1422 | * If all ACs are delivery-enabled then we should reply | ||
1423 | * from any of them, if only some are enabled we reply | ||
1424 | * only from the non-enabled ones. | ||
1425 | */ | ||
1426 | if (ignore_for_response == BIT(IEEE80211_NUM_ACS) - 1) | ||
1427 | ignore_for_response = 0; | ||
1428 | |||
1429 | ieee80211_sta_ps_deliver_response(sta, 1, ignore_for_response, | ||
1430 | IEEE80211_FRAME_RELEASE_PSPOLL); | ||
1431 | } | ||
1432 | |||
1433 | void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta) | ||
1434 | { | ||
1435 | int n_frames = sta->sta.max_sp; | ||
1436 | u8 delivery_enabled = sta->sta.uapsd_queues; | ||
1437 | |||
1438 | /* | ||
1439 | * If we ever grow support for TSPEC this might happen if | ||
1440 | * the TSPEC update from hostapd comes in between a trigger | ||
1441 | * frame setting WLAN_STA_UAPSD in the RX path and this | ||
1442 | * actually getting called. | ||
1443 | */ | ||
1444 | if (!delivery_enabled) | ||
1445 | return; | ||
1446 | |||
1447 | switch (sta->sta.max_sp) { | ||
1448 | case 1: | ||
1449 | n_frames = 2; | ||
1450 | break; | ||
1451 | case 2: | ||
1452 | n_frames = 4; | ||
1453 | break; | ||
1454 | case 3: | ||
1455 | n_frames = 6; | ||
1456 | break; | ||
1457 | case 0: | ||
1458 | /* XXX: what is a good value? */ | ||
1459 | n_frames = 8; | ||
1460 | break; | ||
1461 | } | ||
1462 | |||
1463 | ieee80211_sta_ps_deliver_response(sta, n_frames, ~delivery_enabled, | ||
1464 | IEEE80211_FRAME_RELEASE_UAPSD); | ||
1465 | } | ||
1466 | |||
1106 | void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | 1467 | void ieee80211_sta_block_awake(struct ieee80211_hw *hw, |
1107 | struct ieee80211_sta *pubsta, bool block) | 1468 | struct ieee80211_sta *pubsta, bool block) |
1108 | { | 1469 | { |
@@ -1111,17 +1472,50 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | |||
1111 | trace_api_sta_block_awake(sta->local, pubsta, block); | 1472 | trace_api_sta_block_awake(sta->local, pubsta, block); |
1112 | 1473 | ||
1113 | if (block) | 1474 | if (block) |
1114 | set_sta_flags(sta, WLAN_STA_PS_DRIVER); | 1475 | set_sta_flag(sta, WLAN_STA_PS_DRIVER); |
1115 | else if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) | 1476 | else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) |
1116 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); | 1477 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); |
1117 | } | 1478 | } |
1118 | EXPORT_SYMBOL(ieee80211_sta_block_awake); | 1479 | EXPORT_SYMBOL(ieee80211_sta_block_awake); |
1119 | 1480 | ||
1120 | void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta) | 1481 | void ieee80211_sta_eosp_irqsafe(struct ieee80211_sta *pubsta) |
1482 | { | ||
1483 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
1484 | struct ieee80211_local *local = sta->local; | ||
1485 | struct sk_buff *skb; | ||
1486 | struct skb_eosp_msg_data *data; | ||
1487 | |||
1488 | trace_api_eosp(local, pubsta); | ||
1489 | |||
1490 | skb = alloc_skb(0, GFP_ATOMIC); | ||
1491 | if (!skb) { | ||
1492 | /* too bad ... but race is better than loss */ | ||
1493 | clear_sta_flag(sta, WLAN_STA_SP); | ||
1494 | return; | ||
1495 | } | ||
1496 | |||
1497 | data = (void *)skb->cb; | ||
1498 | memcpy(data->sta, pubsta->addr, ETH_ALEN); | ||
1499 | memcpy(data->iface, sta->sdata->vif.addr, ETH_ALEN); | ||
1500 | skb->pkt_type = IEEE80211_EOSP_MSG; | ||
1501 | skb_queue_tail(&local->skb_queue, skb); | ||
1502 | tasklet_schedule(&local->tasklet); | ||
1503 | } | ||
1504 | EXPORT_SYMBOL(ieee80211_sta_eosp_irqsafe); | ||
1505 | |||
1506 | void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, | ||
1507 | u8 tid, bool buffered) | ||
1121 | { | 1508 | { |
1122 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | 1509 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
1123 | 1510 | ||
1124 | set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); | 1511 | if (WARN_ON(tid >= STA_TID_NUM)) |
1125 | sta_info_set_tim_bit(sta); | 1512 | return; |
1513 | |||
1514 | if (buffered) | ||
1515 | set_bit(tid, &sta->driver_buffered_tids); | ||
1516 | else | ||
1517 | clear_bit(tid, &sta->driver_buffered_tids); | ||
1518 | |||
1519 | sta_info_recalc_tim(sta); | ||
1126 | } | 1520 | } |
1127 | EXPORT_SYMBOL(ieee80211_sta_set_tim); | 1521 | EXPORT_SYMBOL(ieee80211_sta_set_buffered); |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 56a3d38a2cd1..8c8ce05ad26f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -19,7 +19,8 @@ | |||
19 | /** | 19 | /** |
20 | * enum ieee80211_sta_info_flags - Stations flags | 20 | * enum ieee80211_sta_info_flags - Stations flags |
21 | * | 21 | * |
22 | * These flags are used with &struct sta_info's @flags member. | 22 | * These flags are used with &struct sta_info's @flags member, but |
23 | * only indirectly with set_sta_flag() and friends. | ||
23 | * | 24 | * |
24 | * @WLAN_STA_AUTH: Station is authenticated. | 25 | * @WLAN_STA_AUTH: Station is authenticated. |
25 | * @WLAN_STA_ASSOC: Station is associated. | 26 | * @WLAN_STA_ASSOC: Station is associated. |
@@ -43,24 +44,33 @@ | |||
43 | * be in the queues | 44 | * be in the queues |
44 | * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping | 45 | * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping |
45 | * station in power-save mode, reply when the driver unblocks. | 46 | * station in power-save mode, reply when the driver unblocks. |
46 | * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal | 47 | * @WLAN_STA_TDLS_PEER: Station is a TDLS peer. |
47 | * buffers. Automatically cleared on station wake-up. | 48 | * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct |
49 | * packets. This means the link is enabled. | ||
50 | * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was | ||
51 | * keeping station in power-save mode, reply when the driver | ||
52 | * unblocks the station. | ||
53 | * @WLAN_STA_SP: Station is in a service period, so don't try to | ||
54 | * reply to other uAPSD trigger frames or PS-Poll. | ||
48 | */ | 55 | */ |
49 | enum ieee80211_sta_info_flags { | 56 | enum ieee80211_sta_info_flags { |
50 | WLAN_STA_AUTH = 1<<0, | 57 | WLAN_STA_AUTH, |
51 | WLAN_STA_ASSOC = 1<<1, | 58 | WLAN_STA_ASSOC, |
52 | WLAN_STA_PS_STA = 1<<2, | 59 | WLAN_STA_PS_STA, |
53 | WLAN_STA_AUTHORIZED = 1<<3, | 60 | WLAN_STA_AUTHORIZED, |
54 | WLAN_STA_SHORT_PREAMBLE = 1<<4, | 61 | WLAN_STA_SHORT_PREAMBLE, |
55 | WLAN_STA_ASSOC_AP = 1<<5, | 62 | WLAN_STA_ASSOC_AP, |
56 | WLAN_STA_WME = 1<<6, | 63 | WLAN_STA_WME, |
57 | WLAN_STA_WDS = 1<<7, | 64 | WLAN_STA_WDS, |
58 | WLAN_STA_CLEAR_PS_FILT = 1<<9, | 65 | WLAN_STA_CLEAR_PS_FILT, |
59 | WLAN_STA_MFP = 1<<10, | 66 | WLAN_STA_MFP, |
60 | WLAN_STA_BLOCK_BA = 1<<11, | 67 | WLAN_STA_BLOCK_BA, |
61 | WLAN_STA_PS_DRIVER = 1<<12, | 68 | WLAN_STA_PS_DRIVER, |
62 | WLAN_STA_PSPOLL = 1<<13, | 69 | WLAN_STA_PSPOLL, |
63 | WLAN_STA_PS_DRIVER_BUF = 1<<14, | 70 | WLAN_STA_TDLS_PEER, |
71 | WLAN_STA_TDLS_PEER_AUTH, | ||
72 | WLAN_STA_UAPSD, | ||
73 | WLAN_STA_SP, | ||
64 | }; | 74 | }; |
65 | 75 | ||
66 | #define STA_TID_NUM 16 | 76 | #define STA_TID_NUM 16 |
@@ -203,15 +213,16 @@ struct sta_ampdu_mlme { | |||
203 | * @last_rx_rate_flag: rx status flag of the last data packet | 213 | * @last_rx_rate_flag: rx status flag of the last data packet |
204 | * @lock: used for locking all fields that require locking, see comments | 214 | * @lock: used for locking all fields that require locking, see comments |
205 | * in the header file. | 215 | * in the header file. |
206 | * @flaglock: spinlock for flags accesses | ||
207 | * @drv_unblock_wk: used for driver PS unblocking | 216 | * @drv_unblock_wk: used for driver PS unblocking |
208 | * @listen_interval: listen interval of this station, when we're acting as AP | 217 | * @listen_interval: listen interval of this station, when we're acting as AP |
209 | * @flags: STA flags, see &enum ieee80211_sta_info_flags | 218 | * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly |
210 | * @ps_tx_buf: buffer of frames to transmit to this station | 219 | * @ps_tx_buf: buffers (per AC) of frames to transmit to this station |
211 | * when it leaves power saving state | 220 | * when it leaves power saving state or polls |
212 | * @tx_filtered: buffer of frames we already tried to transmit | 221 | * @tx_filtered: buffers (per AC) of frames we already tried to |
213 | * but were filtered by hardware due to STA having entered | 222 | * transmit but were filtered by hardware due to STA having |
214 | * power saving state | 223 | * entered power saving state, these are also delivered to |
224 | * the station when it leaves powersave or polls for frames | ||
225 | * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on | ||
215 | * @rx_packets: Number of MSDUs received from this STA | 226 | * @rx_packets: Number of MSDUs received from this STA |
216 | * @rx_bytes: Number of bytes received from this STA | 227 | * @rx_bytes: Number of bytes received from this STA |
217 | * @wep_weak_iv_count: number of weak WEP IVs received from this station | 228 | * @wep_weak_iv_count: number of weak WEP IVs received from this station |
@@ -261,7 +272,6 @@ struct sta_info { | |||
261 | struct rate_control_ref *rate_ctrl; | 272 | struct rate_control_ref *rate_ctrl; |
262 | void *rate_ctrl_priv; | 273 | void *rate_ctrl_priv; |
263 | spinlock_t lock; | 274 | spinlock_t lock; |
264 | spinlock_t flaglock; | ||
265 | 275 | ||
266 | struct work_struct drv_unblock_wk; | 276 | struct work_struct drv_unblock_wk; |
267 | 277 | ||
@@ -271,18 +281,16 @@ struct sta_info { | |||
271 | 281 | ||
272 | bool uploaded; | 282 | bool uploaded; |
273 | 283 | ||
274 | /* | 284 | /* use the accessors defined below */ |
275 | * frequently updated, locked with own spinlock (flaglock), | 285 | unsigned long _flags; |
276 | * use the accessors defined below | ||
277 | */ | ||
278 | u32 flags; | ||
279 | 286 | ||
280 | /* | 287 | /* |
281 | * STA powersave frame queues, no more than the internal | 288 | * STA powersave frame queues, no more than the internal |
282 | * locking required. | 289 | * locking required. |
283 | */ | 290 | */ |
284 | struct sk_buff_head ps_tx_buf; | 291 | struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS]; |
285 | struct sk_buff_head tx_filtered; | 292 | struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS]; |
293 | unsigned long driver_buffered_tids; | ||
286 | 294 | ||
287 | /* Updated from RX path only, no locking requirements */ | 295 | /* Updated from RX path only, no locking requirements */ |
288 | unsigned long rx_packets, rx_bytes; | 296 | unsigned long rx_packets, rx_bytes; |
@@ -358,60 +366,28 @@ static inline enum nl80211_plink_state sta_plink_state(struct sta_info *sta) | |||
358 | return NL80211_PLINK_LISTEN; | 366 | return NL80211_PLINK_LISTEN; |
359 | } | 367 | } |
360 | 368 | ||
361 | static inline void set_sta_flags(struct sta_info *sta, const u32 flags) | 369 | static inline void set_sta_flag(struct sta_info *sta, |
370 | enum ieee80211_sta_info_flags flag) | ||
362 | { | 371 | { |
363 | unsigned long irqfl; | 372 | set_bit(flag, &sta->_flags); |
364 | |||
365 | spin_lock_irqsave(&sta->flaglock, irqfl); | ||
366 | sta->flags |= flags; | ||
367 | spin_unlock_irqrestore(&sta->flaglock, irqfl); | ||
368 | } | 373 | } |
369 | 374 | ||
370 | static inline void clear_sta_flags(struct sta_info *sta, const u32 flags) | 375 | static inline void clear_sta_flag(struct sta_info *sta, |
376 | enum ieee80211_sta_info_flags flag) | ||
371 | { | 377 | { |
372 | unsigned long irqfl; | 378 | clear_bit(flag, &sta->_flags); |
373 | |||
374 | spin_lock_irqsave(&sta->flaglock, irqfl); | ||
375 | sta->flags &= ~flags; | ||
376 | spin_unlock_irqrestore(&sta->flaglock, irqfl); | ||
377 | } | 379 | } |
378 | 380 | ||
379 | static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) | 381 | static inline int test_sta_flag(struct sta_info *sta, |
382 | enum ieee80211_sta_info_flags flag) | ||
380 | { | 383 | { |
381 | u32 ret; | 384 | return test_bit(flag, &sta->_flags); |
382 | unsigned long irqfl; | ||
383 | |||
384 | spin_lock_irqsave(&sta->flaglock, irqfl); | ||
385 | ret = sta->flags & flags; | ||
386 | spin_unlock_irqrestore(&sta->flaglock, irqfl); | ||
387 | |||
388 | return ret; | ||
389 | } | 385 | } |
390 | 386 | ||
391 | static inline u32 test_and_clear_sta_flags(struct sta_info *sta, | 387 | static inline int test_and_clear_sta_flag(struct sta_info *sta, |
392 | const u32 flags) | 388 | enum ieee80211_sta_info_flags flag) |
393 | { | 389 | { |
394 | u32 ret; | 390 | return test_and_clear_bit(flag, &sta->_flags); |
395 | unsigned long irqfl; | ||
396 | |||
397 | spin_lock_irqsave(&sta->flaglock, irqfl); | ||
398 | ret = sta->flags & flags; | ||
399 | sta->flags &= ~flags; | ||
400 | spin_unlock_irqrestore(&sta->flaglock, irqfl); | ||
401 | |||
402 | return ret; | ||
403 | } | ||
404 | |||
405 | static inline u32 get_sta_flags(struct sta_info *sta) | ||
406 | { | ||
407 | u32 ret; | ||
408 | unsigned long irqfl; | ||
409 | |||
410 | spin_lock_irqsave(&sta->flaglock, irqfl); | ||
411 | ret = sta->flags; | ||
412 | spin_unlock_irqrestore(&sta->flaglock, irqfl); | ||
413 | |||
414 | return ret; | ||
415 | } | 391 | } |
416 | 392 | ||
417 | void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, | 393 | void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, |
@@ -429,8 +405,8 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid) | |||
429 | #define STA_HASH(sta) (sta[5]) | 405 | #define STA_HASH(sta) (sta[5]) |
430 | 406 | ||
431 | 407 | ||
432 | /* Maximum number of frames to buffer per power saving station */ | 408 | /* Maximum number of frames to buffer per power saving station per AC */ |
433 | #define STA_MAX_TX_BUFFER 128 | 409 | #define STA_MAX_TX_BUFFER 64 |
434 | 410 | ||
435 | /* Minimum buffered frame expiry time. If STA uses listen interval that is | 411 | /* Minimum buffered frame expiry time. If STA uses listen interval that is |
436 | * smaller than this value, the minimum value here is used instead. */ | 412 | * smaller than this value, the minimum value here is used instead. */ |
@@ -523,8 +499,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, | |||
523 | int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, | 499 | int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, |
524 | const u8 *addr); | 500 | const u8 *addr); |
525 | 501 | ||
526 | void sta_info_set_tim_bit(struct sta_info *sta); | 502 | void sta_info_recalc_tim(struct sta_info *sta); |
527 | void sta_info_clear_tim_bit(struct sta_info *sta); | ||
528 | 503 | ||
529 | void sta_info_init(struct ieee80211_local *local); | 504 | void sta_info_init(struct ieee80211_local *local); |
530 | void sta_info_stop(struct ieee80211_local *local); | 505 | void sta_info_stop(struct ieee80211_local *local); |
@@ -535,5 +510,6 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | |||
535 | 510 | ||
536 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta); | 511 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta); |
537 | void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); | 512 | void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); |
513 | void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); | ||
538 | 514 | ||
539 | #endif /* STA_INFO_H */ | 515 | #endif /* STA_INFO_H */ |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index d50358c45ab0..864a9c3bcf46 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include "rate.h" | 14 | #include "rate.h" |
15 | #include "mesh.h" | 15 | #include "mesh.h" |
16 | #include "led.h" | 16 | #include "led.h" |
17 | #include "wme.h" | ||
17 | 18 | ||
18 | 19 | ||
19 | void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, | 20 | void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, |
@@ -43,6 +44,8 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
43 | struct sk_buff *skb) | 44 | struct sk_buff *skb) |
44 | { | 45 | { |
45 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 46 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
47 | struct ieee80211_hdr *hdr = (void *)skb->data; | ||
48 | int ac; | ||
46 | 49 | ||
47 | /* | 50 | /* |
48 | * This skb 'survived' a round-trip through the driver, and | 51 | * This skb 'survived' a round-trip through the driver, and |
@@ -63,11 +66,37 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
63 | sta->tx_filtered_count++; | 66 | sta->tx_filtered_count++; |
64 | 67 | ||
65 | /* | 68 | /* |
69 | * Clear more-data bit on filtered frames, it might be set | ||
70 | * but later frames might time out so it might have to be | ||
71 | * clear again ... It's all rather unlikely (this frame | ||
72 | * should time out first, right?) but let's not confuse | ||
73 | * peers unnecessarily. | ||
74 | */ | ||
75 | if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_MOREDATA)) | ||
76 | hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
77 | |||
78 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
79 | u8 *p = ieee80211_get_qos_ctl(hdr); | ||
80 | int tid = *p & IEEE80211_QOS_CTL_TID_MASK; | ||
81 | |||
82 | /* | ||
83 | * Clear EOSP if set, this could happen e.g. | ||
84 | * if an absence period (us being a P2P GO) | ||
85 | * shortens the SP. | ||
86 | */ | ||
87 | if (*p & IEEE80211_QOS_CTL_EOSP) | ||
88 | *p &= ~IEEE80211_QOS_CTL_EOSP; | ||
89 | ac = ieee802_1d_to_ac[tid & 7]; | ||
90 | } else { | ||
91 | ac = IEEE80211_AC_BE; | ||
92 | } | ||
93 | |||
94 | /* | ||
66 | * Clear the TX filter mask for this STA when sending the next | 95 | * Clear the TX filter mask for this STA when sending the next |
67 | * packet. If the STA went to power save mode, this will happen | 96 | * packet. If the STA went to power save mode, this will happen |
68 | * when it wakes up for the next time. | 97 | * when it wakes up for the next time. |
69 | */ | 98 | */ |
70 | set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT); | 99 | set_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT); |
71 | 100 | ||
72 | /* | 101 | /* |
73 | * This code races in the following way: | 102 | * This code races in the following way: |
@@ -103,13 +132,19 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
103 | * changes before calling TX status events if ordering can be | 132 | * changes before calling TX status events if ordering can be |
104 | * unknown. | 133 | * unknown. |
105 | */ | 134 | */ |
106 | if (test_sta_flags(sta, WLAN_STA_PS_STA) && | 135 | if (test_sta_flag(sta, WLAN_STA_PS_STA) && |
107 | skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { | 136 | skb_queue_len(&sta->tx_filtered[ac]) < STA_MAX_TX_BUFFER) { |
108 | skb_queue_tail(&sta->tx_filtered, skb); | 137 | skb_queue_tail(&sta->tx_filtered[ac], skb); |
138 | sta_info_recalc_tim(sta); | ||
139 | |||
140 | if (!timer_pending(&local->sta_cleanup)) | ||
141 | mod_timer(&local->sta_cleanup, | ||
142 | round_jiffies(jiffies + | ||
143 | STA_INFO_CLEANUP_INTERVAL)); | ||
109 | return; | 144 | return; |
110 | } | 145 | } |
111 | 146 | ||
112 | if (!test_sta_flags(sta, WLAN_STA_PS_STA) && | 147 | if (!test_sta_flag(sta, WLAN_STA_PS_STA) && |
113 | !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { | 148 | !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { |
114 | /* Software retry the packet once */ | 149 | /* Software retry the packet once */ |
115 | info->flags |= IEEE80211_TX_INTFL_RETRIED; | 150 | info->flags |= IEEE80211_TX_INTFL_RETRIED; |
@@ -121,8 +156,8 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
121 | if (net_ratelimit()) | 156 | if (net_ratelimit()) |
122 | wiphy_debug(local->hw.wiphy, | 157 | wiphy_debug(local->hw.wiphy, |
123 | "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", | 158 | "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", |
124 | skb_queue_len(&sta->tx_filtered), | 159 | skb_queue_len(&sta->tx_filtered[ac]), |
125 | !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies); | 160 | !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies); |
126 | #endif | 161 | #endif |
127 | dev_kfree_skb(skb); | 162 | dev_kfree_skb(skb); |
128 | } | 163 | } |
@@ -249,8 +284,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
249 | if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) | 284 | if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) |
250 | continue; | 285 | continue; |
251 | 286 | ||
287 | if (info->flags & IEEE80211_TX_STATUS_EOSP) | ||
288 | clear_sta_flag(sta, WLAN_STA_SP); | ||
289 | |||
252 | acked = !!(info->flags & IEEE80211_TX_STAT_ACK); | 290 | acked = !!(info->flags & IEEE80211_TX_STAT_ACK); |
253 | if (!acked && test_sta_flags(sta, WLAN_STA_PS_STA)) { | 291 | if (!acked && test_sta_flag(sta, WLAN_STA_PS_STA)) { |
254 | /* | 292 | /* |
255 | * The STA is in power save mode, so assume | 293 | * The STA is in power save mode, so assume |
256 | * that this TX packet failed because of that. | 294 | * that this TX packet failed because of that. |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7cd6c28968b2..ad2ee4a90ec4 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -253,7 +253,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) | |||
253 | 253 | ||
254 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; | 254 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; |
255 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 255 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
256 | u32 sta_flags; | 256 | bool assoc = false; |
257 | 257 | ||
258 | if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) | 258 | if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) |
259 | return TX_CONTINUE; | 259 | return TX_CONTINUE; |
@@ -284,10 +284,11 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) | |||
284 | if (tx->flags & IEEE80211_TX_PS_BUFFERED) | 284 | if (tx->flags & IEEE80211_TX_PS_BUFFERED) |
285 | return TX_CONTINUE; | 285 | return TX_CONTINUE; |
286 | 286 | ||
287 | sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0; | 287 | if (tx->sta) |
288 | assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC); | ||
288 | 289 | ||
289 | if (likely(tx->flags & IEEE80211_TX_UNICAST)) { | 290 | if (likely(tx->flags & IEEE80211_TX_UNICAST)) { |
290 | if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && | 291 | if (unlikely(!assoc && |
291 | tx->sdata->vif.type != NL80211_IFTYPE_ADHOC && | 292 | tx->sdata->vif.type != NL80211_IFTYPE_ADHOC && |
292 | ieee80211_is_data(hdr->frame_control))) { | 293 | ieee80211_is_data(hdr->frame_control))) { |
293 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 294 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
@@ -343,13 +344,22 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
343 | total += skb_queue_len(&ap->ps_bc_buf); | 344 | total += skb_queue_len(&ap->ps_bc_buf); |
344 | } | 345 | } |
345 | 346 | ||
347 | /* | ||
348 | * Drop one frame from each station from the lowest-priority | ||
349 | * AC that has frames at all. | ||
350 | */ | ||
346 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | 351 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
347 | skb = skb_dequeue(&sta->ps_tx_buf); | 352 | int ac; |
348 | if (skb) { | 353 | |
349 | purged++; | 354 | for (ac = IEEE80211_AC_BK; ac >= IEEE80211_AC_VO; ac--) { |
350 | dev_kfree_skb(skb); | 355 | skb = skb_dequeue(&sta->ps_tx_buf[ac]); |
356 | total += skb_queue_len(&sta->ps_tx_buf[ac]); | ||
357 | if (skb) { | ||
358 | purged++; | ||
359 | dev_kfree_skb(skb); | ||
360 | break; | ||
361 | } | ||
351 | } | 362 | } |
352 | total += skb_queue_len(&sta->ps_tx_buf); | ||
353 | } | 363 | } |
354 | 364 | ||
355 | rcu_read_unlock(); | 365 | rcu_read_unlock(); |
@@ -418,7 +428,7 @@ static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, | |||
418 | if (!ieee80211_is_mgmt(fc)) | 428 | if (!ieee80211_is_mgmt(fc)) |
419 | return 0; | 429 | return 0; |
420 | 430 | ||
421 | if (sta == NULL || !test_sta_flags(sta, WLAN_STA_MFP)) | 431 | if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP)) |
422 | return 0; | 432 | return 0; |
423 | 433 | ||
424 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) | 434 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) |
@@ -435,7 +445,6 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
435 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 445 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
436 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; | 446 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; |
437 | struct ieee80211_local *local = tx->local; | 447 | struct ieee80211_local *local = tx->local; |
438 | u32 staflags; | ||
439 | 448 | ||
440 | if (unlikely(!sta || | 449 | if (unlikely(!sta || |
441 | ieee80211_is_probe_resp(hdr->frame_control) || | 450 | ieee80211_is_probe_resp(hdr->frame_control) || |
@@ -444,57 +453,52 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
444 | ieee80211_is_reassoc_resp(hdr->frame_control))) | 453 | ieee80211_is_reassoc_resp(hdr->frame_control))) |
445 | return TX_CONTINUE; | 454 | return TX_CONTINUE; |
446 | 455 | ||
447 | staflags = get_sta_flags(sta); | 456 | if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) || |
457 | test_sta_flag(sta, WLAN_STA_PS_DRIVER)) && | ||
458 | !(info->flags & IEEE80211_TX_CTL_POLL_RESPONSE))) { | ||
459 | int ac = skb_get_queue_mapping(tx->skb); | ||
448 | 460 | ||
449 | if (unlikely((staflags & (WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) && | ||
450 | !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) { | ||
451 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 461 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
452 | printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries " | 462 | printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n", |
453 | "before %d)\n", | 463 | sta->sta.addr, sta->sta.aid, ac); |
454 | sta->sta.addr, sta->sta.aid, | ||
455 | skb_queue_len(&sta->ps_tx_buf)); | ||
456 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | 464 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ |
457 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) | 465 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) |
458 | purge_old_ps_buffers(tx->local); | 466 | purge_old_ps_buffers(tx->local); |
459 | if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { | 467 | if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) { |
460 | struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); | 468 | struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); |
461 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 469 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
462 | if (net_ratelimit()) { | 470 | if (net_ratelimit()) |
463 | printk(KERN_DEBUG "%s: STA %pM TX " | 471 | printk(KERN_DEBUG "%s: STA %pM TX buffer for " |
464 | "buffer full - dropping oldest frame\n", | 472 | "AC %d full - dropping oldest frame\n", |
465 | tx->sdata->name, sta->sta.addr); | 473 | tx->sdata->name, sta->sta.addr, ac); |
466 | } | ||
467 | #endif | 474 | #endif |
468 | dev_kfree_skb(old); | 475 | dev_kfree_skb(old); |
469 | } else | 476 | } else |
470 | tx->local->total_ps_buffered++; | 477 | tx->local->total_ps_buffered++; |
471 | 478 | ||
472 | /* | ||
473 | * Queue frame to be sent after STA wakes up/polls, | ||
474 | * but don't set the TIM bit if the driver is blocking | ||
475 | * wakeup or poll response transmissions anyway. | ||
476 | */ | ||
477 | if (skb_queue_empty(&sta->ps_tx_buf) && | ||
478 | !(staflags & WLAN_STA_PS_DRIVER)) | ||
479 | sta_info_set_tim_bit(sta); | ||
480 | |||
481 | info->control.jiffies = jiffies; | 479 | info->control.jiffies = jiffies; |
482 | info->control.vif = &tx->sdata->vif; | 480 | info->control.vif = &tx->sdata->vif; |
483 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 481 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
484 | skb_queue_tail(&sta->ps_tx_buf, tx->skb); | 482 | skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb); |
485 | 483 | ||
486 | if (!timer_pending(&local->sta_cleanup)) | 484 | if (!timer_pending(&local->sta_cleanup)) |
487 | mod_timer(&local->sta_cleanup, | 485 | mod_timer(&local->sta_cleanup, |
488 | round_jiffies(jiffies + | 486 | round_jiffies(jiffies + |
489 | STA_INFO_CLEANUP_INTERVAL)); | 487 | STA_INFO_CLEANUP_INTERVAL)); |
490 | 488 | ||
489 | /* | ||
490 | * We queued up some frames, so the TIM bit might | ||
491 | * need to be set, recalculate it. | ||
492 | */ | ||
493 | sta_info_recalc_tim(sta); | ||
494 | |||
491 | return TX_QUEUED; | 495 | return TX_QUEUED; |
492 | } | 496 | } |
493 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 497 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
494 | else if (unlikely(staflags & WLAN_STA_PS_STA)) { | 498 | else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) { |
495 | printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll " | 499 | printk(KERN_DEBUG |
496 | "set -> send frame\n", tx->sdata->name, | 500 | "%s: STA %pM in PS mode, but polling/in SP -> send frame\n", |
497 | sta->sta.addr); | 501 | tx->sdata->name, sta->sta.addr); |
498 | } | 502 | } |
499 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | 503 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ |
500 | 504 | ||
@@ -552,7 +556,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
552 | !(info->flags & IEEE80211_TX_CTL_INJECTED) && | 556 | !(info->flags & IEEE80211_TX_CTL_INJECTED) && |
553 | (!ieee80211_is_robust_mgmt_frame(hdr) || | 557 | (!ieee80211_is_robust_mgmt_frame(hdr) || |
554 | (ieee80211_is_action(hdr->frame_control) && | 558 | (ieee80211_is_action(hdr->frame_control) && |
555 | tx->sta && test_sta_flags(tx->sta, WLAN_STA_MFP)))) { | 559 | tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))) { |
556 | I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); | 560 | I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); |
557 | return TX_DROP; | 561 | return TX_DROP; |
558 | } else | 562 | } else |
@@ -611,7 +615,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
611 | u32 len; | 615 | u32 len; |
612 | bool inval = false, rts = false, short_preamble = false; | 616 | bool inval = false, rts = false, short_preamble = false; |
613 | struct ieee80211_tx_rate_control txrc; | 617 | struct ieee80211_tx_rate_control txrc; |
614 | u32 sta_flags; | 618 | bool assoc = false; |
615 | 619 | ||
616 | memset(&txrc, 0, sizeof(txrc)); | 620 | memset(&txrc, 0, sizeof(txrc)); |
617 | 621 | ||
@@ -647,17 +651,17 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
647 | */ | 651 | */ |
648 | if (tx->sdata->vif.bss_conf.use_short_preamble && | 652 | if (tx->sdata->vif.bss_conf.use_short_preamble && |
649 | (ieee80211_is_data(hdr->frame_control) || | 653 | (ieee80211_is_data(hdr->frame_control) || |
650 | (tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE)))) | 654 | (tx->sta && test_sta_flag(tx->sta, WLAN_STA_SHORT_PREAMBLE)))) |
651 | txrc.short_preamble = short_preamble = true; | 655 | txrc.short_preamble = short_preamble = true; |
652 | 656 | ||
653 | sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0; | 657 | if (tx->sta) |
658 | assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC); | ||
654 | 659 | ||
655 | /* | 660 | /* |
656 | * Lets not bother rate control if we're associated and cannot | 661 | * Lets not bother rate control if we're associated and cannot |
657 | * talk to the sta. This should not happen. | 662 | * talk to the sta. This should not happen. |
658 | */ | 663 | */ |
659 | if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && | 664 | if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc && |
660 | (sta_flags & WLAN_STA_ASSOC) && | ||
661 | !rate_usable_index_exists(sband, &tx->sta->sta), | 665 | !rate_usable_index_exists(sband, &tx->sta->sta), |
662 | "%s: Dropped data frame as no usable bitrate found while " | 666 | "%s: Dropped data frame as no usable bitrate found while " |
663 | "scanning and associated. Target station: " | 667 | "scanning and associated. Target station: " |
@@ -800,6 +804,9 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | |||
800 | if (ieee80211_hdrlen(hdr->frame_control) < 24) | 804 | if (ieee80211_hdrlen(hdr->frame_control) < 24) |
801 | return TX_CONTINUE; | 805 | return TX_CONTINUE; |
802 | 806 | ||
807 | if (ieee80211_is_qos_nullfunc(hdr->frame_control)) | ||
808 | return TX_CONTINUE; | ||
809 | |||
803 | /* | 810 | /* |
804 | * Anything but QoS data that has a sequence number field | 811 | * Anything but QoS data that has a sequence number field |
805 | * (is long enough) gets a sequence number from the global | 812 | * (is long enough) gets a sequence number from the global |
@@ -1047,6 +1054,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1047 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1054 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1048 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, | 1055 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, |
1049 | NULL); | 1056 | NULL); |
1057 | u16 txflags; | ||
1050 | 1058 | ||
1051 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 1059 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
1052 | tx->flags &= ~IEEE80211_TX_FRAGMENTED; | 1060 | tx->flags &= ~IEEE80211_TX_FRAGMENTED; |
@@ -1095,6 +1103,13 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1095 | tx->flags |= IEEE80211_TX_FRAGMENTED; | 1103 | tx->flags |= IEEE80211_TX_FRAGMENTED; |
1096 | break; | 1104 | break; |
1097 | 1105 | ||
1106 | case IEEE80211_RADIOTAP_TX_FLAGS: | ||
1107 | txflags = le16_to_cpu(get_unaligned((__le16*) | ||
1108 | iterator.this_arg)); | ||
1109 | if (txflags & IEEE80211_RADIOTAP_F_TX_NOACK) | ||
1110 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||
1111 | break; | ||
1112 | |||
1098 | /* | 1113 | /* |
1099 | * Please update the file | 1114 | * Please update the file |
1100 | * Documentation/networking/mac80211-injection.txt | 1115 | * Documentation/networking/mac80211-injection.txt |
@@ -1232,6 +1247,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1232 | tx->sta = sta_info_get(sdata, hdr->addr1); | 1247 | tx->sta = sta_info_get(sdata, hdr->addr1); |
1233 | 1248 | ||
1234 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && | 1249 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && |
1250 | !ieee80211_is_qos_nullfunc(hdr->frame_control) && | ||
1235 | (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) && | 1251 | (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) && |
1236 | !(local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)) { | 1252 | !(local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)) { |
1237 | struct tid_ampdu_tx *tid_tx; | 1253 | struct tid_ampdu_tx *tid_tx; |
@@ -1258,8 +1274,11 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1258 | tx->flags |= IEEE80211_TX_UNICAST; | 1274 | tx->flags |= IEEE80211_TX_UNICAST; |
1259 | if (unlikely(local->wifi_wme_noack_test)) | 1275 | if (unlikely(local->wifi_wme_noack_test)) |
1260 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | 1276 | info->flags |= IEEE80211_TX_CTL_NO_ACK; |
1261 | else | 1277 | /* |
1262 | info->flags &= ~IEEE80211_TX_CTL_NO_ACK; | 1278 | * Flags are initialized to 0. Hence, no need to |
1279 | * explicitly unset IEEE80211_TX_CTL_NO_ACK since | ||
1280 | * it might already be set for injected frames. | ||
1281 | */ | ||
1263 | } | 1282 | } |
1264 | 1283 | ||
1265 | if (tx->flags & IEEE80211_TX_FRAGMENTED) { | 1284 | if (tx->flags & IEEE80211_TX_FRAGMENTED) { |
@@ -1273,7 +1292,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1273 | 1292 | ||
1274 | if (!tx->sta) | 1293 | if (!tx->sta) |
1275 | info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; | 1294 | info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; |
1276 | else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT)) | 1295 | else if (test_and_clear_sta_flag(tx->sta, WLAN_STA_CLEAR_PS_FILT)) |
1277 | info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; | 1296 | info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; |
1278 | 1297 | ||
1279 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 1298 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
@@ -1515,8 +1534,7 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, | |||
1515 | return 0; | 1534 | return 0; |
1516 | } | 1535 | } |
1517 | 1536 | ||
1518 | static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | 1537 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
1519 | struct sk_buff *skb) | ||
1520 | { | 1538 | { |
1521 | struct ieee80211_local *local = sdata->local; | 1539 | struct ieee80211_local *local = sdata->local; |
1522 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1540 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
@@ -1724,8 +1742,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1724 | int encaps_len, skip_header_bytes; | 1742 | int encaps_len, skip_header_bytes; |
1725 | int nh_pos, h_pos; | 1743 | int nh_pos, h_pos; |
1726 | struct sta_info *sta = NULL; | 1744 | struct sta_info *sta = NULL; |
1727 | u32 sta_flags = 0; | 1745 | bool wme_sta = false, authorized = false, tdls_auth = false; |
1728 | struct sk_buff *tmp_skb; | 1746 | struct sk_buff *tmp_skb; |
1747 | bool tdls_direct = false; | ||
1729 | 1748 | ||
1730 | if (unlikely(skb->len < ETH_HLEN)) { | 1749 | if (unlikely(skb->len < ETH_HLEN)) { |
1731 | ret = NETDEV_TX_OK; | 1750 | ret = NETDEV_TX_OK; |
@@ -1749,7 +1768,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1749 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1768 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
1750 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | 1769 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); |
1751 | hdrlen = 30; | 1770 | hdrlen = 30; |
1752 | sta_flags = get_sta_flags(sta); | 1771 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); |
1772 | wme_sta = test_sta_flag(sta, WLAN_STA_WME); | ||
1753 | } | 1773 | } |
1754 | rcu_read_unlock(); | 1774 | rcu_read_unlock(); |
1755 | if (sta) | 1775 | if (sta) |
@@ -1837,11 +1857,50 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1837 | break; | 1857 | break; |
1838 | #endif | 1858 | #endif |
1839 | case NL80211_IFTYPE_STATION: | 1859 | case NL80211_IFTYPE_STATION: |
1840 | memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); | 1860 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { |
1841 | if (sdata->u.mgd.use_4addr && | 1861 | bool tdls_peer = false; |
1842 | cpu_to_be16(ethertype) != sdata->control_port_protocol) { | 1862 | |
1843 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | 1863 | rcu_read_lock(); |
1864 | sta = sta_info_get(sdata, skb->data); | ||
1865 | if (sta) { | ||
1866 | authorized = test_sta_flag(sta, | ||
1867 | WLAN_STA_AUTHORIZED); | ||
1868 | wme_sta = test_sta_flag(sta, WLAN_STA_WME); | ||
1869 | tdls_peer = test_sta_flag(sta, | ||
1870 | WLAN_STA_TDLS_PEER); | ||
1871 | tdls_auth = test_sta_flag(sta, | ||
1872 | WLAN_STA_TDLS_PEER_AUTH); | ||
1873 | } | ||
1874 | rcu_read_unlock(); | ||
1875 | |||
1876 | /* | ||
1877 | * If the TDLS link is enabled, send everything | ||
1878 | * directly. Otherwise, allow TDLS setup frames | ||
1879 | * to be transmitted indirectly. | ||
1880 | */ | ||
1881 | tdls_direct = tdls_peer && (tdls_auth || | ||
1882 | !(ethertype == ETH_P_TDLS && skb->len > 14 && | ||
1883 | skb->data[14] == WLAN_TDLS_SNAP_RFTYPE)); | ||
1884 | } | ||
1885 | |||
1886 | if (tdls_direct) { | ||
1887 | /* link during setup - throw out frames to peer */ | ||
1888 | if (!tdls_auth) { | ||
1889 | ret = NETDEV_TX_OK; | ||
1890 | goto fail; | ||
1891 | } | ||
1892 | |||
1893 | /* DA SA BSSID */ | ||
1894 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | ||
1895 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
1896 | memcpy(hdr.addr3, sdata->u.mgd.bssid, ETH_ALEN); | ||
1897 | hdrlen = 24; | ||
1898 | } else if (sdata->u.mgd.use_4addr && | ||
1899 | cpu_to_be16(ethertype) != sdata->control_port_protocol) { | ||
1900 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | | ||
1901 | IEEE80211_FCTL_TODS); | ||
1844 | /* RA TA DA SA */ | 1902 | /* RA TA DA SA */ |
1903 | memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); | ||
1845 | memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); | 1904 | memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); |
1846 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1905 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
1847 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | 1906 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); |
@@ -1849,6 +1908,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1849 | } else { | 1908 | } else { |
1850 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | 1909 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
1851 | /* BSSID SA DA */ | 1910 | /* BSSID SA DA */ |
1911 | memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); | ||
1852 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 1912 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
1853 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1913 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
1854 | hdrlen = 24; | 1914 | hdrlen = 24; |
@@ -1874,17 +1934,19 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1874 | if (!is_multicast_ether_addr(hdr.addr1)) { | 1934 | if (!is_multicast_ether_addr(hdr.addr1)) { |
1875 | rcu_read_lock(); | 1935 | rcu_read_lock(); |
1876 | sta = sta_info_get(sdata, hdr.addr1); | 1936 | sta = sta_info_get(sdata, hdr.addr1); |
1877 | if (sta) | 1937 | if (sta) { |
1878 | sta_flags = get_sta_flags(sta); | 1938 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); |
1939 | wme_sta = test_sta_flag(sta, WLAN_STA_WME); | ||
1940 | } | ||
1879 | rcu_read_unlock(); | 1941 | rcu_read_unlock(); |
1880 | } | 1942 | } |
1881 | 1943 | ||
1882 | /* For mesh, the use of the QoS header is mandatory */ | 1944 | /* For mesh, the use of the QoS header is mandatory */ |
1883 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 1945 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
1884 | sta_flags |= WLAN_STA_WME; | 1946 | wme_sta = true; |
1885 | 1947 | ||
1886 | /* receiver and we are QoS enabled, use a QoS type frame */ | 1948 | /* receiver and we are QoS enabled, use a QoS type frame */ |
1887 | if ((sta_flags & WLAN_STA_WME) && local->hw.queues >= 4) { | 1949 | if (wme_sta && local->hw.queues >= 4) { |
1888 | fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); | 1950 | fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); |
1889 | hdrlen += 2; | 1951 | hdrlen += 2; |
1890 | } | 1952 | } |
@@ -1894,8 +1956,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1894 | * EAPOL frames from the local station. | 1956 | * EAPOL frames from the local station. |
1895 | */ | 1957 | */ |
1896 | if (!ieee80211_vif_is_mesh(&sdata->vif) && | 1958 | if (!ieee80211_vif_is_mesh(&sdata->vif) && |
1897 | unlikely(!is_multicast_ether_addr(hdr.addr1) && | 1959 | unlikely(!is_multicast_ether_addr(hdr.addr1) && !authorized && |
1898 | !(sta_flags & WLAN_STA_AUTHORIZED) && | ||
1899 | !(cpu_to_be16(ethertype) == sdata->control_port_protocol && | 1960 | !(cpu_to_be16(ethertype) == sdata->control_port_protocol && |
1900 | compare_ether_addr(sdata->vif.addr, | 1961 | compare_ether_addr(sdata->vif.addr, |
1901 | skb->data + ETH_ALEN) == 0))) { | 1962 | skb->data + ETH_ALEN) == 0))) { |
@@ -2307,9 +2368,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2307 | *pos++ = WLAN_EID_SSID; | 2368 | *pos++ = WLAN_EID_SSID; |
2308 | *pos++ = 0x0; | 2369 | *pos++ = 0x0; |
2309 | 2370 | ||
2310 | if (mesh_add_srates_ie(skb, sdata) || | 2371 | if (ieee80211_add_srates_ie(&sdata->vif, skb) || |
2311 | mesh_add_ds_params_ie(skb, sdata) || | 2372 | mesh_add_ds_params_ie(skb, sdata) || |
2312 | mesh_add_ext_srates_ie(skb, sdata) || | 2373 | ieee80211_add_ext_srates_ie(&sdata->vif, skb) || |
2313 | mesh_add_rsn_ie(skb, sdata) || | 2374 | mesh_add_rsn_ie(skb, sdata) || |
2314 | mesh_add_meshid_ie(skb, sdata) || | 2375 | mesh_add_meshid_ie(skb, sdata) || |
2315 | mesh_add_meshconf_ie(skb, sdata) || | 2376 | mesh_add_meshconf_ie(skb, sdata) || |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 2c9dc360dc6d..7439d26bf5f9 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -367,14 +367,14 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, | |||
367 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 367 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
368 | } | 368 | } |
369 | 369 | ||
370 | int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | 370 | void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, |
371 | struct sk_buff_head *skbs, | 371 | struct sk_buff_head *skbs, |
372 | void (*fn)(void *data), void *data) | 372 | void (*fn)(void *data), void *data) |
373 | { | 373 | { |
374 | struct ieee80211_hw *hw = &local->hw; | 374 | struct ieee80211_hw *hw = &local->hw; |
375 | struct sk_buff *skb; | 375 | struct sk_buff *skb; |
376 | unsigned long flags; | 376 | unsigned long flags; |
377 | int queue, ret = 0, i; | 377 | int queue, i; |
378 | 378 | ||
379 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 379 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
380 | for (i = 0; i < hw->queues; i++) | 380 | for (i = 0; i < hw->queues; i++) |
@@ -389,7 +389,6 @@ int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | |||
389 | continue; | 389 | continue; |
390 | } | 390 | } |
391 | 391 | ||
392 | ret++; | ||
393 | queue = skb_get_queue_mapping(skb); | 392 | queue = skb_get_queue_mapping(skb); |
394 | __skb_queue_tail(&local->pending[queue], skb); | 393 | __skb_queue_tail(&local->pending[queue], skb); |
395 | } | 394 | } |
@@ -401,14 +400,12 @@ int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | |||
401 | __ieee80211_wake_queue(hw, i, | 400 | __ieee80211_wake_queue(hw, i, |
402 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 401 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); |
403 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 402 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
404 | |||
405 | return ret; | ||
406 | } | 403 | } |
407 | 404 | ||
408 | int ieee80211_add_pending_skbs(struct ieee80211_local *local, | 405 | void ieee80211_add_pending_skbs(struct ieee80211_local *local, |
409 | struct sk_buff_head *skbs) | 406 | struct sk_buff_head *skbs) |
410 | { | 407 | { |
411 | return ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); | 408 | ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); |
412 | } | 409 | } |
413 | 410 | ||
414 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 411 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
@@ -1125,7 +1122,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1125 | 1122 | ||
1126 | list_for_each_entry(sta, &local->sta_list, list) { | 1123 | list_for_each_entry(sta, &local->sta_list, list) { |
1127 | ieee80211_sta_tear_down_BA_sessions(sta, true); | 1124 | ieee80211_sta_tear_down_BA_sessions(sta, true); |
1128 | clear_sta_flags(sta, WLAN_STA_BLOCK_BA); | 1125 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); |
1129 | } | 1126 | } |
1130 | 1127 | ||
1131 | mutex_unlock(&local->sta_mtx); | 1128 | mutex_unlock(&local->sta_mtx); |
@@ -1364,3 +1361,60 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif) | |||
1364 | _ieee80211_enable_rssi_reports(sdata, 0, 0); | 1361 | _ieee80211_enable_rssi_reports(sdata, 0, 0); |
1365 | } | 1362 | } |
1366 | EXPORT_SYMBOL(ieee80211_disable_rssi_reports); | 1363 | EXPORT_SYMBOL(ieee80211_disable_rssi_reports); |
1364 | |||
1365 | int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb) | ||
1366 | { | ||
1367 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1368 | struct ieee80211_local *local = sdata->local; | ||
1369 | struct ieee80211_supported_band *sband; | ||
1370 | int rate; | ||
1371 | u8 i, rates, *pos; | ||
1372 | |||
1373 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1374 | rates = sband->n_bitrates; | ||
1375 | if (rates > 8) | ||
1376 | rates = 8; | ||
1377 | |||
1378 | if (skb_tailroom(skb) < rates + 2) | ||
1379 | return -ENOMEM; | ||
1380 | |||
1381 | pos = skb_put(skb, rates + 2); | ||
1382 | *pos++ = WLAN_EID_SUPP_RATES; | ||
1383 | *pos++ = rates; | ||
1384 | for (i = 0; i < rates; i++) { | ||
1385 | rate = sband->bitrates[i].bitrate; | ||
1386 | *pos++ = (u8) (rate / 5); | ||
1387 | } | ||
1388 | |||
1389 | return 0; | ||
1390 | } | ||
1391 | |||
1392 | int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb) | ||
1393 | { | ||
1394 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1395 | struct ieee80211_local *local = sdata->local; | ||
1396 | struct ieee80211_supported_band *sband; | ||
1397 | int rate; | ||
1398 | u8 i, exrates, *pos; | ||
1399 | |||
1400 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1401 | exrates = sband->n_bitrates; | ||
1402 | if (exrates > 8) | ||
1403 | exrates -= 8; | ||
1404 | else | ||
1405 | exrates = 0; | ||
1406 | |||
1407 | if (skb_tailroom(skb) < exrates + 2) | ||
1408 | return -ENOMEM; | ||
1409 | |||
1410 | if (exrates) { | ||
1411 | pos = skb_put(skb, exrates + 2); | ||
1412 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
1413 | *pos++ = exrates; | ||
1414 | for (i = 8; i < sband->n_bitrates; i++) { | ||
1415 | rate = sband->bitrates[i].bitrate; | ||
1416 | *pos++ = (u8) (rate / 5); | ||
1417 | } | ||
1418 | } | ||
1419 | return 0; | ||
1420 | } | ||
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 971004c9b04f..fd52e695c071 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -72,7 +72,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
72 | case NL80211_IFTYPE_AP_VLAN: | 72 | case NL80211_IFTYPE_AP_VLAN: |
73 | sta = rcu_dereference(sdata->u.vlan.sta); | 73 | sta = rcu_dereference(sdata->u.vlan.sta); |
74 | if (sta) { | 74 | if (sta) { |
75 | qos = get_sta_flags(sta) & WLAN_STA_WME; | 75 | qos = test_sta_flag(sta, WLAN_STA_WME); |
76 | break; | 76 | break; |
77 | } | 77 | } |
78 | case NL80211_IFTYPE_AP: | 78 | case NL80211_IFTYPE_AP: |
@@ -99,7 +99,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
99 | if (!sta && ra && !is_multicast_ether_addr(ra)) { | 99 | if (!sta && ra && !is_multicast_ether_addr(ra)) { |
100 | sta = sta_info_get(sdata, ra); | 100 | sta = sta_info_get(sdata, ra); |
101 | if (sta) | 101 | if (sta) |
102 | qos = get_sta_flags(sta) & WLAN_STA_WME; | 102 | qos = test_sta_flag(sta, WLAN_STA_WME); |
103 | } | 103 | } |
104 | rcu_read_unlock(); | 104 | rcu_read_unlock(); |
105 | 105 | ||
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index 256c5ddd2d72..128677d69056 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c | |||
@@ -101,6 +101,14 @@ static int rfkill_gpio_probe(struct platform_device *pdev) | |||
101 | if (!rfkill) | 101 | if (!rfkill) |
102 | return -ENOMEM; | 102 | return -ENOMEM; |
103 | 103 | ||
104 | if (pdata->gpio_runtime_setup) { | ||
105 | ret = pdata->gpio_runtime_setup(pdev); | ||
106 | if (ret) { | ||
107 | pr_warn("%s: can't set up gpio\n", __func__); | ||
108 | return ret; | ||
109 | } | ||
110 | } | ||
111 | |||
104 | rfkill->pdata = pdata; | 112 | rfkill->pdata = pdata; |
105 | 113 | ||
106 | len = strlen(pdata->name); | 114 | len = strlen(pdata->name); |
@@ -182,7 +190,10 @@ fail_alloc: | |||
182 | static int rfkill_gpio_remove(struct platform_device *pdev) | 190 | static int rfkill_gpio_remove(struct platform_device *pdev) |
183 | { | 191 | { |
184 | struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev); | 192 | struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev); |
193 | struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data; | ||
185 | 194 | ||
195 | if (pdata->gpio_runtime_close) | ||
196 | pdata->gpio_runtime_close(pdev); | ||
186 | rfkill_unregister(rfkill->rfkill_dev); | 197 | rfkill_unregister(rfkill->rfkill_dev); |
187 | rfkill_destroy(rfkill->rfkill_dev); | 198 | rfkill_destroy(rfkill->rfkill_dev); |
188 | if (gpio_is_valid(rfkill->pdata->shutdown_gpio)) | 199 | if (gpio_is_valid(rfkill->pdata->shutdown_gpio)) |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b85075761e24..edf655aeea00 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -192,6 +192,11 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
192 | [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG }, | 192 | [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG }, |
193 | [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED }, | 193 | [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED }, |
194 | [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG }, | 194 | [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG }, |
195 | [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 }, | ||
196 | [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 }, | ||
197 | [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 }, | ||
198 | [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG }, | ||
199 | [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG }, | ||
195 | }; | 200 | }; |
196 | 201 | ||
197 | /* policy for the key attributes */ | 202 | /* policy for the key attributes */ |
@@ -732,9 +737,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
732 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH); | 737 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH); |
733 | if (dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) | 738 | if (dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) |
734 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_AP_UAPSD); | 739 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_AP_UAPSD); |
735 | |||
736 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) | 740 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) |
737 | NLA_PUT_FLAG(msg, NL80211_ATTR_ROAM_SUPPORT); | 741 | NLA_PUT_FLAG(msg, NL80211_ATTR_ROAM_SUPPORT); |
742 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) | ||
743 | NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_SUPPORT); | ||
744 | if (dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) | ||
745 | NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP); | ||
738 | 746 | ||
739 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, | 747 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, |
740 | sizeof(u32) * dev->wiphy.n_cipher_suites, | 748 | sizeof(u32) * dev->wiphy.n_cipher_suites, |
@@ -877,6 +885,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
877 | } | 885 | } |
878 | CMD(set_channel, SET_CHANNEL); | 886 | CMD(set_channel, SET_CHANNEL); |
879 | CMD(set_wds_peer, SET_WDS_PEER); | 887 | CMD(set_wds_peer, SET_WDS_PEER); |
888 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { | ||
889 | CMD(tdls_mgmt, TDLS_MGMT); | ||
890 | CMD(tdls_oper, TDLS_OPER); | ||
891 | } | ||
880 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | 892 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) |
881 | CMD(sched_scan_start, START_SCHED_SCAN); | 893 | CMD(sched_scan_start, START_SCHED_SCAN); |
882 | 894 | ||
@@ -2518,18 +2530,25 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2518 | break; | 2530 | break; |
2519 | case NL80211_IFTYPE_P2P_CLIENT: | 2531 | case NL80211_IFTYPE_P2P_CLIENT: |
2520 | case NL80211_IFTYPE_STATION: | 2532 | case NL80211_IFTYPE_STATION: |
2521 | /* disallow everything but AUTHORIZED flag */ | 2533 | /* disallow things sta doesn't support */ |
2522 | if (params.plink_action) | 2534 | if (params.plink_action) |
2523 | err = -EINVAL; | 2535 | err = -EINVAL; |
2524 | if (params.vlan) | 2536 | if (params.vlan) |
2525 | err = -EINVAL; | 2537 | err = -EINVAL; |
2526 | if (params.supported_rates) | 2538 | if (params.supported_rates && |
2539 | !(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
2527 | err = -EINVAL; | 2540 | err = -EINVAL; |
2528 | if (params.ht_capa) | 2541 | if (params.ht_capa) |
2529 | err = -EINVAL; | 2542 | err = -EINVAL; |
2530 | if (params.listen_interval >= 0) | 2543 | if (params.listen_interval >= 0) |
2531 | err = -EINVAL; | 2544 | err = -EINVAL; |
2532 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | 2545 | if (params.sta_flags_mask & |
2546 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
2547 | BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
2548 | err = -EINVAL; | ||
2549 | /* can't change the TDLS bit */ | ||
2550 | if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) && | ||
2551 | (params.sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
2533 | err = -EINVAL; | 2552 | err = -EINVAL; |
2534 | break; | 2553 | break; |
2535 | case NL80211_IFTYPE_MESH_POINT: | 2554 | case NL80211_IFTYPE_MESH_POINT: |
@@ -2643,12 +2662,25 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2643 | 2662 | ||
2644 | if (params.max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) | 2663 | if (params.max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) |
2645 | return -EINVAL; | 2664 | return -EINVAL; |
2665 | |||
2666 | params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD; | ||
2646 | } | 2667 | } |
2647 | 2668 | ||
2648 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2669 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2649 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 2670 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2650 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | 2671 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && |
2651 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 2672 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO && |
2673 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) | ||
2674 | return -EINVAL; | ||
2675 | |||
2676 | /* | ||
2677 | * Only managed stations can add TDLS peers, and only when the | ||
2678 | * wiphy supports external TDLS setup. | ||
2679 | */ | ||
2680 | if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION && | ||
2681 | !((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) && | ||
2682 | (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) && | ||
2683 | (rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))) | ||
2652 | return -EINVAL; | 2684 | return -EINVAL; |
2653 | 2685 | ||
2654 | err = get_vlan(info, rdev, ¶ms.vlan); | 2686 | err = get_vlan(info, rdev, ¶ms.vlan); |
@@ -4964,6 +4996,57 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) | |||
4964 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); | 4996 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); |
4965 | } | 4997 | } |
4966 | 4998 | ||
4999 | static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) | ||
5000 | { | ||
5001 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5002 | struct net_device *dev = info->user_ptr[1]; | ||
5003 | u8 action_code, dialog_token; | ||
5004 | u16 status_code; | ||
5005 | u8 *peer; | ||
5006 | |||
5007 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || | ||
5008 | !rdev->ops->tdls_mgmt) | ||
5009 | return -EOPNOTSUPP; | ||
5010 | |||
5011 | if (!info->attrs[NL80211_ATTR_TDLS_ACTION] || | ||
5012 | !info->attrs[NL80211_ATTR_STATUS_CODE] || | ||
5013 | !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] || | ||
5014 | !info->attrs[NL80211_ATTR_IE] || | ||
5015 | !info->attrs[NL80211_ATTR_MAC]) | ||
5016 | return -EINVAL; | ||
5017 | |||
5018 | peer = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
5019 | action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]); | ||
5020 | status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); | ||
5021 | dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]); | ||
5022 | |||
5023 | return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, | ||
5024 | dialog_token, status_code, | ||
5025 | nla_data(info->attrs[NL80211_ATTR_IE]), | ||
5026 | nla_len(info->attrs[NL80211_ATTR_IE])); | ||
5027 | } | ||
5028 | |||
5029 | static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info) | ||
5030 | { | ||
5031 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5032 | struct net_device *dev = info->user_ptr[1]; | ||
5033 | enum nl80211_tdls_operation operation; | ||
5034 | u8 *peer; | ||
5035 | |||
5036 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || | ||
5037 | !rdev->ops->tdls_oper) | ||
5038 | return -EOPNOTSUPP; | ||
5039 | |||
5040 | if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] || | ||
5041 | !info->attrs[NL80211_ATTR_MAC]) | ||
5042 | return -EINVAL; | ||
5043 | |||
5044 | operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]); | ||
5045 | peer = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
5046 | |||
5047 | return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, operation); | ||
5048 | } | ||
5049 | |||
4967 | static int nl80211_remain_on_channel(struct sk_buff *skb, | 5050 | static int nl80211_remain_on_channel(struct sk_buff *skb, |
4968 | struct genl_info *info) | 5051 | struct genl_info *info) |
4969 | { | 5052 | { |
@@ -6279,6 +6362,22 @@ static struct genl_ops nl80211_ops[] = { | |||
6279 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 6362 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
6280 | NL80211_FLAG_NEED_RTNL, | 6363 | NL80211_FLAG_NEED_RTNL, |
6281 | }, | 6364 | }, |
6365 | { | ||
6366 | .cmd = NL80211_CMD_TDLS_MGMT, | ||
6367 | .doit = nl80211_tdls_mgmt, | ||
6368 | .policy = nl80211_policy, | ||
6369 | .flags = GENL_ADMIN_PERM, | ||
6370 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
6371 | NL80211_FLAG_NEED_RTNL, | ||
6372 | }, | ||
6373 | { | ||
6374 | .cmd = NL80211_CMD_TDLS_OPER, | ||
6375 | .doit = nl80211_tdls_oper, | ||
6376 | .policy = nl80211_policy, | ||
6377 | .flags = GENL_ADMIN_PERM, | ||
6378 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
6379 | NL80211_FLAG_NEED_RTNL, | ||
6380 | }, | ||
6282 | }; | 6381 | }; |
6283 | 6382 | ||
6284 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 6383 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 6304ed63588a..2f178f73943f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -396,8 +396,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
396 | } | 396 | } |
397 | break; | 397 | break; |
398 | case cpu_to_le16(0): | 398 | case cpu_to_le16(0): |
399 | if (iftype != NL80211_IFTYPE_ADHOC) | 399 | if (iftype != NL80211_IFTYPE_ADHOC && |
400 | return -1; | 400 | iftype != NL80211_IFTYPE_STATION) |
401 | return -1; | ||
401 | break; | 402 | break; |
402 | } | 403 | } |
403 | 404 | ||