1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30#define VERSION "2.4"
31
32#include <linux/config.h>
33#include <linux/module.h>
34
35#include <linux/types.h>
36#include <linux/list.h>
37#include <linux/errno.h>
38#include <linux/kernel.h>
39#include <linux/major.h>
40#include <linux/sched.h>
41#include <linux/slab.h>
42#include <linux/skbuff.h>
43#include <linux/init.h>
44#include <linux/poll.h>
45#include <linux/proc_fs.h>
46#include <net/sock.h>
47
48#if defined(CONFIG_KMOD)
49#include <linux/kmod.h>
50#endif
51
52#include <net/bluetooth/bluetooth.h>
53
54#ifndef AF_BLUETOOTH_DEBUG
55#undef BT_DBG
56#define BT_DBG( A... )
57#endif
58
59
60#define BLUEZ_MAX_PROTO 7
61static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
62
63int bluez_sock_register(int proto, struct net_proto_family *ops)
64{
65 if (proto < 0 || proto >= BLUEZ_MAX_PROTO)
66 return -EINVAL;
67
68 if (bluez_proto[proto])
69 return -EEXIST;
70
71 bluez_proto[proto] = ops;
72 return 0;
73}
74
75int bluez_sock_unregister(int proto)
76{
77 if (proto < 0 || proto >= BLUEZ_MAX_PROTO)
78 return -EINVAL;
79
80 if (!bluez_proto[proto])
81 return -ENOENT;
82
83 bluez_proto[proto] = NULL;
84 return 0;
85}
86
87static int bluez_sock_create(struct socket *sock, int proto)
88{
89 if (proto < 0 || proto >= BLUEZ_MAX_PROTO)
90 return -EINVAL;
91
92#if defined(CONFIG_KMOD)
93 if (!bluez_proto[proto]) {
94 char module_name[30];
95 sprintf(module_name, "bt-proto-%d", proto);
96 request_module(module_name);
97 }
98#endif
99
100 if (!bluez_proto[proto])
101 return -ENOENT;
102
103 return bluez_proto[proto]->create(sock, proto);
104}
105
106void bluez_sock_init(struct socket *sock, struct sock *sk)
107{
108 sock_init_data(sock, sk);
109 INIT_LIST_HEAD(&bluez_pi(sk)->accept_q);
110}
111
112void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
113{
114 write_lock_bh(&l->lock);
115 sk->next = l->head;
116 l->head = sk;
117 sock_hold(sk);
118 write_unlock_bh(&l->lock);
119}
120
121void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
122{
123 struct sock **skp;
124
125 write_lock_bh(&l->lock);
126 for (skp = &l->head; *skp; skp = &((*skp)->next)) {
127 if (*skp == sk) {
128 *skp = sk->next;
129 __sock_put(sk);
130 break;
131 }
132 }
133 write_unlock_bh(&l->lock);
134}
135
136void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
137{
138 BT_DBG("parent %p, sk %p", parent, sk);
139
140 sock_hold(sk);
141 list_add_tail(&bluez_pi(sk)->accept_q, &bluez_pi(parent)->accept_q);
142 bluez_pi(sk)->parent = parent;
143 parent->ack_backlog++;
144}
145
146static void bluez_accept_unlink(struct sock *sk)
147{
148 BT_DBG("sk %p state %d", sk, sk->state);
149
150 list_del_init(&bluez_pi(sk)->accept_q);
151 bluez_pi(sk)->parent->ack_backlog--;
152 bluez_pi(sk)->parent = NULL;
153 sock_put(sk);
154}
155
156struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock)
157{
158 struct list_head *p, *n;
159 struct bluez_pinfo *pi;
160 struct sock *sk;
161
162 BT_DBG("parent %p", parent);
163
164 list_for_each_safe(p, n, &bluez_pi(parent)->accept_q) {
165 pi = list_entry(p, struct bluez_pinfo, accept_q);
166 sk = bluez_sk(pi);
167
168 lock_sock(sk);
169 if (sk->state == BT_CLOSED) {
170 release_sock(sk);
171 bluez_accept_unlink(sk);
172 continue;
173 }
174
175 if (sk->state == BT_CONNECTED || !newsock) {
176 bluez_accept_unlink(sk);
177 if (newsock)
178 sock_graft(sk, newsock);
179 release_sock(sk);
180 return sk;
181 }
182 release_sock(sk);
183 }
184 return NULL;
185}
186
187int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
188{
189 int noblock = flags & MSG_DONTWAIT;
190 struct sock *sk = sock->sk;
191 struct sk_buff *skb;
192 int copied, err;
193
194 BT_DBG("sock %p sk %p len %d", sock, sk, len);
195
196 if (flags & (MSG_OOB))
197 return -EOPNOTSUPP;
198
199 if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) {
200 if (sk->shutdown & RCV_SHUTDOWN)
201 return 0;
202 return err;
203 }
204
205 msg->msg_namelen = 0;
206
207 copied = skb->len;
208 if (len < copied) {
209 msg->msg_flags |= MSG_TRUNC;
210 copied = len;
211 }
212
213 skb->h.raw = skb->data;
214 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
215
216 skb_free_datagram(sk, skb);
217
218 return err ? : copied;
219}
220
221unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
222{
223 struct sock *sk = sock->sk;
224 unsigned int mask = 0;
225
226 BT_DBG("sock %p, sk %p", sock, sk);
227
228 poll_wait(file, sk->sleep, wait);
229
230 if (sk->err || !skb_queue_empty(&sk->error_queue))
231 mask |= POLLERR;
232
233 if (sk->shutdown == SHUTDOWN_MASK)
234 mask |= POLLHUP;
235
236 if (!skb_queue_empty(&sk->receive_queue) ||
237 !list_empty(&bluez_pi(sk)->accept_q) ||
238 (sk->shutdown & RCV_SHUTDOWN))
239 mask |= POLLIN | POLLRDNORM;
240
241 if (sk->state == BT_CLOSED)
242 mask |= POLLHUP;
243
244 if (sk->state == BT_CONNECT ||
245 sk->state == BT_CONNECT2 ||
246 sk->state == BT_CONFIG)
247 return mask;
248
249 if (sock_writeable(sk))
250 mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
251 else
252 set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
253
254 return mask;
255}
256
257int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
258{
259 DECLARE_WAITQUEUE(wait, current);
260 int err = 0;
261
262 BT_DBG("sk %p", sk);
263
264 add_wait_queue(sk->sleep, &wait);
265 while (sk->state != state) {
266 set_current_state(TASK_INTERRUPTIBLE);
267
268 if (!timeo) {
269 err = -EAGAIN;
270 break;
271 }
272
273 if (signal_pending(current)) {
274 err = sock_intr_errno(timeo);
275 break;
276 }
277
278 release_sock(sk);
279 timeo = schedule_timeout(timeo);
280 lock_sock(sk);
281
282 if (sk->err) {
283 err = sock_error(sk);
284 break;
285 }
286 }
287 set_current_state(TASK_RUNNING);
288 remove_wait_queue(sk->sleep, &wait);
289 return err;
290}
291
292struct net_proto_family bluez_sock_family_ops =
293{
294 PF_BLUETOOTH, bluez_sock_create
295};
296
297int bluez_init(void)
298{
299 BT_INFO("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
300 VERSION);
301 BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
302
303 proc_mkdir("bluetooth", NULL);
304
305 sock_register(&bluez_sock_family_ops);
306
307
308 hci_core_init();
309
310
311 hci_sock_init();
312
313 return 0;
314}
315
316void bluez_cleanup(void)
317{
318
319 hci_sock_cleanup();
320
321
322 hci_core_cleanup();
323
324 sock_unregister(PF_BLUETOOTH);
325
326 remove_proc_entry("bluetooth", NULL);
327}
328
329#ifdef MODULE
330module_init(bluez_init);
331module_exit(bluez_cleanup);
332
333MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
334MODULE_DESCRIPTION("BlueZ Core ver " VERSION);
335MODULE_LICENSE("GPL");
336#endif
337