Commit | Line | Data |
---|---|---|
bb58f747 GP |
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 | ||
bb58f747 GP |
65 | static void l2cap_sock_destruct(struct sock *sk) |
66 | { | |
67 | BT_DBG("sk %p", sk); | |
68 | ||
69 | skb_queue_purge(&sk->sk_receive_queue); | |
70 | skb_queue_purge(&sk->sk_write_queue); | |
71 | } | |
72 | ||
73 | void l2cap_sock_init(struct sock *sk, struct sock *parent) | |
74 | { | |
75 | struct l2cap_pinfo *pi = l2cap_pi(sk); | |
76 | ||
77 | BT_DBG("sk %p", sk); | |
78 | ||
79 | if (parent) { | |
80 | sk->sk_type = parent->sk_type; | |
81 | bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; | |
82 | ||
83 | pi->imtu = l2cap_pi(parent)->imtu; | |
84 | pi->omtu = l2cap_pi(parent)->omtu; | |
85 | pi->conf_state = l2cap_pi(parent)->conf_state; | |
86 | pi->mode = l2cap_pi(parent)->mode; | |
87 | pi->fcs = l2cap_pi(parent)->fcs; | |
88 | pi->max_tx = l2cap_pi(parent)->max_tx; | |
89 | pi->tx_win = l2cap_pi(parent)->tx_win; | |
90 | pi->sec_level = l2cap_pi(parent)->sec_level; | |
91 | pi->role_switch = l2cap_pi(parent)->role_switch; | |
92 | pi->force_reliable = l2cap_pi(parent)->force_reliable; | |
93 | pi->flushable = l2cap_pi(parent)->flushable; | |
94 | } else { | |
95 | pi->imtu = L2CAP_DEFAULT_MTU; | |
96 | pi->omtu = 0; | |
97 | if (!disable_ertm && sk->sk_type == SOCK_STREAM) { | |
98 | pi->mode = L2CAP_MODE_ERTM; | |
99 | pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; | |
100 | } else { | |
101 | pi->mode = L2CAP_MODE_BASIC; | |
102 | } | |
103 | pi->max_tx = L2CAP_DEFAULT_MAX_TX; | |
104 | pi->fcs = L2CAP_FCS_CRC16; | |
105 | pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; | |
106 | pi->sec_level = BT_SECURITY_LOW; | |
107 | pi->role_switch = 0; | |
108 | pi->force_reliable = 0; | |
109 | pi->flushable = BT_FLUSHABLE_OFF; | |
110 | } | |
111 | ||
112 | /* Default config options */ | |
113 | pi->conf_len = 0; | |
114 | pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; | |
115 | skb_queue_head_init(TX_QUEUE(sk)); | |
116 | skb_queue_head_init(SREJ_QUEUE(sk)); | |
117 | skb_queue_head_init(BUSY_QUEUE(sk)); | |
118 | INIT_LIST_HEAD(SREJ_LIST(sk)); | |
119 | } | |
120 | ||
121 | static struct proto l2cap_proto = { | |
122 | .name = "L2CAP", | |
123 | .owner = THIS_MODULE, | |
124 | .obj_size = sizeof(struct l2cap_pinfo) | |
125 | }; | |
126 | ||
127 | struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) | |
128 | { | |
129 | struct sock *sk; | |
130 | ||
131 | sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto); | |
132 | if (!sk) | |
133 | return NULL; | |
134 | ||
135 | sock_init_data(sock, sk); | |
136 | INIT_LIST_HEAD(&bt_sk(sk)->accept_q); | |
137 | ||
138 | sk->sk_destruct = l2cap_sock_destruct; | |
139 | sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT); | |
140 | ||
141 | sock_reset_flag(sk, SOCK_ZAPPED); | |
142 | ||
143 | sk->sk_protocol = proto; | |
144 | sk->sk_state = BT_OPEN; | |
145 | ||
146 | setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk); | |
147 | ||
148 | bt_sock_link(&l2cap_sk_list, sk); | |
149 | return sk; | |
150 | } | |
151 | ||
152 | static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, | |
153 | int kern) | |
154 | { | |
155 | struct sock *sk; | |
156 | ||
157 | BT_DBG("sock %p", sock); | |
158 | ||
159 | sock->state = SS_UNCONNECTED; | |
160 | ||
161 | if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM && | |
162 | sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) | |
163 | return -ESOCKTNOSUPPORT; | |
164 | ||
165 | if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) | |
166 | return -EPERM; | |
167 | ||
168 | sock->ops = &l2cap_sock_ops; | |
169 | ||
170 | sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC); | |
171 | if (!sk) | |
172 | return -ENOMEM; | |
173 | ||
174 | l2cap_sock_init(sk, NULL); | |
175 | return 0; | |
176 | } | |
177 | ||
65390587 GP |
178 | const struct proto_ops l2cap_sock_ops = { |
179 | .family = PF_BLUETOOTH, | |
180 | .owner = THIS_MODULE, | |
181 | .release = l2cap_sock_release, | |
182 | .bind = l2cap_sock_bind, | |
183 | .connect = l2cap_sock_connect, | |
184 | .listen = l2cap_sock_listen, | |
185 | .accept = l2cap_sock_accept, | |
186 | .getname = l2cap_sock_getname, | |
187 | .sendmsg = l2cap_sock_sendmsg, | |
188 | .recvmsg = l2cap_sock_recvmsg, | |
189 | .poll = bt_sock_poll, | |
190 | .ioctl = bt_sock_ioctl, | |
191 | .mmap = sock_no_mmap, | |
192 | .socketpair = sock_no_socketpair, | |
193 | .shutdown = l2cap_sock_shutdown, | |
194 | .setsockopt = l2cap_sock_setsockopt, | |
195 | .getsockopt = l2cap_sock_getsockopt | |
196 | }; | |
197 | ||
bb58f747 GP |
198 | static const struct net_proto_family l2cap_sock_family_ops = { |
199 | .family = PF_BLUETOOTH, | |
200 | .owner = THIS_MODULE, | |
201 | .create = l2cap_sock_create, | |
202 | }; | |
203 | ||
204 | int __init l2cap_init_sockets(void) | |
205 | { | |
206 | int err; | |
207 | ||
208 | err = proto_register(&l2cap_proto, 0); | |
209 | if (err < 0) | |
210 | return err; | |
211 | ||
212 | err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops); | |
213 | if (err < 0) | |
214 | goto error; | |
215 | ||
216 | BT_INFO("L2CAP socket layer initialized"); | |
217 | ||
218 | return 0; | |
219 | ||
220 | error: | |
221 | BT_ERR("L2CAP socket registration failed"); | |
222 | proto_unregister(&l2cap_proto); | |
223 | return err; | |
224 | } | |
225 | ||
226 | void l2cap_cleanup_sockets(void) | |
227 | { | |
228 | if (bt_sock_unregister(BTPROTO_L2CAP) < 0) | |
229 | BT_ERR("L2CAP socket unregistration failed"); | |
230 | ||
231 | proto_unregister(&l2cap_proto); | |
232 | } |