ng_l2cap_misc.c revision 107120
1107120Sjulian/* 2107120Sjulian * ng_l2cap_misc.c 3107120Sjulian * 4107120Sjulian * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 5107120Sjulian * All rights reserved. 6107120Sjulian * 7107120Sjulian * Redistribution and use in source and binary forms, with or without 8107120Sjulian * modification, are permitted provided that the following conditions 9107120Sjulian * are met: 10107120Sjulian * 1. Redistributions of source code must retain the above copyright 11107120Sjulian * notice, this list of conditions and the following disclaimer. 12107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright 13107120Sjulian * notice, this list of conditions and the following disclaimer in the 14107120Sjulian * documentation and/or other materials provided with the distribution. 15107120Sjulian * 16107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26107120Sjulian * SUCH DAMAGE. 27107120Sjulian * 28107120Sjulian * $Id: ng_l2cap_misc.c,v 1.16 2002/09/04 21:38:38 max Exp $ 29107120Sjulian * $FreeBSD: head/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c 107120 2002-11-20 23:01:59Z julian $ 30107120Sjulian */ 31107120Sjulian 32107120Sjulian#include <sys/param.h> 33107120Sjulian#include <sys/systm.h> 34107120Sjulian#include <sys/kernel.h> 35107120Sjulian#include <sys/malloc.h> 36107120Sjulian#include <sys/mbuf.h> 37107120Sjulian#include <sys/queue.h> 38107120Sjulian#include <netgraph/ng_message.h> 39107120Sjulian#include <netgraph/netgraph.h> 40107120Sjulian#include "ng_bluetooth.h" 41107120Sjulian#include "ng_hci.h" 42107120Sjulian#include "ng_l2cap.h" 43107120Sjulian#include "ng_l2cap_var.h" 44107120Sjulian#include "ng_l2cap_cmds.h" 45107120Sjulian#include "ng_l2cap_evnt.h" 46107120Sjulian#include "ng_l2cap_llpi.h" 47107120Sjulian#include "ng_l2cap_ulpi.h" 48107120Sjulian#include "ng_l2cap_misc.h" 49107120Sjulian 50107120Sjulianstatic u_int16_t ng_l2cap_get_cid (ng_l2cap_p); 51107120Sjulianstatic void ng_l2cap_queue_lp_timeout (void *); 52107120Sjulianstatic void ng_l2cap_queue_command_timeout (void *); 53107120Sjulian 54107120Sjulian/****************************************************************************** 55107120Sjulian ****************************************************************************** 56107120Sjulian ** Utility routines 57107120Sjulian ****************************************************************************** 58107120Sjulian ******************************************************************************/ 59107120Sjulian 60107120Sjulian/* 61107120Sjulian * Send hook information to the upper layer 62107120Sjulian */ 63107120Sjulian 64107120Sjulianvoid 65107120Sjulianng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2) 66107120Sjulian{ 67107120Sjulian ng_l2cap_p l2cap = NULL; 68107120Sjulian struct ng_mesg *msg = NULL; 69107120Sjulian int error = 0; 70107120Sjulian 71107120Sjulian if (node == NULL || NG_NODE_NOT_VALID(node) || 72107120Sjulian hook == NULL || NG_HOOK_NOT_VALID(hook)) 73107120Sjulian return; 74107120Sjulian 75107120Sjulian l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node); 76107120Sjulian if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci) || 77107120Sjulian bcmp(&l2cap->bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2cap->bdaddr)) == 0) 78107120Sjulian return; 79107120Sjulian 80107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_HOOK_INFO, 81107120Sjulian sizeof(bdaddr_t), M_NOWAIT); 82107120Sjulian if (msg != NULL) { 83107120Sjulian bcopy(&l2cap->bdaddr, msg->data, sizeof(bdaddr_t)); 84107120Sjulian NG_SEND_MSG_HOOK(error, node, msg, hook, NULL); 85107120Sjulian } else 86107120Sjulian error = ENOMEM; 87107120Sjulian 88107120Sjulian if (error != 0) 89107120Sjulian NG_L2CAP_INFO( 90107120Sjulian"%s: %s - failed to send HOOK_INFO message to hook \"%s\", error=%d\n", 91107120Sjulian __func__, NG_NODE_NAME(l2cap->node), NG_HOOK_NAME(hook), 92107120Sjulian error); 93107120Sjulian} /* ng_l2cap_send_hook_info */ 94107120Sjulian 95107120Sjulian/* 96107120Sjulian * Create new connection descriptor for the "remote" unit. Will create new 97107120Sjulian * connection descriptor and signal channel. Will link both connection and 98107120Sjulian * channel to the l2cap node. 99107120Sjulian */ 100107120Sjulian 101107120Sjulianng_l2cap_con_p 102107120Sjulianng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr) 103107120Sjulian{ 104107120Sjulian ng_l2cap_con_p con = NULL; 105107120Sjulian 106107120Sjulian /* Create new connection descriptor */ 107107120Sjulian MALLOC(con, ng_l2cap_con_p, sizeof(*con), M_NETGRAPH_L2CAP, 108107120Sjulian M_NOWAIT|M_ZERO); 109107120Sjulian if (con == NULL) 110107120Sjulian return (NULL); 111107120Sjulian 112107120Sjulian con->l2cap = l2cap; 113107120Sjulian con->state = NG_L2CAP_CON_CLOSED; 114107120Sjulian 115107120Sjulian bcopy(bdaddr, &con->remote, sizeof(con->remote)); 116107120Sjulian callout_handle_init(&con->con_timo); 117107120Sjulian 118107120Sjulian con->ident = NG_L2CAP_FIRST_IDENT - 1; 119107120Sjulian TAILQ_INIT(&con->cmd_list); 120107120Sjulian 121107120Sjulian /* Link connection */ 122107120Sjulian LIST_INSERT_HEAD(&l2cap->con_list, con, next); 123107120Sjulian 124107120Sjulian return (con); 125107120Sjulian} /* ng_l2cap_new_con */ 126107120Sjulian 127107120Sjulian/* 128107120Sjulian * Free connection descriptor. Will unlink connection and free everything. 129107120Sjulian */ 130107120Sjulian 131107120Sjulianvoid 132107120Sjulianng_l2cap_free_con(ng_l2cap_con_p con) 133107120Sjulian{ 134107120Sjulian ng_l2cap_chan_p f = NULL, n = NULL; 135107120Sjulian 136107120Sjulian if (con->state == NG_L2CAP_W4_LP_CON_CFM) 137107120Sjulian ng_l2cap_lp_untimeout(con); 138107120Sjulian 139107120Sjulian if (con->tx_pkt != NULL) { 140107120Sjulian while (con->tx_pkt != NULL) { 141107120Sjulian struct mbuf *m = con->tx_pkt->m_nextpkt; 142107120Sjulian 143107120Sjulian m_freem(con->tx_pkt); 144107120Sjulian con->tx_pkt = m; 145107120Sjulian } 146107120Sjulian } 147107120Sjulian 148107120Sjulian NG_FREE_M(con->rx_pkt); 149107120Sjulian 150107120Sjulian for (f = LIST_FIRST(&con->l2cap->chan_list); f != NULL; ) { 151107120Sjulian n = LIST_NEXT(f, next); 152107120Sjulian 153107120Sjulian if (f->con == con) 154107120Sjulian ng_l2cap_free_chan(f); 155107120Sjulian 156107120Sjulian f = n; 157107120Sjulian } 158107120Sjulian 159107120Sjulian while (!TAILQ_EMPTY(&con->cmd_list)) { 160107120Sjulian ng_l2cap_cmd_p cmd = TAILQ_FIRST(&con->cmd_list); 161107120Sjulian 162107120Sjulian ng_l2cap_unlink_cmd(cmd); 163107120Sjulian ng_l2cap_free_cmd(cmd); 164107120Sjulian } 165107120Sjulian 166107120Sjulian LIST_REMOVE(con, next); 167107120Sjulian bzero(con, sizeof(*con)); 168107120Sjulian FREE(con, M_NETGRAPH_L2CAP); 169107120Sjulian} /* ng_l2cap_free_con */ 170107120Sjulian 171107120Sjulian/* 172107120Sjulian * Get connection by "remote" address 173107120Sjulian */ 174107120Sjulian 175107120Sjulianng_l2cap_con_p 176107120Sjulianng_l2cap_con_by_addr(ng_l2cap_p l2cap, bdaddr_p bdaddr) 177107120Sjulian{ 178107120Sjulian ng_l2cap_con_p con = NULL; 179107120Sjulian 180107120Sjulian LIST_FOREACH(con, &l2cap->con_list, next) 181107120Sjulian if (bcmp(bdaddr, &con->remote, sizeof(con->remote)) == 0) 182107120Sjulian break; 183107120Sjulian 184107120Sjulian return (con); 185107120Sjulian} /* ng_l2cap_con_by_addr */ 186107120Sjulian 187107120Sjulian/* 188107120Sjulian * Get connection by "handle" 189107120Sjulian */ 190107120Sjulian 191107120Sjulianng_l2cap_con_p 192107120Sjulianng_l2cap_con_by_handle(ng_l2cap_p l2cap, u_int16_t con_handle) 193107120Sjulian{ 194107120Sjulian ng_l2cap_con_p con = NULL; 195107120Sjulian 196107120Sjulian LIST_FOREACH(con, &l2cap->con_list, next) 197107120Sjulian if (con->con_handle == con_handle) 198107120Sjulian break; 199107120Sjulian 200107120Sjulian return (con); 201107120Sjulian} /* ng_l2cap_con_by_handle */ 202107120Sjulian 203107120Sjulian/* 204107120Sjulian * Allocate new L2CAP channel descriptor on "con" conection with "psm". 205107120Sjulian * Will link the channel to the l2cap node 206107120Sjulian */ 207107120Sjulian 208107120Sjulianng_l2cap_chan_p 209107120Sjulianng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm) 210107120Sjulian{ 211107120Sjulian ng_l2cap_chan_p ch = NULL; 212107120Sjulian 213107120Sjulian MALLOC(ch, ng_l2cap_chan_p, sizeof(*ch), M_NETGRAPH_L2CAP, 214107120Sjulian M_NOWAIT|M_ZERO); 215107120Sjulian if (ch == NULL) 216107120Sjulian return (NULL); 217107120Sjulian 218107120Sjulian ch->scid = ng_l2cap_get_cid(l2cap); 219107120Sjulian 220107120Sjulian if (ch->scid != NG_L2CAP_NULL_CID) { 221107120Sjulian /* Initialize channel */ 222107120Sjulian ch->psm = psm; 223107120Sjulian ch->con = con; 224107120Sjulian ch->state = NG_L2CAP_CLOSED; 225107120Sjulian 226107120Sjulian /* Set MTU and flow control settings to defaults */ 227107120Sjulian ch->imtu = NG_L2CAP_MTU_DEFAULT; 228107120Sjulian bcopy(ng_l2cap_default_flow(), &ch->iflow, sizeof(ch->iflow)); 229107120Sjulian 230107120Sjulian ch->omtu = NG_L2CAP_MTU_DEFAULT; 231107120Sjulian bcopy(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)); 232107120Sjulian 233107120Sjulian ch->flush_timo = NG_L2CAP_FLUSH_TIMO_DEFAULT; 234107120Sjulian ch->link_timo = NG_L2CAP_LINK_TIMO_DEFAULT; 235107120Sjulian 236107120Sjulian LIST_INSERT_HEAD(&l2cap->chan_list, ch, next); 237107120Sjulian } else { 238107120Sjulian bzero(ch, sizeof(*ch)); 239107120Sjulian FREE(ch, M_NETGRAPH_L2CAP); 240107120Sjulian ch = NULL; 241107120Sjulian } 242107120Sjulian 243107120Sjulian return (ch); 244107120Sjulian} /* ng_l2cap_new_chan */ 245107120Sjulian 246107120Sjulian/* 247107120Sjulian * Get channel by source (local) channel ID 248107120Sjulian */ 249107120Sjulian 250107120Sjulianng_l2cap_chan_p 251107120Sjulianng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid) 252107120Sjulian{ 253107120Sjulian ng_l2cap_chan_p ch = NULL; 254107120Sjulian 255107120Sjulian LIST_FOREACH(ch, &l2cap->chan_list, next) 256107120Sjulian if (ch->scid == scid) 257107120Sjulian break; 258107120Sjulian 259107120Sjulian return (ch); 260107120Sjulian} /* ng_l2cap_chan_by_scid */ 261107120Sjulian 262107120Sjulian/* 263107120Sjulian * Free channel descriptor. 264107120Sjulian */ 265107120Sjulian 266107120Sjulianvoid 267107120Sjulianng_l2cap_free_chan(ng_l2cap_chan_p ch) 268107120Sjulian{ 269107120Sjulian ng_l2cap_cmd_p f = NULL, n = NULL; 270107120Sjulian 271107120Sjulian f = TAILQ_FIRST(&ch->con->cmd_list); 272107120Sjulian while (f != NULL) { 273107120Sjulian n = TAILQ_NEXT(f, next); 274107120Sjulian 275107120Sjulian if (f->ch == ch) { 276107120Sjulian ng_l2cap_unlink_cmd(f); 277107120Sjulian ng_l2cap_free_cmd(f); 278107120Sjulian } 279107120Sjulian 280107120Sjulian f = n; 281107120Sjulian } 282107120Sjulian 283107120Sjulian LIST_REMOVE(ch, next); 284107120Sjulian bzero(ch, sizeof(*ch)); 285107120Sjulian FREE(ch, M_NETGRAPH_L2CAP); 286107120Sjulian} /* ng_l2cap_free_chan */ 287107120Sjulian 288107120Sjulian/* 289107120Sjulian * Create new L2CAP command descriptor. WILL NOT add command to the queue. 290107120Sjulian */ 291107120Sjulian 292107120Sjulianng_l2cap_cmd_p 293107120Sjulianng_l2cap_new_cmd(ng_l2cap_con_p con, ng_l2cap_chan_p ch, u_int8_t ident, 294107120Sjulian u_int8_t code, u_int32_t token) 295107120Sjulian{ 296107120Sjulian ng_l2cap_cmd_p cmd = NULL; 297107120Sjulian 298107120Sjulian KASSERT((ch == NULL || ch->con == con), 299107120Sjulian("%s: %s - invalid channel pointer!\n", 300107120Sjulian __func__, NG_NODE_NAME(con->l2cap->node))); 301107120Sjulian 302107120Sjulian MALLOC(cmd, ng_l2cap_cmd_p, sizeof(*cmd), M_NETGRAPH_L2CAP, 303107120Sjulian M_NOWAIT|M_ZERO); 304107120Sjulian if (cmd == NULL) 305107120Sjulian return (NULL); 306107120Sjulian 307107120Sjulian cmd->con = con; 308107120Sjulian cmd->ch = ch; 309107120Sjulian cmd->ident = ident; 310107120Sjulian cmd->code = code; 311107120Sjulian cmd->token = token; 312107120Sjulian callout_handle_init(&cmd->timo); 313107120Sjulian 314107120Sjulian return (cmd); 315107120Sjulian} /* ng_l2cap_new_cmd */ 316107120Sjulian 317107120Sjulian/* 318107120Sjulian * Get L2CAP command descriptor by ident 319107120Sjulian */ 320107120Sjulian 321107120Sjulianng_l2cap_cmd_p 322107120Sjulianng_l2cap_cmd_by_ident(ng_l2cap_con_p con, u_int8_t ident) 323107120Sjulian{ 324107120Sjulian ng_l2cap_cmd_p cmd = NULL; 325107120Sjulian 326107120Sjulian TAILQ_FOREACH(cmd, &con->cmd_list, next) 327107120Sjulian if (cmd->ident == ident) 328107120Sjulian break; 329107120Sjulian 330107120Sjulian return (cmd); 331107120Sjulian} /* ng_l2cap_cmd_by_ident */ 332107120Sjulian 333107120Sjulian/* 334107120Sjulian * Set LP timeout 335107120Sjulian */ 336107120Sjulian 337107120Sjulianvoid 338107120Sjulianng_l2cap_lp_timeout(ng_l2cap_con_p con) 339107120Sjulian{ 340107120Sjulian NG_NODE_REF(con->l2cap->node); 341107120Sjulian con->con_timo = timeout(ng_l2cap_queue_lp_timeout, con, 342107120Sjulian bluetooth_hci_connect_timeout()); 343107120Sjulian} /* ng_l2cap_lp_timeout */ 344107120Sjulian 345107120Sjulian/* 346107120Sjulian * Unset LP timeout 347107120Sjulian */ 348107120Sjulian 349107120Sjulianvoid 350107120Sjulianng_l2cap_lp_untimeout(ng_l2cap_con_p con) 351107120Sjulian{ 352107120Sjulian untimeout(ng_l2cap_queue_lp_timeout, con, con->con_timo); 353107120Sjulian NG_NODE_UNREF(con->l2cap->node); 354107120Sjulian} /* ng_l2cap_lp_untimeout */ 355107120Sjulian 356107120Sjulian/* 357107120Sjulian * OK, timeout has happend so queue LP timeout processing function 358107120Sjulian */ 359107120Sjulian 360107120Sjulianstatic void 361107120Sjulianng_l2cap_queue_lp_timeout(void *context) 362107120Sjulian{ 363107120Sjulian ng_l2cap_con_p con = (ng_l2cap_con_p) context; 364107120Sjulian node_p node = con->l2cap->node; 365107120Sjulian 366107120Sjulian /* 367107120Sjulian * We need to save node pointer here, because ng_send_fn() 368107120Sjulian * can execute ng_l2cap_process_lp_timeout() without putting 369107120Sjulian * item into node's queue (if node can be locked). Once 370107120Sjulian * ng_l2cap_process_lp_timeout() executed the con pointer 371107120Sjulian * is no longer valid. 372107120Sjulian */ 373107120Sjulian 374107120Sjulian if (NG_NODE_IS_VALID(node)) 375107120Sjulian ng_send_fn(node, NULL, &ng_l2cap_process_lp_timeout, con, 0); 376107120Sjulian 377107120Sjulian NG_NODE_UNREF(node); 378107120Sjulian} /* ng_l2cap_queue_lp_timeout */ 379107120Sjulian 380107120Sjulian/* 381107120Sjulian * Set L2CAP command timeout 382107120Sjulian */ 383107120Sjulian 384107120Sjulianvoid 385107120Sjulianng_l2cap_command_timeout(ng_l2cap_cmd_p cmd, int timo) 386107120Sjulian{ 387107120Sjulian NG_NODE_REF(cmd->con->l2cap->node); 388107120Sjulian cmd->flags |= NG_L2CAP_CMD_PENDING; 389107120Sjulian cmd->timo = timeout(ng_l2cap_queue_command_timeout, cmd, timo); 390107120Sjulian} /* ng_l2cap_command_timeout */ 391107120Sjulian 392107120Sjulian/* 393107120Sjulian * Unset L2CAP command timeout 394107120Sjulian */ 395107120Sjulian 396107120Sjulianvoid 397107120Sjulianng_l2cap_command_untimeout(ng_l2cap_cmd_p cmd) 398107120Sjulian{ 399107120Sjulian cmd->flags &= ~NG_L2CAP_CMD_PENDING; 400107120Sjulian untimeout(ng_l2cap_queue_command_timeout, cmd, cmd->timo); 401107120Sjulian NG_NODE_UNREF(cmd->con->l2cap->node); 402107120Sjulian} /* ng_l2cap_command_untimeout */ 403107120Sjulian 404107120Sjulian/* 405107120Sjulian * OK, timeout has happend so queue L2CAP command timeout processing function 406107120Sjulian */ 407107120Sjulian 408107120Sjulianstatic void 409107120Sjulianng_l2cap_queue_command_timeout(void *context) 410107120Sjulian{ 411107120Sjulian ng_l2cap_cmd_p cmd = (ng_l2cap_cmd_p) context; 412107120Sjulian node_p node = cmd->con->l2cap->node; 413107120Sjulian 414107120Sjulian /* 415107120Sjulian * We need to save node pointer here, because ng_send_fn() 416107120Sjulian * can execute ng_l2cap_process_command_timeout() without 417107120Sjulian * putting item into node's queue (if node can be locked). 418107120Sjulian * Once ng_l2cap_process_command_timeout() executed the 419107120Sjulian * cmd pointer is no longer valid. 420107120Sjulian */ 421107120Sjulian 422107120Sjulian if (NG_NODE_IS_VALID(node)) 423107120Sjulian ng_send_fn(node,NULL,&ng_l2cap_process_command_timeout,cmd,0); 424107120Sjulian 425107120Sjulian NG_NODE_UNREF(node); 426107120Sjulian} /* ng_l2cap_queue_command_timeout */ 427107120Sjulian 428107120Sjulian/* 429107120Sjulian * Prepend "m"buf with "size" bytes 430107120Sjulian */ 431107120Sjulian 432107120Sjulianstruct mbuf * 433107120Sjulianng_l2cap_prepend(struct mbuf *m, int size) 434107120Sjulian{ 435107120Sjulian M_PREPEND(m, size, M_DONTWAIT); 436107120Sjulian if (m == NULL || (m->m_len < size && (m = m_pullup(m, size)) == NULL)) 437107120Sjulian return (NULL); 438107120Sjulian 439107120Sjulian return (m); 440107120Sjulian} /* ng_l2cap_prepend */ 441107120Sjulian 442107120Sjulian/* 443107120Sjulian * Default flow settings 444107120Sjulian */ 445107120Sjulian 446107120Sjulianng_l2cap_flow_p 447107120Sjulianng_l2cap_default_flow(void) 448107120Sjulian{ 449107120Sjulian static ng_l2cap_flow_t default_flow = { 450107120Sjulian /* flags */ 0x0, 451107120Sjulian /* service_type */ NG_HCI_SERVICE_TYPE_BEST_EFFORT, 452107120Sjulian /* token_rate */ 0xffffffff, /* maximum */ 453107120Sjulian /* token_bucket_size */ 0xffffffff, /* maximum */ 454107120Sjulian /* peak_bandwidth */ 0x00000000, /* maximum */ 455107120Sjulian /* latency */ 0xffffffff, /* don't care */ 456107120Sjulian /* delay_variation */ 0xffffffff /* don't care */ 457107120Sjulian }; 458107120Sjulian 459107120Sjulian return (&default_flow); 460107120Sjulian} /* ng_l2cap_default_flow */ 461107120Sjulian 462107120Sjulian/* 463107120Sjulian * Get next available channel ID 464107120Sjulian * XXX FIXME this is *UGLY* but will do for now 465107120Sjulian */ 466107120Sjulian 467107120Sjulianstatic u_int16_t 468107120Sjulianng_l2cap_get_cid(ng_l2cap_p l2cap) 469107120Sjulian{ 470107120Sjulian u_int16_t cid = l2cap->cid + 1; 471107120Sjulian 472107120Sjulian if (cid < NG_L2CAP_FIRST_CID) 473107120Sjulian cid = NG_L2CAP_FIRST_CID; 474107120Sjulian 475107120Sjulian while (cid != l2cap->cid) { 476107120Sjulian if (ng_l2cap_chan_by_scid(l2cap, cid) == NULL) { 477107120Sjulian l2cap->cid = cid; 478107120Sjulian 479107120Sjulian return (cid); 480107120Sjulian } 481107120Sjulian 482107120Sjulian cid ++; 483107120Sjulian if (cid < NG_L2CAP_FIRST_CID) 484107120Sjulian cid = NG_L2CAP_FIRST_CID; 485107120Sjulian } 486107120Sjulian 487107120Sjulian return (NG_L2CAP_NULL_CID); 488107120Sjulian} /* ng_l2cap_get_cid */ 489107120Sjulian 490107120Sjulian/* 491107120Sjulian * Get next available command ident 492107120Sjulian * XXX FIXME this is *UGLY* but will do for now 493107120Sjulian */ 494107120Sjulian 495107120Sjulianu_int8_t 496107120Sjulianng_l2cap_get_ident(ng_l2cap_con_p con) 497107120Sjulian{ 498107120Sjulian u_int8_t ident = con->ident + 1; 499107120Sjulian 500107120Sjulian if (ident < NG_L2CAP_FIRST_IDENT) 501107120Sjulian ident = NG_L2CAP_FIRST_IDENT; 502107120Sjulian 503107120Sjulian while (ident != con->ident) { 504107120Sjulian if (ng_l2cap_cmd_by_ident(con, ident) == NULL) { 505107120Sjulian con->ident = ident; 506107120Sjulian 507107120Sjulian return (ident); 508107120Sjulian } 509107120Sjulian 510107120Sjulian ident ++; 511107120Sjulian if (ident < NG_L2CAP_FIRST_IDENT) 512107120Sjulian ident = NG_L2CAP_FIRST_IDENT; 513107120Sjulian } 514107120Sjulian 515107120Sjulian return (NG_L2CAP_NULL_IDENT); 516107120Sjulian} /* ng_l2cap_get_ident */ 517107120Sjulian 518