xref: /freebsd/sys/netgraph/bluetooth/hci/ng_hci_evnt.c (revision 49b49cda41feabe3439f7318e8bf40e3896c7bf4)
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 	u_int16_t	h;
917 
918 	NG_HCI_M_PULLUP(event, sizeof(*ep));
919 	if (event == NULL)
920 		return (ENOBUFS);
921 
922 	ep = mtod(event, ng_hci_encryption_change_ep *);
923 	h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
924 	con = ng_hci_con_by_handle(unit, h);
925 
926 	if (ep->status == 0) {
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_SCO) {
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 	/*Anyway, propagete encryption status to upper layer*/
949 	ng_hci_lp_enc_change(con, con->encryption_mode);
950 
951 	NG_FREE_M(event);
952 
953 	return (error);
954 } /* encryption_change */
955 
956 /* Read remote feature complete event */
957 static int
958 read_remote_features_compl(ng_hci_unit_p unit, struct mbuf *event)
959 {
960 	ng_hci_read_remote_features_compl_ep	*ep = NULL;
961 	ng_hci_unit_con_p			 con = NULL;
962 	ng_hci_neighbor_p			 n = NULL;
963 	u_int16_t				 h;
964 	int					 error = 0;
965 
966 	NG_HCI_M_PULLUP(event, sizeof(*ep));
967 	if (event == NULL)
968 		return (ENOBUFS);
969 
970 	ep = mtod(event, ng_hci_read_remote_features_compl_ep *);
971 
972 	if (ep->status == 0) {
973 		/* Check if we have this connection handle */
974 		h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
975 		con = ng_hci_con_by_handle(unit, h);
976 		if (con == NULL) {
977 			NG_HCI_ALERT(
978 "%s: %s - invalid connection handle=%d\n",
979 				__func__, NG_NODE_NAME(unit->node), h);
980 			error = ENOENT;
981 			goto out;
982 		}
983 
984 		/* Update cache entry */
985 		n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL);
986 		if (n == NULL) {
987 			n = ng_hci_new_neighbor(unit);
988 			if (n == NULL) {
989 				error = ENOMEM;
990 				goto out;
991 			}
992 
993 			bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
994 			n->addrtype = NG_HCI_LINK_ACL;
995 		} else
996 			getmicrotime(&n->updated);
997 
998 		bcopy(ep->features, n->features, sizeof(n->features));
999 	} else
1000 		NG_HCI_ERR(
1001 "%s: %s - failed to read remote unit features, status=%d\n",
1002 			__func__, NG_NODE_NAME(unit->node), ep->status);
1003 out:
1004 	NG_FREE_M(event);
1005 
1006 	return (error);
1007 } /* read_remote_features_compl */
1008 
1009 /* QoS setup complete event */
1010 static int
1011 qos_setup_compl(ng_hci_unit_p unit, struct mbuf *event)
1012 {
1013 	ng_hci_qos_setup_compl_ep	*ep = NULL;
1014 	ng_hci_unit_con_p		 con = NULL;
1015 	u_int16_t			 h;
1016 	int				 error = 0;
1017 
1018 	NG_HCI_M_PULLUP(event, sizeof(*ep));
1019 	if (event == NULL)
1020 		return (ENOBUFS);
1021 
1022 	ep = mtod(event, ng_hci_qos_setup_compl_ep *);
1023 
1024 	/* Check if we have this connection handle */
1025 	h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1026 	con = ng_hci_con_by_handle(unit, h);
1027 	if (con == NULL) {
1028 		NG_HCI_ALERT(
1029 "%s: %s - invalid connection handle=%d\n",
1030 			__func__, NG_NODE_NAME(unit->node), h);
1031 		error = ENOENT;
1032 	} else if (con->link_type != NG_HCI_LINK_ACL) {
1033 		NG_HCI_ALERT(
1034 "%s: %s - invalid link type=%d, handle=%d\n",
1035 			__func__, NG_NODE_NAME(unit->node), con->link_type, h);
1036 		error = EINVAL;
1037 	} else if (con->state != NG_HCI_CON_OPEN) {
1038 		NG_HCI_ALERT(
1039 "%s: %s - invalid connection state=%d, handle=%d\n",
1040 			__func__, NG_NODE_NAME(unit->node),
1041 			con->state, h);
1042 		error = EINVAL;
1043 	} else /* Notify upper layer */
1044 		error = ng_hci_lp_qos_cfm(con, ep->status);
1045 
1046 	NG_FREE_M(event);
1047 
1048 	return (error);
1049 } /* qos_setup_compl */
1050 
1051 /* Hardware error event */
1052 static int
1053 hardware_error(ng_hci_unit_p unit, struct mbuf *event)
1054 {
1055 	NG_HCI_ALERT(
1056 "%s: %s - hardware error %#x\n",
1057 		__func__, NG_NODE_NAME(unit->node), *mtod(event, u_int8_t *));
1058 
1059 	NG_FREE_M(event);
1060 
1061 	return (0);
1062 } /* hardware_error */
1063 
1064 /* Role change event */
1065 static int
1066 role_change(ng_hci_unit_p unit, struct mbuf *event)
1067 {
1068 	ng_hci_role_change_ep	*ep = NULL;
1069 	ng_hci_unit_con_p	 con = NULL;
1070 
1071 	NG_HCI_M_PULLUP(event, sizeof(*ep));
1072 	if (event == NULL)
1073 		return (ENOBUFS);
1074 
1075 	ep = mtod(event, ng_hci_role_change_ep *);
1076 
1077 	if (ep->status == 0) {
1078 		/* XXX shoud we also change "role" for SCO connections? */
1079 		con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
1080 		if (con != NULL)
1081 			con->role = ep->role;
1082 		else
1083 			NG_HCI_ALERT(
1084 "%s: %s - ACL connection does not exist, bdaddr=%x:%x:%x:%x:%x:%x\n",
1085 				__func__, NG_NODE_NAME(unit->node),
1086 				ep->bdaddr.b[5], ep->bdaddr.b[4],
1087 				ep->bdaddr.b[3], ep->bdaddr.b[2],
1088 				ep->bdaddr.b[1], ep->bdaddr.b[0]);
1089 	} else
1090 		NG_HCI_ERR(
1091 "%s: %s - failed to change role, status=%d, bdaddr=%x:%x:%x:%x:%x:%x\n",
1092 			__func__, NG_NODE_NAME(unit->node), ep->status,
1093 			ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
1094 			ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
1095 
1096 	NG_FREE_M(event);
1097 
1098 	return (0);
1099 } /* role_change */
1100 
1101 /* Number of completed packets event */
1102 static int
1103 num_compl_pkts(ng_hci_unit_p unit, struct mbuf *event)
1104 {
1105 	ng_hci_num_compl_pkts_ep	*ep = NULL;
1106 	ng_hci_unit_con_p		 con = NULL;
1107 	u_int16_t			 h, p;
1108 
1109 	NG_HCI_M_PULLUP(event, sizeof(*ep));
1110 	if (event == NULL)
1111 		return (ENOBUFS);
1112 
1113 	ep = mtod(event, ng_hci_num_compl_pkts_ep *);
1114 	m_adj(event, sizeof(*ep));
1115 
1116 	for (; ep->num_con_handles > 0; ep->num_con_handles --) {
1117 		/* Get connection handle */
1118 		m_copydata(event, 0, sizeof(h), (caddr_t) &h);
1119 		m_adj(event, sizeof(h));
1120 		h = NG_HCI_CON_HANDLE(le16toh(h));
1121 
1122 		/* Get number of completed packets */
1123 		m_copydata(event, 0, sizeof(p), (caddr_t) &p);
1124 		m_adj(event, sizeof(p));
1125 		p = le16toh(p);
1126 
1127 		/* Check if we have this connection handle */
1128 		con = ng_hci_con_by_handle(unit, h);
1129 		if (con != NULL) {
1130 			con->pending -= p;
1131 			if (con->pending < 0) {
1132 				NG_HCI_WARN(
1133 "%s: %s - pending packet counter is out of sync! " \
1134 "handle=%d, pending=%d, ncp=%d\n",	__func__, NG_NODE_NAME(unit->node),
1135 					con->con_handle, con->pending, p);
1136 
1137 				con->pending = 0;
1138 			}
1139 
1140 			/* Update buffer descriptor */
1141 			if (con->link_type != NG_HCI_LINK_SCO)
1142 				NG_HCI_BUFF_ACL_FREE(unit->buffer, p);
1143 			else
1144 				NG_HCI_BUFF_SCO_FREE(unit->buffer, p);
1145 		} else
1146 			NG_HCI_ALERT(
1147 "%s: %s - invalid connection handle=%d\n",
1148 				__func__, NG_NODE_NAME(unit->node), h);
1149 	}
1150 
1151 	NG_FREE_M(event);
1152 
1153 	/* Send more data */
1154 	ng_hci_send_data(unit);
1155 
1156 	return (0);
1157 } /* num_compl_pkts */
1158 
1159 /* Mode change event */
1160 static int
1161 mode_change(ng_hci_unit_p unit, struct mbuf *event)
1162 {
1163 	ng_hci_mode_change_ep	*ep = NULL;
1164 	ng_hci_unit_con_p	 con = NULL;
1165 	int			 error = 0;
1166 
1167 	NG_HCI_M_PULLUP(event, sizeof(*ep));
1168 	if (event == NULL)
1169 		return (ENOBUFS);
1170 
1171 	ep = mtod(event, ng_hci_mode_change_ep *);
1172 
1173 	if (ep->status == 0) {
1174 		u_int16_t	h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1175 
1176 		con = ng_hci_con_by_handle(unit, h);
1177 		if (con == NULL) {
1178 			NG_HCI_ALERT(
1179 "%s: %s - invalid connection handle=%d\n",
1180 				__func__, NG_NODE_NAME(unit->node), h);
1181 			error = ENOENT;
1182 		} else if (con->link_type != NG_HCI_LINK_ACL) {
1183 			NG_HCI_ALERT(
1184 "%s: %s - invalid link type=%d\n",
1185 				__func__, NG_NODE_NAME(unit->node),
1186 				con->link_type);
1187 			error = EINVAL;
1188 		} else
1189 			con->mode = ep->unit_mode;
1190 	} else
1191 		NG_HCI_ERR(
1192 "%s: %s - failed to change mode, status=%d\n",
1193 			__func__, NG_NODE_NAME(unit->node), ep->status);
1194 
1195 	NG_FREE_M(event);
1196 
1197 	return (error);
1198 } /* mode_change */
1199 
1200 /* Data buffer overflow event */
1201 static int
1202 data_buffer_overflow(ng_hci_unit_p unit, struct mbuf *event)
1203 {
1204 	NG_HCI_ALERT(
1205 "%s: %s - %s data buffer overflow\n",
1206 		__func__, NG_NODE_NAME(unit->node),
1207 		(*mtod(event, u_int8_t *) == NG_HCI_LINK_ACL)? "ACL" : "SCO");
1208 
1209 	NG_FREE_M(event);
1210 
1211 	return (0);
1212 } /* data_buffer_overflow */
1213 
1214 /* Read clock offset complete event */
1215 static int
1216 read_clock_offset_compl(ng_hci_unit_p unit, struct mbuf *event)
1217 {
1218 	ng_hci_read_clock_offset_compl_ep	*ep = NULL;
1219 	ng_hci_unit_con_p			 con = NULL;
1220 	ng_hci_neighbor_p			 n = NULL;
1221 	int					 error = 0;
1222 
1223 	NG_HCI_M_PULLUP(event, sizeof(*ep));
1224 	if (event == NULL)
1225 		return (ENOBUFS);
1226 
1227 	ep = mtod(event, ng_hci_read_clock_offset_compl_ep *);
1228 
1229 	if (ep->status == 0) {
1230 		u_int16_t	h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1231 
1232 		con = ng_hci_con_by_handle(unit, h);
1233 		if (con == NULL) {
1234 			NG_HCI_ALERT(
1235 "%s: %s - invalid connection handle=%d\n",
1236 				__func__, NG_NODE_NAME(unit->node), h);
1237 			error = ENOENT;
1238 			goto out;
1239 		}
1240 
1241 		/* Update cache entry */
1242 		n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL);
1243 		if (n == NULL) {
1244 			n = ng_hci_new_neighbor(unit);
1245 			if (n == NULL) {
1246 				error = ENOMEM;
1247 				goto out;
1248 			}
1249 
1250 			bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1251 			n->addrtype = NG_HCI_LINK_ACL;
1252 		} else
1253 			getmicrotime(&n->updated);
1254 
1255 		n->clock_offset = le16toh(ep->clock_offset);
1256 	} else
1257 		NG_HCI_ERR(
1258 "%s: %s - failed to Read Remote Clock Offset, status=%d\n",
1259 			__func__, NG_NODE_NAME(unit->node), ep->status);
1260 out:
1261 	NG_FREE_M(event);
1262 
1263 	return (error);
1264 } /* read_clock_offset_compl */
1265 
1266 /* QoS violation event */
1267 static int
1268 qos_violation(ng_hci_unit_p unit, struct mbuf *event)
1269 {
1270 	ng_hci_qos_violation_ep	*ep = NULL;
1271 	ng_hci_unit_con_p	 con = NULL;
1272 	u_int16_t		 h;
1273 	int			 error = 0;
1274 
1275 	NG_HCI_M_PULLUP(event, sizeof(*ep));
1276 	if (event == NULL)
1277 		return (ENOBUFS);
1278 
1279 	ep = mtod(event, ng_hci_qos_violation_ep *);
1280 
1281 	/* Check if we have this connection handle */
1282 	h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1283 	con = ng_hci_con_by_handle(unit, h);
1284 	if (con == NULL) {
1285 		NG_HCI_ALERT(
1286 "%s: %s - invalid connection handle=%d\n",
1287 			__func__, NG_NODE_NAME(unit->node), h);
1288 		error = ENOENT;
1289 	} else if (con->link_type != NG_HCI_LINK_ACL) {
1290 		NG_HCI_ALERT(
1291 "%s: %s - invalid link type=%d\n",
1292 			__func__, NG_NODE_NAME(unit->node), con->link_type);
1293 		error = EINVAL;
1294 	} else if (con->state != NG_HCI_CON_OPEN) {
1295 		NG_HCI_ALERT(
1296 "%s: %s - invalid connection state=%d, handle=%d\n",
1297 			__func__, NG_NODE_NAME(unit->node), con->state, h);
1298 		error = EINVAL;
1299 	} else /* Notify upper layer */
1300 		error = ng_hci_lp_qos_ind(con);
1301 
1302 	NG_FREE_M(event);
1303 
1304 	return (error);
1305 } /* qos_violation */
1306 
1307 /* Page scan mode change event */
1308 static int
1309 page_scan_mode_change(ng_hci_unit_p unit, struct mbuf *event)
1310 {
1311 	ng_hci_page_scan_mode_change_ep	*ep = NULL;
1312 	ng_hci_neighbor_p		 n = NULL;
1313 	int				 error = 0;
1314 
1315 	NG_HCI_M_PULLUP(event, sizeof(*ep));
1316 	if (event == NULL)
1317 		return (ENOBUFS);
1318 
1319 	ep = mtod(event, ng_hci_page_scan_mode_change_ep *);
1320 
1321 	/* Update cache entry */
1322 	n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
1323 	if (n == NULL) {
1324 		n = ng_hci_new_neighbor(unit);
1325 		if (n == NULL) {
1326 			error = ENOMEM;
1327 			goto out;
1328 		}
1329 
1330 		bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1331 		n->addrtype = NG_HCI_LINK_ACL;
1332 	} else
1333 		getmicrotime(&n->updated);
1334 
1335 	n->page_scan_mode = ep->page_scan_mode;
1336 out:
1337 	NG_FREE_M(event);
1338 
1339 	return (error);
1340 } /* page_scan_mode_change */
1341 
1342 /* Page scan repetition mode change event */
1343 static int
1344 page_scan_rep_mode_change(ng_hci_unit_p unit, struct mbuf *event)
1345 {
1346 	ng_hci_page_scan_rep_mode_change_ep	*ep = NULL;
1347 	ng_hci_neighbor_p			 n = NULL;
1348 	int					 error = 0;
1349 
1350 	NG_HCI_M_PULLUP(event, sizeof(*ep));
1351 	if (event == NULL)
1352 		return (ENOBUFS);
1353 
1354 	ep = mtod(event, ng_hci_page_scan_rep_mode_change_ep *);
1355 
1356 	/* Update cache entry */
1357 	n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
1358 	if (n == NULL) {
1359 		n = ng_hci_new_neighbor(unit);
1360 		if (n == NULL) {
1361 			error = ENOMEM;
1362 			goto out;
1363 		}
1364 
1365 		bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1366 		n->addrtype = NG_HCI_LINK_ACL;
1367 	} else
1368 		getmicrotime(&n->updated);
1369 
1370 	n->page_scan_rep_mode = ep->page_scan_rep_mode;
1371 out:
1372 	NG_FREE_M(event);
1373 
1374 	return (error);
1375 } /* page_scan_rep_mode_change */
1376 
1377