diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/l2cap.c | 166 |
1 files changed, 118 insertions, 48 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 6e180d255505..2e3abdfbd69d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -55,7 +55,7 @@ | |||
55 | #define BT_DBG(D...) | 55 | #define BT_DBG(D...) |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | #define VERSION "2.9" | 58 | #define VERSION "2.10" |
59 | 59 | ||
60 | static u32 l2cap_feat_mask = 0x0000; | 60 | static u32 l2cap_feat_mask = 0x0000; |
61 | 61 | ||
@@ -253,6 +253,21 @@ static void l2cap_chan_del(struct sock *sk, int err) | |||
253 | sk->sk_state_change(sk); | 253 | sk->sk_state_change(sk); |
254 | } | 254 | } |
255 | 255 | ||
256 | /* Service level security */ | ||
257 | static inline int l2cap_check_link_mode(struct sock *sk) | ||
258 | { | ||
259 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; | ||
260 | |||
261 | if ((l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) || | ||
262 | (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)) | ||
263 | return hci_conn_encrypt(conn->hcon); | ||
264 | |||
265 | if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) | ||
266 | return hci_conn_auth(conn->hcon); | ||
267 | |||
268 | return 1; | ||
269 | } | ||
270 | |||
256 | static inline u8 l2cap_get_ident(struct l2cap_conn *conn) | 271 | static inline u8 l2cap_get_ident(struct l2cap_conn *conn) |
257 | { | 272 | { |
258 | u8 id; | 273 | u8 id; |
@@ -287,6 +302,34 @@ static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 | |||
287 | return hci_send_acl(conn->hcon, skb, 0); | 302 | return hci_send_acl(conn->hcon, skb, 0); |
288 | } | 303 | } |
289 | 304 | ||
305 | static void l2cap_do_start(struct sock *sk) | ||
306 | { | ||
307 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; | ||
308 | |||
309 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { | ||
310 | struct l2cap_conn_req req; | ||
311 | req.scid = cpu_to_le16(l2cap_pi(sk)->scid); | ||
312 | req.psm = l2cap_pi(sk)->psm; | ||
313 | |||
314 | l2cap_pi(sk)->ident = l2cap_get_ident(conn); | ||
315 | |||
316 | l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | ||
317 | L2CAP_CONN_REQ, sizeof(req), &req); | ||
318 | } else { | ||
319 | struct l2cap_info_req req; | ||
320 | req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); | ||
321 | |||
322 | conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; | ||
323 | conn->info_ident = l2cap_get_ident(conn); | ||
324 | |||
325 | mod_timer(&conn->info_timer, jiffies + | ||
326 | msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); | ||
327 | |||
328 | l2cap_send_cmd(conn, conn->info_ident, | ||
329 | L2CAP_INFO_REQ, sizeof(req), &req); | ||
330 | } | ||
331 | } | ||
332 | |||
290 | /* ---- L2CAP connections ---- */ | 333 | /* ---- L2CAP connections ---- */ |
291 | static void l2cap_conn_start(struct l2cap_conn *conn) | 334 | static void l2cap_conn_start(struct l2cap_conn *conn) |
292 | { | 335 | { |
@@ -301,16 +344,35 @@ static void l2cap_conn_start(struct l2cap_conn *conn) | |||
301 | bh_lock_sock(sk); | 344 | bh_lock_sock(sk); |
302 | 345 | ||
303 | if (sk->sk_type != SOCK_SEQPACKET) { | 346 | if (sk->sk_type != SOCK_SEQPACKET) { |
304 | l2cap_sock_clear_timer(sk); | 347 | bh_unlock_sock(sk); |
305 | sk->sk_state = BT_CONNECTED; | 348 | continue; |
306 | sk->sk_state_change(sk); | 349 | } |
307 | } else if (sk->sk_state == BT_CONNECT) { | 350 | |
351 | if (sk->sk_state == BT_CONNECT) { | ||
308 | struct l2cap_conn_req req; | 352 | struct l2cap_conn_req req; |
309 | l2cap_pi(sk)->ident = l2cap_get_ident(conn); | ||
310 | req.scid = cpu_to_le16(l2cap_pi(sk)->scid); | 353 | req.scid = cpu_to_le16(l2cap_pi(sk)->scid); |
311 | req.psm = l2cap_pi(sk)->psm; | 354 | req.psm = l2cap_pi(sk)->psm; |
355 | |||
356 | l2cap_pi(sk)->ident = l2cap_get_ident(conn); | ||
357 | |||
312 | l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | 358 | l2cap_send_cmd(conn, l2cap_pi(sk)->ident, |
313 | L2CAP_CONN_REQ, sizeof(req), &req); | 359 | L2CAP_CONN_REQ, sizeof(req), &req); |
360 | } else if (sk->sk_state == BT_CONNECT2) { | ||
361 | struct l2cap_conn_rsp rsp; | ||
362 | rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); | ||
363 | rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); | ||
364 | |||
365 | if (l2cap_check_link_mode(sk)) { | ||
366 | sk->sk_state = BT_CONFIG; | ||
367 | rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); | ||
368 | rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); | ||
369 | } else { | ||
370 | rsp.result = cpu_to_le16(L2CAP_CR_PEND); | ||
371 | rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); | ||
372 | } | ||
373 | |||
374 | l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | ||
375 | L2CAP_CONN_RSP, sizeof(rsp), &rsp); | ||
314 | } | 376 | } |
315 | 377 | ||
316 | bh_unlock_sock(sk); | 378 | bh_unlock_sock(sk); |
@@ -321,22 +383,27 @@ static void l2cap_conn_start(struct l2cap_conn *conn) | |||
321 | 383 | ||
322 | static void l2cap_conn_ready(struct l2cap_conn *conn) | 384 | static void l2cap_conn_ready(struct l2cap_conn *conn) |
323 | { | 385 | { |
324 | BT_DBG("conn %p", conn); | 386 | struct l2cap_chan_list *l = &conn->chan_list; |
387 | struct sock *sk; | ||
325 | 388 | ||
326 | if (conn->chan_list.head || !hlist_empty(&l2cap_sk_list.head)) { | 389 | BT_DBG("conn %p", conn); |
327 | struct l2cap_info_req req; | ||
328 | 390 | ||
329 | req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); | 391 | read_lock(&l->lock); |
330 | 392 | ||
331 | conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; | 393 | for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { |
332 | conn->info_ident = l2cap_get_ident(conn); | 394 | bh_lock_sock(sk); |
333 | 395 | ||
334 | mod_timer(&conn->info_timer, | 396 | if (sk->sk_type != SOCK_SEQPACKET) { |
335 | jiffies + msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); | 397 | l2cap_sock_clear_timer(sk); |
398 | sk->sk_state = BT_CONNECTED; | ||
399 | sk->sk_state_change(sk); | ||
400 | } else if (sk->sk_state == BT_CONNECT) | ||
401 | l2cap_do_start(sk); | ||
336 | 402 | ||
337 | l2cap_send_cmd(conn, conn->info_ident, | 403 | bh_unlock_sock(sk); |
338 | L2CAP_INFO_REQ, sizeof(req), &req); | ||
339 | } | 404 | } |
405 | |||
406 | read_unlock(&l->lock); | ||
340 | } | 407 | } |
341 | 408 | ||
342 | /* Notify sockets that we cannot guaranty reliability anymore */ | 409 | /* Notify sockets that we cannot guaranty reliability anymore */ |
@@ -729,22 +796,11 @@ static int l2cap_do_connect(struct sock *sk) | |||
729 | l2cap_sock_set_timer(sk, sk->sk_sndtimeo); | 796 | l2cap_sock_set_timer(sk, sk->sk_sndtimeo); |
730 | 797 | ||
731 | if (hcon->state == BT_CONNECTED) { | 798 | if (hcon->state == BT_CONNECTED) { |
732 | if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)) { | 799 | if (sk->sk_type != SOCK_SEQPACKET) { |
733 | l2cap_conn_ready(conn); | ||
734 | goto done; | ||
735 | } | ||
736 | |||
737 | if (sk->sk_type == SOCK_SEQPACKET) { | ||
738 | struct l2cap_conn_req req; | ||
739 | l2cap_pi(sk)->ident = l2cap_get_ident(conn); | ||
740 | req.scid = cpu_to_le16(l2cap_pi(sk)->scid); | ||
741 | req.psm = l2cap_pi(sk)->psm; | ||
742 | l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | ||
743 | L2CAP_CONN_REQ, sizeof(req), &req); | ||
744 | } else { | ||
745 | l2cap_sock_clear_timer(sk); | 800 | l2cap_sock_clear_timer(sk); |
746 | sk->sk_state = BT_CONNECTED; | 801 | sk->sk_state = BT_CONNECTED; |
747 | } | 802 | } else |
803 | l2cap_do_start(sk); | ||
748 | } | 804 | } |
749 | 805 | ||
750 | done: | 806 | done: |
@@ -1477,7 +1533,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd | |||
1477 | struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; | 1533 | struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; |
1478 | struct l2cap_conn_rsp rsp; | 1534 | struct l2cap_conn_rsp rsp; |
1479 | struct sock *sk, *parent; | 1535 | struct sock *sk, *parent; |
1480 | int result = 0, status = 0; | 1536 | int result, status = 0; |
1481 | 1537 | ||
1482 | u16 dcid = 0, scid = __le16_to_cpu(req->scid); | 1538 | u16 dcid = 0, scid = __le16_to_cpu(req->scid); |
1483 | __le16 psm = req->psm; | 1539 | __le16 psm = req->psm; |
@@ -1526,25 +1582,24 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd | |||
1526 | 1582 | ||
1527 | l2cap_sock_set_timer(sk, sk->sk_sndtimeo); | 1583 | l2cap_sock_set_timer(sk, sk->sk_sndtimeo); |
1528 | 1584 | ||
1529 | /* Service level security */ | ||
1530 | result = L2CAP_CR_PEND; | ||
1531 | status = L2CAP_CS_AUTHEN_PEND; | ||
1532 | sk->sk_state = BT_CONNECT2; | ||
1533 | l2cap_pi(sk)->ident = cmd->ident; | 1585 | l2cap_pi(sk)->ident = cmd->ident; |
1534 | 1586 | ||
1535 | if ((l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) || | 1587 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { |
1536 | (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)) { | 1588 | if (l2cap_check_link_mode(sk)) { |
1537 | if (!hci_conn_encrypt(conn->hcon)) | 1589 | sk->sk_state = BT_CONFIG; |
1538 | goto done; | 1590 | result = L2CAP_CR_SUCCESS; |
1539 | } else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) { | 1591 | status = L2CAP_CS_NO_INFO; |
1540 | if (!hci_conn_auth(conn->hcon)) | 1592 | } else { |
1541 | goto done; | 1593 | sk->sk_state = BT_CONNECT2; |
1594 | result = L2CAP_CR_PEND; | ||
1595 | status = L2CAP_CS_AUTHEN_PEND; | ||
1596 | } | ||
1597 | } else { | ||
1598 | sk->sk_state = BT_CONNECT2; | ||
1599 | result = L2CAP_CR_PEND; | ||
1600 | status = L2CAP_CS_NO_INFO; | ||
1542 | } | 1601 | } |
1543 | 1602 | ||
1544 | sk->sk_state = BT_CONFIG; | ||
1545 | result = status = 0; | ||
1546 | |||
1547 | done: | ||
1548 | write_unlock_bh(&list->lock); | 1603 | write_unlock_bh(&list->lock); |
1549 | 1604 | ||
1550 | response: | 1605 | response: |
@@ -1556,6 +1611,21 @@ sendresp: | |||
1556 | rsp.result = cpu_to_le16(result); | 1611 | rsp.result = cpu_to_le16(result); |
1557 | rsp.status = cpu_to_le16(status); | 1612 | rsp.status = cpu_to_le16(status); |
1558 | l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); | 1613 | l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); |
1614 | |||
1615 | if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) { | ||
1616 | struct l2cap_info_req info; | ||
1617 | info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); | ||
1618 | |||
1619 | conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; | ||
1620 | conn->info_ident = l2cap_get_ident(conn); | ||
1621 | |||
1622 | mod_timer(&conn->info_timer, jiffies + | ||
1623 | msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); | ||
1624 | |||
1625 | l2cap_send_cmd(conn, conn->info_ident, | ||
1626 | L2CAP_INFO_REQ, sizeof(info), &info); | ||
1627 | } | ||
1628 | |||
1559 | return 0; | 1629 | return 0; |
1560 | } | 1630 | } |
1561 | 1631 | ||
@@ -1664,9 +1734,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr | |||
1664 | } | 1734 | } |
1665 | 1735 | ||
1666 | if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { | 1736 | if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { |
1667 | u8 req[64]; | 1737 | u8 buf[64]; |
1668 | l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, | 1738 | l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, |
1669 | l2cap_build_conf_req(sk, req), req); | 1739 | l2cap_build_conf_req(sk, buf), buf); |
1670 | } | 1740 | } |
1671 | 1741 | ||
1672 | unlock: | 1742 | unlock: |