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 *const irlmp_state[] = {
37 "LAP_STANDBY",
38 "LAP_U_CONNECT",
39 "LAP_ACTIVE",
40 };
41
42 const char *const 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 *const 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 bizarre. 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