Hi,

        Could you process and send this patch to Linus. You may want
to do a bit of cleanup...

        This basically fix a long standing bug in the stack. You were
not changing the link parameters at the right time. I had already seen
its manifestation before :
http://www.pasta.cs.uit.no/pipermail/linux-irda/2000-September/001783.html

        By the way I've got the USB driver working here. Could you
give me the list of problems you saw with it ? I'll try to fix
everything I can...

        Have fun...

        Jean
diff -u -p linux/include/net/irda/irda_device.d6.h linux/include/net/irda/irda_device.h
--- linux/include/net/irda/irda_device.d6.h     Fri Dec 29 16:19:09 2000
+++ linux/include/net/irda/irda_device.h        Fri Dec 29 18:23:51 2000
@@ -220,7 +220,7 @@ extern inline __u16 irda_get_mtt(struct 
 /*
  * Function irda_get_speed (skb)
  *
- *    Extact the speed this frame should be sent out with from the skb
+ *    Extract the speed that should be set *after* this frame from the skb
  *
  */
 #define irda_get_speed(skb) (                                          \
@@ -241,6 +241,17 @@ extern inline __u32 irda_get_speed(struc
        return speed;
 }
 #endif
+
+/*
+ * Function irda_get_new_xbofs (skb)
+ *
+ *    Extract the xbofs that should be set *after* this frame from the skb
+ *
+ */
+#define irda_get_new_xbofs(skb) (                                              \
+       (((struct irda_skb_cb*) skb->cb)->magic == LAP_MAGIC) ?         \
+                  ((struct irda_skb_cb *)(skb->cb))->next_xbofs : 12   \
+)
 
 #endif /* IRDA_DEVICE_H */
 
