diff options
author | Ville Tervo <ville.tervo@nokia.com> | 2011-02-10 20:38:50 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-02-16 14:33:02 -0500 |
commit | b62f328b8f20abe97cdbaaf44c6e4f5e7a610f18 (patch) | |
tree | 85788ac51ee97fc12765e715f679c447f27ba5ac /net/bluetooth | |
parent | acd7d3708555b3da7522e23c183cc21efc785f72 (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>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/hci_event.c | 10 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 94 | ||||
-rw-r--r-- | net/bluetooth/l2cap_sock.c | 7 |
3 files changed, 104 insertions, 7 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3155ad588076..74f04a27734d 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 123c1bfa0ce6..3079175065d4 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 | */ | ||
595 | static 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 | |||
624 | static 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 | |||
664 | clean: | ||
665 | bh_unlock_sock(parent); | ||
666 | } | ||
667 | |||
584 | static void l2cap_conn_ready(struct l2cap_conn *conn) | 668 | static 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 f45d361e84d1..a8d289373794 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 | ||
150 | done: | 153 | done: |
@@ -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 | ||