aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2009-02-12 08:02:50 -0500
committerMarcel Holtmann <marcel@holtmann.org>2009-02-27 00:14:43 -0500
commit2950f21acb0f6b8fcd964485c2ebf1e06545ac20 (patch)
treea38b8c5a78849b9c88df24abe51d4e9c3a35424a
parentf29972de8e7476706ab3c01304a505e7c95d9040 (diff)
Bluetooth: Ask upper layers for HCI disconnect reason
Some of the qualification tests demand that in case of failures in L2CAP the HCI disconnect should indicate a reason why L2CAP fails. This is a bluntly layer violation since multiple L2CAP connections could be using the same ACL and thus forcing a disconnect reason is not a good idea. To comply with the Bluetooth test specification, the disconnect reason is now stored in the L2CAP connection structure and every time a new L2CAP channel is added it will set back to its default. So only in the case where the L2CAP channel with the disconnect reason is really the last one, it will propagated to the HCI layer. The HCI layer has been extended with a disconnect indication that allows it to ask upper layers for a disconnect reason. The upper layer must not support this callback and in that case it will nicely default to the existing behavior. If an upper layer like L2CAP can provide a disconnect reason that one will be used to disconnect the ACL or SCO link. No modification to the ACL disconnect timeout have been made. So in case of Linux to Linux connection the initiator will disconnect the ACL link before the acceptor side can signal the specific disconnect reason. That is perfectly fine since Linux doesn't make use of this value anyway. The L2CAP layer has a perfect valid error code for rejecting connection due to a security violation. It is unclear why the Bluetooth specification insists on having specific HCI disconnect reason. Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--include/net/bluetooth/hci_core.h25
-rw-r--r--include/net/bluetooth/l2cap.h2
-rw-r--r--net/bluetooth/hci_conn.c6
-rw-r--r--net/bluetooth/hci_event.c2
-rw-r--r--net/bluetooth/l2cap.c20
-rw-r--r--net/bluetooth/sco.c4
6 files changed, 49 insertions, 10 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 9473fce499e7..01f9316b4c23 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -478,7 +478,8 @@ struct hci_proto {
478 478
479 int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type); 479 int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
480 int (*connect_cfm) (struct hci_conn *conn, __u8 status); 480 int (*connect_cfm) (struct hci_conn *conn, __u8 status);
481 int (*disconn_ind) (struct hci_conn *conn, __u8 reason); 481 int (*disconn_ind) (struct hci_conn *conn);
482 int (*disconn_cfm) (struct hci_conn *conn, __u8 reason);
482 int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags); 483 int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
483 int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb); 484 int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
484 int (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt); 485 int (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
@@ -513,17 +514,33 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
513 hp->connect_cfm(conn, status); 514 hp->connect_cfm(conn, status);
514} 515}
515 516
516static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason) 517static inline int hci_proto_disconn_ind(struct hci_conn *conn)
517{ 518{
518 register struct hci_proto *hp; 519 register struct hci_proto *hp;
520 int reason = 0x13;
519 521
520 hp = hci_proto[HCI_PROTO_L2CAP]; 522 hp = hci_proto[HCI_PROTO_L2CAP];
521 if (hp && hp->disconn_ind) 523 if (hp && hp->disconn_ind)
522 hp->disconn_ind(conn, reason); 524 reason = hp->disconn_ind(conn);
523 525
524 hp = hci_proto[HCI_PROTO_SCO]; 526 hp = hci_proto[HCI_PROTO_SCO];
525 if (hp && hp->disconn_ind) 527 if (hp && hp->disconn_ind)
526 hp->disconn_ind(conn, reason); 528 reason = hp->disconn_ind(conn);
529
530 return reason;
531}
532
533static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
534{
535 register struct hci_proto *hp;
536
537 hp = hci_proto[HCI_PROTO_L2CAP];
538 if (hp && hp->disconn_cfm)
539 hp->disconn_cfm(conn, reason);
540
541 hp = hci_proto[HCI_PROTO_SCO];
542 if (hp && hp->disconn_cfm)
543 hp->disconn_cfm(conn, reason);
527} 544}
528 545
529static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) 546static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 54737c5dc86c..f566aa1f0a4c 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -221,6 +221,8 @@ struct l2cap_conn {
221 __u8 rx_ident; 221 __u8 rx_ident;
222 __u8 tx_ident; 222 __u8 tx_ident;
223 223
224 __u8 disc_reason;
225
224 struct l2cap_chan_list chan_list; 226 struct l2cap_chan_list chan_list;
225}; 227};
226 228
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index dcdaa4be7847..96281a11a186 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -159,6 +159,7 @@ static void hci_conn_timeout(unsigned long arg)
159{ 159{
160 struct hci_conn *conn = (void *) arg; 160 struct hci_conn *conn = (void *) arg;
161 struct hci_dev *hdev = conn->hdev; 161 struct hci_dev *hdev = conn->hdev;
162 __u8 reason;
162 163
163 BT_DBG("conn %p state %d", conn, conn->state); 164 BT_DBG("conn %p state %d", conn, conn->state);
164 165
@@ -177,7 +178,8 @@ static void hci_conn_timeout(unsigned long arg)
177 break; 178 break;
178 case BT_CONFIG: 179 case BT_CONFIG:
179 case BT_CONNECTED: 180 case BT_CONNECTED:
180 hci_acl_disconn(conn, 0x13); 181 reason = hci_proto_disconn_ind(conn);
182 hci_acl_disconn(conn, reason);
181 break; 183 break;
182 default: 184 default:
183 conn->state = BT_CLOSED; 185 conn->state = BT_CLOSED;
@@ -562,7 +564,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
562 564
563 hci_conn_del_sysfs(c); 565 hci_conn_del_sysfs(c);
564 566
565 hci_proto_disconn_ind(c, 0x16); 567 hci_proto_disconn_cfm(c, 0x16);
566 hci_conn_del(c); 568 hci_conn_del(c);
567 } 569 }
568} 570}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 899b8991a466..c396542c2b82 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1021,7 +1021,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
1021 1021
1022 hci_conn_del_sysfs(conn); 1022 hci_conn_del_sysfs(conn);
1023 1023
1024 hci_proto_disconn_ind(conn, ev->reason); 1024 hci_proto_disconn_cfm(conn, ev->reason);
1025 hci_conn_del(conn); 1025 hci_conn_del(conn);
1026 } 1026 }
1027 1027
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 7bba469b6828..d563f2ebcbb3 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -206,6 +206,8 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
206 206
207 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); 207 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
208 208
209 conn->disc_reason = 0x13;
210
209 l2cap_pi(sk)->conn = conn; 211 l2cap_pi(sk)->conn = conn;
210 212
211 if (sk->sk_type == SOCK_SEQPACKET) { 213 if (sk->sk_type == SOCK_SEQPACKET) {
@@ -491,6 +493,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
491 spin_lock_init(&conn->lock); 493 spin_lock_init(&conn->lock);
492 rwlock_init(&conn->chan_list.lock); 494 rwlock_init(&conn->chan_list.lock);
493 495
496 conn->disc_reason = 0x13;
497
494 return conn; 498 return conn;
495} 499}
496 500
@@ -1840,6 +1844,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
1840 /* Check if the ACL is secure enough (if not SDP) */ 1844 /* Check if the ACL is secure enough (if not SDP) */
1841 if (psm != cpu_to_le16(0x0001) && 1845 if (psm != cpu_to_le16(0x0001) &&
1842 !hci_conn_check_link_mode(conn->hcon)) { 1846 !hci_conn_check_link_mode(conn->hcon)) {
1847 conn->disc_reason = 0x05;
1843 result = L2CAP_CR_SEC_BLOCK; 1848 result = L2CAP_CR_SEC_BLOCK;
1844 goto response; 1849 goto response;
1845 } 1850 }
@@ -2472,7 +2477,19 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
2472 return 0; 2477 return 0;
2473} 2478}
2474 2479
2475static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason) 2480static int l2cap_disconn_ind(struct hci_conn *hcon)
2481{
2482 struct l2cap_conn *conn = hcon->l2cap_data;
2483
2484 BT_DBG("hcon %p", hcon);
2485
2486 if (hcon->type != ACL_LINK || !conn)
2487 return 0x13;
2488
2489 return conn->disc_reason;
2490}
2491
2492static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
2476{ 2493{
2477 BT_DBG("hcon %p reason %d", hcon, reason); 2494 BT_DBG("hcon %p reason %d", hcon, reason);
2478 2495
@@ -2717,6 +2734,7 @@ static struct hci_proto l2cap_hci_proto = {
2717 .connect_ind = l2cap_connect_ind, 2734 .connect_ind = l2cap_connect_ind,
2718 .connect_cfm = l2cap_connect_cfm, 2735 .connect_cfm = l2cap_connect_cfm,
2719 .disconn_ind = l2cap_disconn_ind, 2736 .disconn_ind = l2cap_disconn_ind,
2737 .disconn_cfm = l2cap_disconn_cfm,
2720 .security_cfm = l2cap_security_cfm, 2738 .security_cfm = l2cap_security_cfm,
2721 .recv_acldata = l2cap_recv_acldata 2739 .recv_acldata = l2cap_recv_acldata
2722}; 2740};
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 7f10f97cd697..51ae0c3e470a 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -902,7 +902,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
902 return 0; 902 return 0;
903} 903}
904 904
905static int sco_disconn_ind(struct hci_conn *hcon, __u8 reason) 905static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
906{ 906{
907 BT_DBG("hcon %p reason %d", hcon, reason); 907 BT_DBG("hcon %p reason %d", hcon, reason);
908 908
@@ -985,7 +985,7 @@ static struct hci_proto sco_hci_proto = {
985 .id = HCI_PROTO_SCO, 985 .id = HCI_PROTO_SCO,
986 .connect_ind = sco_connect_ind, 986 .connect_ind = sco_connect_ind,
987 .connect_cfm = sco_connect_cfm, 987 .connect_cfm = sco_connect_cfm,
988 .disconn_ind = sco_disconn_ind, 988 .disconn_cfm = sco_disconn_cfm,
989 .recv_scodata = sco_recv_scodata 989 .recv_scodata = sco_recv_scodata
990}; 990};
991 991