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