aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Tervo <ville.tervo@nokia.com>2011-02-10 20:38:50 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2011-02-16 14:33:02 -0500
commitb62f328b8f20abe97cdbaaf44c6e4f5e7a610f18 (patch)
tree85788ac51ee97fc12765e715f679c447f27ba5ac
parentacd7d3708555b3da7522e23c183cc21efc785f72 (diff)
Bluetooth: Add server socket support for LE connection
Add support for LE server sockets. Signed-off-by: Ville Tervo <ville.tervo@nokia.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
-rw-r--r--include/net/bluetooth/l2cap.h1
-rw-r--r--net/bluetooth/hci_event.c10
-rw-r--r--net/bluetooth/l2cap_core.c94
-rw-r--r--net/bluetooth/l2cap_sock.c7
4 files changed, 105 insertions, 7 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index cd7a64250e3..41b3bc56f13 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -38,6 +38,7 @@
38#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */ 38#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */
39#define L2CAP_DEFAULT_ACK_TO 200 39#define L2CAP_DEFAULT_ACK_TO 200
40#define L2CAP_LOCAL_BUSY_TRIES 12 40#define L2CAP_LOCAL_BUSY_TRIES 12
41#define L2CAP_LE_DEFAULT_MTU 23
41 42
42#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ 43#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
43#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ 44#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 3155ad58807..74f04a27734 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2405,8 +2405,14 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
2405 hci_dev_lock(hdev); 2405 hci_dev_lock(hdev);
2406 2406
2407 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr); 2407 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
2408 if (!conn) 2408 if (!conn) {
2409 goto unlock; 2409 conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
2410 if (!conn) {
2411 BT_ERR("No memory for new connection");
2412 hci_dev_unlock(hdev);
2413 return;
2414 }
2415 }
2410 2416
2411 if (ev->status) { 2417 if (ev->status) {
2412 hci_proto_connect_cfm(conn, ev->status); 2418 hci_proto_connect_cfm(conn, ev->status);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 123c1bfa0ce..3079175065d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -181,8 +181,16 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
181 l2cap_pi(sk)->conn = conn; 181 l2cap_pi(sk)->conn = conn;
182 182
183 if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) { 183 if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) {
184 /* Alloc CID for connection-oriented socket */ 184 if (conn->hcon->type == LE_LINK) {
185 l2cap_pi(sk)->scid = l2cap_alloc_cid(l); 185 /* LE connection */
186 l2cap_pi(sk)->omtu = L2CAP_LE_DEFAULT_MTU;
187 l2cap_pi(sk)->scid = L2CAP_CID_LE_DATA;
188 l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA;
189 } else {
190 /* Alloc CID for connection-oriented socket */
191 l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
192 l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
193 }
186 } else if (sk->sk_type == SOCK_DGRAM) { 194 } else if (sk->sk_type == SOCK_DGRAM) {
187 /* Connectionless socket */ 195 /* Connectionless socket */
188 l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS; 196 l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS;
@@ -581,6 +589,82 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
581 } 589 }
582} 590}
583 591
592/* Find socket with cid and source bdaddr.
593 * Returns closest match, locked.
594 */
595static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src)
596{
597 struct sock *s, *sk = NULL, *sk1 = NULL;
598 struct hlist_node *node;
599
600 read_lock(&l2cap_sk_list.lock);
601
602 sk_for_each(sk, node, &l2cap_sk_list.head) {
603 if (state && sk->sk_state != state)
604 continue;
605
606 if (l2cap_pi(sk)->scid == cid) {
607 /* Exact match. */
608 if (!bacmp(&bt_sk(sk)->src, src))
609 break;
610
611 /* Closest match */
612 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
613 sk1 = sk;
614 }
615 }
616 s = node ? sk : sk1;
617 if (s)
618 bh_lock_sock(s);
619 read_unlock(&l2cap_sk_list.lock);
620
621 return s;
622}
623
624static void l2cap_le_conn_ready(struct l2cap_conn *conn)
625{
626 struct l2cap_chan_list *list = &conn->chan_list;
627 struct sock *parent, *uninitialized_var(sk);
628
629 BT_DBG("");
630
631 /* Check if we have socket listening on cid */
632 parent = l2cap_get_sock_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
633 conn->src);
634 if (!parent)
635 return;
636
637 /* Check for backlog size */
638 if (sk_acceptq_is_full(parent)) {
639 BT_DBG("backlog full %d", parent->sk_ack_backlog);
640 goto clean;
641 }
642
643 sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
644 if (!sk)
645 goto clean;
646
647 write_lock_bh(&list->lock);
648
649 hci_conn_hold(conn->hcon);
650
651 l2cap_sock_init(sk, parent);
652 bacpy(&bt_sk(sk)->src, conn->src);
653 bacpy(&bt_sk(sk)->dst, conn->dst);
654
655 __l2cap_chan_add(conn, sk, parent);
656
657 l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
658
659 sk->sk_state = BT_CONNECTED;
660 parent->sk_data_ready(parent, 0);
661
662 write_unlock_bh(&list->lock);
663
664clean:
665 bh_unlock_sock(parent);
666}
667
584static void l2cap_conn_ready(struct l2cap_conn *conn) 668static void l2cap_conn_ready(struct l2cap_conn *conn)
585{ 669{
586 struct l2cap_chan_list *l = &conn->chan_list; 670 struct l2cap_chan_list *l = &conn->chan_list;
@@ -588,6 +672,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
588 672
589 BT_DBG("conn %p", conn); 673 BT_DBG("conn %p", conn);
590 674
675 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
676 l2cap_le_conn_ready(conn);
677
591 read_lock(&l->lock); 678 read_lock(&l->lock);
592 679
593 for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { 680 for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
@@ -670,7 +757,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
670 spin_lock_init(&conn->lock); 757 spin_lock_init(&conn->lock);
671 rwlock_init(&conn->chan_list.lock); 758 rwlock_init(&conn->chan_list.lock);
672 759
673 setup_timer(&conn->info_timer, l2cap_info_timeout, 760 if (hcon->type != LE_LINK)
761 setup_timer(&conn->info_timer, l2cap_info_timeout,
674 (unsigned long) conn); 762 (unsigned long) conn);
675 763
676 conn->disc_reason = 0x13; 764 conn->disc_reason = 0x13;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index f45d361e84d..a8d28937379 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -103,7 +103,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
103 len = min_t(unsigned int, sizeof(la), alen); 103 len = min_t(unsigned int, sizeof(la), alen);
104 memcpy(&la, addr, len); 104 memcpy(&la, addr, len);
105 105
106 if (la.l2_cid) 106 if (la.l2_cid && la.l2_psm)
107 return -EINVAL; 107 return -EINVAL;
108 108
109 lock_sock(sk); 109 lock_sock(sk);
@@ -145,6 +145,9 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
145 l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; 145 l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
146 } 146 }
147 147
148 if (la.l2_cid)
149 l2cap_pi(sk)->scid = la.l2_cid;
150
148 write_unlock_bh(&l2cap_sk_list.lock); 151 write_unlock_bh(&l2cap_sk_list.lock);
149 152
150done: 153done:
@@ -266,7 +269,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
266 goto done; 269 goto done;
267 } 270 }
268 271
269 if (!l2cap_pi(sk)->psm) { 272 if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->dcid) {
270 bdaddr_t *src = &bt_sk(sk)->src; 273 bdaddr_t *src = &bt_sk(sk)->src;
271 u16 psm; 274 u16 psm;
272 275