diff -u -p linux/include/net/irda/irlap.d6.h linux/include/net/irda/irlap.h
--- linux/include/net/irda/irlap.d6.h   Fri Dec 29 17:47:59 2000
+++ linux/include/net/irda/irlap.h      Fri Dec 29 18:22:53 2000
@@ -168,7 +168,7 @@ struct irlap_cb {
        hashbin_t   *discovery_log;
        discovery_t *discovery_cmd;
 
-       __u32 speed; 
+       __u32 speed;            /* Link speed */
 
        struct qos_info  qos_tx;   /* QoS requested by peer */
        struct qos_info  qos_rx;   /* QoS requested by self */
@@ -179,6 +179,7 @@ struct irlap_cb {
        int    mtt_required;  /* Minumum turnaround time required */
        int    xbofs_delay;   /* Nr of XBOF's used to MTT */
        int    bofs_count;    /* Negotiated extra BOFs */
+       int    next_bofs;     /* Negotiated extra BOFs after next frame */
 
 #ifdef CONFIG_IRDA_COMPRESSION
        struct irda_compressor compressor;
@@ -237,7 +238,7 @@ void irlap_wait_min_turn_around(struct i
 
 void irlap_init_qos_capabilities(struct irlap_cb *, struct qos_info *);
 void irlap_apply_default_connection_parameters(struct irlap_cb *self);
-void irlap_apply_connection_parameters(struct irlap_cb *self);
+void irlap_apply_connection_parameters(struct irlap_cb *self, int now);
 void irlap_set_local_busy(struct irlap_cb *self, int status);
 
 #define IRLAP_GET_HEADER_SIZE(self) 2 /* Will be different when we get VFIR */
diff -u -p linux/include/net/irda/irda.d6.h linux/include/net/irda/irda.h
--- linux/include/net/irda/irda.d6.h    Fri Dec 29 17:45:19 2000
+++ linux/include/net/irda/irda.h       Fri Dec 29 18:22:53 2000
@@ -177,9 +177,10 @@ typedef union {
  */
 struct irda_skb_cb {
        magic_t magic;       /* Be sure that we can trust the information */
-       __u32   speed;       /* The Speed this frame should be sent with */
+       __u32   speed;       /* The Speed to be set *after* this frame */
        __u16   mtt;         /* Minimum turn around time */
        __u16   xbofs;       /* Number of xbofs required, used by SIR mode */
+       __u16   next_xbofs;  /* Number of xbofs required *after* this frame */
        void    *context;    /* May be used by drivers */
        void    (*destructor)(struct sk_buff *skb); /* Used for flow control */
        __u16   xbofs_delay; /* Number of xbofs used for generating the mtt */
diff -u -p linux/net/irda/irlap.d6.c linux/net/irda/irlap.c
--- linux/net/irda/irlap.d6.c   Fri Dec 29 17:22:55 2000
+++ linux/net/irda/irlap.c      Fri Dec 29 18:01:34 2000
@@ -1056,23 +1056,31 @@ void irlap_apply_default_connection_para
 }
 
 /*
- * Function irlap_apply_connection_parameters (qos)
+ * Function irlap_apply_connection_parameters (qos, now)
  *
  *    Initialize IrLAP with the negotiated QoS values
  *
+ * If 'now' is false, the speed and xbofs will be changed after the next
+ * frame is sent.
+ * If 'now' is true, the speed and xbofs is changed immediately
  */
-void irlap_apply_connection_parameters(struct irlap_cb *self) 
+void irlap_apply_connection_parameters(struct irlap_cb *self, int now) 
 {
        IRDA_DEBUG(4, __FUNCTION__ "()\n");
        
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == LAP_MAGIC, return;);
 
-       irlap_change_speed(self, self->qos_tx.baud_rate.value, FALSE);
+       /* Set the negociated xbofs value */
+       self->next_bofs   = self->qos_tx.additional_bofs.value;
+       if(now)
+               self->bofs_count = self->next_bofs;
+
+       /* Set the negociated link speed (may need the new xbofs value) */
+       irlap_change_speed(self, self->qos_tx.baud_rate.value, now);
 
        self->window_size = self->qos_tx.window_size.value;
        self->window      = self->qos_tx.window_size.value;
-       self->bofs_count  = self->qos_tx.additional_bofs.value;
 
        /*
         *  Calculate how many bytes it is possible to transmit before the
diff -u -p linux/net/irda/irlap_frame.d6.c linux/net/irda/irlap_frame.c
--- linux/net/irda/irlap_frame.d6.c     Fri Dec 29 17:23:23 2000
+++ linux/net/irda/irlap_frame.c        Fri Dec 29 18:23:00 2000
@@ -70,10 +70,13 @@ static inline void irlap_insert_info(str
         * force the negotiated minimum turnaround time 
         */
        cb->xbofs = self->bofs_count;
+       cb->next_xbofs = self->next_bofs;
        cb->xbofs_delay = self->xbofs_delay;
        
        /* Reset XBOF's delay (used only for getting min turn time) */
        self->xbofs_delay = 0;
+       /* Put the correct xbofs value for the next packet */
+       self->bofs_count = self->next_bofs;
 }
 
 /*
diff -u -p linux/net/irda/irlap_event.d6.c linux/net/irda/irlap_event.c
--- linux/net/irda/irlap_event.d6.c     Fri Dec 29 17:31:37 2000
+++ linux/net/irda/irlap_event.c        Fri Dec 29 17:30:58 2000
@@ -694,13 +694,13 @@ static int irlap_state_conn(struct irlap
 
                /* 
                 * Applying the parameters now will make sure we change speed
-                * after we have sent the next frame
+                * *after* we have sent the next frame
                 */
-               irlap_apply_connection_parameters(self);
+               irlap_apply_connection_parameters(self, FALSE);
 
                /* 
                 * Sending this frame will force a speed change after it has
-                * been sent
+                * been sent (i.e. the frame will be sent at 9600).
                 */
                irlap_send_ua_response_frame(self, &self->qos_rx);
 
@@ -794,8 +794,9 @@ static int irlap_state_setup(struct irla
 
                        irlap_qos_negotiate(self, skb);
                        
+                       /* Send UA frame and then change link settings */
+                       irlap_apply_connection_parameters(self, FALSE);
                        irlap_send_ua_response_frame(self, &self->qos_rx);
-                       irlap_apply_connection_parameters(self);
 
                        irlap_next_state(self, LAP_NRM_S);
                        irlap_connect_confirm(self, skb);
@@ -827,10 +828,11 @@ static int irlap_state_setup(struct irla
 
                irlap_qos_negotiate(self, skb);
 
-               irlap_apply_connection_parameters(self);
+               /* Set the new link setting *now* (before the rr frame) */
+               irlap_apply_connection_parameters(self, TRUE);
                self->retry_count = 0;
                
-               /* This frame will actually force the speed change */
+               /* This frame will actually be sent at the new speed */
                irlap_send_rr_frame(self, CMD_FRAME);
 
                irlap_start_final_timer(self, self->final_timeout/2);

Reply via email to