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