diff options
Diffstat (limited to 'net')
47 files changed, 1849 insertions, 919 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 58f9762b339a..9d49ee6d7219 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c | |||
@@ -567,8 +567,6 @@ static void bt_seq_stop(struct seq_file *seq, void *v) | |||
567 | 567 | ||
568 | static int bt_seq_show(struct seq_file *seq, void *v) | 568 | static int bt_seq_show(struct seq_file *seq, void *v) |
569 | { | 569 | { |
570 | struct sock *sk; | ||
571 | struct bt_sock *bt; | ||
572 | struct bt_seq_state *s = seq->private; | 570 | struct bt_seq_state *s = seq->private; |
573 | struct bt_sock_list *l = s->l; | 571 | struct bt_sock_list *l = s->l; |
574 | bdaddr_t src_baswapped, dst_baswapped; | 572 | bdaddr_t src_baswapped, dst_baswapped; |
@@ -583,8 +581,8 @@ static int bt_seq_show(struct seq_file *seq, void *v) | |||
583 | 581 | ||
584 | seq_putc(seq, '\n'); | 582 | seq_putc(seq, '\n'); |
585 | } else { | 583 | } else { |
586 | sk = sk_entry(v); | 584 | struct sock *sk = sk_entry(v); |
587 | bt = bt_sk(sk); | 585 | struct bt_sock *bt = bt_sk(sk); |
588 | baswap(&src_baswapped, &bt->src); | 586 | baswap(&src_baswapped, &bt->src); |
589 | baswap(&dst_baswapped, &bt->dst); | 587 | baswap(&dst_baswapped, &bt->dst); |
590 | 588 | ||
@@ -624,7 +622,7 @@ static int bt_seq_open(struct inode *inode, struct file *file) | |||
624 | sk_list = PDE(inode)->data; | 622 | sk_list = PDE(inode)->data; |
625 | s = __seq_open_private(file, &bt_seq_ops, | 623 | s = __seq_open_private(file, &bt_seq_ops, |
626 | sizeof(struct bt_seq_state)); | 624 | sizeof(struct bt_seq_state)); |
627 | if (s == NULL) | 625 | if (!s) |
628 | return -ENOMEM; | 626 | return -ENOMEM; |
629 | 627 | ||
630 | s->l = sk_list; | 628 | s->l = sk_list; |
@@ -646,7 +644,7 @@ int bt_procfs_init(struct module* module, struct net *net, const char *name, | |||
646 | sk_list->fops.release = seq_release_private; | 644 | sk_list->fops.release = seq_release_private; |
647 | 645 | ||
648 | pde = proc_net_fops_create(net, name, 0, &sk_list->fops); | 646 | pde = proc_net_fops_create(net, name, 0, &sk_list->fops); |
649 | if (pde == NULL) | 647 | if (!pde) |
650 | return -ENOMEM; | 648 | return -ENOMEM; |
651 | 649 | ||
652 | pde->data = sk_list; | 650 | pde->data = sk_list; |
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 3c094e78dde9..b9196a44f759 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <net/bluetooth/a2mp.h> | 31 | #include <net/bluetooth/a2mp.h> |
32 | #include <net/bluetooth/smp.h> | 32 | #include <net/bluetooth/smp.h> |
33 | 33 | ||
34 | static void hci_le_connect(struct hci_conn *conn) | 34 | static void hci_le_create_connection(struct hci_conn *conn) |
35 | { | 35 | { |
36 | struct hci_dev *hdev = conn->hdev; | 36 | struct hci_dev *hdev = conn->hdev; |
37 | struct hci_cp_le_create_conn cp; | 37 | struct hci_cp_le_create_conn cp; |
@@ -55,12 +55,12 @@ static void hci_le_connect(struct hci_conn *conn) | |||
55 | hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); | 55 | hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); |
56 | } | 56 | } |
57 | 57 | ||
58 | static void hci_le_connect_cancel(struct hci_conn *conn) | 58 | static void hci_le_create_connection_cancel(struct hci_conn *conn) |
59 | { | 59 | { |
60 | hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL); | 60 | hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL); |
61 | } | 61 | } |
62 | 62 | ||
63 | void hci_acl_connect(struct hci_conn *conn) | 63 | static void hci_acl_create_connection(struct hci_conn *conn) |
64 | { | 64 | { |
65 | struct hci_dev *hdev = conn->hdev; | 65 | struct hci_dev *hdev = conn->hdev; |
66 | struct inquiry_entry *ie; | 66 | struct inquiry_entry *ie; |
@@ -104,7 +104,7 @@ void hci_acl_connect(struct hci_conn *conn) | |||
104 | hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp); | 104 | hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp); |
105 | } | 105 | } |
106 | 106 | ||
107 | static void hci_acl_connect_cancel(struct hci_conn *conn) | 107 | static void hci_acl_create_connection_cancel(struct hci_conn *conn) |
108 | { | 108 | { |
109 | struct hci_cp_create_conn_cancel cp; | 109 | struct hci_cp_create_conn_cancel cp; |
110 | 110 | ||
@@ -130,7 +130,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason) | |||
130 | hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp); | 130 | hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp); |
131 | } | 131 | } |
132 | 132 | ||
133 | void hci_add_sco(struct hci_conn *conn, __u16 handle) | 133 | static void hci_add_sco(struct hci_conn *conn, __u16 handle) |
134 | { | 134 | { |
135 | struct hci_dev *hdev = conn->hdev; | 135 | struct hci_dev *hdev = conn->hdev; |
136 | struct hci_cp_add_sco cp; | 136 | struct hci_cp_add_sco cp; |
@@ -246,9 +246,9 @@ static void hci_conn_timeout(struct work_struct *work) | |||
246 | case BT_CONNECT2: | 246 | case BT_CONNECT2: |
247 | if (conn->out) { | 247 | if (conn->out) { |
248 | if (conn->type == ACL_LINK) | 248 | if (conn->type == ACL_LINK) |
249 | hci_acl_connect_cancel(conn); | 249 | hci_acl_create_connection_cancel(conn); |
250 | else if (conn->type == LE_LINK) | 250 | else if (conn->type == LE_LINK) |
251 | hci_le_connect_cancel(conn); | 251 | hci_le_create_connection_cancel(conn); |
252 | } | 252 | } |
253 | break; | 253 | break; |
254 | case BT_CONFIG: | 254 | case BT_CONFIG: |
@@ -471,40 +471,37 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) | |||
471 | } | 471 | } |
472 | EXPORT_SYMBOL(hci_get_route); | 472 | EXPORT_SYMBOL(hci_get_route); |
473 | 473 | ||
474 | /* Create SCO, ACL or LE connection. | 474 | static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, |
475 | * Device _must_ be locked */ | 475 | u8 dst_type, u8 sec_level, u8 auth_type) |
476 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, | ||
477 | __u8 dst_type, __u8 sec_level, __u8 auth_type) | ||
478 | { | 476 | { |
479 | struct hci_conn *acl; | ||
480 | struct hci_conn *sco; | ||
481 | struct hci_conn *le; | 477 | struct hci_conn *le; |
482 | 478 | ||
483 | BT_DBG("%s dst %s", hdev->name, batostr(dst)); | 479 | le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); |
480 | if (!le) { | ||
481 | le = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); | ||
482 | if (le) | ||
483 | return ERR_PTR(-EBUSY); | ||
484 | 484 | ||
485 | if (type == LE_LINK) { | 485 | le = hci_conn_add(hdev, LE_LINK, dst); |
486 | le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); | 486 | if (!le) |
487 | if (!le) { | 487 | return ERR_PTR(-ENOMEM); |
488 | le = hci_conn_hash_lookup_state(hdev, LE_LINK, | ||
489 | BT_CONNECT); | ||
490 | if (le) | ||
491 | return ERR_PTR(-EBUSY); | ||
492 | 488 | ||
493 | le = hci_conn_add(hdev, LE_LINK, dst); | 489 | le->dst_type = bdaddr_to_le(dst_type); |
494 | if (!le) | 490 | hci_le_create_connection(le); |
495 | return ERR_PTR(-ENOMEM); | 491 | } |
496 | 492 | ||
497 | le->dst_type = bdaddr_to_le(dst_type); | 493 | le->pending_sec_level = sec_level; |
498 | hci_le_connect(le); | 494 | le->auth_type = auth_type; |
499 | } | ||
500 | 495 | ||
501 | le->pending_sec_level = sec_level; | 496 | hci_conn_hold(le); |
502 | le->auth_type = auth_type; | ||
503 | 497 | ||
504 | hci_conn_hold(le); | 498 | return le; |
499 | } | ||
505 | 500 | ||
506 | return le; | 501 | static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, |
507 | } | 502 | u8 sec_level, u8 auth_type) |
503 | { | ||
504 | struct hci_conn *acl; | ||
508 | 505 | ||
509 | acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); | 506 | acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); |
510 | if (!acl) { | 507 | if (!acl) { |
@@ -519,10 +516,20 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, | |||
519 | acl->sec_level = BT_SECURITY_LOW; | 516 | acl->sec_level = BT_SECURITY_LOW; |
520 | acl->pending_sec_level = sec_level; | 517 | acl->pending_sec_level = sec_level; |
521 | acl->auth_type = auth_type; | 518 | acl->auth_type = auth_type; |
522 | hci_acl_connect(acl); | 519 | hci_acl_create_connection(acl); |
523 | } | 520 | } |
524 | 521 | ||
525 | if (type == ACL_LINK) | 522 | return acl; |
523 | } | ||
524 | |||
525 | static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, | ||
526 | bdaddr_t *dst, u8 sec_level, u8 auth_type) | ||
527 | { | ||
528 | struct hci_conn *acl; | ||
529 | struct hci_conn *sco; | ||
530 | |||
531 | acl = hci_connect_acl(hdev, dst, sec_level, auth_type); | ||
532 | if (IS_ERR(acl)) | ||
526 | return acl; | 533 | return acl; |
527 | 534 | ||
528 | sco = hci_conn_hash_lookup_ba(hdev, type, dst); | 535 | sco = hci_conn_hash_lookup_ba(hdev, type, dst); |
@@ -556,6 +563,25 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, | |||
556 | return sco; | 563 | return sco; |
557 | } | 564 | } |
558 | 565 | ||
566 | /* Create SCO, ACL or LE connection. */ | ||
567 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, | ||
568 | __u8 dst_type, __u8 sec_level, __u8 auth_type) | ||
569 | { | ||
570 | BT_DBG("%s dst %s type 0x%x", hdev->name, batostr(dst), type); | ||
571 | |||
572 | switch (type) { | ||
573 | case LE_LINK: | ||
574 | return hci_connect_le(hdev, dst, dst_type, sec_level, auth_type); | ||
575 | case ACL_LINK: | ||
576 | return hci_connect_acl(hdev, dst, sec_level, auth_type); | ||
577 | case SCO_LINK: | ||
578 | case ESCO_LINK: | ||
579 | return hci_connect_sco(hdev, type, dst, sec_level, auth_type); | ||
580 | } | ||
581 | |||
582 | return ERR_PTR(-EINVAL); | ||
583 | } | ||
584 | |||
559 | /* Check link security requirement */ | 585 | /* Check link security requirement */ |
560 | int hci_conn_check_link_mode(struct hci_conn *conn) | 586 | int hci_conn_check_link_mode(struct hci_conn *conn) |
561 | { | 587 | { |
@@ -775,7 +801,7 @@ void hci_conn_check_pending(struct hci_dev *hdev) | |||
775 | 801 | ||
776 | conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2); | 802 | conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2); |
777 | if (conn) | 803 | if (conn) |
778 | hci_acl_connect(conn); | 804 | hci_acl_create_connection(conn); |
779 | 805 | ||
780 | hci_dev_unlock(hdev); | 806 | hci_dev_unlock(hdev); |
781 | } | 807 | } |
@@ -913,7 +939,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) | |||
913 | return chan; | 939 | return chan; |
914 | } | 940 | } |
915 | 941 | ||
916 | int hci_chan_del(struct hci_chan *chan) | 942 | void hci_chan_del(struct hci_chan *chan) |
917 | { | 943 | { |
918 | struct hci_conn *conn = chan->conn; | 944 | struct hci_conn *conn = chan->conn; |
919 | struct hci_dev *hdev = conn->hdev; | 945 | struct hci_dev *hdev = conn->hdev; |
@@ -926,8 +952,6 @@ int hci_chan_del(struct hci_chan *chan) | |||
926 | 952 | ||
927 | skb_queue_purge(&chan->data_q); | 953 | skb_queue_purge(&chan->data_q); |
928 | kfree(chan); | 954 | kfree(chan); |
929 | |||
930 | return 0; | ||
931 | } | 955 | } |
932 | 956 | ||
933 | void hci_chan_list_flush(struct hci_conn *conn) | 957 | void hci_chan_list_flush(struct hci_conn *conn) |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fa974a19d365..e4070517ff3b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -231,6 +231,9 @@ static void amp_init(struct hci_dev *hdev) | |||
231 | 231 | ||
232 | /* Read Local AMP Info */ | 232 | /* Read Local AMP Info */ |
233 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); | 233 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); |
234 | |||
235 | /* Read Data Blk size */ | ||
236 | hci_send_cmd(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL); | ||
234 | } | 237 | } |
235 | 238 | ||
236 | static void hci_init_req(struct hci_dev *hdev, unsigned long opt) | 239 | static void hci_init_req(struct hci_dev *hdev, unsigned long opt) |
@@ -268,7 +271,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) | |||
268 | BT_ERR("Unknown device type %d", hdev->dev_type); | 271 | BT_ERR("Unknown device type %d", hdev->dev_type); |
269 | break; | 272 | break; |
270 | } | 273 | } |
271 | |||
272 | } | 274 | } |
273 | 275 | ||
274 | static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt) | 276 | static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt) |
@@ -1652,6 +1654,7 @@ struct hci_dev *hci_alloc_dev(void) | |||
1652 | INIT_LIST_HEAD(&hdev->link_keys); | 1654 | INIT_LIST_HEAD(&hdev->link_keys); |
1653 | INIT_LIST_HEAD(&hdev->long_term_keys); | 1655 | INIT_LIST_HEAD(&hdev->long_term_keys); |
1654 | INIT_LIST_HEAD(&hdev->remote_oob_data); | 1656 | INIT_LIST_HEAD(&hdev->remote_oob_data); |
1657 | INIT_LIST_HEAD(&hdev->conn_hash.list); | ||
1655 | 1658 | ||
1656 | INIT_WORK(&hdev->rx_work, hci_rx_work); | 1659 | INIT_WORK(&hdev->rx_work, hci_rx_work); |
1657 | INIT_WORK(&hdev->cmd_work, hci_cmd_work); | 1660 | INIT_WORK(&hdev->cmd_work, hci_cmd_work); |
@@ -1674,7 +1677,6 @@ struct hci_dev *hci_alloc_dev(void) | |||
1674 | 1677 | ||
1675 | hci_init_sysfs(hdev); | 1678 | hci_init_sysfs(hdev); |
1676 | discovery_init(hdev); | 1679 | discovery_init(hdev); |
1677 | hci_conn_hash_init(hdev); | ||
1678 | 1680 | ||
1679 | return hdev; | 1681 | return hdev; |
1680 | } | 1682 | } |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 4fd2cf3bcd05..2022b43c7353 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -29,6 +29,7 @@ | |||
29 | 29 | ||
30 | #include <net/bluetooth/bluetooth.h> | 30 | #include <net/bluetooth/bluetooth.h> |
31 | #include <net/bluetooth/hci_core.h> | 31 | #include <net/bluetooth/hci_core.h> |
32 | #include <net/bluetooth/mgmt.h> | ||
32 | 33 | ||
33 | /* Handle HCI Event packets */ | 34 | /* Handle HCI Event packets */ |
34 | 35 | ||
@@ -303,7 +304,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) | |||
303 | 304 | ||
304 | hci_dev_lock(hdev); | 305 | hci_dev_lock(hdev); |
305 | 306 | ||
306 | if (status != 0) { | 307 | if (status) { |
307 | mgmt_write_scan_failed(hdev, param, status); | 308 | mgmt_write_scan_failed(hdev, param, status); |
308 | hdev->discov_timeout = 0; | 309 | hdev->discov_timeout = 0; |
309 | goto done; | 310 | goto done; |
@@ -925,7 +926,7 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb) | |||
925 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) | 926 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) |
926 | mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status); | 927 | mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status); |
927 | 928 | ||
928 | if (rp->status != 0) | 929 | if (rp->status) |
929 | goto unlock; | 930 | goto unlock; |
930 | 931 | ||
931 | cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY); | 932 | cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY); |
@@ -1891,6 +1892,22 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
1891 | } | 1892 | } |
1892 | } | 1893 | } |
1893 | 1894 | ||
1895 | static u8 hci_to_mgmt_reason(u8 err) | ||
1896 | { | ||
1897 | switch (err) { | ||
1898 | case HCI_ERROR_CONNECTION_TIMEOUT: | ||
1899 | return MGMT_DEV_DISCONN_TIMEOUT; | ||
1900 | case HCI_ERROR_REMOTE_USER_TERM: | ||
1901 | case HCI_ERROR_REMOTE_LOW_RESOURCES: | ||
1902 | case HCI_ERROR_REMOTE_POWER_OFF: | ||
1903 | return MGMT_DEV_DISCONN_REMOTE; | ||
1904 | case HCI_ERROR_LOCAL_HOST_TERM: | ||
1905 | return MGMT_DEV_DISCONN_LOCAL_HOST; | ||
1906 | default: | ||
1907 | return MGMT_DEV_DISCONN_UNKNOWN; | ||
1908 | } | ||
1909 | } | ||
1910 | |||
1894 | static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1911 | static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
1895 | { | 1912 | { |
1896 | struct hci_ev_disconn_complete *ev = (void *) skb->data; | 1913 | struct hci_ev_disconn_complete *ev = (void *) skb->data; |
@@ -1909,12 +1926,15 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
1909 | 1926 | ||
1910 | if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && | 1927 | if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && |
1911 | (conn->type == ACL_LINK || conn->type == LE_LINK)) { | 1928 | (conn->type == ACL_LINK || conn->type == LE_LINK)) { |
1912 | if (ev->status != 0) | 1929 | if (ev->status) { |
1913 | mgmt_disconnect_failed(hdev, &conn->dst, conn->type, | 1930 | mgmt_disconnect_failed(hdev, &conn->dst, conn->type, |
1914 | conn->dst_type, ev->status); | 1931 | conn->dst_type, ev->status); |
1915 | else | 1932 | } else { |
1933 | u8 reason = hci_to_mgmt_reason(ev->reason); | ||
1934 | |||
1916 | mgmt_device_disconnected(hdev, &conn->dst, conn->type, | 1935 | mgmt_device_disconnected(hdev, &conn->dst, conn->type, |
1917 | conn->dst_type); | 1936 | conn->dst_type, reason); |
1937 | } | ||
1918 | } | 1938 | } |
1919 | 1939 | ||
1920 | if (ev->status == 0) { | 1940 | if (ev->status == 0) { |
@@ -3259,6 +3279,65 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev, | |||
3259 | mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0); | 3279 | mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0); |
3260 | } | 3280 | } |
3261 | 3281 | ||
3282 | static void hci_user_passkey_notify_evt(struct hci_dev *hdev, | ||
3283 | struct sk_buff *skb) | ||
3284 | { | ||
3285 | struct hci_ev_user_passkey_notify *ev = (void *) skb->data; | ||
3286 | struct hci_conn *conn; | ||
3287 | |||
3288 | BT_DBG("%s", hdev->name); | ||
3289 | |||
3290 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); | ||
3291 | if (!conn) | ||
3292 | return; | ||
3293 | |||
3294 | conn->passkey_notify = __le32_to_cpu(ev->passkey); | ||
3295 | conn->passkey_entered = 0; | ||
3296 | |||
3297 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) | ||
3298 | mgmt_user_passkey_notify(hdev, &conn->dst, conn->type, | ||
3299 | conn->dst_type, conn->passkey_notify, | ||
3300 | conn->passkey_entered); | ||
3301 | } | ||
3302 | |||
3303 | static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
3304 | { | ||
3305 | struct hci_ev_keypress_notify *ev = (void *) skb->data; | ||
3306 | struct hci_conn *conn; | ||
3307 | |||
3308 | BT_DBG("%s", hdev->name); | ||
3309 | |||
3310 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); | ||
3311 | if (!conn) | ||
3312 | return; | ||
3313 | |||
3314 | switch (ev->type) { | ||
3315 | case HCI_KEYPRESS_STARTED: | ||
3316 | conn->passkey_entered = 0; | ||
3317 | return; | ||
3318 | |||
3319 | case HCI_KEYPRESS_ENTERED: | ||
3320 | conn->passkey_entered++; | ||
3321 | break; | ||
3322 | |||
3323 | case HCI_KEYPRESS_ERASED: | ||
3324 | conn->passkey_entered--; | ||
3325 | break; | ||
3326 | |||
3327 | case HCI_KEYPRESS_CLEARED: | ||
3328 | conn->passkey_entered = 0; | ||
3329 | break; | ||
3330 | |||
3331 | case HCI_KEYPRESS_COMPLETED: | ||
3332 | return; | ||
3333 | } | ||
3334 | |||
3335 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) | ||
3336 | mgmt_user_passkey_notify(hdev, &conn->dst, conn->type, | ||
3337 | conn->dst_type, conn->passkey_notify, | ||
3338 | conn->passkey_entered); | ||
3339 | } | ||
3340 | |||
3262 | static void hci_simple_pair_complete_evt(struct hci_dev *hdev, | 3341 | static void hci_simple_pair_complete_evt(struct hci_dev *hdev, |
3263 | struct sk_buff *skb) | 3342 | struct sk_buff *skb) |
3264 | { | 3343 | { |
@@ -3278,7 +3357,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev, | |||
3278 | * initiated the authentication. A traditional auth_complete | 3357 | * initiated the authentication. A traditional auth_complete |
3279 | * event gets always produced as initiator and is also mapped to | 3358 | * event gets always produced as initiator and is also mapped to |
3280 | * the mgmt_auth_failed event */ | 3359 | * the mgmt_auth_failed event */ |
3281 | if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0) | 3360 | if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status) |
3282 | mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, | 3361 | mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, |
3283 | ev->status); | 3362 | ev->status); |
3284 | 3363 | ||
@@ -3623,6 +3702,14 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
3623 | hci_user_passkey_request_evt(hdev, skb); | 3702 | hci_user_passkey_request_evt(hdev, skb); |
3624 | break; | 3703 | break; |
3625 | 3704 | ||
3705 | case HCI_EV_USER_PASSKEY_NOTIFY: | ||
3706 | hci_user_passkey_notify_evt(hdev, skb); | ||
3707 | break; | ||
3708 | |||
3709 | case HCI_EV_KEYPRESS_NOTIFY: | ||
3710 | hci_keypress_notify_evt(hdev, skb); | ||
3711 | break; | ||
3712 | |||
3626 | case HCI_EV_SIMPLE_PAIR_COMPLETE: | 3713 | case HCI_EV_SIMPLE_PAIR_COMPLETE: |
3627 | hci_simple_pair_complete_evt(hdev, skb); | 3714 | hci_simple_pair_complete_evt(hdev, skb); |
3628 | break; | 3715 | break; |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e0abaf3cb6a5..7a59e929febc 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -406,7 +406,7 @@ struct l2cap_chan *l2cap_chan_create(void) | |||
406 | 406 | ||
407 | chan->state = BT_OPEN; | 407 | chan->state = BT_OPEN; |
408 | 408 | ||
409 | atomic_set(&chan->refcnt, 1); | 409 | kref_init(&chan->kref); |
410 | 410 | ||
411 | /* This flag is cleared in l2cap_chan_ready() */ | 411 | /* This flag is cleared in l2cap_chan_ready() */ |
412 | set_bit(CONF_NOT_COMPLETE, &chan->conf_state); | 412 | set_bit(CONF_NOT_COMPLETE, &chan->conf_state); |
@@ -416,8 +416,10 @@ struct l2cap_chan *l2cap_chan_create(void) | |||
416 | return chan; | 416 | return chan; |
417 | } | 417 | } |
418 | 418 | ||
419 | static void l2cap_chan_destroy(struct l2cap_chan *chan) | 419 | static void l2cap_chan_destroy(struct kref *kref) |
420 | { | 420 | { |
421 | struct l2cap_chan *chan = container_of(kref, struct l2cap_chan, kref); | ||
422 | |||
421 | BT_DBG("chan %p", chan); | 423 | BT_DBG("chan %p", chan); |
422 | 424 | ||
423 | write_lock(&chan_list_lock); | 425 | write_lock(&chan_list_lock); |
@@ -429,17 +431,16 @@ static void l2cap_chan_destroy(struct l2cap_chan *chan) | |||
429 | 431 | ||
430 | void l2cap_chan_hold(struct l2cap_chan *c) | 432 | void l2cap_chan_hold(struct l2cap_chan *c) |
431 | { | 433 | { |
432 | BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt)); | 434 | BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->kref.refcount)); |
433 | 435 | ||
434 | atomic_inc(&c->refcnt); | 436 | kref_get(&c->kref); |
435 | } | 437 | } |
436 | 438 | ||
437 | void l2cap_chan_put(struct l2cap_chan *c) | 439 | void l2cap_chan_put(struct l2cap_chan *c) |
438 | { | 440 | { |
439 | BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt)); | 441 | BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->kref.refcount)); |
440 | 442 | ||
441 | if (atomic_dec_and_test(&c->refcnt)) | 443 | kref_put(&c->kref, l2cap_chan_destroy); |
442 | l2cap_chan_destroy(c); | ||
443 | } | 444 | } |
444 | 445 | ||
445 | void l2cap_chan_set_defaults(struct l2cap_chan *chan) | 446 | void l2cap_chan_set_defaults(struct l2cap_chan *chan) |
@@ -1448,7 +1449,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, | |||
1448 | int err; | 1449 | int err; |
1449 | 1450 | ||
1450 | BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst), | 1451 | BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst), |
1451 | dst_type, __le16_to_cpu(chan->psm)); | 1452 | dst_type, __le16_to_cpu(psm)); |
1452 | 1453 | ||
1453 | hdev = hci_get_route(dst, src); | 1454 | hdev = hci_get_route(dst, src); |
1454 | if (!hdev) | 1455 | if (!hdev) |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a3329cbd3e4d..8934343be0ea 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 1 | 38 | #define MGMT_REVISION 2 |
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, |
@@ -99,6 +99,7 @@ static const u16 mgmt_events[] = { | |||
99 | MGMT_EV_DEVICE_BLOCKED, | 99 | MGMT_EV_DEVICE_BLOCKED, |
100 | MGMT_EV_DEVICE_UNBLOCKED, | 100 | MGMT_EV_DEVICE_UNBLOCKED, |
101 | MGMT_EV_DEVICE_UNPAIRED, | 101 | MGMT_EV_DEVICE_UNPAIRED, |
102 | MGMT_EV_PASSKEY_NOTIFY, | ||
102 | }; | 103 | }; |
103 | 104 | ||
104 | /* | 105 | /* |
@@ -3077,16 +3078,17 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data) | |||
3077 | } | 3078 | } |
3078 | 3079 | ||
3079 | int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, | 3080 | int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, |
3080 | u8 link_type, u8 addr_type) | 3081 | u8 link_type, u8 addr_type, u8 reason) |
3081 | { | 3082 | { |
3082 | struct mgmt_addr_info ev; | 3083 | struct mgmt_ev_device_disconnected ev; |
3083 | struct sock *sk = NULL; | 3084 | struct sock *sk = NULL; |
3084 | int err; | 3085 | int err; |
3085 | 3086 | ||
3086 | mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk); | 3087 | mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk); |
3087 | 3088 | ||
3088 | bacpy(&ev.bdaddr, bdaddr); | 3089 | bacpy(&ev.addr.bdaddr, bdaddr); |
3089 | ev.type = link_to_bdaddr(link_type, addr_type); | 3090 | ev.addr.type = link_to_bdaddr(link_type, addr_type); |
3091 | ev.reason = reason; | ||
3090 | 3092 | ||
3091 | err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), | 3093 | err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), |
3092 | sk); | 3094 | sk); |
@@ -3275,6 +3277,22 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
3275 | MGMT_OP_USER_PASSKEY_NEG_REPLY); | 3277 | MGMT_OP_USER_PASSKEY_NEG_REPLY); |
3276 | } | 3278 | } |
3277 | 3279 | ||
3280 | int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr, | ||
3281 | u8 link_type, u8 addr_type, u32 passkey, | ||
3282 | u8 entered) | ||
3283 | { | ||
3284 | struct mgmt_ev_passkey_notify ev; | ||
3285 | |||
3286 | BT_DBG("%s", hdev->name); | ||
3287 | |||
3288 | bacpy(&ev.addr.bdaddr, bdaddr); | ||
3289 | ev.addr.type = link_to_bdaddr(link_type, addr_type); | ||
3290 | ev.passkey = __cpu_to_le32(passkey); | ||
3291 | ev.entered = entered; | ||
3292 | |||
3293 | return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL); | ||
3294 | } | ||
3295 | |||
3278 | int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | 3296 | int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, |
3279 | u8 addr_type, u8 status) | 3297 | u8 addr_type, u8 status) |
3280 | { | 3298 | { |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index d0deb3edae21..3195a6307f50 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -869,7 +869,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
869 | 869 | ||
870 | } else { | 870 | } else { |
871 | ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, | 871 | ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, |
872 | true); | 872 | false); |
873 | } | 873 | } |
874 | 874 | ||
875 | out: | 875 | out: |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 03fe6d1cff42..05f3a313db88 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -20,7 +20,8 @@ | |||
20 | #include "rate.h" | 20 | #include "rate.h" |
21 | #include "mesh.h" | 21 | #include "mesh.h" |
22 | 22 | ||
23 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, char *name, | 23 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, |
24 | const char *name, | ||
24 | enum nl80211_iftype type, | 25 | enum nl80211_iftype type, |
25 | u32 *flags, | 26 | u32 *flags, |
26 | struct vif_params *params) | 27 | struct vif_params *params) |
@@ -170,6 +171,38 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
170 | } | 171 | } |
171 | } | 172 | } |
172 | 173 | ||
174 | switch (sdata->vif.type) { | ||
175 | case NL80211_IFTYPE_STATION: | ||
176 | if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED) | ||
177 | key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; | ||
178 | break; | ||
179 | case NL80211_IFTYPE_AP: | ||
180 | case NL80211_IFTYPE_AP_VLAN: | ||
181 | /* Keys without a station are used for TX only */ | ||
182 | if (key->sta && test_sta_flag(key->sta, WLAN_STA_MFP)) | ||
183 | key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; | ||
184 | break; | ||
185 | case NL80211_IFTYPE_ADHOC: | ||
186 | /* no MFP (yet) */ | ||
187 | break; | ||
188 | case NL80211_IFTYPE_MESH_POINT: | ||
189 | #ifdef CONFIG_MAC80211_MESH | ||
190 | if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE) | ||
191 | key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; | ||
192 | break; | ||
193 | #endif | ||
194 | case NL80211_IFTYPE_WDS: | ||
195 | case NL80211_IFTYPE_MONITOR: | ||
196 | case NL80211_IFTYPE_P2P_DEVICE: | ||
197 | case NL80211_IFTYPE_UNSPECIFIED: | ||
198 | case NUM_NL80211_IFTYPES: | ||
199 | case NL80211_IFTYPE_P2P_CLIENT: | ||
200 | case NL80211_IFTYPE_P2P_GO: | ||
201 | /* shouldn't happen */ | ||
202 | WARN_ON_ONCE(1); | ||
203 | break; | ||
204 | } | ||
205 | |||
173 | err = ieee80211_key_link(key, sdata, sta); | 206 | err = ieee80211_key_link(key, sdata, sta); |
174 | if (err) | 207 | if (err) |
175 | ieee80211_key_free(sdata->local, key); | 208 | ieee80211_key_free(sdata->local, key); |
@@ -2038,9 +2071,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | |||
2038 | */ | 2071 | */ |
2039 | if (!sdata->u.mgd.associated || | 2072 | if (!sdata->u.mgd.associated || |
2040 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { | 2073 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { |
2041 | mutex_lock(&sdata->local->iflist_mtx); | ||
2042 | ieee80211_recalc_smps(sdata->local); | 2074 | ieee80211_recalc_smps(sdata->local); |
2043 | mutex_unlock(&sdata->local->iflist_mtx); | ||
2044 | return 0; | 2075 | return 0; |
2045 | } | 2076 | } |
2046 | 2077 | ||
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f0f87e5a1d35..0bfc914ddd15 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -68,16 +68,14 @@ ieee80211_get_channel_mode(struct ieee80211_local *local, | |||
68 | return mode; | 68 | return mode; |
69 | } | 69 | } |
70 | 70 | ||
71 | bool ieee80211_set_channel_type(struct ieee80211_local *local, | 71 | static enum nl80211_channel_type |
72 | struct ieee80211_sub_if_data *sdata, | 72 | ieee80211_get_superchan(struct ieee80211_local *local, |
73 | enum nl80211_channel_type chantype) | 73 | struct ieee80211_sub_if_data *sdata) |
74 | { | 74 | { |
75 | struct ieee80211_sub_if_data *tmp; | ||
76 | enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT; | 75 | enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT; |
77 | bool result; | 76 | struct ieee80211_sub_if_data *tmp; |
78 | 77 | ||
79 | mutex_lock(&local->iflist_mtx); | 78 | mutex_lock(&local->iflist_mtx); |
80 | |||
81 | list_for_each_entry(tmp, &local->interfaces, list) { | 79 | list_for_each_entry(tmp, &local->interfaces, list) { |
82 | if (tmp == sdata) | 80 | if (tmp == sdata) |
83 | continue; | 81 | continue; |
@@ -103,39 +101,70 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local, | |||
103 | break; | 101 | break; |
104 | } | 102 | } |
105 | } | 103 | } |
104 | mutex_unlock(&local->iflist_mtx); | ||
106 | 105 | ||
107 | switch (superchan) { | 106 | return superchan; |
107 | } | ||
108 | |||
109 | static bool | ||
110 | ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, | ||
111 | enum nl80211_channel_type chantype2, | ||
112 | enum nl80211_channel_type *compat) | ||
113 | { | ||
114 | /* | ||
115 | * start out with chantype1 being the result, | ||
116 | * overwriting later if needed | ||
117 | */ | ||
118 | if (compat) | ||
119 | *compat = chantype1; | ||
120 | |||
121 | switch (chantype1) { | ||
108 | case NL80211_CHAN_NO_HT: | 122 | case NL80211_CHAN_NO_HT: |
123 | if (compat) | ||
124 | *compat = chantype2; | ||
125 | break; | ||
109 | case NL80211_CHAN_HT20: | 126 | case NL80211_CHAN_HT20: |
110 | /* | 127 | /* |
111 | * allow any change that doesn't go to no-HT | 128 | * allow any change that doesn't go to no-HT |
112 | * (if it already is no-HT no change is needed) | 129 | * (if it already is no-HT no change is needed) |
113 | */ | 130 | */ |
114 | if (chantype == NL80211_CHAN_NO_HT) | 131 | if (chantype2 == NL80211_CHAN_NO_HT) |
115 | break; | 132 | break; |
116 | superchan = chantype; | 133 | if (compat) |
134 | *compat = chantype2; | ||
117 | break; | 135 | break; |
118 | case NL80211_CHAN_HT40PLUS: | 136 | case NL80211_CHAN_HT40PLUS: |
119 | case NL80211_CHAN_HT40MINUS: | 137 | case NL80211_CHAN_HT40MINUS: |
120 | /* allow smaller bandwidth and same */ | 138 | /* allow smaller bandwidth and same */ |
121 | if (chantype == NL80211_CHAN_NO_HT) | 139 | if (chantype2 == NL80211_CHAN_NO_HT) |
122 | break; | 140 | break; |
123 | if (chantype == NL80211_CHAN_HT20) | 141 | if (chantype2 == NL80211_CHAN_HT20) |
124 | break; | 142 | break; |
125 | if (superchan == chantype) | 143 | if (chantype2 == chantype1) |
126 | break; | 144 | break; |
127 | result = false; | 145 | return false; |
128 | goto out; | ||
129 | } | 146 | } |
130 | 147 | ||
131 | local->_oper_channel_type = superchan; | 148 | return true; |
149 | } | ||
150 | |||
151 | bool ieee80211_set_channel_type(struct ieee80211_local *local, | ||
152 | struct ieee80211_sub_if_data *sdata, | ||
153 | enum nl80211_channel_type chantype) | ||
154 | { | ||
155 | enum nl80211_channel_type superchan; | ||
156 | enum nl80211_channel_type compatchan; | ||
157 | |||
158 | superchan = ieee80211_get_superchan(local, sdata); | ||
159 | if (!ieee80211_channel_types_are_compatible(superchan, chantype, | ||
160 | &compatchan)) | ||
161 | return false; | ||
162 | |||
163 | local->_oper_channel_type = compatchan; | ||
132 | 164 | ||
133 | if (sdata) | 165 | if (sdata) |
134 | sdata->vif.bss_conf.channel_type = chantype; | 166 | sdata->vif.bss_conf.channel_type = chantype; |
135 | 167 | ||
136 | result = true; | 168 | return true; |
137 | out: | ||
138 | mutex_unlock(&local->iflist_mtx); | ||
139 | 169 | ||
140 | return result; | ||
141 | } | 170 | } |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 97173f8144d4..466f4b45dd94 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -70,6 +70,7 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x", | |||
70 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", | 70 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", |
71 | local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); | 71 | local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); |
72 | 72 | ||
73 | #ifdef CONFIG_PM | ||
73 | static ssize_t reset_write(struct file *file, const char __user *user_buf, | 74 | static ssize_t reset_write(struct file *file, const char __user *user_buf, |
74 | size_t count, loff_t *ppos) | 75 | size_t count, loff_t *ppos) |
75 | { | 76 | { |
@@ -88,6 +89,7 @@ static const struct file_operations reset_ops = { | |||
88 | .open = simple_open, | 89 | .open = simple_open, |
89 | .llseek = noop_llseek, | 90 | .llseek = noop_llseek, |
90 | }; | 91 | }; |
92 | #endif | ||
91 | 93 | ||
92 | static ssize_t hwflags_read(struct file *file, char __user *user_buf, | 94 | static ssize_t hwflags_read(struct file *file, char __user *user_buf, |
93 | size_t count, loff_t *ppos) | 95 | size_t count, loff_t *ppos) |
@@ -245,7 +247,9 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
245 | DEBUGFS_ADD(total_ps_buffered); | 247 | DEBUGFS_ADD(total_ps_buffered); |
246 | DEBUGFS_ADD(wep_iv); | 248 | DEBUGFS_ADD(wep_iv); |
247 | DEBUGFS_ADD(queues); | 249 | DEBUGFS_ADD(queues); |
250 | #ifdef CONFIG_PM | ||
248 | DEBUGFS_ADD_MODE(reset, 0200); | 251 | DEBUGFS_ADD_MODE(reset, 0200); |
252 | #endif | ||
249 | DEBUGFS_ADD(hwflags); | 253 | DEBUGFS_ADD(hwflags); |
250 | DEBUGFS_ADD(user_power); | 254 | DEBUGFS_ADD(user_power); |
251 | DEBUGFS_ADD(power); | 255 | DEBUGFS_ADD(power); |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index a9d93285dba7..5f3620f0bc0a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -278,7 +278,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, | |||
278 | if (auth && !sdata->u.ibss.auth_frame_registrations) { | 278 | if (auth && !sdata->u.ibss.auth_frame_registrations) { |
279 | ibss_dbg(sdata, | 279 | ibss_dbg(sdata, |
280 | "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", | 280 | "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", |
281 | sdata->vif.addr, sdata->u.ibss.bssid, addr); | 281 | sdata->vif.addr, addr, sdata->u.ibss.bssid); |
282 | ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0, | 282 | ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0, |
283 | addr, sdata->u.ibss.bssid, NULL, 0, 0); | 283 | addr, sdata->u.ibss.bssid, NULL, 0, 0); |
284 | } | 284 | } |
@@ -332,11 +332,27 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
332 | return ieee80211_ibss_finish_sta(sta, auth); | 332 | return ieee80211_ibss_finish_sta(sta, auth); |
333 | } | 333 | } |
334 | 334 | ||
335 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, | ||
336 | struct ieee80211_mgmt *mgmt, | ||
337 | size_t len) | ||
338 | { | ||
339 | u16 reason = le16_to_cpu(mgmt->u.deauth.reason_code); | ||
340 | |||
341 | if (len < IEEE80211_DEAUTH_FRAME_LEN) | ||
342 | return; | ||
343 | |||
344 | ibss_dbg(sdata, "RX DeAuth SA=%pM DA=%pM BSSID=%pM (reason: %d)\n", | ||
345 | mgmt->sa, mgmt->da, mgmt->bssid, reason); | ||
346 | sta_info_destroy_addr(sdata, mgmt->sa); | ||
347 | } | ||
348 | |||
335 | static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | 349 | static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, |
336 | struct ieee80211_mgmt *mgmt, | 350 | struct ieee80211_mgmt *mgmt, |
337 | size_t len) | 351 | size_t len) |
338 | { | 352 | { |
339 | u16 auth_alg, auth_transaction; | 353 | u16 auth_alg, auth_transaction; |
354 | struct sta_info *sta; | ||
355 | u8 deauth_frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | ||
340 | 356 | ||
341 | lockdep_assert_held(&sdata->u.ibss.mtx); | 357 | lockdep_assert_held(&sdata->u.ibss.mtx); |
342 | 358 | ||
@@ -352,10 +368,22 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
352 | "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", | 368 | "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", |
353 | mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); | 369 | mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); |
354 | sta_info_destroy_addr(sdata, mgmt->sa); | 370 | sta_info_destroy_addr(sdata, mgmt->sa); |
355 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); | 371 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); |
356 | rcu_read_unlock(); | 372 | rcu_read_unlock(); |
357 | 373 | ||
358 | /* | 374 | /* |
375 | * if we have any problem in allocating the new station, we reply with a | ||
376 | * DEAUTH frame to tell the other end that we had a problem | ||
377 | */ | ||
378 | if (!sta) { | ||
379 | ieee80211_send_deauth_disassoc(sdata, sdata->u.ibss.bssid, | ||
380 | IEEE80211_STYPE_DEAUTH, | ||
381 | WLAN_REASON_UNSPECIFIED, true, | ||
382 | deauth_frame_buf); | ||
383 | return; | ||
384 | } | ||
385 | |||
386 | /* | ||
359 | * IEEE 802.11 standard does not require authentication in IBSS | 387 | * IEEE 802.11 standard does not require authentication in IBSS |
360 | * networks and most implementations do not seem to use it. | 388 | * networks and most implementations do not seem to use it. |
361 | * However, try to reply to authentication attempts if someone | 389 | * However, try to reply to authentication attempts if someone |
@@ -902,6 +930,9 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
902 | case IEEE80211_STYPE_AUTH: | 930 | case IEEE80211_STYPE_AUTH: |
903 | ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len); | 931 | ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len); |
904 | break; | 932 | break; |
933 | case IEEE80211_STYPE_DEAUTH: | ||
934 | ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len); | ||
935 | break; | ||
905 | } | 936 | } |
906 | 937 | ||
907 | mgmt_out: | 938 | mgmt_out: |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 204bfedba306..8c804550465b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -68,6 +68,8 @@ struct ieee80211_local; | |||
68 | #define IEEE80211_DEFAULT_MAX_SP_LEN \ | 68 | #define IEEE80211_DEFAULT_MAX_SP_LEN \ |
69 | IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL | 69 | IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL |
70 | 70 | ||
71 | #define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */) | ||
72 | |||
71 | struct ieee80211_fragment_entry { | 73 | struct ieee80211_fragment_entry { |
72 | unsigned long first_frag_time; | 74 | unsigned long first_frag_time; |
73 | unsigned int seq; | 75 | unsigned int seq; |
@@ -411,6 +413,7 @@ struct ieee80211_if_managed { | |||
411 | struct work_struct monitor_work; | 413 | struct work_struct monitor_work; |
412 | struct work_struct chswitch_work; | 414 | struct work_struct chswitch_work; |
413 | struct work_struct beacon_connection_loss_work; | 415 | struct work_struct beacon_connection_loss_work; |
416 | struct work_struct csa_connection_drop_work; | ||
414 | 417 | ||
415 | unsigned long beacon_timeout; | 418 | unsigned long beacon_timeout; |
416 | unsigned long probe_timeout; | 419 | unsigned long probe_timeout; |
@@ -970,7 +973,6 @@ struct ieee80211_local { | |||
970 | int scan_channel_idx; | 973 | int scan_channel_idx; |
971 | int scan_ies_len; | 974 | int scan_ies_len; |
972 | 975 | ||
973 | struct ieee80211_sched_scan_ies sched_scan_ies; | ||
974 | struct work_struct sched_scan_stopped_work; | 976 | struct work_struct sched_scan_stopped_work; |
975 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; | 977 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; |
976 | 978 | ||
@@ -1057,7 +1059,7 @@ struct ieee80211_local { | |||
1057 | bool disable_dynamic_ps; | 1059 | bool disable_dynamic_ps; |
1058 | 1060 | ||
1059 | int user_power_level; /* in dBm */ | 1061 | int user_power_level; /* in dBm */ |
1060 | int power_constr_level; /* in dBm */ | 1062 | int ap_power_level; /* in dBm */ |
1061 | 1063 | ||
1062 | enum ieee80211_smps_mode smps_mode; | 1064 | enum ieee80211_smps_mode smps_mode; |
1063 | 1065 | ||
@@ -1165,7 +1167,6 @@ struct ieee802_11_elems { | |||
1165 | u8 prep_len; | 1167 | u8 prep_len; |
1166 | u8 perr_len; | 1168 | u8 perr_len; |
1167 | u8 country_elem_len; | 1169 | u8 country_elem_len; |
1168 | u8 pwr_constr_elem_len; | ||
1169 | u8 quiet_elem_len; | 1170 | u8 quiet_elem_len; |
1170 | u8 num_of_quiet_elem; /* can be more the one */ | 1171 | u8 num_of_quiet_elem; /* can be more the one */ |
1171 | u8 timeout_int_len; | 1172 | u8 timeout_int_len; |
@@ -1367,7 +1368,6 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | |||
1367 | int ieee80211_reconfig(struct ieee80211_local *local); | 1368 | int ieee80211_reconfig(struct ieee80211_local *local); |
1368 | void ieee80211_stop_device(struct ieee80211_local *local); | 1369 | void ieee80211_stop_device(struct ieee80211_local *local); |
1369 | 1370 | ||
1370 | #ifdef CONFIG_PM | ||
1371 | int __ieee80211_suspend(struct ieee80211_hw *hw, | 1371 | int __ieee80211_suspend(struct ieee80211_hw *hw, |
1372 | struct cfg80211_wowlan *wowlan); | 1372 | struct cfg80211_wowlan *wowlan); |
1373 | 1373 | ||
@@ -1381,18 +1381,6 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) | |||
1381 | 1381 | ||
1382 | return ieee80211_reconfig(hw_to_local(hw)); | 1382 | return ieee80211_reconfig(hw_to_local(hw)); |
1383 | } | 1383 | } |
1384 | #else | ||
1385 | static inline int __ieee80211_suspend(struct ieee80211_hw *hw, | ||
1386 | struct cfg80211_wowlan *wowlan) | ||
1387 | { | ||
1388 | return 0; | ||
1389 | } | ||
1390 | |||
1391 | static inline int __ieee80211_resume(struct ieee80211_hw *hw) | ||
1392 | { | ||
1393 | return 0; | ||
1394 | } | ||
1395 | #endif | ||
1396 | 1384 | ||
1397 | /* utility functions/constants */ | 1385 | /* utility functions/constants */ |
1398 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ | 1386 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ |
@@ -1459,6 +1447,9 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
1459 | u16 transaction, u16 auth_alg, | 1447 | u16 transaction, u16 auth_alg, |
1460 | u8 *extra, size_t extra_len, const u8 *bssid, | 1448 | u8 *extra, size_t extra_len, const u8 *bssid, |
1461 | const u8 *da, const u8 *key, u8 key_len, u8 key_idx); | 1449 | const u8 *da, const u8 *key, u8 key_len, u8 key_idx); |
1450 | void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | ||
1451 | const u8 *bssid, u16 stype, u16 reason, | ||
1452 | bool send_frame, u8 *frame_buf); | ||
1462 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1453 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
1463 | const u8 *ie, size_t ie_len, | 1454 | const u8 *ie, size_t ie_len, |
1464 | enum ieee80211_band band, u32 rate_mask, | 1455 | enum ieee80211_band band, u32 rate_mask, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d747da541747..6f8a73c64fb3 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -793,11 +793,20 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
793 | flush_work(&sdata->work); | 793 | flush_work(&sdata->work); |
794 | /* | 794 | /* |
795 | * When we get here, the interface is marked down. | 795 | * When we get here, the interface is marked down. |
796 | * Call synchronize_rcu() to wait for the RX path | 796 | * Call rcu_barrier() to wait both for the RX path |
797 | * should it be using the interface and enqueuing | 797 | * should it be using the interface and enqueuing |
798 | * frames at this very time on another CPU. | 798 | * frames at this very time on another CPU, and |
799 | * for the sta free call_rcu callbacks. | ||
799 | */ | 800 | */ |
800 | synchronize_rcu(); | 801 | rcu_barrier(); |
802 | |||
803 | /* | ||
804 | * free_sta_rcu() enqueues a work for the actual | ||
805 | * sta cleanup, so we need to flush it while | ||
806 | * sdata is still valid. | ||
807 | */ | ||
808 | flush_workqueue(local->workqueue); | ||
809 | |||
801 | skb_queue_purge(&sdata->skb_queue); | 810 | skb_queue_purge(&sdata->skb_queue); |
802 | 811 | ||
803 | /* | 812 | /* |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 7ae678ba5d67..d27e61aaa71b 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -402,7 +402,7 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
402 | * Synchronize so the TX path can no longer be using | 402 | * Synchronize so the TX path can no longer be using |
403 | * this key before we free/remove it. | 403 | * this key before we free/remove it. |
404 | */ | 404 | */ |
405 | synchronize_rcu(); | 405 | synchronize_net(); |
406 | 406 | ||
407 | if (key->local) | 407 | if (key->local) |
408 | ieee80211_key_disable_hw_accel(key); | 408 | ieee80211_key_disable_hw_accel(key); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index bd7529363193..c80c4490351c 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -150,13 +150,11 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
150 | 150 | ||
151 | if (test_bit(SCAN_SW_SCANNING, &local->scanning) || | 151 | if (test_bit(SCAN_SW_SCANNING, &local->scanning) || |
152 | test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || | 152 | test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || |
153 | test_bit(SCAN_HW_SCANNING, &local->scanning)) | 153 | test_bit(SCAN_HW_SCANNING, &local->scanning) || |
154 | !local->ap_power_level) | ||
154 | power = chan->max_power; | 155 | power = chan->max_power; |
155 | else | 156 | else |
156 | power = local->power_constr_level ? | 157 | power = min(chan->max_power, local->ap_power_level); |
157 | min(chan->max_power, | ||
158 | (chan->max_reg_power - local->power_constr_level)) : | ||
159 | chan->max_power; | ||
160 | 158 | ||
161 | if (local->user_power_level >= 0) | 159 | if (local->user_power_level >= 0) |
162 | power = min(power, local->user_power_level); | 160 | power = min(power, local->user_power_level); |
@@ -366,9 +364,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) | |||
366 | struct ieee80211_local *local = | 364 | struct ieee80211_local *local = |
367 | container_of(work, struct ieee80211_local, recalc_smps); | 365 | container_of(work, struct ieee80211_local, recalc_smps); |
368 | 366 | ||
369 | mutex_lock(&local->iflist_mtx); | ||
370 | ieee80211_recalc_smps(local); | 367 | ieee80211_recalc_smps(local); |
371 | mutex_unlock(&local->iflist_mtx); | ||
372 | } | 368 | } |
373 | 369 | ||
374 | #ifdef CONFIG_INET | 370 | #ifdef CONFIG_INET |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 9d7ad366ef09..3ab34d816897 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -537,7 +537,8 @@ int mesh_plink_open(struct sta_info *sta) | |||
537 | spin_lock_bh(&sta->lock); | 537 | spin_lock_bh(&sta->lock); |
538 | get_random_bytes(&llid, 2); | 538 | get_random_bytes(&llid, 2); |
539 | sta->llid = llid; | 539 | sta->llid = llid; |
540 | if (sta->plink_state != NL80211_PLINK_LISTEN) { | 540 | if (sta->plink_state != NL80211_PLINK_LISTEN && |
541 | sta->plink_state != NL80211_PLINK_BLOCKED) { | ||
541 | spin_unlock_bh(&sta->lock); | 542 | spin_unlock_bh(&sta->lock); |
542 | return -EBUSY; | 543 | return -EBUSY; |
543 | } | 544 | } |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5d77650d4363..e714ed8bb198 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -88,8 +88,6 @@ MODULE_PARM_DESC(probe_wait_ms, | |||
88 | #define TMR_RUNNING_TIMER 0 | 88 | #define TMR_RUNNING_TIMER 0 |
89 | #define TMR_RUNNING_CHANSW 1 | 89 | #define TMR_RUNNING_CHANSW 1 |
90 | 90 | ||
91 | #define DEAUTH_DISASSOC_LEN (24 /* hdr */ + 2 /* reason */) | ||
92 | |||
93 | /* | 91 | /* |
94 | * All cfg80211 functions have to be called outside a locked | 92 | * All cfg80211 functions have to be called outside a locked |
95 | * section so that they can acquire a lock themselves... This | 93 | * section so that they can acquire a lock themselves... This |
@@ -574,46 +572,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
574 | ieee80211_tx_skb(sdata, skb); | 572 | ieee80211_tx_skb(sdata, skb); |
575 | } | 573 | } |
576 | 574 | ||
577 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | ||
578 | const u8 *bssid, u16 stype, | ||
579 | u16 reason, bool send_frame, | ||
580 | u8 *frame_buf) | ||
581 | { | ||
582 | struct ieee80211_local *local = sdata->local; | ||
583 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
584 | struct sk_buff *skb; | ||
585 | struct ieee80211_mgmt *mgmt = (void *)frame_buf; | ||
586 | |||
587 | /* build frame */ | ||
588 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | ||
589 | mgmt->duration = 0; /* initialize only */ | ||
590 | mgmt->seq_ctrl = 0; /* initialize only */ | ||
591 | memcpy(mgmt->da, bssid, ETH_ALEN); | ||
592 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
593 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
594 | /* u.deauth.reason_code == u.disassoc.reason_code */ | ||
595 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | ||
596 | |||
597 | if (send_frame) { | ||
598 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
599 | DEAUTH_DISASSOC_LEN); | ||
600 | if (!skb) | ||
601 | return; | ||
602 | |||
603 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
604 | |||
605 | /* copy in frame */ | ||
606 | memcpy(skb_put(skb, DEAUTH_DISASSOC_LEN), | ||
607 | mgmt, DEAUTH_DISASSOC_LEN); | ||
608 | |||
609 | if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) | ||
610 | IEEE80211_SKB_CB(skb)->flags |= | ||
611 | IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
612 | |||
613 | ieee80211_tx_skb(sdata, skb); | ||
614 | } | ||
615 | } | ||
616 | |||
617 | void ieee80211_send_pspoll(struct ieee80211_local *local, | 575 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
618 | struct ieee80211_sub_if_data *sdata) | 576 | struct ieee80211_sub_if_data *sdata) |
619 | { | 577 | { |
@@ -730,16 +688,13 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | |||
730 | 688 | ||
731 | trace_api_chswitch_done(sdata, success); | 689 | trace_api_chswitch_done(sdata, success); |
732 | if (!success) { | 690 | if (!success) { |
733 | /* | 691 | sdata_info(sdata, |
734 | * If the channel switch was not successful, stay | 692 | "driver channel switch failed, disconnecting\n"); |
735 | * around on the old channel. We currently lack | 693 | ieee80211_queue_work(&sdata->local->hw, |
736 | * good handling of this situation, possibly we | 694 | &ifmgd->csa_connection_drop_work); |
737 | * should just drop the association. | 695 | } else { |
738 | */ | 696 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); |
739 | sdata->local->csa_channel = sdata->local->oper_channel; | ||
740 | } | 697 | } |
741 | |||
742 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | ||
743 | } | 698 | } |
744 | EXPORT_SYMBOL(ieee80211_chswitch_done); | 699 | EXPORT_SYMBOL(ieee80211_chswitch_done); |
745 | 700 | ||
@@ -784,8 +739,14 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
784 | return; | 739 | return; |
785 | 740 | ||
786 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | 741 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); |
787 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) | 742 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) { |
743 | sdata_info(sdata, | ||
744 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", | ||
745 | ifmgd->associated->bssid, new_freq); | ||
746 | ieee80211_queue_work(&sdata->local->hw, | ||
747 | &ifmgd->csa_connection_drop_work); | ||
788 | return; | 748 | return; |
749 | } | ||
789 | 750 | ||
790 | sdata->local->csa_channel = new_ch; | 751 | sdata->local->csa_channel = new_ch; |
791 | 752 | ||
@@ -818,23 +779,71 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
818 | } | 779 | } |
819 | 780 | ||
820 | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | 781 | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, |
821 | u16 capab_info, u8 *pwr_constr_elem, | 782 | struct ieee80211_channel *channel, |
822 | u8 pwr_constr_elem_len) | 783 | const u8 *country_ie, u8 country_ie_len, |
784 | const u8 *pwr_constr_elem) | ||
823 | { | 785 | { |
824 | struct ieee80211_conf *conf = &sdata->local->hw.conf; | 786 | struct ieee80211_country_ie_triplet *triplet; |
787 | int chan = ieee80211_frequency_to_channel(channel->center_freq); | ||
788 | int i, chan_pwr, chan_increment, new_ap_level; | ||
789 | bool have_chan_pwr = false; | ||
825 | 790 | ||
826 | if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) | 791 | /* Invalid IE */ |
792 | if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) | ||
827 | return; | 793 | return; |
828 | 794 | ||
829 | /* Power constraint IE length should be 1 octet */ | 795 | triplet = (void *)(country_ie + 3); |
830 | if (pwr_constr_elem_len != 1) | 796 | country_ie_len -= 3; |
831 | return; | ||
832 | 797 | ||
833 | if ((*pwr_constr_elem <= conf->channel->max_reg_power) && | 798 | switch (channel->band) { |
834 | (*pwr_constr_elem != sdata->local->power_constr_level)) { | 799 | default: |
835 | sdata->local->power_constr_level = *pwr_constr_elem; | 800 | WARN_ON_ONCE(1); |
836 | ieee80211_hw_config(sdata->local, 0); | 801 | /* fall through */ |
802 | case IEEE80211_BAND_2GHZ: | ||
803 | case IEEE80211_BAND_60GHZ: | ||
804 | chan_increment = 1; | ||
805 | break; | ||
806 | case IEEE80211_BAND_5GHZ: | ||
807 | chan_increment = 4; | ||
808 | break; | ||
837 | } | 809 | } |
810 | |||
811 | /* find channel */ | ||
812 | while (country_ie_len >= 3) { | ||
813 | u8 first_channel = triplet->chans.first_channel; | ||
814 | |||
815 | if (first_channel >= IEEE80211_COUNTRY_EXTENSION_ID) | ||
816 | goto next; | ||
817 | |||
818 | for (i = 0; i < triplet->chans.num_channels; i++) { | ||
819 | if (first_channel + i * chan_increment == chan) { | ||
820 | have_chan_pwr = true; | ||
821 | chan_pwr = triplet->chans.max_power; | ||
822 | break; | ||
823 | } | ||
824 | } | ||
825 | if (have_chan_pwr) | ||
826 | break; | ||
827 | |||
828 | next: | ||
829 | triplet++; | ||
830 | country_ie_len -= 3; | ||
831 | } | ||
832 | |||
833 | if (!have_chan_pwr) | ||
834 | return; | ||
835 | |||
836 | new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); | ||
837 | |||
838 | if (sdata->local->ap_power_level == new_ap_level) | ||
839 | return; | ||
840 | |||
841 | sdata_info(sdata, | ||
842 | "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", | ||
843 | new_ap_level, chan_pwr, *pwr_constr_elem, | ||
844 | sdata->u.mgd.bssid); | ||
845 | sdata->local->ap_power_level = new_ap_level; | ||
846 | ieee80211_hw_config(sdata->local, 0); | ||
838 | } | 847 | } |
839 | 848 | ||
840 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) | 849 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) |
@@ -1339,9 +1348,9 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1339 | 1348 | ||
1340 | mutex_lock(&local->iflist_mtx); | 1349 | mutex_lock(&local->iflist_mtx); |
1341 | ieee80211_recalc_ps(local, -1); | 1350 | ieee80211_recalc_ps(local, -1); |
1342 | ieee80211_recalc_smps(local); | ||
1343 | mutex_unlock(&local->iflist_mtx); | 1351 | mutex_unlock(&local->iflist_mtx); |
1344 | 1352 | ||
1353 | ieee80211_recalc_smps(local); | ||
1345 | ieee80211_recalc_ps_vif(sdata); | 1354 | ieee80211_recalc_ps_vif(sdata); |
1346 | 1355 | ||
1347 | netif_tx_start_all_queues(sdata->dev); | 1356 | netif_tx_start_all_queues(sdata->dev); |
@@ -1390,7 +1399,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1390 | sta = sta_info_get(sdata, ifmgd->bssid); | 1399 | sta = sta_info_get(sdata, ifmgd->bssid); |
1391 | if (sta) { | 1400 | if (sta) { |
1392 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | 1401 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); |
1393 | ieee80211_sta_tear_down_BA_sessions(sta, tx); | 1402 | ieee80211_sta_tear_down_BA_sessions(sta, false); |
1394 | } | 1403 | } |
1395 | mutex_unlock(&local->sta_mtx); | 1404 | mutex_unlock(&local->sta_mtx); |
1396 | 1405 | ||
@@ -1438,7 +1447,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1438 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | 1447 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); |
1439 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | 1448 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); |
1440 | 1449 | ||
1441 | local->power_constr_level = 0; | 1450 | local->ap_power_level = 0; |
1442 | 1451 | ||
1443 | del_timer_sync(&local->dynamic_ps_timer); | 1452 | del_timer_sync(&local->dynamic_ps_timer); |
1444 | cancel_work_sync(&local->dynamic_ps_enable_work); | 1453 | cancel_work_sync(&local->dynamic_ps_enable_work); |
@@ -1692,11 +1701,12 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1692 | } | 1701 | } |
1693 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); | 1702 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); |
1694 | 1703 | ||
1695 | static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | 1704 | static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata, |
1705 | bool transmit_frame) | ||
1696 | { | 1706 | { |
1697 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1707 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1698 | struct ieee80211_local *local = sdata->local; | 1708 | struct ieee80211_local *local = sdata->local; |
1699 | u8 frame_buf[DEAUTH_DISASSOC_LEN]; | 1709 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
1700 | 1710 | ||
1701 | mutex_lock(&ifmgd->mtx); | 1711 | mutex_lock(&ifmgd->mtx); |
1702 | if (!ifmgd->associated) { | 1712 | if (!ifmgd->associated) { |
@@ -1704,19 +1714,17 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1704 | return; | 1714 | return; |
1705 | } | 1715 | } |
1706 | 1716 | ||
1707 | sdata_info(sdata, "Connection to AP %pM lost\n", | ||
1708 | ifmgd->associated->bssid); | ||
1709 | |||
1710 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 1717 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
1711 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 1718 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
1712 | false, frame_buf); | 1719 | transmit_frame, frame_buf); |
1720 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
1713 | mutex_unlock(&ifmgd->mtx); | 1721 | mutex_unlock(&ifmgd->mtx); |
1714 | 1722 | ||
1715 | /* | 1723 | /* |
1716 | * must be outside lock due to cfg80211, | 1724 | * must be outside lock due to cfg80211, |
1717 | * but that's not a problem. | 1725 | * but that's not a problem. |
1718 | */ | 1726 | */ |
1719 | cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 1727 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); |
1720 | 1728 | ||
1721 | mutex_lock(&local->mtx); | 1729 | mutex_lock(&local->mtx); |
1722 | ieee80211_recalc_idle(local); | 1730 | ieee80211_recalc_idle(local); |
@@ -1739,10 +1747,24 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work) | |||
1739 | rcu_read_unlock(); | 1747 | rcu_read_unlock(); |
1740 | } | 1748 | } |
1741 | 1749 | ||
1742 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | 1750 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) { |
1743 | __ieee80211_connection_loss(sdata); | 1751 | sdata_info(sdata, "Connection to AP %pM lost\n", |
1744 | else | 1752 | ifmgd->bssid); |
1753 | __ieee80211_disconnect(sdata, false); | ||
1754 | } else { | ||
1745 | ieee80211_mgd_probe_ap(sdata, true); | 1755 | ieee80211_mgd_probe_ap(sdata, true); |
1756 | } | ||
1757 | } | ||
1758 | |||
1759 | static void ieee80211_csa_connection_drop_work(struct work_struct *work) | ||
1760 | { | ||
1761 | struct ieee80211_sub_if_data *sdata = | ||
1762 | container_of(work, struct ieee80211_sub_if_data, | ||
1763 | u.mgd.csa_connection_drop_work); | ||
1764 | |||
1765 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
1766 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1767 | __ieee80211_disconnect(sdata, true); | ||
1746 | } | 1768 | } |
1747 | 1769 | ||
1748 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | 1770 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) |
@@ -2530,15 +2552,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2530 | bssid, true); | 2552 | bssid, true); |
2531 | } | 2553 | } |
2532 | 2554 | ||
2533 | /* Note: country IE parsing is done for us by cfg80211 */ | 2555 | if (elems.country_elem && elems.pwr_constr_elem && |
2534 | if (elems.country_elem) { | 2556 | mgmt->u.probe_resp.capab_info & |
2535 | /* TODO: IBSS also needs this */ | 2557 | cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) |
2536 | if (elems.pwr_constr_elem) | 2558 | ieee80211_handle_pwr_constr(sdata, local->oper_channel, |
2537 | ieee80211_handle_pwr_constr(sdata, | 2559 | elems.country_elem, |
2538 | le16_to_cpu(mgmt->u.probe_resp.capab_info), | 2560 | elems.country_elem_len, |
2539 | elems.pwr_constr_elem, | 2561 | elems.pwr_constr_elem); |
2540 | elems.pwr_constr_elem_len); | ||
2541 | } | ||
2542 | 2562 | ||
2543 | ieee80211_bss_info_change_notify(sdata, changed); | 2563 | ieee80211_bss_info_change_notify(sdata, changed); |
2544 | } | 2564 | } |
@@ -2635,7 +2655,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2635 | { | 2655 | { |
2636 | struct ieee80211_local *local = sdata->local; | 2656 | struct ieee80211_local *local = sdata->local; |
2637 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2657 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2638 | u8 frame_buf[DEAUTH_DISASSOC_LEN]; | 2658 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
2639 | 2659 | ||
2640 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, | 2660 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, |
2641 | false, frame_buf); | 2661 | false, frame_buf); |
@@ -2645,7 +2665,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2645 | * must be outside lock due to cfg80211, | 2665 | * must be outside lock due to cfg80211, |
2646 | * but that's not a problem. | 2666 | * but that's not a problem. |
2647 | */ | 2667 | */ |
2648 | cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 2668 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); |
2649 | 2669 | ||
2650 | mutex_lock(&local->mtx); | 2670 | mutex_lock(&local->mtx); |
2651 | ieee80211_recalc_idle(local); | 2671 | ieee80211_recalc_idle(local); |
@@ -2929,6 +2949,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
2929 | 2949 | ||
2930 | cancel_work_sync(&ifmgd->monitor_work); | 2950 | cancel_work_sync(&ifmgd->monitor_work); |
2931 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); | 2951 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); |
2952 | cancel_work_sync(&ifmgd->csa_connection_drop_work); | ||
2932 | if (del_timer_sync(&ifmgd->timer)) | 2953 | if (del_timer_sync(&ifmgd->timer)) |
2933 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | 2954 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); |
2934 | 2955 | ||
@@ -2985,6 +3006,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
2985 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 3006 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
2986 | INIT_WORK(&ifmgd->beacon_connection_loss_work, | 3007 | INIT_WORK(&ifmgd->beacon_connection_loss_work, |
2987 | ieee80211_beacon_connection_loss_work); | 3008 | ieee80211_beacon_connection_loss_work); |
3009 | INIT_WORK(&ifmgd->csa_connection_drop_work, | ||
3010 | ieee80211_csa_connection_drop_work); | ||
2988 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); | 3011 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); |
2989 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 3012 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
2990 | (unsigned long) sdata); | 3013 | (unsigned long) sdata); |
@@ -3525,7 +3548,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
3525 | struct cfg80211_deauth_request *req) | 3548 | struct cfg80211_deauth_request *req) |
3526 | { | 3549 | { |
3527 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3550 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3528 | u8 frame_buf[DEAUTH_DISASSOC_LEN]; | 3551 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
3529 | 3552 | ||
3530 | mutex_lock(&ifmgd->mtx); | 3553 | mutex_lock(&ifmgd->mtx); |
3531 | 3554 | ||
@@ -3553,7 +3576,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
3553 | 3576 | ||
3554 | mutex_unlock(&ifmgd->mtx); | 3577 | mutex_unlock(&ifmgd->mtx); |
3555 | 3578 | ||
3556 | __cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 3579 | __cfg80211_send_deauth(sdata->dev, frame_buf, |
3580 | IEEE80211_DEAUTH_FRAME_LEN); | ||
3557 | 3581 | ||
3558 | mutex_lock(&sdata->local->mtx); | 3582 | mutex_lock(&sdata->local->mtx); |
3559 | ieee80211_recalc_idle(sdata->local); | 3583 | ieee80211_recalc_idle(sdata->local); |
@@ -3567,7 +3591,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
3567 | { | 3591 | { |
3568 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3592 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3569 | u8 bssid[ETH_ALEN]; | 3593 | u8 bssid[ETH_ALEN]; |
3570 | u8 frame_buf[DEAUTH_DISASSOC_LEN]; | 3594 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
3571 | 3595 | ||
3572 | mutex_lock(&ifmgd->mtx); | 3596 | mutex_lock(&ifmgd->mtx); |
3573 | 3597 | ||
@@ -3592,7 +3616,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
3592 | frame_buf); | 3616 | frame_buf); |
3593 | mutex_unlock(&ifmgd->mtx); | 3617 | mutex_unlock(&ifmgd->mtx); |
3594 | 3618 | ||
3595 | __cfg80211_send_disassoc(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 3619 | __cfg80211_send_disassoc(sdata->dev, frame_buf, |
3620 | IEEE80211_DEAUTH_FRAME_LEN); | ||
3596 | 3621 | ||
3597 | mutex_lock(&sdata->local->mtx); | 3622 | mutex_lock(&sdata->local->mtx); |
3598 | ieee80211_recalc_idle(sdata->local); | 3623 | ieee80211_recalc_idle(sdata->local); |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 507121dad082..83608ac16780 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -233,8 +233,7 @@ static void ieee80211_hw_roc_start(struct work_struct *work) | |||
233 | u32 dur = dep->duration; | 233 | u32 dur = dep->duration; |
234 | dep->duration = dur - roc->duration; | 234 | dep->duration = dur - roc->duration; |
235 | roc->duration = dur; | 235 | roc->duration = dur; |
236 | list_del(&dep->list); | 236 | list_move(&dep->list, &roc->list); |
237 | list_add(&dep->list, &roc->list); | ||
238 | } | 237 | } |
239 | } | 238 | } |
240 | out_unlock: | 239 | out_unlock: |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 740e414d44f4..c4cdbde24fd3 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -407,7 +407,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
407 | enum ieee80211_band band = local->hw.conf.channel->band; | 407 | enum ieee80211_band band = local->hw.conf.channel->band; |
408 | 408 | ||
409 | sdata = rcu_dereference_protected(local->scan_sdata, | 409 | sdata = rcu_dereference_protected(local->scan_sdata, |
410 | lockdep_is_held(&local->mtx));; | 410 | lockdep_is_held(&local->mtx)); |
411 | 411 | ||
412 | for (i = 0; i < local->scan_req->n_ssids; i++) | 412 | for (i = 0; i < local->scan_req->n_ssids; i++) |
413 | ieee80211_send_probe_req( | 413 | ieee80211_send_probe_req( |
@@ -917,6 +917,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
917 | struct cfg80211_sched_scan_request *req) | 917 | struct cfg80211_sched_scan_request *req) |
918 | { | 918 | { |
919 | struct ieee80211_local *local = sdata->local; | 919 | struct ieee80211_local *local = sdata->local; |
920 | struct ieee80211_sched_scan_ies sched_scan_ies; | ||
920 | int ret, i; | 921 | int ret, i; |
921 | 922 | ||
922 | mutex_lock(&local->mtx); | 923 | mutex_lock(&local->mtx); |
@@ -935,33 +936,28 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
935 | if (!local->hw.wiphy->bands[i]) | 936 | if (!local->hw.wiphy->bands[i]) |
936 | continue; | 937 | continue; |
937 | 938 | ||
938 | local->sched_scan_ies.ie[i] = kzalloc(2 + | 939 | sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + |
939 | IEEE80211_MAX_SSID_LEN + | 940 | local->scan_ies_len + |
940 | local->scan_ies_len + | 941 | req->ie_len, |
941 | req->ie_len, | 942 | GFP_KERNEL); |
942 | GFP_KERNEL); | 943 | if (!sched_scan_ies.ie[i]) { |
943 | if (!local->sched_scan_ies.ie[i]) { | ||
944 | ret = -ENOMEM; | 944 | ret = -ENOMEM; |
945 | goto out_free; | 945 | goto out_free; |
946 | } | 946 | } |
947 | 947 | ||
948 | local->sched_scan_ies.len[i] = | 948 | sched_scan_ies.len[i] = |
949 | ieee80211_build_preq_ies(local, | 949 | ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], |
950 | local->sched_scan_ies.ie[i], | ||
951 | req->ie, req->ie_len, i, | 950 | req->ie, req->ie_len, i, |
952 | (u32) -1, 0); | 951 | (u32) -1, 0); |
953 | } | 952 | } |
954 | 953 | ||
955 | ret = drv_sched_scan_start(local, sdata, req, | 954 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); |
956 | &local->sched_scan_ies); | 955 | if (ret == 0) |
957 | if (ret == 0) { | ||
958 | rcu_assign_pointer(local->sched_scan_sdata, sdata); | 956 | rcu_assign_pointer(local->sched_scan_sdata, sdata); |
959 | goto out; | ||
960 | } | ||
961 | 957 | ||
962 | out_free: | 958 | out_free: |
963 | while (i > 0) | 959 | while (i > 0) |
964 | kfree(local->sched_scan_ies.ie[--i]); | 960 | kfree(sched_scan_ies.ie[--i]); |
965 | out: | 961 | out: |
966 | mutex_unlock(&local->mtx); | 962 | mutex_unlock(&local->mtx); |
967 | return ret; | 963 | return ret; |
@@ -970,7 +966,7 @@ out: | |||
970 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) | 966 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) |
971 | { | 967 | { |
972 | struct ieee80211_local *local = sdata->local; | 968 | struct ieee80211_local *local = sdata->local; |
973 | int ret = 0, i; | 969 | int ret = 0; |
974 | 970 | ||
975 | mutex_lock(&local->mtx); | 971 | mutex_lock(&local->mtx); |
976 | 972 | ||
@@ -979,12 +975,9 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) | |||
979 | goto out; | 975 | goto out; |
980 | } | 976 | } |
981 | 977 | ||
982 | if (rcu_access_pointer(local->sched_scan_sdata)) { | 978 | if (rcu_access_pointer(local->sched_scan_sdata)) |
983 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
984 | kfree(local->sched_scan_ies.ie[i]); | ||
985 | |||
986 | drv_sched_scan_stop(local, sdata); | 979 | drv_sched_scan_stop(local, sdata); |
987 | } | 980 | |
988 | out: | 981 | out: |
989 | mutex_unlock(&local->mtx); | 982 | mutex_unlock(&local->mtx); |
990 | 983 | ||
@@ -1006,7 +999,6 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) | |||
1006 | struct ieee80211_local *local = | 999 | struct ieee80211_local *local = |
1007 | container_of(work, struct ieee80211_local, | 1000 | container_of(work, struct ieee80211_local, |
1008 | sched_scan_stopped_work); | 1001 | sched_scan_stopped_work); |
1009 | int i; | ||
1010 | 1002 | ||
1011 | mutex_lock(&local->mtx); | 1003 | mutex_lock(&local->mtx); |
1012 | 1004 | ||
@@ -1015,9 +1007,6 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) | |||
1015 | return; | 1007 | return; |
1016 | } | 1008 | } |
1017 | 1009 | ||
1018 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
1019 | kfree(local->sched_scan_ies.ie[i]); | ||
1020 | |||
1021 | rcu_assign_pointer(local->sched_scan_sdata, NULL); | 1010 | rcu_assign_pointer(local->sched_scan_sdata, NULL); |
1022 | 1011 | ||
1023 | mutex_unlock(&local->mtx); | 1012 | mutex_unlock(&local->mtx); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 06fa75ceb025..797dd36a220d 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -91,6 +91,70 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
91 | return -ENOENT; | 91 | return -ENOENT; |
92 | } | 92 | } |
93 | 93 | ||
94 | static void free_sta_work(struct work_struct *wk) | ||
95 | { | ||
96 | struct sta_info *sta = container_of(wk, struct sta_info, free_sta_wk); | ||
97 | int ac, i; | ||
98 | struct tid_ampdu_tx *tid_tx; | ||
99 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
100 | struct ieee80211_local *local = sdata->local; | ||
101 | |||
102 | /* | ||
103 | * At this point, when being called as call_rcu callback, | ||
104 | * neither mac80211 nor the driver can reference this | ||
105 | * sta struct any more except by still existing timers | ||
106 | * associated with this station that we clean up below. | ||
107 | */ | ||
108 | |||
109 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { | ||
110 | BUG_ON(!sdata->bss); | ||
111 | |||
112 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
113 | |||
114 | atomic_dec(&sdata->bss->num_sta_ps); | ||
115 | sta_info_recalc_tim(sta); | ||
116 | } | ||
117 | |||
118 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
119 | local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); | ||
120 | __skb_queue_purge(&sta->ps_tx_buf[ac]); | ||
121 | __skb_queue_purge(&sta->tx_filtered[ac]); | ||
122 | } | ||
123 | |||
124 | #ifdef CONFIG_MAC80211_MESH | ||
125 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
126 | mesh_accept_plinks_update(sdata); | ||
127 | mesh_plink_deactivate(sta); | ||
128 | del_timer_sync(&sta->plink_timer); | ||
129 | } | ||
130 | #endif | ||
131 | |||
132 | cancel_work_sync(&sta->drv_unblock_wk); | ||
133 | |||
134 | /* | ||
135 | * Destroy aggregation state here. It would be nice to wait for the | ||
136 | * driver to finish aggregation stop and then clean up, but for now | ||
137 | * drivers have to handle aggregation stop being requested, followed | ||
138 | * directly by station destruction. | ||
139 | */ | ||
140 | for (i = 0; i < STA_TID_NUM; i++) { | ||
141 | tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); | ||
142 | if (!tid_tx) | ||
143 | continue; | ||
144 | __skb_queue_purge(&tid_tx->pending); | ||
145 | kfree(tid_tx); | ||
146 | } | ||
147 | |||
148 | sta_info_free(local, sta); | ||
149 | } | ||
150 | |||
151 | static void free_sta_rcu(struct rcu_head *h) | ||
152 | { | ||
153 | struct sta_info *sta = container_of(h, struct sta_info, rcu_head); | ||
154 | |||
155 | ieee80211_queue_work(&sta->local->hw, &sta->free_sta_wk); | ||
156 | } | ||
157 | |||
94 | /* protected by RCU */ | 158 | /* protected by RCU */ |
95 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | 159 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, |
96 | const u8 *addr) | 160 | const u8 *addr) |
@@ -241,6 +305,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
241 | 305 | ||
242 | spin_lock_init(&sta->lock); | 306 | spin_lock_init(&sta->lock); |
243 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 307 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); |
308 | INIT_WORK(&sta->free_sta_wk, free_sta_work); | ||
244 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 309 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
245 | mutex_init(&sta->ampdu_mlme.mtx); | 310 | mutex_init(&sta->ampdu_mlme.mtx); |
246 | 311 | ||
@@ -654,8 +719,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
654 | { | 719 | { |
655 | struct ieee80211_local *local; | 720 | struct ieee80211_local *local; |
656 | struct ieee80211_sub_if_data *sdata; | 721 | struct ieee80211_sub_if_data *sdata; |
657 | int ret, i, ac; | 722 | int ret, i; |
658 | struct tid_ampdu_tx *tid_tx; | ||
659 | 723 | ||
660 | might_sleep(); | 724 | might_sleep(); |
661 | 725 | ||
@@ -674,7 +738,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
674 | * will be sufficient. | 738 | * will be sufficient. |
675 | */ | 739 | */ |
676 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | 740 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); |
677 | ieee80211_sta_tear_down_BA_sessions(sta, true); | 741 | ieee80211_sta_tear_down_BA_sessions(sta, false); |
678 | 742 | ||
679 | ret = sta_info_hash_del(local, sta); | 743 | ret = sta_info_hash_del(local, sta); |
680 | if (ret) | 744 | if (ret) |
@@ -711,65 +775,14 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
711 | WARN_ON_ONCE(ret != 0); | 775 | WARN_ON_ONCE(ret != 0); |
712 | } | 776 | } |
713 | 777 | ||
714 | /* | ||
715 | * At this point, after we wait for an RCU grace period, | ||
716 | * neither mac80211 nor the driver can reference this | ||
717 | * sta struct any more except by still existing timers | ||
718 | * associated with this station that we clean up below. | ||
719 | */ | ||
720 | synchronize_rcu(); | ||
721 | |||
722 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { | ||
723 | BUG_ON(!sdata->bss); | ||
724 | |||
725 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
726 | |||
727 | atomic_dec(&sdata->bss->num_sta_ps); | ||
728 | sta_info_recalc_tim(sta); | ||
729 | } | ||
730 | |||
731 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
732 | local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); | ||
733 | __skb_queue_purge(&sta->ps_tx_buf[ac]); | ||
734 | __skb_queue_purge(&sta->tx_filtered[ac]); | ||
735 | } | ||
736 | |||
737 | #ifdef CONFIG_MAC80211_MESH | ||
738 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
739 | mesh_accept_plinks_update(sdata); | ||
740 | #endif | ||
741 | |||
742 | sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); | 778 | sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); |
743 | 779 | ||
744 | cancel_work_sync(&sta->drv_unblock_wk); | ||
745 | |||
746 | cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); | 780 | cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); |
747 | 781 | ||
748 | rate_control_remove_sta_debugfs(sta); | 782 | rate_control_remove_sta_debugfs(sta); |
749 | ieee80211_sta_debugfs_remove(sta); | 783 | ieee80211_sta_debugfs_remove(sta); |
750 | 784 | ||
751 | #ifdef CONFIG_MAC80211_MESH | 785 | call_rcu(&sta->rcu_head, free_sta_rcu); |
752 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { | ||
753 | mesh_plink_deactivate(sta); | ||
754 | del_timer_sync(&sta->plink_timer); | ||
755 | } | ||
756 | #endif | ||
757 | |||
758 | /* | ||
759 | * Destroy aggregation state here. It would be nice to wait for the | ||
760 | * driver to finish aggregation stop and then clean up, but for now | ||
761 | * drivers have to handle aggregation stop being requested, followed | ||
762 | * directly by station destruction. | ||
763 | */ | ||
764 | for (i = 0; i < STA_TID_NUM; i++) { | ||
765 | tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); | ||
766 | if (!tid_tx) | ||
767 | continue; | ||
768 | __skb_queue_purge(&tid_tx->pending); | ||
769 | kfree(tid_tx); | ||
770 | } | ||
771 | |||
772 | sta_info_free(local, sta); | ||
773 | 786 | ||
774 | return 0; | 787 | return 0; |
775 | } | 788 | } |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index a470e1123a55..c88f161f8118 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -287,6 +287,7 @@ struct sta_ampdu_mlme { | |||
287 | struct sta_info { | 287 | struct sta_info { |
288 | /* General information, mostly static */ | 288 | /* General information, mostly static */ |
289 | struct list_head list; | 289 | struct list_head list; |
290 | struct rcu_head rcu_head; | ||
290 | struct sta_info __rcu *hnext; | 291 | struct sta_info __rcu *hnext; |
291 | struct ieee80211_local *local; | 292 | struct ieee80211_local *local; |
292 | struct ieee80211_sub_if_data *sdata; | 293 | struct ieee80211_sub_if_data *sdata; |
@@ -297,6 +298,7 @@ struct sta_info { | |||
297 | spinlock_t lock; | 298 | spinlock_t lock; |
298 | 299 | ||
299 | struct work_struct drv_unblock_wk; | 300 | struct work_struct drv_unblock_wk; |
301 | struct work_struct free_sta_wk; | ||
300 | 302 | ||
301 | u16 listen_interval; | 303 | u16 listen_interval; |
302 | 304 | ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index b0801b7d572d..2ce89732d0f2 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -517,29 +517,41 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
517 | 517 | ||
518 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { | 518 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { |
519 | u64 cookie = (unsigned long)skb; | 519 | u64 cookie = (unsigned long)skb; |
520 | bool found = false; | ||
521 | |||
520 | acked = info->flags & IEEE80211_TX_STAT_ACK; | 522 | acked = info->flags & IEEE80211_TX_STAT_ACK; |
521 | 523 | ||
522 | if (ieee80211_is_nullfunc(hdr->frame_control) || | 524 | rcu_read_lock(); |
523 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | 525 | |
524 | cfg80211_probe_status(skb->dev, hdr->addr1, | 526 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
525 | cookie, acked, GFP_ATOMIC); | 527 | if (!sdata->dev) |
526 | } else if (skb->dev) { | 528 | continue; |
527 | cfg80211_mgmt_tx_status( | ||
528 | skb->dev->ieee80211_ptr, cookie, skb->data, | ||
529 | skb->len, acked, GFP_ATOMIC); | ||
530 | } else { | ||
531 | struct ieee80211_sub_if_data *p2p_sdata; | ||
532 | 529 | ||
533 | rcu_read_lock(); | 530 | if (skb->dev != sdata->dev) |
531 | continue; | ||
534 | 532 | ||
535 | p2p_sdata = rcu_dereference(local->p2p_sdata); | 533 | found = true; |
536 | if (p2p_sdata) { | 534 | break; |
537 | cfg80211_mgmt_tx_status( | 535 | } |
538 | &p2p_sdata->wdev, cookie, skb->data, | 536 | |
539 | skb->len, acked, GFP_ATOMIC); | 537 | if (!skb->dev) { |
540 | } | 538 | sdata = rcu_dereference(local->p2p_sdata); |
541 | rcu_read_unlock(); | 539 | if (sdata) |
540 | found = true; | ||
541 | } | ||
542 | |||
543 | if (!found) | ||
544 | skb->dev = NULL; | ||
545 | else if (ieee80211_is_nullfunc(hdr->frame_control) || | ||
546 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | ||
547 | cfg80211_probe_status(sdata->dev, hdr->addr1, | ||
548 | cookie, acked, GFP_ATOMIC); | ||
549 | } else { | ||
550 | cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, | ||
551 | skb->len, acked, GFP_ATOMIC); | ||
542 | } | 552 | } |
553 | |||
554 | rcu_read_unlock(); | ||
543 | } | 555 | } |
544 | 556 | ||
545 | if (unlikely(info->ack_frame_id)) { | 557 | if (unlikely(info->ack_frame_id)) { |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 29eb4e678235..e0e0d1d0e830 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -580,7 +580,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
580 | tx->key = NULL; | 580 | tx->key = NULL; |
581 | else | 581 | else |
582 | skip_hw = (tx->key->conf.flags & | 582 | skip_hw = (tx->key->conf.flags & |
583 | IEEE80211_KEY_FLAG_SW_MGMT) && | 583 | IEEE80211_KEY_FLAG_SW_MGMT_TX) && |
584 | ieee80211_is_mgmt(hdr->frame_control); | 584 | ieee80211_is_mgmt(hdr->frame_control); |
585 | break; | 585 | break; |
586 | case WLAN_CIPHER_SUITE_AES_CMAC: | 586 | case WLAN_CIPHER_SUITE_AES_CMAC: |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 471fb0516c99..22ca35054dd0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -792,8 +792,11 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
792 | elems->country_elem_len = elen; | 792 | elems->country_elem_len = elen; |
793 | break; | 793 | break; |
794 | case WLAN_EID_PWR_CONSTRAINT: | 794 | case WLAN_EID_PWR_CONSTRAINT: |
795 | if (elen != 1) { | ||
796 | elem_parse_failed = true; | ||
797 | break; | ||
798 | } | ||
795 | elems->pwr_constr_elem = pos; | 799 | elems->pwr_constr_elem = pos; |
796 | elems->pwr_constr_elem_len = elen; | ||
797 | break; | 800 | break; |
798 | case WLAN_EID_TIMEOUT_INTERVAL: | 801 | case WLAN_EID_TIMEOUT_INTERVAL: |
799 | elems->timeout_int = pos; | 802 | elems->timeout_int = pos; |
@@ -1004,6 +1007,45 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
1004 | ieee80211_tx_skb(sdata, skb); | 1007 | ieee80211_tx_skb(sdata, skb); |
1005 | } | 1008 | } |
1006 | 1009 | ||
1010 | void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | ||
1011 | const u8 *bssid, u16 stype, u16 reason, | ||
1012 | bool send_frame, u8 *frame_buf) | ||
1013 | { | ||
1014 | struct ieee80211_local *local = sdata->local; | ||
1015 | struct sk_buff *skb; | ||
1016 | struct ieee80211_mgmt *mgmt = (void *)frame_buf; | ||
1017 | |||
1018 | /* build frame */ | ||
1019 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | ||
1020 | mgmt->duration = 0; /* initialize only */ | ||
1021 | mgmt->seq_ctrl = 0; /* initialize only */ | ||
1022 | memcpy(mgmt->da, bssid, ETH_ALEN); | ||
1023 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
1024 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
1025 | /* u.deauth.reason_code == u.disassoc.reason_code */ | ||
1026 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | ||
1027 | |||
1028 | if (send_frame) { | ||
1029 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
1030 | IEEE80211_DEAUTH_FRAME_LEN); | ||
1031 | if (!skb) | ||
1032 | return; | ||
1033 | |||
1034 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1035 | |||
1036 | /* copy in frame */ | ||
1037 | memcpy(skb_put(skb, IEEE80211_DEAUTH_FRAME_LEN), | ||
1038 | mgmt, IEEE80211_DEAUTH_FRAME_LEN); | ||
1039 | |||
1040 | if (sdata->vif.type != NL80211_IFTYPE_STATION || | ||
1041 | !(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED)) | ||
1042 | IEEE80211_SKB_CB(skb)->flags |= | ||
1043 | IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
1044 | |||
1045 | ieee80211_tx_skb(sdata, skb); | ||
1046 | } | ||
1047 | } | ||
1048 | |||
1007 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1049 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
1008 | const u8 *ie, size_t ie_len, | 1050 | const u8 *ie, size_t ie_len, |
1009 | enum ieee80211_band band, u32 rate_mask, | 1051 | enum ieee80211_band band, u32 rate_mask, |
@@ -1564,14 +1606,13 @@ static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, | |||
1564 | return 0; | 1606 | return 0; |
1565 | } | 1607 | } |
1566 | 1608 | ||
1567 | /* must hold iflist_mtx */ | ||
1568 | void ieee80211_recalc_smps(struct ieee80211_local *local) | 1609 | void ieee80211_recalc_smps(struct ieee80211_local *local) |
1569 | { | 1610 | { |
1570 | struct ieee80211_sub_if_data *sdata; | 1611 | struct ieee80211_sub_if_data *sdata; |
1571 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; | 1612 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; |
1572 | int count = 0; | 1613 | int count = 0; |
1573 | 1614 | ||
1574 | lockdep_assert_held(&local->iflist_mtx); | 1615 | mutex_lock(&local->iflist_mtx); |
1575 | 1616 | ||
1576 | /* | 1617 | /* |
1577 | * This function could be improved to handle multiple | 1618 | * This function could be improved to handle multiple |
@@ -1600,12 +1641,14 @@ void ieee80211_recalc_smps(struct ieee80211_local *local) | |||
1600 | } | 1641 | } |
1601 | 1642 | ||
1602 | if (smps_mode == local->smps_mode) | 1643 | if (smps_mode == local->smps_mode) |
1603 | return; | 1644 | goto unlock; |
1604 | 1645 | ||
1605 | set: | 1646 | set: |
1606 | local->smps_mode = smps_mode; | 1647 | local->smps_mode = smps_mode; |
1607 | /* changed flag is auto-detected for this */ | 1648 | /* changed flag is auto-detected for this */ |
1608 | ieee80211_hw_config(local, 0); | 1649 | ieee80211_hw_config(local, 0); |
1650 | unlock: | ||
1651 | mutex_unlock(&local->iflist_mtx); | ||
1609 | } | 1652 | } |
1610 | 1653 | ||
1611 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | 1654 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) |
diff --git a/net/nfc/core.c b/net/nfc/core.c index ff749794bc5b..c9eacc1f145f 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c | |||
@@ -679,7 +679,7 @@ static void nfc_release(struct device *d) | |||
679 | 679 | ||
680 | if (dev->ops->check_presence) { | 680 | if (dev->ops->check_presence) { |
681 | del_timer_sync(&dev->check_pres_timer); | 681 | del_timer_sync(&dev->check_pres_timer); |
682 | destroy_workqueue(dev->check_pres_wq); | 682 | cancel_work_sync(&dev->check_pres_work); |
683 | } | 683 | } |
684 | 684 | ||
685 | nfc_genl_data_exit(&dev->genl_data); | 685 | nfc_genl_data_exit(&dev->genl_data); |
@@ -715,7 +715,7 @@ static void nfc_check_pres_timeout(unsigned long data) | |||
715 | { | 715 | { |
716 | struct nfc_dev *dev = (struct nfc_dev *)data; | 716 | struct nfc_dev *dev = (struct nfc_dev *)data; |
717 | 717 | ||
718 | queue_work(dev->check_pres_wq, &dev->check_pres_work); | 718 | queue_work(system_nrt_wq, &dev->check_pres_work); |
719 | } | 719 | } |
720 | 720 | ||
721 | struct class nfc_class = { | 721 | struct class nfc_class = { |
@@ -784,20 +784,11 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, | |||
784 | dev->targets_generation = 1; | 784 | dev->targets_generation = 1; |
785 | 785 | ||
786 | if (ops->check_presence) { | 786 | if (ops->check_presence) { |
787 | char name[32]; | ||
788 | init_timer(&dev->check_pres_timer); | 787 | init_timer(&dev->check_pres_timer); |
789 | dev->check_pres_timer.data = (unsigned long)dev; | 788 | dev->check_pres_timer.data = (unsigned long)dev; |
790 | dev->check_pres_timer.function = nfc_check_pres_timeout; | 789 | dev->check_pres_timer.function = nfc_check_pres_timeout; |
791 | 790 | ||
792 | INIT_WORK(&dev->check_pres_work, nfc_check_pres_work); | 791 | INIT_WORK(&dev->check_pres_work, nfc_check_pres_work); |
793 | snprintf(name, sizeof(name), "nfc%d_check_pres_wq", dev->idx); | ||
794 | dev->check_pres_wq = alloc_workqueue(name, WQ_NON_REENTRANT | | ||
795 | WQ_UNBOUND | | ||
796 | WQ_MEM_RECLAIM, 1); | ||
797 | if (dev->check_pres_wq == NULL) { | ||
798 | kfree(dev); | ||
799 | return NULL; | ||
800 | } | ||
801 | } | 792 | } |
802 | 793 | ||
803 | return dev; | 794 | return dev; |
diff --git a/net/nfc/hci/Makefile b/net/nfc/hci/Makefile index f9c44b2fb065..c5dbb6891b24 100644 --- a/net/nfc/hci/Makefile +++ b/net/nfc/hci/Makefile | |||
@@ -4,5 +4,5 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_NFC_HCI) += hci.o | 5 | obj-$(CONFIG_NFC_HCI) += hci.o |
6 | 6 | ||
7 | hci-y := core.o hcp.o command.o | 7 | hci-y := core.o hcp.o command.o llc.o llc_nop.o |
8 | hci-$(CONFIG_NFC_SHDLC) += shdlc.o | 8 | hci-$(CONFIG_NFC_SHDLC) += llc_shdlc.o |
diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 46362ef979db..71c6a7086b8f 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c | |||
@@ -28,10 +28,29 @@ | |||
28 | 28 | ||
29 | #include "hci.h" | 29 | #include "hci.h" |
30 | 30 | ||
31 | static void nfc_hci_execute_cb(struct nfc_hci_dev *hdev, int err, | 31 | static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, |
32 | struct sk_buff *skb, void *cb_data) | 32 | const u8 *param, size_t param_len, |
33 | data_exchange_cb_t cb, void *cb_context) | ||
33 | { | 34 | { |
34 | struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)cb_data; | 35 | pr_debug("exec cmd async through pipe=%d, cmd=%d, plen=%zd\n", pipe, |
36 | cmd, param_len); | ||
37 | |||
38 | /* TODO: Define hci cmd execution delay. Should it be the same | ||
39 | * for all commands? | ||
40 | */ | ||
41 | return nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_COMMAND, cmd, | ||
42 | param, param_len, cb, cb_context, 3000); | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * HCI command execution completion callback. | ||
47 | * err will be a standard linux error (may be converted from HCI response) | ||
48 | * skb contains the response data and must be disposed, or may be NULL if | ||
49 | * an error occured | ||
50 | */ | ||
51 | static void nfc_hci_execute_cb(void *context, struct sk_buff *skb, int err) | ||
52 | { | ||
53 | struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)context; | ||
35 | 54 | ||
36 | pr_debug("HCI Cmd completed with result=%d\n", err); | 55 | pr_debug("HCI Cmd completed with result=%d\n", err); |
37 | 56 | ||
@@ -55,7 +74,8 @@ static int nfc_hci_execute_cmd(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, | |||
55 | hcp_ew.exec_complete = false; | 74 | hcp_ew.exec_complete = false; |
56 | hcp_ew.result_skb = NULL; | 75 | hcp_ew.result_skb = NULL; |
57 | 76 | ||
58 | pr_debug("through pipe=%d, cmd=%d, plen=%zd\n", pipe, cmd, param_len); | 77 | pr_debug("exec cmd sync through pipe=%d, cmd=%d, plen=%zd\n", pipe, |
78 | cmd, param_len); | ||
59 | 79 | ||
60 | /* TODO: Define hci cmd execution delay. Should it be the same | 80 | /* TODO: Define hci cmd execution delay. Should it be the same |
61 | * for all commands? | 81 | * for all commands? |
@@ -133,6 +153,23 @@ int nfc_hci_send_cmd(struct nfc_hci_dev *hdev, u8 gate, u8 cmd, | |||
133 | } | 153 | } |
134 | EXPORT_SYMBOL(nfc_hci_send_cmd); | 154 | EXPORT_SYMBOL(nfc_hci_send_cmd); |
135 | 155 | ||
156 | int nfc_hci_send_cmd_async(struct nfc_hci_dev *hdev, u8 gate, u8 cmd, | ||
157 | const u8 *param, size_t param_len, | ||
158 | data_exchange_cb_t cb, void *cb_context) | ||
159 | { | ||
160 | u8 pipe; | ||
161 | |||
162 | pr_debug("\n"); | ||
163 | |||
164 | pipe = hdev->gate2pipe[gate]; | ||
165 | if (pipe == NFC_HCI_INVALID_PIPE) | ||
166 | return -EADDRNOTAVAIL; | ||
167 | |||
168 | return nfc_hci_execute_cmd_async(hdev, pipe, cmd, param, param_len, | ||
169 | cb, cb_context); | ||
170 | } | ||
171 | EXPORT_SYMBOL(nfc_hci_send_cmd_async); | ||
172 | |||
136 | int nfc_hci_set_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx, | 173 | int nfc_hci_set_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx, |
137 | const u8 *param, size_t param_len) | 174 | const u8 *param, size_t param_len) |
138 | { | 175 | { |
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 1ac7b3fac6c9..d378d93de62e 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include <net/nfc/nfc.h> | 27 | #include <net/nfc/nfc.h> |
28 | #include <net/nfc/hci.h> | 28 | #include <net/nfc/hci.h> |
29 | #include <net/nfc/llc.h> | ||
29 | 30 | ||
30 | #include "hci.h" | 31 | #include "hci.h" |
31 | 32 | ||
@@ -57,12 +58,11 @@ static void nfc_hci_msg_tx_work(struct work_struct *work) | |||
57 | if (hdev->cmd_pending_msg) { | 58 | if (hdev->cmd_pending_msg) { |
58 | if (timer_pending(&hdev->cmd_timer) == 0) { | 59 | if (timer_pending(&hdev->cmd_timer) == 0) { |
59 | if (hdev->cmd_pending_msg->cb) | 60 | if (hdev->cmd_pending_msg->cb) |
60 | hdev->cmd_pending_msg->cb(hdev, | 61 | hdev->cmd_pending_msg->cb(hdev-> |
61 | -ETIME, | ||
62 | NULL, | ||
63 | hdev-> | ||
64 | cmd_pending_msg-> | 62 | cmd_pending_msg-> |
65 | cb_context); | 63 | cb_context, |
64 | NULL, | ||
65 | -ETIME); | ||
66 | kfree(hdev->cmd_pending_msg); | 66 | kfree(hdev->cmd_pending_msg); |
67 | hdev->cmd_pending_msg = NULL; | 67 | hdev->cmd_pending_msg = NULL; |
68 | } else | 68 | } else |
@@ -78,12 +78,12 @@ next_msg: | |||
78 | 78 | ||
79 | pr_debug("msg_tx_queue has a cmd to send\n"); | 79 | pr_debug("msg_tx_queue has a cmd to send\n"); |
80 | while ((skb = skb_dequeue(&msg->msg_frags)) != NULL) { | 80 | while ((skb = skb_dequeue(&msg->msg_frags)) != NULL) { |
81 | r = hdev->ops->xmit(hdev, skb); | 81 | r = nfc_llc_xmit_from_hci(hdev->llc, skb); |
82 | if (r < 0) { | 82 | if (r < 0) { |
83 | kfree_skb(skb); | 83 | kfree_skb(skb); |
84 | skb_queue_purge(&msg->msg_frags); | 84 | skb_queue_purge(&msg->msg_frags); |
85 | if (msg->cb) | 85 | if (msg->cb) |
86 | msg->cb(hdev, r, NULL, msg->cb_context); | 86 | msg->cb(msg->cb_context, NULL, r); |
87 | kfree(msg); | 87 | kfree(msg); |
88 | break; | 88 | break; |
89 | } | 89 | } |
@@ -133,15 +133,15 @@ static void __nfc_hci_cmd_completion(struct nfc_hci_dev *hdev, int err, | |||
133 | del_timer_sync(&hdev->cmd_timer); | 133 | del_timer_sync(&hdev->cmd_timer); |
134 | 134 | ||
135 | if (hdev->cmd_pending_msg->cb) | 135 | if (hdev->cmd_pending_msg->cb) |
136 | hdev->cmd_pending_msg->cb(hdev, err, skb, | 136 | hdev->cmd_pending_msg->cb(hdev->cmd_pending_msg->cb_context, |
137 | hdev->cmd_pending_msg->cb_context); | 137 | skb, err); |
138 | else | 138 | else |
139 | kfree_skb(skb); | 139 | kfree_skb(skb); |
140 | 140 | ||
141 | kfree(hdev->cmd_pending_msg); | 141 | kfree(hdev->cmd_pending_msg); |
142 | hdev->cmd_pending_msg = NULL; | 142 | hdev->cmd_pending_msg = NULL; |
143 | 143 | ||
144 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); | 144 | queue_work(system_nrt_wq, &hdev->msg_tx_work); |
145 | } | 145 | } |
146 | 146 | ||
147 | void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, | 147 | void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, |
@@ -326,7 +326,7 @@ static void nfc_hci_cmd_timeout(unsigned long data) | |||
326 | { | 326 | { |
327 | struct nfc_hci_dev *hdev = (struct nfc_hci_dev *)data; | 327 | struct nfc_hci_dev *hdev = (struct nfc_hci_dev *)data; |
328 | 328 | ||
329 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); | 329 | queue_work(system_nrt_wq, &hdev->msg_tx_work); |
330 | } | 330 | } |
331 | 331 | ||
332 | static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, | 332 | static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, |
@@ -398,8 +398,7 @@ disconnect_all: | |||
398 | nfc_hci_disconnect_all_gates(hdev); | 398 | nfc_hci_disconnect_all_gates(hdev); |
399 | 399 | ||
400 | exit: | 400 | exit: |
401 | if (skb) | 401 | kfree_skb(skb); |
402 | kfree_skb(skb); | ||
403 | 402 | ||
404 | return r; | 403 | return r; |
405 | } | 404 | } |
@@ -470,29 +469,38 @@ static int hci_dev_up(struct nfc_dev *nfc_dev) | |||
470 | return r; | 469 | return r; |
471 | } | 470 | } |
472 | 471 | ||
472 | r = nfc_llc_start(hdev->llc); | ||
473 | if (r < 0) | ||
474 | goto exit_close; | ||
475 | |||
473 | r = hci_dev_session_init(hdev); | 476 | r = hci_dev_session_init(hdev); |
474 | if (r < 0) | 477 | if (r < 0) |
475 | goto exit; | 478 | goto exit_llc; |
476 | 479 | ||
477 | r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, | 480 | r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, |
478 | NFC_HCI_EVT_END_OPERATION, NULL, 0); | 481 | NFC_HCI_EVT_END_OPERATION, NULL, 0); |
479 | if (r < 0) | 482 | if (r < 0) |
480 | goto exit; | 483 | goto exit_llc; |
481 | 484 | ||
482 | if (hdev->ops->hci_ready) { | 485 | if (hdev->ops->hci_ready) { |
483 | r = hdev->ops->hci_ready(hdev); | 486 | r = hdev->ops->hci_ready(hdev); |
484 | if (r < 0) | 487 | if (r < 0) |
485 | goto exit; | 488 | goto exit_llc; |
486 | } | 489 | } |
487 | 490 | ||
488 | r = hci_dev_version(hdev); | 491 | r = hci_dev_version(hdev); |
489 | if (r < 0) | 492 | if (r < 0) |
490 | goto exit; | 493 | goto exit_llc; |
494 | |||
495 | return 0; | ||
496 | |||
497 | exit_llc: | ||
498 | nfc_llc_stop(hdev->llc); | ||
499 | |||
500 | exit_close: | ||
501 | if (hdev->ops->close) | ||
502 | hdev->ops->close(hdev); | ||
491 | 503 | ||
492 | exit: | ||
493 | if (r < 0) | ||
494 | if (hdev->ops->close) | ||
495 | hdev->ops->close(hdev); | ||
496 | return r; | 504 | return r; |
497 | } | 505 | } |
498 | 506 | ||
@@ -500,6 +508,8 @@ static int hci_dev_down(struct nfc_dev *nfc_dev) | |||
500 | { | 508 | { |
501 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); | 509 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); |
502 | 510 | ||
511 | nfc_llc_stop(hdev->llc); | ||
512 | |||
503 | if (hdev->ops->close) | 513 | if (hdev->ops->close) |
504 | hdev->ops->close(hdev); | 514 | hdev->ops->close(hdev); |
505 | 515 | ||
@@ -539,13 +549,37 @@ static void hci_deactivate_target(struct nfc_dev *nfc_dev, | |||
539 | { | 549 | { |
540 | } | 550 | } |
541 | 551 | ||
552 | #define HCI_CB_TYPE_TRANSCEIVE 1 | ||
553 | |||
554 | static void hci_transceive_cb(void *context, struct sk_buff *skb, int err) | ||
555 | { | ||
556 | struct nfc_hci_dev *hdev = context; | ||
557 | |||
558 | switch (hdev->async_cb_type) { | ||
559 | case HCI_CB_TYPE_TRANSCEIVE: | ||
560 | /* | ||
561 | * TODO: Check RF Error indicator to make sure data is valid. | ||
562 | * It seems that HCI cmd can complete without error, but data | ||
563 | * can be invalid if an RF error occured? Ignore for now. | ||
564 | */ | ||
565 | if (err == 0) | ||
566 | skb_trim(skb, skb->len - 1); /* RF Err ind */ | ||
567 | |||
568 | hdev->async_cb(hdev->async_cb_context, skb, err); | ||
569 | break; | ||
570 | default: | ||
571 | if (err == 0) | ||
572 | kfree_skb(skb); | ||
573 | break; | ||
574 | } | ||
575 | } | ||
576 | |||
542 | static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, | 577 | static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, |
543 | struct sk_buff *skb, data_exchange_cb_t cb, | 578 | struct sk_buff *skb, data_exchange_cb_t cb, |
544 | void *cb_context) | 579 | void *cb_context) |
545 | { | 580 | { |
546 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); | 581 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); |
547 | int r; | 582 | int r; |
548 | struct sk_buff *res_skb = NULL; | ||
549 | 583 | ||
550 | pr_debug("target_idx=%d\n", target->idx); | 584 | pr_debug("target_idx=%d\n", target->idx); |
551 | 585 | ||
@@ -553,40 +587,37 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, | |||
553 | case NFC_HCI_RF_READER_A_GATE: | 587 | case NFC_HCI_RF_READER_A_GATE: |
554 | case NFC_HCI_RF_READER_B_GATE: | 588 | case NFC_HCI_RF_READER_B_GATE: |
555 | if (hdev->ops->data_exchange) { | 589 | if (hdev->ops->data_exchange) { |
556 | r = hdev->ops->data_exchange(hdev, target, skb, | 590 | r = hdev->ops->data_exchange(hdev, target, skb, cb, |
557 | &res_skb); | 591 | cb_context); |
558 | if (r <= 0) /* handled */ | 592 | if (r <= 0) /* handled */ |
559 | break; | 593 | break; |
560 | } | 594 | } |
561 | 595 | ||
562 | *skb_push(skb, 1) = 0; /* CTR, see spec:10.2.2.1 */ | 596 | *skb_push(skb, 1) = 0; /* CTR, see spec:10.2.2.1 */ |
563 | r = nfc_hci_send_cmd(hdev, target->hci_reader_gate, | 597 | |
564 | NFC_HCI_WR_XCHG_DATA, | 598 | hdev->async_cb_type = HCI_CB_TYPE_TRANSCEIVE; |
565 | skb->data, skb->len, &res_skb); | 599 | hdev->async_cb = cb; |
566 | /* | 600 | hdev->async_cb_context = cb_context; |
567 | * TODO: Check RF Error indicator to make sure data is valid. | 601 | |
568 | * It seems that HCI cmd can complete without error, but data | 602 | r = nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, |
569 | * can be invalid if an RF error occured? Ignore for now. | 603 | NFC_HCI_WR_XCHG_DATA, skb->data, |
570 | */ | 604 | skb->len, hci_transceive_cb, hdev); |
571 | if (r == 0) | ||
572 | skb_trim(res_skb, res_skb->len - 1); /* RF Err ind */ | ||
573 | break; | 605 | break; |
574 | default: | 606 | default: |
575 | if (hdev->ops->data_exchange) { | 607 | if (hdev->ops->data_exchange) { |
576 | r = hdev->ops->data_exchange(hdev, target, skb, | 608 | r = hdev->ops->data_exchange(hdev, target, skb, cb, |
577 | &res_skb); | 609 | cb_context); |
578 | if (r == 1) | 610 | if (r == 1) |
579 | r = -ENOTSUPP; | 611 | r = -ENOTSUPP; |
580 | } | 612 | } |
581 | else | 613 | else |
582 | r = -ENOTSUPP; | 614 | r = -ENOTSUPP; |
615 | break; | ||
583 | } | 616 | } |
584 | 617 | ||
585 | kfree_skb(skb); | 618 | kfree_skb(skb); |
586 | 619 | ||
587 | cb(cb_context, res_skb, r); | 620 | return r; |
588 | |||
589 | return 0; | ||
590 | } | 621 | } |
591 | 622 | ||
592 | static int hci_check_presence(struct nfc_dev *nfc_dev, | 623 | static int hci_check_presence(struct nfc_dev *nfc_dev, |
@@ -600,6 +631,93 @@ static int hci_check_presence(struct nfc_dev *nfc_dev, | |||
600 | return 0; | 631 | return 0; |
601 | } | 632 | } |
602 | 633 | ||
634 | static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) | ||
635 | { | ||
636 | mutex_lock(&hdev->msg_tx_mutex); | ||
637 | |||
638 | if (hdev->cmd_pending_msg == NULL) { | ||
639 | nfc_driver_failure(hdev->ndev, err); | ||
640 | goto exit; | ||
641 | } | ||
642 | |||
643 | __nfc_hci_cmd_completion(hdev, err, NULL); | ||
644 | |||
645 | exit: | ||
646 | mutex_unlock(&hdev->msg_tx_mutex); | ||
647 | } | ||
648 | |||
649 | static void nfc_hci_llc_failure(struct nfc_hci_dev *hdev, int err) | ||
650 | { | ||
651 | nfc_hci_failure(hdev, err); | ||
652 | } | ||
653 | |||
654 | static void nfc_hci_recv_from_llc(struct nfc_hci_dev *hdev, struct sk_buff *skb) | ||
655 | { | ||
656 | struct hcp_packet *packet; | ||
657 | u8 type; | ||
658 | u8 instruction; | ||
659 | struct sk_buff *hcp_skb; | ||
660 | u8 pipe; | ||
661 | struct sk_buff *frag_skb; | ||
662 | int msg_len; | ||
663 | |||
664 | packet = (struct hcp_packet *)skb->data; | ||
665 | if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { | ||
666 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | ||
667 | return; | ||
668 | } | ||
669 | |||
670 | /* it's the last fragment. Does it need re-aggregation? */ | ||
671 | if (skb_queue_len(&hdev->rx_hcp_frags)) { | ||
672 | pipe = packet->header & NFC_HCI_FRAGMENT; | ||
673 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | ||
674 | |||
675 | msg_len = 0; | ||
676 | skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { | ||
677 | msg_len += (frag_skb->len - | ||
678 | NFC_HCI_HCP_PACKET_HEADER_LEN); | ||
679 | } | ||
680 | |||
681 | hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + | ||
682 | msg_len, GFP_KERNEL); | ||
683 | if (hcp_skb == NULL) { | ||
684 | nfc_hci_failure(hdev, -ENOMEM); | ||
685 | return; | ||
686 | } | ||
687 | |||
688 | *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; | ||
689 | |||
690 | skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { | ||
691 | msg_len = frag_skb->len - NFC_HCI_HCP_PACKET_HEADER_LEN; | ||
692 | memcpy(skb_put(hcp_skb, msg_len), | ||
693 | frag_skb->data + NFC_HCI_HCP_PACKET_HEADER_LEN, | ||
694 | msg_len); | ||
695 | } | ||
696 | |||
697 | skb_queue_purge(&hdev->rx_hcp_frags); | ||
698 | } else { | ||
699 | packet->header &= NFC_HCI_FRAGMENT; | ||
700 | hcp_skb = skb; | ||
701 | } | ||
702 | |||
703 | /* if this is a response, dispatch immediately to | ||
704 | * unblock waiting cmd context. Otherwise, enqueue to dispatch | ||
705 | * in separate context where handler can also execute command. | ||
706 | */ | ||
707 | packet = (struct hcp_packet *)hcp_skb->data; | ||
708 | type = HCP_MSG_GET_TYPE(packet->message.header); | ||
709 | if (type == NFC_HCI_HCP_RESPONSE) { | ||
710 | pipe = packet->header; | ||
711 | instruction = HCP_MSG_GET_CMD(packet->message.header); | ||
712 | skb_pull(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN + | ||
713 | NFC_HCI_HCP_MESSAGE_HEADER_LEN); | ||
714 | nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, hcp_skb); | ||
715 | } else { | ||
716 | skb_queue_tail(&hdev->msg_rx_queue, hcp_skb); | ||
717 | queue_work(system_nrt_wq, &hdev->msg_rx_work); | ||
718 | } | ||
719 | } | ||
720 | |||
603 | static struct nfc_ops hci_nfc_ops = { | 721 | static struct nfc_ops hci_nfc_ops = { |
604 | .dev_up = hci_dev_up, | 722 | .dev_up = hci_dev_up, |
605 | .dev_down = hci_dev_down, | 723 | .dev_down = hci_dev_down, |
@@ -614,6 +732,7 @@ static struct nfc_ops hci_nfc_ops = { | |||
614 | struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, | 732 | struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, |
615 | struct nfc_hci_init_data *init_data, | 733 | struct nfc_hci_init_data *init_data, |
616 | u32 protocols, | 734 | u32 protocols, |
735 | const char *llc_name, | ||
617 | int tx_headroom, | 736 | int tx_headroom, |
618 | int tx_tailroom, | 737 | int tx_tailroom, |
619 | int max_link_payload) | 738 | int max_link_payload) |
@@ -630,10 +749,19 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, | |||
630 | if (hdev == NULL) | 749 | if (hdev == NULL) |
631 | return NULL; | 750 | return NULL; |
632 | 751 | ||
752 | hdev->llc = nfc_llc_allocate(llc_name, hdev, ops->xmit, | ||
753 | nfc_hci_recv_from_llc, tx_headroom, | ||
754 | tx_tailroom, nfc_hci_llc_failure); | ||
755 | if (hdev->llc == NULL) { | ||
756 | kfree(hdev); | ||
757 | return NULL; | ||
758 | } | ||
759 | |||
633 | hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, | 760 | hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, |
634 | tx_headroom + HCI_CMDS_HEADROOM, | 761 | tx_headroom + HCI_CMDS_HEADROOM, |
635 | tx_tailroom); | 762 | tx_tailroom); |
636 | if (!hdev->ndev) { | 763 | if (!hdev->ndev) { |
764 | nfc_llc_free(hdev->llc); | ||
637 | kfree(hdev); | 765 | kfree(hdev); |
638 | return NULL; | 766 | return NULL; |
639 | } | 767 | } |
@@ -653,29 +781,18 @@ EXPORT_SYMBOL(nfc_hci_allocate_device); | |||
653 | void nfc_hci_free_device(struct nfc_hci_dev *hdev) | 781 | void nfc_hci_free_device(struct nfc_hci_dev *hdev) |
654 | { | 782 | { |
655 | nfc_free_device(hdev->ndev); | 783 | nfc_free_device(hdev->ndev); |
784 | nfc_llc_free(hdev->llc); | ||
656 | kfree(hdev); | 785 | kfree(hdev); |
657 | } | 786 | } |
658 | EXPORT_SYMBOL(nfc_hci_free_device); | 787 | EXPORT_SYMBOL(nfc_hci_free_device); |
659 | 788 | ||
660 | int nfc_hci_register_device(struct nfc_hci_dev *hdev) | 789 | int nfc_hci_register_device(struct nfc_hci_dev *hdev) |
661 | { | 790 | { |
662 | struct device *dev = &hdev->ndev->dev; | ||
663 | const char *devname = dev_name(dev); | ||
664 | char name[32]; | ||
665 | int r = 0; | ||
666 | |||
667 | mutex_init(&hdev->msg_tx_mutex); | 791 | mutex_init(&hdev->msg_tx_mutex); |
668 | 792 | ||
669 | INIT_LIST_HEAD(&hdev->msg_tx_queue); | 793 | INIT_LIST_HEAD(&hdev->msg_tx_queue); |
670 | 794 | ||
671 | INIT_WORK(&hdev->msg_tx_work, nfc_hci_msg_tx_work); | 795 | INIT_WORK(&hdev->msg_tx_work, nfc_hci_msg_tx_work); |
672 | snprintf(name, sizeof(name), "%s_hci_msg_tx_wq", devname); | ||
673 | hdev->msg_tx_wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND | | ||
674 | WQ_MEM_RECLAIM, 1); | ||
675 | if (hdev->msg_tx_wq == NULL) { | ||
676 | r = -ENOMEM; | ||
677 | goto exit; | ||
678 | } | ||
679 | 796 | ||
680 | init_timer(&hdev->cmd_timer); | 797 | init_timer(&hdev->cmd_timer); |
681 | hdev->cmd_timer.data = (unsigned long)hdev; | 798 | hdev->cmd_timer.data = (unsigned long)hdev; |
@@ -684,27 +801,10 @@ int nfc_hci_register_device(struct nfc_hci_dev *hdev) | |||
684 | skb_queue_head_init(&hdev->rx_hcp_frags); | 801 | skb_queue_head_init(&hdev->rx_hcp_frags); |
685 | 802 | ||
686 | INIT_WORK(&hdev->msg_rx_work, nfc_hci_msg_rx_work); | 803 | INIT_WORK(&hdev->msg_rx_work, nfc_hci_msg_rx_work); |
687 | snprintf(name, sizeof(name), "%s_hci_msg_rx_wq", devname); | ||
688 | hdev->msg_rx_wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND | | ||
689 | WQ_MEM_RECLAIM, 1); | ||
690 | if (hdev->msg_rx_wq == NULL) { | ||
691 | r = -ENOMEM; | ||
692 | goto exit; | ||
693 | } | ||
694 | 804 | ||
695 | skb_queue_head_init(&hdev->msg_rx_queue); | 805 | skb_queue_head_init(&hdev->msg_rx_queue); |
696 | 806 | ||
697 | r = nfc_register_device(hdev->ndev); | 807 | return nfc_register_device(hdev->ndev); |
698 | |||
699 | exit: | ||
700 | if (r < 0) { | ||
701 | if (hdev->msg_tx_wq) | ||
702 | destroy_workqueue(hdev->msg_tx_wq); | ||
703 | if (hdev->msg_rx_wq) | ||
704 | destroy_workqueue(hdev->msg_rx_wq); | ||
705 | } | ||
706 | |||
707 | return r; | ||
708 | } | 808 | } |
709 | EXPORT_SYMBOL(nfc_hci_register_device); | 809 | EXPORT_SYMBOL(nfc_hci_register_device); |
710 | 810 | ||
@@ -725,9 +825,8 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev) | |||
725 | 825 | ||
726 | nfc_unregister_device(hdev->ndev); | 826 | nfc_unregister_device(hdev->ndev); |
727 | 827 | ||
728 | destroy_workqueue(hdev->msg_tx_wq); | 828 | cancel_work_sync(&hdev->msg_tx_work); |
729 | 829 | cancel_work_sync(&hdev->msg_rx_work); | |
730 | destroy_workqueue(hdev->msg_rx_wq); | ||
731 | } | 830 | } |
732 | EXPORT_SYMBOL(nfc_hci_unregister_device); | 831 | EXPORT_SYMBOL(nfc_hci_unregister_device); |
733 | 832 | ||
@@ -743,93 +842,30 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev) | |||
743 | } | 842 | } |
744 | EXPORT_SYMBOL(nfc_hci_get_clientdata); | 843 | EXPORT_SYMBOL(nfc_hci_get_clientdata); |
745 | 844 | ||
746 | static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) | ||
747 | { | ||
748 | mutex_lock(&hdev->msg_tx_mutex); | ||
749 | |||
750 | if (hdev->cmd_pending_msg == NULL) { | ||
751 | nfc_driver_failure(hdev->ndev, err); | ||
752 | goto exit; | ||
753 | } | ||
754 | |||
755 | __nfc_hci_cmd_completion(hdev, err, NULL); | ||
756 | |||
757 | exit: | ||
758 | mutex_unlock(&hdev->msg_tx_mutex); | ||
759 | } | ||
760 | |||
761 | void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) | 845 | void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) |
762 | { | 846 | { |
763 | nfc_hci_failure(hdev, err); | 847 | nfc_hci_failure(hdev, err); |
764 | } | 848 | } |
765 | EXPORT_SYMBOL(nfc_hci_driver_failure); | 849 | EXPORT_SYMBOL(nfc_hci_driver_failure); |
766 | 850 | ||
767 | void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) | 851 | void inline nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) |
768 | { | 852 | { |
769 | struct hcp_packet *packet; | 853 | nfc_llc_rcv_from_drv(hdev->llc, skb); |
770 | u8 type; | 854 | } |
771 | u8 instruction; | 855 | EXPORT_SYMBOL(nfc_hci_recv_frame); |
772 | struct sk_buff *hcp_skb; | ||
773 | u8 pipe; | ||
774 | struct sk_buff *frag_skb; | ||
775 | int msg_len; | ||
776 | |||
777 | packet = (struct hcp_packet *)skb->data; | ||
778 | if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { | ||
779 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | ||
780 | return; | ||
781 | } | ||
782 | |||
783 | /* it's the last fragment. Does it need re-aggregation? */ | ||
784 | if (skb_queue_len(&hdev->rx_hcp_frags)) { | ||
785 | pipe = packet->header & NFC_HCI_FRAGMENT; | ||
786 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | ||
787 | |||
788 | msg_len = 0; | ||
789 | skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { | ||
790 | msg_len += (frag_skb->len - | ||
791 | NFC_HCI_HCP_PACKET_HEADER_LEN); | ||
792 | } | ||
793 | |||
794 | hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + | ||
795 | msg_len, GFP_KERNEL); | ||
796 | if (hcp_skb == NULL) { | ||
797 | nfc_hci_failure(hdev, -ENOMEM); | ||
798 | return; | ||
799 | } | ||
800 | |||
801 | *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; | ||
802 | |||
803 | skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { | ||
804 | msg_len = frag_skb->len - NFC_HCI_HCP_PACKET_HEADER_LEN; | ||
805 | memcpy(skb_put(hcp_skb, msg_len), | ||
806 | frag_skb->data + NFC_HCI_HCP_PACKET_HEADER_LEN, | ||
807 | msg_len); | ||
808 | } | ||
809 | 856 | ||
810 | skb_queue_purge(&hdev->rx_hcp_frags); | 857 | static int __init nfc_hci_init(void) |
811 | } else { | 858 | { |
812 | packet->header &= NFC_HCI_FRAGMENT; | 859 | return nfc_llc_init(); |
813 | hcp_skb = skb; | 860 | } |
814 | } | ||
815 | 861 | ||
816 | /* if this is a response, dispatch immediately to | 862 | static void __exit nfc_hci_exit(void) |
817 | * unblock waiting cmd context. Otherwise, enqueue to dispatch | 863 | { |
818 | * in separate context where handler can also execute command. | 864 | nfc_llc_exit(); |
819 | */ | ||
820 | packet = (struct hcp_packet *)hcp_skb->data; | ||
821 | type = HCP_MSG_GET_TYPE(packet->message.header); | ||
822 | if (type == NFC_HCI_HCP_RESPONSE) { | ||
823 | pipe = packet->header; | ||
824 | instruction = HCP_MSG_GET_CMD(packet->message.header); | ||
825 | skb_pull(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN + | ||
826 | NFC_HCI_HCP_MESSAGE_HEADER_LEN); | ||
827 | nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, hcp_skb); | ||
828 | } else { | ||
829 | skb_queue_tail(&hdev->msg_rx_queue, hcp_skb); | ||
830 | queue_work(hdev->msg_rx_wq, &hdev->msg_rx_work); | ||
831 | } | ||
832 | } | 865 | } |
833 | EXPORT_SYMBOL(nfc_hci_recv_frame); | 866 | |
867 | subsys_initcall(nfc_hci_init); | ||
868 | module_exit(nfc_hci_exit); | ||
834 | 869 | ||
835 | MODULE_LICENSE("GPL"); | 870 | MODULE_LICENSE("GPL"); |
871 | MODULE_DESCRIPTION("NFC HCI Core"); | ||
diff --git a/net/nfc/hci/hci.h b/net/nfc/hci/hci.h index fa9a21e92239..b274d12c18ac 100644 --- a/net/nfc/hci/hci.h +++ b/net/nfc/hci/hci.h | |||
@@ -20,6 +20,8 @@ | |||
20 | #ifndef __LOCAL_HCI_H | 20 | #ifndef __LOCAL_HCI_H |
21 | #define __LOCAL_HCI_H | 21 | #define __LOCAL_HCI_H |
22 | 22 | ||
23 | #include <net/nfc/hci.h> | ||
24 | |||
23 | struct gate_pipe_map { | 25 | struct gate_pipe_map { |
24 | u8 gate; | 26 | u8 gate; |
25 | u8 pipe; | 27 | u8 pipe; |
@@ -35,15 +37,6 @@ struct hcp_packet { | |||
35 | struct hcp_message message; | 37 | struct hcp_message message; |
36 | } __packed; | 38 | } __packed; |
37 | 39 | ||
38 | /* | ||
39 | * HCI command execution completion callback. | ||
40 | * result will be a standard linux error (may be converted from HCI response) | ||
41 | * skb contains the response data and must be disposed, or may be NULL if | ||
42 | * an error occured | ||
43 | */ | ||
44 | typedef void (*hci_cmd_cb_t) (struct nfc_hci_dev *hdev, int result, | ||
45 | struct sk_buff *skb, void *cb_data); | ||
46 | |||
47 | struct hcp_exec_waiter { | 40 | struct hcp_exec_waiter { |
48 | wait_queue_head_t *wq; | 41 | wait_queue_head_t *wq; |
49 | bool exec_complete; | 42 | bool exec_complete; |
@@ -55,7 +48,7 @@ struct hci_msg { | |||
55 | struct list_head msg_l; | 48 | struct list_head msg_l; |
56 | struct sk_buff_head msg_frags; | 49 | struct sk_buff_head msg_frags; |
57 | bool wait_response; | 50 | bool wait_response; |
58 | hci_cmd_cb_t cb; | 51 | data_exchange_cb_t cb; |
59 | void *cb_context; | 52 | void *cb_context; |
60 | unsigned long completion_delay; | 53 | unsigned long completion_delay; |
61 | }; | 54 | }; |
@@ -83,7 +76,7 @@ struct hci_create_pipe_resp { | |||
83 | int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, | 76 | int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, |
84 | u8 type, u8 instruction, | 77 | u8 type, u8 instruction, |
85 | const u8 *payload, size_t payload_len, | 78 | const u8 *payload, size_t payload_len, |
86 | hci_cmd_cb_t cb, void *cb_data, | 79 | data_exchange_cb_t cb, void *cb_context, |
87 | unsigned long completion_delay); | 80 | unsigned long completion_delay); |
88 | 81 | ||
89 | u8 nfc_hci_pipe2gate(struct nfc_hci_dev *hdev, u8 pipe); | 82 | u8 nfc_hci_pipe2gate(struct nfc_hci_dev *hdev, u8 pipe); |
diff --git a/net/nfc/hci/hcp.c b/net/nfc/hci/hcp.c index f4dad1a89740..208eedd07ee3 100644 --- a/net/nfc/hci/hcp.c +++ b/net/nfc/hci/hcp.c | |||
@@ -35,7 +35,7 @@ | |||
35 | int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, | 35 | int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, |
36 | u8 type, u8 instruction, | 36 | u8 type, u8 instruction, |
37 | const u8 *payload, size_t payload_len, | 37 | const u8 *payload, size_t payload_len, |
38 | hci_cmd_cb_t cb, void *cb_data, | 38 | data_exchange_cb_t cb, void *cb_context, |
39 | unsigned long completion_delay) | 39 | unsigned long completion_delay) |
40 | { | 40 | { |
41 | struct nfc_dev *ndev = hdev->ndev; | 41 | struct nfc_dev *ndev = hdev->ndev; |
@@ -52,7 +52,7 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, | |||
52 | skb_queue_head_init(&cmd->msg_frags); | 52 | skb_queue_head_init(&cmd->msg_frags); |
53 | cmd->wait_response = (type == NFC_HCI_HCP_COMMAND) ? true : false; | 53 | cmd->wait_response = (type == NFC_HCI_HCP_COMMAND) ? true : false; |
54 | cmd->cb = cb; | 54 | cmd->cb = cb; |
55 | cmd->cb_context = cb_data; | 55 | cmd->cb_context = cb_context; |
56 | cmd->completion_delay = completion_delay; | 56 | cmd->completion_delay = completion_delay; |
57 | 57 | ||
58 | hci_len = payload_len + 1; | 58 | hci_len = payload_len + 1; |
@@ -108,7 +108,7 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, | |||
108 | list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue); | 108 | list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue); |
109 | mutex_unlock(&hdev->msg_tx_mutex); | 109 | mutex_unlock(&hdev->msg_tx_mutex); |
110 | 110 | ||
111 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); | 111 | queue_work(system_nrt_wq, &hdev->msg_tx_work); |
112 | 112 | ||
113 | return 0; | 113 | return 0; |
114 | 114 | ||
diff --git a/net/nfc/hci/llc.c b/net/nfc/hci/llc.c new file mode 100644 index 000000000000..ae1205ded87f --- /dev/null +++ b/net/nfc/hci/llc.c | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * Link Layer Control manager | ||
3 | * | ||
4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <net/nfc/llc.h> | ||
22 | |||
23 | #include "llc.h" | ||
24 | |||
25 | static struct list_head llc_engines; | ||
26 | |||
27 | int nfc_llc_init(void) | ||
28 | { | ||
29 | int r; | ||
30 | |||
31 | INIT_LIST_HEAD(&llc_engines); | ||
32 | |||
33 | r = nfc_llc_nop_register(); | ||
34 | if (r) | ||
35 | goto exit; | ||
36 | |||
37 | r = nfc_llc_shdlc_register(); | ||
38 | if (r) | ||
39 | goto exit; | ||
40 | |||
41 | return 0; | ||
42 | |||
43 | exit: | ||
44 | nfc_llc_exit(); | ||
45 | return r; | ||
46 | } | ||
47 | |||
48 | void nfc_llc_exit(void) | ||
49 | { | ||
50 | struct nfc_llc_engine *llc_engine, *n; | ||
51 | |||
52 | list_for_each_entry_safe(llc_engine, n, &llc_engines, entry) { | ||
53 | list_del(&llc_engine->entry); | ||
54 | kfree(llc_engine->name); | ||
55 | kfree(llc_engine); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | int nfc_llc_register(const char *name, struct nfc_llc_ops *ops) | ||
60 | { | ||
61 | struct nfc_llc_engine *llc_engine; | ||
62 | |||
63 | llc_engine = kzalloc(sizeof(struct nfc_llc_engine), GFP_KERNEL); | ||
64 | if (llc_engine == NULL) | ||
65 | return -ENOMEM; | ||
66 | |||
67 | llc_engine->name = kstrdup(name, GFP_KERNEL); | ||
68 | if (llc_engine->name == NULL) { | ||
69 | kfree(llc_engine); | ||
70 | return -ENOMEM; | ||
71 | } | ||
72 | llc_engine->ops = ops; | ||
73 | |||
74 | INIT_LIST_HEAD(&llc_engine->entry); | ||
75 | list_add_tail (&llc_engine->entry, &llc_engines); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static struct nfc_llc_engine *nfc_llc_name_to_engine(const char *name) | ||
81 | { | ||
82 | struct nfc_llc_engine *llc_engine; | ||
83 | |||
84 | list_for_each_entry(llc_engine, &llc_engines, entry) { | ||
85 | if (strcmp(llc_engine->name, name) == 0) | ||
86 | return llc_engine; | ||
87 | } | ||
88 | |||
89 | return NULL; | ||
90 | } | ||
91 | |||
92 | void nfc_llc_unregister(const char *name) | ||
93 | { | ||
94 | struct nfc_llc_engine *llc_engine; | ||
95 | |||
96 | llc_engine = nfc_llc_name_to_engine(name); | ||
97 | if (llc_engine == NULL) | ||
98 | return; | ||
99 | |||
100 | list_del(&llc_engine->entry); | ||
101 | kfree(llc_engine->name); | ||
102 | kfree(llc_engine); | ||
103 | } | ||
104 | |||
105 | struct nfc_llc *nfc_llc_allocate(const char *name, struct nfc_hci_dev *hdev, | ||
106 | xmit_to_drv_t xmit_to_drv, | ||
107 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
108 | int tx_tailroom, llc_failure_t llc_failure) | ||
109 | { | ||
110 | struct nfc_llc_engine *llc_engine; | ||
111 | struct nfc_llc *llc; | ||
112 | |||
113 | llc_engine = nfc_llc_name_to_engine(name); | ||
114 | if (llc_engine == NULL) | ||
115 | return NULL; | ||
116 | |||
117 | llc = kzalloc(sizeof(struct nfc_llc), GFP_KERNEL); | ||
118 | if (llc == NULL) | ||
119 | return NULL; | ||
120 | |||
121 | llc->data = llc_engine->ops->init(hdev, xmit_to_drv, rcv_to_hci, | ||
122 | tx_headroom, tx_tailroom, | ||
123 | &llc->rx_headroom, &llc->rx_tailroom, | ||
124 | llc_failure); | ||
125 | if (llc->data == NULL) { | ||
126 | kfree(llc); | ||
127 | return NULL; | ||
128 | } | ||
129 | llc->ops = llc_engine->ops; | ||
130 | |||
131 | return llc; | ||
132 | } | ||
133 | |||
134 | void nfc_llc_free(struct nfc_llc *llc) | ||
135 | { | ||
136 | llc->ops->deinit(llc); | ||
137 | kfree(llc); | ||
138 | } | ||
139 | |||
140 | inline void nfc_llc_get_rx_head_tail_room(struct nfc_llc *llc, int *rx_headroom, | ||
141 | int *rx_tailroom) | ||
142 | { | ||
143 | *rx_headroom = llc->rx_headroom; | ||
144 | *rx_tailroom = llc->rx_tailroom; | ||
145 | } | ||
146 | |||
147 | inline int nfc_llc_start(struct nfc_llc *llc) | ||
148 | { | ||
149 | return llc->ops->start(llc); | ||
150 | } | ||
151 | |||
152 | inline int nfc_llc_stop(struct nfc_llc *llc) | ||
153 | { | ||
154 | return llc->ops->stop(llc); | ||
155 | } | ||
156 | |||
157 | inline void nfc_llc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb) | ||
158 | { | ||
159 | llc->ops->rcv_from_drv(llc, skb); | ||
160 | } | ||
161 | |||
162 | inline int nfc_llc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb) | ||
163 | { | ||
164 | return llc->ops->xmit_from_hci(llc, skb); | ||
165 | } | ||
166 | |||
167 | inline void *nfc_llc_get_data(struct nfc_llc *llc) | ||
168 | { | ||
169 | return llc->data; | ||
170 | } | ||
diff --git a/net/nfc/hci/llc.h b/net/nfc/hci/llc.h new file mode 100644 index 000000000000..7be0b7f3ceb6 --- /dev/null +++ b/net/nfc/hci/llc.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Link Layer Control manager | ||
3 | * | ||
4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __LOCAL_LLC_H_ | ||
22 | #define __LOCAL_LLC_H_ | ||
23 | |||
24 | #include <net/nfc/hci.h> | ||
25 | #include <net/nfc/llc.h> | ||
26 | #include <linux/skbuff.h> | ||
27 | |||
28 | struct nfc_llc_ops { | ||
29 | void *(*init) (struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, | ||
30 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
31 | int tx_tailroom, int *rx_headroom, int *rx_tailroom, | ||
32 | llc_failure_t llc_failure); | ||
33 | void (*deinit) (struct nfc_llc *llc); | ||
34 | int (*start) (struct nfc_llc *llc); | ||
35 | int (*stop) (struct nfc_llc *llc); | ||
36 | void (*rcv_from_drv) (struct nfc_llc *llc, struct sk_buff *skb); | ||
37 | int (*xmit_from_hci) (struct nfc_llc *llc, struct sk_buff *skb); | ||
38 | }; | ||
39 | |||
40 | struct nfc_llc_engine { | ||
41 | const char *name; | ||
42 | struct nfc_llc_ops *ops; | ||
43 | struct list_head entry; | ||
44 | }; | ||
45 | |||
46 | struct nfc_llc { | ||
47 | void *data; | ||
48 | struct nfc_llc_ops *ops; | ||
49 | int rx_headroom; | ||
50 | int rx_tailroom; | ||
51 | }; | ||
52 | |||
53 | void *nfc_llc_get_data(struct nfc_llc *llc); | ||
54 | |||
55 | int nfc_llc_register(const char *name, struct nfc_llc_ops *ops); | ||
56 | void nfc_llc_unregister(const char *name); | ||
57 | |||
58 | int nfc_llc_nop_register(void); | ||
59 | |||
60 | #if defined(CONFIG_NFC_SHDLC) | ||
61 | int nfc_llc_shdlc_register(void); | ||
62 | #else | ||
63 | static inline int nfc_llc_shdlc_register(void) | ||
64 | { | ||
65 | return 0; | ||
66 | } | ||
67 | #endif | ||
68 | |||
69 | #endif /* __LOCAL_LLC_H_ */ | ||
diff --git a/net/nfc/hci/llc_nop.c b/net/nfc/hci/llc_nop.c new file mode 100644 index 000000000000..87b10291b40f --- /dev/null +++ b/net/nfc/hci/llc_nop.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * nop (passthrough) Link Layer Control | ||
3 | * | ||
4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | |||
23 | #include "llc.h" | ||
24 | |||
25 | struct llc_nop { | ||
26 | struct nfc_hci_dev *hdev; | ||
27 | xmit_to_drv_t xmit_to_drv; | ||
28 | rcv_to_hci_t rcv_to_hci; | ||
29 | int tx_headroom; | ||
30 | int tx_tailroom; | ||
31 | llc_failure_t llc_failure; | ||
32 | }; | ||
33 | |||
34 | static void *llc_nop_init(struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, | ||
35 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
36 | int tx_tailroom, int *rx_headroom, int *rx_tailroom, | ||
37 | llc_failure_t llc_failure) | ||
38 | { | ||
39 | struct llc_nop *llc_nop; | ||
40 | |||
41 | *rx_headroom = 0; | ||
42 | *rx_tailroom = 0; | ||
43 | |||
44 | llc_nop = kzalloc(sizeof(struct llc_nop), GFP_KERNEL); | ||
45 | if (llc_nop == NULL) | ||
46 | return NULL; | ||
47 | |||
48 | llc_nop->hdev = hdev; | ||
49 | llc_nop->xmit_to_drv = xmit_to_drv; | ||
50 | llc_nop->rcv_to_hci = rcv_to_hci; | ||
51 | llc_nop->tx_headroom = tx_headroom; | ||
52 | llc_nop->tx_tailroom = tx_tailroom; | ||
53 | llc_nop->llc_failure = llc_failure; | ||
54 | |||
55 | return llc_nop; | ||
56 | } | ||
57 | |||
58 | static void llc_nop_deinit(struct nfc_llc *llc) | ||
59 | { | ||
60 | kfree(nfc_llc_get_data(llc)); | ||
61 | } | ||
62 | |||
63 | static int llc_nop_start(struct nfc_llc *llc) | ||
64 | { | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int llc_nop_stop(struct nfc_llc *llc) | ||
69 | { | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static void llc_nop_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb) | ||
74 | { | ||
75 | struct llc_nop *llc_nop = nfc_llc_get_data(llc); | ||
76 | |||
77 | llc_nop->rcv_to_hci(llc_nop->hdev, skb); | ||
78 | } | ||
79 | |||
80 | static int llc_nop_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb) | ||
81 | { | ||
82 | struct llc_nop *llc_nop = nfc_llc_get_data(llc); | ||
83 | |||
84 | return llc_nop->xmit_to_drv(llc_nop->hdev, skb); | ||
85 | } | ||
86 | |||
87 | static struct nfc_llc_ops llc_nop_ops = { | ||
88 | .init = llc_nop_init, | ||
89 | .deinit = llc_nop_deinit, | ||
90 | .start = llc_nop_start, | ||
91 | .stop = llc_nop_stop, | ||
92 | .rcv_from_drv = llc_nop_rcv_from_drv, | ||
93 | .xmit_from_hci = llc_nop_xmit_from_hci, | ||
94 | }; | ||
95 | |||
96 | int nfc_llc_nop_register(void) | ||
97 | { | ||
98 | return nfc_llc_register(LLC_NOP_NAME, &llc_nop_ops); | ||
99 | } | ||
diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/llc_shdlc.c index 6f840c18c892..8f69d791dcb3 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/llc_shdlc.c | |||
@@ -1,10 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * shdlc Link Layer Control | ||
3 | * | ||
2 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | 4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. |
3 | * | 5 | * |
4 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify it |
5 | * it under the terms of the GNU General Public License as published by | 7 | * under the terms and conditions of the GNU General Public License, |
6 | * the Free Software Foundation; either version 2 of the License, or | 8 | * version 2, as published by the Free Software Foundation. |
7 | * (at your option) any later version. | ||
8 | * | 9 | * |
9 | * This program is distributed in the hope that it will be useful, | 10 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
@@ -19,18 +20,65 @@ | |||
19 | 20 | ||
20 | #define pr_fmt(fmt) "shdlc: %s: " fmt, __func__ | 21 | #define pr_fmt(fmt) "shdlc: %s: " fmt, __func__ |
21 | 22 | ||
23 | #include <linux/types.h> | ||
22 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
23 | #include <linux/export.h> | ||
24 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
25 | #include <linux/crc-ccitt.h> | ||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/skbuff.h> | 27 | #include <linux/skbuff.h> |
28 | 28 | ||
29 | #include <net/nfc/hci.h> | 29 | #include "llc.h" |
30 | #include <net/nfc/shdlc.h> | 30 | |
31 | enum shdlc_state { | ||
32 | SHDLC_DISCONNECTED = 0, | ||
33 | SHDLC_CONNECTING = 1, | ||
34 | SHDLC_NEGOTIATING = 2, | ||
35 | SHDLC_HALF_CONNECTED = 3, | ||
36 | SHDLC_CONNECTED = 4 | ||
37 | }; | ||
38 | |||
39 | struct llc_shdlc { | ||
40 | struct nfc_hci_dev *hdev; | ||
41 | xmit_to_drv_t xmit_to_drv; | ||
42 | rcv_to_hci_t rcv_to_hci; | ||
43 | |||
44 | struct mutex state_mutex; | ||
45 | enum shdlc_state state; | ||
46 | int hard_fault; | ||
47 | |||
48 | wait_queue_head_t *connect_wq; | ||
49 | int connect_tries; | ||
50 | int connect_result; | ||
51 | struct timer_list connect_timer;/* aka T3 in spec 10.6.1 */ | ||
52 | |||
53 | u8 w; /* window size */ | ||
54 | bool srej_support; | ||
55 | |||
56 | struct timer_list t1_timer; /* send ack timeout */ | ||
57 | bool t1_active; | ||
58 | |||
59 | struct timer_list t2_timer; /* guard/retransmit timeout */ | ||
60 | bool t2_active; | ||
61 | |||
62 | int ns; /* next seq num for send */ | ||
63 | int nr; /* next expected seq num for receive */ | ||
64 | int dnr; /* oldest sent unacked seq num */ | ||
65 | |||
66 | struct sk_buff_head rcv_q; | ||
67 | |||
68 | struct sk_buff_head send_q; | ||
69 | bool rnr; /* other side is not ready to receive */ | ||
70 | |||
71 | struct sk_buff_head ack_pending_q; | ||
72 | |||
73 | struct work_struct sm_work; | ||
74 | |||
75 | int tx_headroom; | ||
76 | int tx_tailroom; | ||
77 | |||
78 | llc_failure_t llc_failure; | ||
79 | }; | ||
31 | 80 | ||
32 | #define SHDLC_LLC_HEAD_ROOM 2 | 81 | #define SHDLC_LLC_HEAD_ROOM 2 |
33 | #define SHDLC_LLC_TAIL_ROOM 2 | ||
34 | 82 | ||
35 | #define SHDLC_MAX_WINDOW 4 | 83 | #define SHDLC_MAX_WINDOW 4 |
36 | #define SHDLC_SREJ_SUPPORT false | 84 | #define SHDLC_SREJ_SUPPORT false |
@@ -71,7 +119,7 @@ do { \ | |||
71 | } while (0) | 119 | } while (0) |
72 | 120 | ||
73 | /* checks x < y <= z modulo 8 */ | 121 | /* checks x < y <= z modulo 8 */ |
74 | static bool nfc_shdlc_x_lt_y_lteq_z(int x, int y, int z) | 122 | static bool llc_shdlc_x_lt_y_lteq_z(int x, int y, int z) |
75 | { | 123 | { |
76 | if (x < z) | 124 | if (x < z) |
77 | return ((x < y) && (y <= z)) ? true : false; | 125 | return ((x < y) && (y <= z)) ? true : false; |
@@ -80,7 +128,7 @@ static bool nfc_shdlc_x_lt_y_lteq_z(int x, int y, int z) | |||
80 | } | 128 | } |
81 | 129 | ||
82 | /* checks x <= y < z modulo 8 */ | 130 | /* checks x <= y < z modulo 8 */ |
83 | static bool nfc_shdlc_x_lteq_y_lt_z(int x, int y, int z) | 131 | static bool llc_shdlc_x_lteq_y_lt_z(int x, int y, int z) |
84 | { | 132 | { |
85 | if (x <= z) | 133 | if (x <= z) |
86 | return ((x <= y) && (y < z)) ? true : false; | 134 | return ((x <= y) && (y < z)) ? true : false; |
@@ -88,36 +136,21 @@ static bool nfc_shdlc_x_lteq_y_lt_z(int x, int y, int z) | |||
88 | return ((y >= x) || (y < z)) ? true : false; | 136 | return ((y >= x) || (y < z)) ? true : false; |
89 | } | 137 | } |
90 | 138 | ||
91 | static struct sk_buff *nfc_shdlc_alloc_skb(struct nfc_shdlc *shdlc, | 139 | static struct sk_buff *llc_shdlc_alloc_skb(struct llc_shdlc *shdlc, |
92 | int payload_len) | 140 | int payload_len) |
93 | { | 141 | { |
94 | struct sk_buff *skb; | 142 | struct sk_buff *skb; |
95 | 143 | ||
96 | skb = alloc_skb(shdlc->client_headroom + SHDLC_LLC_HEAD_ROOM + | 144 | skb = alloc_skb(shdlc->tx_headroom + SHDLC_LLC_HEAD_ROOM + |
97 | shdlc->client_tailroom + SHDLC_LLC_TAIL_ROOM + | 145 | shdlc->tx_tailroom + payload_len, GFP_KERNEL); |
98 | payload_len, GFP_KERNEL); | ||
99 | if (skb) | 146 | if (skb) |
100 | skb_reserve(skb, shdlc->client_headroom + SHDLC_LLC_HEAD_ROOM); | 147 | skb_reserve(skb, shdlc->tx_headroom + SHDLC_LLC_HEAD_ROOM); |
101 | 148 | ||
102 | return skb; | 149 | return skb; |
103 | } | 150 | } |
104 | 151 | ||
105 | static void nfc_shdlc_add_len_crc(struct sk_buff *skb) | ||
106 | { | ||
107 | u16 crc; | ||
108 | int len; | ||
109 | |||
110 | len = skb->len + 2; | ||
111 | *skb_push(skb, 1) = len; | ||
112 | |||
113 | crc = crc_ccitt(0xffff, skb->data, skb->len); | ||
114 | crc = ~crc; | ||
115 | *skb_put(skb, 1) = crc & 0xff; | ||
116 | *skb_put(skb, 1) = crc >> 8; | ||
117 | } | ||
118 | |||
119 | /* immediately sends an S frame. */ | 152 | /* immediately sends an S frame. */ |
120 | static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc, | 153 | static int llc_shdlc_send_s_frame(struct llc_shdlc *shdlc, |
121 | enum sframe_type sframe_type, int nr) | 154 | enum sframe_type sframe_type, int nr) |
122 | { | 155 | { |
123 | int r; | 156 | int r; |
@@ -125,15 +158,13 @@ static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc, | |||
125 | 158 | ||
126 | pr_debug("sframe_type=%d nr=%d\n", sframe_type, nr); | 159 | pr_debug("sframe_type=%d nr=%d\n", sframe_type, nr); |
127 | 160 | ||
128 | skb = nfc_shdlc_alloc_skb(shdlc, 0); | 161 | skb = llc_shdlc_alloc_skb(shdlc, 0); |
129 | if (skb == NULL) | 162 | if (skb == NULL) |
130 | return -ENOMEM; | 163 | return -ENOMEM; |
131 | 164 | ||
132 | *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_S | (sframe_type << 3) | nr; | 165 | *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_S | (sframe_type << 3) | nr; |
133 | 166 | ||
134 | nfc_shdlc_add_len_crc(skb); | 167 | r = shdlc->xmit_to_drv(shdlc->hdev, skb); |
135 | |||
136 | r = shdlc->ops->xmit(shdlc, skb); | ||
137 | 168 | ||
138 | kfree_skb(skb); | 169 | kfree_skb(skb); |
139 | 170 | ||
@@ -141,7 +172,7 @@ static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc, | |||
141 | } | 172 | } |
142 | 173 | ||
143 | /* immediately sends an U frame. skb may contain optional payload */ | 174 | /* immediately sends an U frame. skb may contain optional payload */ |
144 | static int nfc_shdlc_send_u_frame(struct nfc_shdlc *shdlc, | 175 | static int llc_shdlc_send_u_frame(struct llc_shdlc *shdlc, |
145 | struct sk_buff *skb, | 176 | struct sk_buff *skb, |
146 | enum uframe_modifier uframe_modifier) | 177 | enum uframe_modifier uframe_modifier) |
147 | { | 178 | { |
@@ -151,9 +182,7 @@ static int nfc_shdlc_send_u_frame(struct nfc_shdlc *shdlc, | |||
151 | 182 | ||
152 | *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_U | uframe_modifier; | 183 | *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_U | uframe_modifier; |
153 | 184 | ||
154 | nfc_shdlc_add_len_crc(skb); | 185 | r = shdlc->xmit_to_drv(shdlc->hdev, skb); |
155 | |||
156 | r = shdlc->ops->xmit(shdlc, skb); | ||
157 | 186 | ||
158 | kfree_skb(skb); | 187 | kfree_skb(skb); |
159 | 188 | ||
@@ -164,7 +193,7 @@ static int nfc_shdlc_send_u_frame(struct nfc_shdlc *shdlc, | |||
164 | * Free ack_pending frames until y_nr - 1, and reset t2 according to | 193 | * Free ack_pending frames until y_nr - 1, and reset t2 according to |
165 | * the remaining oldest ack_pending frame sent time | 194 | * the remaining oldest ack_pending frame sent time |
166 | */ | 195 | */ |
167 | static void nfc_shdlc_reset_t2(struct nfc_shdlc *shdlc, int y_nr) | 196 | static void llc_shdlc_reset_t2(struct llc_shdlc *shdlc, int y_nr) |
168 | { | 197 | { |
169 | struct sk_buff *skb; | 198 | struct sk_buff *skb; |
170 | int dnr = shdlc->dnr; /* MUST initially be < y_nr */ | 199 | int dnr = shdlc->dnr; /* MUST initially be < y_nr */ |
@@ -204,7 +233,7 @@ static void nfc_shdlc_reset_t2(struct nfc_shdlc *shdlc, int y_nr) | |||
204 | * Receive validated frames from lower layer. skb contains HCI payload only. | 233 | * Receive validated frames from lower layer. skb contains HCI payload only. |
205 | * Handle according to algorithm at spec:10.8.2 | 234 | * Handle according to algorithm at spec:10.8.2 |
206 | */ | 235 | */ |
207 | static void nfc_shdlc_rcv_i_frame(struct nfc_shdlc *shdlc, | 236 | static void llc_shdlc_rcv_i_frame(struct llc_shdlc *shdlc, |
208 | struct sk_buff *skb, int ns, int nr) | 237 | struct sk_buff *skb, int ns, int nr) |
209 | { | 238 | { |
210 | int x_ns = ns; | 239 | int x_ns = ns; |
@@ -216,66 +245,64 @@ static void nfc_shdlc_rcv_i_frame(struct nfc_shdlc *shdlc, | |||
216 | goto exit; | 245 | goto exit; |
217 | 246 | ||
218 | if (x_ns != shdlc->nr) { | 247 | if (x_ns != shdlc->nr) { |
219 | nfc_shdlc_send_s_frame(shdlc, S_FRAME_REJ, shdlc->nr); | 248 | llc_shdlc_send_s_frame(shdlc, S_FRAME_REJ, shdlc->nr); |
220 | goto exit; | 249 | goto exit; |
221 | } | 250 | } |
222 | 251 | ||
223 | if (shdlc->t1_active == false) { | 252 | if (shdlc->t1_active == false) { |
224 | shdlc->t1_active = true; | 253 | shdlc->t1_active = true; |
225 | mod_timer(&shdlc->t1_timer, | 254 | mod_timer(&shdlc->t1_timer, jiffies + |
226 | msecs_to_jiffies(SHDLC_T1_VALUE_MS(shdlc->w))); | 255 | msecs_to_jiffies(SHDLC_T1_VALUE_MS(shdlc->w))); |
227 | pr_debug("(re)Start T1(send ack)\n"); | 256 | pr_debug("(re)Start T1(send ack)\n"); |
228 | } | 257 | } |
229 | 258 | ||
230 | if (skb->len) { | 259 | if (skb->len) { |
231 | nfc_hci_recv_frame(shdlc->hdev, skb); | 260 | shdlc->rcv_to_hci(shdlc->hdev, skb); |
232 | skb = NULL; | 261 | skb = NULL; |
233 | } | 262 | } |
234 | 263 | ||
235 | shdlc->nr = (shdlc->nr + 1) % 8; | 264 | shdlc->nr = (shdlc->nr + 1) % 8; |
236 | 265 | ||
237 | if (nfc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { | 266 | if (llc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { |
238 | nfc_shdlc_reset_t2(shdlc, y_nr); | 267 | llc_shdlc_reset_t2(shdlc, y_nr); |
239 | 268 | ||
240 | shdlc->dnr = y_nr; | 269 | shdlc->dnr = y_nr; |
241 | } | 270 | } |
242 | 271 | ||
243 | exit: | 272 | exit: |
244 | if (skb) | 273 | kfree_skb(skb); |
245 | kfree_skb(skb); | ||
246 | } | 274 | } |
247 | 275 | ||
248 | static void nfc_shdlc_rcv_ack(struct nfc_shdlc *shdlc, int y_nr) | 276 | static void llc_shdlc_rcv_ack(struct llc_shdlc *shdlc, int y_nr) |
249 | { | 277 | { |
250 | pr_debug("remote acked up to frame %d excluded\n", y_nr); | 278 | pr_debug("remote acked up to frame %d excluded\n", y_nr); |
251 | 279 | ||
252 | if (nfc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { | 280 | if (llc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { |
253 | nfc_shdlc_reset_t2(shdlc, y_nr); | 281 | llc_shdlc_reset_t2(shdlc, y_nr); |
254 | shdlc->dnr = y_nr; | 282 | shdlc->dnr = y_nr; |
255 | } | 283 | } |
256 | } | 284 | } |
257 | 285 | ||
258 | static void nfc_shdlc_requeue_ack_pending(struct nfc_shdlc *shdlc) | 286 | static void llc_shdlc_requeue_ack_pending(struct llc_shdlc *shdlc) |
259 | { | 287 | { |
260 | struct sk_buff *skb; | 288 | struct sk_buff *skb; |
261 | 289 | ||
262 | pr_debug("ns reset to %d\n", shdlc->dnr); | 290 | pr_debug("ns reset to %d\n", shdlc->dnr); |
263 | 291 | ||
264 | while ((skb = skb_dequeue_tail(&shdlc->ack_pending_q))) { | 292 | while ((skb = skb_dequeue_tail(&shdlc->ack_pending_q))) { |
265 | skb_pull(skb, 2); /* remove len+control */ | 293 | skb_pull(skb, 1); /* remove control field */ |
266 | skb_trim(skb, skb->len - 2); /* remove crc */ | ||
267 | skb_queue_head(&shdlc->send_q, skb); | 294 | skb_queue_head(&shdlc->send_q, skb); |
268 | } | 295 | } |
269 | shdlc->ns = shdlc->dnr; | 296 | shdlc->ns = shdlc->dnr; |
270 | } | 297 | } |
271 | 298 | ||
272 | static void nfc_shdlc_rcv_rej(struct nfc_shdlc *shdlc, int y_nr) | 299 | static void llc_shdlc_rcv_rej(struct llc_shdlc *shdlc, int y_nr) |
273 | { | 300 | { |
274 | struct sk_buff *skb; | 301 | struct sk_buff *skb; |
275 | 302 | ||
276 | pr_debug("remote asks retransmition from frame %d\n", y_nr); | 303 | pr_debug("remote asks retransmition from frame %d\n", y_nr); |
277 | 304 | ||
278 | if (nfc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) { | 305 | if (llc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) { |
279 | if (shdlc->t2_active) { | 306 | if (shdlc->t2_active) { |
280 | del_timer_sync(&shdlc->t2_timer); | 307 | del_timer_sync(&shdlc->t2_timer); |
281 | shdlc->t2_active = false; | 308 | shdlc->t2_active = false; |
@@ -289,12 +316,12 @@ static void nfc_shdlc_rcv_rej(struct nfc_shdlc *shdlc, int y_nr) | |||
289 | } | 316 | } |
290 | } | 317 | } |
291 | 318 | ||
292 | nfc_shdlc_requeue_ack_pending(shdlc); | 319 | llc_shdlc_requeue_ack_pending(shdlc); |
293 | } | 320 | } |
294 | } | 321 | } |
295 | 322 | ||
296 | /* See spec RR:10.8.3 REJ:10.8.4 */ | 323 | /* See spec RR:10.8.3 REJ:10.8.4 */ |
297 | static void nfc_shdlc_rcv_s_frame(struct nfc_shdlc *shdlc, | 324 | static void llc_shdlc_rcv_s_frame(struct llc_shdlc *shdlc, |
298 | enum sframe_type s_frame_type, int nr) | 325 | enum sframe_type s_frame_type, int nr) |
299 | { | 326 | { |
300 | struct sk_buff *skb; | 327 | struct sk_buff *skb; |
@@ -304,21 +331,21 @@ static void nfc_shdlc_rcv_s_frame(struct nfc_shdlc *shdlc, | |||
304 | 331 | ||
305 | switch (s_frame_type) { | 332 | switch (s_frame_type) { |
306 | case S_FRAME_RR: | 333 | case S_FRAME_RR: |
307 | nfc_shdlc_rcv_ack(shdlc, nr); | 334 | llc_shdlc_rcv_ack(shdlc, nr); |
308 | if (shdlc->rnr == true) { /* see SHDLC 10.7.7 */ | 335 | if (shdlc->rnr == true) { /* see SHDLC 10.7.7 */ |
309 | shdlc->rnr = false; | 336 | shdlc->rnr = false; |
310 | if (shdlc->send_q.qlen == 0) { | 337 | if (shdlc->send_q.qlen == 0) { |
311 | skb = nfc_shdlc_alloc_skb(shdlc, 0); | 338 | skb = llc_shdlc_alloc_skb(shdlc, 0); |
312 | if (skb) | 339 | if (skb) |
313 | skb_queue_tail(&shdlc->send_q, skb); | 340 | skb_queue_tail(&shdlc->send_q, skb); |
314 | } | 341 | } |
315 | } | 342 | } |
316 | break; | 343 | break; |
317 | case S_FRAME_REJ: | 344 | case S_FRAME_REJ: |
318 | nfc_shdlc_rcv_rej(shdlc, nr); | 345 | llc_shdlc_rcv_rej(shdlc, nr); |
319 | break; | 346 | break; |
320 | case S_FRAME_RNR: | 347 | case S_FRAME_RNR: |
321 | nfc_shdlc_rcv_ack(shdlc, nr); | 348 | llc_shdlc_rcv_ack(shdlc, nr); |
322 | shdlc->rnr = true; | 349 | shdlc->rnr = true; |
323 | break; | 350 | break; |
324 | default: | 351 | default: |
@@ -326,7 +353,7 @@ static void nfc_shdlc_rcv_s_frame(struct nfc_shdlc *shdlc, | |||
326 | } | 353 | } |
327 | } | 354 | } |
328 | 355 | ||
329 | static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) | 356 | static void llc_shdlc_connect_complete(struct llc_shdlc *shdlc, int r) |
330 | { | 357 | { |
331 | pr_debug("result=%d\n", r); | 358 | pr_debug("result=%d\n", r); |
332 | 359 | ||
@@ -337,7 +364,7 @@ static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) | |||
337 | shdlc->nr = 0; | 364 | shdlc->nr = 0; |
338 | shdlc->dnr = 0; | 365 | shdlc->dnr = 0; |
339 | 366 | ||
340 | shdlc->state = SHDLC_CONNECTED; | 367 | shdlc->state = SHDLC_HALF_CONNECTED; |
341 | } else { | 368 | } else { |
342 | shdlc->state = SHDLC_DISCONNECTED; | 369 | shdlc->state = SHDLC_DISCONNECTED; |
343 | } | 370 | } |
@@ -347,36 +374,36 @@ static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) | |||
347 | wake_up(shdlc->connect_wq); | 374 | wake_up(shdlc->connect_wq); |
348 | } | 375 | } |
349 | 376 | ||
350 | static int nfc_shdlc_connect_initiate(struct nfc_shdlc *shdlc) | 377 | static int llc_shdlc_connect_initiate(struct llc_shdlc *shdlc) |
351 | { | 378 | { |
352 | struct sk_buff *skb; | 379 | struct sk_buff *skb; |
353 | 380 | ||
354 | pr_debug("\n"); | 381 | pr_debug("\n"); |
355 | 382 | ||
356 | skb = nfc_shdlc_alloc_skb(shdlc, 2); | 383 | skb = llc_shdlc_alloc_skb(shdlc, 2); |
357 | if (skb == NULL) | 384 | if (skb == NULL) |
358 | return -ENOMEM; | 385 | return -ENOMEM; |
359 | 386 | ||
360 | *skb_put(skb, 1) = SHDLC_MAX_WINDOW; | 387 | *skb_put(skb, 1) = SHDLC_MAX_WINDOW; |
361 | *skb_put(skb, 1) = SHDLC_SREJ_SUPPORT ? 1 : 0; | 388 | *skb_put(skb, 1) = SHDLC_SREJ_SUPPORT ? 1 : 0; |
362 | 389 | ||
363 | return nfc_shdlc_send_u_frame(shdlc, skb, U_FRAME_RSET); | 390 | return llc_shdlc_send_u_frame(shdlc, skb, U_FRAME_RSET); |
364 | } | 391 | } |
365 | 392 | ||
366 | static int nfc_shdlc_connect_send_ua(struct nfc_shdlc *shdlc) | 393 | static int llc_shdlc_connect_send_ua(struct llc_shdlc *shdlc) |
367 | { | 394 | { |
368 | struct sk_buff *skb; | 395 | struct sk_buff *skb; |
369 | 396 | ||
370 | pr_debug("\n"); | 397 | pr_debug("\n"); |
371 | 398 | ||
372 | skb = nfc_shdlc_alloc_skb(shdlc, 0); | 399 | skb = llc_shdlc_alloc_skb(shdlc, 0); |
373 | if (skb == NULL) | 400 | if (skb == NULL) |
374 | return -ENOMEM; | 401 | return -ENOMEM; |
375 | 402 | ||
376 | return nfc_shdlc_send_u_frame(shdlc, skb, U_FRAME_UA); | 403 | return llc_shdlc_send_u_frame(shdlc, skb, U_FRAME_UA); |
377 | } | 404 | } |
378 | 405 | ||
379 | static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | 406 | static void llc_shdlc_rcv_u_frame(struct llc_shdlc *shdlc, |
380 | struct sk_buff *skb, | 407 | struct sk_buff *skb, |
381 | enum uframe_modifier u_frame_modifier) | 408 | enum uframe_modifier u_frame_modifier) |
382 | { | 409 | { |
@@ -388,8 +415,13 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | |||
388 | 415 | ||
389 | switch (u_frame_modifier) { | 416 | switch (u_frame_modifier) { |
390 | case U_FRAME_RSET: | 417 | case U_FRAME_RSET: |
391 | if (shdlc->state == SHDLC_NEGOCIATING) { | 418 | switch (shdlc->state) { |
392 | /* we sent RSET, but chip wants to negociate */ | 419 | case SHDLC_NEGOTIATING: |
420 | case SHDLC_CONNECTING: | ||
421 | /* | ||
422 | * We sent RSET, but chip wants to negociate or we | ||
423 | * got RSET before we managed to send out our. | ||
424 | */ | ||
393 | if (skb->len > 0) | 425 | if (skb->len > 0) |
394 | w = skb->data[0]; | 426 | w = skb->data[0]; |
395 | 427 | ||
@@ -401,22 +433,34 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | |||
401 | (SHDLC_SREJ_SUPPORT || (srej_support == false))) { | 433 | (SHDLC_SREJ_SUPPORT || (srej_support == false))) { |
402 | shdlc->w = w; | 434 | shdlc->w = w; |
403 | shdlc->srej_support = srej_support; | 435 | shdlc->srej_support = srej_support; |
404 | r = nfc_shdlc_connect_send_ua(shdlc); | 436 | r = llc_shdlc_connect_send_ua(shdlc); |
405 | nfc_shdlc_connect_complete(shdlc, r); | 437 | llc_shdlc_connect_complete(shdlc, r); |
406 | } | 438 | } |
407 | } else if (shdlc->state == SHDLC_CONNECTED) { | 439 | break; |
440 | case SHDLC_HALF_CONNECTED: | ||
441 | /* | ||
442 | * Chip resent RSET due to its timeout - Ignote it | ||
443 | * as we already sent UA. | ||
444 | */ | ||
445 | break; | ||
446 | case SHDLC_CONNECTED: | ||
408 | /* | 447 | /* |
409 | * Chip wants to reset link. This is unexpected and | 448 | * Chip wants to reset link. This is unexpected and |
410 | * unsupported. | 449 | * unsupported. |
411 | */ | 450 | */ |
412 | shdlc->hard_fault = -ECONNRESET; | 451 | shdlc->hard_fault = -ECONNRESET; |
452 | break; | ||
453 | default: | ||
454 | break; | ||
413 | } | 455 | } |
414 | break; | 456 | break; |
415 | case U_FRAME_UA: | 457 | case U_FRAME_UA: |
416 | if ((shdlc->state == SHDLC_CONNECTING && | 458 | if ((shdlc->state == SHDLC_CONNECTING && |
417 | shdlc->connect_tries > 0) || | 459 | shdlc->connect_tries > 0) || |
418 | (shdlc->state == SHDLC_NEGOCIATING)) | 460 | (shdlc->state == SHDLC_NEGOTIATING)) { |
419 | nfc_shdlc_connect_complete(shdlc, 0); | 461 | llc_shdlc_connect_complete(shdlc, 0); |
462 | shdlc->state = SHDLC_CONNECTED; | ||
463 | } | ||
420 | break; | 464 | break; |
421 | default: | 465 | default: |
422 | break; | 466 | break; |
@@ -425,7 +469,7 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | |||
425 | kfree_skb(skb); | 469 | kfree_skb(skb); |
426 | } | 470 | } |
427 | 471 | ||
428 | static void nfc_shdlc_handle_rcv_queue(struct nfc_shdlc *shdlc) | 472 | static void llc_shdlc_handle_rcv_queue(struct llc_shdlc *shdlc) |
429 | { | 473 | { |
430 | struct sk_buff *skb; | 474 | struct sk_buff *skb; |
431 | u8 control; | 475 | u8 control; |
@@ -443,19 +487,25 @@ static void nfc_shdlc_handle_rcv_queue(struct nfc_shdlc *shdlc) | |||
443 | switch (control & SHDLC_CONTROL_HEAD_MASK) { | 487 | switch (control & SHDLC_CONTROL_HEAD_MASK) { |
444 | case SHDLC_CONTROL_HEAD_I: | 488 | case SHDLC_CONTROL_HEAD_I: |
445 | case SHDLC_CONTROL_HEAD_I2: | 489 | case SHDLC_CONTROL_HEAD_I2: |
490 | if (shdlc->state == SHDLC_HALF_CONNECTED) | ||
491 | shdlc->state = SHDLC_CONNECTED; | ||
492 | |||
446 | ns = (control & SHDLC_CONTROL_NS_MASK) >> 3; | 493 | ns = (control & SHDLC_CONTROL_NS_MASK) >> 3; |
447 | nr = control & SHDLC_CONTROL_NR_MASK; | 494 | nr = control & SHDLC_CONTROL_NR_MASK; |
448 | nfc_shdlc_rcv_i_frame(shdlc, skb, ns, nr); | 495 | llc_shdlc_rcv_i_frame(shdlc, skb, ns, nr); |
449 | break; | 496 | break; |
450 | case SHDLC_CONTROL_HEAD_S: | 497 | case SHDLC_CONTROL_HEAD_S: |
498 | if (shdlc->state == SHDLC_HALF_CONNECTED) | ||
499 | shdlc->state = SHDLC_CONNECTED; | ||
500 | |||
451 | s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3; | 501 | s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3; |
452 | nr = control & SHDLC_CONTROL_NR_MASK; | 502 | nr = control & SHDLC_CONTROL_NR_MASK; |
453 | nfc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr); | 503 | llc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr); |
454 | kfree_skb(skb); | 504 | kfree_skb(skb); |
455 | break; | 505 | break; |
456 | case SHDLC_CONTROL_HEAD_U: | 506 | case SHDLC_CONTROL_HEAD_U: |
457 | u_frame_modifier = control & SHDLC_CONTROL_M_MASK; | 507 | u_frame_modifier = control & SHDLC_CONTROL_M_MASK; |
458 | nfc_shdlc_rcv_u_frame(shdlc, skb, u_frame_modifier); | 508 | llc_shdlc_rcv_u_frame(shdlc, skb, u_frame_modifier); |
459 | break; | 509 | break; |
460 | default: | 510 | default: |
461 | pr_err("UNKNOWN Control=%d\n", control); | 511 | pr_err("UNKNOWN Control=%d\n", control); |
@@ -465,7 +515,7 @@ static void nfc_shdlc_handle_rcv_queue(struct nfc_shdlc *shdlc) | |||
465 | } | 515 | } |
466 | } | 516 | } |
467 | 517 | ||
468 | static int nfc_shdlc_w_used(int ns, int dnr) | 518 | static int llc_shdlc_w_used(int ns, int dnr) |
469 | { | 519 | { |
470 | int unack_count; | 520 | int unack_count; |
471 | 521 | ||
@@ -478,7 +528,7 @@ static int nfc_shdlc_w_used(int ns, int dnr) | |||
478 | } | 528 | } |
479 | 529 | ||
480 | /* Send frames according to algorithm at spec:10.8.1 */ | 530 | /* Send frames according to algorithm at spec:10.8.1 */ |
481 | static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | 531 | static void llc_shdlc_handle_send_queue(struct llc_shdlc *shdlc) |
482 | { | 532 | { |
483 | struct sk_buff *skb; | 533 | struct sk_buff *skb; |
484 | int r; | 534 | int r; |
@@ -489,7 +539,7 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | |||
489 | ("sendQlen=%d ns=%d dnr=%d rnr=%s w_room=%d unackQlen=%d\n", | 539 | ("sendQlen=%d ns=%d dnr=%d rnr=%s w_room=%d unackQlen=%d\n", |
490 | shdlc->send_q.qlen, shdlc->ns, shdlc->dnr, | 540 | shdlc->send_q.qlen, shdlc->ns, shdlc->dnr, |
491 | shdlc->rnr == false ? "false" : "true", | 541 | shdlc->rnr == false ? "false" : "true", |
492 | shdlc->w - nfc_shdlc_w_used(shdlc->ns, shdlc->dnr), | 542 | shdlc->w - llc_shdlc_w_used(shdlc->ns, shdlc->dnr), |
493 | shdlc->ack_pending_q.qlen); | 543 | shdlc->ack_pending_q.qlen); |
494 | 544 | ||
495 | while (shdlc->send_q.qlen && shdlc->ack_pending_q.qlen < shdlc->w && | 545 | while (shdlc->send_q.qlen && shdlc->ack_pending_q.qlen < shdlc->w && |
@@ -508,11 +558,9 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | |||
508 | 558 | ||
509 | pr_debug("Sending I-Frame %d, waiting to rcv %d\n", shdlc->ns, | 559 | pr_debug("Sending I-Frame %d, waiting to rcv %d\n", shdlc->ns, |
510 | shdlc->nr); | 560 | shdlc->nr); |
511 | /* SHDLC_DUMP_SKB("shdlc frame written", skb); */ | 561 | SHDLC_DUMP_SKB("shdlc frame written", skb); |
512 | |||
513 | nfc_shdlc_add_len_crc(skb); | ||
514 | 562 | ||
515 | r = shdlc->ops->xmit(shdlc, skb); | 563 | r = shdlc->xmit_to_drv(shdlc->hdev, skb); |
516 | if (r < 0) { | 564 | if (r < 0) { |
517 | shdlc->hard_fault = r; | 565 | shdlc->hard_fault = r; |
518 | break; | 566 | break; |
@@ -534,36 +582,36 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | |||
534 | } | 582 | } |
535 | } | 583 | } |
536 | 584 | ||
537 | static void nfc_shdlc_connect_timeout(unsigned long data) | 585 | static void llc_shdlc_connect_timeout(unsigned long data) |
538 | { | 586 | { |
539 | struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data; | 587 | struct llc_shdlc *shdlc = (struct llc_shdlc *)data; |
540 | 588 | ||
541 | pr_debug("\n"); | 589 | pr_debug("\n"); |
542 | 590 | ||
543 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 591 | queue_work(system_nrt_wq, &shdlc->sm_work); |
544 | } | 592 | } |
545 | 593 | ||
546 | static void nfc_shdlc_t1_timeout(unsigned long data) | 594 | static void llc_shdlc_t1_timeout(unsigned long data) |
547 | { | 595 | { |
548 | struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data; | 596 | struct llc_shdlc *shdlc = (struct llc_shdlc *)data; |
549 | 597 | ||
550 | pr_debug("SoftIRQ: need to send ack\n"); | 598 | pr_debug("SoftIRQ: need to send ack\n"); |
551 | 599 | ||
552 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 600 | queue_work(system_nrt_wq, &shdlc->sm_work); |
553 | } | 601 | } |
554 | 602 | ||
555 | static void nfc_shdlc_t2_timeout(unsigned long data) | 603 | static void llc_shdlc_t2_timeout(unsigned long data) |
556 | { | 604 | { |
557 | struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data; | 605 | struct llc_shdlc *shdlc = (struct llc_shdlc *)data; |
558 | 606 | ||
559 | pr_debug("SoftIRQ: need to retransmit\n"); | 607 | pr_debug("SoftIRQ: need to retransmit\n"); |
560 | 608 | ||
561 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 609 | queue_work(system_nrt_wq, &shdlc->sm_work); |
562 | } | 610 | } |
563 | 611 | ||
564 | static void nfc_shdlc_sm_work(struct work_struct *work) | 612 | static void llc_shdlc_sm_work(struct work_struct *work) |
565 | { | 613 | { |
566 | struct nfc_shdlc *shdlc = container_of(work, struct nfc_shdlc, sm_work); | 614 | struct llc_shdlc *shdlc = container_of(work, struct llc_shdlc, sm_work); |
567 | int r; | 615 | int r; |
568 | 616 | ||
569 | pr_debug("\n"); | 617 | pr_debug("\n"); |
@@ -578,46 +626,47 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
578 | break; | 626 | break; |
579 | case SHDLC_CONNECTING: | 627 | case SHDLC_CONNECTING: |
580 | if (shdlc->hard_fault) { | 628 | if (shdlc->hard_fault) { |
581 | nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); | 629 | llc_shdlc_connect_complete(shdlc, shdlc->hard_fault); |
582 | break; | 630 | break; |
583 | } | 631 | } |
584 | 632 | ||
585 | if (shdlc->connect_tries++ < 5) | 633 | if (shdlc->connect_tries++ < 5) |
586 | r = nfc_shdlc_connect_initiate(shdlc); | 634 | r = llc_shdlc_connect_initiate(shdlc); |
587 | else | 635 | else |
588 | r = -ETIME; | 636 | r = -ETIME; |
589 | if (r < 0) | 637 | if (r < 0) |
590 | nfc_shdlc_connect_complete(shdlc, r); | 638 | llc_shdlc_connect_complete(shdlc, r); |
591 | else { | 639 | else { |
592 | mod_timer(&shdlc->connect_timer, jiffies + | 640 | mod_timer(&shdlc->connect_timer, jiffies + |
593 | msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS)); | 641 | msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS)); |
594 | 642 | ||
595 | shdlc->state = SHDLC_NEGOCIATING; | 643 | shdlc->state = SHDLC_NEGOTIATING; |
596 | } | 644 | } |
597 | break; | 645 | break; |
598 | case SHDLC_NEGOCIATING: | 646 | case SHDLC_NEGOTIATING: |
599 | if (timer_pending(&shdlc->connect_timer) == 0) { | 647 | if (timer_pending(&shdlc->connect_timer) == 0) { |
600 | shdlc->state = SHDLC_CONNECTING; | 648 | shdlc->state = SHDLC_CONNECTING; |
601 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 649 | queue_work(system_nrt_wq, &shdlc->sm_work); |
602 | } | 650 | } |
603 | 651 | ||
604 | nfc_shdlc_handle_rcv_queue(shdlc); | 652 | llc_shdlc_handle_rcv_queue(shdlc); |
605 | 653 | ||
606 | if (shdlc->hard_fault) { | 654 | if (shdlc->hard_fault) { |
607 | nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); | 655 | llc_shdlc_connect_complete(shdlc, shdlc->hard_fault); |
608 | break; | 656 | break; |
609 | } | 657 | } |
610 | break; | 658 | break; |
659 | case SHDLC_HALF_CONNECTED: | ||
611 | case SHDLC_CONNECTED: | 660 | case SHDLC_CONNECTED: |
612 | nfc_shdlc_handle_rcv_queue(shdlc); | 661 | llc_shdlc_handle_rcv_queue(shdlc); |
613 | nfc_shdlc_handle_send_queue(shdlc); | 662 | llc_shdlc_handle_send_queue(shdlc); |
614 | 663 | ||
615 | if (shdlc->t1_active && timer_pending(&shdlc->t1_timer) == 0) { | 664 | if (shdlc->t1_active && timer_pending(&shdlc->t1_timer) == 0) { |
616 | pr_debug | 665 | pr_debug |
617 | ("Handle T1(send ack) elapsed (T1 now inactive)\n"); | 666 | ("Handle T1(send ack) elapsed (T1 now inactive)\n"); |
618 | 667 | ||
619 | shdlc->t1_active = false; | 668 | shdlc->t1_active = false; |
620 | r = nfc_shdlc_send_s_frame(shdlc, S_FRAME_RR, | 669 | r = llc_shdlc_send_s_frame(shdlc, S_FRAME_RR, |
621 | shdlc->nr); | 670 | shdlc->nr); |
622 | if (r < 0) | 671 | if (r < 0) |
623 | shdlc->hard_fault = r; | 672 | shdlc->hard_fault = r; |
@@ -629,12 +678,12 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
629 | 678 | ||
630 | shdlc->t2_active = false; | 679 | shdlc->t2_active = false; |
631 | 680 | ||
632 | nfc_shdlc_requeue_ack_pending(shdlc); | 681 | llc_shdlc_requeue_ack_pending(shdlc); |
633 | nfc_shdlc_handle_send_queue(shdlc); | 682 | llc_shdlc_handle_send_queue(shdlc); |
634 | } | 683 | } |
635 | 684 | ||
636 | if (shdlc->hard_fault) { | 685 | if (shdlc->hard_fault) { |
637 | nfc_hci_driver_failure(shdlc->hdev, shdlc->hard_fault); | 686 | shdlc->llc_failure(shdlc->hdev, shdlc->hard_fault); |
638 | } | 687 | } |
639 | break; | 688 | break; |
640 | default: | 689 | default: |
@@ -647,7 +696,7 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
647 | * Called from syscall context to establish shdlc link. Sleeps until | 696 | * Called from syscall context to establish shdlc link. Sleeps until |
648 | * link is ready or failure. | 697 | * link is ready or failure. |
649 | */ | 698 | */ |
650 | static int nfc_shdlc_connect(struct nfc_shdlc *shdlc) | 699 | static int llc_shdlc_connect(struct llc_shdlc *shdlc) |
651 | { | 700 | { |
652 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(connect_wq); | 701 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(connect_wq); |
653 | 702 | ||
@@ -662,14 +711,14 @@ static int nfc_shdlc_connect(struct nfc_shdlc *shdlc) | |||
662 | 711 | ||
663 | mutex_unlock(&shdlc->state_mutex); | 712 | mutex_unlock(&shdlc->state_mutex); |
664 | 713 | ||
665 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 714 | queue_work(system_nrt_wq, &shdlc->sm_work); |
666 | 715 | ||
667 | wait_event(connect_wq, shdlc->connect_result != 1); | 716 | wait_event(connect_wq, shdlc->connect_result != 1); |
668 | 717 | ||
669 | return shdlc->connect_result; | 718 | return shdlc->connect_result; |
670 | } | 719 | } |
671 | 720 | ||
672 | static void nfc_shdlc_disconnect(struct nfc_shdlc *shdlc) | 721 | static void llc_shdlc_disconnect(struct llc_shdlc *shdlc) |
673 | { | 722 | { |
674 | pr_debug("\n"); | 723 | pr_debug("\n"); |
675 | 724 | ||
@@ -679,7 +728,7 @@ static void nfc_shdlc_disconnect(struct nfc_shdlc *shdlc) | |||
679 | 728 | ||
680 | mutex_unlock(&shdlc->state_mutex); | 729 | mutex_unlock(&shdlc->state_mutex); |
681 | 730 | ||
682 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 731 | queue_work(system_nrt_wq, &shdlc->sm_work); |
683 | } | 732 | } |
684 | 733 | ||
685 | /* | 734 | /* |
@@ -687,7 +736,7 @@ static void nfc_shdlc_disconnect(struct nfc_shdlc *shdlc) | |||
687 | * skb contains only LLC header and payload. | 736 | * skb contains only LLC header and payload. |
688 | * If skb == NULL, it is a notification that the link below is dead. | 737 | * If skb == NULL, it is a notification that the link below is dead. |
689 | */ | 738 | */ |
690 | void nfc_shdlc_recv_frame(struct nfc_shdlc *shdlc, struct sk_buff *skb) | 739 | static void llc_shdlc_recv_frame(struct llc_shdlc *shdlc, struct sk_buff *skb) |
691 | { | 740 | { |
692 | if (skb == NULL) { | 741 | if (skb == NULL) { |
693 | pr_err("NULL Frame -> link is dead\n"); | 742 | pr_err("NULL Frame -> link is dead\n"); |
@@ -697,176 +746,37 @@ void nfc_shdlc_recv_frame(struct nfc_shdlc *shdlc, struct sk_buff *skb) | |||
697 | skb_queue_tail(&shdlc->rcv_q, skb); | 746 | skb_queue_tail(&shdlc->rcv_q, skb); |
698 | } | 747 | } |
699 | 748 | ||
700 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 749 | queue_work(system_nrt_wq, &shdlc->sm_work); |
701 | } | ||
702 | EXPORT_SYMBOL(nfc_shdlc_recv_frame); | ||
703 | |||
704 | static int nfc_shdlc_open(struct nfc_hci_dev *hdev) | ||
705 | { | ||
706 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
707 | int r; | ||
708 | |||
709 | pr_debug("\n"); | ||
710 | |||
711 | if (shdlc->ops->open) { | ||
712 | r = shdlc->ops->open(shdlc); | ||
713 | if (r < 0) | ||
714 | return r; | ||
715 | } | ||
716 | |||
717 | r = nfc_shdlc_connect(shdlc); | ||
718 | if (r < 0 && shdlc->ops->close) | ||
719 | shdlc->ops->close(shdlc); | ||
720 | |||
721 | return r; | ||
722 | } | ||
723 | |||
724 | static void nfc_shdlc_close(struct nfc_hci_dev *hdev) | ||
725 | { | ||
726 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
727 | |||
728 | pr_debug("\n"); | ||
729 | |||
730 | nfc_shdlc_disconnect(shdlc); | ||
731 | |||
732 | if (shdlc->ops->close) | ||
733 | shdlc->ops->close(shdlc); | ||
734 | } | 750 | } |
735 | 751 | ||
736 | static int nfc_shdlc_hci_ready(struct nfc_hci_dev *hdev) | 752 | static void *llc_shdlc_init(struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, |
753 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
754 | int tx_tailroom, int *rx_headroom, int *rx_tailroom, | ||
755 | llc_failure_t llc_failure) | ||
737 | { | 756 | { |
738 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | 757 | struct llc_shdlc *shdlc; |
739 | int r = 0; | ||
740 | |||
741 | pr_debug("\n"); | ||
742 | 758 | ||
743 | if (shdlc->ops->hci_ready) | 759 | *rx_headroom = SHDLC_LLC_HEAD_ROOM; |
744 | r = shdlc->ops->hci_ready(shdlc); | 760 | *rx_tailroom = 0; |
745 | |||
746 | return r; | ||
747 | } | ||
748 | |||
749 | static int nfc_shdlc_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb) | ||
750 | { | ||
751 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
752 | |||
753 | SHDLC_DUMP_SKB("queuing HCP packet to shdlc", skb); | ||
754 | |||
755 | skb_queue_tail(&shdlc->send_q, skb); | ||
756 | 761 | ||
757 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 762 | shdlc = kzalloc(sizeof(struct llc_shdlc), GFP_KERNEL); |
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev, | ||
763 | u32 im_protocols, u32 tm_protocols) | ||
764 | { | ||
765 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
766 | |||
767 | pr_debug("\n"); | ||
768 | |||
769 | if (shdlc->ops->start_poll) | ||
770 | return shdlc->ops->start_poll(shdlc, | ||
771 | im_protocols, tm_protocols); | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static int nfc_shdlc_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, | ||
777 | struct nfc_target *target) | ||
778 | { | ||
779 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
780 | |||
781 | if (shdlc->ops->target_from_gate) | ||
782 | return shdlc->ops->target_from_gate(shdlc, gate, target); | ||
783 | |||
784 | return -EPERM; | ||
785 | } | ||
786 | |||
787 | static int nfc_shdlc_complete_target_discovered(struct nfc_hci_dev *hdev, | ||
788 | u8 gate, | ||
789 | struct nfc_target *target) | ||
790 | { | ||
791 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
792 | |||
793 | pr_debug("\n"); | ||
794 | |||
795 | if (shdlc->ops->complete_target_discovered) | ||
796 | return shdlc->ops->complete_target_discovered(shdlc, gate, | ||
797 | target); | ||
798 | |||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev, | ||
803 | struct nfc_target *target, | ||
804 | struct sk_buff *skb, | ||
805 | struct sk_buff **res_skb) | ||
806 | { | ||
807 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
808 | |||
809 | if (shdlc->ops->data_exchange) | ||
810 | return shdlc->ops->data_exchange(shdlc, target, skb, res_skb); | ||
811 | |||
812 | return -EPERM; | ||
813 | } | ||
814 | |||
815 | static int nfc_shdlc_check_presence(struct nfc_hci_dev *hdev, | ||
816 | struct nfc_target *target) | ||
817 | { | ||
818 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
819 | |||
820 | if (shdlc->ops->check_presence) | ||
821 | return shdlc->ops->check_presence(shdlc, target); | ||
822 | |||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | static struct nfc_hci_ops shdlc_ops = { | ||
827 | .open = nfc_shdlc_open, | ||
828 | .close = nfc_shdlc_close, | ||
829 | .hci_ready = nfc_shdlc_hci_ready, | ||
830 | .xmit = nfc_shdlc_xmit, | ||
831 | .start_poll = nfc_shdlc_start_poll, | ||
832 | .target_from_gate = nfc_shdlc_target_from_gate, | ||
833 | .complete_target_discovered = nfc_shdlc_complete_target_discovered, | ||
834 | .data_exchange = nfc_shdlc_data_exchange, | ||
835 | .check_presence = nfc_shdlc_check_presence, | ||
836 | }; | ||
837 | |||
838 | struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, | ||
839 | struct nfc_hci_init_data *init_data, | ||
840 | u32 protocols, | ||
841 | int tx_headroom, int tx_tailroom, | ||
842 | int max_link_payload, const char *devname) | ||
843 | { | ||
844 | struct nfc_shdlc *shdlc; | ||
845 | int r; | ||
846 | char name[32]; | ||
847 | |||
848 | if (ops->xmit == NULL) | ||
849 | return NULL; | ||
850 | |||
851 | shdlc = kzalloc(sizeof(struct nfc_shdlc), GFP_KERNEL); | ||
852 | if (shdlc == NULL) | 763 | if (shdlc == NULL) |
853 | return NULL; | 764 | return NULL; |
854 | 765 | ||
855 | mutex_init(&shdlc->state_mutex); | 766 | mutex_init(&shdlc->state_mutex); |
856 | shdlc->ops = ops; | ||
857 | shdlc->state = SHDLC_DISCONNECTED; | 767 | shdlc->state = SHDLC_DISCONNECTED; |
858 | 768 | ||
859 | init_timer(&shdlc->connect_timer); | 769 | init_timer(&shdlc->connect_timer); |
860 | shdlc->connect_timer.data = (unsigned long)shdlc; | 770 | shdlc->connect_timer.data = (unsigned long)shdlc; |
861 | shdlc->connect_timer.function = nfc_shdlc_connect_timeout; | 771 | shdlc->connect_timer.function = llc_shdlc_connect_timeout; |
862 | 772 | ||
863 | init_timer(&shdlc->t1_timer); | 773 | init_timer(&shdlc->t1_timer); |
864 | shdlc->t1_timer.data = (unsigned long)shdlc; | 774 | shdlc->t1_timer.data = (unsigned long)shdlc; |
865 | shdlc->t1_timer.function = nfc_shdlc_t1_timeout; | 775 | shdlc->t1_timer.function = llc_shdlc_t1_timeout; |
866 | 776 | ||
867 | init_timer(&shdlc->t2_timer); | 777 | init_timer(&shdlc->t2_timer); |
868 | shdlc->t2_timer.data = (unsigned long)shdlc; | 778 | shdlc->t2_timer.data = (unsigned long)shdlc; |
869 | shdlc->t2_timer.function = nfc_shdlc_t2_timeout; | 779 | shdlc->t2_timer.function = llc_shdlc_t2_timeout; |
870 | 780 | ||
871 | shdlc->w = SHDLC_MAX_WINDOW; | 781 | shdlc->w = SHDLC_MAX_WINDOW; |
872 | shdlc->srej_support = SHDLC_SREJ_SUPPORT; | 782 | shdlc->srej_support = SHDLC_SREJ_SUPPORT; |
@@ -875,77 +785,73 @@ struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, | |||
875 | skb_queue_head_init(&shdlc->send_q); | 785 | skb_queue_head_init(&shdlc->send_q); |
876 | skb_queue_head_init(&shdlc->ack_pending_q); | 786 | skb_queue_head_init(&shdlc->ack_pending_q); |
877 | 787 | ||
878 | INIT_WORK(&shdlc->sm_work, nfc_shdlc_sm_work); | 788 | INIT_WORK(&shdlc->sm_work, llc_shdlc_sm_work); |
879 | snprintf(name, sizeof(name), "%s_shdlc_sm_wq", devname); | ||
880 | shdlc->sm_wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND | | ||
881 | WQ_MEM_RECLAIM, 1); | ||
882 | if (shdlc->sm_wq == NULL) | ||
883 | goto err_allocwq; | ||
884 | 789 | ||
885 | shdlc->client_headroom = tx_headroom; | 790 | shdlc->hdev = hdev; |
886 | shdlc->client_tailroom = tx_tailroom; | 791 | shdlc->xmit_to_drv = xmit_to_drv; |
887 | 792 | shdlc->rcv_to_hci = rcv_to_hci; | |
888 | shdlc->hdev = nfc_hci_allocate_device(&shdlc_ops, init_data, protocols, | 793 | shdlc->tx_headroom = tx_headroom; |
889 | tx_headroom + SHDLC_LLC_HEAD_ROOM, | 794 | shdlc->tx_tailroom = tx_tailroom; |
890 | tx_tailroom + SHDLC_LLC_TAIL_ROOM, | 795 | shdlc->llc_failure = llc_failure; |
891 | max_link_payload); | ||
892 | if (shdlc->hdev == NULL) | ||
893 | goto err_allocdev; | ||
894 | |||
895 | nfc_hci_set_clientdata(shdlc->hdev, shdlc); | ||
896 | |||
897 | r = nfc_hci_register_device(shdlc->hdev); | ||
898 | if (r < 0) | ||
899 | goto err_regdev; | ||
900 | 796 | ||
901 | return shdlc; | 797 | return shdlc; |
798 | } | ||
902 | 799 | ||
903 | err_regdev: | 800 | static void llc_shdlc_deinit(struct nfc_llc *llc) |
904 | nfc_hci_free_device(shdlc->hdev); | 801 | { |
802 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); | ||
905 | 803 | ||
906 | err_allocdev: | 804 | skb_queue_purge(&shdlc->rcv_q); |
907 | destroy_workqueue(shdlc->sm_wq); | 805 | skb_queue_purge(&shdlc->send_q); |
806 | skb_queue_purge(&shdlc->ack_pending_q); | ||
908 | 807 | ||
909 | err_allocwq: | ||
910 | kfree(shdlc); | 808 | kfree(shdlc); |
911 | |||
912 | return NULL; | ||
913 | } | 809 | } |
914 | EXPORT_SYMBOL(nfc_shdlc_allocate); | ||
915 | 810 | ||
916 | void nfc_shdlc_free(struct nfc_shdlc *shdlc) | 811 | static int llc_shdlc_start(struct nfc_llc *llc) |
917 | { | 812 | { |
918 | pr_debug("\n"); | 813 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); |
919 | 814 | ||
920 | nfc_hci_unregister_device(shdlc->hdev); | 815 | return llc_shdlc_connect(shdlc); |
921 | nfc_hci_free_device(shdlc->hdev); | 816 | } |
922 | 817 | ||
923 | destroy_workqueue(shdlc->sm_wq); | 818 | static int llc_shdlc_stop(struct nfc_llc *llc) |
819 | { | ||
820 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); | ||
924 | 821 | ||
925 | skb_queue_purge(&shdlc->rcv_q); | 822 | llc_shdlc_disconnect(shdlc); |
926 | skb_queue_purge(&shdlc->send_q); | ||
927 | skb_queue_purge(&shdlc->ack_pending_q); | ||
928 | 823 | ||
929 | kfree(shdlc); | 824 | return 0; |
930 | } | 825 | } |
931 | EXPORT_SYMBOL(nfc_shdlc_free); | ||
932 | 826 | ||
933 | void nfc_shdlc_set_clientdata(struct nfc_shdlc *shdlc, void *clientdata) | 827 | static void llc_shdlc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb) |
934 | { | 828 | { |
935 | pr_debug("\n"); | 829 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); |
936 | 830 | ||
937 | shdlc->clientdata = clientdata; | 831 | llc_shdlc_recv_frame(shdlc, skb); |
938 | } | 832 | } |
939 | EXPORT_SYMBOL(nfc_shdlc_set_clientdata); | ||
940 | 833 | ||
941 | void *nfc_shdlc_get_clientdata(struct nfc_shdlc *shdlc) | 834 | static int llc_shdlc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb) |
942 | { | 835 | { |
943 | return shdlc->clientdata; | 836 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); |
837 | |||
838 | skb_queue_tail(&shdlc->send_q, skb); | ||
839 | |||
840 | queue_work(system_nrt_wq, &shdlc->sm_work); | ||
841 | |||
842 | return 0; | ||
944 | } | 843 | } |
945 | EXPORT_SYMBOL(nfc_shdlc_get_clientdata); | ||
946 | 844 | ||
947 | struct nfc_hci_dev *nfc_shdlc_get_hci_dev(struct nfc_shdlc *shdlc) | 845 | static struct nfc_llc_ops llc_shdlc_ops = { |
846 | .init = llc_shdlc_init, | ||
847 | .deinit = llc_shdlc_deinit, | ||
848 | .start = llc_shdlc_start, | ||
849 | .stop = llc_shdlc_stop, | ||
850 | .rcv_from_drv = llc_shdlc_rcv_from_drv, | ||
851 | .xmit_from_hci = llc_shdlc_xmit_from_hci, | ||
852 | }; | ||
853 | |||
854 | int nfc_llc_shdlc_register(void) | ||
948 | { | 855 | { |
949 | return shdlc->hdev; | 856 | return nfc_llc_register(LLC_SHDLC_NAME, &llc_shdlc_ops); |
950 | } | 857 | } |
951 | EXPORT_SYMBOL(nfc_shdlc_get_hci_dev); | ||
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index b982b5b890d7..c45ccd6c094c 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c | |||
@@ -312,6 +312,8 @@ int nfc_llcp_send_symm(struct nfc_dev *dev) | |||
312 | 312 | ||
313 | skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM); | 313 | skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM); |
314 | 314 | ||
315 | nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_TX); | ||
316 | |||
315 | return nfc_data_exchange(dev, local->target_idx, skb, | 317 | return nfc_data_exchange(dev, local->target_idx, skb, |
316 | nfc_llcp_recv, local); | 318 | nfc_llcp_recv, local); |
317 | } | 319 | } |
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 82f0f7588b46..c12c5ef3d036 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
@@ -56,7 +56,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) | |||
56 | sk_for_each_safe(sk, node, tmp, &local->sockets.head) { | 56 | sk_for_each_safe(sk, node, tmp, &local->sockets.head) { |
57 | llcp_sock = nfc_llcp_sock(sk); | 57 | llcp_sock = nfc_llcp_sock(sk); |
58 | 58 | ||
59 | lock_sock(sk); | 59 | bh_lock_sock(sk); |
60 | 60 | ||
61 | if (sk->sk_state == LLCP_CONNECTED) | 61 | if (sk->sk_state == LLCP_CONNECTED) |
62 | nfc_put_device(llcp_sock->dev); | 62 | nfc_put_device(llcp_sock->dev); |
@@ -68,26 +68,26 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) | |||
68 | list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue, | 68 | list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue, |
69 | accept_queue) { | 69 | accept_queue) { |
70 | accept_sk = &lsk->sk; | 70 | accept_sk = &lsk->sk; |
71 | lock_sock(accept_sk); | 71 | bh_lock_sock(accept_sk); |
72 | 72 | ||
73 | nfc_llcp_accept_unlink(accept_sk); | 73 | nfc_llcp_accept_unlink(accept_sk); |
74 | 74 | ||
75 | accept_sk->sk_state = LLCP_CLOSED; | 75 | accept_sk->sk_state = LLCP_CLOSED; |
76 | 76 | ||
77 | release_sock(accept_sk); | 77 | bh_unlock_sock(accept_sk); |
78 | 78 | ||
79 | sock_orphan(accept_sk); | 79 | sock_orphan(accept_sk); |
80 | } | 80 | } |
81 | 81 | ||
82 | if (listen == true) { | 82 | if (listen == true) { |
83 | release_sock(sk); | 83 | bh_unlock_sock(sk); |
84 | continue; | 84 | continue; |
85 | } | 85 | } |
86 | } | 86 | } |
87 | 87 | ||
88 | sk->sk_state = LLCP_CLOSED; | 88 | sk->sk_state = LLCP_CLOSED; |
89 | 89 | ||
90 | release_sock(sk); | 90 | bh_unlock_sock(sk); |
91 | 91 | ||
92 | sock_orphan(sk); | 92 | sock_orphan(sk); |
93 | 93 | ||
@@ -114,9 +114,9 @@ static void local_release(struct kref *ref) | |||
114 | nfc_llcp_socket_release(local, false); | 114 | nfc_llcp_socket_release(local, false); |
115 | del_timer_sync(&local->link_timer); | 115 | del_timer_sync(&local->link_timer); |
116 | skb_queue_purge(&local->tx_queue); | 116 | skb_queue_purge(&local->tx_queue); |
117 | destroy_workqueue(local->tx_wq); | 117 | cancel_work_sync(&local->tx_work); |
118 | destroy_workqueue(local->rx_wq); | 118 | cancel_work_sync(&local->rx_work); |
119 | destroy_workqueue(local->timeout_wq); | 119 | cancel_work_sync(&local->timeout_work); |
120 | kfree_skb(local->rx_pending); | 120 | kfree_skb(local->rx_pending); |
121 | kfree(local); | 121 | kfree(local); |
122 | } | 122 | } |
@@ -181,7 +181,7 @@ static void nfc_llcp_symm_timer(unsigned long data) | |||
181 | 181 | ||
182 | pr_err("SYMM timeout\n"); | 182 | pr_err("SYMM timeout\n"); |
183 | 183 | ||
184 | queue_work(local->timeout_wq, &local->timeout_work); | 184 | queue_work(system_nrt_wq, &local->timeout_work); |
185 | } | 185 | } |
186 | 186 | ||
187 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) | 187 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) |
@@ -426,6 +426,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | |||
426 | u8 *miux_tlv, miux_length; | 426 | u8 *miux_tlv, miux_length; |
427 | __be16 miux; | 427 | __be16 miux; |
428 | u8 gb_len = 0; | 428 | u8 gb_len = 0; |
429 | int ret = 0; | ||
429 | 430 | ||
430 | version = LLCP_VERSION_11; | 431 | version = LLCP_VERSION_11; |
431 | version_tlv = nfc_llcp_build_tlv(LLCP_TLV_VERSION, &version, | 432 | version_tlv = nfc_llcp_build_tlv(LLCP_TLV_VERSION, &version, |
@@ -450,8 +451,8 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | |||
450 | gb_len += ARRAY_SIZE(llcp_magic); | 451 | gb_len += ARRAY_SIZE(llcp_magic); |
451 | 452 | ||
452 | if (gb_len > NFC_MAX_GT_LEN) { | 453 | if (gb_len > NFC_MAX_GT_LEN) { |
453 | kfree(version_tlv); | 454 | ret = -EINVAL; |
454 | return -EINVAL; | 455 | goto out; |
455 | } | 456 | } |
456 | 457 | ||
457 | gb_cur = local->gb; | 458 | gb_cur = local->gb; |
@@ -471,12 +472,15 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | |||
471 | memcpy(gb_cur, miux_tlv, miux_length); | 472 | memcpy(gb_cur, miux_tlv, miux_length); |
472 | gb_cur += miux_length; | 473 | gb_cur += miux_length; |
473 | 474 | ||
475 | local->gb_len = gb_len; | ||
476 | |||
477 | out: | ||
474 | kfree(version_tlv); | 478 | kfree(version_tlv); |
475 | kfree(lto_tlv); | 479 | kfree(lto_tlv); |
480 | kfree(wks_tlv); | ||
481 | kfree(miux_tlv); | ||
476 | 482 | ||
477 | local->gb_len = gb_len; | 483 | return ret; |
478 | |||
479 | return 0; | ||
480 | } | 484 | } |
481 | 485 | ||
482 | u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) | 486 | u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) |
@@ -554,6 +558,46 @@ static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu) | |||
554 | sock->recv_ack_n = (sock->recv_n - 1) % 16; | 558 | sock->recv_ack_n = (sock->recv_n - 1) % 16; |
555 | } | 559 | } |
556 | 560 | ||
561 | void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local, | ||
562 | struct sk_buff *skb, u8 direction) | ||
563 | { | ||
564 | struct hlist_node *node; | ||
565 | struct sk_buff *skb_copy = NULL, *nskb; | ||
566 | struct sock *sk; | ||
567 | u8 *data; | ||
568 | |||
569 | read_lock(&local->raw_sockets.lock); | ||
570 | |||
571 | sk_for_each(sk, node, &local->raw_sockets.head) { | ||
572 | if (sk->sk_state != LLCP_BOUND) | ||
573 | continue; | ||
574 | |||
575 | if (skb_copy == NULL) { | ||
576 | skb_copy = __pskb_copy(skb, NFC_LLCP_RAW_HEADER_SIZE, | ||
577 | GFP_ATOMIC); | ||
578 | |||
579 | if (skb_copy == NULL) | ||
580 | continue; | ||
581 | |||
582 | data = skb_push(skb_copy, NFC_LLCP_RAW_HEADER_SIZE); | ||
583 | |||
584 | data[0] = local->dev ? local->dev->idx : 0xFF; | ||
585 | data[1] = direction; | ||
586 | } | ||
587 | |||
588 | nskb = skb_clone(skb_copy, GFP_ATOMIC); | ||
589 | if (!nskb) | ||
590 | continue; | ||
591 | |||
592 | if (sock_queue_rcv_skb(sk, nskb)) | ||
593 | kfree_skb(nskb); | ||
594 | } | ||
595 | |||
596 | read_unlock(&local->raw_sockets.lock); | ||
597 | |||
598 | kfree_skb(skb_copy); | ||
599 | } | ||
600 | |||
557 | static void nfc_llcp_tx_work(struct work_struct *work) | 601 | static void nfc_llcp_tx_work(struct work_struct *work) |
558 | { | 602 | { |
559 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, | 603 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, |
@@ -574,6 +618,9 @@ static void nfc_llcp_tx_work(struct work_struct *work) | |||
574 | DUMP_PREFIX_OFFSET, 16, 1, | 618 | DUMP_PREFIX_OFFSET, 16, 1, |
575 | skb->data, skb->len, true); | 619 | skb->data, skb->len, true); |
576 | 620 | ||
621 | nfc_llcp_send_to_raw_sock(local, skb, | ||
622 | NFC_LLCP_DIRECTION_TX); | ||
623 | |||
577 | ret = nfc_data_exchange(local->dev, local->target_idx, | 624 | ret = nfc_data_exchange(local->dev, local->target_idx, |
578 | skb, nfc_llcp_recv, local); | 625 | skb, nfc_llcp_recv, local); |
579 | 626 | ||
@@ -1018,6 +1065,8 @@ static void nfc_llcp_rx_work(struct work_struct *work) | |||
1018 | print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET, | 1065 | print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET, |
1019 | 16, 1, skb->data, skb->len, true); | 1066 | 16, 1, skb->data, skb->len, true); |
1020 | 1067 | ||
1068 | nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX); | ||
1069 | |||
1021 | switch (ptype) { | 1070 | switch (ptype) { |
1022 | case LLCP_PDU_SYMM: | 1071 | case LLCP_PDU_SYMM: |
1023 | pr_debug("SYMM\n"); | 1072 | pr_debug("SYMM\n"); |
@@ -1052,7 +1101,7 @@ static void nfc_llcp_rx_work(struct work_struct *work) | |||
1052 | 1101 | ||
1053 | } | 1102 | } |
1054 | 1103 | ||
1055 | queue_work(local->tx_wq, &local->tx_work); | 1104 | queue_work(system_nrt_wq, &local->tx_work); |
1056 | kfree_skb(local->rx_pending); | 1105 | kfree_skb(local->rx_pending); |
1057 | local->rx_pending = NULL; | 1106 | local->rx_pending = NULL; |
1058 | 1107 | ||
@@ -1071,7 +1120,7 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err) | |||
1071 | 1120 | ||
1072 | local->rx_pending = skb_get(skb); | 1121 | local->rx_pending = skb_get(skb); |
1073 | del_timer(&local->link_timer); | 1122 | del_timer(&local->link_timer); |
1074 | queue_work(local->rx_wq, &local->rx_work); | 1123 | queue_work(system_nrt_wq, &local->rx_work); |
1075 | 1124 | ||
1076 | return; | 1125 | return; |
1077 | } | 1126 | } |
@@ -1086,7 +1135,7 @@ int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb) | |||
1086 | 1135 | ||
1087 | local->rx_pending = skb_get(skb); | 1136 | local->rx_pending = skb_get(skb); |
1088 | del_timer(&local->link_timer); | 1137 | del_timer(&local->link_timer); |
1089 | queue_work(local->rx_wq, &local->rx_work); | 1138 | queue_work(system_nrt_wq, &local->rx_work); |
1090 | 1139 | ||
1091 | return 0; | 1140 | return 0; |
1092 | } | 1141 | } |
@@ -1121,7 +1170,7 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, | |||
1121 | if (rf_mode == NFC_RF_INITIATOR) { | 1170 | if (rf_mode == NFC_RF_INITIATOR) { |
1122 | pr_debug("Queueing Tx work\n"); | 1171 | pr_debug("Queueing Tx work\n"); |
1123 | 1172 | ||
1124 | queue_work(local->tx_wq, &local->tx_work); | 1173 | queue_work(system_nrt_wq, &local->tx_work); |
1125 | } else { | 1174 | } else { |
1126 | mod_timer(&local->link_timer, | 1175 | mod_timer(&local->link_timer, |
1127 | jiffies + msecs_to_jiffies(local->remote_lto)); | 1176 | jiffies + msecs_to_jiffies(local->remote_lto)); |
@@ -1130,10 +1179,7 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, | |||
1130 | 1179 | ||
1131 | int nfc_llcp_register_device(struct nfc_dev *ndev) | 1180 | int nfc_llcp_register_device(struct nfc_dev *ndev) |
1132 | { | 1181 | { |
1133 | struct device *dev = &ndev->dev; | ||
1134 | struct nfc_llcp_local *local; | 1182 | struct nfc_llcp_local *local; |
1135 | char name[32]; | ||
1136 | int err; | ||
1137 | 1183 | ||
1138 | local = kzalloc(sizeof(struct nfc_llcp_local), GFP_KERNEL); | 1184 | local = kzalloc(sizeof(struct nfc_llcp_local), GFP_KERNEL); |
1139 | if (local == NULL) | 1185 | if (local == NULL) |
@@ -1149,41 +1195,15 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) | |||
1149 | 1195 | ||
1150 | skb_queue_head_init(&local->tx_queue); | 1196 | skb_queue_head_init(&local->tx_queue); |
1151 | INIT_WORK(&local->tx_work, nfc_llcp_tx_work); | 1197 | INIT_WORK(&local->tx_work, nfc_llcp_tx_work); |
1152 | snprintf(name, sizeof(name), "%s_llcp_tx_wq", dev_name(dev)); | ||
1153 | local->tx_wq = | ||
1154 | alloc_workqueue(name, | ||
1155 | WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, | ||
1156 | 1); | ||
1157 | if (local->tx_wq == NULL) { | ||
1158 | err = -ENOMEM; | ||
1159 | goto err_local; | ||
1160 | } | ||
1161 | 1198 | ||
1162 | local->rx_pending = NULL; | 1199 | local->rx_pending = NULL; |
1163 | INIT_WORK(&local->rx_work, nfc_llcp_rx_work); | 1200 | INIT_WORK(&local->rx_work, nfc_llcp_rx_work); |
1164 | snprintf(name, sizeof(name), "%s_llcp_rx_wq", dev_name(dev)); | ||
1165 | local->rx_wq = | ||
1166 | alloc_workqueue(name, | ||
1167 | WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, | ||
1168 | 1); | ||
1169 | if (local->rx_wq == NULL) { | ||
1170 | err = -ENOMEM; | ||
1171 | goto err_tx_wq; | ||
1172 | } | ||
1173 | 1201 | ||
1174 | INIT_WORK(&local->timeout_work, nfc_llcp_timeout_work); | 1202 | INIT_WORK(&local->timeout_work, nfc_llcp_timeout_work); |
1175 | snprintf(name, sizeof(name), "%s_llcp_timeout_wq", dev_name(dev)); | ||
1176 | local->timeout_wq = | ||
1177 | alloc_workqueue(name, | ||
1178 | WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, | ||
1179 | 1); | ||
1180 | if (local->timeout_wq == NULL) { | ||
1181 | err = -ENOMEM; | ||
1182 | goto err_rx_wq; | ||
1183 | } | ||
1184 | 1203 | ||
1185 | local->sockets.lock = __RW_LOCK_UNLOCKED(local->sockets.lock); | 1204 | rwlock_init(&local->sockets.lock); |
1186 | local->connecting_sockets.lock = __RW_LOCK_UNLOCKED(local->connecting_sockets.lock); | 1205 | rwlock_init(&local->connecting_sockets.lock); |
1206 | rwlock_init(&local->raw_sockets.lock); | ||
1187 | 1207 | ||
1188 | nfc_llcp_build_gb(local); | 1208 | nfc_llcp_build_gb(local); |
1189 | 1209 | ||
@@ -1193,17 +1213,6 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) | |||
1193 | list_add(&llcp_devices, &local->list); | 1213 | list_add(&llcp_devices, &local->list); |
1194 | 1214 | ||
1195 | return 0; | 1215 | return 0; |
1196 | |||
1197 | err_rx_wq: | ||
1198 | destroy_workqueue(local->rx_wq); | ||
1199 | |||
1200 | err_tx_wq: | ||
1201 | destroy_workqueue(local->tx_wq); | ||
1202 | |||
1203 | err_local: | ||
1204 | kfree(local); | ||
1205 | |||
1206 | return 0; | ||
1207 | } | 1216 | } |
1208 | 1217 | ||
1209 | void nfc_llcp_unregister_device(struct nfc_dev *dev) | 1218 | void nfc_llcp_unregister_device(struct nfc_dev *dev) |
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 83b8bba5a280..fdb2d24e60bd 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h | |||
@@ -56,12 +56,9 @@ struct nfc_llcp_local { | |||
56 | 56 | ||
57 | struct timer_list link_timer; | 57 | struct timer_list link_timer; |
58 | struct sk_buff_head tx_queue; | 58 | struct sk_buff_head tx_queue; |
59 | struct workqueue_struct *tx_wq; | ||
60 | struct work_struct tx_work; | 59 | struct work_struct tx_work; |
61 | struct workqueue_struct *rx_wq; | ||
62 | struct work_struct rx_work; | 60 | struct work_struct rx_work; |
63 | struct sk_buff *rx_pending; | 61 | struct sk_buff *rx_pending; |
64 | struct workqueue_struct *timeout_wq; | ||
65 | struct work_struct timeout_work; | 62 | struct work_struct timeout_work; |
66 | 63 | ||
67 | u32 target_idx; | 64 | u32 target_idx; |
@@ -89,6 +86,7 @@ struct nfc_llcp_local { | |||
89 | /* sockets array */ | 86 | /* sockets array */ |
90 | struct llcp_sock_list sockets; | 87 | struct llcp_sock_list sockets; |
91 | struct llcp_sock_list connecting_sockets; | 88 | struct llcp_sock_list connecting_sockets; |
89 | struct llcp_sock_list raw_sockets; | ||
92 | }; | 90 | }; |
93 | 91 | ||
94 | struct nfc_llcp_sock { | 92 | struct nfc_llcp_sock { |
@@ -187,6 +185,8 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, | |||
187 | u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local); | 185 | u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local); |
188 | void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap); | 186 | void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap); |
189 | int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock); | 187 | int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock); |
188 | void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local, | ||
189 | struct sk_buff *skb, u8 direction); | ||
190 | 190 | ||
191 | /* Sock API */ | 191 | /* Sock API */ |
192 | struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp); | 192 | struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp); |
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index ddeb9aa398f0..40f056debf9a 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c | |||
@@ -142,6 +142,60 @@ error: | |||
142 | return ret; | 142 | return ret; |
143 | } | 143 | } |
144 | 144 | ||
145 | static int llcp_raw_sock_bind(struct socket *sock, struct sockaddr *addr, | ||
146 | int alen) | ||
147 | { | ||
148 | struct sock *sk = sock->sk; | ||
149 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | ||
150 | struct nfc_llcp_local *local; | ||
151 | struct nfc_dev *dev; | ||
152 | struct sockaddr_nfc_llcp llcp_addr; | ||
153 | int len, ret = 0; | ||
154 | |||
155 | if (!addr || addr->sa_family != AF_NFC) | ||
156 | return -EINVAL; | ||
157 | |||
158 | pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); | ||
159 | |||
160 | memset(&llcp_addr, 0, sizeof(llcp_addr)); | ||
161 | len = min_t(unsigned int, sizeof(llcp_addr), alen); | ||
162 | memcpy(&llcp_addr, addr, len); | ||
163 | |||
164 | lock_sock(sk); | ||
165 | |||
166 | if (sk->sk_state != LLCP_CLOSED) { | ||
167 | ret = -EBADFD; | ||
168 | goto error; | ||
169 | } | ||
170 | |||
171 | dev = nfc_get_device(llcp_addr.dev_idx); | ||
172 | if (dev == NULL) { | ||
173 | ret = -ENODEV; | ||
174 | goto error; | ||
175 | } | ||
176 | |||
177 | local = nfc_llcp_find_local(dev); | ||
178 | if (local == NULL) { | ||
179 | ret = -ENODEV; | ||
180 | goto put_dev; | ||
181 | } | ||
182 | |||
183 | llcp_sock->dev = dev; | ||
184 | llcp_sock->local = nfc_llcp_local_get(local); | ||
185 | llcp_sock->nfc_protocol = llcp_addr.nfc_protocol; | ||
186 | |||
187 | nfc_llcp_sock_link(&local->raw_sockets, sk); | ||
188 | |||
189 | sk->sk_state = LLCP_BOUND; | ||
190 | |||
191 | put_dev: | ||
192 | nfc_put_device(dev); | ||
193 | |||
194 | error: | ||
195 | release_sock(sk); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
145 | static int llcp_sock_listen(struct socket *sock, int backlog) | 199 | static int llcp_sock_listen(struct socket *sock, int backlog) |
146 | { | 200 | { |
147 | struct sock *sk = sock->sk; | 201 | struct sock *sk = sock->sk; |
@@ -300,9 +354,6 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr, | |||
300 | pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, | 354 | pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, |
301 | llcp_sock->dsap, llcp_sock->ssap); | 355 | llcp_sock->dsap, llcp_sock->ssap); |
302 | 356 | ||
303 | if (llcp_sock == NULL || llcp_sock->dev == NULL) | ||
304 | return -EBADFD; | ||
305 | |||
306 | uaddr->sa_family = AF_NFC; | 357 | uaddr->sa_family = AF_NFC; |
307 | 358 | ||
308 | *len = sizeof(struct sockaddr_nfc_llcp); | 359 | *len = sizeof(struct sockaddr_nfc_llcp); |
@@ -421,7 +472,10 @@ static int llcp_sock_release(struct socket *sock) | |||
421 | 472 | ||
422 | release_sock(sk); | 473 | release_sock(sk); |
423 | 474 | ||
424 | nfc_llcp_sock_unlink(&local->sockets, sk); | 475 | if (sock->type == SOCK_RAW) |
476 | nfc_llcp_sock_unlink(&local->raw_sockets, sk); | ||
477 | else | ||
478 | nfc_llcp_sock_unlink(&local->sockets, sk); | ||
425 | 479 | ||
426 | out: | 480 | out: |
427 | sock_orphan(sk); | 481 | sock_orphan(sk); |
@@ -617,7 +671,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
617 | if (!(flags & MSG_PEEK)) { | 671 | if (!(flags & MSG_PEEK)) { |
618 | 672 | ||
619 | /* SOCK_STREAM: re-queue skb if it contains unreceived data */ | 673 | /* SOCK_STREAM: re-queue skb if it contains unreceived data */ |
620 | if (sk->sk_type == SOCK_STREAM) { | 674 | if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_RAW) { |
621 | skb_pull(skb, copied); | 675 | skb_pull(skb, copied); |
622 | if (skb->len) { | 676 | if (skb->len) { |
623 | skb_queue_head(&sk->sk_receive_queue, skb); | 677 | skb_queue_head(&sk->sk_receive_queue, skb); |
@@ -658,6 +712,26 @@ static const struct proto_ops llcp_sock_ops = { | |||
658 | .mmap = sock_no_mmap, | 712 | .mmap = sock_no_mmap, |
659 | }; | 713 | }; |
660 | 714 | ||
715 | static const struct proto_ops llcp_rawsock_ops = { | ||
716 | .family = PF_NFC, | ||
717 | .owner = THIS_MODULE, | ||
718 | .bind = llcp_raw_sock_bind, | ||
719 | .connect = sock_no_connect, | ||
720 | .release = llcp_sock_release, | ||
721 | .socketpair = sock_no_socketpair, | ||
722 | .accept = sock_no_accept, | ||
723 | .getname = llcp_sock_getname, | ||
724 | .poll = llcp_sock_poll, | ||
725 | .ioctl = sock_no_ioctl, | ||
726 | .listen = sock_no_listen, | ||
727 | .shutdown = sock_no_shutdown, | ||
728 | .setsockopt = sock_no_setsockopt, | ||
729 | .getsockopt = sock_no_getsockopt, | ||
730 | .sendmsg = sock_no_sendmsg, | ||
731 | .recvmsg = llcp_sock_recvmsg, | ||
732 | .mmap = sock_no_mmap, | ||
733 | }; | ||
734 | |||
661 | static void llcp_sock_destruct(struct sock *sk) | 735 | static void llcp_sock_destruct(struct sock *sk) |
662 | { | 736 | { |
663 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | 737 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); |
@@ -735,10 +809,15 @@ static int llcp_sock_create(struct net *net, struct socket *sock, | |||
735 | 809 | ||
736 | pr_debug("%p\n", sock); | 810 | pr_debug("%p\n", sock); |
737 | 811 | ||
738 | if (sock->type != SOCK_STREAM && sock->type != SOCK_DGRAM) | 812 | if (sock->type != SOCK_STREAM && |
813 | sock->type != SOCK_DGRAM && | ||
814 | sock->type != SOCK_RAW) | ||
739 | return -ESOCKTNOSUPPORT; | 815 | return -ESOCKTNOSUPPORT; |
740 | 816 | ||
741 | sock->ops = &llcp_sock_ops; | 817 | if (sock->type == SOCK_RAW) |
818 | sock->ops = &llcp_rawsock_ops; | ||
819 | else | ||
820 | sock->ops = &llcp_sock_ops; | ||
742 | 821 | ||
743 | sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC); | 822 | sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC); |
744 | if (sk == NULL) | 823 | if (sk == NULL) |
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index f81efe13985a..acf9abb7d99b 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c | |||
@@ -176,6 +176,27 @@ static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt) | |||
176 | (1 + ((*num) * sizeof(struct disc_map_config))), &cmd); | 176 | (1 + ((*num) * sizeof(struct disc_map_config))), &cmd); |
177 | } | 177 | } |
178 | 178 | ||
179 | struct nci_set_config_param { | ||
180 | __u8 id; | ||
181 | size_t len; | ||
182 | __u8 *val; | ||
183 | }; | ||
184 | |||
185 | static void nci_set_config_req(struct nci_dev *ndev, unsigned long opt) | ||
186 | { | ||
187 | struct nci_set_config_param *param = (struct nci_set_config_param *)opt; | ||
188 | struct nci_core_set_config_cmd cmd; | ||
189 | |||
190 | BUG_ON(param->len > NCI_MAX_PARAM_LEN); | ||
191 | |||
192 | cmd.num_params = 1; | ||
193 | cmd.param.id = param->id; | ||
194 | cmd.param.len = param->len; | ||
195 | memcpy(cmd.param.val, param->val, param->len); | ||
196 | |||
197 | nci_send_cmd(ndev, NCI_OP_CORE_SET_CONFIG_CMD, (3 + param->len), &cmd); | ||
198 | } | ||
199 | |||
179 | static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) | 200 | static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) |
180 | { | 201 | { |
181 | struct nci_rf_disc_cmd cmd; | 202 | struct nci_rf_disc_cmd cmd; |
@@ -388,6 +409,32 @@ static int nci_dev_down(struct nfc_dev *nfc_dev) | |||
388 | return nci_close_device(ndev); | 409 | return nci_close_device(ndev); |
389 | } | 410 | } |
390 | 411 | ||
412 | static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) | ||
413 | { | ||
414 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
415 | struct nci_set_config_param param; | ||
416 | __u8 local_gb[NFC_MAX_GT_LEN]; | ||
417 | int i, rc = 0; | ||
418 | |||
419 | param.val = nfc_get_local_general_bytes(nfc_dev, ¶m.len); | ||
420 | if ((param.val == NULL) || (param.len == 0)) | ||
421 | return rc; | ||
422 | |||
423 | if (param.len > NCI_MAX_PARAM_LEN) | ||
424 | return -EINVAL; | ||
425 | |||
426 | for (i = 0; i < param.len; i++) | ||
427 | local_gb[param.len-1-i] = param.val[i]; | ||
428 | |||
429 | param.id = NCI_PN_ATR_REQ_GEN_BYTES; | ||
430 | param.val = local_gb; | ||
431 | |||
432 | rc = nci_request(ndev, nci_set_config_req, (unsigned long)¶m, | ||
433 | msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); | ||
434 | |||
435 | return rc; | ||
436 | } | ||
437 | |||
391 | static int nci_start_poll(struct nfc_dev *nfc_dev, | 438 | static int nci_start_poll(struct nfc_dev *nfc_dev, |
392 | __u32 im_protocols, __u32 tm_protocols) | 439 | __u32 im_protocols, __u32 tm_protocols) |
393 | { | 440 | { |
@@ -415,6 +462,14 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, | |||
415 | return -EBUSY; | 462 | return -EBUSY; |
416 | } | 463 | } |
417 | 464 | ||
465 | if (im_protocols & NFC_PROTO_NFC_DEP_MASK) { | ||
466 | rc = nci_set_local_general_bytes(nfc_dev); | ||
467 | if (rc) { | ||
468 | pr_err("failed to set local general bytes\n"); | ||
469 | return rc; | ||
470 | } | ||
471 | } | ||
472 | |||
418 | rc = nci_request(ndev, nci_rf_discover_req, im_protocols, | 473 | rc = nci_request(ndev, nci_rf_discover_req, im_protocols, |
419 | msecs_to_jiffies(NCI_RF_DISC_TIMEOUT)); | 474 | msecs_to_jiffies(NCI_RF_DISC_TIMEOUT)); |
420 | 475 | ||
@@ -509,7 +564,7 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, | |||
509 | { | 564 | { |
510 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | 565 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); |
511 | 566 | ||
512 | pr_debug("target_idx %d\n", target->idx); | 567 | pr_debug("entry\n"); |
513 | 568 | ||
514 | if (!ndev->target_active_prot) { | 569 | if (!ndev->target_active_prot) { |
515 | pr_err("unable to deactivate target, no active target\n"); | 570 | pr_err("unable to deactivate target, no active target\n"); |
@@ -524,6 +579,38 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, | |||
524 | } | 579 | } |
525 | } | 580 | } |
526 | 581 | ||
582 | |||
583 | static int nci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, | ||
584 | __u8 comm_mode, __u8 *gb, size_t gb_len) | ||
585 | { | ||
586 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
587 | int rc; | ||
588 | |||
589 | pr_debug("target_idx %d, comm_mode %d\n", target->idx, comm_mode); | ||
590 | |||
591 | rc = nci_activate_target(nfc_dev, target, NFC_PROTO_NFC_DEP); | ||
592 | if (rc) | ||
593 | return rc; | ||
594 | |||
595 | rc = nfc_set_remote_general_bytes(nfc_dev, ndev->remote_gb, | ||
596 | ndev->remote_gb_len); | ||
597 | if (!rc) | ||
598 | rc = nfc_dep_link_is_up(nfc_dev, target->idx, NFC_COMM_PASSIVE, | ||
599 | NFC_RF_INITIATOR); | ||
600 | |||
601 | return rc; | ||
602 | } | ||
603 | |||
604 | static int nci_dep_link_down(struct nfc_dev *nfc_dev) | ||
605 | { | ||
606 | pr_debug("entry\n"); | ||
607 | |||
608 | nci_deactivate_target(nfc_dev, NULL); | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | |||
527 | static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, | 614 | static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, |
528 | struct sk_buff *skb, | 615 | struct sk_buff *skb, |
529 | data_exchange_cb_t cb, void *cb_context) | 616 | data_exchange_cb_t cb, void *cb_context) |
@@ -557,6 +644,8 @@ static struct nfc_ops nci_nfc_ops = { | |||
557 | .dev_down = nci_dev_down, | 644 | .dev_down = nci_dev_down, |
558 | .start_poll = nci_start_poll, | 645 | .start_poll = nci_start_poll, |
559 | .stop_poll = nci_stop_poll, | 646 | .stop_poll = nci_stop_poll, |
647 | .dep_link_up = nci_dep_link_up, | ||
648 | .dep_link_down = nci_dep_link_down, | ||
560 | .activate_target = nci_activate_target, | 649 | .activate_target = nci_activate_target, |
561 | .deactivate_target = nci_deactivate_target, | 650 | .deactivate_target = nci_deactivate_target, |
562 | .im_transceive = nci_transceive, | 651 | .im_transceive = nci_transceive, |
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index af7a93b04393..b2aa98ef0927 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c | |||
@@ -176,6 +176,8 @@ static int nci_add_new_protocol(struct nci_dev *ndev, | |||
176 | protocol = NFC_PROTO_ISO14443_B_MASK; | 176 | protocol = NFC_PROTO_ISO14443_B_MASK; |
177 | else if (rf_protocol == NCI_RF_PROTOCOL_T3T) | 177 | else if (rf_protocol == NCI_RF_PROTOCOL_T3T) |
178 | protocol = NFC_PROTO_FELICA_MASK; | 178 | protocol = NFC_PROTO_FELICA_MASK; |
179 | else if (rf_protocol == NCI_RF_PROTOCOL_NFC_DEP) | ||
180 | protocol = NFC_PROTO_NFC_DEP_MASK; | ||
179 | else | 181 | else |
180 | protocol = 0; | 182 | protocol = 0; |
181 | 183 | ||
@@ -361,6 +363,33 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, | |||
361 | return NCI_STATUS_OK; | 363 | return NCI_STATUS_OK; |
362 | } | 364 | } |
363 | 365 | ||
366 | static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev, | ||
367 | struct nci_rf_intf_activated_ntf *ntf, __u8 *data) | ||
368 | { | ||
369 | struct activation_params_poll_nfc_dep *poll; | ||
370 | int i; | ||
371 | |||
372 | switch (ntf->activation_rf_tech_and_mode) { | ||
373 | case NCI_NFC_A_PASSIVE_POLL_MODE: | ||
374 | case NCI_NFC_F_PASSIVE_POLL_MODE: | ||
375 | poll = &ntf->activation_params.poll_nfc_dep; | ||
376 | poll->atr_res_len = min_t(__u8, *data++, 63); | ||
377 | pr_debug("atr_res_len %d\n", poll->atr_res_len); | ||
378 | if (poll->atr_res_len > 0) { | ||
379 | for (i = 0; i < poll->atr_res_len; i++) | ||
380 | poll->atr_res[poll->atr_res_len-1-i] = data[i]; | ||
381 | } | ||
382 | break; | ||
383 | |||
384 | default: | ||
385 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", | ||
386 | ntf->activation_rf_tech_and_mode); | ||
387 | return NCI_STATUS_RF_PROTOCOL_ERROR; | ||
388 | } | ||
389 | |||
390 | return NCI_STATUS_OK; | ||
391 | } | ||
392 | |||
364 | static void nci_target_auto_activated(struct nci_dev *ndev, | 393 | static void nci_target_auto_activated(struct nci_dev *ndev, |
365 | struct nci_rf_intf_activated_ntf *ntf) | 394 | struct nci_rf_intf_activated_ntf *ntf) |
366 | { | 395 | { |
@@ -454,6 +483,11 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, | |||
454 | &ntf, data); | 483 | &ntf, data); |
455 | break; | 484 | break; |
456 | 485 | ||
486 | case NCI_RF_INTERFACE_NFC_DEP: | ||
487 | err = nci_extract_activation_params_nfc_dep(ndev, | ||
488 | &ntf, data); | ||
489 | break; | ||
490 | |||
457 | case NCI_RF_INTERFACE_FRAME: | 491 | case NCI_RF_INTERFACE_FRAME: |
458 | /* no activation params */ | 492 | /* no activation params */ |
459 | break; | 493 | break; |
@@ -473,6 +507,24 @@ exit: | |||
473 | 507 | ||
474 | /* set the available credits to initial value */ | 508 | /* set the available credits to initial value */ |
475 | atomic_set(&ndev->credits_cnt, ndev->initial_num_credits); | 509 | atomic_set(&ndev->credits_cnt, ndev->initial_num_credits); |
510 | |||
511 | /* store general bytes to be reported later in dep_link_up */ | ||
512 | if (ntf.rf_interface == NCI_RF_INTERFACE_NFC_DEP) { | ||
513 | ndev->remote_gb_len = 0; | ||
514 | |||
515 | if (ntf.activation_params_len > 0) { | ||
516 | /* ATR_RES general bytes at offset 15 */ | ||
517 | ndev->remote_gb_len = min_t(__u8, | ||
518 | (ntf.activation_params | ||
519 | .poll_nfc_dep.atr_res_len | ||
520 | - NFC_ATR_RES_GT_OFFSET), | ||
521 | NFC_MAX_GT_LEN); | ||
522 | memcpy(ndev->remote_gb, | ||
523 | (ntf.activation_params.poll_nfc_dep | ||
524 | .atr_res + NFC_ATR_RES_GT_OFFSET), | ||
525 | ndev->remote_gb_len); | ||
526 | } | ||
527 | } | ||
476 | } | 528 | } |
477 | 529 | ||
478 | if (atomic_read(&ndev->state) == NCI_DISCOVERY) { | 530 | if (atomic_read(&ndev->state) == NCI_DISCOVERY) { |
diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index 3003c3390e49..dd072f38ad00 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c | |||
@@ -119,6 +119,16 @@ exit: | |||
119 | nci_req_complete(ndev, rsp_1->status); | 119 | nci_req_complete(ndev, rsp_1->status); |
120 | } | 120 | } |
121 | 121 | ||
122 | static void nci_core_set_config_rsp_packet(struct nci_dev *ndev, | ||
123 | struct sk_buff *skb) | ||
124 | { | ||
125 | struct nci_core_set_config_rsp *rsp = (void *) skb->data; | ||
126 | |||
127 | pr_debug("status 0x%x\n", rsp->status); | ||
128 | |||
129 | nci_req_complete(ndev, rsp->status); | ||
130 | } | ||
131 | |||
122 | static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev, | 132 | static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev, |
123 | struct sk_buff *skb) | 133 | struct sk_buff *skb) |
124 | { | 134 | { |
@@ -194,6 +204,10 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) | |||
194 | nci_core_init_rsp_packet(ndev, skb); | 204 | nci_core_init_rsp_packet(ndev, skb); |
195 | break; | 205 | break; |
196 | 206 | ||
207 | case NCI_OP_CORE_SET_CONFIG_RSP: | ||
208 | nci_core_set_config_rsp_packet(ndev, skb); | ||
209 | break; | ||
210 | |||
197 | case NCI_OP_RF_DISCOVER_MAP_RSP: | 211 | case NCI_OP_RF_DISCOVER_MAP_RSP: |
198 | nci_rf_disc_map_rsp_packet(ndev, skb); | 212 | nci_rf_disc_map_rsp_packet(ndev, skb); |
199 | break; | 213 | break; |
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 4bbb70e32d1e..c1b5285cbde7 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c | |||
@@ -761,31 +761,63 @@ static struct genl_ops nfc_genl_ops[] = { | |||
761 | }, | 761 | }, |
762 | }; | 762 | }; |
763 | 763 | ||
764 | static int nfc_genl_rcv_nl_event(struct notifier_block *this, | 764 | |
765 | unsigned long event, void *ptr) | 765 | struct urelease_work { |
766 | struct work_struct w; | ||
767 | int portid; | ||
768 | }; | ||
769 | |||
770 | static void nfc_urelease_event_work(struct work_struct *work) | ||
766 | { | 771 | { |
767 | struct netlink_notify *n = ptr; | 772 | struct urelease_work *w = container_of(work, struct urelease_work, w); |
768 | struct class_dev_iter iter; | 773 | struct class_dev_iter iter; |
769 | struct nfc_dev *dev; | 774 | struct nfc_dev *dev; |
770 | 775 | ||
771 | if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC) | 776 | pr_debug("portid %d\n", w->portid); |
772 | goto out; | ||
773 | 777 | ||
774 | pr_debug("NETLINK_URELEASE event from id %d\n", n->portid); | 778 | mutex_lock(&nfc_devlist_mutex); |
775 | 779 | ||
776 | nfc_device_iter_init(&iter); | 780 | nfc_device_iter_init(&iter); |
777 | dev = nfc_device_iter_next(&iter); | 781 | dev = nfc_device_iter_next(&iter); |
778 | 782 | ||
779 | while (dev) { | 783 | while (dev) { |
780 | if (dev->genl_data.poll_req_portid == n->portid) { | 784 | mutex_lock(&dev->genl_data.genl_data_mutex); |
785 | |||
786 | if (dev->genl_data.poll_req_portid == w->portid) { | ||
781 | nfc_stop_poll(dev); | 787 | nfc_stop_poll(dev); |
782 | dev->genl_data.poll_req_portid = 0; | 788 | dev->genl_data.poll_req_portid = 0; |
783 | } | 789 | } |
790 | |||
791 | mutex_unlock(&dev->genl_data.genl_data_mutex); | ||
792 | |||
784 | dev = nfc_device_iter_next(&iter); | 793 | dev = nfc_device_iter_next(&iter); |
785 | } | 794 | } |
786 | 795 | ||
787 | nfc_device_iter_exit(&iter); | 796 | nfc_device_iter_exit(&iter); |
788 | 797 | ||
798 | mutex_unlock(&nfc_devlist_mutex); | ||
799 | |||
800 | kfree(w); | ||
801 | } | ||
802 | |||
803 | static int nfc_genl_rcv_nl_event(struct notifier_block *this, | ||
804 | unsigned long event, void *ptr) | ||
805 | { | ||
806 | struct netlink_notify *n = ptr; | ||
807 | struct urelease_work *w; | ||
808 | |||
809 | if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC) | ||
810 | goto out; | ||
811 | |||
812 | pr_debug("NETLINK_URELEASE event from id %d\n", n->portid); | ||
813 | |||
814 | w = kmalloc(sizeof(*w), GFP_ATOMIC); | ||
815 | if (w) { | ||
816 | INIT_WORK((struct work_struct *) w, nfc_urelease_event_work); | ||
817 | w->portid = n->portid; | ||
818 | schedule_work((struct work_struct *) w); | ||
819 | } | ||
820 | |||
789 | out: | 821 | out: |
790 | return NOTIFY_DONE; | 822 | return NOTIFY_DONE; |
791 | } | 823 | } |
diff --git a/net/rfkill/core.c b/net/rfkill/core.c index c275bad12068..a5c952741279 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c | |||
@@ -270,6 +270,7 @@ static bool __rfkill_set_hw_state(struct rfkill *rfkill, | |||
270 | static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | 270 | static void rfkill_set_block(struct rfkill *rfkill, bool blocked) |
271 | { | 271 | { |
272 | unsigned long flags; | 272 | unsigned long flags; |
273 | bool prev, curr; | ||
273 | int err; | 274 | int err; |
274 | 275 | ||
275 | if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) | 276 | if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) |
@@ -284,6 +285,8 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | |||
284 | rfkill->ops->query(rfkill, rfkill->data); | 285 | rfkill->ops->query(rfkill, rfkill->data); |
285 | 286 | ||
286 | spin_lock_irqsave(&rfkill->lock, flags); | 287 | spin_lock_irqsave(&rfkill->lock, flags); |
288 | prev = rfkill->state & RFKILL_BLOCK_SW; | ||
289 | |||
287 | if (rfkill->state & RFKILL_BLOCK_SW) | 290 | if (rfkill->state & RFKILL_BLOCK_SW) |
288 | rfkill->state |= RFKILL_BLOCK_SW_PREV; | 291 | rfkill->state |= RFKILL_BLOCK_SW_PREV; |
289 | else | 292 | else |
@@ -313,10 +316,13 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | |||
313 | } | 316 | } |
314 | rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL; | 317 | rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL; |
315 | rfkill->state &= ~RFKILL_BLOCK_SW_PREV; | 318 | rfkill->state &= ~RFKILL_BLOCK_SW_PREV; |
319 | curr = rfkill->state & RFKILL_BLOCK_SW; | ||
316 | spin_unlock_irqrestore(&rfkill->lock, flags); | 320 | spin_unlock_irqrestore(&rfkill->lock, flags); |
317 | 321 | ||
318 | rfkill_led_trigger_event(rfkill); | 322 | rfkill_led_trigger_event(rfkill); |
319 | rfkill_event(rfkill); | 323 | |
324 | if (prev != curr) | ||
325 | rfkill_event(rfkill); | ||
320 | } | 326 | } |
321 | 327 | ||
322 | #ifdef CONFIG_RFKILL_INPUT | 328 | #ifdef CONFIG_RFKILL_INPUT |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index ec7fcee5bad6..8016fee0752b 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -612,6 +612,17 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) | |||
612 | } | 612 | } |
613 | EXPORT_SYMBOL(cfg80211_del_sta); | 613 | EXPORT_SYMBOL(cfg80211_del_sta); |
614 | 614 | ||
615 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, | ||
616 | enum nl80211_connect_failed_reason reason, | ||
617 | gfp_t gfp) | ||
618 | { | ||
619 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
620 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
621 | |||
622 | nl80211_send_conn_failed_event(rdev, dev, mac_addr, reason, gfp); | ||
623 | } | ||
624 | EXPORT_SYMBOL(cfg80211_conn_failed); | ||
625 | |||
615 | struct cfg80211_mgmt_registration { | 626 | struct cfg80211_mgmt_registration { |
616 | struct list_head list; | 627 | struct list_head list; |
617 | 628 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 139946dc8020..0418a6d5c1a6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -8364,6 +8364,40 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
8364 | nlmsg_free(msg); | 8364 | nlmsg_free(msg); |
8365 | } | 8365 | } |
8366 | 8366 | ||
8367 | void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, | ||
8368 | struct net_device *dev, const u8 *mac_addr, | ||
8369 | enum nl80211_connect_failed_reason reason, | ||
8370 | gfp_t gfp) | ||
8371 | { | ||
8372 | struct sk_buff *msg; | ||
8373 | void *hdr; | ||
8374 | |||
8375 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
8376 | if (!msg) | ||
8377 | return; | ||
8378 | |||
8379 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED); | ||
8380 | if (!hdr) { | ||
8381 | nlmsg_free(msg); | ||
8382 | return; | ||
8383 | } | ||
8384 | |||
8385 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | ||
8386 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) || | ||
8387 | nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason)) | ||
8388 | goto nla_put_failure; | ||
8389 | |||
8390 | genlmsg_end(msg, hdr); | ||
8391 | |||
8392 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
8393 | nl80211_mlme_mcgrp.id, gfp); | ||
8394 | return; | ||
8395 | |||
8396 | nla_put_failure: | ||
8397 | genlmsg_cancel(msg, hdr); | ||
8398 | nlmsg_free(msg); | ||
8399 | } | ||
8400 | |||
8367 | static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, | 8401 | static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, |
8368 | const u8 *addr, gfp_t gfp) | 8402 | const u8 *addr, gfp_t gfp) |
8369 | { | 8403 | { |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 9f2616fffb40..f6153516068c 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -91,6 +91,11 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
91 | struct net_device *dev, const u8 *mac_addr, | 91 | struct net_device *dev, const u8 *mac_addr, |
92 | gfp_t gfp); | 92 | gfp_t gfp); |
93 | 93 | ||
94 | void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, | ||
95 | struct net_device *dev, const u8 *mac_addr, | ||
96 | enum nl80211_connect_failed_reason reason, | ||
97 | gfp_t gfp); | ||
98 | |||
94 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 99 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
95 | struct wireless_dev *wdev, u32 nlpid, | 100 | struct wireless_dev *wdev, u32 nlpid, |
96 | int freq, int sig_dbm, | 101 | int freq, int sig_dbm, |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 1ad04e54014c..844823973daf 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -504,9 +504,11 @@ static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range, | |||
504 | * | 504 | * |
505 | * This lets us know if a specific frequency rule is or is not relevant to | 505 | * This lets us know if a specific frequency rule is or is not relevant to |
506 | * a specific frequency's band. Bands are device specific and artificial | 506 | * a specific frequency's band. Bands are device specific and artificial |
507 | * definitions (the "2.4 GHz band" and the "5 GHz band"), however it is | 507 | * definitions (the "2.4 GHz band", the "5 GHz band" and the "60GHz band"), |
508 | * safe for now to assume that a frequency rule should not be part of a | 508 | * however it is safe for now to assume that a frequency rule should not be |
509 | * frequency's band if the start freq or end freq are off by more than 2 GHz. | 509 | * part of a frequency's band if the start freq or end freq are off by more |
510 | * than 2 GHz for the 2.4 and 5 GHz bands, and by more than 10 GHz for the | ||
511 | * 60 GHz band. | ||
510 | * This resolution can be lowered and should be considered as we add | 512 | * This resolution can be lowered and should be considered as we add |
511 | * regulatory rule support for other "bands". | 513 | * regulatory rule support for other "bands". |
512 | **/ | 514 | **/ |
@@ -514,9 +516,16 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
514 | u32 freq_khz) | 516 | u32 freq_khz) |
515 | { | 517 | { |
516 | #define ONE_GHZ_IN_KHZ 1000000 | 518 | #define ONE_GHZ_IN_KHZ 1000000 |
517 | if (abs(freq_khz - freq_range->start_freq_khz) <= (2 * ONE_GHZ_IN_KHZ)) | 519 | /* |
520 | * From 802.11ad: directional multi-gigabit (DMG): | ||
521 | * Pertaining to operation in a frequency band containing a channel | ||
522 | * with the Channel starting frequency above 45 GHz. | ||
523 | */ | ||
524 | u32 limit = freq_khz > 45 * ONE_GHZ_IN_KHZ ? | ||
525 | 10 * ONE_GHZ_IN_KHZ : 2 * ONE_GHZ_IN_KHZ; | ||
526 | if (abs(freq_khz - freq_range->start_freq_khz) <= limit) | ||
518 | return true; | 527 | return true; |
519 | if (abs(freq_khz - freq_range->end_freq_khz) <= (2 * ONE_GHZ_IN_KHZ)) | 528 | if (abs(freq_khz - freq_range->end_freq_khz) <= limit) |
520 | return true; | 529 | return true; |
521 | return false; | 530 | return false; |
522 | #undef ONE_GHZ_IN_KHZ | 531 | #undef ONE_GHZ_IN_KHZ |
@@ -2193,7 +2202,6 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd) | |||
2193 | static int __set_regdom(const struct ieee80211_regdomain *rd) | 2202 | static int __set_regdom(const struct ieee80211_regdomain *rd) |
2194 | { | 2203 | { |
2195 | const struct ieee80211_regdomain *intersected_rd = NULL; | 2204 | const struct ieee80211_regdomain *intersected_rd = NULL; |
2196 | struct cfg80211_registered_device *rdev = NULL; | ||
2197 | struct wiphy *request_wiphy; | 2205 | struct wiphy *request_wiphy; |
2198 | /* Some basic sanity checks first */ | 2206 | /* Some basic sanity checks first */ |
2199 | 2207 | ||
@@ -2305,24 +2313,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2305 | return 0; | 2313 | return 0; |
2306 | } | 2314 | } |
2307 | 2315 | ||
2308 | if (!intersected_rd) | 2316 | return -EINVAL; |
2309 | return -EINVAL; | ||
2310 | |||
2311 | rdev = wiphy_to_dev(request_wiphy); | ||
2312 | |||
2313 | rdev->country_ie_alpha2[0] = rd->alpha2[0]; | ||
2314 | rdev->country_ie_alpha2[1] = rd->alpha2[1]; | ||
2315 | rdev->env = last_request->country_ie_env; | ||
2316 | |||
2317 | BUG_ON(intersected_rd == rd); | ||
2318 | |||
2319 | kfree(rd); | ||
2320 | rd = NULL; | ||
2321 | |||
2322 | reset_regdomains(false); | ||
2323 | cfg80211_regdomain = intersected_rd; | ||
2324 | |||
2325 | return 0; | ||
2326 | } | 2317 | } |
2327 | 2318 | ||
2328 | 2319 | ||