Deleted Added
full compact
ng_l2cap_misc.c (107120) ng_l2cap_misc.c (109623)
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 $
29 * $FreeBSD: head/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c 107120 2002-11-20 23:01:59Z julian $
29 * $FreeBSD: head/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c 109623 2003-01-21 08:56:16Z alfred $
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{
435 M_PREPEND(m, size, M_DONTWAIT);
435 M_PREPEND(m, size, M_NOWAIT);
436 if (m == NULL || (m->m_len < size && (m = m_pullup(m, size)) == NULL))
437 return (NULL);
438
439 return (m);
440} /* ng_l2cap_prepend */
441
442/*
443 * Default flow settings
444 */
445
446ng_l2cap_flow_p
447ng_l2cap_default_flow(void)
448{
449 static ng_l2cap_flow_t default_flow = {
450 /* flags */ 0x0,
451 /* service_type */ NG_HCI_SERVICE_TYPE_BEST_EFFORT,
452 /* token_rate */ 0xffffffff, /* maximum */
453 /* token_bucket_size */ 0xffffffff, /* maximum */
454 /* peak_bandwidth */ 0x00000000, /* maximum */
455 /* latency */ 0xffffffff, /* don't care */
456 /* delay_variation */ 0xffffffff /* don't care */
457 };
458
459 return (&default_flow);
460} /* ng_l2cap_default_flow */
461
462/*
463 * Get next available channel ID
464 * XXX FIXME this is *UGLY* but will do for now
465 */
466
467static u_int16_t
468ng_l2cap_get_cid(ng_l2cap_p l2cap)
469{
470 u_int16_t cid = l2cap->cid + 1;
471
472 if (cid < NG_L2CAP_FIRST_CID)
473 cid = NG_L2CAP_FIRST_CID;
474
475 while (cid != l2cap->cid) {
476 if (ng_l2cap_chan_by_scid(l2cap, cid) == NULL) {
477 l2cap->cid = cid;
478
479 return (cid);
480 }
481
482 cid ++;
483 if (cid < NG_L2CAP_FIRST_CID)
484 cid = NG_L2CAP_FIRST_CID;
485 }
486
487 return (NG_L2CAP_NULL_CID);
488} /* ng_l2cap_get_cid */
489
490/*
491 * Get next available command ident
492 * XXX FIXME this is *UGLY* but will do for now
493 */
494
495u_int8_t
496ng_l2cap_get_ident(ng_l2cap_con_p con)
497{
498 u_int8_t ident = con->ident + 1;
499
500 if (ident < NG_L2CAP_FIRST_IDENT)
501 ident = NG_L2CAP_FIRST_IDENT;
502
503 while (ident != con->ident) {
504 if (ng_l2cap_cmd_by_ident(con, ident) == NULL) {
505 con->ident = ident;
506
507 return (ident);
508 }
509
510 ident ++;
511 if (ident < NG_L2CAP_FIRST_IDENT)
512 ident = NG_L2CAP_FIRST_IDENT;
513 }
514
515 return (NG_L2CAP_NULL_IDENT);
516} /* ng_l2cap_get_ident */
517
436 if (m == NULL || (m->m_len < size && (m = m_pullup(m, size)) == NULL))
437 return (NULL);
438
439 return (m);
440} /* ng_l2cap_prepend */
441
442/*
443 * Default flow settings
444 */
445
446ng_l2cap_flow_p
447ng_l2cap_default_flow(void)
448{
449 static ng_l2cap_flow_t default_flow = {
450 /* flags */ 0x0,
451 /* service_type */ NG_HCI_SERVICE_TYPE_BEST_EFFORT,
452 /* token_rate */ 0xffffffff, /* maximum */
453 /* token_bucket_size */ 0xffffffff, /* maximum */
454 /* peak_bandwidth */ 0x00000000, /* maximum */
455 /* latency */ 0xffffffff, /* don't care */
456 /* delay_variation */ 0xffffffff /* don't care */
457 };
458
459 return (&default_flow);
460} /* ng_l2cap_default_flow */
461
462/*
463 * Get next available channel ID
464 * XXX FIXME this is *UGLY* but will do for now
465 */
466
467static u_int16_t
468ng_l2cap_get_cid(ng_l2cap_p l2cap)
469{
470 u_int16_t cid = l2cap->cid + 1;
471
472 if (cid < NG_L2CAP_FIRST_CID)
473 cid = NG_L2CAP_FIRST_CID;
474
475 while (cid != l2cap->cid) {
476 if (ng_l2cap_chan_by_scid(l2cap, cid) == NULL) {
477 l2cap->cid = cid;
478
479 return (cid);
480 }
481
482 cid ++;
483 if (cid < NG_L2CAP_FIRST_CID)
484 cid = NG_L2CAP_FIRST_CID;
485 }
486
487 return (NG_L2CAP_NULL_CID);
488} /* ng_l2cap_get_cid */
489
490/*
491 * Get next available command ident
492 * XXX FIXME this is *UGLY* but will do for now
493 */
494
495u_int8_t
496ng_l2cap_get_ident(ng_l2cap_con_p con)
497{
498 u_int8_t ident = con->ident + 1;
499
500 if (ident < NG_L2CAP_FIRST_IDENT)
501 ident = NG_L2CAP_FIRST_IDENT;
502
503 while (ident != con->ident) {
504 if (ng_l2cap_cmd_by_ident(con, ident) == NULL) {
505 con->ident = ident;
506
507 return (ident);
508 }
509
510 ident ++;
511 if (ident < NG_L2CAP_FIRST_IDENT)
512 ident = NG_L2CAP_FIRST_IDENT;
513 }
514
515 return (NG_L2CAP_NULL_IDENT);
516} /* ng_l2cap_get_ident */
517