1/* 2 * ng_l2cap_misc.c 3 * 4 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: ng_l2cap_misc.c,v 1.16 2002/09/04 21:38:38 max Exp $
| 1/* 2 * ng_l2cap_misc.c 3 * 4 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: ng_l2cap_misc.c,v 1.16 2002/09/04 21:38:38 max Exp $
|
30 */ 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/kernel.h> 35#include <sys/malloc.h> 36#include <sys/mbuf.h> 37#include <sys/queue.h> 38#include <netgraph/ng_message.h> 39#include <netgraph/netgraph.h> 40#include "ng_bluetooth.h" 41#include "ng_hci.h" 42#include "ng_l2cap.h" 43#include "ng_l2cap_var.h" 44#include "ng_l2cap_cmds.h" 45#include "ng_l2cap_evnt.h" 46#include "ng_l2cap_llpi.h" 47#include "ng_l2cap_ulpi.h" 48#include "ng_l2cap_misc.h" 49 50static u_int16_t ng_l2cap_get_cid (ng_l2cap_p); 51static void ng_l2cap_queue_lp_timeout (void *); 52static void ng_l2cap_queue_command_timeout (void *); 53 54/****************************************************************************** 55 ****************************************************************************** 56 ** Utility routines 57 ****************************************************************************** 58 ******************************************************************************/ 59 60/* 61 * Send hook information to the upper layer 62 */ 63 64void 65ng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2) 66{ 67 ng_l2cap_p l2cap = NULL; 68 struct ng_mesg *msg = NULL; 69 int error = 0; 70 71 if (node == NULL || NG_NODE_NOT_VALID(node) || 72 hook == NULL || NG_HOOK_NOT_VALID(hook)) 73 return; 74 75 l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node); 76 if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci) || 77 bcmp(&l2cap->bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2cap->bdaddr)) == 0) 78 return; 79 80 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_HOOK_INFO, 81 sizeof(bdaddr_t), M_NOWAIT); 82 if (msg != NULL) { 83 bcopy(&l2cap->bdaddr, msg->data, sizeof(bdaddr_t)); 84 NG_SEND_MSG_HOOK(error, node, msg, hook, NULL); 85 } else 86 error = ENOMEM; 87 88 if (error != 0) 89 NG_L2CAP_INFO( 90"%s: %s - failed to send HOOK_INFO message to hook \"%s\", error=%d\n", 91 __func__, NG_NODE_NAME(l2cap->node), NG_HOOK_NAME(hook), 92 error); 93} /* ng_l2cap_send_hook_info */ 94 95/* 96 * Create new connection descriptor for the "remote" unit. Will create new 97 * connection descriptor and signal channel. Will link both connection and 98 * channel to the l2cap node. 99 */ 100 101ng_l2cap_con_p 102ng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr) 103{ 104 ng_l2cap_con_p con = NULL; 105 106 /* Create new connection descriptor */ 107 MALLOC(con, ng_l2cap_con_p, sizeof(*con), M_NETGRAPH_L2CAP, 108 M_NOWAIT|M_ZERO); 109 if (con == NULL) 110 return (NULL); 111 112 con->l2cap = l2cap; 113 con->state = NG_L2CAP_CON_CLOSED; 114 115 bcopy(bdaddr, &con->remote, sizeof(con->remote)); 116 callout_handle_init(&con->con_timo); 117 118 con->ident = NG_L2CAP_FIRST_IDENT - 1; 119 TAILQ_INIT(&con->cmd_list); 120 121 /* Link connection */ 122 LIST_INSERT_HEAD(&l2cap->con_list, con, next); 123 124 return (con); 125} /* ng_l2cap_new_con */ 126 127/* 128 * Free connection descriptor. Will unlink connection and free everything. 129 */ 130 131void 132ng_l2cap_free_con(ng_l2cap_con_p con) 133{ 134 ng_l2cap_chan_p f = NULL, n = NULL; 135 136 if (con->state == NG_L2CAP_W4_LP_CON_CFM) 137 ng_l2cap_lp_untimeout(con); 138 139 if (con->tx_pkt != NULL) { 140 while (con->tx_pkt != NULL) { 141 struct mbuf *m = con->tx_pkt->m_nextpkt; 142 143 m_freem(con->tx_pkt); 144 con->tx_pkt = m; 145 } 146 } 147 148 NG_FREE_M(con->rx_pkt); 149 150 for (f = LIST_FIRST(&con->l2cap->chan_list); f != NULL; ) { 151 n = LIST_NEXT(f, next); 152 153 if (f->con == con) 154 ng_l2cap_free_chan(f); 155 156 f = n; 157 } 158 159 while (!TAILQ_EMPTY(&con->cmd_list)) { 160 ng_l2cap_cmd_p cmd = TAILQ_FIRST(&con->cmd_list); 161 162 ng_l2cap_unlink_cmd(cmd); 163 ng_l2cap_free_cmd(cmd); 164 } 165 166 LIST_REMOVE(con, next); 167 bzero(con, sizeof(*con)); 168 FREE(con, M_NETGRAPH_L2CAP); 169} /* ng_l2cap_free_con */ 170 171/* 172 * Get connection by "remote" address 173 */ 174 175ng_l2cap_con_p 176ng_l2cap_con_by_addr(ng_l2cap_p l2cap, bdaddr_p bdaddr) 177{ 178 ng_l2cap_con_p con = NULL; 179 180 LIST_FOREACH(con, &l2cap->con_list, next) 181 if (bcmp(bdaddr, &con->remote, sizeof(con->remote)) == 0) 182 break; 183 184 return (con); 185} /* ng_l2cap_con_by_addr */ 186 187/* 188 * Get connection by "handle" 189 */ 190 191ng_l2cap_con_p 192ng_l2cap_con_by_handle(ng_l2cap_p l2cap, u_int16_t con_handle) 193{ 194 ng_l2cap_con_p con = NULL; 195 196 LIST_FOREACH(con, &l2cap->con_list, next) 197 if (con->con_handle == con_handle) 198 break; 199 200 return (con); 201} /* ng_l2cap_con_by_handle */ 202 203/* 204 * Allocate new L2CAP channel descriptor on "con" conection with "psm". 205 * Will link the channel to the l2cap node 206 */ 207 208ng_l2cap_chan_p 209ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm) 210{ 211 ng_l2cap_chan_p ch = NULL; 212 213 MALLOC(ch, ng_l2cap_chan_p, sizeof(*ch), M_NETGRAPH_L2CAP, 214 M_NOWAIT|M_ZERO); 215 if (ch == NULL) 216 return (NULL); 217 218 ch->scid = ng_l2cap_get_cid(l2cap); 219 220 if (ch->scid != NG_L2CAP_NULL_CID) { 221 /* Initialize channel */ 222 ch->psm = psm; 223 ch->con = con; 224 ch->state = NG_L2CAP_CLOSED; 225 226 /* Set MTU and flow control settings to defaults */ 227 ch->imtu = NG_L2CAP_MTU_DEFAULT; 228 bcopy(ng_l2cap_default_flow(), &ch->iflow, sizeof(ch->iflow)); 229 230 ch->omtu = NG_L2CAP_MTU_DEFAULT; 231 bcopy(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)); 232 233 ch->flush_timo = NG_L2CAP_FLUSH_TIMO_DEFAULT; 234 ch->link_timo = NG_L2CAP_LINK_TIMO_DEFAULT; 235 236 LIST_INSERT_HEAD(&l2cap->chan_list, ch, next); 237 } else { 238 bzero(ch, sizeof(*ch)); 239 FREE(ch, M_NETGRAPH_L2CAP); 240 ch = NULL; 241 } 242 243 return (ch); 244} /* ng_l2cap_new_chan */ 245 246/* 247 * Get channel by source (local) channel ID 248 */ 249 250ng_l2cap_chan_p 251ng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid) 252{ 253 ng_l2cap_chan_p ch = NULL; 254 255 LIST_FOREACH(ch, &l2cap->chan_list, next) 256 if (ch->scid == scid) 257 break; 258 259 return (ch); 260} /* ng_l2cap_chan_by_scid */ 261 262/* 263 * Free channel descriptor. 264 */ 265 266void 267ng_l2cap_free_chan(ng_l2cap_chan_p ch) 268{ 269 ng_l2cap_cmd_p f = NULL, n = NULL; 270 271 f = TAILQ_FIRST(&ch->con->cmd_list); 272 while (f != NULL) { 273 n = TAILQ_NEXT(f, next); 274 275 if (f->ch == ch) { 276 ng_l2cap_unlink_cmd(f); 277 ng_l2cap_free_cmd(f); 278 } 279 280 f = n; 281 } 282 283 LIST_REMOVE(ch, next); 284 bzero(ch, sizeof(*ch)); 285 FREE(ch, M_NETGRAPH_L2CAP); 286} /* ng_l2cap_free_chan */ 287 288/* 289 * Create new L2CAP command descriptor. WILL NOT add command to the queue. 290 */ 291 292ng_l2cap_cmd_p 293ng_l2cap_new_cmd(ng_l2cap_con_p con, ng_l2cap_chan_p ch, u_int8_t ident, 294 u_int8_t code, u_int32_t token) 295{ 296 ng_l2cap_cmd_p cmd = NULL; 297 298 KASSERT((ch == NULL || ch->con == con), 299("%s: %s - invalid channel pointer!\n", 300 __func__, NG_NODE_NAME(con->l2cap->node))); 301 302 MALLOC(cmd, ng_l2cap_cmd_p, sizeof(*cmd), M_NETGRAPH_L2CAP, 303 M_NOWAIT|M_ZERO); 304 if (cmd == NULL) 305 return (NULL); 306 307 cmd->con = con; 308 cmd->ch = ch; 309 cmd->ident = ident; 310 cmd->code = code; 311 cmd->token = token; 312 callout_handle_init(&cmd->timo); 313 314 return (cmd); 315} /* ng_l2cap_new_cmd */ 316 317/* 318 * Get L2CAP command descriptor by ident 319 */ 320 321ng_l2cap_cmd_p 322ng_l2cap_cmd_by_ident(ng_l2cap_con_p con, u_int8_t ident) 323{ 324 ng_l2cap_cmd_p cmd = NULL; 325 326 TAILQ_FOREACH(cmd, &con->cmd_list, next) 327 if (cmd->ident == ident) 328 break; 329 330 return (cmd); 331} /* ng_l2cap_cmd_by_ident */ 332 333/* 334 * Set LP timeout 335 */ 336 337void 338ng_l2cap_lp_timeout(ng_l2cap_con_p con) 339{ 340 NG_NODE_REF(con->l2cap->node); 341 con->con_timo = timeout(ng_l2cap_queue_lp_timeout, con, 342 bluetooth_hci_connect_timeout()); 343} /* ng_l2cap_lp_timeout */ 344 345/* 346 * Unset LP timeout 347 */ 348 349void 350ng_l2cap_lp_untimeout(ng_l2cap_con_p con) 351{ 352 untimeout(ng_l2cap_queue_lp_timeout, con, con->con_timo); 353 NG_NODE_UNREF(con->l2cap->node); 354} /* ng_l2cap_lp_untimeout */ 355 356/* 357 * OK, timeout has happend so queue LP timeout processing function 358 */ 359 360static void 361ng_l2cap_queue_lp_timeout(void *context) 362{ 363 ng_l2cap_con_p con = (ng_l2cap_con_p) context; 364 node_p node = con->l2cap->node; 365 366 /* 367 * We need to save node pointer here, because ng_send_fn() 368 * can execute ng_l2cap_process_lp_timeout() without putting 369 * item into node's queue (if node can be locked). Once 370 * ng_l2cap_process_lp_timeout() executed the con pointer 371 * is no longer valid. 372 */ 373 374 if (NG_NODE_IS_VALID(node)) 375 ng_send_fn(node, NULL, &ng_l2cap_process_lp_timeout, con, 0); 376 377 NG_NODE_UNREF(node); 378} /* ng_l2cap_queue_lp_timeout */ 379 380/* 381 * Set L2CAP command timeout 382 */ 383 384void 385ng_l2cap_command_timeout(ng_l2cap_cmd_p cmd, int timo) 386{ 387 NG_NODE_REF(cmd->con->l2cap->node); 388 cmd->flags |= NG_L2CAP_CMD_PENDING; 389 cmd->timo = timeout(ng_l2cap_queue_command_timeout, cmd, timo); 390} /* ng_l2cap_command_timeout */ 391 392/* 393 * Unset L2CAP command timeout 394 */ 395 396void 397ng_l2cap_command_untimeout(ng_l2cap_cmd_p cmd) 398{ 399 cmd->flags &= ~NG_L2CAP_CMD_PENDING; 400 untimeout(ng_l2cap_queue_command_timeout, cmd, cmd->timo); 401 NG_NODE_UNREF(cmd->con->l2cap->node); 402} /* ng_l2cap_command_untimeout */ 403 404/* 405 * OK, timeout has happend so queue L2CAP command timeout processing function 406 */ 407 408static void 409ng_l2cap_queue_command_timeout(void *context) 410{ 411 ng_l2cap_cmd_p cmd = (ng_l2cap_cmd_p) context; 412 node_p node = cmd->con->l2cap->node; 413 414 /* 415 * We need to save node pointer here, because ng_send_fn() 416 * can execute ng_l2cap_process_command_timeout() without 417 * putting item into node's queue (if node can be locked). 418 * Once ng_l2cap_process_command_timeout() executed the 419 * cmd pointer is no longer valid. 420 */ 421 422 if (NG_NODE_IS_VALID(node)) 423 ng_send_fn(node,NULL,&ng_l2cap_process_command_timeout,cmd,0); 424 425 NG_NODE_UNREF(node); 426} /* ng_l2cap_queue_command_timeout */ 427 428/* 429 * Prepend "m"buf with "size" bytes 430 */ 431 432struct mbuf * 433ng_l2cap_prepend(struct mbuf *m, int size) 434{
| 30 */ 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/kernel.h> 35#include <sys/malloc.h> 36#include <sys/mbuf.h> 37#include <sys/queue.h> 38#include <netgraph/ng_message.h> 39#include <netgraph/netgraph.h> 40#include "ng_bluetooth.h" 41#include "ng_hci.h" 42#include "ng_l2cap.h" 43#include "ng_l2cap_var.h" 44#include "ng_l2cap_cmds.h" 45#include "ng_l2cap_evnt.h" 46#include "ng_l2cap_llpi.h" 47#include "ng_l2cap_ulpi.h" 48#include "ng_l2cap_misc.h" 49 50static u_int16_t ng_l2cap_get_cid (ng_l2cap_p); 51static void ng_l2cap_queue_lp_timeout (void *); 52static void ng_l2cap_queue_command_timeout (void *); 53 54/****************************************************************************** 55 ****************************************************************************** 56 ** Utility routines 57 ****************************************************************************** 58 ******************************************************************************/ 59 60/* 61 * Send hook information to the upper layer 62 */ 63 64void 65ng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2) 66{ 67 ng_l2cap_p l2cap = NULL; 68 struct ng_mesg *msg = NULL; 69 int error = 0; 70 71 if (node == NULL || NG_NODE_NOT_VALID(node) || 72 hook == NULL || NG_HOOK_NOT_VALID(hook)) 73 return; 74 75 l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node); 76 if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci) || 77 bcmp(&l2cap->bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2cap->bdaddr)) == 0) 78 return; 79 80 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_HOOK_INFO, 81 sizeof(bdaddr_t), M_NOWAIT); 82 if (msg != NULL) { 83 bcopy(&l2cap->bdaddr, msg->data, sizeof(bdaddr_t)); 84 NG_SEND_MSG_HOOK(error, node, msg, hook, NULL); 85 } else 86 error = ENOMEM; 87 88 if (error != 0) 89 NG_L2CAP_INFO( 90"%s: %s - failed to send HOOK_INFO message to hook \"%s\", error=%d\n", 91 __func__, NG_NODE_NAME(l2cap->node), NG_HOOK_NAME(hook), 92 error); 93} /* ng_l2cap_send_hook_info */ 94 95/* 96 * Create new connection descriptor for the "remote" unit. Will create new 97 * connection descriptor and signal channel. Will link both connection and 98 * channel to the l2cap node. 99 */ 100 101ng_l2cap_con_p 102ng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr) 103{ 104 ng_l2cap_con_p con = NULL; 105 106 /* Create new connection descriptor */ 107 MALLOC(con, ng_l2cap_con_p, sizeof(*con), M_NETGRAPH_L2CAP, 108 M_NOWAIT|M_ZERO); 109 if (con == NULL) 110 return (NULL); 111 112 con->l2cap = l2cap; 113 con->state = NG_L2CAP_CON_CLOSED; 114 115 bcopy(bdaddr, &con->remote, sizeof(con->remote)); 116 callout_handle_init(&con->con_timo); 117 118 con->ident = NG_L2CAP_FIRST_IDENT - 1; 119 TAILQ_INIT(&con->cmd_list); 120 121 /* Link connection */ 122 LIST_INSERT_HEAD(&l2cap->con_list, con, next); 123 124 return (con); 125} /* ng_l2cap_new_con */ 126 127/* 128 * Free connection descriptor. Will unlink connection and free everything. 129 */ 130 131void 132ng_l2cap_free_con(ng_l2cap_con_p con) 133{ 134 ng_l2cap_chan_p f = NULL, n = NULL; 135 136 if (con->state == NG_L2CAP_W4_LP_CON_CFM) 137 ng_l2cap_lp_untimeout(con); 138 139 if (con->tx_pkt != NULL) { 140 while (con->tx_pkt != NULL) { 141 struct mbuf *m = con->tx_pkt->m_nextpkt; 142 143 m_freem(con->tx_pkt); 144 con->tx_pkt = m; 145 } 146 } 147 148 NG_FREE_M(con->rx_pkt); 149 150 for (f = LIST_FIRST(&con->l2cap->chan_list); f != NULL; ) { 151 n = LIST_NEXT(f, next); 152 153 if (f->con == con) 154 ng_l2cap_free_chan(f); 155 156 f = n; 157 } 158 159 while (!TAILQ_EMPTY(&con->cmd_list)) { 160 ng_l2cap_cmd_p cmd = TAILQ_FIRST(&con->cmd_list); 161 162 ng_l2cap_unlink_cmd(cmd); 163 ng_l2cap_free_cmd(cmd); 164 } 165 166 LIST_REMOVE(con, next); 167 bzero(con, sizeof(*con)); 168 FREE(con, M_NETGRAPH_L2CAP); 169} /* ng_l2cap_free_con */ 170 171/* 172 * Get connection by "remote" address 173 */ 174 175ng_l2cap_con_p 176ng_l2cap_con_by_addr(ng_l2cap_p l2cap, bdaddr_p bdaddr) 177{ 178 ng_l2cap_con_p con = NULL; 179 180 LIST_FOREACH(con, &l2cap->con_list, next) 181 if (bcmp(bdaddr, &con->remote, sizeof(con->remote)) == 0) 182 break; 183 184 return (con); 185} /* ng_l2cap_con_by_addr */ 186 187/* 188 * Get connection by "handle" 189 */ 190 191ng_l2cap_con_p 192ng_l2cap_con_by_handle(ng_l2cap_p l2cap, u_int16_t con_handle) 193{ 194 ng_l2cap_con_p con = NULL; 195 196 LIST_FOREACH(con, &l2cap->con_list, next) 197 if (con->con_handle == con_handle) 198 break; 199 200 return (con); 201} /* ng_l2cap_con_by_handle */ 202 203/* 204 * Allocate new L2CAP channel descriptor on "con" conection with "psm". 205 * Will link the channel to the l2cap node 206 */ 207 208ng_l2cap_chan_p 209ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm) 210{ 211 ng_l2cap_chan_p ch = NULL; 212 213 MALLOC(ch, ng_l2cap_chan_p, sizeof(*ch), M_NETGRAPH_L2CAP, 214 M_NOWAIT|M_ZERO); 215 if (ch == NULL) 216 return (NULL); 217 218 ch->scid = ng_l2cap_get_cid(l2cap); 219 220 if (ch->scid != NG_L2CAP_NULL_CID) { 221 /* Initialize channel */ 222 ch->psm = psm; 223 ch->con = con; 224 ch->state = NG_L2CAP_CLOSED; 225 226 /* Set MTU and flow control settings to defaults */ 227 ch->imtu = NG_L2CAP_MTU_DEFAULT; 228 bcopy(ng_l2cap_default_flow(), &ch->iflow, sizeof(ch->iflow)); 229 230 ch->omtu = NG_L2CAP_MTU_DEFAULT; 231 bcopy(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)); 232 233 ch->flush_timo = NG_L2CAP_FLUSH_TIMO_DEFAULT; 234 ch->link_timo = NG_L2CAP_LINK_TIMO_DEFAULT; 235 236 LIST_INSERT_HEAD(&l2cap->chan_list, ch, next); 237 } else { 238 bzero(ch, sizeof(*ch)); 239 FREE(ch, M_NETGRAPH_L2CAP); 240 ch = NULL; 241 } 242 243 return (ch); 244} /* ng_l2cap_new_chan */ 245 246/* 247 * Get channel by source (local) channel ID 248 */ 249 250ng_l2cap_chan_p 251ng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid) 252{ 253 ng_l2cap_chan_p ch = NULL; 254 255 LIST_FOREACH(ch, &l2cap->chan_list, next) 256 if (ch->scid == scid) 257 break; 258 259 return (ch); 260} /* ng_l2cap_chan_by_scid */ 261 262/* 263 * Free channel descriptor. 264 */ 265 266void 267ng_l2cap_free_chan(ng_l2cap_chan_p ch) 268{ 269 ng_l2cap_cmd_p f = NULL, n = NULL; 270 271 f = TAILQ_FIRST(&ch->con->cmd_list); 272 while (f != NULL) { 273 n = TAILQ_NEXT(f, next); 274 275 if (f->ch == ch) { 276 ng_l2cap_unlink_cmd(f); 277 ng_l2cap_free_cmd(f); 278 } 279 280 f = n; 281 } 282 283 LIST_REMOVE(ch, next); 284 bzero(ch, sizeof(*ch)); 285 FREE(ch, M_NETGRAPH_L2CAP); 286} /* ng_l2cap_free_chan */ 287 288/* 289 * Create new L2CAP command descriptor. WILL NOT add command to the queue. 290 */ 291 292ng_l2cap_cmd_p 293ng_l2cap_new_cmd(ng_l2cap_con_p con, ng_l2cap_chan_p ch, u_int8_t ident, 294 u_int8_t code, u_int32_t token) 295{ 296 ng_l2cap_cmd_p cmd = NULL; 297 298 KASSERT((ch == NULL || ch->con == con), 299("%s: %s - invalid channel pointer!\n", 300 __func__, NG_NODE_NAME(con->l2cap->node))); 301 302 MALLOC(cmd, ng_l2cap_cmd_p, sizeof(*cmd), M_NETGRAPH_L2CAP, 303 M_NOWAIT|M_ZERO); 304 if (cmd == NULL) 305 return (NULL); 306 307 cmd->con = con; 308 cmd->ch = ch; 309 cmd->ident = ident; 310 cmd->code = code; 311 cmd->token = token; 312 callout_handle_init(&cmd->timo); 313 314 return (cmd); 315} /* ng_l2cap_new_cmd */ 316 317/* 318 * Get L2CAP command descriptor by ident 319 */ 320 321ng_l2cap_cmd_p 322ng_l2cap_cmd_by_ident(ng_l2cap_con_p con, u_int8_t ident) 323{ 324 ng_l2cap_cmd_p cmd = NULL; 325 326 TAILQ_FOREACH(cmd, &con->cmd_list, next) 327 if (cmd->ident == ident) 328 break; 329 330 return (cmd); 331} /* ng_l2cap_cmd_by_ident */ 332 333/* 334 * Set LP timeout 335 */ 336 337void 338ng_l2cap_lp_timeout(ng_l2cap_con_p con) 339{ 340 NG_NODE_REF(con->l2cap->node); 341 con->con_timo = timeout(ng_l2cap_queue_lp_timeout, con, 342 bluetooth_hci_connect_timeout()); 343} /* ng_l2cap_lp_timeout */ 344 345/* 346 * Unset LP timeout 347 */ 348 349void 350ng_l2cap_lp_untimeout(ng_l2cap_con_p con) 351{ 352 untimeout(ng_l2cap_queue_lp_timeout, con, con->con_timo); 353 NG_NODE_UNREF(con->l2cap->node); 354} /* ng_l2cap_lp_untimeout */ 355 356/* 357 * OK, timeout has happend so queue LP timeout processing function 358 */ 359 360static void 361ng_l2cap_queue_lp_timeout(void *context) 362{ 363 ng_l2cap_con_p con = (ng_l2cap_con_p) context; 364 node_p node = con->l2cap->node; 365 366 /* 367 * We need to save node pointer here, because ng_send_fn() 368 * can execute ng_l2cap_process_lp_timeout() without putting 369 * item into node's queue (if node can be locked). Once 370 * ng_l2cap_process_lp_timeout() executed the con pointer 371 * is no longer valid. 372 */ 373 374 if (NG_NODE_IS_VALID(node)) 375 ng_send_fn(node, NULL, &ng_l2cap_process_lp_timeout, con, 0); 376 377 NG_NODE_UNREF(node); 378} /* ng_l2cap_queue_lp_timeout */ 379 380/* 381 * Set L2CAP command timeout 382 */ 383 384void 385ng_l2cap_command_timeout(ng_l2cap_cmd_p cmd, int timo) 386{ 387 NG_NODE_REF(cmd->con->l2cap->node); 388 cmd->flags |= NG_L2CAP_CMD_PENDING; 389 cmd->timo = timeout(ng_l2cap_queue_command_timeout, cmd, timo); 390} /* ng_l2cap_command_timeout */ 391 392/* 393 * Unset L2CAP command timeout 394 */ 395 396void 397ng_l2cap_command_untimeout(ng_l2cap_cmd_p cmd) 398{ 399 cmd->flags &= ~NG_L2CAP_CMD_PENDING; 400 untimeout(ng_l2cap_queue_command_timeout, cmd, cmd->timo); 401 NG_NODE_UNREF(cmd->con->l2cap->node); 402} /* ng_l2cap_command_untimeout */ 403 404/* 405 * OK, timeout has happend so queue L2CAP command timeout processing function 406 */ 407 408static void 409ng_l2cap_queue_command_timeout(void *context) 410{ 411 ng_l2cap_cmd_p cmd = (ng_l2cap_cmd_p) context; 412 node_p node = cmd->con->l2cap->node; 413 414 /* 415 * We need to save node pointer here, because ng_send_fn() 416 * can execute ng_l2cap_process_command_timeout() without 417 * putting item into node's queue (if node can be locked). 418 * Once ng_l2cap_process_command_timeout() executed the 419 * cmd pointer is no longer valid. 420 */ 421 422 if (NG_NODE_IS_VALID(node)) 423 ng_send_fn(node,NULL,&ng_l2cap_process_command_timeout,cmd,0); 424 425 NG_NODE_UNREF(node); 426} /* ng_l2cap_queue_command_timeout */ 427 428/* 429 * Prepend "m"buf with "size" bytes 430 */ 431 432struct mbuf * 433ng_l2cap_prepend(struct mbuf *m, int size) 434{
|