diff options
author | David S. Miller <davem@davemloft.net> | 2011-05-16 22:49:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-05-16 22:49:41 -0400 |
commit | d46d4d64a85c6ff6118b33afd5d63bcb7e4be54a (patch) | |
tree | 007fb7d1cfbccac15d7c7551927372ba46777428 /net | |
parent | 2142c131a3e290ae350f8a0b0d354c0585a96df1 (diff) | |
parent | e00cf3b9eb7839b952e434a75bff6b99e47337ac (diff) |
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
46 files changed, 1960 insertions, 607 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7f5ad8a2b22d..3163330cd4f1 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -623,6 +623,23 @@ encrypt: | |||
623 | } | 623 | } |
624 | EXPORT_SYMBOL(hci_conn_security); | 624 | EXPORT_SYMBOL(hci_conn_security); |
625 | 625 | ||
626 | /* Check secure link requirement */ | ||
627 | int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level) | ||
628 | { | ||
629 | BT_DBG("conn %p", conn); | ||
630 | |||
631 | if (sec_level != BT_SECURITY_HIGH) | ||
632 | return 1; /* Accept if non-secure is required */ | ||
633 | |||
634 | if (conn->key_type == HCI_LK_AUTH_COMBINATION || | ||
635 | (conn->key_type == HCI_LK_COMBINATION && | ||
636 | conn->pin_length == 16)) | ||
637 | return 1; | ||
638 | |||
639 | return 0; /* Reject not secure link */ | ||
640 | } | ||
641 | EXPORT_SYMBOL(hci_conn_check_secure); | ||
642 | |||
626 | /* Change link key */ | 643 | /* Change link key */ |
627 | int hci_conn_change_link_key(struct hci_conn *conn) | 644 | int hci_conn_change_link_key(struct hci_conn *conn) |
628 | { | 645 | { |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d5aa97ee6ffa..f13ddbf858ba 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -1440,7 +1440,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff | |||
1440 | 1440 | ||
1441 | conn->state = BT_CLOSED; | 1441 | conn->state = BT_CLOSED; |
1442 | 1442 | ||
1443 | if (conn->type == ACL_LINK) | 1443 | if (conn->type == ACL_LINK || conn->type == LE_LINK) |
1444 | mgmt_disconnected(hdev->id, &conn->dst); | 1444 | mgmt_disconnected(hdev->id, &conn->dst); |
1445 | 1445 | ||
1446 | hci_proto_disconn_cfm(conn, ev->reason); | 1446 | hci_proto_disconn_cfm(conn, ev->reason); |
@@ -2659,12 +2659,15 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff | |||
2659 | } | 2659 | } |
2660 | 2660 | ||
2661 | if (ev->status) { | 2661 | if (ev->status) { |
2662 | mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status); | ||
2662 | hci_proto_connect_cfm(conn, ev->status); | 2663 | hci_proto_connect_cfm(conn, ev->status); |
2663 | conn->state = BT_CLOSED; | 2664 | conn->state = BT_CLOSED; |
2664 | hci_conn_del(conn); | 2665 | hci_conn_del(conn); |
2665 | goto unlock; | 2666 | goto unlock; |
2666 | } | 2667 | } |
2667 | 2668 | ||
2669 | mgmt_connected(hdev->id, &ev->bdaddr); | ||
2670 | |||
2668 | conn->handle = __le16_to_cpu(ev->handle); | 2671 | conn->handle = __le16_to_cpu(ev->handle); |
2669 | conn->state = BT_CONNECTED; | 2672 | conn->state = BT_CONNECTED; |
2670 | 2673 | ||
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a378acc491ec..4f3bc741183c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -62,9 +62,8 @@ static u8 l2cap_fixed_chan[8] = { 0x02, }; | |||
62 | 62 | ||
63 | static struct workqueue_struct *_busy_wq; | 63 | static struct workqueue_struct *_busy_wq; |
64 | 64 | ||
65 | struct bt_sock_list l2cap_sk_list = { | 65 | LIST_HEAD(chan_list); |
66 | .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) | 66 | DEFINE_RWLOCK(chan_list_lock); |
67 | }; | ||
68 | 67 | ||
69 | static void l2cap_busy_work(struct work_struct *work); | 68 | static void l2cap_busy_work(struct work_struct *work); |
70 | 69 | ||
@@ -135,6 +134,64 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn | |||
135 | return c; | 134 | return c; |
136 | } | 135 | } |
137 | 136 | ||
137 | static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) | ||
138 | { | ||
139 | struct l2cap_chan *c; | ||
140 | |||
141 | list_for_each_entry(c, &chan_list, global_l) { | ||
142 | if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src)) | ||
143 | goto found; | ||
144 | } | ||
145 | |||
146 | c = NULL; | ||
147 | found: | ||
148 | return c; | ||
149 | } | ||
150 | |||
151 | int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) | ||
152 | { | ||
153 | int err; | ||
154 | |||
155 | write_lock_bh(&chan_list_lock); | ||
156 | |||
157 | if (psm && __l2cap_global_chan_by_addr(psm, src)) { | ||
158 | err = -EADDRINUSE; | ||
159 | goto done; | ||
160 | } | ||
161 | |||
162 | if (psm) { | ||
163 | chan->psm = psm; | ||
164 | chan->sport = psm; | ||
165 | err = 0; | ||
166 | } else { | ||
167 | u16 p; | ||
168 | |||
169 | err = -EINVAL; | ||
170 | for (p = 0x1001; p < 0x1100; p += 2) | ||
171 | if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) { | ||
172 | chan->psm = cpu_to_le16(p); | ||
173 | chan->sport = cpu_to_le16(p); | ||
174 | err = 0; | ||
175 | break; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | done: | ||
180 | write_unlock_bh(&chan_list_lock); | ||
181 | return err; | ||
182 | } | ||
183 | |||
184 | int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) | ||
185 | { | ||
186 | write_lock_bh(&chan_list_lock); | ||
187 | |||
188 | chan->scid = scid; | ||
189 | |||
190 | write_unlock_bh(&chan_list_lock); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
138 | static u16 l2cap_alloc_cid(struct l2cap_conn *conn) | 195 | static u16 l2cap_alloc_cid(struct l2cap_conn *conn) |
139 | { | 196 | { |
140 | u16 cid = L2CAP_CID_DYN_START; | 197 | u16 cid = L2CAP_CID_DYN_START; |
@@ -147,7 +204,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) | |||
147 | return 0; | 204 | return 0; |
148 | } | 205 | } |
149 | 206 | ||
150 | struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) | 207 | struct l2cap_chan *l2cap_chan_create(struct sock *sk) |
151 | { | 208 | { |
152 | struct l2cap_chan *chan; | 209 | struct l2cap_chan *chan; |
153 | 210 | ||
@@ -157,11 +214,19 @@ struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) | |||
157 | 214 | ||
158 | chan->sk = sk; | 215 | chan->sk = sk; |
159 | 216 | ||
217 | write_lock_bh(&chan_list_lock); | ||
218 | list_add(&chan->global_l, &chan_list); | ||
219 | write_unlock_bh(&chan_list_lock); | ||
220 | |||
160 | return chan; | 221 | return chan; |
161 | } | 222 | } |
162 | 223 | ||
163 | void l2cap_chan_free(struct l2cap_chan *chan) | 224 | void l2cap_chan_destroy(struct l2cap_chan *chan) |
164 | { | 225 | { |
226 | write_lock_bh(&chan_list_lock); | ||
227 | list_del(&chan->global_l); | ||
228 | write_unlock_bh(&chan_list_lock); | ||
229 | |||
165 | kfree(chan); | 230 | kfree(chan); |
166 | } | 231 | } |
167 | 232 | ||
@@ -591,48 +656,51 @@ static void l2cap_conn_start(struct l2cap_conn *conn) | |||
591 | /* Find socket with cid and source bdaddr. | 656 | /* Find socket with cid and source bdaddr. |
592 | * Returns closest match, locked. | 657 | * Returns closest match, locked. |
593 | */ | 658 | */ |
594 | static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) | 659 | static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src) |
595 | { | 660 | { |
596 | struct sock *sk = NULL, *sk1 = NULL; | 661 | struct l2cap_chan *c, *c1 = NULL; |
597 | struct hlist_node *node; | ||
598 | 662 | ||
599 | read_lock(&l2cap_sk_list.lock); | 663 | read_lock(&chan_list_lock); |
600 | 664 | ||
601 | sk_for_each(sk, node, &l2cap_sk_list.head) { | 665 | list_for_each_entry(c, &chan_list, global_l) { |
602 | struct l2cap_chan *chan = l2cap_pi(sk)->chan; | 666 | struct sock *sk = c->sk; |
603 | 667 | ||
604 | if (state && sk->sk_state != state) | 668 | if (state && sk->sk_state != state) |
605 | continue; | 669 | continue; |
606 | 670 | ||
607 | if (chan->scid == cid) { | 671 | if (c->scid == cid) { |
608 | /* Exact match. */ | 672 | /* Exact match. */ |
609 | if (!bacmp(&bt_sk(sk)->src, src)) | 673 | if (!bacmp(&bt_sk(sk)->src, src)) { |
610 | break; | 674 | read_unlock(&chan_list_lock); |
675 | return c; | ||
676 | } | ||
611 | 677 | ||
612 | /* Closest match */ | 678 | /* Closest match */ |
613 | if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) | 679 | if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) |
614 | sk1 = sk; | 680 | c1 = c; |
615 | } | 681 | } |
616 | } | 682 | } |
617 | 683 | ||
618 | read_unlock(&l2cap_sk_list.lock); | 684 | read_unlock(&chan_list_lock); |
619 | 685 | ||
620 | return node ? sk : sk1; | 686 | return c1; |
621 | } | 687 | } |
622 | 688 | ||
623 | static void l2cap_le_conn_ready(struct l2cap_conn *conn) | 689 | static void l2cap_le_conn_ready(struct l2cap_conn *conn) |
624 | { | 690 | { |
625 | struct sock *parent, *sk; | 691 | struct sock *parent, *sk; |
626 | struct l2cap_chan *chan; | 692 | struct l2cap_chan *chan, *pchan; |
627 | 693 | ||
628 | BT_DBG(""); | 694 | BT_DBG(""); |
629 | 695 | ||
630 | /* Check if we have socket listening on cid */ | 696 | /* Check if we have socket listening on cid */ |
631 | parent = l2cap_get_sock_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA, | 697 | pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA, |
632 | conn->src); | 698 | conn->src); |
633 | if (!parent) | 699 | if (!pchan) |
634 | return; | 700 | return; |
635 | 701 | ||
702 | parent = pchan->sk; | ||
703 | |||
636 | bh_lock_sock(parent); | 704 | bh_lock_sock(parent); |
637 | 705 | ||
638 | /* Check for backlog size */ | 706 | /* Check for backlog size */ |
@@ -645,7 +713,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) | |||
645 | if (!sk) | 713 | if (!sk) |
646 | goto clean; | 714 | goto clean; |
647 | 715 | ||
648 | chan = l2cap_chan_alloc(sk); | 716 | chan = l2cap_chan_create(sk); |
649 | if (!chan) { | 717 | if (!chan) { |
650 | l2cap_sock_kill(sk); | 718 | l2cap_sock_kill(sk); |
651 | goto clean; | 719 | goto clean; |
@@ -823,33 +891,34 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *ch | |||
823 | /* Find socket with psm and source bdaddr. | 891 | /* Find socket with psm and source bdaddr. |
824 | * Returns closest match. | 892 | * Returns closest match. |
825 | */ | 893 | */ |
826 | static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) | 894 | static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src) |
827 | { | 895 | { |
828 | struct sock *sk = NULL, *sk1 = NULL; | 896 | struct l2cap_chan *c, *c1 = NULL; |
829 | struct hlist_node *node; | ||
830 | 897 | ||
831 | read_lock(&l2cap_sk_list.lock); | 898 | read_lock(&chan_list_lock); |
832 | 899 | ||
833 | sk_for_each(sk, node, &l2cap_sk_list.head) { | 900 | list_for_each_entry(c, &chan_list, global_l) { |
834 | struct l2cap_chan *chan = l2cap_pi(sk)->chan; | 901 | struct sock *sk = c->sk; |
835 | 902 | ||
836 | if (state && sk->sk_state != state) | 903 | if (state && sk->sk_state != state) |
837 | continue; | 904 | continue; |
838 | 905 | ||
839 | if (chan->psm == psm) { | 906 | if (c->psm == psm) { |
840 | /* Exact match. */ | 907 | /* Exact match. */ |
841 | if (!bacmp(&bt_sk(sk)->src, src)) | 908 | if (!bacmp(&bt_sk(sk)->src, src)) { |
842 | break; | 909 | read_unlock_bh(&chan_list_lock); |
910 | return c; | ||
911 | } | ||
843 | 912 | ||
844 | /* Closest match */ | 913 | /* Closest match */ |
845 | if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) | 914 | if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) |
846 | sk1 = sk; | 915 | c1 = c; |
847 | } | 916 | } |
848 | } | 917 | } |
849 | 918 | ||
850 | read_unlock(&l2cap_sk_list.lock); | 919 | read_unlock(&chan_list_lock); |
851 | 920 | ||
852 | return node ? sk : sk1; | 921 | return c1; |
853 | } | 922 | } |
854 | 923 | ||
855 | int l2cap_chan_connect(struct l2cap_chan *chan) | 924 | int l2cap_chan_connect(struct l2cap_chan *chan) |
@@ -2019,7 +2088,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd | |||
2019 | { | 2088 | { |
2020 | struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; | 2089 | struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; |
2021 | struct l2cap_conn_rsp rsp; | 2090 | struct l2cap_conn_rsp rsp; |
2022 | struct l2cap_chan *chan = NULL; | 2091 | struct l2cap_chan *chan = NULL, *pchan; |
2023 | struct sock *parent, *sk = NULL; | 2092 | struct sock *parent, *sk = NULL; |
2024 | int result, status = L2CAP_CS_NO_INFO; | 2093 | int result, status = L2CAP_CS_NO_INFO; |
2025 | 2094 | ||
@@ -2029,12 +2098,14 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd | |||
2029 | BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); | 2098 | BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); |
2030 | 2099 | ||
2031 | /* Check if we have socket listening on psm */ | 2100 | /* Check if we have socket listening on psm */ |
2032 | parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src); | 2101 | pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src); |
2033 | if (!parent) { | 2102 | if (!pchan) { |
2034 | result = L2CAP_CR_BAD_PSM; | 2103 | result = L2CAP_CR_BAD_PSM; |
2035 | goto sendresp; | 2104 | goto sendresp; |
2036 | } | 2105 | } |
2037 | 2106 | ||
2107 | parent = pchan->sk; | ||
2108 | |||
2038 | bh_lock_sock(parent); | 2109 | bh_lock_sock(parent); |
2039 | 2110 | ||
2040 | /* Check if the ACL is secure enough (if not SDP) */ | 2111 | /* Check if the ACL is secure enough (if not SDP) */ |
@@ -2057,7 +2128,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd | |||
2057 | if (!sk) | 2128 | if (!sk) |
2058 | goto response; | 2129 | goto response; |
2059 | 2130 | ||
2060 | chan = l2cap_chan_alloc(sk); | 2131 | chan = l2cap_chan_create(sk); |
2061 | if (!chan) { | 2132 | if (!chan) { |
2062 | l2cap_sock_kill(sk); | 2133 | l2cap_sock_kill(sk); |
2063 | goto response; | 2134 | goto response; |
@@ -3685,11 +3756,14 @@ done: | |||
3685 | static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb) | 3756 | static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb) |
3686 | { | 3757 | { |
3687 | struct sock *sk; | 3758 | struct sock *sk; |
3759 | struct l2cap_chan *chan; | ||
3688 | 3760 | ||
3689 | sk = l2cap_get_sock_by_psm(0, psm, conn->src); | 3761 | chan = l2cap_global_chan_by_psm(0, psm, conn->src); |
3690 | if (!sk) | 3762 | if (!chan) |
3691 | goto drop; | 3763 | goto drop; |
3692 | 3764 | ||
3765 | sk = chan->sk; | ||
3766 | |||
3693 | bh_lock_sock(sk); | 3767 | bh_lock_sock(sk); |
3694 | 3768 | ||
3695 | BT_DBG("sk %p, len %d", sk, skb->len); | 3769 | BT_DBG("sk %p, len %d", sk, skb->len); |
@@ -3715,11 +3789,14 @@ done: | |||
3715 | static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) | 3789 | static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) |
3716 | { | 3790 | { |
3717 | struct sock *sk; | 3791 | struct sock *sk; |
3792 | struct l2cap_chan *chan; | ||
3718 | 3793 | ||
3719 | sk = l2cap_get_sock_by_scid(0, cid, conn->src); | 3794 | chan = l2cap_global_chan_by_scid(0, cid, conn->src); |
3720 | if (!sk) | 3795 | if (!chan) |
3721 | goto drop; | 3796 | goto drop; |
3722 | 3797 | ||
3798 | sk = chan->sk; | ||
3799 | |||
3723 | bh_lock_sock(sk); | 3800 | bh_lock_sock(sk); |
3724 | 3801 | ||
3725 | BT_DBG("sk %p, len %d", sk, skb->len); | 3802 | BT_DBG("sk %p, len %d", sk, skb->len); |
@@ -3786,8 +3863,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) | |||
3786 | static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) | 3863 | static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) |
3787 | { | 3864 | { |
3788 | int exact = 0, lm1 = 0, lm2 = 0; | 3865 | int exact = 0, lm1 = 0, lm2 = 0; |
3789 | register struct sock *sk; | 3866 | struct l2cap_chan *c; |
3790 | struct hlist_node *node; | ||
3791 | 3867 | ||
3792 | if (type != ACL_LINK) | 3868 | if (type != ACL_LINK) |
3793 | return -EINVAL; | 3869 | return -EINVAL; |
@@ -3795,25 +3871,25 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) | |||
3795 | BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); | 3871 | BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); |
3796 | 3872 | ||
3797 | /* Find listening sockets and check their link_mode */ | 3873 | /* Find listening sockets and check their link_mode */ |
3798 | read_lock(&l2cap_sk_list.lock); | 3874 | read_lock(&chan_list_lock); |
3799 | sk_for_each(sk, node, &l2cap_sk_list.head) { | 3875 | list_for_each_entry(c, &chan_list, global_l) { |
3800 | struct l2cap_chan *chan = l2cap_pi(sk)->chan; | 3876 | struct sock *sk = c->sk; |
3801 | 3877 | ||
3802 | if (sk->sk_state != BT_LISTEN) | 3878 | if (sk->sk_state != BT_LISTEN) |
3803 | continue; | 3879 | continue; |
3804 | 3880 | ||
3805 | if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { | 3881 | if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { |
3806 | lm1 |= HCI_LM_ACCEPT; | 3882 | lm1 |= HCI_LM_ACCEPT; |
3807 | if (chan->role_switch) | 3883 | if (c->role_switch) |
3808 | lm1 |= HCI_LM_MASTER; | 3884 | lm1 |= HCI_LM_MASTER; |
3809 | exact++; | 3885 | exact++; |
3810 | } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { | 3886 | } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { |
3811 | lm2 |= HCI_LM_ACCEPT; | 3887 | lm2 |= HCI_LM_ACCEPT; |
3812 | if (chan->role_switch) | 3888 | if (c->role_switch) |
3813 | lm2 |= HCI_LM_MASTER; | 3889 | lm2 |= HCI_LM_MASTER; |
3814 | } | 3890 | } |
3815 | } | 3891 | } |
3816 | read_unlock(&l2cap_sk_list.lock); | 3892 | read_unlock(&chan_list_lock); |
3817 | 3893 | ||
3818 | return exact ? lm1 : lm2; | 3894 | return exact ? lm1 : lm2; |
3819 | } | 3895 | } |
@@ -4066,25 +4142,22 @@ drop: | |||
4066 | 4142 | ||
4067 | static int l2cap_debugfs_show(struct seq_file *f, void *p) | 4143 | static int l2cap_debugfs_show(struct seq_file *f, void *p) |
4068 | { | 4144 | { |
4069 | struct sock *sk; | 4145 | struct l2cap_chan *c; |
4070 | struct hlist_node *node; | ||
4071 | 4146 | ||
4072 | read_lock_bh(&l2cap_sk_list.lock); | 4147 | read_lock_bh(&chan_list_lock); |
4073 | 4148 | ||
4074 | sk_for_each(sk, node, &l2cap_sk_list.head) { | 4149 | list_for_each_entry(c, &chan_list, global_l) { |
4075 | struct l2cap_pinfo *pi = l2cap_pi(sk); | 4150 | struct sock *sk = c->sk; |
4076 | struct l2cap_chan *chan = pi->chan; | ||
4077 | 4151 | ||
4078 | seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n", | 4152 | seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n", |
4079 | batostr(&bt_sk(sk)->src), | 4153 | batostr(&bt_sk(sk)->src), |
4080 | batostr(&bt_sk(sk)->dst), | 4154 | batostr(&bt_sk(sk)->dst), |
4081 | sk->sk_state, __le16_to_cpu(chan->psm), | 4155 | sk->sk_state, __le16_to_cpu(c->psm), |
4082 | chan->scid, chan->dcid, | 4156 | c->scid, c->dcid, c->imtu, c->omtu, |
4083 | chan->imtu, chan->omtu, chan->sec_level, | 4157 | c->sec_level, c->mode); |
4084 | chan->mode); | ||
4085 | } | 4158 | } |
4086 | 4159 | ||
4087 | read_unlock_bh(&l2cap_sk_list.lock); | 4160 | read_unlock_bh(&chan_list_lock); |
4088 | 4161 | ||
4089 | return 0; | 4162 | return 0; |
4090 | } | 4163 | } |
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 7c4a9ae9b3ce..18dc9888d8c2 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c | |||
@@ -78,22 +78,6 @@ void l2cap_sock_clear_timer(struct sock *sk) | |||
78 | sk_stop_timer(sk, &sk->sk_timer); | 78 | sk_stop_timer(sk, &sk->sk_timer); |
79 | } | 79 | } |
80 | 80 | ||
81 | static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) | ||
82 | { | ||
83 | struct sock *sk; | ||
84 | struct hlist_node *node; | ||
85 | sk_for_each(sk, node, &l2cap_sk_list.head) { | ||
86 | struct l2cap_chan *chan = l2cap_pi(sk)->chan; | ||
87 | |||
88 | if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src)) | ||
89 | goto found; | ||
90 | } | ||
91 | |||
92 | sk = NULL; | ||
93 | found: | ||
94 | return sk; | ||
95 | } | ||
96 | |||
97 | static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | 81 | static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) |
98 | { | 82 | { |
99 | struct sock *sk = sock->sk; | 83 | struct sock *sk = sock->sk; |
@@ -136,26 +120,20 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | |||
136 | } | 120 | } |
137 | } | 121 | } |
138 | 122 | ||
139 | write_lock_bh(&l2cap_sk_list.lock); | 123 | if (la.l2_cid) |
124 | err = l2cap_add_scid(chan, la.l2_cid); | ||
125 | else | ||
126 | err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm); | ||
140 | 127 | ||
141 | if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) { | 128 | if (err < 0) |
142 | err = -EADDRINUSE; | 129 | goto done; |
143 | } else { | ||
144 | /* Save source address */ | ||
145 | bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); | ||
146 | chan->psm = la.l2_psm; | ||
147 | chan->sport = la.l2_psm; | ||
148 | sk->sk_state = BT_BOUND; | ||
149 | |||
150 | if (__le16_to_cpu(la.l2_psm) == 0x0001 || | ||
151 | __le16_to_cpu(la.l2_psm) == 0x0003) | ||
152 | chan->sec_level = BT_SECURITY_SDP; | ||
153 | } | ||
154 | 130 | ||
155 | if (la.l2_cid) | 131 | if (__le16_to_cpu(la.l2_psm) == 0x0001 || |
156 | chan->scid = la.l2_cid; | 132 | __le16_to_cpu(la.l2_psm) == 0x0003) |
133 | chan->sec_level = BT_SECURITY_SDP; | ||
157 | 134 | ||
158 | write_unlock_bh(&l2cap_sk_list.lock); | 135 | bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); |
136 | sk->sk_state = BT_BOUND; | ||
159 | 137 | ||
160 | done: | 138 | done: |
161 | release_sock(sk); | 139 | release_sock(sk); |
@@ -278,28 +256,6 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) | |||
278 | goto done; | 256 | goto done; |
279 | } | 257 | } |
280 | 258 | ||
281 | if (!chan->psm && !chan->scid) { | ||
282 | bdaddr_t *src = &bt_sk(sk)->src; | ||
283 | u16 psm; | ||
284 | |||
285 | err = -EINVAL; | ||
286 | |||
287 | write_lock_bh(&l2cap_sk_list.lock); | ||
288 | |||
289 | for (psm = 0x1001; psm < 0x1100; psm += 2) | ||
290 | if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { | ||
291 | chan->psm = cpu_to_le16(psm); | ||
292 | chan->sport = cpu_to_le16(psm); | ||
293 | err = 0; | ||
294 | break; | ||
295 | } | ||
296 | |||
297 | write_unlock_bh(&l2cap_sk_list.lock); | ||
298 | |||
299 | if (err < 0) | ||
300 | goto done; | ||
301 | } | ||
302 | |||
303 | sk->sk_max_ack_backlog = backlog; | 259 | sk->sk_max_ack_backlog = backlog; |
304 | sk->sk_ack_backlog = 0; | 260 | sk->sk_ack_backlog = 0; |
305 | sk->sk_state = BT_LISTEN; | 261 | sk->sk_state = BT_LISTEN; |
@@ -852,8 +808,7 @@ void l2cap_sock_kill(struct sock *sk) | |||
852 | 808 | ||
853 | /* Kill poor orphan */ | 809 | /* Kill poor orphan */ |
854 | 810 | ||
855 | l2cap_chan_free(l2cap_pi(sk)->chan); | 811 | l2cap_chan_destroy(l2cap_pi(sk)->chan); |
856 | bt_sock_unlink(&l2cap_sk_list, sk); | ||
857 | sock_set_flag(sk, SOCK_DEAD); | 812 | sock_set_flag(sk, SOCK_DEAD); |
858 | sock_put(sk); | 813 | sock_put(sk); |
859 | } | 814 | } |
@@ -1069,7 +1024,6 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, g | |||
1069 | 1024 | ||
1070 | setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk); | 1025 | setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk); |
1071 | 1026 | ||
1072 | bt_sock_link(&l2cap_sk_list, sk); | ||
1073 | return sk; | 1027 | return sk; |
1074 | } | 1028 | } |
1075 | 1029 | ||
@@ -1096,7 +1050,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, | |||
1096 | if (!sk) | 1050 | if (!sk) |
1097 | return -ENOMEM; | 1051 | return -ENOMEM; |
1098 | 1052 | ||
1099 | chan = l2cap_chan_alloc(sk); | 1053 | chan = l2cap_chan_create(sk); |
1100 | if (!chan) { | 1054 | if (!chan) { |
1101 | l2cap_sock_kill(sk); | 1055 | l2cap_sock_kill(sk); |
1102 | return -ENOMEM; | 1056 | return -ENOMEM; |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 2481d257ed98..dae382ce7020 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -1033,6 +1033,9 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1033 | } | 1033 | } |
1034 | 1034 | ||
1035 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); | 1035 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); |
1036 | if (!conn) | ||
1037 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); | ||
1038 | |||
1036 | if (!conn) { | 1039 | if (!conn) { |
1037 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN); | 1040 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN); |
1038 | goto failed; | 1041 | goto failed; |
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 121a5c13b989..5759bb7054f7 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c | |||
@@ -2096,7 +2096,7 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt) | |||
2096 | if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags)) | 2096 | if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags)) |
2097 | continue; | 2097 | continue; |
2098 | 2098 | ||
2099 | if (!status) | 2099 | if (!status && hci_conn_check_secure(conn, d->sec_level)) |
2100 | set_bit(RFCOMM_AUTH_ACCEPT, &d->flags); | 2100 | set_bit(RFCOMM_AUTH_ACCEPT, &d->flags); |
2101 | else | 2101 | else |
2102 | set_bit(RFCOMM_AUTH_REJECT, &d->flags); | 2102 | set_bit(RFCOMM_AUTH_REJECT, &d->flags); |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 0c9d0c07eae6..9c0d76cdca92 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -63,7 +63,8 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
63 | 63 | ||
64 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 64 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
65 | 65 | ||
66 | tid_rx = sta->ampdu_mlme.tid_rx[tid]; | 66 | tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid], |
67 | lockdep_is_held(&sta->ampdu_mlme.mtx)); | ||
67 | 68 | ||
68 | if (!tid_rx) | 69 | if (!tid_rx) |
69 | return; | 70 | return; |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 63d852cb4ca2..cd5125f77cc5 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -136,6 +136,14 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 | |||
136 | ieee80211_tx_skb(sdata, skb); | 136 | ieee80211_tx_skb(sdata, skb); |
137 | } | 137 | } |
138 | 138 | ||
139 | void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, | ||
140 | struct tid_ampdu_tx *tid_tx) | ||
141 | { | ||
142 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | ||
143 | lockdep_assert_held(&sta->lock); | ||
144 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); | ||
145 | } | ||
146 | |||
139 | static void kfree_tid_tx(struct rcu_head *rcu_head) | 147 | static void kfree_tid_tx(struct rcu_head *rcu_head) |
140 | { | 148 | { |
141 | struct tid_ampdu_tx *tid_tx = | 149 | struct tid_ampdu_tx *tid_tx = |
@@ -149,19 +157,22 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
149 | bool tx) | 157 | bool tx) |
150 | { | 158 | { |
151 | struct ieee80211_local *local = sta->local; | 159 | struct ieee80211_local *local = sta->local; |
152 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 160 | struct tid_ampdu_tx *tid_tx; |
153 | int ret; | 161 | int ret; |
154 | 162 | ||
155 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 163 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
156 | 164 | ||
157 | if (!tid_tx) | ||
158 | return -ENOENT; | ||
159 | |||
160 | spin_lock_bh(&sta->lock); | 165 | spin_lock_bh(&sta->lock); |
161 | 166 | ||
167 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | ||
168 | if (!tid_tx) { | ||
169 | spin_unlock_bh(&sta->lock); | ||
170 | return -ENOENT; | ||
171 | } | ||
172 | |||
162 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | 173 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { |
163 | /* not even started yet! */ | 174 | /* not even started yet! */ |
164 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 175 | ieee80211_assign_tid_tx(sta, tid, NULL); |
165 | spin_unlock_bh(&sta->lock); | 176 | spin_unlock_bh(&sta->lock); |
166 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); | 177 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); |
167 | return 0; | 178 | return 0; |
@@ -283,13 +294,13 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid) | |||
283 | 294 | ||
284 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | 295 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) |
285 | { | 296 | { |
286 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 297 | struct tid_ampdu_tx *tid_tx; |
287 | struct ieee80211_local *local = sta->local; | 298 | struct ieee80211_local *local = sta->local; |
288 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 299 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
289 | u16 start_seq_num; | 300 | u16 start_seq_num; |
290 | int ret; | 301 | int ret; |
291 | 302 | ||
292 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 303 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
293 | 304 | ||
294 | /* | 305 | /* |
295 | * While we're asking the driver about the aggregation, | 306 | * While we're asking the driver about the aggregation, |
@@ -318,7 +329,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
318 | " tid %d\n", tid); | 329 | " tid %d\n", tid); |
319 | #endif | 330 | #endif |
320 | spin_lock_bh(&sta->lock); | 331 | spin_lock_bh(&sta->lock); |
321 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 332 | ieee80211_assign_tid_tx(sta, tid, NULL); |
322 | spin_unlock_bh(&sta->lock); | 333 | spin_unlock_bh(&sta->lock); |
323 | 334 | ||
324 | ieee80211_wake_queue_agg(local, tid); | 335 | ieee80211_wake_queue_agg(local, tid); |
@@ -396,9 +407,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
396 | goto err_unlock_sta; | 407 | goto err_unlock_sta; |
397 | } | 408 | } |
398 | 409 | ||
399 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 410 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
400 | /* check if the TID is not in aggregation flow already */ | 411 | /* check if the TID is not in aggregation flow already */ |
401 | if (tid_tx) { | 412 | if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { |
402 | #ifdef CONFIG_MAC80211_HT_DEBUG | 413 | #ifdef CONFIG_MAC80211_HT_DEBUG |
403 | printk(KERN_DEBUG "BA request denied - session is not " | 414 | printk(KERN_DEBUG "BA request denied - session is not " |
404 | "idle on tid %u\n", tid); | 415 | "idle on tid %u\n", tid); |
@@ -433,8 +444,11 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
433 | sta->ampdu_mlme.dialog_token_allocator++; | 444 | sta->ampdu_mlme.dialog_token_allocator++; |
434 | tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; | 445 | tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; |
435 | 446 | ||
436 | /* finally, assign it to the array */ | 447 | /* |
437 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); | 448 | * Finally, assign it to the start array; the work item will |
449 | * collect it and move it to the normal array. | ||
450 | */ | ||
451 | sta->ampdu_mlme.tid_start_tx[tid] = tid_tx; | ||
438 | 452 | ||
439 | ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work); | 453 | ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work); |
440 | 454 | ||
@@ -480,16 +494,19 @@ ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) | |||
480 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | 494 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, |
481 | struct sta_info *sta, u16 tid) | 495 | struct sta_info *sta, u16 tid) |
482 | { | 496 | { |
497 | struct tid_ampdu_tx *tid_tx; | ||
498 | |||
483 | lockdep_assert_held(&sta->ampdu_mlme.mtx); | 499 | lockdep_assert_held(&sta->ampdu_mlme.mtx); |
484 | 500 | ||
501 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | ||
502 | |||
485 | #ifdef CONFIG_MAC80211_HT_DEBUG | 503 | #ifdef CONFIG_MAC80211_HT_DEBUG |
486 | printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); | 504 | printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); |
487 | #endif | 505 | #endif |
488 | 506 | ||
489 | drv_ampdu_action(local, sta->sdata, | 507 | drv_ampdu_action(local, sta->sdata, |
490 | IEEE80211_AMPDU_TX_OPERATIONAL, | 508 | IEEE80211_AMPDU_TX_OPERATIONAL, |
491 | &sta->sta, tid, NULL, | 509 | &sta->sta, tid, NULL, tid_tx->buf_size); |
492 | sta->ampdu_mlme.tid_tx[tid]->buf_size); | ||
493 | 510 | ||
494 | /* | 511 | /* |
495 | * synchronize with TX path, while splicing the TX path | 512 | * synchronize with TX path, while splicing the TX path |
@@ -497,13 +514,13 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | |||
497 | */ | 514 | */ |
498 | spin_lock_bh(&sta->lock); | 515 | spin_lock_bh(&sta->lock); |
499 | 516 | ||
500 | ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid); | 517 | ieee80211_agg_splice_packets(local, tid_tx, tid); |
501 | /* | 518 | /* |
502 | * Now mark as operational. This will be visible | 519 | * Now mark as operational. This will be visible |
503 | * in the TX path, and lets it go lock-free in | 520 | * in the TX path, and lets it go lock-free in |
504 | * the common case. | 521 | * the common case. |
505 | */ | 522 | */ |
506 | set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state); | 523 | set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
507 | ieee80211_agg_splice_finish(local, tid); | 524 | ieee80211_agg_splice_finish(local, tid); |
508 | 525 | ||
509 | spin_unlock_bh(&sta->lock); | 526 | spin_unlock_bh(&sta->lock); |
@@ -537,7 +554,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) | |||
537 | } | 554 | } |
538 | 555 | ||
539 | mutex_lock(&sta->ampdu_mlme.mtx); | 556 | mutex_lock(&sta->ampdu_mlme.mtx); |
540 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 557 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
541 | 558 | ||
542 | if (WARN_ON(!tid_tx)) { | 559 | if (WARN_ON(!tid_tx)) { |
543 | #ifdef CONFIG_MAC80211_HT_DEBUG | 560 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -615,7 +632,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
615 | return -EINVAL; | 632 | return -EINVAL; |
616 | 633 | ||
617 | spin_lock_bh(&sta->lock); | 634 | spin_lock_bh(&sta->lock); |
618 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 635 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
619 | 636 | ||
620 | if (!tid_tx) { | 637 | if (!tid_tx) { |
621 | ret = -ENOENT; | 638 | ret = -ENOENT; |
@@ -671,7 +688,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
671 | 688 | ||
672 | mutex_lock(&sta->ampdu_mlme.mtx); | 689 | mutex_lock(&sta->ampdu_mlme.mtx); |
673 | spin_lock_bh(&sta->lock); | 690 | spin_lock_bh(&sta->lock); |
674 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 691 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
675 | 692 | ||
676 | if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | 693 | if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { |
677 | #ifdef CONFIG_MAC80211_HT_DEBUG | 694 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -697,7 +714,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
697 | ieee80211_agg_splice_packets(local, tid_tx, tid); | 714 | ieee80211_agg_splice_packets(local, tid_tx, tid); |
698 | 715 | ||
699 | /* future packets must not find the tid_tx struct any more */ | 716 | /* future packets must not find the tid_tx struct any more */ |
700 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | 717 | ieee80211_assign_tid_tx(sta, tid, NULL); |
701 | 718 | ||
702 | ieee80211_agg_splice_finish(local, tid); | 719 | ieee80211_agg_splice_finish(local, tid); |
703 | 720 | ||
@@ -752,7 +769,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
752 | 769 | ||
753 | mutex_lock(&sta->ampdu_mlme.mtx); | 770 | mutex_lock(&sta->ampdu_mlme.mtx); |
754 | 771 | ||
755 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 772 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
756 | if (!tid_tx) | 773 | if (!tid_tx) |
757 | goto out; | 774 | goto out; |
758 | 775 | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 12d52cec9515..be70c70d3f5b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -136,7 +136,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
136 | mutex_lock(&sdata->local->sta_mtx); | 136 | mutex_lock(&sdata->local->sta_mtx); |
137 | 137 | ||
138 | if (mac_addr) { | 138 | if (mac_addr) { |
139 | sta = sta_info_get_bss(sdata, mac_addr); | 139 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
140 | sta = sta_info_get(sdata, mac_addr); | ||
141 | else | ||
142 | sta = sta_info_get_bss(sdata, mac_addr); | ||
140 | if (!sta) { | 143 | if (!sta) { |
141 | ieee80211_key_free(sdata->local, key); | 144 | ieee80211_key_free(sdata->local, key); |
142 | err = -ENOENT; | 145 | err = -ENOENT; |
@@ -157,13 +160,14 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
157 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 160 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
158 | u8 key_idx, bool pairwise, const u8 *mac_addr) | 161 | u8 key_idx, bool pairwise, const u8 *mac_addr) |
159 | { | 162 | { |
160 | struct ieee80211_sub_if_data *sdata; | 163 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
164 | struct ieee80211_local *local = sdata->local; | ||
161 | struct sta_info *sta; | 165 | struct sta_info *sta; |
166 | struct ieee80211_key *key = NULL; | ||
162 | int ret; | 167 | int ret; |
163 | 168 | ||
164 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 169 | mutex_lock(&local->sta_mtx); |
165 | 170 | mutex_lock(&local->key_mtx); | |
166 | mutex_lock(&sdata->local->sta_mtx); | ||
167 | 171 | ||
168 | if (mac_addr) { | 172 | if (mac_addr) { |
169 | ret = -ENOENT; | 173 | ret = -ENOENT; |
@@ -172,33 +176,24 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
172 | if (!sta) | 176 | if (!sta) |
173 | goto out_unlock; | 177 | goto out_unlock; |
174 | 178 | ||
175 | if (pairwise) { | 179 | if (pairwise) |
176 | if (sta->ptk) { | 180 | key = key_mtx_dereference(local, sta->ptk); |
177 | ieee80211_key_free(sdata->local, sta->ptk); | 181 | else |
178 | ret = 0; | 182 | key = key_mtx_dereference(local, sta->gtk[key_idx]); |
179 | } | 183 | } else |
180 | } else { | 184 | key = key_mtx_dereference(local, sdata->keys[key_idx]); |
181 | if (sta->gtk[key_idx]) { | ||
182 | ieee80211_key_free(sdata->local, | ||
183 | sta->gtk[key_idx]); | ||
184 | ret = 0; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | goto out_unlock; | ||
189 | } | ||
190 | 185 | ||
191 | if (!sdata->keys[key_idx]) { | 186 | if (!key) { |
192 | ret = -ENOENT; | 187 | ret = -ENOENT; |
193 | goto out_unlock; | 188 | goto out_unlock; |
194 | } | 189 | } |
195 | 190 | ||
196 | ieee80211_key_free(sdata->local, sdata->keys[key_idx]); | 191 | __ieee80211_key_free(key); |
197 | WARN_ON(sdata->keys[key_idx]); | ||
198 | 192 | ||
199 | ret = 0; | 193 | ret = 0; |
200 | out_unlock: | 194 | out_unlock: |
201 | mutex_unlock(&sdata->local->sta_mtx); | 195 | mutex_unlock(&local->key_mtx); |
196 | mutex_unlock(&local->sta_mtx); | ||
202 | 197 | ||
203 | return ret; | 198 | return ret; |
204 | } | 199 | } |
@@ -228,11 +223,11 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
228 | goto out; | 223 | goto out; |
229 | 224 | ||
230 | if (pairwise) | 225 | if (pairwise) |
231 | key = sta->ptk; | 226 | key = rcu_dereference(sta->ptk); |
232 | else if (key_idx < NUM_DEFAULT_KEYS) | 227 | else if (key_idx < NUM_DEFAULT_KEYS) |
233 | key = sta->gtk[key_idx]; | 228 | key = rcu_dereference(sta->gtk[key_idx]); |
234 | } else | 229 | } else |
235 | key = sdata->keys[key_idx]; | 230 | key = rcu_dereference(sdata->keys[key_idx]); |
236 | 231 | ||
237 | if (!key) | 232 | if (!key) |
238 | goto out; | 233 | goto out; |
@@ -468,7 +463,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
468 | int size; | 463 | int size; |
469 | int err = -EINVAL; | 464 | int err = -EINVAL; |
470 | 465 | ||
471 | old = sdata->u.ap.beacon; | 466 | old = rtnl_dereference(sdata->u.ap.beacon); |
472 | 467 | ||
473 | /* head must not be zero-length */ | 468 | /* head must not be zero-length */ |
474 | if (params->head && !params->head_len) | 469 | if (params->head && !params->head_len) |
@@ -563,8 +558,7 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
563 | 558 | ||
564 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 559 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
565 | 560 | ||
566 | old = sdata->u.ap.beacon; | 561 | old = rtnl_dereference(sdata->u.ap.beacon); |
567 | |||
568 | if (old) | 562 | if (old) |
569 | return -EALREADY; | 563 | return -EALREADY; |
570 | 564 | ||
@@ -579,8 +573,7 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
579 | 573 | ||
580 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 574 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
581 | 575 | ||
582 | old = sdata->u.ap.beacon; | 576 | old = rtnl_dereference(sdata->u.ap.beacon); |
583 | |||
584 | if (!old) | 577 | if (!old) |
585 | return -ENOENT; | 578 | return -ENOENT; |
586 | 579 | ||
@@ -594,8 +587,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | |||
594 | 587 | ||
595 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 588 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
596 | 589 | ||
597 | old = sdata->u.ap.beacon; | 590 | old = rtnl_dereference(sdata->u.ap.beacon); |
598 | |||
599 | if (!old) | 591 | if (!old) |
600 | return -ENOENT; | 592 | return -ENOENT; |
601 | 593 | ||
@@ -734,15 +726,29 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
734 | params->ht_capa, | 726 | params->ht_capa, |
735 | &sta->sta.ht_cap); | 727 | &sta->sta.ht_cap); |
736 | 728 | ||
737 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { | 729 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
738 | switch (params->plink_action) { | 730 | #ifdef CONFIG_MAC80211_MESH |
739 | case PLINK_ACTION_OPEN: | 731 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) |
740 | mesh_plink_open(sta); | 732 | switch (params->plink_state) { |
741 | break; | 733 | case NL80211_PLINK_LISTEN: |
742 | case PLINK_ACTION_BLOCK: | 734 | case NL80211_PLINK_ESTAB: |
743 | mesh_plink_block(sta); | 735 | case NL80211_PLINK_BLOCKED: |
744 | break; | 736 | sta->plink_state = params->plink_state; |
745 | } | 737 | break; |
738 | default: | ||
739 | /* nothing */ | ||
740 | break; | ||
741 | } | ||
742 | else | ||
743 | switch (params->plink_action) { | ||
744 | case PLINK_ACTION_OPEN: | ||
745 | mesh_plink_open(sta); | ||
746 | break; | ||
747 | case PLINK_ACTION_BLOCK: | ||
748 | mesh_plink_block(sta); | ||
749 | break; | ||
750 | } | ||
751 | #endif | ||
746 | } | 752 | } |
747 | } | 753 | } |
748 | 754 | ||
@@ -943,8 +949,10 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
943 | static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | 949 | static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, |
944 | struct mpath_info *pinfo) | 950 | struct mpath_info *pinfo) |
945 | { | 951 | { |
946 | if (mpath->next_hop) | 952 | struct sta_info *next_hop_sta = rcu_dereference(mpath->next_hop); |
947 | memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); | 953 | |
954 | if (next_hop_sta) | ||
955 | memcpy(next_hop, next_hop_sta->sta.addr, ETH_ALEN); | ||
948 | else | 956 | else |
949 | memset(next_hop, 0, ETH_ALEN); | 957 | memset(next_hop, 0, ETH_ALEN); |
950 | 958 | ||
@@ -1064,7 +1072,11 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, | |||
1064 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); | 1072 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); |
1065 | ifmsh->mesh_pp_id = setup->path_sel_proto; | 1073 | ifmsh->mesh_pp_id = setup->path_sel_proto; |
1066 | ifmsh->mesh_pm_id = setup->path_metric; | 1074 | ifmsh->mesh_pm_id = setup->path_metric; |
1067 | ifmsh->is_secure = setup->is_secure; | 1075 | ifmsh->security = IEEE80211_MESH_SEC_NONE; |
1076 | if (setup->is_authenticated) | ||
1077 | ifmsh->security |= IEEE80211_MESH_SEC_AUTHED; | ||
1078 | if (setup->is_secure) | ||
1079 | ifmsh->security |= IEEE80211_MESH_SEC_SECURED; | ||
1068 | 1080 | ||
1069 | return 0; | 1081 | return 0; |
1070 | } | 1082 | } |
@@ -1297,9 +1309,10 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1297 | } | 1309 | } |
1298 | 1310 | ||
1299 | #ifdef CONFIG_PM | 1311 | #ifdef CONFIG_PM |
1300 | static int ieee80211_suspend(struct wiphy *wiphy) | 1312 | static int ieee80211_suspend(struct wiphy *wiphy, |
1313 | struct cfg80211_wowlan *wowlan) | ||
1301 | { | 1314 | { |
1302 | return __ieee80211_suspend(wiphy_priv(wiphy)); | 1315 | return __ieee80211_suspend(wiphy_priv(wiphy), wowlan); |
1303 | } | 1316 | } |
1304 | 1317 | ||
1305 | static int ieee80211_resume(struct wiphy *wiphy) | 1318 | static int ieee80211_resume(struct wiphy *wiphy) |
@@ -1342,6 +1355,30 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1342 | return ieee80211_request_scan(sdata, req); | 1355 | return ieee80211_request_scan(sdata, req); |
1343 | } | 1356 | } |
1344 | 1357 | ||
1358 | static int | ||
1359 | ieee80211_sched_scan_start(struct wiphy *wiphy, | ||
1360 | struct net_device *dev, | ||
1361 | struct cfg80211_sched_scan_request *req) | ||
1362 | { | ||
1363 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1364 | |||
1365 | if (!sdata->local->ops->sched_scan_start) | ||
1366 | return -EOPNOTSUPP; | ||
1367 | |||
1368 | return ieee80211_request_sched_scan_start(sdata, req); | ||
1369 | } | ||
1370 | |||
1371 | static int | ||
1372 | ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) | ||
1373 | { | ||
1374 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1375 | |||
1376 | if (!sdata->local->ops->sched_scan_stop) | ||
1377 | return -EOPNOTSUPP; | ||
1378 | |||
1379 | return ieee80211_request_sched_scan_stop(sdata); | ||
1380 | } | ||
1381 | |||
1345 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, | 1382 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, |
1346 | struct cfg80211_auth_request *req) | 1383 | struct cfg80211_auth_request *req) |
1347 | { | 1384 | { |
@@ -2083,6 +2120,8 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2083 | .suspend = ieee80211_suspend, | 2120 | .suspend = ieee80211_suspend, |
2084 | .resume = ieee80211_resume, | 2121 | .resume = ieee80211_resume, |
2085 | .scan = ieee80211_scan, | 2122 | .scan = ieee80211_scan, |
2123 | .sched_scan_start = ieee80211_sched_scan_start, | ||
2124 | .sched_scan_stop = ieee80211_sched_scan_stop, | ||
2086 | .auth = ieee80211_auth, | 2125 | .auth = ieee80211_auth, |
2087 | .assoc = ieee80211_assoc, | 2126 | .assoc = ieee80211_assoc, |
2088 | .deauth = ieee80211_deauth, | 2127 | .deauth = ieee80211_deauth, |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 0a602dbfdb2b..186e02f7cc32 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -135,7 +135,7 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf, | |||
135 | struct ieee80211_local *local = file->private_data; | 135 | struct ieee80211_local *local = file->private_data; |
136 | 136 | ||
137 | rtnl_lock(); | 137 | rtnl_lock(); |
138 | __ieee80211_suspend(&local->hw); | 138 | __ieee80211_suspend(&local->hw, NULL); |
139 | __ieee80211_resume(&local->hw); | 139 | __ieee80211_resume(&local->hw); |
140 | rtnl_unlock(); | 140 | rtnl_unlock(); |
141 | 141 | ||
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index f7ef3477c24a..33c58b85c911 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -241,16 +241,12 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key) | |||
241 | if (!key->debugfs.dir) | 241 | if (!key->debugfs.dir) |
242 | return; | 242 | return; |
243 | 243 | ||
244 | rcu_read_lock(); | 244 | sta = key->sta; |
245 | sta = rcu_dereference(key->sta); | 245 | if (sta) { |
246 | if (sta) | ||
247 | sprintf(buf, "../../stations/%pM", sta->sta.addr); | 246 | sprintf(buf, "../../stations/%pM", sta->sta.addr); |
248 | rcu_read_unlock(); | ||
249 | |||
250 | /* using sta as a boolean is fine outside RCU lock */ | ||
251 | if (sta) | ||
252 | key->debugfs.stalink = | 247 | key->debugfs.stalink = |
253 | debugfs_create_symlink("station", key->debugfs.dir, buf); | 248 | debugfs_create_symlink("station", key->debugfs.dir, buf); |
249 | } | ||
254 | 250 | ||
255 | DEBUGFS_ADD(keylen); | 251 | DEBUGFS_ADD(keylen); |
256 | DEBUGFS_ADD(flags); | 252 | DEBUGFS_ADD(flags); |
@@ -286,7 +282,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
286 | lockdep_assert_held(&sdata->local->key_mtx); | 282 | lockdep_assert_held(&sdata->local->key_mtx); |
287 | 283 | ||
288 | if (sdata->default_unicast_key) { | 284 | if (sdata->default_unicast_key) { |
289 | key = sdata->default_unicast_key; | 285 | key = key_mtx_dereference(sdata->local, |
286 | sdata->default_unicast_key); | ||
290 | sprintf(buf, "../keys/%d", key->debugfs.cnt); | 287 | sprintf(buf, "../keys/%d", key->debugfs.cnt); |
291 | sdata->debugfs.default_unicast_key = | 288 | sdata->debugfs.default_unicast_key = |
292 | debugfs_create_symlink("default_unicast_key", | 289 | debugfs_create_symlink("default_unicast_key", |
@@ -297,7 +294,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
297 | } | 294 | } |
298 | 295 | ||
299 | if (sdata->default_multicast_key) { | 296 | if (sdata->default_multicast_key) { |
300 | key = sdata->default_multicast_key; | 297 | key = key_mtx_dereference(sdata->local, |
298 | sdata->default_multicast_key); | ||
301 | sprintf(buf, "../keys/%d", key->debugfs.cnt); | 299 | sprintf(buf, "../keys/%d", key->debugfs.cnt); |
302 | sdata->debugfs.default_multicast_key = | 300 | sdata->debugfs.default_multicast_key = |
303 | debugfs_create_symlink("default_multicast_key", | 301 | debugfs_create_symlink("default_multicast_key", |
@@ -316,9 +314,8 @@ void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) | |||
316 | if (!sdata->debugfs.dir) | 314 | if (!sdata->debugfs.dir) |
317 | return; | 315 | return; |
318 | 316 | ||
319 | /* this is running under the key lock */ | 317 | key = key_mtx_dereference(sdata->local, |
320 | 318 | sdata->default_mgmt_key); | |
321 | key = sdata->default_mgmt_key; | ||
322 | if (key) { | 319 | if (key) { |
323 | sprintf(buf, "../keys/%d", key->debugfs.cnt); | 320 | sprintf(buf, "../keys/%d", key->debugfs.cnt); |
324 | sdata->debugfs.default_mgmt_key = | 321 | sdata->debugfs.default_mgmt_key = |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 2ddb56e5b51f..eebf7a67daf7 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -41,6 +41,33 @@ static inline void drv_stop(struct ieee80211_local *local) | |||
41 | local->started = false; | 41 | local->started = false; |
42 | } | 42 | } |
43 | 43 | ||
44 | #ifdef CONFIG_PM | ||
45 | static inline int drv_suspend(struct ieee80211_local *local, | ||
46 | struct cfg80211_wowlan *wowlan) | ||
47 | { | ||
48 | int ret; | ||
49 | |||
50 | might_sleep(); | ||
51 | |||
52 | trace_drv_suspend(local); | ||
53 | ret = local->ops->suspend(&local->hw, wowlan); | ||
54 | trace_drv_return_int(local, ret); | ||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | static inline int drv_resume(struct ieee80211_local *local) | ||
59 | { | ||
60 | int ret; | ||
61 | |||
62 | might_sleep(); | ||
63 | |||
64 | trace_drv_resume(local); | ||
65 | ret = local->ops->resume(&local->hw); | ||
66 | trace_drv_return_int(local, ret); | ||
67 | return ret; | ||
68 | } | ||
69 | #endif | ||
70 | |||
44 | static inline int drv_add_interface(struct ieee80211_local *local, | 71 | static inline int drv_add_interface(struct ieee80211_local *local, |
45 | struct ieee80211_vif *vif) | 72 | struct ieee80211_vif *vif) |
46 | { | 73 | { |
@@ -185,12 +212,39 @@ static inline int drv_hw_scan(struct ieee80211_local *local, | |||
185 | 212 | ||
186 | might_sleep(); | 213 | might_sleep(); |
187 | 214 | ||
188 | trace_drv_hw_scan(local, sdata, req); | 215 | trace_drv_hw_scan(local, sdata); |
189 | ret = local->ops->hw_scan(&local->hw, &sdata->vif, req); | 216 | ret = local->ops->hw_scan(&local->hw, &sdata->vif, req); |
190 | trace_drv_return_int(local, ret); | 217 | trace_drv_return_int(local, ret); |
191 | return ret; | 218 | return ret; |
192 | } | 219 | } |
193 | 220 | ||
221 | static inline int | ||
222 | drv_sched_scan_start(struct ieee80211_local *local, | ||
223 | struct ieee80211_sub_if_data *sdata, | ||
224 | struct cfg80211_sched_scan_request *req, | ||
225 | struct ieee80211_sched_scan_ies *ies) | ||
226 | { | ||
227 | int ret; | ||
228 | |||
229 | might_sleep(); | ||
230 | |||
231 | trace_drv_sched_scan_start(local, sdata); | ||
232 | ret = local->ops->sched_scan_start(&local->hw, &sdata->vif, | ||
233 | req, ies); | ||
234 | trace_drv_return_int(local, ret); | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | static inline void drv_sched_scan_stop(struct ieee80211_local *local, | ||
239 | struct ieee80211_sub_if_data *sdata) | ||
240 | { | ||
241 | might_sleep(); | ||
242 | |||
243 | trace_drv_sched_scan_stop(local, sdata); | ||
244 | local->ops->sched_scan_stop(&local->hw, &sdata->vif); | ||
245 | trace_drv_return_void(local); | ||
246 | } | ||
247 | |||
194 | static inline void drv_sw_scan_start(struct ieee80211_local *local) | 248 | static inline void drv_sw_scan_start(struct ieee80211_local *local) |
195 | { | 249 | { |
196 | might_sleep(); | 250 | might_sleep(); |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 191e834ec46b..ed9edcbd9aa5 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -55,6 +55,70 @@ DECLARE_EVENT_CLASS(local_only_evt, | |||
55 | TP_printk(LOCAL_PR_FMT, LOCAL_PR_ARG) | 55 | TP_printk(LOCAL_PR_FMT, LOCAL_PR_ARG) |
56 | ); | 56 | ); |
57 | 57 | ||
58 | DECLARE_EVENT_CLASS(local_sdata_addr_evt, | ||
59 | TP_PROTO(struct ieee80211_local *local, | ||
60 | struct ieee80211_sub_if_data *sdata), | ||
61 | TP_ARGS(local, sdata), | ||
62 | |||
63 | TP_STRUCT__entry( | ||
64 | LOCAL_ENTRY | ||
65 | VIF_ENTRY | ||
66 | __array(char, addr, 6) | ||
67 | ), | ||
68 | |||
69 | TP_fast_assign( | ||
70 | LOCAL_ASSIGN; | ||
71 | VIF_ASSIGN; | ||
72 | memcpy(__entry->addr, sdata->vif.addr, 6); | ||
73 | ), | ||
74 | |||
75 | TP_printk( | ||
76 | LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", | ||
77 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr | ||
78 | ) | ||
79 | ); | ||
80 | |||
81 | DECLARE_EVENT_CLASS(local_u32_evt, | ||
82 | TP_PROTO(struct ieee80211_local *local, u32 value), | ||
83 | TP_ARGS(local, value), | ||
84 | |||
85 | TP_STRUCT__entry( | ||
86 | LOCAL_ENTRY | ||
87 | __field(u32, value) | ||
88 | ), | ||
89 | |||
90 | TP_fast_assign( | ||
91 | LOCAL_ASSIGN; | ||
92 | __entry->value = value; | ||
93 | ), | ||
94 | |||
95 | TP_printk( | ||
96 | LOCAL_PR_FMT " value:%d", | ||
97 | LOCAL_PR_ARG, __entry->value | ||
98 | ) | ||
99 | ); | ||
100 | |||
101 | DECLARE_EVENT_CLASS(local_sdata_evt, | ||
102 | TP_PROTO(struct ieee80211_local *local, | ||
103 | struct ieee80211_sub_if_data *sdata), | ||
104 | TP_ARGS(local, sdata), | ||
105 | |||
106 | TP_STRUCT__entry( | ||
107 | LOCAL_ENTRY | ||
108 | VIF_ENTRY | ||
109 | ), | ||
110 | |||
111 | TP_fast_assign( | ||
112 | LOCAL_ASSIGN; | ||
113 | VIF_ASSIGN; | ||
114 | ), | ||
115 | |||
116 | TP_printk( | ||
117 | LOCAL_PR_FMT VIF_PR_FMT, | ||
118 | LOCAL_PR_ARG, VIF_PR_ARG | ||
119 | ) | ||
120 | ); | ||
121 | |||
58 | DEFINE_EVENT(local_only_evt, drv_return_void, | 122 | DEFINE_EVENT(local_only_evt, drv_return_void, |
59 | TP_PROTO(struct ieee80211_local *local), | 123 | TP_PROTO(struct ieee80211_local *local), |
60 | TP_ARGS(local) | 124 | TP_ARGS(local) |
@@ -108,33 +172,25 @@ DEFINE_EVENT(local_only_evt, drv_start, | |||
108 | TP_ARGS(local) | 172 | TP_ARGS(local) |
109 | ); | 173 | ); |
110 | 174 | ||
175 | DEFINE_EVENT(local_only_evt, drv_suspend, | ||
176 | TP_PROTO(struct ieee80211_local *local), | ||
177 | TP_ARGS(local) | ||
178 | ); | ||
179 | |||
180 | DEFINE_EVENT(local_only_evt, drv_resume, | ||
181 | TP_PROTO(struct ieee80211_local *local), | ||
182 | TP_ARGS(local) | ||
183 | ); | ||
184 | |||
111 | DEFINE_EVENT(local_only_evt, drv_stop, | 185 | DEFINE_EVENT(local_only_evt, drv_stop, |
112 | TP_PROTO(struct ieee80211_local *local), | 186 | TP_PROTO(struct ieee80211_local *local), |
113 | TP_ARGS(local) | 187 | TP_ARGS(local) |
114 | ); | 188 | ); |
115 | 189 | ||
116 | TRACE_EVENT(drv_add_interface, | 190 | DEFINE_EVENT(local_sdata_addr_evt, drv_add_interface, |
117 | TP_PROTO(struct ieee80211_local *local, | 191 | TP_PROTO(struct ieee80211_local *local, |
118 | struct ieee80211_sub_if_data *sdata), | 192 | struct ieee80211_sub_if_data *sdata), |
119 | 193 | TP_ARGS(local, sdata) | |
120 | TP_ARGS(local, sdata), | ||
121 | |||
122 | TP_STRUCT__entry( | ||
123 | LOCAL_ENTRY | ||
124 | VIF_ENTRY | ||
125 | __array(char, addr, 6) | ||
126 | ), | ||
127 | |||
128 | TP_fast_assign( | ||
129 | LOCAL_ASSIGN; | ||
130 | VIF_ASSIGN; | ||
131 | memcpy(__entry->addr, sdata->vif.addr, 6); | ||
132 | ), | ||
133 | |||
134 | TP_printk( | ||
135 | LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", | ||
136 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr | ||
137 | ) | ||
138 | ); | 194 | ); |
139 | 195 | ||
140 | TRACE_EVENT(drv_change_interface, | 196 | TRACE_EVENT(drv_change_interface, |
@@ -165,27 +221,10 @@ TRACE_EVENT(drv_change_interface, | |||
165 | ) | 221 | ) |
166 | ); | 222 | ); |
167 | 223 | ||
168 | TRACE_EVENT(drv_remove_interface, | 224 | DEFINE_EVENT(local_sdata_addr_evt, drv_remove_interface, |
169 | TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata), | 225 | TP_PROTO(struct ieee80211_local *local, |
170 | 226 | struct ieee80211_sub_if_data *sdata), | |
171 | TP_ARGS(local, sdata), | 227 | TP_ARGS(local, sdata) |
172 | |||
173 | TP_STRUCT__entry( | ||
174 | LOCAL_ENTRY | ||
175 | VIF_ENTRY | ||
176 | __array(char, addr, 6) | ||
177 | ), | ||
178 | |||
179 | TP_fast_assign( | ||
180 | LOCAL_ASSIGN; | ||
181 | VIF_ASSIGN; | ||
182 | memcpy(__entry->addr, sdata->vif.addr, 6); | ||
183 | ), | ||
184 | |||
185 | TP_printk( | ||
186 | LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", | ||
187 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr | ||
188 | ) | ||
189 | ); | 228 | ); |
190 | 229 | ||
191 | TRACE_EVENT(drv_config, | 230 | TRACE_EVENT(drv_config, |
@@ -415,27 +454,22 @@ TRACE_EVENT(drv_update_tkip_key, | |||
415 | ) | 454 | ) |
416 | ); | 455 | ); |
417 | 456 | ||
418 | TRACE_EVENT(drv_hw_scan, | 457 | DEFINE_EVENT(local_sdata_evt, drv_hw_scan, |
419 | TP_PROTO(struct ieee80211_local *local, | 458 | TP_PROTO(struct ieee80211_local *local, |
420 | struct ieee80211_sub_if_data *sdata, | 459 | struct ieee80211_sub_if_data *sdata), |
421 | struct cfg80211_scan_request *req), | 460 | TP_ARGS(local, sdata) |
422 | 461 | ); | |
423 | TP_ARGS(local, sdata, req), | ||
424 | |||
425 | TP_STRUCT__entry( | ||
426 | LOCAL_ENTRY | ||
427 | VIF_ENTRY | ||
428 | ), | ||
429 | 462 | ||
430 | TP_fast_assign( | 463 | DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start, |
431 | LOCAL_ASSIGN; | 464 | TP_PROTO(struct ieee80211_local *local, |
432 | VIF_ASSIGN; | 465 | struct ieee80211_sub_if_data *sdata), |
433 | ), | 466 | TP_ARGS(local, sdata) |
467 | ); | ||
434 | 468 | ||
435 | TP_printk( | 469 | DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop, |
436 | LOCAL_PR_FMT VIF_PR_FMT, | 470 | TP_PROTO(struct ieee80211_local *local, |
437 | LOCAL_PR_ARG,VIF_PR_ARG | 471 | struct ieee80211_sub_if_data *sdata), |
438 | ) | 472 | TP_ARGS(local, sdata) |
439 | ); | 473 | ); |
440 | 474 | ||
441 | DEFINE_EVENT(local_only_evt, drv_sw_scan_start, | 475 | DEFINE_EVENT(local_only_evt, drv_sw_scan_start, |
@@ -504,46 +538,14 @@ TRACE_EVENT(drv_get_tkip_seq, | |||
504 | ) | 538 | ) |
505 | ); | 539 | ); |
506 | 540 | ||
507 | TRACE_EVENT(drv_set_frag_threshold, | 541 | DEFINE_EVENT(local_u32_evt, drv_set_frag_threshold, |
508 | TP_PROTO(struct ieee80211_local *local, u32 value), | 542 | TP_PROTO(struct ieee80211_local *local, u32 value), |
509 | 543 | TP_ARGS(local, value) | |
510 | TP_ARGS(local, value), | ||
511 | |||
512 | TP_STRUCT__entry( | ||
513 | LOCAL_ENTRY | ||
514 | __field(u32, value) | ||
515 | ), | ||
516 | |||
517 | TP_fast_assign( | ||
518 | LOCAL_ASSIGN; | ||
519 | __entry->value = value; | ||
520 | ), | ||
521 | |||
522 | TP_printk( | ||
523 | LOCAL_PR_FMT " value:%d", | ||
524 | LOCAL_PR_ARG, __entry->value | ||
525 | ) | ||
526 | ); | 544 | ); |
527 | 545 | ||
528 | TRACE_EVENT(drv_set_rts_threshold, | 546 | DEFINE_EVENT(local_u32_evt, drv_set_rts_threshold, |
529 | TP_PROTO(struct ieee80211_local *local, u32 value), | 547 | TP_PROTO(struct ieee80211_local *local, u32 value), |
530 | 548 | TP_ARGS(local, value) | |
531 | TP_ARGS(local, value), | ||
532 | |||
533 | TP_STRUCT__entry( | ||
534 | LOCAL_ENTRY | ||
535 | __field(u32, value) | ||
536 | ), | ||
537 | |||
538 | TP_fast_assign( | ||
539 | LOCAL_ASSIGN; | ||
540 | __entry->value = value; | ||
541 | ), | ||
542 | |||
543 | TP_printk( | ||
544 | LOCAL_PR_FMT " value:%d", | ||
545 | LOCAL_PR_ARG, __entry->value | ||
546 | ) | ||
547 | ); | 549 | ); |
548 | 550 | ||
549 | TRACE_EVENT(drv_set_coverage_class, | 551 | TRACE_EVENT(drv_set_coverage_class, |
@@ -1194,6 +1196,42 @@ TRACE_EVENT(api_scan_completed, | |||
1194 | ) | 1196 | ) |
1195 | ); | 1197 | ); |
1196 | 1198 | ||
1199 | TRACE_EVENT(api_sched_scan_results, | ||
1200 | TP_PROTO(struct ieee80211_local *local), | ||
1201 | |||
1202 | TP_ARGS(local), | ||
1203 | |||
1204 | TP_STRUCT__entry( | ||
1205 | LOCAL_ENTRY | ||
1206 | ), | ||
1207 | |||
1208 | TP_fast_assign( | ||
1209 | LOCAL_ASSIGN; | ||
1210 | ), | ||
1211 | |||
1212 | TP_printk( | ||
1213 | LOCAL_PR_FMT, LOCAL_PR_ARG | ||
1214 | ) | ||
1215 | ); | ||
1216 | |||
1217 | TRACE_EVENT(api_sched_scan_stopped, | ||
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 | |||
1197 | TRACE_EVENT(api_sta_block_awake, | 1235 | TRACE_EVENT(api_sta_block_awake, |
1198 | TP_PROTO(struct ieee80211_local *local, | 1236 | TP_PROTO(struct ieee80211_local *local, |
1199 | struct ieee80211_sta *sta, bool block), | 1237 | struct ieee80211_sta *sta, bool block), |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index b9e4b9bd2179..591add22bcc0 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -140,14 +140,29 @@ void ieee80211_ba_session_work(struct work_struct *work) | |||
140 | sta, tid, WLAN_BACK_RECIPIENT, | 140 | sta, tid, WLAN_BACK_RECIPIENT, |
141 | WLAN_REASON_QSTA_TIMEOUT, true); | 141 | WLAN_REASON_QSTA_TIMEOUT, true); |
142 | 142 | ||
143 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 143 | tid_tx = sta->ampdu_mlme.tid_start_tx[tid]; |
144 | if (!tid_tx) | 144 | if (tid_tx) { |
145 | continue; | 145 | /* |
146 | * Assign it over to the normal tid_tx array | ||
147 | * where it "goes live". | ||
148 | */ | ||
149 | spin_lock_bh(&sta->lock); | ||
150 | |||
151 | sta->ampdu_mlme.tid_start_tx[tid] = NULL; | ||
152 | /* could there be a race? */ | ||
153 | if (sta->ampdu_mlme.tid_tx[tid]) | ||
154 | kfree(tid_tx); | ||
155 | else | ||
156 | ieee80211_assign_tid_tx(sta, tid, tid_tx); | ||
157 | spin_unlock_bh(&sta->lock); | ||
146 | 158 | ||
147 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) | ||
148 | ieee80211_tx_ba_session_handle_start(sta, tid); | 159 | ieee80211_tx_ba_session_handle_start(sta, tid); |
149 | else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP, | 160 | continue; |
150 | &tid_tx->state)) | 161 | } |
162 | |||
163 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | ||
164 | if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP, | ||
165 | &tid_tx->state)) | ||
151 | ___ieee80211_stop_tx_ba_session(sta, tid, | 166 | ___ieee80211_stop_tx_ba_session(sta, tid, |
152 | WLAN_BACK_INITIATOR, | 167 | WLAN_BACK_INITIATOR, |
153 | true); | 168 | true); |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index b81860c94698..421eaa6b0c2b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -662,12 +662,16 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
662 | int tx_last_beacon, len = req->len; | 662 | int tx_last_beacon, len = req->len; |
663 | struct sk_buff *skb; | 663 | struct sk_buff *skb; |
664 | struct ieee80211_mgmt *resp; | 664 | struct ieee80211_mgmt *resp; |
665 | struct sk_buff *presp; | ||
665 | u8 *pos, *end; | 666 | u8 *pos, *end; |
666 | 667 | ||
667 | lockdep_assert_held(&ifibss->mtx); | 668 | lockdep_assert_held(&ifibss->mtx); |
668 | 669 | ||
670 | presp = rcu_dereference_protected(ifibss->presp, | ||
671 | lockdep_is_held(&ifibss->mtx)); | ||
672 | |||
669 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || | 673 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || |
670 | len < 24 + 2 || !ifibss->presp) | 674 | len < 24 + 2 || !presp) |
671 | return; | 675 | return; |
672 | 676 | ||
673 | tx_last_beacon = drv_tx_last_beacon(local); | 677 | tx_last_beacon = drv_tx_last_beacon(local); |
@@ -705,7 +709,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
705 | } | 709 | } |
706 | 710 | ||
707 | /* Reply with ProbeResp */ | 711 | /* Reply with ProbeResp */ |
708 | skb = skb_copy(ifibss->presp, GFP_KERNEL); | 712 | skb = skb_copy(presp, GFP_KERNEL); |
709 | if (!skb) | 713 | if (!skb) |
710 | return; | 714 | return; |
711 | 715 | ||
@@ -985,7 +989,8 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
985 | 989 | ||
986 | /* remove beacon */ | 990 | /* remove beacon */ |
987 | kfree(sdata->u.ibss.ie); | 991 | kfree(sdata->u.ibss.ie); |
988 | skb = sdata->u.ibss.presp; | 992 | skb = rcu_dereference_protected(sdata->u.ibss.presp, |
993 | lockdep_is_held(&sdata->u.ibss.mtx)); | ||
989 | rcu_assign_pointer(sdata->u.ibss.presp, NULL); | 994 | rcu_assign_pointer(sdata->u.ibss.presp, NULL); |
990 | sdata->vif.bss_conf.ibss_joined = false; | 995 | sdata->vif.bss_conf.ibss_joined = false; |
991 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | 996 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 027c0467d7a3..2025af52b195 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -214,7 +214,7 @@ struct beacon_data { | |||
214 | }; | 214 | }; |
215 | 215 | ||
216 | struct ieee80211_if_ap { | 216 | struct ieee80211_if_ap { |
217 | struct beacon_data *beacon; | 217 | struct beacon_data __rcu *beacon; |
218 | 218 | ||
219 | struct list_head vlans; | 219 | struct list_head vlans; |
220 | 220 | ||
@@ -237,7 +237,7 @@ struct ieee80211_if_vlan { | |||
237 | struct list_head list; | 237 | struct list_head list; |
238 | 238 | ||
239 | /* used for all tx if the VLAN is configured to 4-addr mode */ | 239 | /* used for all tx if the VLAN is configured to 4-addr mode */ |
240 | struct sta_info *sta; | 240 | struct sta_info __rcu *sta; |
241 | }; | 241 | }; |
242 | 242 | ||
243 | struct mesh_stats { | 243 | struct mesh_stats { |
@@ -442,7 +442,8 @@ struct ieee80211_if_ibss { | |||
442 | 442 | ||
443 | unsigned long ibss_join_req; | 443 | unsigned long ibss_join_req; |
444 | /* probe response/beacon for IBSS */ | 444 | /* probe response/beacon for IBSS */ |
445 | struct sk_buff *presp, *skb; | 445 | struct sk_buff __rcu *presp; |
446 | struct sk_buff *skb; | ||
446 | 447 | ||
447 | enum { | 448 | enum { |
448 | IEEE80211_IBSS_MLME_SEARCH, | 449 | IEEE80211_IBSS_MLME_SEARCH, |
@@ -490,7 +491,11 @@ struct ieee80211_if_mesh { | |||
490 | bool accepting_plinks; | 491 | bool accepting_plinks; |
491 | const u8 *ie; | 492 | const u8 *ie; |
492 | u8 ie_len; | 493 | u8 ie_len; |
493 | bool is_secure; | 494 | enum { |
495 | IEEE80211_MESH_SEC_NONE = 0x0, | ||
496 | IEEE80211_MESH_SEC_AUTHED = 0x1, | ||
497 | IEEE80211_MESH_SEC_SECURED = 0x2, | ||
498 | } security; | ||
494 | }; | 499 | }; |
495 | 500 | ||
496 | #ifdef CONFIG_MAC80211_MESH | 501 | #ifdef CONFIG_MAC80211_MESH |
@@ -563,9 +568,10 @@ struct ieee80211_sub_if_data { | |||
563 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; | 568 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; |
564 | unsigned int fragment_next; | 569 | unsigned int fragment_next; |
565 | 570 | ||
566 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 571 | struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
567 | struct ieee80211_key *default_unicast_key, *default_multicast_key; | 572 | struct ieee80211_key __rcu *default_unicast_key; |
568 | struct ieee80211_key *default_mgmt_key; | 573 | struct ieee80211_key __rcu *default_multicast_key; |
574 | struct ieee80211_key __rcu *default_mgmt_key; | ||
569 | 575 | ||
570 | u16 sequence_number; | 576 | u16 sequence_number; |
571 | __be16 control_port_protocol; | 577 | __be16 control_port_protocol; |
@@ -764,6 +770,9 @@ struct ieee80211_local { | |||
764 | /* device is started */ | 770 | /* device is started */ |
765 | bool started; | 771 | bool started; |
766 | 772 | ||
773 | /* wowlan is enabled -- don't reconfig on resume */ | ||
774 | bool wowlan; | ||
775 | |||
767 | int tx_headroom; /* required headroom for hardware/radiotap */ | 776 | int tx_headroom; /* required headroom for hardware/radiotap */ |
768 | 777 | ||
769 | /* count for keys needing tailroom space allocation */ | 778 | /* count for keys needing tailroom space allocation */ |
@@ -798,7 +807,7 @@ struct ieee80211_local { | |||
798 | spinlock_t sta_lock; | 807 | spinlock_t sta_lock; |
799 | unsigned long num_sta; | 808 | unsigned long num_sta; |
800 | struct list_head sta_list, sta_pending_list; | 809 | struct list_head sta_list, sta_pending_list; |
801 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 810 | struct sta_info __rcu *sta_hash[STA_HASH_SIZE]; |
802 | struct timer_list sta_cleanup; | 811 | struct timer_list sta_cleanup; |
803 | struct work_struct sta_finish_work; | 812 | struct work_struct sta_finish_work; |
804 | int sta_generation; | 813 | int sta_generation; |
@@ -840,6 +849,10 @@ struct ieee80211_local { | |||
840 | int scan_channel_idx; | 849 | int scan_channel_idx; |
841 | int scan_ies_len; | 850 | int scan_ies_len; |
842 | 851 | ||
852 | bool sched_scanning; | ||
853 | struct ieee80211_sched_scan_ies sched_scan_ies; | ||
854 | struct work_struct sched_scan_stopped_work; | ||
855 | |||
843 | unsigned long leave_oper_channel_time; | 856 | unsigned long leave_oper_channel_time; |
844 | enum mac80211_scan_state next_scan_state; | 857 | enum mac80211_scan_state next_scan_state; |
845 | struct delayed_work scan_work; | 858 | struct delayed_work scan_work; |
@@ -1147,6 +1160,12 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | |||
1147 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | 1160 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
1148 | struct ieee80211_bss *bss); | 1161 | struct ieee80211_bss *bss); |
1149 | 1162 | ||
1163 | /* scheduled scan handling */ | ||
1164 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | ||
1165 | struct cfg80211_sched_scan_request *req); | ||
1166 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); | ||
1167 | void ieee80211_sched_scan_stopped_work(struct work_struct *work); | ||
1168 | |||
1150 | /* off-channel helpers */ | 1169 | /* off-channel helpers */ |
1151 | bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); | 1170 | bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); |
1152 | void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local, | 1171 | void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local, |
@@ -1250,7 +1269,8 @@ int ieee80211_reconfig(struct ieee80211_local *local); | |||
1250 | void ieee80211_stop_device(struct ieee80211_local *local); | 1269 | void ieee80211_stop_device(struct ieee80211_local *local); |
1251 | 1270 | ||
1252 | #ifdef CONFIG_PM | 1271 | #ifdef CONFIG_PM |
1253 | int __ieee80211_suspend(struct ieee80211_hw *hw); | 1272 | int __ieee80211_suspend(struct ieee80211_hw *hw, |
1273 | struct cfg80211_wowlan *wowlan); | ||
1254 | 1274 | ||
1255 | static inline int __ieee80211_resume(struct ieee80211_hw *hw) | 1275 | static inline int __ieee80211_resume(struct ieee80211_hw *hw) |
1256 | { | 1276 | { |
@@ -1263,7 +1283,8 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) | |||
1263 | return ieee80211_reconfig(hw_to_local(hw)); | 1283 | return ieee80211_reconfig(hw_to_local(hw)); |
1264 | } | 1284 | } |
1265 | #else | 1285 | #else |
1266 | static inline int __ieee80211_suspend(struct ieee80211_hw *hw) | 1286 | static inline int __ieee80211_suspend(struct ieee80211_hw *hw, |
1287 | struct cfg80211_wowlan *wowlan) | ||
1267 | { | 1288 | { |
1268 | return 0; | 1289 | return 0; |
1269 | } | 1290 | } |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 80c29d626aa4..7dfbe71dc637 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -449,7 +449,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
449 | /* APs need special treatment */ | 449 | /* APs need special treatment */ |
450 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 450 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
451 | struct ieee80211_sub_if_data *vlan, *tmpsdata; | 451 | struct ieee80211_sub_if_data *vlan, *tmpsdata; |
452 | struct beacon_data *old_beacon = sdata->u.ap.beacon; | 452 | struct beacon_data *old_beacon = |
453 | rtnl_dereference(sdata->u.ap.beacon); | ||
453 | 454 | ||
454 | /* sdata_running will return false, so this will disable */ | 455 | /* sdata_running will return false, so this will disable */ |
455 | ieee80211_bss_info_change_notify(sdata, | 456 | ieee80211_bss_info_change_notify(sdata, |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index b510721e3b3d..31afd712930d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -195,7 +195,7 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, | |||
195 | assert_key_lock(sdata->local); | 195 | assert_key_lock(sdata->local); |
196 | 196 | ||
197 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) | 197 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) |
198 | key = sdata->keys[idx]; | 198 | key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
199 | 199 | ||
200 | if (uni) | 200 | if (uni) |
201 | rcu_assign_pointer(sdata->default_unicast_key, key); | 201 | rcu_assign_pointer(sdata->default_unicast_key, key); |
@@ -222,7 +222,7 @@ __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx) | |||
222 | 222 | ||
223 | if (idx >= NUM_DEFAULT_KEYS && | 223 | if (idx >= NUM_DEFAULT_KEYS && |
224 | idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) | 224 | idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) |
225 | key = sdata->keys[idx]; | 225 | key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
226 | 226 | ||
227 | rcu_assign_pointer(sdata->default_mgmt_key, key); | 227 | rcu_assign_pointer(sdata->default_mgmt_key, key); |
228 | 228 | ||
@@ -266,9 +266,15 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
266 | else | 266 | else |
267 | idx = new->conf.keyidx; | 267 | idx = new->conf.keyidx; |
268 | 268 | ||
269 | defunikey = old && sdata->default_unicast_key == old; | 269 | defunikey = old && |
270 | defmultikey = old && sdata->default_multicast_key == old; | 270 | old == key_mtx_dereference(sdata->local, |
271 | defmgmtkey = old && sdata->default_mgmt_key == old; | 271 | sdata->default_unicast_key); |
272 | defmultikey = old && | ||
273 | old == key_mtx_dereference(sdata->local, | ||
274 | sdata->default_multicast_key); | ||
275 | defmgmtkey = old && | ||
276 | old == key_mtx_dereference(sdata->local, | ||
277 | sdata->default_mgmt_key); | ||
272 | 278 | ||
273 | if (defunikey && !new) | 279 | if (defunikey && !new) |
274 | __ieee80211_set_default_key(sdata, -1, true, false); | 280 | __ieee80211_set_default_key(sdata, -1, true, false); |
@@ -451,11 +457,11 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
451 | mutex_lock(&sdata->local->key_mtx); | 457 | mutex_lock(&sdata->local->key_mtx); |
452 | 458 | ||
453 | if (sta && pairwise) | 459 | if (sta && pairwise) |
454 | old_key = sta->ptk; | 460 | old_key = key_mtx_dereference(sdata->local, sta->ptk); |
455 | else if (sta) | 461 | else if (sta) |
456 | old_key = sta->gtk[idx]; | 462 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); |
457 | else | 463 | else |
458 | old_key = sdata->keys[idx]; | 464 | old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
459 | 465 | ||
460 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); | 466 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); |
461 | __ieee80211_key_destroy(old_key); | 467 | __ieee80211_key_destroy(old_key); |
@@ -471,8 +477,11 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
471 | return ret; | 477 | return ret; |
472 | } | 478 | } |
473 | 479 | ||
474 | static void __ieee80211_key_free(struct ieee80211_key *key) | 480 | void __ieee80211_key_free(struct ieee80211_key *key) |
475 | { | 481 | { |
482 | if (!key) | ||
483 | return; | ||
484 | |||
476 | /* | 485 | /* |
477 | * Replace key with nothingness if it was ever used. | 486 | * Replace key with nothingness if it was ever used. |
478 | */ | 487 | */ |
@@ -486,9 +495,6 @@ static void __ieee80211_key_free(struct ieee80211_key *key) | |||
486 | void ieee80211_key_free(struct ieee80211_local *local, | 495 | void ieee80211_key_free(struct ieee80211_local *local, |
487 | struct ieee80211_key *key) | 496 | struct ieee80211_key *key) |
488 | { | 497 | { |
489 | if (!key) | ||
490 | return; | ||
491 | |||
492 | mutex_lock(&local->key_mtx); | 498 | mutex_lock(&local->key_mtx); |
493 | __ieee80211_key_free(key); | 499 | __ieee80211_key_free(key); |
494 | mutex_unlock(&local->key_mtx); | 500 | mutex_unlock(&local->key_mtx); |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 4ddbe27eb570..d801d5351336 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -135,6 +135,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
135 | int __must_check ieee80211_key_link(struct ieee80211_key *key, | 135 | int __must_check ieee80211_key_link(struct ieee80211_key *key, |
136 | struct ieee80211_sub_if_data *sdata, | 136 | struct ieee80211_sub_if_data *sdata, |
137 | struct sta_info *sta); | 137 | struct sta_info *sta); |
138 | void __ieee80211_key_free(struct ieee80211_key *key); | ||
138 | void ieee80211_key_free(struct ieee80211_local *local, | 139 | void ieee80211_key_free(struct ieee80211_local *local, |
139 | struct ieee80211_key *key); | 140 | struct ieee80211_key *key); |
140 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, | 141 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, |
@@ -145,4 +146,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); | |||
145 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); | 146 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); |
146 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); | 147 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); |
147 | 148 | ||
149 | #define key_mtx_dereference(local, ref) \ | ||
150 | rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx))) | ||
151 | |||
148 | #endif /* IEEE80211_KEY_H */ | 152 | #endif /* IEEE80211_KEY_H */ |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 61877662e8f8..0d7b08db8e56 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -358,7 +358,8 @@ static void ieee80211_restart_work(struct work_struct *work) | |||
358 | flush_workqueue(local->workqueue); | 358 | flush_workqueue(local->workqueue); |
359 | 359 | ||
360 | mutex_lock(&local->mtx); | 360 | mutex_lock(&local->mtx); |
361 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), | 361 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || |
362 | local->sched_scanning, | ||
362 | "%s called with hardware scan in progress\n", __func__); | 363 | "%s called with hardware scan in progress\n", __func__); |
363 | mutex_unlock(&local->mtx); | 364 | mutex_unlock(&local->mtx); |
364 | 365 | ||
@@ -580,8 +581,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
580 | 581 | ||
581 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | | 582 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | |
582 | WIPHY_FLAG_4ADDR_AP | | 583 | WIPHY_FLAG_4ADDR_AP | |
583 | WIPHY_FLAG_4ADDR_STATION | | 584 | WIPHY_FLAG_4ADDR_STATION; |
584 | WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS; | ||
585 | 585 | ||
586 | if (!ops->set_key) | 586 | if (!ops->set_key) |
587 | wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | 587 | wiphy->flags |= WIPHY_FLAG_IBSS_RSN; |
@@ -652,6 +652,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
652 | setup_timer(&local->dynamic_ps_timer, | 652 | setup_timer(&local->dynamic_ps_timer, |
653 | ieee80211_dynamic_ps_timer, (unsigned long) local); | 653 | ieee80211_dynamic_ps_timer, (unsigned long) local); |
654 | 654 | ||
655 | INIT_WORK(&local->sched_scan_stopped_work, | ||
656 | ieee80211_sched_scan_stopped_work); | ||
657 | |||
655 | sta_info_init(local); | 658 | sta_info_init(local); |
656 | 659 | ||
657 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { | 660 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { |
@@ -682,7 +685,7 @@ EXPORT_SYMBOL(ieee80211_alloc_hw); | |||
682 | int ieee80211_register_hw(struct ieee80211_hw *hw) | 685 | int ieee80211_register_hw(struct ieee80211_hw *hw) |
683 | { | 686 | { |
684 | struct ieee80211_local *local = hw_to_local(hw); | 687 | struct ieee80211_local *local = hw_to_local(hw); |
685 | int result; | 688 | int result, i; |
686 | enum ieee80211_band band; | 689 | enum ieee80211_band band; |
687 | int channels, max_bitrates; | 690 | int channels, max_bitrates; |
688 | bool supp_ht; | 691 | bool supp_ht; |
@@ -697,6 +700,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
697 | WLAN_CIPHER_SUITE_AES_CMAC | 700 | WLAN_CIPHER_SUITE_AES_CMAC |
698 | }; | 701 | }; |
699 | 702 | ||
703 | if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) | ||
704 | #ifdef CONFIG_PM | ||
705 | && (!local->ops->suspend || !local->ops->resume) | ||
706 | #endif | ||
707 | ) | ||
708 | return -EINVAL; | ||
709 | |||
700 | if (hw->max_report_rates == 0) | 710 | if (hw->max_report_rates == 0) |
701 | hw->max_report_rates = hw->max_rates; | 711 | hw->max_report_rates = hw->max_rates; |
702 | 712 | ||
@@ -733,11 +743,19 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
733 | return -ENOMEM; | 743 | return -ENOMEM; |
734 | 744 | ||
735 | /* if low-level driver supports AP, we also support VLAN */ | 745 | /* if low-level driver supports AP, we also support VLAN */ |
736 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) | 746 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { |
737 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); | 747 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); |
748 | hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN); | ||
749 | } | ||
738 | 750 | ||
739 | /* mac80211 always supports monitor */ | 751 | /* mac80211 always supports monitor */ |
740 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | 752 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); |
753 | hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); | ||
754 | |||
755 | /* mac80211 doesn't support more than 1 channel */ | ||
756 | for (i = 0; i < hw->wiphy->n_iface_combinations; i++) | ||
757 | if (hw->wiphy->iface_combinations[i].num_different_channels > 1) | ||
758 | return -EINVAL; | ||
741 | 759 | ||
742 | #ifndef CONFIG_MAC80211_MESH | 760 | #ifndef CONFIG_MAC80211_MESH |
743 | /* mesh depends on Kconfig, but drivers should set it if they want */ | 761 | /* mesh depends on Kconfig, but drivers should set it if they want */ |
@@ -827,6 +845,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
827 | if (!local->ops->remain_on_channel) | 845 | if (!local->ops->remain_on_channel) |
828 | local->hw.wiphy->max_remain_on_channel_duration = 5000; | 846 | local->hw.wiphy->max_remain_on_channel_duration = 5000; |
829 | 847 | ||
848 | if (local->ops->sched_scan_start) | ||
849 | local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | ||
850 | |||
830 | result = wiphy_register(local->hw.wiphy); | 851 | result = wiphy_register(local->hw.wiphy); |
831 | if (result < 0) | 852 | if (result < 0) |
832 | goto fail_wiphy_register; | 853 | goto fail_wiphy_register; |
@@ -850,8 +871,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
850 | * and we need some headroom for passing the frame to monitor | 871 | * and we need some headroom for passing the frame to monitor |
851 | * interfaces, but never both at the same time. | 872 | * interfaces, but never both at the same time. |
852 | */ | 873 | */ |
874 | #ifndef __CHECKER__ | ||
853 | BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM != | 875 | BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM != |
854 | sizeof(struct ieee80211_tx_status_rtap_hdr)); | 876 | sizeof(struct ieee80211_tx_status_rtap_hdr)); |
877 | #endif | ||
855 | local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, | 878 | local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, |
856 | sizeof(struct ieee80211_tx_status_rtap_hdr)); | 879 | sizeof(struct ieee80211_tx_status_rtap_hdr)); |
857 | 880 | ||
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index c1299e249541..29e9980c8e60 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -287,49 +287,6 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
287 | } | 287 | } |
288 | } | 288 | } |
289 | 289 | ||
290 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl) | ||
291 | { | ||
292 | /* Use last four bytes of hw addr and interface index as hash index */ | ||
293 | return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd) | ||
294 | & tbl->hash_mask; | ||
295 | } | ||
296 | |||
297 | struct mesh_table *mesh_table_alloc(int size_order) | ||
298 | { | ||
299 | int i; | ||
300 | struct mesh_table *newtbl; | ||
301 | |||
302 | newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL); | ||
303 | if (!newtbl) | ||
304 | return NULL; | ||
305 | |||
306 | newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) * | ||
307 | (1 << size_order), GFP_KERNEL); | ||
308 | |||
309 | if (!newtbl->hash_buckets) { | ||
310 | kfree(newtbl); | ||
311 | return NULL; | ||
312 | } | ||
313 | |||
314 | newtbl->hashwlock = kmalloc(sizeof(spinlock_t) * | ||
315 | (1 << size_order), GFP_KERNEL); | ||
316 | if (!newtbl->hashwlock) { | ||
317 | kfree(newtbl->hash_buckets); | ||
318 | kfree(newtbl); | ||
319 | return NULL; | ||
320 | } | ||
321 | |||
322 | newtbl->size_order = size_order; | ||
323 | newtbl->hash_mask = (1 << size_order) - 1; | ||
324 | atomic_set(&newtbl->entries, 0); | ||
325 | get_random_bytes(&newtbl->hash_rnd, | ||
326 | sizeof(newtbl->hash_rnd)); | ||
327 | for (i = 0; i <= newtbl->hash_mask; i++) | ||
328 | spin_lock_init(&newtbl->hashwlock[i]); | ||
329 | |||
330 | return newtbl; | ||
331 | } | ||
332 | |||
333 | 290 | ||
334 | static void ieee80211_mesh_path_timer(unsigned long data) | 291 | static void ieee80211_mesh_path_timer(unsigned long data) |
335 | { | 292 | { |
@@ -574,7 +531,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
574 | &elems); | 531 | &elems); |
575 | 532 | ||
576 | /* ignore beacons from secure mesh peers if our security is off */ | 533 | /* ignore beacons from secure mesh peers if our security is off */ |
577 | if (elems.rsn_len && !sdata->u.mesh.is_secure) | 534 | if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) |
578 | return; | 535 | return; |
579 | 536 | ||
580 | if (elems.ds_params && elems.ds_params_len == 1) | 537 | if (elems.ds_params && elems.ds_params_len == 1) |
@@ -600,7 +557,7 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | |||
600 | struct ieee80211_rx_status *rx_status) | 557 | struct ieee80211_rx_status *rx_status) |
601 | { | 558 | { |
602 | switch (mgmt->u.action.category) { | 559 | switch (mgmt->u.action.category) { |
603 | case WLAN_CATEGORY_MESH_PLINK: | 560 | case WLAN_CATEGORY_MESH_ACTION: |
604 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | 561 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); |
605 | break; | 562 | break; |
606 | case WLAN_CATEGORY_MESH_PATH_SEL: | 563 | case WLAN_CATEGORY_MESH_PATH_SEL: |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 10acf1cc8082..e7c5fddb4804 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -92,7 +92,7 @@ struct mesh_path { | |||
92 | u8 dst[ETH_ALEN]; | 92 | u8 dst[ETH_ALEN]; |
93 | u8 mpp[ETH_ALEN]; /* used for MPP or MAP */ | 93 | u8 mpp[ETH_ALEN]; /* used for MPP or MAP */ |
94 | struct ieee80211_sub_if_data *sdata; | 94 | struct ieee80211_sub_if_data *sdata; |
95 | struct sta_info *next_hop; | 95 | struct sta_info __rcu *next_hop; |
96 | struct timer_list timer; | 96 | struct timer_list timer; |
97 | struct sk_buff_head frame_queue; | 97 | struct sk_buff_head frame_queue; |
98 | struct rcu_head rcu; | 98 | struct rcu_head rcu; |
@@ -240,12 +240,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
240 | 240 | ||
241 | /* Private interfaces */ | 241 | /* Private interfaces */ |
242 | /* Mesh tables */ | 242 | /* Mesh tables */ |
243 | struct mesh_table *mesh_table_alloc(int size_order); | ||
244 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs); | ||
245 | void mesh_mpath_table_grow(void); | 243 | void mesh_mpath_table_grow(void); |
246 | void mesh_mpp_table_grow(void); | 244 | void mesh_mpp_table_grow(void); |
247 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | ||
248 | struct mesh_table *tbl); | ||
249 | /* Mesh paths */ | 245 | /* Mesh paths */ |
250 | int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode, | 246 | int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode, |
251 | const u8 *ra, struct ieee80211_sub_if_data *sdata); | 247 | const u8 *ra, struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index e57f2e728cfe..2b18053070c1 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -391,7 +391,6 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
391 | (mpath->flags & MESH_PATH_SN_VALID)) { | 391 | (mpath->flags & MESH_PATH_SN_VALID)) { |
392 | if (SN_GT(mpath->sn, orig_sn) || | 392 | if (SN_GT(mpath->sn, orig_sn) || |
393 | (mpath->sn == orig_sn && | 393 | (mpath->sn == orig_sn && |
394 | action == MPATH_PREQ && | ||
395 | new_metric >= mpath->metric)) { | 394 | new_metric >= mpath->metric)) { |
396 | process = false; | 395 | process = false; |
397 | fresh_info = false; | 396 | fresh_info = false; |
@@ -561,6 +560,14 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
561 | } | 560 | } |
562 | 561 | ||
563 | 562 | ||
563 | static inline struct sta_info * | ||
564 | next_hop_deref_protected(struct mesh_path *mpath) | ||
565 | { | ||
566 | return rcu_dereference_protected(mpath->next_hop, | ||
567 | lockdep_is_held(&mpath->state_lock)); | ||
568 | } | ||
569 | |||
570 | |||
564 | static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | 571 | static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, |
565 | struct ieee80211_mgmt *mgmt, | 572 | struct ieee80211_mgmt *mgmt, |
566 | u8 *prep_elem, u32 metric) | 573 | u8 *prep_elem, u32 metric) |
@@ -600,7 +607,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
600 | spin_unlock_bh(&mpath->state_lock); | 607 | spin_unlock_bh(&mpath->state_lock); |
601 | goto fail; | 608 | goto fail; |
602 | } | 609 | } |
603 | memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); | 610 | memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN); |
604 | spin_unlock_bh(&mpath->state_lock); | 611 | spin_unlock_bh(&mpath->state_lock); |
605 | --ttl; | 612 | --ttl; |
606 | flags = PREP_IE_FLAGS(prep_elem); | 613 | flags = PREP_IE_FLAGS(prep_elem); |
@@ -652,7 +659,8 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | |||
652 | if (mpath) { | 659 | if (mpath) { |
653 | spin_lock_bh(&mpath->state_lock); | 660 | spin_lock_bh(&mpath->state_lock); |
654 | if (mpath->flags & MESH_PATH_ACTIVE && | 661 | if (mpath->flags & MESH_PATH_ACTIVE && |
655 | memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 && | 662 | memcmp(ta, next_hop_deref_protected(mpath)->sta.addr, |
663 | ETH_ALEN) == 0 && | ||
656 | (!(mpath->flags & MESH_PATH_SN_VALID) || | 664 | (!(mpath->flags & MESH_PATH_SN_VALID) || |
657 | SN_GT(target_sn, mpath->sn))) { | 665 | SN_GT(target_sn, mpath->sn))) { |
658 | mpath->flags &= ~MESH_PATH_ACTIVE; | 666 | mpath->flags &= ~MESH_PATH_ACTIVE; |
@@ -914,6 +922,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
914 | { | 922 | { |
915 | struct sk_buff *skb_to_free = NULL; | 923 | struct sk_buff *skb_to_free = NULL; |
916 | struct mesh_path *mpath; | 924 | struct mesh_path *mpath; |
925 | struct sta_info *next_hop; | ||
917 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 926 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
918 | u8 *target_addr = hdr->addr3; | 927 | u8 *target_addr = hdr->addr3; |
919 | int err = 0; | 928 | int err = 0; |
@@ -941,7 +950,11 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
941 | mesh_queue_preq(mpath, | 950 | mesh_queue_preq(mpath, |
942 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); | 951 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); |
943 | } | 952 | } |
944 | memcpy(hdr->addr1, mpath->next_hop->sta.addr, ETH_ALEN); | 953 | next_hop = rcu_dereference(mpath->next_hop); |
954 | if (next_hop) | ||
955 | memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN); | ||
956 | else | ||
957 | err = -ENOENT; | ||
945 | } else { | 958 | } else { |
946 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 959 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
947 | if (!(mpath->flags & MESH_PATH_RESOLVING)) { | 960 | if (!(mpath->flags & MESH_PATH_RESOLVING)) { |
@@ -967,20 +980,11 @@ endlookup: | |||
967 | 980 | ||
968 | void mesh_path_timer(unsigned long data) | 981 | void mesh_path_timer(unsigned long data) |
969 | { | 982 | { |
970 | struct ieee80211_sub_if_data *sdata; | 983 | struct mesh_path *mpath = (void *) data; |
971 | struct mesh_path *mpath; | 984 | struct ieee80211_sub_if_data *sdata = mpath->sdata; |
972 | |||
973 | rcu_read_lock(); | ||
974 | mpath = (struct mesh_path *) data; | ||
975 | mpath = rcu_dereference(mpath); | ||
976 | if (!mpath) | ||
977 | goto endmpathtimer; | ||
978 | sdata = mpath->sdata; | ||
979 | 985 | ||
980 | if (sdata->local->quiescing) { | 986 | if (sdata->local->quiescing) |
981 | rcu_read_unlock(); | ||
982 | return; | 987 | return; |
983 | } | ||
984 | 988 | ||
985 | spin_lock_bh(&mpath->state_lock); | 989 | spin_lock_bh(&mpath->state_lock); |
986 | if (mpath->flags & MESH_PATH_RESOLVED || | 990 | if (mpath->flags & MESH_PATH_RESOLVED || |
@@ -997,8 +1001,6 @@ void mesh_path_timer(unsigned long data) | |||
997 | } | 1001 | } |
998 | 1002 | ||
999 | spin_unlock_bh(&mpath->state_lock); | 1003 | spin_unlock_bh(&mpath->state_lock); |
1000 | endmpathtimer: | ||
1001 | rcu_read_unlock(); | ||
1002 | } | 1004 | } |
1003 | 1005 | ||
1004 | void | 1006 | void |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 35c715adaae2..83ce48e31913 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -40,6 +40,50 @@ static struct mesh_table *mesh_paths; | |||
40 | static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ | 40 | static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ |
41 | 41 | ||
42 | int mesh_paths_generation; | 42 | int mesh_paths_generation; |
43 | |||
44 | /* This lock will have the grow table function as writer and add / delete nodes | ||
45 | * as readers. When reading the table (i.e. doing lookups) we are well protected | ||
46 | * by RCU | ||
47 | */ | ||
48 | static DEFINE_RWLOCK(pathtbl_resize_lock); | ||
49 | |||
50 | |||
51 | static struct mesh_table *mesh_table_alloc(int size_order) | ||
52 | { | ||
53 | int i; | ||
54 | struct mesh_table *newtbl; | ||
55 | |||
56 | newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL); | ||
57 | if (!newtbl) | ||
58 | return NULL; | ||
59 | |||
60 | newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) * | ||
61 | (1 << size_order), GFP_KERNEL); | ||
62 | |||
63 | if (!newtbl->hash_buckets) { | ||
64 | kfree(newtbl); | ||
65 | return NULL; | ||
66 | } | ||
67 | |||
68 | newtbl->hashwlock = kmalloc(sizeof(spinlock_t) * | ||
69 | (1 << size_order), GFP_KERNEL); | ||
70 | if (!newtbl->hashwlock) { | ||
71 | kfree(newtbl->hash_buckets); | ||
72 | kfree(newtbl); | ||
73 | return NULL; | ||
74 | } | ||
75 | |||
76 | newtbl->size_order = size_order; | ||
77 | newtbl->hash_mask = (1 << size_order) - 1; | ||
78 | atomic_set(&newtbl->entries, 0); | ||
79 | get_random_bytes(&newtbl->hash_rnd, | ||
80 | sizeof(newtbl->hash_rnd)); | ||
81 | for (i = 0; i <= newtbl->hash_mask; i++) | ||
82 | spin_lock_init(&newtbl->hashwlock[i]); | ||
83 | |||
84 | return newtbl; | ||
85 | } | ||
86 | |||
43 | static void __mesh_table_free(struct mesh_table *tbl) | 87 | static void __mesh_table_free(struct mesh_table *tbl) |
44 | { | 88 | { |
45 | kfree(tbl->hash_buckets); | 89 | kfree(tbl->hash_buckets); |
@@ -47,7 +91,7 @@ static void __mesh_table_free(struct mesh_table *tbl) | |||
47 | kfree(tbl); | 91 | kfree(tbl); |
48 | } | 92 | } |
49 | 93 | ||
50 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs) | 94 | static void mesh_table_free(struct mesh_table *tbl, bool free_leafs) |
51 | { | 95 | { |
52 | struct hlist_head *mesh_hash; | 96 | struct hlist_head *mesh_hash; |
53 | struct hlist_node *p, *q; | 97 | struct hlist_node *p, *q; |
@@ -55,18 +99,18 @@ void mesh_table_free(struct mesh_table *tbl, bool free_leafs) | |||
55 | 99 | ||
56 | mesh_hash = tbl->hash_buckets; | 100 | mesh_hash = tbl->hash_buckets; |
57 | for (i = 0; i <= tbl->hash_mask; i++) { | 101 | for (i = 0; i <= tbl->hash_mask; i++) { |
58 | spin_lock(&tbl->hashwlock[i]); | 102 | spin_lock_bh(&tbl->hashwlock[i]); |
59 | hlist_for_each_safe(p, q, &mesh_hash[i]) { | 103 | hlist_for_each_safe(p, q, &mesh_hash[i]) { |
60 | tbl->free_node(p, free_leafs); | 104 | tbl->free_node(p, free_leafs); |
61 | atomic_dec(&tbl->entries); | 105 | atomic_dec(&tbl->entries); |
62 | } | 106 | } |
63 | spin_unlock(&tbl->hashwlock[i]); | 107 | spin_unlock_bh(&tbl->hashwlock[i]); |
64 | } | 108 | } |
65 | __mesh_table_free(tbl); | 109 | __mesh_table_free(tbl); |
66 | } | 110 | } |
67 | 111 | ||
68 | static int mesh_table_grow(struct mesh_table *oldtbl, | 112 | static int mesh_table_grow(struct mesh_table *oldtbl, |
69 | struct mesh_table *newtbl) | 113 | struct mesh_table *newtbl) |
70 | { | 114 | { |
71 | struct hlist_head *oldhash; | 115 | struct hlist_head *oldhash; |
72 | struct hlist_node *p, *q; | 116 | struct hlist_node *p, *q; |
@@ -76,7 +120,6 @@ static int mesh_table_grow(struct mesh_table *oldtbl, | |||
76 | < oldtbl->mean_chain_len * (oldtbl->hash_mask + 1)) | 120 | < oldtbl->mean_chain_len * (oldtbl->hash_mask + 1)) |
77 | return -EAGAIN; | 121 | return -EAGAIN; |
78 | 122 | ||
79 | |||
80 | newtbl->free_node = oldtbl->free_node; | 123 | newtbl->free_node = oldtbl->free_node; |
81 | newtbl->mean_chain_len = oldtbl->mean_chain_len; | 124 | newtbl->mean_chain_len = oldtbl->mean_chain_len; |
82 | newtbl->copy_node = oldtbl->copy_node; | 125 | newtbl->copy_node = oldtbl->copy_node; |
@@ -98,12 +141,14 @@ errcopy: | |||
98 | return -ENOMEM; | 141 | return -ENOMEM; |
99 | } | 142 | } |
100 | 143 | ||
144 | static u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | ||
145 | struct mesh_table *tbl) | ||
146 | { | ||
147 | /* Use last four bytes of hw addr and interface index as hash index */ | ||
148 | return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd) | ||
149 | & tbl->hash_mask; | ||
150 | } | ||
101 | 151 | ||
102 | /* This lock will have the grow table function as writer and add / delete nodes | ||
103 | * as readers. When reading the table (i.e. doing lookups) we are well protected | ||
104 | * by RCU | ||
105 | */ | ||
106 | static DEFINE_RWLOCK(pathtbl_resize_lock); | ||
107 | 152 | ||
108 | /** | 153 | /** |
109 | * | 154 | * |
@@ -275,7 +320,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
275 | if (!new_node) | 320 | if (!new_node) |
276 | goto err_node_alloc; | 321 | goto err_node_alloc; |
277 | 322 | ||
278 | read_lock(&pathtbl_resize_lock); | 323 | read_lock_bh(&pathtbl_resize_lock); |
279 | memcpy(new_mpath->dst, dst, ETH_ALEN); | 324 | memcpy(new_mpath->dst, dst, ETH_ALEN); |
280 | new_mpath->sdata = sdata; | 325 | new_mpath->sdata = sdata; |
281 | new_mpath->flags = 0; | 326 | new_mpath->flags = 0; |
@@ -290,7 +335,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
290 | hash_idx = mesh_table_hash(dst, sdata, mesh_paths); | 335 | hash_idx = mesh_table_hash(dst, sdata, mesh_paths); |
291 | bucket = &mesh_paths->hash_buckets[hash_idx]; | 336 | bucket = &mesh_paths->hash_buckets[hash_idx]; |
292 | 337 | ||
293 | spin_lock(&mesh_paths->hashwlock[hash_idx]); | 338 | spin_lock_bh(&mesh_paths->hashwlock[hash_idx]); |
294 | 339 | ||
295 | err = -EEXIST; | 340 | err = -EEXIST; |
296 | hlist_for_each_entry(node, n, bucket, list) { | 341 | hlist_for_each_entry(node, n, bucket, list) { |
@@ -306,8 +351,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
306 | 351 | ||
307 | mesh_paths_generation++; | 352 | mesh_paths_generation++; |
308 | 353 | ||
309 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 354 | spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]); |
310 | read_unlock(&pathtbl_resize_lock); | 355 | read_unlock_bh(&pathtbl_resize_lock); |
311 | if (grow) { | 356 | if (grow) { |
312 | set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); | 357 | set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); |
313 | ieee80211_queue_work(&local->hw, &sdata->work); | 358 | ieee80211_queue_work(&local->hw, &sdata->work); |
@@ -315,8 +360,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
315 | return 0; | 360 | return 0; |
316 | 361 | ||
317 | err_exists: | 362 | err_exists: |
318 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 363 | spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]); |
319 | read_unlock(&pathtbl_resize_lock); | 364 | read_unlock_bh(&pathtbl_resize_lock); |
320 | kfree(new_node); | 365 | kfree(new_node); |
321 | err_node_alloc: | 366 | err_node_alloc: |
322 | kfree(new_mpath); | 367 | kfree(new_mpath); |
@@ -329,18 +374,21 @@ void mesh_mpath_table_grow(void) | |||
329 | { | 374 | { |
330 | struct mesh_table *oldtbl, *newtbl; | 375 | struct mesh_table *oldtbl, *newtbl; |
331 | 376 | ||
332 | newtbl = mesh_table_alloc(mesh_paths->size_order + 1); | 377 | rcu_read_lock(); |
378 | newtbl = mesh_table_alloc(rcu_dereference(mesh_paths)->size_order + 1); | ||
333 | if (!newtbl) | 379 | if (!newtbl) |
334 | return; | 380 | return; |
335 | write_lock(&pathtbl_resize_lock); | 381 | write_lock_bh(&pathtbl_resize_lock); |
336 | oldtbl = mesh_paths; | 382 | oldtbl = mesh_paths; |
337 | if (mesh_table_grow(mesh_paths, newtbl) < 0) { | 383 | if (mesh_table_grow(mesh_paths, newtbl) < 0) { |
384 | rcu_read_unlock(); | ||
338 | __mesh_table_free(newtbl); | 385 | __mesh_table_free(newtbl); |
339 | write_unlock(&pathtbl_resize_lock); | 386 | write_unlock_bh(&pathtbl_resize_lock); |
340 | return; | 387 | return; |
341 | } | 388 | } |
389 | rcu_read_unlock(); | ||
342 | rcu_assign_pointer(mesh_paths, newtbl); | 390 | rcu_assign_pointer(mesh_paths, newtbl); |
343 | write_unlock(&pathtbl_resize_lock); | 391 | write_unlock_bh(&pathtbl_resize_lock); |
344 | 392 | ||
345 | synchronize_rcu(); | 393 | synchronize_rcu(); |
346 | mesh_table_free(oldtbl, false); | 394 | mesh_table_free(oldtbl, false); |
@@ -350,18 +398,21 @@ void mesh_mpp_table_grow(void) | |||
350 | { | 398 | { |
351 | struct mesh_table *oldtbl, *newtbl; | 399 | struct mesh_table *oldtbl, *newtbl; |
352 | 400 | ||
353 | newtbl = mesh_table_alloc(mpp_paths->size_order + 1); | 401 | rcu_read_lock(); |
402 | newtbl = mesh_table_alloc(rcu_dereference(mpp_paths)->size_order + 1); | ||
354 | if (!newtbl) | 403 | if (!newtbl) |
355 | return; | 404 | return; |
356 | write_lock(&pathtbl_resize_lock); | 405 | write_lock_bh(&pathtbl_resize_lock); |
357 | oldtbl = mpp_paths; | 406 | oldtbl = mpp_paths; |
358 | if (mesh_table_grow(mpp_paths, newtbl) < 0) { | 407 | if (mesh_table_grow(mpp_paths, newtbl) < 0) { |
408 | rcu_read_unlock(); | ||
359 | __mesh_table_free(newtbl); | 409 | __mesh_table_free(newtbl); |
360 | write_unlock(&pathtbl_resize_lock); | 410 | write_unlock_bh(&pathtbl_resize_lock); |
361 | return; | 411 | return; |
362 | } | 412 | } |
413 | rcu_read_unlock(); | ||
363 | rcu_assign_pointer(mpp_paths, newtbl); | 414 | rcu_assign_pointer(mpp_paths, newtbl); |
364 | write_unlock(&pathtbl_resize_lock); | 415 | write_unlock_bh(&pathtbl_resize_lock); |
365 | 416 | ||
366 | synchronize_rcu(); | 417 | synchronize_rcu(); |
367 | mesh_table_free(oldtbl, false); | 418 | mesh_table_free(oldtbl, false); |
@@ -395,7 +446,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
395 | if (!new_node) | 446 | if (!new_node) |
396 | goto err_node_alloc; | 447 | goto err_node_alloc; |
397 | 448 | ||
398 | read_lock(&pathtbl_resize_lock); | 449 | read_lock_bh(&pathtbl_resize_lock); |
399 | memcpy(new_mpath->dst, dst, ETH_ALEN); | 450 | memcpy(new_mpath->dst, dst, ETH_ALEN); |
400 | memcpy(new_mpath->mpp, mpp, ETH_ALEN); | 451 | memcpy(new_mpath->mpp, mpp, ETH_ALEN); |
401 | new_mpath->sdata = sdata; | 452 | new_mpath->sdata = sdata; |
@@ -408,7 +459,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
408 | hash_idx = mesh_table_hash(dst, sdata, mpp_paths); | 459 | hash_idx = mesh_table_hash(dst, sdata, mpp_paths); |
409 | bucket = &mpp_paths->hash_buckets[hash_idx]; | 460 | bucket = &mpp_paths->hash_buckets[hash_idx]; |
410 | 461 | ||
411 | spin_lock(&mpp_paths->hashwlock[hash_idx]); | 462 | spin_lock_bh(&mpp_paths->hashwlock[hash_idx]); |
412 | 463 | ||
413 | err = -EEXIST; | 464 | err = -EEXIST; |
414 | hlist_for_each_entry(node, n, bucket, list) { | 465 | hlist_for_each_entry(node, n, bucket, list) { |
@@ -422,8 +473,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
422 | mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1)) | 473 | mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1)) |
423 | grow = 1; | 474 | grow = 1; |
424 | 475 | ||
425 | spin_unlock(&mpp_paths->hashwlock[hash_idx]); | 476 | spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]); |
426 | read_unlock(&pathtbl_resize_lock); | 477 | read_unlock_bh(&pathtbl_resize_lock); |
427 | if (grow) { | 478 | if (grow) { |
428 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); | 479 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); |
429 | ieee80211_queue_work(&local->hw, &sdata->work); | 480 | ieee80211_queue_work(&local->hw, &sdata->work); |
@@ -431,8 +482,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
431 | return 0; | 482 | return 0; |
432 | 483 | ||
433 | err_exists: | 484 | err_exists: |
434 | spin_unlock(&mpp_paths->hashwlock[hash_idx]); | 485 | spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]); |
435 | read_unlock(&pathtbl_resize_lock); | 486 | read_unlock_bh(&pathtbl_resize_lock); |
436 | kfree(new_node); | 487 | kfree(new_node); |
437 | err_node_alloc: | 488 | err_node_alloc: |
438 | kfree(new_mpath); | 489 | kfree(new_mpath); |
@@ -545,11 +596,11 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) | |||
545 | int hash_idx; | 596 | int hash_idx; |
546 | int err = 0; | 597 | int err = 0; |
547 | 598 | ||
548 | read_lock(&pathtbl_resize_lock); | 599 | read_lock_bh(&pathtbl_resize_lock); |
549 | hash_idx = mesh_table_hash(addr, sdata, mesh_paths); | 600 | hash_idx = mesh_table_hash(addr, sdata, mesh_paths); |
550 | bucket = &mesh_paths->hash_buckets[hash_idx]; | 601 | bucket = &mesh_paths->hash_buckets[hash_idx]; |
551 | 602 | ||
552 | spin_lock(&mesh_paths->hashwlock[hash_idx]); | 603 | spin_lock_bh(&mesh_paths->hashwlock[hash_idx]); |
553 | hlist_for_each_entry(node, n, bucket, list) { | 604 | hlist_for_each_entry(node, n, bucket, list) { |
554 | mpath = node->mpath; | 605 | mpath = node->mpath; |
555 | if (mpath->sdata == sdata && | 606 | if (mpath->sdata == sdata && |
@@ -567,8 +618,8 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) | |||
567 | err = -ENXIO; | 618 | err = -ENXIO; |
568 | enddel: | 619 | enddel: |
569 | mesh_paths_generation++; | 620 | mesh_paths_generation++; |
570 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 621 | spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]); |
571 | read_unlock(&pathtbl_resize_lock); | 622 | read_unlock_bh(&pathtbl_resize_lock); |
572 | return err; | 623 | return err; |
573 | } | 624 | } |
574 | 625 | ||
@@ -720,7 +771,7 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata) | |||
720 | struct hlist_node *p; | 771 | struct hlist_node *p; |
721 | int i; | 772 | int i; |
722 | 773 | ||
723 | read_lock(&pathtbl_resize_lock); | 774 | read_lock_bh(&pathtbl_resize_lock); |
724 | for_each_mesh_entry(mesh_paths, p, node, i) { | 775 | for_each_mesh_entry(mesh_paths, p, node, i) { |
725 | if (node->mpath->sdata != sdata) | 776 | if (node->mpath->sdata != sdata) |
726 | continue; | 777 | continue; |
@@ -735,7 +786,7 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata) | |||
735 | } else | 786 | } else |
736 | spin_unlock_bh(&mpath->state_lock); | 787 | spin_unlock_bh(&mpath->state_lock); |
737 | } | 788 | } |
738 | read_unlock(&pathtbl_resize_lock); | 789 | read_unlock_bh(&pathtbl_resize_lock); |
739 | } | 790 | } |
740 | 791 | ||
741 | void mesh_pathtbl_unregister(void) | 792 | void mesh_pathtbl_unregister(void) |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 84e5b056af02..f4adc0917888 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -43,7 +43,7 @@ | |||
43 | #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks) | 43 | #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks) |
44 | 44 | ||
45 | enum plink_frame_type { | 45 | enum plink_frame_type { |
46 | PLINK_OPEN = 0, | 46 | PLINK_OPEN = 1, |
47 | PLINK_CONFIRM, | 47 | PLINK_CONFIRM, |
48 | PLINK_CLOSE | 48 | PLINK_CLOSE |
49 | }; | 49 | }; |
@@ -83,7 +83,7 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | |||
83 | */ | 83 | */ |
84 | static inline void mesh_plink_fsm_restart(struct sta_info *sta) | 84 | static inline void mesh_plink_fsm_restart(struct sta_info *sta) |
85 | { | 85 | { |
86 | sta->plink_state = PLINK_LISTEN; | 86 | sta->plink_state = NL80211_PLINK_LISTEN; |
87 | sta->llid = sta->plid = sta->reason = 0; | 87 | sta->llid = sta->plid = sta->reason = 0; |
88 | sta->plink_retries = 0; | 88 | sta->plink_retries = 0; |
89 | } | 89 | } |
@@ -126,11 +126,11 @@ static bool __mesh_plink_deactivate(struct sta_info *sta) | |||
126 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 126 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
127 | bool deactivated = false; | 127 | bool deactivated = false; |
128 | 128 | ||
129 | if (sta->plink_state == PLINK_ESTAB) { | 129 | if (sta->plink_state == NL80211_PLINK_ESTAB) { |
130 | mesh_plink_dec_estab_count(sdata); | 130 | mesh_plink_dec_estab_count(sdata); |
131 | deactivated = true; | 131 | deactivated = true; |
132 | } | 132 | } |
133 | sta->plink_state = PLINK_BLOCKED; | 133 | sta->plink_state = NL80211_PLINK_BLOCKED; |
134 | mesh_path_flush_by_nexthop(sta); | 134 | mesh_path_flush_by_nexthop(sta); |
135 | 135 | ||
136 | return deactivated; | 136 | return deactivated; |
@@ -181,8 +181,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
181 | IEEE80211_STYPE_ACTION); | 181 | IEEE80211_STYPE_ACTION); |
182 | memcpy(mgmt->da, da, ETH_ALEN); | 182 | memcpy(mgmt->da, da, ETH_ALEN); |
183 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | 183 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
184 | /* BSSID is left zeroed, wildcard value */ | 184 | memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); |
185 | mgmt->u.action.category = WLAN_CATEGORY_MESH_PLINK; | 185 | mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION; |
186 | mgmt->u.action.u.plink_action.action_code = action; | 186 | mgmt->u.action.u.plink_action.action_code = action; |
187 | 187 | ||
188 | if (action == PLINK_CLOSE) | 188 | if (action == PLINK_CLOSE) |
@@ -251,7 +251,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, | |||
251 | rcu_read_unlock(); | 251 | rcu_read_unlock(); |
252 | /* Userspace handles peer allocation when security is enabled | 252 | /* Userspace handles peer allocation when security is enabled |
253 | * */ | 253 | * */ |
254 | if (sdata->u.mesh.is_secure) | 254 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) |
255 | cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, | 255 | cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, |
256 | elems->ie_start, elems->total_len, | 256 | elems->ie_start, elems->total_len, |
257 | GFP_KERNEL); | 257 | GFP_KERNEL); |
@@ -268,7 +268,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, | |||
268 | sta->last_rx = jiffies; | 268 | sta->last_rx = jiffies; |
269 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; | 269 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; |
270 | if (mesh_peer_accepts_plinks(elems) && | 270 | if (mesh_peer_accepts_plinks(elems) && |
271 | sta->plink_state == PLINK_LISTEN && | 271 | sta->plink_state == NL80211_PLINK_LISTEN && |
272 | sdata->u.mesh.accepting_plinks && | 272 | sdata->u.mesh.accepting_plinks && |
273 | sdata->u.mesh.mshcfg.auto_open_plinks) | 273 | sdata->u.mesh.mshcfg.auto_open_plinks) |
274 | mesh_plink_open(sta); | 274 | mesh_plink_open(sta); |
@@ -308,8 +308,8 @@ static void mesh_plink_timer(unsigned long data) | |||
308 | sdata = sta->sdata; | 308 | sdata = sta->sdata; |
309 | 309 | ||
310 | switch (sta->plink_state) { | 310 | switch (sta->plink_state) { |
311 | case PLINK_OPN_RCVD: | 311 | case NL80211_PLINK_OPN_RCVD: |
312 | case PLINK_OPN_SNT: | 312 | case NL80211_PLINK_OPN_SNT: |
313 | /* retry timer */ | 313 | /* retry timer */ |
314 | if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { | 314 | if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { |
315 | u32 rand; | 315 | u32 rand; |
@@ -328,17 +328,17 @@ static void mesh_plink_timer(unsigned long data) | |||
328 | } | 328 | } |
329 | reason = cpu_to_le16(MESH_MAX_RETRIES); | 329 | reason = cpu_to_le16(MESH_MAX_RETRIES); |
330 | /* fall through on else */ | 330 | /* fall through on else */ |
331 | case PLINK_CNF_RCVD: | 331 | case NL80211_PLINK_CNF_RCVD: |
332 | /* confirm timer */ | 332 | /* confirm timer */ |
333 | if (!reason) | 333 | if (!reason) |
334 | reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); | 334 | reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); |
335 | sta->plink_state = PLINK_HOLDING; | 335 | sta->plink_state = NL80211_PLINK_HOLDING; |
336 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 336 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
337 | spin_unlock_bh(&sta->lock); | 337 | spin_unlock_bh(&sta->lock); |
338 | mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid, | 338 | mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid, |
339 | reason); | 339 | reason); |
340 | break; | 340 | break; |
341 | case PLINK_HOLDING: | 341 | case NL80211_PLINK_HOLDING: |
342 | /* holding timer */ | 342 | /* holding timer */ |
343 | del_timer(&sta->plink_timer); | 343 | del_timer(&sta->plink_timer); |
344 | mesh_plink_fsm_restart(sta); | 344 | mesh_plink_fsm_restart(sta); |
@@ -386,11 +386,11 @@ int mesh_plink_open(struct sta_info *sta) | |||
386 | spin_lock_bh(&sta->lock); | 386 | spin_lock_bh(&sta->lock); |
387 | get_random_bytes(&llid, 2); | 387 | get_random_bytes(&llid, 2); |
388 | sta->llid = llid; | 388 | sta->llid = llid; |
389 | if (sta->plink_state != PLINK_LISTEN) { | 389 | if (sta->plink_state != NL80211_PLINK_LISTEN) { |
390 | spin_unlock_bh(&sta->lock); | 390 | spin_unlock_bh(&sta->lock); |
391 | return -EBUSY; | 391 | return -EBUSY; |
392 | } | 392 | } |
393 | sta->plink_state = PLINK_OPN_SNT; | 393 | sta->plink_state = NL80211_PLINK_OPN_SNT; |
394 | mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); | 394 | mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); |
395 | spin_unlock_bh(&sta->lock); | 395 | spin_unlock_bh(&sta->lock); |
396 | mpl_dbg("Mesh plink: starting establishment with %pM\n", | 396 | mpl_dbg("Mesh plink: starting establishment with %pM\n", |
@@ -407,7 +407,7 @@ void mesh_plink_block(struct sta_info *sta) | |||
407 | 407 | ||
408 | spin_lock_bh(&sta->lock); | 408 | spin_lock_bh(&sta->lock); |
409 | deactivated = __mesh_plink_deactivate(sta); | 409 | deactivated = __mesh_plink_deactivate(sta); |
410 | sta->plink_state = PLINK_BLOCKED; | 410 | sta->plink_state = NL80211_PLINK_BLOCKED; |
411 | spin_unlock_bh(&sta->lock); | 411 | spin_unlock_bh(&sta->lock); |
412 | 412 | ||
413 | if (deactivated) | 413 | if (deactivated) |
@@ -430,13 +430,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
430 | __le16 plid, llid, reason; | 430 | __le16 plid, llid, reason; |
431 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | 431 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG |
432 | static const char *mplstates[] = { | 432 | static const char *mplstates[] = { |
433 | [PLINK_LISTEN] = "LISTEN", | 433 | [NL80211_PLINK_LISTEN] = "LISTEN", |
434 | [PLINK_OPN_SNT] = "OPN-SNT", | 434 | [NL80211_PLINK_OPN_SNT] = "OPN-SNT", |
435 | [PLINK_OPN_RCVD] = "OPN-RCVD", | 435 | [NL80211_PLINK_OPN_RCVD] = "OPN-RCVD", |
436 | [PLINK_CNF_RCVD] = "CNF_RCVD", | 436 | [NL80211_PLINK_CNF_RCVD] = "CNF_RCVD", |
437 | [PLINK_ESTAB] = "ESTAB", | 437 | [NL80211_PLINK_ESTAB] = "ESTAB", |
438 | [PLINK_HOLDING] = "HOLDING", | 438 | [NL80211_PLINK_HOLDING] = "HOLDING", |
439 | [PLINK_BLOCKED] = "BLOCKED" | 439 | [NL80211_PLINK_BLOCKED] = "BLOCKED" |
440 | }; | 440 | }; |
441 | #endif | 441 | #endif |
442 | 442 | ||
@@ -460,7 +460,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
460 | mpl_dbg("Mesh plink: missing necessary peer link ie\n"); | 460 | mpl_dbg("Mesh plink: missing necessary peer link ie\n"); |
461 | return; | 461 | return; |
462 | } | 462 | } |
463 | if (elems.rsn_len && !sdata->u.mesh.is_secure) { | 463 | if (elems.rsn_len && |
464 | sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { | ||
464 | mpl_dbg("Mesh plink: can't establish link with secure peer\n"); | 465 | mpl_dbg("Mesh plink: can't establish link with secure peer\n"); |
465 | return; | 466 | return; |
466 | } | 467 | } |
@@ -501,7 +502,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
501 | return; | 502 | return; |
502 | } | 503 | } |
503 | 504 | ||
504 | if (sta && sta->plink_state == PLINK_BLOCKED) { | 505 | if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) { |
505 | rcu_read_unlock(); | 506 | rcu_read_unlock(); |
506 | return; | 507 | return; |
507 | } | 508 | } |
@@ -571,7 +572,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
571 | event = CNF_ACPT; | 572 | event = CNF_ACPT; |
572 | break; | 573 | break; |
573 | case PLINK_CLOSE: | 574 | case PLINK_CLOSE: |
574 | if (sta->plink_state == PLINK_ESTAB) | 575 | if (sta->plink_state == NL80211_PLINK_ESTAB) |
575 | /* Do not check for llid or plid. This does not | 576 | /* Do not check for llid or plid. This does not |
576 | * follow the standard but since multiple plinks | 577 | * follow the standard but since multiple plinks |
577 | * per sta are not supported, it is necessary in | 578 | * per sta are not supported, it is necessary in |
@@ -606,14 +607,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
606 | reason = 0; | 607 | reason = 0; |
607 | switch (sta->plink_state) { | 608 | switch (sta->plink_state) { |
608 | /* spin_unlock as soon as state is updated at each case */ | 609 | /* spin_unlock as soon as state is updated at each case */ |
609 | case PLINK_LISTEN: | 610 | case NL80211_PLINK_LISTEN: |
610 | switch (event) { | 611 | switch (event) { |
611 | case CLS_ACPT: | 612 | case CLS_ACPT: |
612 | mesh_plink_fsm_restart(sta); | 613 | mesh_plink_fsm_restart(sta); |
613 | spin_unlock_bh(&sta->lock); | 614 | spin_unlock_bh(&sta->lock); |
614 | break; | 615 | break; |
615 | case OPN_ACPT: | 616 | case OPN_ACPT: |
616 | sta->plink_state = PLINK_OPN_RCVD; | 617 | sta->plink_state = NL80211_PLINK_OPN_RCVD; |
617 | sta->plid = plid; | 618 | sta->plid = plid; |
618 | get_random_bytes(&llid, 2); | 619 | get_random_bytes(&llid, 2); |
619 | sta->llid = llid; | 620 | sta->llid = llid; |
@@ -630,7 +631,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
630 | } | 631 | } |
631 | break; | 632 | break; |
632 | 633 | ||
633 | case PLINK_OPN_SNT: | 634 | case NL80211_PLINK_OPN_SNT: |
634 | switch (event) { | 635 | switch (event) { |
635 | case OPN_RJCT: | 636 | case OPN_RJCT: |
636 | case CNF_RJCT: | 637 | case CNF_RJCT: |
@@ -639,7 +640,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
639 | if (!reason) | 640 | if (!reason) |
640 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 641 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
641 | sta->reason = reason; | 642 | sta->reason = reason; |
642 | sta->plink_state = PLINK_HOLDING; | 643 | sta->plink_state = NL80211_PLINK_HOLDING; |
643 | if (!mod_plink_timer(sta, | 644 | if (!mod_plink_timer(sta, |
644 | dot11MeshHoldingTimeout(sdata))) | 645 | dot11MeshHoldingTimeout(sdata))) |
645 | sta->ignore_plink_timer = true; | 646 | sta->ignore_plink_timer = true; |
@@ -651,7 +652,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
651 | break; | 652 | break; |
652 | case OPN_ACPT: | 653 | case OPN_ACPT: |
653 | /* retry timer is left untouched */ | 654 | /* retry timer is left untouched */ |
654 | sta->plink_state = PLINK_OPN_RCVD; | 655 | sta->plink_state = NL80211_PLINK_OPN_RCVD; |
655 | sta->plid = plid; | 656 | sta->plid = plid; |
656 | llid = sta->llid; | 657 | llid = sta->llid; |
657 | spin_unlock_bh(&sta->lock); | 658 | spin_unlock_bh(&sta->lock); |
@@ -659,7 +660,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
659 | plid, 0); | 660 | plid, 0); |
660 | break; | 661 | break; |
661 | case CNF_ACPT: | 662 | case CNF_ACPT: |
662 | sta->plink_state = PLINK_CNF_RCVD; | 663 | sta->plink_state = NL80211_PLINK_CNF_RCVD; |
663 | if (!mod_plink_timer(sta, | 664 | if (!mod_plink_timer(sta, |
664 | dot11MeshConfirmTimeout(sdata))) | 665 | dot11MeshConfirmTimeout(sdata))) |
665 | sta->ignore_plink_timer = true; | 666 | sta->ignore_plink_timer = true; |
@@ -672,7 +673,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
672 | } | 673 | } |
673 | break; | 674 | break; |
674 | 675 | ||
675 | case PLINK_OPN_RCVD: | 676 | case NL80211_PLINK_OPN_RCVD: |
676 | switch (event) { | 677 | switch (event) { |
677 | case OPN_RJCT: | 678 | case OPN_RJCT: |
678 | case CNF_RJCT: | 679 | case CNF_RJCT: |
@@ -681,7 +682,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
681 | if (!reason) | 682 | if (!reason) |
682 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 683 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
683 | sta->reason = reason; | 684 | sta->reason = reason; |
684 | sta->plink_state = PLINK_HOLDING; | 685 | sta->plink_state = NL80211_PLINK_HOLDING; |
685 | if (!mod_plink_timer(sta, | 686 | if (!mod_plink_timer(sta, |
686 | dot11MeshHoldingTimeout(sdata))) | 687 | dot11MeshHoldingTimeout(sdata))) |
687 | sta->ignore_plink_timer = true; | 688 | sta->ignore_plink_timer = true; |
@@ -699,7 +700,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
699 | break; | 700 | break; |
700 | case CNF_ACPT: | 701 | case CNF_ACPT: |
701 | del_timer(&sta->plink_timer); | 702 | del_timer(&sta->plink_timer); |
702 | sta->plink_state = PLINK_ESTAB; | 703 | sta->plink_state = NL80211_PLINK_ESTAB; |
703 | spin_unlock_bh(&sta->lock); | 704 | spin_unlock_bh(&sta->lock); |
704 | mesh_plink_inc_estab_count(sdata); | 705 | mesh_plink_inc_estab_count(sdata); |
705 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 706 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); |
@@ -712,7 +713,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
712 | } | 713 | } |
713 | break; | 714 | break; |
714 | 715 | ||
715 | case PLINK_CNF_RCVD: | 716 | case NL80211_PLINK_CNF_RCVD: |
716 | switch (event) { | 717 | switch (event) { |
717 | case OPN_RJCT: | 718 | case OPN_RJCT: |
718 | case CNF_RJCT: | 719 | case CNF_RJCT: |
@@ -721,7 +722,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
721 | if (!reason) | 722 | if (!reason) |
722 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 723 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
723 | sta->reason = reason; | 724 | sta->reason = reason; |
724 | sta->plink_state = PLINK_HOLDING; | 725 | sta->plink_state = NL80211_PLINK_HOLDING; |
725 | if (!mod_plink_timer(sta, | 726 | if (!mod_plink_timer(sta, |
726 | dot11MeshHoldingTimeout(sdata))) | 727 | dot11MeshHoldingTimeout(sdata))) |
727 | sta->ignore_plink_timer = true; | 728 | sta->ignore_plink_timer = true; |
@@ -733,7 +734,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
733 | break; | 734 | break; |
734 | case OPN_ACPT: | 735 | case OPN_ACPT: |
735 | del_timer(&sta->plink_timer); | 736 | del_timer(&sta->plink_timer); |
736 | sta->plink_state = PLINK_ESTAB; | 737 | sta->plink_state = NL80211_PLINK_ESTAB; |
737 | spin_unlock_bh(&sta->lock); | 738 | spin_unlock_bh(&sta->lock); |
738 | mesh_plink_inc_estab_count(sdata); | 739 | mesh_plink_inc_estab_count(sdata); |
739 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 740 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); |
@@ -748,13 +749,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
748 | } | 749 | } |
749 | break; | 750 | break; |
750 | 751 | ||
751 | case PLINK_ESTAB: | 752 | case NL80211_PLINK_ESTAB: |
752 | switch (event) { | 753 | switch (event) { |
753 | case CLS_ACPT: | 754 | case CLS_ACPT: |
754 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 755 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
755 | sta->reason = reason; | 756 | sta->reason = reason; |
756 | deactivated = __mesh_plink_deactivate(sta); | 757 | deactivated = __mesh_plink_deactivate(sta); |
757 | sta->plink_state = PLINK_HOLDING; | 758 | sta->plink_state = NL80211_PLINK_HOLDING; |
758 | llid = sta->llid; | 759 | llid = sta->llid; |
759 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 760 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
760 | spin_unlock_bh(&sta->lock); | 761 | spin_unlock_bh(&sta->lock); |
@@ -774,7 +775,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
774 | break; | 775 | break; |
775 | } | 776 | } |
776 | break; | 777 | break; |
777 | case PLINK_HOLDING: | 778 | case NL80211_PLINK_HOLDING: |
778 | switch (event) { | 779 | switch (event) { |
779 | case CLS_ACPT: | 780 | case CLS_ACPT: |
780 | if (del_timer(&sta->plink_timer)) | 781 | if (del_timer(&sta->plink_timer)) |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a41f234bd486..4f6b2675e41d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -750,6 +750,8 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
750 | dynamic_ps_enable_work); | 750 | dynamic_ps_enable_work); |
751 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; | 751 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; |
752 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 752 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
753 | unsigned long flags; | ||
754 | int q; | ||
753 | 755 | ||
754 | /* can only happen when PS was just disabled anyway */ | 756 | /* can only happen when PS was just disabled anyway */ |
755 | if (!sdata) | 757 | if (!sdata) |
@@ -758,6 +760,24 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
758 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 760 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
759 | return; | 761 | return; |
760 | 762 | ||
763 | /* | ||
764 | * transmission can be stopped by others which leads to | ||
765 | * dynamic_ps_timer expiry. Postpond the ps timer if it | ||
766 | * is not the actual idle state. | ||
767 | */ | ||
768 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
769 | for (q = 0; q < local->hw.queues; q++) { | ||
770 | if (local->queue_stop_reasons[q]) { | ||
771 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | ||
772 | flags); | ||
773 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
774 | msecs_to_jiffies( | ||
775 | local->hw.conf.dynamic_ps_timeout)); | ||
776 | return; | ||
777 | } | ||
778 | } | ||
779 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
780 | |||
761 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && | 781 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
762 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { | 782 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { |
763 | netif_tx_stop_all_queues(sdata->dev); | 783 | netif_tx_stop_all_queues(sdata->dev); |
@@ -781,7 +801,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
781 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 801 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
782 | } | 802 | } |
783 | 803 | ||
784 | netif_tx_start_all_queues(sdata->dev); | 804 | netif_tx_wake_all_queues(sdata->dev); |
785 | } | 805 | } |
786 | 806 | ||
787 | void ieee80211_dynamic_ps_timer(unsigned long data) | 807 | void ieee80211_dynamic_ps_timer(unsigned long data) |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 042461710880..730778a2c90c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -6,7 +6,7 @@ | |||
6 | #include "driver-ops.h" | 6 | #include "driver-ops.h" |
7 | #include "led.h" | 7 | #include "led.h" |
8 | 8 | ||
9 | int __ieee80211_suspend(struct ieee80211_hw *hw) | 9 | int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) |
10 | { | 10 | { |
11 | struct ieee80211_local *local = hw_to_local(hw); | 11 | struct ieee80211_local *local = hw_to_local(hw); |
12 | struct ieee80211_sub_if_data *sdata; | 12 | struct ieee80211_sub_if_data *sdata; |
@@ -47,6 +47,16 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
47 | cancel_work_sync(&local->dynamic_ps_enable_work); | 47 | cancel_work_sync(&local->dynamic_ps_enable_work); |
48 | del_timer_sync(&local->dynamic_ps_timer); | 48 | del_timer_sync(&local->dynamic_ps_timer); |
49 | 49 | ||
50 | local->wowlan = wowlan && local->open_count; | ||
51 | if (local->wowlan) { | ||
52 | int err = drv_suspend(local, wowlan); | ||
53 | if (err) { | ||
54 | local->quiescing = false; | ||
55 | return err; | ||
56 | } | ||
57 | goto suspend; | ||
58 | } | ||
59 | |||
50 | /* disable keys */ | 60 | /* disable keys */ |
51 | list_for_each_entry(sdata, &local->interfaces, list) | 61 | list_for_each_entry(sdata, &local->interfaces, list) |
52 | ieee80211_disable_keys(sdata); | 62 | ieee80211_disable_keys(sdata); |
@@ -104,6 +114,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
104 | if (local->open_count) | 114 | if (local->open_count) |
105 | ieee80211_stop_device(local); | 115 | ieee80211_stop_device(local); |
106 | 116 | ||
117 | suspend: | ||
107 | local->suspended = true; | 118 | local->suspended = true; |
108 | /* need suspended to be visible before quiescing is false */ | 119 | /* need suspended to be visible before quiescing is false */ |
109 | barrier(); | 120 | barrier(); |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 778c604d7939..8adac67395f7 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -417,8 +417,8 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
417 | tx_time_single = mr->ack_time + mr->perfect_tx_time; | 417 | tx_time_single = mr->ack_time + mr->perfect_tx_time; |
418 | 418 | ||
419 | /* contention window */ | 419 | /* contention window */ |
420 | tx_time_single += t_slot + min(cw, mp->cw_max); | 420 | tx_time_single += (t_slot * cw) >> 1; |
421 | cw = (cw << 1) | 1; | 421 | cw = min((cw << 1) | 1, mp->cw_max); |
422 | 422 | ||
423 | tx_time += tx_time_single; | 423 | tx_time += tx_time_single; |
424 | tx_time_cts += tx_time_single + mi->sp_ack_dur; | 424 | tx_time_cts += tx_time_single + mi->sp_ack_dur; |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index c06aa3ac6b9d..333b5118be6d 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -464,6 +464,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
464 | const struct mcs_group *group; | 464 | const struct mcs_group *group; |
465 | unsigned int tx_time, tx_time_rtscts, tx_time_data; | 465 | unsigned int tx_time, tx_time_rtscts, tx_time_data; |
466 | unsigned int cw = mp->cw_min; | 466 | unsigned int cw = mp->cw_min; |
467 | unsigned int ctime = 0; | ||
467 | unsigned int t_slot = 9; /* FIXME */ | 468 | unsigned int t_slot = 9; /* FIXME */ |
468 | unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); | 469 | unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); |
469 | 470 | ||
@@ -480,13 +481,27 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
480 | 481 | ||
481 | group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; | 482 | group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
482 | tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len; | 483 | tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len; |
483 | tx_time = 2 * (t_slot + mi->overhead + tx_time_data); | 484 | |
484 | tx_time_rtscts = 2 * (t_slot + mi->overhead_rtscts + tx_time_data); | 485 | /* Contention time for first 2 tries */ |
486 | ctime = (t_slot * cw) >> 1; | ||
487 | cw = min((cw << 1) | 1, mp->cw_max); | ||
488 | ctime += (t_slot * cw) >> 1; | ||
489 | cw = min((cw << 1) | 1, mp->cw_max); | ||
490 | |||
491 | /* Total TX time for data and Contention after first 2 tries */ | ||
492 | tx_time = ctime + 2 * (mi->overhead + tx_time_data); | ||
493 | tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data); | ||
494 | |||
495 | /* See how many more tries we can fit inside segment size */ | ||
485 | do { | 496 | do { |
486 | cw = (cw << 1) | 1; | 497 | /* Contention time for this try */ |
487 | cw = min(cw, mp->cw_max); | 498 | ctime = (t_slot * cw) >> 1; |
488 | tx_time += cw + t_slot + mi->overhead; | 499 | cw = min((cw << 1) | 1, mp->cw_max); |
489 | tx_time_rtscts += cw + t_slot + mi->overhead_rtscts; | 500 | |
501 | /* Total TX time after this try */ | ||
502 | tx_time += ctime + mi->overhead + tx_time_data; | ||
503 | tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data; | ||
504 | |||
490 | if (tx_time_rtscts < mp->segment_size) | 505 | if (tx_time_rtscts < mp->segment_size) |
491 | mr->retry_count_rtscts++; | 506 | mr->retry_count_rtscts++; |
492 | } while ((tx_time < mp->segment_size) && | 507 | } while ((tx_time < mp->segment_size) && |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 13a6697651ad..7fa8c6be7bf0 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -404,11 +404,13 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) | |||
404 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 404 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
405 | struct sk_buff *skb = rx->skb; | 405 | struct sk_buff *skb = rx->skb; |
406 | 406 | ||
407 | if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN))) | 407 | if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) && |
408 | !local->sched_scanning)) | ||
408 | return RX_CONTINUE; | 409 | return RX_CONTINUE; |
409 | 410 | ||
410 | if (test_bit(SCAN_HW_SCANNING, &local->scanning) || | 411 | if (test_bit(SCAN_HW_SCANNING, &local->scanning) || |
411 | test_bit(SCAN_SW_SCANNING, &local->scanning)) | 412 | test_bit(SCAN_SW_SCANNING, &local->scanning) || |
413 | local->sched_scanning) | ||
412 | return ieee80211_scan_rx(rx->sdata, skb); | 414 | return ieee80211_scan_rx(rx->sdata, skb); |
413 | 415 | ||
414 | /* scanning finished during invoking of handlers */ | 416 | /* scanning finished during invoking of handlers */ |
@@ -488,15 +490,18 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
488 | * establisment frame, beacon or probe, drop the frame. | 490 | * establisment frame, beacon or probe, drop the frame. |
489 | */ | 491 | */ |
490 | 492 | ||
491 | if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) { | 493 | if (!rx->sta || sta_plink_state(rx->sta) != NL80211_PLINK_ESTAB) { |
492 | struct ieee80211_mgmt *mgmt; | 494 | struct ieee80211_mgmt *mgmt; |
493 | 495 | ||
494 | if (!ieee80211_is_mgmt(hdr->frame_control)) | 496 | if (!ieee80211_is_mgmt(hdr->frame_control)) |
495 | return RX_DROP_MONITOR; | 497 | return RX_DROP_MONITOR; |
496 | 498 | ||
497 | if (ieee80211_is_action(hdr->frame_control)) { | 499 | if (ieee80211_is_action(hdr->frame_control)) { |
500 | u8 category; | ||
498 | mgmt = (struct ieee80211_mgmt *)hdr; | 501 | mgmt = (struct ieee80211_mgmt *)hdr; |
499 | if (mgmt->u.action.category != WLAN_CATEGORY_MESH_PLINK) | 502 | category = mgmt->u.action.category; |
503 | if (category != WLAN_CATEGORY_MESH_ACTION && | ||
504 | category != WLAN_CATEGORY_SELF_PROTECTED) | ||
500 | return RX_DROP_MONITOR; | 505 | return RX_DROP_MONITOR; |
501 | return RX_CONTINUE; | 506 | return RX_CONTINUE; |
502 | } | 507 | } |
@@ -1778,7 +1783,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
1778 | 1783 | ||
1779 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, | 1784 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, |
1780 | rx->sdata->vif.type, | 1785 | rx->sdata->vif.type, |
1781 | rx->local->hw.extra_tx_headroom); | 1786 | rx->local->hw.extra_tx_headroom, true); |
1782 | 1787 | ||
1783 | while (!skb_queue_empty(&frame_list)) { | 1788 | while (!skb_queue_empty(&frame_list)) { |
1784 | rx->skb = __skb_dequeue(&frame_list); | 1789 | rx->skb = __skb_dequeue(&frame_list); |
@@ -2205,7 +2210,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2205 | goto handled; | 2210 | goto handled; |
2206 | } | 2211 | } |
2207 | break; | 2212 | break; |
2208 | case WLAN_CATEGORY_MESH_PLINK: | 2213 | case WLAN_CATEGORY_MESH_ACTION: |
2209 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | 2214 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
2210 | break; | 2215 | break; |
2211 | goto queue; | 2216 | goto queue; |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 489b6ad200d4..d20046b5d8f4 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/if_arp.h> | 15 | #include <linux/if_arp.h> |
16 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
17 | #include <linux/pm_qos_params.h> | 17 | #include <linux/pm_qos_params.h> |
18 | #include <linux/slab.h> | ||
18 | #include <net/sch_generic.h> | 19 | #include <net/sch_generic.h> |
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | #include <net/mac80211.h> | 21 | #include <net/mac80211.h> |
@@ -170,7 +171,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
170 | return RX_CONTINUE; | 171 | return RX_CONTINUE; |
171 | 172 | ||
172 | if (skb->len < 24) | 173 | if (skb->len < 24) |
173 | return RX_DROP_MONITOR; | 174 | return RX_CONTINUE; |
174 | 175 | ||
175 | presp = ieee80211_is_probe_resp(fc); | 176 | presp = ieee80211_is_probe_resp(fc); |
176 | if (presp) { | 177 | if (presp) { |
@@ -850,3 +851,122 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) | |||
850 | } | 851 | } |
851 | mutex_unlock(&local->mtx); | 852 | mutex_unlock(&local->mtx); |
852 | } | 853 | } |
854 | |||
855 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | ||
856 | struct cfg80211_sched_scan_request *req) | ||
857 | { | ||
858 | struct ieee80211_local *local = sdata->local; | ||
859 | int ret, i; | ||
860 | |||
861 | mutex_lock(&sdata->local->mtx); | ||
862 | |||
863 | if (local->sched_scanning) { | ||
864 | ret = -EBUSY; | ||
865 | goto out; | ||
866 | } | ||
867 | |||
868 | if (!local->ops->sched_scan_start) { | ||
869 | ret = -ENOTSUPP; | ||
870 | goto out; | ||
871 | } | ||
872 | |||
873 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
874 | local->sched_scan_ies.ie[i] = kzalloc(2 + | ||
875 | IEEE80211_MAX_SSID_LEN + | ||
876 | local->scan_ies_len, | ||
877 | GFP_KERNEL); | ||
878 | if (!local->sched_scan_ies.ie[i]) { | ||
879 | ret = -ENOMEM; | ||
880 | goto out_free; | ||
881 | } | ||
882 | |||
883 | local->sched_scan_ies.len[i] = | ||
884 | ieee80211_build_preq_ies(local, | ||
885 | local->sched_scan_ies.ie[i], | ||
886 | req->ie, req->ie_len, i, | ||
887 | (u32) -1, 0); | ||
888 | } | ||
889 | |||
890 | ret = drv_sched_scan_start(local, sdata, req, | ||
891 | &local->sched_scan_ies); | ||
892 | if (ret == 0) { | ||
893 | local->sched_scanning = true; | ||
894 | goto out; | ||
895 | } | ||
896 | |||
897 | out_free: | ||
898 | while (i > 0) | ||
899 | kfree(local->sched_scan_ies.ie[--i]); | ||
900 | out: | ||
901 | mutex_unlock(&sdata->local->mtx); | ||
902 | return ret; | ||
903 | } | ||
904 | |||
905 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) | ||
906 | { | ||
907 | struct ieee80211_local *local = sdata->local; | ||
908 | int ret = 0, i; | ||
909 | |||
910 | mutex_lock(&sdata->local->mtx); | ||
911 | |||
912 | if (!local->ops->sched_scan_stop) { | ||
913 | ret = -ENOTSUPP; | ||
914 | goto out; | ||
915 | } | ||
916 | |||
917 | if (local->sched_scanning) { | ||
918 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
919 | kfree(local->sched_scan_ies.ie[i]); | ||
920 | |||
921 | drv_sched_scan_stop(local, sdata); | ||
922 | local->sched_scanning = false; | ||
923 | } | ||
924 | out: | ||
925 | mutex_unlock(&sdata->local->mtx); | ||
926 | |||
927 | return ret; | ||
928 | } | ||
929 | |||
930 | void ieee80211_sched_scan_results(struct ieee80211_hw *hw) | ||
931 | { | ||
932 | struct ieee80211_local *local = hw_to_local(hw); | ||
933 | |||
934 | trace_api_sched_scan_results(local); | ||
935 | |||
936 | cfg80211_sched_scan_results(hw->wiphy); | ||
937 | } | ||
938 | EXPORT_SYMBOL(ieee80211_sched_scan_results); | ||
939 | |||
940 | void ieee80211_sched_scan_stopped_work(struct work_struct *work) | ||
941 | { | ||
942 | struct ieee80211_local *local = | ||
943 | container_of(work, struct ieee80211_local, | ||
944 | sched_scan_stopped_work); | ||
945 | int i; | ||
946 | |||
947 | mutex_lock(&local->mtx); | ||
948 | |||
949 | if (!local->sched_scanning) { | ||
950 | mutex_unlock(&local->mtx); | ||
951 | return; | ||
952 | } | ||
953 | |||
954 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
955 | kfree(local->sched_scan_ies.ie[i]); | ||
956 | |||
957 | local->sched_scanning = false; | ||
958 | |||
959 | mutex_unlock(&local->mtx); | ||
960 | |||
961 | cfg80211_sched_scan_stopped(local->hw.wiphy); | ||
962 | } | ||
963 | |||
964 | void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw) | ||
965 | { | ||
966 | struct ieee80211_local *local = hw_to_local(hw); | ||
967 | |||
968 | trace_api_sched_scan_stopped(local); | ||
969 | |||
970 | ieee80211_queue_work(&local->hw, &local->sched_scan_stopped_work); | ||
971 | } | ||
972 | EXPORT_SYMBOL(ieee80211_sched_scan_stopped); | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index d9e6e81ff6b2..b83870bf60fa 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -67,7 +67,8 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
67 | { | 67 | { |
68 | struct sta_info *s; | 68 | struct sta_info *s; |
69 | 69 | ||
70 | s = local->sta_hash[STA_HASH(sta->sta.addr)]; | 70 | s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)], |
71 | lockdep_is_held(&local->sta_lock)); | ||
71 | if (!s) | 72 | if (!s) |
72 | return -ENOENT; | 73 | return -ENOENT; |
73 | if (s == sta) { | 74 | if (s == sta) { |
@@ -76,9 +77,11 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
76 | return 0; | 77 | return 0; |
77 | } | 78 | } |
78 | 79 | ||
79 | while (s->hnext && s->hnext != sta) | 80 | while (rcu_access_pointer(s->hnext) && |
80 | s = s->hnext; | 81 | rcu_access_pointer(s->hnext) != sta) |
81 | if (s->hnext) { | 82 | s = rcu_dereference_protected(s->hnext, |
83 | lockdep_is_held(&local->sta_lock)); | ||
84 | if (rcu_access_pointer(s->hnext)) { | ||
82 | rcu_assign_pointer(s->hnext, sta->hnext); | 85 | rcu_assign_pointer(s->hnext, sta->hnext); |
83 | return 0; | 86 | return 0; |
84 | } | 87 | } |
@@ -274,7 +277,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
274 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 277 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
275 | 278 | ||
276 | #ifdef CONFIG_MAC80211_MESH | 279 | #ifdef CONFIG_MAC80211_MESH |
277 | sta->plink_state = PLINK_LISTEN; | 280 | sta->plink_state = NL80211_PLINK_LISTEN; |
278 | init_timer(&sta->plink_timer); | 281 | init_timer(&sta->plink_timer); |
279 | #endif | 282 | #endif |
280 | 283 | ||
@@ -652,10 +655,12 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
652 | if (ret) | 655 | if (ret) |
653 | return ret; | 656 | return ret; |
654 | 657 | ||
658 | mutex_lock(&local->key_mtx); | ||
655 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) | 659 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) |
656 | ieee80211_key_free(local, sta->gtk[i]); | 660 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i])); |
657 | if (sta->ptk) | 661 | if (sta->ptk) |
658 | ieee80211_key_free(local, sta->ptk); | 662 | __ieee80211_key_free(key_mtx_dereference(local, sta->ptk)); |
663 | mutex_unlock(&local->key_mtx); | ||
659 | 664 | ||
660 | sta->dead = true; | 665 | sta->dead = true; |
661 | 666 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index aa0adcbf3a93..c6ae8718bd57 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -152,6 +152,7 @@ struct tid_ampdu_rx { | |||
152 | * | 152 | * |
153 | * @tid_rx: aggregation info for Rx per TID -- RCU protected | 153 | * @tid_rx: aggregation info for Rx per TID -- RCU protected |
154 | * @tid_tx: aggregation info for Tx per TID | 154 | * @tid_tx: aggregation info for Tx per TID |
155 | * @tid_start_tx: sessions where start was requested | ||
155 | * @addba_req_num: number of times addBA request has been sent. | 156 | * @addba_req_num: number of times addBA request has been sent. |
156 | * @dialog_token_allocator: dialog token enumerator for each new session; | 157 | * @dialog_token_allocator: dialog token enumerator for each new session; |
157 | * @work: work struct for starting/stopping aggregation | 158 | * @work: work struct for starting/stopping aggregation |
@@ -163,40 +164,18 @@ struct tid_ampdu_rx { | |||
163 | struct sta_ampdu_mlme { | 164 | struct sta_ampdu_mlme { |
164 | struct mutex mtx; | 165 | struct mutex mtx; |
165 | /* rx */ | 166 | /* rx */ |
166 | struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; | 167 | struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM]; |
167 | unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)]; | 168 | unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)]; |
168 | /* tx */ | 169 | /* tx */ |
169 | struct work_struct work; | 170 | struct work_struct work; |
170 | struct tid_ampdu_tx *tid_tx[STA_TID_NUM]; | 171 | struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM]; |
172 | struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM]; | ||
171 | u8 addba_req_num[STA_TID_NUM]; | 173 | u8 addba_req_num[STA_TID_NUM]; |
172 | u8 dialog_token_allocator; | 174 | u8 dialog_token_allocator; |
173 | }; | 175 | }; |
174 | 176 | ||
175 | 177 | ||
176 | /** | 178 | /** |
177 | * enum plink_state - state of a mesh peer link finite state machine | ||
178 | * | ||
179 | * @PLINK_LISTEN: initial state, considered the implicit state of non existent | ||
180 | * mesh peer links | ||
181 | * @PLINK_OPN_SNT: mesh plink open frame has been sent to this mesh peer | ||
182 | * @PLINK_OPN_RCVD: mesh plink open frame has been received from this mesh peer | ||
183 | * @PLINK_CNF_RCVD: mesh plink confirm frame has been received from this mesh | ||
184 | * peer | ||
185 | * @PLINK_ESTAB: mesh peer link is established | ||
186 | * @PLINK_HOLDING: mesh peer link is being closed or cancelled | ||
187 | * @PLINK_BLOCKED: all frames transmitted from this mesh plink are discarded | ||
188 | */ | ||
189 | enum plink_state { | ||
190 | PLINK_LISTEN, | ||
191 | PLINK_OPN_SNT, | ||
192 | PLINK_OPN_RCVD, | ||
193 | PLINK_CNF_RCVD, | ||
194 | PLINK_ESTAB, | ||
195 | PLINK_HOLDING, | ||
196 | PLINK_BLOCKED | ||
197 | }; | ||
198 | |||
199 | /** | ||
200 | * struct sta_info - STA information | 179 | * struct sta_info - STA information |
201 | * | 180 | * |
202 | * This structure collects information about a station that | 181 | * This structure collects information about a station that |
@@ -264,11 +243,11 @@ enum plink_state { | |||
264 | struct sta_info { | 243 | struct sta_info { |
265 | /* General information, mostly static */ | 244 | /* General information, mostly static */ |
266 | struct list_head list; | 245 | struct list_head list; |
267 | struct sta_info *hnext; | 246 | struct sta_info __rcu *hnext; |
268 | struct ieee80211_local *local; | 247 | struct ieee80211_local *local; |
269 | struct ieee80211_sub_if_data *sdata; | 248 | struct ieee80211_sub_if_data *sdata; |
270 | struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 249 | struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
271 | struct ieee80211_key *ptk; | 250 | struct ieee80211_key __rcu *ptk; |
272 | struct rate_control_ref *rate_ctrl; | 251 | struct rate_control_ref *rate_ctrl; |
273 | void *rate_ctrl_priv; | 252 | void *rate_ctrl_priv; |
274 | spinlock_t lock; | 253 | spinlock_t lock; |
@@ -339,7 +318,7 @@ struct sta_info { | |||
339 | u8 plink_retries; | 318 | u8 plink_retries; |
340 | bool ignore_plink_timer; | 319 | bool ignore_plink_timer; |
341 | bool plink_timer_was_running; | 320 | bool plink_timer_was_running; |
342 | enum plink_state plink_state; | 321 | enum nl80211_plink_state plink_state; |
343 | u32 plink_timeout; | 322 | u32 plink_timeout; |
344 | struct timer_list plink_timer; | 323 | struct timer_list plink_timer; |
345 | #endif | 324 | #endif |
@@ -357,12 +336,12 @@ struct sta_info { | |||
357 | struct ieee80211_sta sta; | 336 | struct ieee80211_sta sta; |
358 | }; | 337 | }; |
359 | 338 | ||
360 | static inline enum plink_state sta_plink_state(struct sta_info *sta) | 339 | static inline enum nl80211_plink_state sta_plink_state(struct sta_info *sta) |
361 | { | 340 | { |
362 | #ifdef CONFIG_MAC80211_MESH | 341 | #ifdef CONFIG_MAC80211_MESH |
363 | return sta->plink_state; | 342 | return sta->plink_state; |
364 | #endif | 343 | #endif |
365 | return PLINK_LISTEN; | 344 | return NL80211_PLINK_LISTEN; |
366 | } | 345 | } |
367 | 346 | ||
368 | static inline void set_sta_flags(struct sta_info *sta, const u32 flags) | 347 | static inline void set_sta_flags(struct sta_info *sta, const u32 flags) |
@@ -421,7 +400,16 @@ static inline u32 get_sta_flags(struct sta_info *sta) | |||
421 | return ret; | 400 | return ret; |
422 | } | 401 | } |
423 | 402 | ||
403 | void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, | ||
404 | struct tid_ampdu_tx *tid_tx); | ||
424 | 405 | ||
406 | static inline struct tid_ampdu_tx * | ||
407 | rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid) | ||
408 | { | ||
409 | return rcu_dereference_protected(sta->ampdu_mlme.tid_tx[tid], | ||
410 | lockdep_is_held(&sta->lock) || | ||
411 | lockdep_is_held(&sta->ampdu_mlme.mtx)); | ||
412 | } | ||
425 | 413 | ||
426 | #define STA_HASH_SIZE 256 | 414 | #define STA_HASH_SIZE 256 |
427 | #define STA_HASH(sta) (sta[5]) | 415 | #define STA_HASH(sta) (sta[5]) |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e3e3aa173af0..6eeaaa2bbafe 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1147,7 +1147,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, | |||
1147 | * packet pass through because splicing the frames | 1147 | * packet pass through because splicing the frames |
1148 | * back is already done. | 1148 | * back is already done. |
1149 | */ | 1149 | */ |
1150 | tid_tx = tx->sta->ampdu_mlme.tid_tx[tid]; | 1150 | tid_tx = rcu_dereference_protected_tid_tx(tx->sta, tid); |
1151 | 1151 | ||
1152 | if (!tid_tx) { | 1152 | if (!tid_tx) { |
1153 | /* do nothing, let packet pass through */ | 1153 | /* do nothing, let packet pass through */ |
@@ -1751,6 +1751,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1751 | ret = NETDEV_TX_OK; | 1751 | ret = NETDEV_TX_OK; |
1752 | goto fail; | 1752 | goto fail; |
1753 | } | 1753 | } |
1754 | rcu_read_lock(); | ||
1754 | if (!is_multicast_ether_addr(skb->data)) | 1755 | if (!is_multicast_ether_addr(skb->data)) |
1755 | mppath = mpp_path_lookup(skb->data, sdata); | 1756 | mppath = mpp_path_lookup(skb->data, sdata); |
1756 | 1757 | ||
@@ -1765,13 +1766,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1765 | !(mppath && compare_ether_addr(mppath->mpp, skb->data))) { | 1766 | !(mppath && compare_ether_addr(mppath->mpp, skb->data))) { |
1766 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, | 1767 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, |
1767 | skb->data, skb->data + ETH_ALEN); | 1768 | skb->data, skb->data + ETH_ALEN); |
1769 | rcu_read_unlock(); | ||
1768 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, | 1770 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, |
1769 | sdata, NULL, NULL); | 1771 | sdata, NULL, NULL); |
1770 | } else { | 1772 | } else { |
1771 | int is_mesh_mcast = 1; | 1773 | int is_mesh_mcast = 1; |
1772 | const u8 *mesh_da; | 1774 | const u8 *mesh_da; |
1773 | 1775 | ||
1774 | rcu_read_lock(); | ||
1775 | if (is_multicast_ether_addr(skb->data)) | 1776 | if (is_multicast_ether_addr(skb->data)) |
1776 | /* DA TA mSA AE:SA */ | 1777 | /* DA TA mSA AE:SA */ |
1777 | mesh_da = skb->data; | 1778 | mesh_da = skb->data; |
@@ -2534,8 +2535,9 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
2534 | skb_set_network_header(skb, 0); | 2535 | skb_set_network_header(skb, 0); |
2535 | skb_set_transport_header(skb, 0); | 2536 | skb_set_transport_header(skb, 0); |
2536 | 2537 | ||
2537 | /* send all internal mgmt frames on VO */ | 2538 | /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */ |
2538 | skb_set_queue_mapping(skb, 0); | 2539 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); |
2540 | skb->priority = 7; | ||
2539 | 2541 | ||
2540 | /* | 2542 | /* |
2541 | * The other path calling ieee80211_xmit is from the tasklet, | 2543 | * The other path calling ieee80211_xmit is from the tasklet, |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ef0560a2346a..d3fe2d237485 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1125,9 +1125,27 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1125 | struct sta_info *sta; | 1125 | struct sta_info *sta; |
1126 | int res; | 1126 | int res; |
1127 | 1127 | ||
1128 | #ifdef CONFIG_PM | ||
1128 | if (local->suspended) | 1129 | if (local->suspended) |
1129 | local->resuming = true; | 1130 | local->resuming = true; |
1130 | 1131 | ||
1132 | if (local->wowlan) { | ||
1133 | local->wowlan = false; | ||
1134 | res = drv_resume(local); | ||
1135 | if (res < 0) { | ||
1136 | local->resuming = false; | ||
1137 | return res; | ||
1138 | } | ||
1139 | if (res == 0) | ||
1140 | goto wake_up; | ||
1141 | WARN_ON(res > 1); | ||
1142 | /* | ||
1143 | * res is 1, which means the driver requested | ||
1144 | * to go through a regular reset on wakeup. | ||
1145 | */ | ||
1146 | } | ||
1147 | #endif | ||
1148 | |||
1131 | /* restart hardware */ | 1149 | /* restart hardware */ |
1132 | if (local->open_count) { | 1150 | if (local->open_count) { |
1133 | /* | 1151 | /* |
@@ -1258,6 +1276,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1258 | if (ieee80211_sdata_running(sdata)) | 1276 | if (ieee80211_sdata_running(sdata)) |
1259 | ieee80211_enable_keys(sdata); | 1277 | ieee80211_enable_keys(sdata); |
1260 | 1278 | ||
1279 | wake_up: | ||
1261 | ieee80211_wake_queues_by_reason(hw, | 1280 | ieee80211_wake_queues_by_reason(hw, |
1262 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 1281 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
1263 | 1282 | ||
diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 0198191b756d..be90640a2774 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c | |||
@@ -1024,7 +1024,6 @@ static int rfkill_fop_open(struct inode *inode, struct file *file) | |||
1024 | * start getting events from elsewhere but hold mtx to get | 1024 | * start getting events from elsewhere but hold mtx to get |
1025 | * startup events added first | 1025 | * startup events added first |
1026 | */ | 1026 | */ |
1027 | list_add(&data->list, &rfkill_fds); | ||
1028 | 1027 | ||
1029 | list_for_each_entry(rfkill, &rfkill_list, node) { | 1028 | list_for_each_entry(rfkill, &rfkill_list, node) { |
1030 | ev = kzalloc(sizeof(*ev), GFP_KERNEL); | 1029 | ev = kzalloc(sizeof(*ev), GFP_KERNEL); |
@@ -1033,6 +1032,7 @@ static int rfkill_fop_open(struct inode *inode, struct file *file) | |||
1033 | rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD); | 1032 | rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD); |
1034 | list_add_tail(&ev->list, &data->events); | 1033 | list_add_tail(&ev->list, &data->events); |
1035 | } | 1034 | } |
1035 | list_add(&data->list, &rfkill_fds); | ||
1036 | mutex_unlock(&data->mtx); | 1036 | mutex_unlock(&data->mtx); |
1037 | mutex_unlock(&rfkill_global_mutex); | 1037 | mutex_unlock(&rfkill_global_mutex); |
1038 | 1038 | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index bbf1fa11107a..c22ef3492ee6 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -370,7 +370,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
370 | spin_lock_init(&rdev->bss_lock); | 370 | spin_lock_init(&rdev->bss_lock); |
371 | INIT_LIST_HEAD(&rdev->bss_list); | 371 | INIT_LIST_HEAD(&rdev->bss_list); |
372 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); | 372 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
373 | 373 | INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); | |
374 | #ifdef CONFIG_CFG80211_WEXT | 374 | #ifdef CONFIG_CFG80211_WEXT |
375 | rdev->wiphy.wext = &cfg80211_wext_handler; | 375 | rdev->wiphy.wext = &cfg80211_wext_handler; |
376 | #endif | 376 | #endif |
@@ -416,6 +416,67 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
416 | } | 416 | } |
417 | EXPORT_SYMBOL(wiphy_new); | 417 | EXPORT_SYMBOL(wiphy_new); |
418 | 418 | ||
419 | static int wiphy_verify_combinations(struct wiphy *wiphy) | ||
420 | { | ||
421 | const struct ieee80211_iface_combination *c; | ||
422 | int i, j; | ||
423 | |||
424 | /* If we have combinations enforce them */ | ||
425 | if (wiphy->n_iface_combinations) | ||
426 | wiphy->flags |= WIPHY_FLAG_ENFORCE_COMBINATIONS; | ||
427 | |||
428 | for (i = 0; i < wiphy->n_iface_combinations; i++) { | ||
429 | u32 cnt = 0; | ||
430 | u16 all_iftypes = 0; | ||
431 | |||
432 | c = &wiphy->iface_combinations[i]; | ||
433 | |||
434 | /* Combinations with just one interface aren't real */ | ||
435 | if (WARN_ON(c->max_interfaces < 2)) | ||
436 | return -EINVAL; | ||
437 | |||
438 | /* Need at least one channel */ | ||
439 | if (WARN_ON(!c->num_different_channels)) | ||
440 | return -EINVAL; | ||
441 | |||
442 | if (WARN_ON(!c->n_limits)) | ||
443 | return -EINVAL; | ||
444 | |||
445 | for (j = 0; j < c->n_limits; j++) { | ||
446 | u16 types = c->limits[j].types; | ||
447 | |||
448 | /* | ||
449 | * interface types shouldn't overlap, this is | ||
450 | * used in cfg80211_can_change_interface() | ||
451 | */ | ||
452 | if (WARN_ON(types & all_iftypes)) | ||
453 | return -EINVAL; | ||
454 | all_iftypes |= types; | ||
455 | |||
456 | if (WARN_ON(!c->limits[j].max)) | ||
457 | return -EINVAL; | ||
458 | |||
459 | /* Shouldn't list software iftypes in combinations! */ | ||
460 | if (WARN_ON(wiphy->software_iftypes & types)) | ||
461 | return -EINVAL; | ||
462 | |||
463 | cnt += c->limits[j].max; | ||
464 | /* | ||
465 | * Don't advertise an unsupported type | ||
466 | * in a combination. | ||
467 | */ | ||
468 | if (WARN_ON((wiphy->interface_modes & types) != types)) | ||
469 | return -EINVAL; | ||
470 | } | ||
471 | |||
472 | /* You can't even choose that many! */ | ||
473 | if (WARN_ON(cnt < c->max_interfaces)) | ||
474 | return -EINVAL; | ||
475 | } | ||
476 | |||
477 | return 0; | ||
478 | } | ||
479 | |||
419 | int wiphy_register(struct wiphy *wiphy) | 480 | int wiphy_register(struct wiphy *wiphy) |
420 | { | 481 | { |
421 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 482 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
@@ -444,6 +505,10 @@ int wiphy_register(struct wiphy *wiphy) | |||
444 | if (WARN_ON(ifmodes != wiphy->interface_modes)) | 505 | if (WARN_ON(ifmodes != wiphy->interface_modes)) |
445 | wiphy->interface_modes = ifmodes; | 506 | wiphy->interface_modes = ifmodes; |
446 | 507 | ||
508 | res = wiphy_verify_combinations(wiphy); | ||
509 | if (res) | ||
510 | return res; | ||
511 | |||
447 | /* sanity check supported bands/channels */ | 512 | /* sanity check supported bands/channels */ |
448 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 513 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
449 | sband = wiphy->bands[band]; | 514 | sband = wiphy->bands[band]; |
@@ -493,6 +558,13 @@ int wiphy_register(struct wiphy *wiphy) | |||
493 | return -EINVAL; | 558 | return -EINVAL; |
494 | } | 559 | } |
495 | 560 | ||
561 | if (rdev->wiphy.wowlan.n_patterns) { | ||
562 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || | ||
563 | rdev->wiphy.wowlan.pattern_min_len > | ||
564 | rdev->wiphy.wowlan.pattern_max_len)) | ||
565 | return -EINVAL; | ||
566 | } | ||
567 | |||
496 | /* check and set up bitrates */ | 568 | /* check and set up bitrates */ |
497 | ieee80211_set_bitrate_flags(wiphy); | 569 | ieee80211_set_bitrate_flags(wiphy); |
498 | 570 | ||
@@ -631,6 +703,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) | |||
631 | mutex_destroy(&rdev->devlist_mtx); | 703 | mutex_destroy(&rdev->devlist_mtx); |
632 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) | 704 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) |
633 | cfg80211_put_bss(&scan->pub); | 705 | cfg80211_put_bss(&scan->pub); |
706 | cfg80211_rdev_free_wowlan(rdev); | ||
634 | kfree(rdev); | 707 | kfree(rdev); |
635 | } | 708 | } |
636 | 709 | ||
@@ -664,6 +737,11 @@ static void wdev_cleanup_work(struct work_struct *work) | |||
664 | ___cfg80211_scan_done(rdev, true); | 737 | ___cfg80211_scan_done(rdev, true); |
665 | } | 738 | } |
666 | 739 | ||
740 | if (WARN_ON(rdev->sched_scan_req && | ||
741 | rdev->sched_scan_req->dev == wdev->netdev)) { | ||
742 | __cfg80211_stop_sched_scan(rdev, false); | ||
743 | } | ||
744 | |||
667 | cfg80211_unlock_rdev(rdev); | 745 | cfg80211_unlock_rdev(rdev); |
668 | 746 | ||
669 | mutex_lock(&rdev->devlist_mtx); | 747 | mutex_lock(&rdev->devlist_mtx); |
@@ -685,6 +763,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
685 | struct net_device *dev = ndev; | 763 | struct net_device *dev = ndev; |
686 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 764 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
687 | struct cfg80211_registered_device *rdev; | 765 | struct cfg80211_registered_device *rdev; |
766 | int ret; | ||
688 | 767 | ||
689 | if (!wdev) | 768 | if (!wdev) |
690 | return NOTIFY_DONE; | 769 | return NOTIFY_DONE; |
@@ -751,6 +830,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
751 | break; | 830 | break; |
752 | case NL80211_IFTYPE_P2P_CLIENT: | 831 | case NL80211_IFTYPE_P2P_CLIENT: |
753 | case NL80211_IFTYPE_STATION: | 832 | case NL80211_IFTYPE_STATION: |
833 | cfg80211_lock_rdev(rdev); | ||
834 | __cfg80211_stop_sched_scan(rdev, false); | ||
835 | cfg80211_unlock_rdev(rdev); | ||
836 | |||
754 | wdev_lock(wdev); | 837 | wdev_lock(wdev); |
755 | #ifdef CONFIG_CFG80211_WEXT | 838 | #ifdef CONFIG_CFG80211_WEXT |
756 | kfree(wdev->wext.ie); | 839 | kfree(wdev->wext.ie); |
@@ -769,6 +852,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
769 | default: | 852 | default: |
770 | break; | 853 | break; |
771 | } | 854 | } |
855 | wdev->beacon_interval = 0; | ||
772 | break; | 856 | break; |
773 | case NETDEV_DOWN: | 857 | case NETDEV_DOWN: |
774 | dev_hold(dev); | 858 | dev_hold(dev); |
@@ -875,6 +959,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
875 | return notifier_from_errno(-EOPNOTSUPP); | 959 | return notifier_from_errno(-EOPNOTSUPP); |
876 | if (rfkill_blocked(rdev->rfkill)) | 960 | if (rfkill_blocked(rdev->rfkill)) |
877 | return notifier_from_errno(-ERFKILL); | 961 | return notifier_from_errno(-ERFKILL); |
962 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | ||
963 | if (ret) | ||
964 | return notifier_from_errno(ret); | ||
878 | break; | 965 | break; |
879 | } | 966 | } |
880 | 967 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index 26a0a084e16b..bf0fb40e3c8b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -60,8 +60,10 @@ struct cfg80211_registered_device { | |||
60 | struct rb_root bss_tree; | 60 | struct rb_root bss_tree; |
61 | u32 bss_generation; | 61 | u32 bss_generation; |
62 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ | 62 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ |
63 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
63 | unsigned long suspend_at; | 64 | unsigned long suspend_at; |
64 | struct work_struct scan_done_wk; | 65 | struct work_struct scan_done_wk; |
66 | struct work_struct sched_scan_results_wk; | ||
65 | 67 | ||
66 | #ifdef CONFIG_NL80211_TESTMODE | 68 | #ifdef CONFIG_NL80211_TESTMODE |
67 | struct genl_info *testmode_info; | 69 | struct genl_info *testmode_info; |
@@ -70,6 +72,8 @@ struct cfg80211_registered_device { | |||
70 | struct work_struct conn_work; | 72 | struct work_struct conn_work; |
71 | struct work_struct event_work; | 73 | struct work_struct event_work; |
72 | 74 | ||
75 | struct cfg80211_wowlan *wowlan; | ||
76 | |||
73 | /* must be last because of the way we do wiphy_priv(), | 77 | /* must be last because of the way we do wiphy_priv(), |
74 | * and it should at least be aligned to NETDEV_ALIGN */ | 78 | * and it should at least be aligned to NETDEV_ALIGN */ |
75 | struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); | 79 | struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); |
@@ -89,6 +93,18 @@ bool wiphy_idx_valid(int wiphy_idx) | |||
89 | return wiphy_idx >= 0; | 93 | return wiphy_idx >= 0; |
90 | } | 94 | } |
91 | 95 | ||
96 | static inline void | ||
97 | cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev) | ||
98 | { | ||
99 | int i; | ||
100 | |||
101 | if (!rdev->wowlan) | ||
102 | return; | ||
103 | for (i = 0; i < rdev->wowlan->n_patterns; i++) | ||
104 | kfree(rdev->wowlan->patterns[i].mask); | ||
105 | kfree(rdev->wowlan->patterns); | ||
106 | kfree(rdev->wowlan); | ||
107 | } | ||
92 | 108 | ||
93 | extern struct workqueue_struct *cfg80211_wq; | 109 | extern struct workqueue_struct *cfg80211_wq; |
94 | extern struct mutex cfg80211_mutex; | 110 | extern struct mutex cfg80211_mutex; |
@@ -397,12 +413,26 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | |||
397 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); | 413 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); |
398 | void __cfg80211_scan_done(struct work_struct *wk); | 414 | void __cfg80211_scan_done(struct work_struct *wk); |
399 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); | 415 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); |
416 | void __cfg80211_sched_scan_results(struct work_struct *wk); | ||
417 | int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, | ||
418 | bool driver_initiated); | ||
400 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); | 419 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); |
401 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | 420 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, |
402 | struct net_device *dev, enum nl80211_iftype ntype, | 421 | struct net_device *dev, enum nl80211_iftype ntype, |
403 | u32 *flags, struct vif_params *params); | 422 | u32 *flags, struct vif_params *params); |
404 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); | 423 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); |
405 | 424 | ||
425 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | ||
426 | struct wireless_dev *wdev, | ||
427 | enum nl80211_iftype iftype); | ||
428 | |||
429 | static inline int | ||
430 | cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, | ||
431 | enum nl80211_iftype iftype) | ||
432 | { | ||
433 | return cfg80211_can_change_interface(rdev, NULL, iftype); | ||
434 | } | ||
435 | |||
406 | struct ieee80211_channel * | 436 | struct ieee80211_channel * |
407 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | 437 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, |
408 | int freq, enum nl80211_channel_type channel_type); | 438 | int freq, enum nl80211_channel_type channel_type); |
@@ -412,6 +442,9 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev, | |||
412 | 442 | ||
413 | u16 cfg80211_calculate_bitrate(struct rate_info *rate); | 443 | u16 cfg80211_calculate_bitrate(struct rate_info *rate); |
414 | 444 | ||
445 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | ||
446 | u32 beacon_int); | ||
447 | |||
415 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS | 448 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS |
416 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) | 449 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) |
417 | #else | 450 | #else |
diff --git a/net/wireless/lib80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c index e2e88878ba35..2f265e033ae2 100644 --- a/net/wireless/lib80211_crypt_wep.c +++ b/net/wireless/lib80211_crypt_wep.c | |||
@@ -96,13 +96,12 @@ static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len, | |||
96 | u8 *key, int keylen, void *priv) | 96 | u8 *key, int keylen, void *priv) |
97 | { | 97 | { |
98 | struct lib80211_wep_data *wep = priv; | 98 | struct lib80211_wep_data *wep = priv; |
99 | u32 klen, len; | 99 | u32 klen; |
100 | u8 *pos; | 100 | u8 *pos; |
101 | 101 | ||
102 | if (skb_headroom(skb) < 4 || skb->len < hdr_len) | 102 | if (skb_headroom(skb) < 4 || skb->len < hdr_len) |
103 | return -1; | 103 | return -1; |
104 | 104 | ||
105 | len = skb->len - hdr_len; | ||
106 | pos = skb_push(skb, 4); | 105 | pos = skb_push(skb, 4); |
107 | memmove(pos, pos + 4, hdr_len); | 106 | memmove(pos, pos + 4, hdr_len); |
108 | pos += hdr_len; | 107 | pos += hdr_len; |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 16881fea4ce6..493b939970cd 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -963,6 +963,16 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
963 | if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN)) | 963 | if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN)) |
964 | err = -EINVAL; | 964 | err = -EINVAL; |
965 | break; | 965 | break; |
966 | case NL80211_IFTYPE_MESH_POINT: | ||
967 | if (memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN)) { | ||
968 | err = -EINVAL; | ||
969 | break; | ||
970 | } | ||
971 | /* | ||
972 | * check for mesh DA must be done by driver as | ||
973 | * cfg80211 doesn't track the stations | ||
974 | */ | ||
975 | break; | ||
966 | default: | 976 | default: |
967 | err = -EOPNOTSUPP; | 977 | err = -EOPNOTSUPP; |
968 | break; | 978 | break; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0efa7fd01150..2222ce08ee91 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -173,6 +173,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
173 | [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 }, | 173 | [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 }, |
174 | [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, | 174 | [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, |
175 | [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, | 175 | [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, |
176 | [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, | ||
177 | [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, | ||
178 | [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, | ||
176 | }; | 179 | }; |
177 | 180 | ||
178 | /* policy for the key attributes */ | 181 | /* policy for the key attributes */ |
@@ -194,6 +197,15 @@ nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = { | |||
194 | [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG }, | 197 | [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG }, |
195 | }; | 198 | }; |
196 | 199 | ||
200 | /* policy for WoWLAN attributes */ | ||
201 | static const struct nla_policy | ||
202 | nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { | ||
203 | [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG }, | ||
204 | [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG }, | ||
205 | [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG }, | ||
206 | [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, | ||
207 | }; | ||
208 | |||
197 | /* ifidx get helper */ | 209 | /* ifidx get helper */ |
198 | static int nl80211_get_ifidx(struct netlink_callback *cb) | 210 | static int nl80211_get_ifidx(struct netlink_callback *cb) |
199 | { | 211 | { |
@@ -534,6 +546,7 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
534 | case NL80211_IFTYPE_AP: | 546 | case NL80211_IFTYPE_AP: |
535 | case NL80211_IFTYPE_AP_VLAN: | 547 | case NL80211_IFTYPE_AP_VLAN: |
536 | case NL80211_IFTYPE_P2P_GO: | 548 | case NL80211_IFTYPE_P2P_GO: |
549 | case NL80211_IFTYPE_MESH_POINT: | ||
537 | break; | 550 | break; |
538 | case NL80211_IFTYPE_ADHOC: | 551 | case NL80211_IFTYPE_ADHOC: |
539 | if (!wdev->current_bss) | 552 | if (!wdev->current_bss) |
@@ -551,6 +564,88 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
551 | return 0; | 564 | return 0; |
552 | } | 565 | } |
553 | 566 | ||
567 | static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) | ||
568 | { | ||
569 | struct nlattr *nl_modes = nla_nest_start(msg, attr); | ||
570 | int i; | ||
571 | |||
572 | if (!nl_modes) | ||
573 | goto nla_put_failure; | ||
574 | |||
575 | i = 0; | ||
576 | while (ifmodes) { | ||
577 | if (ifmodes & 1) | ||
578 | NLA_PUT_FLAG(msg, i); | ||
579 | ifmodes >>= 1; | ||
580 | i++; | ||
581 | } | ||
582 | |||
583 | nla_nest_end(msg, nl_modes); | ||
584 | return 0; | ||
585 | |||
586 | nla_put_failure: | ||
587 | return -ENOBUFS; | ||
588 | } | ||
589 | |||
590 | static int nl80211_put_iface_combinations(struct wiphy *wiphy, | ||
591 | struct sk_buff *msg) | ||
592 | { | ||
593 | struct nlattr *nl_combis; | ||
594 | int i, j; | ||
595 | |||
596 | nl_combis = nla_nest_start(msg, | ||
597 | NL80211_ATTR_INTERFACE_COMBINATIONS); | ||
598 | if (!nl_combis) | ||
599 | goto nla_put_failure; | ||
600 | |||
601 | for (i = 0; i < wiphy->n_iface_combinations; i++) { | ||
602 | const struct ieee80211_iface_combination *c; | ||
603 | struct nlattr *nl_combi, *nl_limits; | ||
604 | |||
605 | c = &wiphy->iface_combinations[i]; | ||
606 | |||
607 | nl_combi = nla_nest_start(msg, i + 1); | ||
608 | if (!nl_combi) | ||
609 | goto nla_put_failure; | ||
610 | |||
611 | nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS); | ||
612 | if (!nl_limits) | ||
613 | goto nla_put_failure; | ||
614 | |||
615 | for (j = 0; j < c->n_limits; j++) { | ||
616 | struct nlattr *nl_limit; | ||
617 | |||
618 | nl_limit = nla_nest_start(msg, j + 1); | ||
619 | if (!nl_limit) | ||
620 | goto nla_put_failure; | ||
621 | NLA_PUT_U32(msg, NL80211_IFACE_LIMIT_MAX, | ||
622 | c->limits[j].max); | ||
623 | if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES, | ||
624 | c->limits[j].types)) | ||
625 | goto nla_put_failure; | ||
626 | nla_nest_end(msg, nl_limit); | ||
627 | } | ||
628 | |||
629 | nla_nest_end(msg, nl_limits); | ||
630 | |||
631 | if (c->beacon_int_infra_match) | ||
632 | NLA_PUT_FLAG(msg, | ||
633 | NL80211_IFACE_COMB_STA_AP_BI_MATCH); | ||
634 | NLA_PUT_U32(msg, NL80211_IFACE_COMB_NUM_CHANNELS, | ||
635 | c->num_different_channels); | ||
636 | NLA_PUT_U32(msg, NL80211_IFACE_COMB_MAXNUM, | ||
637 | c->max_interfaces); | ||
638 | |||
639 | nla_nest_end(msg, nl_combi); | ||
640 | } | ||
641 | |||
642 | nla_nest_end(msg, nl_combis); | ||
643 | |||
644 | return 0; | ||
645 | nla_put_failure: | ||
646 | return -ENOBUFS; | ||
647 | } | ||
648 | |||
554 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 649 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
555 | struct cfg80211_registered_device *dev) | 650 | struct cfg80211_registered_device *dev) |
556 | { | 651 | { |
@@ -558,13 +653,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
558 | struct nlattr *nl_bands, *nl_band; | 653 | struct nlattr *nl_bands, *nl_band; |
559 | struct nlattr *nl_freqs, *nl_freq; | 654 | struct nlattr *nl_freqs, *nl_freq; |
560 | struct nlattr *nl_rates, *nl_rate; | 655 | struct nlattr *nl_rates, *nl_rate; |
561 | struct nlattr *nl_modes; | ||
562 | struct nlattr *nl_cmds; | 656 | struct nlattr *nl_cmds; |
563 | enum ieee80211_band band; | 657 | enum ieee80211_band band; |
564 | struct ieee80211_channel *chan; | 658 | struct ieee80211_channel *chan; |
565 | struct ieee80211_rate *rate; | 659 | struct ieee80211_rate *rate; |
566 | int i; | 660 | int i; |
567 | u16 ifmodes = dev->wiphy.interface_modes; | ||
568 | const struct ieee80211_txrx_stypes *mgmt_stypes = | 661 | const struct ieee80211_txrx_stypes *mgmt_stypes = |
569 | dev->wiphy.mgmt_stypes; | 662 | dev->wiphy.mgmt_stypes; |
570 | 663 | ||
@@ -624,20 +717,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
624 | } | 717 | } |
625 | } | 718 | } |
626 | 719 | ||
627 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 720 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, |
628 | if (!nl_modes) | 721 | dev->wiphy.interface_modes)) |
629 | goto nla_put_failure; | 722 | goto nla_put_failure; |
630 | 723 | ||
631 | i = 0; | ||
632 | while (ifmodes) { | ||
633 | if (ifmodes & 1) | ||
634 | NLA_PUT_FLAG(msg, i); | ||
635 | ifmodes >>= 1; | ||
636 | i++; | ||
637 | } | ||
638 | |||
639 | nla_nest_end(msg, nl_modes); | ||
640 | |||
641 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 724 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); |
642 | if (!nl_bands) | 725 | if (!nl_bands) |
643 | goto nla_put_failure; | 726 | goto nla_put_failure; |
@@ -749,6 +832,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
749 | } | 832 | } |
750 | CMD(set_channel, SET_CHANNEL); | 833 | CMD(set_channel, SET_CHANNEL); |
751 | CMD(set_wds_peer, SET_WDS_PEER); | 834 | CMD(set_wds_peer, SET_WDS_PEER); |
835 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | ||
836 | CMD(sched_scan_start, START_SCHED_SCAN); | ||
752 | 837 | ||
753 | #undef CMD | 838 | #undef CMD |
754 | 839 | ||
@@ -821,6 +906,42 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
821 | nla_nest_end(msg, nl_ifs); | 906 | nla_nest_end(msg, nl_ifs); |
822 | } | 907 | } |
823 | 908 | ||
909 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { | ||
910 | struct nlattr *nl_wowlan; | ||
911 | |||
912 | nl_wowlan = nla_nest_start(msg, | ||
913 | NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); | ||
914 | if (!nl_wowlan) | ||
915 | goto nla_put_failure; | ||
916 | |||
917 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) | ||
918 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); | ||
919 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) | ||
920 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); | ||
921 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) | ||
922 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); | ||
923 | if (dev->wiphy.wowlan.n_patterns) { | ||
924 | struct nl80211_wowlan_pattern_support pat = { | ||
925 | .max_patterns = dev->wiphy.wowlan.n_patterns, | ||
926 | .min_pattern_len = | ||
927 | dev->wiphy.wowlan.pattern_min_len, | ||
928 | .max_pattern_len = | ||
929 | dev->wiphy.wowlan.pattern_max_len, | ||
930 | }; | ||
931 | NLA_PUT(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, | ||
932 | sizeof(pat), &pat); | ||
933 | } | ||
934 | |||
935 | nla_nest_end(msg, nl_wowlan); | ||
936 | } | ||
937 | |||
938 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | ||
939 | dev->wiphy.software_iftypes)) | ||
940 | goto nla_put_failure; | ||
941 | |||
942 | if (nl80211_put_iface_combinations(&dev->wiphy, msg)) | ||
943 | goto nla_put_failure; | ||
944 | |||
824 | return genlmsg_end(msg, hdr); | 945 | return genlmsg_end(msg, hdr); |
825 | 946 | ||
826 | nla_put_failure: | 947 | nla_put_failure: |
@@ -1682,14 +1803,6 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1682 | if (err) | 1803 | if (err) |
1683 | goto out; | 1804 | goto out; |
1684 | 1805 | ||
1685 | if (!(rdev->wiphy.flags & | ||
1686 | WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS)) { | ||
1687 | if (!key.def_uni || !key.def_multi) { | ||
1688 | err = -EOPNOTSUPP; | ||
1689 | goto out; | ||
1690 | } | ||
1691 | } | ||
1692 | |||
1693 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx, | 1806 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx, |
1694 | key.def_uni, key.def_multi); | 1807 | key.def_uni, key.def_multi); |
1695 | 1808 | ||
@@ -1840,8 +1953,9 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1840 | struct beacon_parameters *info); | 1953 | struct beacon_parameters *info); |
1841 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 1954 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1842 | struct net_device *dev = info->user_ptr[1]; | 1955 | struct net_device *dev = info->user_ptr[1]; |
1956 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1843 | struct beacon_parameters params; | 1957 | struct beacon_parameters params; |
1844 | int haveinfo = 0; | 1958 | int haveinfo = 0, err; |
1845 | 1959 | ||
1846 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) | 1960 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) |
1847 | return -EINVAL; | 1961 | return -EINVAL; |
@@ -1850,6 +1964,8 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1850 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 1964 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
1851 | return -EOPNOTSUPP; | 1965 | return -EOPNOTSUPP; |
1852 | 1966 | ||
1967 | memset(¶ms, 0, sizeof(params)); | ||
1968 | |||
1853 | switch (info->genlhdr->cmd) { | 1969 | switch (info->genlhdr->cmd) { |
1854 | case NL80211_CMD_NEW_BEACON: | 1970 | case NL80211_CMD_NEW_BEACON: |
1855 | /* these are required for NEW_BEACON */ | 1971 | /* these are required for NEW_BEACON */ |
@@ -1858,6 +1974,15 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1858 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) | 1974 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) |
1859 | return -EINVAL; | 1975 | return -EINVAL; |
1860 | 1976 | ||
1977 | params.interval = | ||
1978 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); | ||
1979 | params.dtim_period = | ||
1980 | nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); | ||
1981 | |||
1982 | err = cfg80211_validate_beacon_int(rdev, params.interval); | ||
1983 | if (err) | ||
1984 | return err; | ||
1985 | |||
1861 | call = rdev->ops->add_beacon; | 1986 | call = rdev->ops->add_beacon; |
1862 | break; | 1987 | break; |
1863 | case NL80211_CMD_SET_BEACON: | 1988 | case NL80211_CMD_SET_BEACON: |
@@ -1871,20 +1996,6 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1871 | if (!call) | 1996 | if (!call) |
1872 | return -EOPNOTSUPP; | 1997 | return -EOPNOTSUPP; |
1873 | 1998 | ||
1874 | memset(¶ms, 0, sizeof(params)); | ||
1875 | |||
1876 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { | ||
1877 | params.interval = | ||
1878 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); | ||
1879 | haveinfo = 1; | ||
1880 | } | ||
1881 | |||
1882 | if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) { | ||
1883 | params.dtim_period = | ||
1884 | nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); | ||
1885 | haveinfo = 1; | ||
1886 | } | ||
1887 | |||
1888 | if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { | 1999 | if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { |
1889 | params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); | 2000 | params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); |
1890 | params.head_len = | 2001 | params.head_len = |
@@ -1902,13 +2013,18 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1902 | if (!haveinfo) | 2013 | if (!haveinfo) |
1903 | return -EINVAL; | 2014 | return -EINVAL; |
1904 | 2015 | ||
1905 | return call(&rdev->wiphy, dev, ¶ms); | 2016 | err = call(&rdev->wiphy, dev, ¶ms); |
2017 | if (!err && params.interval) | ||
2018 | wdev->beacon_interval = params.interval; | ||
2019 | return err; | ||
1906 | } | 2020 | } |
1907 | 2021 | ||
1908 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | 2022 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) |
1909 | { | 2023 | { |
1910 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2024 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1911 | struct net_device *dev = info->user_ptr[1]; | 2025 | struct net_device *dev = info->user_ptr[1]; |
2026 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2027 | int err; | ||
1912 | 2028 | ||
1913 | if (!rdev->ops->del_beacon) | 2029 | if (!rdev->ops->del_beacon) |
1914 | return -EOPNOTSUPP; | 2030 | return -EOPNOTSUPP; |
@@ -1917,7 +2033,10 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1917 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 2033 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
1918 | return -EOPNOTSUPP; | 2034 | return -EOPNOTSUPP; |
1919 | 2035 | ||
1920 | return rdev->ops->del_beacon(&rdev->wiphy, dev); | 2036 | err = rdev->ops->del_beacon(&rdev->wiphy, dev); |
2037 | if (!err) | ||
2038 | wdev->beacon_interval = 0; | ||
2039 | return err; | ||
1921 | } | 2040 | } |
1922 | 2041 | ||
1923 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 2042 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -2216,6 +2335,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2216 | memset(¶ms, 0, sizeof(params)); | 2335 | memset(¶ms, 0, sizeof(params)); |
2217 | 2336 | ||
2218 | params.listen_interval = -1; | 2337 | params.listen_interval = -1; |
2338 | params.plink_state = -1; | ||
2219 | 2339 | ||
2220 | if (info->attrs[NL80211_ATTR_STA_AID]) | 2340 | if (info->attrs[NL80211_ATTR_STA_AID]) |
2221 | return -EINVAL; | 2341 | return -EINVAL; |
@@ -2247,6 +2367,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2247 | params.plink_action = | 2367 | params.plink_action = |
2248 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 2368 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
2249 | 2369 | ||
2370 | if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) | ||
2371 | params.plink_state = | ||
2372 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); | ||
2373 | |||
2250 | err = get_vlan(info, rdev, ¶ms.vlan); | 2374 | err = get_vlan(info, rdev, ¶ms.vlan); |
2251 | if (err) | 2375 | if (err) |
2252 | goto out; | 2376 | goto out; |
@@ -2286,10 +2410,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2286 | err = -EINVAL; | 2410 | err = -EINVAL; |
2287 | if (params.listen_interval >= 0) | 2411 | if (params.listen_interval >= 0) |
2288 | err = -EINVAL; | 2412 | err = -EINVAL; |
2289 | if (params.supported_rates) | ||
2290 | err = -EINVAL; | ||
2291 | if (params.sta_flags_mask & | 2413 | if (params.sta_flags_mask & |
2292 | ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | | 2414 | ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | |
2415 | BIT(NL80211_STA_FLAG_MFP) | | ||
2293 | BIT(NL80211_STA_FLAG_AUTHORIZED))) | 2416 | BIT(NL80211_STA_FLAG_AUTHORIZED))) |
2294 | err = -EINVAL; | 2417 | err = -EINVAL; |
2295 | break; | 2418 | break; |
@@ -2840,6 +2963,7 @@ static const struct nla_policy | |||
2840 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, | 2963 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, |
2841 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, | 2964 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, |
2842 | .len = IEEE80211_MAX_DATA_LEN }, | 2965 | .len = IEEE80211_MAX_DATA_LEN }, |
2966 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, | ||
2843 | }; | 2967 | }; |
2844 | 2968 | ||
2845 | static int nl80211_parse_mesh_config(struct genl_info *info, | 2969 | static int nl80211_parse_mesh_config(struct genl_info *info, |
@@ -2949,7 +3073,8 @@ static int nl80211_parse_mesh_setup(struct genl_info *info, | |||
2949 | setup->ie = nla_data(ieattr); | 3073 | setup->ie = nla_data(ieattr); |
2950 | setup->ie_len = nla_len(ieattr); | 3074 | setup->ie_len = nla_len(ieattr); |
2951 | } | 3075 | } |
2952 | setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]); | 3076 | setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]); |
3077 | setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]); | ||
2953 | 3078 | ||
2954 | return 0; | 3079 | return 0; |
2955 | } | 3080 | } |
@@ -3318,6 +3443,188 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3318 | return err; | 3443 | return err; |
3319 | } | 3444 | } |
3320 | 3445 | ||
3446 | static int nl80211_start_sched_scan(struct sk_buff *skb, | ||
3447 | struct genl_info *info) | ||
3448 | { | ||
3449 | struct cfg80211_sched_scan_request *request; | ||
3450 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
3451 | struct net_device *dev = info->user_ptr[1]; | ||
3452 | struct cfg80211_ssid *ssid; | ||
3453 | struct ieee80211_channel *channel; | ||
3454 | struct nlattr *attr; | ||
3455 | struct wiphy *wiphy; | ||
3456 | int err, tmp, n_ssids = 0, n_channels, i; | ||
3457 | u32 interval; | ||
3458 | enum ieee80211_band band; | ||
3459 | size_t ie_len; | ||
3460 | |||
3461 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | ||
3462 | !rdev->ops->sched_scan_start) | ||
3463 | return -EOPNOTSUPP; | ||
3464 | |||
3465 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3466 | return -EINVAL; | ||
3467 | |||
3468 | if (rdev->sched_scan_req) | ||
3469 | return -EINPROGRESS; | ||
3470 | |||
3471 | if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) | ||
3472 | return -EINVAL; | ||
3473 | |||
3474 | interval = nla_get_u32(info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]); | ||
3475 | if (interval == 0) | ||
3476 | return -EINVAL; | ||
3477 | |||
3478 | wiphy = &rdev->wiphy; | ||
3479 | |||
3480 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | ||
3481 | n_channels = validate_scan_freqs( | ||
3482 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); | ||
3483 | if (!n_channels) | ||
3484 | return -EINVAL; | ||
3485 | } else { | ||
3486 | n_channels = 0; | ||
3487 | |||
3488 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | ||
3489 | if (wiphy->bands[band]) | ||
3490 | n_channels += wiphy->bands[band]->n_channels; | ||
3491 | } | ||
3492 | |||
3493 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) | ||
3494 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], | ||
3495 | tmp) | ||
3496 | n_ssids++; | ||
3497 | |||
3498 | if (n_ssids > wiphy->max_scan_ssids) | ||
3499 | return -EINVAL; | ||
3500 | |||
3501 | if (info->attrs[NL80211_ATTR_IE]) | ||
3502 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
3503 | else | ||
3504 | ie_len = 0; | ||
3505 | |||
3506 | if (ie_len > wiphy->max_scan_ie_len) | ||
3507 | return -EINVAL; | ||
3508 | |||
3509 | request = kzalloc(sizeof(*request) | ||
3510 | + sizeof(*ssid) * n_ssids | ||
3511 | + sizeof(channel) * n_channels | ||
3512 | + ie_len, GFP_KERNEL); | ||
3513 | if (!request) | ||
3514 | return -ENOMEM; | ||
3515 | |||
3516 | if (n_ssids) | ||
3517 | request->ssids = (void *)&request->channels[n_channels]; | ||
3518 | request->n_ssids = n_ssids; | ||
3519 | if (ie_len) { | ||
3520 | if (request->ssids) | ||
3521 | request->ie = (void *)(request->ssids + n_ssids); | ||
3522 | else | ||
3523 | request->ie = (void *)(request->channels + n_channels); | ||
3524 | } | ||
3525 | |||
3526 | i = 0; | ||
3527 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | ||
3528 | /* user specified, bail out if channel not found */ | ||
3529 | nla_for_each_nested(attr, | ||
3530 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], | ||
3531 | tmp) { | ||
3532 | struct ieee80211_channel *chan; | ||
3533 | |||
3534 | chan = ieee80211_get_channel(wiphy, nla_get_u32(attr)); | ||
3535 | |||
3536 | if (!chan) { | ||
3537 | err = -EINVAL; | ||
3538 | goto out_free; | ||
3539 | } | ||
3540 | |||
3541 | /* ignore disabled channels */ | ||
3542 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
3543 | continue; | ||
3544 | |||
3545 | request->channels[i] = chan; | ||
3546 | i++; | ||
3547 | } | ||
3548 | } else { | ||
3549 | /* all channels */ | ||
3550 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
3551 | int j; | ||
3552 | if (!wiphy->bands[band]) | ||
3553 | continue; | ||
3554 | for (j = 0; j < wiphy->bands[band]->n_channels; j++) { | ||
3555 | struct ieee80211_channel *chan; | ||
3556 | |||
3557 | chan = &wiphy->bands[band]->channels[j]; | ||
3558 | |||
3559 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
3560 | continue; | ||
3561 | |||
3562 | request->channels[i] = chan; | ||
3563 | i++; | ||
3564 | } | ||
3565 | } | ||
3566 | } | ||
3567 | |||
3568 | if (!i) { | ||
3569 | err = -EINVAL; | ||
3570 | goto out_free; | ||
3571 | } | ||
3572 | |||
3573 | request->n_channels = i; | ||
3574 | |||
3575 | i = 0; | ||
3576 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { | ||
3577 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], | ||
3578 | tmp) { | ||
3579 | if (request->ssids[i].ssid_len > | ||
3580 | IEEE80211_MAX_SSID_LEN) { | ||
3581 | err = -EINVAL; | ||
3582 | goto out_free; | ||
3583 | } | ||
3584 | memcpy(request->ssids[i].ssid, nla_data(attr), | ||
3585 | nla_len(attr)); | ||
3586 | request->ssids[i].ssid_len = nla_len(attr); | ||
3587 | i++; | ||
3588 | } | ||
3589 | } | ||
3590 | |||
3591 | if (info->attrs[NL80211_ATTR_IE]) { | ||
3592 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
3593 | memcpy((void *)request->ie, | ||
3594 | nla_data(info->attrs[NL80211_ATTR_IE]), | ||
3595 | request->ie_len); | ||
3596 | } | ||
3597 | |||
3598 | request->dev = dev; | ||
3599 | request->wiphy = &rdev->wiphy; | ||
3600 | request->interval = interval; | ||
3601 | |||
3602 | err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); | ||
3603 | if (!err) { | ||
3604 | rdev->sched_scan_req = request; | ||
3605 | nl80211_send_sched_scan(rdev, dev, | ||
3606 | NL80211_CMD_START_SCHED_SCAN); | ||
3607 | goto out; | ||
3608 | } | ||
3609 | |||
3610 | out_free: | ||
3611 | kfree(request); | ||
3612 | out: | ||
3613 | return err; | ||
3614 | } | ||
3615 | |||
3616 | static int nl80211_stop_sched_scan(struct sk_buff *skb, | ||
3617 | struct genl_info *info) | ||
3618 | { | ||
3619 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
3620 | |||
3621 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | ||
3622 | !rdev->ops->sched_scan_stop) | ||
3623 | return -EOPNOTSUPP; | ||
3624 | |||
3625 | return __cfg80211_stop_sched_scan(rdev, false); | ||
3626 | } | ||
3627 | |||
3321 | static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 3628 | static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
3322 | struct cfg80211_registered_device *rdev, | 3629 | struct cfg80211_registered_device *rdev, |
3323 | struct wireless_dev *wdev, | 3630 | struct wireless_dev *wdev, |
@@ -4816,6 +5123,194 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
4816 | return cfg80211_leave_mesh(rdev, dev); | 5123 | return cfg80211_leave_mesh(rdev, dev); |
4817 | } | 5124 | } |
4818 | 5125 | ||
5126 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | ||
5127 | { | ||
5128 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5129 | struct sk_buff *msg; | ||
5130 | void *hdr; | ||
5131 | |||
5132 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | ||
5133 | return -EOPNOTSUPP; | ||
5134 | |||
5135 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
5136 | if (!msg) | ||
5137 | return -ENOMEM; | ||
5138 | |||
5139 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | ||
5140 | NL80211_CMD_GET_WOWLAN); | ||
5141 | if (!hdr) | ||
5142 | goto nla_put_failure; | ||
5143 | |||
5144 | if (rdev->wowlan) { | ||
5145 | struct nlattr *nl_wowlan; | ||
5146 | |||
5147 | nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); | ||
5148 | if (!nl_wowlan) | ||
5149 | goto nla_put_failure; | ||
5150 | |||
5151 | if (rdev->wowlan->any) | ||
5152 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); | ||
5153 | if (rdev->wowlan->disconnect) | ||
5154 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); | ||
5155 | if (rdev->wowlan->magic_pkt) | ||
5156 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); | ||
5157 | if (rdev->wowlan->n_patterns) { | ||
5158 | struct nlattr *nl_pats, *nl_pat; | ||
5159 | int i, pat_len; | ||
5160 | |||
5161 | nl_pats = nla_nest_start(msg, | ||
5162 | NL80211_WOWLAN_TRIG_PKT_PATTERN); | ||
5163 | if (!nl_pats) | ||
5164 | goto nla_put_failure; | ||
5165 | |||
5166 | for (i = 0; i < rdev->wowlan->n_patterns; i++) { | ||
5167 | nl_pat = nla_nest_start(msg, i + 1); | ||
5168 | if (!nl_pat) | ||
5169 | goto nla_put_failure; | ||
5170 | pat_len = rdev->wowlan->patterns[i].pattern_len; | ||
5171 | NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_MASK, | ||
5172 | DIV_ROUND_UP(pat_len, 8), | ||
5173 | rdev->wowlan->patterns[i].mask); | ||
5174 | NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_PATTERN, | ||
5175 | pat_len, | ||
5176 | rdev->wowlan->patterns[i].pattern); | ||
5177 | nla_nest_end(msg, nl_pat); | ||
5178 | } | ||
5179 | nla_nest_end(msg, nl_pats); | ||
5180 | } | ||
5181 | |||
5182 | nla_nest_end(msg, nl_wowlan); | ||
5183 | } | ||
5184 | |||
5185 | genlmsg_end(msg, hdr); | ||
5186 | return genlmsg_reply(msg, info); | ||
5187 | |||
5188 | nla_put_failure: | ||
5189 | nlmsg_free(msg); | ||
5190 | return -ENOBUFS; | ||
5191 | } | ||
5192 | |||
5193 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | ||
5194 | { | ||
5195 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5196 | struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; | ||
5197 | struct cfg80211_wowlan no_triggers = {}; | ||
5198 | struct cfg80211_wowlan new_triggers = {}; | ||
5199 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; | ||
5200 | int err, i; | ||
5201 | |||
5202 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | ||
5203 | return -EOPNOTSUPP; | ||
5204 | |||
5205 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) | ||
5206 | goto no_triggers; | ||
5207 | |||
5208 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, | ||
5209 | nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), | ||
5210 | nla_len(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), | ||
5211 | nl80211_wowlan_policy); | ||
5212 | if (err) | ||
5213 | return err; | ||
5214 | |||
5215 | if (tb[NL80211_WOWLAN_TRIG_ANY]) { | ||
5216 | if (!(wowlan->flags & WIPHY_WOWLAN_ANY)) | ||
5217 | return -EINVAL; | ||
5218 | new_triggers.any = true; | ||
5219 | } | ||
5220 | |||
5221 | if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) { | ||
5222 | if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT)) | ||
5223 | return -EINVAL; | ||
5224 | new_triggers.disconnect = true; | ||
5225 | } | ||
5226 | |||
5227 | if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) { | ||
5228 | if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT)) | ||
5229 | return -EINVAL; | ||
5230 | new_triggers.magic_pkt = true; | ||
5231 | } | ||
5232 | |||
5233 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { | ||
5234 | struct nlattr *pat; | ||
5235 | int n_patterns = 0; | ||
5236 | int rem, pat_len, mask_len; | ||
5237 | struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT]; | ||
5238 | |||
5239 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], | ||
5240 | rem) | ||
5241 | n_patterns++; | ||
5242 | if (n_patterns > wowlan->n_patterns) | ||
5243 | return -EINVAL; | ||
5244 | |||
5245 | new_triggers.patterns = kcalloc(n_patterns, | ||
5246 | sizeof(new_triggers.patterns[0]), | ||
5247 | GFP_KERNEL); | ||
5248 | if (!new_triggers.patterns) | ||
5249 | return -ENOMEM; | ||
5250 | |||
5251 | new_triggers.n_patterns = n_patterns; | ||
5252 | i = 0; | ||
5253 | |||
5254 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], | ||
5255 | rem) { | ||
5256 | nla_parse(pat_tb, MAX_NL80211_WOWLAN_PKTPAT, | ||
5257 | nla_data(pat), nla_len(pat), NULL); | ||
5258 | err = -EINVAL; | ||
5259 | if (!pat_tb[NL80211_WOWLAN_PKTPAT_MASK] || | ||
5260 | !pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]) | ||
5261 | goto error; | ||
5262 | pat_len = nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]); | ||
5263 | mask_len = DIV_ROUND_UP(pat_len, 8); | ||
5264 | if (nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]) != | ||
5265 | mask_len) | ||
5266 | goto error; | ||
5267 | if (pat_len > wowlan->pattern_max_len || | ||
5268 | pat_len < wowlan->pattern_min_len) | ||
5269 | goto error; | ||
5270 | |||
5271 | new_triggers.patterns[i].mask = | ||
5272 | kmalloc(mask_len + pat_len, GFP_KERNEL); | ||
5273 | if (!new_triggers.patterns[i].mask) { | ||
5274 | err = -ENOMEM; | ||
5275 | goto error; | ||
5276 | } | ||
5277 | new_triggers.patterns[i].pattern = | ||
5278 | new_triggers.patterns[i].mask + mask_len; | ||
5279 | memcpy(new_triggers.patterns[i].mask, | ||
5280 | nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]), | ||
5281 | mask_len); | ||
5282 | new_triggers.patterns[i].pattern_len = pat_len; | ||
5283 | memcpy(new_triggers.patterns[i].pattern, | ||
5284 | nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]), | ||
5285 | pat_len); | ||
5286 | i++; | ||
5287 | } | ||
5288 | } | ||
5289 | |||
5290 | if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) { | ||
5291 | struct cfg80211_wowlan *ntrig; | ||
5292 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), | ||
5293 | GFP_KERNEL); | ||
5294 | if (!ntrig) { | ||
5295 | err = -ENOMEM; | ||
5296 | goto error; | ||
5297 | } | ||
5298 | cfg80211_rdev_free_wowlan(rdev); | ||
5299 | rdev->wowlan = ntrig; | ||
5300 | } else { | ||
5301 | no_triggers: | ||
5302 | cfg80211_rdev_free_wowlan(rdev); | ||
5303 | rdev->wowlan = NULL; | ||
5304 | } | ||
5305 | |||
5306 | return 0; | ||
5307 | error: | ||
5308 | for (i = 0; i < new_triggers.n_patterns; i++) | ||
5309 | kfree(new_triggers.patterns[i].mask); | ||
5310 | kfree(new_triggers.patterns); | ||
5311 | return err; | ||
5312 | } | ||
5313 | |||
4819 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 5314 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
4820 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 5315 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
4821 | #define NL80211_FLAG_NEED_RTNL 0x04 | 5316 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -5100,6 +5595,22 @@ static struct genl_ops nl80211_ops[] = { | |||
5100 | .dumpit = nl80211_dump_scan, | 5595 | .dumpit = nl80211_dump_scan, |
5101 | }, | 5596 | }, |
5102 | { | 5597 | { |
5598 | .cmd = NL80211_CMD_START_SCHED_SCAN, | ||
5599 | .doit = nl80211_start_sched_scan, | ||
5600 | .policy = nl80211_policy, | ||
5601 | .flags = GENL_ADMIN_PERM, | ||
5602 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
5603 | NL80211_FLAG_NEED_RTNL, | ||
5604 | }, | ||
5605 | { | ||
5606 | .cmd = NL80211_CMD_STOP_SCHED_SCAN, | ||
5607 | .doit = nl80211_stop_sched_scan, | ||
5608 | .policy = nl80211_policy, | ||
5609 | .flags = GENL_ADMIN_PERM, | ||
5610 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
5611 | NL80211_FLAG_NEED_RTNL, | ||
5612 | }, | ||
5613 | { | ||
5103 | .cmd = NL80211_CMD_AUTHENTICATE, | 5614 | .cmd = NL80211_CMD_AUTHENTICATE, |
5104 | .doit = nl80211_authenticate, | 5615 | .doit = nl80211_authenticate, |
5105 | .policy = nl80211_policy, | 5616 | .policy = nl80211_policy, |
@@ -5314,6 +5825,22 @@ static struct genl_ops nl80211_ops[] = { | |||
5314 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 5825 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
5315 | NL80211_FLAG_NEED_RTNL, | 5826 | NL80211_FLAG_NEED_RTNL, |
5316 | }, | 5827 | }, |
5828 | { | ||
5829 | .cmd = NL80211_CMD_GET_WOWLAN, | ||
5830 | .doit = nl80211_get_wowlan, | ||
5831 | .policy = nl80211_policy, | ||
5832 | /* can be retrieved by unprivileged users */ | ||
5833 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
5834 | NL80211_FLAG_NEED_RTNL, | ||
5835 | }, | ||
5836 | { | ||
5837 | .cmd = NL80211_CMD_SET_WOWLAN, | ||
5838 | .doit = nl80211_set_wowlan, | ||
5839 | .policy = nl80211_policy, | ||
5840 | .flags = GENL_ADMIN_PERM, | ||
5841 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
5842 | NL80211_FLAG_NEED_RTNL, | ||
5843 | }, | ||
5317 | }; | 5844 | }; |
5318 | 5845 | ||
5319 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 5846 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -5409,6 +5936,28 @@ static int nl80211_send_scan_msg(struct sk_buff *msg, | |||
5409 | return -EMSGSIZE; | 5936 | return -EMSGSIZE; |
5410 | } | 5937 | } |
5411 | 5938 | ||
5939 | static int | ||
5940 | nl80211_send_sched_scan_msg(struct sk_buff *msg, | ||
5941 | struct cfg80211_registered_device *rdev, | ||
5942 | struct net_device *netdev, | ||
5943 | u32 pid, u32 seq, int flags, u32 cmd) | ||
5944 | { | ||
5945 | void *hdr; | ||
5946 | |||
5947 | hdr = nl80211hdr_put(msg, pid, seq, flags, cmd); | ||
5948 | if (!hdr) | ||
5949 | return -1; | ||
5950 | |||
5951 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
5952 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
5953 | |||
5954 | return genlmsg_end(msg, hdr); | ||
5955 | |||
5956 | nla_put_failure: | ||
5957 | genlmsg_cancel(msg, hdr); | ||
5958 | return -EMSGSIZE; | ||
5959 | } | ||
5960 | |||
5412 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | 5961 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, |
5413 | struct net_device *netdev) | 5962 | struct net_device *netdev) |
5414 | { | 5963 | { |
@@ -5466,6 +6015,43 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | |||
5466 | nl80211_scan_mcgrp.id, GFP_KERNEL); | 6015 | nl80211_scan_mcgrp.id, GFP_KERNEL); |
5467 | } | 6016 | } |
5468 | 6017 | ||
6018 | void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, | ||
6019 | struct net_device *netdev) | ||
6020 | { | ||
6021 | struct sk_buff *msg; | ||
6022 | |||
6023 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
6024 | if (!msg) | ||
6025 | return; | ||
6026 | |||
6027 | if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, | ||
6028 | NL80211_CMD_SCHED_SCAN_RESULTS) < 0) { | ||
6029 | nlmsg_free(msg); | ||
6030 | return; | ||
6031 | } | ||
6032 | |||
6033 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
6034 | nl80211_scan_mcgrp.id, GFP_KERNEL); | ||
6035 | } | ||
6036 | |||
6037 | void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | ||
6038 | struct net_device *netdev, u32 cmd) | ||
6039 | { | ||
6040 | struct sk_buff *msg; | ||
6041 | |||
6042 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
6043 | if (!msg) | ||
6044 | return; | ||
6045 | |||
6046 | if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) { | ||
6047 | nlmsg_free(msg); | ||
6048 | return; | ||
6049 | } | ||
6050 | |||
6051 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
6052 | nl80211_scan_mcgrp.id, GFP_KERNEL); | ||
6053 | } | ||
6054 | |||
5469 | /* | 6055 | /* |
5470 | * This can happen on global regulatory changes or device specific settings | 6056 | * This can happen on global regulatory changes or device specific settings |
5471 | * based on custom world regulatory domains. | 6057 | * based on custom world regulatory domains. |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index f2af6955a665..2f1bfb87a651 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -12,6 +12,10 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
12 | struct net_device *netdev); | 12 | struct net_device *netdev); |
13 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 13 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
14 | struct net_device *netdev); | 14 | struct net_device *netdev); |
15 | void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | ||
16 | struct net_device *netdev, u32 cmd); | ||
17 | void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, | ||
18 | struct net_device *netdev); | ||
15 | void nl80211_send_reg_change_event(struct regulatory_request *request); | 19 | void nl80211_send_reg_change_event(struct regulatory_request *request); |
16 | void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, | 20 | void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, |
17 | struct net_device *netdev, | 21 | struct net_device *netdev, |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 1613080a96b9..1ad0f39fe091 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -672,11 +672,9 @@ static int freq_reg_info_regd(struct wiphy *wiphy, | |||
672 | for (i = 0; i < regd->n_reg_rules; i++) { | 672 | for (i = 0; i < regd->n_reg_rules; i++) { |
673 | const struct ieee80211_reg_rule *rr; | 673 | const struct ieee80211_reg_rule *rr; |
674 | const struct ieee80211_freq_range *fr = NULL; | 674 | const struct ieee80211_freq_range *fr = NULL; |
675 | const struct ieee80211_power_rule *pr = NULL; | ||
676 | 675 | ||
677 | rr = ®d->reg_rules[i]; | 676 | rr = ®d->reg_rules[i]; |
678 | fr = &rr->freq_range; | 677 | fr = &rr->freq_range; |
679 | pr = &rr->power_rule; | ||
680 | 678 | ||
681 | /* | 679 | /* |
682 | * We only need to know if one frequency rule was | 680 | * We only need to know if one frequency rule was |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index fbf6f33ae4d0..73a441d237b5 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -93,6 +93,69 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | |||
93 | } | 93 | } |
94 | EXPORT_SYMBOL(cfg80211_scan_done); | 94 | EXPORT_SYMBOL(cfg80211_scan_done); |
95 | 95 | ||
96 | void __cfg80211_sched_scan_results(struct work_struct *wk) | ||
97 | { | ||
98 | struct cfg80211_registered_device *rdev; | ||
99 | |||
100 | rdev = container_of(wk, struct cfg80211_registered_device, | ||
101 | sched_scan_results_wk); | ||
102 | |||
103 | cfg80211_lock_rdev(rdev); | ||
104 | |||
105 | /* we don't have sched_scan_req anymore if the scan is stopping */ | ||
106 | if (rdev->sched_scan_req) | ||
107 | nl80211_send_sched_scan_results(rdev, | ||
108 | rdev->sched_scan_req->dev); | ||
109 | |||
110 | cfg80211_unlock_rdev(rdev); | ||
111 | } | ||
112 | |||
113 | void cfg80211_sched_scan_results(struct wiphy *wiphy) | ||
114 | { | ||
115 | /* ignore if we're not scanning */ | ||
116 | if (wiphy_to_dev(wiphy)->sched_scan_req) | ||
117 | queue_work(cfg80211_wq, | ||
118 | &wiphy_to_dev(wiphy)->sched_scan_results_wk); | ||
119 | } | ||
120 | EXPORT_SYMBOL(cfg80211_sched_scan_results); | ||
121 | |||
122 | void cfg80211_sched_scan_stopped(struct wiphy *wiphy) | ||
123 | { | ||
124 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
125 | |||
126 | cfg80211_lock_rdev(rdev); | ||
127 | __cfg80211_stop_sched_scan(rdev, true); | ||
128 | cfg80211_unlock_rdev(rdev); | ||
129 | } | ||
130 | EXPORT_SYMBOL(cfg80211_sched_scan_stopped); | ||
131 | |||
132 | int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, | ||
133 | bool driver_initiated) | ||
134 | { | ||
135 | int err; | ||
136 | struct net_device *dev; | ||
137 | |||
138 | ASSERT_RDEV_LOCK(rdev); | ||
139 | |||
140 | if (!rdev->sched_scan_req) | ||
141 | return 0; | ||
142 | |||
143 | dev = rdev->sched_scan_req->dev; | ||
144 | |||
145 | if (!driver_initiated) { | ||
146 | err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev); | ||
147 | if (err) | ||
148 | return err; | ||
149 | } | ||
150 | |||
151 | nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED); | ||
152 | |||
153 | kfree(rdev->sched_scan_req); | ||
154 | rdev->sched_scan_req = NULL; | ||
155 | |||
156 | return err; | ||
157 | } | ||
158 | |||
96 | static void bss_release(struct kref *ref) | 159 | static void bss_release(struct kref *ref) |
97 | { | 160 | { |
98 | struct cfg80211_internal_bss *bss; | 161 | struct cfg80211_internal_bss *bss; |
@@ -210,7 +273,7 @@ static bool is_mesh(struct cfg80211_bss *a, | |||
210 | { | 273 | { |
211 | const u8 *ie; | 274 | const u8 *ie; |
212 | 275 | ||
213 | if (!is_zero_ether_addr(a->bssid)) | 276 | if (!WLAN_CAPABILITY_IS_MBSS(a->capability)) |
214 | return false; | 277 | return false; |
215 | 278 | ||
216 | ie = cfg80211_find_ie(WLAN_EID_MESH_ID, | 279 | ie = cfg80211_find_ie(WLAN_EID_MESH_ID, |
@@ -248,11 +311,7 @@ static int cmp_bss(struct cfg80211_bss *a, | |||
248 | if (a->channel != b->channel) | 311 | if (a->channel != b->channel) |
249 | return b->channel->center_freq - a->channel->center_freq; | 312 | return b->channel->center_freq - a->channel->center_freq; |
250 | 313 | ||
251 | r = memcmp(a->bssid, b->bssid, ETH_ALEN); | 314 | if (WLAN_CAPABILITY_IS_MBSS(a->capability | b->capability)) { |
252 | if (r) | ||
253 | return r; | ||
254 | |||
255 | if (is_zero_ether_addr(a->bssid)) { | ||
256 | r = cmp_ies(WLAN_EID_MESH_ID, | 315 | r = cmp_ies(WLAN_EID_MESH_ID, |
257 | a->information_elements, | 316 | a->information_elements, |
258 | a->len_information_elements, | 317 | a->len_information_elements, |
@@ -267,6 +326,10 @@ static int cmp_bss(struct cfg80211_bss *a, | |||
267 | b->len_information_elements); | 326 | b->len_information_elements); |
268 | } | 327 | } |
269 | 328 | ||
329 | r = memcmp(a->bssid, b->bssid, ETH_ALEN); | ||
330 | if (r) | ||
331 | return r; | ||
332 | |||
270 | return cmp_ies(WLAN_EID_SSID, | 333 | return cmp_ies(WLAN_EID_SSID, |
271 | a->information_elements, | 334 | a->information_elements, |
272 | a->len_information_elements, | 335 | a->len_information_elements, |
@@ -407,7 +470,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
407 | 470 | ||
408 | res->ts = jiffies; | 471 | res->ts = jiffies; |
409 | 472 | ||
410 | if (is_zero_ether_addr(res->pub.bssid)) { | 473 | if (WLAN_CAPABILITY_IS_MBSS(res->pub.capability)) { |
411 | /* must be mesh, verify */ | 474 | /* must be mesh, verify */ |
412 | meshid = cfg80211_find_ie(WLAN_EID_MESH_ID, | 475 | meshid = cfg80211_find_ie(WLAN_EID_MESH_ID, |
413 | res->pub.information_elements, | 476 | res->pub.information_elements, |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 4294fa22bb2d..c6e4ca6a7d2e 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -93,7 +93,7 @@ static int wiphy_suspend(struct device *dev, pm_message_t state) | |||
93 | 93 | ||
94 | if (rdev->ops->suspend) { | 94 | if (rdev->ops->suspend) { |
95 | rtnl_lock(); | 95 | rtnl_lock(); |
96 | ret = rdev->ops->suspend(&rdev->wiphy); | 96 | ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan); |
97 | rtnl_unlock(); | 97 | rtnl_unlock(); |
98 | } | 98 | } |
99 | 99 | ||
diff --git a/net/wireless/util.c b/net/wireless/util.c index 6a750bc6bcfe..f0536d44d43c 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -544,7 +544,8 @@ EXPORT_SYMBOL(ieee80211_data_from_8023); | |||
544 | 544 | ||
545 | void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, | 545 | void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, |
546 | const u8 *addr, enum nl80211_iftype iftype, | 546 | const u8 *addr, enum nl80211_iftype iftype, |
547 | const unsigned int extra_headroom) | 547 | const unsigned int extra_headroom, |
548 | bool has_80211_header) | ||
548 | { | 549 | { |
549 | struct sk_buff *frame = NULL; | 550 | struct sk_buff *frame = NULL; |
550 | u16 ethertype; | 551 | u16 ethertype; |
@@ -553,14 +554,18 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, | |||
553 | int remaining, err; | 554 | int remaining, err; |
554 | u8 dst[ETH_ALEN], src[ETH_ALEN]; | 555 | u8 dst[ETH_ALEN], src[ETH_ALEN]; |
555 | 556 | ||
556 | err = ieee80211_data_to_8023(skb, addr, iftype); | 557 | if (has_80211_header) { |
557 | if (err) | 558 | err = ieee80211_data_to_8023(skb, addr, iftype); |
558 | goto out; | 559 | if (err) |
560 | goto out; | ||
559 | 561 | ||
560 | /* skip the wrapping header */ | 562 | /* skip the wrapping header */ |
561 | eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); | 563 | eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); |
562 | if (!eth) | 564 | if (!eth) |
563 | goto out; | 565 | goto out; |
566 | } else { | ||
567 | eth = (struct ethhdr *) skb->data; | ||
568 | } | ||
564 | 569 | ||
565 | while (skb != frame) { | 570 | while (skb != frame) { |
566 | u8 padding; | 571 | u8 padding; |
@@ -803,6 +808,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
803 | return -EBUSY; | 808 | return -EBUSY; |
804 | 809 | ||
805 | if (ntype != otype) { | 810 | if (ntype != otype) { |
811 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, | ||
812 | ntype); | ||
813 | if (err) | ||
814 | return err; | ||
815 | |||
806 | dev->ieee80211_ptr->use_4addr = false; | 816 | dev->ieee80211_ptr->use_4addr = false; |
807 | dev->ieee80211_ptr->mesh_id_up_len = 0; | 817 | dev->ieee80211_ptr->mesh_id_up_len = 0; |
808 | 818 | ||
@@ -896,3 +906,103 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate) | |||
896 | /* do NOT round down here */ | 906 | /* do NOT round down here */ |
897 | return (bitrate + 50000) / 100000; | 907 | return (bitrate + 50000) / 100000; |
898 | } | 908 | } |
909 | |||
910 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | ||
911 | u32 beacon_int) | ||
912 | { | ||
913 | struct wireless_dev *wdev; | ||
914 | int res = 0; | ||
915 | |||
916 | if (!beacon_int) | ||
917 | return -EINVAL; | ||
918 | |||
919 | mutex_lock(&rdev->devlist_mtx); | ||
920 | |||
921 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | ||
922 | if (!wdev->beacon_interval) | ||
923 | continue; | ||
924 | if (wdev->beacon_interval != beacon_int) { | ||
925 | res = -EINVAL; | ||
926 | break; | ||
927 | } | ||
928 | } | ||
929 | |||
930 | mutex_unlock(&rdev->devlist_mtx); | ||
931 | |||
932 | return res; | ||
933 | } | ||
934 | |||
935 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | ||
936 | struct wireless_dev *wdev, | ||
937 | enum nl80211_iftype iftype) | ||
938 | { | ||
939 | struct wireless_dev *wdev_iter; | ||
940 | int num[NUM_NL80211_IFTYPES]; | ||
941 | int total = 1; | ||
942 | int i, j; | ||
943 | |||
944 | ASSERT_RTNL(); | ||
945 | |||
946 | /* Always allow software iftypes */ | ||
947 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | ||
948 | return 0; | ||
949 | |||
950 | /* | ||
951 | * Drivers will gradually all set this flag, until all | ||
952 | * have it we only enforce for those that set it. | ||
953 | */ | ||
954 | if (!(rdev->wiphy.flags & WIPHY_FLAG_ENFORCE_COMBINATIONS)) | ||
955 | return 0; | ||
956 | |||
957 | memset(num, 0, sizeof(num)); | ||
958 | |||
959 | num[iftype] = 1; | ||
960 | |||
961 | mutex_lock(&rdev->devlist_mtx); | ||
962 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { | ||
963 | if (wdev_iter == wdev) | ||
964 | continue; | ||
965 | if (!netif_running(wdev_iter->netdev)) | ||
966 | continue; | ||
967 | |||
968 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) | ||
969 | continue; | ||
970 | |||
971 | num[wdev_iter->iftype]++; | ||
972 | total++; | ||
973 | } | ||
974 | mutex_unlock(&rdev->devlist_mtx); | ||
975 | |||
976 | for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { | ||
977 | const struct ieee80211_iface_combination *c; | ||
978 | struct ieee80211_iface_limit *limits; | ||
979 | |||
980 | c = &rdev->wiphy.iface_combinations[i]; | ||
981 | |||
982 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, | ||
983 | GFP_KERNEL); | ||
984 | if (!limits) | ||
985 | return -ENOMEM; | ||
986 | if (total > c->max_interfaces) | ||
987 | goto cont; | ||
988 | |||
989 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { | ||
990 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | ||
991 | continue; | ||
992 | for (j = 0; j < c->n_limits; j++) { | ||
993 | if (!(limits[j].types & iftype)) | ||
994 | continue; | ||
995 | if (limits[j].max < num[iftype]) | ||
996 | goto cont; | ||
997 | limits[j].max -= num[iftype]; | ||
998 | } | ||
999 | } | ||
1000 | /* yay, it fits */ | ||
1001 | kfree(limits); | ||
1002 | return 0; | ||
1003 | cont: | ||
1004 | kfree(limits); | ||
1005 | } | ||
1006 | |||
1007 | return -EBUSY; | ||
1008 | } | ||