diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-02-03 17:50:35 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-02-07 22:43:30 -0500 |
commit | bb58f747e519aba07a6f05a78d58cf8a0788e2d5 (patch) | |
tree | d65743650d5f1a164bbb709a8aa7df4b13250623 | |
parent | 0a708f8fc46fde3be2116b8d79f7469a24097c90 (diff) |
Bluetooth: Initial work for L2CAP split.
This patch tries to do the minimal to move l2cap_sock_create() and its
dependencies to l2cap_sock.c. It create a API to initialize and cleanup
the L2CAP sockets from l2cap_core.c through l2cap_init_sockets() and
l2cap_cleanup_sockets().
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
-rw-r--r-- | include/net/bluetooth/l2cap.h | 15 | ||||
-rw-r--r-- | net/bluetooth/Makefile | 2 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 187 | ||||
-rw-r--r-- | net/bluetooth/l2cap_sock.c | 213 |
4 files changed, 240 insertions, 177 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7f88a87d7a46..fce5274a4f7b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -424,6 +424,21 @@ static inline int l2cap_tx_window_full(struct sock *sk) | |||
424 | #define __is_sframe(ctrl) ((ctrl) & L2CAP_CTRL_FRAME_TYPE) | 424 | #define __is_sframe(ctrl) ((ctrl) & L2CAP_CTRL_FRAME_TYPE) |
425 | #define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START) | 425 | #define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START) |
426 | 426 | ||
427 | extern int disable_ertm; | ||
428 | extern const struct proto_ops l2cap_sock_ops; | ||
429 | extern struct bt_sock_list l2cap_sk_list; | ||
430 | |||
431 | int l2cap_init_sockets(void); | ||
432 | void l2cap_cleanup_sockets(void); | ||
433 | |||
434 | void l2cap_sock_set_timer(struct sock *sk, long timeout); | ||
435 | void __l2cap_sock_close(struct sock *sk, int reason); | ||
436 | void l2cap_sock_kill(struct sock *sk); | ||
437 | void l2cap_sock_init(struct sock *sk, struct sock *parent); | ||
438 | struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, | ||
439 | int proto, gfp_t prio); | ||
440 | |||
441 | |||
427 | void l2cap_load(void); | 442 | void l2cap_load(void); |
428 | 443 | ||
429 | #endif /* __L2CAP_H */ | 444 | #endif /* __L2CAP_H */ |
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index bf2945e1d9ef..339b42932b33 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile | |||
@@ -11,4 +11,4 @@ obj-$(CONFIG_BT_CMTP) += cmtp/ | |||
11 | obj-$(CONFIG_BT_HIDP) += hidp/ | 11 | obj-$(CONFIG_BT_HIDP) += hidp/ |
12 | 12 | ||
13 | bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o | 13 | bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o |
14 | l2cap-y := l2cap_core.o | 14 | l2cap-y := l2cap_core.o l2cap_sock.o |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 28d2954f94a4..af678efec15f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -24,7 +24,7 @@ | |||
24 | SOFTWARE IS DISCLAIMED. | 24 | SOFTWARE IS DISCLAIMED. |
25 | */ | 25 | */ |
26 | 26 | ||
27 | /* Bluetooth L2CAP core and sockets. */ | 27 | /* Bluetooth L2CAP core. */ |
28 | 28 | ||
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | 30 | ||
@@ -57,24 +57,20 @@ | |||
57 | 57 | ||
58 | #define VERSION "2.15" | 58 | #define VERSION "2.15" |
59 | 59 | ||
60 | static int disable_ertm; | 60 | int disable_ertm; |
61 | 61 | ||
62 | static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; | 62 | static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; |
63 | static u8 l2cap_fixed_chan[8] = { 0x02, }; | 63 | static u8 l2cap_fixed_chan[8] = { 0x02, }; |
64 | 64 | ||
65 | static const struct proto_ops l2cap_sock_ops; | ||
66 | |||
67 | static struct workqueue_struct *_busy_wq; | 65 | static struct workqueue_struct *_busy_wq; |
68 | 66 | ||
69 | static struct bt_sock_list l2cap_sk_list = { | 67 | struct bt_sock_list l2cap_sk_list = { |
70 | .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) | 68 | .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) |
71 | }; | 69 | }; |
72 | 70 | ||
73 | static void l2cap_busy_work(struct work_struct *work); | 71 | static void l2cap_busy_work(struct work_struct *work); |
74 | 72 | ||
75 | static void __l2cap_sock_close(struct sock *sk, int reason); | ||
76 | static void l2cap_sock_close(struct sock *sk); | 73 | static void l2cap_sock_close(struct sock *sk); |
77 | static void l2cap_sock_kill(struct sock *sk); | ||
78 | 74 | ||
79 | static int l2cap_build_conf_req(struct sock *sk, void *data); | 75 | static int l2cap_build_conf_req(struct sock *sk, void *data); |
80 | static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, | 76 | static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, |
@@ -83,7 +79,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, | |||
83 | static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); | 79 | static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); |
84 | 80 | ||
85 | /* ---- L2CAP timers ---- */ | 81 | /* ---- L2CAP timers ---- */ |
86 | static void l2cap_sock_set_timer(struct sock *sk, long timeout) | 82 | void l2cap_sock_set_timer(struct sock *sk, long timeout) |
87 | { | 83 | { |
88 | BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); | 84 | BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); |
89 | sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); | 85 | sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); |
@@ -95,39 +91,6 @@ static void l2cap_sock_clear_timer(struct sock *sk) | |||
95 | sk_stop_timer(sk, &sk->sk_timer); | 91 | sk_stop_timer(sk, &sk->sk_timer); |
96 | } | 92 | } |
97 | 93 | ||
98 | static void l2cap_sock_timeout(unsigned long arg) | ||
99 | { | ||
100 | struct sock *sk = (struct sock *) arg; | ||
101 | int reason; | ||
102 | |||
103 | BT_DBG("sock %p state %d", sk, sk->sk_state); | ||
104 | |||
105 | bh_lock_sock(sk); | ||
106 | |||
107 | if (sock_owned_by_user(sk)) { | ||
108 | /* sk is owned by user. Try again later */ | ||
109 | l2cap_sock_set_timer(sk, HZ / 5); | ||
110 | bh_unlock_sock(sk); | ||
111 | sock_put(sk); | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) | ||
116 | reason = ECONNREFUSED; | ||
117 | else if (sk->sk_state == BT_CONNECT && | ||
118 | l2cap_pi(sk)->sec_level != BT_SECURITY_SDP) | ||
119 | reason = ECONNREFUSED; | ||
120 | else | ||
121 | reason = ETIMEDOUT; | ||
122 | |||
123 | __l2cap_sock_close(sk, reason); | ||
124 | |||
125 | bh_unlock_sock(sk); | ||
126 | |||
127 | l2cap_sock_kill(sk); | ||
128 | sock_put(sk); | ||
129 | } | ||
130 | |||
131 | /* ---- L2CAP channels ---- */ | 94 | /* ---- L2CAP channels ---- */ |
132 | static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) | 95 | static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) |
133 | { | 96 | { |
@@ -801,14 +764,6 @@ static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) | |||
801 | return node ? sk : sk1; | 764 | return node ? sk : sk1; |
802 | } | 765 | } |
803 | 766 | ||
804 | static void l2cap_sock_destruct(struct sock *sk) | ||
805 | { | ||
806 | BT_DBG("sk %p", sk); | ||
807 | |||
808 | skb_queue_purge(&sk->sk_receive_queue); | ||
809 | skb_queue_purge(&sk->sk_write_queue); | ||
810 | } | ||
811 | |||
812 | static void l2cap_sock_cleanup_listen(struct sock *parent) | 767 | static void l2cap_sock_cleanup_listen(struct sock *parent) |
813 | { | 768 | { |
814 | struct sock *sk; | 769 | struct sock *sk; |
@@ -826,7 +781,7 @@ static void l2cap_sock_cleanup_listen(struct sock *parent) | |||
826 | /* Kill socket (only if zapped and orphan) | 781 | /* Kill socket (only if zapped and orphan) |
827 | * Must be called on unlocked socket. | 782 | * Must be called on unlocked socket. |
828 | */ | 783 | */ |
829 | static void l2cap_sock_kill(struct sock *sk) | 784 | void l2cap_sock_kill(struct sock *sk) |
830 | { | 785 | { |
831 | if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket) | 786 | if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket) |
832 | return; | 787 | return; |
@@ -839,7 +794,7 @@ static void l2cap_sock_kill(struct sock *sk) | |||
839 | sock_put(sk); | 794 | sock_put(sk); |
840 | } | 795 | } |
841 | 796 | ||
842 | static void __l2cap_sock_close(struct sock *sk, int reason) | 797 | void __l2cap_sock_close(struct sock *sk, int reason) |
843 | { | 798 | { |
844 | BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); | 799 | BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); |
845 | 800 | ||
@@ -904,111 +859,6 @@ static void l2cap_sock_close(struct sock *sk) | |||
904 | l2cap_sock_kill(sk); | 859 | l2cap_sock_kill(sk); |
905 | } | 860 | } |
906 | 861 | ||
907 | static void l2cap_sock_init(struct sock *sk, struct sock *parent) | ||
908 | { | ||
909 | struct l2cap_pinfo *pi = l2cap_pi(sk); | ||
910 | |||
911 | BT_DBG("sk %p", sk); | ||
912 | |||
913 | if (parent) { | ||
914 | sk->sk_type = parent->sk_type; | ||
915 | bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; | ||
916 | |||
917 | pi->imtu = l2cap_pi(parent)->imtu; | ||
918 | pi->omtu = l2cap_pi(parent)->omtu; | ||
919 | pi->conf_state = l2cap_pi(parent)->conf_state; | ||
920 | pi->mode = l2cap_pi(parent)->mode; | ||
921 | pi->fcs = l2cap_pi(parent)->fcs; | ||
922 | pi->max_tx = l2cap_pi(parent)->max_tx; | ||
923 | pi->tx_win = l2cap_pi(parent)->tx_win; | ||
924 | pi->sec_level = l2cap_pi(parent)->sec_level; | ||
925 | pi->role_switch = l2cap_pi(parent)->role_switch; | ||
926 | pi->force_reliable = l2cap_pi(parent)->force_reliable; | ||
927 | pi->flushable = l2cap_pi(parent)->flushable; | ||
928 | } else { | ||
929 | pi->imtu = L2CAP_DEFAULT_MTU; | ||
930 | pi->omtu = 0; | ||
931 | if (!disable_ertm && sk->sk_type == SOCK_STREAM) { | ||
932 | pi->mode = L2CAP_MODE_ERTM; | ||
933 | pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; | ||
934 | } else { | ||
935 | pi->mode = L2CAP_MODE_BASIC; | ||
936 | } | ||
937 | pi->max_tx = L2CAP_DEFAULT_MAX_TX; | ||
938 | pi->fcs = L2CAP_FCS_CRC16; | ||
939 | pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; | ||
940 | pi->sec_level = BT_SECURITY_LOW; | ||
941 | pi->role_switch = 0; | ||
942 | pi->force_reliable = 0; | ||
943 | pi->flushable = BT_FLUSHABLE_OFF; | ||
944 | } | ||
945 | |||
946 | /* Default config options */ | ||
947 | pi->conf_len = 0; | ||
948 | pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; | ||
949 | skb_queue_head_init(TX_QUEUE(sk)); | ||
950 | skb_queue_head_init(SREJ_QUEUE(sk)); | ||
951 | skb_queue_head_init(BUSY_QUEUE(sk)); | ||
952 | INIT_LIST_HEAD(SREJ_LIST(sk)); | ||
953 | } | ||
954 | |||
955 | static struct proto l2cap_proto = { | ||
956 | .name = "L2CAP", | ||
957 | .owner = THIS_MODULE, | ||
958 | .obj_size = sizeof(struct l2cap_pinfo) | ||
959 | }; | ||
960 | |||
961 | static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) | ||
962 | { | ||
963 | struct sock *sk; | ||
964 | |||
965 | sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto); | ||
966 | if (!sk) | ||
967 | return NULL; | ||
968 | |||
969 | sock_init_data(sock, sk); | ||
970 | INIT_LIST_HEAD(&bt_sk(sk)->accept_q); | ||
971 | |||
972 | sk->sk_destruct = l2cap_sock_destruct; | ||
973 | sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT); | ||
974 | |||
975 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
976 | |||
977 | sk->sk_protocol = proto; | ||
978 | sk->sk_state = BT_OPEN; | ||
979 | |||
980 | setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk); | ||
981 | |||
982 | bt_sock_link(&l2cap_sk_list, sk); | ||
983 | return sk; | ||
984 | } | ||
985 | |||
986 | static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, | ||
987 | int kern) | ||
988 | { | ||
989 | struct sock *sk; | ||
990 | |||
991 | BT_DBG("sock %p", sock); | ||
992 | |||
993 | sock->state = SS_UNCONNECTED; | ||
994 | |||
995 | if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM && | ||
996 | sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) | ||
997 | return -ESOCKTNOSUPPORT; | ||
998 | |||
999 | if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) | ||
1000 | return -EPERM; | ||
1001 | |||
1002 | sock->ops = &l2cap_sock_ops; | ||
1003 | |||
1004 | sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC); | ||
1005 | if (!sk) | ||
1006 | return -ENOMEM; | ||
1007 | |||
1008 | l2cap_sock_init(sk, NULL); | ||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
1012 | static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | 862 | static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) |
1013 | { | 863 | { |
1014 | struct sock *sk = sock->sk; | 864 | struct sock *sk = sock->sk; |
@@ -4865,7 +4715,7 @@ static const struct file_operations l2cap_debugfs_fops = { | |||
4865 | 4715 | ||
4866 | static struct dentry *l2cap_debugfs; | 4716 | static struct dentry *l2cap_debugfs; |
4867 | 4717 | ||
4868 | static const struct proto_ops l2cap_sock_ops = { | 4718 | const struct proto_ops l2cap_sock_ops = { |
4869 | .family = PF_BLUETOOTH, | 4719 | .family = PF_BLUETOOTH, |
4870 | .owner = THIS_MODULE, | 4720 | .owner = THIS_MODULE, |
4871 | .release = l2cap_sock_release, | 4721 | .release = l2cap_sock_release, |
@@ -4885,12 +4735,6 @@ static const struct proto_ops l2cap_sock_ops = { | |||
4885 | .getsockopt = l2cap_sock_getsockopt | 4735 | .getsockopt = l2cap_sock_getsockopt |
4886 | }; | 4736 | }; |
4887 | 4737 | ||
4888 | static const struct net_proto_family l2cap_sock_family_ops = { | ||
4889 | .family = PF_BLUETOOTH, | ||
4890 | .owner = THIS_MODULE, | ||
4891 | .create = l2cap_sock_create, | ||
4892 | }; | ||
4893 | |||
4894 | static struct hci_proto l2cap_hci_proto = { | 4738 | static struct hci_proto l2cap_hci_proto = { |
4895 | .name = "L2CAP", | 4739 | .name = "L2CAP", |
4896 | .id = HCI_PROTO_L2CAP, | 4740 | .id = HCI_PROTO_L2CAP, |
@@ -4906,19 +4750,13 @@ static int __init l2cap_init(void) | |||
4906 | { | 4750 | { |
4907 | int err; | 4751 | int err; |
4908 | 4752 | ||
4909 | err = proto_register(&l2cap_proto, 0); | 4753 | err = l2cap_init_sockets(); |
4910 | if (err < 0) | 4754 | if (err < 0) |
4911 | return err; | 4755 | return err; |
4912 | 4756 | ||
4913 | _busy_wq = create_singlethread_workqueue("l2cap"); | 4757 | _busy_wq = create_singlethread_workqueue("l2cap"); |
4914 | if (!_busy_wq) { | 4758 | if (!_busy_wq) { |
4915 | proto_unregister(&l2cap_proto); | 4759 | err = -ENOMEM; |
4916 | return -ENOMEM; | ||
4917 | } | ||
4918 | |||
4919 | err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops); | ||
4920 | if (err < 0) { | ||
4921 | BT_ERR("L2CAP socket registration failed"); | ||
4922 | goto error; | 4760 | goto error; |
4923 | } | 4761 | } |
4924 | 4762 | ||
@@ -4943,7 +4781,7 @@ static int __init l2cap_init(void) | |||
4943 | 4781 | ||
4944 | error: | 4782 | error: |
4945 | destroy_workqueue(_busy_wq); | 4783 | destroy_workqueue(_busy_wq); |
4946 | proto_unregister(&l2cap_proto); | 4784 | l2cap_cleanup_sockets(); |
4947 | return err; | 4785 | return err; |
4948 | } | 4786 | } |
4949 | 4787 | ||
@@ -4954,13 +4792,10 @@ static void __exit l2cap_exit(void) | |||
4954 | flush_workqueue(_busy_wq); | 4792 | flush_workqueue(_busy_wq); |
4955 | destroy_workqueue(_busy_wq); | 4793 | destroy_workqueue(_busy_wq); |
4956 | 4794 | ||
4957 | if (bt_sock_unregister(BTPROTO_L2CAP) < 0) | ||
4958 | BT_ERR("L2CAP socket unregistration failed"); | ||
4959 | |||
4960 | if (hci_unregister_proto(&l2cap_hci_proto) < 0) | 4795 | if (hci_unregister_proto(&l2cap_hci_proto) < 0) |
4961 | BT_ERR("L2CAP protocol unregistration failed"); | 4796 | BT_ERR("L2CAP protocol unregistration failed"); |
4962 | 4797 | ||
4963 | proto_unregister(&l2cap_proto); | 4798 | l2cap_cleanup_sockets(); |
4964 | } | 4799 | } |
4965 | 4800 | ||
4966 | void l2cap_load(void) | 4801 | void l2cap_load(void) |
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c new file mode 100644 index 000000000000..6ea1894cecb7 --- /dev/null +++ b/net/bluetooth/l2cap_sock.c | |||
@@ -0,0 +1,213 @@ | |||
1 | /* | ||
2 | BlueZ - Bluetooth protocol stack for Linux | ||
3 | Copyright (C) 2000-2001 Qualcomm Incorporated | ||
4 | Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org> | ||
5 | Copyright (C) 2010 Google Inc. | ||
6 | |||
7 | Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> | ||
8 | |||
9 | This program is free software; you can redistribute it and/or modify | ||
10 | it under the terms of the GNU General Public License version 2 as | ||
11 | published by the Free Software Foundation; | ||
12 | |||
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
14 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
16 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
17 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
18 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
19 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
20 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
21 | |||
22 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
23 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
24 | SOFTWARE IS DISCLAIMED. | ||
25 | */ | ||
26 | |||
27 | /* Bluetooth L2CAP sockets. */ | ||
28 | |||
29 | #include <net/bluetooth/bluetooth.h> | ||
30 | #include <net/bluetooth/l2cap.h> | ||
31 | |||
32 | static void l2cap_sock_timeout(unsigned long arg) | ||
33 | { | ||
34 | struct sock *sk = (struct sock *) arg; | ||
35 | int reason; | ||
36 | |||
37 | BT_DBG("sock %p state %d", sk, sk->sk_state); | ||
38 | |||
39 | bh_lock_sock(sk); | ||
40 | |||
41 | if (sock_owned_by_user(sk)) { | ||
42 | /* sk is owned by user. Try again later */ | ||
43 | l2cap_sock_set_timer(sk, HZ / 5); | ||
44 | bh_unlock_sock(sk); | ||
45 | sock_put(sk); | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) | ||
50 | reason = ECONNREFUSED; | ||
51 | else if (sk->sk_state == BT_CONNECT && | ||
52 | l2cap_pi(sk)->sec_level != BT_SECURITY_SDP) | ||
53 | reason = ECONNREFUSED; | ||
54 | else | ||
55 | reason = ETIMEDOUT; | ||
56 | |||
57 | __l2cap_sock_close(sk, reason); | ||
58 | |||
59 | bh_unlock_sock(sk); | ||
60 | |||
61 | l2cap_sock_kill(sk); | ||
62 | sock_put(sk); | ||
63 | } | ||
64 | |||
65 | |||
66 | static void l2cap_sock_destruct(struct sock *sk) | ||
67 | { | ||
68 | BT_DBG("sk %p", sk); | ||
69 | |||
70 | skb_queue_purge(&sk->sk_receive_queue); | ||
71 | skb_queue_purge(&sk->sk_write_queue); | ||
72 | } | ||
73 | |||
74 | void l2cap_sock_init(struct sock *sk, struct sock *parent) | ||
75 | { | ||
76 | struct l2cap_pinfo *pi = l2cap_pi(sk); | ||
77 | |||
78 | BT_DBG("sk %p", sk); | ||
79 | |||
80 | if (parent) { | ||
81 | sk->sk_type = parent->sk_type; | ||
82 | bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; | ||
83 | |||
84 | pi->imtu = l2cap_pi(parent)->imtu; | ||
85 | pi->omtu = l2cap_pi(parent)->omtu; | ||
86 | pi->conf_state = l2cap_pi(parent)->conf_state; | ||
87 | pi->mode = l2cap_pi(parent)->mode; | ||
88 | pi->fcs = l2cap_pi(parent)->fcs; | ||
89 | pi->max_tx = l2cap_pi(parent)->max_tx; | ||
90 | pi->tx_win = l2cap_pi(parent)->tx_win; | ||
91 | pi->sec_level = l2cap_pi(parent)->sec_level; | ||
92 | pi->role_switch = l2cap_pi(parent)->role_switch; | ||
93 | pi->force_reliable = l2cap_pi(parent)->force_reliable; | ||
94 | pi->flushable = l2cap_pi(parent)->flushable; | ||
95 | } else { | ||
96 | pi->imtu = L2CAP_DEFAULT_MTU; | ||
97 | pi->omtu = 0; | ||
98 | if (!disable_ertm && sk->sk_type == SOCK_STREAM) { | ||
99 | pi->mode = L2CAP_MODE_ERTM; | ||
100 | pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; | ||
101 | } else { | ||
102 | pi->mode = L2CAP_MODE_BASIC; | ||
103 | } | ||
104 | pi->max_tx = L2CAP_DEFAULT_MAX_TX; | ||
105 | pi->fcs = L2CAP_FCS_CRC16; | ||
106 | pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; | ||
107 | pi->sec_level = BT_SECURITY_LOW; | ||
108 | pi->role_switch = 0; | ||
109 | pi->force_reliable = 0; | ||
110 | pi->flushable = BT_FLUSHABLE_OFF; | ||
111 | } | ||
112 | |||
113 | /* Default config options */ | ||
114 | pi->conf_len = 0; | ||
115 | pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; | ||
116 | skb_queue_head_init(TX_QUEUE(sk)); | ||
117 | skb_queue_head_init(SREJ_QUEUE(sk)); | ||
118 | skb_queue_head_init(BUSY_QUEUE(sk)); | ||
119 | INIT_LIST_HEAD(SREJ_LIST(sk)); | ||
120 | } | ||
121 | |||
122 | static struct proto l2cap_proto = { | ||
123 | .name = "L2CAP", | ||
124 | .owner = THIS_MODULE, | ||
125 | .obj_size = sizeof(struct l2cap_pinfo) | ||
126 | }; | ||
127 | |||
128 | struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) | ||
129 | { | ||
130 | struct sock *sk; | ||
131 | |||
132 | sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto); | ||
133 | if (!sk) | ||
134 | return NULL; | ||
135 | |||
136 | sock_init_data(sock, sk); | ||
137 | INIT_LIST_HEAD(&bt_sk(sk)->accept_q); | ||
138 | |||
139 | sk->sk_destruct = l2cap_sock_destruct; | ||
140 | sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT); | ||
141 | |||
142 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
143 | |||
144 | sk->sk_protocol = proto; | ||
145 | sk->sk_state = BT_OPEN; | ||
146 | |||
147 | setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk); | ||
148 | |||
149 | bt_sock_link(&l2cap_sk_list, sk); | ||
150 | return sk; | ||
151 | } | ||
152 | |||
153 | static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, | ||
154 | int kern) | ||
155 | { | ||
156 | struct sock *sk; | ||
157 | |||
158 | BT_DBG("sock %p", sock); | ||
159 | |||
160 | sock->state = SS_UNCONNECTED; | ||
161 | |||
162 | if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM && | ||
163 | sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) | ||
164 | return -ESOCKTNOSUPPORT; | ||
165 | |||
166 | if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) | ||
167 | return -EPERM; | ||
168 | |||
169 | sock->ops = &l2cap_sock_ops; | ||
170 | |||
171 | sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC); | ||
172 | if (!sk) | ||
173 | return -ENOMEM; | ||
174 | |||
175 | l2cap_sock_init(sk, NULL); | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static const struct net_proto_family l2cap_sock_family_ops = { | ||
180 | .family = PF_BLUETOOTH, | ||
181 | .owner = THIS_MODULE, | ||
182 | .create = l2cap_sock_create, | ||
183 | }; | ||
184 | |||
185 | int __init l2cap_init_sockets(void) | ||
186 | { | ||
187 | int err; | ||
188 | |||
189 | err = proto_register(&l2cap_proto, 0); | ||
190 | if (err < 0) | ||
191 | return err; | ||
192 | |||
193 | err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops); | ||
194 | if (err < 0) | ||
195 | goto error; | ||
196 | |||
197 | BT_INFO("L2CAP socket layer initialized"); | ||
198 | |||
199 | return 0; | ||
200 | |||
201 | error: | ||
202 | BT_ERR("L2CAP socket registration failed"); | ||
203 | proto_unregister(&l2cap_proto); | ||
204 | return err; | ||
205 | } | ||
206 | |||
207 | void l2cap_cleanup_sockets(void) | ||
208 | { | ||
209 | if (bt_sock_unregister(BTPROTO_L2CAP) < 0) | ||
210 | BT_ERR("L2CAP socket unregistration failed"); | ||
211 | |||
212 | proto_unregister(&l2cap_proto); | ||
213 | } | ||