Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netgraph/bluetooth/socket/ng_btsocket_sco.c
34677 views
1
/*
2
* ng_btsocket_sco.c
3
*/
4
5
/*-
6
* SPDX-License-Identifier: BSD-2-Clause
7
*
8
* Copyright (c) 2001-2002 Maksim Yevmenkin <[email protected]>
9
* All rights reserved.
10
*
11
* Redistribution and use in source and binary forms, with or without
12
* modification, are permitted provided that the following conditions
13
* are met:
14
* 1. Redistributions of source code must retain the above copyright
15
* notice, this list of conditions and the following disclaimer.
16
* 2. Redistributions in binary form must reproduce the above copyright
17
* notice, this list of conditions and the following disclaimer in the
18
* documentation and/or other materials provided with the distribution.
19
*
20
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
* SUCH DAMAGE.
31
*
32
* $Id: ng_btsocket_sco.c,v 1.2 2005/10/31 18:08:51 max Exp $
33
*/
34
35
#include <sys/param.h>
36
#include <sys/systm.h>
37
#include <sys/bitstring.h>
38
#include <sys/domain.h>
39
#include <sys/endian.h>
40
#include <sys/errno.h>
41
#include <sys/filedesc.h>
42
#include <sys/ioccom.h>
43
#include <sys/kernel.h>
44
#include <sys/lock.h>
45
#include <sys/malloc.h>
46
#include <sys/mbuf.h>
47
#include <sys/mutex.h>
48
#include <sys/protosw.h>
49
#include <sys/queue.h>
50
#include <sys/socket.h>
51
#include <sys/socketvar.h>
52
#include <sys/sysctl.h>
53
#include <sys/taskqueue.h>
54
55
#include <net/vnet.h>
56
57
#include <netgraph/ng_message.h>
58
#include <netgraph/netgraph.h>
59
#include <netgraph/bluetooth/include/ng_bluetooth.h>
60
#include <netgraph/bluetooth/include/ng_hci.h>
61
#include <netgraph/bluetooth/include/ng_l2cap.h>
62
#include <netgraph/bluetooth/include/ng_btsocket.h>
63
#include <netgraph/bluetooth/include/ng_btsocket_sco.h>
64
65
/* MALLOC define */
66
#ifdef NG_SEPARATE_MALLOC
67
static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_SCO, "netgraph_btsocks_sco",
68
"Netgraph Bluetooth SCO sockets");
69
#else
70
#define M_NETGRAPH_BTSOCKET_SCO M_NETGRAPH
71
#endif /* NG_SEPARATE_MALLOC */
72
73
/* Netgraph node methods */
74
static ng_constructor_t ng_btsocket_sco_node_constructor;
75
static ng_rcvmsg_t ng_btsocket_sco_node_rcvmsg;
76
static ng_shutdown_t ng_btsocket_sco_node_shutdown;
77
static ng_newhook_t ng_btsocket_sco_node_newhook;
78
static ng_connect_t ng_btsocket_sco_node_connect;
79
static ng_rcvdata_t ng_btsocket_sco_node_rcvdata;
80
static ng_disconnect_t ng_btsocket_sco_node_disconnect;
81
82
static void ng_btsocket_sco_input (void *, int);
83
static void ng_btsocket_sco_rtclean (void *, int);
84
85
/* Netgraph type descriptor */
86
static struct ng_type typestruct = {
87
.version = NG_ABI_VERSION,
88
.name = NG_BTSOCKET_SCO_NODE_TYPE,
89
.constructor = ng_btsocket_sco_node_constructor,
90
.rcvmsg = ng_btsocket_sco_node_rcvmsg,
91
.shutdown = ng_btsocket_sco_node_shutdown,
92
.newhook = ng_btsocket_sco_node_newhook,
93
.connect = ng_btsocket_sco_node_connect,
94
.rcvdata = ng_btsocket_sco_node_rcvdata,
95
.disconnect = ng_btsocket_sco_node_disconnect,
96
};
97
98
/* Globals */
99
static u_int32_t ng_btsocket_sco_debug_level;
100
static node_p ng_btsocket_sco_node;
101
static struct ng_bt_itemq ng_btsocket_sco_queue;
102
static struct mtx ng_btsocket_sco_queue_mtx;
103
static struct task ng_btsocket_sco_queue_task;
104
static struct mtx ng_btsocket_sco_sockets_mtx;
105
static LIST_HEAD(, ng_btsocket_sco_pcb) ng_btsocket_sco_sockets;
106
static LIST_HEAD(, ng_btsocket_sco_rtentry) ng_btsocket_sco_rt;
107
static struct mtx ng_btsocket_sco_rt_mtx;
108
static struct task ng_btsocket_sco_rt_task;
109
static struct timeval ng_btsocket_sco_lasttime;
110
static int ng_btsocket_sco_curpps;
111
112
/* Sysctl tree */
113
SYSCTL_DECL(_net_bluetooth_sco_sockets);
114
static SYSCTL_NODE(_net_bluetooth_sco_sockets, OID_AUTO, seq,
115
CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
116
"Bluetooth SEQPACKET SCO sockets family");
117
SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, debug_level,
118
CTLFLAG_RW,
119
&ng_btsocket_sco_debug_level, NG_BTSOCKET_WARN_LEVEL,
120
"Bluetooth SEQPACKET SCO sockets debug level");
121
SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_len,
122
CTLFLAG_RD,
123
&ng_btsocket_sco_queue.len, 0,
124
"Bluetooth SEQPACKET SCO sockets input queue length");
125
SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_maxlen,
126
CTLFLAG_RD,
127
&ng_btsocket_sco_queue.maxlen, 0,
128
"Bluetooth SEQPACKET SCO sockets input queue max. length");
129
SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_drops,
130
CTLFLAG_RD,
131
&ng_btsocket_sco_queue.drops, 0,
132
"Bluetooth SEQPACKET SCO sockets input queue drops");
133
134
/* Debug */
135
#define NG_BTSOCKET_SCO_INFO \
136
if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_INFO_LEVEL && \
137
ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
138
printf
139
140
#define NG_BTSOCKET_SCO_WARN \
141
if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_WARN_LEVEL && \
142
ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
143
printf
144
145
#define NG_BTSOCKET_SCO_ERR \
146
if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ERR_LEVEL && \
147
ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
148
printf
149
150
#define NG_BTSOCKET_SCO_ALERT \
151
if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \
152
ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
153
printf
154
155
/*
156
* Netgraph message processing routines
157
*/
158
159
static int ng_btsocket_sco_process_lp_con_cfm
160
(struct ng_mesg *, ng_btsocket_sco_rtentry_p);
161
static int ng_btsocket_sco_process_lp_con_ind
162
(struct ng_mesg *, ng_btsocket_sco_rtentry_p);
163
static int ng_btsocket_sco_process_lp_discon_ind
164
(struct ng_mesg *, ng_btsocket_sco_rtentry_p);
165
166
/*
167
* Send LP messages to the lower layer
168
*/
169
170
static int ng_btsocket_sco_send_lp_con_req
171
(ng_btsocket_sco_pcb_p);
172
static int ng_btsocket_sco_send_lp_con_rsp
173
(ng_btsocket_sco_rtentry_p, bdaddr_p, int);
174
static int ng_btsocket_sco_send_lp_discon_req
175
(ng_btsocket_sco_pcb_p);
176
177
static int ng_btsocket_sco_send2
178
(ng_btsocket_sco_pcb_p);
179
180
/*
181
* Timeout processing routines
182
*/
183
184
static void ng_btsocket_sco_timeout (ng_btsocket_sco_pcb_p);
185
static void ng_btsocket_sco_untimeout (ng_btsocket_sco_pcb_p);
186
static void ng_btsocket_sco_process_timeout (void *);
187
188
/*
189
* Other stuff
190
*/
191
192
static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_addr(bdaddr_p);
193
static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_handle(bdaddr_p, int);
194
static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_addrs(bdaddr_p, bdaddr_p);
195
196
#define ng_btsocket_sco_wakeup_input_task() \
197
taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_queue_task)
198
199
#define ng_btsocket_sco_wakeup_route_task() \
200
taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_rt_task)
201
202
/*****************************************************************************
203
*****************************************************************************
204
** Netgraph node interface
205
*****************************************************************************
206
*****************************************************************************/
207
208
/*
209
* Netgraph node constructor. Do not allow to create node of this type.
210
*/
211
212
static int
213
ng_btsocket_sco_node_constructor(node_p node)
214
{
215
return (EINVAL);
216
} /* ng_btsocket_sco_node_constructor */
217
218
/*
219
* Do local shutdown processing. Let old node go and create new fresh one.
220
*/
221
222
static int
223
ng_btsocket_sco_node_shutdown(node_p node)
224
{
225
int error = 0;
226
227
NG_NODE_UNREF(node);
228
229
/* Create new node */
230
error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node);
231
if (error != 0) {
232
NG_BTSOCKET_SCO_ALERT(
233
"%s: Could not create Netgraph node, error=%d\n", __func__, error);
234
235
ng_btsocket_sco_node = NULL;
236
237
return (error);
238
}
239
240
error = ng_name_node(ng_btsocket_sco_node,
241
NG_BTSOCKET_SCO_NODE_TYPE);
242
if (error != 0) {
243
NG_BTSOCKET_SCO_ALERT(
244
"%s: Could not name Netgraph node, error=%d\n", __func__, error);
245
246
NG_NODE_UNREF(ng_btsocket_sco_node);
247
ng_btsocket_sco_node = NULL;
248
249
return (error);
250
}
251
252
return (0);
253
} /* ng_btsocket_sco_node_shutdown */
254
255
/*
256
* We allow any hook to be connected to the node.
257
*/
258
259
static int
260
ng_btsocket_sco_node_newhook(node_p node, hook_p hook, char const *name)
261
{
262
return (0);
263
} /* ng_btsocket_sco_node_newhook */
264
265
/*
266
* Just say "YEP, that's OK by me!"
267
*/
268
269
static int
270
ng_btsocket_sco_node_connect(hook_p hook)
271
{
272
NG_HOOK_SET_PRIVATE(hook, NULL);
273
NG_HOOK_REF(hook); /* Keep extra reference to the hook */
274
275
#if 0
276
NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
277
NG_HOOK_FORCE_QUEUE(hook);
278
#endif
279
280
return (0);
281
} /* ng_btsocket_sco_node_connect */
282
283
/*
284
* Hook disconnection. Schedule route cleanup task
285
*/
286
287
static int
288
ng_btsocket_sco_node_disconnect(hook_p hook)
289
{
290
/*
291
* If hook has private information than we must have this hook in
292
* the routing table and must schedule cleaning for the routing table.
293
* Otherwise hook was connected but we never got "hook_info" message,
294
* so we have never added this hook to the routing table and it save
295
* to just delete it.
296
*/
297
298
if (NG_HOOK_PRIVATE(hook) != NULL)
299
return (ng_btsocket_sco_wakeup_route_task());
300
301
NG_HOOK_UNREF(hook); /* Remove extra reference */
302
303
return (0);
304
} /* ng_btsocket_sco_node_disconnect */
305
306
/*
307
* Process incoming messages
308
*/
309
310
static int
311
ng_btsocket_sco_node_rcvmsg(node_p node, item_p item, hook_p hook)
312
{
313
struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
314
int error = 0;
315
316
if (msg != NULL && msg->header.typecookie == NGM_HCI_COOKIE) {
317
mtx_lock(&ng_btsocket_sco_queue_mtx);
318
if (NG_BT_ITEMQ_FULL(&ng_btsocket_sco_queue)) {
319
NG_BTSOCKET_SCO_ERR(
320
"%s: Input queue is full (msg)\n", __func__);
321
322
NG_BT_ITEMQ_DROP(&ng_btsocket_sco_queue);
323
NG_FREE_ITEM(item);
324
error = ENOBUFS;
325
} else {
326
if (hook != NULL) {
327
NG_HOOK_REF(hook);
328
NGI_SET_HOOK(item, hook);
329
}
330
331
NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_sco_queue, item);
332
error = ng_btsocket_sco_wakeup_input_task();
333
}
334
mtx_unlock(&ng_btsocket_sco_queue_mtx);
335
} else {
336
NG_FREE_ITEM(item);
337
error = EINVAL;
338
}
339
340
return (error);
341
} /* ng_btsocket_sco_node_rcvmsg */
342
343
/*
344
* Receive data on a hook
345
*/
346
347
static int
348
ng_btsocket_sco_node_rcvdata(hook_p hook, item_p item)
349
{
350
int error = 0;
351
352
mtx_lock(&ng_btsocket_sco_queue_mtx);
353
if (NG_BT_ITEMQ_FULL(&ng_btsocket_sco_queue)) {
354
NG_BTSOCKET_SCO_ERR(
355
"%s: Input queue is full (data)\n", __func__);
356
357
NG_BT_ITEMQ_DROP(&ng_btsocket_sco_queue);
358
NG_FREE_ITEM(item);
359
error = ENOBUFS;
360
} else {
361
NG_HOOK_REF(hook);
362
NGI_SET_HOOK(item, hook);
363
364
NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_sco_queue, item);
365
error = ng_btsocket_sco_wakeup_input_task();
366
}
367
mtx_unlock(&ng_btsocket_sco_queue_mtx);
368
369
return (error);
370
} /* ng_btsocket_sco_node_rcvdata */
371
372
/*
373
* Process LP_ConnectCfm event from the lower layer protocol
374
*/
375
376
static int
377
ng_btsocket_sco_process_lp_con_cfm(struct ng_mesg *msg,
378
ng_btsocket_sco_rtentry_p rt)
379
{
380
ng_hci_lp_con_cfm_ep *ep = NULL;
381
ng_btsocket_sco_pcb_t *pcb = NULL;
382
int error = 0;
383
384
if (msg->header.arglen != sizeof(*ep))
385
return (EMSGSIZE);
386
387
ep = (ng_hci_lp_con_cfm_ep *)(msg->data);
388
389
mtx_lock(&ng_btsocket_sco_sockets_mtx);
390
391
/* Look for the socket with the token */
392
pcb = ng_btsocket_sco_pcb_by_addrs(&rt->src, &ep->bdaddr);
393
if (pcb == NULL) {
394
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
395
return (ENOENT);
396
}
397
398
/* pcb is locked */
399
400
NG_BTSOCKET_SCO_INFO(
401
"%s: Got LP_ConnectCfm response, src bdaddr=%x:%x:%x:%x:%x:%x, " \
402
"dst bdaddr=%x:%x:%x:%x:%x:%x, status=%d, handle=%d, state=%d\n",
403
__func__,
404
pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
405
pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
406
pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
407
pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
408
ep->status, ep->con_handle, pcb->state);
409
410
if (pcb->state != NG_BTSOCKET_SCO_CONNECTING) {
411
mtx_unlock(&pcb->pcb_mtx);
412
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
413
414
return (ENOENT);
415
}
416
417
ng_btsocket_sco_untimeout(pcb);
418
419
if (ep->status == 0) {
420
/*
421
* Connection is open. Update connection handle and
422
* socket state
423
*/
424
425
pcb->con_handle = ep->con_handle;
426
pcb->state = NG_BTSOCKET_SCO_OPEN;
427
soisconnected(pcb->so);
428
} else {
429
/*
430
* We have failed to open connection, so disconnect the socket
431
*/
432
433
pcb->so->so_error = ECONNREFUSED; /* XXX convert status ??? */
434
pcb->state = NG_BTSOCKET_SCO_CLOSED;
435
soisdisconnected(pcb->so);
436
}
437
438
mtx_unlock(&pcb->pcb_mtx);
439
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
440
441
return (error);
442
} /* ng_btsocket_sco_process_lp_con_cfm */
443
444
/*
445
* Process LP_ConnectInd indicator. Find socket that listens on address.
446
* Find exact or closest match.
447
*/
448
449
static int
450
ng_btsocket_sco_process_lp_con_ind(struct ng_mesg *msg,
451
ng_btsocket_sco_rtentry_p rt)
452
{
453
ng_hci_lp_con_ind_ep *ep = NULL;
454
ng_btsocket_sco_pcb_t *pcb = NULL, *pcb1 = NULL;
455
int error = 0;
456
u_int16_t status = 0;
457
458
if (msg->header.arglen != sizeof(*ep))
459
return (EMSGSIZE);
460
461
ep = (ng_hci_lp_con_ind_ep *)(msg->data);
462
463
NG_BTSOCKET_SCO_INFO(
464
"%s: Got LP_ConnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
465
"dst bdaddr=%x:%x:%x:%x:%x:%x\n",
466
__func__,
467
rt->src.b[5], rt->src.b[4], rt->src.b[3],
468
rt->src.b[2], rt->src.b[1], rt->src.b[0],
469
ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
470
ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
471
472
mtx_lock(&ng_btsocket_sco_sockets_mtx);
473
474
pcb = ng_btsocket_sco_pcb_by_addr(&rt->src);
475
if (pcb != NULL) {
476
struct socket *so1;
477
478
/* pcb is locked */
479
480
CURVNET_SET(pcb->so->so_vnet);
481
so1 = sonewconn(pcb->so, 0);
482
CURVNET_RESTORE();
483
484
if (so1 == NULL) {
485
status = 0x0d; /* Rejected due to limited resources */
486
goto respond;
487
}
488
489
/*
490
* If we got here than we have created new socket. So complete
491
* connection. If we we listening on specific address then copy
492
* source address from listening socket, otherwise copy source
493
* address from hook's routing information.
494
*/
495
496
pcb1 = so2sco_pcb(so1);
497
KASSERT((pcb1 != NULL),
498
("%s: pcb1 == NULL\n", __func__));
499
500
mtx_lock(&pcb1->pcb_mtx);
501
502
if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)) != 0)
503
bcopy(&pcb->src, &pcb1->src, sizeof(pcb1->src));
504
else
505
bcopy(&rt->src, &pcb1->src, sizeof(pcb1->src));
506
507
pcb1->flags &= ~NG_BTSOCKET_SCO_CLIENT;
508
509
bcopy(&ep->bdaddr, &pcb1->dst, sizeof(pcb1->dst));
510
pcb1->rt = rt;
511
} else
512
/* Nobody listens on requested BDADDR */
513
status = 0x1f; /* Unspecified Error */
514
515
respond:
516
error = ng_btsocket_sco_send_lp_con_rsp(rt, &ep->bdaddr, status);
517
if (pcb1 != NULL) {
518
if (error != 0) {
519
pcb1->so->so_error = error;
520
pcb1->state = NG_BTSOCKET_SCO_CLOSED;
521
soisdisconnected(pcb1->so);
522
} else {
523
pcb1->state = NG_BTSOCKET_SCO_CONNECTING;
524
soisconnecting(pcb1->so);
525
526
ng_btsocket_sco_timeout(pcb1);
527
}
528
529
mtx_unlock(&pcb1->pcb_mtx);
530
}
531
532
if (pcb != NULL)
533
mtx_unlock(&pcb->pcb_mtx);
534
535
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
536
537
return (error);
538
} /* ng_btsocket_sco_process_lp_con_ind */
539
540
/*
541
* Process LP_DisconnectInd indicator
542
*/
543
544
static int
545
ng_btsocket_sco_process_lp_discon_ind(struct ng_mesg *msg,
546
ng_btsocket_sco_rtentry_p rt)
547
{
548
ng_hci_lp_discon_ind_ep *ep = NULL;
549
ng_btsocket_sco_pcb_t *pcb = NULL;
550
551
/* Check message */
552
if (msg->header.arglen != sizeof(*ep))
553
return (EMSGSIZE);
554
555
ep = (ng_hci_lp_discon_ind_ep *)(msg->data);
556
557
mtx_lock(&ng_btsocket_sco_sockets_mtx);
558
559
/* Look for the socket with given channel ID */
560
pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle);
561
if (pcb == NULL) {
562
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
563
return (0);
564
}
565
566
/*
567
* Disconnect the socket. If there was any pending request we can
568
* not do anything here anyway.
569
*/
570
571
/* pcb is locked */
572
573
NG_BTSOCKET_SCO_INFO(
574
"%s: Got LP_DisconnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
575
"dst bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, state=%d\n",
576
__func__,
577
pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
578
pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
579
pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
580
pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
581
pcb->con_handle, pcb->state);
582
583
if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
584
ng_btsocket_sco_untimeout(pcb);
585
586
pcb->state = NG_BTSOCKET_SCO_CLOSED;
587
soisdisconnected(pcb->so);
588
589
mtx_unlock(&pcb->pcb_mtx);
590
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
591
592
return (0);
593
} /* ng_btsocket_sco_process_lp_discon_ind */
594
595
/*
596
* Send LP_ConnectReq request
597
*/
598
599
static int
600
ng_btsocket_sco_send_lp_con_req(ng_btsocket_sco_pcb_p pcb)
601
{
602
struct ng_mesg *msg = NULL;
603
ng_hci_lp_con_req_ep *ep = NULL;
604
int error = 0;
605
606
mtx_assert(&pcb->pcb_mtx, MA_OWNED);
607
608
if (pcb->rt == NULL ||
609
pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
610
return (ENETDOWN);
611
612
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ,
613
sizeof(*ep), M_NOWAIT);
614
if (msg == NULL)
615
return (ENOMEM);
616
617
ep = (ng_hci_lp_con_req_ep *)(msg->data);
618
ep->link_type = NG_HCI_LINK_SCO;
619
bcopy(&pcb->dst, &ep->bdaddr, sizeof(ep->bdaddr));
620
621
NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0);
622
623
return (error);
624
} /* ng_btsocket_sco_send_lp_con_req */
625
626
/*
627
* Send LP_ConnectRsp response
628
*/
629
630
static int
631
ng_btsocket_sco_send_lp_con_rsp(ng_btsocket_sco_rtentry_p rt, bdaddr_p dst, int status)
632
{
633
struct ng_mesg *msg = NULL;
634
ng_hci_lp_con_rsp_ep *ep = NULL;
635
int error = 0;
636
637
if (rt == NULL || rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
638
return (ENETDOWN);
639
640
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP,
641
sizeof(*ep), M_NOWAIT);
642
if (msg == NULL)
643
return (ENOMEM);
644
645
ep = (ng_hci_lp_con_rsp_ep *)(msg->data);
646
ep->status = status;
647
ep->link_type = NG_HCI_LINK_SCO;
648
bcopy(dst, &ep->bdaddr, sizeof(ep->bdaddr));
649
650
NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, rt->hook, 0);
651
652
return (error);
653
} /* ng_btsocket_sco_send_lp_con_rsp */
654
655
/*
656
* Send LP_DisconReq request
657
*/
658
659
static int
660
ng_btsocket_sco_send_lp_discon_req(ng_btsocket_sco_pcb_p pcb)
661
{
662
struct ng_mesg *msg = NULL;
663
ng_hci_lp_discon_req_ep *ep = NULL;
664
int error = 0;
665
666
mtx_assert(&pcb->pcb_mtx, MA_OWNED);
667
668
if (pcb->rt == NULL ||
669
pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
670
return (ENETDOWN);
671
672
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_REQ,
673
sizeof(*ep), M_NOWAIT);
674
if (msg == NULL)
675
return (ENOMEM);
676
677
ep = (ng_hci_lp_discon_req_ep *)(msg->data);
678
ep->con_handle = pcb->con_handle;
679
ep->reason = 0x13; /* User Ended Connection */
680
681
NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0);
682
683
return (error);
684
} /* ng_btsocket_sco_send_lp_discon_req */
685
686
/*****************************************************************************
687
*****************************************************************************
688
** Socket interface
689
*****************************************************************************
690
*****************************************************************************/
691
692
/*
693
* SCO sockets data input routine
694
*/
695
696
static void
697
ng_btsocket_sco_data_input(struct mbuf *m, hook_p hook)
698
{
699
ng_hci_scodata_pkt_t *hdr = NULL;
700
ng_btsocket_sco_pcb_t *pcb = NULL;
701
ng_btsocket_sco_rtentry_t *rt = NULL;
702
u_int16_t con_handle;
703
704
if (hook == NULL) {
705
NG_BTSOCKET_SCO_ALERT(
706
"%s: Invalid source hook for SCO data packet\n", __func__);
707
goto drop;
708
}
709
710
rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook);
711
if (rt == NULL) {
712
NG_BTSOCKET_SCO_ALERT(
713
"%s: Could not find out source bdaddr for SCO data packet\n", __func__);
714
goto drop;
715
}
716
717
/* Make sure we can access header */
718
if (m->m_pkthdr.len < sizeof(*hdr)) {
719
NG_BTSOCKET_SCO_ERR(
720
"%s: SCO data packet too small, len=%d\n", __func__, m->m_pkthdr.len);
721
goto drop;
722
}
723
724
if (m->m_len < sizeof(*hdr)) {
725
m = m_pullup(m, sizeof(*hdr));
726
if (m == NULL)
727
goto drop;
728
}
729
730
/* Strip SCO packet header and verify packet length */
731
hdr = mtod(m, ng_hci_scodata_pkt_t *);
732
m_adj(m, sizeof(*hdr));
733
734
if (hdr->length != m->m_pkthdr.len) {
735
NG_BTSOCKET_SCO_ERR(
736
"%s: Bad SCO data packet length, len=%d, length=%d\n",
737
__func__, m->m_pkthdr.len, hdr->length);
738
goto drop;
739
}
740
741
/*
742
* Now process packet
743
*/
744
745
con_handle = NG_HCI_CON_HANDLE(le16toh(hdr->con_handle));
746
747
NG_BTSOCKET_SCO_INFO(
748
"%s: Received SCO data packet: src bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, " \
749
"length=%d\n", __func__,
750
rt->src.b[5], rt->src.b[4], rt->src.b[3],
751
rt->src.b[2], rt->src.b[1], rt->src.b[0],
752
con_handle, hdr->length);
753
754
mtx_lock(&ng_btsocket_sco_sockets_mtx);
755
756
/* Find socket */
757
pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, con_handle);
758
if (pcb == NULL) {
759
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
760
goto drop;
761
}
762
763
/* pcb is locked */
764
765
if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
766
NG_BTSOCKET_SCO_ERR(
767
"%s: No connected socket found, src bdaddr=%x:%x:%x:%x:%x:%x, state=%d\n",
768
__func__,
769
rt->src.b[5], rt->src.b[4], rt->src.b[3],
770
rt->src.b[2], rt->src.b[1], rt->src.b[0],
771
pcb->state);
772
773
mtx_unlock(&pcb->pcb_mtx);
774
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
775
goto drop;
776
}
777
778
/* Check if we have enough space in socket receive queue */
779
if (m->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) {
780
NG_BTSOCKET_SCO_ERR(
781
"%s: Not enough space in socket receive queue. Dropping SCO data packet, " \
782
"src bdaddr=%x:%x:%x:%x:%x:%x, len=%d, space=%ld\n",
783
__func__,
784
rt->src.b[5], rt->src.b[4], rt->src.b[3],
785
rt->src.b[2], rt->src.b[1], rt->src.b[0],
786
m->m_pkthdr.len,
787
sbspace(&pcb->so->so_rcv));
788
789
mtx_unlock(&pcb->pcb_mtx);
790
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
791
goto drop;
792
}
793
794
/* Append packet to the socket receive queue and wakeup */
795
sbappendrecord(&pcb->so->so_rcv, m);
796
m = NULL;
797
798
sorwakeup(pcb->so);
799
800
mtx_unlock(&pcb->pcb_mtx);
801
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
802
drop:
803
NG_FREE_M(m); /* checks for m != NULL */
804
} /* ng_btsocket_sco_data_input */
805
806
/*
807
* SCO sockets default message input routine
808
*/
809
810
static void
811
ng_btsocket_sco_default_msg_input(struct ng_mesg *msg, hook_p hook)
812
{
813
ng_btsocket_sco_rtentry_t *rt = NULL;
814
815
if (hook == NULL || NG_HOOK_NOT_VALID(hook))
816
return;
817
818
rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook);
819
820
switch (msg->header.cmd) {
821
case NGM_HCI_NODE_UP: {
822
ng_hci_node_up_ep *ep = NULL;
823
824
if (msg->header.arglen != sizeof(*ep))
825
break;
826
827
ep = (ng_hci_node_up_ep *)(msg->data);
828
if (bcmp(&ep->bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
829
break;
830
831
if (rt == NULL) {
832
rt = malloc(sizeof(*rt),
833
M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT|M_ZERO);
834
if (rt == NULL)
835
break;
836
837
NG_HOOK_SET_PRIVATE(hook, rt);
838
839
mtx_lock(&ng_btsocket_sco_rt_mtx);
840
841
LIST_INSERT_HEAD(&ng_btsocket_sco_rt, rt, next);
842
} else
843
mtx_lock(&ng_btsocket_sco_rt_mtx);
844
845
bcopy(&ep->bdaddr, &rt->src, sizeof(rt->src));
846
rt->pkt_size = (ep->pkt_size == 0)? 60 : ep->pkt_size;
847
rt->num_pkts = ep->num_pkts;
848
rt->hook = hook;
849
850
mtx_unlock(&ng_btsocket_sco_rt_mtx);
851
852
NG_BTSOCKET_SCO_INFO(
853
"%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x, pkt_size=%d, " \
854
"num_pkts=%d\n", __func__, NG_HOOK_NAME(hook),
855
rt->src.b[5], rt->src.b[4], rt->src.b[3],
856
rt->src.b[2], rt->src.b[1], rt->src.b[0],
857
rt->pkt_size, rt->num_pkts);
858
} break;
859
860
case NGM_HCI_SYNC_CON_QUEUE: {
861
ng_hci_sync_con_queue_ep *ep = NULL;
862
ng_btsocket_sco_pcb_t *pcb = NULL;
863
864
if (rt == NULL || msg->header.arglen != sizeof(*ep))
865
break;
866
867
ep = (ng_hci_sync_con_queue_ep *)(msg->data);
868
869
rt->pending -= ep->completed;
870
if (rt->pending < 0) {
871
NG_BTSOCKET_SCO_WARN(
872
"%s: Pending packet counter is out of sync! bdaddr=%x:%x:%x:%x:%x:%x, " \
873
"handle=%d, pending=%d, completed=%d\n",
874
__func__,
875
rt->src.b[5], rt->src.b[4], rt->src.b[3],
876
rt->src.b[2], rt->src.b[1], rt->src.b[0],
877
ep->con_handle, rt->pending,
878
ep->completed);
879
880
rt->pending = 0;
881
}
882
883
mtx_lock(&ng_btsocket_sco_sockets_mtx);
884
885
/* Find socket */
886
pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle);
887
if (pcb == NULL) {
888
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
889
break;
890
}
891
892
/* pcb is locked */
893
894
/* Check state */
895
if (pcb->state == NG_BTSOCKET_SCO_OPEN) {
896
/* Remove timeout */
897
ng_btsocket_sco_untimeout(pcb);
898
899
/* Drop completed packets from the send queue */
900
for (; ep->completed > 0; ep->completed --)
901
sbdroprecord(&pcb->so->so_snd);
902
903
/* Send more if we have any */
904
if (sbavail(&pcb->so->so_snd) > 0)
905
if (ng_btsocket_sco_send2(pcb) == 0)
906
ng_btsocket_sco_timeout(pcb);
907
908
/* Wake up writers */
909
sowwakeup(pcb->so);
910
}
911
912
mtx_unlock(&pcb->pcb_mtx);
913
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
914
} break;
915
916
default:
917
NG_BTSOCKET_SCO_WARN(
918
"%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
919
break;
920
}
921
922
NG_FREE_MSG(msg); /* Checks for msg != NULL */
923
} /* ng_btsocket_sco_default_msg_input */
924
925
/*
926
* SCO sockets LP message input routine
927
*/
928
929
static void
930
ng_btsocket_sco_lp_msg_input(struct ng_mesg *msg, hook_p hook)
931
{
932
ng_btsocket_sco_rtentry_p rt = NULL;
933
934
if (hook == NULL) {
935
NG_BTSOCKET_SCO_ALERT(
936
"%s: Invalid source hook for LP message\n", __func__);
937
goto drop;
938
}
939
940
rt = (ng_btsocket_sco_rtentry_p) NG_HOOK_PRIVATE(hook);
941
if (rt == NULL) {
942
NG_BTSOCKET_SCO_ALERT(
943
"%s: Could not find out source bdaddr for LP message\n", __func__);
944
goto drop;
945
}
946
947
switch (msg->header.cmd) {
948
case NGM_HCI_LP_CON_CFM: /* Connection Confirmation Event */
949
ng_btsocket_sco_process_lp_con_cfm(msg, rt);
950
break;
951
952
case NGM_HCI_LP_CON_IND: /* Connection Indication Event */
953
ng_btsocket_sco_process_lp_con_ind(msg, rt);
954
break;
955
956
case NGM_HCI_LP_DISCON_IND: /* Disconnection Indication Event */
957
ng_btsocket_sco_process_lp_discon_ind(msg, rt);
958
break;
959
960
/* XXX FIXME add other LP messages */
961
962
default:
963
NG_BTSOCKET_SCO_WARN(
964
"%s: Unknown LP message, cmd=%d\n", __func__, msg->header.cmd);
965
break;
966
}
967
drop:
968
NG_FREE_MSG(msg);
969
} /* ng_btsocket_sco_lp_msg_input */
970
971
/*
972
* SCO sockets input routine
973
*/
974
975
static void
976
ng_btsocket_sco_input(void *context, int pending)
977
{
978
item_p item = NULL;
979
hook_p hook = NULL;
980
981
for (;;) {
982
mtx_lock(&ng_btsocket_sco_queue_mtx);
983
NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_sco_queue, item);
984
mtx_unlock(&ng_btsocket_sco_queue_mtx);
985
986
if (item == NULL)
987
break;
988
989
NGI_GET_HOOK(item, hook);
990
if (hook != NULL && NG_HOOK_NOT_VALID(hook))
991
goto drop;
992
993
switch(item->el_flags & NGQF_TYPE) {
994
case NGQF_DATA: {
995
struct mbuf *m = NULL;
996
997
NGI_GET_M(item, m);
998
ng_btsocket_sco_data_input(m, hook);
999
} break;
1000
1001
case NGQF_MESG: {
1002
struct ng_mesg *msg = NULL;
1003
1004
NGI_GET_MSG(item, msg);
1005
1006
switch (msg->header.cmd) {
1007
case NGM_HCI_LP_CON_CFM:
1008
case NGM_HCI_LP_CON_IND:
1009
case NGM_HCI_LP_DISCON_IND:
1010
/* XXX FIXME add other LP messages */
1011
ng_btsocket_sco_lp_msg_input(msg, hook);
1012
break;
1013
1014
default:
1015
ng_btsocket_sco_default_msg_input(msg, hook);
1016
break;
1017
}
1018
} break;
1019
1020
default:
1021
KASSERT(0,
1022
("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
1023
break;
1024
}
1025
drop:
1026
if (hook != NULL)
1027
NG_HOOK_UNREF(hook);
1028
1029
NG_FREE_ITEM(item);
1030
}
1031
} /* ng_btsocket_sco_input */
1032
1033
/*
1034
* Route cleanup task. Gets scheduled when hook is disconnected. Here we
1035
* will find all sockets that use "invalid" hook and disconnect them.
1036
*/
1037
1038
static void
1039
ng_btsocket_sco_rtclean(void *context, int pending)
1040
{
1041
ng_btsocket_sco_pcb_p pcb = NULL, pcb_next = NULL;
1042
ng_btsocket_sco_rtentry_p rt = NULL;
1043
1044
/*
1045
* First disconnect all sockets that use "invalid" hook
1046
*/
1047
1048
mtx_lock(&ng_btsocket_sco_sockets_mtx);
1049
1050
for(pcb = LIST_FIRST(&ng_btsocket_sco_sockets); pcb != NULL; ) {
1051
mtx_lock(&pcb->pcb_mtx);
1052
pcb_next = LIST_NEXT(pcb, next);
1053
1054
if (pcb->rt != NULL &&
1055
pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1056
if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1057
ng_btsocket_sco_untimeout(pcb);
1058
1059
pcb->rt = NULL;
1060
pcb->so->so_error = ENETDOWN;
1061
pcb->state = NG_BTSOCKET_SCO_CLOSED;
1062
soisdisconnected(pcb->so);
1063
}
1064
1065
mtx_unlock(&pcb->pcb_mtx);
1066
pcb = pcb_next;
1067
}
1068
1069
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1070
1071
/*
1072
* Now cleanup routing table
1073
*/
1074
1075
mtx_lock(&ng_btsocket_sco_rt_mtx);
1076
1077
for (rt = LIST_FIRST(&ng_btsocket_sco_rt); rt != NULL; ) {
1078
ng_btsocket_sco_rtentry_p rt_next = LIST_NEXT(rt, next);
1079
1080
if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
1081
LIST_REMOVE(rt, next);
1082
1083
NG_HOOK_SET_PRIVATE(rt->hook, NULL);
1084
NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
1085
1086
bzero(rt, sizeof(*rt));
1087
free(rt, M_NETGRAPH_BTSOCKET_SCO);
1088
}
1089
1090
rt = rt_next;
1091
}
1092
1093
mtx_unlock(&ng_btsocket_sco_rt_mtx);
1094
} /* ng_btsocket_sco_rtclean */
1095
1096
/*
1097
* Initialize everything
1098
*/
1099
1100
static void
1101
ng_btsocket_sco_init(void *arg __unused)
1102
{
1103
int error = 0;
1104
1105
ng_btsocket_sco_node = NULL;
1106
ng_btsocket_sco_debug_level = NG_BTSOCKET_WARN_LEVEL;
1107
1108
/* Register Netgraph node type */
1109
error = ng_newtype(&typestruct);
1110
if (error != 0) {
1111
NG_BTSOCKET_SCO_ALERT(
1112
"%s: Could not register Netgraph node type, error=%d\n", __func__, error);
1113
1114
return;
1115
}
1116
1117
/* Create Netgrapg node */
1118
error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node);
1119
if (error != 0) {
1120
NG_BTSOCKET_SCO_ALERT(
1121
"%s: Could not create Netgraph node, error=%d\n", __func__, error);
1122
1123
ng_btsocket_sco_node = NULL;
1124
1125
return;
1126
}
1127
1128
error = ng_name_node(ng_btsocket_sco_node, NG_BTSOCKET_SCO_NODE_TYPE);
1129
if (error != 0) {
1130
NG_BTSOCKET_SCO_ALERT(
1131
"%s: Could not name Netgraph node, error=%d\n", __func__, error);
1132
1133
NG_NODE_UNREF(ng_btsocket_sco_node);
1134
ng_btsocket_sco_node = NULL;
1135
1136
return;
1137
}
1138
1139
/* Create input queue */
1140
NG_BT_ITEMQ_INIT(&ng_btsocket_sco_queue, 300);
1141
mtx_init(&ng_btsocket_sco_queue_mtx,
1142
"btsocks_sco_queue_mtx", NULL, MTX_DEF);
1143
TASK_INIT(&ng_btsocket_sco_queue_task, 0,
1144
ng_btsocket_sco_input, NULL);
1145
1146
/* Create list of sockets */
1147
LIST_INIT(&ng_btsocket_sco_sockets);
1148
mtx_init(&ng_btsocket_sco_sockets_mtx,
1149
"btsocks_sco_sockets_mtx", NULL, MTX_DEF);
1150
1151
/* Routing table */
1152
LIST_INIT(&ng_btsocket_sco_rt);
1153
mtx_init(&ng_btsocket_sco_rt_mtx,
1154
"btsocks_sco_rt_mtx", NULL, MTX_DEF);
1155
TASK_INIT(&ng_btsocket_sco_rt_task, 0,
1156
ng_btsocket_sco_rtclean, NULL);
1157
} /* ng_btsocket_sco_init */
1158
SYSINIT(ng_btsocket_sco_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
1159
ng_btsocket_sco_init, NULL);
1160
1161
/*
1162
* Abort connection on socket
1163
*/
1164
1165
void
1166
ng_btsocket_sco_abort(struct socket *so)
1167
{
1168
so->so_error = ECONNABORTED;
1169
1170
(void) ng_btsocket_sco_disconnect(so);
1171
} /* ng_btsocket_sco_abort */
1172
1173
void
1174
ng_btsocket_sco_close(struct socket *so)
1175
{
1176
(void) ng_btsocket_sco_disconnect(so);
1177
} /* ng_btsocket_sco_close */
1178
1179
/*
1180
* Create and attach new socket
1181
*/
1182
1183
int
1184
ng_btsocket_sco_attach(struct socket *so, int proto, struct thread *td)
1185
{
1186
ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1187
int error;
1188
1189
/* Check socket and protocol */
1190
if (ng_btsocket_sco_node == NULL)
1191
return (EPROTONOSUPPORT);
1192
if (so->so_type != SOCK_SEQPACKET)
1193
return (ESOCKTNOSUPPORT);
1194
1195
#if 0 /* XXX sonewconn() calls pr_attach() with proto == 0 */
1196
if (proto != 0)
1197
if (proto != BLUETOOTH_PROTO_SCO)
1198
return (EPROTONOSUPPORT);
1199
#endif /* XXX */
1200
1201
if (pcb != NULL)
1202
return (EISCONN);
1203
1204
/* Reserve send and receive space if it is not reserved yet */
1205
if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) {
1206
error = soreserve(so, NG_BTSOCKET_SCO_SENDSPACE,
1207
NG_BTSOCKET_SCO_RECVSPACE);
1208
if (error != 0)
1209
return (error);
1210
}
1211
1212
/* Allocate the PCB */
1213
pcb = malloc(sizeof(*pcb),
1214
M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT | M_ZERO);
1215
if (pcb == NULL)
1216
return (ENOMEM);
1217
1218
/* Link the PCB and the socket */
1219
so->so_pcb = (caddr_t) pcb;
1220
pcb->so = so;
1221
pcb->state = NG_BTSOCKET_SCO_CLOSED;
1222
1223
callout_init(&pcb->timo, 1);
1224
1225
/*
1226
* Mark PCB mutex as DUPOK to prevent "duplicated lock of
1227
* the same type" message. When accepting new SCO connection
1228
* ng_btsocket_sco_process_lp_con_ind() holds both PCB mutexes
1229
* for "old" (accepting) PCB and "new" (created) PCB.
1230
*/
1231
1232
mtx_init(&pcb->pcb_mtx, "btsocks_sco_pcb_mtx", NULL,
1233
MTX_DEF|MTX_DUPOK);
1234
1235
/*
1236
* Add the PCB to the list
1237
*
1238
* XXX FIXME VERY IMPORTANT!
1239
*
1240
* This is totally FUBAR. We could get here in two cases:
1241
*
1242
* 1) When user calls socket()
1243
* 2) When we need to accept new incoming connection and call
1244
* sonewconn()
1245
*
1246
* In the first case we must acquire ng_btsocket_sco_sockets_mtx.
1247
* In the second case we hold ng_btsocket_sco_sockets_mtx already.
1248
* So we now need to distinguish between these cases. From reading
1249
* /sys/kern/uipc_socket2.c we can find out that sonewconn() calls
1250
* pr_attach() with proto == 0 and td == NULL. For now use this fact
1251
* to figure out if we were called from socket() or from sonewconn().
1252
*/
1253
1254
if (td != NULL)
1255
mtx_lock(&ng_btsocket_sco_sockets_mtx);
1256
else
1257
mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1258
1259
LIST_INSERT_HEAD(&ng_btsocket_sco_sockets, pcb, next);
1260
1261
if (td != NULL)
1262
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1263
1264
return (0);
1265
} /* ng_btsocket_sco_attach */
1266
1267
/*
1268
* Bind socket
1269
*/
1270
1271
int
1272
ng_btsocket_sco_bind(struct socket *so, struct sockaddr *nam,
1273
struct thread *td)
1274
{
1275
ng_btsocket_sco_pcb_t *pcb = NULL;
1276
struct sockaddr_sco *sa = (struct sockaddr_sco *) nam;
1277
1278
if (ng_btsocket_sco_node == NULL)
1279
return (EINVAL);
1280
1281
/* Verify address */
1282
if (sa == NULL)
1283
return (EINVAL);
1284
if (sa->sco_family != AF_BLUETOOTH)
1285
return (EAFNOSUPPORT);
1286
if (sa->sco_len != sizeof(*sa))
1287
return (EINVAL);
1288
1289
mtx_lock(&ng_btsocket_sco_sockets_mtx);
1290
1291
/*
1292
* Check if other socket has this address already (look for exact
1293
* match in bdaddr) and assign socket address if it's available.
1294
*/
1295
1296
if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(sa->sco_bdaddr)) != 0) {
1297
LIST_FOREACH(pcb, &ng_btsocket_sco_sockets, next) {
1298
mtx_lock(&pcb->pcb_mtx);
1299
1300
if (bcmp(&pcb->src, &sa->sco_bdaddr, sizeof(bdaddr_t)) == 0) {
1301
mtx_unlock(&pcb->pcb_mtx);
1302
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1303
1304
return (EADDRINUSE);
1305
}
1306
1307
mtx_unlock(&pcb->pcb_mtx);
1308
}
1309
}
1310
1311
pcb = so2sco_pcb(so);
1312
if (pcb == NULL) {
1313
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1314
return (EINVAL);
1315
}
1316
1317
mtx_lock(&pcb->pcb_mtx);
1318
bcopy(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src));
1319
mtx_unlock(&pcb->pcb_mtx);
1320
1321
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1322
1323
return (0);
1324
} /* ng_btsocket_sco_bind */
1325
1326
/*
1327
* Connect socket
1328
*/
1329
1330
int
1331
ng_btsocket_sco_connect(struct socket *so, struct sockaddr *nam,
1332
struct thread *td)
1333
{
1334
ng_btsocket_sco_pcb_t *pcb = so2sco_pcb(so);
1335
struct sockaddr_sco *sa = (struct sockaddr_sco *) nam;
1336
ng_btsocket_sco_rtentry_t *rt = NULL;
1337
int have_src, error = 0;
1338
1339
/* Check socket */
1340
if (pcb == NULL)
1341
return (EINVAL);
1342
if (ng_btsocket_sco_node == NULL)
1343
return (EINVAL);
1344
1345
/* Verify address */
1346
if (sa == NULL)
1347
return (EINVAL);
1348
if (sa->sco_family != AF_BLUETOOTH)
1349
return (EAFNOSUPPORT);
1350
if (sa->sco_len != sizeof(*sa))
1351
return (EINVAL);
1352
if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
1353
return (EDESTADDRREQ);
1354
1355
/*
1356
* Routing. Socket should be bound to some source address. The source
1357
* address can be ANY. Destination address must be set and it must not
1358
* be ANY. If source address is ANY then find first rtentry that has
1359
* src != dst.
1360
*/
1361
1362
mtx_lock(&ng_btsocket_sco_rt_mtx);
1363
mtx_lock(&pcb->pcb_mtx);
1364
1365
if (pcb->state == NG_BTSOCKET_SCO_CONNECTING) {
1366
mtx_unlock(&pcb->pcb_mtx);
1367
mtx_unlock(&ng_btsocket_sco_rt_mtx);
1368
1369
return (EINPROGRESS);
1370
}
1371
1372
if (bcmp(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src)) == 0) {
1373
mtx_unlock(&pcb->pcb_mtx);
1374
mtx_unlock(&ng_btsocket_sco_rt_mtx);
1375
1376
return (EINVAL);
1377
}
1378
1379
/* Send destination address and PSM */
1380
bcopy(&sa->sco_bdaddr, &pcb->dst, sizeof(pcb->dst));
1381
1382
pcb->rt = NULL;
1383
have_src = bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src));
1384
1385
LIST_FOREACH(rt, &ng_btsocket_sco_rt, next) {
1386
if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
1387
continue;
1388
1389
/* Match src and dst */
1390
if (have_src) {
1391
if (bcmp(&pcb->src, &rt->src, sizeof(rt->src)) == 0)
1392
break;
1393
} else {
1394
if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
1395
break;
1396
}
1397
}
1398
1399
if (rt != NULL) {
1400
pcb->rt = rt;
1401
1402
if (!have_src)
1403
bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
1404
} else
1405
error = EHOSTUNREACH;
1406
1407
/*
1408
* Send LP_Connect request
1409
*/
1410
1411
if (error == 0) {
1412
error = ng_btsocket_sco_send_lp_con_req(pcb);
1413
if (error == 0) {
1414
pcb->flags |= NG_BTSOCKET_SCO_CLIENT;
1415
pcb->state = NG_BTSOCKET_SCO_CONNECTING;
1416
soisconnecting(pcb->so);
1417
1418
ng_btsocket_sco_timeout(pcb);
1419
}
1420
}
1421
1422
mtx_unlock(&pcb->pcb_mtx);
1423
mtx_unlock(&ng_btsocket_sco_rt_mtx);
1424
1425
return (error);
1426
} /* ng_btsocket_sco_connect */
1427
1428
/*
1429
* Process ioctl's calls on socket
1430
*/
1431
1432
int
1433
ng_btsocket_sco_control(struct socket *so, u_long cmd, void *data,
1434
struct ifnet *ifp, struct thread *td)
1435
{
1436
return (EINVAL);
1437
} /* ng_btsocket_sco_control */
1438
1439
/*
1440
* Process getsockopt/setsockopt system calls
1441
*/
1442
1443
int
1444
ng_btsocket_sco_ctloutput(struct socket *so, struct sockopt *sopt)
1445
{
1446
ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1447
int error, tmp;
1448
1449
if (ng_btsocket_sco_node == NULL)
1450
return (EINVAL);
1451
if (pcb == NULL)
1452
return (EINVAL);
1453
1454
if (sopt->sopt_level != SOL_SCO)
1455
return (0);
1456
1457
mtx_lock(&pcb->pcb_mtx);
1458
1459
switch (sopt->sopt_dir) {
1460
case SOPT_GET:
1461
if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
1462
error = ENOTCONN;
1463
break;
1464
}
1465
1466
switch (sopt->sopt_name) {
1467
case SO_SCO_MTU:
1468
tmp = pcb->rt->pkt_size;
1469
error = sooptcopyout(sopt, &tmp, sizeof(tmp));
1470
break;
1471
1472
case SO_SCO_CONNINFO:
1473
tmp = pcb->con_handle;
1474
error = sooptcopyout(sopt, &tmp, sizeof(tmp));
1475
break;
1476
1477
default:
1478
error = EINVAL;
1479
break;
1480
}
1481
break;
1482
1483
case SOPT_SET:
1484
error = ENOPROTOOPT;
1485
break;
1486
1487
default:
1488
error = EINVAL;
1489
break;
1490
}
1491
1492
mtx_unlock(&pcb->pcb_mtx);
1493
1494
return (error);
1495
} /* ng_btsocket_sco_ctloutput */
1496
1497
/*
1498
* Detach and destroy socket
1499
*/
1500
1501
void
1502
ng_btsocket_sco_detach(struct socket *so)
1503
{
1504
ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1505
1506
KASSERT(pcb != NULL, ("ng_btsocket_sco_detach: pcb == NULL"));
1507
1508
if (ng_btsocket_sco_node == NULL)
1509
return;
1510
1511
mtx_lock(&ng_btsocket_sco_sockets_mtx);
1512
mtx_lock(&pcb->pcb_mtx);
1513
1514
if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1515
ng_btsocket_sco_untimeout(pcb);
1516
1517
if (pcb->state == NG_BTSOCKET_SCO_OPEN)
1518
ng_btsocket_sco_send_lp_discon_req(pcb);
1519
1520
pcb->state = NG_BTSOCKET_SCO_CLOSED;
1521
1522
LIST_REMOVE(pcb, next);
1523
1524
mtx_unlock(&pcb->pcb_mtx);
1525
mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1526
1527
mtx_destroy(&pcb->pcb_mtx);
1528
bzero(pcb, sizeof(*pcb));
1529
free(pcb, M_NETGRAPH_BTSOCKET_SCO);
1530
1531
soisdisconnected(so);
1532
so->so_pcb = NULL;
1533
} /* ng_btsocket_sco_detach */
1534
1535
/*
1536
* Disconnect socket
1537
*/
1538
1539
int
1540
ng_btsocket_sco_disconnect(struct socket *so)
1541
{
1542
ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1543
1544
if (pcb == NULL)
1545
return (EINVAL);
1546
if (ng_btsocket_sco_node == NULL)
1547
return (EINVAL);
1548
1549
mtx_lock(&pcb->pcb_mtx);
1550
1551
if (pcb->state == NG_BTSOCKET_SCO_DISCONNECTING) {
1552
mtx_unlock(&pcb->pcb_mtx);
1553
1554
return (EINPROGRESS);
1555
}
1556
1557
if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1558
ng_btsocket_sco_untimeout(pcb);
1559
1560
if (pcb->state == NG_BTSOCKET_SCO_OPEN) {
1561
ng_btsocket_sco_send_lp_discon_req(pcb);
1562
1563
pcb->state = NG_BTSOCKET_SCO_DISCONNECTING;
1564
soisdisconnecting(so);
1565
1566
ng_btsocket_sco_timeout(pcb);
1567
} else {
1568
pcb->state = NG_BTSOCKET_SCO_CLOSED;
1569
soisdisconnected(so);
1570
}
1571
1572
mtx_unlock(&pcb->pcb_mtx);
1573
1574
return (0);
1575
} /* ng_btsocket_sco_disconnect */
1576
1577
/*
1578
* Listen on socket
1579
*/
1580
1581
int
1582
ng_btsocket_sco_listen(struct socket *so, int backlog, struct thread *td)
1583
{
1584
ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1585
int error;
1586
1587
if (pcb == NULL)
1588
return (EINVAL);
1589
if (ng_btsocket_sco_node == NULL)
1590
return (EINVAL);
1591
1592
SOCK_LOCK(so);
1593
mtx_lock(&pcb->pcb_mtx);
1594
1595
error = solisten_proto_check(so);
1596
if (error != 0)
1597
goto out;
1598
#if 0
1599
if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) {
1600
error = EDESTADDRREQ;
1601
goto out;
1602
}
1603
#endif
1604
solisten_proto(so, backlog);
1605
out:
1606
mtx_unlock(&pcb->pcb_mtx);
1607
SOCK_UNLOCK(so);
1608
1609
return (error);
1610
} /* ng_btsocket_listen */
1611
1612
/*
1613
* Return peer address for getpeername(2) or for accept(2). For the latter
1614
* case no extra work to do here, socket must be connected and ready.
1615
*/
1616
int
1617
ng_btsocket_sco_peeraddr(struct socket *so, struct sockaddr *sa)
1618
{
1619
ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1620
struct sockaddr_sco *sco = (struct sockaddr_sco *)sa;
1621
1622
if (pcb == NULL)
1623
return (EINVAL);
1624
if (ng_btsocket_sco_node == NULL)
1625
return (EINVAL);
1626
1627
*sco = (struct sockaddr_sco ){
1628
.sco_len = sizeof(struct sockaddr_sco),
1629
.sco_family = AF_BLUETOOTH,
1630
};
1631
mtx_lock(&pcb->pcb_mtx);
1632
bcopy(&pcb->dst, &sco->sco_bdaddr, sizeof(sco->sco_bdaddr));
1633
mtx_unlock(&pcb->pcb_mtx);
1634
1635
return (0);
1636
}
1637
1638
/*
1639
* Send data to socket
1640
*/
1641
1642
int
1643
ng_btsocket_sco_send(struct socket *so, int flags, struct mbuf *m,
1644
struct sockaddr *nam, struct mbuf *control, struct thread *td)
1645
{
1646
ng_btsocket_sco_pcb_t *pcb = so2sco_pcb(so);
1647
int error = 0;
1648
1649
if (ng_btsocket_sco_node == NULL) {
1650
error = ENETDOWN;
1651
goto drop;
1652
}
1653
1654
/* Check socket and input */
1655
if (pcb == NULL || m == NULL || control != NULL) {
1656
error = EINVAL;
1657
goto drop;
1658
}
1659
1660
mtx_lock(&pcb->pcb_mtx);
1661
1662
/* Make sure socket is connected */
1663
if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
1664
mtx_unlock(&pcb->pcb_mtx);
1665
error = ENOTCONN;
1666
goto drop;
1667
}
1668
1669
/* Check route */
1670
if (pcb->rt == NULL ||
1671
pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1672
mtx_unlock(&pcb->pcb_mtx);
1673
error = ENETDOWN;
1674
goto drop;
1675
}
1676
1677
/* Check packet size */
1678
if (m->m_pkthdr.len > pcb->rt->pkt_size) {
1679
NG_BTSOCKET_SCO_ERR(
1680
"%s: Packet too big, len=%d, pkt_size=%d\n",
1681
__func__, m->m_pkthdr.len, pcb->rt->pkt_size);
1682
1683
mtx_unlock(&pcb->pcb_mtx);
1684
error = EMSGSIZE;
1685
goto drop;
1686
}
1687
1688
/*
1689
* First put packet on socket send queue. Then check if we have
1690
* pending timeout. If we do not have timeout then we must send
1691
* packet and schedule timeout. Otherwise do nothing and wait for
1692
* NGM_HCI_SYNC_CON_QUEUE message.
1693
*/
1694
1695
sbappendrecord(&pcb->so->so_snd, m);
1696
m = NULL;
1697
1698
if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) {
1699
error = ng_btsocket_sco_send2(pcb);
1700
if (error == 0)
1701
ng_btsocket_sco_timeout(pcb);
1702
else
1703
sbdroprecord(&pcb->so->so_snd); /* XXX */
1704
}
1705
1706
mtx_unlock(&pcb->pcb_mtx);
1707
drop:
1708
NG_FREE_M(m); /* checks for != NULL */
1709
NG_FREE_M(control);
1710
1711
return (error);
1712
} /* ng_btsocket_sco_send */
1713
1714
/*
1715
* Send first packet in the socket queue to the SCO layer
1716
*/
1717
1718
static int
1719
ng_btsocket_sco_send2(ng_btsocket_sco_pcb_p pcb)
1720
{
1721
struct mbuf *m = NULL;
1722
ng_hci_scodata_pkt_t *hdr = NULL;
1723
int error = 0;
1724
1725
mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1726
1727
while (pcb->rt->pending < pcb->rt->num_pkts &&
1728
sbavail(&pcb->so->so_snd) > 0) {
1729
/* Get a copy of the first packet on send queue */
1730
m = m_dup(pcb->so->so_snd.sb_mb, M_NOWAIT);
1731
if (m == NULL) {
1732
error = ENOBUFS;
1733
break;
1734
}
1735
1736
/* Create SCO packet header */
1737
M_PREPEND(m, sizeof(*hdr), M_NOWAIT);
1738
if (m != NULL)
1739
if (m->m_len < sizeof(*hdr))
1740
m = m_pullup(m, sizeof(*hdr));
1741
1742
if (m == NULL) {
1743
error = ENOBUFS;
1744
break;
1745
}
1746
1747
/* Fill in the header */
1748
hdr = mtod(m, ng_hci_scodata_pkt_t *);
1749
hdr->type = NG_HCI_SCO_DATA_PKT;
1750
hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(pcb->con_handle, 0, 0));
1751
hdr->length = m->m_pkthdr.len - sizeof(*hdr);
1752
1753
/* Send packet */
1754
NG_SEND_DATA_ONLY(error, pcb->rt->hook, m);
1755
if (error != 0)
1756
break;
1757
1758
pcb->rt->pending ++;
1759
}
1760
1761
return ((pcb->rt->pending > 0)? 0 : error);
1762
} /* ng_btsocket_sco_send2 */
1763
1764
/*
1765
* Get socket address
1766
*/
1767
1768
int
1769
ng_btsocket_sco_sockaddr(struct socket *so, struct sockaddr *sa)
1770
{
1771
ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1772
struct sockaddr_sco *sco = (struct sockaddr_sco *)sa;
1773
1774
if (pcb == NULL)
1775
return (EINVAL);
1776
if (ng_btsocket_sco_node == NULL)
1777
return (EINVAL);
1778
1779
*sco = (struct sockaddr_sco ){
1780
.sco_len = sizeof(struct sockaddr_sco),
1781
.sco_family = AF_BLUETOOTH,
1782
};
1783
mtx_lock(&pcb->pcb_mtx);
1784
bcopy(&pcb->src, &sco->sco_bdaddr, sizeof(sco->sco_bdaddr));
1785
mtx_unlock(&pcb->pcb_mtx);
1786
1787
return (0);
1788
}
1789
1790
/*****************************************************************************
1791
*****************************************************************************
1792
** Misc. functions
1793
*****************************************************************************
1794
*****************************************************************************/
1795
1796
/*
1797
* Look for the socket that listens on given bdaddr.
1798
* Returns exact or close match (if any).
1799
* Caller must hold ng_btsocket_sco_sockets_mtx.
1800
* Returns with locked pcb.
1801
*/
1802
1803
static ng_btsocket_sco_pcb_p
1804
ng_btsocket_sco_pcb_by_addr(bdaddr_p bdaddr)
1805
{
1806
ng_btsocket_sco_pcb_p p = NULL, p1 = NULL;
1807
1808
mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1809
1810
LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1811
mtx_lock(&p->pcb_mtx);
1812
1813
if (p->so == NULL || !SOLISTENING(p->so)) {
1814
mtx_unlock(&p->pcb_mtx);
1815
continue;
1816
}
1817
1818
if (bcmp(&p->src, bdaddr, sizeof(p->src)) == 0)
1819
return (p); /* return with locked pcb */
1820
1821
if (bcmp(&p->src, NG_HCI_BDADDR_ANY, sizeof(p->src)) == 0)
1822
p1 = p;
1823
1824
mtx_unlock(&p->pcb_mtx);
1825
}
1826
1827
if (p1 != NULL)
1828
mtx_lock(&p1->pcb_mtx);
1829
1830
return (p1);
1831
} /* ng_btsocket_sco_pcb_by_addr */
1832
1833
/*
1834
* Look for the socket that assigned to given source address and handle.
1835
* Caller must hold ng_btsocket_sco_sockets_mtx.
1836
* Returns with locked pcb.
1837
*/
1838
1839
static ng_btsocket_sco_pcb_p
1840
ng_btsocket_sco_pcb_by_handle(bdaddr_p src, int con_handle)
1841
{
1842
ng_btsocket_sco_pcb_p p = NULL;
1843
1844
mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1845
1846
LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1847
mtx_lock(&p->pcb_mtx);
1848
1849
if (p->con_handle == con_handle &&
1850
bcmp(src, &p->src, sizeof(p->src)) == 0)
1851
return (p); /* return with locked pcb */
1852
1853
mtx_unlock(&p->pcb_mtx);
1854
}
1855
1856
return (NULL);
1857
} /* ng_btsocket_sco_pcb_by_handle */
1858
1859
/*
1860
* Look for the socket in CONNECTING state with given source and destination
1861
* addresses. Caller must hold ng_btsocket_sco_sockets_mtx.
1862
* Returns with locked pcb.
1863
*/
1864
1865
static ng_btsocket_sco_pcb_p
1866
ng_btsocket_sco_pcb_by_addrs(bdaddr_p src, bdaddr_p dst)
1867
{
1868
ng_btsocket_sco_pcb_p p = NULL;
1869
1870
mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1871
1872
LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1873
mtx_lock(&p->pcb_mtx);
1874
1875
if (p->state == NG_BTSOCKET_SCO_CONNECTING &&
1876
bcmp(src, &p->src, sizeof(p->src)) == 0 &&
1877
bcmp(dst, &p->dst, sizeof(p->dst)) == 0)
1878
return (p); /* return with locked pcb */
1879
1880
mtx_unlock(&p->pcb_mtx);
1881
}
1882
1883
return (NULL);
1884
} /* ng_btsocket_sco_pcb_by_addrs */
1885
1886
/*
1887
* Set timeout on socket
1888
*/
1889
1890
static void
1891
ng_btsocket_sco_timeout(ng_btsocket_sco_pcb_p pcb)
1892
{
1893
mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1894
1895
if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) {
1896
pcb->flags |= NG_BTSOCKET_SCO_TIMO;
1897
callout_reset(&pcb->timo, bluetooth_sco_rtx_timeout(),
1898
ng_btsocket_sco_process_timeout, pcb);
1899
} else
1900
KASSERT(0,
1901
("%s: Duplicated socket timeout?!\n", __func__));
1902
} /* ng_btsocket_sco_timeout */
1903
1904
/*
1905
* Unset timeout on socket
1906
*/
1907
1908
static void
1909
ng_btsocket_sco_untimeout(ng_btsocket_sco_pcb_p pcb)
1910
{
1911
mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1912
1913
if (pcb->flags & NG_BTSOCKET_SCO_TIMO) {
1914
callout_stop(&pcb->timo);
1915
pcb->flags &= ~NG_BTSOCKET_SCO_TIMO;
1916
} else
1917
KASSERT(0,
1918
("%s: No socket timeout?!\n", __func__));
1919
} /* ng_btsocket_sco_untimeout */
1920
1921
/*
1922
* Process timeout on socket
1923
*/
1924
1925
static void
1926
ng_btsocket_sco_process_timeout(void *xpcb)
1927
{
1928
ng_btsocket_sco_pcb_p pcb = (ng_btsocket_sco_pcb_p) xpcb;
1929
1930
mtx_lock(&pcb->pcb_mtx);
1931
1932
pcb->flags &= ~NG_BTSOCKET_SCO_TIMO;
1933
pcb->so->so_error = ETIMEDOUT;
1934
1935
switch (pcb->state) {
1936
case NG_BTSOCKET_SCO_CONNECTING:
1937
/* Connect timeout - close the socket */
1938
pcb->state = NG_BTSOCKET_SCO_CLOSED;
1939
soisdisconnected(pcb->so);
1940
break;
1941
1942
case NG_BTSOCKET_SCO_OPEN:
1943
/* Send timeout - did not get NGM_HCI_SYNC_CON_QUEUE */
1944
sbdroprecord(&pcb->so->so_snd);
1945
sowwakeup(pcb->so);
1946
/* XXX FIXME what to do with pcb->rt->pending??? */
1947
break;
1948
1949
case NG_BTSOCKET_SCO_DISCONNECTING:
1950
/* Disconnect timeout - disconnect the socket anyway */
1951
pcb->state = NG_BTSOCKET_SCO_CLOSED;
1952
soisdisconnected(pcb->so);
1953
break;
1954
1955
default:
1956
NG_BTSOCKET_SCO_ERR(
1957
"%s: Invalid socket state=%d\n", __func__, pcb->state);
1958
break;
1959
}
1960
1961
mtx_unlock(&pcb->pcb_mtx);
1962
} /* ng_btsocket_sco_process_timeout */
1963
1964