blob: c1fb5db8104215642371b1ff664c96e4f4b62a6c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*********************************************************************
2 *
3 * Filename: irlmp_event.c
4 * Version: 0.8
5 * Description: An IrDA LMP event driver for Linux
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Mon Aug 4 20:40:53 1997
9 * Modified at: Tue Dec 14 23:04:16 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 *
12 * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
13 * All Rights Reserved.
14 * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License as
18 * published by the Free Software Foundation; either version 2 of
19 * the License, or (at your option) any later version.
20 *
Jan Engelhardt96de0e22007-10-19 23:21:04 +020021 * Neither Dag Brattli nor University of Tromsø admit liability nor
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 * provide warranty for any of this software. This material is
23 * provided "AS-IS" and at no charge.
24 *
25 ********************************************************************/
26
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/kernel.h>
28
29#include <net/irda/irda.h>
30#include <net/irda/timer.h>
31#include <net/irda/irlap.h>
32#include <net/irda/irlmp.h>
33#include <net/irda/irlmp_frame.h>
34#include <net/irda/irlmp_event.h>
35
Jan Engelhardt36cbd3d2009-08-05 10:42:58 -070036const char *const irlmp_state[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 "LAP_STANDBY",
38 "LAP_U_CONNECT",
39 "LAP_ACTIVE",
40};
41
Jan Engelhardt36cbd3d2009-08-05 10:42:58 -070042const char *const irlsap_state[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 "LSAP_DISCONNECTED",
44 "LSAP_CONNECT",
45 "LSAP_CONNECT_PEND",
46 "LSAP_DATA_TRANSFER_READY",
47 "LSAP_SETUP",
48 "LSAP_SETUP_PEND",
49};
50
51#ifdef CONFIG_IRDA_DEBUG
Jan Engelhardt36cbd3d2009-08-05 10:42:58 -070052static const char *const irlmp_event[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 "LM_CONNECT_REQUEST",
54 "LM_CONNECT_CONFIRM",
55 "LM_CONNECT_RESPONSE",
56 "LM_CONNECT_INDICATION",
57
58 "LM_DISCONNECT_INDICATION",
59 "LM_DISCONNECT_REQUEST",
60
61 "LM_DATA_REQUEST",
62 "LM_UDATA_REQUEST",
63 "LM_DATA_INDICATION",
64 "LM_UDATA_INDICATION",
65
66 "LM_WATCHDOG_TIMEOUT",
67
68 /* IrLAP events */
69 "LM_LAP_CONNECT_REQUEST",
70 "LM_LAP_CONNECT_INDICATION",
71 "LM_LAP_CONNECT_CONFIRM",
72 "LM_LAP_DISCONNECT_INDICATION",
73 "LM_LAP_DISCONNECT_REQUEST",
74 "LM_LAP_DISCOVERY_REQUEST",
75 "LM_LAP_DISCOVERY_CONFIRM",
76 "LM_LAP_IDLE_TIMEOUT",
77};
78#endif /* CONFIG_IRDA_DEBUG */
79
80/* LAP Connection control proto declarations */
81static void irlmp_state_standby (struct lap_cb *, IRLMP_EVENT,
82 struct sk_buff *);
83static void irlmp_state_u_connect(struct lap_cb *, IRLMP_EVENT,
84 struct sk_buff *);
85static void irlmp_state_active (struct lap_cb *, IRLMP_EVENT,
86 struct sk_buff *);
87
88/* LSAP Connection control proto declarations */
89static int irlmp_state_disconnected(struct lsap_cb *, IRLMP_EVENT,
90 struct sk_buff *);
91static int irlmp_state_connect (struct lsap_cb *, IRLMP_EVENT,
92 struct sk_buff *);
93static int irlmp_state_connect_pend(struct lsap_cb *, IRLMP_EVENT,
94 struct sk_buff *);
95static int irlmp_state_dtr (struct lsap_cb *, IRLMP_EVENT,
96 struct sk_buff *);
97static int irlmp_state_setup (struct lsap_cb *, IRLMP_EVENT,
98 struct sk_buff *);
99static int irlmp_state_setup_pend (struct lsap_cb *, IRLMP_EVENT,
100 struct sk_buff *);
101
102static void (*lap_state[]) (struct lap_cb *, IRLMP_EVENT, struct sk_buff *) =
103{
104 irlmp_state_standby,
105 irlmp_state_u_connect,
106 irlmp_state_active,
107};
108
109static int (*lsap_state[])( struct lsap_cb *, IRLMP_EVENT, struct sk_buff *) =
110{
111 irlmp_state_disconnected,
112 irlmp_state_connect,
113 irlmp_state_connect_pend,
114 irlmp_state_dtr,
115 irlmp_state_setup,
116 irlmp_state_setup_pend
117};
118
119static inline void irlmp_next_lap_state(struct lap_cb *self,
120 IRLMP_STATE state)
121{
122 /*
Harvey Harrison0dc47872008-03-05 20:47:47 -0800123 IRDA_DEBUG(4, "%s(), LMP LAP = %s\n", __func__, irlmp_state[state]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 */
125 self->lap_state = state;
126}
127
128static inline void irlmp_next_lsap_state(struct lsap_cb *self,
129 LSAP_STATE state)
130{
131 /*
132 IRDA_ASSERT(self != NULL, return;);
Harvey Harrison0dc47872008-03-05 20:47:47 -0800133 IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __func__, irlsap_state[state]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 */
135 self->lsap_state = state;
136}
137
138/* Do connection control events */
139int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event,
140 struct sk_buff *skb)
141{
142 IRDA_ASSERT(self != NULL, return -1;);
143 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
144
145 IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800146 __func__, irlmp_event[event], irlsap_state[ self->lsap_state]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148 return (*lsap_state[self->lsap_state]) (self, event, skb);
149}
150
151/*
152 * Function do_lap_event (event, skb, info)
153 *
154 * Do IrLAP control events
155 *
156 */
157void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event,
158 struct sk_buff *skb)
159{
160 IRDA_ASSERT(self != NULL, return;);
161 IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
162
Harvey Harrison0dc47872008-03-05 20:47:47 -0800163 IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 irlmp_event[event],
165 irlmp_state[self->lap_state]);
166
167 (*lap_state[self->lap_state]) (self, event, skb);
168}
169
170void irlmp_discovery_timer_expired(void *data)
171{
Harvey Harrison0dc47872008-03-05 20:47:47 -0800172 IRDA_DEBUG(4, "%s()\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
174 /* We always cleanup the log (active & passive discovery) */
175 irlmp_do_expiry();
176
Ross Burton91cde6f2008-01-22 18:27:53 -0800177 irlmp_do_discovery(sysctl_discovery_slots);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179 /* Restart timer */
180 irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout * HZ);
181}
182
183void irlmp_watchdog_timer_expired(void *data)
184{
185 struct lsap_cb *self = (struct lsap_cb *) data;
186
Harvey Harrison0dc47872008-03-05 20:47:47 -0800187 IRDA_DEBUG(2, "%s()\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
189 IRDA_ASSERT(self != NULL, return;);
190 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
191
192 irlmp_do_lsap_event(self, LM_WATCHDOG_TIMEOUT, NULL);
193}
194
195void irlmp_idle_timer_expired(void *data)
196{
197 struct lap_cb *self = (struct lap_cb *) data;
198
Harvey Harrison0dc47872008-03-05 20:47:47 -0800199 IRDA_DEBUG(2, "%s()\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
201 IRDA_ASSERT(self != NULL, return;);
202 IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
203
204 irlmp_do_lap_event(self, LM_LAP_IDLE_TIMEOUT, NULL);
205}
206
207/*
208 * Send an event on all LSAPs attached to this LAP.
209 */
210static inline void
211irlmp_do_all_lsap_event(hashbin_t * lsap_hashbin,
212 IRLMP_EVENT event)
213{
214 struct lsap_cb *lsap;
215 struct lsap_cb *lsap_next;
216
217 /* Note : this function use the new hashbin_find_next()
218 * function, instead of the old hashbin_get_next().
219 * This make sure that we are always pointing one lsap
220 * ahead, so that if the current lsap is removed as the
221 * result of sending the event, we don't care.
222 * Also, as we store the context ourselves, if an enumeration
223 * of the same lsap hashbin happens as the result of sending the
224 * event, we don't care.
225 * The only problem is if the next lsap is removed. In that case,
226 * hashbin_find_next() will return NULL and we will abort the
227 * enumeration. - Jean II */
228
229 /* Also : we don't accept any skb in input. We can *NOT* pass
230 * the same skb to multiple clients safely, we would need to
231 * skb_clone() it. - Jean II */
232
233 lsap = (struct lsap_cb *) hashbin_get_first(lsap_hashbin);
234
235 while (NULL != hashbin_find_next(lsap_hashbin,
236 (long) lsap,
237 NULL,
238 (void *) &lsap_next) ) {
239 irlmp_do_lsap_event(lsap, event, NULL);
240 lsap = lsap_next;
241 }
242}
243
244/*********************************************************************
245 *
246 * LAP connection control states
247 *
248 ********************************************************************/
249
250/*
251 * Function irlmp_state_standby (event, skb, info)
252 *
253 * STANDBY, The IrLAP connection does not exist.
254 *
255 */
256static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
257 struct sk_buff *skb)
258{
Harvey Harrison0dc47872008-03-05 20:47:47 -0800259 IRDA_DEBUG(4, "%s()\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 IRDA_ASSERT(self->irlap != NULL, return;);
261
262 switch (event) {
263 case LM_LAP_DISCOVERY_REQUEST:
264 /* irlmp_next_station_state( LMP_DISCOVER); */
265
266 irlap_discovery_request(self->irlap, &irlmp->discovery_cmd);
267 break;
268 case LM_LAP_CONNECT_INDICATION:
269 /* It's important to switch state first, to avoid IrLMP to
270 * think that the link is free since IrLMP may then start
271 * discovery before the connection is properly set up. DB.
272 */
273 irlmp_next_lap_state(self, LAP_ACTIVE);
274
275 /* Just accept connection TODO, this should be fixed */
276 irlap_connect_response(self->irlap, skb);
277 break;
278 case LM_LAP_CONNECT_REQUEST:
Harvey Harrison0dc47872008-03-05 20:47:47 -0800279 IRDA_DEBUG(4, "%s() LS_CONNECT_REQUEST\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
281 irlmp_next_lap_state(self, LAP_U_CONNECT);
282
283 /* FIXME: need to set users requested QoS */
284 irlap_connect_request(self->irlap, self->daddr, NULL, 0);
285 break;
286 case LM_LAP_DISCONNECT_INDICATION:
287 IRDA_DEBUG(4, "%s(), Error LM_LAP_DISCONNECT_INDICATION\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800288 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290 irlmp_next_lap_state(self, LAP_STANDBY);
291 break;
292 default:
293 IRDA_DEBUG(0, "%s(), Unknown event %s\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800294 __func__, irlmp_event[event]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 break;
296 }
297}
298
299/*
300 * Function irlmp_state_u_connect (event, skb, info)
301 *
302 * U_CONNECT, The layer above has tried to open an LSAP connection but
303 * since the IrLAP connection does not exist, we must first start an
304 * IrLAP connection. We are now waiting response from IrLAP.
305 * */
306static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
307 struct sk_buff *skb)
308{
Harvey Harrison0dc47872008-03-05 20:47:47 -0800309 IRDA_DEBUG(2, "%s(), event=%s\n", __func__, irlmp_event[event]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 switch (event) {
312 case LM_LAP_CONNECT_INDICATION:
313 /* It's important to switch state first, to avoid IrLMP to
314 * think that the link is free since IrLMP may then start
315 * discovery before the connection is properly set up. DB.
316 */
317 irlmp_next_lap_state(self, LAP_ACTIVE);
318
319 /* Just accept connection TODO, this should be fixed */
320 irlap_connect_response(self->irlap, skb);
321
322 /* Tell LSAPs that they can start sending data */
323 irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);
324
325 /* Note : by the time we get there (LAP retries and co),
326 * the lsaps may already have gone. This avoid getting stuck
327 * forever in LAP_ACTIVE state - Jean II */
328 if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
Harvey Harrison0dc47872008-03-05 20:47:47 -0800329 IRDA_DEBUG(0, "%s() NO LSAPs !\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
331 }
332 break;
333 case LM_LAP_CONNECT_REQUEST:
334 /* Already trying to connect */
335 break;
336 case LM_LAP_CONNECT_CONFIRM:
337 /* For all lsap_ce E Associated do LS_Connect_confirm */
338 irlmp_next_lap_state(self, LAP_ACTIVE);
339
340 /* Tell LSAPs that they can start sending data */
341 irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);
342
343 /* Note : by the time we get there (LAP retries and co),
344 * the lsaps may already have gone. This avoid getting stuck
345 * forever in LAP_ACTIVE state - Jean II */
346 if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
Harvey Harrison0dc47872008-03-05 20:47:47 -0800347 IRDA_DEBUG(0, "%s() NO LSAPs !\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
349 }
350 break;
351 case LM_LAP_DISCONNECT_INDICATION:
Harvey Harrison0dc47872008-03-05 20:47:47 -0800352 IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_INDICATION\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 irlmp_next_lap_state(self, LAP_STANDBY);
354
355 /* Send disconnect event to all LSAPs using this link */
356 irlmp_do_all_lsap_event(self->lsaps,
357 LM_LAP_DISCONNECT_INDICATION);
358 break;
359 case LM_LAP_DISCONNECT_REQUEST:
Harvey Harrison0dc47872008-03-05 20:47:47 -0800360 IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_REQUEST\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362 /* One of the LSAP did timeout or was closed, if it was
363 * the last one, try to get out of here - Jean II */
364 if (HASHBIN_GET_SIZE(self->lsaps) <= 1) {
365 irlap_disconnect_request(self->irlap);
366 }
367 break;
368 default:
369 IRDA_DEBUG(0, "%s(), Unknown event %s\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800370 __func__, irlmp_event[event]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 break;
372 }
373}
374
375/*
376 * Function irlmp_state_active (event, skb, info)
377 *
378 * ACTIVE, IrLAP connection is active
379 *
380 */
381static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
382 struct sk_buff *skb)
383{
Harvey Harrison0dc47872008-03-05 20:47:47 -0800384 IRDA_DEBUG(4, "%s()\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
386 switch (event) {
387 case LM_LAP_CONNECT_REQUEST:
Harvey Harrison0dc47872008-03-05 20:47:47 -0800388 IRDA_DEBUG(4, "%s(), LS_CONNECT_REQUEST\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
390 /*
391 * IrLAP may have a pending disconnect. We tried to close
392 * IrLAP, but it was postponed because the link was
393 * busy or we were still sending packets. As we now
394 * need it, make sure it stays on. Jean II
395 */
396 irlap_clear_disconnect(self->irlap);
397
398 /*
399 * LAP connection already active, just bounce back! Since we
400 * don't know which LSAP that tried to do this, we have to
401 * notify all LSAPs using this LAP, but that should be safe to
402 * do anyway.
403 */
404 irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);
405
406 /* Needed by connect indication */
407 irlmp_do_all_lsap_event(irlmp->unconnected_lsaps,
408 LM_LAP_CONNECT_CONFIRM);
409 /* Keep state */
410 break;
411 case LM_LAP_DISCONNECT_REQUEST:
412 /*
413 * Need to find out if we should close IrLAP or not. If there
414 * is only one LSAP connection left on this link, that LSAP
415 * must be the one that tries to close IrLAP. It will be
416 * removed later and moved to the list of unconnected LSAPs
417 */
418 if (HASHBIN_GET_SIZE(self->lsaps) > 0) {
419 /* Timer value is checked in irsysctl - Jean II */
420 irlmp_start_idle_timer(self, sysctl_lap_keepalive_time * HZ / 1000);
421 } else {
422 /* No more connections, so close IrLAP */
423
424 /* We don't want to change state just yet, because
425 * we want to reflect accurately the real state of
426 * the LAP, not the state we wish it was in,
427 * so that we don't lose LM_LAP_CONNECT_REQUEST.
428 * In some cases, IrLAP won't close the LAP
429 * immediately. For example, it might still be
430 * retrying packets or waiting for the pf bit.
431 * As the LAP always send a DISCONNECT_INDICATION
432 * in PCLOSE or SCLOSE, just change state on that.
433 * Jean II */
434 irlap_disconnect_request(self->irlap);
435 }
436 break;
437 case LM_LAP_IDLE_TIMEOUT:
438 if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
439 /* Same reasoning as above - keep state */
440 irlap_disconnect_request(self->irlap);
441 }
442 break;
443 case LM_LAP_DISCONNECT_INDICATION:
444 irlmp_next_lap_state(self, LAP_STANDBY);
445
446 /* In some case, at this point our side has already closed
447 * all lsaps, and we are waiting for the idle_timer to
448 * expire. If another device reconnect immediately, the
449 * idle timer will expire in the midle of the connection
450 * initialisation, screwing up things a lot...
451 * Therefore, we must stop the timer... */
452 irlmp_stop_idle_timer(self);
453
454 /*
455 * Inform all connected LSAP's using this link
456 */
457 irlmp_do_all_lsap_event(self->lsaps,
458 LM_LAP_DISCONNECT_INDICATION);
459
460 /* Force an expiry of the discovery log.
461 * Now that the LAP is free, the system may attempt to
462 * connect to another device. Unfortunately, our entries
463 * are stale. There is a small window (<3s) before the
464 * normal discovery will run and where irlmp_connect_request()
465 * can get the wrong info, so make sure things get
466 * cleaned *NOW* ;-) - Jean II */
467 irlmp_do_expiry();
468 break;
469 default:
470 IRDA_DEBUG(0, "%s(), Unknown event %s\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800471 __func__, irlmp_event[event]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 break;
473 }
474}
475
476/*********************************************************************
477 *
478 * LSAP connection control states
479 *
480 ********************************************************************/
481
482/*
483 * Function irlmp_state_disconnected (event, skb, info)
484 *
485 * DISCONNECTED
486 *
487 */
488static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
489 struct sk_buff *skb)
490{
491 int ret = 0;
492
Harvey Harrison0dc47872008-03-05 20:47:47 -0800493 IRDA_DEBUG(4, "%s()\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 IRDA_ASSERT(self != NULL, return -1;);
496 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
497
498 switch (event) {
499#ifdef CONFIG_IRDA_ULTRA
500 case LM_UDATA_INDICATION:
501 /* This is most bizzare. Those packets are aka unreliable
502 * connected, aka IrLPT or SOCK_DGRAM/IRDAPROTO_UNITDATA.
503 * Why do we pass them as Ultra ??? Jean II */
504 irlmp_connless_data_indication(self, skb);
505 break;
506#endif /* CONFIG_IRDA_ULTRA */
507 case LM_CONNECT_REQUEST:
Harvey Harrison0dc47872008-03-05 20:47:47 -0800508 IRDA_DEBUG(4, "%s(), LM_CONNECT_REQUEST\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 if (self->conn_skb) {
511 IRDA_WARNING("%s: busy with another request!\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800512 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 return -EBUSY;
514 }
515 /* Don't forget to refcount it (see irlmp_connect_request()) */
516 skb_get(skb);
517 self->conn_skb = skb;
518
519 irlmp_next_lsap_state(self, LSAP_SETUP_PEND);
520
521 /* Start watchdog timer (5 secs for now) */
522 irlmp_start_watchdog_timer(self, 5*HZ);
523
524 irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
525 break;
526 case LM_CONNECT_INDICATION:
527 if (self->conn_skb) {
528 IRDA_WARNING("%s: busy with another request!\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800529 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 return -EBUSY;
531 }
532 /* Don't forget to refcount it (see irlap_driver_rcv()) */
533 skb_get(skb);
534 self->conn_skb = skb;
535
536 irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
537
538 /* Start watchdog timer
539 * This is not mentionned in the spec, but there is a rare
540 * race condition that can get the socket stuck.
541 * If we receive this event while our LAP is closing down,
542 * the LM_LAP_CONNECT_REQUEST get lost and we get stuck in
543 * CONNECT_PEND state forever.
544 * The other cause of getting stuck down there is if the
545 * higher layer never reply to the CONNECT_INDICATION.
546 * Anyway, it make sense to make sure that we always have
547 * a backup plan. 1 second is plenty (should be immediate).
548 * Jean II */
549 irlmp_start_watchdog_timer(self, 1*HZ);
550
551 irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
552 break;
553 default:
554 IRDA_DEBUG(1, "%s(), Unknown event %s on LSAP %#02x\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800555 __func__, irlmp_event[event], self->slsap_sel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 break;
557 }
558 return ret;
559}
560
561/*
562 * Function irlmp_state_connect (self, event, skb)
563 *
564 * CONNECT
565 *
566 */
567static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event,
568 struct sk_buff *skb)
569{
570 struct lsap_cb *lsap;
571 int ret = 0;
572
Harvey Harrison0dc47872008-03-05 20:47:47 -0800573 IRDA_DEBUG(4, "%s()\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
575 IRDA_ASSERT(self != NULL, return -1;);
576 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
577
578 switch (event) {
579 case LM_CONNECT_RESPONSE:
580 /*
581 * Bind this LSAP to the IrLAP link where the connect was
582 * received
583 */
584 lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self,
585 NULL);
586
587 IRDA_ASSERT(lsap == self, return -1;);
588 IRDA_ASSERT(self->lap != NULL, return -1;);
589 IRDA_ASSERT(self->lap->lsaps != NULL, return -1;);
590
591 hashbin_insert(self->lap->lsaps, (irda_queue_t *) self,
592 (long) self, NULL);
593
594 set_bit(0, &self->connected); /* TRUE */
595
596 irlmp_send_lcf_pdu(self->lap, self->dlsap_sel,
597 self->slsap_sel, CONNECT_CNF, skb);
598
599 del_timer(&self->watchdog_timer);
600
601 irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY);
602 break;
603 case LM_WATCHDOG_TIMEOUT:
604 /* May happen, who knows...
605 * Jean II */
Harvey Harrison0dc47872008-03-05 20:47:47 -0800606 IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608 /* Disconnect, get out... - Jean II */
609 self->lap = NULL;
610 self->dlsap_sel = LSAP_ANY;
611 irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
612 break;
613 default:
614 /* LM_LAP_DISCONNECT_INDICATION : Should never happen, we
615 * are *not* yet bound to the IrLAP link. Jean II */
YOSHIFUJI Hideaki6819bc22007-02-09 23:24:53 +0900616 IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800617 __func__, irlmp_event[event], self->slsap_sel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 break;
619 }
620 return ret;
621}
622
623/*
624 * Function irlmp_state_connect_pend (event, skb, info)
625 *
626 * CONNECT_PEND
627 *
628 */
629static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
630 struct sk_buff *skb)
631{
632 struct sk_buff *tx_skb;
633 int ret = 0;
634
Harvey Harrison0dc47872008-03-05 20:47:47 -0800635 IRDA_DEBUG(4, "%s()\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637 IRDA_ASSERT(self != NULL, return -1;);
638 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
639
640 switch (event) {
641 case LM_CONNECT_REQUEST:
642 /* Keep state */
643 break;
644 case LM_CONNECT_RESPONSE:
645 IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, "
Harvey Harrison0dc47872008-03-05 20:47:47 -0800646 "no indication issued yet\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 /* Keep state */
648 break;
649 case LM_DISCONNECT_REQUEST:
650 IRDA_DEBUG(0, "%s(), LM_DISCONNECT_REQUEST, "
Harvey Harrison0dc47872008-03-05 20:47:47 -0800651 "not yet bound to IrLAP connection\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 /* Keep state */
653 break;
654 case LM_LAP_CONNECT_CONFIRM:
Harvey Harrison0dc47872008-03-05 20:47:47 -0800655 IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 irlmp_next_lsap_state(self, LSAP_CONNECT);
657
658 tx_skb = self->conn_skb;
659 self->conn_skb = NULL;
660
661 irlmp_connect_indication(self, tx_skb);
662 /* Drop reference count - see irlmp_connect_indication(). */
663 dev_kfree_skb(tx_skb);
664 break;
665 case LM_WATCHDOG_TIMEOUT:
666 /* Will happen in some rare cases because of a race condition.
667 * Just make sure we don't stay there forever...
668 * Jean II */
Harvey Harrison0dc47872008-03-05 20:47:47 -0800669 IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
671 /* Go back to disconnected mode, keep the socket waiting */
672 self->lap = NULL;
673 self->dlsap_sel = LSAP_ANY;
674 if(self->conn_skb)
675 dev_kfree_skb(self->conn_skb);
676 self->conn_skb = NULL;
677 irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
678 break;
679 default:
680 /* LM_LAP_DISCONNECT_INDICATION : Should never happen, we
681 * are *not* yet bound to the IrLAP link. Jean II */
682 IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800683 __func__, irlmp_event[event], self->slsap_sel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 break;
685 }
686 return ret;
687}
688
689/*
690 * Function irlmp_state_dtr (self, event, skb)
691 *
692 * DATA_TRANSFER_READY
693 *
694 */
695static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event,
696 struct sk_buff *skb)
697{
698 LM_REASON reason;
699 int ret = 0;
700
Harvey Harrison0dc47872008-03-05 20:47:47 -0800701 IRDA_DEBUG(4, "%s()\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703 IRDA_ASSERT(self != NULL, return -1;);
704 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
705 IRDA_ASSERT(self->lap != NULL, return -1;);
706
707 switch (event) {
708 case LM_DATA_REQUEST: /* Optimize for the common case */
709 irlmp_send_data_pdu(self->lap, self->dlsap_sel,
710 self->slsap_sel, FALSE, skb);
711 break;
712 case LM_DATA_INDICATION: /* Optimize for the common case */
713 irlmp_data_indication(self, skb);
714 break;
715 case LM_UDATA_REQUEST:
716 IRDA_ASSERT(skb != NULL, return -1;);
717 irlmp_send_data_pdu(self->lap, self->dlsap_sel,
718 self->slsap_sel, TRUE, skb);
719 break;
720 case LM_UDATA_INDICATION:
721 irlmp_udata_indication(self, skb);
722 break;
723 case LM_CONNECT_REQUEST:
724 IRDA_DEBUG(0, "%s(), LM_CONNECT_REQUEST, "
Harvey Harrison0dc47872008-03-05 20:47:47 -0800725 "error, LSAP already connected\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 /* Keep state */
727 break;
728 case LM_CONNECT_RESPONSE:
729 IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, "
Harvey Harrison0dc47872008-03-05 20:47:47 -0800730 "error, LSAP already connected\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 /* Keep state */
732 break;
733 case LM_DISCONNECT_REQUEST:
734 irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, self->slsap_sel,
735 DISCONNECT, skb);
736 irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
737 /* Called only from irlmp_disconnect_request(), will
738 * unbind from LAP over there. Jean II */
739
740 /* Try to close the LAP connection if its still there */
741 if (self->lap) {
742 IRDA_DEBUG(4, "%s(), trying to close IrLAP\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800743 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 irlmp_do_lap_event(self->lap,
745 LM_LAP_DISCONNECT_REQUEST,
746 NULL);
747 }
748 break;
749 case LM_LAP_DISCONNECT_INDICATION:
750 irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
751
752 reason = irlmp_convert_lap_reason(self->lap->reason);
753
754 irlmp_disconnect_indication(self, reason, NULL);
755 break;
756 case LM_DISCONNECT_INDICATION:
757 irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
758
759 IRDA_ASSERT(self->lap != NULL, return -1;);
760 IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
761
762 IRDA_ASSERT(skb != NULL, return -1;);
763 IRDA_ASSERT(skb->len > 3, return -1;);
764 reason = skb->data[3];
765
766 /* Try to close the LAP connection */
Harvey Harrison0dc47872008-03-05 20:47:47 -0800767 IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
769
770 irlmp_disconnect_indication(self, reason, skb);
771 break;
772 default:
773 IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800774 __func__, irlmp_event[event], self->slsap_sel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 break;
776 }
777 return ret;
778}
779
780/*
781 * Function irlmp_state_setup (event, skb, info)
782 *
783 * SETUP, Station Control has set up the underlying IrLAP connection.
784 * An LSAP connection request has been transmitted to the peer
785 * LSAP-Connection Control FSM and we are awaiting reply.
786 */
787static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event,
788 struct sk_buff *skb)
789{
790 LM_REASON reason;
791 int ret = 0;
792
793 IRDA_ASSERT(self != NULL, return -1;);
794 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
795
Harvey Harrison0dc47872008-03-05 20:47:47 -0800796 IRDA_DEBUG(4, "%s()\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 switch (event) {
799 case LM_CONNECT_CONFIRM:
800 irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY);
801
802 del_timer(&self->watchdog_timer);
803
804 irlmp_connect_confirm(self, skb);
805 break;
806 case LM_DISCONNECT_INDICATION:
807 irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
808
809 IRDA_ASSERT(self->lap != NULL, return -1;);
810 IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
811
812 IRDA_ASSERT(skb != NULL, return -1;);
813 IRDA_ASSERT(skb->len > 3, return -1;);
814 reason = skb->data[3];
815
816 /* Try to close the LAP connection */
Harvey Harrison0dc47872008-03-05 20:47:47 -0800817 IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
819
820 irlmp_disconnect_indication(self, reason, skb);
821 break;
822 case LM_LAP_DISCONNECT_INDICATION:
823 irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
824
825 del_timer(&self->watchdog_timer);
826
827 IRDA_ASSERT(self->lap != NULL, return -1;);
828 IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
829
830 reason = irlmp_convert_lap_reason(self->lap->reason);
831
832 irlmp_disconnect_indication(self, reason, skb);
833 break;
834 case LM_WATCHDOG_TIMEOUT:
Harvey Harrison0dc47872008-03-05 20:47:47 -0800835 IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
837 IRDA_ASSERT(self->lap != NULL, return -1;);
838 irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
839 irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
840
841 irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
842 break;
843 default:
844 IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800845 __func__, irlmp_event[event], self->slsap_sel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 break;
847 }
848 return ret;
849}
850
851/*
852 * Function irlmp_state_setup_pend (event, skb, info)
853 *
854 * SETUP_PEND, An LM_CONNECT_REQUEST has been received from the service
855 * user to set up an LSAP connection. A request has been sent to the
856 * LAP FSM to set up the underlying IrLAP connection, and we
857 * are awaiting confirm.
858 */
859static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
860 struct sk_buff *skb)
861{
862 struct sk_buff *tx_skb;
863 LM_REASON reason;
864 int ret = 0;
865
Harvey Harrison0dc47872008-03-05 20:47:47 -0800866 IRDA_DEBUG(4, "%s()\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
868 IRDA_ASSERT(self != NULL, return -1;);
869 IRDA_ASSERT(irlmp != NULL, return -1;);
870
871 switch (event) {
872 case LM_LAP_CONNECT_CONFIRM:
873 IRDA_ASSERT(self->conn_skb != NULL, return -1;);
874
875 tx_skb = self->conn_skb;
876 self->conn_skb = NULL;
877
878 irlmp_send_lcf_pdu(self->lap, self->dlsap_sel,
879 self->slsap_sel, CONNECT_CMD, tx_skb);
880 /* Drop reference count - see irlap_data_request(). */
881 dev_kfree_skb(tx_skb);
882
883 irlmp_next_lsap_state(self, LSAP_SETUP);
884 break;
885 case LM_WATCHDOG_TIMEOUT:
Harvey Harrison0dc47872008-03-05 20:47:47 -0800886 IRDA_DEBUG(0, "%s() : WATCHDOG_TIMEOUT !\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
888 IRDA_ASSERT(self->lap != NULL, return -1;);
889 irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
890 irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
891
892 irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
893 break;
894 case LM_LAP_DISCONNECT_INDICATION: /* LS_Disconnect.indication */
895 del_timer( &self->watchdog_timer);
896
897 irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
898
899 reason = irlmp_convert_lap_reason(self->lap->reason);
900
901 irlmp_disconnect_indication(self, reason, NULL);
902 break;
903 default:
904 IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
Harvey Harrison0dc47872008-03-05 20:47:47 -0800905 __func__, irlmp_event[event], self->slsap_sel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 break;
907 }
908 return ret;
909}