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 /net/bluetooth/l2cap_sock.c | |
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>
Diffstat (limited to 'net/bluetooth/l2cap_sock.c')
-rw-r--r-- | net/bluetooth/l2cap_sock.c | 213 |
1 files changed, 213 insertions, 0 deletions
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 | } | ||