nrelease - fix/improve livecd
[dragonfly.git] / sys / netgraph7 / bluetooth / socket / ng_btsocket_l2cap.c
CommitLineData
b06ebda0
MD
1/*
2 * ng_btsocket_l2cap.c
3 */
4
5/*-
6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $Id: ng_btsocket_l2cap.c,v 1.16 2003/09/14 23:29:06 max Exp $
31 * $FreeBSD: src/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c,v 1.25 2007/10/31 16:17:20 emax Exp $
32 */
33
34#include <sys/param.h>
35#include <sys/systm.h>
84bfc1a1 36#include <sys/bitstring.h>
b06ebda0
MD
37#include <sys/domain.h>
38#include <sys/endian.h>
39#include <sys/errno.h>
40#include <sys/filedesc.h>
b06ebda0
MD
41#include <sys/kernel.h>
42#include <sys/lock.h>
43#include <sys/malloc.h>
44#include <sys/mbuf.h>
b06ebda0
MD
45#include <sys/protosw.h>
46#include <sys/queue.h>
47#include <sys/socket.h>
48#include <sys/socketvar.h>
49#include <sys/sysctl.h>
50#include <sys/taskqueue.h>
e85b99ab
SW
51#include <sys/msgport2.h>
52#include <sys/refcount.h>
53#include <netgraph7/ng_message.h>
54#include <netgraph7/netgraph.h>
55#include <netgraph7/netgraph2.h>
56#include <netgraph7/bluetooth/include/ng_bluetooth.h>
57#include <netgraph7/bluetooth/include/ng_hci.h>
58#include <netgraph7/bluetooth/include/ng_l2cap.h>
59#include <netgraph7/bluetooth/include/ng_btsocket.h>
60#include <netgraph7/bluetooth/include/ng_btsocket_l2cap.h>
b06ebda0
MD
61
62/* MALLOC define */
63#ifdef NG_SEPARATE_MALLOC
64MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP, "netgraph_btsocks_l2cap",
65 "Netgraph Bluetooth L2CAP sockets");
66#else
67#define M_NETGRAPH_BTSOCKET_L2CAP M_NETGRAPH
68#endif /* NG_SEPARATE_MALLOC */
69
70/* Netgraph node methods */
71static ng_constructor_t ng_btsocket_l2cap_node_constructor;
72static ng_rcvmsg_t ng_btsocket_l2cap_node_rcvmsg;
73static ng_shutdown_t ng_btsocket_l2cap_node_shutdown;
74static ng_newhook_t ng_btsocket_l2cap_node_newhook;
75static ng_connect_t ng_btsocket_l2cap_node_connect;
76static ng_rcvdata_t ng_btsocket_l2cap_node_rcvdata;
77static ng_disconnect_t ng_btsocket_l2cap_node_disconnect;
78
79static void ng_btsocket_l2cap_input (void *, int);
80static void ng_btsocket_l2cap_rtclean (void *, int);
81
82/* Netgraph type descriptor */
83static struct ng_type typestruct = {
84 .version = NG_ABI_VERSION,
85 .name = NG_BTSOCKET_L2CAP_NODE_TYPE,
86 .constructor = ng_btsocket_l2cap_node_constructor,
87 .rcvmsg = ng_btsocket_l2cap_node_rcvmsg,
88 .shutdown = ng_btsocket_l2cap_node_shutdown,
89 .newhook = ng_btsocket_l2cap_node_newhook,
90 .connect = ng_btsocket_l2cap_node_connect,
91 .rcvdata = ng_btsocket_l2cap_node_rcvdata,
92 .disconnect = ng_btsocket_l2cap_node_disconnect,
93};
94
95/* Globals */
96extern int ifqmaxlen;
97static u_int32_t ng_btsocket_l2cap_debug_level;
98static node_p ng_btsocket_l2cap_node;
99static struct ng_bt_itemq ng_btsocket_l2cap_queue;
e85b99ab 100static struct lock ng_btsocket_l2cap_queue_lock;
b06ebda0
MD
101static struct task ng_btsocket_l2cap_queue_task;
102static LIST_HEAD(, ng_btsocket_l2cap_pcb) ng_btsocket_l2cap_sockets;
e85b99ab 103static struct lock ng_btsocket_l2cap_sockets_lock;
b06ebda0 104static LIST_HEAD(, ng_btsocket_l2cap_rtentry) ng_btsocket_l2cap_rt;
e85b99ab 105static struct lock ng_btsocket_l2cap_rt_lock;
b06ebda0
MD
106static struct task ng_btsocket_l2cap_rt_task;
107
108/* Sysctl tree */
109SYSCTL_DECL(_net_bluetooth_l2cap_sockets);
110SYSCTL_NODE(_net_bluetooth_l2cap_sockets, OID_AUTO, seq, CTLFLAG_RW,
111 0, "Bluetooth SEQPACKET L2CAP sockets family");
112SYSCTL_INT(_net_bluetooth_l2cap_sockets_seq, OID_AUTO, debug_level,
113 CTLFLAG_RW,
114 &ng_btsocket_l2cap_debug_level, NG_BTSOCKET_WARN_LEVEL,
115 "Bluetooth SEQPACKET L2CAP sockets debug level");
116SYSCTL_INT(_net_bluetooth_l2cap_sockets_seq, OID_AUTO, queue_len,
117 CTLFLAG_RD,
118 &ng_btsocket_l2cap_queue.len, 0,
119 "Bluetooth SEQPACKET L2CAP sockets input queue length");
120SYSCTL_INT(_net_bluetooth_l2cap_sockets_seq, OID_AUTO, queue_maxlen,
121 CTLFLAG_RD,
122 &ng_btsocket_l2cap_queue.maxlen, 0,
123 "Bluetooth SEQPACKET L2CAP sockets input queue max. length");
124SYSCTL_INT(_net_bluetooth_l2cap_sockets_seq, OID_AUTO, queue_drops,
125 CTLFLAG_RD,
126 &ng_btsocket_l2cap_queue.drops, 0,
127 "Bluetooth SEQPACKET L2CAP sockets input queue drops");
128
129/* Debug */
130#define NG_BTSOCKET_L2CAP_INFO \
131 if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_INFO_LEVEL) \
a62226e4 132 kprintf
b06ebda0
MD
133
134#define NG_BTSOCKET_L2CAP_WARN \
135 if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_WARN_LEVEL) \
a62226e4 136 kprintf
b06ebda0
MD
137
138#define NG_BTSOCKET_L2CAP_ERR \
139 if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_ERR_LEVEL) \
a62226e4 140 kprintf
b06ebda0
MD
141
142#define NG_BTSOCKET_L2CAP_ALERT \
143 if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_ALERT_LEVEL) \
a62226e4 144 kprintf
b06ebda0
MD
145
146/*
147 * Netgraph message processing routines
148 */
149
150static int ng_btsocket_l2cap_process_l2ca_con_req_rsp
151 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
152static int ng_btsocket_l2cap_process_l2ca_con_rsp_rsp
153 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
154static int ng_btsocket_l2cap_process_l2ca_con_ind
155 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
156
157static int ng_btsocket_l2cap_process_l2ca_cfg_req_rsp
158 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
159static int ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp
160 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
161static int ng_btsocket_l2cap_process_l2ca_cfg_ind
162 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
163
164static int ng_btsocket_l2cap_process_l2ca_discon_rsp
165 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
166static int ng_btsocket_l2cap_process_l2ca_discon_ind
167 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
168
169static int ng_btsocket_l2cap_process_l2ca_write_rsp
170 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
171
172/*
173 * Send L2CA_xxx messages to the lower layer
174 */
175
176static int ng_btsocket_l2cap_send_l2ca_con_req
177 (ng_btsocket_l2cap_pcb_p);
178static int ng_btsocket_l2cap_send_l2ca_con_rsp_req
179 (u_int32_t, ng_btsocket_l2cap_rtentry_p, bdaddr_p, int, int, int);
180static int ng_btsocket_l2cap_send_l2ca_cfg_req
181 (ng_btsocket_l2cap_pcb_p);
182static int ng_btsocket_l2cap_send_l2ca_cfg_rsp
183 (ng_btsocket_l2cap_pcb_p);
184static int ng_btsocket_l2cap_send_l2ca_discon_req
185 (u_int32_t, ng_btsocket_l2cap_pcb_p);
186
187static int ng_btsocket_l2cap_send2
188 (ng_btsocket_l2cap_pcb_p);
189
190/*
191 * Timeout processing routines
192 */
193
194static void ng_btsocket_l2cap_timeout (ng_btsocket_l2cap_pcb_p);
195static void ng_btsocket_l2cap_untimeout (ng_btsocket_l2cap_pcb_p);
196static void ng_btsocket_l2cap_process_timeout (void *);
197
198/*
199 * Other stuff
200 */
201
202static ng_btsocket_l2cap_pcb_p ng_btsocket_l2cap_pcb_by_addr(bdaddr_p, int);
203static ng_btsocket_l2cap_pcb_p ng_btsocket_l2cap_pcb_by_token(u_int32_t);
204static ng_btsocket_l2cap_pcb_p ng_btsocket_l2cap_pcb_by_cid (bdaddr_p, int);
205static int ng_btsocket_l2cap_result2errno(int);
206
207#define ng_btsocket_l2cap_wakeup_input_task() \
e85b99ab 208 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_queue_task)
b06ebda0
MD
209
210#define ng_btsocket_l2cap_wakeup_route_task() \
e85b99ab 211 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_rt_task)
b06ebda0
MD
212
213/*****************************************************************************
214 *****************************************************************************
215 ** Netgraph node interface
216 *****************************************************************************
217 *****************************************************************************/
218
219/*
220 * Netgraph node constructor. Do not allow to create node of this type.
221 */
222
223static int
224ng_btsocket_l2cap_node_constructor(node_p node)
225{
226 return (EINVAL);
227} /* ng_btsocket_l2cap_node_constructor */
228
229/*
230 * Do local shutdown processing. Let old node go and create new fresh one.
231 */
232
233static int
234ng_btsocket_l2cap_node_shutdown(node_p node)
235{
236 int error = 0;
237
238 NG_NODE_UNREF(node);
239
240 /* Create new node */
241 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_node);
242 if (error != 0) {
243 NG_BTSOCKET_L2CAP_ALERT(
244"%s: Could not create Netgraph node, error=%d\n", __func__, error);
245
246 ng_btsocket_l2cap_node = NULL;
247
248 return (error);
249 }
250
251 error = ng_name_node(ng_btsocket_l2cap_node,
252 NG_BTSOCKET_L2CAP_NODE_TYPE);
253 if (error != 0) {
254 NG_BTSOCKET_L2CAP_ALERT(
255"%s: Could not name Netgraph node, error=%d\n", __func__, error);
256
257 NG_NODE_UNREF(ng_btsocket_l2cap_node);
258 ng_btsocket_l2cap_node = NULL;
259
260 return (error);
261 }
262
263 return (0);
264} /* ng_btsocket_l2cap_node_shutdown */
265
266/*
267 * We allow any hook to be connected to the node.
268 */
269
270static int
271ng_btsocket_l2cap_node_newhook(node_p node, hook_p hook, char const *name)
272{
273 return (0);
274} /* ng_btsocket_l2cap_node_newhook */
275
276/*
277 * Just say "YEP, that's OK by me!"
278 */
279
280static int
281ng_btsocket_l2cap_node_connect(hook_p hook)
282{
283 NG_HOOK_SET_PRIVATE(hook, NULL);
284 NG_HOOK_REF(hook); /* Keep extra reference to the hook */
285
286#if 0
287 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
288 NG_HOOK_FORCE_QUEUE(hook);
289#endif
290
291 return (0);
292} /* ng_btsocket_l2cap_node_connect */
293
294/*
295 * Hook disconnection. Schedule route cleanup task
296 */
297
298static int
299ng_btsocket_l2cap_node_disconnect(hook_p hook)
300{
301 /*
302 * If hook has private information than we must have this hook in
303 * the routing table and must schedule cleaning for the routing table.
304 * Otherwise hook was connected but we never got "hook_info" message,
305 * so we have never added this hook to the routing table and it save
306 * to just delete it.
307 */
308
309 if (NG_HOOK_PRIVATE(hook) != NULL)
310 return (ng_btsocket_l2cap_wakeup_route_task());
311
312 NG_HOOK_UNREF(hook); /* Remove extra reference */
313
314 return (0);
315} /* ng_btsocket_l2cap_node_disconnect */
316
317/*
318 * Process incoming messages
319 */
320
321static int
322ng_btsocket_l2cap_node_rcvmsg(node_p node, item_p item, hook_p hook)
323{
324 struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
325 int error = 0;
326
327 if (msg != NULL && msg->header.typecookie == NGM_L2CAP_COOKIE) {
e85b99ab 328 lockmgr(&ng_btsocket_l2cap_queue_lock, LK_EXCLUSIVE);
b06ebda0
MD
329 if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_queue)) {
330 NG_BTSOCKET_L2CAP_ERR(
331"%s: Input queue is full (msg)\n", __func__);
332
333 NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_queue);
334 NG_FREE_ITEM(item);
335 error = ENOBUFS;
336 } else {
337 if (hook != NULL) {
338 NG_HOOK_REF(hook);
339 NGI_SET_HOOK(item, hook);
340 }
341
e85b99ab 342 ng_ref_item(item);
b06ebda0
MD
343 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_queue, item);
344 error = ng_btsocket_l2cap_wakeup_input_task();
345 }
e85b99ab 346 lockmgr(&ng_btsocket_l2cap_queue_lock, LK_RELEASE);
b06ebda0
MD
347 } else {
348 NG_FREE_ITEM(item);
349 error = EINVAL;
350 }
351
352 return (error);
353} /* ng_btsocket_l2cap_node_rcvmsg */
354
355/*
356 * Receive data on a hook
357 */
358
359static int
360ng_btsocket_l2cap_node_rcvdata(hook_p hook, item_p item)
361{
362 int error = 0;
363
e85b99ab 364 lockmgr(&ng_btsocket_l2cap_queue_lock, LK_EXCLUSIVE);
b06ebda0
MD
365 if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_queue)) {
366 NG_BTSOCKET_L2CAP_ERR(
367"%s: Input queue is full (data)\n", __func__);
368
369 NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_queue);
370 NG_FREE_ITEM(item);
371 error = ENOBUFS;
372 } else {
373 NG_HOOK_REF(hook);
374 NGI_SET_HOOK(item, hook);
375
e85b99ab 376 ng_ref_item(item);
b06ebda0
MD
377 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_queue, item);
378 error = ng_btsocket_l2cap_wakeup_input_task();
379 }
e85b99ab 380 lockmgr(&ng_btsocket_l2cap_queue_lock, LK_RELEASE);
b06ebda0
MD
381
382 return (error);
383} /* ng_btsocket_l2cap_node_rcvdata */
384
385/*
386 * Process L2CA_Connect respose. Socket layer must have initiated connection,
387 * so we have to have a socket associated with message token.
388 */
389
390static int
391ng_btsocket_l2cap_process_l2ca_con_req_rsp(struct ng_mesg *msg,
392 ng_btsocket_l2cap_rtentry_p rt)
393{
394 ng_l2cap_l2ca_con_op *op = NULL;
395 ng_btsocket_l2cap_pcb_t *pcb = NULL;
396 int error = 0;
397
398 if (msg->header.arglen != sizeof(*op))
399 return (EMSGSIZE);
400
401 op = (ng_l2cap_l2ca_con_op *)(msg->data);
402
e85b99ab 403 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
404
405 /* Look for the socket with the token */
406 pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token);
407 if (pcb == NULL) {
e85b99ab 408 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
409 return (ENOENT);
410 }
411
e85b99ab 412 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
413
414 NG_BTSOCKET_L2CAP_INFO(
415"%s: Got L2CA_Connect response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
416"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, status=%d, " \
417"state=%d\n", __func__, msg->header.token,
418 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
419 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
420 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
421 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
422 pcb->psm, op->lcid, op->result, op->status,
423 pcb->state);
424
425 if (pcb->state != NG_BTSOCKET_L2CAP_CONNECTING) {
e85b99ab
SW
426 lockmgr(&pcb->pcb_lock, LK_RELEASE);
427 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
428
429 return (ENOENT);
430 }
431
432 ng_btsocket_l2cap_untimeout(pcb);
433
434 if (op->result == NG_L2CAP_PENDING) {
435 ng_btsocket_l2cap_timeout(pcb);
e85b99ab
SW
436 lockmgr(&pcb->pcb_lock, LK_RELEASE);
437 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
438
439 return (0);
440 }
441
442 if (op->result == NG_L2CAP_SUCCESS) {
443 /*
444 * Channel is now open, so update local channel ID and
445 * start configuration process. Source and destination
446 * addresses as well as route must be already set.
447 */
448
449 pcb->cid = op->lcid;
450
451 error = ng_btsocket_l2cap_send_l2ca_cfg_req(pcb);
452 if (error != 0) {
453 /* Send disconnect request with "zero" token */
454 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
455
456 /* ... and close the socket */
457 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
458 soisdisconnected(pcb->so);
459 } else {
460 pcb->cfg_state = NG_BTSOCKET_L2CAP_CFG_IN_SENT;
461 pcb->state = NG_BTSOCKET_L2CAP_CONFIGURING;
462
463 ng_btsocket_l2cap_timeout(pcb);
464 }
465 } else {
466 /*
467 * We have failed to open connection, so convert result
468 * code to "errno" code and disconnect the socket. Channel
469 * already has been closed.
470 */
471
472 pcb->so->so_error = ng_btsocket_l2cap_result2errno(op->result);
473 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
474 soisdisconnected(pcb->so);
475 }
476
e85b99ab
SW
477 lockmgr(&pcb->pcb_lock, LK_RELEASE);
478 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
479
480 return (error);
481} /* ng_btsocket_l2cap_process_l2ca_con_req_rsp */
482
483/*
484 * Process L2CA_ConnectRsp response
485 */
486
487static int
488ng_btsocket_l2cap_process_l2ca_con_rsp_rsp(struct ng_mesg *msg,
489 ng_btsocket_l2cap_rtentry_p rt)
490{
491 ng_l2cap_l2ca_con_rsp_op *op = NULL;
492 ng_btsocket_l2cap_pcb_t *pcb = NULL;
493
494 if (msg->header.arglen != sizeof(*op))
495 return (EMSGSIZE);
496
497 op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data);
498
e85b99ab 499 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
500
501 /* Look for the socket with the token */
502 pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token);
503 if (pcb == NULL) {
e85b99ab 504 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
505 return (ENOENT);
506 }
507
e85b99ab 508 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
509
510 NG_BTSOCKET_L2CAP_INFO(
511"%s: Got L2CA_ConnectRsp response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
512"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d\n",
513 __func__, msg->header.token,
514 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
515 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
516 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
517 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
518 pcb->psm, pcb->cid, op->result, pcb->state);
519
520 if (pcb->state != NG_BTSOCKET_L2CAP_CONNECTING) {
e85b99ab
SW
521 lockmgr(&pcb->pcb_lock, LK_RELEASE);
522 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
523
524 return (ENOENT);
525 }
526
527 ng_btsocket_l2cap_untimeout(pcb);
528
529 /* Check the result and disconnect the socket on failure */
530 if (op->result != NG_L2CAP_SUCCESS) {
531 /* Close the socket - channel already closed */
532 pcb->so->so_error = ng_btsocket_l2cap_result2errno(op->result);
533 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
534 soisdisconnected(pcb->so);
535 } else {
536 /* Move to CONFIGURING state and wait for CONFIG_IND */
537 pcb->cfg_state = 0;
538 pcb->state = NG_BTSOCKET_L2CAP_CONFIGURING;
539 ng_btsocket_l2cap_timeout(pcb);
540 }
541
e85b99ab
SW
542 lockmgr(&pcb->pcb_lock, LK_RELEASE);
543 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
544
545 return (0);
546} /* ng_btsocket_process_l2ca_con_rsp_rsp */
547
548/*
549 * Process L2CA_Connect indicator. Find socket that listens on address
550 * and PSM. Find exact or closest match. Create new socket and initiate
551 * connection.
552 */
553
554static int
555ng_btsocket_l2cap_process_l2ca_con_ind(struct ng_mesg *msg,
556 ng_btsocket_l2cap_rtentry_p rt)
557{
558 ng_l2cap_l2ca_con_ind_ip *ip = NULL;
559 ng_btsocket_l2cap_pcb_t *pcb = NULL, *pcb1 = NULL;
560 int error = 0;
561 u_int32_t token = 0;
562 u_int16_t result = 0;
563
564 if (msg->header.arglen != sizeof(*ip))
565 return (EMSGSIZE);
566
567 ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data);
568
569 NG_BTSOCKET_L2CAP_INFO(
570"%s: Got L2CA_Connect indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
571"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, ident=%d\n",
572 __func__,
573 rt->src.b[5], rt->src.b[4], rt->src.b[3],
574 rt->src.b[2], rt->src.b[1], rt->src.b[0],
575 ip->bdaddr.b[5], ip->bdaddr.b[4], ip->bdaddr.b[3],
576 ip->bdaddr.b[2], ip->bdaddr.b[1], ip->bdaddr.b[0],
577 ip->psm, ip->lcid, ip->ident);
578
e85b99ab 579 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
580
581 pcb = ng_btsocket_l2cap_pcb_by_addr(&rt->src, ip->psm);
582 if (pcb != NULL) {
583 struct socket *so1 = NULL;
584
e85b99ab 585 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
586
587 /*
588 * First check the pending connections queue and if we have
589 * space then create new socket and set proper source address.
590 */
591
592 if (pcb->so->so_qlen <= pcb->so->so_qlimit)
593 so1 = sonewconn(pcb->so, 0);
594
595 if (so1 == NULL) {
596 result = NG_L2CAP_NO_RESOURCES;
597 goto respond;
598 }
599
600 /*
601 * If we got here than we have created new socket. So complete
602 * connection. If we we listening on specific address then copy
603 * source address from listening socket, otherwise copy source
604 * address from hook's routing information.
605 */
606
607 pcb1 = so2l2cap_pcb(so1);
608 KASSERT((pcb1 != NULL),
609("%s: pcb1 == NULL\n", __func__));
610
e85b99ab 611 lockmgr(&pcb1->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
612
613 if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)) != 0)
614 bcopy(&pcb->src, &pcb1->src, sizeof(pcb1->src));
615 else
616 bcopy(&rt->src, &pcb1->src, sizeof(pcb1->src));
617
618 pcb1->flags &= ~NG_BTSOCKET_L2CAP_CLIENT;
619
620 bcopy(&ip->bdaddr, &pcb1->dst, sizeof(pcb1->dst));
621 pcb1->psm = ip->psm;
622 pcb1->cid = ip->lcid;
623 pcb1->rt = rt;
624
625 /* Copy socket settings */
626 pcb1->imtu = pcb->imtu;
627 bcopy(&pcb->oflow, &pcb1->oflow, sizeof(pcb1->oflow));
628 pcb1->flush_timo = pcb->flush_timo;
629
630 token = pcb1->token;
631 } else
632 /* Nobody listens on requested BDADDR/PSM */
633 result = NG_L2CAP_PSM_NOT_SUPPORTED;
634
635respond:
636 error = ng_btsocket_l2cap_send_l2ca_con_rsp_req(token, rt,
637 &ip->bdaddr, ip->ident, ip->lcid, result);
638 if (pcb1 != NULL) {
639 if (error != 0) {
640 pcb1->so->so_error = error;
641 pcb1->state = NG_BTSOCKET_L2CAP_CLOSED;
642 soisdisconnected(pcb1->so);
643 } else {
644 pcb1->state = NG_BTSOCKET_L2CAP_CONNECTING;
645 soisconnecting(pcb1->so);
646
647 ng_btsocket_l2cap_timeout(pcb1);
648 }
649
e85b99ab 650 lockmgr(&pcb1->pcb_lock, LK_RELEASE);
b06ebda0
MD
651 }
652
653 if (pcb != NULL)
e85b99ab 654 lockmgr(&pcb->pcb_lock, LK_RELEASE);
b06ebda0 655
e85b99ab 656 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
657
658 return (error);
659} /* ng_btsocket_l2cap_process_l2ca_con_ind */
660
661/*
662 * Process L2CA_Config response
663 */
664
665static int
666ng_btsocket_l2cap_process_l2ca_cfg_req_rsp(struct ng_mesg *msg,
667 ng_btsocket_l2cap_rtentry_p rt)
668{
669 ng_l2cap_l2ca_cfg_op *op = NULL;
670 ng_btsocket_l2cap_pcb_p pcb = NULL;
671
672 if (msg->header.arglen != sizeof(*op))
673 return (EMSGSIZE);
674
675 op = (ng_l2cap_l2ca_cfg_op *)(msg->data);
676
e85b99ab 677 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
678
679 /*
680 * Socket must have issued a Configure request, so we must have a
681 * socket that wants to be configured. Use Netgraph message token
682 * to find it
683 */
684
685 pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token);
686 if (pcb == NULL) {
687 /*
688 * XXX FIXME what to do here? We could not find a
689 * socket with requested token. We even can not send
690 * Disconnect, because we do not know channel ID
691 */
692
e85b99ab 693 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
694 return (ENOENT);
695 }
696
e85b99ab 697 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
698
699 NG_BTSOCKET_L2CAP_INFO(
700"%s: Got L2CA_Config response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
701"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d, " \
702"cfg_state=%x\n",
703 __func__, msg->header.token,
704 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
705 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
706 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
707 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
708 pcb->psm, pcb->cid, op->result, pcb->state, pcb->cfg_state);
709
710 if (pcb->state != NG_BTSOCKET_L2CAP_CONFIGURING) {
e85b99ab
SW
711 lockmgr(&pcb->pcb_lock, LK_RELEASE);
712 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
713
714 return (ENOENT);
715 }
716
717 if (op->result == NG_L2CAP_SUCCESS) {
718 /*
719 * XXX FIXME Actually set flush and link timeout.
720 * Set QoS here if required. Resolve conficts (flush_timo).
721 * Save incoming MTU (peer's outgoing MTU) and outgoing flow
722 * spec.
723 */
724
725 pcb->imtu = op->imtu;
726 bcopy(&op->oflow, &pcb->oflow, sizeof(pcb->oflow));
727 pcb->flush_timo = op->flush_timo;
728
729 /*
730 * We have configured incoming side, so record it and check
731 * if configuration is complete. If complete then mark socket
732 * as connected, otherwise wait for the peer.
733 */
734
735 pcb->cfg_state &= ~NG_BTSOCKET_L2CAP_CFG_IN_SENT;
736 pcb->cfg_state |= NG_BTSOCKET_L2CAP_CFG_IN;
737
738 if (pcb->cfg_state == NG_BTSOCKET_L2CAP_CFG_BOTH) {
739 /* Configuration complete - mark socket as open */
740 ng_btsocket_l2cap_untimeout(pcb);
741 pcb->state = NG_BTSOCKET_L2CAP_OPEN;
742 soisconnected(pcb->so);
743 }
744 } else {
745 /*
746 * Something went wrong. Could be unacceptable parameters,
747 * reject or unknown option. That's too bad, but we will
748 * not negotiate. Send Disconnect and close the channel.
749 */
750
751 ng_btsocket_l2cap_untimeout(pcb);
752
753 switch (op->result) {
754 case NG_L2CAP_UNACCEPTABLE_PARAMS:
755 case NG_L2CAP_UNKNOWN_OPTION:
756 pcb->so->so_error = EINVAL;
757 break;
758
759 default:
760 pcb->so->so_error = ECONNRESET;
761 break;
762 }
763
764 /* Send disconnect with "zero" token */
765 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
766
767 /* ... and close the socket */
768 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
769 soisdisconnected(pcb->so);
770 }
771
e85b99ab
SW
772 lockmgr(&pcb->pcb_lock, LK_RELEASE);
773 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
774
775 return (0);
776} /* ng_btsocket_l2cap_process_l2ca_cfg_req_rsp */
777
778/*
779 * Process L2CA_ConfigRsp response
780 */
781
782static int
783ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp(struct ng_mesg *msg,
784 ng_btsocket_l2cap_rtentry_p rt)
785{
786 ng_l2cap_l2ca_cfg_rsp_op *op = NULL;
787 ng_btsocket_l2cap_pcb_t *pcb = NULL;
788 int error = 0;
789
790 if (msg->header.arglen != sizeof(*op))
791 return (EMSGSIZE);
792
793 op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data);
794
e85b99ab 795 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
796
797 /* Look for the socket with the token */
798 pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token);
799 if (pcb == NULL) {
e85b99ab 800 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
801 return (ENOENT);
802 }
803
e85b99ab 804 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
805
806 NG_BTSOCKET_L2CAP_INFO(
807"%s: Got L2CA_ConfigRsp response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
808"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d, " \
809"cfg_state=%x\n",
810 __func__, msg->header.token,
811 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
812 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
813 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
814 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
815 pcb->psm, pcb->cid, op->result, pcb->state, pcb->cfg_state);
816
817 if (pcb->state != NG_BTSOCKET_L2CAP_CONFIGURING) {
e85b99ab
SW
818 lockmgr(&pcb->pcb_lock, LK_RELEASE);
819 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
820
821 return (ENOENT);
822 }
823
824 /* Check the result and disconnect socket of failure */
825 if (op->result != NG_L2CAP_SUCCESS)
826 goto disconnect;
827
828 /*
829 * Now we done with remote side configuration. Configure local
830 * side if we have not done it yet.
831 */
832
833 pcb->cfg_state &= ~NG_BTSOCKET_L2CAP_CFG_OUT_SENT;
834 pcb->cfg_state |= NG_BTSOCKET_L2CAP_CFG_OUT;
835
836 if (pcb->cfg_state == NG_BTSOCKET_L2CAP_CFG_BOTH) {
837 /* Configuration complete - mask socket as open */
838 ng_btsocket_l2cap_untimeout(pcb);
839 pcb->state = NG_BTSOCKET_L2CAP_OPEN;
840 soisconnected(pcb->so);
841 } else {
842 if (!(pcb->cfg_state & NG_BTSOCKET_L2CAP_CFG_IN_SENT)) {
843 /* Send L2CA_Config request - incoming path */
844 error = ng_btsocket_l2cap_send_l2ca_cfg_req(pcb);
845 if (error != 0)
846 goto disconnect;
847
848 pcb->cfg_state |= NG_BTSOCKET_L2CAP_CFG_IN_SENT;
849 }
850 }
851
e85b99ab
SW
852 lockmgr(&pcb->pcb_lock, LK_RELEASE);
853 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
854
855 return (error);
856
857disconnect:
858 ng_btsocket_l2cap_untimeout(pcb);
859
860 /* Send disconnect with "zero" token */
861 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
862
863 /* ... and close the socket */
864 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
865 soisdisconnected(pcb->so);
866
e85b99ab
SW
867 lockmgr(&pcb->pcb_lock, LK_RELEASE);
868 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
869
870 return (error);
871} /* ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp */
872
873/*
874 * Process L2CA_Config indicator
875 */
876
877static int
878ng_btsocket_l2cap_process_l2ca_cfg_ind(struct ng_mesg *msg,
879 ng_btsocket_l2cap_rtentry_p rt)
880{
881 ng_l2cap_l2ca_cfg_ind_ip *ip = NULL;
882 ng_btsocket_l2cap_pcb_t *pcb = NULL;
883 int error = 0;
884
885 if (msg->header.arglen != sizeof(*ip))
886 return (EMSGSIZE);
887
888 ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data);
889
e85b99ab 890 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
891
892 /* Check for the open socket that has given channel ID */
893 pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, ip->lcid);
894 if (pcb == NULL) {
e85b99ab 895 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
896 return (ENOENT);
897 }
898
e85b99ab 899 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
900
901 NG_BTSOCKET_L2CAP_INFO(
902"%s: Got L2CA_Config indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
903"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, state=%d, cfg_state=%x\n",
904 __func__,
905 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
906 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
907 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
908 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
909 pcb->psm, pcb->cid, pcb->state, pcb->cfg_state);
910
911 /* XXX FIXME re-configuration on open socket */
912 if (pcb->state != NG_BTSOCKET_L2CAP_CONFIGURING) {
e85b99ab
SW
913 lockmgr(&pcb->pcb_lock, LK_RELEASE);
914 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
915
916 return (ENOENT);
917 }
918
919 /*
920 * XXX FIXME Actually set flush and link timeout. Set QoS here if
921 * required. Resolve conficts (flush_timo). Note outgoing MTU (peer's
922 * incoming MTU) and incoming flow spec.
923 */
924
925 pcb->omtu = ip->omtu;
926 bcopy(&ip->iflow, &pcb->iflow, sizeof(pcb->iflow));
927 pcb->flush_timo = ip->flush_timo;
928
929 /*
930 * Send L2CA_Config response to our peer and check for the errors,
931 * if any send disconnect to close the channel.
932 */
933
934 if (!(pcb->cfg_state & NG_BTSOCKET_L2CAP_CFG_OUT_SENT)) {
935 error = ng_btsocket_l2cap_send_l2ca_cfg_rsp(pcb);
936 if (error != 0) {
937 ng_btsocket_l2cap_untimeout(pcb);
938
939 pcb->so->so_error = error;
940
941 /* Send disconnect with "zero" token */
942 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
943
944 /* ... and close the socket */
945 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
946 soisdisconnected(pcb->so);
947 } else
948 pcb->cfg_state |= NG_BTSOCKET_L2CAP_CFG_OUT_SENT;
949 }
950
e85b99ab
SW
951 lockmgr(&pcb->pcb_lock, LK_RELEASE);
952 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
953
954 return (error);
955} /* ng_btsocket_l2cap_process_l2cap_cfg_ind */
956
957/*
958 * Process L2CA_Disconnect response
959 */
960
961static int
962ng_btsocket_l2cap_process_l2ca_discon_rsp(struct ng_mesg *msg,
963 ng_btsocket_l2cap_rtentry_p rt)
964{
965 ng_l2cap_l2ca_discon_op *op = NULL;
966 ng_btsocket_l2cap_pcb_t *pcb = NULL;
967
968 /* Check message */
969 if (msg->header.arglen != sizeof(*op))
970 return (EMSGSIZE);
971
972 op = (ng_l2cap_l2ca_discon_op *)(msg->data);
973
e85b99ab 974 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
975
976 /*
977 * Socket layer must have issued L2CA_Disconnect request, so there
978 * must be a socket that wants to be disconnected. Use Netgraph
979 * message token to find it.
980 */
981
982 pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token);
983 if (pcb == NULL) {
e85b99ab 984 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
985 return (0);
986 }
987
e85b99ab 988 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
989
990 /* XXX Close socket no matter what op->result says */
991 if (pcb->state != NG_BTSOCKET_L2CAP_CLOSED) {
992 NG_BTSOCKET_L2CAP_INFO(
993"%s: Got L2CA_Disconnect response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
994"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d\n",
995 __func__, msg->header.token,
996 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
997 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
998 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
999 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
1000 pcb->psm, pcb->cid, op->result, pcb->state);
1001
1002 ng_btsocket_l2cap_untimeout(pcb);
1003
1004 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
1005 soisdisconnected(pcb->so);
1006 }
1007
e85b99ab
SW
1008 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1009 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
1010
1011 return (0);
1012} /* ng_btsocket_l2cap_process_l2ca_discon_rsp */
1013
1014/*
1015 * Process L2CA_Disconnect indicator
1016 */
1017
1018static int
1019ng_btsocket_l2cap_process_l2ca_discon_ind(struct ng_mesg *msg,
1020 ng_btsocket_l2cap_rtentry_p rt)
1021{
1022 ng_l2cap_l2ca_discon_ind_ip *ip = NULL;
1023 ng_btsocket_l2cap_pcb_t *pcb = NULL;
1024
1025 /* Check message */
1026 if (msg->header.arglen != sizeof(*ip))
1027 return (EMSGSIZE);
1028
1029 ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data);
1030
e85b99ab 1031 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
1032
1033 /* Look for the socket with given channel ID */
1034 pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, ip->lcid);
1035 if (pcb == NULL) {
e85b99ab 1036 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
1037 return (0);
1038 }
1039
1040 /*
1041 * Channel has already been destroyed, so disconnect the socket
1042 * and be done with it. If there was any pending request we can
1043 * not do anything here anyway.
1044 */
1045
e85b99ab 1046 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
1047
1048 NG_BTSOCKET_L2CAP_INFO(
1049"%s: Got L2CA_Disconnect indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
1050"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, state=%d\n",
1051 __func__,
1052 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
1053 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
1054 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
1055 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
1056 pcb->psm, pcb->cid, pcb->state);
1057
1058 if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO)
1059 ng_btsocket_l2cap_untimeout(pcb);
1060
1061 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
1062 soisdisconnected(pcb->so);
1063
e85b99ab
SW
1064 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1065 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
1066
1067 return (0);
1068} /* ng_btsocket_l2cap_process_l2ca_discon_ind */
1069
1070/*
1071 * Process L2CA_Write response
1072 */
1073
1074static int
1075ng_btsocket_l2cap_process_l2ca_write_rsp(struct ng_mesg *msg,
1076 ng_btsocket_l2cap_rtentry_p rt)
1077{
1078 ng_l2cap_l2ca_write_op *op = NULL;
1079 ng_btsocket_l2cap_pcb_t *pcb = NULL;
1080
1081 /* Check message */
1082 if (msg->header.arglen != sizeof(*op))
1083 return (EMSGSIZE);
1084
1085 op = (ng_l2cap_l2ca_write_op *)(msg->data);
1086
e85b99ab 1087 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
1088
1089 /* Look for the socket with given token */
1090 pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token);
1091 if (pcb == NULL) {
e85b99ab 1092 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
1093 return (ENOENT);
1094 }
1095
e85b99ab 1096 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
1097
1098 NG_BTSOCKET_L2CAP_INFO(
1099"%s: Got L2CA_Write response, src bdaddr=%x:%x:%x:%x:%x:%x, " \
1100"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, length=%d, " \
1101"state=%d\n", __func__,
1102 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
1103 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
1104 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
1105 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
1106 pcb->psm, pcb->cid, op->result, op->length,
1107 pcb->state);
1108
1109 if (pcb->state != NG_BTSOCKET_L2CAP_OPEN) {
e85b99ab
SW
1110 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1111 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
1112
1113 return (ENOENT);
1114 }
1115
1116 ng_btsocket_l2cap_untimeout(pcb);
1117
1118 /*
1119 * Check if we have more data to send
1120 */
1121
e85b99ab
SW
1122 sbdroprecord(&pcb->so->so_snd.sb);
1123 if (pcb->so->so_snd.sb.sb_cc > 0) {
b06ebda0
MD
1124 if (ng_btsocket_l2cap_send2(pcb) == 0)
1125 ng_btsocket_l2cap_timeout(pcb);
1126 else
e85b99ab 1127 sbdroprecord(&pcb->so->so_snd.sb); /* XXX */
b06ebda0
MD
1128 }
1129
1130 /*
1131 * Now set the result, drop packet from the socket send queue and
1132 * ask for more (wakeup sender)
1133 */
1134
1135 pcb->so->so_error = ng_btsocket_l2cap_result2errno(op->result);
1136 sowwakeup(pcb->so);
1137
e85b99ab
SW
1138 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1139 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
1140
1141 return (0);
1142} /* ng_btsocket_l2cap_process_l2ca_write_rsp */
1143
1144/*
1145 * Send L2CA_Connect request
1146 */
1147
1148static int
1149ng_btsocket_l2cap_send_l2ca_con_req(ng_btsocket_l2cap_pcb_p pcb)
1150{
1151 struct ng_mesg *msg = NULL;
1152 ng_l2cap_l2ca_con_ip *ip = NULL;
1153 int error = 0;
1154
e85b99ab 1155 KKASSERT(lockowned(&pcb->pcb_lock) != 0);
b06ebda0
MD
1156
1157 if (pcb->rt == NULL ||
1158 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
1159 return (ENETDOWN);
1160
1161 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON,
5a975a3d 1162 sizeof(*ip), M_WAITOK | M_NULLOK);
b06ebda0
MD
1163 if (msg == NULL)
1164 return (ENOMEM);
1165
1166 msg->header.token = pcb->token;
1167
1168 ip = (ng_l2cap_l2ca_con_ip *)(msg->data);
1169 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
1170 ip->psm = pcb->psm;
1171
1172 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg,pcb->rt->hook, 0);
1173
1174 return (error);
1175} /* ng_btsocket_l2cap_send_l2ca_con_req */
1176
1177/*
1178 * Send L2CA_Connect response
1179 */
1180
1181static int
1182ng_btsocket_l2cap_send_l2ca_con_rsp_req(u_int32_t token,
1183 ng_btsocket_l2cap_rtentry_p rt, bdaddr_p dst, int ident,
1184 int lcid, int result)
1185{
1186 struct ng_mesg *msg = NULL;
1187 ng_l2cap_l2ca_con_rsp_ip *ip = NULL;
1188 int error = 0;
1189
1190 if (rt == NULL || rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
1191 return (ENETDOWN);
1192
1193 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP,
5a975a3d 1194 sizeof(*ip), M_WAITOK | M_NULLOK);
b06ebda0
MD
1195 if (msg == NULL)
1196 return (ENOMEM);
1197
1198 msg->header.token = token;
1199
1200 ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data);
1201 bcopy(dst, &ip->bdaddr, sizeof(ip->bdaddr));
1202 ip->ident = ident;
1203 ip->lcid = lcid;
1204 ip->result = result;
1205 ip->status = 0;
1206
1207 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg, rt->hook, 0);
1208
1209 return (error);
1210} /* ng_btsocket_l2cap_send_l2ca_con_rsp_req */
1211
1212/*
1213 * Send L2CA_Config request
1214 */
1215
1216static int
1217ng_btsocket_l2cap_send_l2ca_cfg_req(ng_btsocket_l2cap_pcb_p pcb)
1218{
1219 struct ng_mesg *msg = NULL;
1220 ng_l2cap_l2ca_cfg_ip *ip = NULL;
1221 int error = 0;
1222
e85b99ab 1223 KKASSERT(lockowned(&pcb->pcb_lock) != 0);
b06ebda0
MD
1224
1225 if (pcb->rt == NULL ||
1226 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
1227 return (ENETDOWN);
1228
1229 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG,
5a975a3d 1230 sizeof(*ip), M_WAITOK | M_NULLOK);
b06ebda0
MD
1231 if (msg == NULL)
1232 return (ENOMEM);
1233
1234 msg->header.token = pcb->token;
1235
1236 ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data);
1237 ip->lcid = pcb->cid;
1238 ip->imtu = pcb->imtu;
1239 bcopy(&pcb->oflow, &ip->oflow, sizeof(ip->oflow));
1240 ip->flush_timo = pcb->flush_timo;
1241 ip->link_timo = pcb->link_timo;
1242
1243 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg,pcb->rt->hook, 0);
1244
1245 return (error);
1246} /* ng_btsocket_l2cap_send_l2ca_cfg_req */
1247
1248/*
1249 * Send L2CA_Config response
1250 */
1251
1252static int
1253ng_btsocket_l2cap_send_l2ca_cfg_rsp(ng_btsocket_l2cap_pcb_p pcb)
1254{
1255 struct ng_mesg *msg = NULL;
1256 ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL;
1257 int error = 0;
1258
e85b99ab 1259 KKASSERT(lockowned(&pcb->pcb_lock) != 0);
b06ebda0
MD
1260
1261 if (pcb->rt == NULL ||
1262 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
1263 return (ENETDOWN);
1264
1265 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP,
5a975a3d 1266 sizeof(*ip), M_WAITOK | M_NULLOK);
b06ebda0
MD
1267 if (msg == NULL)
1268 return (ENOMEM);
1269
1270 msg->header.token = pcb->token;
1271
1272 ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data);
1273 ip->lcid = pcb->cid;
1274 ip->omtu = pcb->omtu;
1275 bcopy(&pcb->iflow, &ip->iflow, sizeof(ip->iflow));
1276
1277 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg, pcb->rt->hook, 0);
1278
1279 return (error);
1280} /* ng_btsocket_l2cap_send_l2ca_cfg_rsp */
1281
1282/*
1283 * Send L2CA_Disconnect request
1284 */
1285
1286static int
1287ng_btsocket_l2cap_send_l2ca_discon_req(u_int32_t token,
1288 ng_btsocket_l2cap_pcb_p pcb)
1289{
1290 struct ng_mesg *msg = NULL;
1291 ng_l2cap_l2ca_discon_ip *ip = NULL;
1292 int error = 0;
1293
e85b99ab 1294 KKASSERT(lockowned(&pcb->pcb_lock) != 0);
b06ebda0
MD
1295
1296 if (pcb->rt == NULL ||
1297 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
1298 return (ENETDOWN);
1299
1300 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON,
5a975a3d 1301 sizeof(*ip), M_WAITOK | M_NULLOK);
b06ebda0
MD
1302 if (msg == NULL)
1303 return (ENOMEM);
1304
1305 msg->header.token = token;
1306
1307 ip = (ng_l2cap_l2ca_discon_ip *)(msg->data);
1308 ip->lcid = pcb->cid;
1309
1310 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg,pcb->rt->hook, 0);
1311
1312 return (error);
1313} /* ng_btsocket_l2cap_send_l2ca_discon_req */
1314
1315/*****************************************************************************
1316 *****************************************************************************
1317 ** Socket interface
1318 *****************************************************************************
1319 *****************************************************************************/
1320
1321/*
1322 * L2CAP sockets data input routine
1323 */
1324
1325static void
1326ng_btsocket_l2cap_data_input(struct mbuf *m, hook_p hook)
1327{
1328 ng_l2cap_hdr_t *hdr = NULL;
1329 ng_l2cap_clt_hdr_t *clt_hdr = NULL;
1330 ng_btsocket_l2cap_pcb_t *pcb = NULL;
1331 ng_btsocket_l2cap_rtentry_t *rt = NULL;
1332
1333 if (hook == NULL) {
1334 NG_BTSOCKET_L2CAP_ALERT(
1335"%s: Invalid source hook for L2CAP data packet\n", __func__);
1336 goto drop;
1337 }
1338
1339 rt = (ng_btsocket_l2cap_rtentry_t *) NG_HOOK_PRIVATE(hook);
1340 if (rt == NULL) {
1341 NG_BTSOCKET_L2CAP_ALERT(
1342"%s: Could not find out source bdaddr for L2CAP data packet\n", __func__);
1343 goto drop;
1344 }
1345
1346 /* Make sure we can access header */
1347 if (m->m_pkthdr.len < sizeof(*hdr)) {
1348 NG_BTSOCKET_L2CAP_ERR(
1349"%s: L2CAP data packet too small, len=%d\n", __func__, m->m_pkthdr.len);
1350 goto drop;
1351 }
1352
1353 if (m->m_len < sizeof(*hdr)) {
1354 m = m_pullup(m, sizeof(*hdr));
1355 if (m == NULL)
1356 goto drop;
1357 }
1358
1359 /* Strip L2CAP packet header and verify packet length */
1360 hdr = mtod(m, ng_l2cap_hdr_t *);
1361 m_adj(m, sizeof(*hdr));
1362
1363 if (hdr->length != m->m_pkthdr.len) {
1364 NG_BTSOCKET_L2CAP_ERR(
1365"%s: Bad L2CAP data packet length, len=%d, length=%d\n",
1366 __func__, m->m_pkthdr.len, hdr->length);
1367 goto drop;
1368 }
1369
1370 /*
1371 * Now process packet. Two cases:
1372 *
1373 * 1) Normal packet (cid != 2) then find connected socket and append
1374 * mbuf to the socket queue. Wakeup socket.
1375 *
1376 * 2) Broadcast packet (cid == 2) then find all sockets that connected
1377 * to the given PSM and have SO_BROADCAST bit set and append mbuf
1378 * to the socket queue. Wakeup socket.
1379 */
1380
1381 NG_BTSOCKET_L2CAP_INFO(
1382"%s: Received L2CAP data packet: src bdaddr=%x:%x:%x:%x:%x:%x, " \
1383"dcid=%d, length=%d\n",
1384 __func__,
1385 rt->src.b[5], rt->src.b[4], rt->src.b[3],
1386 rt->src.b[2], rt->src.b[1], rt->src.b[0],
1387 hdr->dcid, hdr->length);
1388
1389 if (hdr->dcid >= NG_L2CAP_FIRST_CID) {
1390
e85b99ab 1391 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
1392
1393 /* Normal packet: find connected socket */
1394 pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, hdr->dcid);
1395 if (pcb == NULL) {
e85b99ab 1396 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
1397 goto drop;
1398 }
1399
e85b99ab 1400 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
1401
1402 if (pcb->state != NG_BTSOCKET_L2CAP_OPEN) {
1403 NG_BTSOCKET_L2CAP_ERR(
1404"%s: No connected socket found, src bdaddr=%x:%x:%x:%x:%x:%x, dcid=%d, " \
1405"state=%d\n", __func__,
1406 rt->src.b[5], rt->src.b[4], rt->src.b[3],
1407 rt->src.b[2], rt->src.b[1], rt->src.b[0],
1408 hdr->dcid, pcb->state);
1409
e85b99ab
SW
1410 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1411 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
1412 goto drop;
1413 }
1414
1415 /* Check packet size against socket's incoming MTU */
1416 if (hdr->length > pcb->imtu) {
1417 NG_BTSOCKET_L2CAP_ERR(
1418"%s: L2CAP data packet too big, src bdaddr=%x:%x:%x:%x:%x:%x, " \
1419"dcid=%d, length=%d, imtu=%d\n",
1420 __func__,
1421 rt->src.b[5], rt->src.b[4], rt->src.b[3],
1422 rt->src.b[2], rt->src.b[1], rt->src.b[0],
1423 hdr->dcid, hdr->length, pcb->imtu);
1424
e85b99ab
SW
1425 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1426 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
1427 goto drop;
1428 }
1429
1430 /* Check if we have enough space in socket receive queue */
e85b99ab 1431 if (m->m_pkthdr.len > ssb_space(&pcb->so->so_rcv)) {
b06ebda0
MD
1432
1433 /*
1434 * This is really bad. Receive queue on socket does
1435 * not have enough space for the packet. We do not
1436 * have any other choice but drop the packet. L2CAP
1437 * does not provide any flow control.
1438 */
1439
1440 NG_BTSOCKET_L2CAP_ERR(
1441"%s: Not enough space in socket receive queue. Dropping L2CAP data packet, " \
1442"src bdaddr=%x:%x:%x:%x:%x:%x, dcid=%d, len=%d, space=%ld\n",
1443 __func__,
1444 rt->src.b[5], rt->src.b[4], rt->src.b[3],
1445 rt->src.b[2], rt->src.b[1], rt->src.b[0],
1446 hdr->dcid, m->m_pkthdr.len,
e85b99ab 1447 ssb_space(&pcb->so->so_rcv));
b06ebda0 1448
e85b99ab
SW
1449 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1450 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
1451 goto drop;
1452 }
1453
1454 /* Append packet to the socket receive queue and wakeup */
e85b99ab 1455 sbappendrecord(&pcb->so->so_rcv.sb, m);
b06ebda0
MD
1456 m = NULL;
1457
1458 sorwakeup(pcb->so);
1459
e85b99ab
SW
1460 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1461 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
1462 } else if (hdr->dcid == NG_L2CAP_CLT_CID) {
1463 /* Broadcast packet: give packet to all sockets */
1464
1465 /* Check packet size against connectionless MTU */
1466 if (hdr->length > NG_L2CAP_MTU_DEFAULT) {
1467 NG_BTSOCKET_L2CAP_ERR(
1468"%s: Connectionless L2CAP data packet too big, " \
1469"src bdaddr=%x:%x:%x:%x:%x:%x, length=%d\n",
1470 __func__,
1471 rt->src.b[5], rt->src.b[4], rt->src.b[3],
1472 rt->src.b[2], rt->src.b[1], rt->src.b[0],
1473 hdr->length);
1474 goto drop;
1475 }
1476
1477 /* Make sure we can access connectionless header */
1478 if (m->m_pkthdr.len < sizeof(*clt_hdr)) {
1479 NG_BTSOCKET_L2CAP_ERR(
1480"%s: Can not get L2CAP connectionless packet header, " \
1481"src bdaddr=%x:%x:%x:%x:%x:%x, length=%d\n",
1482 __func__,
1483 rt->src.b[5], rt->src.b[4], rt->src.b[3],
1484 rt->src.b[2], rt->src.b[1], rt->src.b[0],
1485 hdr->length);
1486 goto drop;
1487 }
1488
1489 if (m->m_len < sizeof(*clt_hdr)) {
1490 m = m_pullup(m, sizeof(*clt_hdr));
1491 if (m == NULL)
1492 goto drop;
1493 }
1494
1495 /* Strip connectionless header and deliver packet */
1496 clt_hdr = mtod(m, ng_l2cap_clt_hdr_t *);
1497 m_adj(m, sizeof(*clt_hdr));
1498
1499 NG_BTSOCKET_L2CAP_INFO(
1500"%s: Got L2CAP connectionless data packet, " \
1501"src bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, length=%d\n",
1502 __func__,
1503 rt->src.b[5], rt->src.b[4], rt->src.b[3],
1504 rt->src.b[2], rt->src.b[1], rt->src.b[0],
1505 clt_hdr->psm, hdr->length);
1506
e85b99ab 1507 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
1508
1509 LIST_FOREACH(pcb, &ng_btsocket_l2cap_sockets, next) {
1510 struct mbuf *copy = NULL;
1511
e85b99ab 1512 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
1513
1514 if (bcmp(&rt->src, &pcb->src, sizeof(pcb->src)) != 0 ||
1515 pcb->psm != clt_hdr->psm ||
1516 pcb->state != NG_BTSOCKET_L2CAP_OPEN ||
1517 (pcb->so->so_options & SO_BROADCAST) == 0 ||
e85b99ab 1518 m->m_pkthdr.len > ssb_space(&pcb->so->so_rcv))
b06ebda0
MD
1519 goto next;
1520
1521 /*
1522 * Create a copy of the packet and append it to the
1523 * socket's queue. If m_dup() failed - no big deal
1524 * it is a broadcast traffic after all
1525 */
1526
b5523eac 1527 copy = m_dup(m, M_NOWAIT);
b06ebda0 1528 if (copy != NULL) {
e85b99ab 1529 sbappendrecord(&pcb->so->so_rcv.sb, copy);
b06ebda0
MD
1530 sorwakeup(pcb->so);
1531 }
1532next:
e85b99ab 1533 lockmgr(&pcb->pcb_lock, LK_RELEASE);
b06ebda0
MD
1534 }
1535
e85b99ab 1536 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0
MD
1537 }
1538drop:
1539 NG_FREE_M(m); /* checks for m != NULL */
1540} /* ng_btsocket_l2cap_data_input */
1541
1542/*
1543 * L2CAP sockets default message input routine
1544 */
1545
1546static void
1547ng_btsocket_l2cap_default_msg_input(struct ng_mesg *msg, hook_p hook)
1548{
1549 switch (msg->header.cmd) {
1550 case NGM_L2CAP_NODE_HOOK_INFO: {
1551 ng_btsocket_l2cap_rtentry_t *rt = NULL;
1552
1553 if (hook == NULL || msg->header.arglen != sizeof(bdaddr_t))
1554 break;
1555
1556 if (bcmp(msg->data, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
1557 break;
1558
e85b99ab 1559 lockmgr(&ng_btsocket_l2cap_rt_lock, LK_EXCLUSIVE);
b06ebda0
MD
1560
1561 rt = (ng_btsocket_l2cap_rtentry_t *) NG_HOOK_PRIVATE(hook);
1562 if (rt == NULL) {
fc025606
SW
1563 rt = kmalloc(sizeof(*rt), M_NETGRAPH_BTSOCKET_L2CAP,
1564 M_WAITOK | M_NULLOK | M_ZERO);
b06ebda0 1565 if (rt == NULL) {
e85b99ab 1566 lockmgr(&ng_btsocket_l2cap_rt_lock, LK_RELEASE);
b06ebda0
MD
1567 break;
1568 }
1569
1570 LIST_INSERT_HEAD(&ng_btsocket_l2cap_rt, rt, next);
1571
1572 NG_HOOK_SET_PRIVATE(hook, rt);
1573 }
1574
1575 bcopy(msg->data, &rt->src, sizeof(rt->src));
1576 rt->hook = hook;
1577
e85b99ab 1578 lockmgr(&ng_btsocket_l2cap_rt_lock, LK_RELEASE);
b06ebda0
MD
1579
1580 NG_BTSOCKET_L2CAP_INFO(
1581"%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n",
1582 __func__, NG_HOOK_NAME(hook),
1583 rt->src.b[5], rt->src.b[4], rt->src.b[3],
1584 rt->src.b[2], rt->src.b[1], rt->src.b[0]);
1585 } break;
1586
1587 default:
1588 NG_BTSOCKET_L2CAP_WARN(
1589"%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
1590 break;
1591 }
1592
1593 NG_FREE_MSG(msg); /* Checks for msg != NULL */
1594} /* ng_btsocket_l2cap_default_msg_input */
1595
1596/*
1597 * L2CAP sockets L2CA message input routine
1598 */
1599
1600static void
1601ng_btsocket_l2cap_l2ca_msg_input(struct ng_mesg *msg, hook_p hook)
1602{
1603 ng_btsocket_l2cap_rtentry_p rt = NULL;
1604
1605 if (hook == NULL) {
1606 NG_BTSOCKET_L2CAP_ALERT(
1607"%s: Invalid source hook for L2CA message\n", __func__);
1608 goto drop;
1609 }
1610
1611 rt = (ng_btsocket_l2cap_rtentry_p) NG_HOOK_PRIVATE(hook);
1612 if (rt == NULL) {
1613 NG_BTSOCKET_L2CAP_ALERT(
1614"%s: Could not find out source bdaddr for L2CA message\n", __func__);
1615 goto drop;
1616 }
1617
1618 switch (msg->header.cmd) {
1619 case NGM_L2CAP_L2CA_CON: /* L2CA_Connect response */
1620 ng_btsocket_l2cap_process_l2ca_con_req_rsp(msg, rt);
1621 break;
1622
1623 case NGM_L2CAP_L2CA_CON_RSP: /* L2CA_ConnectRsp response */
1624 ng_btsocket_l2cap_process_l2ca_con_rsp_rsp(msg, rt);
1625 break;
1626
1627 case NGM_L2CAP_L2CA_CON_IND: /* L2CA_Connect indicator */
1628 ng_btsocket_l2cap_process_l2ca_con_ind(msg, rt);
1629 break;
1630
1631 case NGM_L2CAP_L2CA_CFG: /* L2CA_Config response */
1632 ng_btsocket_l2cap_process_l2ca_cfg_req_rsp(msg, rt);
1633 break;
1634
1635 case NGM_L2CAP_L2CA_CFG_RSP: /* L2CA_ConfigRsp response */
1636 ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp(msg, rt);
1637 break;
1638
1639 case NGM_L2CAP_L2CA_CFG_IND: /* L2CA_Config indicator */
1640 ng_btsocket_l2cap_process_l2ca_cfg_ind(msg, rt);
1641 break;
1642
1643 case NGM_L2CAP_L2CA_DISCON: /* L2CA_Disconnect response */
1644 ng_btsocket_l2cap_process_l2ca_discon_rsp(msg, rt);
1645 break;
1646
1647 case NGM_L2CAP_L2CA_DISCON_IND: /* L2CA_Disconnect indicator */
1648 ng_btsocket_l2cap_process_l2ca_discon_ind(msg, rt);
1649 break;
1650
1651 case NGM_L2CAP_L2CA_WRITE: /* L2CA_Write response */
1652 ng_btsocket_l2cap_process_l2ca_write_rsp(msg, rt);
1653 break;
1654
1655 /* XXX FIXME add other L2CA messages */
1656
1657 default:
1658 NG_BTSOCKET_L2CAP_WARN(
1659"%s: Unknown L2CA message, cmd=%d\n", __func__, msg->header.cmd);
1660 break;
1661 }
1662drop:
1663 NG_FREE_MSG(msg);
1664} /* ng_btsocket_l2cap_l2ca_msg_input */
1665
1666/*
1667 * L2CAP sockets input routine
1668 */
1669
1670static void
1671ng_btsocket_l2cap_input(void *context, int pending)
1672{
1673 item_p item = NULL;
1674 hook_p hook = NULL;
1675
1676 for (;;) {
e85b99ab 1677 lockmgr(&ng_btsocket_l2cap_queue_lock, LK_EXCLUSIVE);
b06ebda0 1678 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_queue, item);
e85b99ab 1679 lockmgr(&ng_btsocket_l2cap_queue_lock, LK_RELEASE);
b06ebda0
MD
1680
1681 if (item == NULL)
1682 break;
1683
1684 NGI_GET_HOOK(item, hook);
1685 if (hook != NULL && NG_HOOK_NOT_VALID(hook))
1686 goto drop;
1687
1688 switch(item->el_flags & NGQF_TYPE) {
1689 case NGQF_DATA: {
1690 struct mbuf *m = NULL;
1691
1692 NGI_GET_M(item, m);
1693 ng_btsocket_l2cap_data_input(m, hook);
1694 } break;
1695
1696 case NGQF_MESG: {
1697 struct ng_mesg *msg = NULL;
1698
1699 NGI_GET_MSG(item, msg);
1700
1701 switch (msg->header.cmd) {
1702 case NGM_L2CAP_L2CA_CON:
1703 case NGM_L2CAP_L2CA_CON_RSP:
1704 case NGM_L2CAP_L2CA_CON_IND:
1705 case NGM_L2CAP_L2CA_CFG:
1706 case NGM_L2CAP_L2CA_CFG_RSP:
1707 case NGM_L2CAP_L2CA_CFG_IND:
1708 case NGM_L2CAP_L2CA_DISCON:
1709 case NGM_L2CAP_L2CA_DISCON_IND:
1710 case NGM_L2CAP_L2CA_WRITE:
1711 /* XXX FIXME add other L2CA messages */
1712 ng_btsocket_l2cap_l2ca_msg_input(msg, hook);
1713 break;
1714
1715 default:
1716 ng_btsocket_l2cap_default_msg_input(msg, hook);
1717 break;
1718 }
1719 } break;
1720
1721 default:
1722 KASSERT(0,
1723("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
1724 break;
1725 }
1726drop:
1727 if (hook != NULL)
1728 NG_HOOK_UNREF(hook);
1729
1730 NG_FREE_ITEM(item);
e85b99ab 1731 ng_unref_item(item, 0);
b06ebda0
MD
1732 }
1733} /* ng_btsocket_l2cap_input */
1734
1735/*
1736 * Route cleanup task. Gets scheduled when hook is disconnected. Here we
1737 * will find all sockets that use "invalid" hook and disconnect them.
1738 */
1739
1740static void
1741ng_btsocket_l2cap_rtclean(void *context, int pending)
1742{
1743 ng_btsocket_l2cap_pcb_p pcb = NULL, pcb_next = NULL;
1744 ng_btsocket_l2cap_rtentry_p rt = NULL;
1745
e85b99ab
SW
1746 lockmgr(&ng_btsocket_l2cap_rt_lock, LK_EXCLUSIVE);
1747 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
1748
1749 /*
1750 * First disconnect all sockets that use "invalid" hook
1751 */
1752
1753 for (pcb = LIST_FIRST(&ng_btsocket_l2cap_sockets); pcb != NULL; ) {
e85b99ab 1754 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
1755 pcb_next = LIST_NEXT(pcb, next);
1756
1757 if (pcb->rt != NULL &&
1758 pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1759 if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO)
1760 ng_btsocket_l2cap_untimeout(pcb);
1761
1762 pcb->so->so_error = ENETDOWN;
1763 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
1764 soisdisconnected(pcb->so);
1765
1766 pcb->token = 0;
1767 pcb->cid = 0;
1768 pcb->rt = NULL;
1769 }
1770
e85b99ab 1771 lockmgr(&pcb->pcb_lock, LK_RELEASE);
b06ebda0
MD
1772 pcb = pcb_next;
1773 }
1774
1775 /*
1776 * Now cleanup routing table
1777 */
1778
1779 for (rt = LIST_FIRST(&ng_btsocket_l2cap_rt); rt != NULL; ) {
1780 ng_btsocket_l2cap_rtentry_p rt_next = LIST_NEXT(rt, next);
1781
1782 if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
1783 LIST_REMOVE(rt, next);
1784
1785 NG_HOOK_SET_PRIVATE(rt->hook, NULL);
1786 NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
1787
1788 bzero(rt, sizeof(*rt));
fc025606 1789 kfree(rt, M_NETGRAPH_BTSOCKET_L2CAP);
b06ebda0
MD
1790 }
1791
1792 rt = rt_next;
1793 }
1794
e85b99ab
SW
1795 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
1796 lockmgr(&ng_btsocket_l2cap_rt_lock, LK_RELEASE);
b06ebda0
MD
1797} /* ng_btsocket_l2cap_rtclean */
1798
1799/*
1800 * Initialize everything
1801 */
1802
1803void
1804ng_btsocket_l2cap_init(void)
1805{
1806 int error = 0;
1807
1808 ng_btsocket_l2cap_node = NULL;
1809 ng_btsocket_l2cap_debug_level = NG_BTSOCKET_WARN_LEVEL;
1810
1811 /* Register Netgraph node type */
1812 error = ng_newtype(&typestruct);
1813 if (error != 0) {
1814 NG_BTSOCKET_L2CAP_ALERT(
1815"%s: Could not register Netgraph node type, error=%d\n", __func__, error);
1816
1817 return;
1818 }
1819
1820 /* Create Netgrapg node */
1821 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_node);
1822 if (error != 0) {
1823 NG_BTSOCKET_L2CAP_ALERT(
1824"%s: Could not create Netgraph node, error=%d\n", __func__, error);
1825
1826 ng_btsocket_l2cap_node = NULL;
1827
1828 return;
1829 }
1830
1831 error = ng_name_node(ng_btsocket_l2cap_node,
1832 NG_BTSOCKET_L2CAP_NODE_TYPE);
1833 if (error != 0) {
1834 NG_BTSOCKET_L2CAP_ALERT(
1835"%s: Could not name Netgraph node, error=%d\n", __func__, error);
1836
1837 NG_NODE_UNREF(ng_btsocket_l2cap_node);
1838 ng_btsocket_l2cap_node = NULL;
1839
1840 return;
1841 }
1842
1843 /* Create input queue */
1844 NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_queue, ifqmaxlen);
e85b99ab
SW
1845 lockinit(&ng_btsocket_l2cap_queue_lock,
1846 "btsocks_l2cap_queue_lock", 0, 0);
b06ebda0
MD
1847 TASK_INIT(&ng_btsocket_l2cap_queue_task, 0,
1848 ng_btsocket_l2cap_input, NULL);
1849
1850 /* Create list of sockets */
1851 LIST_INIT(&ng_btsocket_l2cap_sockets);
e85b99ab
SW
1852 lockinit(&ng_btsocket_l2cap_sockets_lock,
1853 "btsocks_l2cap_sockets_lock", 0, 0);
b06ebda0
MD
1854
1855 /* Routing table */
1856 LIST_INIT(&ng_btsocket_l2cap_rt);
e85b99ab
SW
1857 lockinit(&ng_btsocket_l2cap_rt_lock,
1858 "btsocks_l2cap_rt_lock", 0, 0);
b06ebda0
MD
1859 TASK_INIT(&ng_btsocket_l2cap_rt_task, 0,
1860 ng_btsocket_l2cap_rtclean, NULL);
1861} /* ng_btsocket_l2cap_init */
1862
1863/*
1864 * Abort connection on socket
1865 */
1866
1867void
e85b99ab 1868ng_btsocket_l2cap_abort(netmsg_t msg)
b06ebda0 1869{
e85b99ab
SW
1870 struct socket *so = msg->abort.base.nm_so;
1871
b06ebda0
MD
1872 so->so_error = ECONNABORTED;
1873
e85b99ab 1874 ng_btsocket_l2cap_disconnect(msg);
b06ebda0
MD
1875} /* ng_btsocket_l2cap_abort */
1876
e85b99ab 1877#if 0 /* XXX */
b06ebda0
MD
1878void
1879ng_btsocket_l2cap_close(struct socket *so)
1880{
1881
1882 (void)ng_btsocket_l2cap_disconnect(so);
1883} /* ng_btsocket_l2cap_close */
e85b99ab 1884#endif
b06ebda0
MD
1885
1886/*
1887 * Accept connection on socket. Nothing to do here, socket must be connected
1888 * and ready, so just return peer address and be done with it.
1889 */
1890
e85b99ab
SW
1891void
1892ng_btsocket_l2cap_accept(netmsg_t msg)
b06ebda0 1893{
e85b99ab
SW
1894 int error = 0;
1895
1896 if (ng_btsocket_l2cap_node == NULL) {
1897 error = EINVAL;
1898 goto out;
1899 }
1900
1901 ng_btsocket_l2cap_peeraddr(msg);
1902 return;
b06ebda0 1903
e85b99ab
SW
1904out:
1905 lwkt_replymsg(&msg->accept.base.lmsg, error);
b06ebda0
MD
1906} /* ng_btsocket_l2cap_accept */
1907
1908/*
1909 * Create and attach new socket
1910 */
1911
e85b99ab
SW
1912void
1913ng_btsocket_l2cap_attach(netmsg_t msg)
b06ebda0 1914{
e85b99ab
SW
1915 struct socket *so = msg->attach.base.nm_so;
1916 int proto = msg->attach.nm_proto;
1917 static u_int32_t token = 0;
1918 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so);
1919 int error = 0;
b06ebda0
MD
1920
1921 /* Check socket and protocol */
e85b99ab
SW
1922 if (ng_btsocket_l2cap_node == NULL) {
1923 error = EPROTONOSUPPORT;
1924 goto out;
1925 }
1926 if (so->so_type != SOCK_SEQPACKET) {
1927 error = ESOCKTNOSUPPORT;
1928 goto out;
1929 }
b06ebda0
MD
1930
1931#if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */
1932 if (proto != 0)
e85b99ab
SW
1933 if (proto != BLUETOOTH_PROTO_L2CAP) {
1934 error = EPROTONOSUPPORT;
1935 goto out;
1936 }
b06ebda0
MD
1937#endif /* XXX */
1938
e85b99ab
SW
1939 if (pcb != NULL) {
1940 error = EISCONN;
1941 goto out;
1942 }
b06ebda0
MD
1943
1944 /* Reserve send and receive space if it is not reserved yet */
e85b99ab 1945 if ((so->so_snd.ssb_hiwat == 0) || (so->so_rcv.ssb_hiwat == 0)) {
b06ebda0 1946 error = soreserve(so, NG_BTSOCKET_L2CAP_SENDSPACE,
e85b99ab 1947 NG_BTSOCKET_L2CAP_RECVSPACE, NULL);
b06ebda0 1948 if (error != 0)
e85b99ab 1949 goto out;
b06ebda0
MD
1950 }
1951
1952 /* Allocate the PCB */
fc025606
SW
1953 pcb = kmalloc(sizeof(*pcb), M_NETGRAPH_BTSOCKET_L2CAP,
1954 M_WAITOK | M_NULLOK | M_ZERO);
e85b99ab
SW
1955 if (pcb == NULL) {
1956 error = ENOMEM;
1957 goto out;
1958 }
b06ebda0
MD
1959
1960 /* Link the PCB and the socket */
1961 so->so_pcb = (caddr_t) pcb;
1962 pcb->so = so;
1963 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
1964
1965 /* Initialize PCB */
1966 pcb->imtu = pcb->omtu = NG_L2CAP_MTU_DEFAULT;
1967
1968 /* Default flow */
1969 pcb->iflow.flags = 0x0;
1970 pcb->iflow.service_type = NG_HCI_SERVICE_TYPE_BEST_EFFORT;
1971 pcb->iflow.token_rate = 0xffffffff; /* maximum */
1972 pcb->iflow.token_bucket_size = 0xffffffff; /* maximum */
1973 pcb->iflow.peak_bandwidth = 0x00000000; /* maximum */
1974 pcb->iflow.latency = 0xffffffff; /* don't care */
1975 pcb->iflow.delay_variation = 0xffffffff; /* don't care */
1976
1977 bcopy(&pcb->iflow, &pcb->oflow, sizeof(pcb->oflow));
1978
1979 pcb->flush_timo = NG_L2CAP_FLUSH_TIMO_DEFAULT;
1980 pcb->link_timo = NG_L2CAP_LINK_TIMO_DEFAULT;
1981
e85b99ab 1982 callout_init_mp(&pcb->timo);
b06ebda0
MD
1983
1984 /*
1985 * XXX Mark PCB mutex as DUPOK to prevent "duplicated lock of
1986 * the same type" message. When accepting new L2CAP connection
1987 * ng_btsocket_l2cap_process_l2ca_con_ind() holds both PCB mutexes
1988 * for "old" (accepting) PCB and "new" (created) PCB.
1989 */
1990
e85b99ab 1991 lockinit(&pcb->pcb_lock, "btsocks_l2cap_pcb_lock", 0, LK_CANRECURSE);
b06ebda0
MD
1992
1993 /*
1994 * Add the PCB to the list
1995 *
1996 * XXX FIXME VERY IMPORTANT!
1997 *
1998 * This is totally FUBAR. We could get here in two cases:
1999 *
2000 * 1) When user calls socket()
2001 * 2) When we need to accept new incomming connection and call
2002 * sonewconn()
2003 *
2004 * In the first case we must acquire ng_btsocket_l2cap_sockets_mtx.
2005 * In the second case we hold ng_btsocket_l2cap_sockets_mtx already.
2006 * So we now need to distinguish between these cases. From reading
2007 * /sys/kern/uipc_socket.c we can find out that sonewconn() calls
2008 * pru_attach with proto == 0 and td == NULL. For now use this fact
2009 * to figure out if we were called from socket() or from sonewconn().
2010 */
2011
e85b99ab
SW
2012 if (proto != 0)
2013 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0 2014 else
e85b99ab 2015 KKASSERT(lockowned(&ng_btsocket_l2cap_sockets_lock) != 0);
b06ebda0
MD
2016
2017 /* Set PCB token. Use ng_btsocket_l2cap_sockets_mtx for protection */
2018 if (++ token == 0)
2019 token ++;
2020
2021 pcb->token = token;
2022
2023 LIST_INSERT_HEAD(&ng_btsocket_l2cap_sockets, pcb, next);
2024
e85b99ab
SW
2025 if (proto != 0)
2026 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0 2027
e85b99ab
SW
2028out:
2029 lwkt_replymsg(&msg->attach.base.lmsg, error);
b06ebda0
MD
2030} /* ng_btsocket_l2cap_attach */
2031
2032/*
2033 * Bind socket
2034 */
2035
e85b99ab
SW
2036void
2037ng_btsocket_l2cap_bind(netmsg_t msg)
b06ebda0 2038{
e85b99ab
SW
2039 struct socket *so = msg->bind.base.nm_so;
2040 struct sockaddr *nam = msg->bind.nm_nam;
b06ebda0
MD
2041 ng_btsocket_l2cap_pcb_t *pcb = NULL;
2042 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;
2043 int psm, error = 0;
2044
e85b99ab
SW
2045 if (ng_btsocket_l2cap_node == NULL) {
2046 error = EINVAL;
2047 goto out;
2048 }
b06ebda0
MD
2049
2050 /* Verify address */
e85b99ab
SW
2051 if (sa == NULL) {
2052 error = EINVAL;
2053 goto out;
2054 }
2055 if (sa->l2cap_family != AF_BLUETOOTH) {
2056 error = EAFNOSUPPORT;
2057 goto out;
2058 }
2059 if (sa->l2cap_len != sizeof(*sa)) {
2060 error = EINVAL;
2061 goto out;
2062 }
b06ebda0
MD
2063
2064 psm = le16toh(sa->l2cap_psm);
2065
2066 /*
2067 * Check if other socket has this address already (look for exact
2068 * match PSM and bdaddr) and assign socket address if it's available.
2069 *
2070 * Note: socket can be bound to ANY PSM (zero) thus allowing several
2071 * channels with the same PSM between the same pair of BD_ADDR'es.
2072 */
2073
e85b99ab 2074 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
b06ebda0
MD
2075
2076 LIST_FOREACH(pcb, &ng_btsocket_l2cap_sockets, next)
2077 if (psm != 0 && psm == pcb->psm &&
2078 bcmp(&pcb->src, &sa->l2cap_bdaddr, sizeof(bdaddr_t)) == 0)
2079 break;
2080
2081 if (pcb == NULL) {
2082 /* Set socket address */
2083 pcb = so2l2cap_pcb(so);
2084 if (pcb != NULL) {
2085 bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src));
2086 pcb->psm = psm;
2087 } else
2088 error = EINVAL;
2089 } else
2090 error = EADDRINUSE;
2091
e85b99ab 2092 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0 2093
e85b99ab
SW
2094out:
2095 lwkt_replymsg(&msg->bind.base.lmsg, error);
b06ebda0
MD
2096} /* ng_btsocket_l2cap_bind */
2097
2098/*
2099 * Connect socket
2100 */
2101
e85b99ab
SW
2102void
2103ng_btsocket_l2cap_connect(netmsg_t msg)
b06ebda0 2104{
e85b99ab
SW
2105 struct socket *so = msg->connect.base.nm_so;
2106 struct sockaddr *nam = msg->connect.nm_nam;
b06ebda0
MD
2107 ng_btsocket_l2cap_pcb_t *pcb = so2l2cap_pcb(so);
2108 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;
2109 ng_btsocket_l2cap_rtentry_t *rt = NULL;
2110 int have_src, error = 0;
2111
2112 /* Check socket */
e85b99ab
SW
2113 if (pcb == NULL) {
2114 error = EINVAL;
2115 goto out;
2116 }
2117 if (ng_btsocket_l2cap_node == NULL) {
2118 error = EINVAL;
2119 goto out;
2120 }
2121 if (pcb->state == NG_BTSOCKET_L2CAP_CONNECTING) {
2122 error = EINPROGRESS;
2123 goto out;
2124 }
b06ebda0
MD
2125
2126 /* Verify address */
e85b99ab
SW
2127 if (sa == NULL) {
2128 error = EINVAL;
2129 goto out;
2130 }
2131 if (sa->l2cap_family != AF_BLUETOOTH) {
2132 error = EAFNOSUPPORT;
2133 goto out;
2134 }
2135 if (sa->l2cap_len != sizeof(*sa)) {
2136 error = EINVAL;
2137 goto out;
2138 }
b06ebda0 2139 if (sa->l2cap_psm == 0 ||
e85b99ab
SW
2140 bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) {
2141 error = EDESTADDRREQ;
2142 goto out;
2143 }
2144 if (pcb->psm != 0 && pcb->psm != le16toh(sa->l2cap_psm)) {
2145 error = EINVAL;
2146 goto out;
2147 }
b06ebda0
MD
2148
2149 /*
2150 * Routing. Socket should be bound to some source address. The source
2151 * address can be ANY. Destination address must be set and it must not
2152 * be ANY. If source address is ANY then find first rtentry that has
2153 * src != dst.
2154 */
2155
e85b99ab
SW
2156 lockmgr(&ng_btsocket_l2cap_rt_lock, LK_EXCLUSIVE);
2157 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
2158 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
2159
2160 /* Send destination address and PSM */
2161 bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));
2162 pcb->psm = le16toh(sa->l2cap_psm);
2163
2164 pcb->rt = NULL;
2165 have_src = bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src));
2166
2167 LIST_FOREACH(rt, &ng_btsocket_l2cap_rt, next) {
2168 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
2169 continue;
2170
2171 /* Match src and dst */
2172 if (have_src) {
2173 if (bcmp(&pcb->src, &rt->src, sizeof(rt->src)) == 0)
2174 break;
2175 } else {
2176 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
2177 break;
2178 }
2179 }
2180
2181 if (rt != NULL) {
2182 pcb->rt = rt;
2183
2184 if (!have_src)
2185 bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
2186 } else
2187 error = EHOSTUNREACH;
2188
2189 /*
2190 * Send L2CA_Connect request
2191 */
2192
2193 if (error == 0) {
2194 error = ng_btsocket_l2cap_send_l2ca_con_req(pcb);
2195 if (error == 0) {
2196 pcb->flags |= NG_BTSOCKET_L2CAP_CLIENT;
2197 pcb->state = NG_BTSOCKET_L2CAP_CONNECTING;
2198 soisconnecting(pcb->so);
2199
2200 ng_btsocket_l2cap_timeout(pcb);
2201 }
2202 }
2203
e85b99ab
SW
2204 lockmgr(&pcb->pcb_lock, LK_RELEASE);
2205 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
2206 lockmgr(&ng_btsocket_l2cap_rt_lock, LK_RELEASE);
b06ebda0 2207
e85b99ab
SW
2208out:
2209 lwkt_replymsg(&msg->connect.base.lmsg, error);
b06ebda0
MD
2210} /* ng_btsocket_l2cap_connect */
2211
2212/*
2213 * Process ioctl's calls on socket
2214 */
2215
e85b99ab
SW
2216void
2217ng_btsocket_l2cap_control(netmsg_t msg)
b06ebda0 2218{
e85b99ab 2219 lwkt_replymsg(&msg->control.base.lmsg, EINVAL);
b06ebda0
MD
2220} /* ng_btsocket_l2cap_control */
2221
2222/*
2223 * Process getsockopt/setsockopt system calls
2224 */
2225
e85b99ab
SW
2226void
2227ng_btsocket_l2cap_ctloutput(netmsg_t msg)
b06ebda0 2228{
e85b99ab
SW
2229 struct socket *so = msg->ctloutput.base.nm_so;
2230 struct sockopt *sopt = msg->ctloutput.nm_sopt;
2231 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so);
2232 int error = 0;
2233 ng_l2cap_cfg_opt_val_t v;
b06ebda0 2234
e85b99ab
SW
2235 if (pcb == NULL) {
2236 error = EINVAL;
2237 goto out;
2238 }
2239 if (ng_btsocket_l2cap_node == NULL) {
2240 error = EINVAL;
2241 goto out;
2242 }
b06ebda0
MD
2243
2244 if (sopt->sopt_level != SOL_L2CAP)
e85b99ab 2245 goto out;
b06ebda0 2246
e85b99ab 2247 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
2248
2249 switch (sopt->sopt_dir) {
2250 case SOPT_GET:
2251 switch (sopt->sopt_name) {
2252 case SO_L2CAP_IMTU: /* get incoming MTU */
2253 error = sooptcopyout(sopt, &pcb->imtu,
2254 sizeof(pcb->imtu));
2255 break;
2256
2257 case SO_L2CAP_OMTU: /* get outgoing (peer incoming) MTU */
2258 error = sooptcopyout(sopt, &pcb->omtu,
2259 sizeof(pcb->omtu));
2260 break;
2261
2262 case SO_L2CAP_IFLOW: /* get incoming flow spec. */
2263 error = sooptcopyout(sopt, &pcb->iflow,
2264 sizeof(pcb->iflow));
2265 break;
2266
2267 case SO_L2CAP_OFLOW: /* get outgoing flow spec. */
2268 error = sooptcopyout(sopt, &pcb->oflow,
2269 sizeof(pcb->oflow));
2270 break;
2271
2272 case SO_L2CAP_FLUSH: /* get flush timeout */
2273 error = sooptcopyout(sopt, &pcb->flush_timo,
2274 sizeof(pcb->flush_timo));
2275 break;
2276
2277 default:
2278 error = ENOPROTOOPT;
2279 break;
2280 }
2281 break;
2282
2283 case SOPT_SET:
2284 /*
2285 * XXX
2286 * We do not allow to change these parameters while socket is
2287 * connected or we are in the process of creating a connection.
2288 * May be this should indicate re-configuration of the open
2289 * channel?
2290 */
2291
2292 if (pcb->state != NG_BTSOCKET_L2CAP_CLOSED) {
2293 error = EACCES;
2294 break;
2295 }
2296
2297 switch (sopt->sopt_name) {
2298 case SO_L2CAP_IMTU: /* set incoming MTU */
2299 error = sooptcopyin(sopt, &v, sizeof(v), sizeof(v.mtu));
2300 if (error == 0)
2301 pcb->imtu = v.mtu;
2302 break;
2303
2304 case SO_L2CAP_OFLOW: /* set outgoing flow spec. */
2305 error = sooptcopyin(sopt, &v, sizeof(v),sizeof(v.flow));
2306 if (error == 0)
2307 bcopy(&v.flow, &pcb->oflow, sizeof(pcb->oflow));
2308 break;
2309
2310 case SO_L2CAP_FLUSH: /* set flush timeout */
2311 error = sooptcopyin(sopt, &v, sizeof(v),
2312 sizeof(v.flush_timo));
2313 if (error == 0)
2314 pcb->flush_timo = v.flush_timo;
2315 break;
2316
2317 default:
2318 error = ENOPROTOOPT;
2319 break;
2320 }
2321 break;
2322
2323 default:
2324 error = EINVAL;
2325 break;
2326 }
2327
e85b99ab 2328 lockmgr(&pcb->pcb_lock, LK_RELEASE);
b06ebda0 2329
e85b99ab
SW
2330out:
2331 lwkt_replymsg(&msg->ctloutput.base.lmsg, error);
b06ebda0
MD
2332} /* ng_btsocket_l2cap_ctloutput */
2333
2334/*
2335 * Detach and destroy socket
2336 */
2337
2338void
e85b99ab 2339ng_btsocket_l2cap_detach(netmsg_t msg)
b06ebda0 2340{
e85b99ab
SW
2341 struct socket *so = msg->detach.base.nm_so;
2342 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so);
2343 int error = 0;
b06ebda0
MD
2344
2345 KASSERT(pcb != NULL, ("ng_btsocket_l2cap_detach: pcb == NULL"));
2346
2347 if (ng_btsocket_l2cap_node == NULL)
e85b99ab 2348 goto out;
b06ebda0 2349
e85b99ab
SW
2350 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_EXCLUSIVE);
2351 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
2352
2353 /* XXX what to do with pending request? */
2354 if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO)
2355 ng_btsocket_l2cap_untimeout(pcb);
2356
2357 if (pcb->state != NG_BTSOCKET_L2CAP_CLOSED &&
2358 pcb->state != NG_BTSOCKET_L2CAP_DISCONNECTING)
2359 /* Send disconnect request with "zero" token */
2360 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
2361
2362 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
2363
2364 LIST_REMOVE(pcb, next);
2365
e85b99ab
SW
2366 lockmgr(&pcb->pcb_lock, LK_RELEASE);
2367 lockmgr(&ng_btsocket_l2cap_sockets_lock, LK_RELEASE);
b06ebda0 2368
e85b99ab 2369 lockuninit(&pcb->pcb_lock);
b06ebda0 2370 bzero(pcb, sizeof(*pcb));
fc025606 2371 kfree(pcb, M_NETGRAPH_BTSOCKET_L2CAP);
b06ebda0
MD
2372
2373 soisdisconnected(so);
2374 so->so_pcb = NULL;
e85b99ab
SW
2375
2376out:
2377 lwkt_replymsg(&msg->detach.base.lmsg, error);
b06ebda0
MD
2378} /* ng_btsocket_l2cap_detach */
2379
2380/*
2381 * Disconnect socket
2382 */
2383
e85b99ab
SW
2384void
2385ng_btsocket_l2cap_disconnect(netmsg_t msg)
b06ebda0 2386{
e85b99ab
SW
2387 struct socket *so = msg->disconnect.base.nm_so;
2388 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so);
2389 int error = 0;
b06ebda0 2390
e85b99ab
SW
2391 if (pcb == NULL) {
2392 error = EINVAL;
2393 goto out;
2394 }
2395 if (ng_btsocket_l2cap_node == NULL) {
2396 error = EINVAL;
2397 goto out;
2398 }
b06ebda0 2399
e85b99ab 2400 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
2401
2402 if (pcb->state == NG_BTSOCKET_L2CAP_DISCONNECTING) {
e85b99ab
SW
2403 lockmgr(&pcb->pcb_lock, LK_RELEASE);
2404 error = EINPROGRESS;
2405 goto out;
b06ebda0
MD
2406 }
2407
2408 if (pcb->state != NG_BTSOCKET_L2CAP_CLOSED) {
2409 /* XXX FIXME what to do with pending request? */
2410 if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO)
2411 ng_btsocket_l2cap_untimeout(pcb);
2412
2413 error = ng_btsocket_l2cap_send_l2ca_discon_req(pcb->token, pcb);
2414 if (error == 0) {
2415 pcb->state = NG_BTSOCKET_L2CAP_DISCONNECTING;
2416 soisdisconnecting(so);
2417
2418 ng_btsocket_l2cap_timeout(pcb);
2419 }
2420
2421 /* XXX FIXME what to do if error != 0 */
2422 }
2423
e85b99ab 2424 lockmgr(&pcb->pcb_lock, LK_RELEASE);
b06ebda0 2425
e85b99ab
SW
2426out:
2427 lwkt_replymsg(&msg->disconnect.base.lmsg, error);
b06ebda0
MD
2428} /* ng_btsocket_l2cap_disconnect */
2429
2430/*
2431 * Listen on socket
2432 */
2433
e85b99ab
SW
2434void
2435ng_btsocket_l2cap_listen(netmsg_t msg)
b06ebda0 2436{
e85b99ab
SW
2437 struct socket *so = msg->listen.base.nm_so;
2438 struct thread *td = msg->listen.nm_td;
2439 int backlog = msg->listen.nm_flags; /* XXX */
2440 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so);
2441 int error = 0;
b06ebda0 2442
e85b99ab
SW
2443 if (so->so_state &
2444 (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) {
2445 error = EINVAL;
b06ebda0 2446 goto out;
e85b99ab 2447 }
b06ebda0
MD
2448 if (pcb == NULL) {
2449 error = EINVAL;
2450 goto out;
2451 }
2452 if (ng_btsocket_l2cap_node == NULL) {
2453 error = EINVAL;
2454 goto out;
2455 }
2456 if (pcb->psm == 0) {
2457 error = EADDRNOTAVAIL;
2458 goto out;
2459 }
e85b99ab
SW
2460 solisten(so, backlog, td);
2461
b06ebda0 2462out:
e85b99ab 2463 lwkt_replymsg(&msg->listen.base.lmsg, error);
b06ebda0
MD
2464} /* ng_btsocket_listen */
2465
2466/*
2467 * Get peer address
2468 */
2469
e85b99ab
SW
2470void
2471ng_btsocket_l2cap_peeraddr(netmsg_t msg)
b06ebda0 2472{
e85b99ab
SW
2473 struct socket *so = msg->peeraddr.base.nm_so;
2474 struct sockaddr **nam = msg->peeraddr.nm_nam;
2475 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so);
2476 struct sockaddr_l2cap sa;
2477 int error = 0;
b06ebda0 2478
e85b99ab
SW
2479 if (pcb == NULL) {
2480 error = EINVAL;
2481 goto out;
2482 }
2483 if (ng_btsocket_l2cap_node == NULL) {
2484 error = EINVAL;
2485 goto out;
2486 }
b06ebda0
MD
2487
2488 bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
2489 sa.l2cap_psm = htole16(pcb->psm);
2490 sa.l2cap_len = sizeof(sa);
2491 sa.l2cap_family = AF_BLUETOOTH;
2492
e85b99ab
SW
2493 *nam = dup_sockaddr((struct sockaddr *) &sa);
2494
2495 if (*nam == NULL)
2496 error = ENOMEM;
b06ebda0 2497
e85b99ab
SW
2498out:
2499 lwkt_replymsg(&msg->peeraddr.base.lmsg, error);
b06ebda0
MD
2500} /* ng_btsocket_l2cap_peeraddr */
2501
2502/*
2503 * Send data to socket
2504 */
2505
e85b99ab
SW
2506void
2507ng_btsocket_l2cap_send(netmsg_t msg)
b06ebda0 2508{
e85b99ab
SW
2509 struct socket *so = msg->send.base.nm_so;
2510 struct mbuf *m = msg->send.nm_m;
2511 struct mbuf *control = msg->send.nm_control;
b06ebda0
MD
2512 ng_btsocket_l2cap_pcb_t *pcb = so2l2cap_pcb(so);
2513 int error = 0;
2514
2515 if (ng_btsocket_l2cap_node == NULL) {
2516 error = ENETDOWN;
2517 goto drop;
2518 }
2519
2520 /* Check socket and input */
2521 if (pcb == NULL || m == NULL || control != NULL) {
2522 error = EINVAL;
2523 goto drop;
2524 }
2525
e85b99ab 2526 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
2527
2528 /* Make sure socket is connected */
2529 if (pcb->state != NG_BTSOCKET_L2CAP_OPEN) {
e85b99ab 2530 lockmgr(&pcb->pcb_lock, LK_RELEASE);
b06ebda0
MD
2531 error = ENOTCONN;
2532 goto drop;
2533 }
2534
2535 /* Check route */
2536 if (pcb->rt == NULL ||
2537 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) {
e85b99ab 2538 lockmgr(&pcb->pcb_lock, LK_RELEASE);
b06ebda0
MD
2539 error = ENETDOWN;
2540 goto drop;
2541 }
2542
2543 /* Check packet size agains outgoing (peer's incoming) MTU) */
2544 if (m->m_pkthdr.len > pcb->omtu) {
2545 NG_BTSOCKET_L2CAP_ERR(
2546"%s: Packet too big, len=%d, omtu=%d\n", __func__, m->m_pkthdr.len, pcb->omtu);
2547
e85b99ab 2548 lockmgr(&pcb->pcb_lock, LK_RELEASE);
b06ebda0
MD
2549 error = EMSGSIZE;
2550 goto drop;
2551 }
2552
2553 /*
2554 * First put packet on socket send queue. Then check if we have
2555 * pending timeout. If we do not have timeout then we must send
2556 * packet and schedule timeout. Otherwise do nothing and wait for
2557 * L2CA_WRITE_RSP.
2558 */
2559
e85b99ab 2560 sbappendrecord(&pcb->so->so_snd.sb, m);
b06ebda0
MD
2561 m = NULL;
2562
2563 if (!(pcb->flags & NG_BTSOCKET_L2CAP_TIMO)) {
2564 error = ng_btsocket_l2cap_send2(pcb);
2565 if (error == 0)
2566 ng_btsocket_l2cap_timeout(pcb);
2567 else
e85b99ab 2568 sbdroprecord(&pcb->so->so_snd.sb); /* XXX */
b06ebda0
MD
2569 }
2570
e85b99ab 2571 lockmgr(&pcb->pcb_lock, LK_RELEASE);
b06ebda0
MD
2572drop:
2573 NG_FREE_M(m); /* checks for != NULL */
2574 NG_FREE_M(control);
2575
e85b99ab 2576 lwkt_replymsg(&msg->send.base.lmsg, error);
b06ebda0
MD
2577} /* ng_btsocket_l2cap_send */
2578
2579/*
2580 * Send first packet in the socket queue to the L2CAP layer
2581 */
2582
2583static int
2584ng_btsocket_l2cap_send2(ng_btsocket_l2cap_pcb_p pcb)
2585{
2586 struct mbuf *m = NULL;
2587 ng_l2cap_l2ca_hdr_t *hdr = NULL;
2588 int error = 0;
2589
e85b99ab 2590 KKASSERT(lockowned(&pcb->pcb_lock) != 0);
b06ebda0 2591
e85b99ab 2592 if (pcb->so->so_snd.sb.sb_cc == 0)
b06ebda0
MD
2593 return (EINVAL); /* XXX */
2594
b5523eac 2595 m = m_dup(pcb->so->so_snd.sb.sb_mb, M_NOWAIT);
b06ebda0
MD
2596 if (m == NULL)
2597 return (ENOBUFS);
2598
2599 /* Create L2CA packet header */
b5523eac 2600 M_PREPEND(m, sizeof(*hdr), M_NOWAIT);
b06ebda0
MD
2601 if (m != NULL)
2602 if (m->m_len < sizeof(*hdr))
2603 m = m_pullup(m, sizeof(*hdr));
2604
2605 if (m == NULL) {
2606 NG_BTSOCKET_L2CAP_ERR(
2607"%s: Failed to create L2CA packet header\n", __func__);
2608
2609 return (ENOBUFS);
2610 }
2611
2612 hdr = mtod(m, ng_l2cap_l2ca_hdr_t *);
2613 hdr->token = pcb->token;
2614 hdr->length = m->m_pkthdr.len - sizeof(*hdr);
2615 hdr->lcid = pcb->cid;
2616
2617 NG_BTSOCKET_L2CAP_INFO(
2618"%s: Sending packet: len=%d, length=%d, lcid=%d, token=%d, state=%d\n",
2619 __func__, m->m_pkthdr.len, hdr->length, hdr->lcid,
2620 hdr->token, pcb->state);
2621
2622 /*
2623 * If we got here than we have successfuly creates new L2CAP
2624 * data packet and now we can send it to the L2CAP layer
2625 */
2626
2627 NG_SEND_DATA_ONLY(error, pcb->rt->hook, m);
2628
2629 return (error);
2630} /* ng_btsocket_l2cap_send2 */
2631
2632/*
2633 * Get socket address
2634 */
2635
e85b99ab
SW
2636void
2637ng_btsocket_l2cap_sockaddr(netmsg_t msg)
b06ebda0 2638{
e85b99ab
SW
2639 struct socket *so = msg->sockaddr.base.nm_so;
2640 struct sockaddr **nam = msg->sockaddr.nm_nam;
2641 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so);
2642 struct sockaddr_l2cap sa;
2643 int error = 0;
b06ebda0 2644
e85b99ab
SW
2645 if (pcb == NULL) {
2646 error = EINVAL;
2647 goto out;
2648 }
2649 if (ng_btsocket_l2cap_node == NULL) {
2650 error = EINVAL;
2651 goto out;
2652 }
b06ebda0
MD
2653
2654 bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
2655 sa.l2cap_psm = htole16(pcb->psm);
2656 sa.l2cap_len = sizeof(sa);
2657 sa.l2cap_family = AF_BLUETOOTH;
2658
e85b99ab 2659 *nam = dup_sockaddr((struct sockaddr *) &sa);
b06ebda0 2660
e85b99ab
SW
2661 if (*nam == NULL)
2662 error = ENOMEM;
2663
2664out:
2665 lwkt_replymsg(&msg->sockaddr.base.lmsg, error);
b06ebda0
MD
2666} /* ng_btsocket_l2cap_sockaddr */
2667
2668/*****************************************************************************
2669 *****************************************************************************
2670 ** Misc. functions
2671 *****************************************************************************
2672 *****************************************************************************/
2673
2674/*
2675 * Look for the socket that listens on given PSM and bdaddr. Returns exact or
2676 * close match (if any). Caller must hold ng_btsocket_l2cap_sockets_mtx.
2677 */
2678
2679static ng_btsocket_l2cap_pcb_p
2680ng_btsocket_l2cap_pcb_by_addr(bdaddr_p bdaddr, int psm)
2681{
2682 ng_btsocket_l2cap_pcb_p p = NULL, p1 = NULL;
2683
e85b99ab 2684 KKASSERT(lockowned(&ng_btsocket_l2cap_sockets_lock) != 0);
b06ebda0
MD
2685
2686 LIST_FOREACH(p, &ng_btsocket_l2cap_sockets, next) {
2687 if (p->so == NULL || !(p->so->so_options & SO_ACCEPTCONN) ||
2688 p->psm != psm)
2689 continue;
2690
2691 if (bcmp(&p->src, bdaddr, sizeof(p->src)) == 0)
2692 break;
2693
2694 if (bcmp(&p->src, NG_HCI_BDADDR_ANY, sizeof(p->src)) == 0)
2695 p1 = p;
2696 }
2697
2698 return ((p != NULL)? p : p1);
2699} /* ng_btsocket_l2cap_pcb_by_addr */
2700
2701/*
2702 * Look for the socket that has given token.
2703 * Caller must hold ng_btsocket_l2cap_sockets_mtx.
2704 */
2705
2706static ng_btsocket_l2cap_pcb_p
2707ng_btsocket_l2cap_pcb_by_token(u_int32_t token)
2708{
2709 ng_btsocket_l2cap_pcb_p p = NULL;
2710
2711 if (token == 0)
2712 return (NULL);
2713
e85b99ab 2714 KKASSERT(lockowned(&ng_btsocket_l2cap_sockets_lock) != 0);
b06ebda0
MD
2715
2716 LIST_FOREACH(p, &ng_btsocket_l2cap_sockets, next)
2717 if (p->token == token)
2718 break;
2719
2720 return (p);
2721} /* ng_btsocket_l2cap_pcb_by_token */
2722
2723/*
2724 * Look for the socket that assigned to given source address and channel ID.
2725 * Caller must hold ng_btsocket_l2cap_sockets_mtx
2726 */
2727
2728static ng_btsocket_l2cap_pcb_p
2729ng_btsocket_l2cap_pcb_by_cid(bdaddr_p src, int cid)
2730{
2731 ng_btsocket_l2cap_pcb_p p = NULL;
2732
e85b99ab 2733 KKASSERT(lockowned(&ng_btsocket_l2cap_sockets_lock) != 0);
b06ebda0
MD
2734
2735 LIST_FOREACH(p, &ng_btsocket_l2cap_sockets, next)
2736 if (p->cid == cid && bcmp(src, &p->src, sizeof(p->src)) == 0)
2737 break;
2738
2739 return (p);
2740} /* ng_btsocket_l2cap_pcb_by_cid */
2741
2742/*
2743 * Set timeout on socket
2744 */
2745
2746static void
2747ng_btsocket_l2cap_timeout(ng_btsocket_l2cap_pcb_p pcb)
2748{
e85b99ab 2749 KKASSERT(lockowned(&pcb->pcb_lock) != 0);
b06ebda0
MD
2750
2751 if (!(pcb->flags & NG_BTSOCKET_L2CAP_TIMO)) {
2752 pcb->flags |= NG_BTSOCKET_L2CAP_TIMO;
e85b99ab
SW
2753 callout_reset(&pcb->timo, bluetooth_l2cap_ertx_timeout(),
2754 ng_btsocket_l2cap_process_timeout, pcb);
b06ebda0
MD
2755 } else
2756 KASSERT(0,
2757("%s: Duplicated socket timeout?!\n", __func__));
2758} /* ng_btsocket_l2cap_timeout */
2759
2760/*
2761 * Unset timeout on socket
2762 */
2763
2764static void
2765ng_btsocket_l2cap_untimeout(ng_btsocket_l2cap_pcb_p pcb)
2766{
e85b99ab 2767 KKASSERT(lockowned(&pcb->pcb_lock) != 0);
b06ebda0
MD
2768
2769 if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO) {
e85b99ab 2770 callout_stop(&pcb->timo);
b06ebda0
MD
2771 pcb->flags &= ~NG_BTSOCKET_L2CAP_TIMO;
2772 } else
2773 KASSERT(0,
2774("%s: No socket timeout?!\n", __func__));
2775} /* ng_btsocket_l2cap_untimeout */
2776
2777/*
2778 * Process timeout on socket
2779 */
2780
2781static void
2782ng_btsocket_l2cap_process_timeout(void *xpcb)
2783{
2784 ng_btsocket_l2cap_pcb_p pcb = (ng_btsocket_l2cap_pcb_p) xpcb;
2785
e85b99ab 2786 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
b06ebda0
MD
2787
2788 pcb->flags &= ~NG_BTSOCKET_L2CAP_TIMO;
2789 pcb->so->so_error = ETIMEDOUT;
2790
2791 switch (pcb->state) {
2792 case NG_BTSOCKET_L2CAP_CONNECTING:
2793 case NG_BTSOCKET_L2CAP_CONFIGURING:
2794 /* Send disconnect request with "zero" token */
2795 if (pcb->cid != 0)
2796 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
2797
2798 /* ... and close the socket */
2799 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
2800 soisdisconnected(pcb->so);
2801 break;
2802
2803 case NG_BTSOCKET_L2CAP_OPEN:
2804 /* Send timeout - drop packet and wakeup sender */
e85b99ab 2805 sbdroprecord(&pcb->so->so_snd.sb);
b06ebda0
MD
2806 sowwakeup(pcb->so);
2807 break;
2808
2809 case NG_BTSOCKET_L2CAP_DISCONNECTING:
2810 /* Disconnect timeout - disconnect the socket anyway */
2811 pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
2812 soisdisconnected(pcb->so);
2813 break;
2814
2815 default:
2816 NG_BTSOCKET_L2CAP_ERR(
2817"%s: Invalid socket state=%d\n", __func__, pcb->state);
2818 break;
2819 }
2820
e85b99ab 2821 lockmgr(&pcb->pcb_lock, LK_RELEASE);
b06ebda0
MD
2822} /* ng_btsocket_l2cap_process_timeout */
2823
2824/*
2825 * Translate HCI/L2CAP error code into "errno" code
2826 * XXX Note: Some L2CAP and HCI error codes have the same value, but
2827 * different meaning
2828 */
2829
2830static int
2831ng_btsocket_l2cap_result2errno(int result)
2832{
2833 switch (result) {
2834 case 0x00: /* No error */
2835 return (0);
2836
2837 case 0x01: /* Unknown HCI command */
2838 return (ENODEV);
2839
2840 case 0x02: /* No connection */
2841 return (ENOTCONN);
2842
2843 case 0x03: /* Hardware failure */
2844 return (EIO);
2845
2846 case 0x04: /* Page timeout */
2847 return (EHOSTDOWN);
2848
2849 case 0x05: /* Authentication failure */
2850 case 0x06: /* Key missing */
2851 case 0x18: /* Pairing not allowed */
2852 case 0x21: /* Role change not allowed */
2853 case 0x24: /* LMP PSU not allowed */
2854 case 0x25: /* Encryption mode not acceptable */
2855 case 0x26: /* Unit key used */
2856 return (EACCES);
2857
2858 case 0x07: /* Memory full */
2859 return (ENOMEM);
2860
2861 case 0x08: /* Connection timeout */
2862 case 0x10: /* Host timeout */
2863 case 0x22: /* LMP response timeout */
2864 case 0xee: /* HCI timeout */
2865 case 0xeeee: /* L2CAP timeout */
2866 return (ETIMEDOUT);
2867
2868 case 0x09: /* Max number of connections */
2869 case 0x0a: /* Max number of SCO connections to a unit */
2870 return (EMLINK);
2871
2872 case 0x0b: /* ACL connection already exists */
2873 return (EEXIST);
2874
2875 case 0x0c: /* Command disallowed */
2876 return (EBUSY);
2877
2878 case 0x0d: /* Host rejected due to limited resources */
2879 case 0x0e: /* Host rejected due to securiity reasons */
2880 case 0x0f: /* Host rejected due to remote unit is a personal unit */
2881 case 0x1b: /* SCO offset rejected */
2882 case 0x1c: /* SCO interval rejected */
2883 case 0x1d: /* SCO air mode rejected */
2884 return (ECONNREFUSED);
2885
2886 case 0x11: /* Unsupported feature or parameter value */
2887 case 0x19: /* Unknown LMP PDU */
2888 case 0x1a: /* Unsupported remote feature */
2889 case 0x20: /* Unsupported LMP parameter value */
2890 case 0x27: /* QoS is not supported */
2891 case 0x29: /* Paring with unit key not supported */
2892 return (EOPNOTSUPP);
2893
2894 case 0x12: /* Invalid HCI command parameter */
2895 case 0x1e: /* Invalid LMP parameters */
2896 return (EINVAL);
2897
2898 case 0x13: /* Other end terminated connection: User ended connection */
2899 case 0x14: /* Other end terminated connection: Low resources */
2900 case 0x15: /* Other end terminated connection: About to power off */
2901 return (ECONNRESET);
2902
2903 case 0x16: /* Connection terminated by local host */
2904 return (ECONNABORTED);
2905
2906#if 0 /* XXX not yet */
2907 case 0x17: /* Repeated attempts */
2908 case 0x1f: /* Unspecified error */
2909 case 0x23: /* LMP error transaction collision */
2910 case 0x28: /* Instant passed */
2911#endif
2912 }
2913
2914 return (ENOSYS);
2915} /* ng_btsocket_l2cap_result2errno */
2916