diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-02-08 13:16:17 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-02-08 13:16:17 -0500 |
commit | f5237f278f30a92401539a54f87ee0c717b6f818 (patch) | |
tree | 209d4fd6fb00e660c76ca8ac5d4caed59dbb9957 /net | |
parent | b285109dde7b873b5dc671ef1b3ae3090f4bc72f (diff) | |
parent | b26f5f09ebdeb85ab152344cc1d6d484a3ce967d (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/a2mp.c | 42 | ||||
-rw-r--r-- | net/bluetooth/amp.c | 25 | ||||
-rw-r--r-- | net/bluetooth/bnep/core.c | 1 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 30 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 64 | ||||
-rw-r--r-- | net/bluetooth/hci_sysfs.c | 22 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 5 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 489 | ||||
-rw-r--r-- | net/bluetooth/sco.c | 18 | ||||
-rw-r--r-- | net/mac80211/agg-rx.c | 14 | ||||
-rw-r--r-- | net/mac80211/agg-tx.c | 61 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 36 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/iface.c | 3 | ||||
-rw-r--r-- | net/mac80211/key.c | 5 | ||||
-rw-r--r-- | net/mac80211/main.c | 64 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 168 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 42 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 5 | ||||
-rw-r--r-- | net/mac80211/trace.h | 53 | ||||
-rw-r--r-- | net/mac80211/tx.c | 8 | ||||
-rw-r--r-- | net/wireless/core.c | 5 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 116 | ||||
-rw-r--r-- | net/wireless/rdev-ops.h | 12 | ||||
-rw-r--r-- | net/wireless/trace.h | 18 | ||||
-rw-r--r-- | net/wireless/util.c | 3 |
26 files changed, 933 insertions, 379 deletions
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 2f67d5ecc907..eb0f4b16ff09 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c | |||
@@ -290,7 +290,7 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb, | |||
290 | goto done; | 290 | goto done; |
291 | } | 291 | } |
292 | 292 | ||
293 | mgr->state = READ_LOC_AMP_INFO; | 293 | set_bit(READ_LOC_AMP_INFO, &mgr->state); |
294 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); | 294 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); |
295 | 295 | ||
296 | done: | 296 | done: |
@@ -499,8 +499,16 @@ send_rsp: | |||
499 | if (hdev) | 499 | if (hdev) |
500 | hci_dev_put(hdev); | 500 | hci_dev_put(hdev); |
501 | 501 | ||
502 | a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, sizeof(rsp), | 502 | /* Reply error now and success after HCI Write Remote AMP Assoc |
503 | &rsp); | 503 | command complete with success status |
504 | */ | ||
505 | if (rsp.status != A2MP_STATUS_SUCCESS) { | ||
506 | a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, | ||
507 | sizeof(rsp), &rsp); | ||
508 | } else { | ||
509 | set_bit(WRITE_REMOTE_AMP_ASSOC, &mgr->state); | ||
510 | mgr->ident = hdr->ident; | ||
511 | } | ||
504 | 512 | ||
505 | skb_pull(skb, le16_to_cpu(hdr->len)); | 513 | skb_pull(skb, le16_to_cpu(hdr->len)); |
506 | return 0; | 514 | return 0; |
@@ -840,7 +848,7 @@ struct amp_mgr *amp_mgr_lookup_by_state(u8 state) | |||
840 | 848 | ||
841 | mutex_lock(&_mgr_list_lock); | 849 | mutex_lock(&_mgr_list_lock); |
842 | list_for_each_entry(mgr, &_mgr_list, list) { | 850 | list_for_each_entry(mgr, &_mgr_list, list) { |
843 | if (mgr->state == state) { | 851 | if (test_and_clear_bit(state, &mgr->state)) { |
844 | amp_mgr_get(mgr); | 852 | amp_mgr_get(mgr); |
845 | mutex_unlock(&_mgr_list_lock); | 853 | mutex_unlock(&_mgr_list_lock); |
846 | return mgr; | 854 | return mgr; |
@@ -949,6 +957,32 @@ clean: | |||
949 | kfree(req); | 957 | kfree(req); |
950 | } | 958 | } |
951 | 959 | ||
960 | void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status) | ||
961 | { | ||
962 | struct amp_mgr *mgr; | ||
963 | struct a2mp_physlink_rsp rsp; | ||
964 | struct hci_conn *hs_hcon; | ||
965 | |||
966 | mgr = amp_mgr_lookup_by_state(WRITE_REMOTE_AMP_ASSOC); | ||
967 | if (!mgr) | ||
968 | return; | ||
969 | |||
970 | hs_hcon = hci_conn_hash_lookup_state(hdev, AMP_LINK, BT_CONNECT); | ||
971 | if (!hs_hcon) { | ||
972 | rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION; | ||
973 | } else { | ||
974 | rsp.remote_id = hs_hcon->remote_id; | ||
975 | rsp.status = A2MP_STATUS_SUCCESS; | ||
976 | } | ||
977 | |||
978 | BT_DBG("%s mgr %p hs_hcon %p status %u", hdev->name, mgr, hs_hcon, | ||
979 | status); | ||
980 | |||
981 | rsp.local_id = hdev->id; | ||
982 | a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, mgr->ident, sizeof(rsp), &rsp); | ||
983 | amp_mgr_put(mgr); | ||
984 | } | ||
985 | |||
952 | void a2mp_discover_amp(struct l2cap_chan *chan) | 986 | void a2mp_discover_amp(struct l2cap_chan *chan) |
953 | { | 987 | { |
954 | struct l2cap_conn *conn = chan->conn; | 988 | struct l2cap_conn *conn = chan->conn; |
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 1b0d92c0643a..d459ed43c779 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c | |||
@@ -236,7 +236,7 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) | |||
236 | 236 | ||
237 | cp.max_len = cpu_to_le16(hdev->amp_assoc_size); | 237 | cp.max_len = cpu_to_le16(hdev->amp_assoc_size); |
238 | 238 | ||
239 | mgr->state = READ_LOC_AMP_ASSOC; | 239 | set_bit(READ_LOC_AMP_ASSOC, &mgr->state); |
240 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); | 240 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); |
241 | } | 241 | } |
242 | 242 | ||
@@ -250,7 +250,7 @@ void amp_read_loc_assoc_final_data(struct hci_dev *hdev, | |||
250 | cp.len_so_far = cpu_to_le16(0); | 250 | cp.len_so_far = cpu_to_le16(0); |
251 | cp.max_len = cpu_to_le16(hdev->amp_assoc_size); | 251 | cp.max_len = cpu_to_le16(hdev->amp_assoc_size); |
252 | 252 | ||
253 | mgr->state = READ_LOC_AMP_ASSOC_FINAL; | 253 | set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state); |
254 | 254 | ||
255 | /* Read Local AMP Assoc final link information data */ | 255 | /* Read Local AMP Assoc final link information data */ |
256 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); | 256 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); |
@@ -317,7 +317,9 @@ void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle) | |||
317 | if (!hcon) | 317 | if (!hcon) |
318 | return; | 318 | return; |
319 | 319 | ||
320 | amp_write_rem_assoc_frag(hdev, hcon); | 320 | /* Send A2MP create phylink rsp when all fragments are written */ |
321 | if (amp_write_rem_assoc_frag(hdev, hcon)) | ||
322 | a2mp_send_create_phy_link_rsp(hdev, 0); | ||
321 | } | 323 | } |
322 | 324 | ||
323 | void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle) | 325 | void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle) |
@@ -403,26 +405,20 @@ void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) | |||
403 | 405 | ||
404 | void amp_create_logical_link(struct l2cap_chan *chan) | 406 | void amp_create_logical_link(struct l2cap_chan *chan) |
405 | { | 407 | { |
408 | struct hci_conn *hs_hcon = chan->hs_hcon; | ||
406 | struct hci_cp_create_accept_logical_link cp; | 409 | struct hci_cp_create_accept_logical_link cp; |
407 | struct hci_conn *hcon; | ||
408 | struct hci_dev *hdev; | 410 | struct hci_dev *hdev; |
409 | 411 | ||
410 | BT_DBG("chan %p", chan); | 412 | BT_DBG("chan %p hs_hcon %p dst %pMR", chan, hs_hcon, chan->conn->dst); |
411 | 413 | ||
412 | if (!chan->hs_hcon) | 414 | if (!hs_hcon) |
413 | return; | 415 | return; |
414 | 416 | ||
415 | hdev = hci_dev_hold(chan->hs_hcon->hdev); | 417 | hdev = hci_dev_hold(chan->hs_hcon->hdev); |
416 | if (!hdev) | 418 | if (!hdev) |
417 | return; | 419 | return; |
418 | 420 | ||
419 | BT_DBG("chan %p dst %pMR", chan, chan->conn->dst); | 421 | cp.phy_handle = hs_hcon->handle; |
420 | |||
421 | hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, chan->conn->dst); | ||
422 | if (!hcon) | ||
423 | goto done; | ||
424 | |||
425 | cp.phy_handle = hcon->handle; | ||
426 | 422 | ||
427 | cp.tx_flow_spec.id = chan->local_id; | 423 | cp.tx_flow_spec.id = chan->local_id; |
428 | cp.tx_flow_spec.stype = chan->local_stype; | 424 | cp.tx_flow_spec.stype = chan->local_stype; |
@@ -438,14 +434,13 @@ void amp_create_logical_link(struct l2cap_chan *chan) | |||
438 | cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat); | 434 | cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat); |
439 | cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to); | 435 | cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to); |
440 | 436 | ||
441 | if (hcon->out) | 437 | if (hs_hcon->out) |
442 | hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp), | 438 | hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp), |
443 | &cp); | 439 | &cp); |
444 | else | 440 | else |
445 | hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp), | 441 | hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp), |
446 | &cp); | 442 | &cp); |
447 | 443 | ||
448 | done: | ||
449 | hci_dev_put(hdev); | 444 | hci_dev_put(hdev); |
450 | } | 445 | } |
451 | 446 | ||
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index a5b639702637..e430b1abcd2f 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c | |||
@@ -33,7 +33,6 @@ | |||
33 | 33 | ||
34 | #include <net/bluetooth/bluetooth.h> | 34 | #include <net/bluetooth/bluetooth.h> |
35 | #include <net/bluetooth/hci_core.h> | 35 | #include <net/bluetooth/hci_core.h> |
36 | #include <net/bluetooth/l2cap.h> | ||
37 | 36 | ||
38 | #include "bnep.h" | 37 | #include "bnep.h" |
39 | 38 | ||
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 0f78e34220c9..22e77a786545 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -1146,7 +1146,8 @@ static void hci_power_on(struct work_struct *work) | |||
1146 | return; | 1146 | return; |
1147 | 1147 | ||
1148 | if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) | 1148 | if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) |
1149 | schedule_delayed_work(&hdev->power_off, HCI_AUTO_OFF_TIMEOUT); | 1149 | queue_delayed_work(hdev->req_workqueue, &hdev->power_off, |
1150 | HCI_AUTO_OFF_TIMEOUT); | ||
1150 | 1151 | ||
1151 | if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) | 1152 | if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) |
1152 | mgmt_index_added(hdev); | 1153 | mgmt_index_added(hdev); |
@@ -1182,14 +1183,10 @@ static void hci_discov_off(struct work_struct *work) | |||
1182 | 1183 | ||
1183 | int hci_uuids_clear(struct hci_dev *hdev) | 1184 | int hci_uuids_clear(struct hci_dev *hdev) |
1184 | { | 1185 | { |
1185 | struct list_head *p, *n; | 1186 | struct bt_uuid *uuid, *tmp; |
1186 | |||
1187 | list_for_each_safe(p, n, &hdev->uuids) { | ||
1188 | struct bt_uuid *uuid; | ||
1189 | 1187 | ||
1190 | uuid = list_entry(p, struct bt_uuid, list); | 1188 | list_for_each_entry_safe(uuid, tmp, &hdev->uuids, list) { |
1191 | 1189 | list_del(&uuid->list); | |
1192 | list_del(p); | ||
1193 | kfree(uuid); | 1190 | kfree(uuid); |
1194 | } | 1191 | } |
1195 | 1192 | ||
@@ -1621,8 +1618,8 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, | |||
1621 | if (err < 0) | 1618 | if (err < 0) |
1622 | return err; | 1619 | return err; |
1623 | 1620 | ||
1624 | schedule_delayed_work(&hdev->le_scan_disable, | 1621 | queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, |
1625 | msecs_to_jiffies(timeout)); | 1622 | msecs_to_jiffies(timeout)); |
1626 | 1623 | ||
1627 | return 0; | 1624 | return 0; |
1628 | } | 1625 | } |
@@ -1799,6 +1796,15 @@ int hci_register_dev(struct hci_dev *hdev) | |||
1799 | goto err; | 1796 | goto err; |
1800 | } | 1797 | } |
1801 | 1798 | ||
1799 | hdev->req_workqueue = alloc_workqueue(hdev->name, | ||
1800 | WQ_HIGHPRI | WQ_UNBOUND | | ||
1801 | WQ_MEM_RECLAIM, 1); | ||
1802 | if (!hdev->req_workqueue) { | ||
1803 | destroy_workqueue(hdev->workqueue); | ||
1804 | error = -ENOMEM; | ||
1805 | goto err; | ||
1806 | } | ||
1807 | |||
1802 | error = hci_add_sysfs(hdev); | 1808 | error = hci_add_sysfs(hdev); |
1803 | if (error < 0) | 1809 | if (error < 0) |
1804 | goto err_wqueue; | 1810 | goto err_wqueue; |
@@ -1821,12 +1827,13 @@ int hci_register_dev(struct hci_dev *hdev) | |||
1821 | hci_notify(hdev, HCI_DEV_REG); | 1827 | hci_notify(hdev, HCI_DEV_REG); |
1822 | hci_dev_hold(hdev); | 1828 | hci_dev_hold(hdev); |
1823 | 1829 | ||
1824 | schedule_work(&hdev->power_on); | 1830 | queue_work(hdev->req_workqueue, &hdev->power_on); |
1825 | 1831 | ||
1826 | return id; | 1832 | return id; |
1827 | 1833 | ||
1828 | err_wqueue: | 1834 | err_wqueue: |
1829 | destroy_workqueue(hdev->workqueue); | 1835 | destroy_workqueue(hdev->workqueue); |
1836 | destroy_workqueue(hdev->req_workqueue); | ||
1830 | err: | 1837 | err: |
1831 | ida_simple_remove(&hci_index_ida, hdev->id); | 1838 | ida_simple_remove(&hci_index_ida, hdev->id); |
1832 | write_lock(&hci_dev_list_lock); | 1839 | write_lock(&hci_dev_list_lock); |
@@ -1880,6 +1887,7 @@ void hci_unregister_dev(struct hci_dev *hdev) | |||
1880 | hci_del_sysfs(hdev); | 1887 | hci_del_sysfs(hdev); |
1881 | 1888 | ||
1882 | destroy_workqueue(hdev->workqueue); | 1889 | destroy_workqueue(hdev->workqueue); |
1890 | destroy_workqueue(hdev->req_workqueue); | ||
1883 | 1891 | ||
1884 | hci_dev_lock(hdev); | 1892 | hci_dev_lock(hdev); |
1885 | hci_blacklist_clear(hdev); | 1893 | hci_blacklist_clear(hdev); |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 81b44481d0d9..477726a63512 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -609,8 +609,17 @@ static void le_setup(struct hci_dev *hdev) | |||
609 | /* Read LE Buffer Size */ | 609 | /* Read LE Buffer Size */ |
610 | hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL); | 610 | hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL); |
611 | 611 | ||
612 | /* Read LE Local Supported Features */ | ||
613 | hci_send_cmd(hdev, HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL); | ||
614 | |||
612 | /* Read LE Advertising Channel TX Power */ | 615 | /* Read LE Advertising Channel TX Power */ |
613 | hci_send_cmd(hdev, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); | 616 | hci_send_cmd(hdev, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); |
617 | |||
618 | /* Read LE White List Size */ | ||
619 | hci_send_cmd(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL); | ||
620 | |||
621 | /* Read LE Supported States */ | ||
622 | hci_send_cmd(hdev, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL); | ||
614 | } | 623 | } |
615 | 624 | ||
616 | static void hci_setup(struct hci_dev *hdev) | 625 | static void hci_setup(struct hci_dev *hdev) |
@@ -1090,6 +1099,19 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev, | |||
1090 | hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status); | 1099 | hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status); |
1091 | } | 1100 | } |
1092 | 1101 | ||
1102 | static void hci_cc_le_read_local_features(struct hci_dev *hdev, | ||
1103 | struct sk_buff *skb) | ||
1104 | { | ||
1105 | struct hci_rp_le_read_local_features *rp = (void *) skb->data; | ||
1106 | |||
1107 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | ||
1108 | |||
1109 | if (!rp->status) | ||
1110 | memcpy(hdev->le_features, rp->features, 8); | ||
1111 | |||
1112 | hci_req_complete(hdev, HCI_OP_LE_READ_LOCAL_FEATURES, rp->status); | ||
1113 | } | ||
1114 | |||
1093 | static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, | 1115 | static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, |
1094 | struct sk_buff *skb) | 1116 | struct sk_buff *skb) |
1095 | { | 1117 | { |
@@ -1290,6 +1312,19 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, | |||
1290 | } | 1312 | } |
1291 | } | 1313 | } |
1292 | 1314 | ||
1315 | static void hci_cc_le_read_white_list_size(struct hci_dev *hdev, | ||
1316 | struct sk_buff *skb) | ||
1317 | { | ||
1318 | struct hci_rp_le_read_white_list_size *rp = (void *) skb->data; | ||
1319 | |||
1320 | BT_DBG("%s status 0x%2.2x size %u", hdev->name, rp->status, rp->size); | ||
1321 | |||
1322 | if (!rp->status) | ||
1323 | hdev->le_white_list_size = rp->size; | ||
1324 | |||
1325 | hci_req_complete(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, rp->status); | ||
1326 | } | ||
1327 | |||
1293 | static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb) | 1328 | static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb) |
1294 | { | 1329 | { |
1295 | struct hci_rp_le_ltk_reply *rp = (void *) skb->data; | 1330 | struct hci_rp_le_ltk_reply *rp = (void *) skb->data; |
@@ -1314,6 +1349,19 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) | |||
1314 | hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status); | 1349 | hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status); |
1315 | } | 1350 | } |
1316 | 1351 | ||
1352 | static void hci_cc_le_read_supported_states(struct hci_dev *hdev, | ||
1353 | struct sk_buff *skb) | ||
1354 | { | ||
1355 | struct hci_rp_le_read_supported_states *rp = (void *) skb->data; | ||
1356 | |||
1357 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | ||
1358 | |||
1359 | if (!rp->status) | ||
1360 | memcpy(hdev->le_states, rp->le_states, 8); | ||
1361 | |||
1362 | hci_req_complete(hdev, HCI_OP_LE_READ_SUPPORTED_STATES, rp->status); | ||
1363 | } | ||
1364 | |||
1317 | static void hci_cc_write_le_host_supported(struct hci_dev *hdev, | 1365 | static void hci_cc_write_le_host_supported(struct hci_dev *hdev, |
1318 | struct sk_buff *skb) | 1366 | struct sk_buff *skb) |
1319 | { | 1367 | { |
@@ -2628,6 +2676,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
2628 | hci_cc_le_read_buffer_size(hdev, skb); | 2676 | hci_cc_le_read_buffer_size(hdev, skb); |
2629 | break; | 2677 | break; |
2630 | 2678 | ||
2679 | case HCI_OP_LE_READ_LOCAL_FEATURES: | ||
2680 | hci_cc_le_read_local_features(hdev, skb); | ||
2681 | break; | ||
2682 | |||
2631 | case HCI_OP_LE_READ_ADV_TX_POWER: | 2683 | case HCI_OP_LE_READ_ADV_TX_POWER: |
2632 | hci_cc_le_read_adv_tx_power(hdev, skb); | 2684 | hci_cc_le_read_adv_tx_power(hdev, skb); |
2633 | break; | 2685 | break; |
@@ -2664,6 +2716,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
2664 | hci_cc_le_set_scan_enable(hdev, skb); | 2716 | hci_cc_le_set_scan_enable(hdev, skb); |
2665 | break; | 2717 | break; |
2666 | 2718 | ||
2719 | case HCI_OP_LE_READ_WHITE_LIST_SIZE: | ||
2720 | hci_cc_le_read_white_list_size(hdev, skb); | ||
2721 | break; | ||
2722 | |||
2667 | case HCI_OP_LE_LTK_REPLY: | 2723 | case HCI_OP_LE_LTK_REPLY: |
2668 | hci_cc_le_ltk_reply(hdev, skb); | 2724 | hci_cc_le_ltk_reply(hdev, skb); |
2669 | break; | 2725 | break; |
@@ -2672,6 +2728,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
2672 | hci_cc_le_ltk_neg_reply(hdev, skb); | 2728 | hci_cc_le_ltk_neg_reply(hdev, skb); |
2673 | break; | 2729 | break; |
2674 | 2730 | ||
2731 | case HCI_OP_LE_READ_SUPPORTED_STATES: | ||
2732 | hci_cc_le_read_supported_states(hdev, skb); | ||
2733 | break; | ||
2734 | |||
2675 | case HCI_OP_WRITE_LE_HOST_SUPPORTED: | 2735 | case HCI_OP_WRITE_LE_HOST_SUPPORTED: |
2676 | hci_cc_write_le_host_supported(hdev, skb); | 2736 | hci_cc_write_le_host_supported(hdev, skb); |
2677 | break; | 2737 | break; |
@@ -3928,8 +3988,6 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
3928 | void *ptr = &skb->data[1]; | 3988 | void *ptr = &skb->data[1]; |
3929 | s8 rssi; | 3989 | s8 rssi; |
3930 | 3990 | ||
3931 | hci_dev_lock(hdev); | ||
3932 | |||
3933 | while (num_reports--) { | 3991 | while (num_reports--) { |
3934 | struct hci_ev_le_advertising_info *ev = ptr; | 3992 | struct hci_ev_le_advertising_info *ev = ptr; |
3935 | 3993 | ||
@@ -3939,8 +3997,6 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
3939 | 3997 | ||
3940 | ptr += sizeof(*ev) + ev->length + 1; | 3998 | ptr += sizeof(*ev) + ev->length + 1; |
3941 | } | 3999 | } |
3942 | |||
3943 | hci_dev_unlock(hdev); | ||
3944 | } | 4000 | } |
3945 | 4001 | ||
3946 | static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | 4002 | static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) |
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 55cceee02a84..23b4e242a31a 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | #include <linux/debugfs.h> | 3 | #include <linux/debugfs.h> |
4 | #include <linux/module.h> | 4 | #include <linux/module.h> |
5 | #include <asm/unaligned.h> | ||
5 | 6 | ||
6 | #include <net/bluetooth/bluetooth.h> | 7 | #include <net/bluetooth/bluetooth.h> |
7 | #include <net/bluetooth/hci_core.h> | 8 | #include <net/bluetooth/hci_core.h> |
@@ -461,19 +462,18 @@ static const struct file_operations blacklist_fops = { | |||
461 | 462 | ||
462 | static void print_bt_uuid(struct seq_file *f, u8 *uuid) | 463 | static void print_bt_uuid(struct seq_file *f, u8 *uuid) |
463 | { | 464 | { |
464 | __be32 data0, data4; | 465 | u32 data0, data5; |
465 | __be16 data1, data2, data3, data5; | 466 | u16 data1, data2, data3, data4; |
466 | 467 | ||
467 | memcpy(&data0, &uuid[0], 4); | 468 | data5 = get_unaligned_le32(uuid); |
468 | memcpy(&data1, &uuid[4], 2); | 469 | data4 = get_unaligned_le16(uuid + 4); |
469 | memcpy(&data2, &uuid[6], 2); | 470 | data3 = get_unaligned_le16(uuid + 6); |
470 | memcpy(&data3, &uuid[8], 2); | 471 | data2 = get_unaligned_le16(uuid + 8); |
471 | memcpy(&data4, &uuid[10], 4); | 472 | data1 = get_unaligned_le16(uuid + 10); |
472 | memcpy(&data5, &uuid[14], 2); | 473 | data0 = get_unaligned_le32(uuid + 12); |
473 | 474 | ||
474 | seq_printf(f, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x\n", | 475 | seq_printf(f, "%.8x-%.4x-%.4x-%.4x-%.4x%.8x\n", |
475 | ntohl(data0), ntohs(data1), ntohs(data2), ntohs(data3), | 476 | data0, data1, data2, data3, data4, data5); |
476 | ntohl(data4), ntohs(data5)); | ||
477 | } | 477 | } |
478 | 478 | ||
479 | static int uuids_show(struct seq_file *f, void *p) | 479 | static int uuids_show(struct seq_file *f, void *p) |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 22e658322845..7c7e9321f1ea 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -1527,17 +1527,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) | |||
1527 | BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); | 1527 | BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); |
1528 | 1528 | ||
1529 | switch (hcon->type) { | 1529 | switch (hcon->type) { |
1530 | case AMP_LINK: | ||
1531 | conn->mtu = hcon->hdev->block_mtu; | ||
1532 | break; | ||
1533 | |||
1534 | case LE_LINK: | 1530 | case LE_LINK: |
1535 | if (hcon->hdev->le_mtu) { | 1531 | if (hcon->hdev->le_mtu) { |
1536 | conn->mtu = hcon->hdev->le_mtu; | 1532 | conn->mtu = hcon->hdev->le_mtu; |
1537 | break; | 1533 | break; |
1538 | } | 1534 | } |
1539 | /* fall through */ | 1535 | /* fall through */ |
1540 | |||
1541 | default: | 1536 | default: |
1542 | conn->mtu = hcon->hdev->acl_mtu; | 1537 | conn->mtu = hcon->hdev->acl_mtu; |
1543 | break; | 1538 | break; |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f559b966279c..39395c7144aa 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -35,7 +35,7 @@ | |||
35 | bool enable_hs; | 35 | bool enable_hs; |
36 | 36 | ||
37 | #define MGMT_VERSION 1 | 37 | #define MGMT_VERSION 1 |
38 | #define MGMT_REVISION 2 | 38 | #define MGMT_REVISION 3 |
39 | 39 | ||
40 | static const u16 mgmt_commands[] = { | 40 | static const u16 mgmt_commands[] = { |
41 | MGMT_OP_READ_INDEX_LIST, | 41 | MGMT_OP_READ_INDEX_LIST, |
@@ -435,35 +435,117 @@ static u32 get_current_settings(struct hci_dev *hdev) | |||
435 | 435 | ||
436 | #define PNP_INFO_SVCLASS_ID 0x1200 | 436 | #define PNP_INFO_SVCLASS_ID 0x1200 |
437 | 437 | ||
438 | static u8 bluetooth_base_uuid[] = { | 438 | static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) |
439 | 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, | 439 | { |
440 | 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 440 | u8 *ptr = data, *uuids_start = NULL; |
441 | }; | 441 | struct bt_uuid *uuid; |
442 | |||
443 | if (len < 4) | ||
444 | return ptr; | ||
445 | |||
446 | list_for_each_entry(uuid, &hdev->uuids, list) { | ||
447 | u16 uuid16; | ||
448 | |||
449 | if (uuid->size != 16) | ||
450 | continue; | ||
451 | |||
452 | uuid16 = get_unaligned_le16(&uuid->uuid[12]); | ||
453 | if (uuid16 < 0x1100) | ||
454 | continue; | ||
455 | |||
456 | if (uuid16 == PNP_INFO_SVCLASS_ID) | ||
457 | continue; | ||
442 | 458 | ||
443 | static u16 get_uuid16(u8 *uuid128) | 459 | if (!uuids_start) { |
460 | uuids_start = ptr; | ||
461 | uuids_start[0] = 1; | ||
462 | uuids_start[1] = EIR_UUID16_ALL; | ||
463 | ptr += 2; | ||
464 | } | ||
465 | |||
466 | /* Stop if not enough space to put next UUID */ | ||
467 | if ((ptr - data) + sizeof(u16) > len) { | ||
468 | uuids_start[1] = EIR_UUID16_SOME; | ||
469 | break; | ||
470 | } | ||
471 | |||
472 | *ptr++ = (uuid16 & 0x00ff); | ||
473 | *ptr++ = (uuid16 & 0xff00) >> 8; | ||
474 | uuids_start[0] += sizeof(uuid16); | ||
475 | } | ||
476 | |||
477 | return ptr; | ||
478 | } | ||
479 | |||
480 | static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) | ||
444 | { | 481 | { |
445 | u32 val; | 482 | u8 *ptr = data, *uuids_start = NULL; |
446 | int i; | 483 | struct bt_uuid *uuid; |
484 | |||
485 | if (len < 6) | ||
486 | return ptr; | ||
447 | 487 | ||
448 | for (i = 0; i < 12; i++) { | 488 | list_for_each_entry(uuid, &hdev->uuids, list) { |
449 | if (bluetooth_base_uuid[i] != uuid128[i]) | 489 | if (uuid->size != 32) |
450 | return 0; | 490 | continue; |
491 | |||
492 | if (!uuids_start) { | ||
493 | uuids_start = ptr; | ||
494 | uuids_start[0] = 1; | ||
495 | uuids_start[1] = EIR_UUID32_ALL; | ||
496 | ptr += 2; | ||
497 | } | ||
498 | |||
499 | /* Stop if not enough space to put next UUID */ | ||
500 | if ((ptr - data) + sizeof(u32) > len) { | ||
501 | uuids_start[1] = EIR_UUID32_SOME; | ||
502 | break; | ||
503 | } | ||
504 | |||
505 | memcpy(ptr, &uuid->uuid[12], sizeof(u32)); | ||
506 | ptr += sizeof(u32); | ||
507 | uuids_start[0] += sizeof(u32); | ||
451 | } | 508 | } |
452 | 509 | ||
453 | val = get_unaligned_le32(&uuid128[12]); | 510 | return ptr; |
454 | if (val > 0xffff) | 511 | } |
455 | return 0; | 512 | |
513 | static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) | ||
514 | { | ||
515 | u8 *ptr = data, *uuids_start = NULL; | ||
516 | struct bt_uuid *uuid; | ||
517 | |||
518 | if (len < 18) | ||
519 | return ptr; | ||
456 | 520 | ||
457 | return (u16) val; | 521 | list_for_each_entry(uuid, &hdev->uuids, list) { |
522 | if (uuid->size != 128) | ||
523 | continue; | ||
524 | |||
525 | if (!uuids_start) { | ||
526 | uuids_start = ptr; | ||
527 | uuids_start[0] = 1; | ||
528 | uuids_start[1] = EIR_UUID128_ALL; | ||
529 | ptr += 2; | ||
530 | } | ||
531 | |||
532 | /* Stop if not enough space to put next UUID */ | ||
533 | if ((ptr - data) + 16 > len) { | ||
534 | uuids_start[1] = EIR_UUID128_SOME; | ||
535 | break; | ||
536 | } | ||
537 | |||
538 | memcpy(ptr, uuid->uuid, 16); | ||
539 | ptr += 16; | ||
540 | uuids_start[0] += 16; | ||
541 | } | ||
542 | |||
543 | return ptr; | ||
458 | } | 544 | } |
459 | 545 | ||
460 | static void create_eir(struct hci_dev *hdev, u8 *data) | 546 | static void create_eir(struct hci_dev *hdev, u8 *data) |
461 | { | 547 | { |
462 | u8 *ptr = data; | 548 | u8 *ptr = data; |
463 | u16 eir_len = 0; | ||
464 | u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)]; | ||
465 | int i, truncated = 0; | ||
466 | struct bt_uuid *uuid; | ||
467 | size_t name_len; | 549 | size_t name_len; |
468 | 550 | ||
469 | name_len = strlen(hdev->dev_name); | 551 | name_len = strlen(hdev->dev_name); |
@@ -481,7 +563,6 @@ static void create_eir(struct hci_dev *hdev, u8 *data) | |||
481 | 563 | ||
482 | memcpy(ptr + 2, hdev->dev_name, name_len); | 564 | memcpy(ptr + 2, hdev->dev_name, name_len); |
483 | 565 | ||
484 | eir_len += (name_len + 2); | ||
485 | ptr += (name_len + 2); | 566 | ptr += (name_len + 2); |
486 | } | 567 | } |
487 | 568 | ||
@@ -490,7 +571,6 @@ static void create_eir(struct hci_dev *hdev, u8 *data) | |||
490 | ptr[1] = EIR_TX_POWER; | 571 | ptr[1] = EIR_TX_POWER; |
491 | ptr[2] = (u8) hdev->inq_tx_power; | 572 | ptr[2] = (u8) hdev->inq_tx_power; |
492 | 573 | ||
493 | eir_len += 3; | ||
494 | ptr += 3; | 574 | ptr += 3; |
495 | } | 575 | } |
496 | 576 | ||
@@ -503,60 +583,12 @@ static void create_eir(struct hci_dev *hdev, u8 *data) | |||
503 | put_unaligned_le16(hdev->devid_product, ptr + 6); | 583 | put_unaligned_le16(hdev->devid_product, ptr + 6); |
504 | put_unaligned_le16(hdev->devid_version, ptr + 8); | 584 | put_unaligned_le16(hdev->devid_version, ptr + 8); |
505 | 585 | ||
506 | eir_len += 10; | ||
507 | ptr += 10; | 586 | ptr += 10; |
508 | } | 587 | } |
509 | 588 | ||
510 | memset(uuid16_list, 0, sizeof(uuid16_list)); | 589 | ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); |
511 | 590 | ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); | |
512 | /* Group all UUID16 types */ | 591 | ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); |
513 | list_for_each_entry(uuid, &hdev->uuids, list) { | ||
514 | u16 uuid16; | ||
515 | |||
516 | uuid16 = get_uuid16(uuid->uuid); | ||
517 | if (uuid16 == 0) | ||
518 | return; | ||
519 | |||
520 | if (uuid16 < 0x1100) | ||
521 | continue; | ||
522 | |||
523 | if (uuid16 == PNP_INFO_SVCLASS_ID) | ||
524 | continue; | ||
525 | |||
526 | /* Stop if not enough space to put next UUID */ | ||
527 | if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { | ||
528 | truncated = 1; | ||
529 | break; | ||
530 | } | ||
531 | |||
532 | /* Check for duplicates */ | ||
533 | for (i = 0; uuid16_list[i] != 0; i++) | ||
534 | if (uuid16_list[i] == uuid16) | ||
535 | break; | ||
536 | |||
537 | if (uuid16_list[i] == 0) { | ||
538 | uuid16_list[i] = uuid16; | ||
539 | eir_len += sizeof(u16); | ||
540 | } | ||
541 | } | ||
542 | |||
543 | if (uuid16_list[0] != 0) { | ||
544 | u8 *length = ptr; | ||
545 | |||
546 | /* EIR Data type */ | ||
547 | ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; | ||
548 | |||
549 | ptr += 2; | ||
550 | eir_len += 2; | ||
551 | |||
552 | for (i = 0; uuid16_list[i] != 0; i++) { | ||
553 | *ptr++ = (uuid16_list[i] & 0x00ff); | ||
554 | *ptr++ = (uuid16_list[i] & 0xff00) >> 8; | ||
555 | } | ||
556 | |||
557 | /* EIR Data length */ | ||
558 | *length = (i * sizeof(u16)) + 1; | ||
559 | } | ||
560 | } | 592 | } |
561 | 593 | ||
562 | static int update_eir(struct hci_dev *hdev) | 594 | static int update_eir(struct hci_dev *hdev) |
@@ -728,13 +760,9 @@ static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, | |||
728 | void *data), | 760 | void *data), |
729 | void *data) | 761 | void *data) |
730 | { | 762 | { |
731 | struct list_head *p, *n; | 763 | struct pending_cmd *cmd, *tmp; |
732 | |||
733 | list_for_each_safe(p, n, &hdev->mgmt_pending) { | ||
734 | struct pending_cmd *cmd; | ||
735 | |||
736 | cmd = list_entry(p, struct pending_cmd, list); | ||
737 | 764 | ||
765 | list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { | ||
738 | if (opcode > 0 && cmd->opcode != opcode) | 766 | if (opcode > 0 && cmd->opcode != opcode) |
739 | continue; | 767 | continue; |
740 | 768 | ||
@@ -777,14 +805,19 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, | |||
777 | 805 | ||
778 | BT_DBG("request for %s", hdev->name); | 806 | BT_DBG("request for %s", hdev->name); |
779 | 807 | ||
808 | if (cp->val != 0x00 && cp->val != 0x01) | ||
809 | return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, | ||
810 | MGMT_STATUS_INVALID_PARAMS); | ||
811 | |||
780 | hci_dev_lock(hdev); | 812 | hci_dev_lock(hdev); |
781 | 813 | ||
782 | if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { | 814 | if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { |
783 | cancel_delayed_work(&hdev->power_off); | 815 | cancel_delayed_work(&hdev->power_off); |
784 | 816 | ||
785 | if (cp->val) { | 817 | if (cp->val) { |
786 | err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); | 818 | mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, |
787 | mgmt_powered(hdev, 1); | 819 | data, len); |
820 | err = mgmt_powered(hdev, 1); | ||
788 | goto failed; | 821 | goto failed; |
789 | } | 822 | } |
790 | } | 823 | } |
@@ -807,9 +840,9 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, | |||
807 | } | 840 | } |
808 | 841 | ||
809 | if (cp->val) | 842 | if (cp->val) |
810 | schedule_work(&hdev->power_on); | 843 | queue_work(hdev->req_workqueue, &hdev->power_on); |
811 | else | 844 | else |
812 | schedule_work(&hdev->power_off.work); | 845 | queue_work(hdev->req_workqueue, &hdev->power_off.work); |
813 | 846 | ||
814 | err = 0; | 847 | err = 0; |
815 | 848 | ||
@@ -872,6 +905,10 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
872 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, | 905 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, |
873 | MGMT_STATUS_NOT_SUPPORTED); | 906 | MGMT_STATUS_NOT_SUPPORTED); |
874 | 907 | ||
908 | if (cp->val != 0x00 && cp->val != 0x01) | ||
909 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, | ||
910 | MGMT_STATUS_INVALID_PARAMS); | ||
911 | |||
875 | timeout = __le16_to_cpu(cp->timeout); | 912 | timeout = __le16_to_cpu(cp->timeout); |
876 | if (!cp->val && timeout > 0) | 913 | if (!cp->val && timeout > 0) |
877 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, | 914 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, |
@@ -971,6 +1008,10 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
971 | return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, | 1008 | return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, |
972 | MGMT_STATUS_NOT_SUPPORTED); | 1009 | MGMT_STATUS_NOT_SUPPORTED); |
973 | 1010 | ||
1011 | if (cp->val != 0x00 && cp->val != 0x01) | ||
1012 | return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, | ||
1013 | MGMT_STATUS_INVALID_PARAMS); | ||
1014 | |||
974 | hci_dev_lock(hdev); | 1015 | hci_dev_lock(hdev); |
975 | 1016 | ||
976 | if (!hdev_is_powered(hdev)) { | 1017 | if (!hdev_is_powered(hdev)) { |
@@ -1041,6 +1082,10 @@ static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1041 | 1082 | ||
1042 | BT_DBG("request for %s", hdev->name); | 1083 | BT_DBG("request for %s", hdev->name); |
1043 | 1084 | ||
1085 | if (cp->val != 0x00 && cp->val != 0x01) | ||
1086 | return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE, | ||
1087 | MGMT_STATUS_INVALID_PARAMS); | ||
1088 | |||
1044 | hci_dev_lock(hdev); | 1089 | hci_dev_lock(hdev); |
1045 | 1090 | ||
1046 | if (cp->val) | 1091 | if (cp->val) |
@@ -1073,6 +1118,10 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1073 | return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, | 1118 | return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, |
1074 | MGMT_STATUS_NOT_SUPPORTED); | 1119 | MGMT_STATUS_NOT_SUPPORTED); |
1075 | 1120 | ||
1121 | if (cp->val != 0x00 && cp->val != 0x01) | ||
1122 | return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, | ||
1123 | MGMT_STATUS_INVALID_PARAMS); | ||
1124 | |||
1076 | hci_dev_lock(hdev); | 1125 | hci_dev_lock(hdev); |
1077 | 1126 | ||
1078 | if (!hdev_is_powered(hdev)) { | 1127 | if (!hdev_is_powered(hdev)) { |
@@ -1133,13 +1182,15 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
1133 | 1182 | ||
1134 | BT_DBG("request for %s", hdev->name); | 1183 | BT_DBG("request for %s", hdev->name); |
1135 | 1184 | ||
1136 | hci_dev_lock(hdev); | 1185 | if (!lmp_ssp_capable(hdev)) |
1186 | return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, | ||
1187 | MGMT_STATUS_NOT_SUPPORTED); | ||
1137 | 1188 | ||
1138 | if (!lmp_ssp_capable(hdev)) { | 1189 | if (cp->val != 0x00 && cp->val != 0x01) |
1139 | err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, | 1190 | return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, |
1140 | MGMT_STATUS_NOT_SUPPORTED); | 1191 | MGMT_STATUS_INVALID_PARAMS); |
1141 | goto failed; | 1192 | |
1142 | } | 1193 | hci_dev_lock(hdev); |
1143 | 1194 | ||
1144 | val = !!cp->val; | 1195 | val = !!cp->val; |
1145 | 1196 | ||
@@ -1199,6 +1250,10 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
1199 | return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, | 1250 | return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, |
1200 | MGMT_STATUS_NOT_SUPPORTED); | 1251 | MGMT_STATUS_NOT_SUPPORTED); |
1201 | 1252 | ||
1253 | if (cp->val != 0x00 && cp->val != 0x01) | ||
1254 | return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, | ||
1255 | MGMT_STATUS_INVALID_PARAMS); | ||
1256 | |||
1202 | if (cp->val) | 1257 | if (cp->val) |
1203 | set_bit(HCI_HS_ENABLED, &hdev->dev_flags); | 1258 | set_bit(HCI_HS_ENABLED, &hdev->dev_flags); |
1204 | else | 1259 | else |
@@ -1217,13 +1272,15 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
1217 | 1272 | ||
1218 | BT_DBG("request for %s", hdev->name); | 1273 | BT_DBG("request for %s", hdev->name); |
1219 | 1274 | ||
1220 | hci_dev_lock(hdev); | 1275 | if (!lmp_le_capable(hdev)) |
1276 | return cmd_status(sk, hdev->id, MGMT_OP_SET_LE, | ||
1277 | MGMT_STATUS_NOT_SUPPORTED); | ||
1221 | 1278 | ||
1222 | if (!lmp_le_capable(hdev)) { | 1279 | if (cp->val != 0x00 && cp->val != 0x01) |
1223 | err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, | 1280 | return cmd_status(sk, hdev->id, MGMT_OP_SET_LE, |
1224 | MGMT_STATUS_NOT_SUPPORTED); | 1281 | MGMT_STATUS_INVALID_PARAMS); |
1225 | goto unlock; | 1282 | |
1226 | } | 1283 | hci_dev_lock(hdev); |
1227 | 1284 | ||
1228 | val = !!cp->val; | 1285 | val = !!cp->val; |
1229 | enabled = lmp_host_le_capable(hdev); | 1286 | enabled = lmp_host_le_capable(hdev); |
@@ -1275,6 +1332,25 @@ unlock: | |||
1275 | return err; | 1332 | return err; |
1276 | } | 1333 | } |
1277 | 1334 | ||
1335 | static const u8 bluetooth_base_uuid[] = { | ||
1336 | 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, | ||
1337 | 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1338 | }; | ||
1339 | |||
1340 | static u8 get_uuid_size(const u8 *uuid) | ||
1341 | { | ||
1342 | u32 val; | ||
1343 | |||
1344 | if (memcmp(uuid, bluetooth_base_uuid, 12)) | ||
1345 | return 128; | ||
1346 | |||
1347 | val = get_unaligned_le32(&uuid[12]); | ||
1348 | if (val > 0xffff) | ||
1349 | return 32; | ||
1350 | |||
1351 | return 16; | ||
1352 | } | ||
1353 | |||
1278 | static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | 1354 | static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) |
1279 | { | 1355 | { |
1280 | struct mgmt_cp_add_uuid *cp = data; | 1356 | struct mgmt_cp_add_uuid *cp = data; |
@@ -1300,8 +1376,9 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
1300 | 1376 | ||
1301 | memcpy(uuid->uuid, cp->uuid, 16); | 1377 | memcpy(uuid->uuid, cp->uuid, 16); |
1302 | uuid->svc_hint = cp->svc_hint; | 1378 | uuid->svc_hint = cp->svc_hint; |
1379 | uuid->size = get_uuid_size(cp->uuid); | ||
1303 | 1380 | ||
1304 | list_add(&uuid->list, &hdev->uuids); | 1381 | list_add_tail(&uuid->list, &hdev->uuids); |
1305 | 1382 | ||
1306 | err = update_class(hdev); | 1383 | err = update_class(hdev); |
1307 | if (err < 0) | 1384 | if (err < 0) |
@@ -1332,7 +1409,8 @@ static bool enable_service_cache(struct hci_dev *hdev) | |||
1332 | return false; | 1409 | return false; |
1333 | 1410 | ||
1334 | if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { | 1411 | if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { |
1335 | schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT); | 1412 | queue_delayed_work(hdev->workqueue, &hdev->service_cache, |
1413 | CACHE_TIMEOUT); | ||
1336 | return true; | 1414 | return true; |
1337 | } | 1415 | } |
1338 | 1416 | ||
@@ -1344,7 +1422,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1344 | { | 1422 | { |
1345 | struct mgmt_cp_remove_uuid *cp = data; | 1423 | struct mgmt_cp_remove_uuid *cp = data; |
1346 | struct pending_cmd *cmd; | 1424 | struct pending_cmd *cmd; |
1347 | struct list_head *p, *n; | 1425 | struct bt_uuid *match, *tmp; |
1348 | u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | 1426 | u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
1349 | int err, found; | 1427 | int err, found; |
1350 | 1428 | ||
@@ -1372,9 +1450,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1372 | 1450 | ||
1373 | found = 0; | 1451 | found = 0; |
1374 | 1452 | ||
1375 | list_for_each_safe(p, n, &hdev->uuids) { | 1453 | list_for_each_entry_safe(match, tmp, &hdev->uuids, list) { |
1376 | struct bt_uuid *match = list_entry(p, struct bt_uuid, list); | ||
1377 | |||
1378 | if (memcmp(match->uuid, cp->uuid, 16) != 0) | 1454 | if (memcmp(match->uuid, cp->uuid, 16) != 0) |
1379 | continue; | 1455 | continue; |
1380 | 1456 | ||
@@ -1422,13 +1498,19 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1422 | 1498 | ||
1423 | BT_DBG("request for %s", hdev->name); | 1499 | BT_DBG("request for %s", hdev->name); |
1424 | 1500 | ||
1425 | hci_dev_lock(hdev); | 1501 | if (!lmp_bredr_capable(hdev)) |
1502 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, | ||
1503 | MGMT_STATUS_NOT_SUPPORTED); | ||
1426 | 1504 | ||
1427 | if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { | 1505 | if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) |
1428 | err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, | 1506 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, |
1429 | MGMT_STATUS_BUSY); | 1507 | MGMT_STATUS_BUSY); |
1430 | goto unlock; | 1508 | |
1431 | } | 1509 | if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) |
1510 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, | ||
1511 | MGMT_STATUS_INVALID_PARAMS); | ||
1512 | |||
1513 | hci_dev_lock(hdev); | ||
1432 | 1514 | ||
1433 | hdev->major_class = cp->major; | 1515 | hdev->major_class = cp->major; |
1434 | hdev->minor_class = cp->minor; | 1516 | hdev->minor_class = cp->minor; |
@@ -1483,9 +1565,21 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1483 | MGMT_STATUS_INVALID_PARAMS); | 1565 | MGMT_STATUS_INVALID_PARAMS); |
1484 | } | 1566 | } |
1485 | 1567 | ||
1568 | if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01) | ||
1569 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, | ||
1570 | MGMT_STATUS_INVALID_PARAMS); | ||
1571 | |||
1486 | BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys, | 1572 | BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys, |
1487 | key_count); | 1573 | key_count); |
1488 | 1574 | ||
1575 | for (i = 0; i < key_count; i++) { | ||
1576 | struct mgmt_link_key_info *key = &cp->keys[i]; | ||
1577 | |||
1578 | if (key->addr.type != BDADDR_BREDR) | ||
1579 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, | ||
1580 | MGMT_STATUS_INVALID_PARAMS); | ||
1581 | } | ||
1582 | |||
1489 | hci_dev_lock(hdev); | 1583 | hci_dev_lock(hdev); |
1490 | 1584 | ||
1491 | hci_link_keys_clear(hdev); | 1585 | hci_link_keys_clear(hdev); |
@@ -1533,12 +1627,22 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1533 | struct hci_conn *conn; | 1627 | struct hci_conn *conn; |
1534 | int err; | 1628 | int err; |
1535 | 1629 | ||
1536 | hci_dev_lock(hdev); | ||
1537 | |||
1538 | memset(&rp, 0, sizeof(rp)); | 1630 | memset(&rp, 0, sizeof(rp)); |
1539 | bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); | 1631 | bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); |
1540 | rp.addr.type = cp->addr.type; | 1632 | rp.addr.type = cp->addr.type; |
1541 | 1633 | ||
1634 | if (!bdaddr_type_is_valid(cp->addr.type)) | ||
1635 | return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, | ||
1636 | MGMT_STATUS_INVALID_PARAMS, | ||
1637 | &rp, sizeof(rp)); | ||
1638 | |||
1639 | if (cp->disconnect != 0x00 && cp->disconnect != 0x01) | ||
1640 | return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, | ||
1641 | MGMT_STATUS_INVALID_PARAMS, | ||
1642 | &rp, sizeof(rp)); | ||
1643 | |||
1644 | hci_dev_lock(hdev); | ||
1645 | |||
1542 | if (!hdev_is_powered(hdev)) { | 1646 | if (!hdev_is_powered(hdev)) { |
1543 | err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, | 1647 | err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, |
1544 | MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); | 1648 | MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); |
@@ -1596,6 +1700,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1596 | u16 len) | 1700 | u16 len) |
1597 | { | 1701 | { |
1598 | struct mgmt_cp_disconnect *cp = data; | 1702 | struct mgmt_cp_disconnect *cp = data; |
1703 | struct mgmt_rp_disconnect rp; | ||
1599 | struct hci_cp_disconnect dc; | 1704 | struct hci_cp_disconnect dc; |
1600 | struct pending_cmd *cmd; | 1705 | struct pending_cmd *cmd; |
1601 | struct hci_conn *conn; | 1706 | struct hci_conn *conn; |
@@ -1603,17 +1708,26 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1603 | 1708 | ||
1604 | BT_DBG(""); | 1709 | BT_DBG(""); |
1605 | 1710 | ||
1711 | memset(&rp, 0, sizeof(rp)); | ||
1712 | bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); | ||
1713 | rp.addr.type = cp->addr.type; | ||
1714 | |||
1715 | if (!bdaddr_type_is_valid(cp->addr.type)) | ||
1716 | return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT, | ||
1717 | MGMT_STATUS_INVALID_PARAMS, | ||
1718 | &rp, sizeof(rp)); | ||
1719 | |||
1606 | hci_dev_lock(hdev); | 1720 | hci_dev_lock(hdev); |
1607 | 1721 | ||
1608 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1722 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1609 | err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, | 1723 | err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT, |
1610 | MGMT_STATUS_NOT_POWERED); | 1724 | MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); |
1611 | goto failed; | 1725 | goto failed; |
1612 | } | 1726 | } |
1613 | 1727 | ||
1614 | if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) { | 1728 | if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) { |
1615 | err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, | 1729 | err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT, |
1616 | MGMT_STATUS_BUSY); | 1730 | MGMT_STATUS_BUSY, &rp, sizeof(rp)); |
1617 | goto failed; | 1731 | goto failed; |
1618 | } | 1732 | } |
1619 | 1733 | ||
@@ -1624,8 +1738,8 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1624 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); | 1738 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); |
1625 | 1739 | ||
1626 | if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) { | 1740 | if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) { |
1627 | err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, | 1741 | err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT, |
1628 | MGMT_STATUS_NOT_CONNECTED); | 1742 | MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp)); |
1629 | goto failed; | 1743 | goto failed; |
1630 | } | 1744 | } |
1631 | 1745 | ||
@@ -1903,11 +2017,20 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1903 | 2017 | ||
1904 | BT_DBG(""); | 2018 | BT_DBG(""); |
1905 | 2019 | ||
2020 | memset(&rp, 0, sizeof(rp)); | ||
2021 | bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); | ||
2022 | rp.addr.type = cp->addr.type; | ||
2023 | |||
2024 | if (!bdaddr_type_is_valid(cp->addr.type)) | ||
2025 | return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, | ||
2026 | MGMT_STATUS_INVALID_PARAMS, | ||
2027 | &rp, sizeof(rp)); | ||
2028 | |||
1906 | hci_dev_lock(hdev); | 2029 | hci_dev_lock(hdev); |
1907 | 2030 | ||
1908 | if (!hdev_is_powered(hdev)) { | 2031 | if (!hdev_is_powered(hdev)) { |
1909 | err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE, | 2032 | err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, |
1910 | MGMT_STATUS_NOT_POWERED); | 2033 | MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); |
1911 | goto unlock; | 2034 | goto unlock; |
1912 | } | 2035 | } |
1913 | 2036 | ||
@@ -1924,10 +2047,6 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1924 | conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, | 2047 | conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, |
1925 | cp->addr.type, sec_level, auth_type); | 2048 | cp->addr.type, sec_level, auth_type); |
1926 | 2049 | ||
1927 | memset(&rp, 0, sizeof(rp)); | ||
1928 | bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); | ||
1929 | rp.addr.type = cp->addr.type; | ||
1930 | |||
1931 | if (IS_ERR(conn)) { | 2050 | if (IS_ERR(conn)) { |
1932 | int status; | 2051 | int status; |
1933 | 2052 | ||
@@ -2254,24 +2373,16 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, | |||
2254 | 2373 | ||
2255 | hci_dev_lock(hdev); | 2374 | hci_dev_lock(hdev); |
2256 | 2375 | ||
2257 | if (!hdev_is_powered(hdev)) { | ||
2258 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, | ||
2259 | MGMT_STATUS_NOT_POWERED, &cp->addr, | ||
2260 | sizeof(cp->addr)); | ||
2261 | goto unlock; | ||
2262 | } | ||
2263 | |||
2264 | err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, | 2376 | err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, |
2265 | cp->randomizer); | 2377 | cp->randomizer); |
2266 | if (err < 0) | 2378 | if (err < 0) |
2267 | status = MGMT_STATUS_FAILED; | 2379 | status = MGMT_STATUS_FAILED; |
2268 | else | 2380 | else |
2269 | status = 0; | 2381 | status = MGMT_STATUS_SUCCESS; |
2270 | 2382 | ||
2271 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status, | 2383 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status, |
2272 | &cp->addr, sizeof(cp->addr)); | 2384 | &cp->addr, sizeof(cp->addr)); |
2273 | 2385 | ||
2274 | unlock: | ||
2275 | hci_dev_unlock(hdev); | 2386 | hci_dev_unlock(hdev); |
2276 | return err; | 2387 | return err; |
2277 | } | 2388 | } |
@@ -2287,24 +2398,15 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, | |||
2287 | 2398 | ||
2288 | hci_dev_lock(hdev); | 2399 | hci_dev_lock(hdev); |
2289 | 2400 | ||
2290 | if (!hdev_is_powered(hdev)) { | ||
2291 | err = cmd_complete(sk, hdev->id, | ||
2292 | MGMT_OP_REMOVE_REMOTE_OOB_DATA, | ||
2293 | MGMT_STATUS_NOT_POWERED, &cp->addr, | ||
2294 | sizeof(cp->addr)); | ||
2295 | goto unlock; | ||
2296 | } | ||
2297 | |||
2298 | err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr); | 2401 | err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr); |
2299 | if (err < 0) | 2402 | if (err < 0) |
2300 | status = MGMT_STATUS_INVALID_PARAMS; | 2403 | status = MGMT_STATUS_INVALID_PARAMS; |
2301 | else | 2404 | else |
2302 | status = 0; | 2405 | status = MGMT_STATUS_SUCCESS; |
2303 | 2406 | ||
2304 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | 2407 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, |
2305 | status, &cp->addr, sizeof(cp->addr)); | 2408 | status, &cp->addr, sizeof(cp->addr)); |
2306 | 2409 | ||
2307 | unlock: | ||
2308 | hci_dev_unlock(hdev); | 2410 | hci_dev_unlock(hdev); |
2309 | return err; | 2411 | return err; |
2310 | } | 2412 | } |
@@ -2365,31 +2467,45 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, | |||
2365 | 2467 | ||
2366 | switch (hdev->discovery.type) { | 2468 | switch (hdev->discovery.type) { |
2367 | case DISCOV_TYPE_BREDR: | 2469 | case DISCOV_TYPE_BREDR: |
2368 | if (lmp_bredr_capable(hdev)) | 2470 | if (!lmp_bredr_capable(hdev)) { |
2369 | err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); | 2471 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
2370 | else | 2472 | MGMT_STATUS_NOT_SUPPORTED); |
2371 | err = -ENOTSUPP; | 2473 | mgmt_pending_remove(cmd); |
2474 | goto failed; | ||
2475 | } | ||
2476 | |||
2477 | err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); | ||
2372 | break; | 2478 | break; |
2373 | 2479 | ||
2374 | case DISCOV_TYPE_LE: | 2480 | case DISCOV_TYPE_LE: |
2375 | if (lmp_host_le_capable(hdev)) | 2481 | if (!lmp_host_le_capable(hdev)) { |
2376 | err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, | 2482 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
2377 | LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); | 2483 | MGMT_STATUS_NOT_SUPPORTED); |
2378 | else | 2484 | mgmt_pending_remove(cmd); |
2379 | err = -ENOTSUPP; | 2485 | goto failed; |
2486 | } | ||
2487 | |||
2488 | err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, | ||
2489 | LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); | ||
2380 | break; | 2490 | break; |
2381 | 2491 | ||
2382 | case DISCOV_TYPE_INTERLEAVED: | 2492 | case DISCOV_TYPE_INTERLEAVED: |
2383 | if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev)) | 2493 | if (!lmp_host_le_capable(hdev) || !lmp_bredr_capable(hdev)) { |
2384 | err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, | 2494 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
2385 | LE_SCAN_WIN, | 2495 | MGMT_STATUS_NOT_SUPPORTED); |
2386 | LE_SCAN_TIMEOUT_BREDR_LE); | 2496 | mgmt_pending_remove(cmd); |
2387 | else | 2497 | goto failed; |
2388 | err = -ENOTSUPP; | 2498 | } |
2499 | |||
2500 | err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN, | ||
2501 | LE_SCAN_TIMEOUT_BREDR_LE); | ||
2389 | break; | 2502 | break; |
2390 | 2503 | ||
2391 | default: | 2504 | default: |
2392 | err = -EINVAL; | 2505 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
2506 | MGMT_STATUS_INVALID_PARAMS); | ||
2507 | mgmt_pending_remove(cmd); | ||
2508 | goto failed; | ||
2393 | } | 2509 | } |
2394 | 2510 | ||
2395 | if (err < 0) | 2511 | if (err < 0) |
@@ -2510,7 +2626,8 @@ static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, | |||
2510 | hci_inquiry_cache_update_resolve(hdev, e); | 2626 | hci_inquiry_cache_update_resolve(hdev, e); |
2511 | } | 2627 | } |
2512 | 2628 | ||
2513 | err = 0; | 2629 | err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr, |
2630 | sizeof(cp->addr)); | ||
2514 | 2631 | ||
2515 | failed: | 2632 | failed: |
2516 | hci_dev_unlock(hdev); | 2633 | hci_dev_unlock(hdev); |
@@ -2526,13 +2643,18 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
2526 | 2643 | ||
2527 | BT_DBG("%s", hdev->name); | 2644 | BT_DBG("%s", hdev->name); |
2528 | 2645 | ||
2646 | if (!bdaddr_type_is_valid(cp->addr.type)) | ||
2647 | return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, | ||
2648 | MGMT_STATUS_INVALID_PARAMS, | ||
2649 | &cp->addr, sizeof(cp->addr)); | ||
2650 | |||
2529 | hci_dev_lock(hdev); | 2651 | hci_dev_lock(hdev); |
2530 | 2652 | ||
2531 | err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); | 2653 | err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); |
2532 | if (err < 0) | 2654 | if (err < 0) |
2533 | status = MGMT_STATUS_FAILED; | 2655 | status = MGMT_STATUS_FAILED; |
2534 | else | 2656 | else |
2535 | status = 0; | 2657 | status = MGMT_STATUS_SUCCESS; |
2536 | 2658 | ||
2537 | err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status, | 2659 | err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status, |
2538 | &cp->addr, sizeof(cp->addr)); | 2660 | &cp->addr, sizeof(cp->addr)); |
@@ -2551,13 +2673,18 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
2551 | 2673 | ||
2552 | BT_DBG("%s", hdev->name); | 2674 | BT_DBG("%s", hdev->name); |
2553 | 2675 | ||
2676 | if (!bdaddr_type_is_valid(cp->addr.type)) | ||
2677 | return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, | ||
2678 | MGMT_STATUS_INVALID_PARAMS, | ||
2679 | &cp->addr, sizeof(cp->addr)); | ||
2680 | |||
2554 | hci_dev_lock(hdev); | 2681 | hci_dev_lock(hdev); |
2555 | 2682 | ||
2556 | err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); | 2683 | err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); |
2557 | if (err < 0) | 2684 | if (err < 0) |
2558 | status = MGMT_STATUS_INVALID_PARAMS; | 2685 | status = MGMT_STATUS_INVALID_PARAMS; |
2559 | else | 2686 | else |
2560 | status = 0; | 2687 | status = MGMT_STATUS_SUCCESS; |
2561 | 2688 | ||
2562 | err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status, | 2689 | err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status, |
2563 | &cp->addr, sizeof(cp->addr)); | 2690 | &cp->addr, sizeof(cp->addr)); |
@@ -2612,6 +2739,10 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, | |||
2612 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, | 2739 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, |
2613 | MGMT_STATUS_NOT_SUPPORTED); | 2740 | MGMT_STATUS_NOT_SUPPORTED); |
2614 | 2741 | ||
2742 | if (cp->val != 0x00 && cp->val != 0x01) | ||
2743 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, | ||
2744 | MGMT_STATUS_INVALID_PARAMS); | ||
2745 | |||
2615 | if (!hdev_is_powered(hdev)) | 2746 | if (!hdev_is_powered(hdev)) |
2616 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, | 2747 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, |
2617 | MGMT_STATUS_NOT_POWERED); | 2748 | MGMT_STATUS_NOT_POWERED); |
@@ -2659,12 +2790,23 @@ done: | |||
2659 | return err; | 2790 | return err; |
2660 | } | 2791 | } |
2661 | 2792 | ||
2793 | static bool ltk_is_valid(struct mgmt_ltk_info *key) | ||
2794 | { | ||
2795 | if (key->authenticated != 0x00 && key->authenticated != 0x01) | ||
2796 | return false; | ||
2797 | if (key->master != 0x00 && key->master != 0x01) | ||
2798 | return false; | ||
2799 | if (!bdaddr_type_is_le(key->addr.type)) | ||
2800 | return false; | ||
2801 | return true; | ||
2802 | } | ||
2803 | |||
2662 | static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, | 2804 | static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, |
2663 | void *cp_data, u16 len) | 2805 | void *cp_data, u16 len) |
2664 | { | 2806 | { |
2665 | struct mgmt_cp_load_long_term_keys *cp = cp_data; | 2807 | struct mgmt_cp_load_long_term_keys *cp = cp_data; |
2666 | u16 key_count, expected_len; | 2808 | u16 key_count, expected_len; |
2667 | int i; | 2809 | int i, err; |
2668 | 2810 | ||
2669 | key_count = __le16_to_cpu(cp->key_count); | 2811 | key_count = __le16_to_cpu(cp->key_count); |
2670 | 2812 | ||
@@ -2674,11 +2816,20 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, | |||
2674 | BT_ERR("load_keys: expected %u bytes, got %u bytes", | 2816 | BT_ERR("load_keys: expected %u bytes, got %u bytes", |
2675 | len, expected_len); | 2817 | len, expected_len); |
2676 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, | 2818 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, |
2677 | EINVAL); | 2819 | MGMT_STATUS_INVALID_PARAMS); |
2678 | } | 2820 | } |
2679 | 2821 | ||
2680 | BT_DBG("%s key_count %u", hdev->name, key_count); | 2822 | BT_DBG("%s key_count %u", hdev->name, key_count); |
2681 | 2823 | ||
2824 | for (i = 0; i < key_count; i++) { | ||
2825 | struct mgmt_ltk_info *key = &cp->keys[i]; | ||
2826 | |||
2827 | if (!ltk_is_valid(key)) | ||
2828 | return cmd_status(sk, hdev->id, | ||
2829 | MGMT_OP_LOAD_LONG_TERM_KEYS, | ||
2830 | MGMT_STATUS_INVALID_PARAMS); | ||
2831 | } | ||
2832 | |||
2682 | hci_dev_lock(hdev); | 2833 | hci_dev_lock(hdev); |
2683 | 2834 | ||
2684 | hci_smp_ltks_clear(hdev); | 2835 | hci_smp_ltks_clear(hdev); |
@@ -2698,9 +2849,12 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, | |||
2698 | key->enc_size, key->ediv, key->rand); | 2849 | key->enc_size, key->ediv, key->rand); |
2699 | } | 2850 | } |
2700 | 2851 | ||
2852 | err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0, | ||
2853 | NULL, 0); | ||
2854 | |||
2701 | hci_dev_unlock(hdev); | 2855 | hci_dev_unlock(hdev); |
2702 | 2856 | ||
2703 | return 0; | 2857 | return err; |
2704 | } | 2858 | } |
2705 | 2859 | ||
2706 | static const struct mgmt_handler { | 2860 | static const struct mgmt_handler { |
@@ -2915,6 +3069,8 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) | |||
2915 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); | 3069 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); |
2916 | 3070 | ||
2917 | if (powered) { | 3071 | if (powered) { |
3072 | u8 link_sec; | ||
3073 | |||
2918 | if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && | 3074 | if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && |
2919 | !lmp_host_ssp_capable(hdev)) { | 3075 | !lmp_host_ssp_capable(hdev)) { |
2920 | u8 ssp = 1; | 3076 | u8 ssp = 1; |
@@ -2938,6 +3094,11 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) | |||
2938 | sizeof(cp), &cp); | 3094 | sizeof(cp), &cp); |
2939 | } | 3095 | } |
2940 | 3096 | ||
3097 | link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags); | ||
3098 | if (link_sec != test_bit(HCI_AUTH, &hdev->flags)) | ||
3099 | hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, | ||
3100 | sizeof(link_sec), &link_sec); | ||
3101 | |||
2941 | if (lmp_bredr_capable(hdev)) { | 3102 | if (lmp_bredr_capable(hdev)) { |
2942 | set_bredr_scan(hdev); | 3103 | set_bredr_scan(hdev); |
2943 | update_class(hdev); | 3104 | update_class(hdev); |
@@ -2946,7 +3107,13 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) | |||
2946 | } | 3107 | } |
2947 | } else { | 3108 | } else { |
2948 | u8 status = MGMT_STATUS_NOT_POWERED; | 3109 | u8 status = MGMT_STATUS_NOT_POWERED; |
3110 | u8 zero_cod[] = { 0, 0, 0 }; | ||
3111 | |||
2949 | mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); | 3112 | mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); |
3113 | |||
3114 | if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) | ||
3115 | mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, | ||
3116 | zero_cod, sizeof(zero_cod), NULL); | ||
2950 | } | 3117 | } |
2951 | 3118 | ||
2952 | err = new_settings(hdev, match.sk); | 3119 | err = new_settings(hdev, match.sk); |
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 57f250c20e39..b5178d62064e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c | |||
@@ -900,8 +900,6 @@ static void sco_conn_ready(struct sco_conn *conn) | |||
900 | 900 | ||
901 | BT_DBG("conn %p", conn); | 901 | BT_DBG("conn %p", conn); |
902 | 902 | ||
903 | sco_conn_lock(conn); | ||
904 | |||
905 | if (sk) { | 903 | if (sk) { |
906 | sco_sock_clear_timer(sk); | 904 | sco_sock_clear_timer(sk); |
907 | bh_lock_sock(sk); | 905 | bh_lock_sock(sk); |
@@ -909,9 +907,13 @@ static void sco_conn_ready(struct sco_conn *conn) | |||
909 | sk->sk_state_change(sk); | 907 | sk->sk_state_change(sk); |
910 | bh_unlock_sock(sk); | 908 | bh_unlock_sock(sk); |
911 | } else { | 909 | } else { |
910 | sco_conn_lock(conn); | ||
911 | |||
912 | parent = sco_get_sock_listen(conn->src); | 912 | parent = sco_get_sock_listen(conn->src); |
913 | if (!parent) | 913 | if (!parent) { |
914 | goto done; | 914 | sco_conn_unlock(conn); |
915 | return; | ||
916 | } | ||
915 | 917 | ||
916 | bh_lock_sock(parent); | 918 | bh_lock_sock(parent); |
917 | 919 | ||
@@ -919,7 +921,8 @@ static void sco_conn_ready(struct sco_conn *conn) | |||
919 | BTPROTO_SCO, GFP_ATOMIC); | 921 | BTPROTO_SCO, GFP_ATOMIC); |
920 | if (!sk) { | 922 | if (!sk) { |
921 | bh_unlock_sock(parent); | 923 | bh_unlock_sock(parent); |
922 | goto done; | 924 | sco_conn_unlock(conn); |
925 | return; | ||
923 | } | 926 | } |
924 | 927 | ||
925 | sco_sock_init(sk, parent); | 928 | sco_sock_init(sk, parent); |
@@ -939,10 +942,9 @@ static void sco_conn_ready(struct sco_conn *conn) | |||
939 | parent->sk_data_ready(parent, 1); | 942 | parent->sk_data_ready(parent, 1); |
940 | 943 | ||
941 | bh_unlock_sock(parent); | 944 | bh_unlock_sock(parent); |
942 | } | ||
943 | 945 | ||
944 | done: | 946 | sco_conn_unlock(conn); |
945 | sco_conn_unlock(conn); | 947 | } |
946 | } | 948 | } |
947 | 949 | ||
948 | /* ----- SCO interface with lower layer (HCI) ----- */ | 950 | /* ----- SCO interface with lower layer (HCI) ----- */ |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 808338a1bce5..31bf2586fb84 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -83,8 +83,8 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
83 | if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, | 83 | if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, |
84 | &sta->sta, tid, NULL, 0)) | 84 | &sta->sta, tid, NULL, 0)) |
85 | sdata_info(sta->sdata, | 85 | sdata_info(sta->sdata, |
86 | "HW problem - can not stop rx aggregation for tid %d\n", | 86 | "HW problem - can not stop rx aggregation for %pM tid %d\n", |
87 | tid); | 87 | sta->sta.addr, tid); |
88 | 88 | ||
89 | /* check if this is a self generated aggregation halt */ | 89 | /* check if this is a self generated aggregation halt */ |
90 | if (initiator == WLAN_BACK_RECIPIENT && tx) | 90 | if (initiator == WLAN_BACK_RECIPIENT && tx) |
@@ -159,7 +159,8 @@ static void sta_rx_agg_session_timer_expired(unsigned long data) | |||
159 | } | 159 | } |
160 | rcu_read_unlock(); | 160 | rcu_read_unlock(); |
161 | 161 | ||
162 | ht_dbg(sta->sdata, "rx session timer expired on tid %d\n", (u16)*ptid); | 162 | ht_dbg(sta->sdata, "RX session timer expired on %pM tid %d\n", |
163 | sta->sta.addr, (u16)*ptid); | ||
163 | 164 | ||
164 | set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired); | 165 | set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired); |
165 | ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work); | 166 | ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work); |
@@ -247,7 +248,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
247 | status = WLAN_STATUS_REQUEST_DECLINED; | 248 | status = WLAN_STATUS_REQUEST_DECLINED; |
248 | 249 | ||
249 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { | 250 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { |
250 | ht_dbg(sta->sdata, "Suspend in progress - Denying ADDBA request\n"); | 251 | ht_dbg(sta->sdata, |
252 | "Suspend in progress - Denying ADDBA request (%pM tid %d)\n", | ||
253 | sta->sta.addr, tid); | ||
251 | goto end_no_lock; | 254 | goto end_no_lock; |
252 | } | 255 | } |
253 | 256 | ||
@@ -317,7 +320,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
317 | 320 | ||
318 | ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, | 321 | ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, |
319 | &sta->sta, tid, &start_seq_num, 0); | 322 | &sta->sta, tid, &start_seq_num, 0); |
320 | ht_dbg(sta->sdata, "Rx A-MPDU request on tid %d result %d\n", tid, ret); | 323 | ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n", |
324 | sta->sta.addr, tid, ret); | ||
321 | if (ret) { | 325 | if (ret) { |
322 | kfree(tid_agg_rx->reorder_buf); | 326 | kfree(tid_agg_rx->reorder_buf); |
323 | kfree(tid_agg_rx->reorder_time); | 327 | kfree(tid_agg_rx->reorder_time); |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 2f0ccbc5f13e..13b7683de5a4 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -296,7 +296,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
296 | IEEE80211_AMPDU_TX_STOP_FLUSH_CONT, | 296 | IEEE80211_AMPDU_TX_STOP_FLUSH_CONT, |
297 | &sta->sta, tid, NULL, 0); | 297 | &sta->sta, tid, NULL, 0); |
298 | WARN_ON_ONCE(ret); | 298 | WARN_ON_ONCE(ret); |
299 | goto remove_tid_tx; | 299 | return 0; |
300 | } | 300 | } |
301 | 301 | ||
302 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | 302 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { |
@@ -354,12 +354,15 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
354 | */ | 354 | */ |
355 | } | 355 | } |
356 | 356 | ||
357 | if (reason == AGG_STOP_DESTROY_STA) { | 357 | /* |
358 | remove_tid_tx: | 358 | * In the case of AGG_STOP_DESTROY_STA, the driver won't |
359 | spin_lock_bh(&sta->lock); | 359 | * necessarily call ieee80211_stop_tx_ba_cb(), so this may |
360 | ieee80211_remove_tid_tx(sta, tid); | 360 | * seem like we can leave the tid_tx data pending forever. |
361 | spin_unlock_bh(&sta->lock); | 361 | * This is true, in a way, but "forever" is only until the |
362 | } | 362 | * station struct is actually destroyed. In the meantime, |
363 | * leaving it around ensures that we don't transmit packets | ||
364 | * to the driver on this TID which might confuse it. | ||
365 | */ | ||
363 | 366 | ||
364 | return 0; | 367 | return 0; |
365 | } | 368 | } |
@@ -387,12 +390,13 @@ static void sta_addba_resp_timer_expired(unsigned long data) | |||
387 | test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) { | 390 | test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) { |
388 | rcu_read_unlock(); | 391 | rcu_read_unlock(); |
389 | ht_dbg(sta->sdata, | 392 | ht_dbg(sta->sdata, |
390 | "timer expired on tid %d but we are not (or no longer) expecting addBA response there\n", | 393 | "timer expired on %pM tid %d but we are not (or no longer) expecting addBA response there\n", |
391 | tid); | 394 | sta->sta.addr, tid); |
392 | return; | 395 | return; |
393 | } | 396 | } |
394 | 397 | ||
395 | ht_dbg(sta->sdata, "addBA response timer expired on tid %d\n", tid); | 398 | ht_dbg(sta->sdata, "addBA response timer expired on %pM tid %d\n", |
399 | sta->sta.addr, tid); | ||
396 | 400 | ||
397 | ieee80211_stop_tx_ba_session(&sta->sta, tid); | 401 | ieee80211_stop_tx_ba_session(&sta->sta, tid); |
398 | rcu_read_unlock(); | 402 | rcu_read_unlock(); |
@@ -429,7 +433,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
429 | &sta->sta, tid, &start_seq_num, 0); | 433 | &sta->sta, tid, &start_seq_num, 0); |
430 | if (ret) { | 434 | if (ret) { |
431 | ht_dbg(sdata, | 435 | ht_dbg(sdata, |
432 | "BA request denied - HW unavailable for tid %d\n", tid); | 436 | "BA request denied - HW unavailable for %pM tid %d\n", |
437 | sta->sta.addr, tid); | ||
433 | spin_lock_bh(&sta->lock); | 438 | spin_lock_bh(&sta->lock); |
434 | ieee80211_agg_splice_packets(sdata, tid_tx, tid); | 439 | ieee80211_agg_splice_packets(sdata, tid_tx, tid); |
435 | ieee80211_assign_tid_tx(sta, tid, NULL); | 440 | ieee80211_assign_tid_tx(sta, tid, NULL); |
@@ -442,7 +447,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
442 | 447 | ||
443 | /* activate the timer for the recipient's addBA response */ | 448 | /* activate the timer for the recipient's addBA response */ |
444 | mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); | 449 | mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); |
445 | ht_dbg(sdata, "activated addBA response timer on tid %d\n", tid); | 450 | ht_dbg(sdata, "activated addBA response timer on %pM tid %d\n", |
451 | sta->sta.addr, tid); | ||
446 | 452 | ||
447 | spin_lock_bh(&sta->lock); | 453 | spin_lock_bh(&sta->lock); |
448 | sta->ampdu_mlme.last_addba_req_time[tid] = jiffies; | 454 | sta->ampdu_mlme.last_addba_req_time[tid] = jiffies; |
@@ -489,7 +495,8 @@ static void sta_tx_agg_session_timer_expired(unsigned long data) | |||
489 | 495 | ||
490 | rcu_read_unlock(); | 496 | rcu_read_unlock(); |
491 | 497 | ||
492 | ht_dbg(sta->sdata, "tx session timer expired on tid %d\n", (u16)*ptid); | 498 | ht_dbg(sta->sdata, "tx session timer expired on %pM tid %d\n", |
499 | sta->sta.addr, (u16)*ptid); | ||
493 | 500 | ||
494 | ieee80211_stop_tx_ba_session(&sta->sta, *ptid); | 501 | ieee80211_stop_tx_ba_session(&sta->sta, *ptid); |
495 | } | 502 | } |
@@ -525,7 +532,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
525 | 532 | ||
526 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { | 533 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { |
527 | ht_dbg(sdata, | 534 | ht_dbg(sdata, |
528 | "BA sessions blocked - Denying BA session request\n"); | 535 | "BA sessions blocked - Denying BA session request %pM tid %d\n", |
536 | sta->sta.addr, tid); | ||
529 | return -EINVAL; | 537 | return -EINVAL; |
530 | } | 538 | } |
531 | 539 | ||
@@ -566,8 +574,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
566 | time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] + | 574 | time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] + |
567 | HT_AGG_RETRIES_PERIOD)) { | 575 | HT_AGG_RETRIES_PERIOD)) { |
568 | ht_dbg(sdata, | 576 | ht_dbg(sdata, |
569 | "BA request denied - waiting a grace period after %d failed requests on tid %u\n", | 577 | "BA request denied - waiting a grace period after %d failed requests on %pM tid %u\n", |
570 | sta->ampdu_mlme.addba_req_num[tid], tid); | 578 | sta->ampdu_mlme.addba_req_num[tid], sta->sta.addr, tid); |
571 | ret = -EBUSY; | 579 | ret = -EBUSY; |
572 | goto err_unlock_sta; | 580 | goto err_unlock_sta; |
573 | } | 581 | } |
@@ -576,8 +584,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
576 | /* check if the TID is not in aggregation flow already */ | 584 | /* check if the TID is not in aggregation flow already */ |
577 | if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { | 585 | if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { |
578 | ht_dbg(sdata, | 586 | ht_dbg(sdata, |
579 | "BA request denied - session is not idle on tid %u\n", | 587 | "BA request denied - session is not idle on %pM tid %u\n", |
580 | tid); | 588 | sta->sta.addr, tid); |
581 | ret = -EAGAIN; | 589 | ret = -EAGAIN; |
582 | goto err_unlock_sta; | 590 | goto err_unlock_sta; |
583 | } | 591 | } |
@@ -632,7 +640,8 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | |||
632 | 640 | ||
633 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | 641 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
634 | 642 | ||
635 | ht_dbg(sta->sdata, "Aggregation is on for tid %d\n", tid); | 643 | ht_dbg(sta->sdata, "Aggregation is on for %pM tid %d\n", |
644 | sta->sta.addr, tid); | ||
636 | 645 | ||
637 | drv_ampdu_action(local, sta->sdata, | 646 | drv_ampdu_action(local, sta->sdata, |
638 | IEEE80211_AMPDU_TX_OPERATIONAL, | 647 | IEEE80211_AMPDU_TX_OPERATIONAL, |
@@ -802,7 +811,9 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
802 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | 811 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
803 | 812 | ||
804 | if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | 813 | if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { |
805 | ht_dbg(sdata, "unexpected callback to A-MPDU stop\n"); | 814 | ht_dbg(sdata, |
815 | "unexpected callback to A-MPDU stop for %pM tid %d\n", | ||
816 | sta->sta.addr, tid); | ||
806 | goto unlock_sta; | 817 | goto unlock_sta; |
807 | } | 818 | } |
808 | 819 | ||
@@ -861,13 +872,15 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
861 | goto out; | 872 | goto out; |
862 | 873 | ||
863 | if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) { | 874 | if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) { |
864 | ht_dbg(sta->sdata, "wrong addBA response token, tid %d\n", tid); | 875 | ht_dbg(sta->sdata, "wrong addBA response token, %pM tid %d\n", |
876 | sta->sta.addr, tid); | ||
865 | goto out; | 877 | goto out; |
866 | } | 878 | } |
867 | 879 | ||
868 | del_timer_sync(&tid_tx->addba_resp_timer); | 880 | del_timer_sync(&tid_tx->addba_resp_timer); |
869 | 881 | ||
870 | ht_dbg(sta->sdata, "switched off addBA timer for tid %d\n", tid); | 882 | ht_dbg(sta->sdata, "switched off addBA timer for %pM tid %d\n", |
883 | sta->sta.addr, tid); | ||
871 | 884 | ||
872 | /* | 885 | /* |
873 | * addba_resp_timer may have fired before we got here, and | 886 | * addba_resp_timer may have fired before we got here, and |
@@ -877,8 +890,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
877 | if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || | 890 | if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || |
878 | test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | 891 | test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { |
879 | ht_dbg(sta->sdata, | 892 | ht_dbg(sta->sdata, |
880 | "got addBA resp for tid %d but we already gave up\n", | 893 | "got addBA resp for %pM tid %d but we already gave up\n", |
881 | tid); | 894 | sta->sta.addr, tid); |
882 | goto out; | 895 | goto out; |
883 | } | 896 | } |
884 | 897 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 0c07f94c5378..434b3c4f31b5 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -569,7 +569,8 @@ static inline void drv_sta_rc_update(struct ieee80211_local *local, | |||
569 | check_sdata_in_driver(sdata); | 569 | check_sdata_in_driver(sdata); |
570 | 570 | ||
571 | WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED && | 571 | WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED && |
572 | sdata->vif.type != NL80211_IFTYPE_ADHOC); | 572 | (sdata->vif.type != NL80211_IFTYPE_ADHOC && |
573 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT)); | ||
573 | 574 | ||
574 | trace_drv_sta_rc_update(local, sdata, sta, changed); | 575 | trace_drv_sta_rc_update(local, sdata, sta, changed); |
575 | if (local->ops->sta_rc_update) | 576 | if (local->ops->sta_rc_update) |
@@ -845,11 +846,12 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local, | |||
845 | } | 846 | } |
846 | 847 | ||
847 | static inline void drv_rssi_callback(struct ieee80211_local *local, | 848 | static inline void drv_rssi_callback(struct ieee80211_local *local, |
849 | struct ieee80211_sub_if_data *sdata, | ||
848 | const enum ieee80211_rssi_event event) | 850 | const enum ieee80211_rssi_event event) |
849 | { | 851 | { |
850 | trace_drv_rssi_callback(local, event); | 852 | trace_drv_rssi_callback(local, sdata, event); |
851 | if (local->ops->rssi_callback) | 853 | if (local->ops->rssi_callback) |
852 | local->ops->rssi_callback(&local->hw, event); | 854 | local->ops->rssi_callback(&local->hw, &sdata->vif, event); |
853 | trace_drv_return_void(local); | 855 | trace_drv_return_void(local); |
854 | } | 856 | } |
855 | 857 | ||
@@ -1020,4 +1022,32 @@ static inline void drv_restart_complete(struct ieee80211_local *local) | |||
1020 | trace_drv_return_void(local); | 1022 | trace_drv_return_void(local); |
1021 | } | 1023 | } |
1022 | 1024 | ||
1025 | static inline void | ||
1026 | drv_set_default_unicast_key(struct ieee80211_local *local, | ||
1027 | struct ieee80211_sub_if_data *sdata, | ||
1028 | int key_idx) | ||
1029 | { | ||
1030 | check_sdata_in_driver(sdata); | ||
1031 | |||
1032 | WARN_ON_ONCE(key_idx < -1 || key_idx > 3); | ||
1033 | |||
1034 | trace_drv_set_default_unicast_key(local, sdata, key_idx); | ||
1035 | if (local->ops->set_default_unicast_key) | ||
1036 | local->ops->set_default_unicast_key(&local->hw, &sdata->vif, | ||
1037 | key_idx); | ||
1038 | trace_drv_return_void(local); | ||
1039 | } | ||
1040 | |||
1041 | #if IS_ENABLED(CONFIG_IPV6) | ||
1042 | static inline void drv_ipv6_addr_change(struct ieee80211_local *local, | ||
1043 | struct ieee80211_sub_if_data *sdata, | ||
1044 | struct inet6_dev *idev) | ||
1045 | { | ||
1046 | trace_drv_ipv6_addr_change(local, sdata); | ||
1047 | if (local->ops->ipv6_addr_change) | ||
1048 | local->ops->ipv6_addr_change(&local->hw, &sdata->vif, idev); | ||
1049 | trace_drv_return_void(local); | ||
1050 | } | ||
1051 | #endif | ||
1052 | |||
1023 | #endif /* __MAC80211_DRIVER_OPS */ | 1053 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 63f0430c131e..5fba867d9e2e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -747,8 +747,6 @@ struct ieee80211_sub_if_data { | |||
747 | struct work_struct work; | 747 | struct work_struct work; |
748 | struct sk_buff_head skb_queue; | 748 | struct sk_buff_head skb_queue; |
749 | 749 | ||
750 | bool arp_filter_state; | ||
751 | |||
752 | u8 needed_rx_chains; | 750 | u8 needed_rx_chains; |
753 | enum ieee80211_smps_mode smps_mode; | 751 | enum ieee80211_smps_mode smps_mode; |
754 | 752 | ||
@@ -1129,6 +1127,7 @@ struct ieee80211_local { | |||
1129 | struct timer_list dynamic_ps_timer; | 1127 | struct timer_list dynamic_ps_timer; |
1130 | struct notifier_block network_latency_notifier; | 1128 | struct notifier_block network_latency_notifier; |
1131 | struct notifier_block ifa_notifier; | 1129 | struct notifier_block ifa_notifier; |
1130 | struct notifier_block ifa6_notifier; | ||
1132 | 1131 | ||
1133 | /* | 1132 | /* |
1134 | * The dynamic ps timeout configured from user space via WEXT - | 1133 | * The dynamic ps timeout configured from user space via WEXT - |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 06fac2991d40..0a36dc6346bb 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1574,9 +1574,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1574 | /* initialise type-independent data */ | 1574 | /* initialise type-independent data */ |
1575 | sdata->wdev.wiphy = local->hw.wiphy; | 1575 | sdata->wdev.wiphy = local->hw.wiphy; |
1576 | sdata->local = local; | 1576 | sdata->local = local; |
1577 | #ifdef CONFIG_INET | ||
1578 | sdata->arp_filter_state = true; | ||
1579 | #endif | ||
1580 | 1577 | ||
1581 | for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) | 1578 | for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) |
1582 | skb_queue_head_init(&sdata->fragments[i].skb_list); | 1579 | skb_queue_head_init(&sdata->fragments[i].skb_list); |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 619c5d697999..ef252eb58c36 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -204,8 +204,11 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, | |||
204 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) | 204 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) |
205 | key = key_mtx_dereference(sdata->local, sdata->keys[idx]); | 205 | key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
206 | 206 | ||
207 | if (uni) | 207 | if (uni) { |
208 | rcu_assign_pointer(sdata->default_unicast_key, key); | 208 | rcu_assign_pointer(sdata->default_unicast_key, key); |
209 | drv_set_default_unicast_key(sdata->local, sdata, idx); | ||
210 | } | ||
211 | |||
209 | if (multi) | 212 | if (multi) |
210 | rcu_assign_pointer(sdata->default_multicast_key, key); | 213 | rcu_assign_pointer(sdata->default_multicast_key, key); |
211 | 214 | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 39cfe8f10ad2..2bdd454e8bcf 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/inetdevice.h> | 23 | #include <linux/inetdevice.h> |
24 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
25 | #include <net/cfg80211.h> | 25 | #include <net/cfg80211.h> |
26 | #include <net/addrconf.h> | ||
26 | 27 | ||
27 | #include "ieee80211_i.h" | 28 | #include "ieee80211_i.h" |
28 | #include "driver-ops.h" | 29 | #include "driver-ops.h" |
@@ -349,27 +350,19 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, | |||
349 | 350 | ||
350 | /* Copy the addresses to the bss_conf list */ | 351 | /* Copy the addresses to the bss_conf list */ |
351 | ifa = idev->ifa_list; | 352 | ifa = idev->ifa_list; |
352 | while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) { | 353 | while (ifa) { |
353 | bss_conf->arp_addr_list[c] = ifa->ifa_address; | 354 | if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN) |
355 | bss_conf->arp_addr_list[c] = ifa->ifa_address; | ||
354 | ifa = ifa->ifa_next; | 356 | ifa = ifa->ifa_next; |
355 | c++; | 357 | c++; |
356 | } | 358 | } |
357 | 359 | ||
358 | /* If not all addresses fit the list, disable filtering */ | ||
359 | if (ifa) { | ||
360 | sdata->arp_filter_state = false; | ||
361 | c = 0; | ||
362 | } else { | ||
363 | sdata->arp_filter_state = true; | ||
364 | } | ||
365 | bss_conf->arp_addr_cnt = c; | 360 | bss_conf->arp_addr_cnt = c; |
366 | 361 | ||
367 | /* Configure driver only if associated (which also implies it is up) */ | 362 | /* Configure driver only if associated (which also implies it is up) */ |
368 | if (ifmgd->associated) { | 363 | if (ifmgd->associated) |
369 | bss_conf->arp_filter_enabled = sdata->arp_filter_state; | ||
370 | ieee80211_bss_info_change_notify(sdata, | 364 | ieee80211_bss_info_change_notify(sdata, |
371 | BSS_CHANGED_ARP_FILTER); | 365 | BSS_CHANGED_ARP_FILTER); |
372 | } | ||
373 | 366 | ||
374 | mutex_unlock(&ifmgd->mtx); | 367 | mutex_unlock(&ifmgd->mtx); |
375 | 368 | ||
@@ -377,6 +370,37 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, | |||
377 | } | 370 | } |
378 | #endif | 371 | #endif |
379 | 372 | ||
373 | #if IS_ENABLED(CONFIG_IPV6) | ||
374 | static int ieee80211_ifa6_changed(struct notifier_block *nb, | ||
375 | unsigned long data, void *arg) | ||
376 | { | ||
377 | struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg; | ||
378 | struct inet6_dev *idev = ifa->idev; | ||
379 | struct net_device *ndev = ifa->idev->dev; | ||
380 | struct ieee80211_local *local = | ||
381 | container_of(nb, struct ieee80211_local, ifa6_notifier); | ||
382 | struct wireless_dev *wdev = ndev->ieee80211_ptr; | ||
383 | struct ieee80211_sub_if_data *sdata; | ||
384 | |||
385 | /* Make sure it's our interface that got changed */ | ||
386 | if (!wdev || wdev->wiphy != local->hw.wiphy) | ||
387 | return NOTIFY_DONE; | ||
388 | |||
389 | sdata = IEEE80211_DEV_TO_SUB_IF(ndev); | ||
390 | |||
391 | /* | ||
392 | * For now only support station mode. This is mostly because | ||
393 | * doing AP would have to handle AP_VLAN in some way ... | ||
394 | */ | ||
395 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
396 | return NOTIFY_DONE; | ||
397 | |||
398 | drv_ipv6_addr_change(local, sdata, idev); | ||
399 | |||
400 | return NOTIFY_DONE; | ||
401 | } | ||
402 | #endif | ||
403 | |||
380 | static int ieee80211_napi_poll(struct napi_struct *napi, int budget) | 404 | static int ieee80211_napi_poll(struct napi_struct *napi, int budget) |
381 | { | 405 | { |
382 | struct ieee80211_local *local = | 406 | struct ieee80211_local *local = |
@@ -985,12 +1009,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
985 | goto fail_ifa; | 1009 | goto fail_ifa; |
986 | #endif | 1010 | #endif |
987 | 1011 | ||
1012 | #if IS_ENABLED(CONFIG_IPV6) | ||
1013 | local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed; | ||
1014 | result = register_inet6addr_notifier(&local->ifa6_notifier); | ||
1015 | if (result) | ||
1016 | goto fail_ifa6; | ||
1017 | #endif | ||
1018 | |||
988 | netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll, | 1019 | netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll, |
989 | local->hw.napi_weight); | 1020 | local->hw.napi_weight); |
990 | 1021 | ||
991 | return 0; | 1022 | return 0; |
992 | 1023 | ||
1024 | #if IS_ENABLED(CONFIG_IPV6) | ||
1025 | fail_ifa6: | ||
993 | #ifdef CONFIG_INET | 1026 | #ifdef CONFIG_INET |
1027 | unregister_inetaddr_notifier(&local->ifa_notifier); | ||
1028 | #endif | ||
1029 | #endif | ||
1030 | #if defined(CONFIG_INET) || defined(CONFIG_IPV6) | ||
994 | fail_ifa: | 1031 | fail_ifa: |
995 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, | 1032 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, |
996 | &local->network_latency_notifier); | 1033 | &local->network_latency_notifier); |
@@ -1026,6 +1063,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
1026 | #ifdef CONFIG_INET | 1063 | #ifdef CONFIG_INET |
1027 | unregister_inetaddr_notifier(&local->ifa_notifier); | 1064 | unregister_inetaddr_notifier(&local->ifa_notifier); |
1028 | #endif | 1065 | #endif |
1066 | #if IS_ENABLED(CONFIG_IPV6) | ||
1067 | unregister_inet6addr_notifier(&local->ifa6_notifier); | ||
1068 | #endif | ||
1029 | 1069 | ||
1030 | rtnl_lock(); | 1070 | rtnl_lock(); |
1031 | 1071 | ||
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 9e0416696a83..81e612682bc3 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -55,30 +55,6 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) | |||
55 | sta->plink_retries = 0; | 55 | sta->plink_retries = 0; |
56 | } | 56 | } |
57 | 57 | ||
58 | /* | ||
59 | * Allocate mesh sta entry and insert into station table | ||
60 | */ | ||
61 | static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | ||
62 | u8 *hw_addr) | ||
63 | { | ||
64 | struct sta_info *sta; | ||
65 | |||
66 | if (sdata->local->num_sta >= MESH_MAX_PLINKS) | ||
67 | return NULL; | ||
68 | |||
69 | sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); | ||
70 | if (!sta) | ||
71 | return NULL; | ||
72 | |||
73 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); | ||
74 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); | ||
75 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
76 | |||
77 | set_sta_flag(sta, WLAN_STA_WME); | ||
78 | |||
79 | return sta; | ||
80 | } | ||
81 | |||
82 | /** | 58 | /** |
83 | * mesh_set_ht_prot_mode - set correct HT protection mode | 59 | * mesh_set_ht_prot_mode - set correct HT protection mode |
84 | * | 60 | * |
@@ -309,53 +285,27 @@ free: | |||
309 | return err; | 285 | return err; |
310 | } | 286 | } |
311 | 287 | ||
312 | /** | 288 | static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, |
313 | * mesh_peer_init - initialize new mesh peer and return resulting sta_info | 289 | struct sta_info *sta, |
314 | * | 290 | struct ieee802_11_elems *elems, bool insert) |
315 | * @sdata: local meshif | ||
316 | * @addr: peer's address | ||
317 | * @elems: IEs from beacon or mesh peering frame | ||
318 | * | ||
319 | * call under RCU | ||
320 | */ | ||
321 | static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, | ||
322 | u8 *addr, | ||
323 | struct ieee802_11_elems *elems) | ||
324 | { | 291 | { |
325 | struct ieee80211_local *local = sdata->local; | 292 | struct ieee80211_local *local = sdata->local; |
326 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | 293 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); |
327 | struct ieee80211_supported_band *sband; | 294 | struct ieee80211_supported_band *sband; |
328 | u32 rates, basic_rates = 0; | 295 | u32 rates, basic_rates = 0, changed = 0; |
329 | struct sta_info *sta; | ||
330 | bool insert = false; | ||
331 | 296 | ||
332 | sband = local->hw.wiphy->bands[band]; | 297 | sband = local->hw.wiphy->bands[band]; |
333 | rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates); | 298 | rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates); |
334 | 299 | ||
335 | sta = sta_info_get(sdata, addr); | ||
336 | if (!sta) { | ||
337 | /* Userspace handles peer allocation when security is enabled */ | ||
338 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) { | ||
339 | cfg80211_notify_new_peer_candidate(sdata->dev, addr, | ||
340 | elems->ie_start, | ||
341 | elems->total_len, | ||
342 | GFP_ATOMIC); | ||
343 | return NULL; | ||
344 | } | ||
345 | |||
346 | sta = mesh_plink_alloc(sdata, addr); | ||
347 | if (!sta) | ||
348 | return NULL; | ||
349 | insert = true; | ||
350 | } | ||
351 | |||
352 | spin_lock_bh(&sta->lock); | 300 | spin_lock_bh(&sta->lock); |
353 | sta->last_rx = jiffies; | 301 | sta->last_rx = jiffies; |
354 | if (sta->plink_state == NL80211_PLINK_ESTAB) { | ||
355 | spin_unlock_bh(&sta->lock); | ||
356 | return sta; | ||
357 | } | ||
358 | 302 | ||
303 | /* rates and capabilities don't change during peering */ | ||
304 | if (sta->plink_state == NL80211_PLINK_ESTAB) | ||
305 | goto out; | ||
306 | |||
307 | if (sta->sta.supp_rates[band] != rates) | ||
308 | changed |= IEEE80211_RC_SUPP_RATES_CHANGED; | ||
359 | sta->sta.supp_rates[band] = rates; | 309 | sta->sta.supp_rates[band] = rates; |
360 | if (elems->ht_cap_elem && | 310 | if (elems->ht_cap_elem && |
361 | sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) | 311 | sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) |
@@ -374,27 +324,115 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, | |||
374 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 324 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
375 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, | 325 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, |
376 | elems->ht_operation, &chandef); | 326 | elems->ht_operation, &chandef); |
327 | if (sta->ch_width != chandef.width) | ||
328 | changed |= IEEE80211_RC_BW_CHANGED; | ||
377 | sta->ch_width = chandef.width; | 329 | sta->ch_width = chandef.width; |
378 | } | 330 | } |
379 | 331 | ||
380 | if (insert) | 332 | if (insert) |
381 | rate_control_rate_init(sta); | 333 | rate_control_rate_init(sta); |
334 | else | ||
335 | rate_control_rate_update(local, sband, sta, changed); | ||
336 | out: | ||
382 | spin_unlock_bh(&sta->lock); | 337 | spin_unlock_bh(&sta->lock); |
338 | } | ||
339 | |||
340 | static struct sta_info * | ||
341 | __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr) | ||
342 | { | ||
343 | struct sta_info *sta; | ||
383 | 344 | ||
384 | if (insert && sta_info_insert(sta)) | 345 | if (sdata->local->num_sta >= MESH_MAX_PLINKS) |
385 | return NULL; | 346 | return NULL; |
386 | 347 | ||
348 | sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); | ||
349 | if (!sta) | ||
350 | return NULL; | ||
351 | |||
352 | sta->plink_state = NL80211_PLINK_LISTEN; | ||
353 | init_timer(&sta->plink_timer); | ||
354 | |||
355 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); | ||
356 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); | ||
357 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
358 | |||
359 | set_sta_flag(sta, WLAN_STA_WME); | ||
360 | |||
361 | return sta; | ||
362 | } | ||
363 | |||
364 | static struct sta_info * | ||
365 | mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr, | ||
366 | struct ieee802_11_elems *elems) | ||
367 | { | ||
368 | struct sta_info *sta = NULL; | ||
369 | |||
370 | /* Userspace handles peer allocation when security is enabled */ | ||
371 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) | ||
372 | cfg80211_notify_new_peer_candidate(sdata->dev, addr, | ||
373 | elems->ie_start, | ||
374 | elems->total_len, | ||
375 | GFP_KERNEL); | ||
376 | else | ||
377 | sta = __mesh_sta_info_alloc(sdata, addr); | ||
378 | |||
379 | return sta; | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | * mesh_sta_info_get - return mesh sta info entry for @addr. | ||
384 | * | ||
385 | * @sdata: local meshif | ||
386 | * @addr: peer's address | ||
387 | * @elems: IEs from beacon or mesh peering frame. | ||
388 | * | ||
389 | * Return existing or newly allocated sta_info under RCU read lock. | ||
390 | * (re)initialize with given IEs. | ||
391 | */ | ||
392 | static struct sta_info * | ||
393 | mesh_sta_info_get(struct ieee80211_sub_if_data *sdata, | ||
394 | u8 *addr, struct ieee802_11_elems *elems) __acquires(RCU) | ||
395 | { | ||
396 | struct sta_info *sta = NULL; | ||
397 | |||
398 | rcu_read_lock(); | ||
399 | sta = sta_info_get(sdata, addr); | ||
400 | if (sta) { | ||
401 | mesh_sta_info_init(sdata, sta, elems, false); | ||
402 | } else { | ||
403 | rcu_read_unlock(); | ||
404 | /* can't run atomic */ | ||
405 | sta = mesh_sta_info_alloc(sdata, addr, elems); | ||
406 | if (!sta) { | ||
407 | rcu_read_lock(); | ||
408 | return NULL; | ||
409 | } | ||
410 | |||
411 | mesh_sta_info_init(sdata, sta, elems, true); | ||
412 | |||
413 | if (sta_info_insert_rcu(sta)) | ||
414 | return NULL; | ||
415 | } | ||
416 | |||
387 | return sta; | 417 | return sta; |
388 | } | 418 | } |
389 | 419 | ||
420 | /* | ||
421 | * mesh_neighbour_update - update or initialize new mesh neighbor. | ||
422 | * | ||
423 | * @sdata: local meshif | ||
424 | * @addr: peer's address | ||
425 | * @elems: IEs from beacon or mesh peering frame | ||
426 | * | ||
427 | * Initiates peering if appropriate. | ||
428 | */ | ||
390 | void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | 429 | void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, |
391 | u8 *hw_addr, | 430 | u8 *hw_addr, |
392 | struct ieee802_11_elems *elems) | 431 | struct ieee802_11_elems *elems) |
393 | { | 432 | { |
394 | struct sta_info *sta; | 433 | struct sta_info *sta; |
395 | 434 | ||
396 | rcu_read_lock(); | 435 | sta = mesh_sta_info_get(sdata, hw_addr, elems); |
397 | sta = mesh_peer_init(sdata, hw_addr, elems); | ||
398 | if (!sta) | 436 | if (!sta) |
399 | goto out; | 437 | goto out; |
400 | 438 | ||
@@ -632,6 +670,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
632 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) | 670 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) |
633 | memcpy(&llid, PLINK_GET_PLID(elems.peering), 2); | 671 | memcpy(&llid, PLINK_GET_PLID(elems.peering), 2); |
634 | 672 | ||
673 | /* WARNING: Only for sta pointer, is dropped & re-acquired */ | ||
635 | rcu_read_lock(); | 674 | rcu_read_lock(); |
636 | 675 | ||
637 | sta = sta_info_get(sdata, mgmt->sa); | 676 | sta = sta_info_get(sdata, mgmt->sa); |
@@ -735,8 +774,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
735 | } | 774 | } |
736 | 775 | ||
737 | if (event == OPN_ACPT) { | 776 | if (event == OPN_ACPT) { |
777 | rcu_read_unlock(); | ||
738 | /* allocate sta entry if necessary and update info */ | 778 | /* allocate sta entry if necessary and update info */ |
739 | sta = mesh_peer_init(sdata, mgmt->sa, &elems); | 779 | sta = mesh_sta_info_get(sdata, mgmt->sa, &elems); |
740 | if (!sta) { | 780 | if (!sta) { |
741 | mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); | 781 | mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); |
742 | rcu_read_unlock(); | 782 | rcu_read_unlock(); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e930175771ff..5913fb924b12 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1465,10 +1465,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1465 | bss_info_changed |= BSS_CHANGED_CQM; | 1465 | bss_info_changed |= BSS_CHANGED_CQM; |
1466 | 1466 | ||
1467 | /* Enable ARP filtering */ | 1467 | /* Enable ARP filtering */ |
1468 | if (bss_conf->arp_filter_enabled != sdata->arp_filter_state) { | 1468 | if (bss_conf->arp_addr_cnt) |
1469 | bss_conf->arp_filter_enabled = sdata->arp_filter_state; | ||
1470 | bss_info_changed |= BSS_CHANGED_ARP_FILTER; | 1469 | bss_info_changed |= BSS_CHANGED_ARP_FILTER; |
1471 | } | ||
1472 | 1470 | ||
1473 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); | 1471 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); |
1474 | 1472 | ||
@@ -1489,7 +1487,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1489 | { | 1487 | { |
1490 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1488 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1491 | struct ieee80211_local *local = sdata->local; | 1489 | struct ieee80211_local *local = sdata->local; |
1492 | struct sta_info *sta; | ||
1493 | u32 changed = 0; | 1490 | u32 changed = 0; |
1494 | 1491 | ||
1495 | ASSERT_MGD_MTX(ifmgd); | 1492 | ASSERT_MGD_MTX(ifmgd); |
@@ -1521,14 +1518,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1521 | netif_tx_stop_all_queues(sdata->dev); | 1518 | netif_tx_stop_all_queues(sdata->dev); |
1522 | netif_carrier_off(sdata->dev); | 1519 | netif_carrier_off(sdata->dev); |
1523 | 1520 | ||
1524 | mutex_lock(&local->sta_mtx); | ||
1525 | sta = sta_info_get(sdata, ifmgd->bssid); | ||
1526 | if (sta) { | ||
1527 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
1528 | ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA); | ||
1529 | } | ||
1530 | mutex_unlock(&local->sta_mtx); | ||
1531 | |||
1532 | /* | 1521 | /* |
1533 | * if we want to get out of ps before disassoc (why?) we have | 1522 | * if we want to get out of ps before disassoc (why?) we have |
1534 | * to do it before sending disassoc, as otherwise the null-packet | 1523 | * to do it before sending disassoc, as otherwise the null-packet |
@@ -1582,10 +1571,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1582 | cancel_work_sync(&local->dynamic_ps_enable_work); | 1571 | cancel_work_sync(&local->dynamic_ps_enable_work); |
1583 | 1572 | ||
1584 | /* Disable ARP filtering */ | 1573 | /* Disable ARP filtering */ |
1585 | if (sdata->vif.bss_conf.arp_filter_enabled) { | 1574 | if (sdata->vif.bss_conf.arp_addr_cnt) |
1586 | sdata->vif.bss_conf.arp_filter_enabled = false; | ||
1587 | changed |= BSS_CHANGED_ARP_FILTER; | 1575 | changed |= BSS_CHANGED_ARP_FILTER; |
1588 | } | ||
1589 | 1576 | ||
1590 | sdata->vif.bss_conf.qos = false; | 1577 | sdata->vif.bss_conf.qos = false; |
1591 | changed |= BSS_CHANGED_QOS; | 1578 | changed |= BSS_CHANGED_QOS; |
@@ -2608,12 +2595,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2608 | if (sig > ifmgd->rssi_max_thold && | 2595 | if (sig > ifmgd->rssi_max_thold && |
2609 | (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) { | 2596 | (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) { |
2610 | ifmgd->last_ave_beacon_signal = sig; | 2597 | ifmgd->last_ave_beacon_signal = sig; |
2611 | drv_rssi_callback(local, RSSI_EVENT_HIGH); | 2598 | drv_rssi_callback(local, sdata, RSSI_EVENT_HIGH); |
2612 | } else if (sig < ifmgd->rssi_min_thold && | 2599 | } else if (sig < ifmgd->rssi_min_thold && |
2613 | (last_sig >= ifmgd->rssi_max_thold || | 2600 | (last_sig >= ifmgd->rssi_max_thold || |
2614 | last_sig == 0)) { | 2601 | last_sig == 0)) { |
2615 | ifmgd->last_ave_beacon_signal = sig; | 2602 | ifmgd->last_ave_beacon_signal = sig; |
2616 | drv_rssi_callback(local, RSSI_EVENT_LOW); | 2603 | drv_rssi_callback(local, sdata, RSSI_EVENT_LOW); |
2617 | } | 2604 | } |
2618 | } | 2605 | } |
2619 | 2606 | ||
@@ -3169,23 +3156,22 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | |||
3169 | { | 3156 | { |
3170 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3157 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3171 | 3158 | ||
3172 | if (!ifmgd->associated) | 3159 | mutex_lock(&ifmgd->mtx); |
3160 | if (!ifmgd->associated) { | ||
3161 | mutex_unlock(&ifmgd->mtx); | ||
3173 | return; | 3162 | return; |
3163 | } | ||
3174 | 3164 | ||
3175 | if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) { | 3165 | if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) { |
3176 | sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; | 3166 | sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; |
3177 | mutex_lock(&ifmgd->mtx); | 3167 | mlme_dbg(sdata, "driver requested disconnect after resume\n"); |
3178 | if (ifmgd->associated) { | 3168 | ieee80211_sta_connection_lost(sdata, |
3179 | mlme_dbg(sdata, | 3169 | ifmgd->associated->bssid, |
3180 | "driver requested disconnect after resume\n"); | 3170 | WLAN_REASON_UNSPECIFIED); |
3181 | ieee80211_sta_connection_lost(sdata, | ||
3182 | ifmgd->associated->bssid, | ||
3183 | WLAN_REASON_UNSPECIFIED); | ||
3184 | mutex_unlock(&ifmgd->mtx); | ||
3185 | return; | ||
3186 | } | ||
3187 | mutex_unlock(&ifmgd->mtx); | 3171 | mutex_unlock(&ifmgd->mtx); |
3172 | return; | ||
3188 | } | 3173 | } |
3174 | mutex_unlock(&ifmgd->mtx); | ||
3189 | 3175 | ||
3190 | if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) | 3176 | if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) |
3191 | add_timer(&ifmgd->timer); | 3177 | add_timer(&ifmgd->timer); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 9d864ed5f3da..227233c3ff7f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -380,11 +380,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
380 | 380 | ||
381 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); | 381 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); |
382 | 382 | ||
383 | #ifdef CONFIG_MAC80211_MESH | ||
384 | sta->plink_state = NL80211_PLINK_LISTEN; | ||
385 | init_timer(&sta->plink_timer); | ||
386 | #endif | ||
387 | |||
388 | return sta; | 383 | return sta; |
389 | } | 384 | } |
390 | 385 | ||
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 41861b91daa3..6ca53d64cb28 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -347,8 +347,11 @@ TRACE_EVENT(drv_bss_info_changed, | |||
347 | __field(s32, cqm_rssi_hyst); | 347 | __field(s32, cqm_rssi_hyst); |
348 | __field(u32, channel_width); | 348 | __field(u32, channel_width); |
349 | __field(u32, channel_cfreq1); | 349 | __field(u32, channel_cfreq1); |
350 | __dynamic_array(u32, arp_addr_list, info->arp_addr_cnt); | 350 | __dynamic_array(u32, arp_addr_list, |
351 | __field(bool, arp_filter_enabled); | 351 | info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? |
352 | IEEE80211_BSS_ARP_ADDR_LIST_LEN : | ||
353 | info->arp_addr_cnt); | ||
354 | __field(int, arp_addr_cnt); | ||
352 | __field(bool, qos); | 355 | __field(bool, qos); |
353 | __field(bool, idle); | 356 | __field(bool, idle); |
354 | __field(bool, ps); | 357 | __field(bool, ps); |
@@ -384,9 +387,11 @@ TRACE_EVENT(drv_bss_info_changed, | |||
384 | __entry->cqm_rssi_hyst = info->cqm_rssi_hyst; | 387 | __entry->cqm_rssi_hyst = info->cqm_rssi_hyst; |
385 | __entry->channel_width = info->chandef.width; | 388 | __entry->channel_width = info->chandef.width; |
386 | __entry->channel_cfreq1 = info->chandef.center_freq1; | 389 | __entry->channel_cfreq1 = info->chandef.center_freq1; |
390 | __entry->arp_addr_cnt = info->arp_addr_cnt; | ||
387 | memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list, | 391 | memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list, |
388 | sizeof(u32) * info->arp_addr_cnt); | 392 | sizeof(u32) * (info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? |
389 | __entry->arp_filter_enabled = info->arp_filter_enabled; | 393 | IEEE80211_BSS_ARP_ADDR_LIST_LEN : |
394 | info->arp_addr_cnt)); | ||
390 | __entry->qos = info->qos; | 395 | __entry->qos = info->qos; |
391 | __entry->idle = info->idle; | 396 | __entry->idle = info->idle; |
392 | __entry->ps = info->ps; | 397 | __entry->ps = info->ps; |
@@ -1184,23 +1189,26 @@ TRACE_EVENT(drv_set_rekey_data, | |||
1184 | 1189 | ||
1185 | TRACE_EVENT(drv_rssi_callback, | 1190 | TRACE_EVENT(drv_rssi_callback, |
1186 | TP_PROTO(struct ieee80211_local *local, | 1191 | TP_PROTO(struct ieee80211_local *local, |
1192 | struct ieee80211_sub_if_data *sdata, | ||
1187 | enum ieee80211_rssi_event rssi_event), | 1193 | enum ieee80211_rssi_event rssi_event), |
1188 | 1194 | ||
1189 | TP_ARGS(local, rssi_event), | 1195 | TP_ARGS(local, sdata, rssi_event), |
1190 | 1196 | ||
1191 | TP_STRUCT__entry( | 1197 | TP_STRUCT__entry( |
1192 | LOCAL_ENTRY | 1198 | LOCAL_ENTRY |
1199 | VIF_ENTRY | ||
1193 | __field(u32, rssi_event) | 1200 | __field(u32, rssi_event) |
1194 | ), | 1201 | ), |
1195 | 1202 | ||
1196 | TP_fast_assign( | 1203 | TP_fast_assign( |
1197 | LOCAL_ASSIGN; | 1204 | LOCAL_ASSIGN; |
1205 | VIF_ASSIGN; | ||
1198 | __entry->rssi_event = rssi_event; | 1206 | __entry->rssi_event = rssi_event; |
1199 | ), | 1207 | ), |
1200 | 1208 | ||
1201 | TP_printk( | 1209 | TP_printk( |
1202 | LOCAL_PR_FMT " rssi_event:%d", | 1210 | LOCAL_PR_FMT VIF_PR_FMT " rssi_event:%d", |
1203 | LOCAL_PR_ARG, __entry->rssi_event | 1211 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->rssi_event |
1204 | ) | 1212 | ) |
1205 | ); | 1213 | ); |
1206 | 1214 | ||
@@ -1432,6 +1440,14 @@ DEFINE_EVENT(local_only_evt, drv_restart_complete, | |||
1432 | TP_ARGS(local) | 1440 | TP_ARGS(local) |
1433 | ); | 1441 | ); |
1434 | 1442 | ||
1443 | #if IS_ENABLED(CONFIG_IPV6) | ||
1444 | DEFINE_EVENT(local_sdata_evt, drv_ipv6_addr_change, | ||
1445 | TP_PROTO(struct ieee80211_local *local, | ||
1446 | struct ieee80211_sub_if_data *sdata), | ||
1447 | TP_ARGS(local, sdata) | ||
1448 | ); | ||
1449 | #endif | ||
1450 | |||
1435 | /* | 1451 | /* |
1436 | * Tracing for API calls that drivers call. | 1452 | * Tracing for API calls that drivers call. |
1437 | */ | 1453 | */ |
@@ -1821,6 +1837,29 @@ TRACE_EVENT(stop_queue, | |||
1821 | ) | 1837 | ) |
1822 | ); | 1838 | ); |
1823 | 1839 | ||
1840 | TRACE_EVENT(drv_set_default_unicast_key, | ||
1841 | TP_PROTO(struct ieee80211_local *local, | ||
1842 | struct ieee80211_sub_if_data *sdata, | ||
1843 | int key_idx), | ||
1844 | |||
1845 | TP_ARGS(local, sdata, key_idx), | ||
1846 | |||
1847 | TP_STRUCT__entry( | ||
1848 | LOCAL_ENTRY | ||
1849 | VIF_ENTRY | ||
1850 | __field(int, key_idx) | ||
1851 | ), | ||
1852 | |||
1853 | TP_fast_assign( | ||
1854 | LOCAL_ASSIGN; | ||
1855 | VIF_ASSIGN; | ||
1856 | __entry->key_idx = key_idx; | ||
1857 | ), | ||
1858 | |||
1859 | TP_printk(LOCAL_PR_FMT VIF_PR_FMT " key_idx:%d", | ||
1860 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->key_idx) | ||
1861 | ); | ||
1862 | |||
1824 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING | 1863 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING |
1825 | #undef TRACE_SYSTEM | 1864 | #undef TRACE_SYSTEM |
1826 | #define TRACE_SYSTEM mac80211_msg | 1865 | #define TRACE_SYSTEM mac80211_msg |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f32d68186dbc..a2cb6a302cc7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1787,16 +1787,16 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1787 | break; | 1787 | break; |
1788 | /* fall through */ | 1788 | /* fall through */ |
1789 | case NL80211_IFTYPE_AP: | 1789 | case NL80211_IFTYPE_AP: |
1790 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
1791 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
1792 | if (!chanctx_conf) | ||
1793 | goto fail_rcu; | ||
1790 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | 1794 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
1791 | /* DA BSSID SA */ | 1795 | /* DA BSSID SA */ |
1792 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1796 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
1793 | memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); | 1797 | memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); |
1794 | memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); | 1798 | memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); |
1795 | hdrlen = 24; | 1799 | hdrlen = 24; |
1796 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
1797 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
1798 | if (!chanctx_conf) | ||
1799 | goto fail_rcu; | ||
1800 | band = chanctx_conf->def.chan->band; | 1800 | band = chanctx_conf->def.chan->band; |
1801 | break; | 1801 | break; |
1802 | case NL80211_IFTYPE_WDS: | 1802 | case NL80211_IFTYPE_WDS: |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 9245729694d2..40dbe37cfbf6 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -478,6 +478,11 @@ int wiphy_register(struct wiphy *wiphy) | |||
478 | ETH_ALEN))) | 478 | ETH_ALEN))) |
479 | return -EINVAL; | 479 | return -EINVAL; |
480 | 480 | ||
481 | if (WARN_ON(wiphy->max_acl_mac_addrs && | ||
482 | (!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME) || | ||
483 | !rdev->ops->set_mac_acl))) | ||
484 | return -EINVAL; | ||
485 | |||
481 | if (wiphy->addresses) | 486 | if (wiphy->addresses) |
482 | memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN); | 487 | memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN); |
483 | 488 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 33de80364c5c..b5978ab4ad7a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -365,6 +365,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
365 | [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, | 365 | [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, |
366 | [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, | 366 | [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, |
367 | [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, | 367 | [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, |
368 | [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, | ||
369 | [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, | ||
368 | }; | 370 | }; |
369 | 371 | ||
370 | /* policy for the key attributes */ | 372 | /* policy for the key attributes */ |
@@ -1268,6 +1270,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
1268 | dev->wiphy.ht_capa_mod_mask)) | 1270 | dev->wiphy.ht_capa_mod_mask)) |
1269 | goto nla_put_failure; | 1271 | goto nla_put_failure; |
1270 | 1272 | ||
1273 | if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME && | ||
1274 | dev->wiphy.max_acl_mac_addrs && | ||
1275 | nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX, | ||
1276 | dev->wiphy.max_acl_mac_addrs)) | ||
1277 | goto nla_put_failure; | ||
1278 | |||
1271 | return genlmsg_end(msg, hdr); | 1279 | return genlmsg_end(msg, hdr); |
1272 | 1280 | ||
1273 | nla_put_failure: | 1281 | nla_put_failure: |
@@ -2491,6 +2499,97 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
2491 | return err; | 2499 | return err; |
2492 | } | 2500 | } |
2493 | 2501 | ||
2502 | /* This function returns an error or the number of nested attributes */ | ||
2503 | static int validate_acl_mac_addrs(struct nlattr *nl_attr) | ||
2504 | { | ||
2505 | struct nlattr *attr; | ||
2506 | int n_entries = 0, tmp; | ||
2507 | |||
2508 | nla_for_each_nested(attr, nl_attr, tmp) { | ||
2509 | if (nla_len(attr) != ETH_ALEN) | ||
2510 | return -EINVAL; | ||
2511 | |||
2512 | n_entries++; | ||
2513 | } | ||
2514 | |||
2515 | return n_entries; | ||
2516 | } | ||
2517 | |||
2518 | /* | ||
2519 | * This function parses ACL information and allocates memory for ACL data. | ||
2520 | * On successful return, the calling function is responsible to free the | ||
2521 | * ACL buffer returned by this function. | ||
2522 | */ | ||
2523 | static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy, | ||
2524 | struct genl_info *info) | ||
2525 | { | ||
2526 | enum nl80211_acl_policy acl_policy; | ||
2527 | struct nlattr *attr; | ||
2528 | struct cfg80211_acl_data *acl; | ||
2529 | int i = 0, n_entries, tmp; | ||
2530 | |||
2531 | if (!wiphy->max_acl_mac_addrs) | ||
2532 | return ERR_PTR(-EOPNOTSUPP); | ||
2533 | |||
2534 | if (!info->attrs[NL80211_ATTR_ACL_POLICY]) | ||
2535 | return ERR_PTR(-EINVAL); | ||
2536 | |||
2537 | acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]); | ||
2538 | if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED && | ||
2539 | acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED) | ||
2540 | return ERR_PTR(-EINVAL); | ||
2541 | |||
2542 | if (!info->attrs[NL80211_ATTR_MAC_ADDRS]) | ||
2543 | return ERR_PTR(-EINVAL); | ||
2544 | |||
2545 | n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]); | ||
2546 | if (n_entries < 0) | ||
2547 | return ERR_PTR(n_entries); | ||
2548 | |||
2549 | if (n_entries > wiphy->max_acl_mac_addrs) | ||
2550 | return ERR_PTR(-ENOTSUPP); | ||
2551 | |||
2552 | acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries), | ||
2553 | GFP_KERNEL); | ||
2554 | if (!acl) | ||
2555 | return ERR_PTR(-ENOMEM); | ||
2556 | |||
2557 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) { | ||
2558 | memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN); | ||
2559 | i++; | ||
2560 | } | ||
2561 | |||
2562 | acl->n_acl_entries = n_entries; | ||
2563 | acl->acl_policy = acl_policy; | ||
2564 | |||
2565 | return acl; | ||
2566 | } | ||
2567 | |||
2568 | static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info) | ||
2569 | { | ||
2570 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
2571 | struct net_device *dev = info->user_ptr[1]; | ||
2572 | struct cfg80211_acl_data *acl; | ||
2573 | int err; | ||
2574 | |||
2575 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
2576 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
2577 | return -EOPNOTSUPP; | ||
2578 | |||
2579 | if (!dev->ieee80211_ptr->beacon_interval) | ||
2580 | return -EINVAL; | ||
2581 | |||
2582 | acl = parse_acl_data(&rdev->wiphy, info); | ||
2583 | if (IS_ERR(acl)) | ||
2584 | return PTR_ERR(acl); | ||
2585 | |||
2586 | err = rdev_set_mac_acl(rdev, dev, acl); | ||
2587 | |||
2588 | kfree(acl); | ||
2589 | |||
2590 | return err; | ||
2591 | } | ||
2592 | |||
2494 | static int nl80211_parse_beacon(struct genl_info *info, | 2593 | static int nl80211_parse_beacon(struct genl_info *info, |
2495 | struct cfg80211_beacon_data *bcn) | 2594 | struct cfg80211_beacon_data *bcn) |
2496 | { | 2595 | { |
@@ -2734,6 +2833,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2734 | if (err) | 2833 | if (err) |
2735 | return err; | 2834 | return err; |
2736 | 2835 | ||
2836 | if (info->attrs[NL80211_ATTR_ACL_POLICY]) { | ||
2837 | params.acl = parse_acl_data(&rdev->wiphy, info); | ||
2838 | if (IS_ERR(params.acl)) | ||
2839 | return PTR_ERR(params.acl); | ||
2840 | } | ||
2841 | |||
2737 | err = rdev_start_ap(rdev, dev, ¶ms); | 2842 | err = rdev_start_ap(rdev, dev, ¶ms); |
2738 | if (!err) { | 2843 | if (!err) { |
2739 | wdev->preset_chandef = params.chandef; | 2844 | wdev->preset_chandef = params.chandef; |
@@ -2742,6 +2847,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2742 | wdev->ssid_len = params.ssid_len; | 2847 | wdev->ssid_len = params.ssid_len; |
2743 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); | 2848 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); |
2744 | } | 2849 | } |
2850 | |||
2851 | kfree(params.acl); | ||
2852 | |||
2745 | return err; | 2853 | return err; |
2746 | } | 2854 | } |
2747 | 2855 | ||
@@ -7876,6 +7984,14 @@ static struct genl_ops nl80211_ops[] = { | |||
7876 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 7984 | .internal_flags = NL80211_FLAG_NEED_NETDEV | |
7877 | NL80211_FLAG_NEED_RTNL, | 7985 | NL80211_FLAG_NEED_RTNL, |
7878 | }, | 7986 | }, |
7987 | { | ||
7988 | .cmd = NL80211_CMD_SET_MAC_ACL, | ||
7989 | .doit = nl80211_set_mac_acl, | ||
7990 | .policy = nl80211_policy, | ||
7991 | .flags = GENL_ADMIN_PERM, | ||
7992 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
7993 | NL80211_FLAG_NEED_RTNL, | ||
7994 | }, | ||
7879 | }; | 7995 | }; |
7880 | 7996 | ||
7881 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 7997 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 6c0c8191f837..422d38291d66 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -875,4 +875,16 @@ static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev, | |||
875 | rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); | 875 | rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); |
876 | trace_rdev_return_void(&rdev->wiphy); | 876 | trace_rdev_return_void(&rdev->wiphy); |
877 | } | 877 | } |
878 | |||
879 | static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, | ||
880 | struct net_device *dev, | ||
881 | struct cfg80211_acl_data *params) | ||
882 | { | ||
883 | int ret; | ||
884 | |||
885 | trace_rdev_set_mac_acl(&rdev->wiphy, dev, params); | ||
886 | ret = rdev->ops->set_mac_acl(&rdev->wiphy, dev, params); | ||
887 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
888 | return ret; | ||
889 | } | ||
878 | #endif /* __CFG80211_RDEV_OPS */ | 890 | #endif /* __CFG80211_RDEV_OPS */ |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 2134576f426e..8bc553199686 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -1767,6 +1767,24 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_p2p_device, | |||
1767 | TP_ARGS(wiphy, wdev) | 1767 | TP_ARGS(wiphy, wdev) |
1768 | ); | 1768 | ); |
1769 | 1769 | ||
1770 | TRACE_EVENT(rdev_set_mac_acl, | ||
1771 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
1772 | struct cfg80211_acl_data *params), | ||
1773 | TP_ARGS(wiphy, netdev, params), | ||
1774 | TP_STRUCT__entry( | ||
1775 | WIPHY_ENTRY | ||
1776 | NETDEV_ENTRY | ||
1777 | __field(u32, acl_policy) | ||
1778 | ), | ||
1779 | TP_fast_assign( | ||
1780 | WIPHY_ASSIGN; | ||
1781 | WIPHY_ASSIGN; | ||
1782 | __entry->acl_policy = params->acl_policy; | ||
1783 | ), | ||
1784 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", acl policy: %d", | ||
1785 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->acl_policy) | ||
1786 | ); | ||
1787 | |||
1770 | /************************************************************* | 1788 | /************************************************************* |
1771 | * cfg80211 exported functions traces * | 1789 | * cfg80211 exported functions traces * |
1772 | *************************************************************/ | 1790 | *************************************************************/ |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 1c2795d52db0..d7873c7ae0ec 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -1212,7 +1212,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
1212 | case NL80211_IFTYPE_MESH_POINT: | 1212 | case NL80211_IFTYPE_MESH_POINT: |
1213 | case NL80211_IFTYPE_P2P_GO: | 1213 | case NL80211_IFTYPE_P2P_GO: |
1214 | case NL80211_IFTYPE_WDS: | 1214 | case NL80211_IFTYPE_WDS: |
1215 | radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR); | 1215 | radar_required = !!(chan && |
1216 | (chan->flags & IEEE80211_CHAN_RADAR)); | ||
1216 | break; | 1217 | break; |
1217 | case NL80211_IFTYPE_P2P_CLIENT: | 1218 | case NL80211_IFTYPE_P2P_CLIENT: |
1218 | case NL80211_IFTYPE_STATION: | 1219 | case NL80211_IFTYPE_STATION: |