]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.c
Merge clang trunk r238337 from ^/vendor/clang/dist, resolve conflicts,
[FreeBSD/FreeBSD.git] / sys / netgraph / bluetooth / l2cap / ng_l2cap_cmds.c
1 /*
2  * ng_l2cap_cmds.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_cmds.c,v 1.2 2003/09/08 19:11:45 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_bluetooth.h>
44 #include <netgraph/bluetooth/include/ng_hci.h>
45 #include <netgraph/bluetooth/include/ng_l2cap.h>
46 #include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
47 #include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
48 #include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
49 #include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
50 #include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
51 #include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
52
53 /******************************************************************************
54  ******************************************************************************
55  **                    L2CAP commands processing module
56  ******************************************************************************
57  ******************************************************************************/
58
59 /*
60  * Process L2CAP command queue on connection
61  */
62
63 void
64 ng_l2cap_con_wakeup(ng_l2cap_con_p con)
65 {
66         ng_l2cap_cmd_p   cmd = NULL;
67         struct mbuf     *m = NULL;
68         int              error = 0;
69
70         /* Find first non-pending command in the queue */
71         TAILQ_FOREACH(cmd, &con->cmd_list, next) {
72                 KASSERT((cmd->con == con),
73 ("%s: %s - invalid connection pointer!\n",
74                         __func__, NG_NODE_NAME(con->l2cap->node)));
75
76                 if (!(cmd->flags & NG_L2CAP_CMD_PENDING))
77                         break;
78         }
79
80         if (cmd == NULL)
81                 return;
82
83         /* Detach command packet */
84         m = cmd->aux;
85         cmd->aux = NULL;
86
87         /* Process command */
88         switch (cmd->code) {
89         case NG_L2CAP_DISCON_RSP:
90         case NG_L2CAP_ECHO_RSP:
91         case NG_L2CAP_INFO_RSP:
92                 /*
93                  * Do not check return ng_l2cap_lp_send() value, because
94                  * in these cases we do not really have a graceful way out.
95                  * ECHO and INFO responses are internal to the stack and not
96                  * visible to user. REJect is just being nice to remote end
97                  * (otherwise remote end will timeout anyway). DISCON is
98                  * probably most interesting here, however, if it fails
99                  * there is nothing we can do anyway.
100                  */
101
102                 (void) ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
103                 ng_l2cap_unlink_cmd(cmd);
104                 ng_l2cap_free_cmd(cmd);
105                 break;
106         case NG_L2CAP_CMD_REJ:
107                 (void) ng_l2cap_lp_send(con,
108                                         (con->linktype == NG_HCI_LINK_ACL)?
109                                         NG_L2CAP_SIGNAL_CID:
110                                         NG_L2CAP_LESIGNAL_CID
111                                         , m);
112                 ng_l2cap_unlink_cmd(cmd);
113                 ng_l2cap_free_cmd(cmd);
114                 break;
115                 
116         case NG_L2CAP_CON_REQ:
117                 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
118                 if (error != 0) {
119                         ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token,
120                                 NG_L2CAP_NO_RESOURCES, 0);
121                         ng_l2cap_free_chan(cmd->ch); /* will free commands */
122                 } else
123                         ng_l2cap_command_timeout(cmd,
124                                 bluetooth_l2cap_rtx_timeout());
125                 break;
126         case NG_L2CAP_CON_RSP:
127                 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
128                 ng_l2cap_unlink_cmd(cmd);
129                 if (cmd->ch != NULL) {
130                         ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
131                                 (error == 0)? NG_L2CAP_SUCCESS : 
132                                         NG_L2CAP_NO_RESOURCES);
133                         if (error != 0)
134                                 ng_l2cap_free_chan(cmd->ch);
135                 }
136                 ng_l2cap_free_cmd(cmd);
137                 break;
138
139         case NG_L2CAP_CFG_REQ:
140                 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
141                 if (error != 0) {
142                         ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token,
143                                 NG_L2CAP_NO_RESOURCES);
144                         ng_l2cap_unlink_cmd(cmd);
145                         ng_l2cap_free_cmd(cmd);
146                 } else
147                         ng_l2cap_command_timeout(cmd,
148                                 bluetooth_l2cap_rtx_timeout());
149                 break;
150
151         case NG_L2CAP_CFG_RSP:
152                 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
153                 ng_l2cap_unlink_cmd(cmd);
154                 if (cmd->ch != NULL)
155                         ng_l2cap_l2ca_cfg_rsp_rsp(cmd->ch, cmd->token,
156                                 (error == 0)? NG_L2CAP_SUCCESS :
157                                         NG_L2CAP_NO_RESOURCES);
158                 ng_l2cap_free_cmd(cmd);
159                 break;
160
161         case NG_L2CAP_DISCON_REQ:
162                 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
163                 ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
164                         (error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES);
165                 if (error != 0)
166                         ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
167                 else
168                         ng_l2cap_command_timeout(cmd,
169                                 bluetooth_l2cap_rtx_timeout());
170                 break;
171
172         case NG_L2CAP_ECHO_REQ:
173                 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
174                 if (error != 0) {
175                         ng_l2cap_l2ca_ping_rsp(con, cmd->token,
176                                         NG_L2CAP_NO_RESOURCES, NULL);
177                         ng_l2cap_unlink_cmd(cmd);
178                         ng_l2cap_free_cmd(cmd);
179                 } else
180                         ng_l2cap_command_timeout(cmd, 
181                                 bluetooth_l2cap_rtx_timeout());
182                 break;
183
184         case NG_L2CAP_INFO_REQ:
185                 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
186                 if (error != 0) {
187                         ng_l2cap_l2ca_get_info_rsp(con, cmd->token, 
188                                 NG_L2CAP_NO_RESOURCES, NULL);
189                         ng_l2cap_unlink_cmd(cmd);
190                         ng_l2cap_free_cmd(cmd);
191                 } else
192                         ng_l2cap_command_timeout(cmd, 
193                                 bluetooth_l2cap_rtx_timeout());
194                 break;
195
196         case NGM_L2CAP_L2CA_WRITE: {
197                 int     length = m->m_pkthdr.len;
198
199                 if (cmd->ch->dcid == NG_L2CAP_CLT_CID) {
200                         m = ng_l2cap_prepend(m, sizeof(ng_l2cap_clt_hdr_t));
201                         if (m == NULL)
202                                 error = ENOBUFS;
203                         else
204                                 mtod(m, ng_l2cap_clt_hdr_t *)->psm =
205                                                         htole16(cmd->ch->psm);
206                 }
207
208                 if (error == 0)
209                         error = ng_l2cap_lp_send(con, cmd->ch->dcid, m);
210
211                 ng_l2cap_l2ca_write_rsp(cmd->ch, cmd->token,
212                         (error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES,
213                         length);
214
215                 ng_l2cap_unlink_cmd(cmd);
216                 ng_l2cap_free_cmd(cmd);
217                 } break;
218         case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE:
219                 error = ng_l2cap_lp_send(con, NG_L2CAP_LESIGNAL_CID, m);
220                 ng_l2cap_unlink_cmd(cmd);
221                 ng_l2cap_free_cmd(cmd);
222                 break;
223         case NG_L2CAP_CMD_PARAM_UPDATE_REQUEST:
224                   /*TBD.*/
225         /* XXX FIXME add other commands */
226         default:
227                 panic(
228 "%s: %s - unknown command code=%d\n",
229                         __func__, NG_NODE_NAME(con->l2cap->node), cmd->code);
230                 break;
231         }
232 } /* ng_l2cap_con_wakeup */
233
234 /*
235  * We have failed to open ACL connection to the remote unit. Could be negative
236  * confirmation or timeout. So fail any "delayed" commands, notify upper layer,
237  * remove all channels and remove connection descriptor.
238  */
239
240 void
241 ng_l2cap_con_fail(ng_l2cap_con_p con, u_int16_t result)
242 {
243         ng_l2cap_p      l2cap = con->l2cap;
244         ng_l2cap_cmd_p  cmd = NULL;
245         ng_l2cap_chan_p ch = NULL;
246
247         NG_L2CAP_INFO(
248 "%s: %s - ACL connection failed, result=%d\n",
249                 __func__, NG_NODE_NAME(l2cap->node), result);
250
251         /* Connection is dying */
252         con->flags |= NG_L2CAP_CON_DYING;
253
254         /* Clean command queue */
255         while (!TAILQ_EMPTY(&con->cmd_list)) {
256                 cmd = TAILQ_FIRST(&con->cmd_list);
257
258                 ng_l2cap_unlink_cmd(cmd);
259                 if(cmd->flags & NG_L2CAP_CMD_PENDING)
260                         ng_l2cap_command_untimeout(cmd);
261
262                 KASSERT((cmd->con == con),
263 ("%s: %s - invalid connection pointer!\n",
264                         __func__, NG_NODE_NAME(l2cap->node)));
265
266                 switch (cmd->code) {
267                 case NG_L2CAP_CMD_REJ:
268                 case NG_L2CAP_DISCON_RSP:
269                 case NG_L2CAP_ECHO_RSP:
270                 case NG_L2CAP_INFO_RSP:
271                 case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE:
272                         break;
273
274                 case NG_L2CAP_CON_REQ:
275                         ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, result, 0);
276                         break;
277
278                 case NG_L2CAP_CON_RSP:
279                         if (cmd->ch != NULL)
280                                 ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
281                                         result);
282                         break;
283
284                 case NG_L2CAP_CFG_REQ:
285                 case NG_L2CAP_CFG_RSP:
286                 case NGM_L2CAP_L2CA_WRITE:
287                         ng_l2cap_l2ca_discon_ind(cmd->ch);
288                         break;
289
290                 case NG_L2CAP_DISCON_REQ:
291                         ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
292                                 NG_L2CAP_SUCCESS);
293                         break;
294
295                 case NG_L2CAP_ECHO_REQ:
296                         ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
297                                 result, NULL);
298                         break;
299
300                 case NG_L2CAP_INFO_REQ:
301                         ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
302                                 result, NULL);
303                         break;
304
305                 /* XXX FIXME add other commands */
306
307                 default:
308                         panic(
309 "%s: %s - unexpected command code=%d\n",
310                                 __func__, NG_NODE_NAME(l2cap->node), cmd->code);
311                         break;
312                 }
313
314                 if (cmd->ch != NULL)
315                         ng_l2cap_free_chan(cmd->ch);
316
317                 ng_l2cap_free_cmd(cmd);
318         }
319
320         /*
321          * There still might be channels (in OPEN state?) that
322          * did not submit any commands, so disconnect them
323          */
324
325         LIST_FOREACH(ch, &l2cap->chan_list, next)
326                 if (ch->con == con)
327                         ng_l2cap_l2ca_discon_ind(ch);
328
329         /* Free connection descriptor */
330         ng_l2cap_free_con(con);
331 } /* ng_l2cap_con_fail */
332
333 /*
334  * Process L2CAP command timeout. In general - notify upper layer and destroy
335  * channel. Do not pay much attension to return code, just do our best.
336  */
337
338 void
339 ng_l2cap_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2)
340 {
341         ng_l2cap_p      l2cap = NULL;
342         ng_l2cap_con_p  con = NULL;
343         ng_l2cap_cmd_p  cmd = NULL;
344         u_int16_t       con_handle = (arg2 & 0x0ffff);
345         u_int8_t        ident = ((arg2 >> 16) & 0xff);
346
347         if (NG_NODE_NOT_VALID(node)) {
348                 printf("%s: Netgraph node is not valid\n", __func__);
349                 return;
350         }
351
352         l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
353
354         con = ng_l2cap_con_by_handle(l2cap, con_handle);
355         if (con == NULL) {
356                 NG_L2CAP_ALERT(
357 "%s: %s - could not find connection, con_handle=%d\n",
358                         __func__, NG_NODE_NAME(node), con_handle);
359                 return;
360         }
361
362         cmd = ng_l2cap_cmd_by_ident(con, ident);
363         if (cmd == NULL) {
364                 NG_L2CAP_ALERT(
365 "%s: %s - could not find command, con_handle=%d, ident=%d\n",
366                         __func__, NG_NODE_NAME(node), con_handle, ident);
367                 return;
368         }
369
370         cmd->flags &= ~NG_L2CAP_CMD_PENDING;
371         ng_l2cap_unlink_cmd(cmd);
372
373         switch (cmd->code) {
374         case NG_L2CAP_CON_REQ:
375                 ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT, 0);
376                 ng_l2cap_free_chan(cmd->ch); 
377                 break;
378
379         case NG_L2CAP_CFG_REQ:
380                 ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
381                 break;
382
383         case NG_L2CAP_DISCON_REQ:
384                 ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
385                 ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
386                 break;
387
388         case NG_L2CAP_ECHO_REQ:
389                 /* Echo request timed out. Let the upper layer know */
390                 ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
391                         NG_L2CAP_TIMEOUT, NULL);
392                 break;
393
394         case NG_L2CAP_INFO_REQ:
395                 /* Info request timed out. Let the upper layer know */
396                 ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
397                         NG_L2CAP_TIMEOUT, NULL);
398                 break;
399
400         /* XXX FIXME add other commands */
401
402         default:
403                 panic(
404 "%s: %s - unexpected command code=%d\n",
405                         __func__, NG_NODE_NAME(l2cap->node), cmd->code);
406                 break;
407         }
408
409         ng_l2cap_free_cmd(cmd);
410 } /* ng_l2cap_process_command_timeout */
411