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