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/l2cap/ng_l2cap_llpi.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_l2cap_llpi.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_l2cap_llpi.c,v 1.5 2003/09/08 19:11:45 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/include/ng_l2cap.h>
   48 #include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
   49 #include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
   50 #include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
   51 #include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
   52 #include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
   53 #include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
   54 
   55 /******************************************************************************
   56  ******************************************************************************
   57  **                 Lower Layer Protocol (HCI) Interface module
   58  ******************************************************************************
   59  ******************************************************************************/
   60 
   61 /*
   62  * Send LP_ConnectReq event to the lower layer protocol. Create new connection
   63  * descriptor and initialize it. Create LP_ConnectReq event and send it to the
   64  * lower layer, then adjust connection state and start timer. The function WILL
   65  * FAIL if connection to the remote unit already exists.
   66  */
   67 
   68 int
   69 ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr, int type)
   70 {
   71         struct ng_mesg          *msg = NULL;
   72         ng_hci_lp_con_req_ep    *ep = NULL;
   73         ng_l2cap_con_p           con = NULL;
   74         int                      error = 0;
   75 
   76         /* Verify that we DO NOT have connection to the remote unit */
   77         con = ng_l2cap_con_by_addr(l2cap, bdaddr, type);
   78         if (con != NULL) {
   79                 NG_L2CAP_ALERT(
   80 "%s: %s - unexpected LP_ConnectReq event. " \
   81 "Connection already exists, state=%d, con_handle=%d\n",
   82                         __func__, NG_NODE_NAME(l2cap->node), con->state, 
   83                         con->con_handle);
   84 
   85                 return (EEXIST);
   86         }
   87 
   88         /* Check if lower layer protocol is still connected */
   89         if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
   90                 NG_L2CAP_ERR(
   91 "%s: %s - hook \"%s\" is not connected or valid\n",
   92                         __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
   93 
   94                 return (ENOTCONN);
   95         }
   96 
   97         /* Create and intialize new connection descriptor */
   98         con = ng_l2cap_new_con(l2cap, bdaddr, type);
   99         if (con == NULL)
  100                 return (ENOMEM);
  101 
  102         /* Create and send LP_ConnectReq event */
  103         NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ,
  104                 sizeof(*ep), M_NOWAIT);
  105         if (msg == NULL) {
  106                 ng_l2cap_free_con(con);
  107 
  108                 return (ENOMEM);
  109         }
  110 
  111         ep = (ng_hci_lp_con_req_ep *) (msg->data);
  112         bcopy(bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
  113         ep->link_type = type;
  114 
  115         con->flags |= NG_L2CAP_CON_OUTGOING;
  116         con->state = NG_L2CAP_W4_LP_CON_CFM;
  117         ng_l2cap_lp_timeout(con);
  118 
  119         NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
  120         if (error != 0) {
  121                 if (ng_l2cap_lp_untimeout(con) == 0)
  122                         ng_l2cap_free_con(con);
  123 
  124                 /*
  125                  * Do not free connection if ng_l2cap_lp_untimeout() failed
  126                  * let timeout handler deal with it. Always return error to
  127                  * the caller.
  128                  */
  129         }
  130 
  131         return (error);
  132 } /* ng_l2cap_lp_con_req */
  133 
  134 /*
  135  * Process LP_ConnectCfm event from the lower layer protocol. It could be 
  136  * positive or negative. Verify remote unit address then stop the timer and 
  137  * process event.
  138  */
  139 
  140 int
  141 ng_l2cap_lp_con_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
  142 {
  143         ng_hci_lp_con_cfm_ep    *ep = NULL;
  144         ng_l2cap_con_p           con = NULL;
  145         int                      error = 0;
  146 
  147         /* Check message */
  148         if (msg->header.arglen != sizeof(*ep)) {
  149                 NG_L2CAP_ALERT(
  150 "%s: %s - invalid LP_ConnectCfm[Neg] message size\n",
  151                         __func__, NG_NODE_NAME(l2cap->node));
  152                 error = EMSGSIZE;
  153                 goto out;
  154         }
  155 
  156         ep = (ng_hci_lp_con_cfm_ep *) (msg->data);
  157         /* Check if we have requested/accepted this connection */
  158         con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr, ep->link_type);
  159         if (con == NULL) {
  160                 NG_L2CAP_ERR(
  161 "%s: %s - unexpected LP_ConnectCfm event. Connection does not exist\n",
  162                         __func__, NG_NODE_NAME(l2cap->node));
  163                 error = ENOENT;
  164                 goto out;
  165         }
  166 
  167         /* Check connection state */
  168         if (con->state != NG_L2CAP_W4_LP_CON_CFM) {
  169                 NG_L2CAP_ALERT(
  170 "%s: %s - unexpected LP_ConnectCfm event. " \
  171 "Invalid connection state, state=%d, con_handle=%d\n",
  172                         __func__, NG_NODE_NAME(l2cap->node), con->state, 
  173                         con->con_handle);
  174                 error = EINVAL;
  175                 goto out;
  176         }
  177 
  178         /*
  179          * Looks like it is our confirmation. It is safe now to cancel 
  180          * connection timer and notify upper layer. If timeout already
  181          * happened then ignore connection confirmation and let timeout
  182          * handle that.
  183          */
  184 
  185         if ((error = ng_l2cap_lp_untimeout(con)) != 0)
  186                 goto out;
  187 
  188         if (ep->status == 0) {
  189                 con->state = NG_L2CAP_CON_OPEN;
  190                 con->con_handle = ep->con_handle;
  191                 ng_l2cap_lp_deliver(con);
  192         } else /* Negative confirmation - remove connection descriptor */
  193                 ng_l2cap_con_fail(con, ep->status);
  194 out:
  195         return (error);
  196 } /* ng_l2cap_lp_con_cfm */
  197 
  198 /*
  199  * Process LP_ConnectInd event from the lower layer protocol. This is a good 
  200  * place to put some extra check on remote unit address and/or class. We could
  201  * even forward this information to control hook (or check against internal
  202  * black list) and thus implement some kind of firewall. But for now be simple 
  203  * and create new connection descriptor, start timer and send LP_ConnectRsp 
  204  * event (i.e. accept connection).
  205  */
  206 
  207 int
  208 ng_l2cap_lp_con_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
  209 {
  210         ng_hci_lp_con_ind_ep    *ep = NULL;
  211         ng_hci_lp_con_rsp_ep    *rp = NULL;
  212         struct ng_mesg          *rsp = NULL;
  213         ng_l2cap_con_p           con = NULL;
  214         int                      error = 0;
  215 
  216         /* Check message */
  217         if (msg->header.arglen != sizeof(*ep)) {
  218                 NG_L2CAP_ALERT(
  219 "%s: %s - invalid LP_ConnectInd message size\n",
  220                         __func__, NG_NODE_NAME(l2cap->node));
  221 
  222                 return (EMSGSIZE);
  223         }
  224 
  225         ep = (ng_hci_lp_con_ind_ep *) (msg->data);
  226 
  227         /* Make sure we have only one connection to the remote unit */
  228         con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr, ep->link_type);
  229         if (con != NULL) {
  230                 NG_L2CAP_ALERT(
  231 "%s: %s - unexpected LP_ConnectInd event. " \
  232 "Connection already exists, state=%d, con_handle=%d\n",
  233                         __func__, NG_NODE_NAME(l2cap->node), con->state, 
  234                         con->con_handle);
  235 
  236                 return (EEXIST);
  237         }
  238 
  239         /* Check if lower layer protocol is still connected */
  240         if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
  241                 NG_L2CAP_ERR(
  242 "%s: %s - hook \"%s\" is not connected or valid",
  243                         __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
  244 
  245                 return (ENOTCONN);
  246         }
  247 
  248         /* Create and intialize new connection descriptor */
  249         con = ng_l2cap_new_con(l2cap, &ep->bdaddr, ep->link_type);
  250         if (con == NULL)
  251                 return (ENOMEM);
  252 
  253         /* Create and send LP_ConnectRsp event */
  254         NG_MKMESSAGE(rsp, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP,
  255                 sizeof(*rp), M_NOWAIT);
  256         if (rsp == NULL) {
  257                 ng_l2cap_free_con(con);
  258 
  259                 return (ENOMEM);
  260         }
  261 
  262         rp = (ng_hci_lp_con_rsp_ep *)(rsp->data);
  263         rp->status = 0x00; /* accept connection */
  264         rp->link_type = NG_HCI_LINK_ACL;
  265         bcopy(&ep->bdaddr, &rp->bdaddr, sizeof(rp->bdaddr));
  266 
  267         con->state = NG_L2CAP_W4_LP_CON_CFM;
  268         ng_l2cap_lp_timeout(con);
  269 
  270         NG_SEND_MSG_HOOK(error, l2cap->node, rsp, l2cap->hci, 0);
  271         if (error != 0) {
  272                 if (ng_l2cap_lp_untimeout(con) == 0)
  273                         ng_l2cap_free_con(con);
  274 
  275                 /*
  276                  * Do not free connection if ng_l2cap_lp_untimeout() failed
  277                  * let timeout handler deal with it. Always return error to
  278                  * the caller.
  279                  */
  280         }
  281 
  282         return (error);
  283 } /* ng_l2cap_lp_con_ind */
  284 
  285 /*
  286  * Process LP_DisconnectInd event from the lower layer protocol. We have been
  287  * disconnected from the remote unit. So notify the upper layer protocol.
  288  */
  289 
  290 int
  291 ng_l2cap_lp_discon_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
  292 {
  293         ng_hci_lp_discon_ind_ep *ep = NULL;
  294         ng_l2cap_con_p           con = NULL;
  295         int                      error = 0;
  296 
  297         /* Check message */
  298         if (msg->header.arglen != sizeof(*ep)) {
  299                 NG_L2CAP_ALERT(
  300 "%s: %s - invalid LP_DisconnectInd message size\n",
  301                         __func__, NG_NODE_NAME(l2cap->node));
  302                 error = EMSGSIZE;
  303                 goto out;
  304         }
  305 
  306         ep = (ng_hci_lp_discon_ind_ep *) (msg->data);
  307 
  308         /* Check if we have this connection */
  309         con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
  310         if (con == NULL) {
  311                 NG_L2CAP_ERR(
  312 "%s: %s - unexpected LP_DisconnectInd event. " \
  313 "Connection does not exist, con_handle=%d\n",
  314                         __func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
  315                 error = ENOENT;
  316                 goto out;
  317         }
  318 
  319         /* XXX Verify connection state -- do we need to check this? */
  320         if (con->state != NG_L2CAP_CON_OPEN) {
  321                 NG_L2CAP_ERR(
  322 "%s: %s - unexpected LP_DisconnectInd event. " \
  323 "Invalid connection state, state=%d, con_handle=%d\n",
  324                         __func__, NG_NODE_NAME(l2cap->node), con->state, 
  325                         con->con_handle);
  326                 error = EINVAL;
  327                 goto out;
  328         }
  329 
  330         /*
  331          * Notify upper layer and remove connection
  332          * Note: The connection could have auto disconnect timeout set. Try
  333          * to remove it. If auto disconnect timeout happened then ignore
  334          * disconnect indication and let timeout handle that.
  335          */
  336 
  337         if (con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)
  338                 if ((error = ng_l2cap_discon_untimeout(con)) != 0)
  339                         return (error);
  340 
  341         ng_l2cap_con_fail(con, ep->reason);
  342 out:
  343         return (error);
  344 } /* ng_l2cap_lp_discon_ind */
  345 
  346 /*
  347  * Send LP_QoSSetupReq event to the lower layer protocol
  348  */
  349 
  350 int
  351 ng_l2cap_lp_qos_req(ng_l2cap_p l2cap, u_int16_t con_handle,
  352                 ng_l2cap_flow_p flow)
  353 {
  354         struct ng_mesg          *msg = NULL;
  355         ng_hci_lp_qos_req_ep    *ep = NULL;
  356         ng_l2cap_con_p           con = NULL;
  357         int                      error = 0;
  358 
  359         /* Verify that we have this connection */
  360         con = ng_l2cap_con_by_handle(l2cap, con_handle);
  361         if (con == NULL) {
  362                 NG_L2CAP_ERR(
  363 "%s: %s - unexpected LP_QoSSetupReq event. " \
  364 "Connection does not exist, con_handle=%d\n",
  365                         __func__, NG_NODE_NAME(l2cap->node), con_handle);
  366 
  367                 return (ENOENT);
  368         }
  369 
  370         /* Verify connection state */
  371         if (con->state != NG_L2CAP_CON_OPEN) {
  372                 NG_L2CAP_ERR(
  373 "%s: %s - unexpected LP_QoSSetupReq event. " \
  374 "Invalid connection state, state=%d, con_handle=%d\n",
  375                         __func__, NG_NODE_NAME(l2cap->node), con->state,
  376                         con->con_handle);
  377 
  378                 return (EINVAL);
  379         }
  380 
  381         /* Check if lower layer protocol is still connected */
  382         if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
  383                 NG_L2CAP_ERR(
  384 "%s: %s - hook \"%s\" is not connected or valid",
  385                         __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
  386 
  387                 return (ENOTCONN);
  388         }
  389 
  390         /* Create and send LP_QoSSetupReq event */
  391         NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_REQ,
  392                 sizeof(*ep), M_NOWAIT);
  393         if (msg == NULL)
  394                 return (ENOMEM);
  395 
  396         ep = (ng_hci_lp_qos_req_ep *) (msg->data);
  397         ep->con_handle = con_handle;
  398         ep->flags = flow->flags;
  399         ep->service_type = flow->service_type;
  400         ep->token_rate = flow->token_rate;
  401         ep->peak_bandwidth = flow->peak_bandwidth;
  402         ep->latency = flow->latency;
  403         ep->delay_variation = flow->delay_variation;
  404 
  405         NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
  406 
  407         return (error);
  408 } /* ng_l2cap_lp_con_req */
  409 
  410 /*
  411  * Process LP_QoSSetupCfm from the lower layer protocol
  412  */
  413 
  414 int
  415 ng_l2cap_lp_qos_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
  416 {
  417         ng_hci_lp_qos_cfm_ep    *ep = NULL;
  418         int                      error = 0;
  419 
  420         /* Check message */
  421         if (msg->header.arglen != sizeof(*ep)) {
  422                 NG_L2CAP_ALERT(
  423 "%s: %s - invalid LP_QoSSetupCfm[Neg] message size\n",
  424                         __func__, NG_NODE_NAME(l2cap->node));
  425                 error = EMSGSIZE;
  426                 goto out;
  427         }
  428 
  429         ep = (ng_hci_lp_qos_cfm_ep *) (msg->data);
  430         /* XXX FIXME do something */
  431 out:
  432         return (error);
  433 } /* ng_l2cap_lp_qos_cfm */
  434 
  435 /*
  436  * Process LP_QoSViolationInd event from the lower layer protocol. Lower 
  437  * layer protocol has detected QoS Violation, so we MUST notify the 
  438  * upper layer.
  439  */
  440 
  441 int
  442 ng_l2cap_lp_qos_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
  443 {
  444         ng_hci_lp_qos_ind_ep    *ep = NULL;
  445         ng_l2cap_con_p           con = NULL;
  446         int                      error = 0;
  447 
  448         /* Check message */
  449         if (msg->header.arglen != sizeof(*ep)) {
  450                 NG_L2CAP_ALERT(
  451 "%s: %s - invalid LP_QoSViolation message size\n",
  452                         __func__, NG_NODE_NAME(l2cap->node));
  453                 error = EMSGSIZE;
  454                 goto out;
  455         }
  456 
  457         ep = (ng_hci_lp_qos_ind_ep *) (msg->data);
  458 
  459         /* Check if we have this connection */
  460         con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
  461         if (con == NULL) {
  462                 NG_L2CAP_ERR(
  463 "%s: %s - unexpected LP_QoSViolationInd event. " \
  464 "Connection does not exist, con_handle=%d\n",
  465                         __func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
  466                 error = ENOENT;
  467                 goto out;
  468         }
  469 
  470         /* Verify connection state */
  471         if (con->state != NG_L2CAP_CON_OPEN) {
  472                 NG_L2CAP_ERR(
  473 "%s: %s - unexpected LP_QoSViolationInd event. " \
  474 "Invalid connection state, state=%d, con_handle=%d\n",
  475                         __func__, NG_NODE_NAME(l2cap->node), con->state, 
  476                         con->con_handle);
  477                 error = EINVAL;
  478                 goto out;
  479         }
  480 
  481         /* XXX FIXME Notify upper layer and terminate channels if required */
  482 out:
  483         return (error);
  484 } /* ng_l2cap_qos_ind */
  485 
  486 int
  487 ng_l2cap_lp_enc_change(ng_l2cap_p l2cap, struct ng_mesg *msg)
  488 {
  489         ng_hci_lp_enc_change_ep *ep = NULL;
  490         ng_l2cap_con_p           con = NULL;
  491         int                      error = 0;
  492         ng_l2cap_chan_p          ch = NULL;
  493         /* Check message */
  494         if (msg->header.arglen != sizeof(*ep)) {
  495                 NG_L2CAP_ALERT(
  496 "%s: %s - invalid LP_ENCChange message size\n",
  497                         __func__, NG_NODE_NAME(l2cap->node));
  498                 error = EMSGSIZE;
  499                 goto out;
  500         }
  501 
  502         ep = (ng_hci_lp_enc_change_ep *) (msg->data);
  503 
  504         /* Check if we have this connection */
  505         con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
  506         if (con == NULL) {
  507                 NG_L2CAP_ERR(
  508 "%s: %s - unexpected LP_Enc Change Event. " \
  509 "Connection does not exist, con_handle=%d\n",
  510                         __func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
  511                 error = ENOENT;
  512                 goto out;
  513         }
  514 
  515         /* Verify connection state */
  516         if (con->state != NG_L2CAP_CON_OPEN) {
  517                 NG_L2CAP_ERR(
  518 "%s: %s - unexpected ENC_CHANGE event. " \
  519 "Invalid connection state, state=%d, con_handle=%d\n",
  520                         __func__, NG_NODE_NAME(l2cap->node), con->state, 
  521                         con->con_handle);
  522                 error = EINVAL;
  523                 goto out;
  524         }
  525 
  526         con->encryption = ep->status;
  527 
  528         LIST_FOREACH(ch, &l2cap->chan_list, next){
  529                 if((ch->con->con_handle == ep->con_handle) &&
  530                    (ch->con->linktype == ep->link_type))
  531                         ng_l2cap_l2ca_encryption_change(ch, ep->status);
  532         }
  533 
  534 out:
  535         return (error);
  536 } /* ng_l2cap_enc_change */
  537 
  538 /*
  539  * Prepare L2CAP packet. Prepend packet with L2CAP packet header and then 
  540  * segment it according to HCI MTU.
  541  */
  542 
  543 int
  544 ng_l2cap_lp_send(ng_l2cap_con_p con, u_int16_t dcid, struct mbuf *m0)
  545 {
  546         ng_l2cap_p               l2cap = con->l2cap;
  547         ng_l2cap_hdr_t          *l2cap_hdr = NULL;
  548         ng_hci_acldata_pkt_t    *acl_hdr = NULL;
  549         struct mbuf             *m_last = NULL, *m = NULL;
  550         int                      len, flag = (con->linktype == NG_HCI_LINK_ACL) ? NG_HCI_PACKET_START : NG_HCI_LE_PACKET_START;
  551 
  552         KASSERT((con->tx_pkt == NULL),
  553 ("%s: %s - another packet pending?!\n", __func__, NG_NODE_NAME(l2cap->node)));
  554         KASSERT((l2cap->pkt_size > 0),
  555 ("%s: %s - invalid l2cap->pkt_size?!\n", __func__, NG_NODE_NAME(l2cap->node)));
  556 
  557         /* Prepend mbuf with L2CAP header */
  558         m0 = ng_l2cap_prepend(m0, sizeof(*l2cap_hdr));
  559         if (m0 == NULL) {
  560                 NG_L2CAP_ALERT(
  561 "%s: %s - ng_l2cap_prepend(%zd) failed\n",
  562                         __func__, NG_NODE_NAME(l2cap->node),
  563                         sizeof(*l2cap_hdr));
  564 
  565                 goto fail;
  566         }
  567 
  568         l2cap_hdr = mtod(m0, ng_l2cap_hdr_t *);
  569         l2cap_hdr->length = htole16(m0->m_pkthdr.len - sizeof(*l2cap_hdr));
  570         l2cap_hdr->dcid = htole16(dcid);
  571 
  572         /*
  573          * Segment single L2CAP packet according to the HCI layer MTU. Convert 
  574          * each segment into ACL data packet and prepend it with ACL data packet
  575          * header. Link all segments together via m_nextpkt link. 
  576          *
  577          * XXX BC (Broadcast flag) will always be 0 (zero).
  578          */
  579 
  580         while (m0 != NULL) {
  581                 /* Check length of the packet against HCI MTU */
  582                 len = m0->m_pkthdr.len;
  583                 if (len > l2cap->pkt_size) {
  584                         m = m_split(m0, l2cap->pkt_size, M_NOWAIT);
  585                         if (m == NULL) {
  586                                 NG_L2CAP_ALERT(
  587 "%s: %s - m_split(%d) failed\n",        __func__, NG_NODE_NAME(l2cap->node),
  588                                         l2cap->pkt_size);
  589                                 goto fail;
  590                         }
  591 
  592                         len = l2cap->pkt_size;
  593                 }
  594 
  595                 /* Convert packet fragment into ACL data packet */
  596                 m0 = ng_l2cap_prepend(m0, sizeof(*acl_hdr));
  597                 if (m0 == NULL) {
  598                         NG_L2CAP_ALERT(
  599 "%s: %s - ng_l2cap_prepend(%zd) failed\n",
  600                                 __func__, NG_NODE_NAME(l2cap->node),
  601                                 sizeof(*acl_hdr));
  602                         goto fail;
  603                 }
  604 
  605                 acl_hdr = mtod(m0, ng_hci_acldata_pkt_t *);
  606                 acl_hdr->type = NG_HCI_ACL_DATA_PKT;
  607                 acl_hdr->length = htole16(len);
  608                 acl_hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(
  609                                         con->con_handle, flag, 0));
  610 
  611                 /* Add fragment to the chain */
  612                 m0->m_nextpkt = NULL;
  613 
  614                 if (con->tx_pkt == NULL)
  615                         con->tx_pkt = m_last = m0;
  616                 else {
  617                         m_last->m_nextpkt = m0;
  618                         m_last = m0;
  619                 }
  620 
  621                 NG_L2CAP_INFO(
  622 "%s: %s - attaching ACL packet, con_handle=%d, PB=%#x, length=%d\n",
  623                         __func__, NG_NODE_NAME(l2cap->node), con->con_handle,
  624                         flag, len);
  625 
  626                 m0 = m;
  627                 m = NULL;
  628                 flag = NG_HCI_PACKET_FRAGMENT;
  629         }
  630 
  631         return (0);
  632 fail:
  633         NG_FREE_M(m0);
  634         NG_FREE_M(m);
  635 
  636         while (con->tx_pkt != NULL) {
  637                 m = con->tx_pkt->m_nextpkt;
  638                 m_freem(con->tx_pkt);
  639                 con->tx_pkt = m;
  640         }
  641 
  642         return (ENOBUFS);
  643 } /* ng_l2cap_lp_send */
  644 
  645 /*
  646  * Receive ACL data packet from the HCI layer. First strip ACL packet header
  647  * and get connection handle, PB (Packet Boundary) flag and payload length.
  648  * Then find connection descriptor and verify its state. Then process ACL 
  649  * packet as follows.
  650  * 
  651  * 1) If we got first segment (pb == NG_HCI_PACKET_START) then extract L2CAP 
  652  *    header and get total length of the L2CAP packet. Then start new L2CAP 
  653  *    packet.
  654  *
  655  * 2) If we got other (then first :) segment (pb == NG_HCI_PACKET_FRAGMENT)
  656  *    then add segment to the packet.
  657  */
  658 
  659 int
  660 ng_l2cap_lp_receive(ng_l2cap_p l2cap, struct mbuf *m)
  661 {
  662         ng_hci_acldata_pkt_t    *acl_hdr = NULL;
  663         ng_l2cap_hdr_t          *l2cap_hdr = NULL;
  664         ng_l2cap_con_p           con = NULL;
  665         u_int16_t                con_handle, length, pb;
  666         int                      error = 0;
  667 
  668         /* Check ACL data packet */
  669         if (m->m_pkthdr.len < sizeof(*acl_hdr)) {
  670                 NG_L2CAP_ERR(
  671 "%s: %s - invalid ACL data packet. Packet too small, length=%d\n",
  672                         __func__, NG_NODE_NAME(l2cap->node), m->m_pkthdr.len);
  673                 error = EMSGSIZE;
  674                 goto drop;
  675         }
  676 
  677         /* Strip ACL data packet header */
  678         NG_L2CAP_M_PULLUP(m, sizeof(*acl_hdr));
  679         if (m == NULL)
  680                 return (ENOBUFS);
  681 
  682         acl_hdr = mtod(m, ng_hci_acldata_pkt_t *);
  683         m_adj(m, sizeof(*acl_hdr));
  684 
  685         /* Get ACL connection handle, PB flag and payload length */
  686         acl_hdr->con_handle = le16toh(acl_hdr->con_handle);
  687         con_handle = NG_HCI_CON_HANDLE(acl_hdr->con_handle);
  688         pb = NG_HCI_PB_FLAG(acl_hdr->con_handle);
  689         length = le16toh(acl_hdr->length);
  690 
  691         NG_L2CAP_INFO(
  692 "%s: %s - got ACL data packet, con_handle=%d, PB=%#x, length=%d\n",
  693                 __func__, NG_NODE_NAME(l2cap->node), con_handle, pb, length);
  694 
  695         /* Get connection descriptor */
  696         con = ng_l2cap_con_by_handle(l2cap, con_handle);
  697         if (con == NULL) {
  698                 NG_L2CAP_ERR(
  699 "%s: %s - unexpected ACL data packet. " \
  700 "Connection does not exist, con_handle=%d\n",
  701                         __func__, NG_NODE_NAME(l2cap->node), con_handle);
  702                 error = ENOENT;
  703                 goto drop;
  704         }
  705 
  706         /* Verify connection state */
  707         if (con->state != NG_L2CAP_CON_OPEN) {
  708                 NG_L2CAP_ERR(
  709 "%s: %s - unexpected ACL data packet. Invalid connection state=%d\n",
  710                         __func__, NG_NODE_NAME(l2cap->node), con->state);
  711                 error = EHOSTDOWN;
  712                 goto drop;
  713         }
  714 
  715         /* Process packet */
  716         if ((pb == NG_HCI_PACKET_START) || (pb == NG_HCI_LE_PACKET_START))
  717           {
  718                 if (con->rx_pkt != NULL) {
  719                         NG_L2CAP_ERR(
  720 "%s: %s - dropping incomplete L2CAP packet, got %d bytes, want %d bytes\n",
  721                                 __func__, NG_NODE_NAME(l2cap->node),
  722                                 con->rx_pkt->m_pkthdr.len, con->rx_pkt_len);
  723                         NG_FREE_M(con->rx_pkt);
  724                         con->rx_pkt_len = 0;
  725                 }
  726 
  727                 /* Get L2CAP header */
  728                 if (m->m_pkthdr.len < sizeof(*l2cap_hdr)) {
  729                         NG_L2CAP_ERR(
  730 "%s: %s - invalid L2CAP packet start fragment. Packet too small, length=%d\n",
  731                                 __func__, NG_NODE_NAME(l2cap->node),
  732                                 m->m_pkthdr.len);
  733                         error = EMSGSIZE;
  734                         goto drop;
  735                 }
  736 
  737                 NG_L2CAP_M_PULLUP(m, sizeof(*l2cap_hdr));
  738                 if (m == NULL)
  739                         return (ENOBUFS);
  740 
  741                 l2cap_hdr = mtod(m, ng_l2cap_hdr_t *);
  742 
  743                 NG_L2CAP_INFO(
  744 "%s: %s - staring new L2CAP packet, con_handle=%d, length=%d\n",
  745                         __func__, NG_NODE_NAME(l2cap->node), con_handle,
  746                         le16toh(l2cap_hdr->length));
  747 
  748                 /* Start new L2CAP packet */
  749                 con->rx_pkt = m;
  750                 con->rx_pkt_len = le16toh(l2cap_hdr->length)+sizeof(*l2cap_hdr);
  751         } else if (pb == NG_HCI_PACKET_FRAGMENT) {
  752                 if (con->rx_pkt == NULL) {
  753                         NG_L2CAP_ERR(
  754 "%s: %s - unexpected ACL data packet fragment, con_handle=%d\n",
  755                                 __func__, NG_NODE_NAME(l2cap->node), 
  756                                 con->con_handle);
  757                         goto drop;
  758                 }
  759 
  760                 /* Add fragment to the L2CAP packet */
  761                 m_cat(con->rx_pkt, m);
  762                 con->rx_pkt->m_pkthdr.len += length;
  763         } else {
  764                 NG_L2CAP_ERR(
  765 "%s: %s - invalid ACL data packet. Invalid PB flag=%#x\n",
  766                         __func__, NG_NODE_NAME(l2cap->node), pb);
  767                 error = EINVAL;
  768                 goto drop;
  769         }
  770 
  771         con->rx_pkt_len -= length;
  772         if (con->rx_pkt_len < 0) {
  773                 NG_L2CAP_ALERT(
  774 "%s: %s - packet length mismatch. Got %d bytes, offset %d bytes\n",
  775                         __func__, NG_NODE_NAME(l2cap->node), 
  776                         con->rx_pkt->m_pkthdr.len, con->rx_pkt_len);
  777                 NG_FREE_M(con->rx_pkt);
  778                 con->rx_pkt_len = 0;
  779         } else if (con->rx_pkt_len == 0) {
  780                 /* OK, we have got complete L2CAP packet, so process it */
  781                 error = ng_l2cap_receive(con);
  782                 con->rx_pkt = NULL;
  783                 con->rx_pkt_len = 0;
  784         }
  785 
  786         return (error);
  787 
  788 drop:
  789         NG_FREE_M(m);
  790 
  791         return (error);
  792 } /* ng_l2cap_lp_receive */
  793 
  794 /*
  795  * Send queued ACL packets to the HCI layer
  796  */
  797 
  798 void
  799 ng_l2cap_lp_deliver(ng_l2cap_con_p con)
  800 {
  801         ng_l2cap_p       l2cap = con->l2cap;
  802         struct mbuf     *m = NULL;
  803         int              error;
  804 
  805         /* Check connection */
  806         if (con->state != NG_L2CAP_CON_OPEN)
  807                 return;
  808 
  809         if (con->tx_pkt == NULL)
  810                 ng_l2cap_con_wakeup(con);
  811 
  812         if (con->tx_pkt == NULL)
  813                 return;
  814 
  815         /* Check if lower layer protocol is still connected */
  816         if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
  817                 NG_L2CAP_ERR(
  818 "%s: %s - hook \"%s\" is not connected or valid",
  819                         __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
  820 
  821                 goto drop; /* XXX what to do with "pending"? */
  822         }
  823 
  824         /* Send ACL data packets */
  825         while (con->pending < con->l2cap->num_pkts && con->tx_pkt != NULL) {
  826                 m = con->tx_pkt;
  827                 con->tx_pkt = con->tx_pkt->m_nextpkt;
  828                 m->m_nextpkt = NULL;
  829 
  830                 if(m->m_flags &M_PROTO2){
  831                         ng_l2cap_lp_receive(con->l2cap, m);
  832                         continue;
  833                 }
  834                 NG_L2CAP_INFO(
  835 "%s: %s - sending ACL packet, con_handle=%d, len=%d\n", 
  836                         __func__, NG_NODE_NAME(l2cap->node), con->con_handle, 
  837                         m->m_pkthdr.len);
  838 
  839                 NG_SEND_DATA_ONLY(error, l2cap->hci, m);
  840                 if (error != 0) {
  841                         NG_L2CAP_ERR(
  842 "%s: %s - could not send ACL data packet, con_handle=%d, error=%d\n",
  843                                 __func__, NG_NODE_NAME(l2cap->node), 
  844                                 con->con_handle, error);
  845 
  846                         goto drop; /* XXX what to do with "pending"? */
  847                 }
  848 
  849                 con->pending ++;
  850         }
  851 
  852         NG_L2CAP_INFO(
  853 "%s: %s - %d ACL packets have been sent, con_handle=%d\n",
  854                 __func__, NG_NODE_NAME(l2cap->node), con->pending, 
  855                 con->con_handle);
  856 
  857         return;
  858 
  859 drop:
  860         while (con->tx_pkt != NULL) {
  861                 m = con->tx_pkt->m_nextpkt;
  862                 m_freem(con->tx_pkt);
  863                 con->tx_pkt = m;
  864         }
  865 } /* ng_l2cap_lp_deliver */
  866 
  867 /*
  868  * Process connection timeout. Remove connection from the list. If there
  869  * are any channels that wait for the connection then notify them. Free 
  870  * connection descriptor.
  871  */
  872 
  873 void
  874 ng_l2cap_process_lp_timeout(node_p node, hook_p hook, void *arg1, int con_handle)
  875 {
  876         ng_l2cap_p      l2cap = NULL;
  877         ng_l2cap_con_p  con = NULL;
  878 
  879         if (NG_NODE_NOT_VALID(node)) {
  880                 printf("%s: Netgraph node is not valid\n", __func__);
  881                 return;
  882         }
  883 
  884         l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
  885         con = ng_l2cap_con_by_handle(l2cap, con_handle);
  886 
  887         if (con == NULL) {
  888                 NG_L2CAP_ALERT(
  889 "%s: %s - could not find connection, con_handle=%d\n",
  890                         __func__, NG_NODE_NAME(node), con_handle);
  891                 return;
  892         }
  893 
  894         if (!(con->flags & NG_L2CAP_CON_LP_TIMO)) {
  895                 NG_L2CAP_ALERT(
  896 "%s: %s - no pending LP timeout, con_handle=%d, state=%d, flags=%#x\n",
  897                         __func__, NG_NODE_NAME(node), con_handle, con->state,
  898                         con->flags);
  899                 return;
  900         }
  901 
  902         /*
  903          * Notify channels that connection has timed out. This will remove 
  904          * connection, channels and pending commands.
  905          */
  906 
  907         con->flags &= ~NG_L2CAP_CON_LP_TIMO;
  908         ng_l2cap_con_fail(con, NG_L2CAP_TIMEOUT);
  909 } /* ng_l2cap_process_lp_timeout */
  910 
  911 /*
  912  * Process auto disconnect timeout and send LP_DisconReq event to the 
  913  * lower layer protocol
  914  */
  915 
  916 void
  917 ng_l2cap_process_discon_timeout(node_p node, hook_p hook, void *arg1, int con_handle)
  918 {
  919         ng_l2cap_p               l2cap = NULL;
  920         ng_l2cap_con_p           con = NULL;
  921         struct ng_mesg          *msg = NULL;
  922         ng_hci_lp_discon_req_ep *ep = NULL;
  923         int                      error;
  924 
  925         if (NG_NODE_NOT_VALID(node)) {
  926                 printf("%s: Netgraph node is not valid\n", __func__);
  927                 return;
  928         }
  929 
  930         l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
  931         con = ng_l2cap_con_by_handle(l2cap, con_handle);
  932 
  933         if (con == NULL) {
  934                 NG_L2CAP_ALERT(
  935 "%s: %s - could not find connection, con_handle=%d\n",
  936                         __func__, NG_NODE_NAME(node), con_handle);
  937                 return;
  938         }
  939 
  940         if (!(con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)) {
  941                 NG_L2CAP_ALERT(
  942 "%s: %s - no pending disconnect timeout, con_handle=%d, state=%d, flags=%#x\n",
  943                         __func__, NG_NODE_NAME(node), con_handle, con->state,
  944                         con->flags);
  945                 return;
  946         }
  947 
  948         con->flags &= ~NG_L2CAP_CON_AUTO_DISCON_TIMO;
  949 
  950         /* Check if lower layer protocol is still connected */
  951         if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
  952                 NG_L2CAP_ERR(
  953 "%s: %s - hook \"%s\" is not connected or valid\n",
  954                         __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
  955                 return;
  956         }
  957 
  958         /* Create and send LP_DisconReq event */
  959         NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_REQ,
  960                 sizeof(*ep), M_NOWAIT);
  961         if (msg == NULL)
  962                 return;
  963 
  964         ep = (ng_hci_lp_discon_req_ep *) (msg->data);
  965         ep->con_handle = con->con_handle;
  966         ep->reason = 0x13; /* User Ended Connection */
  967 
  968         NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
  969 } /* ng_l2cap_process_discon_timeout */

Cache object: df4aa9303044918e99da3700e225f65e


[ 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.