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