diff options
-rw-r--r-- | net/bluetooth/hidp/core.c | 555 | ||||
-rw-r--r-- | net/bluetooth/hidp/hidp.h | 53 |
2 files changed, 583 insertions, 25 deletions
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index cef1021d5403..8d30a33b27d9 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | HIDP implementation for Linux Bluetooth stack (BlueZ). | 2 | HIDP implementation for Linux Bluetooth stack (BlueZ). |
3 | Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org> | 3 | Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org> |
4 | Copyright (C) 2013 David Herrmann <dh.herrmann@gmail.com> | ||
4 | 5 | ||
5 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License version 2 as | 7 | it under the terms of the GNU General Public License version 2 as |
@@ -20,6 +21,7 @@ | |||
20 | SOFTWARE IS DISCLAIMED. | 21 | SOFTWARE IS DISCLAIMED. |
21 | */ | 22 | */ |
22 | 23 | ||
24 | #include <linux/kref.h> | ||
23 | #include <linux/module.h> | 25 | #include <linux/module.h> |
24 | #include <linux/file.h> | 26 | #include <linux/file.h> |
25 | #include <linux/kthread.h> | 27 | #include <linux/kthread.h> |
@@ -59,6 +61,13 @@ static unsigned char hidp_keycode[256] = { | |||
59 | 61 | ||
60 | static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; | 62 | static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; |
61 | 63 | ||
64 | static int hidp_session_probe(struct l2cap_conn *conn, | ||
65 | struct l2cap_user *user); | ||
66 | static void hidp_session_remove(struct l2cap_conn *conn, | ||
67 | struct l2cap_user *user); | ||
68 | static int hidp_session_thread(void *arg); | ||
69 | static void hidp_session_terminate(struct hidp_session *s); | ||
70 | |||
62 | static inline void hidp_schedule(struct hidp_session *session) | 71 | static inline void hidp_schedule(struct hidp_session *session) |
63 | { | 72 | { |
64 | struct sock *ctrl_sk = session->ctrl_sock->sk; | 73 | struct sock *ctrl_sk = session->ctrl_sock->sk; |
@@ -838,7 +847,7 @@ static int hidp_setup_input(struct hidp_session *session, | |||
838 | input->relbit[0] |= BIT_MASK(REL_WHEEL); | 847 | input->relbit[0] |= BIT_MASK(REL_WHEEL); |
839 | } | 848 | } |
840 | 849 | ||
841 | input->dev.parent = &session->conn->dev; | 850 | input->dev.parent = &session->hconn->dev; |
842 | 851 | ||
843 | input->event = hidp_input_event; | 852 | input->event = hidp_input_event; |
844 | 853 | ||
@@ -942,7 +951,7 @@ static int hidp_setup_hid(struct hidp_session *session, | |||
942 | snprintf(hid->uniq, sizeof(hid->uniq), "%pMR", | 951 | snprintf(hid->uniq, sizeof(hid->uniq), "%pMR", |
943 | &bt_sk(session->ctrl_sock->sk)->dst); | 952 | &bt_sk(session->ctrl_sock->sk)->dst); |
944 | 953 | ||
945 | hid->dev.parent = &session->conn->dev; | 954 | hid->dev.parent = &session->hconn->dev; |
946 | hid->ll_driver = &hidp_hid_driver; | 955 | hid->ll_driver = &hidp_hid_driver; |
947 | 956 | ||
948 | hid->hid_get_raw_report = hidp_get_raw_report; | 957 | hid->hid_get_raw_report = hidp_get_raw_report; |
@@ -964,6 +973,543 @@ fault: | |||
964 | return err; | 973 | return err; |
965 | } | 974 | } |
966 | 975 | ||
976 | /* initialize session devices */ | ||
977 | static int hidp_session_dev_init(struct hidp_session *session, | ||
978 | struct hidp_connadd_req *req) | ||
979 | { | ||
980 | int ret; | ||
981 | |||
982 | if (req->rd_size > 0) { | ||
983 | ret = hidp_setup_hid(session, req); | ||
984 | if (ret && ret != -ENODEV) | ||
985 | return ret; | ||
986 | } | ||
987 | |||
988 | if (!session->hid) { | ||
989 | ret = hidp_setup_input(session, req); | ||
990 | if (ret < 0) | ||
991 | return ret; | ||
992 | } | ||
993 | |||
994 | return 0; | ||
995 | } | ||
996 | |||
997 | /* destroy session devices */ | ||
998 | static void hidp_session_dev_destroy(struct hidp_session *session) | ||
999 | { | ||
1000 | if (session->hid) | ||
1001 | put_device(&session->hid->dev); | ||
1002 | else if (session->input) | ||
1003 | input_put_device(session->input); | ||
1004 | |||
1005 | kfree(session->rd_data); | ||
1006 | session->rd_data = NULL; | ||
1007 | } | ||
1008 | |||
1009 | /* add HID/input devices to their underlying bus systems */ | ||
1010 | static int hidp_session_dev_add(struct hidp_session *session) | ||
1011 | { | ||
1012 | int ret; | ||
1013 | |||
1014 | /* Both HID and input systems drop a ref-count when unregistering the | ||
1015 | * device but they don't take a ref-count when registering them. Work | ||
1016 | * around this by explicitly taking a refcount during registration | ||
1017 | * which is dropped automatically by unregistering the devices. */ | ||
1018 | |||
1019 | if (session->hid) { | ||
1020 | ret = hid_add_device(session->hid); | ||
1021 | if (ret) | ||
1022 | return ret; | ||
1023 | get_device(&session->hid->dev); | ||
1024 | } else if (session->input) { | ||
1025 | ret = input_register_device(session->input); | ||
1026 | if (ret) | ||
1027 | return ret; | ||
1028 | input_get_device(session->input); | ||
1029 | } | ||
1030 | |||
1031 | return 0; | ||
1032 | } | ||
1033 | |||
1034 | /* remove HID/input devices from their bus systems */ | ||
1035 | static void hidp_session_dev_del(struct hidp_session *session) | ||
1036 | { | ||
1037 | if (session->hid) | ||
1038 | hid_destroy_device(session->hid); | ||
1039 | else if (session->input) | ||
1040 | input_unregister_device(session->input); | ||
1041 | } | ||
1042 | |||
1043 | /* | ||
1044 | * Create new session object | ||
1045 | * Allocate session object, initialize static fields, copy input data into the | ||
1046 | * object and take a reference to all sub-objects. | ||
1047 | * This returns 0 on success and puts a pointer to the new session object in | ||
1048 | * \out. Otherwise, an error code is returned. | ||
1049 | * The new session object has an initial ref-count of 1. | ||
1050 | */ | ||
1051 | static int hidp_session_new(struct hidp_session **out, const bdaddr_t *bdaddr, | ||
1052 | struct socket *ctrl_sock, | ||
1053 | struct socket *intr_sock, | ||
1054 | struct hidp_connadd_req *req, | ||
1055 | struct l2cap_conn *conn) | ||
1056 | { | ||
1057 | struct hidp_session *session; | ||
1058 | int ret; | ||
1059 | struct bt_sock *ctrl, *intr; | ||
1060 | |||
1061 | ctrl = bt_sk(ctrl_sock->sk); | ||
1062 | intr = bt_sk(intr_sock->sk); | ||
1063 | |||
1064 | session = kzalloc(sizeof(*session), GFP_KERNEL); | ||
1065 | if (!session) | ||
1066 | return -ENOMEM; | ||
1067 | |||
1068 | /* object and runtime management */ | ||
1069 | kref_init(&session->ref); | ||
1070 | atomic_set(&session->state, HIDP_SESSION_IDLING); | ||
1071 | init_waitqueue_head(&session->state_queue); | ||
1072 | session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID); | ||
1073 | |||
1074 | /* connection management */ | ||
1075 | bacpy(&session->bdaddr, bdaddr); | ||
1076 | session->conn = conn; | ||
1077 | session->user.probe = hidp_session_probe; | ||
1078 | session->user.remove = hidp_session_remove; | ||
1079 | session->ctrl_sock = ctrl_sock; | ||
1080 | session->intr_sock = intr_sock; | ||
1081 | skb_queue_head_init(&session->ctrl_transmit); | ||
1082 | skb_queue_head_init(&session->intr_transmit); | ||
1083 | session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl)->chan->omtu, | ||
1084 | l2cap_pi(ctrl)->chan->imtu); | ||
1085 | session->intr_mtu = min_t(uint, l2cap_pi(intr)->chan->omtu, | ||
1086 | l2cap_pi(intr)->chan->imtu); | ||
1087 | session->idle_to = req->idle_to; | ||
1088 | |||
1089 | /* device management */ | ||
1090 | setup_timer(&session->timer, hidp_idle_timeout, | ||
1091 | (unsigned long)session); | ||
1092 | |||
1093 | /* session data */ | ||
1094 | mutex_init(&session->report_mutex); | ||
1095 | init_waitqueue_head(&session->report_queue); | ||
1096 | |||
1097 | ret = hidp_session_dev_init(session, req); | ||
1098 | if (ret) | ||
1099 | goto err_free; | ||
1100 | |||
1101 | l2cap_conn_get(session->conn); | ||
1102 | get_file(session->intr_sock->file); | ||
1103 | get_file(session->ctrl_sock->file); | ||
1104 | *out = session; | ||
1105 | return 0; | ||
1106 | |||
1107 | err_free: | ||
1108 | kfree(session); | ||
1109 | return ret; | ||
1110 | } | ||
1111 | |||
1112 | /* increase ref-count of the given session by one */ | ||
1113 | static void hidp_session_get(struct hidp_session *session) | ||
1114 | { | ||
1115 | kref_get(&session->ref); | ||
1116 | } | ||
1117 | |||
1118 | /* release callback */ | ||
1119 | static void session_free(struct kref *ref) | ||
1120 | { | ||
1121 | struct hidp_session *session = container_of(ref, struct hidp_session, | ||
1122 | ref); | ||
1123 | |||
1124 | hidp_session_dev_destroy(session); | ||
1125 | skb_queue_purge(&session->ctrl_transmit); | ||
1126 | skb_queue_purge(&session->intr_transmit); | ||
1127 | fput(session->intr_sock->file); | ||
1128 | fput(session->ctrl_sock->file); | ||
1129 | l2cap_conn_put(session->conn); | ||
1130 | kfree(session); | ||
1131 | } | ||
1132 | |||
1133 | /* decrease ref-count of the given session by one */ | ||
1134 | static void hidp_session_put(struct hidp_session *session) | ||
1135 | { | ||
1136 | kref_put(&session->ref, session_free); | ||
1137 | } | ||
1138 | |||
1139 | /* | ||
1140 | * Search the list of active sessions for a session with target address | ||
1141 | * \bdaddr. You must hold at least a read-lock on \hidp_session_sem. As long as | ||
1142 | * you do not release this lock, the session objects cannot vanish and you can | ||
1143 | * safely take a reference to the session yourself. | ||
1144 | */ | ||
1145 | static struct hidp_session *__hidp_session_find(const bdaddr_t *bdaddr) | ||
1146 | { | ||
1147 | struct hidp_session *session; | ||
1148 | |||
1149 | list_for_each_entry(session, &hidp_session_list, list) { | ||
1150 | if (!bacmp(bdaddr, &session->bdaddr)) | ||
1151 | return session; | ||
1152 | } | ||
1153 | |||
1154 | return NULL; | ||
1155 | } | ||
1156 | |||
1157 | /* | ||
1158 | * Same as __hidp_session_find() but no locks must be held. This also takes a | ||
1159 | * reference of the returned session (if non-NULL) so you must drop this | ||
1160 | * reference if you no longer use the object. | ||
1161 | */ | ||
1162 | static struct hidp_session *hidp_session_find(const bdaddr_t *bdaddr) | ||
1163 | { | ||
1164 | struct hidp_session *session; | ||
1165 | |||
1166 | down_read(&hidp_session_sem); | ||
1167 | |||
1168 | session = __hidp_session_find(bdaddr); | ||
1169 | if (session) | ||
1170 | hidp_session_get(session); | ||
1171 | |||
1172 | up_read(&hidp_session_sem); | ||
1173 | |||
1174 | return session; | ||
1175 | } | ||
1176 | |||
1177 | /* | ||
1178 | * Start session synchronously | ||
1179 | * This starts a session thread and waits until initialization | ||
1180 | * is done or returns an error if it couldn't be started. | ||
1181 | * If this returns 0 the session thread is up and running. You must call | ||
1182 | * hipd_session_stop_sync() before deleting any runtime resources. | ||
1183 | */ | ||
1184 | static int hidp_session_start_sync(struct hidp_session *session) | ||
1185 | { | ||
1186 | unsigned int vendor, product; | ||
1187 | |||
1188 | if (session->hid) { | ||
1189 | vendor = session->hid->vendor; | ||
1190 | product = session->hid->product; | ||
1191 | } else if (session->input) { | ||
1192 | vendor = session->input->id.vendor; | ||
1193 | product = session->input->id.product; | ||
1194 | } else { | ||
1195 | vendor = 0x0000; | ||
1196 | product = 0x0000; | ||
1197 | } | ||
1198 | |||
1199 | session->task = kthread_run(hidp_session_thread, session, | ||
1200 | "khidpd_%04x%04x", vendor, product); | ||
1201 | if (IS_ERR(session->task)) | ||
1202 | return PTR_ERR(session->task); | ||
1203 | |||
1204 | while (atomic_read(&session->state) <= HIDP_SESSION_IDLING) | ||
1205 | wait_event(session->state_queue, | ||
1206 | atomic_read(&session->state) > HIDP_SESSION_IDLING); | ||
1207 | |||
1208 | return 0; | ||
1209 | } | ||
1210 | |||
1211 | /* | ||
1212 | * Terminate session thread | ||
1213 | * Wake up session thread and notify it to stop. This is asynchronous and | ||
1214 | * returns immediately. Call this whenever a runtime error occurs and you want | ||
1215 | * the session to stop. | ||
1216 | * Note: wake_up_process() performs any necessary memory-barriers for us. | ||
1217 | */ | ||
1218 | static void hidp_session_terminate(struct hidp_session *session) | ||
1219 | { | ||
1220 | atomic_inc(&session->terminate); | ||
1221 | wake_up_process(session->task); | ||
1222 | } | ||
1223 | |||
1224 | /* | ||
1225 | * Probe HIDP session | ||
1226 | * This is called from the l2cap_conn core when our l2cap_user object is bound | ||
1227 | * to the hci-connection. We get the session via the \user object and can now | ||
1228 | * start the session thread, register the HID/input devices and link it into | ||
1229 | * the global session list. | ||
1230 | * The global session-list owns its own reference to the session object so you | ||
1231 | * can drop your own reference after registering the l2cap_user object. | ||
1232 | */ | ||
1233 | static int hidp_session_probe(struct l2cap_conn *conn, | ||
1234 | struct l2cap_user *user) | ||
1235 | { | ||
1236 | struct hidp_session *session = container_of(user, | ||
1237 | struct hidp_session, | ||
1238 | user); | ||
1239 | struct hidp_session *s; | ||
1240 | int ret; | ||
1241 | |||
1242 | down_write(&hidp_session_sem); | ||
1243 | |||
1244 | /* check that no other session for this device exists */ | ||
1245 | s = __hidp_session_find(&session->bdaddr); | ||
1246 | if (s) { | ||
1247 | ret = -EEXIST; | ||
1248 | goto out_unlock; | ||
1249 | } | ||
1250 | |||
1251 | ret = hidp_session_start_sync(session); | ||
1252 | if (ret) | ||
1253 | goto out_unlock; | ||
1254 | |||
1255 | ret = hidp_session_dev_add(session); | ||
1256 | if (ret) | ||
1257 | goto out_stop; | ||
1258 | |||
1259 | hidp_session_get(session); | ||
1260 | list_add(&session->list, &hidp_session_list); | ||
1261 | ret = 0; | ||
1262 | goto out_unlock; | ||
1263 | |||
1264 | out_stop: | ||
1265 | hidp_session_terminate(session); | ||
1266 | out_unlock: | ||
1267 | up_write(&hidp_session_sem); | ||
1268 | return ret; | ||
1269 | } | ||
1270 | |||
1271 | /* | ||
1272 | * Remove HIDP session | ||
1273 | * Called from the l2cap_conn core when either we explicitly unregistered | ||
1274 | * the l2cap_user object or if the underlying connection is shut down. | ||
1275 | * We signal the hidp-session thread to shut down, unregister the HID/input | ||
1276 | * devices and unlink the session from the global list. | ||
1277 | * This drops the reference to the session that is owned by the global | ||
1278 | * session-list. | ||
1279 | * Note: We _must_ not synchronosly wait for the session-thread to shut down. | ||
1280 | * This is, because the session-thread might be waiting for an HCI lock that is | ||
1281 | * held while we are called. Therefore, we only unregister the devices and | ||
1282 | * notify the session-thread to terminate. The thread itself owns a reference | ||
1283 | * to the session object so it can safely shut down. | ||
1284 | */ | ||
1285 | static void hidp_session_remove(struct l2cap_conn *conn, | ||
1286 | struct l2cap_user *user) | ||
1287 | { | ||
1288 | struct hidp_session *session = container_of(user, | ||
1289 | struct hidp_session, | ||
1290 | user); | ||
1291 | |||
1292 | down_write(&hidp_session_sem); | ||
1293 | |||
1294 | hidp_session_terminate(session); | ||
1295 | hidp_session_dev_del(session); | ||
1296 | list_del(&session->list); | ||
1297 | |||
1298 | up_write(&hidp_session_sem); | ||
1299 | |||
1300 | hidp_session_put(session); | ||
1301 | } | ||
1302 | |||
1303 | /* | ||
1304 | * Session Worker | ||
1305 | * This performs the actual main-loop of the HIDP worker. We first check | ||
1306 | * whether the underlying connection is still alive, then parse all pending | ||
1307 | * messages and finally send all outstanding messages. | ||
1308 | */ | ||
1309 | static void hidp_session_run(struct hidp_session *session) | ||
1310 | { | ||
1311 | struct sock *ctrl_sk = session->ctrl_sock->sk; | ||
1312 | struct sock *intr_sk = session->intr_sock->sk; | ||
1313 | struct sk_buff *skb; | ||
1314 | |||
1315 | for (;;) { | ||
1316 | /* | ||
1317 | * This thread can be woken up two ways: | ||
1318 | * - You call hidp_session_terminate() which sets the | ||
1319 | * session->terminate flag and wakes this thread up. | ||
1320 | * - Via modifying the socket state of ctrl/intr_sock. This | ||
1321 | * thread is woken up by ->sk_state_changed(). | ||
1322 | * | ||
1323 | * Note: set_current_state() performs any necessary | ||
1324 | * memory-barriers for us. | ||
1325 | */ | ||
1326 | set_current_state(TASK_INTERRUPTIBLE); | ||
1327 | |||
1328 | if (atomic_read(&session->terminate)) | ||
1329 | break; | ||
1330 | |||
1331 | if (ctrl_sk->sk_state != BT_CONNECTED || | ||
1332 | intr_sk->sk_state != BT_CONNECTED) | ||
1333 | break; | ||
1334 | |||
1335 | /* parse incoming intr-skbs */ | ||
1336 | while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) { | ||
1337 | skb_orphan(skb); | ||
1338 | if (!skb_linearize(skb)) | ||
1339 | hidp_recv_intr_frame(session, skb); | ||
1340 | else | ||
1341 | kfree_skb(skb); | ||
1342 | } | ||
1343 | |||
1344 | /* send pending intr-skbs */ | ||
1345 | hidp_process_intr_transmit(session); | ||
1346 | |||
1347 | /* parse incoming ctrl-skbs */ | ||
1348 | while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { | ||
1349 | skb_orphan(skb); | ||
1350 | if (!skb_linearize(skb)) | ||
1351 | hidp_recv_ctrl_frame(session, skb); | ||
1352 | else | ||
1353 | kfree_skb(skb); | ||
1354 | } | ||
1355 | |||
1356 | /* send pending ctrl-skbs */ | ||
1357 | hidp_process_ctrl_transmit(session); | ||
1358 | |||
1359 | schedule(); | ||
1360 | } | ||
1361 | |||
1362 | atomic_inc(&session->terminate); | ||
1363 | set_current_state(TASK_RUNNING); | ||
1364 | } | ||
1365 | |||
1366 | /* | ||
1367 | * HIDP session thread | ||
1368 | * This thread runs the I/O for a single HIDP session. Startup is synchronous | ||
1369 | * which allows us to take references to ourself here instead of doing that in | ||
1370 | * the caller. | ||
1371 | * When we are ready to run we notify the caller and call hidp_session_run(). | ||
1372 | */ | ||
1373 | static int hidp_session_thread(void *arg) | ||
1374 | { | ||
1375 | struct hidp_session *session = arg; | ||
1376 | wait_queue_t ctrl_wait, intr_wait; | ||
1377 | |||
1378 | BT_DBG("session %p", session); | ||
1379 | |||
1380 | /* initialize runtime environment */ | ||
1381 | hidp_session_get(session); | ||
1382 | __module_get(THIS_MODULE); | ||
1383 | set_user_nice(current, -15); | ||
1384 | hidp_set_timer(session); | ||
1385 | |||
1386 | init_waitqueue_entry(&ctrl_wait, current); | ||
1387 | init_waitqueue_entry(&intr_wait, current); | ||
1388 | add_wait_queue(sk_sleep(session->ctrl_sock->sk), &ctrl_wait); | ||
1389 | add_wait_queue(sk_sleep(session->intr_sock->sk), &intr_wait); | ||
1390 | /* This memory barrier is paired with wq_has_sleeper(). See | ||
1391 | * sock_poll_wait() for more information why this is needed. */ | ||
1392 | smp_mb(); | ||
1393 | |||
1394 | /* notify synchronous startup that we're ready */ | ||
1395 | atomic_inc(&session->state); | ||
1396 | wake_up(&session->state_queue); | ||
1397 | |||
1398 | /* run session */ | ||
1399 | hidp_session_run(session); | ||
1400 | |||
1401 | /* cleanup runtime environment */ | ||
1402 | remove_wait_queue(sk_sleep(session->intr_sock->sk), &intr_wait); | ||
1403 | remove_wait_queue(sk_sleep(session->intr_sock->sk), &ctrl_wait); | ||
1404 | wake_up_interruptible(&session->report_queue); | ||
1405 | hidp_del_timer(session); | ||
1406 | |||
1407 | /* | ||
1408 | * If we stopped ourself due to any internal signal, we should try to | ||
1409 | * unregister our own session here to avoid having it linger until the | ||
1410 | * parent l2cap_conn dies or user-space cleans it up. | ||
1411 | * This does not deadlock as we don't do any synchronous shutdown. | ||
1412 | * Instead, this call has the same semantics as if user-space tried to | ||
1413 | * delete the session. | ||
1414 | */ | ||
1415 | l2cap_unregister_user(session->conn, &session->user); | ||
1416 | hidp_session_put(session); | ||
1417 | |||
1418 | module_put_and_exit(0); | ||
1419 | return 0; | ||
1420 | } | ||
1421 | |||
1422 | static int hidp_verify_sockets(struct socket *ctrl_sock, | ||
1423 | struct socket *intr_sock) | ||
1424 | { | ||
1425 | struct bt_sock *ctrl, *intr; | ||
1426 | struct hidp_session *session; | ||
1427 | |||
1428 | if (!l2cap_is_socket(ctrl_sock) || !l2cap_is_socket(intr_sock)) | ||
1429 | return -EINVAL; | ||
1430 | |||
1431 | ctrl = bt_sk(ctrl_sock->sk); | ||
1432 | intr = bt_sk(intr_sock->sk); | ||
1433 | |||
1434 | if (bacmp(&ctrl->src, &intr->src) || bacmp(&ctrl->dst, &intr->dst)) | ||
1435 | return -ENOTUNIQ; | ||
1436 | if (ctrl->sk.sk_state != BT_CONNECTED || | ||
1437 | intr->sk.sk_state != BT_CONNECTED) | ||
1438 | return -EBADFD; | ||
1439 | |||
1440 | /* early session check, we check again during session registration */ | ||
1441 | session = hidp_session_find(&ctrl->dst); | ||
1442 | if (session) { | ||
1443 | hidp_session_put(session); | ||
1444 | return -EEXIST; | ||
1445 | } | ||
1446 | |||
1447 | return 0; | ||
1448 | } | ||
1449 | |||
1450 | int hidp_connection_add(struct hidp_connadd_req *req, | ||
1451 | struct socket *ctrl_sock, | ||
1452 | struct socket *intr_sock) | ||
1453 | { | ||
1454 | struct hidp_session *session; | ||
1455 | struct l2cap_conn *conn; | ||
1456 | struct l2cap_chan *chan = l2cap_pi(ctrl_sock->sk)->chan; | ||
1457 | int ret; | ||
1458 | |||
1459 | ret = hidp_verify_sockets(ctrl_sock, intr_sock); | ||
1460 | if (ret) | ||
1461 | return ret; | ||
1462 | |||
1463 | conn = NULL; | ||
1464 | l2cap_chan_lock(chan); | ||
1465 | if (chan->conn) { | ||
1466 | l2cap_conn_get(chan->conn); | ||
1467 | conn = chan->conn; | ||
1468 | } | ||
1469 | l2cap_chan_unlock(chan); | ||
1470 | |||
1471 | if (!conn) | ||
1472 | return -EBADFD; | ||
1473 | |||
1474 | ret = hidp_session_new(&session, &bt_sk(ctrl_sock->sk)->dst, ctrl_sock, | ||
1475 | intr_sock, req, conn); | ||
1476 | if (ret) | ||
1477 | goto out_conn; | ||
1478 | |||
1479 | ret = l2cap_register_user(conn, &session->user); | ||
1480 | if (ret) | ||
1481 | goto out_session; | ||
1482 | |||
1483 | ret = 0; | ||
1484 | |||
1485 | out_session: | ||
1486 | hidp_session_put(session); | ||
1487 | out_conn: | ||
1488 | l2cap_conn_put(conn); | ||
1489 | return ret; | ||
1490 | } | ||
1491 | |||
1492 | int hidp_connection_del(struct hidp_conndel_req *req) | ||
1493 | { | ||
1494 | struct hidp_session *session; | ||
1495 | |||
1496 | session = hidp_session_find(&req->bdaddr); | ||
1497 | if (!session) | ||
1498 | return -ENOENT; | ||
1499 | |||
1500 | if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) | ||
1501 | hidp_send_ctrl_message(session, | ||
1502 | HIDP_TRANS_HID_CONTROL | | ||
1503 | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, | ||
1504 | NULL, 0); | ||
1505 | else | ||
1506 | l2cap_unregister_user(session->conn, &session->user); | ||
1507 | |||
1508 | hidp_session_put(session); | ||
1509 | |||
1510 | return 0; | ||
1511 | } | ||
1512 | |||
967 | int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) | 1513 | int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) |
968 | { | 1514 | { |
969 | struct hidp_session *session, *s; | 1515 | struct hidp_session *session, *s; |
@@ -1006,8 +1552,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, | |||
1006 | session->ctrl_sock = ctrl_sock; | 1552 | session->ctrl_sock = ctrl_sock; |
1007 | session->intr_sock = intr_sock; | 1553 | session->intr_sock = intr_sock; |
1008 | 1554 | ||
1009 | session->conn = hidp_get_connection(session); | 1555 | session->hconn = hidp_get_connection(session); |
1010 | if (!session->conn) { | 1556 | if (!session->hconn) { |
1011 | err = -ENOTCONN; | 1557 | err = -ENOTCONN; |
1012 | goto failed; | 1558 | goto failed; |
1013 | } | 1559 | } |
@@ -1208,6 +1754,7 @@ module_init(hidp_init); | |||
1208 | module_exit(hidp_exit); | 1754 | module_exit(hidp_exit); |
1209 | 1755 | ||
1210 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); | 1756 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); |
1757 | MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>"); | ||
1211 | MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION); | 1758 | MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION); |
1212 | MODULE_VERSION(VERSION); | 1759 | MODULE_VERSION(VERSION); |
1213 | MODULE_LICENSE("GPL"); | 1760 | MODULE_LICENSE("GPL"); |
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index c84442061793..c4fb980c2434 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h | |||
@@ -24,7 +24,9 @@ | |||
24 | #define __HIDP_H | 24 | #define __HIDP_H |
25 | 25 | ||
26 | #include <linux/types.h> | 26 | #include <linux/types.h> |
27 | #include <linux/kref.h> | ||
27 | #include <net/bluetooth/bluetooth.h> | 28 | #include <net/bluetooth/bluetooth.h> |
29 | #include <net/bluetooth/l2cap.h> | ||
28 | 30 | ||
29 | /* HIDP header masks */ | 31 | /* HIDP header masks */ |
30 | #define HIDP_HEADER_TRANS_MASK 0xf0 | 32 | #define HIDP_HEADER_TRANS_MASK 0xf0 |
@@ -119,42 +121,55 @@ struct hidp_connlist_req { | |||
119 | struct hidp_conninfo __user *ci; | 121 | struct hidp_conninfo __user *ci; |
120 | }; | 122 | }; |
121 | 123 | ||
124 | int hidp_connection_add(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock); | ||
125 | int hidp_connection_del(struct hidp_conndel_req *req); | ||
122 | int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock); | 126 | int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock); |
123 | int hidp_del_connection(struct hidp_conndel_req *req); | 127 | int hidp_del_connection(struct hidp_conndel_req *req); |
124 | int hidp_get_connlist(struct hidp_connlist_req *req); | 128 | int hidp_get_connlist(struct hidp_connlist_req *req); |
125 | int hidp_get_conninfo(struct hidp_conninfo *ci); | 129 | int hidp_get_conninfo(struct hidp_conninfo *ci); |
126 | 130 | ||
131 | enum hidp_session_state { | ||
132 | HIDP_SESSION_IDLING, | ||
133 | HIDP_SESSION_RUNNING, | ||
134 | }; | ||
135 | |||
127 | /* HIDP session defines */ | 136 | /* HIDP session defines */ |
128 | struct hidp_session { | 137 | struct hidp_session { |
129 | struct list_head list; | 138 | struct list_head list; |
139 | struct kref ref; | ||
130 | 140 | ||
131 | struct hci_conn *conn; | 141 | /* runtime management */ |
142 | atomic_t state; | ||
143 | wait_queue_head_t state_queue; | ||
144 | atomic_t terminate; | ||
145 | struct task_struct *task; | ||
146 | unsigned long flags; | ||
132 | 147 | ||
148 | /* connection management */ | ||
149 | bdaddr_t bdaddr; | ||
150 | struct hci_conn *hconn; | ||
151 | struct l2cap_conn *conn; | ||
152 | struct l2cap_user user; | ||
133 | struct socket *ctrl_sock; | 153 | struct socket *ctrl_sock; |
134 | struct socket *intr_sock; | 154 | struct socket *intr_sock; |
135 | 155 | struct sk_buff_head ctrl_transmit; | |
136 | bdaddr_t bdaddr; | 156 | struct sk_buff_head intr_transmit; |
137 | |||
138 | unsigned long flags; | ||
139 | unsigned long idle_to; | ||
140 | |||
141 | uint ctrl_mtu; | 157 | uint ctrl_mtu; |
142 | uint intr_mtu; | 158 | uint intr_mtu; |
159 | unsigned long idle_to; | ||
143 | 160 | ||
144 | atomic_t terminate; | 161 | /* device management */ |
145 | struct task_struct *task; | ||
146 | |||
147 | unsigned char keys[8]; | ||
148 | unsigned char leds; | ||
149 | |||
150 | struct input_dev *input; | 162 | struct input_dev *input; |
151 | |||
152 | struct hid_device *hid; | 163 | struct hid_device *hid; |
153 | |||
154 | struct timer_list timer; | 164 | struct timer_list timer; |
155 | 165 | ||
156 | struct sk_buff_head ctrl_transmit; | 166 | /* Report descriptor */ |
157 | struct sk_buff_head intr_transmit; | 167 | __u8 *rd_data; |
168 | uint rd_size; | ||
169 | |||
170 | /* session data */ | ||
171 | unsigned char keys[8]; | ||
172 | unsigned char leds; | ||
158 | 173 | ||
159 | /* Used in hidp_get_raw_report() */ | 174 | /* Used in hidp_get_raw_report() */ |
160 | int waiting_report_type; /* HIDP_DATA_RTYPE_* */ | 175 | int waiting_report_type; /* HIDP_DATA_RTYPE_* */ |
@@ -166,10 +181,6 @@ struct hidp_session { | |||
166 | /* Used in hidp_output_raw_report() */ | 181 | /* Used in hidp_output_raw_report() */ |
167 | int output_report_success; /* boolean */ | 182 | int output_report_success; /* boolean */ |
168 | 183 | ||
169 | /* Report descriptor */ | ||
170 | __u8 *rd_data; | ||
171 | uint rd_size; | ||
172 | |||
173 | wait_queue_head_t startup_queue; | 184 | wait_queue_head_t startup_queue; |
174 | int waiting_for_startup; | 185 | int waiting_for_startup; |
175 | }; | 186 | }; |