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_evnt.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_evnt.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_evnt.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  **                    L2CAP events processing module
   58  ******************************************************************************
   59  ******************************************************************************/
   60 
   61 static int ng_l2cap_process_signal_cmd (ng_l2cap_con_p);
   62 static int ng_l2cap_process_lesignal_cmd (ng_l2cap_con_p);
   63 static int ng_l2cap_process_cmd_rej    (ng_l2cap_con_p, u_int8_t);
   64 static int ng_l2cap_process_cmd_urq    (ng_l2cap_con_p, u_int8_t);
   65 static int ng_l2cap_process_cmd_urs    (ng_l2cap_con_p, u_int8_t);
   66 static int ng_l2cap_process_con_req    (ng_l2cap_con_p, u_int8_t);
   67 static int ng_l2cap_process_con_rsp    (ng_l2cap_con_p, u_int8_t);
   68 static int ng_l2cap_process_cfg_req    (ng_l2cap_con_p, u_int8_t);
   69 static int ng_l2cap_process_cfg_rsp    (ng_l2cap_con_p, u_int8_t);
   70 static int ng_l2cap_process_discon_req (ng_l2cap_con_p, u_int8_t);
   71 static int ng_l2cap_process_discon_rsp (ng_l2cap_con_p, u_int8_t);
   72 static int ng_l2cap_process_echo_req   (ng_l2cap_con_p, u_int8_t);
   73 static int ng_l2cap_process_echo_rsp   (ng_l2cap_con_p, u_int8_t);
   74 static int ng_l2cap_process_info_req   (ng_l2cap_con_p, u_int8_t);
   75 static int ng_l2cap_process_info_rsp   (ng_l2cap_con_p, u_int8_t);
   76 static int send_l2cap_reject
   77         (ng_l2cap_con_p, u_int8_t, u_int16_t, u_int16_t, u_int16_t, u_int16_t);
   78 static int send_l2cap_con_rej
   79         (ng_l2cap_con_p, u_int8_t, u_int16_t, u_int16_t, u_int16_t);
   80 static int send_l2cap_cfg_rsp
   81         (ng_l2cap_con_p, u_int8_t, u_int16_t, u_int16_t, struct mbuf *);
   82 static int send_l2cap_param_urs
   83        (ng_l2cap_con_p , u_int8_t , u_int16_t);
   84 
   85 static int get_next_l2cap_opt
   86         (struct mbuf *, int *, ng_l2cap_cfg_opt_p, ng_l2cap_cfg_opt_val_p);
   87 
   88 /*
   89  * Receive L2CAP packet. First get L2CAP header and verify packet. Than
   90  * get destination channel and process packet.
   91  */
   92 
   93 int
   94 ng_l2cap_receive(ng_l2cap_con_p con)
   95 {
   96         ng_l2cap_p       l2cap = con->l2cap;
   97         ng_l2cap_hdr_t  *hdr = NULL;
   98         int              error = 0;
   99 
  100         /* Check packet */
  101         if (con->rx_pkt->m_pkthdr.len < sizeof(*hdr)) {
  102                 NG_L2CAP_ERR(
  103 "%s: %s - invalid L2CAP packet. Packet too small, len=%d\n",
  104                         __func__, NG_NODE_NAME(l2cap->node), 
  105                         con->rx_pkt->m_pkthdr.len);
  106                 error = EMSGSIZE;
  107                 goto drop;
  108         }
  109 
  110         /* Get L2CAP header */
  111         NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
  112         if (con->rx_pkt == NULL)
  113                 return (ENOBUFS);
  114 
  115         hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *);
  116         hdr->length = le16toh(hdr->length);
  117         hdr->dcid = le16toh(hdr->dcid);
  118 
  119         /* Check payload size */
  120         if (hdr->length != con->rx_pkt->m_pkthdr.len - sizeof(*hdr)) {
  121                 NG_L2CAP_ERR(
  122 "%s: %s - invalid L2CAP packet. Payload length mismatch, length=%d, len=%zd\n",
  123                         __func__, NG_NODE_NAME(l2cap->node), hdr->length, 
  124                         con->rx_pkt->m_pkthdr.len - sizeof(*hdr));
  125                 error = EMSGSIZE;
  126                 goto drop;
  127         }
  128 
  129         /* Process packet */
  130         switch (hdr->dcid) {
  131         case NG_L2CAP_SIGNAL_CID: /* L2CAP command */
  132                 m_adj(con->rx_pkt, sizeof(*hdr));
  133                 error = ng_l2cap_process_signal_cmd(con);
  134                 break;
  135         case NG_L2CAP_LESIGNAL_CID:
  136                 m_adj(con->rx_pkt, sizeof(*hdr));
  137                 error = ng_l2cap_process_lesignal_cmd(con);
  138                 break;
  139         case NG_L2CAP_CLT_CID: /* Connectionless packet */
  140                 error = ng_l2cap_l2ca_clt_receive(con);
  141                 break;
  142 
  143         default: /* Data packet */
  144                 error = ng_l2cap_l2ca_receive(con);
  145                 break;
  146         }
  147 
  148         return (error);
  149 drop:
  150         NG_FREE_M(con->rx_pkt);
  151 
  152         return (error);
  153 } /* ng_l2cap_receive */
  154 
  155 /*
  156  * Process L2CAP signaling command. We already know that destination channel ID
  157  * is 0x1 that means we have received signaling command from peer's L2CAP layer.
  158  * So get command header, decode and process it.
  159  *
  160  * XXX do we need to check signaling MTU here?
  161  */
  162 
  163 static int
  164 ng_l2cap_process_signal_cmd(ng_l2cap_con_p con)
  165 {
  166         ng_l2cap_p               l2cap = con->l2cap;
  167         ng_l2cap_cmd_hdr_t      *hdr = NULL;
  168         struct mbuf             *m = NULL;
  169 
  170         while (con->rx_pkt != NULL) {
  171                 /* Verify packet length */
  172                 if (con->rx_pkt->m_pkthdr.len < sizeof(*hdr)) {
  173                         NG_L2CAP_ERR(
  174 "%s: %s - invalid L2CAP signaling command. Packet too small, len=%d\n",
  175                                 __func__, NG_NODE_NAME(l2cap->node),
  176                                 con->rx_pkt->m_pkthdr.len);
  177                         NG_FREE_M(con->rx_pkt);
  178 
  179                         return (EMSGSIZE);
  180                 }
  181 
  182                 /* Get signaling command */
  183                 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
  184                 if (con->rx_pkt == NULL)
  185                         return (ENOBUFS);
  186 
  187                 hdr = mtod(con->rx_pkt, ng_l2cap_cmd_hdr_t *);
  188                 hdr->length = le16toh(hdr->length);
  189                 m_adj(con->rx_pkt, sizeof(*hdr));
  190 
  191                 /* Verify command length */
  192                 if (con->rx_pkt->m_pkthdr.len < hdr->length) {
  193                         NG_L2CAP_ERR(
  194 "%s: %s - invalid L2CAP signaling command, code=%#x, ident=%d. " \
  195 "Invalid command length=%d, m_pkthdr.len=%d\n",
  196                                 __func__, NG_NODE_NAME(l2cap->node),
  197                                 hdr->code, hdr->ident, hdr->length,
  198                                 con->rx_pkt->m_pkthdr.len);
  199                         NG_FREE_M(con->rx_pkt);
  200 
  201                         return (EMSGSIZE);
  202                 }
  203 
  204                 /* Get the command, save the rest (if any) */
  205                 if (con->rx_pkt->m_pkthdr.len > hdr->length)
  206                         m = m_split(con->rx_pkt, hdr->length, M_NOWAIT);
  207                 else
  208                         m = NULL;
  209 
  210                 /* Process command */
  211                 switch (hdr->code) {
  212                 case NG_L2CAP_CMD_REJ:
  213                         ng_l2cap_process_cmd_rej(con, hdr->ident);
  214                         break;
  215 
  216                 case NG_L2CAP_CON_REQ:
  217                         ng_l2cap_process_con_req(con, hdr->ident);
  218                         break;
  219 
  220                 case NG_L2CAP_CON_RSP:
  221                         ng_l2cap_process_con_rsp(con, hdr->ident);
  222                         break;
  223 
  224                 case NG_L2CAP_CFG_REQ:
  225                         ng_l2cap_process_cfg_req(con, hdr->ident);
  226                         break;
  227 
  228                 case NG_L2CAP_CFG_RSP:
  229                         ng_l2cap_process_cfg_rsp(con, hdr->ident);
  230                         break;
  231 
  232                 case NG_L2CAP_DISCON_REQ:
  233                         ng_l2cap_process_discon_req(con, hdr->ident);
  234                         break;
  235 
  236                 case NG_L2CAP_DISCON_RSP:
  237                         ng_l2cap_process_discon_rsp(con, hdr->ident);
  238                         break;
  239 
  240                 case NG_L2CAP_ECHO_REQ:
  241                         ng_l2cap_process_echo_req(con, hdr->ident);
  242                         break;
  243 
  244                 case NG_L2CAP_ECHO_RSP:
  245                         ng_l2cap_process_echo_rsp(con, hdr->ident);
  246                         break;
  247 
  248                 case NG_L2CAP_INFO_REQ:
  249                         ng_l2cap_process_info_req(con, hdr->ident);
  250                         break;
  251 
  252                 case NG_L2CAP_INFO_RSP:
  253                         ng_l2cap_process_info_rsp(con, hdr->ident);
  254                         break;
  255 
  256                 default:
  257                         NG_L2CAP_ERR(
  258 "%s: %s - unknown L2CAP signaling command, code=%#x, ident=%d, length=%d\n",
  259                                 __func__, NG_NODE_NAME(l2cap->node),
  260                                 hdr->code, hdr->ident, hdr->length);
  261 
  262                         /*
  263                          * Send L2CAP_CommandRej. Do not really care 
  264                          * about the result
  265                          */
  266 
  267                         send_l2cap_reject(con, hdr->ident,
  268                                 NG_L2CAP_REJ_NOT_UNDERSTOOD, 0, 0, 0);
  269                         NG_FREE_M(con->rx_pkt);
  270                         break;
  271                 }
  272 
  273                 con->rx_pkt = m;
  274         }
  275 
  276         return (0);
  277 } /* ng_l2cap_process_signal_cmd */
  278 static int
  279 ng_l2cap_process_lesignal_cmd(ng_l2cap_con_p con)
  280 {
  281         ng_l2cap_p               l2cap = con->l2cap;
  282         ng_l2cap_cmd_hdr_t      *hdr = NULL;
  283         struct mbuf             *m = NULL;
  284 
  285         while (con->rx_pkt != NULL) {
  286                 /* Verify packet length */
  287                 if (con->rx_pkt->m_pkthdr.len < sizeof(*hdr)) {
  288                         NG_L2CAP_ERR(
  289 "%s: %s - invalid L2CAP signaling command. Packet too small, len=%d\n",
  290                                 __func__, NG_NODE_NAME(l2cap->node),
  291                                 con->rx_pkt->m_pkthdr.len);
  292                         NG_FREE_M(con->rx_pkt);
  293 
  294                         return (EMSGSIZE);
  295                 }
  296 
  297                 /* Get signaling command */
  298                 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
  299                 if (con->rx_pkt == NULL)
  300                         return (ENOBUFS);
  301 
  302                 hdr = mtod(con->rx_pkt, ng_l2cap_cmd_hdr_t *);
  303                 hdr->length = le16toh(hdr->length);
  304                 m_adj(con->rx_pkt, sizeof(*hdr));
  305 
  306                 /* Verify command length */
  307                 if (con->rx_pkt->m_pkthdr.len < hdr->length) {
  308                         NG_L2CAP_ERR(
  309 "%s: %s - invalid L2CAP signaling command, code=%#x, ident=%d. " \
  310 "Invalid command length=%d, m_pkthdr.len=%d\n",
  311                                 __func__, NG_NODE_NAME(l2cap->node),
  312                                 hdr->code, hdr->ident, hdr->length,
  313                                 con->rx_pkt->m_pkthdr.len);
  314                         NG_FREE_M(con->rx_pkt);
  315 
  316                         return (EMSGSIZE);
  317                 }
  318 
  319                 /* Get the command, save the rest (if any) */
  320                 if (con->rx_pkt->m_pkthdr.len > hdr->length)
  321                         m = m_split(con->rx_pkt, hdr->length, M_NOWAIT);
  322                 else
  323                         m = NULL;
  324 
  325                 /* Process command */
  326                 switch (hdr->code) {
  327                 case NG_L2CAP_CMD_REJ:
  328                         ng_l2cap_process_cmd_rej(con, hdr->ident);
  329                         break;
  330                 case NG_L2CAP_CMD_PARAM_UPDATE_REQUEST:
  331                         ng_l2cap_process_cmd_urq(con, hdr->ident);
  332                         break;
  333                 case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE:
  334                         ng_l2cap_process_cmd_urs(con, hdr->ident);
  335                         break;
  336                         
  337 
  338                 default:
  339                         NG_L2CAP_ERR(
  340 "%s: %s - unknown L2CAP signaling command, code=%#x, ident=%d, length=%d\n",
  341                                 __func__, NG_NODE_NAME(l2cap->node),
  342                                 hdr->code, hdr->ident, hdr->length);
  343 
  344                         /*
  345                          * Send L2CAP_CommandRej. Do not really care 
  346                          * about the result
  347                          */
  348 
  349                         send_l2cap_reject(con, hdr->ident,
  350                                 NG_L2CAP_REJ_NOT_UNDERSTOOD, 0, 0, 0);
  351                         NG_FREE_M(con->rx_pkt);
  352                         break;
  353                 }
  354 
  355                 con->rx_pkt = m;
  356         }
  357 
  358         return (0);
  359 } /* ng_l2cap_process_signal_cmd */
  360 /*Update Paramater Request*/
  361 static int ng_l2cap_process_cmd_urq(ng_l2cap_con_p con, uint8_t ident)
  362 {
  363         /* We do not implement parameter negotiation for now. */
  364         send_l2cap_param_urs(con, ident, NG_L2CAP_UPDATE_PARAM_ACCEPT);
  365         NG_FREE_M(con->rx_pkt);
  366         return 0;
  367 }
  368 
  369 static int ng_l2cap_process_cmd_urs(ng_l2cap_con_p con, uint8_t ident)
  370 {
  371         /* We only support master side yet .*/
  372         //send_l2cap_reject(con,ident ... );
  373 
  374         NG_FREE_M(con->rx_pkt);
  375         return 0;
  376 }
  377 
  378 /*
  379  * Process L2CAP_CommandRej command
  380  */
  381 
  382 static int
  383 ng_l2cap_process_cmd_rej(ng_l2cap_con_p con, u_int8_t ident)
  384 {
  385         ng_l2cap_p               l2cap = con->l2cap;
  386         ng_l2cap_cmd_rej_cp     *cp = NULL;
  387         ng_l2cap_cmd_p           cmd = NULL;
  388 
  389         /* Get command parameters */
  390         NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*cp));
  391         if (con->rx_pkt == NULL)
  392                 return (ENOBUFS);
  393 
  394         cp = mtod(con->rx_pkt, ng_l2cap_cmd_rej_cp *);
  395         cp->reason = le16toh(cp->reason);
  396 
  397         /* Check if we have pending command descriptor */
  398         cmd = ng_l2cap_cmd_by_ident(con, ident);
  399         if (cmd != NULL) {
  400                 /* If command timeout already happened then ignore reject */
  401                 if (ng_l2cap_command_untimeout(cmd) != 0) {
  402                         NG_FREE_M(con->rx_pkt);
  403                         return (ETIMEDOUT);
  404                 }
  405 
  406                 ng_l2cap_unlink_cmd(cmd);
  407 
  408                 switch (cmd->code) {
  409                 case NG_L2CAP_CON_REQ:
  410                         ng_l2cap_l2ca_con_rsp(cmd->ch,cmd->token,cp->reason,0);
  411                         ng_l2cap_free_chan(cmd->ch);
  412                         break;
  413 
  414                 case NG_L2CAP_CFG_REQ:
  415                         ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, cp->reason);
  416                         break;
  417 
  418                 case NG_L2CAP_DISCON_REQ:
  419                         ng_l2cap_l2ca_discon_rsp(cmd->ch,cmd->token,cp->reason);
  420                         ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
  421                         break;
  422 
  423                 case NG_L2CAP_ECHO_REQ:
  424                         ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
  425                                 cp->reason, NULL);
  426                         break;
  427 
  428                 case NG_L2CAP_INFO_REQ:
  429                         ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
  430                                 cp->reason, NULL);
  431                         break;
  432 
  433                 default:
  434                         NG_L2CAP_ALERT(
  435 "%s: %s - unexpected L2CAP_CommandRej. Unexpected L2CAP command opcode=%d\n",
  436                                 __func__, NG_NODE_NAME(l2cap->node), cmd->code);
  437                         break;
  438                 }
  439 
  440                 ng_l2cap_free_cmd(cmd);
  441         } else
  442                 NG_L2CAP_ERR(
  443 "%s: %s - unexpected L2CAP_CommandRej command. " \
  444 "Requested ident does not exist, ident=%d\n",
  445                         __func__, NG_NODE_NAME(l2cap->node), ident);
  446 
  447         NG_FREE_M(con->rx_pkt);
  448 
  449         return (0);
  450 } /* ng_l2cap_process_cmd_rej */
  451 
  452 /*
  453  * Process L2CAP_ConnectReq command
  454  */
  455 
  456 static int
  457 ng_l2cap_process_con_req(ng_l2cap_con_p con, u_int8_t ident)
  458 {
  459         ng_l2cap_p               l2cap = con->l2cap;
  460         struct mbuf             *m = con->rx_pkt;
  461         ng_l2cap_con_req_cp     *cp = NULL;
  462         ng_l2cap_chan_p          ch = NULL;
  463         int                      error = 0;
  464         u_int16_t                dcid, psm;
  465         int idtype;
  466 
  467         /* Get command parameters */
  468         NG_L2CAP_M_PULLUP(m, sizeof(*cp));
  469         if (m == NULL)
  470                 return (ENOBUFS);
  471 
  472         cp = mtod(m, ng_l2cap_con_req_cp *);
  473         psm = le16toh(cp->psm);
  474         dcid = le16toh(cp->scid);
  475 
  476         NG_FREE_M(m);
  477         con->rx_pkt = NULL;
  478         if(dcid == NG_L2CAP_ATT_CID)
  479                 idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
  480         else if(dcid == NG_L2CAP_SMP_CID)
  481                 idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
  482         else if( con->linktype != NG_HCI_LINK_ACL)
  483                 idtype = NG_L2CAP_L2CA_IDTYPE_LE;
  484         else
  485                 idtype = NG_L2CAP_L2CA_IDTYPE_BREDR;
  486 
  487         /*
  488          * Create new channel and send L2CA_ConnectInd notification 
  489          * to the upper layer protocol.
  490          */
  491 
  492         ch = ng_l2cap_new_chan(l2cap, con, psm, idtype);
  493 
  494         if (ch == NULL)
  495                 return (send_l2cap_con_rej(con, ident, 0, dcid,
  496                                 NG_L2CAP_NO_RESOURCES));
  497 
  498         /* Update channel IDs */
  499         ch->dcid = dcid;
  500 
  501         /* Sent L2CA_ConnectInd notification to the upper layer */
  502         ch->ident = ident;
  503         ch->state = NG_L2CAP_W4_L2CA_CON_RSP;
  504 
  505         error = ng_l2cap_l2ca_con_ind(ch);
  506         if (error != 0) {
  507                 send_l2cap_con_rej(con, ident, ch->scid, dcid, 
  508                         (error == ENOMEM)? NG_L2CAP_NO_RESOURCES :
  509                                 NG_L2CAP_PSM_NOT_SUPPORTED);
  510                 ng_l2cap_free_chan(ch);
  511         }
  512 
  513         return (error);
  514 } /* ng_l2cap_process_con_req */
  515 
  516 /*
  517  * Process L2CAP_ConnectRsp command
  518  */
  519 
  520 static int
  521 ng_l2cap_process_con_rsp(ng_l2cap_con_p con, u_int8_t ident)
  522 {
  523         ng_l2cap_p               l2cap = con->l2cap;
  524         struct mbuf             *m = con->rx_pkt;
  525         ng_l2cap_con_rsp_cp     *cp = NULL;
  526         ng_l2cap_cmd_p           cmd = NULL;
  527         u_int16_t                scid, dcid, result, status;
  528         int                      error = 0;
  529 
  530         /* Get command parameters */
  531         NG_L2CAP_M_PULLUP(m, sizeof(*cp));
  532         if (m == NULL)
  533                 return (ENOBUFS);
  534 
  535         cp = mtod(m, ng_l2cap_con_rsp_cp *);
  536         dcid = le16toh(cp->dcid);
  537         scid = le16toh(cp->scid);
  538         result = le16toh(cp->result);
  539         status = le16toh(cp->status);
  540 
  541         NG_FREE_M(m);
  542         con->rx_pkt = NULL;
  543 
  544         /* Check if we have pending command descriptor */
  545         cmd = ng_l2cap_cmd_by_ident(con, ident);
  546         if (cmd == NULL) {
  547                 NG_L2CAP_ERR(
  548 "%s: %s - unexpected L2CAP_ConnectRsp command. ident=%d, con_handle=%d\n",
  549                         __func__, NG_NODE_NAME(l2cap->node), ident, 
  550                         con->con_handle);
  551 
  552                 return (ENOENT);
  553         }
  554 
  555         /* Verify channel state, if invalid - do nothing */
  556         if (cmd->ch->state != NG_L2CAP_W4_L2CAP_CON_RSP) {
  557                 NG_L2CAP_ERR(
  558 "%s: %s - unexpected L2CAP_ConnectRsp. " \
  559 "Invalid channel state, cid=%d, state=%d\n",
  560                         __func__, NG_NODE_NAME(l2cap->node), scid, 
  561                         cmd->ch->state);
  562                 goto reject;
  563         }
  564 
  565         /* Verify CIDs and send reject if does not match */
  566         if (cmd->ch->scid != scid) {
  567                 NG_L2CAP_ERR(
  568 "%s: %s - unexpected L2CAP_ConnectRsp. Channel IDs do not match, scid=%d(%d)\n",
  569                          __func__, NG_NODE_NAME(l2cap->node), cmd->ch->scid, 
  570                         scid);
  571                 goto reject;
  572         }
  573 
  574         /*
  575          * Looks good. We got confirmation from our peer. Now process
  576          * it. First disable RTX timer. Then check the result and send 
  577          * notification to the upper layer. If command timeout already
  578          * happened then ignore response.
  579          */
  580 
  581         if ((error = ng_l2cap_command_untimeout(cmd)) != 0)
  582                 return (error);
  583 
  584         if (result == NG_L2CAP_PENDING) {
  585                 /*
  586                  * Our peer wants more time to complete connection. We shall 
  587                  * start ERTX timer and wait. Keep command in the list.
  588                  */
  589 
  590                 cmd->ch->dcid = dcid;
  591                 ng_l2cap_command_timeout(cmd, bluetooth_l2cap_ertx_timeout());
  592 
  593                 error = ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, 
  594                                 result, status);
  595                 if (error != 0)
  596                         ng_l2cap_free_chan(cmd->ch);
  597         } else {
  598                 ng_l2cap_unlink_cmd(cmd);
  599 
  600                 if (result == NG_L2CAP_SUCCESS) {
  601                         /*
  602                          * Channel is open. Complete command and move to CONFIG
  603                          * state. Since we have sent positive confirmation we 
  604                          * expect to receive L2CA_Config request from the upper
  605                          * layer protocol.
  606                          */
  607 
  608                         cmd->ch->dcid = dcid;
  609                         cmd->ch->state = ((cmd->ch->scid == NG_L2CAP_ATT_CID)||
  610                                           (cmd->ch->scid == NG_L2CAP_SMP_CID))
  611                                           ?
  612                           NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
  613                 } else
  614                         /* There was an error, so close the channel */
  615                         NG_L2CAP_INFO(
  616 "%s: %s - failed to open L2CAP channel, result=%d, status=%d\n",
  617                                 __func__, NG_NODE_NAME(l2cap->node), result, 
  618                                 status);
  619 
  620                 error = ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, 
  621                                 result, status);
  622 
  623                 /* XXX do we have to remove the channel on error? */
  624                 if (error != 0 || result != NG_L2CAP_SUCCESS)
  625                         ng_l2cap_free_chan(cmd->ch);
  626 
  627                 ng_l2cap_free_cmd(cmd);
  628         }
  629 
  630         return (error);
  631 
  632 reject:
  633         /* Send reject. Do not really care about the result */
  634         send_l2cap_reject(con, ident, NG_L2CAP_REJ_INVALID_CID, 0, scid, dcid);
  635 
  636         return (0);
  637 } /* ng_l2cap_process_con_rsp */
  638 
  639 /*
  640  * Process L2CAP_ConfigReq command
  641  */
  642 
  643 static int
  644 ng_l2cap_process_cfg_req(ng_l2cap_con_p con, u_int8_t ident)
  645 {
  646         ng_l2cap_p               l2cap = con->l2cap;
  647         struct mbuf             *m = con->rx_pkt;
  648         ng_l2cap_cfg_req_cp     *cp = NULL;
  649         ng_l2cap_chan_p          ch = NULL;
  650         u_int16_t                dcid, respond, result;
  651         ng_l2cap_cfg_opt_t       hdr;
  652         ng_l2cap_cfg_opt_val_t   val;
  653         int                      off, error = 0;
  654 
  655         /* Get command parameters */
  656         con->rx_pkt = NULL;
  657         NG_L2CAP_M_PULLUP(m, sizeof(*cp));
  658         if (m == NULL)
  659                 return (ENOBUFS);
  660 
  661         cp = mtod(m, ng_l2cap_cfg_req_cp *);
  662         dcid = le16toh(cp->dcid);
  663         respond = NG_L2CAP_OPT_CFLAG(le16toh(cp->flags));
  664         m_adj(m, sizeof(*cp));
  665 
  666         /* Check if we have this channel and it is in valid state */
  667         ch = ng_l2cap_chan_by_scid(l2cap, dcid, NG_L2CAP_L2CA_IDTYPE_BREDR);
  668         if (ch == NULL) {
  669                 NG_L2CAP_ERR(
  670 "%s: %s - unexpected L2CAP_ConfigReq command. " \
  671 "Channel does not exist, cid=%d\n",
  672                         __func__, NG_NODE_NAME(l2cap->node), dcid);
  673                 goto reject;
  674         }
  675 
  676         /* Verify channel state */
  677         if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN) {
  678                 NG_L2CAP_ERR(
  679 "%s: %s - unexpected L2CAP_ConfigReq. " \
  680 "Invalid channel state, cid=%d, state=%d\n",
  681                         __func__, NG_NODE_NAME(l2cap->node), dcid, ch->state);
  682                 goto reject;
  683         }
  684 
  685         if (ch->state == NG_L2CAP_OPEN) { /* Re-configuration */
  686                 ch->cfg_state = 0;
  687                 ch->state = NG_L2CAP_CONFIG;
  688         }
  689 
  690         for (result = 0, off = 0; ; ) {
  691                 error = get_next_l2cap_opt(m, &off, &hdr, &val);
  692                 if (error == 0) { /* We done with this packet */
  693                         NG_FREE_M(m);
  694                         break;
  695                 } else if (error > 0) { /* Got option */
  696                         switch (hdr.type) {
  697                         case NG_L2CAP_OPT_MTU:
  698                                 ch->omtu = val.mtu;
  699                                 break;
  700 
  701                         case NG_L2CAP_OPT_FLUSH_TIMO:
  702                                 ch->flush_timo = val.flush_timo;
  703                                 break;
  704 
  705                         case NG_L2CAP_OPT_QOS:
  706                                 bcopy(&val.flow, &ch->iflow, sizeof(ch->iflow));
  707                                 break;
  708 
  709                         default: /* Ignore unknown hint option */
  710                                 break;
  711                         }
  712                 } else { /* Oops, something is wrong */
  713                         respond = 1;
  714 
  715                         if (error == -3) {
  716                                 /*
  717                                  * Adjust mbuf so we can get to the start
  718                                  * of the first option we did not like.
  719                                  */
  720 
  721                                 m_adj(m, off - sizeof(hdr));
  722                                 m->m_pkthdr.len = sizeof(hdr) + hdr.length;
  723 
  724                                 result = NG_L2CAP_UNKNOWN_OPTION;
  725                         } else {
  726                                 /* XXX FIXME Send other reject codes? */
  727                                 NG_FREE_M(m);
  728                                 result = NG_L2CAP_REJECT;
  729                         }
  730 
  731                         break;
  732                 }
  733         }
  734 
  735         /*
  736          * Now check and see if we have to respond. If everything was OK then 
  737          * respond contain "C flag" and (if set) we will respond with empty 
  738          * packet and will wait for more options. 
  739          * 
  740          * Other case is that we did not like peer's options and will respond 
  741          * with L2CAP_Config response command with Reject error code. 
  742          * 
  743          * When "respond == 0" than we have received all options and we will 
  744          * sent L2CA_ConfigInd event to the upper layer protocol.
  745          */
  746 
  747         if (respond) {
  748                 error = send_l2cap_cfg_rsp(con, ident, ch->dcid, result, m);
  749                 if (error != 0) {
  750                         ng_l2cap_l2ca_discon_ind(ch);
  751                         ng_l2cap_free_chan(ch);
  752                 }
  753         } else {
  754                 /* Send L2CA_ConfigInd event to the upper layer protocol */
  755                 ch->ident = ident;
  756                 error = ng_l2cap_l2ca_cfg_ind(ch);
  757                 if (error != 0)
  758                         ng_l2cap_free_chan(ch);
  759         }
  760 
  761         return (error);
  762 
  763 reject:
  764         /* Send reject. Do not really care about the result */
  765         NG_FREE_M(m);
  766 
  767         send_l2cap_reject(con, ident, NG_L2CAP_REJ_INVALID_CID, 0, 0, dcid);
  768 
  769         return (0);
  770 } /* ng_l2cap_process_cfg_req */
  771 
  772 /*
  773  * Process L2CAP_ConfigRsp command
  774  */
  775 
  776 static int
  777 ng_l2cap_process_cfg_rsp(ng_l2cap_con_p con, u_int8_t ident)
  778 {
  779         ng_l2cap_p               l2cap = con->l2cap;
  780         struct mbuf             *m = con->rx_pkt;
  781         ng_l2cap_cfg_rsp_cp     *cp = NULL;
  782         ng_l2cap_cmd_p           cmd = NULL;
  783         u_int16_t                scid, cflag, result;
  784         ng_l2cap_cfg_opt_t       hdr;
  785         ng_l2cap_cfg_opt_val_t   val;
  786         int                      off, error = 0;
  787 
  788         /* Get command parameters */
  789         con->rx_pkt = NULL;
  790         NG_L2CAP_M_PULLUP(m, sizeof(*cp));
  791         if (m == NULL)
  792                 return (ENOBUFS);
  793 
  794         cp = mtod(m, ng_l2cap_cfg_rsp_cp *);
  795         scid = le16toh(cp->scid);
  796         cflag = NG_L2CAP_OPT_CFLAG(le16toh(cp->flags));
  797         result = le16toh(cp->result);
  798         m_adj(m, sizeof(*cp));
  799 
  800         /* Check if we have this command */
  801         cmd = ng_l2cap_cmd_by_ident(con, ident);
  802         if (cmd == NULL) {
  803                 NG_L2CAP_ERR(
  804 "%s: %s - unexpected L2CAP_ConfigRsp command. ident=%d, con_handle=%d\n",
  805                         __func__, NG_NODE_NAME(l2cap->node), ident, 
  806                         con->con_handle);
  807                 NG_FREE_M(m);
  808 
  809                 return (ENOENT);
  810         }
  811 
  812         /* Verify CIDs and send reject if does not match */
  813         if (cmd->ch->scid != scid) {
  814                 NG_L2CAP_ERR(
  815 "%s: %s - unexpected L2CAP_ConfigRsp. " \
  816 "Channel ID does not match, scid=%d(%d)\n",
  817                         __func__, NG_NODE_NAME(l2cap->node), cmd->ch->scid, 
  818                         scid);
  819                 goto reject;
  820         }
  821 
  822         /* Verify channel state and reject if invalid */
  823         if (cmd->ch->state != NG_L2CAP_CONFIG) {
  824                 NG_L2CAP_ERR(
  825 "%s: %s - unexpected L2CAP_ConfigRsp. " \
  826 "Invalid channel state, scid=%d, state=%d\n",
  827                         __func__, NG_NODE_NAME(l2cap->node), cmd->ch->scid,
  828                         cmd->ch->state);
  829                 goto reject;
  830         }
  831 
  832         /*
  833          * Looks like it is our response, so process it. First parse options,
  834          * then verify C flag. If it is set then we shall expect more 
  835          * configuration options from the peer and we will wait. Otherwise we 
  836          * have received all options and we will send L2CA_ConfigRsp event to
  837          * the upper layer protocol. If command timeout already happened then
  838          * ignore response.
  839          */
  840 
  841         if ((error = ng_l2cap_command_untimeout(cmd)) != 0) {
  842                 NG_FREE_M(m);
  843                 return (error);
  844         }
  845 
  846         for (off = 0; ; ) {
  847                 error = get_next_l2cap_opt(m, &off, &hdr, &val); 
  848                 if (error == 0) /* We done with this packet */
  849                         break;
  850                 else if (error > 0) { /* Got option */
  851                         switch (hdr.type) {
  852                         case NG_L2CAP_OPT_MTU:
  853                                 cmd->ch->imtu = val.mtu;
  854                         break;
  855 
  856                         case NG_L2CAP_OPT_FLUSH_TIMO:
  857                                 cmd->ch->flush_timo = val.flush_timo;
  858                                 break;
  859 
  860                         case NG_L2CAP_OPT_QOS:
  861                                 bcopy(&val.flow, &cmd->ch->oflow,
  862                                         sizeof(cmd->ch->oflow));
  863                         break;
  864 
  865                         default: /* Ignore unknown hint option */
  866                                 break;
  867                         }
  868                 } else {
  869                         /*
  870                          * XXX FIXME What to do here?
  871                          *
  872                          * This is really BAD :( options packet was broken, or 
  873                          * peer sent us option that we did not understand. Let 
  874                          * upper layer know and do not wait for more options.
  875                          */
  876 
  877                         NG_L2CAP_ALERT(
  878 "%s: %s - failed to parse configuration options, error=%d\n", 
  879                                 __func__, NG_NODE_NAME(l2cap->node), error);
  880 
  881                         result = NG_L2CAP_UNKNOWN;
  882                         cflag = 0;
  883 
  884                         break;
  885                 }
  886         }
  887 
  888         NG_FREE_M(m);
  889 
  890         if (cflag) /* Restart timer and wait for more options */
  891                 ng_l2cap_command_timeout(cmd, bluetooth_l2cap_rtx_timeout());
  892         else {
  893                 ng_l2cap_unlink_cmd(cmd);
  894 
  895                 /* Send L2CA_Config response to the upper layer protocol */
  896                 error = ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, result);
  897                 if (error != 0) {
  898                         /*
  899                          * XXX FIXME what to do here? we were not able to send
  900                          * response to the upper layer protocol, so for now 
  901                          * just close the channel. Send L2CAP_Disconnect to 
  902                          * remote peer?
  903                          */
  904 
  905                         NG_L2CAP_ERR(
  906 "%s: %s - failed to send L2CA_Config response, error=%d\n",
  907                         __func__, NG_NODE_NAME(l2cap->node), error);
  908 
  909                         ng_l2cap_free_chan(cmd->ch);
  910                 }
  911 
  912                 ng_l2cap_free_cmd(cmd);
  913         }
  914 
  915         return (error);
  916 
  917 reject:
  918         /* Send reject. Do not really care about the result */
  919         NG_FREE_M(m);
  920 
  921         send_l2cap_reject(con, ident, NG_L2CAP_REJ_INVALID_CID, 0, scid, 0);
  922 
  923         return (0);
  924 } /* ng_l2cap_process_cfg_rsp */
  925 
  926 /*
  927  * Process L2CAP_DisconnectReq command
  928  */
  929 
  930 static int
  931 ng_l2cap_process_discon_req(ng_l2cap_con_p con, u_int8_t ident)
  932 {
  933         ng_l2cap_p               l2cap = con->l2cap;
  934         ng_l2cap_discon_req_cp  *cp = NULL;
  935         ng_l2cap_chan_p          ch = NULL;
  936         ng_l2cap_cmd_p           cmd = NULL;
  937         u_int16_t                scid, dcid;
  938 
  939         /* Get command parameters */
  940         NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*cp));
  941         if (con->rx_pkt == NULL)
  942                 return (ENOBUFS);
  943 
  944         cp = mtod(con->rx_pkt, ng_l2cap_discon_req_cp *);
  945         dcid = le16toh(cp->dcid);
  946         scid = le16toh(cp->scid);
  947 
  948         NG_FREE_M(con->rx_pkt);
  949 
  950         /* Check if we have this channel and it is in valid state */
  951         ch = ng_l2cap_chan_by_scid(l2cap, dcid, NG_L2CAP_L2CA_IDTYPE_BREDR);
  952         if (ch == NULL) {
  953                 NG_L2CAP_ERR(
  954 "%s: %s - unexpected L2CAP_DisconnectReq message. " \
  955 "Channel does not exist, cid=%d\n",
  956                         __func__, NG_NODE_NAME(l2cap->node), dcid);
  957                 goto reject;
  958         }
  959 
  960         /* XXX Verify channel state and reject if invalid -- is that true? */
  961         if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG &&
  962             ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) {
  963                 NG_L2CAP_ERR(
  964 "%s: %s - unexpected L2CAP_DisconnectReq. " \
  965 "Invalid channel state, cid=%d, state=%d\n",
  966                         __func__, NG_NODE_NAME(l2cap->node), dcid, ch->state);
  967                 goto reject;
  968         }
  969 
  970         /* Match destination channel ID */
  971         if (ch->dcid != scid || ch->scid != dcid) {
  972                 NG_L2CAP_ERR(
  973 "%s: %s - unexpected L2CAP_DisconnectReq. " \
  974 "Channel IDs does not match, channel: scid=%d, dcid=%d, " \
  975 "request: scid=%d, dcid=%d\n",
  976                         __func__, NG_NODE_NAME(l2cap->node), ch->scid, ch->dcid,
  977                         scid, dcid);
  978                 goto reject;
  979         }
  980 
  981         /*
  982          * Looks good, so notify upper layer protocol that channel is about 
  983          * to be disconnected and send L2CA_DisconnectInd message. Then respond
  984          * with L2CAP_DisconnectRsp.
  985          */
  986 
  987         if (ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) {
  988                 ng_l2cap_l2ca_discon_ind(ch); /* do not care about result */
  989                 ng_l2cap_free_chan(ch);
  990         }
  991 
  992         /* Send L2CAP_DisconnectRsp */
  993         cmd = ng_l2cap_new_cmd(con, NULL, ident, NG_L2CAP_DISCON_RSP, 0);
  994         if (cmd == NULL)
  995                 return (ENOMEM);
  996 
  997         _ng_l2cap_discon_rsp(cmd->aux, ident, dcid, scid);
  998         if (cmd->aux == NULL) {
  999                 ng_l2cap_free_cmd(cmd);
 1000 
 1001                 return (ENOBUFS);
 1002         }
 1003 
 1004         /* Link command to the queue */
 1005         ng_l2cap_link_cmd(con, cmd);
 1006         ng_l2cap_lp_deliver(con);
 1007 
 1008         return (0);
 1009 
 1010 reject:
 1011         /* Send reject. Do not really care about the result */
 1012         send_l2cap_reject(con, ident, NG_L2CAP_REJ_INVALID_CID, 0, scid, dcid);
 1013 
 1014         return (0);
 1015 } /* ng_l2cap_process_discon_req */
 1016 
 1017 /*
 1018  * Process L2CAP_DisconnectRsp command
 1019  */
 1020 
 1021 static int
 1022 ng_l2cap_process_discon_rsp(ng_l2cap_con_p con, u_int8_t ident)
 1023 {
 1024         ng_l2cap_p               l2cap = con->l2cap;
 1025         ng_l2cap_discon_rsp_cp  *cp = NULL;
 1026         ng_l2cap_cmd_p           cmd = NULL;
 1027         u_int16_t                scid, dcid;
 1028         int                      error = 0;
 1029 
 1030         /* Get command parameters */
 1031         NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*cp));
 1032         if (con->rx_pkt == NULL)
 1033                 return (ENOBUFS);
 1034 
 1035         cp = mtod(con->rx_pkt, ng_l2cap_discon_rsp_cp *);
 1036         dcid = le16toh(cp->dcid);
 1037         scid = le16toh(cp->scid);
 1038 
 1039         NG_FREE_M(con->rx_pkt);
 1040 
 1041         /* Check if we have pending command descriptor */
 1042         cmd = ng_l2cap_cmd_by_ident(con, ident);
 1043         if (cmd == NULL) {
 1044                 NG_L2CAP_ERR(
 1045 "%s: %s - unexpected L2CAP_DisconnectRsp command. ident=%d, con_handle=%d\n",
 1046                         __func__, NG_NODE_NAME(l2cap->node), ident, 
 1047                         con->con_handle);
 1048                 goto out;
 1049         }
 1050 
 1051         /* Verify channel state, do nothing if invalid */
 1052         if (cmd->ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) {
 1053                 NG_L2CAP_ERR(
 1054 "%s: %s - unexpected L2CAP_DisconnectRsp. " \
 1055 "Invalid channel state, cid=%d, state=%d\n",
 1056                         __func__, NG_NODE_NAME(l2cap->node), scid,
 1057                         cmd->ch->state);
 1058                 goto out;
 1059         }
 1060 
 1061         /* Verify CIDs and send reject if does not match */
 1062         if (cmd->ch->scid != scid || cmd->ch->dcid != dcid) {
 1063                 NG_L2CAP_ERR(
 1064 "%s: %s - unexpected L2CAP_DisconnectRsp. " \
 1065 "Channel IDs do not match, scid=%d(%d), dcid=%d(%d)\n",
 1066                         __func__, NG_NODE_NAME(l2cap->node), cmd->ch->scid, 
 1067                         scid, cmd->ch->dcid, dcid);
 1068                 goto out;
 1069         }
 1070 
 1071         /*
 1072          * Looks like we have successfully disconnected channel, so notify 
 1073          * upper layer. If command timeout already happened then ignore
 1074          * response.
 1075          */
 1076 
 1077         if ((error = ng_l2cap_command_untimeout(cmd)) != 0)
 1078                 goto out;
 1079 
 1080         error = ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token, NG_L2CAP_SUCCESS);
 1081         ng_l2cap_free_chan(cmd->ch); /* this will free commands too */
 1082 out:
 1083         return (error);
 1084 } /* ng_l2cap_process_discon_rsp */
 1085 
 1086 /*
 1087  * Process L2CAP_EchoReq command
 1088  */
 1089 
 1090 static int
 1091 ng_l2cap_process_echo_req(ng_l2cap_con_p con, u_int8_t ident)
 1092 {
 1093         ng_l2cap_p               l2cap = con->l2cap;
 1094         ng_l2cap_cmd_hdr_t      *hdr = NULL;
 1095         ng_l2cap_cmd_p           cmd = NULL;
 1096 
 1097         con->rx_pkt = ng_l2cap_prepend(con->rx_pkt, sizeof(*hdr));
 1098         if (con->rx_pkt == NULL) {
 1099                 NG_L2CAP_ALERT(
 1100 "%s: %s - ng_l2cap_prepend() failed, size=%zd\n",
 1101                         __func__, NG_NODE_NAME(l2cap->node), sizeof(*hdr));
 1102 
 1103                 return (ENOBUFS);
 1104         }
 1105 
 1106         hdr = mtod(con->rx_pkt, ng_l2cap_cmd_hdr_t *);
 1107         hdr->code = NG_L2CAP_ECHO_RSP;
 1108         hdr->ident = ident;
 1109         hdr->length = htole16(con->rx_pkt->m_pkthdr.len - sizeof(*hdr));
 1110 
 1111         cmd = ng_l2cap_new_cmd(con, NULL, ident, NG_L2CAP_ECHO_RSP, 0);
 1112         if (cmd == NULL) {
 1113                 NG_FREE_M(con->rx_pkt);
 1114 
 1115                 return (ENOBUFS);
 1116         }
 1117 
 1118         /* Attach data and link command to the queue */
 1119         cmd->aux = con->rx_pkt;
 1120         con->rx_pkt = NULL;
 1121         ng_l2cap_link_cmd(con, cmd);
 1122         ng_l2cap_lp_deliver(con);
 1123 
 1124         return (0);
 1125 } /* ng_l2cap_process_echo_req */
 1126 
 1127 /*
 1128  * Process L2CAP_EchoRsp command
 1129  */
 1130 
 1131 static int
 1132 ng_l2cap_process_echo_rsp(ng_l2cap_con_p con, u_int8_t ident)
 1133 {
 1134         ng_l2cap_p      l2cap = con->l2cap;
 1135         ng_l2cap_cmd_p  cmd = NULL;
 1136         int             error = 0;
 1137 
 1138         /* Check if we have this command */
 1139         cmd = ng_l2cap_cmd_by_ident(con, ident);
 1140         if (cmd != NULL) {
 1141                 /* If command timeout already happened then ignore response */
 1142                 if ((error = ng_l2cap_command_untimeout(cmd)) != 0) {
 1143                         NG_FREE_M(con->rx_pkt);
 1144                         return (error);
 1145                 }
 1146 
 1147                 ng_l2cap_unlink_cmd(cmd);
 1148 
 1149                 error = ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
 1150                                 NG_L2CAP_SUCCESS, con->rx_pkt);
 1151 
 1152                 ng_l2cap_free_cmd(cmd);
 1153                 con->rx_pkt = NULL;
 1154         } else {
 1155                 NG_L2CAP_ERR(
 1156 "%s: %s - unexpected L2CAP_EchoRsp command. " \
 1157 "Requested ident does not exist, ident=%d\n",
 1158                         __func__, NG_NODE_NAME(l2cap->node), ident);
 1159                 NG_FREE_M(con->rx_pkt);
 1160         }
 1161 
 1162         return (error);
 1163 } /* ng_l2cap_process_echo_rsp */
 1164 
 1165 /*
 1166  * Process L2CAP_InfoReq command
 1167  */
 1168 
 1169 static int
 1170 ng_l2cap_process_info_req(ng_l2cap_con_p con, u_int8_t ident)
 1171 {
 1172         ng_l2cap_p      l2cap = con->l2cap;
 1173         ng_l2cap_cmd_p  cmd = NULL;
 1174         u_int16_t       type;
 1175 
 1176         /* Get command parameters */
 1177         NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(ng_l2cap_info_req_cp));
 1178         if (con->rx_pkt == NULL)
 1179                 return (ENOBUFS);
 1180 
 1181         type = le16toh(mtod(con->rx_pkt, ng_l2cap_info_req_cp *)->type);
 1182         NG_FREE_M(con->rx_pkt);
 1183 
 1184         cmd = ng_l2cap_new_cmd(con, NULL, ident, NG_L2CAP_INFO_RSP, 0);
 1185         if (cmd == NULL)
 1186                 return (ENOMEM);
 1187 
 1188         switch (type) {
 1189         case NG_L2CAP_CONNLESS_MTU:
 1190                 _ng_l2cap_info_rsp(cmd->aux, ident, NG_L2CAP_CONNLESS_MTU,
 1191                                 NG_L2CAP_SUCCESS, NG_L2CAP_MTU_DEFAULT);
 1192                 break;
 1193 
 1194         default:
 1195                 _ng_l2cap_info_rsp(cmd->aux, ident, type,
 1196                                 NG_L2CAP_NOT_SUPPORTED, 0);
 1197                 break;
 1198         }
 1199 
 1200         if (cmd->aux == NULL) {
 1201                 ng_l2cap_free_cmd(cmd);
 1202 
 1203                 return (ENOBUFS);
 1204         }
 1205 
 1206         /* Link command to the queue */
 1207         ng_l2cap_link_cmd(con, cmd);
 1208         ng_l2cap_lp_deliver(con);
 1209 
 1210         return (0);
 1211 } /* ng_l2cap_process_info_req */
 1212 
 1213 /*
 1214  * Process L2CAP_InfoRsp command
 1215  */
 1216 
 1217 static int
 1218 ng_l2cap_process_info_rsp(ng_l2cap_con_p con, u_int8_t ident)
 1219 {
 1220         ng_l2cap_p               l2cap = con->l2cap;
 1221         ng_l2cap_info_rsp_cp    *cp = NULL;
 1222         ng_l2cap_cmd_p           cmd = NULL;
 1223         int                      error = 0;
 1224 
 1225         /* Get command parameters */
 1226         NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*cp));
 1227         if (con->rx_pkt == NULL)
 1228                 return (ENOBUFS);
 1229 
 1230         cp = mtod(con->rx_pkt, ng_l2cap_info_rsp_cp *);
 1231         cp->type = le16toh(cp->type);
 1232         cp->result = le16toh(cp->result);
 1233         m_adj(con->rx_pkt, sizeof(*cp));
 1234 
 1235         /* Check if we have pending command descriptor */
 1236         cmd = ng_l2cap_cmd_by_ident(con, ident);
 1237         if (cmd == NULL) {
 1238                 NG_L2CAP_ERR(
 1239 "%s: %s - unexpected L2CAP_InfoRsp command. " \
 1240 "Requested ident does not exist, ident=%d\n",
 1241                         __func__, NG_NODE_NAME(l2cap->node), ident);
 1242                 NG_FREE_M(con->rx_pkt);
 1243 
 1244                 return (ENOENT);
 1245         }
 1246 
 1247         /* If command timeout already happened then ignore response */
 1248         if ((error = ng_l2cap_command_untimeout(cmd)) != 0) {
 1249                 NG_FREE_M(con->rx_pkt);
 1250                 return (error);
 1251         }
 1252 
 1253         ng_l2cap_unlink_cmd(cmd);
 1254 
 1255         if (cp->result == NG_L2CAP_SUCCESS) {
 1256                 switch (cp->type) {
 1257                 case NG_L2CAP_CONNLESS_MTU:
 1258                         if (con->rx_pkt->m_pkthdr.len == sizeof(u_int16_t))
 1259                                 *mtod(con->rx_pkt, u_int16_t *) = 
 1260                                         le16toh(*mtod(con->rx_pkt,u_int16_t *));
 1261                         else {
 1262                                 cp->result = NG_L2CAP_UNKNOWN; /* XXX */
 1263 
 1264                                 NG_L2CAP_ERR(
 1265 "%s: %s - invalid L2CAP_InfoRsp command. " \
 1266 "Bad connectionless MTU parameter, len=%d\n",
 1267                                         __func__, NG_NODE_NAME(l2cap->node),
 1268                                         con->rx_pkt->m_pkthdr.len);
 1269                         }
 1270                         break;
 1271 
 1272                 default:
 1273                         NG_L2CAP_WARN(
 1274 "%s: %s - invalid L2CAP_InfoRsp command. Unknown info type=%d\n",
 1275                                 __func__, NG_NODE_NAME(l2cap->node), cp->type);
 1276                         break;
 1277                 }
 1278         }
 1279 
 1280         error = ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
 1281                         cp->result, con->rx_pkt);
 1282 
 1283         ng_l2cap_free_cmd(cmd);
 1284         con->rx_pkt = NULL;
 1285 
 1286         return (error);
 1287 } /* ng_l2cap_process_info_rsp */
 1288 
 1289 /*
 1290  * Send L2CAP reject
 1291  */
 1292 
 1293 static int
 1294 send_l2cap_reject(ng_l2cap_con_p con, u_int8_t ident, u_int16_t reason,
 1295                 u_int16_t mtu, u_int16_t scid, u_int16_t dcid)
 1296 {
 1297         ng_l2cap_cmd_p  cmd = NULL;
 1298 
 1299         cmd = ng_l2cap_new_cmd(con, NULL, ident, NG_L2CAP_CMD_REJ, 0);
 1300         if (cmd == NULL)
 1301                 return (ENOMEM);
 1302 
 1303          _ng_l2cap_cmd_rej(cmd->aux, cmd->ident, reason, mtu, scid, dcid);
 1304         if (cmd->aux == NULL) {
 1305                 ng_l2cap_free_cmd(cmd);
 1306 
 1307                 return (ENOBUFS);
 1308         }
 1309 
 1310         /* Link command to the queue */
 1311         ng_l2cap_link_cmd(con, cmd);
 1312         ng_l2cap_lp_deliver(con);
 1313 
 1314         return (0);
 1315 } /* send_l2cap_reject */
 1316 
 1317 /*
 1318  * Send L2CAP connection reject
 1319  */
 1320 
 1321 static int
 1322 send_l2cap_con_rej(ng_l2cap_con_p con, u_int8_t ident, u_int16_t scid,
 1323                 u_int16_t dcid, u_int16_t result)
 1324 {
 1325         ng_l2cap_cmd_p  cmd = NULL;
 1326 
 1327         cmd = ng_l2cap_new_cmd(con, NULL, ident, NG_L2CAP_CON_RSP, 0);
 1328         if (cmd == NULL)
 1329                 return (ENOMEM);
 1330 
 1331         _ng_l2cap_con_rsp(cmd->aux, cmd->ident, scid, dcid, result, 0);
 1332         if (cmd->aux == NULL) {
 1333                 ng_l2cap_free_cmd(cmd);
 1334 
 1335                 return (ENOBUFS);
 1336         }
 1337 
 1338         /* Link command to the queue */
 1339         ng_l2cap_link_cmd(con, cmd);
 1340         ng_l2cap_lp_deliver(con);
 1341 
 1342         return (0);
 1343 } /* send_l2cap_con_rej */
 1344 
 1345 /*
 1346  * Send L2CAP config response
 1347  */
 1348 
 1349 static int 
 1350 send_l2cap_cfg_rsp(ng_l2cap_con_p con, u_int8_t ident, u_int16_t scid,
 1351                 u_int16_t result, struct mbuf *opt)
 1352 {
 1353         ng_l2cap_cmd_p  cmd = NULL;
 1354 
 1355         cmd = ng_l2cap_new_cmd(con, NULL, ident, NG_L2CAP_CFG_RSP, 0);
 1356         if (cmd == NULL) {
 1357                 NG_FREE_M(opt);
 1358 
 1359                 return (ENOMEM);
 1360         }
 1361 
 1362         _ng_l2cap_cfg_rsp(cmd->aux, cmd->ident, scid, 0, result, opt);
 1363         if (cmd->aux == NULL) {
 1364                 ng_l2cap_free_cmd(cmd);
 1365 
 1366                 return (ENOBUFS);
 1367         }
 1368 
 1369         /* Link command to the queue */
 1370         ng_l2cap_link_cmd(con, cmd);
 1371         ng_l2cap_lp_deliver(con);
 1372 
 1373         return (0);
 1374 } /* send_l2cap_cfg_rsp */
 1375 
 1376 static int 
 1377 send_l2cap_param_urs(ng_l2cap_con_p con, u_int8_t ident,
 1378                      u_int16_t result)
 1379 {
 1380         ng_l2cap_cmd_p  cmd = NULL;
 1381 
 1382         cmd = ng_l2cap_new_cmd(con, NULL, ident,
 1383                                NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE,
 1384                                0);
 1385         if (cmd == NULL) {
 1386                 return (ENOMEM);
 1387         }
 1388 
 1389         _ng_l2cap_cmd_urs(cmd->aux, cmd->ident, result);
 1390         if (cmd->aux == NULL) {
 1391                 ng_l2cap_free_cmd(cmd);
 1392 
 1393                 return (ENOBUFS);
 1394         }
 1395 
 1396         /* Link command to the queue */
 1397         ng_l2cap_link_cmd(con, cmd);
 1398         ng_l2cap_lp_deliver(con);
 1399 
 1400         return (0);
 1401 } /* send_l2cap_cfg_rsp */
 1402 
 1403 /*
 1404  * Get next L2CAP configuration option
 1405  *
 1406  * Return codes:
 1407  *  0   no option
 1408  *  1   we have got option
 1409  * -1   header too short
 1410  * -2   bad option value or length
 1411  * -3   unknown option
 1412  */
 1413 
 1414 static int
 1415 get_next_l2cap_opt(struct mbuf *m, int *off, ng_l2cap_cfg_opt_p hdr,
 1416                 ng_l2cap_cfg_opt_val_p val)
 1417 {
 1418         int     hint, len = m->m_pkthdr.len - (*off);
 1419 
 1420         if (len == 0)
 1421                 return (0);
 1422         if (len < 0 || len < sizeof(*hdr))
 1423                 return (-1);
 1424 
 1425         m_copydata(m, *off, sizeof(*hdr), (caddr_t) hdr);
 1426         *off += sizeof(*hdr);
 1427         len  -= sizeof(*hdr);
 1428 
 1429         hint = NG_L2CAP_OPT_HINT(hdr->type);
 1430         hdr->type &= NG_L2CAP_OPT_HINT_MASK;
 1431 
 1432         switch (hdr->type) {
 1433         case NG_L2CAP_OPT_MTU:
 1434                 if (hdr->length != NG_L2CAP_OPT_MTU_SIZE || len < hdr->length)
 1435                         return (-2);
 1436 
 1437                 m_copydata(m, *off, NG_L2CAP_OPT_MTU_SIZE, (caddr_t) val);
 1438                 val->mtu = le16toh(val->mtu);
 1439                 *off += NG_L2CAP_OPT_MTU_SIZE;
 1440                 break;
 1441 
 1442         case NG_L2CAP_OPT_FLUSH_TIMO:
 1443                 if (hdr->length != NG_L2CAP_OPT_FLUSH_TIMO_SIZE || 
 1444                     len < hdr->length)
 1445                         return (-2);
 1446 
 1447                 m_copydata(m, *off, NG_L2CAP_OPT_FLUSH_TIMO_SIZE, (caddr_t)val);
 1448                 val->flush_timo = le16toh(val->flush_timo);
 1449                 *off += NG_L2CAP_OPT_FLUSH_TIMO_SIZE;
 1450                 break;
 1451 
 1452         case NG_L2CAP_OPT_QOS:
 1453                 if (hdr->length != NG_L2CAP_OPT_QOS_SIZE || len < hdr->length)
 1454                         return (-2);
 1455 
 1456                 m_copydata(m, *off, NG_L2CAP_OPT_QOS_SIZE, (caddr_t) val);
 1457                 val->flow.token_rate = le32toh(val->flow.token_rate);
 1458                 val->flow.token_bucket_size = 
 1459                                 le32toh(val->flow.token_bucket_size);
 1460                 val->flow.peak_bandwidth = le32toh(val->flow.peak_bandwidth);
 1461                 val->flow.latency = le32toh(val->flow.latency);
 1462                 val->flow.delay_variation = le32toh(val->flow.delay_variation);
 1463                 *off += NG_L2CAP_OPT_QOS_SIZE;
 1464                 break;
 1465 
 1466         default:
 1467                 if (hint)
 1468                         *off += hdr->length;
 1469                 else
 1470                         return (-3);
 1471                 break;
 1472         }
 1473 
 1474         return (1);
 1475 } /* get_next_l2cap_opt */

Cache object: a24c476467e8ad914dacabcdc409a1cf


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