diff options
| -rw-r--r-- | include/net/bluetooth/hci.h | 8 | ||||
| -rw-r--r-- | include/net/bluetooth/hci_core.h | 2 | ||||
| -rw-r--r-- | include/net/bluetooth/mgmt.h | 6 | ||||
| -rw-r--r-- | net/bluetooth/hci_conn.c | 1 | ||||
| -rw-r--r-- | net/bluetooth/hci_core.c | 1 | ||||
| -rw-r--r-- | net/bluetooth/hci_event.c | 30 | ||||
| -rw-r--r-- | net/bluetooth/mgmt.c | 32 |
7 files changed, 78 insertions, 2 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index e8e52da2b26b..4bee030e4b52 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h | |||
| @@ -402,6 +402,14 @@ struct hci_cp_reject_sync_conn_req { | |||
| 402 | __u8 reason; | 402 | __u8 reason; |
| 403 | } __packed; | 403 | } __packed; |
| 404 | 404 | ||
| 405 | #define HCI_OP_IO_CAPABILITY_REPLY 0x042b | ||
| 406 | struct hci_cp_io_capability_reply { | ||
| 407 | bdaddr_t bdaddr; | ||
| 408 | __u8 capability; | ||
| 409 | __u8 oob_data; | ||
| 410 | __u8 authentication; | ||
| 411 | } __packed; | ||
| 412 | |||
| 405 | #define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434 | 413 | #define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434 |
| 406 | struct hci_cp_io_capability_neg_reply { | 414 | struct hci_cp_io_capability_neg_reply { |
| 407 | bdaddr_t bdaddr; | 415 | bdaddr_t bdaddr; |
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9ac3da6e4a9a..6163bff6fa91 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
| @@ -106,6 +106,7 @@ struct hci_dev { | |||
| 106 | __u16 manufacturer; | 106 | __u16 manufacturer; |
| 107 | __le16 lmp_subver; | 107 | __le16 lmp_subver; |
| 108 | __u16 voice_setting; | 108 | __u16 voice_setting; |
| 109 | __u8 io_capability; | ||
| 109 | 110 | ||
| 110 | __u16 pkt_type; | 111 | __u16 pkt_type; |
| 111 | __u16 esco_type; | 112 | __u16 esco_type; |
| @@ -214,6 +215,7 @@ struct hci_conn { | |||
| 214 | __u8 sec_level; | 215 | __u8 sec_level; |
| 215 | __u8 pending_sec_level; | 216 | __u8 pending_sec_level; |
| 216 | __u8 pin_length; | 217 | __u8 pin_length; |
| 218 | __u8 io_capability; | ||
| 217 | __u8 power_save; | 219 | __u8 power_save; |
| 218 | __u16 disc_timeout; | 220 | __u16 disc_timeout; |
| 219 | unsigned long pend; | 221 | unsigned long pend; |
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 46fb56d21b59..44ac55c85079 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h | |||
| @@ -154,6 +154,12 @@ struct mgmt_cp_pin_code_neg_reply { | |||
| 154 | bdaddr_t bdaddr; | 154 | bdaddr_t bdaddr; |
| 155 | } __packed; | 155 | } __packed; |
| 156 | 156 | ||
| 157 | #define MGMT_OP_SET_IO_CAPABILITY 0x0013 | ||
| 158 | struct mgmt_cp_set_io_capability { | ||
| 159 | __le16 index; | ||
| 160 | __u8 io_capability; | ||
| 161 | } __packed; | ||
| 162 | |||
| 157 | #define MGMT_EV_CMD_COMPLETE 0x0001 | 163 | #define MGMT_EV_CMD_COMPLETE 0x0001 |
| 158 | struct mgmt_ev_cmd_complete { | 164 | struct mgmt_ev_cmd_complete { |
| 159 | __le16 opcode; | 165 | __le16 opcode; |
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 99cd8d9d891b..42dc39f25b72 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
| @@ -234,6 +234,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | |||
| 234 | conn->mode = HCI_CM_ACTIVE; | 234 | conn->mode = HCI_CM_ACTIVE; |
| 235 | conn->state = BT_OPEN; | 235 | conn->state = BT_OPEN; |
| 236 | conn->auth_type = HCI_AT_GENERAL_BONDING; | 236 | conn->auth_type = HCI_AT_GENERAL_BONDING; |
| 237 | conn->io_capability = hdev->io_capability; | ||
| 237 | 238 | ||
| 238 | conn->power_save = 1; | 239 | conn->power_save = 1; |
| 239 | conn->disc_timeout = HCI_DISCONN_TIMEOUT; | 240 | conn->disc_timeout = HCI_DISCONN_TIMEOUT; |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8ca8cf147058..bf6729a53378 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
| @@ -1084,6 +1084,7 @@ int hci_register_dev(struct hci_dev *hdev) | |||
| 1084 | hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); | 1084 | hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); |
| 1085 | hdev->esco_type = (ESCO_HV1); | 1085 | hdev->esco_type = (ESCO_HV1); |
| 1086 | hdev->link_mode = (HCI_LM_ACCEPT); | 1086 | hdev->link_mode = (HCI_LM_ACCEPT); |
| 1087 | hdev->io_capability = 0x03; /* No Input No Output */ | ||
| 1087 | 1088 | ||
| 1088 | hdev->idle_timeout = 0; | 1089 | hdev->idle_timeout = 0; |
| 1089 | hdev->sniff_max_interval = 800; | 1090 | hdev->sniff_max_interval = 800; |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 98bcf78f2021..617f58363dbc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
| @@ -2198,6 +2198,25 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct | |||
| 2198 | hci_dev_unlock(hdev); | 2198 | hci_dev_unlock(hdev); |
| 2199 | } | 2199 | } |
| 2200 | 2200 | ||
| 2201 | static inline u8 hci_get_auth_req(struct hci_conn *conn) | ||
| 2202 | { | ||
| 2203 | /* If remote requests dedicated bonding follow that lead */ | ||
| 2204 | if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) { | ||
| 2205 | /* If both remote and local IO capabilities allow MITM | ||
| 2206 | * protection then require it, otherwise don't */ | ||
| 2207 | if (conn->remote_cap == 0x03 || conn->io_capability == 0x03) | ||
| 2208 | return 0x02; | ||
| 2209 | else | ||
| 2210 | return 0x03; | ||
| 2211 | } | ||
| 2212 | |||
| 2213 | /* If remote requests no-bonding follow that lead */ | ||
| 2214 | if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01) | ||
| 2215 | return 0x00; | ||
| 2216 | |||
| 2217 | return conn->auth_type; | ||
| 2218 | } | ||
| 2219 | |||
| 2201 | static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | 2220 | static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) |
| 2202 | { | 2221 | { |
| 2203 | struct hci_ev_io_capa_request *ev = (void *) skb->data; | 2222 | struct hci_ev_io_capa_request *ev = (void *) skb->data; |
| @@ -2218,8 +2237,15 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff | |||
| 2218 | 2237 | ||
| 2219 | if (test_bit(HCI_PAIRABLE, &hdev->flags) || | 2238 | if (test_bit(HCI_PAIRABLE, &hdev->flags) || |
| 2220 | (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { | 2239 | (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { |
| 2221 | /* FIXME: Do IO capa response based on information | 2240 | struct hci_cp_io_capability_reply cp; |
| 2222 | * provided through the management interface */ | 2241 | |
| 2242 | bacpy(&cp.bdaddr, &ev->bdaddr); | ||
| 2243 | cp.capability = conn->io_capability; | ||
| 2244 | cp.oob_data = 0; | ||
| 2245 | cp.authentication = hci_get_auth_req(conn); | ||
| 2246 | |||
| 2247 | hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY, | ||
| 2248 | sizeof(cp), &cp); | ||
| 2223 | } else { | 2249 | } else { |
| 2224 | struct hci_cp_io_capability_neg_reply cp; | 2250 | struct hci_cp_io_capability_neg_reply cp; |
| 2225 | 2251 | ||
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3800aaf5792d..b2bda83050a4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
| @@ -1016,6 +1016,35 @@ failed: | |||
| 1016 | return err; | 1016 | return err; |
| 1017 | } | 1017 | } |
| 1018 | 1018 | ||
| 1019 | static int set_io_capability(struct sock *sk, unsigned char *data, u16 len) | ||
| 1020 | { | ||
| 1021 | struct hci_dev *hdev; | ||
| 1022 | struct mgmt_cp_set_io_capability *cp; | ||
| 1023 | u16 dev_id; | ||
| 1024 | |||
| 1025 | BT_DBG(""); | ||
| 1026 | |||
| 1027 | cp = (void *) data; | ||
| 1028 | dev_id = get_unaligned_le16(&cp->index); | ||
| 1029 | |||
| 1030 | hdev = hci_dev_get(dev_id); | ||
| 1031 | if (!hdev) | ||
| 1032 | return cmd_status(sk, MGMT_OP_SET_IO_CAPABILITY, ENODEV); | ||
| 1033 | |||
| 1034 | hci_dev_lock_bh(hdev); | ||
| 1035 | |||
| 1036 | hdev->io_capability = cp->io_capability; | ||
| 1037 | |||
| 1038 | BT_DBG("%s IO capability set to 0x%02x", hdev->name, | ||
| 1039 | hdev->io_capability); | ||
| 1040 | |||
| 1041 | hci_dev_unlock_bh(hdev); | ||
| 1042 | hci_dev_put(hdev); | ||
| 1043 | |||
| 1044 | return cmd_complete(sk, MGMT_OP_SET_IO_CAPABILITY, | ||
| 1045 | &dev_id, sizeof(dev_id)); | ||
| 1046 | } | ||
| 1047 | |||
| 1019 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | 1048 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) |
| 1020 | { | 1049 | { |
| 1021 | unsigned char *buf; | 1050 | unsigned char *buf; |
| @@ -1098,6 +1127,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
| 1098 | case MGMT_OP_PIN_CODE_NEG_REPLY: | 1127 | case MGMT_OP_PIN_CODE_NEG_REPLY: |
| 1099 | err = pin_code_neg_reply(sk, buf + sizeof(*hdr), len); | 1128 | err = pin_code_neg_reply(sk, buf + sizeof(*hdr), len); |
| 1100 | break; | 1129 | break; |
| 1130 | case MGMT_OP_SET_IO_CAPABILITY: | ||
| 1131 | err = set_io_capability(sk, buf + sizeof(*hdr), len); | ||
| 1132 | break; | ||
| 1101 | default: | 1133 | default: |
| 1102 | BT_DBG("Unknown op %u", opcode); | 1134 | BT_DBG("Unknown op %u", opcode); |
| 1103 | err = cmd_status(sk, opcode, 0x01); | 1135 | err = cmd_status(sk, opcode, 0x01); |
