2.2.0-final
[davej-history.git] / net / irda / irlmp_event.c
bloba1f5379588271b953617f0d9cc88176e687a8a0e
1 /*********************************************************************
2 *
3 * Filename: irlmp_event.c
4 * Version: 0.1
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[] = {
36 "LAP_STANDBY",
37 "LAP_U_CONNECT",
38 "LAP_ACTIVE",
41 char *irlsap_state[] = {
42 "LSAP_DISCONNECTED",
43 "LSAP_CONNECT",
44 "LSAP_CONNECT_PEND",
45 "LSAP_DATA_TRANSFER_READY",
46 "LSAP_SETUP",
47 "LSAP_SETUP_PEND",
50 static char *irlmp_event[] = {
51 "LM_CONNECT_REQUEST",
52 "LM_CONNECT_CONFIRM",
53 "LM_CONNECT_RESPONSE",
54 "LM_CONNECT_INDICATION",
56 "LM_DISCONNECT_INDICATION",
57 "LM_DISCONNECT_REQUEST",
59 "LM_DATA_REQUEST",
60 "LM_UDATA_REQUEST",
61 "LM_DATA_INDICATION",
62 "LM_UDATA_INDICATION",
64 "LM_WATCHDOG_TIMEOUT",
66 /* IrLAP events */
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,
78 struct sk_buff *);
79 static void irlmp_state_u_connect( struct lap_cb *, IRLMP_EVENT,
80 struct sk_buff *);
81 static void irlmp_state_active ( struct lap_cb *, IRLMP_EVENT,
82 struct sk_buff *);
84 /* LSAP Connection control proto declarations */
85 static void irlmp_state_disconnected( struct lsap_cb *, IRLMP_EVENT,
86 struct sk_buff *);
87 static void irlmp_state_connect ( struct lsap_cb *, IRLMP_EVENT,
88 struct sk_buff *);
89 static void irlmp_state_connect_pend( struct lsap_cb *, IRLMP_EVENT,
90 struct sk_buff *);
91 static void irlmp_state_dtr ( struct lsap_cb *, IRLMP_EVENT,
92 struct sk_buff *);
93 static void irlmp_state_setup ( struct lsap_cb *, IRLMP_EVENT,
94 struct sk_buff *);
95 static void irlmp_state_setup_pend ( struct lsap_cb *, IRLMP_EVENT,
96 struct sk_buff *);
98 static void (*lap_state[]) ( struct lap_cb *, IRLMP_EVENT, struct sk_buff *) =
100 irlmp_state_standby,
101 irlmp_state_u_connect,
102 irlmp_state_active,
105 static void (*lsap_state[])( struct lsap_cb *, IRLMP_EVENT, struct sk_buff *) =
107 irlmp_state_disconnected,
108 irlmp_state_connect,
109 irlmp_state_connect_pend,
110 irlmp_state_dtr,
111 irlmp_state_setup,
112 irlmp_state_setup_pend
115 /* Do connection control events */
116 void irlmp_do_lsap_event( struct lsap_cb *self, IRLMP_EVENT event,
117 struct sk_buff *skb)
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,
135 struct sk_buff *skb)
137 ASSERT( self != NULL, return;);
138 ASSERT( self->magic == LMP_LAP_MAGIC, return;);
140 DEBUG( 4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
141 irlmp_event[event],
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);
155 /* Restart timer */
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,
184 struct sk_buff *skb)
186 DEBUG( 4, __FUNCTION__ "()\n");
187 ASSERT( self->irlap != NULL, return;);
189 switch( event) {
190 case LM_LAP_DISCOVERY_REQUEST:
191 /* irlmp_next_station_state( LMP_DISCOVER); */
193 irlap_discovery_request( self->irlap, &irlmp->discovery_cmd);
194 break;
195 case LM_LAP_DISCOVERY_CONFIRM:
196 /* irlmp_next_station_state( LMP_READY); */
197 irlmp_discovery_confirm( self, self->cachelog);
198 break;
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);
208 break;
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);
216 break;
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);
222 break;
223 default:
224 DEBUG( 4, "irlmp_state_standby: Unknown event\n");
225 break;
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.
235 * */
236 static void irlmp_state_u_connect( struct lap_cb *self, IRLMP_EVENT event,
237 struct sk_buff *skb)
239 struct lsap_cb *lsap;
240 struct lsap_cb *lsap_current;
242 DEBUG( 4, __FUNCTION__ "()\n");
244 switch( event) {
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);
254 break;
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;);
266 lsap_current = lsap;
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,
272 NULL);
274 break;
275 case LM_LAP_DISCONNECT_REQUEST:
276 DEBUG( 4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n");
278 irlmp_next_lap_state( self, LAP_STANDBY);
280 /* FIXME */
281 /* irlap_disconnect_request( self->irlap); */
282 break;
283 default:
284 DEBUG( 4, __FUNCTION__ "(), Unknown event\n");
285 break;
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,
296 struct sk_buff *skb)
298 struct lsap_cb *lsap;
299 struct lsap_cb *lsap_current;
301 DEBUG( 4, __FUNCTION__ "()\n");
303 switch( event) {
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
311 * do anyway.
313 lsap = ( struct lsap_cb *) hashbin_get_first( self->lsaps);
314 while ( lsap != NULL) {
315 irlmp_do_lsap_event( lsap, LM_LAP_CONNECT_CONFIRM,
316 skb);
317 lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
320 /* Keep state */
321 break;
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);
335 break;
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;);
348 lsap_current = lsap;
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,
354 NULL);
356 break;
357 default:
358 DEBUG( 4, __FUNCTION__ "(), Unknown event %d\n", event);
359 break;
363 /*********************************************************************
365 * LSAP connection control states
367 ********************************************************************/
370 * Function irlmp_state_disconnected (event, skb, info)
372 * DISCONNECTED
375 static void irlmp_state_disconnected( struct lsap_cb *self, IRLMP_EVENT event,
376 struct sk_buff *skb)
378 struct lsap_cb *lsap;
380 DEBUG( 4, __FUNCTION__ "()\n");
382 ASSERT( self != NULL, return;);
383 ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
385 switch( event) {
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);
394 break;
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
401 * received
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);
416 break;
417 default:
418 /* DEBUG( 4, "irlmp_state_disconnected: Unknown event %d\n",
419 event); */
420 break;
425 * Function irlmp_state_connect (self, event, skb)
427 * CONNECT
430 static void irlmp_state_connect( struct lsap_cb *self, IRLMP_EVENT event,
431 struct sk_buff *skb)
434 DEBUG( 4, __FUNCTION__ "()\n");
436 ASSERT( self != NULL, return;);
437 ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
439 switch( event) {
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);
449 break;
450 default:
451 DEBUG( 4, "irlmp_state_connect: Unknown event\n");
452 break;
457 * Function irlmp_state_connect_pend (event, skb, info)
459 * CONNECT_PEND
462 static void irlmp_state_connect_pend( struct lsap_cb *self, IRLMP_EVENT event,
463 struct sk_buff *skb)
465 DEBUG( 4, __FUNCTION__ "()\n");
467 ASSERT( self != NULL, return;);
468 ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
470 switch( event) {
471 case LM_CONNECT_REQUEST:
472 /* Keep state */
473 break;
474 case LM_CONNECT_RESPONSE:
475 printk( KERN_WARNING
476 "IrLMP CONNECT-PEND, No indication issued yet\n");
477 /* Keep state */
478 break;
479 case LM_DISCONNECT_REQUEST:
480 printk( KERN_WARNING
481 "IrLMP CONNECT-PEND, "
482 "Not yet bound to IrLAP connection\n");
483 /* Keep state */
484 break;
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);
489 break;
491 default:
492 DEBUG( 4, "irlmp_state_connect_pend: Unknown event %d\n",
493 event);
494 break;
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,
505 struct sk_buff *skb)
507 LM_REASON reason;
509 DEBUG( 4, __FUNCTION__ "()\n");
511 ASSERT( self != NULL, return;);
512 ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
513 ASSERT( self->lap != NULL, return;);
515 switch( event) {
516 case LM_CONNECT_REQUEST:
517 printk( KERN_WARNING
518 "IrLMP DTR: Error, LSAP allready connected\n");
519 /* Keep state */
520 break;
521 case LM_CONNECT_RESPONSE:
522 printk( KERN_WARNING
523 "IrLMP DTR: Error, LSAP allready connected\n");
524 /* Keep state */
525 break;
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 */
534 if ( self->lap) {
535 DEBUG( 4, __FUNCTION__ "(), trying to close IrLAP\n");
536 irlmp_do_lap_event( self->lap,
537 LM_LAP_DISCONNECT_REQUEST,
538 NULL);
541 break;
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);*/
547 break;
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);
552 break;
553 case LM_DATA_INDICATION:
554 irlmp_data_indication( self, skb);
555 /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
556 break;
557 case LM_UDATA_INDICATION:
558 irlmp_udata_indication( self, skb);
559 /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
560 break;
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);
567 break;
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,
579 NULL);
581 irlmp_disconnect_indication( self, reason, skb);
583 break;
584 default:
585 DEBUG( 4, __FUNCTION__ "(), Unknown event %d\n", event);
586 break;
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,
598 struct sk_buff *skb)
600 LM_REASON reason;
602 ASSERT( self != NULL, return;);
603 ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
605 DEBUG( 4, "irlmp_state_setup()\n");
607 switch( event) {
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);
616 break;
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);
628 break;
629 default:
630 DEBUG( 4, __FUNCTION__ "(), Unknown event %d\n", event);
631 break;
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,
644 struct sk_buff *skb)
647 DEBUG( 4, __FUNCTION__ "()\n");
649 ASSERT( self != NULL, return;);
650 ASSERT( irlmp != NULL, return;);
652 switch( event) {
653 case LM_LAP_CONNECT_CONFIRM:
654 irlmp_send_lcf_pdu( self->lap, self->dlsap_sel,
655 self->slsap_sel, CONNECT_CMD,
656 self->tmp_skb);
657 irlmp_next_lsap_state( self, LSAP_SETUP);
658 break;
659 case LM_DISCONNECT_INDICATION:
660 del_timer( &self->watchdog_timer);
662 irlmp_next_lsap_state( self, LSAP_DISCONNECTED);
663 break;
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);
671 break;
672 default:
673 DEBUG( 4, __FUNCTION__ "(), Unknown event %d\n", event);
674 break;
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;