aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2011-02-19 10:05:56 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2011-02-21 15:22:43 -0500
commite9a416b5ce0c0f93819f55d34cf6882196e9c3b2 (patch)
treed5225a0013d3e561f02fc36d89e34c0db162fcf5 /net
parent366a033698266c304abd6365ea3bcaec36860328 (diff)
Bluetooth: Add mgmt_pair_device command
This patch adds a new mgmt_pair_device which can be used to initiate a dedicated bonding procedure. Some extra callbacks are added to the hci_conn struct so that the pairing code can get notified of the completion of the procedure. Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/mgmt.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 52e5f88b753a..d7fc54dcbc9e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -38,6 +38,7 @@ struct pending_cmd {
38 int index; 38 int index;
39 void *cmd; 39 void *cmd;
40 struct sock *sk; 40 struct sock *sk;
41 void *user_data;
41}; 42};
42 43
43LIST_HEAD(cmd_list); 44LIST_HEAD(cmd_list);
@@ -1063,6 +1064,135 @@ static int set_io_capability(struct sock *sk, unsigned char *data, u16 len)
1063 &dev_id, sizeof(dev_id)); 1064 &dev_id, sizeof(dev_id));
1064} 1065}
1065 1066
1067static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1068{
1069 struct hci_dev *hdev = conn->hdev;
1070 struct list_head *p;
1071
1072 list_for_each(p, &cmd_list) {
1073 struct pending_cmd *cmd;
1074
1075 cmd = list_entry(p, struct pending_cmd, list);
1076
1077 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1078 continue;
1079
1080 if (cmd->index != hdev->id)
1081 continue;
1082
1083 if (cmd->user_data != conn)
1084 continue;
1085
1086 return cmd;
1087 }
1088
1089 return NULL;
1090}
1091
1092static void pairing_complete(struct pending_cmd *cmd, u8 status)
1093{
1094 struct mgmt_rp_pair_device rp;
1095 struct hci_conn *conn = cmd->user_data;
1096
1097 rp.index = cmd->index;
1098 bacpy(&rp.bdaddr, &conn->dst);
1099 rp.status = status;
1100
1101 cmd_complete(cmd->sk, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
1102
1103 /* So we don't get further callbacks for this connection */
1104 conn->connect_cfm_cb = NULL;
1105 conn->security_cfm_cb = NULL;
1106 conn->disconn_cfm_cb = NULL;
1107
1108 hci_conn_put(conn);
1109
1110 list_del(&cmd->list);
1111 mgmt_pending_free(cmd);
1112}
1113
1114static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1115{
1116 struct pending_cmd *cmd;
1117
1118 BT_DBG("status %u", status);
1119
1120 cmd = find_pairing(conn);
1121 if (!cmd) {
1122 BT_DBG("Unable to find a pending command");
1123 return;
1124 }
1125
1126 pairing_complete(cmd, status);
1127}
1128
1129static int pair_device(struct sock *sk, unsigned char *data, u16 len)
1130{
1131 struct hci_dev *hdev;
1132 struct mgmt_cp_pair_device *cp;
1133 struct pending_cmd *cmd;
1134 u8 sec_level, auth_type;
1135 struct hci_conn *conn;
1136 u16 dev_id;
1137 int err;
1138
1139 BT_DBG("");
1140
1141 cp = (void *) data;
1142 dev_id = get_unaligned_le16(&cp->index);
1143
1144 hdev = hci_dev_get(dev_id);
1145 if (!hdev)
1146 return cmd_status(sk, MGMT_OP_PAIR_DEVICE, ENODEV);
1147
1148 hci_dev_lock_bh(hdev);
1149
1150 if (cp->io_cap == 0x03) {
1151 sec_level = BT_SECURITY_MEDIUM;
1152 auth_type = HCI_AT_DEDICATED_BONDING;
1153 } else {
1154 sec_level = BT_SECURITY_HIGH;
1155 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
1156 }
1157
1158 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
1159 if (!conn) {
1160 err = -ENOMEM;
1161 goto unlock;
1162 }
1163
1164 if (conn->connect_cfm_cb) {
1165 hci_conn_put(conn);
1166 err = cmd_status(sk, MGMT_OP_PAIR_DEVICE, EBUSY);
1167 goto unlock;
1168 }
1169
1170 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, dev_id, data, len);
1171 if (!cmd) {
1172 err = -ENOMEM;
1173 hci_conn_put(conn);
1174 goto unlock;
1175 }
1176
1177 conn->connect_cfm_cb = pairing_complete_cb;
1178 conn->security_cfm_cb = pairing_complete_cb;
1179 conn->disconn_cfm_cb = pairing_complete_cb;
1180 conn->io_capability = cp->io_cap;
1181 cmd->user_data = conn;
1182
1183 if (conn->state == BT_CONNECTED &&
1184 hci_conn_security(conn, sec_level, auth_type))
1185 pairing_complete(cmd, 0);
1186
1187 err = 0;
1188
1189unlock:
1190 hci_dev_unlock_bh(hdev);
1191 hci_dev_put(hdev);
1192
1193 return err;
1194}
1195
1066int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) 1196int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1067{ 1197{
1068 unsigned char *buf; 1198 unsigned char *buf;
@@ -1148,6 +1278,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1148 case MGMT_OP_SET_IO_CAPABILITY: 1278 case MGMT_OP_SET_IO_CAPABILITY:
1149 err = set_io_capability(sk, buf + sizeof(*hdr), len); 1279 err = set_io_capability(sk, buf + sizeof(*hdr), len);
1150 break; 1280 break;
1281 case MGMT_OP_PAIR_DEVICE:
1282 err = pair_device(sk, buf + sizeof(*hdr), len);
1283 break;
1151 default: 1284 default:
1152 BT_DBG("Unknown op %u", opcode); 1285 BT_DBG("Unknown op %u", opcode);
1153 err = cmd_status(sk, opcode, 0x01); 1286 err = cmd_status(sk, opcode, 0x01);