ir248_disco_fixes_4.diff :
------------------------
        o [CORRECT] Fix corner case where getting stuck in LMP state machine
        o [CORRECT] Fix rare deadlock in LAP secondary state machine
        o [FEATURE] Bypass LMP state machine when propagating discovery event
                - Fix many case where event is discarded and not passed up
                - Reduce overhead on a critical path
        o [FEATURE] Properly do expiry when discovery is not active

diff -u -p linux/include/net/irda/irlmp.d8.h linux/include/net/irda/irlmp.h
--- linux/include/net/irda/irlmp.d8.h   Thu Sep 13 11:49:34 2001
+++ linux/include/net/irda/irlmp.h      Thu Sep 13 11:51:00 2001
@@ -217,6 +217,7 @@ int  irlmp_disconnect_request(struct lsa
 void irlmp_discovery_confirm(hashbin_t *discovery_log);
 void irlmp_discovery_request(int nslots);
 struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask);
+void irlmp_do_expiry(void);
 void irlmp_do_discovery(int nslots);
 discovery_t *irlmp_get_discovery_response(void);
 void irlmp_discovery_expiry(discovery_t *expiry);
diff -u -p linux/net/irda/irlmp.d8.c linux/net/irda/irlmp.c
--- linux/net/irda/irlmp.d8.c   Thu Sep 13 11:49:48 2001
+++ linux/net/irda/irlmp.c      Thu Sep 13 11:51:00 2001
@@ -693,10 +693,43 @@ void irlmp_disconnect_indication(struct 
 }
 
 /*
+ * Function irlmp_do_expiry (void)
+ *
+ *    Do a cleanup of the discovery log (remove old entries)
+ *
+ * Note : separate from irlmp_do_discovery() so that we can handle
+ * passive discovery properly.
+ */
+void irlmp_do_expiry()
+{
+       struct lap_cb *lap;
+
+       /*
+        * Expire discovery on all links which are *not* connected.
+        * On links which are connected, we can't do discovery
+        * anymore and can't refresh the log, so we freeze the
+        * discovery log to keep info about the device we are
+        * connected to. - Jean II
+        */
+       lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
+       while (lap != NULL) {
+               ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
+               
+               if (lap->lap_state == LAP_STANDBY) {
+                       /* Expire discoveries discovered on this link */
+                       irlmp_expire_discoveries(irlmp->cachelog, lap->saddr,
+                                                FALSE);
+               }
+               lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
+       }
+}
+
+/*
  * Function irlmp_do_discovery (nslots)
  *
  *    Do some discovery on all links
  *
+ * Note : log expiry is done above.
  */
 void irlmp_do_discovery(int nslots)
 {
@@ -731,10 +764,6 @@ void irlmp_do_discovery(int nslots)
                ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
                
                if (lap->lap_state == LAP_STANDBY) {
-                       /* Expire discoveries discovered on this link */
-                       irlmp_expire_discoveries(irlmp->cachelog, lap->saddr,
-                                                FALSE);
-
                        /* Try to discover */
                        irlmp_do_lap_event(lap, LM_LAP_DISCOVERY_REQUEST, 
                                           NULL);
@@ -764,6 +793,9 @@ void irlmp_discovery_request(int nslots)
         */
        if (!sysctl_discovery)
                irlmp_do_discovery(nslots);
+       /* Note : we never do expiry here. Expiry will run on the
+        * discovery timer regardless of the state of sysctl_discovery
+        * Jean II */
 }
 
 /*
diff -u -p linux/net/irda/irlmp_event.d8.c linux/net/irda/irlmp_event.c
--- linux/net/irda/irlmp_event.d8.c     Thu Sep 13 11:50:03 2001
+++ linux/net/irda/irlmp_event.c        Thu Sep 13 11:51:00 2001
@@ -150,6 +150,10 @@ void irlmp_discovery_timer_expired(void 
 {
        IRDA_DEBUG(4, __FUNCTION__ "()\n");
        
+       /* We always cleanup the log (active & passive discovery) */ 
+       irlmp_do_expiry();
+
+       /* Active discovery is conditional */
        if (sysctl_discovery)
                irlmp_do_discovery(sysctl_discovery_slots);
 
@@ -205,10 +209,6 @@ static void irlmp_state_standby(struct l
                
                irlap_discovery_request(self->irlap, &irlmp->discovery_cmd);
                break;
-       case LM_LAP_DISCOVERY_CONFIRM:
-               /* irlmp_next_station_state( LMP_READY); */
-               irlmp_discovery_confirm(irlmp->cachelog);
-               break;
        case LM_LAP_CONNECT_INDICATION:
                /*  It's important to switch state first, to avoid IrLMP to 
                 *  think that the link is free since IrLMP may then start
@@ -274,6 +274,12 @@ static void irlmp_state_u_connect(struct
                        irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
                        lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
                }
+               /* Note : by the time we get there (LAP retries and co),
+                * the lsaps may already have gone. This avoid getting stuck
+                * forever in LAP_ACTIVE state - Jean II */
+               if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
+                       irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
+               }
                break;
        case LM_LAP_CONNECT_REQUEST:
                /* Already trying to connect */
@@ -287,6 +293,12 @@ static void irlmp_state_u_connect(struct
                while (lsap != NULL) {
                        irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
                        lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
+               }
+               /* Note : by the time we get there (LAP retries and co),
+                * the lsaps may already have gone. This avoid getting stuck
+                * forever in LAP_ACTIVE state - Jean II */
+               if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
+                       irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
                }
                break;
        case LM_LAP_DISCONNECT_INDICATION:
diff -u -p linux/net/irda/irlmp_frame.d8.c linux/net/irda/irlmp_frame.c
--- linux/net/irda/irlmp_frame.d8.c     Thu Sep 13 11:50:15 2001
+++ linux/net/irda/irlmp_frame.c        Thu Sep 13 11:51:00 2001
@@ -359,8 +359,9 @@ static void irlmp_discovery_timeout(u_lo
        self = (struct lap_cb *) priv;
        ASSERT(self != NULL, return;);
 
-       /* Just handle it the same way as a discovery confirm */
-       irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
+       /* Just handle it the same way as a discovery confirm,
+        * bypass the LM_LAP state machine (see below) */
+       irlmp_discovery_confirm(irlmp->cachelog);
 }
 
 /*
@@ -377,8 +378,12 @@ static void irlmp_discovery_timeout(u_lo
  *       we always get ~100% of these.
  *     o Make faster discovery, statistically divide time of discovery
  *       events by 2 (important for the latency aspect and user feel)
+ *     o Even is we do active discovery, the other node might not
+ *       answer our discoveries (ex: Palm).
+ *
  * However, when both devices discover each other, they might attempt to
- * connect to each other, and it would create collisions on the medium.
+ * connect to each other following the discovery event, and it would create
+ * collisions on the medium (SNRM battle).
  * The trick here is to defer the event by a little delay to avoid both
  * devices to jump in exactly at the same time...
  *
@@ -387,6 +392,14 @@ static void irlmp_discovery_timeout(u_lo
  * period/timeout that may be set is 1s). The message triggering this
  * event was the last of the discovery, so the medium is now free...
  * Maybe more testing is needed to get the value right...
+
+ * One more problem : the other node might do only a single discovery
+ * and connect immediately to us, and we would receive only a single
+ * discovery indication event, and because of the delay, it will arrive
+ * while the LAP is connected. That's another good reason to
+ * bypass the LM_LAP state machine ;-)
+ *
+ * Jean II
  */
 void irlmp_link_discovery_indication(struct lap_cb *self, 
                                     discovery_t *discovery)
@@ -427,8 +440,13 @@ void irlmp_link_discovery_confirm(struct
        if(timer_pending(&disco_delay))
                del_timer(&disco_delay);
 
-       /* Propagate event to the state machine */
-       irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
+       /* Propagate event to various LSAPs registered for it.
+        * We bypass the LM_LAP state machine because
+        *      1) We do it regardless of the LM_LAP state
+        *      2) It doesn't affect the LM_LAP state
+        *      3) Faster, slimer, simpler, ...
+        * Jean II */
+       irlmp_discovery_confirm(irlmp->cachelog);
 }
 
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
diff -u -p linux/net/irda/irlap_event.d8.c linux/net/irda/irlap_event.c
--- linux/net/irda/irlap_event.d8.c     Thu Sep 13 11:50:26 2001
+++ linux/net/irda/irlap_event.c        Thu Sep 13 11:51:00 2001
@@ -2018,7 +2018,7 @@ static int irlap_state_sclose(struct irl
 {
        int ret = 0;
 
-       IRDA_DEBUG(0, __FUNCTION__ "()\n");
+       IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
        ASSERT(self != NULL, return -ENODEV;);
        ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
@@ -2048,6 +2048,9 @@ static int irlap_state_sclose(struct irl
                irlap_disconnect_indication(self, LAP_DISC_INDICATION);
                break;
        case WD_TIMER_EXPIRED:
+               /* Always switch state before calling upper layers */
+               irlap_next_state(self, LAP_NDM);
+
                irlap_apply_default_connection_parameters(self);
                
                irlap_disconnect_indication(self, LAP_DISC_INDICATION);
_______________________________________________
Linux-IrDA mailing list  -  [EMAIL PROTECTED]
http://www.pasta.cs.UiT.No/mailman/listinfo/linux-irda

Reply via email to