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