diff options
author | David S. Miller <davem@davemloft.net> | 2011-01-06 13:55:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-01-06 13:55:42 -0500 |
commit | 5f9251cb93237c9578160df9acc6ce9948ad8c52 (patch) | |
tree | 5a5718b5a076ce6f04bb3d0e1691aa65d87cc8a8 /net | |
parent | 2c6607c611cb7bf0a6750bcea34a258144e302c5 (diff) | |
parent | 06778b1c383afbdb88ffd837e117bec06a76f450 (diff) |
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/Makefile | 2 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 17 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 33 | ||||
-rw-r--r-- | net/bluetooth/hci_sock.c | 52 | ||||
-rw-r--r-- | net/bluetooth/l2cap.c | 8 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 308 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 142 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 30 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 80 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 21 | ||||
-rw-r--r-- | net/mac80211/iface.c | 9 | ||||
-rw-r--r-- | net/mac80211/key.c | 44 | ||||
-rw-r--r-- | net/mac80211/led.c | 4 | ||||
-rw-r--r-- | net/mac80211/main.c | 8 | ||||
-rw-r--r-- | net/mac80211/offchannel.c | 85 | ||||
-rw-r--r-- | net/mac80211/rx.c | 112 | ||||
-rw-r--r-- | net/mac80211/tx.c | 14 | ||||
-rw-r--r-- | net/mac80211/wme.c | 20 | ||||
-rw-r--r-- | net/wireless/reg.c | 2 |
19 files changed, 855 insertions, 136 deletions
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 7ca1f46a471a..250f954f0213 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile | |||
@@ -10,4 +10,4 @@ obj-$(CONFIG_BT_BNEP) += bnep/ | |||
10 | obj-$(CONFIG_BT_CMTP) += cmtp/ | 10 | obj-$(CONFIG_BT_CMTP) += cmtp/ |
11 | obj-$(CONFIG_BT_HIDP) += hidp/ | 11 | obj-$(CONFIG_BT_HIDP) += hidp/ |
12 | 12 | ||
13 | bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o | 13 | bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 51c61f75a797..8b602d881fd7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -91,9 +91,16 @@ static void hci_notify(struct hci_dev *hdev, int event) | |||
91 | 91 | ||
92 | /* ---- HCI requests ---- */ | 92 | /* ---- HCI requests ---- */ |
93 | 93 | ||
94 | void hci_req_complete(struct hci_dev *hdev, int result) | 94 | void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) |
95 | { | 95 | { |
96 | BT_DBG("%s result 0x%2.2x", hdev->name, result); | 96 | BT_DBG("%s command 0x%04x result 0x%2.2x", hdev->name, cmd, result); |
97 | |||
98 | /* If the request has set req_last_cmd (typical for multi-HCI | ||
99 | * command requests) check if the completed command matches | ||
100 | * this, and if not just return. Single HCI command requests | ||
101 | * typically leave req_last_cmd as 0 */ | ||
102 | if (hdev->req_last_cmd && cmd != hdev->req_last_cmd) | ||
103 | return; | ||
97 | 104 | ||
98 | if (hdev->req_status == HCI_REQ_PEND) { | 105 | if (hdev->req_status == HCI_REQ_PEND) { |
99 | hdev->req_result = result; | 106 | hdev->req_result = result; |
@@ -149,7 +156,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, | |||
149 | break; | 156 | break; |
150 | } | 157 | } |
151 | 158 | ||
152 | hdev->req_status = hdev->req_result = 0; | 159 | hdev->req_last_cmd = hdev->req_status = hdev->req_result = 0; |
153 | 160 | ||
154 | BT_DBG("%s end: err %d", hdev->name, err); | 161 | BT_DBG("%s end: err %d", hdev->name, err); |
155 | 162 | ||
@@ -252,6 +259,8 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) | |||
252 | /* Connection accept timeout ~20 secs */ | 259 | /* Connection accept timeout ~20 secs */ |
253 | param = cpu_to_le16(0x7d00); | 260 | param = cpu_to_le16(0x7d00); |
254 | hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); | 261 | hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); |
262 | |||
263 | hdev->req_last_cmd = HCI_OP_WRITE_CA_TIMEOUT; | ||
255 | } | 264 | } |
256 | 265 | ||
257 | static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) | 266 | static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) |
@@ -960,6 +969,7 @@ int hci_register_dev(struct hci_dev *hdev) | |||
960 | } | 969 | } |
961 | } | 970 | } |
962 | 971 | ||
972 | mgmt_index_added(hdev->id); | ||
963 | hci_notify(hdev, HCI_DEV_REG); | 973 | hci_notify(hdev, HCI_DEV_REG); |
964 | 974 | ||
965 | return id; | 975 | return id; |
@@ -989,6 +999,7 @@ int hci_unregister_dev(struct hci_dev *hdev) | |||
989 | for (i = 0; i < NUM_REASSEMBLY; i++) | 999 | for (i = 0; i < NUM_REASSEMBLY; i++) |
990 | kfree_skb(hdev->reassembly[i]); | 1000 | kfree_skb(hdev->reassembly[i]); |
991 | 1001 | ||
1002 | mgmt_index_removed(hdev->id); | ||
992 | hci_notify(hdev, HCI_DEV_UNREG); | 1003 | hci_notify(hdev, HCI_DEV_UNREG); |
993 | 1004 | ||
994 | if (hdev->rfkill) { | 1005 | if (hdev->rfkill) { |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8923b36a67a2..38100170d380 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -58,7 +58,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) | |||
58 | 58 | ||
59 | clear_bit(HCI_INQUIRY, &hdev->flags); | 59 | clear_bit(HCI_INQUIRY, &hdev->flags); |
60 | 60 | ||
61 | hci_req_complete(hdev, status); | 61 | hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); |
62 | 62 | ||
63 | hci_conn_check_pending(hdev); | 63 | hci_conn_check_pending(hdev); |
64 | } | 64 | } |
@@ -174,7 +174,7 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *s | |||
174 | if (!status) | 174 | if (!status) |
175 | hdev->link_policy = get_unaligned_le16(sent); | 175 | hdev->link_policy = get_unaligned_le16(sent); |
176 | 176 | ||
177 | hci_req_complete(hdev, status); | 177 | hci_req_complete(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, status); |
178 | } | 178 | } |
179 | 179 | ||
180 | static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) | 180 | static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -183,7 +183,7 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) | |||
183 | 183 | ||
184 | BT_DBG("%s status 0x%x", hdev->name, status); | 184 | BT_DBG("%s status 0x%x", hdev->name, status); |
185 | 185 | ||
186 | hci_req_complete(hdev, status); | 186 | hci_req_complete(hdev, HCI_OP_RESET, status); |
187 | } | 187 | } |
188 | 188 | ||
189 | static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) | 189 | static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -235,7 +235,7 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) | |||
235 | clear_bit(HCI_AUTH, &hdev->flags); | 235 | clear_bit(HCI_AUTH, &hdev->flags); |
236 | } | 236 | } |
237 | 237 | ||
238 | hci_req_complete(hdev, status); | 238 | hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status); |
239 | } | 239 | } |
240 | 240 | ||
241 | static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb) | 241 | static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -258,7 +258,7 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb) | |||
258 | clear_bit(HCI_ENCRYPT, &hdev->flags); | 258 | clear_bit(HCI_ENCRYPT, &hdev->flags); |
259 | } | 259 | } |
260 | 260 | ||
261 | hci_req_complete(hdev, status); | 261 | hci_req_complete(hdev, HCI_OP_WRITE_ENCRYPT_MODE, status); |
262 | } | 262 | } |
263 | 263 | ||
264 | static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) | 264 | static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -285,7 +285,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) | |||
285 | set_bit(HCI_PSCAN, &hdev->flags); | 285 | set_bit(HCI_PSCAN, &hdev->flags); |
286 | } | 286 | } |
287 | 287 | ||
288 | hci_req_complete(hdev, status); | 288 | hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status); |
289 | } | 289 | } |
290 | 290 | ||
291 | static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb) | 291 | static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -383,7 +383,7 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) | |||
383 | 383 | ||
384 | BT_DBG("%s status 0x%x", hdev->name, status); | 384 | BT_DBG("%s status 0x%x", hdev->name, status); |
385 | 385 | ||
386 | hci_req_complete(hdev, status); | 386 | hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status); |
387 | } | 387 | } |
388 | 388 | ||
389 | static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) | 389 | static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -536,7 +536,16 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb) | |||
536 | if (!rp->status) | 536 | if (!rp->status) |
537 | bacpy(&hdev->bdaddr, &rp->bdaddr); | 537 | bacpy(&hdev->bdaddr, &rp->bdaddr); |
538 | 538 | ||
539 | hci_req_complete(hdev, rp->status); | 539 | hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status); |
540 | } | ||
541 | |||
542 | static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb) | ||
543 | { | ||
544 | __u8 status = *((__u8 *) skb->data); | ||
545 | |||
546 | BT_DBG("%s status 0x%x", hdev->name, status); | ||
547 | |||
548 | hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status); | ||
540 | } | 549 | } |
541 | 550 | ||
542 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) | 551 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) |
@@ -544,7 +553,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) | |||
544 | BT_DBG("%s status 0x%x", hdev->name, status); | 553 | BT_DBG("%s status 0x%x", hdev->name, status); |
545 | 554 | ||
546 | if (status) { | 555 | if (status) { |
547 | hci_req_complete(hdev, status); | 556 | hci_req_complete(hdev, HCI_OP_INQUIRY, status); |
548 | 557 | ||
549 | hci_conn_check_pending(hdev); | 558 | hci_conn_check_pending(hdev); |
550 | } else | 559 | } else |
@@ -871,7 +880,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff | |||
871 | 880 | ||
872 | clear_bit(HCI_INQUIRY, &hdev->flags); | 881 | clear_bit(HCI_INQUIRY, &hdev->flags); |
873 | 882 | ||
874 | hci_req_complete(hdev, status); | 883 | hci_req_complete(hdev, HCI_OP_INQUIRY, status); |
875 | 884 | ||
876 | hci_conn_check_pending(hdev); | 885 | hci_conn_check_pending(hdev); |
877 | } | 886 | } |
@@ -1379,6 +1388,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
1379 | hci_cc_read_bd_addr(hdev, skb); | 1388 | hci_cc_read_bd_addr(hdev, skb); |
1380 | break; | 1389 | break; |
1381 | 1390 | ||
1391 | case HCI_OP_WRITE_CA_TIMEOUT: | ||
1392 | hci_cc_write_ca_timeout(hdev, skb); | ||
1393 | break; | ||
1394 | |||
1382 | default: | 1395 | default: |
1383 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); | 1396 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); |
1384 | break; | 1397 | break; |
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index b3753bad2a55..29827c77f6ce 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c | |||
@@ -49,6 +49,8 @@ | |||
49 | #include <net/bluetooth/bluetooth.h> | 49 | #include <net/bluetooth/bluetooth.h> |
50 | #include <net/bluetooth/hci_core.h> | 50 | #include <net/bluetooth/hci_core.h> |
51 | 51 | ||
52 | static int enable_mgmt; | ||
53 | |||
52 | /* ----- HCI socket interface ----- */ | 54 | /* ----- HCI socket interface ----- */ |
53 | 55 | ||
54 | static inline int hci_test_bit(int nr, void *addr) | 56 | static inline int hci_test_bit(int nr, void *addr) |
@@ -102,6 +104,12 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) | |||
102 | if (skb->sk == sk) | 104 | if (skb->sk == sk) |
103 | continue; | 105 | continue; |
104 | 106 | ||
107 | if (bt_cb(skb)->channel != hci_pi(sk)->channel) | ||
108 | continue; | ||
109 | |||
110 | if (bt_cb(skb)->channel == HCI_CHANNEL_CONTROL) | ||
111 | goto clone; | ||
112 | |||
105 | /* Apply filter */ | 113 | /* Apply filter */ |
106 | flt = &hci_pi(sk)->filter; | 114 | flt = &hci_pi(sk)->filter; |
107 | 115 | ||
@@ -125,12 +133,14 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) | |||
125 | continue; | 133 | continue; |
126 | } | 134 | } |
127 | 135 | ||
136 | clone: | ||
128 | nskb = skb_clone(skb, GFP_ATOMIC); | 137 | nskb = skb_clone(skb, GFP_ATOMIC); |
129 | if (!nskb) | 138 | if (!nskb) |
130 | continue; | 139 | continue; |
131 | 140 | ||
132 | /* Put type byte before the data */ | 141 | /* Put type byte before the data */ |
133 | memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); | 142 | if (bt_cb(skb)->channel == HCI_CHANNEL_RAW) |
143 | memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); | ||
134 | 144 | ||
135 | if (sock_queue_rcv_skb(sk, nskb)) | 145 | if (sock_queue_rcv_skb(sk, nskb)) |
136 | kfree_skb(nskb); | 146 | kfree_skb(nskb); |
@@ -353,25 +363,38 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a | |||
353 | 363 | ||
354 | static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | 364 | static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) |
355 | { | 365 | { |
356 | struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr; | 366 | struct sockaddr_hci haddr; |
357 | struct sock *sk = sock->sk; | 367 | struct sock *sk = sock->sk; |
358 | struct hci_dev *hdev = NULL; | 368 | struct hci_dev *hdev = NULL; |
359 | int err = 0; | 369 | int len, err = 0; |
360 | 370 | ||
361 | BT_DBG("sock %p sk %p", sock, sk); | 371 | BT_DBG("sock %p sk %p", sock, sk); |
362 | 372 | ||
363 | if (!haddr || haddr->hci_family != AF_BLUETOOTH) | 373 | if (!addr) |
374 | return -EINVAL; | ||
375 | |||
376 | memset(&haddr, 0, sizeof(haddr)); | ||
377 | len = min_t(unsigned int, sizeof(haddr), addr_len); | ||
378 | memcpy(&haddr, addr, len); | ||
379 | |||
380 | if (haddr.hci_family != AF_BLUETOOTH) | ||
381 | return -EINVAL; | ||
382 | |||
383 | if (haddr.hci_channel > HCI_CHANNEL_CONTROL) | ||
384 | return -EINVAL; | ||
385 | |||
386 | if (haddr.hci_channel == HCI_CHANNEL_CONTROL && !enable_mgmt) | ||
364 | return -EINVAL; | 387 | return -EINVAL; |
365 | 388 | ||
366 | lock_sock(sk); | 389 | lock_sock(sk); |
367 | 390 | ||
368 | if (hci_pi(sk)->hdev) { | 391 | if (sk->sk_state == BT_BOUND || hci_pi(sk)->hdev) { |
369 | err = -EALREADY; | 392 | err = -EALREADY; |
370 | goto done; | 393 | goto done; |
371 | } | 394 | } |
372 | 395 | ||
373 | if (haddr->hci_dev != HCI_DEV_NONE) { | 396 | if (haddr.hci_dev != HCI_DEV_NONE) { |
374 | hdev = hci_dev_get(haddr->hci_dev); | 397 | hdev = hci_dev_get(haddr.hci_dev); |
375 | if (!hdev) { | 398 | if (!hdev) { |
376 | err = -ENODEV; | 399 | err = -ENODEV; |
377 | goto done; | 400 | goto done; |
@@ -380,6 +403,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le | |||
380 | atomic_inc(&hdev->promisc); | 403 | atomic_inc(&hdev->promisc); |
381 | } | 404 | } |
382 | 405 | ||
406 | hci_pi(sk)->channel = haddr.hci_channel; | ||
383 | hci_pi(sk)->hdev = hdev; | 407 | hci_pi(sk)->hdev = hdev; |
384 | sk->sk_state = BT_BOUND; | 408 | sk->sk_state = BT_BOUND; |
385 | 409 | ||
@@ -502,6 +526,17 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
502 | 526 | ||
503 | lock_sock(sk); | 527 | lock_sock(sk); |
504 | 528 | ||
529 | switch (hci_pi(sk)->channel) { | ||
530 | case HCI_CHANNEL_RAW: | ||
531 | break; | ||
532 | case HCI_CHANNEL_CONTROL: | ||
533 | err = mgmt_control(sk, msg, len); | ||
534 | goto done; | ||
535 | default: | ||
536 | err = -EINVAL; | ||
537 | goto done; | ||
538 | } | ||
539 | |||
505 | hdev = hci_pi(sk)->hdev; | 540 | hdev = hci_pi(sk)->hdev; |
506 | if (!hdev) { | 541 | if (!hdev) { |
507 | err = -EBADFD; | 542 | err = -EBADFD; |
@@ -831,3 +866,6 @@ void __exit hci_sock_cleanup(void) | |||
831 | 866 | ||
832 | proto_unregister(&hci_sk_proto); | 867 | proto_unregister(&hci_sk_proto); |
833 | } | 868 | } |
869 | |||
870 | module_param(enable_mgmt, bool, 0644); | ||
871 | MODULE_PARM_DESC(enable_mgmt, "Enable Management interface"); | ||
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c12eccfdfe01..c791fcda7b2d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -3124,8 +3124,14 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr | |||
3124 | if (!sk) | 3124 | if (!sk) |
3125 | return -ENOENT; | 3125 | return -ENOENT; |
3126 | 3126 | ||
3127 | if (sk->sk_state == BT_DISCONN) | 3127 | if (sk->sk_state != BT_CONFIG) { |
3128 | struct l2cap_cmd_rej rej; | ||
3129 | |||
3130 | rej.reason = cpu_to_le16(0x0002); | ||
3131 | l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ, | ||
3132 | sizeof(rej), &rej); | ||
3128 | goto unlock; | 3133 | goto unlock; |
3134 | } | ||
3129 | 3135 | ||
3130 | /* Reject if config buffer is too small. */ | 3136 | /* Reject if config buffer is too small. */ |
3131 | len = cmd_len - sizeof(*req); | 3137 | len = cmd_len - sizeof(*req); |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c new file mode 100644 index 000000000000..f827fd908380 --- /dev/null +++ b/net/bluetooth/mgmt.c | |||
@@ -0,0 +1,308 @@ | |||
1 | /* | ||
2 | BlueZ - Bluetooth protocol stack for Linux | ||
3 | Copyright (C) 2010 Nokia Corporation | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License version 2 as | ||
7 | published by the Free Software Foundation; | ||
8 | |||
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
10 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
11 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
12 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
13 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
14 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | |||
18 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
19 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
20 | SOFTWARE IS DISCLAIMED. | ||
21 | */ | ||
22 | |||
23 | /* Bluetooth HCI Management interface */ | ||
24 | |||
25 | #include <asm/uaccess.h> | ||
26 | #include <asm/unaligned.h> | ||
27 | |||
28 | #include <net/bluetooth/bluetooth.h> | ||
29 | #include <net/bluetooth/hci_core.h> | ||
30 | #include <net/bluetooth/mgmt.h> | ||
31 | |||
32 | #define MGMT_VERSION 0 | ||
33 | #define MGMT_REVISION 1 | ||
34 | |||
35 | static int cmd_status(struct sock *sk, u16 cmd, u8 status) | ||
36 | { | ||
37 | struct sk_buff *skb; | ||
38 | struct mgmt_hdr *hdr; | ||
39 | struct mgmt_ev_cmd_status *ev; | ||
40 | |||
41 | BT_DBG("sock %p", sk); | ||
42 | |||
43 | skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC); | ||
44 | if (!skb) | ||
45 | return -ENOMEM; | ||
46 | |||
47 | hdr = (void *) skb_put(skb, sizeof(*hdr)); | ||
48 | |||
49 | hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS); | ||
50 | hdr->len = cpu_to_le16(sizeof(*ev)); | ||
51 | |||
52 | ev = (void *) skb_put(skb, sizeof(*ev)); | ||
53 | ev->status = status; | ||
54 | put_unaligned_le16(cmd, &ev->opcode); | ||
55 | |||
56 | if (sock_queue_rcv_skb(sk, skb) < 0) | ||
57 | kfree_skb(skb); | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int read_version(struct sock *sk) | ||
63 | { | ||
64 | struct sk_buff *skb; | ||
65 | struct mgmt_hdr *hdr; | ||
66 | struct mgmt_ev_cmd_complete *ev; | ||
67 | struct mgmt_rp_read_version *rp; | ||
68 | |||
69 | BT_DBG("sock %p", sk); | ||
70 | |||
71 | skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC); | ||
72 | if (!skb) | ||
73 | return -ENOMEM; | ||
74 | |||
75 | hdr = (void *) skb_put(skb, sizeof(*hdr)); | ||
76 | hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE); | ||
77 | hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp)); | ||
78 | |||
79 | ev = (void *) skb_put(skb, sizeof(*ev)); | ||
80 | put_unaligned_le16(MGMT_OP_READ_VERSION, &ev->opcode); | ||
81 | |||
82 | rp = (void *) skb_put(skb, sizeof(*rp)); | ||
83 | rp->version = MGMT_VERSION; | ||
84 | put_unaligned_le16(MGMT_REVISION, &rp->revision); | ||
85 | |||
86 | if (sock_queue_rcv_skb(sk, skb) < 0) | ||
87 | kfree_skb(skb); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static int read_index_list(struct sock *sk) | ||
93 | { | ||
94 | struct sk_buff *skb; | ||
95 | struct mgmt_hdr *hdr; | ||
96 | struct mgmt_ev_cmd_complete *ev; | ||
97 | struct mgmt_rp_read_index_list *rp; | ||
98 | struct list_head *p; | ||
99 | size_t body_len; | ||
100 | u16 count; | ||
101 | int i; | ||
102 | |||
103 | BT_DBG("sock %p", sk); | ||
104 | |||
105 | read_lock(&hci_dev_list_lock); | ||
106 | |||
107 | count = 0; | ||
108 | list_for_each(p, &hci_dev_list) { | ||
109 | count++; | ||
110 | } | ||
111 | |||
112 | body_len = sizeof(*ev) + sizeof(*rp) + (2 * count); | ||
113 | skb = alloc_skb(sizeof(*hdr) + body_len, GFP_ATOMIC); | ||
114 | if (!skb) | ||
115 | return -ENOMEM; | ||
116 | |||
117 | hdr = (void *) skb_put(skb, sizeof(*hdr)); | ||
118 | hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE); | ||
119 | hdr->len = cpu_to_le16(body_len); | ||
120 | |||
121 | ev = (void *) skb_put(skb, sizeof(*ev)); | ||
122 | put_unaligned_le16(MGMT_OP_READ_INDEX_LIST, &ev->opcode); | ||
123 | |||
124 | rp = (void *) skb_put(skb, sizeof(*rp) + (2 * count)); | ||
125 | put_unaligned_le16(count, &rp->num_controllers); | ||
126 | |||
127 | i = 0; | ||
128 | list_for_each(p, &hci_dev_list) { | ||
129 | struct hci_dev *d = list_entry(p, struct hci_dev, list); | ||
130 | put_unaligned_le16(d->id, &rp->index[i++]); | ||
131 | BT_DBG("Added hci%u", d->id); | ||
132 | } | ||
133 | |||
134 | read_unlock(&hci_dev_list_lock); | ||
135 | |||
136 | if (sock_queue_rcv_skb(sk, skb) < 0) | ||
137 | kfree_skb(skb); | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int read_controller_info(struct sock *sk, unsigned char *data, u16 len) | ||
143 | { | ||
144 | struct sk_buff *skb; | ||
145 | struct mgmt_hdr *hdr; | ||
146 | struct mgmt_ev_cmd_complete *ev; | ||
147 | struct mgmt_rp_read_info *rp; | ||
148 | struct mgmt_cp_read_info *cp; | ||
149 | struct hci_dev *hdev; | ||
150 | u16 dev_id; | ||
151 | |||
152 | BT_DBG("sock %p", sk); | ||
153 | |||
154 | if (len != 2) | ||
155 | return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL); | ||
156 | |||
157 | skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC); | ||
158 | if (!skb) | ||
159 | return -ENOMEM; | ||
160 | |||
161 | hdr = (void *) skb_put(skb, sizeof(*hdr)); | ||
162 | hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE); | ||
163 | hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp)); | ||
164 | |||
165 | ev = (void *) skb_put(skb, sizeof(*ev)); | ||
166 | put_unaligned_le16(MGMT_OP_READ_INFO, &ev->opcode); | ||
167 | |||
168 | rp = (void *) skb_put(skb, sizeof(*rp)); | ||
169 | |||
170 | cp = (void *) data; | ||
171 | dev_id = get_unaligned_le16(&cp->index); | ||
172 | |||
173 | BT_DBG("request for hci%u", dev_id); | ||
174 | |||
175 | hdev = hci_dev_get(dev_id); | ||
176 | if (!hdev) { | ||
177 | kfree_skb(skb); | ||
178 | return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV); | ||
179 | } | ||
180 | |||
181 | hci_dev_lock_bh(hdev); | ||
182 | |||
183 | put_unaligned_le16(hdev->id, &rp->index); | ||
184 | rp->type = hdev->dev_type; | ||
185 | |||
186 | rp->powered = test_bit(HCI_UP, &hdev->flags); | ||
187 | rp->discoverable = test_bit(HCI_ISCAN, &hdev->flags); | ||
188 | rp->pairable = test_bit(HCI_PSCAN, &hdev->flags); | ||
189 | |||
190 | if (test_bit(HCI_AUTH, &hdev->flags)) | ||
191 | rp->sec_mode = 3; | ||
192 | else if (hdev->ssp_mode > 0) | ||
193 | rp->sec_mode = 4; | ||
194 | else | ||
195 | rp->sec_mode = 2; | ||
196 | |||
197 | bacpy(&rp->bdaddr, &hdev->bdaddr); | ||
198 | memcpy(rp->features, hdev->features, 8); | ||
199 | memcpy(rp->dev_class, hdev->dev_class, 3); | ||
200 | put_unaligned_le16(hdev->manufacturer, &rp->manufacturer); | ||
201 | rp->hci_ver = hdev->hci_ver; | ||
202 | put_unaligned_le16(hdev->hci_rev, &rp->hci_rev); | ||
203 | |||
204 | hci_dev_unlock_bh(hdev); | ||
205 | hci_dev_put(hdev); | ||
206 | |||
207 | if (sock_queue_rcv_skb(sk, skb) < 0) | ||
208 | kfree_skb(skb); | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | ||
214 | { | ||
215 | unsigned char *buf; | ||
216 | struct mgmt_hdr *hdr; | ||
217 | u16 opcode, len; | ||
218 | int err; | ||
219 | |||
220 | BT_DBG("got %zu bytes", msglen); | ||
221 | |||
222 | if (msglen < sizeof(*hdr)) | ||
223 | return -EINVAL; | ||
224 | |||
225 | buf = kmalloc(msglen, GFP_ATOMIC); | ||
226 | if (!buf) | ||
227 | return -ENOMEM; | ||
228 | |||
229 | if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) { | ||
230 | err = -EFAULT; | ||
231 | goto done; | ||
232 | } | ||
233 | |||
234 | hdr = (struct mgmt_hdr *) buf; | ||
235 | opcode = get_unaligned_le16(&hdr->opcode); | ||
236 | len = get_unaligned_le16(&hdr->len); | ||
237 | |||
238 | if (len != msglen - sizeof(*hdr)) { | ||
239 | err = -EINVAL; | ||
240 | goto done; | ||
241 | } | ||
242 | |||
243 | switch (opcode) { | ||
244 | case MGMT_OP_READ_VERSION: | ||
245 | err = read_version(sk); | ||
246 | break; | ||
247 | case MGMT_OP_READ_INDEX_LIST: | ||
248 | err = read_index_list(sk); | ||
249 | break; | ||
250 | case MGMT_OP_READ_INFO: | ||
251 | err = read_controller_info(sk, buf + sizeof(*hdr), len); | ||
252 | break; | ||
253 | default: | ||
254 | BT_DBG("Unknown op %u", opcode); | ||
255 | err = cmd_status(sk, opcode, 0x01); | ||
256 | break; | ||
257 | } | ||
258 | |||
259 | if (err < 0) | ||
260 | goto done; | ||
261 | |||
262 | err = msglen; | ||
263 | |||
264 | done: | ||
265 | kfree(buf); | ||
266 | return err; | ||
267 | } | ||
268 | |||
269 | static int mgmt_event(u16 event, void *data, u16 data_len) | ||
270 | { | ||
271 | struct sk_buff *skb; | ||
272 | struct mgmt_hdr *hdr; | ||
273 | |||
274 | skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC); | ||
275 | if (!skb) | ||
276 | return -ENOMEM; | ||
277 | |||
278 | bt_cb(skb)->channel = HCI_CHANNEL_CONTROL; | ||
279 | |||
280 | hdr = (void *) skb_put(skb, sizeof(*hdr)); | ||
281 | hdr->opcode = cpu_to_le16(event); | ||
282 | hdr->len = cpu_to_le16(data_len); | ||
283 | |||
284 | memcpy(skb_put(skb, data_len), data, data_len); | ||
285 | |||
286 | hci_send_to_sock(NULL, skb); | ||
287 | kfree_skb(skb); | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | int mgmt_index_added(u16 index) | ||
293 | { | ||
294 | struct mgmt_ev_index_added ev; | ||
295 | |||
296 | put_unaligned_le16(index, &ev.index); | ||
297 | |||
298 | return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev)); | ||
299 | } | ||
300 | |||
301 | int mgmt_index_removed(u16 index) | ||
302 | { | ||
303 | struct mgmt_ev_index_added ev; | ||
304 | |||
305 | put_unaligned_le16(index, &ev.index); | ||
306 | |||
307 | return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev)); | ||
308 | } | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5892b0302454..4bc8a9250cfd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1593,6 +1593,37 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
1593 | return 0; | 1593 | return 0; |
1594 | } | 1594 | } |
1595 | 1595 | ||
1596 | static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local, | ||
1597 | struct net_device *dev, | ||
1598 | struct ieee80211_channel *chan, | ||
1599 | enum nl80211_channel_type chantype, | ||
1600 | unsigned int duration, u64 *cookie) | ||
1601 | { | ||
1602 | int ret; | ||
1603 | u32 random_cookie; | ||
1604 | |||
1605 | lockdep_assert_held(&local->mtx); | ||
1606 | |||
1607 | if (local->hw_roc_cookie) | ||
1608 | return -EBUSY; | ||
1609 | /* must be nonzero */ | ||
1610 | random_cookie = random32() | 1; | ||
1611 | |||
1612 | *cookie = random_cookie; | ||
1613 | local->hw_roc_dev = dev; | ||
1614 | local->hw_roc_cookie = random_cookie; | ||
1615 | local->hw_roc_channel = chan; | ||
1616 | local->hw_roc_channel_type = chantype; | ||
1617 | local->hw_roc_duration = duration; | ||
1618 | ret = drv_remain_on_channel(local, chan, chantype, duration); | ||
1619 | if (ret) { | ||
1620 | local->hw_roc_channel = NULL; | ||
1621 | local->hw_roc_cookie = 0; | ||
1622 | } | ||
1623 | |||
1624 | return ret; | ||
1625 | } | ||
1626 | |||
1596 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, | 1627 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, |
1597 | struct net_device *dev, | 1628 | struct net_device *dev, |
1598 | struct ieee80211_channel *chan, | 1629 | struct ieee80211_channel *chan, |
@@ -1601,16 +1632,63 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy, | |||
1601 | u64 *cookie) | 1632 | u64 *cookie) |
1602 | { | 1633 | { |
1603 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1634 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1635 | struct ieee80211_local *local = sdata->local; | ||
1636 | |||
1637 | if (local->ops->remain_on_channel) { | ||
1638 | int ret; | ||
1639 | |||
1640 | mutex_lock(&local->mtx); | ||
1641 | ret = ieee80211_remain_on_channel_hw(local, dev, | ||
1642 | chan, channel_type, | ||
1643 | duration, cookie); | ||
1644 | local->hw_roc_for_tx = false; | ||
1645 | mutex_unlock(&local->mtx); | ||
1646 | |||
1647 | return ret; | ||
1648 | } | ||
1604 | 1649 | ||
1605 | return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, | 1650 | return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, |
1606 | duration, cookie); | 1651 | duration, cookie); |
1607 | } | 1652 | } |
1608 | 1653 | ||
1654 | static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local, | ||
1655 | u64 cookie) | ||
1656 | { | ||
1657 | int ret; | ||
1658 | |||
1659 | lockdep_assert_held(&local->mtx); | ||
1660 | |||
1661 | if (local->hw_roc_cookie != cookie) | ||
1662 | return -ENOENT; | ||
1663 | |||
1664 | ret = drv_cancel_remain_on_channel(local); | ||
1665 | if (ret) | ||
1666 | return ret; | ||
1667 | |||
1668 | local->hw_roc_cookie = 0; | ||
1669 | local->hw_roc_channel = NULL; | ||
1670 | |||
1671 | ieee80211_recalc_idle(local); | ||
1672 | |||
1673 | return 0; | ||
1674 | } | ||
1675 | |||
1609 | static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | 1676 | static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, |
1610 | struct net_device *dev, | 1677 | struct net_device *dev, |
1611 | u64 cookie) | 1678 | u64 cookie) |
1612 | { | 1679 | { |
1613 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1680 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1681 | struct ieee80211_local *local = sdata->local; | ||
1682 | |||
1683 | if (local->ops->cancel_remain_on_channel) { | ||
1684 | int ret; | ||
1685 | |||
1686 | mutex_lock(&local->mtx); | ||
1687 | ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); | ||
1688 | mutex_unlock(&local->mtx); | ||
1689 | |||
1690 | return ret; | ||
1691 | } | ||
1614 | 1692 | ||
1615 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); | 1693 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); |
1616 | } | 1694 | } |
@@ -1662,6 +1740,12 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1662 | channel_type != local->_oper_channel_type)) | 1740 | channel_type != local->_oper_channel_type)) |
1663 | is_offchan = true; | 1741 | is_offchan = true; |
1664 | 1742 | ||
1743 | if (chan == local->hw_roc_channel) { | ||
1744 | /* TODO: check channel type? */ | ||
1745 | is_offchan = false; | ||
1746 | flags |= IEEE80211_TX_CTL_TX_OFFCHAN; | ||
1747 | } | ||
1748 | |||
1665 | if (is_offchan && !offchan) | 1749 | if (is_offchan && !offchan) |
1666 | return -EBUSY; | 1750 | return -EBUSY; |
1667 | 1751 | ||
@@ -1700,6 +1784,49 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1700 | 1784 | ||
1701 | *cookie = (unsigned long) skb; | 1785 | *cookie = (unsigned long) skb; |
1702 | 1786 | ||
1787 | if (is_offchan && local->ops->remain_on_channel) { | ||
1788 | unsigned int duration; | ||
1789 | int ret; | ||
1790 | |||
1791 | mutex_lock(&local->mtx); | ||
1792 | /* | ||
1793 | * If the duration is zero, then the driver | ||
1794 | * wouldn't actually do anything. Set it to | ||
1795 | * 100 for now. | ||
1796 | * | ||
1797 | * TODO: cancel the off-channel operation | ||
1798 | * when we get the SKB's TX status and | ||
1799 | * the wait time was zero before. | ||
1800 | */ | ||
1801 | duration = 100; | ||
1802 | if (wait) | ||
1803 | duration = wait; | ||
1804 | ret = ieee80211_remain_on_channel_hw(local, dev, chan, | ||
1805 | channel_type, | ||
1806 | duration, cookie); | ||
1807 | if (ret) { | ||
1808 | kfree_skb(skb); | ||
1809 | mutex_unlock(&local->mtx); | ||
1810 | return ret; | ||
1811 | } | ||
1812 | |||
1813 | local->hw_roc_for_tx = true; | ||
1814 | local->hw_roc_duration = wait; | ||
1815 | |||
1816 | /* | ||
1817 | * queue up frame for transmission after | ||
1818 | * ieee80211_ready_on_channel call | ||
1819 | */ | ||
1820 | |||
1821 | /* modify cookie to prevent API mismatches */ | ||
1822 | *cookie ^= 2; | ||
1823 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; | ||
1824 | local->hw_roc_skb = skb; | ||
1825 | mutex_unlock(&local->mtx); | ||
1826 | |||
1827 | return 0; | ||
1828 | } | ||
1829 | |||
1703 | /* | 1830 | /* |
1704 | * Can transmit right away if the channel was the | 1831 | * Can transmit right away if the channel was the |
1705 | * right one and there's no wait involved... If a | 1832 | * right one and there's no wait involved... If a |
@@ -1740,6 +1867,21 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, | |||
1740 | int ret = -ENOENT; | 1867 | int ret = -ENOENT; |
1741 | 1868 | ||
1742 | mutex_lock(&local->mtx); | 1869 | mutex_lock(&local->mtx); |
1870 | |||
1871 | if (local->ops->cancel_remain_on_channel) { | ||
1872 | cookie ^= 2; | ||
1873 | ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); | ||
1874 | |||
1875 | if (ret == 0) { | ||
1876 | kfree_skb(local->hw_roc_skb); | ||
1877 | local->hw_roc_skb = NULL; | ||
1878 | } | ||
1879 | |||
1880 | mutex_unlock(&local->mtx); | ||
1881 | |||
1882 | return ret; | ||
1883 | } | ||
1884 | |||
1743 | list_for_each_entry(wk, &local->work_list, list) { | 1885 | list_for_each_entry(wk, &local->work_list, list) { |
1744 | if (wk->sdata != sdata) | 1886 | if (wk->sdata != sdata) |
1745 | continue; | 1887 | continue; |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index af0c4398cceb..98d589960a49 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -465,4 +465,34 @@ static inline int drv_get_antenna(struct ieee80211_local *local, | |||
465 | return ret; | 465 | return ret; |
466 | } | 466 | } |
467 | 467 | ||
468 | static inline int drv_remain_on_channel(struct ieee80211_local *local, | ||
469 | struct ieee80211_channel *chan, | ||
470 | enum nl80211_channel_type chantype, | ||
471 | unsigned int duration) | ||
472 | { | ||
473 | int ret; | ||
474 | |||
475 | might_sleep(); | ||
476 | |||
477 | trace_drv_remain_on_channel(local, chan, chantype, duration); | ||
478 | ret = local->ops->remain_on_channel(&local->hw, chan, chantype, | ||
479 | duration); | ||
480 | trace_drv_return_int(local, ret); | ||
481 | |||
482 | return ret; | ||
483 | } | ||
484 | |||
485 | static inline int drv_cancel_remain_on_channel(struct ieee80211_local *local) | ||
486 | { | ||
487 | int ret; | ||
488 | |||
489 | might_sleep(); | ||
490 | |||
491 | trace_drv_cancel_remain_on_channel(local); | ||
492 | ret = local->ops->cancel_remain_on_channel(&local->hw); | ||
493 | trace_drv_return_int(local, ret); | ||
494 | |||
495 | return ret; | ||
496 | } | ||
497 | |||
468 | #endif /* __MAC80211_DRIVER_OPS */ | 498 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index c2772f23ac9c..49c84218b2f4 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -933,6 +933,50 @@ TRACE_EVENT(drv_get_antenna, | |||
933 | ) | 933 | ) |
934 | ); | 934 | ); |
935 | 935 | ||
936 | TRACE_EVENT(drv_remain_on_channel, | ||
937 | TP_PROTO(struct ieee80211_local *local, struct ieee80211_channel *chan, | ||
938 | enum nl80211_channel_type chantype, unsigned int duration), | ||
939 | |||
940 | TP_ARGS(local, chan, chantype, duration), | ||
941 | |||
942 | TP_STRUCT__entry( | ||
943 | LOCAL_ENTRY | ||
944 | __field(int, center_freq) | ||
945 | __field(int, channel_type) | ||
946 | __field(unsigned int, duration) | ||
947 | ), | ||
948 | |||
949 | TP_fast_assign( | ||
950 | LOCAL_ASSIGN; | ||
951 | __entry->center_freq = chan->center_freq; | ||
952 | __entry->channel_type = chantype; | ||
953 | __entry->duration = duration; | ||
954 | ), | ||
955 | |||
956 | TP_printk( | ||
957 | LOCAL_PR_FMT " freq:%dMHz duration:%dms", | ||
958 | LOCAL_PR_ARG, __entry->center_freq, __entry->duration | ||
959 | ) | ||
960 | ); | ||
961 | |||
962 | TRACE_EVENT(drv_cancel_remain_on_channel, | ||
963 | TP_PROTO(struct ieee80211_local *local), | ||
964 | |||
965 | TP_ARGS(local), | ||
966 | |||
967 | TP_STRUCT__entry( | ||
968 | LOCAL_ENTRY | ||
969 | ), | ||
970 | |||
971 | TP_fast_assign( | ||
972 | LOCAL_ASSIGN; | ||
973 | ), | ||
974 | |||
975 | TP_printk( | ||
976 | LOCAL_PR_FMT, LOCAL_PR_ARG | ||
977 | ) | ||
978 | ); | ||
979 | |||
936 | /* | 980 | /* |
937 | * Tracing for API calls that drivers call. | 981 | * Tracing for API calls that drivers call. |
938 | */ | 982 | */ |
@@ -1170,6 +1214,42 @@ TRACE_EVENT(api_chswitch_done, | |||
1170 | ) | 1214 | ) |
1171 | ); | 1215 | ); |
1172 | 1216 | ||
1217 | TRACE_EVENT(api_ready_on_channel, | ||
1218 | TP_PROTO(struct ieee80211_local *local), | ||
1219 | |||
1220 | TP_ARGS(local), | ||
1221 | |||
1222 | TP_STRUCT__entry( | ||
1223 | LOCAL_ENTRY | ||
1224 | ), | ||
1225 | |||
1226 | TP_fast_assign( | ||
1227 | LOCAL_ASSIGN; | ||
1228 | ), | ||
1229 | |||
1230 | TP_printk( | ||
1231 | LOCAL_PR_FMT, LOCAL_PR_ARG | ||
1232 | ) | ||
1233 | ); | ||
1234 | |||
1235 | TRACE_EVENT(api_remain_on_channel_expired, | ||
1236 | TP_PROTO(struct ieee80211_local *local), | ||
1237 | |||
1238 | TP_ARGS(local), | ||
1239 | |||
1240 | TP_STRUCT__entry( | ||
1241 | LOCAL_ENTRY | ||
1242 | ), | ||
1243 | |||
1244 | TP_fast_assign( | ||
1245 | LOCAL_ASSIGN; | ||
1246 | ), | ||
1247 | |||
1248 | TP_printk( | ||
1249 | LOCAL_PR_FMT, LOCAL_PR_ARG | ||
1250 | ) | ||
1251 | ); | ||
1252 | |||
1173 | /* | 1253 | /* |
1174 | * Tracing for internal functions | 1254 | * Tracing for internal functions |
1175 | * (which may also be called in response to driver calls) | 1255 | * (which may also be called in response to driver calls) |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a05893a238b7..c47d7c0e48a4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -168,6 +168,7 @@ typedef unsigned __bitwise__ ieee80211_rx_result; | |||
168 | * @IEEE80211_RX_FRAGMENTED: fragmented frame | 168 | * @IEEE80211_RX_FRAGMENTED: fragmented frame |
169 | * @IEEE80211_RX_AMSDU: a-MSDU packet | 169 | * @IEEE80211_RX_AMSDU: a-MSDU packet |
170 | * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed | 170 | * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed |
171 | * @IEEE80211_RX_DEFERRED_RELEASE: frame was subjected to receive reordering | ||
171 | * | 172 | * |
172 | * These are per-frame flags that are attached to a frame in the | 173 | * These are per-frame flags that are attached to a frame in the |
173 | * @rx_flags field of &struct ieee80211_rx_status. | 174 | * @rx_flags field of &struct ieee80211_rx_status. |
@@ -178,6 +179,7 @@ enum ieee80211_packet_rx_flags { | |||
178 | IEEE80211_RX_FRAGMENTED = BIT(2), | 179 | IEEE80211_RX_FRAGMENTED = BIT(2), |
179 | IEEE80211_RX_AMSDU = BIT(3), | 180 | IEEE80211_RX_AMSDU = BIT(3), |
180 | IEEE80211_RX_MALFORMED_ACTION_FRM = BIT(4), | 181 | IEEE80211_RX_MALFORMED_ACTION_FRM = BIT(4), |
182 | IEEE80211_RX_DEFERRED_RELEASE = BIT(5), | ||
181 | }; | 183 | }; |
182 | 184 | ||
183 | /** | 185 | /** |
@@ -774,6 +776,15 @@ struct ieee80211_local { | |||
774 | struct sk_buff_head skb_queue; | 776 | struct sk_buff_head skb_queue; |
775 | struct sk_buff_head skb_queue_unreliable; | 777 | struct sk_buff_head skb_queue_unreliable; |
776 | 778 | ||
779 | /* | ||
780 | * Internal FIFO queue which is shared between multiple rx path | ||
781 | * stages. Its main task is to provide a serialization mechanism, | ||
782 | * so all rx handlers can enjoy having exclusive access to their | ||
783 | * private data structures. | ||
784 | */ | ||
785 | struct sk_buff_head rx_skb_queue; | ||
786 | bool running_rx_handler; /* protected by rx_skb_queue.lock */ | ||
787 | |||
777 | /* Station data */ | 788 | /* Station data */ |
778 | /* | 789 | /* |
779 | * The mutex only protects the list and counter, | 790 | * The mutex only protects the list and counter, |
@@ -940,6 +951,15 @@ struct ieee80211_local { | |||
940 | } debugfs; | 951 | } debugfs; |
941 | #endif | 952 | #endif |
942 | 953 | ||
954 | struct ieee80211_channel *hw_roc_channel; | ||
955 | struct net_device *hw_roc_dev; | ||
956 | struct sk_buff *hw_roc_skb; | ||
957 | struct work_struct hw_roc_start, hw_roc_done; | ||
958 | enum nl80211_channel_type hw_roc_channel_type; | ||
959 | unsigned int hw_roc_duration; | ||
960 | u32 hw_roc_cookie; | ||
961 | bool hw_roc_for_tx; | ||
962 | |||
943 | /* dummy netdev for use w/ NAPI */ | 963 | /* dummy netdev for use w/ NAPI */ |
944 | struct net_device napi_dev; | 964 | struct net_device napi_dev; |
945 | 965 | ||
@@ -1131,6 +1151,7 @@ void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local); | |||
1131 | void ieee80211_offchannel_stop_station(struct ieee80211_local *local); | 1151 | void ieee80211_offchannel_stop_station(struct ieee80211_local *local); |
1132 | void ieee80211_offchannel_return(struct ieee80211_local *local, | 1152 | void ieee80211_offchannel_return(struct ieee80211_local *local, |
1133 | bool enable_beaconing); | 1153 | bool enable_beaconing); |
1154 | void ieee80211_hw_roc_setup(struct ieee80211_local *local); | ||
1134 | 1155 | ||
1135 | /* interface handling */ | 1156 | /* interface handling */ |
1136 | int ieee80211_iface_init(void); | 1157 | int ieee80211_iface_init(void); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b6db237672ff..8acba456744e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1264,7 +1264,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1264 | { | 1264 | { |
1265 | struct ieee80211_sub_if_data *sdata; | 1265 | struct ieee80211_sub_if_data *sdata; |
1266 | int count = 0; | 1266 | int count = 0; |
1267 | bool working = false, scanning = false; | 1267 | bool working = false, scanning = false, hw_roc = false; |
1268 | struct ieee80211_work *wk; | 1268 | struct ieee80211_work *wk; |
1269 | unsigned int led_trig_start = 0, led_trig_stop = 0; | 1269 | unsigned int led_trig_start = 0, led_trig_stop = 0; |
1270 | 1270 | ||
@@ -1308,6 +1308,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1308 | local->scan_sdata->vif.bss_conf.idle = false; | 1308 | local->scan_sdata->vif.bss_conf.idle = false; |
1309 | } | 1309 | } |
1310 | 1310 | ||
1311 | if (local->hw_roc_channel) | ||
1312 | hw_roc = true; | ||
1313 | |||
1311 | list_for_each_entry(sdata, &local->interfaces, list) { | 1314 | list_for_each_entry(sdata, &local->interfaces, list) { |
1312 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | 1315 | if (sdata->old_idle == sdata->vif.bss_conf.idle) |
1313 | continue; | 1316 | continue; |
@@ -1316,7 +1319,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1316 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | 1319 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); |
1317 | } | 1320 | } |
1318 | 1321 | ||
1319 | if (working || scanning) | 1322 | if (working || scanning || hw_roc) |
1320 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; | 1323 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; |
1321 | else | 1324 | else |
1322 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; | 1325 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; |
@@ -1328,6 +1331,8 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1328 | 1331 | ||
1329 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); | 1332 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); |
1330 | 1333 | ||
1334 | if (hw_roc) | ||
1335 | return ieee80211_idle_off(local, "hw remain-on-channel"); | ||
1331 | if (working) | 1336 | if (working) |
1332 | return ieee80211_idle_off(local, "working"); | 1337 | return ieee80211_idle_off(local, "working"); |
1333 | if (scanning) | 1338 | if (scanning) |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 84cf9196820f..8c02469b7176 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -30,19 +30,20 @@ | |||
30 | * keys and per-station keys. Since each station belongs to an interface, | 30 | * keys and per-station keys. Since each station belongs to an interface, |
31 | * each station key also belongs to that interface. | 31 | * each station key also belongs to that interface. |
32 | * | 32 | * |
33 | * Hardware acceleration is done on a best-effort basis, for each key | 33 | * Hardware acceleration is done on a best-effort basis for algorithms |
34 | * that is eligible the hardware is asked to enable that key but if | 34 | * that are implemented in software, for each key the hardware is asked |
35 | * it cannot do that they key is simply kept for software encryption. | 35 | * to enable that key for offloading but if it cannot do that the key is |
36 | * There is currently no way of knowing this except by looking into | 36 | * simply kept for software encryption (unless it is for an algorithm |
37 | * debugfs. | 37 | * that isn't implemented in software). |
38 | * There is currently no way of knowing whether a key is handled in SW | ||
39 | * or HW except by looking into debugfs. | ||
38 | * | 40 | * |
39 | * All key operations are protected internally. | 41 | * All key management is internally protected by a mutex. Within all |
40 | * | 42 | * other parts of mac80211, key references are, just as STA structure |
41 | * Within mac80211, key references are, just as STA structure references, | 43 | * references, protected by RCU. Note, however, that some things are |
42 | * protected by RCU. Note, however, that some things are unprotected, | 44 | * unprotected, namely the key->sta dereferences within the hardware |
43 | * namely the key->sta dereferences within the hardware acceleration | 45 | * acceleration functions. This means that sta_info_destroy() must |
44 | * functions. This means that sta_info_destroy() must remove the key | 46 | * remove the key which waits for an RCU grace period. |
45 | * which waits for an RCU grace period. | ||
46 | */ | 47 | */ |
47 | 48 | ||
48 | static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 49 | static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
@@ -279,13 +280,8 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
279 | new->conf.keyidx); | 280 | new->conf.keyidx); |
280 | } | 281 | } |
281 | 282 | ||
282 | if (old) { | 283 | if (old) |
283 | /* | 284 | list_del(&old->list); |
284 | * We'll use an empty list to indicate that the key | ||
285 | * has already been removed. | ||
286 | */ | ||
287 | list_del_init(&old->list); | ||
288 | } | ||
289 | } | 285 | } |
290 | 286 | ||
291 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | 287 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, |
@@ -379,6 +375,12 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
379 | if (!key) | 375 | if (!key) |
380 | return; | 376 | return; |
381 | 377 | ||
378 | /* | ||
379 | * Synchronize so the TX path can no longer be using | ||
380 | * this key before we free/remove it. | ||
381 | */ | ||
382 | synchronize_rcu(); | ||
383 | |||
382 | if (key->local) | 384 | if (key->local) |
383 | ieee80211_key_disable_hw_accel(key); | 385 | ieee80211_key_disable_hw_accel(key); |
384 | 386 | ||
@@ -420,8 +422,8 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
420 | struct sta_info *ap; | 422 | struct sta_info *ap; |
421 | 423 | ||
422 | /* | 424 | /* |
423 | * We're getting a sta pointer in, | 425 | * We're getting a sta pointer in, so must be under |
424 | * so must be under RCU read lock. | 426 | * appropriate locking for sta_info_get(). |
425 | */ | 427 | */ |
426 | 428 | ||
427 | /* same here, the AP could be using QoS */ | 429 | /* same here, the AP could be using QoS */ |
diff --git a/net/mac80211/led.c b/net/mac80211/led.c index 4905eb8af572..14590332c81c 100644 --- a/net/mac80211/led.c +++ b/net/mac80211/led.c | |||
@@ -215,8 +215,8 @@ static void tpt_trig_timer(unsigned long data) | |||
215 | read_unlock(&tpt_trig->trig.leddev_list_lock); | 215 | read_unlock(&tpt_trig->trig.leddev_list_lock); |
216 | } | 216 | } |
217 | 217 | ||
218 | extern char *__ieee80211_create_tpt_led_trigger( | 218 | char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw, |
219 | struct ieee80211_hw *hw, unsigned int flags, | 219 | unsigned int flags, |
220 | const struct ieee80211_tpt_blink *blink_table, | 220 | const struct ieee80211_tpt_blink *blink_table, |
221 | unsigned int blink_table_len) | 221 | unsigned int blink_table_len) |
222 | { | 222 | { |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index bbe8e0ac6e52..485d36bc9a46 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -569,6 +569,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
569 | spin_lock_init(&local->filter_lock); | 569 | spin_lock_init(&local->filter_lock); |
570 | spin_lock_init(&local->queue_stop_reason_lock); | 570 | spin_lock_init(&local->queue_stop_reason_lock); |
571 | 571 | ||
572 | skb_queue_head_init(&local->rx_skb_queue); | ||
573 | |||
572 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); | 574 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); |
573 | 575 | ||
574 | ieee80211_work_init(local); | 576 | ieee80211_work_init(local); |
@@ -607,6 +609,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
607 | 609 | ||
608 | ieee80211_led_names(local); | 610 | ieee80211_led_names(local); |
609 | 611 | ||
612 | ieee80211_hw_roc_setup(local); | ||
613 | |||
610 | return local_to_hw(local); | 614 | return local_to_hw(local); |
611 | } | 615 | } |
612 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 616 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
@@ -751,7 +755,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
751 | } | 755 | } |
752 | } | 756 | } |
753 | 757 | ||
754 | local->hw.wiphy->max_remain_on_channel_duration = 5000; | 758 | if (!local->ops->remain_on_channel) |
759 | local->hw.wiphy->max_remain_on_channel_duration = 5000; | ||
755 | 760 | ||
756 | result = wiphy_register(local->hw.wiphy); | 761 | result = wiphy_register(local->hw.wiphy); |
757 | if (result < 0) | 762 | if (result < 0) |
@@ -914,6 +919,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
914 | wiphy_warn(local->hw.wiphy, "skb_queue not empty\n"); | 919 | wiphy_warn(local->hw.wiphy, "skb_queue not empty\n"); |
915 | skb_queue_purge(&local->skb_queue); | 920 | skb_queue_purge(&local->skb_queue); |
916 | skb_queue_purge(&local->skb_queue_unreliable); | 921 | skb_queue_purge(&local->skb_queue_unreliable); |
922 | skb_queue_purge(&local->rx_skb_queue); | ||
917 | 923 | ||
918 | destroy_workqueue(local->workqueue); | 924 | destroy_workqueue(local->workqueue); |
919 | wiphy_unregister(local->hw.wiphy); | 925 | wiphy_unregister(local->hw.wiphy); |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 4b564091e51d..b4e52676f3fb 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -14,6 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | #include <net/mac80211.h> | 15 | #include <net/mac80211.h> |
16 | #include "ieee80211_i.h" | 16 | #include "ieee80211_i.h" |
17 | #include "driver-trace.h" | ||
17 | 18 | ||
18 | /* | 19 | /* |
19 | * inform AP that we will go to sleep so that it will buffer the frames | 20 | * inform AP that we will go to sleep so that it will buffer the frames |
@@ -190,3 +191,87 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, | |||
190 | } | 191 | } |
191 | mutex_unlock(&local->iflist_mtx); | 192 | mutex_unlock(&local->iflist_mtx); |
192 | } | 193 | } |
194 | |||
195 | static void ieee80211_hw_roc_start(struct work_struct *work) | ||
196 | { | ||
197 | struct ieee80211_local *local = | ||
198 | container_of(work, struct ieee80211_local, hw_roc_start); | ||
199 | struct ieee80211_sub_if_data *sdata; | ||
200 | |||
201 | mutex_lock(&local->mtx); | ||
202 | |||
203 | if (!local->hw_roc_channel) { | ||
204 | mutex_unlock(&local->mtx); | ||
205 | return; | ||
206 | } | ||
207 | |||
208 | ieee80211_recalc_idle(local); | ||
209 | |||
210 | if (local->hw_roc_skb) { | ||
211 | sdata = IEEE80211_DEV_TO_SUB_IF(local->hw_roc_dev); | ||
212 | ieee80211_tx_skb(sdata, local->hw_roc_skb); | ||
213 | local->hw_roc_skb = NULL; | ||
214 | } else { | ||
215 | cfg80211_ready_on_channel(local->hw_roc_dev, | ||
216 | local->hw_roc_cookie, | ||
217 | local->hw_roc_channel, | ||
218 | local->hw_roc_channel_type, | ||
219 | local->hw_roc_duration, | ||
220 | GFP_KERNEL); | ||
221 | } | ||
222 | |||
223 | mutex_unlock(&local->mtx); | ||
224 | } | ||
225 | |||
226 | void ieee80211_ready_on_channel(struct ieee80211_hw *hw) | ||
227 | { | ||
228 | struct ieee80211_local *local = hw_to_local(hw); | ||
229 | |||
230 | trace_api_ready_on_channel(local); | ||
231 | |||
232 | ieee80211_queue_work(hw, &local->hw_roc_start); | ||
233 | } | ||
234 | EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel); | ||
235 | |||
236 | static void ieee80211_hw_roc_done(struct work_struct *work) | ||
237 | { | ||
238 | struct ieee80211_local *local = | ||
239 | container_of(work, struct ieee80211_local, hw_roc_done); | ||
240 | |||
241 | mutex_lock(&local->mtx); | ||
242 | |||
243 | if (!local->hw_roc_channel) { | ||
244 | mutex_unlock(&local->mtx); | ||
245 | return; | ||
246 | } | ||
247 | |||
248 | if (!local->hw_roc_for_tx) | ||
249 | cfg80211_remain_on_channel_expired(local->hw_roc_dev, | ||
250 | local->hw_roc_cookie, | ||
251 | local->hw_roc_channel, | ||
252 | local->hw_roc_channel_type, | ||
253 | GFP_KERNEL); | ||
254 | |||
255 | local->hw_roc_channel = NULL; | ||
256 | local->hw_roc_cookie = 0; | ||
257 | |||
258 | ieee80211_recalc_idle(local); | ||
259 | |||
260 | mutex_unlock(&local->mtx); | ||
261 | } | ||
262 | |||
263 | void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw) | ||
264 | { | ||
265 | struct ieee80211_local *local = hw_to_local(hw); | ||
266 | |||
267 | trace_api_remain_on_channel_expired(local); | ||
268 | |||
269 | ieee80211_queue_work(hw, &local->hw_roc_done); | ||
270 | } | ||
271 | EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired); | ||
272 | |||
273 | void ieee80211_hw_roc_setup(struct ieee80211_local *local) | ||
274 | { | ||
275 | INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start); | ||
276 | INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done); | ||
277 | } | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5e9d3bc6a2d9..a6701ed87f0d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -533,10 +533,11 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) | |||
533 | 533 | ||
534 | static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, | 534 | static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, |
535 | struct tid_ampdu_rx *tid_agg_rx, | 535 | struct tid_ampdu_rx *tid_agg_rx, |
536 | int index, | 536 | int index) |
537 | struct sk_buff_head *frames) | ||
538 | { | 537 | { |
538 | struct ieee80211_local *local = hw_to_local(hw); | ||
539 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; | 539 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; |
540 | struct ieee80211_rx_status *status; | ||
540 | 541 | ||
541 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 542 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
542 | 543 | ||
@@ -546,7 +547,9 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, | |||
546 | /* release the frame from the reorder ring buffer */ | 547 | /* release the frame from the reorder ring buffer */ |
547 | tid_agg_rx->stored_mpdu_num--; | 548 | tid_agg_rx->stored_mpdu_num--; |
548 | tid_agg_rx->reorder_buf[index] = NULL; | 549 | tid_agg_rx->reorder_buf[index] = NULL; |
549 | __skb_queue_tail(frames, skb); | 550 | status = IEEE80211_SKB_RXCB(skb); |
551 | status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE; | ||
552 | skb_queue_tail(&local->rx_skb_queue, skb); | ||
550 | 553 | ||
551 | no_frame: | 554 | no_frame: |
552 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); | 555 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); |
@@ -554,8 +557,7 @@ no_frame: | |||
554 | 557 | ||
555 | static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, | 558 | static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, |
556 | struct tid_ampdu_rx *tid_agg_rx, | 559 | struct tid_ampdu_rx *tid_agg_rx, |
557 | u16 head_seq_num, | 560 | u16 head_seq_num) |
558 | struct sk_buff_head *frames) | ||
559 | { | 561 | { |
560 | int index; | 562 | int index; |
561 | 563 | ||
@@ -564,7 +566,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, | |||
564 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { | 566 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { |
565 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 567 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % |
566 | tid_agg_rx->buf_size; | 568 | tid_agg_rx->buf_size; |
567 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames); | 569 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index); |
568 | } | 570 | } |
569 | } | 571 | } |
570 | 572 | ||
@@ -580,8 +582,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, | |||
580 | #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) | 582 | #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) |
581 | 583 | ||
582 | static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, | 584 | static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, |
583 | struct tid_ampdu_rx *tid_agg_rx, | 585 | struct tid_ampdu_rx *tid_agg_rx) |
584 | struct sk_buff_head *frames) | ||
585 | { | 586 | { |
586 | int index, j; | 587 | int index, j; |
587 | 588 | ||
@@ -612,8 +613,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, | |||
612 | wiphy_debug(hw->wiphy, | 613 | wiphy_debug(hw->wiphy, |
613 | "release an RX reorder frame due to timeout on earlier frames\n"); | 614 | "release an RX reorder frame due to timeout on earlier frames\n"); |
614 | #endif | 615 | #endif |
615 | ieee80211_release_reorder_frame(hw, tid_agg_rx, | 616 | ieee80211_release_reorder_frame(hw, tid_agg_rx, j); |
616 | j, frames); | ||
617 | 617 | ||
618 | /* | 618 | /* |
619 | * Increment the head seq# also for the skipped slots. | 619 | * Increment the head seq# also for the skipped slots. |
@@ -623,31 +623,11 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, | |||
623 | skipped = 0; | 623 | skipped = 0; |
624 | } | 624 | } |
625 | } else while (tid_agg_rx->reorder_buf[index]) { | 625 | } else while (tid_agg_rx->reorder_buf[index]) { |
626 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames); | 626 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index); |
627 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 627 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % |
628 | tid_agg_rx->buf_size; | 628 | tid_agg_rx->buf_size; |
629 | } | 629 | } |
630 | 630 | ||
631 | /* | ||
632 | * Disable the reorder release timer for now. | ||
633 | * | ||
634 | * The current implementation lacks a proper locking scheme | ||
635 | * which would protect vital statistic and debug counters | ||
636 | * from being updated by two different but concurrent BHs. | ||
637 | * | ||
638 | * More information about the topic is available from: | ||
639 | * - thread: http://marc.info/?t=128635927000001 | ||
640 | * | ||
641 | * What was wrong: | ||
642 | * => http://marc.info/?l=linux-wireless&m=128636170811964 | ||
643 | * "Basically the thing is that until your patch, the data | ||
644 | * in the struct didn't actually need locking because it | ||
645 | * was accessed by the RX path only which is not concurrent." | ||
646 | * | ||
647 | * List of what needs to be fixed: | ||
648 | * => http://marc.info/?l=linux-wireless&m=128656352920957 | ||
649 | * | ||
650 | |||
651 | if (tid_agg_rx->stored_mpdu_num) { | 631 | if (tid_agg_rx->stored_mpdu_num) { |
652 | j = index = seq_sub(tid_agg_rx->head_seq_num, | 632 | j = index = seq_sub(tid_agg_rx->head_seq_num, |
653 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; | 633 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; |
@@ -666,10 +646,6 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, | |||
666 | } else { | 646 | } else { |
667 | del_timer(&tid_agg_rx->reorder_timer); | 647 | del_timer(&tid_agg_rx->reorder_timer); |
668 | } | 648 | } |
669 | */ | ||
670 | |||
671 | set_release_timer: | ||
672 | return; | ||
673 | } | 649 | } |
674 | 650 | ||
675 | /* | 651 | /* |
@@ -679,8 +655,7 @@ set_release_timer: | |||
679 | */ | 655 | */ |
680 | static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | 656 | static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, |
681 | struct tid_ampdu_rx *tid_agg_rx, | 657 | struct tid_ampdu_rx *tid_agg_rx, |
682 | struct sk_buff *skb, | 658 | struct sk_buff *skb) |
683 | struct sk_buff_head *frames) | ||
684 | { | 659 | { |
685 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 660 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
686 | u16 sc = le16_to_cpu(hdr->seq_ctrl); | 661 | u16 sc = le16_to_cpu(hdr->seq_ctrl); |
@@ -707,8 +682,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
707 | if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { | 682 | if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { |
708 | head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); | 683 | head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); |
709 | /* release stored frames up to new head to stack */ | 684 | /* release stored frames up to new head to stack */ |
710 | ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num, | 685 | ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num); |
711 | frames); | ||
712 | } | 686 | } |
713 | 687 | ||
714 | /* Now the new frame is always in the range of the reordering buffer */ | 688 | /* Now the new frame is always in the range of the reordering buffer */ |
@@ -736,7 +710,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
736 | tid_agg_rx->reorder_buf[index] = skb; | 710 | tid_agg_rx->reorder_buf[index] = skb; |
737 | tid_agg_rx->reorder_time[index] = jiffies; | 711 | tid_agg_rx->reorder_time[index] = jiffies; |
738 | tid_agg_rx->stored_mpdu_num++; | 712 | tid_agg_rx->stored_mpdu_num++; |
739 | ieee80211_sta_reorder_release(hw, tid_agg_rx, frames); | 713 | ieee80211_sta_reorder_release(hw, tid_agg_rx); |
740 | 714 | ||
741 | out: | 715 | out: |
742 | spin_unlock(&tid_agg_rx->reorder_lock); | 716 | spin_unlock(&tid_agg_rx->reorder_lock); |
@@ -747,8 +721,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
747 | * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns | 721 | * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns |
748 | * true if the MPDU was buffered, false if it should be processed. | 722 | * true if the MPDU was buffered, false if it should be processed. |
749 | */ | 723 | */ |
750 | static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | 724 | static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx) |
751 | struct sk_buff_head *frames) | ||
752 | { | 725 | { |
753 | struct sk_buff *skb = rx->skb; | 726 | struct sk_buff *skb = rx->skb; |
754 | struct ieee80211_local *local = rx->local; | 727 | struct ieee80211_local *local = rx->local; |
@@ -803,11 +776,11 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |||
803 | * sure that we cannot get to it any more before doing | 776 | * sure that we cannot get to it any more before doing |
804 | * anything with it. | 777 | * anything with it. |
805 | */ | 778 | */ |
806 | if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) | 779 | if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb)) |
807 | return; | 780 | return; |
808 | 781 | ||
809 | dont_reorder: | 782 | dont_reorder: |
810 | __skb_queue_tail(frames, skb); | 783 | skb_queue_tail(&local->rx_skb_queue, skb); |
811 | } | 784 | } |
812 | 785 | ||
813 | static ieee80211_rx_result debug_noinline | 786 | static ieee80211_rx_result debug_noinline |
@@ -1189,6 +1162,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1189 | * exchange sequence. | 1162 | * exchange sequence. |
1190 | */ | 1163 | */ |
1191 | if (!ieee80211_has_morefrags(hdr->frame_control) && | 1164 | if (!ieee80211_has_morefrags(hdr->frame_control) && |
1165 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && | ||
1192 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || | 1166 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || |
1193 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { | 1167 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { |
1194 | if (test_sta_flags(sta, WLAN_STA_PS_STA)) { | 1168 | if (test_sta_flags(sta, WLAN_STA_PS_STA)) { |
@@ -1831,11 +1805,11 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1831 | 1805 | ||
1832 | fwd_skb = skb_copy(skb, GFP_ATOMIC); | 1806 | fwd_skb = skb_copy(skb, GFP_ATOMIC); |
1833 | 1807 | ||
1834 | if (!fwd_skb && net_ratelimit()) { | 1808 | if (!fwd_skb && net_ratelimit()) |
1835 | printk(KERN_DEBUG "%s: failed to clone mesh frame\n", | 1809 | printk(KERN_DEBUG "%s: failed to clone mesh frame\n", |
1836 | sdata->name); | 1810 | sdata->name); |
1811 | if (!fwd_skb) | ||
1837 | goto out; | 1812 | goto out; |
1838 | } | ||
1839 | 1813 | ||
1840 | fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; | 1814 | fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; |
1841 | memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); | 1815 | memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); |
@@ -1930,7 +1904,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1930 | } | 1904 | } |
1931 | 1905 | ||
1932 | static ieee80211_rx_result debug_noinline | 1906 | static ieee80211_rx_result debug_noinline |
1933 | ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) | 1907 | ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) |
1934 | { | 1908 | { |
1935 | struct ieee80211_local *local = rx->local; | 1909 | struct ieee80211_local *local = rx->local; |
1936 | struct ieee80211_hw *hw = &local->hw; | 1910 | struct ieee80211_hw *hw = &local->hw; |
@@ -1970,8 +1944,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) | |||
1970 | 1944 | ||
1971 | spin_lock(&tid_agg_rx->reorder_lock); | 1945 | spin_lock(&tid_agg_rx->reorder_lock); |
1972 | /* release stored frames up to start of BAR */ | 1946 | /* release stored frames up to start of BAR */ |
1973 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num, | 1947 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num); |
1974 | frames); | ||
1975 | spin_unlock(&tid_agg_rx->reorder_lock); | 1948 | spin_unlock(&tid_agg_rx->reorder_lock); |
1976 | 1949 | ||
1977 | kfree_skb(skb); | 1950 | kfree_skb(skb); |
@@ -2488,8 +2461,7 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx, | |||
2488 | } | 2461 | } |
2489 | } | 2462 | } |
2490 | 2463 | ||
2491 | static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, | 2464 | static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx) |
2492 | struct sk_buff_head *frames) | ||
2493 | { | 2465 | { |
2494 | ieee80211_rx_result res = RX_DROP_MONITOR; | 2466 | ieee80211_rx_result res = RX_DROP_MONITOR; |
2495 | struct sk_buff *skb; | 2467 | struct sk_buff *skb; |
@@ -2501,7 +2473,15 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, | |||
2501 | goto rxh_next; \ | 2473 | goto rxh_next; \ |
2502 | } while (0); | 2474 | } while (0); |
2503 | 2475 | ||
2504 | while ((skb = __skb_dequeue(frames))) { | 2476 | spin_lock(&rx->local->rx_skb_queue.lock); |
2477 | if (rx->local->running_rx_handler) | ||
2478 | goto unlock; | ||
2479 | |||
2480 | rx->local->running_rx_handler = true; | ||
2481 | |||
2482 | while ((skb = __skb_dequeue(&rx->local->rx_skb_queue))) { | ||
2483 | spin_unlock(&rx->local->rx_skb_queue.lock); | ||
2484 | |||
2505 | /* | 2485 | /* |
2506 | * all the other fields are valid across frames | 2486 | * all the other fields are valid across frames |
2507 | * that belong to an aMPDU since they are on the | 2487 | * that belong to an aMPDU since they are on the |
@@ -2524,12 +2504,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, | |||
2524 | CALL_RXH(ieee80211_rx_h_mesh_fwding); | 2504 | CALL_RXH(ieee80211_rx_h_mesh_fwding); |
2525 | #endif | 2505 | #endif |
2526 | CALL_RXH(ieee80211_rx_h_data) | 2506 | CALL_RXH(ieee80211_rx_h_data) |
2527 | 2507 | CALL_RXH(ieee80211_rx_h_ctrl); | |
2528 | /* special treatment -- needs the queue */ | ||
2529 | res = ieee80211_rx_h_ctrl(rx, frames); | ||
2530 | if (res != RX_CONTINUE) | ||
2531 | goto rxh_next; | ||
2532 | |||
2533 | CALL_RXH(ieee80211_rx_h_mgmt_check) | 2508 | CALL_RXH(ieee80211_rx_h_mgmt_check) |
2534 | CALL_RXH(ieee80211_rx_h_action) | 2509 | CALL_RXH(ieee80211_rx_h_action) |
2535 | CALL_RXH(ieee80211_rx_h_userspace_mgmt) | 2510 | CALL_RXH(ieee80211_rx_h_userspace_mgmt) |
@@ -2538,18 +2513,20 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, | |||
2538 | 2513 | ||
2539 | rxh_next: | 2514 | rxh_next: |
2540 | ieee80211_rx_handlers_result(rx, res); | 2515 | ieee80211_rx_handlers_result(rx, res); |
2541 | 2516 | spin_lock(&rx->local->rx_skb_queue.lock); | |
2542 | #undef CALL_RXH | 2517 | #undef CALL_RXH |
2543 | } | 2518 | } |
2519 | |||
2520 | rx->local->running_rx_handler = false; | ||
2521 | |||
2522 | unlock: | ||
2523 | spin_unlock(&rx->local->rx_skb_queue.lock); | ||
2544 | } | 2524 | } |
2545 | 2525 | ||
2546 | static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) | 2526 | static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) |
2547 | { | 2527 | { |
2548 | struct sk_buff_head reorder_release; | ||
2549 | ieee80211_rx_result res = RX_DROP_MONITOR; | 2528 | ieee80211_rx_result res = RX_DROP_MONITOR; |
2550 | 2529 | ||
2551 | __skb_queue_head_init(&reorder_release); | ||
2552 | |||
2553 | #define CALL_RXH(rxh) \ | 2530 | #define CALL_RXH(rxh) \ |
2554 | do { \ | 2531 | do { \ |
2555 | res = rxh(rx); \ | 2532 | res = rxh(rx); \ |
@@ -2560,9 +2537,9 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) | |||
2560 | CALL_RXH(ieee80211_rx_h_passive_scan) | 2537 | CALL_RXH(ieee80211_rx_h_passive_scan) |
2561 | CALL_RXH(ieee80211_rx_h_check) | 2538 | CALL_RXH(ieee80211_rx_h_check) |
2562 | 2539 | ||
2563 | ieee80211_rx_reorder_ampdu(rx, &reorder_release); | 2540 | ieee80211_rx_reorder_ampdu(rx); |
2564 | 2541 | ||
2565 | ieee80211_rx_handlers(rx, &reorder_release); | 2542 | ieee80211_rx_handlers(rx); |
2566 | return; | 2543 | return; |
2567 | 2544 | ||
2568 | rxh_next: | 2545 | rxh_next: |
@@ -2577,7 +2554,6 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) | |||
2577 | */ | 2554 | */ |
2578 | void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) | 2555 | void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) |
2579 | { | 2556 | { |
2580 | struct sk_buff_head frames; | ||
2581 | struct ieee80211_rx_data rx = { | 2557 | struct ieee80211_rx_data rx = { |
2582 | .sta = sta, | 2558 | .sta = sta, |
2583 | .sdata = sta->sdata, | 2559 | .sdata = sta->sdata, |
@@ -2590,13 +2566,11 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) | |||
2590 | if (!tid_agg_rx) | 2566 | if (!tid_agg_rx) |
2591 | return; | 2567 | return; |
2592 | 2568 | ||
2593 | __skb_queue_head_init(&frames); | ||
2594 | |||
2595 | spin_lock(&tid_agg_rx->reorder_lock); | 2569 | spin_lock(&tid_agg_rx->reorder_lock); |
2596 | ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx, &frames); | 2570 | ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx); |
2597 | spin_unlock(&tid_agg_rx->reorder_lock); | 2571 | spin_unlock(&tid_agg_rx->reorder_lock); |
2598 | 2572 | ||
2599 | ieee80211_rx_handlers(&rx, &frames); | 2573 | ieee80211_rx_handlers(&rx); |
2600 | } | 2574 | } |
2601 | 2575 | ||
2602 | /* main receive path */ | 2576 | /* main receive path */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 68c2fbd16ebb..5950e3abead9 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1750,6 +1750,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1750 | __le16 fc; | 1750 | __le16 fc; |
1751 | struct ieee80211_hdr hdr; | 1751 | struct ieee80211_hdr hdr; |
1752 | struct ieee80211s_hdr mesh_hdr __maybe_unused; | 1752 | struct ieee80211s_hdr mesh_hdr __maybe_unused; |
1753 | struct mesh_path *mppath = NULL; | ||
1753 | const u8 *encaps_data; | 1754 | const u8 *encaps_data; |
1754 | int encaps_len, skip_header_bytes; | 1755 | int encaps_len, skip_header_bytes; |
1755 | int nh_pos, h_pos; | 1756 | int nh_pos, h_pos; |
@@ -1810,16 +1811,23 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1810 | ret = NETDEV_TX_OK; | 1811 | ret = NETDEV_TX_OK; |
1811 | goto fail; | 1812 | goto fail; |
1812 | } | 1813 | } |
1814 | if (!is_multicast_ether_addr(skb->data)) | ||
1815 | mppath = mpp_path_lookup(skb->data, sdata); | ||
1813 | 1816 | ||
1817 | /* | ||
1818 | * Do not use address extension, if it is a packet from | ||
1819 | * the same interface and the destination is not being | ||
1820 | * proxied by any other mest point. | ||
1821 | */ | ||
1814 | if (compare_ether_addr(sdata->vif.addr, | 1822 | if (compare_ether_addr(sdata->vif.addr, |
1815 | skb->data + ETH_ALEN) == 0) { | 1823 | skb->data + ETH_ALEN) == 0 && |
1824 | (!mppath || !compare_ether_addr(mppath->mpp, skb->data))) { | ||
1816 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, | 1825 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, |
1817 | skb->data, skb->data + ETH_ALEN); | 1826 | skb->data, skb->data + ETH_ALEN); |
1818 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, | 1827 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, |
1819 | sdata, NULL, NULL); | 1828 | sdata, NULL, NULL); |
1820 | } else { | 1829 | } else { |
1821 | /* packet from other interface */ | 1830 | /* packet from other interface */ |
1822 | struct mesh_path *mppath; | ||
1823 | int is_mesh_mcast = 1; | 1831 | int is_mesh_mcast = 1; |
1824 | const u8 *mesh_da; | 1832 | const u8 *mesh_da; |
1825 | 1833 | ||
@@ -1830,8 +1838,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1830 | else { | 1838 | else { |
1831 | static const u8 bcast[ETH_ALEN] = | 1839 | static const u8 bcast[ETH_ALEN] = |
1832 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | 1840 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
1833 | |||
1834 | mppath = mpp_path_lookup(skb->data, sdata); | ||
1835 | if (mppath) { | 1841 | if (mppath) { |
1836 | /* RA TA mDA mSA AE:DA SA */ | 1842 | /* RA TA mDA mSA AE:DA SA */ |
1837 | mesh_da = mppath->mpp; | 1843 | mesh_da = mppath->mpp; |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 58e75bbc1f91..28bc084dbfb9 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -59,26 +59,22 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
59 | { | 59 | { |
60 | struct ieee80211_local *local = sdata->local; | 60 | struct ieee80211_local *local = sdata->local; |
61 | struct sta_info *sta = NULL; | 61 | struct sta_info *sta = NULL; |
62 | u32 sta_flags = 0; | ||
63 | const u8 *ra = NULL; | 62 | const u8 *ra = NULL; |
64 | bool qos = false; | 63 | bool qos = false; |
65 | 64 | ||
66 | if (local->hw.queues < 4 || skb->len < 6) { | 65 | if (local->hw.queues < 4 || skb->len < 6) { |
67 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 66 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
68 | return min_t(u16, local->hw.queues - 1, | 67 | return min_t(u16, local->hw.queues - 1, IEEE80211_AC_BE); |
69 | ieee802_1d_to_ac[skb->priority]); | ||
70 | } | 68 | } |
71 | 69 | ||
72 | rcu_read_lock(); | 70 | rcu_read_lock(); |
73 | switch (sdata->vif.type) { | 71 | switch (sdata->vif.type) { |
74 | case NL80211_IFTYPE_AP_VLAN: | 72 | case NL80211_IFTYPE_AP_VLAN: |
75 | rcu_read_lock(); | ||
76 | sta = rcu_dereference(sdata->u.vlan.sta); | 73 | sta = rcu_dereference(sdata->u.vlan.sta); |
77 | if (sta) | 74 | if (sta) { |
78 | sta_flags = get_sta_flags(sta); | 75 | qos = get_sta_flags(sta) & WLAN_STA_WME; |
79 | rcu_read_unlock(); | ||
80 | if (sta) | ||
81 | break; | 76 | break; |
77 | } | ||
82 | case NL80211_IFTYPE_AP: | 78 | case NL80211_IFTYPE_AP: |
83 | ra = skb->data; | 79 | ra = skb->data; |
84 | break; | 80 | break; |
@@ -107,17 +103,13 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
107 | if (!sta && ra && !is_multicast_ether_addr(ra)) { | 103 | if (!sta && ra && !is_multicast_ether_addr(ra)) { |
108 | sta = sta_info_get(sdata, ra); | 104 | sta = sta_info_get(sdata, ra); |
109 | if (sta) | 105 | if (sta) |
110 | sta_flags = get_sta_flags(sta); | 106 | qos = get_sta_flags(sta) & WLAN_STA_WME; |
111 | } | 107 | } |
112 | |||
113 | if (sta_flags & WLAN_STA_WME) | ||
114 | qos = true; | ||
115 | |||
116 | rcu_read_unlock(); | 108 | rcu_read_unlock(); |
117 | 109 | ||
118 | if (!qos) { | 110 | if (!qos) { |
119 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 111 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
120 | return ieee802_1d_to_ac[skb->priority]; | 112 | return IEEE80211_AC_BE; |
121 | } | 113 | } |
122 | 114 | ||
123 | /* use the data classifier to determine what 802.1d tag the | 115 | /* use the data classifier to determine what 802.1d tag the |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 99d41831d76e..37693b6ef23a 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -752,7 +752,7 @@ static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, | |||
752 | snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain); | 752 | snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain); |
753 | 753 | ||
754 | REG_DBG_PRINT("Updating information on frequency %d MHz " | 754 | REG_DBG_PRINT("Updating information on frequency %d MHz " |
755 | "for %d a MHz width channel with regulatory rule:\n", | 755 | "for a %d MHz width channel with regulatory rule:\n", |
756 | chan->center_freq, | 756 | chan->center_freq, |
757 | KHZ_TO_MHZ(desired_bw_khz)); | 757 | KHZ_TO_MHZ(desired_bw_khz)); |
758 | 758 | ||