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