1 /*********************************************************************
3 * Filename: irlmp_event.c
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: Sat Jan 16 22:22:29 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
12 * Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>,
13 * All Rights Reserved.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of
18 * the License, or (at your option) any later version.
20 * Neither Dag Brattli nor University of Tromsø admit liability nor
21 * provide warranty for any of this software. This material is
22 * provided "AS-IS" and at no charge.
24 ********************************************************************/
26 #include <linux/kernel.h>
28 #include <net/irda/irda.h>
29 #include <net/irda/timer.h>
30 #include <net/irda/irlap.h>
31 #include <net/irda/irlmp.h>
32 #include <net/irda/irlmp_frame.h>
33 #include <net/irda/irlmp_event.h>
35 char *irlmp_state
[] = {
41 char *irlsap_state
[] = {
45 "LSAP_DATA_TRANSFER_READY",
50 static char *irlmp_event
[] = {
53 "LM_CONNECT_RESPONSE",
54 "LM_CONNECT_INDICATION",
56 "LM_DISCONNECT_INDICATION",
57 "LM_DISCONNECT_REQUEST",
62 "LM_UDATA_INDICATION",
64 "LM_WATCHDOG_TIMEOUT",
67 "LM_LAP_CONNECT_REQUEST",
68 "LM_LAP_CONNECT_INDICATION",
69 "LM_LAP_CONNECT_CONFIRM",
70 "LM_LAP_DISCONNECT_INDICATION",
71 "LM_LAP_DISCONNECT_REQUEST",
72 "LM_LAP_DISCOVERY_REQUEST",
73 "LM_LAP_DISCOVERY_CONFIRM",
76 /* LAP Connection control proto declarations */
77 static void irlmp_state_standby ( struct lap_cb
*, IRLMP_EVENT
,
79 static void irlmp_state_u_connect( struct lap_cb
*, IRLMP_EVENT
,
81 static void irlmp_state_active ( struct lap_cb
*, IRLMP_EVENT
,
84 /* LSAP Connection control proto declarations */
85 static void irlmp_state_disconnected( struct lsap_cb
*, IRLMP_EVENT
,
87 static void irlmp_state_connect ( struct lsap_cb
*, IRLMP_EVENT
,
89 static void irlmp_state_connect_pend( struct lsap_cb
*, IRLMP_EVENT
,
91 static void irlmp_state_dtr ( struct lsap_cb
*, IRLMP_EVENT
,
93 static void irlmp_state_setup ( struct lsap_cb
*, IRLMP_EVENT
,
95 static void irlmp_state_setup_pend ( struct lsap_cb
*, IRLMP_EVENT
,
98 static void (*lap_state
[]) ( struct lap_cb
*, IRLMP_EVENT
, struct sk_buff
*) =
101 irlmp_state_u_connect
,
105 static void (*lsap_state
[])( struct lsap_cb
*, IRLMP_EVENT
, struct sk_buff
*) =
107 irlmp_state_disconnected
,
109 irlmp_state_connect_pend
,
112 irlmp_state_setup_pend
115 /* Do connection control events */
116 void irlmp_do_lsap_event( struct lsap_cb
*self
, IRLMP_EVENT event
,
119 ASSERT( self
!= NULL
, return;);
120 ASSERT( self
->magic
== LMP_LSAP_MAGIC
, return;);
122 DEBUG( 4, __FUNCTION__
"(), EVENT = %s, STATE = %s\n",
123 irlmp_event
[ event
], irlmp_state
[ self
->lsap_state
]);
125 (*lsap_state
[ self
->lsap_state
]) ( self
, event
, skb
);
129 * Function do_lap_event (event, skb, info)
131 * Do IrLAP control events
134 void irlmp_do_lap_event( struct lap_cb
*self
, IRLMP_EVENT event
,
137 ASSERT( self
!= NULL
, return;);
138 ASSERT( self
->magic
== LMP_LAP_MAGIC
, return;);
140 DEBUG( 4, __FUNCTION__
"(), EVENT = %s, STATE = %s\n",
142 irlmp_state
[self
->lap_state
]);
144 (*lap_state
[ self
->lap_state
]) ( self
, event
, skb
);
147 void irlmp_discovery_timer_expired( unsigned long data
)
149 /* struct irlmp_cb *self = ( struct irlmp_cb *) data; */
151 DEBUG( 4, "IrLMP, discovery timer expired!\n");
153 irlmp_discovery_request( 8);
156 irlmp_start_discovery_timer( irlmp
, 300);
159 void irlmp_watchdog_timer_expired( unsigned long data
)
161 struct lsap_cb
*self
= ( struct lsap_cb
*) data
;
163 DEBUG( 0, __FUNCTION__
"()\n");
165 ASSERT( self
!= NULL
, return;);
166 ASSERT( self
->magic
== LMP_LSAP_MAGIC
, return;);
168 irlmp_do_lsap_event( self
, LM_WATCHDOG_TIMEOUT
, NULL
);
171 /*********************************************************************
173 * LAP connection control states
175 ********************************************************************/
178 * Function irlmp_state_standby (event, skb, info)
180 * STANDBY, The IrLAP connection does not exist.
183 static void irlmp_state_standby( struct lap_cb
*self
, IRLMP_EVENT event
,
186 DEBUG( 4, __FUNCTION__
"()\n");
187 ASSERT( self
->irlap
!= NULL
, return;);
190 case LM_LAP_DISCOVERY_REQUEST
:
191 /* irlmp_next_station_state( LMP_DISCOVER); */
193 irlap_discovery_request( self
->irlap
, &irlmp
->discovery_cmd
);
195 case LM_LAP_DISCOVERY_CONFIRM
:
196 /* irlmp_next_station_state( LMP_READY); */
197 irlmp_discovery_confirm( self
, self
->cachelog
);
199 case LM_LAP_CONNECT_INDICATION
:
200 /* It's important to switch state first, to avoid IrLMP to
201 * think that the link is free since IrLMP may then start
202 * discovery before the connection is properly set up. DB.
204 irlmp_next_lap_state( self
, LAP_ACTIVE
);
206 /* Just accept connection TODO, this should be fixed */
207 irlap_connect_response( self
->irlap
, skb
);
209 case LM_LAP_CONNECT_REQUEST
:
210 DEBUG( 4, "irlmp_state_standby() LS_CONNECT_REQUEST\n");
212 /* FIXME: need to set users requested QoS */
213 irlap_connect_request( self
->irlap
, self
->daddr
, NULL
, 0);
215 irlmp_next_lap_state( self
, LAP_U_CONNECT
);
217 case LM_LAP_DISCONNECT_INDICATION
:
218 DEBUG( 4, __FUNCTION__
219 "(), Error LM_LAP_DISCONNECT_INDICATION\n");
221 irlmp_next_lap_state( self
, LAP_STANDBY
);
224 DEBUG( 4, "irlmp_state_standby: Unknown event\n");
230 * Function irlmp_state_u_connect (event, skb, info)
232 * U_CONNECT, The layer above has tried to open an LSAP connection but
233 * since the IrLAP connection does not exist, we must first start an
234 * IrLAP connection. We are now waiting response from IrLAP.
236 static void irlmp_state_u_connect( struct lap_cb
*self
, IRLMP_EVENT event
,
239 struct lsap_cb
*lsap
;
240 struct lsap_cb
*lsap_current
;
242 DEBUG( 4, __FUNCTION__
"()\n");
245 case LM_LAP_CONNECT_CONFIRM
:
246 /* For all lsap_ce E Associated do LS_Connect_confirm */
247 irlmp_next_lap_state( self
, LAP_ACTIVE
);
249 lsap
= ( struct lsap_cb
*) hashbin_get_first( self
->lsaps
);
250 while ( lsap
!= NULL
) {
251 irlmp_do_lsap_event(lsap
, LM_LAP_CONNECT_CONFIRM
, skb
);
252 lsap
= (struct lsap_cb
*) hashbin_get_next(self
->lsaps
);
255 case LM_LAP_DISCONNECT_INDICATION
:
256 DEBUG( 4, __FUNCTION__
"(), IRLAP_DISCONNECT_INDICATION\n");
258 irlmp_next_lap_state( self
, LAP_STANDBY
);
260 /* Send disconnect event to all LSAPs using this link */
262 lsap
= ( struct lsap_cb
*) hashbin_get_first( self
->lsaps
);
263 while ( lsap
!= NULL
) {
264 ASSERT( lsap
->magic
== LMP_LSAP_MAGIC
, return;);
268 /* Be sure to stay one item ahead */
269 lsap
= ( struct lsap_cb
*) hashbin_get_next( self
->lsaps
);
270 irlmp_do_lsap_event( lsap_current
,
271 LM_LAP_DISCONNECT_INDICATION
,
275 case LM_LAP_DISCONNECT_REQUEST
:
276 DEBUG( 4, __FUNCTION__
"(), LM_LAP_DISCONNECT_REQUEST\n");
278 irlmp_next_lap_state( self
, LAP_STANDBY
);
281 /* irlap_disconnect_request( self->irlap); */
284 DEBUG( 4, __FUNCTION__
"(), Unknown event\n");
290 * Function irlmp_state_active (event, skb, info)
292 * ACTIVE, IrLAP connection is active
295 static void irlmp_state_active( struct lap_cb
*self
, IRLMP_EVENT event
,
298 struct lsap_cb
*lsap
;
299 struct lsap_cb
*lsap_current
;
301 DEBUG( 4, __FUNCTION__
"()\n");
304 case LM_LAP_CONNECT_REQUEST
:
305 DEBUG( 4, __FUNCTION__
"(), LS_CONNECT_REQUEST\n");
308 * LAP connection allready active, just bounce back! Since we
309 * don't know which LSAP that tried to do this, we have to
310 * notify all LSAPs using this LAP, but that should be safe to
313 lsap
= ( struct lsap_cb
*) hashbin_get_first( self
->lsaps
);
314 while ( lsap
!= NULL
) {
315 irlmp_do_lsap_event( lsap
, LM_LAP_CONNECT_CONFIRM
,
317 lsap
= (struct lsap_cb
*) hashbin_get_next(self
->lsaps
);
322 case LM_LAP_DISCONNECT_REQUEST
:
323 DEBUG( 4, __FUNCTION__
"(), LM_LAP_DISCONNECT_REQUEST\n");
326 * Need to find out if we should close IrLAP or not
328 if ( hashbin_get_size( self
->lsaps
) == 0) {
329 DEBUG( 0, __FUNCTION__
330 "(), no more LSAPs so time to disconnect IrLAP\n");
331 irlmp_next_lap_state( self
, LAP_STANDBY
);
333 irlap_disconnect_request( self
->irlap
);
336 case LM_LAP_DISCONNECT_INDICATION
:
337 DEBUG( 4, __FUNCTION__
"(), IRLAP_DISCONNECT_INDICATION\n");
339 irlmp_next_lap_state( self
, LAP_STANDBY
);
342 * Inform all connected LSAP's using this link
344 lsap
= ( struct lsap_cb
*) hashbin_get_first( self
->lsaps
);
345 while ( lsap
!= NULL
) {
346 ASSERT( lsap
->magic
== LMP_LSAP_MAGIC
, return;);
350 /* Be sure to stay one item ahead */
351 lsap
= ( struct lsap_cb
*) hashbin_get_next( self
->lsaps
);
352 irlmp_do_lsap_event( lsap_current
,
353 LM_LAP_DISCONNECT_INDICATION
,
358 DEBUG( 4, __FUNCTION__
"(), Unknown event %d\n", event
);
363 /*********************************************************************
365 * LSAP connection control states
367 ********************************************************************/
370 * Function irlmp_state_disconnected (event, skb, info)
375 static void irlmp_state_disconnected( struct lsap_cb
*self
, IRLMP_EVENT event
,
378 struct lsap_cb
*lsap
;
380 DEBUG( 4, __FUNCTION__
"()\n");
382 ASSERT( self
!= NULL
, return;);
383 ASSERT( self
->magic
== LMP_LSAP_MAGIC
, return;);
386 case LM_CONNECT_REQUEST
:
387 DEBUG( 4, __FUNCTION__
"(), LM_CONNECT_REQUEST\n");
388 irlmp_next_lsap_state( self
, LSAP_SETUP_PEND
);
390 irlmp_do_lap_event( self
->lap
, LM_LAP_CONNECT_REQUEST
, NULL
);
392 /* Start watchdog timer ( 5 secs for now) */
393 irlmp_start_watchdog_timer( self
, 500);
395 case LM_CONNECT_INDICATION
:
396 irlmp_next_lsap_state( self
, LSAP_CONNECT_PEND
);
400 * Bind this LSAP to the IrLAP link where the connect was
402 * FIXME: this should be done in the LAP state machine
404 lsap
= hashbin_remove( irlmp
->unconnected_lsaps
,
405 self
->slsap_sel
, NULL
);
407 ASSERT( lsap
== self
, return;);
409 ASSERT( self
->lap
!= NULL
, return;);
410 ASSERT( self
->lap
->lsaps
!= NULL
, return;);
412 hashbin_insert( self
->lap
->lsaps
, (QUEUE
*) self
,
413 self
->slsap_sel
, NULL
);
415 irlmp_do_lap_event( self
->lap
, LM_LAP_CONNECT_REQUEST
, skb
);
418 /* DEBUG( 4, "irlmp_state_disconnected: Unknown event %d\n",
425 * Function irlmp_state_connect (self, event, skb)
430 static void irlmp_state_connect( struct lsap_cb
*self
, IRLMP_EVENT event
,
434 DEBUG( 4, __FUNCTION__
"()\n");
436 ASSERT( self
!= NULL
, return;);
437 ASSERT( self
->magic
== LMP_LSAP_MAGIC
, return;);
440 case LM_CONNECT_RESPONSE
:
441 ASSERT( skb
!= NULL
, return;);
443 irlmp_send_lcf_pdu( self
->lap
, self
->dlsap_sel
,
444 self
->slsap_sel
, CONNECT_CNF
, skb
);
446 del_timer( &self
->watchdog_timer
);
448 irlmp_next_lsap_state( self
, LSAP_DATA_TRANSFER_READY
);
451 DEBUG( 4, "irlmp_state_connect: Unknown event\n");
457 * Function irlmp_state_connect_pend (event, skb, info)
462 static void irlmp_state_connect_pend( struct lsap_cb
*self
, IRLMP_EVENT event
,
465 DEBUG( 4, __FUNCTION__
"()\n");
467 ASSERT( self
!= NULL
, return;);
468 ASSERT( self
->magic
== LMP_LSAP_MAGIC
, return;);
471 case LM_CONNECT_REQUEST
:
474 case LM_CONNECT_RESPONSE
:
476 "IrLMP CONNECT-PEND, No indication issued yet\n");
479 case LM_DISCONNECT_REQUEST
:
481 "IrLMP CONNECT-PEND, "
482 "Not yet bound to IrLAP connection\n");
485 case LM_LAP_CONNECT_CONFIRM
:
486 DEBUG( 4, "irlmp_state_connect_pend: LS_CONNECT_CONFIRM\n");
487 irlmp_next_lsap_state( self
, LSAP_CONNECT
);
488 irlmp_connect_indication( self
, skb
);
492 DEBUG( 4, "irlmp_state_connect_pend: Unknown event %d\n",
499 * Function irlmp_state_dtr (self, event, skb)
501 * DATA_TRANSFER_READY
504 static void irlmp_state_dtr( struct lsap_cb
*self
, IRLMP_EVENT event
,
509 DEBUG( 4, __FUNCTION__
"()\n");
511 ASSERT( self
!= NULL
, return;);
512 ASSERT( self
->magic
== LMP_LSAP_MAGIC
, return;);
513 ASSERT( self
->lap
!= NULL
, return;);
516 case LM_CONNECT_REQUEST
:
518 "IrLMP DTR: Error, LSAP allready connected\n");
521 case LM_CONNECT_RESPONSE
:
523 "IrLMP DTR: Error, LSAP allready connected\n");
526 case LM_DISCONNECT_REQUEST
:
527 ASSERT( skb
!= NULL
, return;);
529 irlmp_send_lcf_pdu( self
->lap
, self
->dlsap_sel
,
530 self
->slsap_sel
, DISCONNECT
, skb
);
531 irlmp_next_lsap_state( self
, LSAP_DISCONNECTED
);
533 /* Try to close the LAP connection if its still there */
535 DEBUG( 4, __FUNCTION__
"(), trying to close IrLAP\n");
536 irlmp_do_lap_event( self
->lap
,
537 LM_LAP_DISCONNECT_REQUEST
,
542 case LM_DATA_REQUEST
:
543 ASSERT( skb
!= NULL
, return;);
544 irlmp_send_data_pdu( self
->lap
, self
->dlsap_sel
,
545 self
->slsap_sel
, FALSE
, skb
);
546 /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
548 case LM_UDATA_REQUEST
:
549 ASSERT( skb
!= NULL
, return;);
550 irlmp_send_data_pdu( self
->lap
, self
->dlsap_sel
,
551 self
->slsap_sel
, TRUE
, skb
);
553 case LM_DATA_INDICATION
:
554 irlmp_data_indication( self
, skb
);
555 /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
557 case LM_UDATA_INDICATION
:
558 irlmp_udata_indication( self
, skb
);
559 /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
561 case LM_LAP_DISCONNECT_INDICATION
:
562 irlmp_next_lsap_state( self
, LSAP_DISCONNECTED
);
564 reason
= irlmp_convert_lap_reason( self
->lap
->reason
);
566 irlmp_disconnect_indication( self
, reason
, NULL
);
568 case LM_DISCONNECT_INDICATION
:
569 irlmp_next_lsap_state( self
, LSAP_DISCONNECTED
);
571 ASSERT( self
->lap
!= NULL
, return;);
572 ASSERT( self
->lap
->magic
== LMP_LAP_MAGIC
, return;);
574 reason
= irlmp_convert_lap_reason( self
->lap
->reason
);
576 /* Try to close the LAP connection */
577 DEBUG( 4, __FUNCTION__
"(), trying to close IrLAP\n");
578 irlmp_do_lap_event( self
->lap
, LM_LAP_DISCONNECT_REQUEST
,
581 irlmp_disconnect_indication( self
, reason
, skb
);
585 DEBUG( 4, __FUNCTION__
"(), Unknown event %d\n", event
);
591 * Function irlmp_state_setup (event, skb, info)
593 * SETUP, Station Control has set up the underlying IrLAP connection.
594 * An LSAP connection request has been transmitted to the peer
595 * LSAP-Connection Control FSM and we are awaiting reply.
597 static void irlmp_state_setup( struct lsap_cb
*self
, IRLMP_EVENT event
,
602 ASSERT( self
!= NULL
, return;);
603 ASSERT( self
->magic
== LMP_LSAP_MAGIC
, return;);
605 DEBUG( 4, "irlmp_state_setup()\n");
608 case LM_CONNECT_CONFIRM
:
609 ASSERT( skb
!= NULL
, return;);
611 irlmp_next_lsap_state( self
, LSAP_DATA_TRANSFER_READY
);
613 del_timer( &self
->watchdog_timer
);
615 irlmp_connect_confirm( self
, skb
);
617 case LM_DISCONNECT_INDICATION
:
618 irlmp_next_lsap_state( self
, LSAP_DISCONNECTED
);
620 del_timer( &self
->watchdog_timer
);
622 ASSERT( self
->lap
!= NULL
, return;);
623 ASSERT( self
->lap
->magic
== LMP_LAP_MAGIC
, return;);
625 reason
= irlmp_convert_lap_reason( self
->lap
->reason
);
627 irlmp_disconnect_indication( self
, reason
, skb
);
630 DEBUG( 4, __FUNCTION__
"(), Unknown event %d\n", event
);
636 * Function irlmp_state_setup_pend (event, skb, info)
638 * SETUP_PEND, An LM_CONNECT_REQUEST has been received from the service
639 * user to set up an LSAP connection. A request has been sent to the
640 * LAP FSM to set up the underlying IrLAP connection, and we
641 * are awaiting confirm.
643 static void irlmp_state_setup_pend( struct lsap_cb
*self
, IRLMP_EVENT event
,
647 DEBUG( 4, __FUNCTION__
"()\n");
649 ASSERT( self
!= NULL
, return;);
650 ASSERT( irlmp
!= NULL
, return;);
653 case LM_LAP_CONNECT_CONFIRM
:
654 irlmp_send_lcf_pdu( self
->lap
, self
->dlsap_sel
,
655 self
->slsap_sel
, CONNECT_CMD
,
657 irlmp_next_lsap_state( self
, LSAP_SETUP
);
659 case LM_DISCONNECT_INDICATION
:
660 del_timer( &self
->watchdog_timer
);
662 irlmp_next_lsap_state( self
, LSAP_DISCONNECTED
);
664 case LM_WATCHDOG_TIMEOUT
:
665 DEBUG( 0, __FUNCTION__
"() WATCHDOG_TIMEOUT!\n");
667 /* FIXME: should we do a disconnect_indication? */
668 ASSERT( self
->lap
!= NULL
, return;);
669 irlmp_do_lap_event( self
->lap
, LM_LAP_DISCONNECT_REQUEST
, NULL
);
670 irlmp_next_lsap_state( self
, LSAP_DISCONNECTED
);
673 DEBUG( 4, __FUNCTION__
"(), Unknown event %d\n", event
);
678 void irlmp_next_lap_state( struct lap_cb
*self
, IRLMP_STATE state
)
680 DEBUG( 4, __FUNCTION__
"(), LMP LAP = %s\n", irlmp_state
[state
]);
681 self
->lap_state
= state
;
684 void irlmp_next_lsap_state( struct lsap_cb
*self
, LSAP_STATE state
)
686 ASSERT( self
!= NULL
, return;);
688 DEBUG( 4, __FUNCTION__
"(), LMP LSAP = %s\n", irlsap_state
[state
]);
689 self
->lsap_state
= state
;