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