6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
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 $
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bitstring.h>
37 #include <sys/domain.h>
38 #include <sys/endian.h>
39 #include <sys/errno.h>
40 #include <sys/filedesc.h>
41 #include <sys/ioccom.h>
42 #include <sys/kernel.h>
44 #include <sys/malloc.h>
46 #include <sys/mutex.h>
47 #include <sys/protosw.h>
48 #include <sys/queue.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/sysctl.h>
52 #include <sys/taskqueue.h>
53 #include <netgraph/ng_message.h>
54 #include <netgraph/netgraph.h>
55 #include <netgraph/bluetooth/include/ng_bluetooth.h>
56 #include <netgraph/bluetooth/include/ng_hci.h>
57 #include <netgraph/bluetooth/include/ng_l2cap.h>
58 #include <netgraph/bluetooth/include/ng_btsocket.h>
59 #include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
62 #ifdef NG_SEPARATE_MALLOC
63 MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP
, "netgraph_btsocks_l2cap",
64 "Netgraph Bluetooth L2CAP sockets");
66 #define M_NETGRAPH_BTSOCKET_L2CAP M_NETGRAPH
67 #endif /* NG_SEPARATE_MALLOC */
69 /* Netgraph node methods */
70 static ng_constructor_t ng_btsocket_l2cap_node_constructor
;
71 static ng_rcvmsg_t ng_btsocket_l2cap_node_rcvmsg
;
72 static ng_shutdown_t ng_btsocket_l2cap_node_shutdown
;
73 static ng_newhook_t ng_btsocket_l2cap_node_newhook
;
74 static ng_connect_t ng_btsocket_l2cap_node_connect
;
75 static ng_rcvdata_t ng_btsocket_l2cap_node_rcvdata
;
76 static ng_disconnect_t ng_btsocket_l2cap_node_disconnect
;
78 static void ng_btsocket_l2cap_input (void *, int);
79 static void ng_btsocket_l2cap_rtclean (void *, int);
81 /* Netgraph type descriptor */
82 static struct ng_type typestruct
= {
83 .version
= NG_ABI_VERSION
,
84 .name
= NG_BTSOCKET_L2CAP_NODE_TYPE
,
85 .constructor
= ng_btsocket_l2cap_node_constructor
,
86 .rcvmsg
= ng_btsocket_l2cap_node_rcvmsg
,
87 .shutdown
= ng_btsocket_l2cap_node_shutdown
,
88 .newhook
= ng_btsocket_l2cap_node_newhook
,
89 .connect
= ng_btsocket_l2cap_node_connect
,
90 .rcvdata
= ng_btsocket_l2cap_node_rcvdata
,
91 .disconnect
= ng_btsocket_l2cap_node_disconnect
,
96 static u_int32_t ng_btsocket_l2cap_debug_level
;
97 static node_p ng_btsocket_l2cap_node
;
98 static struct ng_bt_itemq ng_btsocket_l2cap_queue
;
99 static struct mtx ng_btsocket_l2cap_queue_mtx
;
100 static struct task ng_btsocket_l2cap_queue_task
;
101 static LIST_HEAD(, ng_btsocket_l2cap_pcb
) ng_btsocket_l2cap_sockets
;
102 static struct mtx ng_btsocket_l2cap_sockets_mtx
;
103 static LIST_HEAD(, ng_btsocket_l2cap_rtentry
) ng_btsocket_l2cap_rt
;
104 static struct mtx ng_btsocket_l2cap_rt_mtx
;
105 static struct task ng_btsocket_l2cap_rt_task
;
108 SYSCTL_DECL(_net_bluetooth_l2cap_sockets
);
109 SYSCTL_NODE(_net_bluetooth_l2cap_sockets
, OID_AUTO
, seq
, CTLFLAG_RW
,
110 0, "Bluetooth SEQPACKET L2CAP sockets family");
111 SYSCTL_INT(_net_bluetooth_l2cap_sockets_seq
, OID_AUTO
, debug_level
,
113 &ng_btsocket_l2cap_debug_level
, NG_BTSOCKET_WARN_LEVEL
,
114 "Bluetooth SEQPACKET L2CAP sockets debug level");
115 SYSCTL_INT(_net_bluetooth_l2cap_sockets_seq
, OID_AUTO
, queue_len
,
117 &ng_btsocket_l2cap_queue
.len
, 0,
118 "Bluetooth SEQPACKET L2CAP sockets input queue length");
119 SYSCTL_INT(_net_bluetooth_l2cap_sockets_seq
, OID_AUTO
, queue_maxlen
,
121 &ng_btsocket_l2cap_queue
.maxlen
, 0,
122 "Bluetooth SEQPACKET L2CAP sockets input queue max. length");
123 SYSCTL_INT(_net_bluetooth_l2cap_sockets_seq
, OID_AUTO
, queue_drops
,
125 &ng_btsocket_l2cap_queue
.drops
, 0,
126 "Bluetooth SEQPACKET L2CAP sockets input queue drops");
129 #define NG_BTSOCKET_L2CAP_INFO \
130 if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_INFO_LEVEL) \
133 #define NG_BTSOCKET_L2CAP_WARN \
134 if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_WARN_LEVEL) \
137 #define NG_BTSOCKET_L2CAP_ERR \
138 if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_ERR_LEVEL) \
141 #define NG_BTSOCKET_L2CAP_ALERT \
142 if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_ALERT_LEVEL) \
146 * Netgraph message processing routines
149 static int ng_btsocket_l2cap_process_l2ca_con_req_rsp
150 (struct ng_mesg
*, ng_btsocket_l2cap_rtentry_p
);
151 static int ng_btsocket_l2cap_process_l2ca_con_rsp_rsp
152 (struct ng_mesg
*, ng_btsocket_l2cap_rtentry_p
);
153 static int ng_btsocket_l2cap_process_l2ca_con_ind
154 (struct ng_mesg
*, ng_btsocket_l2cap_rtentry_p
);
156 static int ng_btsocket_l2cap_process_l2ca_cfg_req_rsp
157 (struct ng_mesg
*, ng_btsocket_l2cap_rtentry_p
);
158 static int ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp
159 (struct ng_mesg
*, ng_btsocket_l2cap_rtentry_p
);
160 static int ng_btsocket_l2cap_process_l2ca_cfg_ind
161 (struct ng_mesg
*, ng_btsocket_l2cap_rtentry_p
);
163 static int ng_btsocket_l2cap_process_l2ca_discon_rsp
164 (struct ng_mesg
*, ng_btsocket_l2cap_rtentry_p
);
165 static int ng_btsocket_l2cap_process_l2ca_discon_ind
166 (struct ng_mesg
*, ng_btsocket_l2cap_rtentry_p
);
168 static int ng_btsocket_l2cap_process_l2ca_write_rsp
169 (struct ng_mesg
*, ng_btsocket_l2cap_rtentry_p
);
172 * Send L2CA_xxx messages to the lower layer
175 static int ng_btsocket_l2cap_send_l2ca_con_req
176 (ng_btsocket_l2cap_pcb_p
);
177 static int ng_btsocket_l2cap_send_l2ca_con_rsp_req
178 (u_int32_t
, ng_btsocket_l2cap_rtentry_p
, bdaddr_p
, int, int, int);
179 static int ng_btsocket_l2cap_send_l2ca_cfg_req
180 (ng_btsocket_l2cap_pcb_p
);
181 static int ng_btsocket_l2cap_send_l2ca_cfg_rsp
182 (ng_btsocket_l2cap_pcb_p
);
183 static int ng_btsocket_l2cap_send_l2ca_discon_req
184 (u_int32_t
, ng_btsocket_l2cap_pcb_p
);
186 static int ng_btsocket_l2cap_send2
187 (ng_btsocket_l2cap_pcb_p
);
190 * Timeout processing routines
193 static void ng_btsocket_l2cap_timeout (ng_btsocket_l2cap_pcb_p
);
194 static void ng_btsocket_l2cap_untimeout (ng_btsocket_l2cap_pcb_p
);
195 static void ng_btsocket_l2cap_process_timeout (void *);
201 static ng_btsocket_l2cap_pcb_p
ng_btsocket_l2cap_pcb_by_addr(bdaddr_p
, int);
202 static ng_btsocket_l2cap_pcb_p
ng_btsocket_l2cap_pcb_by_token(u_int32_t
);
203 static ng_btsocket_l2cap_pcb_p
ng_btsocket_l2cap_pcb_by_cid (bdaddr_p
, int);
204 static int ng_btsocket_l2cap_result2errno(int);
206 #define ng_btsocket_l2cap_wakeup_input_task() \
207 taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_l2cap_queue_task)
209 #define ng_btsocket_l2cap_wakeup_route_task() \
210 taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_l2cap_rt_task)
212 /*****************************************************************************
213 *****************************************************************************
214 ** Netgraph node interface
215 *****************************************************************************
216 *****************************************************************************/
219 * Netgraph node constructor. Do not allow to create node of this type.
223 ng_btsocket_l2cap_node_constructor(node_p node
)
226 } /* ng_btsocket_l2cap_node_constructor */
229 * Do local shutdown processing. Let old node go and create new fresh one.
233 ng_btsocket_l2cap_node_shutdown(node_p node
)
239 /* Create new node */
240 error
= ng_make_node_common(&typestruct
, &ng_btsocket_l2cap_node
);
242 NG_BTSOCKET_L2CAP_ALERT(
243 "%s: Could not create Netgraph node, error=%d\n", __func__
, error
);
245 ng_btsocket_l2cap_node
= NULL
;
250 error
= ng_name_node(ng_btsocket_l2cap_node
,
251 NG_BTSOCKET_L2CAP_NODE_TYPE
);
253 NG_BTSOCKET_L2CAP_ALERT(
254 "%s: Could not name Netgraph node, error=%d\n", __func__
, error
);
256 NG_NODE_UNREF(ng_btsocket_l2cap_node
);
257 ng_btsocket_l2cap_node
= NULL
;
263 } /* ng_btsocket_l2cap_node_shutdown */
266 * We allow any hook to be connected to the node.
270 ng_btsocket_l2cap_node_newhook(node_p node
, hook_p hook
, char const *name
)
273 } /* ng_btsocket_l2cap_node_newhook */
276 * Just say "YEP, that's OK by me!"
280 ng_btsocket_l2cap_node_connect(hook_p hook
)
282 NG_HOOK_SET_PRIVATE(hook
, NULL
);
283 NG_HOOK_REF(hook
); /* Keep extra reference to the hook */
286 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook
));
287 NG_HOOK_FORCE_QUEUE(hook
);
291 } /* ng_btsocket_l2cap_node_connect */
294 * Hook disconnection. Schedule route cleanup task
298 ng_btsocket_l2cap_node_disconnect(hook_p hook
)
301 * If hook has private information than we must have this hook in
302 * the routing table and must schedule cleaning for the routing table.
303 * Otherwise hook was connected but we never got "hook_info" message,
304 * so we have never added this hook to the routing table and it save
308 if (NG_HOOK_PRIVATE(hook
) != NULL
)
309 return (ng_btsocket_l2cap_wakeup_route_task());
311 NG_HOOK_UNREF(hook
); /* Remove extra reference */
314 } /* ng_btsocket_l2cap_node_disconnect */
317 * Process incoming messages
321 ng_btsocket_l2cap_node_rcvmsg(node_p node
, item_p item
, hook_p hook
)
323 struct ng_mesg
*msg
= NGI_MSG(item
); /* item still has message */
326 if (msg
!= NULL
&& msg
->header
.typecookie
== NGM_L2CAP_COOKIE
) {
327 mtx_lock(&ng_btsocket_l2cap_queue_mtx
);
328 if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_queue
)) {
329 NG_BTSOCKET_L2CAP_ERR(
330 "%s: Input queue is full (msg)\n", __func__
);
332 NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_queue
);
338 NGI_SET_HOOK(item
, hook
);
341 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_queue
, item
);
342 error
= ng_btsocket_l2cap_wakeup_input_task();
344 mtx_unlock(&ng_btsocket_l2cap_queue_mtx
);
351 } /* ng_btsocket_l2cap_node_rcvmsg */
354 * Receive data on a hook
358 ng_btsocket_l2cap_node_rcvdata(hook_p hook
, item_p item
)
362 mtx_lock(&ng_btsocket_l2cap_queue_mtx
);
363 if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_queue
)) {
364 NG_BTSOCKET_L2CAP_ERR(
365 "%s: Input queue is full (data)\n", __func__
);
367 NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_queue
);
372 NGI_SET_HOOK(item
, hook
);
374 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_queue
, item
);
375 error
= ng_btsocket_l2cap_wakeup_input_task();
377 mtx_unlock(&ng_btsocket_l2cap_queue_mtx
);
380 } /* ng_btsocket_l2cap_node_rcvdata */
383 * Process L2CA_Connect respose. Socket layer must have initiated connection,
384 * so we have to have a socket associated with message token.
388 ng_btsocket_l2cap_process_l2ca_con_req_rsp(struct ng_mesg
*msg
,
389 ng_btsocket_l2cap_rtentry_p rt
)
391 ng_l2cap_l2ca_con_op
*op
= NULL
;
392 ng_btsocket_l2cap_pcb_t
*pcb
= NULL
;
395 if (msg
->header
.arglen
!= sizeof(*op
))
398 op
= (ng_l2cap_l2ca_con_op
*)(msg
->data
);
400 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
402 /* Look for the socket with the token */
403 pcb
= ng_btsocket_l2cap_pcb_by_token(msg
->header
.token
);
405 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
409 mtx_lock(&pcb
->pcb_mtx
);
411 NG_BTSOCKET_L2CAP_INFO(
412 "%s: Got L2CA_Connect response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
413 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, status=%d, " \
414 "state=%d\n", __func__
, msg
->header
.token
,
415 pcb
->src
.b
[5], pcb
->src
.b
[4], pcb
->src
.b
[3],
416 pcb
->src
.b
[2], pcb
->src
.b
[1], pcb
->src
.b
[0],
417 pcb
->dst
.b
[5], pcb
->dst
.b
[4], pcb
->dst
.b
[3],
418 pcb
->dst
.b
[2], pcb
->dst
.b
[1], pcb
->dst
.b
[0],
419 pcb
->psm
, op
->lcid
, op
->result
, op
->status
,
422 if (pcb
->state
!= NG_BTSOCKET_L2CAP_CONNECTING
) {
423 mtx_unlock(&pcb
->pcb_mtx
);
424 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
429 ng_btsocket_l2cap_untimeout(pcb
);
431 if (op
->result
== NG_L2CAP_PENDING
) {
432 ng_btsocket_l2cap_timeout(pcb
);
433 mtx_unlock(&pcb
->pcb_mtx
);
434 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
439 if (op
->result
== NG_L2CAP_SUCCESS
) {
441 * Channel is now open, so update local channel ID and
442 * start configuration process. Source and destination
443 * addresses as well as route must be already set.
448 error
= ng_btsocket_l2cap_send_l2ca_cfg_req(pcb
);
450 /* Send disconnect request with "zero" token */
451 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb
);
453 /* ... and close the socket */
454 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
455 soisdisconnected(pcb
->so
);
457 pcb
->cfg_state
= NG_BTSOCKET_L2CAP_CFG_IN_SENT
;
458 pcb
->state
= NG_BTSOCKET_L2CAP_CONFIGURING
;
460 ng_btsocket_l2cap_timeout(pcb
);
464 * We have failed to open connection, so convert result
465 * code to "errno" code and disconnect the socket. Channel
466 * already has been closed.
469 pcb
->so
->so_error
= ng_btsocket_l2cap_result2errno(op
->result
);
470 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
471 soisdisconnected(pcb
->so
);
474 mtx_unlock(&pcb
->pcb_mtx
);
475 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
478 } /* ng_btsocket_l2cap_process_l2ca_con_req_rsp */
481 * Process L2CA_ConnectRsp response
485 ng_btsocket_l2cap_process_l2ca_con_rsp_rsp(struct ng_mesg
*msg
,
486 ng_btsocket_l2cap_rtentry_p rt
)
488 ng_l2cap_l2ca_con_rsp_op
*op
= NULL
;
489 ng_btsocket_l2cap_pcb_t
*pcb
= NULL
;
491 if (msg
->header
.arglen
!= sizeof(*op
))
494 op
= (ng_l2cap_l2ca_con_rsp_op
*)(msg
->data
);
496 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
498 /* Look for the socket with the token */
499 pcb
= ng_btsocket_l2cap_pcb_by_token(msg
->header
.token
);
501 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
505 mtx_lock(&pcb
->pcb_mtx
);
507 NG_BTSOCKET_L2CAP_INFO(
508 "%s: Got L2CA_ConnectRsp response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
509 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d\n",
510 __func__
, msg
->header
.token
,
511 pcb
->src
.b
[5], pcb
->src
.b
[4], pcb
->src
.b
[3],
512 pcb
->src
.b
[2], pcb
->src
.b
[1], pcb
->src
.b
[0],
513 pcb
->dst
.b
[5], pcb
->dst
.b
[4], pcb
->dst
.b
[3],
514 pcb
->dst
.b
[2], pcb
->dst
.b
[1], pcb
->dst
.b
[0],
515 pcb
->psm
, pcb
->cid
, op
->result
, pcb
->state
);
517 if (pcb
->state
!= NG_BTSOCKET_L2CAP_CONNECTING
) {
518 mtx_unlock(&pcb
->pcb_mtx
);
519 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
524 ng_btsocket_l2cap_untimeout(pcb
);
526 /* Check the result and disconnect the socket on failure */
527 if (op
->result
!= NG_L2CAP_SUCCESS
) {
528 /* Close the socket - channel already closed */
529 pcb
->so
->so_error
= ng_btsocket_l2cap_result2errno(op
->result
);
530 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
531 soisdisconnected(pcb
->so
);
533 /* Move to CONFIGURING state and wait for CONFIG_IND */
535 pcb
->state
= NG_BTSOCKET_L2CAP_CONFIGURING
;
536 ng_btsocket_l2cap_timeout(pcb
);
539 mtx_unlock(&pcb
->pcb_mtx
);
540 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
543 } /* ng_btsocket_process_l2ca_con_rsp_rsp */
546 * Process L2CA_Connect indicator. Find socket that listens on address
547 * and PSM. Find exact or closest match. Create new socket and initiate
552 ng_btsocket_l2cap_process_l2ca_con_ind(struct ng_mesg
*msg
,
553 ng_btsocket_l2cap_rtentry_p rt
)
555 ng_l2cap_l2ca_con_ind_ip
*ip
= NULL
;
556 ng_btsocket_l2cap_pcb_t
*pcb
= NULL
, *pcb1
= NULL
;
559 u_int16_t result
= 0;
561 if (msg
->header
.arglen
!= sizeof(*ip
))
564 ip
= (ng_l2cap_l2ca_con_ind_ip
*)(msg
->data
);
566 NG_BTSOCKET_L2CAP_INFO(
567 "%s: Got L2CA_Connect indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
568 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, ident=%d\n",
570 rt
->src
.b
[5], rt
->src
.b
[4], rt
->src
.b
[3],
571 rt
->src
.b
[2], rt
->src
.b
[1], rt
->src
.b
[0],
572 ip
->bdaddr
.b
[5], ip
->bdaddr
.b
[4], ip
->bdaddr
.b
[3],
573 ip
->bdaddr
.b
[2], ip
->bdaddr
.b
[1], ip
->bdaddr
.b
[0],
574 ip
->psm
, ip
->lcid
, ip
->ident
);
576 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
578 pcb
= ng_btsocket_l2cap_pcb_by_addr(&rt
->src
, ip
->psm
);
580 struct socket
*so1
= NULL
;
582 mtx_lock(&pcb
->pcb_mtx
);
585 * First check the pending connections queue and if we have
586 * space then create new socket and set proper source address.
589 if (pcb
->so
->so_qlen
<= pcb
->so
->so_qlimit
)
590 so1
= sonewconn(pcb
->so
, 0);
593 result
= NG_L2CAP_NO_RESOURCES
;
598 * If we got here than we have created new socket. So complete
599 * connection. If we we listening on specific address then copy
600 * source address from listening socket, otherwise copy source
601 * address from hook's routing information.
604 pcb1
= so2l2cap_pcb(so1
);
605 KASSERT((pcb1
!= NULL
),
606 ("%s: pcb1 == NULL\n", __func__
));
608 mtx_lock(&pcb1
->pcb_mtx
);
610 if (bcmp(&pcb
->src
, NG_HCI_BDADDR_ANY
, sizeof(pcb
->src
)) != 0)
611 bcopy(&pcb
->src
, &pcb1
->src
, sizeof(pcb1
->src
));
613 bcopy(&rt
->src
, &pcb1
->src
, sizeof(pcb1
->src
));
615 pcb1
->flags
&= ~NG_BTSOCKET_L2CAP_CLIENT
;
617 bcopy(&ip
->bdaddr
, &pcb1
->dst
, sizeof(pcb1
->dst
));
619 pcb1
->cid
= ip
->lcid
;
622 /* Copy socket settings */
623 pcb1
->imtu
= pcb
->imtu
;
624 bcopy(&pcb
->oflow
, &pcb1
->oflow
, sizeof(pcb1
->oflow
));
625 pcb1
->flush_timo
= pcb
->flush_timo
;
629 /* Nobody listens on requested BDADDR/PSM */
630 result
= NG_L2CAP_PSM_NOT_SUPPORTED
;
633 error
= ng_btsocket_l2cap_send_l2ca_con_rsp_req(token
, rt
,
634 &ip
->bdaddr
, ip
->ident
, ip
->lcid
, result
);
637 pcb1
->so
->so_error
= error
;
638 pcb1
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
639 soisdisconnected(pcb1
->so
);
641 pcb1
->state
= NG_BTSOCKET_L2CAP_CONNECTING
;
642 soisconnecting(pcb1
->so
);
644 ng_btsocket_l2cap_timeout(pcb1
);
647 mtx_unlock(&pcb1
->pcb_mtx
);
651 mtx_unlock(&pcb
->pcb_mtx
);
653 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
656 } /* ng_btsocket_l2cap_process_l2ca_con_ind */
659 * Process L2CA_Config response
663 ng_btsocket_l2cap_process_l2ca_cfg_req_rsp(struct ng_mesg
*msg
,
664 ng_btsocket_l2cap_rtentry_p rt
)
666 ng_l2cap_l2ca_cfg_op
*op
= NULL
;
667 ng_btsocket_l2cap_pcb_p pcb
= NULL
;
669 if (msg
->header
.arglen
!= sizeof(*op
))
672 op
= (ng_l2cap_l2ca_cfg_op
*)(msg
->data
);
674 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
677 * Socket must have issued a Configure request, so we must have a
678 * socket that wants to be configured. Use Netgraph message token
682 pcb
= ng_btsocket_l2cap_pcb_by_token(msg
->header
.token
);
685 * XXX FIXME what to do here? We could not find a
686 * socket with requested token. We even can not send
687 * Disconnect, because we do not know channel ID
690 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
694 mtx_lock(&pcb
->pcb_mtx
);
696 NG_BTSOCKET_L2CAP_INFO(
697 "%s: Got L2CA_Config response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
698 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d, " \
700 __func__
, msg
->header
.token
,
701 pcb
->src
.b
[5], pcb
->src
.b
[4], pcb
->src
.b
[3],
702 pcb
->src
.b
[2], pcb
->src
.b
[1], pcb
->src
.b
[0],
703 pcb
->dst
.b
[5], pcb
->dst
.b
[4], pcb
->dst
.b
[3],
704 pcb
->dst
.b
[2], pcb
->dst
.b
[1], pcb
->dst
.b
[0],
705 pcb
->psm
, pcb
->cid
, op
->result
, pcb
->state
, pcb
->cfg_state
);
707 if (pcb
->state
!= NG_BTSOCKET_L2CAP_CONFIGURING
) {
708 mtx_unlock(&pcb
->pcb_mtx
);
709 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
714 if (op
->result
== NG_L2CAP_SUCCESS
) {
716 * XXX FIXME Actually set flush and link timeout.
717 * Set QoS here if required. Resolve conficts (flush_timo).
718 * Save incoming MTU (peer's outgoing MTU) and outgoing flow
722 pcb
->imtu
= op
->imtu
;
723 bcopy(&op
->oflow
, &pcb
->oflow
, sizeof(pcb
->oflow
));
724 pcb
->flush_timo
= op
->flush_timo
;
727 * We have configured incoming side, so record it and check
728 * if configuration is complete. If complete then mark socket
729 * as connected, otherwise wait for the peer.
732 pcb
->cfg_state
&= ~NG_BTSOCKET_L2CAP_CFG_IN_SENT
;
733 pcb
->cfg_state
|= NG_BTSOCKET_L2CAP_CFG_IN
;
735 if (pcb
->cfg_state
== NG_BTSOCKET_L2CAP_CFG_BOTH
) {
736 /* Configuration complete - mark socket as open */
737 ng_btsocket_l2cap_untimeout(pcb
);
738 pcb
->state
= NG_BTSOCKET_L2CAP_OPEN
;
739 soisconnected(pcb
->so
);
743 * Something went wrong. Could be unacceptable parameters,
744 * reject or unknown option. That's too bad, but we will
745 * not negotiate. Send Disconnect and close the channel.
748 ng_btsocket_l2cap_untimeout(pcb
);
750 switch (op
->result
) {
751 case NG_L2CAP_UNACCEPTABLE_PARAMS
:
752 case NG_L2CAP_UNKNOWN_OPTION
:
753 pcb
->so
->so_error
= EINVAL
;
757 pcb
->so
->so_error
= ECONNRESET
;
761 /* Send disconnect with "zero" token */
762 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb
);
764 /* ... and close the socket */
765 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
766 soisdisconnected(pcb
->so
);
769 mtx_unlock(&pcb
->pcb_mtx
);
770 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
773 } /* ng_btsocket_l2cap_process_l2ca_cfg_req_rsp */
776 * Process L2CA_ConfigRsp response
780 ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp(struct ng_mesg
*msg
,
781 ng_btsocket_l2cap_rtentry_p rt
)
783 ng_l2cap_l2ca_cfg_rsp_op
*op
= NULL
;
784 ng_btsocket_l2cap_pcb_t
*pcb
= NULL
;
787 if (msg
->header
.arglen
!= sizeof(*op
))
790 op
= (ng_l2cap_l2ca_cfg_rsp_op
*)(msg
->data
);
792 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
794 /* Look for the socket with the token */
795 pcb
= ng_btsocket_l2cap_pcb_by_token(msg
->header
.token
);
797 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
801 mtx_lock(&pcb
->pcb_mtx
);
803 NG_BTSOCKET_L2CAP_INFO(
804 "%s: Got L2CA_ConfigRsp response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
805 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d, " \
807 __func__
, msg
->header
.token
,
808 pcb
->src
.b
[5], pcb
->src
.b
[4], pcb
->src
.b
[3],
809 pcb
->src
.b
[2], pcb
->src
.b
[1], pcb
->src
.b
[0],
810 pcb
->dst
.b
[5], pcb
->dst
.b
[4], pcb
->dst
.b
[3],
811 pcb
->dst
.b
[2], pcb
->dst
.b
[1], pcb
->dst
.b
[0],
812 pcb
->psm
, pcb
->cid
, op
->result
, pcb
->state
, pcb
->cfg_state
);
814 if (pcb
->state
!= NG_BTSOCKET_L2CAP_CONFIGURING
) {
815 mtx_unlock(&pcb
->pcb_mtx
);
816 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
821 /* Check the result and disconnect socket of failure */
822 if (op
->result
!= NG_L2CAP_SUCCESS
)
826 * Now we done with remote side configuration. Configure local
827 * side if we have not done it yet.
830 pcb
->cfg_state
&= ~NG_BTSOCKET_L2CAP_CFG_OUT_SENT
;
831 pcb
->cfg_state
|= NG_BTSOCKET_L2CAP_CFG_OUT
;
833 if (pcb
->cfg_state
== NG_BTSOCKET_L2CAP_CFG_BOTH
) {
834 /* Configuration complete - mask socket as open */
835 ng_btsocket_l2cap_untimeout(pcb
);
836 pcb
->state
= NG_BTSOCKET_L2CAP_OPEN
;
837 soisconnected(pcb
->so
);
839 if (!(pcb
->cfg_state
& NG_BTSOCKET_L2CAP_CFG_IN_SENT
)) {
840 /* Send L2CA_Config request - incoming path */
841 error
= ng_btsocket_l2cap_send_l2ca_cfg_req(pcb
);
845 pcb
->cfg_state
|= NG_BTSOCKET_L2CAP_CFG_IN_SENT
;
849 mtx_unlock(&pcb
->pcb_mtx
);
850 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
855 ng_btsocket_l2cap_untimeout(pcb
);
857 /* Send disconnect with "zero" token */
858 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb
);
860 /* ... and close the socket */
861 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
862 soisdisconnected(pcb
->so
);
864 mtx_unlock(&pcb
->pcb_mtx
);
865 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
868 } /* ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp */
871 * Process L2CA_Config indicator
875 ng_btsocket_l2cap_process_l2ca_cfg_ind(struct ng_mesg
*msg
,
876 ng_btsocket_l2cap_rtentry_p rt
)
878 ng_l2cap_l2ca_cfg_ind_ip
*ip
= NULL
;
879 ng_btsocket_l2cap_pcb_t
*pcb
= NULL
;
882 if (msg
->header
.arglen
!= sizeof(*ip
))
885 ip
= (ng_l2cap_l2ca_cfg_ind_ip
*)(msg
->data
);
887 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
889 /* Check for the open socket that has given channel ID */
890 pcb
= ng_btsocket_l2cap_pcb_by_cid(&rt
->src
, ip
->lcid
);
892 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
896 mtx_lock(&pcb
->pcb_mtx
);
898 NG_BTSOCKET_L2CAP_INFO(
899 "%s: Got L2CA_Config indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
900 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, state=%d, cfg_state=%x\n",
902 pcb
->src
.b
[5], pcb
->src
.b
[4], pcb
->src
.b
[3],
903 pcb
->src
.b
[2], pcb
->src
.b
[1], pcb
->src
.b
[0],
904 pcb
->dst
.b
[5], pcb
->dst
.b
[4], pcb
->dst
.b
[3],
905 pcb
->dst
.b
[2], pcb
->dst
.b
[1], pcb
->dst
.b
[0],
906 pcb
->psm
, pcb
->cid
, pcb
->state
, pcb
->cfg_state
);
908 /* XXX FIXME re-configuration on open socket */
909 if (pcb
->state
!= NG_BTSOCKET_L2CAP_CONFIGURING
) {
910 mtx_unlock(&pcb
->pcb_mtx
);
911 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
917 * XXX FIXME Actually set flush and link timeout. Set QoS here if
918 * required. Resolve conficts (flush_timo). Note outgoing MTU (peer's
919 * incoming MTU) and incoming flow spec.
922 pcb
->omtu
= ip
->omtu
;
923 bcopy(&ip
->iflow
, &pcb
->iflow
, sizeof(pcb
->iflow
));
924 pcb
->flush_timo
= ip
->flush_timo
;
927 * Send L2CA_Config response to our peer and check for the errors,
928 * if any send disconnect to close the channel.
931 if (!(pcb
->cfg_state
& NG_BTSOCKET_L2CAP_CFG_OUT_SENT
)) {
932 error
= ng_btsocket_l2cap_send_l2ca_cfg_rsp(pcb
);
934 ng_btsocket_l2cap_untimeout(pcb
);
936 pcb
->so
->so_error
= error
;
938 /* Send disconnect with "zero" token */
939 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb
);
941 /* ... and close the socket */
942 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
943 soisdisconnected(pcb
->so
);
945 pcb
->cfg_state
|= NG_BTSOCKET_L2CAP_CFG_OUT_SENT
;
948 mtx_unlock(&pcb
->pcb_mtx
);
949 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
952 } /* ng_btsocket_l2cap_process_l2cap_cfg_ind */
955 * Process L2CA_Disconnect response
959 ng_btsocket_l2cap_process_l2ca_discon_rsp(struct ng_mesg
*msg
,
960 ng_btsocket_l2cap_rtentry_p rt
)
962 ng_l2cap_l2ca_discon_op
*op
= NULL
;
963 ng_btsocket_l2cap_pcb_t
*pcb
= NULL
;
966 if (msg
->header
.arglen
!= sizeof(*op
))
969 op
= (ng_l2cap_l2ca_discon_op
*)(msg
->data
);
971 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
974 * Socket layer must have issued L2CA_Disconnect request, so there
975 * must be a socket that wants to be disconnected. Use Netgraph
976 * message token to find it.
979 pcb
= ng_btsocket_l2cap_pcb_by_token(msg
->header
.token
);
981 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
985 mtx_lock(&pcb
->pcb_mtx
);
987 /* XXX Close socket no matter what op->result says */
988 if (pcb
->state
!= NG_BTSOCKET_L2CAP_CLOSED
) {
989 NG_BTSOCKET_L2CAP_INFO(
990 "%s: Got L2CA_Disconnect response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
991 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d\n",
992 __func__
, msg
->header
.token
,
993 pcb
->src
.b
[5], pcb
->src
.b
[4], pcb
->src
.b
[3],
994 pcb
->src
.b
[2], pcb
->src
.b
[1], pcb
->src
.b
[0],
995 pcb
->dst
.b
[5], pcb
->dst
.b
[4], pcb
->dst
.b
[3],
996 pcb
->dst
.b
[2], pcb
->dst
.b
[1], pcb
->dst
.b
[0],
997 pcb
->psm
, pcb
->cid
, op
->result
, pcb
->state
);
999 ng_btsocket_l2cap_untimeout(pcb
);
1001 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
1002 soisdisconnected(pcb
->so
);
1005 mtx_unlock(&pcb
->pcb_mtx
);
1006 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1009 } /* ng_btsocket_l2cap_process_l2ca_discon_rsp */
1012 * Process L2CA_Disconnect indicator
1016 ng_btsocket_l2cap_process_l2ca_discon_ind(struct ng_mesg
*msg
,
1017 ng_btsocket_l2cap_rtentry_p rt
)
1019 ng_l2cap_l2ca_discon_ind_ip
*ip
= NULL
;
1020 ng_btsocket_l2cap_pcb_t
*pcb
= NULL
;
1023 if (msg
->header
.arglen
!= sizeof(*ip
))
1026 ip
= (ng_l2cap_l2ca_discon_ind_ip
*)(msg
->data
);
1028 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
1030 /* Look for the socket with given channel ID */
1031 pcb
= ng_btsocket_l2cap_pcb_by_cid(&rt
->src
, ip
->lcid
);
1033 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1038 * Channel has already been destroyed, so disconnect the socket
1039 * and be done with it. If there was any pending request we can
1040 * not do anything here anyway.
1043 mtx_lock(&pcb
->pcb_mtx
);
1045 NG_BTSOCKET_L2CAP_INFO(
1046 "%s: Got L2CA_Disconnect indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
1047 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, state=%d\n",
1049 pcb
->src
.b
[5], pcb
->src
.b
[4], pcb
->src
.b
[3],
1050 pcb
->src
.b
[2], pcb
->src
.b
[1], pcb
->src
.b
[0],
1051 pcb
->dst
.b
[5], pcb
->dst
.b
[4], pcb
->dst
.b
[3],
1052 pcb
->dst
.b
[2], pcb
->dst
.b
[1], pcb
->dst
.b
[0],
1053 pcb
->psm
, pcb
->cid
, pcb
->state
);
1055 if (pcb
->flags
& NG_BTSOCKET_L2CAP_TIMO
)
1056 ng_btsocket_l2cap_untimeout(pcb
);
1058 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
1059 soisdisconnected(pcb
->so
);
1061 mtx_unlock(&pcb
->pcb_mtx
);
1062 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1065 } /* ng_btsocket_l2cap_process_l2ca_discon_ind */
1068 * Process L2CA_Write response
1072 ng_btsocket_l2cap_process_l2ca_write_rsp(struct ng_mesg
*msg
,
1073 ng_btsocket_l2cap_rtentry_p rt
)
1075 ng_l2cap_l2ca_write_op
*op
= NULL
;
1076 ng_btsocket_l2cap_pcb_t
*pcb
= NULL
;
1079 if (msg
->header
.arglen
!= sizeof(*op
))
1082 op
= (ng_l2cap_l2ca_write_op
*)(msg
->data
);
1084 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
1086 /* Look for the socket with given token */
1087 pcb
= ng_btsocket_l2cap_pcb_by_token(msg
->header
.token
);
1089 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1093 mtx_lock(&pcb
->pcb_mtx
);
1095 NG_BTSOCKET_L2CAP_INFO(
1096 "%s: Got L2CA_Write response, src bdaddr=%x:%x:%x:%x:%x:%x, " \
1097 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, length=%d, " \
1098 "state=%d\n", __func__
,
1099 pcb
->src
.b
[5], pcb
->src
.b
[4], pcb
->src
.b
[3],
1100 pcb
->src
.b
[2], pcb
->src
.b
[1], pcb
->src
.b
[0],
1101 pcb
->dst
.b
[5], pcb
->dst
.b
[4], pcb
->dst
.b
[3],
1102 pcb
->dst
.b
[2], pcb
->dst
.b
[1], pcb
->dst
.b
[0],
1103 pcb
->psm
, pcb
->cid
, op
->result
, op
->length
,
1106 if (pcb
->state
!= NG_BTSOCKET_L2CAP_OPEN
) {
1107 mtx_unlock(&pcb
->pcb_mtx
);
1108 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1113 ng_btsocket_l2cap_untimeout(pcb
);
1116 * Check if we have more data to send
1119 sbdroprecord(&pcb
->so
->so_snd
);
1120 if (pcb
->so
->so_snd
.sb_cc
> 0) {
1121 if (ng_btsocket_l2cap_send2(pcb
) == 0)
1122 ng_btsocket_l2cap_timeout(pcb
);
1124 sbdroprecord(&pcb
->so
->so_snd
); /* XXX */
1128 * Now set the result, drop packet from the socket send queue and
1129 * ask for more (wakeup sender)
1132 pcb
->so
->so_error
= ng_btsocket_l2cap_result2errno(op
->result
);
1135 mtx_unlock(&pcb
->pcb_mtx
);
1136 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1139 } /* ng_btsocket_l2cap_process_l2ca_write_rsp */
1142 * Send L2CA_Connect request
1146 ng_btsocket_l2cap_send_l2ca_con_req(ng_btsocket_l2cap_pcb_p pcb
)
1148 struct ng_mesg
*msg
= NULL
;
1149 ng_l2cap_l2ca_con_ip
*ip
= NULL
;
1152 mtx_assert(&pcb
->pcb_mtx
, MA_OWNED
);
1154 if (pcb
->rt
== NULL
||
1155 pcb
->rt
->hook
== NULL
|| NG_HOOK_NOT_VALID(pcb
->rt
->hook
))
1158 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
, NGM_L2CAP_L2CA_CON
,
1159 sizeof(*ip
), M_NOWAIT
);
1163 msg
->header
.token
= pcb
->token
;
1165 ip
= (ng_l2cap_l2ca_con_ip
*)(msg
->data
);
1166 bcopy(&pcb
->dst
, &ip
->bdaddr
, sizeof(ip
->bdaddr
));
1169 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_node
, msg
,pcb
->rt
->hook
, 0);
1172 } /* ng_btsocket_l2cap_send_l2ca_con_req */
1175 * Send L2CA_Connect response
1179 ng_btsocket_l2cap_send_l2ca_con_rsp_req(u_int32_t token
,
1180 ng_btsocket_l2cap_rtentry_p rt
, bdaddr_p dst
, int ident
,
1181 int lcid
, int result
)
1183 struct ng_mesg
*msg
= NULL
;
1184 ng_l2cap_l2ca_con_rsp_ip
*ip
= NULL
;
1187 if (rt
== NULL
|| rt
->hook
== NULL
|| NG_HOOK_NOT_VALID(rt
->hook
))
1190 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
, NGM_L2CAP_L2CA_CON_RSP
,
1191 sizeof(*ip
), M_NOWAIT
);
1195 msg
->header
.token
= token
;
1197 ip
= (ng_l2cap_l2ca_con_rsp_ip
*)(msg
->data
);
1198 bcopy(dst
, &ip
->bdaddr
, sizeof(ip
->bdaddr
));
1201 ip
->result
= result
;
1204 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_node
, msg
, rt
->hook
, 0);
1207 } /* ng_btsocket_l2cap_send_l2ca_con_rsp_req */
1210 * Send L2CA_Config request
1214 ng_btsocket_l2cap_send_l2ca_cfg_req(ng_btsocket_l2cap_pcb_p pcb
)
1216 struct ng_mesg
*msg
= NULL
;
1217 ng_l2cap_l2ca_cfg_ip
*ip
= NULL
;
1220 mtx_assert(&pcb
->pcb_mtx
, MA_OWNED
);
1222 if (pcb
->rt
== NULL
||
1223 pcb
->rt
->hook
== NULL
|| NG_HOOK_NOT_VALID(pcb
->rt
->hook
))
1226 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
, NGM_L2CAP_L2CA_CFG
,
1227 sizeof(*ip
), M_NOWAIT
);
1231 msg
->header
.token
= pcb
->token
;
1233 ip
= (ng_l2cap_l2ca_cfg_ip
*)(msg
->data
);
1234 ip
->lcid
= pcb
->cid
;
1235 ip
->imtu
= pcb
->imtu
;
1236 bcopy(&pcb
->oflow
, &ip
->oflow
, sizeof(ip
->oflow
));
1237 ip
->flush_timo
= pcb
->flush_timo
;
1238 ip
->link_timo
= pcb
->link_timo
;
1240 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_node
, msg
,pcb
->rt
->hook
, 0);
1243 } /* ng_btsocket_l2cap_send_l2ca_cfg_req */
1246 * Send L2CA_Config response
1250 ng_btsocket_l2cap_send_l2ca_cfg_rsp(ng_btsocket_l2cap_pcb_p pcb
)
1252 struct ng_mesg
*msg
= NULL
;
1253 ng_l2cap_l2ca_cfg_rsp_ip
*ip
= NULL
;
1256 mtx_assert(&pcb
->pcb_mtx
, MA_OWNED
);
1258 if (pcb
->rt
== NULL
||
1259 pcb
->rt
->hook
== NULL
|| NG_HOOK_NOT_VALID(pcb
->rt
->hook
))
1262 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
, NGM_L2CAP_L2CA_CFG_RSP
,
1263 sizeof(*ip
), M_NOWAIT
);
1267 msg
->header
.token
= pcb
->token
;
1269 ip
= (ng_l2cap_l2ca_cfg_rsp_ip
*)(msg
->data
);
1270 ip
->lcid
= pcb
->cid
;
1271 ip
->omtu
= pcb
->omtu
;
1272 bcopy(&pcb
->iflow
, &ip
->iflow
, sizeof(ip
->iflow
));
1274 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_node
, msg
, pcb
->rt
->hook
, 0);
1277 } /* ng_btsocket_l2cap_send_l2ca_cfg_rsp */
1280 * Send L2CA_Disconnect request
1284 ng_btsocket_l2cap_send_l2ca_discon_req(u_int32_t token
,
1285 ng_btsocket_l2cap_pcb_p pcb
)
1287 struct ng_mesg
*msg
= NULL
;
1288 ng_l2cap_l2ca_discon_ip
*ip
= NULL
;
1291 mtx_assert(&pcb
->pcb_mtx
, MA_OWNED
);
1293 if (pcb
->rt
== NULL
||
1294 pcb
->rt
->hook
== NULL
|| NG_HOOK_NOT_VALID(pcb
->rt
->hook
))
1297 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
, NGM_L2CAP_L2CA_DISCON
,
1298 sizeof(*ip
), M_NOWAIT
);
1302 msg
->header
.token
= token
;
1304 ip
= (ng_l2cap_l2ca_discon_ip
*)(msg
->data
);
1305 ip
->lcid
= pcb
->cid
;
1307 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_node
, msg
,pcb
->rt
->hook
, 0);
1310 } /* ng_btsocket_l2cap_send_l2ca_discon_req */
1312 /*****************************************************************************
1313 *****************************************************************************
1315 *****************************************************************************
1316 *****************************************************************************/
1319 * L2CAP sockets data input routine
1323 ng_btsocket_l2cap_data_input(struct mbuf
*m
, hook_p hook
)
1325 ng_l2cap_hdr_t
*hdr
= NULL
;
1326 ng_l2cap_clt_hdr_t
*clt_hdr
= NULL
;
1327 ng_btsocket_l2cap_pcb_t
*pcb
= NULL
;
1328 ng_btsocket_l2cap_rtentry_t
*rt
= NULL
;
1331 NG_BTSOCKET_L2CAP_ALERT(
1332 "%s: Invalid source hook for L2CAP data packet\n", __func__
);
1336 rt
= (ng_btsocket_l2cap_rtentry_t
*) NG_HOOK_PRIVATE(hook
);
1338 NG_BTSOCKET_L2CAP_ALERT(
1339 "%s: Could not find out source bdaddr for L2CAP data packet\n", __func__
);
1343 /* Make sure we can access header */
1344 if (m
->m_pkthdr
.len
< sizeof(*hdr
)) {
1345 NG_BTSOCKET_L2CAP_ERR(
1346 "%s: L2CAP data packet too small, len=%d\n", __func__
, m
->m_pkthdr
.len
);
1350 if (m
->m_len
< sizeof(*hdr
)) {
1351 m
= m_pullup(m
, sizeof(*hdr
));
1356 /* Strip L2CAP packet header and verify packet length */
1357 hdr
= mtod(m
, ng_l2cap_hdr_t
*);
1358 m_adj(m
, sizeof(*hdr
));
1360 if (hdr
->length
!= m
->m_pkthdr
.len
) {
1361 NG_BTSOCKET_L2CAP_ERR(
1362 "%s: Bad L2CAP data packet length, len=%d, length=%d\n",
1363 __func__
, m
->m_pkthdr
.len
, hdr
->length
);
1368 * Now process packet. Two cases:
1370 * 1) Normal packet (cid != 2) then find connected socket and append
1371 * mbuf to the socket queue. Wakeup socket.
1373 * 2) Broadcast packet (cid == 2) then find all sockets that connected
1374 * to the given PSM and have SO_BROADCAST bit set and append mbuf
1375 * to the socket queue. Wakeup socket.
1378 NG_BTSOCKET_L2CAP_INFO(
1379 "%s: Received L2CAP data packet: src bdaddr=%x:%x:%x:%x:%x:%x, " \
1380 "dcid=%d, length=%d\n",
1382 rt
->src
.b
[5], rt
->src
.b
[4], rt
->src
.b
[3],
1383 rt
->src
.b
[2], rt
->src
.b
[1], rt
->src
.b
[0],
1384 hdr
->dcid
, hdr
->length
);
1386 if (hdr
->dcid
>= NG_L2CAP_FIRST_CID
) {
1388 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
1390 /* Normal packet: find connected socket */
1391 pcb
= ng_btsocket_l2cap_pcb_by_cid(&rt
->src
, hdr
->dcid
);
1393 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1397 mtx_lock(&pcb
->pcb_mtx
);
1399 if (pcb
->state
!= NG_BTSOCKET_L2CAP_OPEN
) {
1400 NG_BTSOCKET_L2CAP_ERR(
1401 "%s: No connected socket found, src bdaddr=%x:%x:%x:%x:%x:%x, dcid=%d, " \
1402 "state=%d\n", __func__
,
1403 rt
->src
.b
[5], rt
->src
.b
[4], rt
->src
.b
[3],
1404 rt
->src
.b
[2], rt
->src
.b
[1], rt
->src
.b
[0],
1405 hdr
->dcid
, pcb
->state
);
1407 mtx_unlock(&pcb
->pcb_mtx
);
1408 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1412 /* Check packet size against socket's incoming MTU */
1413 if (hdr
->length
> pcb
->imtu
) {
1414 NG_BTSOCKET_L2CAP_ERR(
1415 "%s: L2CAP data packet too big, src bdaddr=%x:%x:%x:%x:%x:%x, " \
1416 "dcid=%d, length=%d, imtu=%d\n",
1418 rt
->src
.b
[5], rt
->src
.b
[4], rt
->src
.b
[3],
1419 rt
->src
.b
[2], rt
->src
.b
[1], rt
->src
.b
[0],
1420 hdr
->dcid
, hdr
->length
, pcb
->imtu
);
1422 mtx_unlock(&pcb
->pcb_mtx
);
1423 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1427 /* Check if we have enough space in socket receive queue */
1428 if (m
->m_pkthdr
.len
> sbspace(&pcb
->so
->so_rcv
)) {
1431 * This is really bad. Receive queue on socket does
1432 * not have enough space for the packet. We do not
1433 * have any other choice but drop the packet. L2CAP
1434 * does not provide any flow control.
1437 NG_BTSOCKET_L2CAP_ERR(
1438 "%s: Not enough space in socket receive queue. Dropping L2CAP data packet, " \
1439 "src bdaddr=%x:%x:%x:%x:%x:%x, dcid=%d, len=%d, space=%ld\n",
1441 rt
->src
.b
[5], rt
->src
.b
[4], rt
->src
.b
[3],
1442 rt
->src
.b
[2], rt
->src
.b
[1], rt
->src
.b
[0],
1443 hdr
->dcid
, m
->m_pkthdr
.len
,
1444 sbspace(&pcb
->so
->so_rcv
));
1446 mtx_unlock(&pcb
->pcb_mtx
);
1447 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1451 /* Append packet to the socket receive queue and wakeup */
1452 sbappendrecord(&pcb
->so
->so_rcv
, m
);
1457 mtx_unlock(&pcb
->pcb_mtx
);
1458 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1459 } else if (hdr
->dcid
== NG_L2CAP_CLT_CID
) {
1460 /* Broadcast packet: give packet to all sockets */
1462 /* Check packet size against connectionless MTU */
1463 if (hdr
->length
> NG_L2CAP_MTU_DEFAULT
) {
1464 NG_BTSOCKET_L2CAP_ERR(
1465 "%s: Connectionless L2CAP data packet too big, " \
1466 "src bdaddr=%x:%x:%x:%x:%x:%x, length=%d\n",
1468 rt
->src
.b
[5], rt
->src
.b
[4], rt
->src
.b
[3],
1469 rt
->src
.b
[2], rt
->src
.b
[1], rt
->src
.b
[0],
1474 /* Make sure we can access connectionless header */
1475 if (m
->m_pkthdr
.len
< sizeof(*clt_hdr
)) {
1476 NG_BTSOCKET_L2CAP_ERR(
1477 "%s: Can not get L2CAP connectionless packet header, " \
1478 "src bdaddr=%x:%x:%x:%x:%x:%x, length=%d\n",
1480 rt
->src
.b
[5], rt
->src
.b
[4], rt
->src
.b
[3],
1481 rt
->src
.b
[2], rt
->src
.b
[1], rt
->src
.b
[0],
1486 if (m
->m_len
< sizeof(*clt_hdr
)) {
1487 m
= m_pullup(m
, sizeof(*clt_hdr
));
1492 /* Strip connectionless header and deliver packet */
1493 clt_hdr
= mtod(m
, ng_l2cap_clt_hdr_t
*);
1494 m_adj(m
, sizeof(*clt_hdr
));
1496 NG_BTSOCKET_L2CAP_INFO(
1497 "%s: Got L2CAP connectionless data packet, " \
1498 "src bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, length=%d\n",
1500 rt
->src
.b
[5], rt
->src
.b
[4], rt
->src
.b
[3],
1501 rt
->src
.b
[2], rt
->src
.b
[1], rt
->src
.b
[0],
1502 clt_hdr
->psm
, hdr
->length
);
1504 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
1506 LIST_FOREACH(pcb
, &ng_btsocket_l2cap_sockets
, next
) {
1507 struct mbuf
*copy
= NULL
;
1509 mtx_lock(&pcb
->pcb_mtx
);
1511 if (bcmp(&rt
->src
, &pcb
->src
, sizeof(pcb
->src
)) != 0 ||
1512 pcb
->psm
!= clt_hdr
->psm
||
1513 pcb
->state
!= NG_BTSOCKET_L2CAP_OPEN
||
1514 (pcb
->so
->so_options
& SO_BROADCAST
) == 0 ||
1515 m
->m_pkthdr
.len
> sbspace(&pcb
->so
->so_rcv
))
1519 * Create a copy of the packet and append it to the
1520 * socket's queue. If m_dup() failed - no big deal
1521 * it is a broadcast traffic after all
1524 copy
= m_dup(m
, M_DONTWAIT
);
1526 sbappendrecord(&pcb
->so
->so_rcv
, copy
);
1530 mtx_unlock(&pcb
->pcb_mtx
);
1533 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1536 NG_FREE_M(m
); /* checks for m != NULL */
1537 } /* ng_btsocket_l2cap_data_input */
1540 * L2CAP sockets default message input routine
1544 ng_btsocket_l2cap_default_msg_input(struct ng_mesg
*msg
, hook_p hook
)
1546 switch (msg
->header
.cmd
) {
1547 case NGM_L2CAP_NODE_HOOK_INFO
: {
1548 ng_btsocket_l2cap_rtentry_t
*rt
= NULL
;
1550 if (hook
== NULL
|| msg
->header
.arglen
!= sizeof(bdaddr_t
))
1553 if (bcmp(msg
->data
, NG_HCI_BDADDR_ANY
, sizeof(bdaddr_t
)) == 0)
1556 mtx_lock(&ng_btsocket_l2cap_rt_mtx
);
1558 rt
= (ng_btsocket_l2cap_rtentry_t
*) NG_HOOK_PRIVATE(hook
);
1560 MALLOC(rt
, ng_btsocket_l2cap_rtentry_p
, sizeof(*rt
),
1561 M_NETGRAPH_BTSOCKET_L2CAP
, M_NOWAIT
|M_ZERO
);
1563 mtx_unlock(&ng_btsocket_l2cap_rt_mtx
);
1567 LIST_INSERT_HEAD(&ng_btsocket_l2cap_rt
, rt
, next
);
1569 NG_HOOK_SET_PRIVATE(hook
, rt
);
1572 bcopy(msg
->data
, &rt
->src
, sizeof(rt
->src
));
1575 mtx_unlock(&ng_btsocket_l2cap_rt_mtx
);
1577 NG_BTSOCKET_L2CAP_INFO(
1578 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n",
1579 __func__
, NG_HOOK_NAME(hook
),
1580 rt
->src
.b
[5], rt
->src
.b
[4], rt
->src
.b
[3],
1581 rt
->src
.b
[2], rt
->src
.b
[1], rt
->src
.b
[0]);
1585 NG_BTSOCKET_L2CAP_WARN(
1586 "%s: Unknown message, cmd=%d\n", __func__
, msg
->header
.cmd
);
1590 NG_FREE_MSG(msg
); /* Checks for msg != NULL */
1591 } /* ng_btsocket_l2cap_default_msg_input */
1594 * L2CAP sockets L2CA message input routine
1598 ng_btsocket_l2cap_l2ca_msg_input(struct ng_mesg
*msg
, hook_p hook
)
1600 ng_btsocket_l2cap_rtentry_p rt
= NULL
;
1603 NG_BTSOCKET_L2CAP_ALERT(
1604 "%s: Invalid source hook for L2CA message\n", __func__
);
1608 rt
= (ng_btsocket_l2cap_rtentry_p
) NG_HOOK_PRIVATE(hook
);
1610 NG_BTSOCKET_L2CAP_ALERT(
1611 "%s: Could not find out source bdaddr for L2CA message\n", __func__
);
1615 switch (msg
->header
.cmd
) {
1616 case NGM_L2CAP_L2CA_CON
: /* L2CA_Connect response */
1617 ng_btsocket_l2cap_process_l2ca_con_req_rsp(msg
, rt
);
1620 case NGM_L2CAP_L2CA_CON_RSP
: /* L2CA_ConnectRsp response */
1621 ng_btsocket_l2cap_process_l2ca_con_rsp_rsp(msg
, rt
);
1624 case NGM_L2CAP_L2CA_CON_IND
: /* L2CA_Connect indicator */
1625 ng_btsocket_l2cap_process_l2ca_con_ind(msg
, rt
);
1628 case NGM_L2CAP_L2CA_CFG
: /* L2CA_Config response */
1629 ng_btsocket_l2cap_process_l2ca_cfg_req_rsp(msg
, rt
);
1632 case NGM_L2CAP_L2CA_CFG_RSP
: /* L2CA_ConfigRsp response */
1633 ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp(msg
, rt
);
1636 case NGM_L2CAP_L2CA_CFG_IND
: /* L2CA_Config indicator */
1637 ng_btsocket_l2cap_process_l2ca_cfg_ind(msg
, rt
);
1640 case NGM_L2CAP_L2CA_DISCON
: /* L2CA_Disconnect response */
1641 ng_btsocket_l2cap_process_l2ca_discon_rsp(msg
, rt
);
1644 case NGM_L2CAP_L2CA_DISCON_IND
: /* L2CA_Disconnect indicator */
1645 ng_btsocket_l2cap_process_l2ca_discon_ind(msg
, rt
);
1648 case NGM_L2CAP_L2CA_WRITE
: /* L2CA_Write response */
1649 ng_btsocket_l2cap_process_l2ca_write_rsp(msg
, rt
);
1652 /* XXX FIXME add other L2CA messages */
1655 NG_BTSOCKET_L2CAP_WARN(
1656 "%s: Unknown L2CA message, cmd=%d\n", __func__
, msg
->header
.cmd
);
1661 } /* ng_btsocket_l2cap_l2ca_msg_input */
1664 * L2CAP sockets input routine
1668 ng_btsocket_l2cap_input(void *context
, int pending
)
1674 mtx_lock(&ng_btsocket_l2cap_queue_mtx
);
1675 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_queue
, item
);
1676 mtx_unlock(&ng_btsocket_l2cap_queue_mtx
);
1681 NGI_GET_HOOK(item
, hook
);
1682 if (hook
!= NULL
&& NG_HOOK_NOT_VALID(hook
))
1685 switch(item
->el_flags
& NGQF_TYPE
) {
1687 struct mbuf
*m
= NULL
;
1690 ng_btsocket_l2cap_data_input(m
, hook
);
1694 struct ng_mesg
*msg
= NULL
;
1696 NGI_GET_MSG(item
, msg
);
1698 switch (msg
->header
.cmd
) {
1699 case NGM_L2CAP_L2CA_CON
:
1700 case NGM_L2CAP_L2CA_CON_RSP
:
1701 case NGM_L2CAP_L2CA_CON_IND
:
1702 case NGM_L2CAP_L2CA_CFG
:
1703 case NGM_L2CAP_L2CA_CFG_RSP
:
1704 case NGM_L2CAP_L2CA_CFG_IND
:
1705 case NGM_L2CAP_L2CA_DISCON
:
1706 case NGM_L2CAP_L2CA_DISCON_IND
:
1707 case NGM_L2CAP_L2CA_WRITE
:
1708 /* XXX FIXME add other L2CA messages */
1709 ng_btsocket_l2cap_l2ca_msg_input(msg
, hook
);
1713 ng_btsocket_l2cap_default_msg_input(msg
, hook
);
1720 ("%s: invalid item type=%ld\n", __func__
, (item
->el_flags
& NGQF_TYPE
)));
1725 NG_HOOK_UNREF(hook
);
1729 } /* ng_btsocket_l2cap_input */
1732 * Route cleanup task. Gets scheduled when hook is disconnected. Here we
1733 * will find all sockets that use "invalid" hook and disconnect them.
1737 ng_btsocket_l2cap_rtclean(void *context
, int pending
)
1739 ng_btsocket_l2cap_pcb_p pcb
= NULL
, pcb_next
= NULL
;
1740 ng_btsocket_l2cap_rtentry_p rt
= NULL
;
1742 mtx_lock(&ng_btsocket_l2cap_rt_mtx
);
1743 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
1746 * First disconnect all sockets that use "invalid" hook
1749 for (pcb
= LIST_FIRST(&ng_btsocket_l2cap_sockets
); pcb
!= NULL
; ) {
1750 mtx_lock(&pcb
->pcb_mtx
);
1751 pcb_next
= LIST_NEXT(pcb
, next
);
1753 if (pcb
->rt
!= NULL
&&
1754 pcb
->rt
->hook
!= NULL
&& NG_HOOK_NOT_VALID(pcb
->rt
->hook
)) {
1755 if (pcb
->flags
& NG_BTSOCKET_L2CAP_TIMO
)
1756 ng_btsocket_l2cap_untimeout(pcb
);
1758 pcb
->so
->so_error
= ENETDOWN
;
1759 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
1760 soisdisconnected(pcb
->so
);
1767 mtx_unlock(&pcb
->pcb_mtx
);
1772 * Now cleanup routing table
1775 for (rt
= LIST_FIRST(&ng_btsocket_l2cap_rt
); rt
!= NULL
; ) {
1776 ng_btsocket_l2cap_rtentry_p rt_next
= LIST_NEXT(rt
, next
);
1778 if (rt
->hook
!= NULL
&& NG_HOOK_NOT_VALID(rt
->hook
)) {
1779 LIST_REMOVE(rt
, next
);
1781 NG_HOOK_SET_PRIVATE(rt
->hook
, NULL
);
1782 NG_HOOK_UNREF(rt
->hook
); /* Remove extra reference */
1784 bzero(rt
, sizeof(*rt
));
1785 FREE(rt
, M_NETGRAPH_BTSOCKET_L2CAP
);
1791 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
1792 mtx_unlock(&ng_btsocket_l2cap_rt_mtx
);
1793 } /* ng_btsocket_l2cap_rtclean */
1796 * Initialize everything
1800 ng_btsocket_l2cap_init(void)
1804 ng_btsocket_l2cap_node
= NULL
;
1805 ng_btsocket_l2cap_debug_level
= NG_BTSOCKET_WARN_LEVEL
;
1807 /* Register Netgraph node type */
1808 error
= ng_newtype(&typestruct
);
1810 NG_BTSOCKET_L2CAP_ALERT(
1811 "%s: Could not register Netgraph node type, error=%d\n", __func__
, error
);
1816 /* Create Netgrapg node */
1817 error
= ng_make_node_common(&typestruct
, &ng_btsocket_l2cap_node
);
1819 NG_BTSOCKET_L2CAP_ALERT(
1820 "%s: Could not create Netgraph node, error=%d\n", __func__
, error
);
1822 ng_btsocket_l2cap_node
= NULL
;
1827 error
= ng_name_node(ng_btsocket_l2cap_node
,
1828 NG_BTSOCKET_L2CAP_NODE_TYPE
);
1830 NG_BTSOCKET_L2CAP_ALERT(
1831 "%s: Could not name Netgraph node, error=%d\n", __func__
, error
);
1833 NG_NODE_UNREF(ng_btsocket_l2cap_node
);
1834 ng_btsocket_l2cap_node
= NULL
;
1839 /* Create input queue */
1840 NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_queue
, ifqmaxlen
);
1841 mtx_init(&ng_btsocket_l2cap_queue_mtx
,
1842 "btsocks_l2cap_queue_mtx", NULL
, MTX_DEF
);
1843 TASK_INIT(&ng_btsocket_l2cap_queue_task
, 0,
1844 ng_btsocket_l2cap_input
, NULL
);
1846 /* Create list of sockets */
1847 LIST_INIT(&ng_btsocket_l2cap_sockets
);
1848 mtx_init(&ng_btsocket_l2cap_sockets_mtx
,
1849 "btsocks_l2cap_sockets_mtx", NULL
, MTX_DEF
);
1852 LIST_INIT(&ng_btsocket_l2cap_rt
);
1853 mtx_init(&ng_btsocket_l2cap_rt_mtx
,
1854 "btsocks_l2cap_rt_mtx", NULL
, MTX_DEF
);
1855 TASK_INIT(&ng_btsocket_l2cap_rt_task
, 0,
1856 ng_btsocket_l2cap_rtclean
, NULL
);
1857 } /* ng_btsocket_l2cap_init */
1860 * Abort connection on socket
1864 ng_btsocket_l2cap_abort(struct socket
*so
)
1866 so
->so_error
= ECONNABORTED
;
1868 (void)ng_btsocket_l2cap_disconnect(so
);
1869 } /* ng_btsocket_l2cap_abort */
1872 ng_btsocket_l2cap_close(struct socket
*so
)
1875 (void)ng_btsocket_l2cap_disconnect(so
);
1876 } /* ng_btsocket_l2cap_close */
1879 * Accept connection on socket. Nothing to do here, socket must be connected
1880 * and ready, so just return peer address and be done with it.
1884 ng_btsocket_l2cap_accept(struct socket
*so
, struct sockaddr
**nam
)
1886 if (ng_btsocket_l2cap_node
== NULL
)
1889 return (ng_btsocket_l2cap_peeraddr(so
, nam
));
1890 } /* ng_btsocket_l2cap_accept */
1893 * Create and attach new socket
1897 ng_btsocket_l2cap_attach(struct socket
*so
, int proto
, struct thread
*td
)
1899 static u_int32_t token
= 0;
1900 ng_btsocket_l2cap_pcb_p pcb
= so2l2cap_pcb(so
);
1903 /* Check socket and protocol */
1904 if (ng_btsocket_l2cap_node
== NULL
)
1905 return (EPROTONOSUPPORT
);
1906 if (so
->so_type
!= SOCK_SEQPACKET
)
1907 return (ESOCKTNOSUPPORT
);
1909 #if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */
1911 if (proto
!= BLUETOOTH_PROTO_L2CAP
)
1912 return (EPROTONOSUPPORT
);
1918 /* Reserve send and receive space if it is not reserved yet */
1919 if ((so
->so_snd
.sb_hiwat
== 0) || (so
->so_rcv
.sb_hiwat
== 0)) {
1920 error
= soreserve(so
, NG_BTSOCKET_L2CAP_SENDSPACE
,
1921 NG_BTSOCKET_L2CAP_RECVSPACE
);
1926 /* Allocate the PCB */
1927 MALLOC(pcb
, ng_btsocket_l2cap_pcb_p
, sizeof(*pcb
),
1928 M_NETGRAPH_BTSOCKET_L2CAP
, M_NOWAIT
| M_ZERO
);
1932 /* Link the PCB and the socket */
1933 so
->so_pcb
= (caddr_t
) pcb
;
1935 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
1937 /* Initialize PCB */
1938 pcb
->imtu
= pcb
->omtu
= NG_L2CAP_MTU_DEFAULT
;
1941 pcb
->iflow
.flags
= 0x0;
1942 pcb
->iflow
.service_type
= NG_HCI_SERVICE_TYPE_BEST_EFFORT
;
1943 pcb
->iflow
.token_rate
= 0xffffffff; /* maximum */
1944 pcb
->iflow
.token_bucket_size
= 0xffffffff; /* maximum */
1945 pcb
->iflow
.peak_bandwidth
= 0x00000000; /* maximum */
1946 pcb
->iflow
.latency
= 0xffffffff; /* don't care */
1947 pcb
->iflow
.delay_variation
= 0xffffffff; /* don't care */
1949 bcopy(&pcb
->iflow
, &pcb
->oflow
, sizeof(pcb
->oflow
));
1951 pcb
->flush_timo
= NG_L2CAP_FLUSH_TIMO_DEFAULT
;
1952 pcb
->link_timo
= NG_L2CAP_LINK_TIMO_DEFAULT
;
1954 callout_handle_init(&pcb
->timo
);
1957 * XXX Mark PCB mutex as DUPOK to prevent "duplicated lock of
1958 * the same type" message. When accepting new L2CAP connection
1959 * ng_btsocket_l2cap_process_l2ca_con_ind() holds both PCB mutexes
1960 * for "old" (accepting) PCB and "new" (created) PCB.
1963 mtx_init(&pcb
->pcb_mtx
, "btsocks_l2cap_pcb_mtx", NULL
,
1967 * Add the PCB to the list
1969 * XXX FIXME VERY IMPORTANT!
1971 * This is totally FUBAR. We could get here in two cases:
1973 * 1) When user calls socket()
1974 * 2) When we need to accept new incomming connection and call
1977 * In the first case we must acquire ng_btsocket_l2cap_sockets_mtx.
1978 * In the second case we hold ng_btsocket_l2cap_sockets_mtx already.
1979 * So we now need to distinguish between these cases. From reading
1980 * /sys/kern/uipc_socket.c we can find out that sonewconn() calls
1981 * pru_attach with proto == 0 and td == NULL. For now use this fact
1982 * to figure out if we were called from socket() or from sonewconn().
1986 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
1988 mtx_assert(&ng_btsocket_l2cap_sockets_mtx
, MA_OWNED
);
1990 /* Set PCB token. Use ng_btsocket_l2cap_sockets_mtx for protection */
1996 LIST_INSERT_HEAD(&ng_btsocket_l2cap_sockets
, pcb
, next
);
1999 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
2002 } /* ng_btsocket_l2cap_attach */
2009 ng_btsocket_l2cap_bind(struct socket
*so
, struct sockaddr
*nam
,
2012 ng_btsocket_l2cap_pcb_t
*pcb
= NULL
;
2013 struct sockaddr_l2cap
*sa
= (struct sockaddr_l2cap
*) nam
;
2016 if (ng_btsocket_l2cap_node
== NULL
)
2019 /* Verify address */
2022 if (sa
->l2cap_family
!= AF_BLUETOOTH
)
2023 return (EAFNOSUPPORT
);
2024 if (sa
->l2cap_len
!= sizeof(*sa
))
2027 psm
= le16toh(sa
->l2cap_psm
);
2030 * Check if other socket has this address already (look for exact
2031 * match PSM and bdaddr) and assign socket address if it's available.
2033 * Note: socket can be bound to ANY PSM (zero) thus allowing several
2034 * channels with the same PSM between the same pair of BD_ADDR'es.
2037 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
2039 LIST_FOREACH(pcb
, &ng_btsocket_l2cap_sockets
, next
)
2040 if (psm
!= 0 && psm
== pcb
->psm
&&
2041 bcmp(&pcb
->src
, &sa
->l2cap_bdaddr
, sizeof(bdaddr_t
)) == 0)
2045 /* Set socket address */
2046 pcb
= so2l2cap_pcb(so
);
2048 bcopy(&sa
->l2cap_bdaddr
, &pcb
->src
, sizeof(pcb
->src
));
2055 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
2058 } /* ng_btsocket_l2cap_bind */
2065 ng_btsocket_l2cap_connect(struct socket
*so
, struct sockaddr
*nam
,
2068 ng_btsocket_l2cap_pcb_t
*pcb
= so2l2cap_pcb(so
);
2069 struct sockaddr_l2cap
*sa
= (struct sockaddr_l2cap
*) nam
;
2070 ng_btsocket_l2cap_rtentry_t
*rt
= NULL
;
2071 int have_src
, error
= 0;
2076 if (ng_btsocket_l2cap_node
== NULL
)
2078 if (pcb
->state
== NG_BTSOCKET_L2CAP_CONNECTING
)
2079 return (EINPROGRESS
);
2081 /* Verify address */
2084 if (sa
->l2cap_family
!= AF_BLUETOOTH
)
2085 return (EAFNOSUPPORT
);
2086 if (sa
->l2cap_len
!= sizeof(*sa
))
2088 if (sa
->l2cap_psm
== 0 ||
2089 bcmp(&sa
->l2cap_bdaddr
, NG_HCI_BDADDR_ANY
, sizeof(bdaddr_t
)) == 0)
2090 return (EDESTADDRREQ
);
2091 if (pcb
->psm
!= 0 && pcb
->psm
!= le16toh(sa
->l2cap_psm
))
2095 * Routing. Socket should be bound to some source address. The source
2096 * address can be ANY. Destination address must be set and it must not
2097 * be ANY. If source address is ANY then find first rtentry that has
2101 mtx_lock(&ng_btsocket_l2cap_rt_mtx
);
2102 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
2103 mtx_lock(&pcb
->pcb_mtx
);
2105 /* Send destination address and PSM */
2106 bcopy(&sa
->l2cap_bdaddr
, &pcb
->dst
, sizeof(pcb
->dst
));
2107 pcb
->psm
= le16toh(sa
->l2cap_psm
);
2110 have_src
= bcmp(&pcb
->src
, NG_HCI_BDADDR_ANY
, sizeof(pcb
->src
));
2112 LIST_FOREACH(rt
, &ng_btsocket_l2cap_rt
, next
) {
2113 if (rt
->hook
== NULL
|| NG_HOOK_NOT_VALID(rt
->hook
))
2116 /* Match src and dst */
2118 if (bcmp(&pcb
->src
, &rt
->src
, sizeof(rt
->src
)) == 0)
2121 if (bcmp(&pcb
->dst
, &rt
->src
, sizeof(rt
->src
)) != 0)
2130 bcopy(&rt
->src
, &pcb
->src
, sizeof(pcb
->src
));
2132 error
= EHOSTUNREACH
;
2135 * Send L2CA_Connect request
2139 error
= ng_btsocket_l2cap_send_l2ca_con_req(pcb
);
2141 pcb
->flags
|= NG_BTSOCKET_L2CAP_CLIENT
;
2142 pcb
->state
= NG_BTSOCKET_L2CAP_CONNECTING
;
2143 soisconnecting(pcb
->so
);
2145 ng_btsocket_l2cap_timeout(pcb
);
2149 mtx_unlock(&pcb
->pcb_mtx
);
2150 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
2151 mtx_unlock(&ng_btsocket_l2cap_rt_mtx
);
2154 } /* ng_btsocket_l2cap_connect */
2157 * Process ioctl's calls on socket
2161 ng_btsocket_l2cap_control(struct socket
*so
, u_long cmd
, caddr_t data
,
2162 struct ifnet
*ifp
, struct thread
*td
)
2165 } /* ng_btsocket_l2cap_control */
2168 * Process getsockopt/setsockopt system calls
2172 ng_btsocket_l2cap_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
2174 ng_btsocket_l2cap_pcb_p pcb
= so2l2cap_pcb(so
);
2176 ng_l2cap_cfg_opt_val_t v
;
2180 if (ng_btsocket_l2cap_node
== NULL
)
2183 if (sopt
->sopt_level
!= SOL_L2CAP
)
2186 mtx_lock(&pcb
->pcb_mtx
);
2188 switch (sopt
->sopt_dir
) {
2190 switch (sopt
->sopt_name
) {
2191 case SO_L2CAP_IMTU
: /* get incoming MTU */
2192 error
= sooptcopyout(sopt
, &pcb
->imtu
,
2196 case SO_L2CAP_OMTU
: /* get outgoing (peer incoming) MTU */
2197 error
= sooptcopyout(sopt
, &pcb
->omtu
,
2201 case SO_L2CAP_IFLOW
: /* get incoming flow spec. */
2202 error
= sooptcopyout(sopt
, &pcb
->iflow
,
2203 sizeof(pcb
->iflow
));
2206 case SO_L2CAP_OFLOW
: /* get outgoing flow spec. */
2207 error
= sooptcopyout(sopt
, &pcb
->oflow
,
2208 sizeof(pcb
->oflow
));
2211 case SO_L2CAP_FLUSH
: /* get flush timeout */
2212 error
= sooptcopyout(sopt
, &pcb
->flush_timo
,
2213 sizeof(pcb
->flush_timo
));
2217 error
= ENOPROTOOPT
;
2225 * We do not allow to change these parameters while socket is
2226 * connected or we are in the process of creating a connection.
2227 * May be this should indicate re-configuration of the open
2231 if (pcb
->state
!= NG_BTSOCKET_L2CAP_CLOSED
) {
2236 switch (sopt
->sopt_name
) {
2237 case SO_L2CAP_IMTU
: /* set incoming MTU */
2238 error
= sooptcopyin(sopt
, &v
, sizeof(v
), sizeof(v
.mtu
));
2243 case SO_L2CAP_OFLOW
: /* set outgoing flow spec. */
2244 error
= sooptcopyin(sopt
, &v
, sizeof(v
),sizeof(v
.flow
));
2246 bcopy(&v
.flow
, &pcb
->oflow
, sizeof(pcb
->oflow
));
2249 case SO_L2CAP_FLUSH
: /* set flush timeout */
2250 error
= sooptcopyin(sopt
, &v
, sizeof(v
),
2251 sizeof(v
.flush_timo
));
2253 pcb
->flush_timo
= v
.flush_timo
;
2257 error
= ENOPROTOOPT
;
2267 mtx_unlock(&pcb
->pcb_mtx
);
2270 } /* ng_btsocket_l2cap_ctloutput */
2273 * Detach and destroy socket
2277 ng_btsocket_l2cap_detach(struct socket
*so
)
2279 ng_btsocket_l2cap_pcb_p pcb
= so2l2cap_pcb(so
);
2281 KASSERT(pcb
!= NULL
, ("ng_btsocket_l2cap_detach: pcb == NULL"));
2283 if (ng_btsocket_l2cap_node
== NULL
)
2286 mtx_lock(&ng_btsocket_l2cap_sockets_mtx
);
2287 mtx_lock(&pcb
->pcb_mtx
);
2289 /* XXX what to do with pending request? */
2290 if (pcb
->flags
& NG_BTSOCKET_L2CAP_TIMO
)
2291 ng_btsocket_l2cap_untimeout(pcb
);
2293 if (pcb
->state
!= NG_BTSOCKET_L2CAP_CLOSED
&&
2294 pcb
->state
!= NG_BTSOCKET_L2CAP_DISCONNECTING
)
2295 /* Send disconnect request with "zero" token */
2296 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb
);
2298 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
2300 LIST_REMOVE(pcb
, next
);
2302 mtx_unlock(&pcb
->pcb_mtx
);
2303 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx
);
2305 mtx_destroy(&pcb
->pcb_mtx
);
2306 bzero(pcb
, sizeof(*pcb
));
2307 FREE(pcb
, M_NETGRAPH_BTSOCKET_L2CAP
);
2309 soisdisconnected(so
);
2311 } /* ng_btsocket_l2cap_detach */
2318 ng_btsocket_l2cap_disconnect(struct socket
*so
)
2320 ng_btsocket_l2cap_pcb_p pcb
= so2l2cap_pcb(so
);
2325 if (ng_btsocket_l2cap_node
== NULL
)
2328 mtx_lock(&pcb
->pcb_mtx
);
2330 if (pcb
->state
== NG_BTSOCKET_L2CAP_DISCONNECTING
) {
2331 mtx_unlock(&pcb
->pcb_mtx
);
2332 return (EINPROGRESS
);
2335 if (pcb
->state
!= NG_BTSOCKET_L2CAP_CLOSED
) {
2336 /* XXX FIXME what to do with pending request? */
2337 if (pcb
->flags
& NG_BTSOCKET_L2CAP_TIMO
)
2338 ng_btsocket_l2cap_untimeout(pcb
);
2340 error
= ng_btsocket_l2cap_send_l2ca_discon_req(pcb
->token
, pcb
);
2342 pcb
->state
= NG_BTSOCKET_L2CAP_DISCONNECTING
;
2343 soisdisconnecting(so
);
2345 ng_btsocket_l2cap_timeout(pcb
);
2348 /* XXX FIXME what to do if error != 0 */
2351 mtx_unlock(&pcb
->pcb_mtx
);
2354 } /* ng_btsocket_l2cap_disconnect */
2361 ng_btsocket_l2cap_listen(struct socket
*so
, int backlog
, struct thread
*td
)
2363 ng_btsocket_l2cap_pcb_p pcb
= so2l2cap_pcb(so
);
2367 error
= solisten_proto_check(so
);
2374 if (ng_btsocket_l2cap_node
== NULL
) {
2378 if (pcb
->psm
== 0) {
2379 error
= EADDRNOTAVAIL
;
2382 solisten_proto(so
, backlog
);
2386 } /* ng_btsocket_listen */
2393 ng_btsocket_l2cap_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
2395 ng_btsocket_l2cap_pcb_p pcb
= so2l2cap_pcb(so
);
2396 struct sockaddr_l2cap sa
;
2400 if (ng_btsocket_l2cap_node
== NULL
)
2403 bcopy(&pcb
->dst
, &sa
.l2cap_bdaddr
, sizeof(sa
.l2cap_bdaddr
));
2404 sa
.l2cap_psm
= htole16(pcb
->psm
);
2405 sa
.l2cap_len
= sizeof(sa
);
2406 sa
.l2cap_family
= AF_BLUETOOTH
;
2408 *nam
= sodupsockaddr((struct sockaddr
*) &sa
, M_NOWAIT
);
2410 return ((*nam
== NULL
)? ENOMEM
: 0);
2411 } /* ng_btsocket_l2cap_peeraddr */
2414 * Send data to socket
2418 ng_btsocket_l2cap_send(struct socket
*so
, int flags
, struct mbuf
*m
,
2419 struct sockaddr
*nam
, struct mbuf
*control
, struct thread
*td
)
2421 ng_btsocket_l2cap_pcb_t
*pcb
= so2l2cap_pcb(so
);
2424 if (ng_btsocket_l2cap_node
== NULL
) {
2429 /* Check socket and input */
2430 if (pcb
== NULL
|| m
== NULL
|| control
!= NULL
) {
2435 mtx_lock(&pcb
->pcb_mtx
);
2437 /* Make sure socket is connected */
2438 if (pcb
->state
!= NG_BTSOCKET_L2CAP_OPEN
) {
2439 mtx_unlock(&pcb
->pcb_mtx
);
2445 if (pcb
->rt
== NULL
||
2446 pcb
->rt
->hook
== NULL
|| NG_HOOK_NOT_VALID(pcb
->rt
->hook
)) {
2447 mtx_unlock(&pcb
->pcb_mtx
);
2452 /* Check packet size agains outgoing (peer's incoming) MTU) */
2453 if (m
->m_pkthdr
.len
> pcb
->omtu
) {
2454 NG_BTSOCKET_L2CAP_ERR(
2455 "%s: Packet too big, len=%d, omtu=%d\n", __func__
, m
->m_pkthdr
.len
, pcb
->omtu
);
2457 mtx_unlock(&pcb
->pcb_mtx
);
2463 * First put packet on socket send queue. Then check if we have
2464 * pending timeout. If we do not have timeout then we must send
2465 * packet and schedule timeout. Otherwise do nothing and wait for
2469 sbappendrecord(&pcb
->so
->so_snd
, m
);
2472 if (!(pcb
->flags
& NG_BTSOCKET_L2CAP_TIMO
)) {
2473 error
= ng_btsocket_l2cap_send2(pcb
);
2475 ng_btsocket_l2cap_timeout(pcb
);
2477 sbdroprecord(&pcb
->so
->so_snd
); /* XXX */
2480 mtx_unlock(&pcb
->pcb_mtx
);
2482 NG_FREE_M(m
); /* checks for != NULL */
2486 } /* ng_btsocket_l2cap_send */
2489 * Send first packet in the socket queue to the L2CAP layer
2493 ng_btsocket_l2cap_send2(ng_btsocket_l2cap_pcb_p pcb
)
2495 struct mbuf
*m
= NULL
;
2496 ng_l2cap_l2ca_hdr_t
*hdr
= NULL
;
2499 mtx_assert(&pcb
->pcb_mtx
, MA_OWNED
);
2501 if (pcb
->so
->so_snd
.sb_cc
== 0)
2502 return (EINVAL
); /* XXX */
2504 m
= m_dup(pcb
->so
->so_snd
.sb_mb
, M_DONTWAIT
);
2508 /* Create L2CA packet header */
2509 M_PREPEND(m
, sizeof(*hdr
), M_DONTWAIT
);
2511 if (m
->m_len
< sizeof(*hdr
))
2512 m
= m_pullup(m
, sizeof(*hdr
));
2515 NG_BTSOCKET_L2CAP_ERR(
2516 "%s: Failed to create L2CA packet header\n", __func__
);
2521 hdr
= mtod(m
, ng_l2cap_l2ca_hdr_t
*);
2522 hdr
->token
= pcb
->token
;
2523 hdr
->length
= m
->m_pkthdr
.len
- sizeof(*hdr
);
2524 hdr
->lcid
= pcb
->cid
;
2526 NG_BTSOCKET_L2CAP_INFO(
2527 "%s: Sending packet: len=%d, length=%d, lcid=%d, token=%d, state=%d\n",
2528 __func__
, m
->m_pkthdr
.len
, hdr
->length
, hdr
->lcid
,
2529 hdr
->token
, pcb
->state
);
2532 * If we got here than we have successfuly creates new L2CAP
2533 * data packet and now we can send it to the L2CAP layer
2536 NG_SEND_DATA_ONLY(error
, pcb
->rt
->hook
, m
);
2539 } /* ng_btsocket_l2cap_send2 */
2542 * Get socket address
2546 ng_btsocket_l2cap_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
2548 ng_btsocket_l2cap_pcb_p pcb
= so2l2cap_pcb(so
);
2549 struct sockaddr_l2cap sa
;
2553 if (ng_btsocket_l2cap_node
== NULL
)
2556 bcopy(&pcb
->src
, &sa
.l2cap_bdaddr
, sizeof(sa
.l2cap_bdaddr
));
2557 sa
.l2cap_psm
= htole16(pcb
->psm
);
2558 sa
.l2cap_len
= sizeof(sa
);
2559 sa
.l2cap_family
= AF_BLUETOOTH
;
2561 *nam
= sodupsockaddr((struct sockaddr
*) &sa
, M_NOWAIT
);
2563 return ((*nam
== NULL
)? ENOMEM
: 0);
2564 } /* ng_btsocket_l2cap_sockaddr */
2566 /*****************************************************************************
2567 *****************************************************************************
2569 *****************************************************************************
2570 *****************************************************************************/
2573 * Look for the socket that listens on given PSM and bdaddr. Returns exact or
2574 * close match (if any). Caller must hold ng_btsocket_l2cap_sockets_mtx.
2577 static ng_btsocket_l2cap_pcb_p
2578 ng_btsocket_l2cap_pcb_by_addr(bdaddr_p bdaddr
, int psm
)
2580 ng_btsocket_l2cap_pcb_p p
= NULL
, p1
= NULL
;
2582 mtx_assert(&ng_btsocket_l2cap_sockets_mtx
, MA_OWNED
);
2584 LIST_FOREACH(p
, &ng_btsocket_l2cap_sockets
, next
) {
2585 if (p
->so
== NULL
|| !(p
->so
->so_options
& SO_ACCEPTCONN
) ||
2589 if (bcmp(&p
->src
, bdaddr
, sizeof(p
->src
)) == 0)
2592 if (bcmp(&p
->src
, NG_HCI_BDADDR_ANY
, sizeof(p
->src
)) == 0)
2596 return ((p
!= NULL
)? p
: p1
);
2597 } /* ng_btsocket_l2cap_pcb_by_addr */
2600 * Look for the socket that has given token.
2601 * Caller must hold ng_btsocket_l2cap_sockets_mtx.
2604 static ng_btsocket_l2cap_pcb_p
2605 ng_btsocket_l2cap_pcb_by_token(u_int32_t token
)
2607 ng_btsocket_l2cap_pcb_p p
= NULL
;
2612 mtx_assert(&ng_btsocket_l2cap_sockets_mtx
, MA_OWNED
);
2614 LIST_FOREACH(p
, &ng_btsocket_l2cap_sockets
, next
)
2615 if (p
->token
== token
)
2619 } /* ng_btsocket_l2cap_pcb_by_token */
2622 * Look for the socket that assigned to given source address and channel ID.
2623 * Caller must hold ng_btsocket_l2cap_sockets_mtx
2626 static ng_btsocket_l2cap_pcb_p
2627 ng_btsocket_l2cap_pcb_by_cid(bdaddr_p src
, int cid
)
2629 ng_btsocket_l2cap_pcb_p p
= NULL
;
2631 mtx_assert(&ng_btsocket_l2cap_sockets_mtx
, MA_OWNED
);
2633 LIST_FOREACH(p
, &ng_btsocket_l2cap_sockets
, next
)
2634 if (p
->cid
== cid
&& bcmp(src
, &p
->src
, sizeof(p
->src
)) == 0)
2638 } /* ng_btsocket_l2cap_pcb_by_cid */
2641 * Set timeout on socket
2645 ng_btsocket_l2cap_timeout(ng_btsocket_l2cap_pcb_p pcb
)
2647 mtx_assert(&pcb
->pcb_mtx
, MA_OWNED
);
2649 if (!(pcb
->flags
& NG_BTSOCKET_L2CAP_TIMO
)) {
2650 pcb
->flags
|= NG_BTSOCKET_L2CAP_TIMO
;
2651 pcb
->timo
= timeout(ng_btsocket_l2cap_process_timeout
, pcb
,
2652 bluetooth_l2cap_ertx_timeout());
2655 ("%s: Duplicated socket timeout?!\n", __func__
));
2656 } /* ng_btsocket_l2cap_timeout */
2659 * Unset timeout on socket
2663 ng_btsocket_l2cap_untimeout(ng_btsocket_l2cap_pcb_p pcb
)
2665 mtx_assert(&pcb
->pcb_mtx
, MA_OWNED
);
2667 if (pcb
->flags
& NG_BTSOCKET_L2CAP_TIMO
) {
2668 untimeout(ng_btsocket_l2cap_process_timeout
, pcb
, pcb
->timo
);
2669 pcb
->flags
&= ~NG_BTSOCKET_L2CAP_TIMO
;
2672 ("%s: No socket timeout?!\n", __func__
));
2673 } /* ng_btsocket_l2cap_untimeout */
2676 * Process timeout on socket
2680 ng_btsocket_l2cap_process_timeout(void *xpcb
)
2682 ng_btsocket_l2cap_pcb_p pcb
= (ng_btsocket_l2cap_pcb_p
) xpcb
;
2684 mtx_lock(&pcb
->pcb_mtx
);
2686 pcb
->flags
&= ~NG_BTSOCKET_L2CAP_TIMO
;
2687 pcb
->so
->so_error
= ETIMEDOUT
;
2689 switch (pcb
->state
) {
2690 case NG_BTSOCKET_L2CAP_CONNECTING
:
2691 case NG_BTSOCKET_L2CAP_CONFIGURING
:
2692 /* Send disconnect request with "zero" token */
2694 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb
);
2696 /* ... and close the socket */
2697 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
2698 soisdisconnected(pcb
->so
);
2701 case NG_BTSOCKET_L2CAP_OPEN
:
2702 /* Send timeout - drop packet and wakeup sender */
2703 sbdroprecord(&pcb
->so
->so_snd
);
2707 case NG_BTSOCKET_L2CAP_DISCONNECTING
:
2708 /* Disconnect timeout - disconnect the socket anyway */
2709 pcb
->state
= NG_BTSOCKET_L2CAP_CLOSED
;
2710 soisdisconnected(pcb
->so
);
2714 NG_BTSOCKET_L2CAP_ERR(
2715 "%s: Invalid socket state=%d\n", __func__
, pcb
->state
);
2719 mtx_unlock(&pcb
->pcb_mtx
);
2720 } /* ng_btsocket_l2cap_process_timeout */
2723 * Translate HCI/L2CAP error code into "errno" code
2724 * XXX Note: Some L2CAP and HCI error codes have the same value, but
2729 ng_btsocket_l2cap_result2errno(int result
)
2732 case 0x00: /* No error */
2735 case 0x01: /* Unknown HCI command */
2738 case 0x02: /* No connection */
2741 case 0x03: /* Hardware failure */
2744 case 0x04: /* Page timeout */
2747 case 0x05: /* Authentication failure */
2748 case 0x06: /* Key missing */
2749 case 0x18: /* Pairing not allowed */
2750 case 0x21: /* Role change not allowed */
2751 case 0x24: /* LMP PSU not allowed */
2752 case 0x25: /* Encryption mode not acceptable */
2753 case 0x26: /* Unit key used */
2756 case 0x07: /* Memory full */
2759 case 0x08: /* Connection timeout */
2760 case 0x10: /* Host timeout */
2761 case 0x22: /* LMP response timeout */
2762 case 0xee: /* HCI timeout */
2763 case 0xeeee: /* L2CAP timeout */
2766 case 0x09: /* Max number of connections */
2767 case 0x0a: /* Max number of SCO connections to a unit */
2770 case 0x0b: /* ACL connection already exists */
2773 case 0x0c: /* Command disallowed */
2776 case 0x0d: /* Host rejected due to limited resources */
2777 case 0x0e: /* Host rejected due to securiity reasons */
2778 case 0x0f: /* Host rejected due to remote unit is a personal unit */
2779 case 0x1b: /* SCO offset rejected */
2780 case 0x1c: /* SCO interval rejected */
2781 case 0x1d: /* SCO air mode rejected */
2782 return (ECONNREFUSED
);
2784 case 0x11: /* Unsupported feature or parameter value */
2785 case 0x19: /* Unknown LMP PDU */
2786 case 0x1a: /* Unsupported remote feature */
2787 case 0x20: /* Unsupported LMP parameter value */
2788 case 0x27: /* QoS is not supported */
2789 case 0x29: /* Paring with unit key not supported */
2790 return (EOPNOTSUPP
);
2792 case 0x12: /* Invalid HCI command parameter */
2793 case 0x1e: /* Invalid LMP parameters */
2796 case 0x13: /* Other end terminated connection: User ended connection */
2797 case 0x14: /* Other end terminated connection: Low resources */
2798 case 0x15: /* Other end terminated connection: About to power off */
2799 return (ECONNRESET
);
2801 case 0x16: /* Connection terminated by local host */
2802 return (ECONNABORTED
);
2804 #if 0 /* XXX not yet */
2805 case 0x17: /* Repeated attempts */
2806 case 0x1f: /* Unspecified error */
2807 case 0x23: /* LMP error transaction collision */
2808 case 0x28: /* Instant passed */
2813 } /* ng_btsocket_l2cap_result2errno */