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