diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2010-06-07 19:54:45 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2010-07-21 13:39:09 -0400 |
commit | cf6c2c0b9f47ee3cd12684b905725c8376d52135 (patch) | |
tree | 0564fbf6b00891c810d8b91dbdb33c3e97ce1ce4 /net/bluetooth/l2cap.c | |
parent | 2ba13ed678775195e8255b4e503c59d48b615bd8 (diff) |
Bluetooth: Disconnect early if mode is not supported
When mode is mandatory we shall not send connect request and report this
to the userspace as well.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r-- | net/bluetooth/l2cap.c | 56 |
1 files changed, 40 insertions, 16 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 2fb45c481762..6a33d269389e 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -456,6 +456,22 @@ static void l2cap_do_start(struct sock *sk) | |||
456 | } | 456 | } |
457 | } | 457 | } |
458 | 458 | ||
459 | static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) | ||
460 | { | ||
461 | u32 local_feat_mask = l2cap_feat_mask; | ||
462 | if (enable_ertm) | ||
463 | local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING; | ||
464 | |||
465 | switch (mode) { | ||
466 | case L2CAP_MODE_ERTM: | ||
467 | return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask; | ||
468 | case L2CAP_MODE_STREAMING: | ||
469 | return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask; | ||
470 | default: | ||
471 | return 0x00; | ||
472 | } | ||
473 | } | ||
474 | |||
459 | static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) | 475 | static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) |
460 | { | 476 | { |
461 | struct l2cap_disconn_req req; | 477 | struct l2cap_disconn_req req; |
@@ -484,10 +500,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int | |||
484 | static void l2cap_conn_start(struct l2cap_conn *conn) | 500 | static void l2cap_conn_start(struct l2cap_conn *conn) |
485 | { | 501 | { |
486 | struct l2cap_chan_list *l = &conn->chan_list; | 502 | struct l2cap_chan_list *l = &conn->chan_list; |
503 | struct sock_del_list del, *tmp1, *tmp2; | ||
487 | struct sock *sk; | 504 | struct sock *sk; |
488 | 505 | ||
489 | BT_DBG("conn %p", conn); | 506 | BT_DBG("conn %p", conn); |
490 | 507 | ||
508 | INIT_LIST_HEAD(&del.list); | ||
509 | |||
491 | read_lock(&l->lock); | 510 | read_lock(&l->lock); |
492 | 511 | ||
493 | for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { | 512 | for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { |
@@ -503,6 +522,19 @@ static void l2cap_conn_start(struct l2cap_conn *conn) | |||
503 | if (l2cap_check_security(sk) && | 522 | if (l2cap_check_security(sk) && |
504 | __l2cap_no_conn_pending(sk)) { | 523 | __l2cap_no_conn_pending(sk)) { |
505 | struct l2cap_conn_req req; | 524 | struct l2cap_conn_req req; |
525 | |||
526 | if (!l2cap_mode_supported(l2cap_pi(sk)->mode, | ||
527 | conn->feat_mask) | ||
528 | && l2cap_pi(sk)->conf_state & | ||
529 | L2CAP_CONF_STATE2_DEVICE) { | ||
530 | tmp1 = kzalloc(sizeof(struct srej_list), | ||
531 | GFP_ATOMIC); | ||
532 | tmp1->sk = sk; | ||
533 | list_add_tail(&tmp1->list, &del.list); | ||
534 | bh_unlock_sock(sk); | ||
535 | continue; | ||
536 | } | ||
537 | |||
506 | req.scid = cpu_to_le16(l2cap_pi(sk)->scid); | 538 | req.scid = cpu_to_le16(l2cap_pi(sk)->scid); |
507 | req.psm = l2cap_pi(sk)->psm; | 539 | req.psm = l2cap_pi(sk)->psm; |
508 | 540 | ||
@@ -542,6 +574,14 @@ static void l2cap_conn_start(struct l2cap_conn *conn) | |||
542 | } | 574 | } |
543 | 575 | ||
544 | read_unlock(&l->lock); | 576 | read_unlock(&l->lock); |
577 | |||
578 | list_for_each_entry_safe(tmp1, tmp2, &del.list, list) { | ||
579 | bh_lock_sock(tmp1->sk); | ||
580 | __l2cap_sock_close(tmp1->sk, ECONNRESET); | ||
581 | bh_unlock_sock(tmp1->sk); | ||
582 | list_del(&tmp1->list); | ||
583 | kfree(tmp1); | ||
584 | } | ||
545 | } | 585 | } |
546 | 586 | ||
547 | static void l2cap_conn_ready(struct l2cap_conn *conn) | 587 | static void l2cap_conn_ready(struct l2cap_conn *conn) |
@@ -2429,22 +2469,6 @@ static inline void l2cap_ertm_init(struct sock *sk) | |||
2429 | INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); | 2469 | INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); |
2430 | } | 2470 | } |
2431 | 2471 | ||
2432 | static int l2cap_mode_supported(__u8 mode, __u32 feat_mask) | ||
2433 | { | ||
2434 | u32 local_feat_mask = l2cap_feat_mask; | ||
2435 | if (enable_ertm) | ||
2436 | local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING; | ||
2437 | |||
2438 | switch (mode) { | ||
2439 | case L2CAP_MODE_ERTM: | ||
2440 | return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask; | ||
2441 | case L2CAP_MODE_STREAMING: | ||
2442 | return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask; | ||
2443 | default: | ||
2444 | return 0x00; | ||
2445 | } | ||
2446 | } | ||
2447 | |||
2448 | static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) | 2472 | static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) |
2449 | { | 2473 | { |
2450 | switch (mode) { | 2474 | switch (mode) { |