Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.c
34814 views
1
/*
2
* ng_l2cap_cmds.c
3
*/
4
5
/*-
6
* SPDX-License-Identifier: BSD-2-Clause
7
*
8
* Copyright (c) Maksim Yevmenkin <[email protected]>
9
* All rights reserved.
10
*
11
* Redistribution and use in source and binary forms, with or without
12
* modification, are permitted provided that the following conditions
13
* are met:
14
* 1. Redistributions of source code must retain the above copyright
15
* notice, this list of conditions and the following disclaimer.
16
* 2. Redistributions in binary form must reproduce the above copyright
17
* notice, this list of conditions and the following disclaimer in the
18
* documentation and/or other materials provided with the distribution.
19
*
20
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
* SUCH DAMAGE.
31
*
32
* $Id: ng_l2cap_cmds.c,v 1.2 2003/09/08 19:11:45 max Exp $
33
*/
34
35
#include <sys/param.h>
36
#include <sys/systm.h>
37
#include <sys/kernel.h>
38
#include <sys/endian.h>
39
#include <sys/malloc.h>
40
#include <sys/mbuf.h>
41
#include <sys/queue.h>
42
#include <netgraph/ng_message.h>
43
#include <netgraph/netgraph.h>
44
#include <netgraph/bluetooth/include/ng_bluetooth.h>
45
#include <netgraph/bluetooth/include/ng_hci.h>
46
#include <netgraph/bluetooth/include/ng_l2cap.h>
47
#include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
48
#include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
49
#include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
50
#include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
51
#include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
52
#include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
53
54
/******************************************************************************
55
******************************************************************************
56
** L2CAP commands processing module
57
******************************************************************************
58
******************************************************************************/
59
60
/*
61
* Process L2CAP command queue on connection
62
*/
63
64
void
65
ng_l2cap_con_wakeup(ng_l2cap_con_p con)
66
{
67
ng_l2cap_cmd_p cmd = NULL;
68
struct mbuf *m = NULL;
69
int error = 0;
70
71
/* Find first non-pending command in the queue */
72
TAILQ_FOREACH(cmd, &con->cmd_list, next) {
73
KASSERT((cmd->con == con),
74
("%s: %s - invalid connection pointer!\n",
75
__func__, NG_NODE_NAME(con->l2cap->node)));
76
77
if (!(cmd->flags & NG_L2CAP_CMD_PENDING))
78
break;
79
}
80
81
if (cmd == NULL)
82
return;
83
84
/* Detach command packet */
85
m = cmd->aux;
86
cmd->aux = NULL;
87
88
/* Process command */
89
switch (cmd->code) {
90
case NG_L2CAP_DISCON_RSP:
91
case NG_L2CAP_ECHO_RSP:
92
case NG_L2CAP_INFO_RSP:
93
/*
94
* Do not check return ng_l2cap_lp_send() value, because
95
* in these cases we do not really have a graceful way out.
96
* ECHO and INFO responses are internal to the stack and not
97
* visible to user. REJect is just being nice to remote end
98
* (otherwise remote end will timeout anyway). DISCON is
99
* probably most interesting here, however, if it fails
100
* there is nothing we can do anyway.
101
*/
102
103
(void) ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
104
ng_l2cap_unlink_cmd(cmd);
105
ng_l2cap_free_cmd(cmd);
106
break;
107
case NG_L2CAP_CMD_REJ:
108
(void) ng_l2cap_lp_send(con,
109
(con->linktype == NG_HCI_LINK_ACL)?
110
NG_L2CAP_SIGNAL_CID:
111
NG_L2CAP_LESIGNAL_CID
112
, m);
113
ng_l2cap_unlink_cmd(cmd);
114
ng_l2cap_free_cmd(cmd);
115
break;
116
117
case NG_L2CAP_CON_REQ:
118
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
119
if (error != 0) {
120
ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token,
121
NG_L2CAP_NO_RESOURCES, 0);
122
ng_l2cap_free_chan(cmd->ch); /* will free commands */
123
} else
124
ng_l2cap_command_timeout(cmd,
125
bluetooth_l2cap_rtx_timeout());
126
break;
127
case NG_L2CAP_CON_RSP:
128
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
129
ng_l2cap_unlink_cmd(cmd);
130
if (cmd->ch != NULL) {
131
ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
132
(error == 0)? NG_L2CAP_SUCCESS :
133
NG_L2CAP_NO_RESOURCES);
134
if (error != 0)
135
ng_l2cap_free_chan(cmd->ch);
136
}
137
ng_l2cap_free_cmd(cmd);
138
break;
139
140
case NG_L2CAP_CFG_REQ:
141
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
142
if (error != 0) {
143
ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token,
144
NG_L2CAP_NO_RESOURCES);
145
ng_l2cap_unlink_cmd(cmd);
146
ng_l2cap_free_cmd(cmd);
147
} else
148
ng_l2cap_command_timeout(cmd,
149
bluetooth_l2cap_rtx_timeout());
150
break;
151
152
case NG_L2CAP_CFG_RSP:
153
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
154
ng_l2cap_unlink_cmd(cmd);
155
if (cmd->ch != NULL)
156
ng_l2cap_l2ca_cfg_rsp_rsp(cmd->ch, cmd->token,
157
(error == 0)? NG_L2CAP_SUCCESS :
158
NG_L2CAP_NO_RESOURCES);
159
ng_l2cap_free_cmd(cmd);
160
break;
161
162
case NG_L2CAP_DISCON_REQ:
163
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
164
ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
165
(error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES);
166
if (error != 0)
167
ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
168
else
169
ng_l2cap_command_timeout(cmd,
170
bluetooth_l2cap_rtx_timeout());
171
break;
172
173
case NG_L2CAP_ECHO_REQ:
174
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
175
if (error != 0) {
176
ng_l2cap_l2ca_ping_rsp(con, cmd->token,
177
NG_L2CAP_NO_RESOURCES, NULL);
178
ng_l2cap_unlink_cmd(cmd);
179
ng_l2cap_free_cmd(cmd);
180
} else
181
ng_l2cap_command_timeout(cmd,
182
bluetooth_l2cap_rtx_timeout());
183
break;
184
185
case NG_L2CAP_INFO_REQ:
186
error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
187
if (error != 0) {
188
ng_l2cap_l2ca_get_info_rsp(con, cmd->token,
189
NG_L2CAP_NO_RESOURCES, NULL);
190
ng_l2cap_unlink_cmd(cmd);
191
ng_l2cap_free_cmd(cmd);
192
} else
193
ng_l2cap_command_timeout(cmd,
194
bluetooth_l2cap_rtx_timeout());
195
break;
196
197
case NGM_L2CAP_L2CA_WRITE: {
198
int length = m->m_pkthdr.len;
199
200
if (cmd->ch->dcid == NG_L2CAP_CLT_CID) {
201
m = ng_l2cap_prepend(m, sizeof(ng_l2cap_clt_hdr_t));
202
if (m == NULL)
203
error = ENOBUFS;
204
else
205
mtod(m, ng_l2cap_clt_hdr_t *)->psm =
206
htole16(cmd->ch->psm);
207
}
208
209
if (error == 0)
210
error = ng_l2cap_lp_send(con, cmd->ch->dcid, m);
211
212
ng_l2cap_l2ca_write_rsp(cmd->ch, cmd->token,
213
(error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES,
214
length);
215
216
ng_l2cap_unlink_cmd(cmd);
217
ng_l2cap_free_cmd(cmd);
218
} break;
219
case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE:
220
error = ng_l2cap_lp_send(con, NG_L2CAP_LESIGNAL_CID, m);
221
ng_l2cap_unlink_cmd(cmd);
222
ng_l2cap_free_cmd(cmd);
223
break;
224
case NG_L2CAP_CMD_PARAM_UPDATE_REQUEST:
225
/*TBD.*/
226
/* XXX FIXME add other commands */
227
default:
228
panic(
229
"%s: %s - unknown command code=%d\n",
230
__func__, NG_NODE_NAME(con->l2cap->node), cmd->code);
231
break;
232
}
233
} /* ng_l2cap_con_wakeup */
234
235
/*
236
* We have failed to open ACL connection to the remote unit. Could be negative
237
* confirmation or timeout. So fail any "delayed" commands, notify upper layer,
238
* remove all channels and remove connection descriptor.
239
*/
240
241
void
242
ng_l2cap_con_fail(ng_l2cap_con_p con, u_int16_t result)
243
{
244
ng_l2cap_p l2cap = con->l2cap;
245
ng_l2cap_cmd_p cmd = NULL;
246
ng_l2cap_chan_p ch = NULL;
247
248
NG_L2CAP_INFO(
249
"%s: %s - ACL connection failed, result=%d\n",
250
__func__, NG_NODE_NAME(l2cap->node), result);
251
252
/* Connection is dying */
253
con->flags |= NG_L2CAP_CON_DYING;
254
255
/* Clean command queue */
256
while (!TAILQ_EMPTY(&con->cmd_list)) {
257
cmd = TAILQ_FIRST(&con->cmd_list);
258
259
ng_l2cap_unlink_cmd(cmd);
260
if(cmd->flags & NG_L2CAP_CMD_PENDING)
261
ng_l2cap_command_untimeout(cmd);
262
263
KASSERT((cmd->con == con),
264
("%s: %s - invalid connection pointer!\n",
265
__func__, NG_NODE_NAME(l2cap->node)));
266
267
switch (cmd->code) {
268
case NG_L2CAP_CMD_REJ:
269
case NG_L2CAP_DISCON_RSP:
270
case NG_L2CAP_ECHO_RSP:
271
case NG_L2CAP_INFO_RSP:
272
case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE:
273
break;
274
275
case NG_L2CAP_CON_REQ:
276
ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, result, 0);
277
break;
278
279
case NG_L2CAP_CON_RSP:
280
if (cmd->ch != NULL)
281
ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
282
result);
283
break;
284
285
case NG_L2CAP_CFG_REQ:
286
case NG_L2CAP_CFG_RSP:
287
case NGM_L2CAP_L2CA_WRITE:
288
ng_l2cap_l2ca_discon_ind(cmd->ch);
289
break;
290
291
case NG_L2CAP_DISCON_REQ:
292
ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
293
NG_L2CAP_SUCCESS);
294
break;
295
296
case NG_L2CAP_ECHO_REQ:
297
ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
298
result, NULL);
299
break;
300
301
case NG_L2CAP_INFO_REQ:
302
ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
303
result, NULL);
304
break;
305
306
/* XXX FIXME add other commands */
307
308
default:
309
panic(
310
"%s: %s - unexpected command code=%d\n",
311
__func__, NG_NODE_NAME(l2cap->node), cmd->code);
312
break;
313
}
314
315
if (cmd->ch != NULL)
316
ng_l2cap_free_chan(cmd->ch);
317
318
ng_l2cap_free_cmd(cmd);
319
}
320
321
/*
322
* There still might be channels (in OPEN state?) that
323
* did not submit any commands, so disconnect them
324
*/
325
326
LIST_FOREACH(ch, &l2cap->chan_list, next)
327
if (ch->con == con)
328
ng_l2cap_l2ca_discon_ind(ch);
329
330
/* Free connection descriptor */
331
ng_l2cap_free_con(con);
332
} /* ng_l2cap_con_fail */
333
334
/*
335
* Process L2CAP command timeout. In general - notify upper layer and destroy
336
* channel. Do not pay much attention to return code, just do our best.
337
*/
338
339
void
340
ng_l2cap_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2)
341
{
342
ng_l2cap_p l2cap = NULL;
343
ng_l2cap_con_p con = NULL;
344
ng_l2cap_cmd_p cmd = NULL;
345
u_int16_t con_handle = (arg2 & 0x0ffff);
346
u_int8_t ident = ((arg2 >> 16) & 0xff);
347
348
if (NG_NODE_NOT_VALID(node)) {
349
printf("%s: Netgraph node is not valid\n", __func__);
350
return;
351
}
352
353
l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
354
355
con = ng_l2cap_con_by_handle(l2cap, con_handle);
356
if (con == NULL) {
357
NG_L2CAP_ALERT(
358
"%s: %s - could not find connection, con_handle=%d\n",
359
__func__, NG_NODE_NAME(node), con_handle);
360
return;
361
}
362
363
cmd = ng_l2cap_cmd_by_ident(con, ident);
364
if (cmd == NULL) {
365
NG_L2CAP_ALERT(
366
"%s: %s - could not find command, con_handle=%d, ident=%d\n",
367
__func__, NG_NODE_NAME(node), con_handle, ident);
368
return;
369
}
370
371
cmd->flags &= ~NG_L2CAP_CMD_PENDING;
372
ng_l2cap_unlink_cmd(cmd);
373
374
switch (cmd->code) {
375
case NG_L2CAP_CON_REQ:
376
ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT, 0);
377
ng_l2cap_free_chan(cmd->ch);
378
break;
379
380
case NG_L2CAP_CFG_REQ:
381
ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
382
break;
383
384
case NG_L2CAP_DISCON_REQ:
385
ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
386
ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
387
break;
388
389
case NG_L2CAP_ECHO_REQ:
390
/* Echo request timed out. Let the upper layer know */
391
ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
392
NG_L2CAP_TIMEOUT, NULL);
393
break;
394
395
case NG_L2CAP_INFO_REQ:
396
/* Info request timed out. Let the upper layer know */
397
ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
398
NG_L2CAP_TIMEOUT, NULL);
399
break;
400
401
/* XXX FIXME add other commands */
402
403
default:
404
panic(
405
"%s: %s - unexpected command code=%d\n",
406
__func__, NG_NODE_NAME(l2cap->node), cmd->code);
407
break;
408
}
409
410
ng_l2cap_free_cmd(cmd);
411
} /* ng_l2cap_process_command_timeout */
412
413