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