Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netgraph/bluetooth/hci/ng_hci_evnt.c
34814 views
1
/*
2
* ng_hci_evnt.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_evnt.c,v 1.6 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
** HCI event processing module
55
******************************************************************************
56
******************************************************************************/
57
58
/*
59
* Event processing routines
60
*/
61
62
static int inquiry_result (ng_hci_unit_p, struct mbuf *);
63
static int con_compl (ng_hci_unit_p, struct mbuf *);
64
static int con_req (ng_hci_unit_p, struct mbuf *);
65
static int discon_compl (ng_hci_unit_p, struct mbuf *);
66
static int encryption_change (ng_hci_unit_p, struct mbuf *);
67
static int read_remote_features_compl (ng_hci_unit_p, struct mbuf *);
68
static int qos_setup_compl (ng_hci_unit_p, struct mbuf *);
69
static int hardware_error (ng_hci_unit_p, struct mbuf *);
70
static int role_change (ng_hci_unit_p, struct mbuf *);
71
static int num_compl_pkts (ng_hci_unit_p, struct mbuf *);
72
static int mode_change (ng_hci_unit_p, struct mbuf *);
73
static int data_buffer_overflow (ng_hci_unit_p, struct mbuf *);
74
static int read_clock_offset_compl (ng_hci_unit_p, struct mbuf *);
75
static int qos_violation (ng_hci_unit_p, struct mbuf *);
76
static int page_scan_mode_change (ng_hci_unit_p, struct mbuf *);
77
static int page_scan_rep_mode_change (ng_hci_unit_p, struct mbuf *);
78
static int sync_con_queue (ng_hci_unit_p, ng_hci_unit_con_p, int);
79
static int send_data_packets (ng_hci_unit_p, int, int);
80
static int le_event (ng_hci_unit_p, struct mbuf *);
81
82
/*
83
* Process HCI event packet
84
*/
85
86
int
87
ng_hci_process_event(ng_hci_unit_p unit, struct mbuf *event)
88
{
89
ng_hci_event_pkt_t *hdr = NULL;
90
int error = 0;
91
92
/* Get event packet header */
93
NG_HCI_M_PULLUP(event, sizeof(*hdr));
94
if (event == NULL)
95
return (ENOBUFS);
96
97
hdr = mtod(event, ng_hci_event_pkt_t *);
98
99
NG_HCI_INFO(
100
"%s: %s - got HCI event=%#x, length=%d\n",
101
__func__, NG_NODE_NAME(unit->node), hdr->event, hdr->length);
102
103
/* Get rid of event header and process event */
104
m_adj(event, sizeof(*hdr));
105
106
switch (hdr->event) {
107
case NG_HCI_EVENT_INQUIRY_COMPL:
108
case NG_HCI_EVENT_RETURN_LINK_KEYS:
109
case NG_HCI_EVENT_PIN_CODE_REQ:
110
case NG_HCI_EVENT_LINK_KEY_REQ:
111
case NG_HCI_EVENT_LINK_KEY_NOTIFICATION:
112
case NG_HCI_EVENT_LOOPBACK_COMMAND:
113
case NG_HCI_EVENT_AUTH_COMPL:
114
case NG_HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL:
115
case NG_HCI_EVENT_MASTER_LINK_KEY_COMPL:
116
case NG_HCI_EVENT_FLUSH_OCCUR: /* XXX Do we have to handle it? */
117
case NG_HCI_EVENT_MAX_SLOT_CHANGE:
118
case NG_HCI_EVENT_CON_PKT_TYPE_CHANGED:
119
case NG_HCI_EVENT_BT_LOGO:
120
case NG_HCI_EVENT_VENDOR:
121
case NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL:
122
case NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL:
123
case NG_HCI_EVENT_IO_CAPABILITY_REQUEST:
124
case NG_HCI_EVENT_SIMPLE_PAIRING_COMPLETE:
125
/* These do not need post processing */
126
NG_FREE_M(event);
127
break;
128
case NG_HCI_EVENT_LE:
129
error = le_event(unit, event);
130
break;
131
132
case NG_HCI_EVENT_INQUIRY_RESULT:
133
error = inquiry_result(unit, event);
134
break;
135
136
case NG_HCI_EVENT_CON_COMPL:
137
error = con_compl(unit, event);
138
break;
139
140
case NG_HCI_EVENT_CON_REQ:
141
error = con_req(unit, event);
142
break;
143
144
case NG_HCI_EVENT_DISCON_COMPL:
145
error = discon_compl(unit, event);
146
break;
147
148
case NG_HCI_EVENT_ENCRYPTION_CHANGE:
149
error = encryption_change(unit, event);
150
break;
151
152
case NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL:
153
error = read_remote_features_compl(unit, event);
154
break;
155
156
case NG_HCI_EVENT_QOS_SETUP_COMPL:
157
error = qos_setup_compl(unit, event);
158
break;
159
160
case NG_HCI_EVENT_COMMAND_COMPL:
161
error = ng_hci_process_command_complete(unit, event);
162
break;
163
164
case NG_HCI_EVENT_COMMAND_STATUS:
165
error = ng_hci_process_command_status(unit, event);
166
break;
167
168
case NG_HCI_EVENT_HARDWARE_ERROR:
169
error = hardware_error(unit, event);
170
break;
171
172
case NG_HCI_EVENT_ROLE_CHANGE:
173
error = role_change(unit, event);
174
break;
175
176
case NG_HCI_EVENT_NUM_COMPL_PKTS:
177
error = num_compl_pkts(unit, event);
178
break;
179
180
case NG_HCI_EVENT_MODE_CHANGE:
181
error = mode_change(unit, event);
182
break;
183
184
case NG_HCI_EVENT_DATA_BUFFER_OVERFLOW:
185
error = data_buffer_overflow(unit, event);
186
break;
187
188
case NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL:
189
error = read_clock_offset_compl(unit, event);
190
break;
191
192
case NG_HCI_EVENT_QOS_VIOLATION:
193
error = qos_violation(unit, event);
194
break;
195
196
case NG_HCI_EVENT_PAGE_SCAN_MODE_CHANGE:
197
error = page_scan_mode_change(unit, event);
198
break;
199
200
case NG_HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE:
201
error = page_scan_rep_mode_change(unit, event);
202
break;
203
204
default:
205
NG_FREE_M(event);
206
error = EINVAL;
207
break;
208
}
209
210
return (error);
211
} /* ng_hci_process_event */
212
213
/*
214
* Send ACL and/or SCO data to the unit driver
215
*/
216
217
void
218
ng_hci_send_data(ng_hci_unit_p unit)
219
{
220
int count;
221
222
/* Send ACL data */
223
NG_HCI_BUFF_ACL_AVAIL(unit->buffer, count);
224
225
NG_HCI_INFO(
226
"%s: %s - sending ACL data packets, count=%d\n",
227
__func__, NG_NODE_NAME(unit->node), count);
228
229
if (count > 0) {
230
count = send_data_packets(unit, NG_HCI_LINK_ACL, count);
231
NG_HCI_STAT_ACL_SENT(unit->stat, count);
232
NG_HCI_BUFF_ACL_USE(unit->buffer, count);
233
}
234
235
/* Send SCO data */
236
NG_HCI_BUFF_SCO_AVAIL(unit->buffer, count);
237
238
NG_HCI_INFO(
239
"%s: %s - sending SCO data packets, count=%d\n",
240
__func__, NG_NODE_NAME(unit->node), count);
241
242
if (count > 0) {
243
count = send_data_packets(unit, NG_HCI_LINK_SCO, count);
244
NG_HCI_STAT_SCO_SENT(unit->stat, count);
245
NG_HCI_BUFF_SCO_USE(unit->buffer, count);
246
}
247
} /* ng_hci_send_data */
248
249
/*
250
* Send data packets to the lower layer.
251
*/
252
253
static int
254
send_data_packets(ng_hci_unit_p unit, int link_type, int limit)
255
{
256
ng_hci_unit_con_p con = NULL, winner = NULL;
257
int reallink_type;
258
item_p item = NULL;
259
int min_pending, total_sent, sent, error, v;
260
261
for (total_sent = 0; limit > 0; ) {
262
min_pending = 0x0fffffff;
263
winner = NULL;
264
265
/*
266
* Find the connection that has has data to send
267
* and the smallest number of pending packets
268
*/
269
270
LIST_FOREACH(con, &unit->con_list, next) {
271
reallink_type = (con->link_type == NG_HCI_LINK_SCO)?
272
NG_HCI_LINK_SCO: NG_HCI_LINK_ACL;
273
if (reallink_type != link_type){
274
continue;
275
}
276
if (NG_BT_ITEMQ_LEN(&con->conq) == 0)
277
continue;
278
279
if (con->pending < min_pending) {
280
winner = con;
281
min_pending = con->pending;
282
}
283
}
284
285
if (winner == NULL)
286
break;
287
288
/*
289
* OK, we have a winner now send as much packets as we can
290
* Count the number of packets we have sent and then sync
291
* winner connection queue.
292
*/
293
294
for (sent = 0; limit > 0; limit --, total_sent ++, sent ++) {
295
NG_BT_ITEMQ_DEQUEUE(&winner->conq, item);
296
if (item == NULL)
297
break;
298
299
NG_HCI_INFO(
300
"%s: %s - sending data packet, handle=%d, len=%d\n",
301
__func__, NG_NODE_NAME(unit->node),
302
winner->con_handle, NGI_M(item)->m_pkthdr.len);
303
304
/* Check if driver hook still there */
305
v = (unit->drv != NULL && NG_HOOK_IS_VALID(unit->drv));
306
if (!v || (unit->state & NG_HCI_UNIT_READY) !=
307
NG_HCI_UNIT_READY) {
308
NG_HCI_ERR(
309
"%s: %s - could not send data. Hook \"%s\" is %svalid, state=%#x\n",
310
__func__, NG_NODE_NAME(unit->node),
311
NG_HCI_HOOK_DRV, ((v)? "" : "not "),
312
unit->state);
313
314
NG_FREE_ITEM(item);
315
error = ENOTCONN;
316
} else {
317
v = NGI_M(item)->m_pkthdr.len;
318
319
/* Give packet to raw hook */
320
ng_hci_mtap(unit, NGI_M(item));
321
322
/* ... and forward item to the driver */
323
NG_FWD_ITEM_HOOK(error, item, unit->drv);
324
}
325
326
if (error != 0) {
327
NG_HCI_ERR(
328
"%s: %s - could not send data packet, handle=%d, error=%d\n",
329
__func__, NG_NODE_NAME(unit->node),
330
winner->con_handle, error);
331
break;
332
}
333
334
winner->pending ++;
335
NG_HCI_STAT_BYTES_SENT(unit->stat, v);
336
}
337
338
/*
339
* Sync connection queue for the winner
340
*/
341
sync_con_queue(unit, winner, sent);
342
}
343
344
return (total_sent);
345
} /* send_data_packets */
346
347
/*
348
* Send flow control messages to the upper layer
349
*/
350
351
static int
352
sync_con_queue(ng_hci_unit_p unit, ng_hci_unit_con_p con, int completed)
353
{
354
hook_p hook = NULL;
355
struct ng_mesg *msg = NULL;
356
ng_hci_sync_con_queue_ep *state = NULL;
357
int error;
358
359
hook = (con->link_type != NG_HCI_LINK_SCO)? unit->acl : unit->sco;
360
if (hook == NULL || NG_HOOK_NOT_VALID(hook))
361
return (ENOTCONN);
362
363
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_SYNC_CON_QUEUE,
364
sizeof(*state), M_NOWAIT);
365
if (msg == NULL)
366
return (ENOMEM);
367
368
state = (ng_hci_sync_con_queue_ep *)(msg->data);
369
state->con_handle = con->con_handle;
370
state->completed = completed;
371
372
NG_SEND_MSG_HOOK(error, unit->node, msg, hook, 0);
373
374
return (error);
375
} /* sync_con_queue */
376
/* le meta event */
377
/* Inquiry result event */
378
static int
379
le_advertizing_report(ng_hci_unit_p unit, struct mbuf *event)
380
{
381
ng_hci_le_advertising_report_ep *ep = NULL;
382
ng_hci_neighbor_p n = NULL;
383
bdaddr_t bdaddr;
384
int error = 0;
385
int num_reports = 0;
386
u_int8_t addr_type;
387
388
NG_HCI_M_PULLUP(event, sizeof(*ep));
389
if (event == NULL)
390
return (ENOBUFS);
391
392
ep = mtod(event, ng_hci_le_advertising_report_ep *);
393
num_reports = ep->num_reports;
394
m_adj(event, sizeof(*ep));
395
ep = NULL;
396
397
for (; num_reports > 0; num_reports --) {
398
/* event_type */
399
m_adj(event, sizeof(u_int8_t));
400
401
/* Get remote unit address */
402
NG_HCI_M_PULLUP(event, sizeof(u_int8_t));
403
if (event == NULL) {
404
error = ENOBUFS;
405
goto out;
406
}
407
addr_type = *mtod(event, u_int8_t *);
408
m_adj(event, sizeof(u_int8_t));
409
410
m_copydata(event, 0, sizeof(bdaddr), (caddr_t) &bdaddr);
411
m_adj(event, sizeof(bdaddr));
412
413
/* Lookup entry in the cache */
414
n = ng_hci_get_neighbor(unit, &bdaddr, (addr_type) ? NG_HCI_LINK_LE_RANDOM:NG_HCI_LINK_LE_PUBLIC);
415
if (n == NULL) {
416
/* Create new entry */
417
n = ng_hci_new_neighbor(unit);
418
if (n == NULL) {
419
error = ENOMEM;
420
break;
421
}
422
bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr));
423
n->addrtype = (addr_type)? NG_HCI_LINK_LE_RANDOM :
424
NG_HCI_LINK_LE_PUBLIC;
425
426
} else
427
getmicrotime(&n->updated);
428
429
{
430
/*
431
* TODO: Make these information
432
* Available from userland.
433
*/
434
u_int8_t length_data;
435
436
event = m_pullup(event, sizeof(u_int8_t));
437
if(event == NULL){
438
NG_HCI_WARN("%s: Event datasize Pullup Failed\n", __func__);
439
goto out;
440
}
441
length_data = *mtod(event, u_int8_t *);
442
m_adj(event, sizeof(u_int8_t));
443
n->extinq_size = (length_data < NG_HCI_EXTINQ_MAX)?
444
length_data : NG_HCI_EXTINQ_MAX;
445
446
/*Advertizement data*/
447
event = m_pullup(event, n->extinq_size);
448
if(event == NULL){
449
NG_HCI_WARN("%s: Event data pullup Failed\n", __func__);
450
goto out;
451
}
452
m_copydata(event, 0, n->extinq_size, n->extinq_data);
453
m_adj(event, n->extinq_size);
454
event = m_pullup(event, sizeof(char ));
455
/*Get RSSI*/
456
if(event == NULL){
457
NG_HCI_WARN("%s: Event rssi pull up Failed\n", __func__);
458
459
goto out;
460
}
461
n->page_scan_mode = *mtod(event, char *);
462
m_adj(event, sizeof(u_int8_t));
463
}
464
}
465
out:
466
NG_FREE_M(event);
467
468
return (error);
469
} /* inquiry_result */
470
471
static int le_connection_complete(ng_hci_unit_p unit, struct mbuf *event)
472
{
473
int error = 0;
474
475
ng_hci_le_connection_complete_ep *ep = NULL;
476
ng_hci_unit_con_p con = NULL;
477
int link_type;
478
uint8_t uclass[3] = {0,0,0};//dummy uclass
479
480
NG_HCI_M_PULLUP(event, sizeof(*ep));
481
if (event == NULL)
482
return (ENOBUFS);
483
484
ep = mtod(event, ng_hci_le_connection_complete_ep *);
485
link_type = (ep->address_type)? NG_HCI_LINK_LE_RANDOM :
486
NG_HCI_LINK_LE_PUBLIC;
487
/*
488
* Find the first connection descriptor that matches the following:
489
*
490
* 1) con->link_type == link_type
491
* 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE
492
* 3) con->bdaddr == ep->address
493
*/
494
LIST_FOREACH(con, &unit->con_list, next)
495
if (con->link_type == link_type &&
496
con->state == NG_HCI_CON_W4_CONN_COMPLETE &&
497
bcmp(&con->bdaddr, &ep->address, sizeof(bdaddr_t)) == 0)
498
break;
499
500
/*
501
* Two possible cases:
502
*
503
* 1) We have found connection descriptor. That means upper layer has
504
* requested this connection via LP_CON_REQ message. In this case
505
* connection must have timeout set. If ng_hci_con_untimeout() fails
506
* then timeout message already went into node's queue. In this case
507
* ignore Connection_Complete event and let timeout deal with it.
508
*
509
* 2) We do not have connection descriptor. That means upper layer
510
* nas not requested this connection , (less likely) we gave up
511
* on this connection (timeout) or as node act as slave role.
512
* The most likely scenario is that
513
* we have received LE_Create_Connection command
514
* from the RAW hook
515
*/
516
517
if (con == NULL) {
518
if (ep->status != 0)
519
goto out;
520
521
con = ng_hci_new_con(unit, link_type);
522
if (con == NULL) {
523
error = ENOMEM;
524
goto out;
525
}
526
527
con->state = NG_HCI_CON_W4_LP_CON_RSP;
528
ng_hci_con_timeout(con);
529
530
bcopy(&ep->address, &con->bdaddr, sizeof(con->bdaddr));
531
error = ng_hci_lp_con_ind(con, uclass);
532
if (error != 0) {
533
ng_hci_con_untimeout(con);
534
ng_hci_free_con(con);
535
goto out;
536
}
537
538
} else if ((error = ng_hci_con_untimeout(con)) != 0)
539
goto out;
540
541
/*
542
* Update connection descriptor and send notification
543
* to the upper layers.
544
*/
545
546
con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->handle));
547
con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE;
548
549
ng_hci_lp_con_cfm(con, ep->status);
550
551
/* Adjust connection state */
552
if (ep->status != 0)
553
ng_hci_free_con(con);
554
else {
555
con->state = NG_HCI_CON_OPEN;
556
557
/*
558
* Change link policy for the ACL connections. Enable all
559
* supported link modes. Enable Role switch as well if
560
* device supports it.
561
*/
562
}
563
564
out:
565
NG_FREE_M(event);
566
567
return (error);
568
569
}
570
571
static int le_connection_update(ng_hci_unit_p unit, struct mbuf *event)
572
{
573
int error = 0;
574
/*TBD*/
575
576
NG_FREE_M(event);
577
return error;
578
579
}
580
static int
581
le_event(ng_hci_unit_p unit, struct mbuf *event)
582
{
583
int error = 0;
584
ng_hci_le_ep *lep;
585
586
NG_HCI_M_PULLUP(event, sizeof(*lep));
587
if(event ==NULL){
588
return ENOBUFS;
589
}
590
lep = mtod(event, ng_hci_le_ep *);
591
m_adj(event, sizeof(*lep));
592
switch(lep->subevent_code){
593
case NG_HCI_LEEV_CON_COMPL:
594
le_connection_complete(unit, event);
595
break;
596
case NG_HCI_LEEV_ADVREP:
597
le_advertizing_report(unit, event);
598
break;
599
case NG_HCI_LEEV_CON_UPDATE_COMPL:
600
le_connection_update(unit, event);
601
break;
602
case NG_HCI_LEEV_READ_REMOTE_FEATURES_COMPL:
603
//TBD
604
/*FALLTHROUGH*/
605
case NG_HCI_LEEV_LONG_TERM_KEY_REQUEST:
606
//TBD
607
/*FALLTHROUGH*/
608
default:
609
NG_FREE_M(event);
610
}
611
return error;
612
}
613
614
/* Inquiry result event */
615
static int
616
inquiry_result(ng_hci_unit_p unit, struct mbuf *event)
617
{
618
ng_hci_inquiry_result_ep *ep = NULL;
619
ng_hci_neighbor_p n = NULL;
620
bdaddr_t bdaddr;
621
int error = 0;
622
623
NG_HCI_M_PULLUP(event, sizeof(*ep));
624
if (event == NULL)
625
return (ENOBUFS);
626
627
ep = mtod(event, ng_hci_inquiry_result_ep *);
628
m_adj(event, sizeof(*ep));
629
630
for (; ep->num_responses > 0; ep->num_responses --) {
631
/* Get remote unit address */
632
m_copydata(event, 0, sizeof(bdaddr), (caddr_t) &bdaddr);
633
m_adj(event, sizeof(bdaddr));
634
635
/* Lookup entry in the cache */
636
n = ng_hci_get_neighbor(unit, &bdaddr, NG_HCI_LINK_ACL);
637
if (n == NULL) {
638
/* Create new entry */
639
n = ng_hci_new_neighbor(unit);
640
if (n == NULL) {
641
error = ENOMEM;
642
break;
643
}
644
} else
645
getmicrotime(&n->updated);
646
647
bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr));
648
n->addrtype = NG_HCI_LINK_ACL;
649
650
/* XXX call m_pullup here? */
651
652
n->page_scan_rep_mode = *mtod(event, u_int8_t *);
653
m_adj(event, sizeof(u_int8_t));
654
655
/* page_scan_period_mode */
656
m_adj(event, sizeof(u_int8_t));
657
658
n->page_scan_mode = *mtod(event, u_int8_t *);
659
m_adj(event, sizeof(u_int8_t));
660
661
/* class */
662
m_adj(event, NG_HCI_CLASS_SIZE);
663
664
/* clock offset */
665
m_copydata(event, 0, sizeof(n->clock_offset),
666
(caddr_t) &n->clock_offset);
667
n->clock_offset = le16toh(n->clock_offset);
668
}
669
670
NG_FREE_M(event);
671
672
return (error);
673
} /* inquiry_result */
674
675
/* Connection complete event */
676
static int
677
con_compl(ng_hci_unit_p unit, struct mbuf *event)
678
{
679
ng_hci_con_compl_ep *ep = NULL;
680
ng_hci_unit_con_p con = NULL;
681
int error = 0;
682
683
NG_HCI_M_PULLUP(event, sizeof(*ep));
684
if (event == NULL)
685
return (ENOBUFS);
686
687
ep = mtod(event, ng_hci_con_compl_ep *);
688
689
/*
690
* Find the first connection descriptor that matches the following:
691
*
692
* 1) con->link_type == ep->link_type
693
* 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE
694
* 3) con->bdaddr == ep->bdaddr
695
*/
696
697
LIST_FOREACH(con, &unit->con_list, next)
698
if (con->link_type == ep->link_type &&
699
con->state == NG_HCI_CON_W4_CONN_COMPLETE &&
700
bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0)
701
break;
702
703
/*
704
* Two possible cases:
705
*
706
* 1) We have found connection descriptor. That means upper layer has
707
* requested this connection via LP_CON_REQ message. In this case
708
* connection must have timeout set. If ng_hci_con_untimeout() fails
709
* then timeout message already went into node's queue. In this case
710
* ignore Connection_Complete event and let timeout deal with it.
711
*
712
* 2) We do not have connection descriptor. That means upper layer
713
* nas not requested this connection or (less likely) we gave up
714
* on this connection (timeout). The most likely scenario is that
715
* we have received Create_Connection/Add_SCO_Connection command
716
* from the RAW hook
717
*/
718
719
if (con == NULL) {
720
if (ep->status != 0)
721
goto out;
722
723
con = ng_hci_new_con(unit, ep->link_type);
724
if (con == NULL) {
725
error = ENOMEM;
726
goto out;
727
}
728
729
bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));
730
} else if ((error = ng_hci_con_untimeout(con)) != 0)
731
goto out;
732
733
/*
734
* Update connection descriptor and send notification
735
* to the upper layers.
736
*/
737
738
con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
739
con->encryption_mode = ep->encryption_mode;
740
741
ng_hci_lp_con_cfm(con, ep->status);
742
743
/* Adjust connection state */
744
if (ep->status != 0)
745
ng_hci_free_con(con);
746
else {
747
con->state = NG_HCI_CON_OPEN;
748
749
/*
750
* Change link policy for the ACL connections. Enable all
751
* supported link modes. Enable Role switch as well if
752
* device supports it.
753
*/
754
755
if (ep->link_type == NG_HCI_LINK_ACL) {
756
struct __link_policy {
757
ng_hci_cmd_pkt_t hdr;
758
ng_hci_write_link_policy_settings_cp cp;
759
} __attribute__ ((packed)) *lp;
760
struct mbuf *m;
761
762
MGETHDR(m, M_NOWAIT, MT_DATA);
763
if (m != NULL) {
764
m->m_pkthdr.len = m->m_len = sizeof(*lp);
765
lp = mtod(m, struct __link_policy *);
766
767
lp->hdr.type = NG_HCI_CMD_PKT;
768
lp->hdr.opcode = htole16(NG_HCI_OPCODE(
769
NG_HCI_OGF_LINK_POLICY,
770
NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS));
771
lp->hdr.length = sizeof(lp->cp);
772
773
lp->cp.con_handle = ep->con_handle;
774
775
lp->cp.settings = 0;
776
if ((unit->features[0] & NG_HCI_LMP_SWITCH) &&
777
unit->role_switch)
778
lp->cp.settings |= 0x1;
779
if (unit->features[0] & NG_HCI_LMP_HOLD_MODE)
780
lp->cp.settings |= 0x2;
781
if (unit->features[0] & NG_HCI_LMP_SNIFF_MODE)
782
lp->cp.settings |= 0x4;
783
if (unit->features[1] & NG_HCI_LMP_PARK_MODE)
784
lp->cp.settings |= 0x8;
785
786
lp->cp.settings &= unit->link_policy_mask;
787
lp->cp.settings = htole16(lp->cp.settings);
788
789
NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
790
if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
791
ng_hci_send_command(unit);
792
}
793
}
794
}
795
out:
796
NG_FREE_M(event);
797
798
return (error);
799
} /* con_compl */
800
801
/* Connection request event */
802
static int
803
con_req(ng_hci_unit_p unit, struct mbuf *event)
804
{
805
ng_hci_con_req_ep *ep = NULL;
806
ng_hci_unit_con_p con = NULL;
807
int error = 0;
808
809
NG_HCI_M_PULLUP(event, sizeof(*ep));
810
if (event == NULL)
811
return (ENOBUFS);
812
813
ep = mtod(event, ng_hci_con_req_ep *);
814
815
/*
816
* Find the first connection descriptor that matches the following:
817
*
818
* 1) con->link_type == ep->link_type
819
*
820
* 2) con->state == NG_HCI_CON_W4_LP_CON_RSP ||
821
* con->state == NG_HCI_CON_W4_CONN_COMPL
822
*
823
* 3) con->bdaddr == ep->bdaddr
824
*
825
* Possible cases:
826
*
827
* 1) We do not have connection descriptor. This is simple. Create
828
* new fresh connection descriptor and send notification to the
829
* appropriate upstream hook (based on link_type).
830
*
831
* 2) We found connection handle. This is more complicated.
832
*
833
* 2.1) ACL links
834
*
835
* Since only one ACL link can exist between each pair of
836
* units then we have a race. Our upper layer has requested
837
* an ACL connection to the remote unit, but we did not send
838
* command yet. At the same time the remote unit has requested
839
* an ACL connection from us. In this case we will ignore
840
* Connection_Request event. This probably will cause connect
841
* failure on both units.
842
*
843
* 2.2) SCO links
844
*
845
* The spec on page 45 says :
846
*
847
* "The master can support up to three SCO links to the same
848
* slave or to different slaves. A slave can support up to
849
* three SCO links from the same master, or two SCO links if
850
* the links originate from different masters."
851
*
852
* The only problem is how to handle multiple SCO links between
853
* matster and slave. For now we will assume that multiple SCO
854
* links MUST be opened one after another.
855
*/
856
857
LIST_FOREACH(con, &unit->con_list, next)
858
if (con->link_type == ep->link_type &&
859
(con->state == NG_HCI_CON_W4_LP_CON_RSP ||
860
con->state == NG_HCI_CON_W4_CONN_COMPLETE) &&
861
bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0)
862
break;
863
864
if (con == NULL) {
865
con = ng_hci_new_con(unit, ep->link_type);
866
if (con != NULL) {
867
bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));
868
869
con->state = NG_HCI_CON_W4_LP_CON_RSP;
870
ng_hci_con_timeout(con);
871
872
error = ng_hci_lp_con_ind(con, ep->uclass);
873
if (error != 0) {
874
ng_hci_con_untimeout(con);
875
ng_hci_free_con(con);
876
}
877
} else
878
error = ENOMEM;
879
}
880
881
NG_FREE_M(event);
882
883
return (error);
884
} /* con_req */
885
886
/* Disconnect complete event */
887
static int
888
discon_compl(ng_hci_unit_p unit, struct mbuf *event)
889
{
890
ng_hci_discon_compl_ep *ep = NULL;
891
ng_hci_unit_con_p con = NULL;
892
int error = 0;
893
u_int16_t h;
894
895
NG_HCI_M_PULLUP(event, sizeof(*ep));
896
if (event == NULL)
897
return (ENOBUFS);
898
899
ep = mtod(event, ng_hci_discon_compl_ep *);
900
901
/*
902
* XXX
903
* Do we have to send notification if ep->status != 0?
904
* For now we will send notification for both ACL and SCO connections
905
* ONLY if ep->status == 0.
906
*/
907
908
if (ep->status == 0) {
909
h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
910
con = ng_hci_con_by_handle(unit, h);
911
if (con != NULL) {
912
error = ng_hci_lp_discon_ind(con, ep->reason);
913
914
/* Remove all timeouts (if any) */
915
if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
916
ng_hci_con_untimeout(con);
917
918
ng_hci_free_con(con);
919
} else {
920
NG_HCI_ALERT(
921
"%s: %s - invalid connection handle=%d\n",
922
__func__, NG_NODE_NAME(unit->node), h);
923
error = ENOENT;
924
}
925
}
926
927
NG_FREE_M(event);
928
929
return (error);
930
} /* discon_compl */
931
932
/* Encryption change event */
933
static int
934
encryption_change(ng_hci_unit_p unit, struct mbuf *event)
935
{
936
ng_hci_encryption_change_ep *ep = NULL;
937
ng_hci_unit_con_p con = NULL;
938
int error = 0;
939
u_int16_t h;
940
941
NG_HCI_M_PULLUP(event, sizeof(*ep));
942
if (event == NULL)
943
return (ENOBUFS);
944
945
ep = mtod(event, ng_hci_encryption_change_ep *);
946
h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
947
con = ng_hci_con_by_handle(unit, h);
948
949
if (ep->status == 0) {
950
if (con == NULL) {
951
NG_HCI_ALERT(
952
"%s: %s - invalid connection handle=%d\n",
953
__func__, NG_NODE_NAME(unit->node), h);
954
error = ENOENT;
955
} else if (con->link_type == NG_HCI_LINK_SCO) {
956
NG_HCI_ALERT(
957
"%s: %s - invalid link type=%d\n",
958
__func__, NG_NODE_NAME(unit->node),
959
con->link_type);
960
error = EINVAL;
961
} else if (ep->encryption_enable)
962
/* XXX is that true? */
963
con->encryption_mode = NG_HCI_ENCRYPTION_MODE_P2P;
964
else
965
con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE;
966
} else
967
NG_HCI_ERR(
968
"%s: %s - failed to change encryption mode, status=%d\n",
969
__func__, NG_NODE_NAME(unit->node), ep->status);
970
971
/*Anyway, propagete encryption status to upper layer*/
972
ng_hci_lp_enc_change(con, con->encryption_mode);
973
974
NG_FREE_M(event);
975
976
return (error);
977
} /* encryption_change */
978
979
/* Read remote feature complete event */
980
static int
981
read_remote_features_compl(ng_hci_unit_p unit, struct mbuf *event)
982
{
983
ng_hci_read_remote_features_compl_ep *ep = NULL;
984
ng_hci_unit_con_p con = NULL;
985
ng_hci_neighbor_p n = NULL;
986
u_int16_t h;
987
int error = 0;
988
989
NG_HCI_M_PULLUP(event, sizeof(*ep));
990
if (event == NULL)
991
return (ENOBUFS);
992
993
ep = mtod(event, ng_hci_read_remote_features_compl_ep *);
994
995
if (ep->status == 0) {
996
/* Check if we have this connection handle */
997
h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
998
con = ng_hci_con_by_handle(unit, h);
999
if (con == NULL) {
1000
NG_HCI_ALERT(
1001
"%s: %s - invalid connection handle=%d\n",
1002
__func__, NG_NODE_NAME(unit->node), h);
1003
error = ENOENT;
1004
goto out;
1005
}
1006
1007
/* Update cache entry */
1008
n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL);
1009
if (n == NULL) {
1010
n = ng_hci_new_neighbor(unit);
1011
if (n == NULL) {
1012
error = ENOMEM;
1013
goto out;
1014
}
1015
1016
bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1017
n->addrtype = NG_HCI_LINK_ACL;
1018
} else
1019
getmicrotime(&n->updated);
1020
1021
bcopy(ep->features, n->features, sizeof(n->features));
1022
} else
1023
NG_HCI_ERR(
1024
"%s: %s - failed to read remote unit features, status=%d\n",
1025
__func__, NG_NODE_NAME(unit->node), ep->status);
1026
out:
1027
NG_FREE_M(event);
1028
1029
return (error);
1030
} /* read_remote_features_compl */
1031
1032
/* QoS setup complete event */
1033
static int
1034
qos_setup_compl(ng_hci_unit_p unit, struct mbuf *event)
1035
{
1036
ng_hci_qos_setup_compl_ep *ep = NULL;
1037
ng_hci_unit_con_p con = NULL;
1038
u_int16_t h;
1039
int error = 0;
1040
1041
NG_HCI_M_PULLUP(event, sizeof(*ep));
1042
if (event == NULL)
1043
return (ENOBUFS);
1044
1045
ep = mtod(event, ng_hci_qos_setup_compl_ep *);
1046
1047
/* Check if we have this connection handle */
1048
h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1049
con = ng_hci_con_by_handle(unit, h);
1050
if (con == NULL) {
1051
NG_HCI_ALERT(
1052
"%s: %s - invalid connection handle=%d\n",
1053
__func__, NG_NODE_NAME(unit->node), h);
1054
error = ENOENT;
1055
} else if (con->link_type != NG_HCI_LINK_ACL) {
1056
NG_HCI_ALERT(
1057
"%s: %s - invalid link type=%d, handle=%d\n",
1058
__func__, NG_NODE_NAME(unit->node), con->link_type, h);
1059
error = EINVAL;
1060
} else if (con->state != NG_HCI_CON_OPEN) {
1061
NG_HCI_ALERT(
1062
"%s: %s - invalid connection state=%d, handle=%d\n",
1063
__func__, NG_NODE_NAME(unit->node),
1064
con->state, h);
1065
error = EINVAL;
1066
} else /* Notify upper layer */
1067
error = ng_hci_lp_qos_cfm(con, ep->status);
1068
1069
NG_FREE_M(event);
1070
1071
return (error);
1072
} /* qos_setup_compl */
1073
1074
/* Hardware error event */
1075
static int
1076
hardware_error(ng_hci_unit_p unit, struct mbuf *event)
1077
{
1078
NG_HCI_ALERT(
1079
"%s: %s - hardware error %#x\n",
1080
__func__, NG_NODE_NAME(unit->node), *mtod(event, u_int8_t *));
1081
1082
NG_FREE_M(event);
1083
1084
return (0);
1085
} /* hardware_error */
1086
1087
/* Role change event */
1088
static int
1089
role_change(ng_hci_unit_p unit, struct mbuf *event)
1090
{
1091
ng_hci_role_change_ep *ep = NULL;
1092
ng_hci_unit_con_p con = NULL;
1093
1094
NG_HCI_M_PULLUP(event, sizeof(*ep));
1095
if (event == NULL)
1096
return (ENOBUFS);
1097
1098
ep = mtod(event, ng_hci_role_change_ep *);
1099
1100
if (ep->status == 0) {
1101
/* XXX shoud we also change "role" for SCO connections? */
1102
con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
1103
if (con != NULL)
1104
con->role = ep->role;
1105
else
1106
NG_HCI_ALERT(
1107
"%s: %s - ACL connection does not exist, bdaddr=%x:%x:%x:%x:%x:%x\n",
1108
__func__, NG_NODE_NAME(unit->node),
1109
ep->bdaddr.b[5], ep->bdaddr.b[4],
1110
ep->bdaddr.b[3], ep->bdaddr.b[2],
1111
ep->bdaddr.b[1], ep->bdaddr.b[0]);
1112
} else
1113
NG_HCI_ERR(
1114
"%s: %s - failed to change role, status=%d, bdaddr=%x:%x:%x:%x:%x:%x\n",
1115
__func__, NG_NODE_NAME(unit->node), ep->status,
1116
ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
1117
ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
1118
1119
NG_FREE_M(event);
1120
1121
return (0);
1122
} /* role_change */
1123
1124
/* Number of completed packets event */
1125
static int
1126
num_compl_pkts(ng_hci_unit_p unit, struct mbuf *event)
1127
{
1128
ng_hci_num_compl_pkts_ep *ep = NULL;
1129
ng_hci_unit_con_p con = NULL;
1130
u_int16_t h, p;
1131
1132
NG_HCI_M_PULLUP(event, sizeof(*ep));
1133
if (event == NULL)
1134
return (ENOBUFS);
1135
1136
ep = mtod(event, ng_hci_num_compl_pkts_ep *);
1137
m_adj(event, sizeof(*ep));
1138
1139
for (; ep->num_con_handles > 0; ep->num_con_handles --) {
1140
/* Get connection handle */
1141
m_copydata(event, 0, sizeof(h), (caddr_t) &h);
1142
m_adj(event, sizeof(h));
1143
h = NG_HCI_CON_HANDLE(le16toh(h));
1144
1145
/* Get number of completed packets */
1146
m_copydata(event, 0, sizeof(p), (caddr_t) &p);
1147
m_adj(event, sizeof(p));
1148
p = le16toh(p);
1149
1150
/* Check if we have this connection handle */
1151
con = ng_hci_con_by_handle(unit, h);
1152
if (con != NULL) {
1153
con->pending -= p;
1154
if (con->pending < 0) {
1155
NG_HCI_WARN(
1156
"%s: %s - pending packet counter is out of sync! " \
1157
"handle=%d, pending=%d, ncp=%d\n", __func__, NG_NODE_NAME(unit->node),
1158
con->con_handle, con->pending, p);
1159
1160
con->pending = 0;
1161
}
1162
1163
/* Update buffer descriptor */
1164
if (con->link_type != NG_HCI_LINK_SCO)
1165
NG_HCI_BUFF_ACL_FREE(unit->buffer, p);
1166
else
1167
NG_HCI_BUFF_SCO_FREE(unit->buffer, p);
1168
} else
1169
NG_HCI_ALERT(
1170
"%s: %s - invalid connection handle=%d\n",
1171
__func__, NG_NODE_NAME(unit->node), h);
1172
}
1173
1174
NG_FREE_M(event);
1175
1176
/* Send more data */
1177
ng_hci_send_data(unit);
1178
1179
return (0);
1180
} /* num_compl_pkts */
1181
1182
/* Mode change event */
1183
static int
1184
mode_change(ng_hci_unit_p unit, struct mbuf *event)
1185
{
1186
ng_hci_mode_change_ep *ep = NULL;
1187
ng_hci_unit_con_p con = NULL;
1188
int error = 0;
1189
1190
NG_HCI_M_PULLUP(event, sizeof(*ep));
1191
if (event == NULL)
1192
return (ENOBUFS);
1193
1194
ep = mtod(event, ng_hci_mode_change_ep *);
1195
1196
if (ep->status == 0) {
1197
u_int16_t h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1198
1199
con = ng_hci_con_by_handle(unit, h);
1200
if (con == NULL) {
1201
NG_HCI_ALERT(
1202
"%s: %s - invalid connection handle=%d\n",
1203
__func__, NG_NODE_NAME(unit->node), h);
1204
error = ENOENT;
1205
} else if (con->link_type != NG_HCI_LINK_ACL) {
1206
NG_HCI_ALERT(
1207
"%s: %s - invalid link type=%d\n",
1208
__func__, NG_NODE_NAME(unit->node),
1209
con->link_type);
1210
error = EINVAL;
1211
} else
1212
con->mode = ep->unit_mode;
1213
} else
1214
NG_HCI_ERR(
1215
"%s: %s - failed to change mode, status=%d\n",
1216
__func__, NG_NODE_NAME(unit->node), ep->status);
1217
1218
NG_FREE_M(event);
1219
1220
return (error);
1221
} /* mode_change */
1222
1223
/* Data buffer overflow event */
1224
static int
1225
data_buffer_overflow(ng_hci_unit_p unit, struct mbuf *event)
1226
{
1227
NG_HCI_ALERT(
1228
"%s: %s - %s data buffer overflow\n",
1229
__func__, NG_NODE_NAME(unit->node),
1230
(*mtod(event, u_int8_t *) == NG_HCI_LINK_ACL)? "ACL" : "SCO");
1231
1232
NG_FREE_M(event);
1233
1234
return (0);
1235
} /* data_buffer_overflow */
1236
1237
/* Read clock offset complete event */
1238
static int
1239
read_clock_offset_compl(ng_hci_unit_p unit, struct mbuf *event)
1240
{
1241
ng_hci_read_clock_offset_compl_ep *ep = NULL;
1242
ng_hci_unit_con_p con = NULL;
1243
ng_hci_neighbor_p n = NULL;
1244
int error = 0;
1245
1246
NG_HCI_M_PULLUP(event, sizeof(*ep));
1247
if (event == NULL)
1248
return (ENOBUFS);
1249
1250
ep = mtod(event, ng_hci_read_clock_offset_compl_ep *);
1251
1252
if (ep->status == 0) {
1253
u_int16_t h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1254
1255
con = ng_hci_con_by_handle(unit, h);
1256
if (con == NULL) {
1257
NG_HCI_ALERT(
1258
"%s: %s - invalid connection handle=%d\n",
1259
__func__, NG_NODE_NAME(unit->node), h);
1260
error = ENOENT;
1261
goto out;
1262
}
1263
1264
/* Update cache entry */
1265
n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL);
1266
if (n == NULL) {
1267
n = ng_hci_new_neighbor(unit);
1268
if (n == NULL) {
1269
error = ENOMEM;
1270
goto out;
1271
}
1272
1273
bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1274
n->addrtype = NG_HCI_LINK_ACL;
1275
} else
1276
getmicrotime(&n->updated);
1277
1278
n->clock_offset = le16toh(ep->clock_offset);
1279
} else
1280
NG_HCI_ERR(
1281
"%s: %s - failed to Read Remote Clock Offset, status=%d\n",
1282
__func__, NG_NODE_NAME(unit->node), ep->status);
1283
out:
1284
NG_FREE_M(event);
1285
1286
return (error);
1287
} /* read_clock_offset_compl */
1288
1289
/* QoS violation event */
1290
static int
1291
qos_violation(ng_hci_unit_p unit, struct mbuf *event)
1292
{
1293
ng_hci_qos_violation_ep *ep = NULL;
1294
ng_hci_unit_con_p con = NULL;
1295
u_int16_t h;
1296
int error = 0;
1297
1298
NG_HCI_M_PULLUP(event, sizeof(*ep));
1299
if (event == NULL)
1300
return (ENOBUFS);
1301
1302
ep = mtod(event, ng_hci_qos_violation_ep *);
1303
1304
/* Check if we have this connection handle */
1305
h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1306
con = ng_hci_con_by_handle(unit, h);
1307
if (con == NULL) {
1308
NG_HCI_ALERT(
1309
"%s: %s - invalid connection handle=%d\n",
1310
__func__, NG_NODE_NAME(unit->node), h);
1311
error = ENOENT;
1312
} else if (con->link_type != NG_HCI_LINK_ACL) {
1313
NG_HCI_ALERT(
1314
"%s: %s - invalid link type=%d\n",
1315
__func__, NG_NODE_NAME(unit->node), con->link_type);
1316
error = EINVAL;
1317
} else if (con->state != NG_HCI_CON_OPEN) {
1318
NG_HCI_ALERT(
1319
"%s: %s - invalid connection state=%d, handle=%d\n",
1320
__func__, NG_NODE_NAME(unit->node), con->state, h);
1321
error = EINVAL;
1322
} else /* Notify upper layer */
1323
error = ng_hci_lp_qos_ind(con);
1324
1325
NG_FREE_M(event);
1326
1327
return (error);
1328
} /* qos_violation */
1329
1330
/* Page scan mode change event */
1331
static int
1332
page_scan_mode_change(ng_hci_unit_p unit, struct mbuf *event)
1333
{
1334
ng_hci_page_scan_mode_change_ep *ep = NULL;
1335
ng_hci_neighbor_p n = NULL;
1336
int error = 0;
1337
1338
NG_HCI_M_PULLUP(event, sizeof(*ep));
1339
if (event == NULL)
1340
return (ENOBUFS);
1341
1342
ep = mtod(event, ng_hci_page_scan_mode_change_ep *);
1343
1344
/* Update cache entry */
1345
n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
1346
if (n == NULL) {
1347
n = ng_hci_new_neighbor(unit);
1348
if (n == NULL) {
1349
error = ENOMEM;
1350
goto out;
1351
}
1352
1353
bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1354
n->addrtype = NG_HCI_LINK_ACL;
1355
} else
1356
getmicrotime(&n->updated);
1357
1358
n->page_scan_mode = ep->page_scan_mode;
1359
out:
1360
NG_FREE_M(event);
1361
1362
return (error);
1363
} /* page_scan_mode_change */
1364
1365
/* Page scan repetition mode change event */
1366
static int
1367
page_scan_rep_mode_change(ng_hci_unit_p unit, struct mbuf *event)
1368
{
1369
ng_hci_page_scan_rep_mode_change_ep *ep = NULL;
1370
ng_hci_neighbor_p n = NULL;
1371
int error = 0;
1372
1373
NG_HCI_M_PULLUP(event, sizeof(*ep));
1374
if (event == NULL)
1375
return (ENOBUFS);
1376
1377
ep = mtod(event, ng_hci_page_scan_rep_mode_change_ep *);
1378
1379
/* Update cache entry */
1380
n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
1381
if (n == NULL) {
1382
n = ng_hci_new_neighbor(unit);
1383
if (n == NULL) {
1384
error = ENOMEM;
1385
goto out;
1386
}
1387
1388
bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1389
n->addrtype = NG_HCI_LINK_ACL;
1390
} else
1391
getmicrotime(&n->updated);
1392
1393
n->page_scan_rep_mode = ep->page_scan_rep_mode;
1394
out:
1395
NG_FREE_M(event);
1396
1397
return (error);
1398
} /* page_scan_rep_mode_change */
1399
1400