Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netgraph/bluetooth/hci/ng_hci_ulpi.c
34814 views
1
/*
2
* ng_hci_ulpi.c
3
*/
4
5
/*-
6
* SPDX-License-Identifier: BSD-2-Clause
7
*
8
* Copyright (c) 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_hci_ulpi.c,v 1.7 2003/09/08 18:57:51 max Exp $
33
*/
34
35
#include <sys/param.h>
36
#include <sys/systm.h>
37
#include <sys/kernel.h>
38
#include <sys/endian.h>
39
#include <sys/malloc.h>
40
#include <sys/mbuf.h>
41
#include <sys/queue.h>
42
#include <netgraph/ng_message.h>
43
#include <netgraph/netgraph.h>
44
#include <netgraph/bluetooth/include/ng_bluetooth.h>
45
#include <netgraph/bluetooth/include/ng_hci.h>
46
#include <netgraph/bluetooth/hci/ng_hci_var.h>
47
#include <netgraph/bluetooth/hci/ng_hci_cmds.h>
48
#include <netgraph/bluetooth/hci/ng_hci_evnt.h>
49
#include <netgraph/bluetooth/hci/ng_hci_ulpi.h>
50
#include <netgraph/bluetooth/hci/ng_hci_misc.h>
51
52
/******************************************************************************
53
******************************************************************************
54
** Upper Layer Protocol Interface module
55
******************************************************************************
56
******************************************************************************/
57
58
static int ng_hci_lp_acl_con_req (ng_hci_unit_p, item_p, hook_p);
59
static int ng_hci_lp_sco_con_req (ng_hci_unit_p, item_p, hook_p);
60
static int ng_hci_lp_le_con_req (ng_hci_unit_p, item_p, hook_p, int);
61
62
/*
63
* Process LP_ConnectReq event from the upper layer protocol
64
*/
65
66
int
67
ng_hci_lp_con_req(ng_hci_unit_p unit, item_p item, hook_p hook)
68
{
69
int link_type;
70
71
if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) {
72
NG_HCI_WARN(
73
"%s: %s - unit is not ready, state=%#x\n",
74
__func__, NG_NODE_NAME(unit->node), unit->state);
75
76
NG_FREE_ITEM(item);
77
78
return (ENXIO);
79
}
80
81
if (NGI_MSG(item)->header.arglen != sizeof(ng_hci_lp_con_req_ep)) {
82
NG_HCI_ALERT(
83
"%s: %s - invalid LP_ConnectReq message size=%d\n",
84
__func__, NG_NODE_NAME(unit->node),
85
NGI_MSG(item)->header.arglen);
86
87
NG_FREE_ITEM(item);
88
89
return (EMSGSIZE);
90
}
91
link_type = ((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type;
92
switch(link_type){
93
case NG_HCI_LINK_ACL:
94
return (ng_hci_lp_acl_con_req(unit, item, hook));
95
case NG_HCI_LINK_SCO:
96
if (hook != unit->sco ) {
97
NG_HCI_WARN(
98
"%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n",
99
__func__, NG_NODE_NAME(unit->node), hook);
100
101
NG_FREE_ITEM(item);
102
103
return (EINVAL);
104
}
105
106
return (ng_hci_lp_sco_con_req(unit, item, hook));
107
case NG_HCI_LINK_LE_PUBLIC:
108
case NG_HCI_LINK_LE_RANDOM:
109
return (ng_hci_lp_le_con_req(unit, item, hook, link_type));
110
default:
111
panic("%s: link_type invalid.", __func__);
112
}
113
114
return (EINVAL);
115
} /* ng_hci_lp_con_req */
116
117
/*
118
* Request to create new ACL connection
119
*/
120
121
static int
122
ng_hci_lp_acl_con_req(ng_hci_unit_p unit, item_p item, hook_p hook)
123
{
124
struct acl_con_req {
125
ng_hci_cmd_pkt_t hdr;
126
ng_hci_create_con_cp cp;
127
} __attribute__ ((packed)) *req = NULL;
128
ng_hci_lp_con_req_ep *ep = NULL;
129
ng_hci_unit_con_p con = NULL;
130
ng_hci_neighbor_t *n = NULL;
131
struct mbuf *m = NULL;
132
int error = 0;
133
134
ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data);
135
136
/*
137
* Only one ACL connection can exist between each pair of units.
138
* So try to find ACL connection descriptor (in any state) that
139
* has requested remote BD_ADDR.
140
*
141
* Two cases:
142
*
143
* 1) We do not have connection to the remote unit. This is simple.
144
* Just create new connection descriptor and send HCI command to
145
* create new connection.
146
*
147
* 2) We do have connection descriptor. We need to check connection
148
* state:
149
*
150
* 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of
151
* accepting connection from the remote unit. This is a race
152
* condition. We will ignore this message.
153
*
154
* 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already
155
* requested connection or we just accepted it. In any case
156
* all we need to do here is set appropriate notification bit
157
* and wait.
158
*
159
* 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back
160
* and let upper layer know that we have connection already.
161
*/
162
163
con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
164
if (con != NULL) {
165
switch (con->state) {
166
case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */
167
error = EALREADY;
168
break;
169
170
case NG_HCI_CON_W4_CONN_COMPLETE:
171
if (hook == unit->acl)
172
con->flags |= NG_HCI_CON_NOTIFY_ACL;
173
else
174
con->flags |= NG_HCI_CON_NOTIFY_SCO;
175
break;
176
177
case NG_HCI_CON_OPEN: {
178
struct ng_mesg *msg = NULL;
179
ng_hci_lp_con_cfm_ep *cfm = NULL;
180
181
if (hook != NULL && NG_HOOK_IS_VALID(hook)) {
182
NGI_GET_MSG(item, msg);
183
NG_FREE_MSG(msg);
184
185
NG_MKMESSAGE(msg, NGM_HCI_COOKIE,
186
NGM_HCI_LP_CON_CFM, sizeof(*cfm),
187
M_NOWAIT);
188
if (msg != NULL) {
189
cfm = (ng_hci_lp_con_cfm_ep *)msg->data;
190
cfm->status = 0;
191
cfm->link_type = con->link_type;
192
cfm->con_handle = con->con_handle;
193
bcopy(&con->bdaddr, &cfm->bdaddr,
194
sizeof(cfm->bdaddr));
195
196
/*
197
* This will forward item back to
198
* sender and set item to NULL
199
*/
200
201
_NGI_MSG(item) = msg;
202
NG_FWD_ITEM_HOOK(error, item, hook);
203
} else
204
error = ENOMEM;
205
} else
206
NG_HCI_INFO(
207
"%s: %s - Source hook is not valid, hook=%p\n",
208
__func__, NG_NODE_NAME(unit->node),
209
hook);
210
} break;
211
212
default:
213
panic(
214
"%s: %s - Invalid connection state=%d\n",
215
__func__, NG_NODE_NAME(unit->node), con->state);
216
break;
217
}
218
219
goto out;
220
}
221
222
/*
223
* If we got here then we need to create new ACL connection descriptor
224
* and submit HCI command. First create new connection desriptor, set
225
* bdaddr and notification flags.
226
*/
227
228
con = ng_hci_new_con(unit, NG_HCI_LINK_ACL);
229
if (con == NULL) {
230
error = ENOMEM;
231
goto out;
232
}
233
234
bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));
235
236
/*
237
* Create HCI command
238
*/
239
240
MGETHDR(m, M_NOWAIT, MT_DATA);
241
if (m == NULL) {
242
ng_hci_free_con(con);
243
error = ENOBUFS;
244
goto out;
245
}
246
247
m->m_pkthdr.len = m->m_len = sizeof(*req);
248
req = mtod(m, struct acl_con_req *);
249
req->hdr.type = NG_HCI_CMD_PKT;
250
req->hdr.length = sizeof(req->cp);
251
req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
252
NG_HCI_OCF_CREATE_CON));
253
254
bcopy(&ep->bdaddr, &req->cp.bdaddr, sizeof(req->cp.bdaddr));
255
256
req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1);
257
if (unit->features[0] & NG_HCI_LMP_3SLOT)
258
req->cp.pkt_type |= (NG_HCI_PKT_DM3|NG_HCI_PKT_DH3);
259
if (unit->features[0] & NG_HCI_LMP_5SLOT)
260
req->cp.pkt_type |= (NG_HCI_PKT_DM5|NG_HCI_PKT_DH5);
261
262
req->cp.pkt_type &= unit->packet_mask;
263
if ((req->cp.pkt_type & (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1|
264
NG_HCI_PKT_DM3|NG_HCI_PKT_DH3|
265
NG_HCI_PKT_DM5|NG_HCI_PKT_DH5)) == 0)
266
req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1);
267
268
req->cp.pkt_type = htole16(req->cp.pkt_type);
269
270
if ((unit->features[0] & NG_HCI_LMP_SWITCH) && unit->role_switch)
271
req->cp.accept_role_switch = 1;
272
else
273
req->cp.accept_role_switch = 0;
274
275
/*
276
* We may speed up connect by specifying valid parameters.
277
* So check the neighbor cache.
278
*/
279
280
n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
281
if (n == NULL) {
282
req->cp.page_scan_rep_mode = 0;
283
req->cp.page_scan_mode = 0;
284
req->cp.clock_offset = 0;
285
} else {
286
req->cp.page_scan_rep_mode = n->page_scan_rep_mode;
287
req->cp.page_scan_mode = n->page_scan_mode;
288
req->cp.clock_offset = htole16(n->clock_offset);
289
}
290
291
/*
292
* Adust connection state
293
*/
294
295
if (hook == unit->acl)
296
con->flags |= NG_HCI_CON_NOTIFY_ACL;
297
else
298
con->flags |= NG_HCI_CON_NOTIFY_SCO;
299
300
con->state = NG_HCI_CON_W4_CONN_COMPLETE;
301
ng_hci_con_timeout(con);
302
303
/*
304
* Queue and send HCI command
305
*/
306
307
NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
308
if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
309
error = ng_hci_send_command(unit);
310
out:
311
if (item != NULL)
312
NG_FREE_ITEM(item);
313
314
return (error);
315
} /* ng_hci_lp_acl_con_req */
316
317
/*
318
* Request to create new SCO connection
319
*/
320
321
static int
322
ng_hci_lp_sco_con_req(ng_hci_unit_p unit, item_p item, hook_p hook)
323
{
324
struct sco_con_req {
325
ng_hci_cmd_pkt_t hdr;
326
ng_hci_add_sco_con_cp cp;
327
} __attribute__ ((packed)) *req = NULL;
328
ng_hci_lp_con_req_ep *ep = NULL;
329
ng_hci_unit_con_p acl_con = NULL, sco_con = NULL;
330
struct mbuf *m = NULL;
331
int error = 0;
332
333
ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data);
334
335
/*
336
* SCO connection without ACL link
337
*
338
* If upper layer requests SCO connection and there is no open ACL
339
* connection to the desired remote unit, we will reject the request.
340
*/
341
342
LIST_FOREACH(acl_con, &unit->con_list, next)
343
if (acl_con->link_type == NG_HCI_LINK_ACL &&
344
acl_con->state == NG_HCI_CON_OPEN &&
345
bcmp(&acl_con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0)
346
break;
347
348
if (acl_con == NULL) {
349
NG_HCI_INFO(
350
"%s: %s - No open ACL connection to bdaddr=%x:%x:%x:%x:%x:%x\n",
351
__func__, NG_NODE_NAME(unit->node),
352
ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
353
ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
354
355
error = ENOENT;
356
goto out;
357
}
358
359
/*
360
* Multiple SCO connections can exist between the same pair of units.
361
* We assume that multiple SCO connections have to be opened one after
362
* another.
363
*
364
* Try to find SCO connection descriptor that matches the following:
365
*
366
* 1) sco_con->link_type == NG_HCI_LINK_SCO
367
*
368
* 2) sco_con->state == NG_HCI_CON_W4_LP_CON_RSP ||
369
* sco_con->state == NG_HCI_CON_W4_CONN_COMPLETE
370
*
371
* 3) sco_con->bdaddr == ep->bdaddr
372
*
373
* Two cases:
374
*
375
* 1) We do not have connection descriptor. This is simple. Just
376
* create new connection and submit Add_SCO_Connection command.
377
*
378
* 2) We do have connection descriptor. We need to check the state.
379
*
380
* 2.1) NG_HCI_CON_W4_LP_CON_RSP means we in the middle of accepting
381
* connection from the remote unit. This is a race condition and
382
* we will ignore the request.
383
*
384
* 2.2) NG_HCI_CON_W4_CONN_COMPLETE means upper layer already requested
385
* connection or we just accepted it.
386
*/
387
388
LIST_FOREACH(sco_con, &unit->con_list, next)
389
if (sco_con->link_type == NG_HCI_LINK_SCO &&
390
(sco_con->state == NG_HCI_CON_W4_LP_CON_RSP ||
391
sco_con->state == NG_HCI_CON_W4_CONN_COMPLETE) &&
392
bcmp(&sco_con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0)
393
break;
394
395
if (sco_con != NULL) {
396
switch (sco_con->state) {
397
case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */
398
error = EALREADY;
399
break;
400
401
case NG_HCI_CON_W4_CONN_COMPLETE:
402
sco_con->flags |= NG_HCI_CON_NOTIFY_SCO;
403
break;
404
405
default:
406
panic(
407
"%s: %s - Invalid connection state=%d\n",
408
__func__, NG_NODE_NAME(unit->node),
409
sco_con->state);
410
break;
411
}
412
413
goto out;
414
}
415
416
/*
417
* If we got here then we need to create new SCO connection descriptor
418
* and submit HCI command.
419
*/
420
421
sco_con = ng_hci_new_con(unit, NG_HCI_LINK_SCO);
422
if (sco_con == NULL) {
423
error = ENOMEM;
424
goto out;
425
}
426
427
bcopy(&ep->bdaddr, &sco_con->bdaddr, sizeof(sco_con->bdaddr));
428
429
/*
430
* Create HCI command
431
*/
432
433
MGETHDR(m, M_NOWAIT, MT_DATA);
434
if (m == NULL) {
435
ng_hci_free_con(sco_con);
436
error = ENOBUFS;
437
goto out;
438
}
439
440
m->m_pkthdr.len = m->m_len = sizeof(*req);
441
req = mtod(m, struct sco_con_req *);
442
req->hdr.type = NG_HCI_CMD_PKT;
443
req->hdr.length = sizeof(req->cp);
444
req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
445
NG_HCI_OCF_ADD_SCO_CON));
446
447
req->cp.con_handle = htole16(acl_con->con_handle);
448
449
req->cp.pkt_type = NG_HCI_PKT_HV1;
450
if (unit->features[1] & NG_HCI_LMP_HV2_PKT)
451
req->cp.pkt_type |= NG_HCI_PKT_HV2;
452
if (unit->features[1] & NG_HCI_LMP_HV3_PKT)
453
req->cp.pkt_type |= NG_HCI_PKT_HV3;
454
455
req->cp.pkt_type &= unit->packet_mask;
456
if ((req->cp.pkt_type & (NG_HCI_PKT_HV1|
457
NG_HCI_PKT_HV2|
458
NG_HCI_PKT_HV3)) == 0)
459
req->cp.pkt_type = NG_HCI_PKT_HV1;
460
461
req->cp.pkt_type = htole16(req->cp.pkt_type);
462
463
/*
464
* Adust connection state
465
*/
466
467
sco_con->flags |= NG_HCI_CON_NOTIFY_SCO;
468
469
sco_con->state = NG_HCI_CON_W4_CONN_COMPLETE;
470
ng_hci_con_timeout(sco_con);
471
472
/*
473
* Queue and send HCI command
474
*/
475
476
NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
477
if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
478
error = ng_hci_send_command(unit);
479
out:
480
NG_FREE_ITEM(item);
481
482
return (error);
483
} /* ng_hci_lp_sco_con_req */
484
485
static int
486
ng_hci_lp_le_con_req(ng_hci_unit_p unit, item_p item, hook_p hook, int link_type)
487
{
488
struct acl_con_req {
489
ng_hci_cmd_pkt_t hdr;
490
ng_hci_le_create_connection_cp cp;
491
} __attribute__ ((packed)) *req = NULL;
492
ng_hci_lp_con_req_ep *ep = NULL;
493
ng_hci_unit_con_p con = NULL;
494
struct mbuf *m = NULL;
495
int error = 0;
496
497
ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data);
498
if((link_type != NG_HCI_LINK_LE_PUBLIC)&&
499
(link_type != NG_HCI_LINK_LE_RANDOM)){
500
printf("%s: Link type %d Cannot be here \n", __func__,
501
link_type);
502
}
503
/*
504
* Only one ACL connection can exist between each pair of units.
505
* So try to find ACL connection descriptor (in any state) that
506
* has requested remote BD_ADDR.
507
*
508
* Two cases:
509
*
510
* 1) We do not have connection to the remote unit. This is simple.
511
* Just create new connection descriptor and send HCI command to
512
* create new connection.
513
*
514
* 2) We do have connection descriptor. We need to check connection
515
* state:
516
*
517
* 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of
518
* accepting connection from the remote unit. This is a race
519
* condition. We will ignore this message.
520
*
521
* 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already
522
* requested connection or we just accepted it. In any case
523
* all we need to do here is set appropriate notification bit
524
* and wait.
525
*
526
* 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back
527
* and let upper layer know that we have connection already.
528
*/
529
530
con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, link_type);
531
if (con != NULL) {
532
switch (con->state) {
533
case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */
534
error = EALREADY;
535
break;
536
537
case NG_HCI_CON_W4_CONN_COMPLETE:
538
if (hook != unit->sco)
539
con->flags |= NG_HCI_CON_NOTIFY_ACL;
540
else
541
con->flags |= NG_HCI_CON_NOTIFY_SCO;
542
break;
543
544
case NG_HCI_CON_OPEN: {
545
struct ng_mesg *msg = NULL;
546
ng_hci_lp_con_cfm_ep *cfm = NULL;
547
548
if (hook != NULL && NG_HOOK_IS_VALID(hook)) {
549
NGI_GET_MSG(item, msg);
550
NG_FREE_MSG(msg);
551
552
NG_MKMESSAGE(msg, NGM_HCI_COOKIE,
553
NGM_HCI_LP_CON_CFM, sizeof(*cfm),
554
M_NOWAIT);
555
if (msg != NULL) {
556
cfm = (ng_hci_lp_con_cfm_ep *)msg->data;
557
cfm->status = 0;
558
cfm->link_type = con->link_type;
559
cfm->con_handle = con->con_handle;
560
bcopy(&con->bdaddr, &cfm->bdaddr,
561
sizeof(cfm->bdaddr));
562
563
/*
564
* This will forward item back to
565
* sender and set item to NULL
566
*/
567
568
_NGI_MSG(item) = msg;
569
NG_FWD_ITEM_HOOK(error, item, hook);
570
} else
571
error = ENOMEM;
572
} else
573
NG_HCI_INFO(
574
"%s: %s - Source hook is not valid, hook=%p\n",
575
__func__, NG_NODE_NAME(unit->node),
576
hook);
577
} break;
578
579
default:
580
panic(
581
"%s: %s - Invalid connection state=%d\n",
582
__func__, NG_NODE_NAME(unit->node), con->state);
583
break;
584
}
585
586
goto out;
587
}
588
589
/*
590
* If we got here then we need to create new ACL connection descriptor
591
* and submit HCI command. First create new connection desriptor, set
592
* bdaddr and notification flags.
593
*/
594
595
con = ng_hci_new_con(unit, link_type);
596
if (con == NULL) {
597
error = ENOMEM;
598
goto out;
599
}
600
601
bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));
602
603
/*
604
* Create HCI command
605
*/
606
607
MGETHDR(m, M_NOWAIT, MT_DATA);
608
if (m == NULL) {
609
ng_hci_free_con(con);
610
error = ENOBUFS;
611
goto out;
612
}
613
614
m->m_pkthdr.len = m->m_len = sizeof(*req);
615
req = mtod(m, struct acl_con_req *);
616
req->hdr.type = NG_HCI_CMD_PKT;
617
req->hdr.length = sizeof(req->cp);
618
req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LE,
619
NG_HCI_OCF_LE_CREATE_CONNECTION));
620
621
bcopy(&ep->bdaddr, &req->cp.peer_addr, sizeof(req->cp.peer_addr));
622
req->cp.own_address_type = 0;
623
req->cp.peer_addr_type = (link_type == NG_HCI_LINK_LE_RANDOM)? 1:0;
624
req->cp.scan_interval = htole16(4);
625
req->cp.scan_window = htole16(4);
626
req->cp.filter_policy = 0;
627
req->cp.conn_interval_min = htole16(0xf);
628
req->cp.conn_interval_max = htole16(0xf);
629
req->cp.conn_latency = htole16(0);
630
req->cp.supervision_timeout = htole16(0xc80);
631
req->cp.min_ce_length = htole16(1);
632
req->cp.max_ce_length = htole16(1);
633
/*
634
* Adust connection state
635
*/
636
637
if (hook != unit->sco)
638
con->flags |= NG_HCI_CON_NOTIFY_ACL;
639
else
640
con->flags |= NG_HCI_CON_NOTIFY_SCO;
641
642
con->state = NG_HCI_CON_W4_CONN_COMPLETE;
643
ng_hci_con_timeout(con);
644
645
/*
646
* Queue and send HCI command
647
*/
648
649
NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
650
if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
651
error = ng_hci_send_command(unit);
652
out:
653
if (item != NULL)
654
NG_FREE_ITEM(item);
655
656
return (error);
657
} /* ng_hci_lp_acl_con_req */
658
659
/*
660
* Process LP_DisconnectReq event from the upper layer protocol
661
*/
662
663
int
664
ng_hci_lp_discon_req(ng_hci_unit_p unit, item_p item, hook_p hook)
665
{
666
struct discon_req {
667
ng_hci_cmd_pkt_t hdr;
668
ng_hci_discon_cp cp;
669
} __attribute__ ((packed)) *req = NULL;
670
ng_hci_lp_discon_req_ep *ep = NULL;
671
ng_hci_unit_con_p con = NULL;
672
struct mbuf *m = NULL;
673
int error = 0;
674
675
/* Check if unit is ready */
676
if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) {
677
NG_HCI_WARN(
678
"%s: %s - unit is not ready, state=%#x\n",
679
__func__, NG_NODE_NAME(unit->node), unit->state);
680
681
error = ENXIO;
682
goto out;
683
}
684
685
if (NGI_MSG(item)->header.arglen != sizeof(*ep)) {
686
NG_HCI_ALERT(
687
"%s: %s - invalid LP_DisconnectReq message size=%d\n",
688
__func__, NG_NODE_NAME(unit->node),
689
NGI_MSG(item)->header.arglen);
690
691
error = EMSGSIZE;
692
goto out;
693
}
694
695
ep = (ng_hci_lp_discon_req_ep *)(NGI_MSG(item)->data);
696
697
con = ng_hci_con_by_handle(unit, ep->con_handle);
698
if (con == NULL) {
699
NG_HCI_ERR(
700
"%s: %s - invalid connection handle=%d\n",
701
__func__, NG_NODE_NAME(unit->node), ep->con_handle);
702
703
error = ENOENT;
704
goto out;
705
}
706
707
if (con->state != NG_HCI_CON_OPEN) {
708
NG_HCI_ERR(
709
"%s: %s - invalid connection state=%d, handle=%d\n",
710
__func__, NG_NODE_NAME(unit->node), con->state,
711
ep->con_handle);
712
713
error = EINVAL;
714
goto out;
715
}
716
717
/*
718
* Create HCI command
719
*/
720
721
MGETHDR(m, M_NOWAIT, MT_DATA);
722
if (m == NULL) {
723
error = ENOBUFS;
724
goto out;
725
}
726
727
m->m_pkthdr.len = m->m_len = sizeof(*req);
728
req = mtod(m, struct discon_req *);
729
req->hdr.type = NG_HCI_CMD_PKT;
730
req->hdr.length = sizeof(req->cp);
731
req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
732
NG_HCI_OCF_DISCON));
733
734
req->cp.con_handle = htole16(ep->con_handle);
735
req->cp.reason = ep->reason;
736
737
/*
738
* Queue and send HCI command
739
*/
740
741
NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
742
if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
743
error = ng_hci_send_command(unit);
744
out:
745
NG_FREE_ITEM(item);
746
747
return (error);
748
} /* ng_hci_lp_discon_req */
749
750
/*
751
* Send LP_ConnectCfm event to the upper layer protocol
752
*/
753
754
int
755
ng_hci_lp_con_cfm(ng_hci_unit_con_p con, int status)
756
{
757
ng_hci_unit_p unit = con->unit;
758
struct ng_mesg *msg = NULL;
759
ng_hci_lp_con_cfm_ep *ep = NULL;
760
int error;
761
762
/*
763
* Check who wants to be notified. For ACL links both ACL and SCO
764
* upstream hooks will be notified (if required). For SCO links
765
* only SCO upstream hook will receive notification
766
*/
767
768
if (con->link_type != NG_HCI_LINK_SCO &&
769
con->flags & NG_HCI_CON_NOTIFY_ACL) {
770
if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
771
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM,
772
sizeof(*ep), M_NOWAIT);
773
if (msg != NULL) {
774
ep = (ng_hci_lp_con_cfm_ep *) msg->data;
775
ep->status = status;
776
ep->link_type = con->link_type;
777
ep->con_handle = con->con_handle;
778
bcopy(&con->bdaddr, &ep->bdaddr,
779
sizeof(ep->bdaddr));
780
781
NG_SEND_MSG_HOOK(error, unit->node, msg,
782
unit->acl, 0);
783
}
784
} else
785
NG_HCI_INFO(
786
"%s: %s - ACL hook not valid, hook=%p\n",
787
__func__, NG_NODE_NAME(unit->node), unit->acl);
788
789
con->flags &= ~NG_HCI_CON_NOTIFY_ACL;
790
}
791
792
if (con->flags & NG_HCI_CON_NOTIFY_SCO) {
793
if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) {
794
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM,
795
sizeof(*ep), M_NOWAIT);
796
if (msg != NULL) {
797
ep = (ng_hci_lp_con_cfm_ep *) msg->data;
798
ep->status = status;
799
ep->link_type = con->link_type;
800
ep->con_handle = con->con_handle;
801
bcopy(&con->bdaddr, &ep->bdaddr,
802
sizeof(ep->bdaddr));
803
804
NG_SEND_MSG_HOOK(error, unit->node, msg,
805
unit->sco, 0);
806
}
807
} else
808
NG_HCI_INFO(
809
"%s: %s - SCO hook not valid, hook=%p\n",
810
__func__, NG_NODE_NAME(unit->node), unit->acl);
811
812
con->flags &= ~NG_HCI_CON_NOTIFY_SCO;
813
}
814
815
return (0);
816
} /* ng_hci_lp_con_cfm */
817
818
int
819
ng_hci_lp_enc_change(ng_hci_unit_con_p con, int status)
820
{
821
ng_hci_unit_p unit = con->unit;
822
struct ng_mesg *msg = NULL;
823
ng_hci_lp_enc_change_ep *ep = NULL;
824
int error;
825
826
if (con->link_type != NG_HCI_LINK_SCO) {
827
if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
828
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_ENC_CHG,
829
sizeof(*ep), M_NOWAIT);
830
if (msg != NULL) {
831
ep = (ng_hci_lp_enc_change_ep *) msg->data;
832
ep->status = status;
833
ep->link_type = con->link_type;
834
ep->con_handle = con->con_handle;
835
836
NG_SEND_MSG_HOOK(error, unit->node, msg,
837
unit->acl, 0);
838
}
839
} else
840
NG_HCI_INFO(
841
"%s: %s - ACL hook not valid, hook=%p\n",
842
__func__, NG_NODE_NAME(unit->node), unit->acl);
843
}
844
return (0);
845
} /* ng_hci_lp_con_cfm */
846
847
/*
848
* Send LP_ConnectInd event to the upper layer protocol
849
*/
850
851
int
852
ng_hci_lp_con_ind(ng_hci_unit_con_p con, u_int8_t *uclass)
853
{
854
ng_hci_unit_p unit = con->unit;
855
struct ng_mesg *msg = NULL;
856
ng_hci_lp_con_ind_ep *ep = NULL;
857
hook_p hook = NULL;
858
int error = 0;
859
860
/*
861
* Connection_Request event is generated for specific link type.
862
* Use link_type to select upstream hook.
863
*/
864
865
if (con->link_type != NG_HCI_LINK_SCO)
866
hook = unit->acl;
867
else
868
hook = unit->sco;
869
870
if (hook != NULL && NG_HOOK_IS_VALID(hook)) {
871
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_IND,
872
sizeof(*ep), M_NOWAIT);
873
if (msg == NULL)
874
return (ENOMEM);
875
876
ep = (ng_hci_lp_con_ind_ep *)(msg->data);
877
ep->link_type = con->link_type;
878
bcopy(uclass, ep->uclass, sizeof(ep->uclass));
879
bcopy(&con->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
880
881
NG_SEND_MSG_HOOK(error, unit->node, msg, hook, 0);
882
} else {
883
NG_HCI_WARN(
884
"%s: %s - Upstream hook is not connected or not valid, hook=%p\n",
885
__func__, NG_NODE_NAME(unit->node), hook);
886
887
error = ENOTCONN;
888
}
889
890
return (error);
891
} /* ng_hci_lp_con_ind */
892
893
/*
894
* Process LP_ConnectRsp event from the upper layer protocol
895
*/
896
897
int
898
ng_hci_lp_con_rsp(ng_hci_unit_p unit, item_p item, hook_p hook)
899
{
900
struct con_rsp_req {
901
ng_hci_cmd_pkt_t hdr;
902
union {
903
ng_hci_accept_con_cp acc;
904
ng_hci_reject_con_cp rej;
905
} __attribute__ ((packed)) cp;
906
} __attribute__ ((packed)) *req = NULL;
907
ng_hci_lp_con_rsp_ep *ep = NULL;
908
ng_hci_unit_con_p con = NULL;
909
struct mbuf *m = NULL;
910
int error = 0;
911
912
/* Check if unit is ready */
913
if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) {
914
NG_HCI_WARN(
915
"%s: %s - unit is not ready, state=%#x\n",
916
__func__, NG_NODE_NAME(unit->node), unit->state);
917
918
error = ENXIO;
919
goto out;
920
}
921
922
if (NGI_MSG(item)->header.arglen != sizeof(*ep)) {
923
NG_HCI_ALERT(
924
"%s: %s - invalid LP_ConnectRsp message size=%d\n",
925
__func__, NG_NODE_NAME(unit->node),
926
NGI_MSG(item)->header.arglen);
927
928
error = EMSGSIZE;
929
goto out;
930
}
931
932
ep = (ng_hci_lp_con_rsp_ep *)(NGI_MSG(item)->data);
933
934
/*
935
* Here we have to deal with race. Upper layers might send conflicting
936
* requests. One might send Accept and other Reject. We will not try
937
* to solve all the problems, so first request will always win.
938
*
939
* Try to find connection that matches the following:
940
*
941
* 1) con->link_type == ep->link_type
942
*
943
* 2) con->state == NG_HCI_CON_W4_LP_CON_RSP ||
944
* con->state == NG_HCI_CON_W4_CONN_COMPLETE
945
*
946
* 3) con->bdaddr == ep->bdaddr
947
*
948
* Two cases:
949
*
950
* 1) We do not have connection descriptor. Could be bogus request or
951
* we have rejected connection already.
952
*
953
* 2) We do have connection descriptor. Then we need to check state:
954
*
955
* 2.1) NG_HCI_CON_W4_LP_CON_RSP means upper layer has requested
956
* connection and it is a first response from the upper layer.
957
* if "status == 0" (Accept) then we will send Accept_Connection
958
* command and change connection state to W4_CONN_COMPLETE, else
959
* send reject and delete connection.
960
*
961
* 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that we already accepted
962
* connection. If "status == 0" we just need to link request
963
* and wait, else ignore Reject request.
964
*/
965
966
LIST_FOREACH(con, &unit->con_list, next)
967
if (con->link_type == ep->link_type &&
968
(con->state == NG_HCI_CON_W4_LP_CON_RSP ||
969
con->state == NG_HCI_CON_W4_CONN_COMPLETE) &&
970
bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0)
971
break;
972
973
if (con == NULL) {
974
/* Reject for non-existing connection is fine */
975
error = (ep->status == 0)? ENOENT : 0;
976
goto out;
977
}
978
979
/*
980
* Remove connection timeout and check connection state.
981
* Note: if ng_hci_con_untimeout() fails (returns non-zero value) then
982
* timeout already happened and event went into node's queue.
983
*/
984
985
if ((error = ng_hci_con_untimeout(con)) != 0)
986
goto out;
987
988
switch (con->state) {
989
case NG_HCI_CON_W4_LP_CON_RSP:
990
991
/*
992
* Create HCI command
993
*/
994
995
MGETHDR(m, M_NOWAIT, MT_DATA);
996
if (m == NULL) {
997
error = ENOBUFS;
998
goto out;
999
}
1000
1001
req = mtod(m, struct con_rsp_req *);
1002
req->hdr.type = NG_HCI_CMD_PKT;
1003
1004
if (ep->status == 0) {
1005
req->hdr.length = sizeof(req->cp.acc);
1006
req->hdr.opcode = htole16(NG_HCI_OPCODE(
1007
NG_HCI_OGF_LINK_CONTROL,
1008
NG_HCI_OCF_ACCEPT_CON));
1009
1010
bcopy(&ep->bdaddr, &req->cp.acc.bdaddr,
1011
sizeof(req->cp.acc.bdaddr));
1012
1013
/*
1014
* We are accepting connection, so if we support role
1015
* switch and role switch was enabled then set role to
1016
* NG_HCI_ROLE_MASTER and let LM perform role switch.
1017
* Otherwise we remain slave. In this case LM WILL NOT
1018
* perform role switch.
1019
*/
1020
1021
if ((unit->features[0] & NG_HCI_LMP_SWITCH) &&
1022
unit->role_switch)
1023
req->cp.acc.role = NG_HCI_ROLE_MASTER;
1024
else
1025
req->cp.acc.role = NG_HCI_ROLE_SLAVE;
1026
1027
/*
1028
* Adjust connection state
1029
*/
1030
1031
if (hook == unit->acl)
1032
con->flags |= NG_HCI_CON_NOTIFY_ACL;
1033
else
1034
con->flags |= NG_HCI_CON_NOTIFY_SCO;
1035
1036
con->state = NG_HCI_CON_W4_CONN_COMPLETE;
1037
ng_hci_con_timeout(con);
1038
} else {
1039
req->hdr.length = sizeof(req->cp.rej);
1040
req->hdr.opcode = htole16(NG_HCI_OPCODE(
1041
NG_HCI_OGF_LINK_CONTROL,
1042
NG_HCI_OCF_REJECT_CON));
1043
1044
bcopy(&ep->bdaddr, &req->cp.rej.bdaddr,
1045
sizeof(req->cp.rej.bdaddr));
1046
1047
req->cp.rej.reason = ep->status;
1048
1049
/*
1050
* Free connection descritor
1051
* Item will be deleted just before return.
1052
*/
1053
1054
ng_hci_free_con(con);
1055
}
1056
1057
m->m_pkthdr.len = m->m_len = sizeof(req->hdr) + req->hdr.length;
1058
1059
/* Queue and send HCI command */
1060
NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
1061
if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
1062
error = ng_hci_send_command(unit);
1063
break;
1064
1065
case NG_HCI_CON_W4_CONN_COMPLETE:
1066
if (ep->status == 0) {
1067
if (hook == unit->acl)
1068
con->flags |= NG_HCI_CON_NOTIFY_ACL;
1069
else
1070
con->flags |= NG_HCI_CON_NOTIFY_SCO;
1071
} else
1072
error = EPERM;
1073
break;
1074
1075
default:
1076
panic(
1077
"%s: %s - Invalid connection state=%d\n",
1078
__func__, NG_NODE_NAME(unit->node), con->state);
1079
break;
1080
}
1081
out:
1082
NG_FREE_ITEM(item);
1083
1084
return (error);
1085
} /* ng_hci_lp_con_rsp */
1086
1087
/*
1088
* Send LP_DisconnectInd to the upper layer protocol
1089
*/
1090
1091
int
1092
ng_hci_lp_discon_ind(ng_hci_unit_con_p con, int reason)
1093
{
1094
ng_hci_unit_p unit = con->unit;
1095
struct ng_mesg *msg = NULL;
1096
ng_hci_lp_discon_ind_ep *ep = NULL;
1097
int error = 0;
1098
1099
/*
1100
* Disconnect_Complete event is generated for specific connection
1101
* handle. For ACL connection handles both ACL and SCO upstream
1102
* hooks will receive notification. For SCO connection handles
1103
* only SCO upstream hook will receive notification.
1104
*/
1105
1106
if (con->link_type != NG_HCI_LINK_SCO) {
1107
if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
1108
NG_MKMESSAGE(msg, NGM_HCI_COOKIE,
1109
NGM_HCI_LP_DISCON_IND, sizeof(*ep), M_NOWAIT);
1110
if (msg == NULL)
1111
return (ENOMEM);
1112
1113
ep = (ng_hci_lp_discon_ind_ep *) msg->data;
1114
ep->reason = reason;
1115
ep->link_type = con->link_type;
1116
ep->con_handle = con->con_handle;
1117
1118
NG_SEND_MSG_HOOK(error,unit->node,msg,unit->acl,0);
1119
} else
1120
NG_HCI_INFO(
1121
"%s: %s - ACL hook is not connected or not valid, hook=%p\n",
1122
__func__, NG_NODE_NAME(unit->node), unit->acl);
1123
}
1124
1125
if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) {
1126
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_IND,
1127
sizeof(*ep), M_NOWAIT);
1128
if (msg == NULL)
1129
return (ENOMEM);
1130
1131
ep = (ng_hci_lp_discon_ind_ep *) msg->data;
1132
ep->reason = reason;
1133
ep->link_type = con->link_type;
1134
ep->con_handle = con->con_handle;
1135
1136
NG_SEND_MSG_HOOK(error, unit->node, msg, unit->sco, 0);
1137
} else
1138
NG_HCI_INFO(
1139
"%s: %s - SCO hook is not connected or not valid, hook=%p\n",
1140
__func__, NG_NODE_NAME(unit->node), unit->sco);
1141
1142
return (0);
1143
} /* ng_hci_lp_discon_ind */
1144
1145
/*
1146
* Process LP_QoSReq action from the upper layer protocol
1147
*/
1148
1149
int
1150
ng_hci_lp_qos_req(ng_hci_unit_p unit, item_p item, hook_p hook)
1151
{
1152
struct qos_setup_req {
1153
ng_hci_cmd_pkt_t hdr;
1154
ng_hci_qos_setup_cp cp;
1155
} __attribute__ ((packed)) *req = NULL;
1156
ng_hci_lp_qos_req_ep *ep = NULL;
1157
ng_hci_unit_con_p con = NULL;
1158
struct mbuf *m = NULL;
1159
int error = 0;
1160
1161
/* Check if unit is ready */
1162
if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) {
1163
NG_HCI_WARN(
1164
"%s: %s - unit is not ready, state=%#x\n",
1165
__func__, NG_NODE_NAME(unit->node), unit->state);
1166
1167
error = ENXIO;
1168
goto out;
1169
}
1170
1171
if (NGI_MSG(item)->header.arglen != sizeof(*ep)) {
1172
NG_HCI_ALERT(
1173
"%s: %s - invalid LP_QoSSetupReq message size=%d\n",
1174
__func__, NG_NODE_NAME(unit->node),
1175
NGI_MSG(item)->header.arglen);
1176
1177
error = EMSGSIZE;
1178
goto out;
1179
}
1180
1181
ep = (ng_hci_lp_qos_req_ep *)(NGI_MSG(item)->data);
1182
1183
con = ng_hci_con_by_handle(unit, ep->con_handle);
1184
if (con == NULL) {
1185
NG_HCI_ERR(
1186
"%s: %s - invalid connection handle=%d\n",
1187
__func__, NG_NODE_NAME(unit->node), ep->con_handle);
1188
1189
error = EINVAL;
1190
goto out;
1191
}
1192
1193
if (con->link_type != NG_HCI_LINK_ACL) {
1194
NG_HCI_ERR("%s: %s - invalid link type=%d\n",
1195
__func__, NG_NODE_NAME(unit->node), con->link_type);
1196
1197
error = EINVAL;
1198
goto out;
1199
}
1200
1201
if (con->state != NG_HCI_CON_OPEN) {
1202
NG_HCI_ERR(
1203
"%s: %s - invalid connection state=%d, handle=%d\n",
1204
__func__, NG_NODE_NAME(unit->node), con->state,
1205
con->con_handle);
1206
1207
error = EINVAL;
1208
goto out;
1209
}
1210
1211
/*
1212
* Create HCI command
1213
*/
1214
1215
MGETHDR(m, M_NOWAIT, MT_DATA);
1216
if (m == NULL) {
1217
error = ENOBUFS;
1218
goto out;
1219
}
1220
1221
m->m_pkthdr.len = m->m_len = sizeof(*req);
1222
req = mtod(m, struct qos_setup_req *);
1223
req->hdr.type = NG_HCI_CMD_PKT;
1224
req->hdr.length = sizeof(req->cp);
1225
req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
1226
NG_HCI_OCF_QOS_SETUP));
1227
1228
req->cp.con_handle = htole16(ep->con_handle);
1229
req->cp.flags = ep->flags;
1230
req->cp.service_type = ep->service_type;
1231
req->cp.token_rate = htole32(ep->token_rate);
1232
req->cp.peak_bandwidth = htole32(ep->peak_bandwidth);
1233
req->cp.latency = htole32(ep->latency);
1234
req->cp.delay_variation = htole32(ep->delay_variation);
1235
1236
/*
1237
* Adjust connection state
1238
*/
1239
1240
if (hook == unit->acl)
1241
con->flags |= NG_HCI_CON_NOTIFY_ACL;
1242
else
1243
con->flags |= NG_HCI_CON_NOTIFY_SCO;
1244
1245
/*
1246
* Queue and send HCI command
1247
*/
1248
1249
NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
1250
if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
1251
error = ng_hci_send_command(unit);
1252
out:
1253
NG_FREE_ITEM(item);
1254
1255
return (error);
1256
} /* ng_hci_lp_qos_req */
1257
1258
/*
1259
* Send LP_QoSCfm event to the upper layer protocol
1260
*/
1261
1262
int
1263
ng_hci_lp_qos_cfm(ng_hci_unit_con_p con, int status)
1264
{
1265
ng_hci_unit_p unit = con->unit;
1266
struct ng_mesg *msg = NULL;
1267
ng_hci_lp_qos_cfm_ep *ep = NULL;
1268
int error;
1269
1270
if (con->flags & NG_HCI_CON_NOTIFY_ACL) {
1271
if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
1272
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_CFM,
1273
sizeof(*ep), M_NOWAIT);
1274
if (msg != NULL) {
1275
ep = (ng_hci_lp_qos_cfm_ep *) msg->data;
1276
ep->status = status;
1277
ep->con_handle = con->con_handle;
1278
1279
NG_SEND_MSG_HOOK(error, unit->node, msg,
1280
unit->acl, 0);
1281
}
1282
} else
1283
NG_HCI_INFO(
1284
"%s: %s - ACL hook not valid, hook=%p\n",
1285
__func__, NG_NODE_NAME(unit->node), unit->acl);
1286
1287
con->flags &= ~NG_HCI_CON_NOTIFY_ACL;
1288
}
1289
1290
if (con->flags & NG_HCI_CON_NOTIFY_SCO) {
1291
if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) {
1292
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_CFM,
1293
sizeof(*ep), M_NOWAIT);
1294
if (msg != NULL) {
1295
ep = (ng_hci_lp_qos_cfm_ep *) msg->data;
1296
ep->status = status;
1297
ep->con_handle = con->con_handle;
1298
1299
NG_SEND_MSG_HOOK(error, unit->node, msg,
1300
unit->sco, 0);
1301
}
1302
} else
1303
NG_HCI_INFO(
1304
"%s: %s - SCO hook not valid, hook=%p\n",
1305
__func__, NG_NODE_NAME(unit->node), unit->sco);
1306
1307
con->flags &= ~NG_HCI_CON_NOTIFY_SCO;
1308
}
1309
1310
return (0);
1311
} /* ng_hci_lp_qos_cfm */
1312
1313
/*
1314
* Send LP_QoSViolationInd event to the upper layer protocol
1315
*/
1316
1317
int
1318
ng_hci_lp_qos_ind(ng_hci_unit_con_p con)
1319
{
1320
ng_hci_unit_p unit = con->unit;
1321
struct ng_mesg *msg = NULL;
1322
ng_hci_lp_qos_ind_ep *ep = NULL;
1323
int error;
1324
1325
/*
1326
* QoS Violation can only be generated for ACL connection handles.
1327
* Both ACL and SCO upstream hooks will receive notification.
1328
*/
1329
1330
if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
1331
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_IND,
1332
sizeof(*ep), M_NOWAIT);
1333
if (msg == NULL)
1334
return (ENOMEM);
1335
1336
ep = (ng_hci_lp_qos_ind_ep *) msg->data;
1337
ep->con_handle = con->con_handle;
1338
1339
NG_SEND_MSG_HOOK(error, unit->node, msg, unit->acl, 0);
1340
} else
1341
NG_HCI_INFO(
1342
"%s: %s - ACL hook is not connected or not valid, hook=%p\n",
1343
__func__, NG_NODE_NAME(unit->node), unit->acl);
1344
1345
if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) {
1346
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_IND,
1347
sizeof(*ep), M_NOWAIT);
1348
if (msg == NULL)
1349
return (ENOMEM);
1350
1351
ep = (ng_hci_lp_qos_ind_ep *) msg->data;
1352
ep->con_handle = con->con_handle;
1353
1354
NG_SEND_MSG_HOOK(error, unit->node, msg, unit->sco, 0);
1355
} else
1356
NG_HCI_INFO(
1357
"%s: %s - SCO hook is not connected or not valid, hook=%p\n",
1358
__func__, NG_NODE_NAME(unit->node), unit->sco);
1359
1360
return (0);
1361
} /* ng_hci_lp_qos_ind */
1362
1363
/*
1364
* Process connection timeout
1365
*/
1366
1367
void
1368
ng_hci_process_con_timeout(node_p node, hook_p hook, void *arg1, int con_handle)
1369
{
1370
ng_hci_unit_p unit = NULL;
1371
ng_hci_unit_con_p con = NULL;
1372
1373
if (NG_NODE_NOT_VALID(node)) {
1374
printf("%s: Netgraph node is not valid\n", __func__);
1375
return;
1376
}
1377
1378
unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node);
1379
con = ng_hci_con_by_handle(unit, con_handle);
1380
1381
if (con == NULL) {
1382
NG_HCI_ALERT(
1383
"%s: %s - could not find connection, handle=%d\n",
1384
__func__, NG_NODE_NAME(node), con_handle);
1385
return;
1386
}
1387
1388
if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING)) {
1389
NG_HCI_ALERT(
1390
"%s: %s - no pending connection timeout, handle=%d, state=%d, flags=%#x\n",
1391
__func__, NG_NODE_NAME(node), con_handle, con->state,
1392
con->flags);
1393
return;
1394
}
1395
1396
con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING;
1397
1398
/*
1399
* We expect to receive connection timeout in one of the following
1400
* states:
1401
*
1402
* 1) NG_HCI_CON_W4_LP_CON_RSP means that upper layer has not responded
1403
* to our LP_CON_IND. Do nothing and destroy connection. Remote peer
1404
* most likely already gave up on us.
1405
*
1406
* 2) NG_HCI_CON_W4_CONN_COMPLETE means upper layer requested connection
1407
* (or we in the process of accepting it) and baseband has timedout
1408
* on us. Inform upper layers and send LP_CON_CFM.
1409
*/
1410
1411
switch (con->state) {
1412
case NG_HCI_CON_W4_LP_CON_RSP:
1413
break;
1414
1415
case NG_HCI_CON_W4_CONN_COMPLETE:
1416
ng_hci_lp_con_cfm(con, 0xee);
1417
break;
1418
1419
default:
1420
panic(
1421
"%s: %s - Invalid connection state=%d\n",
1422
__func__, NG_NODE_NAME(node), con->state);
1423
break;
1424
}
1425
1426
ng_hci_free_con(con);
1427
} /* ng_hci_process_con_timeout */
1428
1429