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