The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/bluetooth/hci/ng_hci_ulpi.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 29d8f9eb9053b296b20ae9876487b872


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.