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