diff options
Diffstat (limited to 'net/bluetooth/hci_core.c')
-rw-r--r-- | net/bluetooth/hci_core.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6d83ca040970..0b96f20238d8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -896,6 +896,115 @@ static const struct file_operations lowpan_debugfs_fops = { | |||
896 | .llseek = default_llseek, | 896 | .llseek = default_llseek, |
897 | }; | 897 | }; |
898 | 898 | ||
899 | static int le_auto_conn_show(struct seq_file *sf, void *ptr) | ||
900 | { | ||
901 | struct hci_dev *hdev = sf->private; | ||
902 | struct hci_conn_params *p; | ||
903 | |||
904 | hci_dev_lock(hdev); | ||
905 | |||
906 | list_for_each_entry(p, &hdev->le_conn_params, list) { | ||
907 | seq_printf(sf, "%pMR %u %u\n", &p->addr, p->addr_type, | ||
908 | p->auto_connect); | ||
909 | } | ||
910 | |||
911 | hci_dev_unlock(hdev); | ||
912 | |||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | static int le_auto_conn_open(struct inode *inode, struct file *file) | ||
917 | { | ||
918 | return single_open(file, le_auto_conn_show, inode->i_private); | ||
919 | } | ||
920 | |||
921 | static ssize_t le_auto_conn_write(struct file *file, const char __user *data, | ||
922 | size_t count, loff_t *offset) | ||
923 | { | ||
924 | struct seq_file *sf = file->private_data; | ||
925 | struct hci_dev *hdev = sf->private; | ||
926 | u8 auto_connect = 0; | ||
927 | bdaddr_t addr; | ||
928 | u8 addr_type; | ||
929 | char *buf; | ||
930 | int err = 0; | ||
931 | int n; | ||
932 | |||
933 | /* Don't allow partial write */ | ||
934 | if (*offset != 0) | ||
935 | return -EINVAL; | ||
936 | |||
937 | if (count < 3) | ||
938 | return -EINVAL; | ||
939 | |||
940 | buf = kzalloc(count, GFP_KERNEL); | ||
941 | if (!buf) | ||
942 | return -ENOMEM; | ||
943 | |||
944 | if (copy_from_user(buf, data, count)) { | ||
945 | err = -EFAULT; | ||
946 | goto done; | ||
947 | } | ||
948 | |||
949 | if (memcmp(buf, "add", 3) == 0) { | ||
950 | n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu", | ||
951 | &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2], | ||
952 | &addr.b[1], &addr.b[0], &addr_type, | ||
953 | &auto_connect); | ||
954 | |||
955 | if (n < 7) { | ||
956 | err = -EINVAL; | ||
957 | goto done; | ||
958 | } | ||
959 | |||
960 | hci_dev_lock(hdev); | ||
961 | err = hci_conn_params_add(hdev, &addr, addr_type, auto_connect, | ||
962 | hdev->le_conn_min_interval, | ||
963 | hdev->le_conn_max_interval); | ||
964 | hci_dev_unlock(hdev); | ||
965 | |||
966 | if (err) | ||
967 | goto done; | ||
968 | } else if (memcmp(buf, "del", 3) == 0) { | ||
969 | n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu", | ||
970 | &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2], | ||
971 | &addr.b[1], &addr.b[0], &addr_type); | ||
972 | |||
973 | if (n < 7) { | ||
974 | err = -EINVAL; | ||
975 | goto done; | ||
976 | } | ||
977 | |||
978 | hci_dev_lock(hdev); | ||
979 | hci_conn_params_del(hdev, &addr, addr_type); | ||
980 | hci_dev_unlock(hdev); | ||
981 | } else if (memcmp(buf, "clr", 3) == 0) { | ||
982 | hci_dev_lock(hdev); | ||
983 | hci_conn_params_clear(hdev); | ||
984 | hci_pend_le_conns_clear(hdev); | ||
985 | hci_update_background_scan(hdev); | ||
986 | hci_dev_unlock(hdev); | ||
987 | } else { | ||
988 | err = -EINVAL; | ||
989 | } | ||
990 | |||
991 | done: | ||
992 | kfree(buf); | ||
993 | |||
994 | if (err) | ||
995 | return err; | ||
996 | else | ||
997 | return count; | ||
998 | } | ||
999 | |||
1000 | static const struct file_operations le_auto_conn_fops = { | ||
1001 | .open = le_auto_conn_open, | ||
1002 | .read = seq_read, | ||
1003 | .write = le_auto_conn_write, | ||
1004 | .llseek = seq_lseek, | ||
1005 | .release = single_release, | ||
1006 | }; | ||
1007 | |||
899 | /* ---- HCI requests ---- */ | 1008 | /* ---- HCI requests ---- */ |
900 | 1009 | ||
901 | static void hci_req_sync_complete(struct hci_dev *hdev, u8 result) | 1010 | static void hci_req_sync_complete(struct hci_dev *hdev, u8 result) |
@@ -1694,6 +1803,8 @@ static int __hci_init(struct hci_dev *hdev) | |||
1694 | hdev, &adv_channel_map_fops); | 1803 | hdev, &adv_channel_map_fops); |
1695 | debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev, | 1804 | debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev, |
1696 | &lowpan_debugfs_fops); | 1805 | &lowpan_debugfs_fops); |
1806 | debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev, | ||
1807 | &le_auto_conn_fops); | ||
1697 | } | 1808 | } |
1698 | 1809 | ||
1699 | return 0; | 1810 | return 0; |