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