Path: blob/main/sys/netgraph/bluetooth/l2cap/ng_l2cap_ulpi.c
34876 views
/*1* ng_l2cap_ulpi.c2*/34/*-5* SPDX-License-Identifier: BSD-2-Clause6*7* Copyright (c) Maksim Yevmenkin <[email protected]>8* All rights reserved.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions and the following disclaimer.15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18*19* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND20* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE21* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE22* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE23* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL24* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS25* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT27* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY28* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF29* SUCH DAMAGE.30*31* $Id: ng_l2cap_ulpi.c,v 1.1 2002/11/24 19:47:06 max Exp $32*/3334#include <sys/param.h>35#include <sys/systm.h>36#include <sys/kernel.h>37#include <sys/endian.h>38#include <sys/malloc.h>39#include <sys/mbuf.h>40#include <sys/queue.h>41#include <netgraph/ng_message.h>42#include <netgraph/netgraph.h>43#include <netgraph/bluetooth/include/ng_hci.h>44#include <netgraph/bluetooth/include/ng_l2cap.h>45#include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>46#include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>47#include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>48#include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>49#include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>50#include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>5152/******************************************************************************53******************************************************************************54** Upper Layer Protocol Interface module55******************************************************************************56******************************************************************************/5758/*59* Process L2CA_Connect request from the upper layer protocol.60*/6162int63ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg)64{65ng_l2cap_l2ca_con_ip *ip = NULL;66ng_l2cap_con_p con = NULL;67ng_l2cap_chan_p ch = NULL;68ng_l2cap_cmd_p cmd = NULL;69int error = 0;7071/* Check message */72if (msg->header.arglen != sizeof(*ip)) {73NG_L2CAP_ALERT(74"%s: %s - invalid L2CA_Connect request message size, size=%d\n",75__func__, NG_NODE_NAME(l2cap->node),76msg->header.arglen);77error = EMSGSIZE;78goto out;79}8081ip = (ng_l2cap_l2ca_con_ip *)(msg->data);8283/* Check if we have connection to the remote unit */84con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);85if (con == NULL) {86/* Submit LP_ConnectReq to the lower layer */87error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);88if (error != 0) {89NG_L2CAP_ERR(90"%s: %s - unable to send LP_ConnectReq message, error=%d\n",91__func__, NG_NODE_NAME(l2cap->node), error);92goto out;93}9495/* This should not fail */96con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);97KASSERT((con != NULL),98("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));99}100101/*102* Create new empty channel descriptor. In case of any failure do103* not touch connection descriptor.104*/105106ch = ng_l2cap_new_chan(l2cap, con, ip->psm, ip->idtype);107if (ch == NULL) {108error = ENOMEM;109goto out;110}111112/* Now create L2CAP_ConnectReq command */113cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(con),114NG_L2CAP_CON_REQ, msg->header.token);115if (cmd == NULL) {116ng_l2cap_free_chan(ch);117error = ENOMEM;118goto out;119}120121if (cmd->ident == NG_L2CAP_NULL_IDENT) {122ng_l2cap_free_cmd(cmd);123ng_l2cap_free_chan(ch);124error = EIO;125goto out;126}127128/* Create L2CAP command packet */129if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){130_ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_ATT_CID,131NG_L2CAP_ATT_CID, 0, 0);132cmd->aux->m_flags |= M_PROTO2;133}else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){134_ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_SMP_CID,135NG_L2CAP_SMP_CID, 0, 0);136cmd->aux->m_flags |= M_PROTO2;137}else{138_ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid);139}140if (cmd->aux == NULL) {141ng_l2cap_free_cmd(cmd);142ng_l2cap_free_chan(ch);143error = ENOBUFS;144goto out;145}146147ch->state = NG_L2CAP_W4_L2CAP_CON_RSP;148149/* Link command to the queue */150ng_l2cap_link_cmd(ch->con, cmd);151ng_l2cap_lp_deliver(ch->con);152out:153return (error);154} /* ng_l2cap_l2ca_con_req */155156/*157* Send L2CA_Connect response to the upper layer protocol.158*/159160int161ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,162u_int16_t status)163{164ng_l2cap_p l2cap = ch->con->l2cap;165struct ng_mesg *msg = NULL;166ng_l2cap_l2ca_con_op *op = NULL;167int error = 0;168169/* Check if upstream hook is connected and valid */170if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {171NG_L2CAP_ERR(172"%s: %s - unable to send L2CA_Connect response message. " \173"Hook is not connected or valid, psm=%d\n",174__func__, NG_NODE_NAME(l2cap->node), ch->psm);175176return (ENOTCONN);177}178179/* Create and send L2CA_Connect response message */180NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON,181sizeof(*op), M_NOWAIT);182if (msg == NULL)183error = ENOMEM;184else {185msg->header.token = token;186msg->header.flags |= NGF_RESP;187188op = (ng_l2cap_l2ca_con_op *)(msg->data);189190/*191* XXX Spec. says we should only populate LCID when result == 0192* What about PENDING? What the heck, for now always populate193* LCID :)194*/195if(ch->scid == NG_L2CAP_ATT_CID){196op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;197op->lcid = ch->con->con_handle;198}else if(ch->scid == NG_L2CAP_SMP_CID){199op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;200op->lcid = ch->con->con_handle;201}else{202op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?203NG_L2CAP_L2CA_IDTYPE_BREDR :204NG_L2CAP_L2CA_IDTYPE_LE;205op->lcid = ch->scid;206}207op->encryption = ch->con->encryption;208op->result = result;209op->status = status;210211NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);212}213214return (error);215} /* ng_l2cap_l2ca_con_rsp */216217/*218* Process L2CA_ConnectRsp request from the upper layer protocol.219*/220221int222ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)223{224ng_l2cap_l2ca_con_rsp_ip *ip = NULL;225ng_l2cap_con_p con = NULL;226ng_l2cap_chan_p ch = NULL;227ng_l2cap_cmd_p cmd = NULL;228u_int16_t dcid;229int error = 0;230231/* Check message */232if (msg->header.arglen != sizeof(*ip)) {233NG_L2CAP_ALERT(234"%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n",235__func__, NG_NODE_NAME(l2cap->node),236msg->header.arglen);237error = EMSGSIZE;238goto out;239}240241ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data);242243/* Check if we have this channel */244if((ip->lcid != NG_L2CAP_ATT_CID)&&245(ip->lcid != NG_L2CAP_SMP_CID)){246ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid247,(ip->linktype == NG_HCI_LINK_ACL)?248NG_L2CAP_L2CA_IDTYPE_BREDR:249NG_L2CAP_L2CA_IDTYPE_LE);250}else{251// For now not support on ATT device.252ch = NULL;253}254if (ch == NULL) {255NG_L2CAP_ALERT(256"%s: %s - unexpected L2CA_ConnectRsp request message. " \257"Channel does not exist, lcid=%d\n",258__func__, NG_NODE_NAME(l2cap->node), ip->lcid);259error = ENOENT;260goto out;261}262263/* Check channel state */264if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) {265NG_L2CAP_ERR(266"%s: %s - unexpected L2CA_ConnectRsp request message. " \267"Invalid channel state, state=%d, lcid=%d\n",268__func__, NG_NODE_NAME(l2cap->node), ch->state,269ip->lcid);270error = EINVAL;271goto out;272}273274dcid = ch->dcid;275con = ch->con;276277/*278* Now we are pretty much sure it is our response. So create and send279* L2CAP_ConnectRsp message to our peer.280*/281282if (ch->ident != ip->ident)283NG_L2CAP_WARN(284"%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \285"Will use response ident=%d\n",286__func__, NG_NODE_NAME(l2cap->node), ch->scid,287ch->ident, ip->ident);288289/* Check result */290switch (ip->result) {291case NG_L2CAP_SUCCESS:292ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||293(ch->scid == NG_L2CAP_SMP_CID))?294NG_L2CAP_OPEN : NG_L2CAP_CONFIG;295ch->cfg_state = 0;296break;297298case NG_L2CAP_PENDING:299break;300301default:302ng_l2cap_free_chan(ch);303ch = NULL;304break;305}306307/* Create L2CAP command */308cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP,309msg->header.token);310if (cmd == NULL) {311if (ch != NULL)312ng_l2cap_free_chan(ch);313314error = ENOMEM;315goto out;316}317318_ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid,319ip->result, ip->status);320if (cmd->aux == NULL) {321if (ch != NULL)322ng_l2cap_free_chan(ch);323324ng_l2cap_free_cmd(cmd);325error = ENOBUFS;326goto out;327}328329/* Link command to the queue */330ng_l2cap_link_cmd(con, cmd);331ng_l2cap_lp_deliver(con);332out:333return (error);334} /* ng_l2cap_l2ca_con_rsp_req */335336int ng_l2cap_l2ca_encryption_change(ng_l2cap_chan_p ch, uint16_t result)337{338ng_l2cap_p l2cap = ch->con->l2cap;339struct ng_mesg *msg = NULL;340ng_l2cap_l2ca_enc_chg_op *op = NULL;341int error = 0;342343/* Check if upstream hook is connected and valid */344if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {345NG_L2CAP_ERR(346"%s: %s - unable to send L2CA_ConnectRsp response message. " \347"Hook is not connected or valid, psm=%d\n",348__func__, NG_NODE_NAME(l2cap->node), ch->psm);349350return (ENOTCONN);351}352353/* Create and send L2CA_ConnectRsp response message */354NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENC_CHANGE,355sizeof(*op), M_NOWAIT);356if (msg == NULL)357error = ENOMEM;358else {359msg->header.token = 0;360msg->header.flags |= NGF_RESP;361362op = (ng_l2cap_l2ca_enc_chg_op *)(msg->data);363op->result = result;364if(ch->scid ==NG_L2CAP_ATT_CID||365ch->scid ==NG_L2CAP_SMP_CID){366op->lcid = ch->con->con_handle;367op->idtype = (ch->scid==NG_L2CAP_ATT_CID)?368NG_L2CAP_L2CA_IDTYPE_ATT:369NG_L2CAP_L2CA_IDTYPE_SMP;370}else{371op->idtype =(ch->con->linktype ==NG_HCI_LINK_ACL)?372NG_L2CAP_L2CA_IDTYPE_BREDR:373NG_L2CAP_L2CA_IDTYPE_LE;374}375376377NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);378}379380return (error);381382}383/*384* Send L2CAP_ConnectRsp response to the upper layer385*/386387int388ng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)389{390ng_l2cap_p l2cap = ch->con->l2cap;391struct ng_mesg *msg = NULL;392ng_l2cap_l2ca_con_rsp_op *op = NULL;393int error = 0;394395/* Check if upstream hook is connected and valid */396if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {397NG_L2CAP_ERR(398"%s: %s - unable to send L2CA_ConnectRsp response message. " \399"Hook is not connected or valid, psm=%d\n",400__func__, NG_NODE_NAME(l2cap->node), ch->psm);401402return (ENOTCONN);403}404405/* Create and send L2CA_ConnectRsp response message */406NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP,407sizeof(*op), M_NOWAIT);408if (msg == NULL)409error = ENOMEM;410else {411msg->header.token = token;412msg->header.flags |= NGF_RESP;413414op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data);415op->result = result;416417NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);418}419420return (error);421} /* ng_l2cap_l2ca_con_rsp_rsp */422423/*424* Send L2CA_ConnectInd message to the upper layer protocol.425*/426427int428ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch)429{430ng_l2cap_p l2cap = ch->con->l2cap;431struct ng_mesg *msg = NULL;432ng_l2cap_l2ca_con_ind_ip *ip = NULL;433int error = 0;434435/* Check if upstream hook is connected and valid */436if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {437NG_L2CAP_ERR(438"%s: %s - unable to send L2CA_ConnectInd message. " \439"Hook is not connected or valid, psm=%d\n",440__func__, NG_NODE_NAME(l2cap->node), ch->psm);441442return (ENOTCONN);443}444445/* Create and send L2CA_ConnectInd message */446NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND,447sizeof(*ip), M_NOWAIT);448if (msg == NULL)449error = ENOMEM;450else {451ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data);452453bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));454ip->lcid = ch->scid;455ip->psm = ch->psm;456ip->ident = ch->ident;457ip->linktype = ch->con->linktype;458459NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);460}461462return (error);463} /* ng_l2cap_l2ca_con_ind */464465/*466* Process L2CA_Config request from the upper layer protocol467*/468469int470ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg)471{472ng_l2cap_l2ca_cfg_ip *ip = NULL;473ng_l2cap_chan_p ch = NULL;474ng_l2cap_cmd_p cmd = NULL;475struct mbuf *opt = NULL;476u_int16_t *mtu = NULL, *flush_timo = NULL;477ng_l2cap_flow_p flow = NULL;478int error = 0;479480/* Check message */481if (msg->header.arglen != sizeof(*ip)) {482NG_L2CAP_ALERT(483"%s: %s - Invalid L2CA_Config request message size, size=%d\n",484__func__, NG_NODE_NAME(l2cap->node),485msg->header.arglen);486error = EMSGSIZE;487goto out;488}489490ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data);491492/* Check if we have this channel */493ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR);494if (ch == NULL) {495NG_L2CAP_ERR(496"%s: %s - unexpected L2CA_Config request message. " \497"Channel does not exist, lcid=%d\n",498__func__, NG_NODE_NAME(l2cap->node), ip->lcid);499error = ENOENT;500goto out;501}502503/* Check channel state */504if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) {505NG_L2CAP_ERR(506"%s: %s - unexpected L2CA_Config request message. " \507"Invalid channel state, state=%d, lcid=%d\n",508__func__, NG_NODE_NAME(l2cap->node), ch->state,509ch->scid);510error = EINVAL;511goto out;512}513514/* Set requested channel configuration options */515ch->imtu = ip->imtu;516bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow));517ch->flush_timo = ip->flush_timo;518ch->link_timo = ip->link_timo;519520/* Compare channel settings with defaults */521if (ch->imtu != NG_L2CAP_MTU_DEFAULT)522mtu = &ch->imtu;523if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT)524flush_timo = &ch->flush_timo;525if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0)526flow = &ch->oflow;527528/* Create configuration options */529_ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow);530if (opt == NULL) {531error = ENOBUFS;532goto out;533}534535/* Create L2CAP command descriptor */536cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),537NG_L2CAP_CFG_REQ, msg->header.token);538if (cmd == NULL) {539NG_FREE_M(opt);540error = ENOMEM;541goto out;542}543544if (cmd->ident == NG_L2CAP_NULL_IDENT) {545ng_l2cap_free_cmd(cmd);546NG_FREE_M(opt);547error = EIO;548goto out;549}550551/* Create L2CAP command packet */552_ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt);553if (cmd->aux == NULL) {554ng_l2cap_free_cmd(cmd);555error = ENOBUFS;556goto out;557}558559/* Adjust channel state for re-configuration */560if (ch->state == NG_L2CAP_OPEN) {561ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||562(ch->scid == NG_L2CAP_SMP_CID))?563NG_L2CAP_OPEN : NG_L2CAP_CONFIG;564ch->cfg_state = 0;565}566567/* Link command to the queue */568ng_l2cap_link_cmd(ch->con, cmd);569ng_l2cap_lp_deliver(ch->con);570out:571return (error);572} /* ng_l2cap_l2ca_cfg_req */573574/*575* Send L2CA_Config response to the upper layer protocol576*/577578int579ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)580{581ng_l2cap_p l2cap = ch->con->l2cap;582struct ng_mesg *msg = NULL;583ng_l2cap_l2ca_cfg_op *op = NULL;584int error = 0;585586/* Check if upstream hook is connected and valid */587if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {588NG_L2CAP_ERR(589"%s: %s - unable to send L2CA_Config response message. " \590"Hook is not connected or valid, psm=%d\n",591__func__, NG_NODE_NAME(l2cap->node), ch->psm);592593return (ENOTCONN);594}595596/* Create and send L2CA_Config response message */597NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG,598sizeof(*op), M_NOWAIT);599if (msg == NULL)600error = ENOMEM;601else {602msg->header.token = token;603msg->header.flags |= NGF_RESP;604605op = (ng_l2cap_l2ca_cfg_op *)(msg->data);606op->result = result;607op->imtu = ch->imtu;608bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow));609op->flush_timo = ch->flush_timo;610611NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);612613if (error == 0 && result == NG_L2CAP_SUCCESS) {614ch->cfg_state |= NG_L2CAP_CFG_IN;615616if (ch->cfg_state == NG_L2CAP_CFG_BOTH)617ch->state = NG_L2CAP_OPEN;618}619}620621return (error);622} /* ng_l2cap_l2ca_cfg_rsp */623624/*625* Process L2CA_ConfigRsp request from the upper layer protocol626*627* XXX XXX XXX628*629* NOTE: The Bluetooth specification says that Configuration_Response630* (L2CA_ConfigRsp) should be used to issue response to configuration request631* indication. The minor problem here is L2CAP command ident. We should use632* ident from original L2CAP request to make sure our peer can match request633* and response. For some reason Bluetooth specification does not include634* ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems635* strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident636* field. So we should store last known L2CAP request command ident in channel.637* Also it seems that upper layer can not reject configuration request, as638* Configuration_Response message does not have status/reason field.639*/640641int642ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)643{644ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL;645ng_l2cap_chan_p ch = NULL;646ng_l2cap_cmd_p cmd = NULL;647struct mbuf *opt = NULL;648u_int16_t *mtu = NULL;649ng_l2cap_flow_p flow = NULL;650int error = 0;651652/* Check message */653if (msg->header.arglen != sizeof(*ip)) {654NG_L2CAP_ALERT(655"%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n",656__func__, NG_NODE_NAME(l2cap->node),657msg->header.arglen);658error = EMSGSIZE;659goto out;660}661662ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data);663664/* Check if we have this channel */665ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid,666NG_L2CAP_L2CA_IDTYPE_BREDR);667if (ch == NULL) {668NG_L2CAP_ERR(669"%s: %s - unexpected L2CA_ConfigRsp request message. " \670"Channel does not exist, lcid=%d\n",671__func__, NG_NODE_NAME(l2cap->node), ip->lcid);672error = ENOENT;673goto out;674}675676/* Check channel state */677if (ch->state != NG_L2CAP_CONFIG) {678NG_L2CAP_ERR(679"%s: %s - unexpected L2CA_ConfigRsp request message. " \680"Invalid channel state, state=%d, lcid=%d\n",681__func__, NG_NODE_NAME(l2cap->node), ch->state,682ch->scid);683error = EINVAL;684goto out;685}686687/* Set channel settings */688if (ip->omtu != ch->omtu) {689ch->omtu = ip->omtu;690mtu = &ch->omtu;691}692693if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) {694bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow));695flow = &ch->iflow;696}697698if (mtu != NULL || flow != NULL) {699_ng_l2cap_build_cfg_options(opt, mtu, NULL, flow);700if (opt == NULL) {701error = ENOBUFS;702goto out;703}704}705706/* Create L2CAP command */707cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP,708msg->header.token);709if (cmd == NULL) {710NG_FREE_M(opt);711error = ENOMEM;712goto out;713}714715_ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt);716if (cmd->aux == NULL) {717ng_l2cap_free_cmd(cmd);718error = ENOBUFS;719goto out;720}721722/* XXX FIXME - not here ??? */723ch->cfg_state |= NG_L2CAP_CFG_OUT;724if (ch->cfg_state == NG_L2CAP_CFG_BOTH)725ch->state = NG_L2CAP_OPEN;726727/* Link command to the queue */728ng_l2cap_link_cmd(ch->con, cmd);729ng_l2cap_lp_deliver(ch->con);730out:731return (error);732} /* ng_l2cap_l2ca_cfg_rsp_req */733734/*735* Send L2CA_ConfigRsp response to the upper layer protocol736*/737738int739ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)740{741ng_l2cap_p l2cap = ch->con->l2cap;742struct ng_mesg *msg = NULL;743ng_l2cap_l2ca_cfg_rsp_op *op = NULL;744int error = 0;745746/* Check if upstream hook is connected and valid */747if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {748NG_L2CAP_ERR(749"%s: %s - unable to send L2CA_ConfigRsp response message. " \750"Hook is not connected or valid, psm=%d\n",751__func__, NG_NODE_NAME(l2cap->node), ch->psm);752753return (ENOTCONN);754}755756/* Create and send L2CA_ConfigRsp response message */757NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP,758sizeof(*op), M_NOWAIT);759if (msg == NULL)760error = ENOMEM;761else {762msg->header.token = token;763msg->header.flags |= NGF_RESP;764765op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data);766op->result = result;767768NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);769}770771return (error);772} /* ng_l2cap_l2ca_cfg_rsp_rsp */773774/*775* Send L2CA_ConfigInd message to the upper layer protocol776*777* XXX XXX XXX778*779* NOTE: The Bluetooth specification says that Configuration_Response780* (L2CA_ConfigRsp) should be used to issue response to configuration request781* indication. The minor problem here is L2CAP command ident. We should use782* ident from original L2CAP request to make sure our peer can match request783* and response. For some reason Bluetooth specification does not include784* ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems785* strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident786* field. So we should store last known L2CAP request command ident in channel.787* Also it seems that upper layer can not reject configuration request, as788* Configuration_Response message does not have status/reason field.789*/790791int792ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch)793{794ng_l2cap_p l2cap = ch->con->l2cap;795struct ng_mesg *msg = NULL;796ng_l2cap_l2ca_cfg_ind_ip *ip = NULL;797int error = 0;798799/* Check if upstream hook is connected and valid */800if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {801NG_L2CAP_ERR(802"%s: %s - Unable to send L2CA_ConfigInd message. " \803"Hook is not connected or valid, psm=%d\n",804__func__, NG_NODE_NAME(l2cap->node), ch->psm);805806return (ENOTCONN);807}808809/* Create and send L2CA_ConnectInd message */810NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND,811sizeof(*ip), M_NOWAIT);812if (msg == NULL)813error = ENOMEM;814else {815ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data);816ip->lcid = ch->scid;817ip->omtu = ch->omtu;818bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow));819ip->flush_timo = ch->flush_timo;820821NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);822}823824return (error);825} /* ng_l2cap_l2ca_cfg_ind */826827/*828* Process L2CA_Write event829*/830831int832ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m)833{834ng_l2cap_l2ca_hdr_t *l2ca_hdr = NULL;835ng_l2cap_chan_p ch = NULL;836ng_l2cap_cmd_p cmd = NULL;837int error = 0;838u_int32_t token = 0;839840/* Make sure we can access L2CA data packet header */841if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) {842NG_L2CAP_ERR(843"%s: %s - L2CA Data packet too small, len=%d\n",844__func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len);845error = EMSGSIZE;846goto drop;847}848849/* Get L2CA data packet header */850NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr));851if (m == NULL)852return (ENOBUFS);853854l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *);855token = l2ca_hdr->token;856m_adj(m, sizeof(*l2ca_hdr));857858/* Verify payload size */859if (l2ca_hdr->length != m->m_pkthdr.len) {860NG_L2CAP_ERR(861"%s: %s - invalid L2CA Data packet. " \862"Payload length does not match, length=%d, len=%d\n",863__func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length,864m->m_pkthdr.len);865error = EMSGSIZE;866goto drop;867}868869/* Check channel ID */870if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){871ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,872l2ca_hdr->lcid);873} else if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){874ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,875l2ca_hdr->lcid);876}else{877if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) {878NG_L2CAP_ERR(879"%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n",880__func__, NG_NODE_NAME(l2cap->node),881l2ca_hdr->lcid);882error = EINVAL;883goto drop;884}885886/* Verify that we have the channel and make sure it is open */887ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid,888l2ca_hdr->idtype);889}890891if (ch == NULL) {892NG_L2CAP_ERR(893"%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n",894__func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid);895error = ENOENT;896goto drop;897}898899if (ch->state != NG_L2CAP_OPEN) {900NG_L2CAP_ERR(901"%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n",902__func__, NG_NODE_NAME(l2cap->node), ch->scid,903ch->state);904error = EHOSTDOWN;905goto drop; /* XXX not always - re-configure */906}907908/* Create L2CAP command descriptor */909cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token);910if (cmd == NULL) {911error = ENOMEM;912goto drop;913}914915/* Attach data packet and link command to the queue */916cmd->aux = m;917ng_l2cap_link_cmd(ch->con, cmd);918ng_l2cap_lp_deliver(ch->con);919920return (error);921drop:922NG_FREE_M(m);923924return (error);925} /* ng_l2cap_l2ca_write_req */926927/*928* Send L2CA_Write response929*/930931int932ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,933u_int16_t length)934{935ng_l2cap_p l2cap = ch->con->l2cap;936struct ng_mesg *msg = NULL;937ng_l2cap_l2ca_write_op *op = NULL;938int error = 0;939940/* Check if upstream hook is connected and valid */941if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {942NG_L2CAP_ERR(943"%s: %s - unable to send L2CA_WriteRsp message. " \944"Hook is not connected or valid, psm=%d\n",945__func__, NG_NODE_NAME(l2cap->node), ch->psm);946947return (ENOTCONN);948}949950/* Create and send L2CA_WriteRsp message */951NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE,952sizeof(*op), M_NOWAIT);953if (msg == NULL)954error = ENOMEM;955else {956msg->header.token = token;957msg->header.flags |= NGF_RESP;958959op = (ng_l2cap_l2ca_write_op *)(msg->data);960op->result = result;961op->length = length;962if(ch->scid == NG_L2CAP_ATT_CID){963op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;964op->lcid = ch->con->con_handle;965}else if(ch->scid == NG_L2CAP_SMP_CID){966op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;967op->lcid = ch->con->con_handle;968}else{969op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?970NG_L2CAP_L2CA_IDTYPE_BREDR :971NG_L2CAP_L2CA_IDTYPE_LE;972op->lcid = ch->scid;973974}975NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);976}977978return (error);979} /* ng_l2cap_l2ca_write_rsp */980981/*982* Receive packet from the lower layer protocol and send it to the upper983* layer protocol (L2CAP_Read)984*/985986int987ng_l2cap_l2ca_receive(ng_l2cap_con_p con)988{989ng_l2cap_p l2cap = con->l2cap;990ng_l2cap_hdr_t *hdr = NULL;991ng_l2cap_chan_p ch = NULL;992int error = 0;993int idtype;994uint16_t *idp;995int silent = 0;996997NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));998if (con->rx_pkt == NULL)999return (ENOBUFS);10001001hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *);10021003/* Check channel */10041005if(hdr->dcid == NG_L2CAP_ATT_CID){1006idtype = NG_L2CAP_L2CA_IDTYPE_ATT;1007ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,1008con->con_handle);1009/*1010* Here,ATT channel is distinguished by1011* connection handle1012*/1013hdr->dcid = con->con_handle;1014silent = 1;1015}else if(hdr->dcid == NG_L2CAP_SMP_CID){1016idtype = NG_L2CAP_L2CA_IDTYPE_SMP;1017ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,1018con->con_handle);1019/*1020* Here,SMP channel is distinguished by1021* connection handle1022*/1023silent = 1;1024hdr->dcid = con->con_handle;1025}else{1026idtype = (con->linktype==NG_HCI_LINK_ACL)?1027NG_L2CAP_L2CA_IDTYPE_BREDR:1028NG_L2CAP_L2CA_IDTYPE_LE;1029ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid, idtype);1030}1031if (ch == NULL) {1032if(!silent)1033NG_L2CAP_ERR(1034"%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d, idtype=%d\n",1035__func__, NG_NODE_NAME(l2cap->node), hdr->dcid, idtype);1036error = ENOENT;1037goto drop;1038}10391040/* Check channel state */1041if (ch->state != NG_L2CAP_OPEN) {1042NG_L2CAP_WARN(1043"%s: %s - unexpected L2CAP data packet. " \1044"Invalid channel state, cid=%d, state=%d\n",1045__func__, NG_NODE_NAME(l2cap->node), ch->scid,1046ch->state);1047error = EHOSTDOWN; /* XXX not always - re-configuration */1048goto drop;1049}10501051/* Check payload size and channel's MTU */1052if (hdr->length > ch->imtu) {1053NG_L2CAP_ERR(1054"%s: %s - invalid L2CAP data packet. " \1055"Packet too big, length=%d, imtu=%d, cid=%d\n",1056__func__, NG_NODE_NAME(l2cap->node), hdr->length,1057ch->imtu, ch->scid);1058error = EMSGSIZE;1059goto drop;1060}10611062/*1063* If we got here then everything looks good and we can sent packet1064* to the upper layer protocol.1065*/10661067/* Check if upstream hook is connected and valid */1068if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {1069NG_L2CAP_ERR(1070"%s: %s - unable to send L2CAP data packet. " \1071"Hook is not connected or valid, psm=%d\n",1072__func__, NG_NODE_NAME(l2cap->node), ch->psm);1073error = ENOTCONN;1074goto drop;1075}1076M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT);1077if(con->rx_pkt == NULL)1078goto drop;1079idp = mtod(con->rx_pkt, uint16_t *);1080*idp = idtype;10811082NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);1083con->rx_pkt = NULL;1084drop:1085NG_FREE_M(con->rx_pkt); /* checks for != NULL */10861087return (error);1088} /* ng_l2cap_receive */10891090/*1091* Receive connectioless (multicast) packet from the lower layer protocol and1092* send it to the upper layer protocol1093*/10941095int1096ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con)1097{1098struct _clt_pkt {1099ng_l2cap_hdr_t h;1100ng_l2cap_clt_hdr_t c_h;1101} __attribute__ ((packed)) *hdr = NULL;1102ng_l2cap_p l2cap = con->l2cap;1103int length, error = 0;11041105NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));1106if (con->rx_pkt == NULL)1107return (ENOBUFS);11081109hdr = mtod(con->rx_pkt, struct _clt_pkt *);11101111/* Check packet */1112length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr);1113if (length < 0) {1114NG_L2CAP_ERR(1115"%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n",1116__func__, NG_NODE_NAME(l2cap->node), length);1117error = EMSGSIZE;1118goto drop;1119}11201121/* Check payload size against CLT MTU */1122if (length > NG_L2CAP_MTU_DEFAULT) {1123NG_L2CAP_ERR(1124"%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n",1125__func__, NG_NODE_NAME(l2cap->node), length,1126NG_L2CAP_MTU_DEFAULT);1127error = EMSGSIZE;1128goto drop;1129}11301131hdr->c_h.psm = le16toh(hdr->c_h.psm);11321133/*1134* If we got here then everything looks good and we can sent packet1135* to the upper layer protocol.1136*/11371138/* Select upstream hook based on PSM */1139switch (hdr->c_h.psm) {1140case NG_L2CAP_PSM_SDP:1141if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED)1142goto drop;1143break;11441145case NG_L2CAP_PSM_RFCOMM:1146if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED)1147goto drop;1148break;11491150case NG_L2CAP_PSM_TCP:1151if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED)1152goto drop;1153break;1154}11551156/* Check if upstream hook is connected and valid */1157if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {1158NG_L2CAP_ERR(1159"%s: %s - unable to send L2CAP CLT data packet. " \1160"Hook is not connected or valid, psm=%d\n",1161__func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm);1162error = ENOTCONN;1163goto drop;1164}11651166NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);1167con->rx_pkt = NULL;1168drop:1169NG_FREE_M(con->rx_pkt); /* checks for != NULL */11701171return (error);1172} /* ng_l2cap_l2ca_clt_receive */11731174/*1175* Send L2CA_QoSViolationInd to the upper layer protocol1176*/11771178int1179ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch)1180{1181ng_l2cap_p l2cap = ch->con->l2cap;1182struct ng_mesg *msg = NULL;1183ng_l2cap_l2ca_qos_ind_ip *ip = NULL;1184int error = 0;11851186/* Check if upstream hook is connected and valid */1187if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {1188NG_L2CAP_ERR(1189"%s: %s - unable to send L2CA_QoSViolationInd message. " \1190"Hook is not connected or valid, psm=%d\n",1191__func__, NG_NODE_NAME(l2cap->node), ch->psm);11921193return (ENOTCONN);1194}11951196/* Create and send L2CA_QoSViolationInd message */1197NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND,1198sizeof(*ip), M_NOWAIT);1199if (msg == NULL)1200error = ENOMEM;1201else {1202ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data);1203bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));1204NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);1205}12061207return (error);1208} /* ng_l2cap_l2ca_qos_ind */12091210/*1211* Process L2CA_Disconnect request from the upper layer protocol.1212*/12131214int1215ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg)1216{1217ng_l2cap_l2ca_discon_ip *ip = NULL;1218ng_l2cap_chan_p ch = NULL;1219ng_l2cap_cmd_p cmd = NULL;1220int error = 0;12211222/* Check message */1223if (msg->header.arglen != sizeof(*ip)) {1224NG_L2CAP_ALERT(1225"%s: %s - invalid L2CA_Disconnect request message size, size=%d\n",1226__func__, NG_NODE_NAME(l2cap->node),1227msg->header.arglen);1228error = EMSGSIZE;1229goto out;1230}12311232ip = (ng_l2cap_l2ca_discon_ip *)(msg->data);12331234if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){1235/* Don't send Disconnect request on L2CAP Layer*/1236ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,1237ip->lcid);12381239if(ch != NULL){1240ng_l2cap_free_chan(ch);1241}else{1242NG_L2CAP_ERR(1243"%s: %s - unexpected L2CA_Disconnect request message. " \1244"Channel does not exist, conhandle=%d\n",1245__func__, NG_NODE_NAME(l2cap->node), ip->lcid);1246error = EINVAL;1247}1248goto out;1249}else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){1250/* Don't send Disconnect request on L2CAP Layer*/1251ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,1252ip->lcid);12531254if(ch != NULL){1255ng_l2cap_free_chan(ch);1256}else{1257NG_L2CAP_ERR(1258"%s: %s - unexpected L2CA_Disconnect request message. " \1259"Channel does not exist, conhandle=%d\n",1260__func__, NG_NODE_NAME(l2cap->node), ip->lcid);1261error = EINVAL;1262}1263goto out;1264}else{1265/* Check if we have this channel */1266ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype);1267}1268if (ch == NULL) {1269NG_L2CAP_ERR(1270"%s: %s - unexpected L2CA_Disconnect request message. " \1271"Channel does not exist, lcid=%d\n",1272__func__, NG_NODE_NAME(l2cap->node), ip->lcid);1273error = ENOENT;1274goto out;1275}12761277/* Check channel state */1278if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN &&1279ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) {1280NG_L2CAP_ERR(1281"%s: %s - unexpected L2CA_Disconnect request message. " \1282"Invalid channel state, state=%d, lcid=%d\n",1283__func__, NG_NODE_NAME(l2cap->node), ch->state,1284ch->scid);1285error = EINVAL;1286goto out;1287}12881289/* Create and send L2CAP_DisconReq message */1290cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),1291NG_L2CAP_DISCON_REQ, msg->header.token);1292if (cmd == NULL) {1293ng_l2cap_free_chan(ch);1294error = ENOMEM;1295goto out;1296}12971298if (cmd->ident == NG_L2CAP_NULL_IDENT) {1299ng_l2cap_free_chan(ch);1300ng_l2cap_free_cmd(cmd);1301error = EIO;1302goto out;1303}13041305_ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid);1306if (cmd->aux == NULL) {1307ng_l2cap_free_chan(ch);1308ng_l2cap_free_cmd(cmd);1309error = ENOBUFS;1310goto out;1311}13121313ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP;13141315/* Link command to the queue */1316ng_l2cap_link_cmd(ch->con, cmd);1317ng_l2cap_lp_deliver(ch->con);1318out:1319return (error);1320} /* ng_l2cap_l2ca_discon_req */13211322/*1323* Send L2CA_Disconnect response to the upper layer protocol1324*/13251326int1327ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)1328{1329ng_l2cap_p l2cap = ch->con->l2cap;1330struct ng_mesg *msg = NULL;1331ng_l2cap_l2ca_discon_op *op = NULL;1332int error = 0;13331334/* Check if upstream hook is connected and valid */1335if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {1336NG_L2CAP_ERR(1337"%s: %s - unable to send L2CA_Disconnect response message. " \1338"Hook is not connected or valid, psm=%d\n",1339__func__, NG_NODE_NAME(l2cap->node), ch->psm);13401341return (ENOTCONN);1342}13431344/* Create and send L2CA_Disconnect response message */1345NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON,1346sizeof(*op), M_NOWAIT);1347if (msg == NULL)1348error = ENOMEM;1349else {1350msg->header.token = token;1351msg->header.flags |= NGF_RESP;13521353op = (ng_l2cap_l2ca_discon_op *)(msg->data);1354op->result = result;13551356NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);1357}13581359return (error);1360} /* ng_l2cap_l2ca_discon_rsp */13611362/*1363* Send L2CA_DisconnectInd message to the upper layer protocol.1364*/13651366int1367ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch)1368{1369ng_l2cap_p l2cap = ch->con->l2cap;1370struct ng_mesg *msg = NULL;1371ng_l2cap_l2ca_discon_ind_ip *ip = NULL;1372int error = 0;13731374/* Check if upstream hook is connected and valid */1375if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {1376NG_L2CAP_ERR(1377"%s: %s - unable to send L2CA_DisconnectInd message. " \1378"Hook is not connected or valid, psm=%d\n",1379__func__, NG_NODE_NAME(l2cap->node), ch->psm);13801381return (ENOTCONN);1382}13831384/* Create and send L2CA_DisconnectInd message */1385NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND,1386sizeof(*ip), M_NOWAIT);1387if (msg == NULL)1388error = ENOMEM;1389else {1390ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data);1391ip->idtype = ch->idtype;1392if(ch->idtype == NG_L2CAP_L2CA_IDTYPE_ATT||1393ch->idtype == NG_L2CAP_L2CA_IDTYPE_SMP)1394ip->lcid = ch->con->con_handle;1395else1396ip->lcid = ch->scid;13971398NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);1399}14001401return (error);1402} /* ng_l2cap_l2ca_discon_ind */14031404/*1405* Process L2CA_GroupCreate request from the upper layer protocol.1406* XXX FIXME1407*/14081409int1410ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg)1411{1412return (ENOTSUP);1413} /* ng_l2cap_l2ca_grp_create */14141415/*1416* Process L2CA_GroupClose request from the upper layer protocol1417* XXX FIXME1418*/14191420int1421ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg)1422{1423return (ENOTSUP);1424} /* ng_l2cap_l2ca_grp_close */14251426/*1427* Process L2CA_GroupAddMember request from the upper layer protocol.1428* XXX FIXME1429*/14301431int1432ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg)1433{1434return (ENOTSUP);1435} /* ng_l2cap_l2ca_grp_add_member_req */14361437/*1438* Send L2CA_GroupAddMember response to the upper layer protocol.1439* XXX FIXME1440*/14411442int1443ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token,1444u_int16_t result)1445{1446return (0);1447} /* ng_l2cap_l2ca_grp_add_member_rsp */14481449/*1450* Process L2CA_GroupDeleteMember request from the upper layer protocol1451* XXX FIXME1452*/14531454int1455ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg)1456{1457return (ENOTSUP);1458} /* ng_l2cap_l2ca_grp_rem_member */14591460/*1461* Process L2CA_GroupGetMembers request from the upper layer protocol1462* XXX FIXME1463*/14641465int1466ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg)1467{1468return (ENOTSUP);1469} /* ng_l2cap_l2ca_grp_get_members */14701471/*1472* Process L2CA_Ping request from the upper layer protocol1473*/14741475int1476ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg)1477{1478ng_l2cap_l2ca_ping_ip *ip = NULL;1479ng_l2cap_con_p con = NULL;1480ng_l2cap_cmd_p cmd = NULL;1481int error = 0;14821483/* Verify message */1484if (msg->header.arglen < sizeof(*ip)) {1485NG_L2CAP_ALERT(1486"%s: %s - invalid L2CA_Ping request message size, size=%d\n",1487__func__, NG_NODE_NAME(l2cap->node),1488msg->header.arglen);1489error = EMSGSIZE;1490goto out;1491}14921493ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);1494if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {1495NG_L2CAP_WARN(1496"%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n",1497__func__, NG_NODE_NAME(l2cap->node), ip->echo_size);1498error = EMSGSIZE;1499goto out;1500}15011502/* Check if we have connection to the unit */1503con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);1504if (con == NULL) {1505/* Submit LP_ConnectReq to the lower layer */1506error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);1507if (error != 0) {1508NG_L2CAP_ERR(1509"%s: %s - unable to send LP_ConnectReq message, error=%d\n",1510__func__, NG_NODE_NAME(l2cap->node), error);1511goto out;1512}15131514/* This should not fail */1515con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);1516KASSERT((con != NULL),1517("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));1518}15191520/* Create L2CAP command descriptor */1521cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),1522NG_L2CAP_ECHO_REQ, msg->header.token);1523if (cmd == NULL) {1524error = ENOMEM;1525goto out;1526}15271528if (cmd->ident == NG_L2CAP_NULL_IDENT) {1529ng_l2cap_free_cmd(cmd);1530error = EIO;1531goto out;1532}15331534/* Create L2CAP command packet */1535_ng_l2cap_echo_req(cmd->aux, cmd->ident,1536msg->data + sizeof(*ip), ip->echo_size);1537if (cmd->aux == NULL) {1538ng_l2cap_free_cmd(cmd);1539error = ENOBUFS;1540goto out;1541}15421543/* Link command to the queue */1544ng_l2cap_link_cmd(con, cmd);1545ng_l2cap_lp_deliver(con);1546out:1547return (error);1548} /* ng_l2cap_l2ca_ping_req */15491550/*1551* Send L2CA_Ping response to the upper layer protocol1552*/15531554int1555ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result,1556struct mbuf *data)1557{1558ng_l2cap_p l2cap = con->l2cap;1559struct ng_mesg *msg = NULL;1560ng_l2cap_l2ca_ping_op *op = NULL;1561int error = 0, size = 0;15621563/* Check if control hook is connected and valid */1564if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {1565NG_L2CAP_WARN(1566"%s: %s - unable to send L2CA_Ping response message. " \1567"Hook is not connected or valid\n",1568__func__, NG_NODE_NAME(l2cap->node));1569error = ENOTCONN;1570goto out;1571}15721573size = (data == NULL)? 0 : data->m_pkthdr.len;15741575/* Create and send L2CA_Ping response message */1576NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING,1577sizeof(*op) + size, M_NOWAIT);1578if (msg == NULL)1579error = ENOMEM;1580else {1581msg->header.token = token;1582msg->header.flags |= NGF_RESP;15831584op = (ng_l2cap_l2ca_ping_op *)(msg->data);1585op->result = result;1586bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr));1587if (data != NULL && size > 0) {1588op->echo_size = size;1589m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));1590}15911592NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);1593}1594out:1595NG_FREE_M(data);15961597return (error);1598} /* ng_l2cap_l2ca_ping_rsp */15991600/*1601* Process L2CA_GetInfo request from the upper layer protocol1602*/16031604int1605ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg)1606{1607ng_l2cap_l2ca_get_info_ip *ip = NULL;1608ng_l2cap_con_p con = NULL;1609ng_l2cap_cmd_p cmd = NULL;1610int error = 0;16111612/* Verify message */1613if (msg->header.arglen != sizeof(*ip)) {1614NG_L2CAP_ALERT(1615"%s: %s - invalid L2CA_GetInfo request message size, size=%d\n",1616__func__, NG_NODE_NAME(l2cap->node),1617msg->header.arglen);1618error = EMSGSIZE;1619goto out;1620}16211622ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);16231624/* Check if we have connection to the unit */1625con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype);1626if (con == NULL) {1627/* Submit LP_ConnectReq to the lower layer */1628error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);1629if (error != 0) {1630NG_L2CAP_ERR(1631"%s: %s - unable to send LP_ConnectReq message, error=%d\n",1632__func__, NG_NODE_NAME(l2cap->node), error);1633goto out;1634}16351636/* This should not fail */1637con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);1638KASSERT((con != NULL),1639("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));1640}16411642/* Create L2CAP command descriptor */1643cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),1644NG_L2CAP_INFO_REQ, msg->header.token);1645if (cmd == NULL) {1646error = ENOMEM;1647goto out;1648}16491650if (cmd->ident == NG_L2CAP_NULL_IDENT) {1651ng_l2cap_free_cmd(cmd);1652error = EIO;1653goto out;1654}16551656/* Create L2CAP command packet */1657_ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type);1658if (cmd->aux == NULL) {1659ng_l2cap_free_cmd(cmd);1660error = ENOBUFS;1661goto out;1662}16631664/* Link command to the queue */1665ng_l2cap_link_cmd(con, cmd);1666ng_l2cap_lp_deliver(con);1667out:1668return (error);1669} /* ng_l2cap_l2ca_get_info_req */16701671/*1672* Send L2CA_GetInfo response to the upper layer protocol1673*/16741675int1676ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token,1677u_int16_t result, struct mbuf *data)1678{1679ng_l2cap_p l2cap = con->l2cap;1680struct ng_mesg *msg = NULL;1681ng_l2cap_l2ca_get_info_op *op = NULL;1682int error = 0, size;16831684/* Check if control hook is connected and valid */1685if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {1686NG_L2CAP_WARN(1687"%s: %s - unable to send L2CA_GetInfo response message. " \1688"Hook is not connected or valid\n",1689__func__, NG_NODE_NAME(l2cap->node));1690error = ENOTCONN;1691goto out;1692}16931694size = (data == NULL)? 0 : data->m_pkthdr.len;16951696/* Create and send L2CA_GetInfo response message */1697NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO,1698sizeof(*op) + size, M_NOWAIT);1699if (msg == NULL)1700error = ENOMEM;1701else {1702msg->header.token = token;1703msg->header.flags |= NGF_RESP;17041705op = (ng_l2cap_l2ca_get_info_op *)(msg->data);1706op->result = result;1707if (data != NULL && size > 0) {1708op->info_size = size;1709m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));1710}17111712NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);1713}1714out:1715NG_FREE_M(data);17161717return (error);1718} /* ng_l2cap_l2ca_get_info_rsp */17191720/*1721* Process L2CA_EnableCLT message from the upper layer protocol1722* XXX convert to NGN_L2CAP_NODE_SET_FLAGS?1723*/17241725int1726ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg)1727{1728ng_l2cap_l2ca_enable_clt_ip *ip = NULL;1729int error = 0;1730#if 01731* ng_l2cap_l2ca_enable_clt_op *op = NULL;1732* u_int16_t result;1733* u_int32_t token;1734#endif17351736/* Check message */1737if (msg->header.arglen != sizeof(*ip)) {1738NG_L2CAP_ALERT(1739"%s: %s - invalid L2CA_EnableCLT message size, size=%d\n",1740__func__, NG_NODE_NAME(l2cap->node),1741msg->header.arglen);17421743return (EMSGSIZE);1744}17451746/* Process request */1747ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data);1748#if 01749* result = NG_L2CAP_SUCCESS;1750#endif17511752switch (ip->psm)1753{1754case 0:1755/* Special case: disable/enable all PSM */1756if (ip->enable)1757l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED |1758NG_L2CAP_CLT_RFCOMM_DISABLED |1759NG_L2CAP_CLT_TCP_DISABLED);1760else1761l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED |1762NG_L2CAP_CLT_RFCOMM_DISABLED |1763NG_L2CAP_CLT_TCP_DISABLED);1764break;17651766case NG_L2CAP_PSM_SDP:1767if (ip->enable)1768l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED;1769else1770l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED;1771break;17721773case NG_L2CAP_PSM_RFCOMM:1774if (ip->enable)1775l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED;1776else1777l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED;1778break;17791780case NG_L2CAP_PSM_TCP:1781if (ip->enable)1782l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED;1783else1784l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED;1785break;17861787default:1788NG_L2CAP_ERR(1789"%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm);1790#if 01791* result = NG_L2CAP_PSM_NOT_SUPPORTED;1792#endif1793error = ENOTSUP;1794break;1795}17961797#if 01798* /* Create and send response message */1799* token = msg->header.token;1800* NG_FREE_MSG(msg);1801* NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT,1802* sizeof(*op), M_NOWAIT);1803* if (msg == NULL)1804* error = ENOMEM;1805* else {1806* msg->header.token = token;1807* msg->header.flags |= NGF_RESP;1808*1809* op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data);1810* op->result = result;1811* }1812*1813* /* Send response to control hook */1814* if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl))1815* NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);1816#endif18171818return (error);1819} /* ng_l2cap_l2ca_enable_clt */182018211822