Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netgraph/bluetooth/l2cap/ng_l2cap_ulpi.c
34876 views
1
/*
2
* ng_l2cap_ulpi.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_ulpi.c,v 1.1 2002/11/24 19:47:06 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_hci.h>
45
#include <netgraph/bluetooth/include/ng_l2cap.h>
46
#include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
47
#include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
48
#include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
49
#include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
50
#include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
51
#include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
52
53
/******************************************************************************
54
******************************************************************************
55
** Upper Layer Protocol Interface module
56
******************************************************************************
57
******************************************************************************/
58
59
/*
60
* Process L2CA_Connect request from the upper layer protocol.
61
*/
62
63
int
64
ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
65
{
66
ng_l2cap_l2ca_con_ip *ip = NULL;
67
ng_l2cap_con_p con = NULL;
68
ng_l2cap_chan_p ch = NULL;
69
ng_l2cap_cmd_p cmd = NULL;
70
int error = 0;
71
72
/* Check message */
73
if (msg->header.arglen != sizeof(*ip)) {
74
NG_L2CAP_ALERT(
75
"%s: %s - invalid L2CA_Connect request message size, size=%d\n",
76
__func__, NG_NODE_NAME(l2cap->node),
77
msg->header.arglen);
78
error = EMSGSIZE;
79
goto out;
80
}
81
82
ip = (ng_l2cap_l2ca_con_ip *)(msg->data);
83
84
/* Check if we have connection to the remote unit */
85
con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
86
if (con == NULL) {
87
/* Submit LP_ConnectReq to the lower layer */
88
error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
89
if (error != 0) {
90
NG_L2CAP_ERR(
91
"%s: %s - unable to send LP_ConnectReq message, error=%d\n",
92
__func__, NG_NODE_NAME(l2cap->node), error);
93
goto out;
94
}
95
96
/* This should not fail */
97
con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
98
KASSERT((con != NULL),
99
("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
100
}
101
102
/*
103
* Create new empty channel descriptor. In case of any failure do
104
* not touch connection descriptor.
105
*/
106
107
ch = ng_l2cap_new_chan(l2cap, con, ip->psm, ip->idtype);
108
if (ch == NULL) {
109
error = ENOMEM;
110
goto out;
111
}
112
113
/* Now create L2CAP_ConnectReq command */
114
cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(con),
115
NG_L2CAP_CON_REQ, msg->header.token);
116
if (cmd == NULL) {
117
ng_l2cap_free_chan(ch);
118
error = ENOMEM;
119
goto out;
120
}
121
122
if (cmd->ident == NG_L2CAP_NULL_IDENT) {
123
ng_l2cap_free_cmd(cmd);
124
ng_l2cap_free_chan(ch);
125
error = EIO;
126
goto out;
127
}
128
129
/* Create L2CAP command packet */
130
if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
131
_ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_ATT_CID,
132
NG_L2CAP_ATT_CID, 0, 0);
133
cmd->aux->m_flags |= M_PROTO2;
134
}else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
135
_ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_SMP_CID,
136
NG_L2CAP_SMP_CID, 0, 0);
137
cmd->aux->m_flags |= M_PROTO2;
138
}else{
139
_ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid);
140
}
141
if (cmd->aux == NULL) {
142
ng_l2cap_free_cmd(cmd);
143
ng_l2cap_free_chan(ch);
144
error = ENOBUFS;
145
goto out;
146
}
147
148
ch->state = NG_L2CAP_W4_L2CAP_CON_RSP;
149
150
/* Link command to the queue */
151
ng_l2cap_link_cmd(ch->con, cmd);
152
ng_l2cap_lp_deliver(ch->con);
153
out:
154
return (error);
155
} /* ng_l2cap_l2ca_con_req */
156
157
/*
158
* Send L2CA_Connect response to the upper layer protocol.
159
*/
160
161
int
162
ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
163
u_int16_t status)
164
{
165
ng_l2cap_p l2cap = ch->con->l2cap;
166
struct ng_mesg *msg = NULL;
167
ng_l2cap_l2ca_con_op *op = NULL;
168
int error = 0;
169
170
/* Check if upstream hook is connected and valid */
171
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
172
NG_L2CAP_ERR(
173
"%s: %s - unable to send L2CA_Connect response message. " \
174
"Hook is not connected or valid, psm=%d\n",
175
__func__, NG_NODE_NAME(l2cap->node), ch->psm);
176
177
return (ENOTCONN);
178
}
179
180
/* Create and send L2CA_Connect response message */
181
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON,
182
sizeof(*op), M_NOWAIT);
183
if (msg == NULL)
184
error = ENOMEM;
185
else {
186
msg->header.token = token;
187
msg->header.flags |= NGF_RESP;
188
189
op = (ng_l2cap_l2ca_con_op *)(msg->data);
190
191
/*
192
* XXX Spec. says we should only populate LCID when result == 0
193
* What about PENDING? What the heck, for now always populate
194
* LCID :)
195
*/
196
if(ch->scid == NG_L2CAP_ATT_CID){
197
op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
198
op->lcid = ch->con->con_handle;
199
}else if(ch->scid == NG_L2CAP_SMP_CID){
200
op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
201
op->lcid = ch->con->con_handle;
202
}else{
203
op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
204
NG_L2CAP_L2CA_IDTYPE_BREDR :
205
NG_L2CAP_L2CA_IDTYPE_LE;
206
op->lcid = ch->scid;
207
}
208
op->encryption = ch->con->encryption;
209
op->result = result;
210
op->status = status;
211
212
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
213
}
214
215
return (error);
216
} /* ng_l2cap_l2ca_con_rsp */
217
218
/*
219
* Process L2CA_ConnectRsp request from the upper layer protocol.
220
*/
221
222
int
223
ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
224
{
225
ng_l2cap_l2ca_con_rsp_ip *ip = NULL;
226
ng_l2cap_con_p con = NULL;
227
ng_l2cap_chan_p ch = NULL;
228
ng_l2cap_cmd_p cmd = NULL;
229
u_int16_t dcid;
230
int error = 0;
231
232
/* Check message */
233
if (msg->header.arglen != sizeof(*ip)) {
234
NG_L2CAP_ALERT(
235
"%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n",
236
__func__, NG_NODE_NAME(l2cap->node),
237
msg->header.arglen);
238
error = EMSGSIZE;
239
goto out;
240
}
241
242
ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data);
243
244
/* Check if we have this channel */
245
if((ip->lcid != NG_L2CAP_ATT_CID)&&
246
(ip->lcid != NG_L2CAP_SMP_CID)){
247
ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid
248
,(ip->linktype == NG_HCI_LINK_ACL)?
249
NG_L2CAP_L2CA_IDTYPE_BREDR:
250
NG_L2CAP_L2CA_IDTYPE_LE);
251
}else{
252
// For now not support on ATT device.
253
ch = NULL;
254
}
255
if (ch == NULL) {
256
NG_L2CAP_ALERT(
257
"%s: %s - unexpected L2CA_ConnectRsp request message. " \
258
"Channel does not exist, lcid=%d\n",
259
__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
260
error = ENOENT;
261
goto out;
262
}
263
264
/* Check channel state */
265
if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) {
266
NG_L2CAP_ERR(
267
"%s: %s - unexpected L2CA_ConnectRsp request message. " \
268
"Invalid channel state, state=%d, lcid=%d\n",
269
__func__, NG_NODE_NAME(l2cap->node), ch->state,
270
ip->lcid);
271
error = EINVAL;
272
goto out;
273
}
274
275
dcid = ch->dcid;
276
con = ch->con;
277
278
/*
279
* Now we are pretty much sure it is our response. So create and send
280
* L2CAP_ConnectRsp message to our peer.
281
*/
282
283
if (ch->ident != ip->ident)
284
NG_L2CAP_WARN(
285
"%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \
286
"Will use response ident=%d\n",
287
__func__, NG_NODE_NAME(l2cap->node), ch->scid,
288
ch->ident, ip->ident);
289
290
/* Check result */
291
switch (ip->result) {
292
case NG_L2CAP_SUCCESS:
293
ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||
294
(ch->scid == NG_L2CAP_SMP_CID))?
295
NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
296
ch->cfg_state = 0;
297
break;
298
299
case NG_L2CAP_PENDING:
300
break;
301
302
default:
303
ng_l2cap_free_chan(ch);
304
ch = NULL;
305
break;
306
}
307
308
/* Create L2CAP command */
309
cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP,
310
msg->header.token);
311
if (cmd == NULL) {
312
if (ch != NULL)
313
ng_l2cap_free_chan(ch);
314
315
error = ENOMEM;
316
goto out;
317
}
318
319
_ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid,
320
ip->result, ip->status);
321
if (cmd->aux == NULL) {
322
if (ch != NULL)
323
ng_l2cap_free_chan(ch);
324
325
ng_l2cap_free_cmd(cmd);
326
error = ENOBUFS;
327
goto out;
328
}
329
330
/* Link command to the queue */
331
ng_l2cap_link_cmd(con, cmd);
332
ng_l2cap_lp_deliver(con);
333
out:
334
return (error);
335
} /* ng_l2cap_l2ca_con_rsp_req */
336
337
int ng_l2cap_l2ca_encryption_change(ng_l2cap_chan_p ch, uint16_t result)
338
{
339
ng_l2cap_p l2cap = ch->con->l2cap;
340
struct ng_mesg *msg = NULL;
341
ng_l2cap_l2ca_enc_chg_op *op = NULL;
342
int error = 0;
343
344
/* Check if upstream hook is connected and valid */
345
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
346
NG_L2CAP_ERR(
347
"%s: %s - unable to send L2CA_ConnectRsp response message. " \
348
"Hook is not connected or valid, psm=%d\n",
349
__func__, NG_NODE_NAME(l2cap->node), ch->psm);
350
351
return (ENOTCONN);
352
}
353
354
/* Create and send L2CA_ConnectRsp response message */
355
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENC_CHANGE,
356
sizeof(*op), M_NOWAIT);
357
if (msg == NULL)
358
error = ENOMEM;
359
else {
360
msg->header.token = 0;
361
msg->header.flags |= NGF_RESP;
362
363
op = (ng_l2cap_l2ca_enc_chg_op *)(msg->data);
364
op->result = result;
365
if(ch->scid ==NG_L2CAP_ATT_CID||
366
ch->scid ==NG_L2CAP_SMP_CID){
367
op->lcid = ch->con->con_handle;
368
op->idtype = (ch->scid==NG_L2CAP_ATT_CID)?
369
NG_L2CAP_L2CA_IDTYPE_ATT:
370
NG_L2CAP_L2CA_IDTYPE_SMP;
371
}else{
372
op->idtype =(ch->con->linktype ==NG_HCI_LINK_ACL)?
373
NG_L2CAP_L2CA_IDTYPE_BREDR:
374
NG_L2CAP_L2CA_IDTYPE_LE;
375
}
376
377
378
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
379
}
380
381
return (error);
382
383
}
384
/*
385
* Send L2CAP_ConnectRsp response to the upper layer
386
*/
387
388
int
389
ng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
390
{
391
ng_l2cap_p l2cap = ch->con->l2cap;
392
struct ng_mesg *msg = NULL;
393
ng_l2cap_l2ca_con_rsp_op *op = NULL;
394
int error = 0;
395
396
/* Check if upstream hook is connected and valid */
397
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
398
NG_L2CAP_ERR(
399
"%s: %s - unable to send L2CA_ConnectRsp response message. " \
400
"Hook is not connected or valid, psm=%d\n",
401
__func__, NG_NODE_NAME(l2cap->node), ch->psm);
402
403
return (ENOTCONN);
404
}
405
406
/* Create and send L2CA_ConnectRsp response message */
407
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP,
408
sizeof(*op), M_NOWAIT);
409
if (msg == NULL)
410
error = ENOMEM;
411
else {
412
msg->header.token = token;
413
msg->header.flags |= NGF_RESP;
414
415
op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data);
416
op->result = result;
417
418
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
419
}
420
421
return (error);
422
} /* ng_l2cap_l2ca_con_rsp_rsp */
423
424
/*
425
* Send L2CA_ConnectInd message to the upper layer protocol.
426
*/
427
428
int
429
ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch)
430
{
431
ng_l2cap_p l2cap = ch->con->l2cap;
432
struct ng_mesg *msg = NULL;
433
ng_l2cap_l2ca_con_ind_ip *ip = NULL;
434
int error = 0;
435
436
/* Check if upstream hook is connected and valid */
437
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
438
NG_L2CAP_ERR(
439
"%s: %s - unable to send L2CA_ConnectInd message. " \
440
"Hook is not connected or valid, psm=%d\n",
441
__func__, NG_NODE_NAME(l2cap->node), ch->psm);
442
443
return (ENOTCONN);
444
}
445
446
/* Create and send L2CA_ConnectInd message */
447
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND,
448
sizeof(*ip), M_NOWAIT);
449
if (msg == NULL)
450
error = ENOMEM;
451
else {
452
ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data);
453
454
bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
455
ip->lcid = ch->scid;
456
ip->psm = ch->psm;
457
ip->ident = ch->ident;
458
ip->linktype = ch->con->linktype;
459
460
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
461
}
462
463
return (error);
464
} /* ng_l2cap_l2ca_con_ind */
465
466
/*
467
* Process L2CA_Config request from the upper layer protocol
468
*/
469
470
int
471
ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
472
{
473
ng_l2cap_l2ca_cfg_ip *ip = NULL;
474
ng_l2cap_chan_p ch = NULL;
475
ng_l2cap_cmd_p cmd = NULL;
476
struct mbuf *opt = NULL;
477
u_int16_t *mtu = NULL, *flush_timo = NULL;
478
ng_l2cap_flow_p flow = NULL;
479
int error = 0;
480
481
/* Check message */
482
if (msg->header.arglen != sizeof(*ip)) {
483
NG_L2CAP_ALERT(
484
"%s: %s - Invalid L2CA_Config request message size, size=%d\n",
485
__func__, NG_NODE_NAME(l2cap->node),
486
msg->header.arglen);
487
error = EMSGSIZE;
488
goto out;
489
}
490
491
ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data);
492
493
/* Check if we have this channel */
494
ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR);
495
if (ch == NULL) {
496
NG_L2CAP_ERR(
497
"%s: %s - unexpected L2CA_Config request message. " \
498
"Channel does not exist, lcid=%d\n",
499
__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
500
error = ENOENT;
501
goto out;
502
}
503
504
/* Check channel state */
505
if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) {
506
NG_L2CAP_ERR(
507
"%s: %s - unexpected L2CA_Config request message. " \
508
"Invalid channel state, state=%d, lcid=%d\n",
509
__func__, NG_NODE_NAME(l2cap->node), ch->state,
510
ch->scid);
511
error = EINVAL;
512
goto out;
513
}
514
515
/* Set requested channel configuration options */
516
ch->imtu = ip->imtu;
517
bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow));
518
ch->flush_timo = ip->flush_timo;
519
ch->link_timo = ip->link_timo;
520
521
/* Compare channel settings with defaults */
522
if (ch->imtu != NG_L2CAP_MTU_DEFAULT)
523
mtu = &ch->imtu;
524
if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT)
525
flush_timo = &ch->flush_timo;
526
if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0)
527
flow = &ch->oflow;
528
529
/* Create configuration options */
530
_ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow);
531
if (opt == NULL) {
532
error = ENOBUFS;
533
goto out;
534
}
535
536
/* Create L2CAP command descriptor */
537
cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
538
NG_L2CAP_CFG_REQ, msg->header.token);
539
if (cmd == NULL) {
540
NG_FREE_M(opt);
541
error = ENOMEM;
542
goto out;
543
}
544
545
if (cmd->ident == NG_L2CAP_NULL_IDENT) {
546
ng_l2cap_free_cmd(cmd);
547
NG_FREE_M(opt);
548
error = EIO;
549
goto out;
550
}
551
552
/* Create L2CAP command packet */
553
_ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt);
554
if (cmd->aux == NULL) {
555
ng_l2cap_free_cmd(cmd);
556
error = ENOBUFS;
557
goto out;
558
}
559
560
/* Adjust channel state for re-configuration */
561
if (ch->state == NG_L2CAP_OPEN) {
562
ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||
563
(ch->scid == NG_L2CAP_SMP_CID))?
564
NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
565
ch->cfg_state = 0;
566
}
567
568
/* Link command to the queue */
569
ng_l2cap_link_cmd(ch->con, cmd);
570
ng_l2cap_lp_deliver(ch->con);
571
out:
572
return (error);
573
} /* ng_l2cap_l2ca_cfg_req */
574
575
/*
576
* Send L2CA_Config response to the upper layer protocol
577
*/
578
579
int
580
ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
581
{
582
ng_l2cap_p l2cap = ch->con->l2cap;
583
struct ng_mesg *msg = NULL;
584
ng_l2cap_l2ca_cfg_op *op = NULL;
585
int error = 0;
586
587
/* Check if upstream hook is connected and valid */
588
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
589
NG_L2CAP_ERR(
590
"%s: %s - unable to send L2CA_Config response message. " \
591
"Hook is not connected or valid, psm=%d\n",
592
__func__, NG_NODE_NAME(l2cap->node), ch->psm);
593
594
return (ENOTCONN);
595
}
596
597
/* Create and send L2CA_Config response message */
598
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG,
599
sizeof(*op), M_NOWAIT);
600
if (msg == NULL)
601
error = ENOMEM;
602
else {
603
msg->header.token = token;
604
msg->header.flags |= NGF_RESP;
605
606
op = (ng_l2cap_l2ca_cfg_op *)(msg->data);
607
op->result = result;
608
op->imtu = ch->imtu;
609
bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow));
610
op->flush_timo = ch->flush_timo;
611
612
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
613
614
if (error == 0 && result == NG_L2CAP_SUCCESS) {
615
ch->cfg_state |= NG_L2CAP_CFG_IN;
616
617
if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
618
ch->state = NG_L2CAP_OPEN;
619
}
620
}
621
622
return (error);
623
} /* ng_l2cap_l2ca_cfg_rsp */
624
625
/*
626
* Process L2CA_ConfigRsp request from the upper layer protocol
627
*
628
* XXX XXX XXX
629
*
630
* NOTE: The Bluetooth specification says that Configuration_Response
631
* (L2CA_ConfigRsp) should be used to issue response to configuration request
632
* indication. The minor problem here is L2CAP command ident. We should use
633
* ident from original L2CAP request to make sure our peer can match request
634
* and response. For some reason Bluetooth specification does not include
635
* ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems
636
* strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident
637
* field. So we should store last known L2CAP request command ident in channel.
638
* Also it seems that upper layer can not reject configuration request, as
639
* Configuration_Response message does not have status/reason field.
640
*/
641
642
int
643
ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
644
{
645
ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL;
646
ng_l2cap_chan_p ch = NULL;
647
ng_l2cap_cmd_p cmd = NULL;
648
struct mbuf *opt = NULL;
649
u_int16_t *mtu = NULL;
650
ng_l2cap_flow_p flow = NULL;
651
int error = 0;
652
653
/* Check message */
654
if (msg->header.arglen != sizeof(*ip)) {
655
NG_L2CAP_ALERT(
656
"%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n",
657
__func__, NG_NODE_NAME(l2cap->node),
658
msg->header.arglen);
659
error = EMSGSIZE;
660
goto out;
661
}
662
663
ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data);
664
665
/* Check if we have this channel */
666
ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid,
667
NG_L2CAP_L2CA_IDTYPE_BREDR);
668
if (ch == NULL) {
669
NG_L2CAP_ERR(
670
"%s: %s - unexpected L2CA_ConfigRsp request message. " \
671
"Channel does not exist, lcid=%d\n",
672
__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
673
error = ENOENT;
674
goto out;
675
}
676
677
/* Check channel state */
678
if (ch->state != NG_L2CAP_CONFIG) {
679
NG_L2CAP_ERR(
680
"%s: %s - unexpected L2CA_ConfigRsp request message. " \
681
"Invalid channel state, state=%d, lcid=%d\n",
682
__func__, NG_NODE_NAME(l2cap->node), ch->state,
683
ch->scid);
684
error = EINVAL;
685
goto out;
686
}
687
688
/* Set channel settings */
689
if (ip->omtu != ch->omtu) {
690
ch->omtu = ip->omtu;
691
mtu = &ch->omtu;
692
}
693
694
if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) {
695
bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow));
696
flow = &ch->iflow;
697
}
698
699
if (mtu != NULL || flow != NULL) {
700
_ng_l2cap_build_cfg_options(opt, mtu, NULL, flow);
701
if (opt == NULL) {
702
error = ENOBUFS;
703
goto out;
704
}
705
}
706
707
/* Create L2CAP command */
708
cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP,
709
msg->header.token);
710
if (cmd == NULL) {
711
NG_FREE_M(opt);
712
error = ENOMEM;
713
goto out;
714
}
715
716
_ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt);
717
if (cmd->aux == NULL) {
718
ng_l2cap_free_cmd(cmd);
719
error = ENOBUFS;
720
goto out;
721
}
722
723
/* XXX FIXME - not here ??? */
724
ch->cfg_state |= NG_L2CAP_CFG_OUT;
725
if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
726
ch->state = NG_L2CAP_OPEN;
727
728
/* Link command to the queue */
729
ng_l2cap_link_cmd(ch->con, cmd);
730
ng_l2cap_lp_deliver(ch->con);
731
out:
732
return (error);
733
} /* ng_l2cap_l2ca_cfg_rsp_req */
734
735
/*
736
* Send L2CA_ConfigRsp response to the upper layer protocol
737
*/
738
739
int
740
ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
741
{
742
ng_l2cap_p l2cap = ch->con->l2cap;
743
struct ng_mesg *msg = NULL;
744
ng_l2cap_l2ca_cfg_rsp_op *op = NULL;
745
int error = 0;
746
747
/* Check if upstream hook is connected and valid */
748
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
749
NG_L2CAP_ERR(
750
"%s: %s - unable to send L2CA_ConfigRsp response message. " \
751
"Hook is not connected or valid, psm=%d\n",
752
__func__, NG_NODE_NAME(l2cap->node), ch->psm);
753
754
return (ENOTCONN);
755
}
756
757
/* Create and send L2CA_ConfigRsp response message */
758
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP,
759
sizeof(*op), M_NOWAIT);
760
if (msg == NULL)
761
error = ENOMEM;
762
else {
763
msg->header.token = token;
764
msg->header.flags |= NGF_RESP;
765
766
op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data);
767
op->result = result;
768
769
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
770
}
771
772
return (error);
773
} /* ng_l2cap_l2ca_cfg_rsp_rsp */
774
775
/*
776
* Send L2CA_ConfigInd message to the upper layer protocol
777
*
778
* XXX XXX XXX
779
*
780
* NOTE: The Bluetooth specification says that Configuration_Response
781
* (L2CA_ConfigRsp) should be used to issue response to configuration request
782
* indication. The minor problem here is L2CAP command ident. We should use
783
* ident from original L2CAP request to make sure our peer can match request
784
* and response. For some reason Bluetooth specification does not include
785
* ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems
786
* strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident
787
* field. So we should store last known L2CAP request command ident in channel.
788
* Also it seems that upper layer can not reject configuration request, as
789
* Configuration_Response message does not have status/reason field.
790
*/
791
792
int
793
ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch)
794
{
795
ng_l2cap_p l2cap = ch->con->l2cap;
796
struct ng_mesg *msg = NULL;
797
ng_l2cap_l2ca_cfg_ind_ip *ip = NULL;
798
int error = 0;
799
800
/* Check if upstream hook is connected and valid */
801
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
802
NG_L2CAP_ERR(
803
"%s: %s - Unable to send L2CA_ConfigInd message. " \
804
"Hook is not connected or valid, psm=%d\n",
805
__func__, NG_NODE_NAME(l2cap->node), ch->psm);
806
807
return (ENOTCONN);
808
}
809
810
/* Create and send L2CA_ConnectInd message */
811
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND,
812
sizeof(*ip), M_NOWAIT);
813
if (msg == NULL)
814
error = ENOMEM;
815
else {
816
ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data);
817
ip->lcid = ch->scid;
818
ip->omtu = ch->omtu;
819
bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow));
820
ip->flush_timo = ch->flush_timo;
821
822
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
823
}
824
825
return (error);
826
} /* ng_l2cap_l2ca_cfg_ind */
827
828
/*
829
* Process L2CA_Write event
830
*/
831
832
int
833
ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m)
834
{
835
ng_l2cap_l2ca_hdr_t *l2ca_hdr = NULL;
836
ng_l2cap_chan_p ch = NULL;
837
ng_l2cap_cmd_p cmd = NULL;
838
int error = 0;
839
u_int32_t token = 0;
840
841
/* Make sure we can access L2CA data packet header */
842
if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) {
843
NG_L2CAP_ERR(
844
"%s: %s - L2CA Data packet too small, len=%d\n",
845
__func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len);
846
error = EMSGSIZE;
847
goto drop;
848
}
849
850
/* Get L2CA data packet header */
851
NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr));
852
if (m == NULL)
853
return (ENOBUFS);
854
855
l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *);
856
token = l2ca_hdr->token;
857
m_adj(m, sizeof(*l2ca_hdr));
858
859
/* Verify payload size */
860
if (l2ca_hdr->length != m->m_pkthdr.len) {
861
NG_L2CAP_ERR(
862
"%s: %s - invalid L2CA Data packet. " \
863
"Payload length does not match, length=%d, len=%d\n",
864
__func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length,
865
m->m_pkthdr.len);
866
error = EMSGSIZE;
867
goto drop;
868
}
869
870
/* Check channel ID */
871
if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
872
ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
873
l2ca_hdr->lcid);
874
} else if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
875
ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
876
l2ca_hdr->lcid);
877
}else{
878
if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) {
879
NG_L2CAP_ERR(
880
"%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n",
881
__func__, NG_NODE_NAME(l2cap->node),
882
l2ca_hdr->lcid);
883
error = EINVAL;
884
goto drop;
885
}
886
887
/* Verify that we have the channel and make sure it is open */
888
ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid,
889
l2ca_hdr->idtype);
890
}
891
892
if (ch == NULL) {
893
NG_L2CAP_ERR(
894
"%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n",
895
__func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid);
896
error = ENOENT;
897
goto drop;
898
}
899
900
if (ch->state != NG_L2CAP_OPEN) {
901
NG_L2CAP_ERR(
902
"%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n",
903
__func__, NG_NODE_NAME(l2cap->node), ch->scid,
904
ch->state);
905
error = EHOSTDOWN;
906
goto drop; /* XXX not always - re-configure */
907
}
908
909
/* Create L2CAP command descriptor */
910
cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token);
911
if (cmd == NULL) {
912
error = ENOMEM;
913
goto drop;
914
}
915
916
/* Attach data packet and link command to the queue */
917
cmd->aux = m;
918
ng_l2cap_link_cmd(ch->con, cmd);
919
ng_l2cap_lp_deliver(ch->con);
920
921
return (error);
922
drop:
923
NG_FREE_M(m);
924
925
return (error);
926
} /* ng_l2cap_l2ca_write_req */
927
928
/*
929
* Send L2CA_Write response
930
*/
931
932
int
933
ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
934
u_int16_t length)
935
{
936
ng_l2cap_p l2cap = ch->con->l2cap;
937
struct ng_mesg *msg = NULL;
938
ng_l2cap_l2ca_write_op *op = NULL;
939
int error = 0;
940
941
/* Check if upstream hook is connected and valid */
942
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
943
NG_L2CAP_ERR(
944
"%s: %s - unable to send L2CA_WriteRsp message. " \
945
"Hook is not connected or valid, psm=%d\n",
946
__func__, NG_NODE_NAME(l2cap->node), ch->psm);
947
948
return (ENOTCONN);
949
}
950
951
/* Create and send L2CA_WriteRsp message */
952
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE,
953
sizeof(*op), M_NOWAIT);
954
if (msg == NULL)
955
error = ENOMEM;
956
else {
957
msg->header.token = token;
958
msg->header.flags |= NGF_RESP;
959
960
op = (ng_l2cap_l2ca_write_op *)(msg->data);
961
op->result = result;
962
op->length = length;
963
if(ch->scid == NG_L2CAP_ATT_CID){
964
op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
965
op->lcid = ch->con->con_handle;
966
}else if(ch->scid == NG_L2CAP_SMP_CID){
967
op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
968
op->lcid = ch->con->con_handle;
969
}else{
970
op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
971
NG_L2CAP_L2CA_IDTYPE_BREDR :
972
NG_L2CAP_L2CA_IDTYPE_LE;
973
op->lcid = ch->scid;
974
975
}
976
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
977
}
978
979
return (error);
980
} /* ng_l2cap_l2ca_write_rsp */
981
982
/*
983
* Receive packet from the lower layer protocol and send it to the upper
984
* layer protocol (L2CAP_Read)
985
*/
986
987
int
988
ng_l2cap_l2ca_receive(ng_l2cap_con_p con)
989
{
990
ng_l2cap_p l2cap = con->l2cap;
991
ng_l2cap_hdr_t *hdr = NULL;
992
ng_l2cap_chan_p ch = NULL;
993
int error = 0;
994
int idtype;
995
uint16_t *idp;
996
int silent = 0;
997
998
NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
999
if (con->rx_pkt == NULL)
1000
return (ENOBUFS);
1001
1002
hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *);
1003
1004
/* Check channel */
1005
1006
if(hdr->dcid == NG_L2CAP_ATT_CID){
1007
idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
1008
ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
1009
con->con_handle);
1010
/*
1011
* Here,ATT channel is distinguished by
1012
* connection handle
1013
*/
1014
hdr->dcid = con->con_handle;
1015
silent = 1;
1016
}else if(hdr->dcid == NG_L2CAP_SMP_CID){
1017
idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
1018
ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
1019
con->con_handle);
1020
/*
1021
* Here,SMP channel is distinguished by
1022
* connection handle
1023
*/
1024
silent = 1;
1025
hdr->dcid = con->con_handle;
1026
}else{
1027
idtype = (con->linktype==NG_HCI_LINK_ACL)?
1028
NG_L2CAP_L2CA_IDTYPE_BREDR:
1029
NG_L2CAP_L2CA_IDTYPE_LE;
1030
ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid, idtype);
1031
}
1032
if (ch == NULL) {
1033
if(!silent)
1034
NG_L2CAP_ERR(
1035
"%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d, idtype=%d\n",
1036
__func__, NG_NODE_NAME(l2cap->node), hdr->dcid, idtype);
1037
error = ENOENT;
1038
goto drop;
1039
}
1040
1041
/* Check channel state */
1042
if (ch->state != NG_L2CAP_OPEN) {
1043
NG_L2CAP_WARN(
1044
"%s: %s - unexpected L2CAP data packet. " \
1045
"Invalid channel state, cid=%d, state=%d\n",
1046
__func__, NG_NODE_NAME(l2cap->node), ch->scid,
1047
ch->state);
1048
error = EHOSTDOWN; /* XXX not always - re-configuration */
1049
goto drop;
1050
}
1051
1052
/* Check payload size and channel's MTU */
1053
if (hdr->length > ch->imtu) {
1054
NG_L2CAP_ERR(
1055
"%s: %s - invalid L2CAP data packet. " \
1056
"Packet too big, length=%d, imtu=%d, cid=%d\n",
1057
__func__, NG_NODE_NAME(l2cap->node), hdr->length,
1058
ch->imtu, ch->scid);
1059
error = EMSGSIZE;
1060
goto drop;
1061
}
1062
1063
/*
1064
* If we got here then everything looks good and we can sent packet
1065
* to the upper layer protocol.
1066
*/
1067
1068
/* Check if upstream hook is connected and valid */
1069
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1070
NG_L2CAP_ERR(
1071
"%s: %s - unable to send L2CAP data packet. " \
1072
"Hook is not connected or valid, psm=%d\n",
1073
__func__, NG_NODE_NAME(l2cap->node), ch->psm);
1074
error = ENOTCONN;
1075
goto drop;
1076
}
1077
M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT);
1078
if(con->rx_pkt == NULL)
1079
goto drop;
1080
idp = mtod(con->rx_pkt, uint16_t *);
1081
*idp = idtype;
1082
1083
NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1084
con->rx_pkt = NULL;
1085
drop:
1086
NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1087
1088
return (error);
1089
} /* ng_l2cap_receive */
1090
1091
/*
1092
* Receive connectioless (multicast) packet from the lower layer protocol and
1093
* send it to the upper layer protocol
1094
*/
1095
1096
int
1097
ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con)
1098
{
1099
struct _clt_pkt {
1100
ng_l2cap_hdr_t h;
1101
ng_l2cap_clt_hdr_t c_h;
1102
} __attribute__ ((packed)) *hdr = NULL;
1103
ng_l2cap_p l2cap = con->l2cap;
1104
int length, error = 0;
1105
1106
NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
1107
if (con->rx_pkt == NULL)
1108
return (ENOBUFS);
1109
1110
hdr = mtod(con->rx_pkt, struct _clt_pkt *);
1111
1112
/* Check packet */
1113
length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr);
1114
if (length < 0) {
1115
NG_L2CAP_ERR(
1116
"%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n",
1117
__func__, NG_NODE_NAME(l2cap->node), length);
1118
error = EMSGSIZE;
1119
goto drop;
1120
}
1121
1122
/* Check payload size against CLT MTU */
1123
if (length > NG_L2CAP_MTU_DEFAULT) {
1124
NG_L2CAP_ERR(
1125
"%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n",
1126
__func__, NG_NODE_NAME(l2cap->node), length,
1127
NG_L2CAP_MTU_DEFAULT);
1128
error = EMSGSIZE;
1129
goto drop;
1130
}
1131
1132
hdr->c_h.psm = le16toh(hdr->c_h.psm);
1133
1134
/*
1135
* If we got here then everything looks good and we can sent packet
1136
* to the upper layer protocol.
1137
*/
1138
1139
/* Select upstream hook based on PSM */
1140
switch (hdr->c_h.psm) {
1141
case NG_L2CAP_PSM_SDP:
1142
if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED)
1143
goto drop;
1144
break;
1145
1146
case NG_L2CAP_PSM_RFCOMM:
1147
if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED)
1148
goto drop;
1149
break;
1150
1151
case NG_L2CAP_PSM_TCP:
1152
if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED)
1153
goto drop;
1154
break;
1155
}
1156
1157
/* Check if upstream hook is connected and valid */
1158
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1159
NG_L2CAP_ERR(
1160
"%s: %s - unable to send L2CAP CLT data packet. " \
1161
"Hook is not connected or valid, psm=%d\n",
1162
__func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm);
1163
error = ENOTCONN;
1164
goto drop;
1165
}
1166
1167
NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1168
con->rx_pkt = NULL;
1169
drop:
1170
NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1171
1172
return (error);
1173
} /* ng_l2cap_l2ca_clt_receive */
1174
1175
/*
1176
* Send L2CA_QoSViolationInd to the upper layer protocol
1177
*/
1178
1179
int
1180
ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch)
1181
{
1182
ng_l2cap_p l2cap = ch->con->l2cap;
1183
struct ng_mesg *msg = NULL;
1184
ng_l2cap_l2ca_qos_ind_ip *ip = NULL;
1185
int error = 0;
1186
1187
/* Check if upstream hook is connected and valid */
1188
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1189
NG_L2CAP_ERR(
1190
"%s: %s - unable to send L2CA_QoSViolationInd message. " \
1191
"Hook is not connected or valid, psm=%d\n",
1192
__func__, NG_NODE_NAME(l2cap->node), ch->psm);
1193
1194
return (ENOTCONN);
1195
}
1196
1197
/* Create and send L2CA_QoSViolationInd message */
1198
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND,
1199
sizeof(*ip), M_NOWAIT);
1200
if (msg == NULL)
1201
error = ENOMEM;
1202
else {
1203
ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data);
1204
bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
1205
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1206
}
1207
1208
return (error);
1209
} /* ng_l2cap_l2ca_qos_ind */
1210
1211
/*
1212
* Process L2CA_Disconnect request from the upper layer protocol.
1213
*/
1214
1215
int
1216
ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1217
{
1218
ng_l2cap_l2ca_discon_ip *ip = NULL;
1219
ng_l2cap_chan_p ch = NULL;
1220
ng_l2cap_cmd_p cmd = NULL;
1221
int error = 0;
1222
1223
/* Check message */
1224
if (msg->header.arglen != sizeof(*ip)) {
1225
NG_L2CAP_ALERT(
1226
"%s: %s - invalid L2CA_Disconnect request message size, size=%d\n",
1227
__func__, NG_NODE_NAME(l2cap->node),
1228
msg->header.arglen);
1229
error = EMSGSIZE;
1230
goto out;
1231
}
1232
1233
ip = (ng_l2cap_l2ca_discon_ip *)(msg->data);
1234
1235
if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
1236
/* Don't send Disconnect request on L2CAP Layer*/
1237
ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
1238
ip->lcid);
1239
1240
if(ch != NULL){
1241
ng_l2cap_free_chan(ch);
1242
}else{
1243
NG_L2CAP_ERR(
1244
"%s: %s - unexpected L2CA_Disconnect request message. " \
1245
"Channel does not exist, conhandle=%d\n",
1246
__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1247
error = EINVAL;
1248
}
1249
goto out;
1250
}else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
1251
/* Don't send Disconnect request on L2CAP Layer*/
1252
ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
1253
ip->lcid);
1254
1255
if(ch != NULL){
1256
ng_l2cap_free_chan(ch);
1257
}else{
1258
NG_L2CAP_ERR(
1259
"%s: %s - unexpected L2CA_Disconnect request message. " \
1260
"Channel does not exist, conhandle=%d\n",
1261
__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1262
error = EINVAL;
1263
}
1264
goto out;
1265
}else{
1266
/* Check if we have this channel */
1267
ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype);
1268
}
1269
if (ch == NULL) {
1270
NG_L2CAP_ERR(
1271
"%s: %s - unexpected L2CA_Disconnect request message. " \
1272
"Channel does not exist, lcid=%d\n",
1273
__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1274
error = ENOENT;
1275
goto out;
1276
}
1277
1278
/* Check channel state */
1279
if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN &&
1280
ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) {
1281
NG_L2CAP_ERR(
1282
"%s: %s - unexpected L2CA_Disconnect request message. " \
1283
"Invalid channel state, state=%d, lcid=%d\n",
1284
__func__, NG_NODE_NAME(l2cap->node), ch->state,
1285
ch->scid);
1286
error = EINVAL;
1287
goto out;
1288
}
1289
1290
/* Create and send L2CAP_DisconReq message */
1291
cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
1292
NG_L2CAP_DISCON_REQ, msg->header.token);
1293
if (cmd == NULL) {
1294
ng_l2cap_free_chan(ch);
1295
error = ENOMEM;
1296
goto out;
1297
}
1298
1299
if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1300
ng_l2cap_free_chan(ch);
1301
ng_l2cap_free_cmd(cmd);
1302
error = EIO;
1303
goto out;
1304
}
1305
1306
_ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid);
1307
if (cmd->aux == NULL) {
1308
ng_l2cap_free_chan(ch);
1309
ng_l2cap_free_cmd(cmd);
1310
error = ENOBUFS;
1311
goto out;
1312
}
1313
1314
ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP;
1315
1316
/* Link command to the queue */
1317
ng_l2cap_link_cmd(ch->con, cmd);
1318
ng_l2cap_lp_deliver(ch->con);
1319
out:
1320
return (error);
1321
} /* ng_l2cap_l2ca_discon_req */
1322
1323
/*
1324
* Send L2CA_Disconnect response to the upper layer protocol
1325
*/
1326
1327
int
1328
ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
1329
{
1330
ng_l2cap_p l2cap = ch->con->l2cap;
1331
struct ng_mesg *msg = NULL;
1332
ng_l2cap_l2ca_discon_op *op = NULL;
1333
int error = 0;
1334
1335
/* Check if upstream hook is connected and valid */
1336
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1337
NG_L2CAP_ERR(
1338
"%s: %s - unable to send L2CA_Disconnect response message. " \
1339
"Hook is not connected or valid, psm=%d\n",
1340
__func__, NG_NODE_NAME(l2cap->node), ch->psm);
1341
1342
return (ENOTCONN);
1343
}
1344
1345
/* Create and send L2CA_Disconnect response message */
1346
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON,
1347
sizeof(*op), M_NOWAIT);
1348
if (msg == NULL)
1349
error = ENOMEM;
1350
else {
1351
msg->header.token = token;
1352
msg->header.flags |= NGF_RESP;
1353
1354
op = (ng_l2cap_l2ca_discon_op *)(msg->data);
1355
op->result = result;
1356
1357
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1358
}
1359
1360
return (error);
1361
} /* ng_l2cap_l2ca_discon_rsp */
1362
1363
/*
1364
* Send L2CA_DisconnectInd message to the upper layer protocol.
1365
*/
1366
1367
int
1368
ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch)
1369
{
1370
ng_l2cap_p l2cap = ch->con->l2cap;
1371
struct ng_mesg *msg = NULL;
1372
ng_l2cap_l2ca_discon_ind_ip *ip = NULL;
1373
int error = 0;
1374
1375
/* Check if upstream hook is connected and valid */
1376
if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1377
NG_L2CAP_ERR(
1378
"%s: %s - unable to send L2CA_DisconnectInd message. " \
1379
"Hook is not connected or valid, psm=%d\n",
1380
__func__, NG_NODE_NAME(l2cap->node), ch->psm);
1381
1382
return (ENOTCONN);
1383
}
1384
1385
/* Create and send L2CA_DisconnectInd message */
1386
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND,
1387
sizeof(*ip), M_NOWAIT);
1388
if (msg == NULL)
1389
error = ENOMEM;
1390
else {
1391
ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data);
1392
ip->idtype = ch->idtype;
1393
if(ch->idtype == NG_L2CAP_L2CA_IDTYPE_ATT||
1394
ch->idtype == NG_L2CAP_L2CA_IDTYPE_SMP)
1395
ip->lcid = ch->con->con_handle;
1396
else
1397
ip->lcid = ch->scid;
1398
1399
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1400
}
1401
1402
return (error);
1403
} /* ng_l2cap_l2ca_discon_ind */
1404
1405
/*
1406
* Process L2CA_GroupCreate request from the upper layer protocol.
1407
* XXX FIXME
1408
*/
1409
1410
int
1411
ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg)
1412
{
1413
return (ENOTSUP);
1414
} /* ng_l2cap_l2ca_grp_create */
1415
1416
/*
1417
* Process L2CA_GroupClose request from the upper layer protocol
1418
* XXX FIXME
1419
*/
1420
1421
int
1422
ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg)
1423
{
1424
return (ENOTSUP);
1425
} /* ng_l2cap_l2ca_grp_close */
1426
1427
/*
1428
* Process L2CA_GroupAddMember request from the upper layer protocol.
1429
* XXX FIXME
1430
*/
1431
1432
int
1433
ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1434
{
1435
return (ENOTSUP);
1436
} /* ng_l2cap_l2ca_grp_add_member_req */
1437
1438
/*
1439
* Send L2CA_GroupAddMember response to the upper layer protocol.
1440
* XXX FIXME
1441
*/
1442
1443
int
1444
ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token,
1445
u_int16_t result)
1446
{
1447
return (0);
1448
} /* ng_l2cap_l2ca_grp_add_member_rsp */
1449
1450
/*
1451
* Process L2CA_GroupDeleteMember request from the upper layer protocol
1452
* XXX FIXME
1453
*/
1454
1455
int
1456
ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg)
1457
{
1458
return (ENOTSUP);
1459
} /* ng_l2cap_l2ca_grp_rem_member */
1460
1461
/*
1462
* Process L2CA_GroupGetMembers request from the upper layer protocol
1463
* XXX FIXME
1464
*/
1465
1466
int
1467
ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg)
1468
{
1469
return (ENOTSUP);
1470
} /* ng_l2cap_l2ca_grp_get_members */
1471
1472
/*
1473
* Process L2CA_Ping request from the upper layer protocol
1474
*/
1475
1476
int
1477
ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1478
{
1479
ng_l2cap_l2ca_ping_ip *ip = NULL;
1480
ng_l2cap_con_p con = NULL;
1481
ng_l2cap_cmd_p cmd = NULL;
1482
int error = 0;
1483
1484
/* Verify message */
1485
if (msg->header.arglen < sizeof(*ip)) {
1486
NG_L2CAP_ALERT(
1487
"%s: %s - invalid L2CA_Ping request message size, size=%d\n",
1488
__func__, NG_NODE_NAME(l2cap->node),
1489
msg->header.arglen);
1490
error = EMSGSIZE;
1491
goto out;
1492
}
1493
1494
ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
1495
if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
1496
NG_L2CAP_WARN(
1497
"%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n",
1498
__func__, NG_NODE_NAME(l2cap->node), ip->echo_size);
1499
error = EMSGSIZE;
1500
goto out;
1501
}
1502
1503
/* Check if we have connection to the unit */
1504
con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1505
if (con == NULL) {
1506
/* Submit LP_ConnectReq to the lower layer */
1507
error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1508
if (error != 0) {
1509
NG_L2CAP_ERR(
1510
"%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1511
__func__, NG_NODE_NAME(l2cap->node), error);
1512
goto out;
1513
}
1514
1515
/* This should not fail */
1516
con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1517
KASSERT((con != NULL),
1518
("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1519
}
1520
1521
/* Create L2CAP command descriptor */
1522
cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1523
NG_L2CAP_ECHO_REQ, msg->header.token);
1524
if (cmd == NULL) {
1525
error = ENOMEM;
1526
goto out;
1527
}
1528
1529
if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1530
ng_l2cap_free_cmd(cmd);
1531
error = EIO;
1532
goto out;
1533
}
1534
1535
/* Create L2CAP command packet */
1536
_ng_l2cap_echo_req(cmd->aux, cmd->ident,
1537
msg->data + sizeof(*ip), ip->echo_size);
1538
if (cmd->aux == NULL) {
1539
ng_l2cap_free_cmd(cmd);
1540
error = ENOBUFS;
1541
goto out;
1542
}
1543
1544
/* Link command to the queue */
1545
ng_l2cap_link_cmd(con, cmd);
1546
ng_l2cap_lp_deliver(con);
1547
out:
1548
return (error);
1549
} /* ng_l2cap_l2ca_ping_req */
1550
1551
/*
1552
* Send L2CA_Ping response to the upper layer protocol
1553
*/
1554
1555
int
1556
ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result,
1557
struct mbuf *data)
1558
{
1559
ng_l2cap_p l2cap = con->l2cap;
1560
struct ng_mesg *msg = NULL;
1561
ng_l2cap_l2ca_ping_op *op = NULL;
1562
int error = 0, size = 0;
1563
1564
/* Check if control hook is connected and valid */
1565
if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1566
NG_L2CAP_WARN(
1567
"%s: %s - unable to send L2CA_Ping response message. " \
1568
"Hook is not connected or valid\n",
1569
__func__, NG_NODE_NAME(l2cap->node));
1570
error = ENOTCONN;
1571
goto out;
1572
}
1573
1574
size = (data == NULL)? 0 : data->m_pkthdr.len;
1575
1576
/* Create and send L2CA_Ping response message */
1577
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING,
1578
sizeof(*op) + size, M_NOWAIT);
1579
if (msg == NULL)
1580
error = ENOMEM;
1581
else {
1582
msg->header.token = token;
1583
msg->header.flags |= NGF_RESP;
1584
1585
op = (ng_l2cap_l2ca_ping_op *)(msg->data);
1586
op->result = result;
1587
bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr));
1588
if (data != NULL && size > 0) {
1589
op->echo_size = size;
1590
m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1591
}
1592
1593
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1594
}
1595
out:
1596
NG_FREE_M(data);
1597
1598
return (error);
1599
} /* ng_l2cap_l2ca_ping_rsp */
1600
1601
/*
1602
* Process L2CA_GetInfo request from the upper layer protocol
1603
*/
1604
1605
int
1606
ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1607
{
1608
ng_l2cap_l2ca_get_info_ip *ip = NULL;
1609
ng_l2cap_con_p con = NULL;
1610
ng_l2cap_cmd_p cmd = NULL;
1611
int error = 0;
1612
1613
/* Verify message */
1614
if (msg->header.arglen != sizeof(*ip)) {
1615
NG_L2CAP_ALERT(
1616
"%s: %s - invalid L2CA_GetInfo request message size, size=%d\n",
1617
__func__, NG_NODE_NAME(l2cap->node),
1618
msg->header.arglen);
1619
error = EMSGSIZE;
1620
goto out;
1621
}
1622
1623
ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1624
1625
/* Check if we have connection to the unit */
1626
con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype);
1627
if (con == NULL) {
1628
/* Submit LP_ConnectReq to the lower layer */
1629
error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
1630
if (error != 0) {
1631
NG_L2CAP_ERR(
1632
"%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1633
__func__, NG_NODE_NAME(l2cap->node), error);
1634
goto out;
1635
}
1636
1637
/* This should not fail */
1638
con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
1639
KASSERT((con != NULL),
1640
("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1641
}
1642
1643
/* Create L2CAP command descriptor */
1644
cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1645
NG_L2CAP_INFO_REQ, msg->header.token);
1646
if (cmd == NULL) {
1647
error = ENOMEM;
1648
goto out;
1649
}
1650
1651
if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1652
ng_l2cap_free_cmd(cmd);
1653
error = EIO;
1654
goto out;
1655
}
1656
1657
/* Create L2CAP command packet */
1658
_ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type);
1659
if (cmd->aux == NULL) {
1660
ng_l2cap_free_cmd(cmd);
1661
error = ENOBUFS;
1662
goto out;
1663
}
1664
1665
/* Link command to the queue */
1666
ng_l2cap_link_cmd(con, cmd);
1667
ng_l2cap_lp_deliver(con);
1668
out:
1669
return (error);
1670
} /* ng_l2cap_l2ca_get_info_req */
1671
1672
/*
1673
* Send L2CA_GetInfo response to the upper layer protocol
1674
*/
1675
1676
int
1677
ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token,
1678
u_int16_t result, struct mbuf *data)
1679
{
1680
ng_l2cap_p l2cap = con->l2cap;
1681
struct ng_mesg *msg = NULL;
1682
ng_l2cap_l2ca_get_info_op *op = NULL;
1683
int error = 0, size;
1684
1685
/* Check if control hook is connected and valid */
1686
if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1687
NG_L2CAP_WARN(
1688
"%s: %s - unable to send L2CA_GetInfo response message. " \
1689
"Hook is not connected or valid\n",
1690
__func__, NG_NODE_NAME(l2cap->node));
1691
error = ENOTCONN;
1692
goto out;
1693
}
1694
1695
size = (data == NULL)? 0 : data->m_pkthdr.len;
1696
1697
/* Create and send L2CA_GetInfo response message */
1698
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO,
1699
sizeof(*op) + size, M_NOWAIT);
1700
if (msg == NULL)
1701
error = ENOMEM;
1702
else {
1703
msg->header.token = token;
1704
msg->header.flags |= NGF_RESP;
1705
1706
op = (ng_l2cap_l2ca_get_info_op *)(msg->data);
1707
op->result = result;
1708
if (data != NULL && size > 0) {
1709
op->info_size = size;
1710
m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1711
}
1712
1713
NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1714
}
1715
out:
1716
NG_FREE_M(data);
1717
1718
return (error);
1719
} /* ng_l2cap_l2ca_get_info_rsp */
1720
1721
/*
1722
* Process L2CA_EnableCLT message from the upper layer protocol
1723
* XXX convert to NGN_L2CAP_NODE_SET_FLAGS?
1724
*/
1725
1726
int
1727
ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg)
1728
{
1729
ng_l2cap_l2ca_enable_clt_ip *ip = NULL;
1730
int error = 0;
1731
#if 0
1732
* ng_l2cap_l2ca_enable_clt_op *op = NULL;
1733
* u_int16_t result;
1734
* u_int32_t token;
1735
#endif
1736
1737
/* Check message */
1738
if (msg->header.arglen != sizeof(*ip)) {
1739
NG_L2CAP_ALERT(
1740
"%s: %s - invalid L2CA_EnableCLT message size, size=%d\n",
1741
__func__, NG_NODE_NAME(l2cap->node),
1742
msg->header.arglen);
1743
1744
return (EMSGSIZE);
1745
}
1746
1747
/* Process request */
1748
ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data);
1749
#if 0
1750
* result = NG_L2CAP_SUCCESS;
1751
#endif
1752
1753
switch (ip->psm)
1754
{
1755
case 0:
1756
/* Special case: disable/enable all PSM */
1757
if (ip->enable)
1758
l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED |
1759
NG_L2CAP_CLT_RFCOMM_DISABLED |
1760
NG_L2CAP_CLT_TCP_DISABLED);
1761
else
1762
l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED |
1763
NG_L2CAP_CLT_RFCOMM_DISABLED |
1764
NG_L2CAP_CLT_TCP_DISABLED);
1765
break;
1766
1767
case NG_L2CAP_PSM_SDP:
1768
if (ip->enable)
1769
l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED;
1770
else
1771
l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED;
1772
break;
1773
1774
case NG_L2CAP_PSM_RFCOMM:
1775
if (ip->enable)
1776
l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED;
1777
else
1778
l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED;
1779
break;
1780
1781
case NG_L2CAP_PSM_TCP:
1782
if (ip->enable)
1783
l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED;
1784
else
1785
l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED;
1786
break;
1787
1788
default:
1789
NG_L2CAP_ERR(
1790
"%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm);
1791
#if 0
1792
* result = NG_L2CAP_PSM_NOT_SUPPORTED;
1793
#endif
1794
error = ENOTSUP;
1795
break;
1796
}
1797
1798
#if 0
1799
* /* Create and send response message */
1800
* token = msg->header.token;
1801
* NG_FREE_MSG(msg);
1802
* NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT,
1803
* sizeof(*op), M_NOWAIT);
1804
* if (msg == NULL)
1805
* error = ENOMEM;
1806
* else {
1807
* msg->header.token = token;
1808
* msg->header.flags |= NGF_RESP;
1809
*
1810
* op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data);
1811
* op->result = result;
1812
* }
1813
*
1814
* /* Send response to control hook */
1815
* if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl))
1816
* NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1817
#endif
1818
1819
return (error);
1820
} /* ng_l2cap_l2ca_enable_clt */
1821
1822