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