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