diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2016-08-27 14:23:40 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2016-09-19 14:19:34 -0400 |
commit | 249fa1699f8642c73eb43e61b321969f0549ab2c (patch) | |
tree | 138dbc93e874fedf16f84a78065e9b6517d527f2 /net/bluetooth | |
parent | 03c979c4717c7fa0c058fafe76ac4d6acdd1fb0d (diff) |
Bluetooth: Add support for sending MGMT open and close to monitor
This sends new notifications to the monitor support whenever a
management channel has been opened or closed. This allows tracing of
control channels really easily.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/hci_sock.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 4dce6dfdb0f2..2d8725006838 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c | |||
@@ -394,6 +394,59 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event) | |||
394 | return skb; | 394 | return skb; |
395 | } | 395 | } |
396 | 396 | ||
397 | static struct sk_buff *create_monitor_ctrl_open(struct sock *sk) | ||
398 | { | ||
399 | struct hci_mon_hdr *hdr; | ||
400 | struct sk_buff *skb; | ||
401 | u16 format = 0x0002; | ||
402 | u8 ver[3]; | ||
403 | u32 flags; | ||
404 | |||
405 | skb = bt_skb_alloc(14 + TASK_COMM_LEN , GFP_ATOMIC); | ||
406 | if (!skb) | ||
407 | return NULL; | ||
408 | |||
409 | mgmt_fill_version_info(ver); | ||
410 | flags = hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) ? 0x1 : 0x0; | ||
411 | |||
412 | put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4)); | ||
413 | put_unaligned_le16(format, skb_put(skb, 2)); | ||
414 | memcpy(skb_put(skb, sizeof(ver)), ver, sizeof(ver)); | ||
415 | put_unaligned_le32(flags, skb_put(skb, 4)); | ||
416 | *skb_put(skb, 1) = TASK_COMM_LEN; | ||
417 | memcpy(skb_put(skb, TASK_COMM_LEN), hci_pi(sk)->comm, TASK_COMM_LEN); | ||
418 | |||
419 | __net_timestamp(skb); | ||
420 | |||
421 | hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE); | ||
422 | hdr->opcode = cpu_to_le16(HCI_MON_CTRL_OPEN); | ||
423 | hdr->index = cpu_to_le16(HCI_DEV_NONE); | ||
424 | hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE); | ||
425 | |||
426 | return skb; | ||
427 | } | ||
428 | |||
429 | static struct sk_buff *create_monitor_ctrl_close(struct sock *sk) | ||
430 | { | ||
431 | struct hci_mon_hdr *hdr; | ||
432 | struct sk_buff *skb; | ||
433 | |||
434 | skb = bt_skb_alloc(4, GFP_ATOMIC); | ||
435 | if (!skb) | ||
436 | return NULL; | ||
437 | |||
438 | put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4)); | ||
439 | |||
440 | __net_timestamp(skb); | ||
441 | |||
442 | hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE); | ||
443 | hdr->opcode = cpu_to_le16(HCI_MON_CTRL_CLOSE); | ||
444 | hdr->index = cpu_to_le16(HCI_DEV_NONE); | ||
445 | hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE); | ||
446 | |||
447 | return skb; | ||
448 | } | ||
449 | |||
397 | static void __printf(2, 3) | 450 | static void __printf(2, 3) |
398 | send_monitor_note(struct sock *sk, const char *fmt, ...) | 451 | send_monitor_note(struct sock *sk, const char *fmt, ...) |
399 | { | 452 | { |
@@ -468,6 +521,29 @@ static void send_monitor_replay(struct sock *sk) | |||
468 | read_unlock(&hci_dev_list_lock); | 521 | read_unlock(&hci_dev_list_lock); |
469 | } | 522 | } |
470 | 523 | ||
524 | static void send_monitor_control_replay(struct sock *mon_sk) | ||
525 | { | ||
526 | struct sock *sk; | ||
527 | |||
528 | read_lock(&hci_sk_list.lock); | ||
529 | |||
530 | sk_for_each(sk, &hci_sk_list.head) { | ||
531 | struct sk_buff *skb; | ||
532 | |||
533 | if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL) | ||
534 | continue; | ||
535 | |||
536 | skb = create_monitor_ctrl_open(sk); | ||
537 | if (!skb) | ||
538 | continue; | ||
539 | |||
540 | if (sock_queue_rcv_skb(mon_sk, skb)) | ||
541 | kfree_skb(skb); | ||
542 | } | ||
543 | |||
544 | read_unlock(&hci_sk_list.lock); | ||
545 | } | ||
546 | |||
471 | /* Generate internal stack event */ | 547 | /* Generate internal stack event */ |
472 | static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) | 548 | static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) |
473 | { | 549 | { |
@@ -595,6 +671,7 @@ static int hci_sock_release(struct socket *sock) | |||
595 | { | 671 | { |
596 | struct sock *sk = sock->sk; | 672 | struct sock *sk = sock->sk; |
597 | struct hci_dev *hdev; | 673 | struct hci_dev *hdev; |
674 | struct sk_buff *skb; | ||
598 | int id; | 675 | int id; |
599 | 676 | ||
600 | BT_DBG("sock %p sk %p", sock, sk); | 677 | BT_DBG("sock %p sk %p", sock, sk); |
@@ -611,6 +688,14 @@ static int hci_sock_release(struct socket *sock) | |||
611 | case HCI_CHANNEL_CONTROL: | 688 | case HCI_CHANNEL_CONTROL: |
612 | id = hci_pi(sk)->cookie; | 689 | id = hci_pi(sk)->cookie; |
613 | 690 | ||
691 | /* Send event to monitor */ | ||
692 | skb = create_monitor_ctrl_close(sk); | ||
693 | if (skb) { | ||
694 | hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, | ||
695 | HCI_SOCK_TRUSTED, NULL); | ||
696 | kfree_skb(skb); | ||
697 | } | ||
698 | |||
614 | hci_pi(sk)->cookie = 0xffffffff; | 699 | hci_pi(sk)->cookie = 0xffffffff; |
615 | ida_simple_remove(&sock_cookie_ida, id); | 700 | ida_simple_remove(&sock_cookie_ida, id); |
616 | break; | 701 | break; |
@@ -931,6 +1016,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, | |||
931 | send_monitor_note(sk, "Bluetooth subsystem version %s", | 1016 | send_monitor_note(sk, "Bluetooth subsystem version %s", |
932 | BT_SUBSYS_VERSION); | 1017 | BT_SUBSYS_VERSION); |
933 | send_monitor_replay(sk); | 1018 | send_monitor_replay(sk); |
1019 | send_monitor_control_replay(sk); | ||
934 | 1020 | ||
935 | atomic_inc(&monitor_promisc); | 1021 | atomic_inc(&monitor_promisc); |
936 | break; | 1022 | break; |
@@ -977,6 +1063,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, | |||
977 | * are changes to settings, class of device, name etc. | 1063 | * are changes to settings, class of device, name etc. |
978 | */ | 1064 | */ |
979 | if (haddr.hci_channel == HCI_CHANNEL_CONTROL) { | 1065 | if (haddr.hci_channel == HCI_CHANNEL_CONTROL) { |
1066 | struct sk_buff *skb; | ||
980 | int id; | 1067 | int id; |
981 | 1068 | ||
982 | id = ida_simple_get(&sock_cookie_ida, 1, 0, GFP_KERNEL); | 1069 | id = ida_simple_get(&sock_cookie_ida, 1, 0, GFP_KERNEL); |
@@ -986,6 +1073,14 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, | |||
986 | hci_pi(sk)->cookie = id; | 1073 | hci_pi(sk)->cookie = id; |
987 | get_task_comm(hci_pi(sk)->comm, current); | 1074 | get_task_comm(hci_pi(sk)->comm, current); |
988 | 1075 | ||
1076 | /* Send event to monitor */ | ||
1077 | skb = create_monitor_ctrl_open(sk); | ||
1078 | if (skb) { | ||
1079 | hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, | ||
1080 | HCI_SOCK_TRUSTED, NULL); | ||
1081 | kfree_skb(skb); | ||
1082 | } | ||
1083 | |||
989 | hci_sock_set_flag(sk, HCI_MGMT_INDEX_EVENTS); | 1084 | hci_sock_set_flag(sk, HCI_MGMT_INDEX_EVENTS); |
990 | hci_sock_set_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS); | 1085 | hci_sock_set_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS); |
991 | hci_sock_set_flag(sk, HCI_MGMT_GENERIC_EVENTS); | 1086 | hci_sock_set_flag(sk, HCI_MGMT_GENERIC_EVENTS); |