|
|
@@ -896,6 +896,115 @@ static const struct file_operations lowpan_debugfs_fops = {
|
|
|
.llseek = default_llseek,
|
|
|
};
|
|
|
|
|
|
+static int le_auto_conn_show(struct seq_file *sf, void *ptr)
|
|
|
+{
|
|
|
+ struct hci_dev *hdev = sf->private;
|
|
|
+ struct hci_conn_params *p;
|
|
|
+
|
|
|
+ hci_dev_lock(hdev);
|
|
|
+
|
|
|
+ list_for_each_entry(p, &hdev->le_conn_params, list) {
|
|
|
+ seq_printf(sf, "%pMR %u %u\n", &p->addr, p->addr_type,
|
|
|
+ p->auto_connect);
|
|
|
+ }
|
|
|
+
|
|
|
+ hci_dev_unlock(hdev);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int le_auto_conn_open(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ return single_open(file, le_auto_conn_show, inode->i_private);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t le_auto_conn_write(struct file *file, const char __user *data,
|
|
|
+ size_t count, loff_t *offset)
|
|
|
+{
|
|
|
+ struct seq_file *sf = file->private_data;
|
|
|
+ struct hci_dev *hdev = sf->private;
|
|
|
+ u8 auto_connect = 0;
|
|
|
+ bdaddr_t addr;
|
|
|
+ u8 addr_type;
|
|
|
+ char *buf;
|
|
|
+ int err = 0;
|
|
|
+ int n;
|
|
|
+
|
|
|
+ /* Don't allow partial write */
|
|
|
+ if (*offset != 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (count < 3)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ buf = kzalloc(count, GFP_KERNEL);
|
|
|
+ if (!buf)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ if (copy_from_user(buf, data, count)) {
|
|
|
+ err = -EFAULT;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (memcmp(buf, "add", 3) == 0) {
|
|
|
+ n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu",
|
|
|
+ &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2],
|
|
|
+ &addr.b[1], &addr.b[0], &addr_type,
|
|
|
+ &auto_connect);
|
|
|
+
|
|
|
+ if (n < 7) {
|
|
|
+ err = -EINVAL;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+ hci_dev_lock(hdev);
|
|
|
+ err = hci_conn_params_add(hdev, &addr, addr_type, auto_connect,
|
|
|
+ hdev->le_conn_min_interval,
|
|
|
+ hdev->le_conn_max_interval);
|
|
|
+ hci_dev_unlock(hdev);
|
|
|
+
|
|
|
+ if (err)
|
|
|
+ goto done;
|
|
|
+ } else if (memcmp(buf, "del", 3) == 0) {
|
|
|
+ n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu",
|
|
|
+ &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2],
|
|
|
+ &addr.b[1], &addr.b[0], &addr_type);
|
|
|
+
|
|
|
+ if (n < 7) {
|
|
|
+ err = -EINVAL;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+ hci_dev_lock(hdev);
|
|
|
+ hci_conn_params_del(hdev, &addr, addr_type);
|
|
|
+ hci_dev_unlock(hdev);
|
|
|
+ } else if (memcmp(buf, "clr", 3) == 0) {
|
|
|
+ hci_dev_lock(hdev);
|
|
|
+ hci_conn_params_clear(hdev);
|
|
|
+ hci_pend_le_conns_clear(hdev);
|
|
|
+ hci_update_background_scan(hdev);
|
|
|
+ hci_dev_unlock(hdev);
|
|
|
+ } else {
|
|
|
+ err = -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+done:
|
|
|
+ kfree(buf);
|
|
|
+
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+ else
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct file_operations le_auto_conn_fops = {
|
|
|
+ .open = le_auto_conn_open,
|
|
|
+ .read = seq_read,
|
|
|
+ .write = le_auto_conn_write,
|
|
|
+ .llseek = seq_lseek,
|
|
|
+ .release = single_release,
|
|
|
+};
|
|
|
+
|
|
|
/* ---- HCI requests ---- */
|
|
|
|
|
|
static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
|
|
|
@@ -1694,6 +1803,8 @@ static int __hci_init(struct hci_dev *hdev)
|
|
|
hdev, &adv_channel_map_fops);
|
|
|
debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev,
|
|
|
&lowpan_debugfs_fops);
|
|
|
+ debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev,
|
|
|
+ &le_auto_conn_fops);
|
|
|
}
|
|
|
|
|
|
return 0;
|