Commit 1489877f authored by Jean Tourrilhes's avatar Jean Tourrilhes Committed by Linus Torvalds

[PATCH] : ir256_lap_icmd_fix-4.diff

ir256_lap_icmd_fix-4.diff :
 -------------------------
	o [CORRECT] Fix Tx queue handling (remove race, keep packets in order)
	o [CORRECT] Synchronise window_size & line_capacity and make sure
	  we never forget to increase them (would stall Tx queue)
	o [FEATURE] Group common code out of if-then-else
	o [FEATURE] Don't harcode LAP header size, use proper constant
	o [FEATURE] Inline irlap_next_state() to decrease bloat
parent 5ba24bbf
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* *
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved. * All Rights Reserved.
* Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -44,6 +45,7 @@ ...@@ -44,6 +45,7 @@
#define LAP_ADDR_HEADER 1 /* IrLAP Address Header */ #define LAP_ADDR_HEADER 1 /* IrLAP Address Header */
#define LAP_CTRL_HEADER 1 /* IrLAP Control Header */ #define LAP_CTRL_HEADER 1 /* IrLAP Control Header */
/* May be different when we get VFIR */
#define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER) #define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER)
#define BROADCAST 0xffffffff /* Broadcast device address */ #define BROADCAST 0xffffffff /* Broadcast device address */
...@@ -210,9 +212,8 @@ void irlap_wait_min_turn_around(struct irlap_cb *, struct qos_info *); ...@@ -210,9 +212,8 @@ void irlap_wait_min_turn_around(struct irlap_cb *, struct qos_info *);
void irlap_init_qos_capabilities(struct irlap_cb *, struct qos_info *); void irlap_init_qos_capabilities(struct irlap_cb *, struct qos_info *);
void irlap_apply_default_connection_parameters(struct irlap_cb *self); void irlap_apply_default_connection_parameters(struct irlap_cb *self);
void irlap_apply_connection_parameters(struct irlap_cb *self, int now); 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 */ #define IRLAP_GET_HEADER_SIZE(self) (LAP_MAX_HEADER)
#define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq) #define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq)
#endif #endif
...@@ -134,7 +134,6 @@ extern const char *irlap_state[]; ...@@ -134,7 +134,6 @@ extern const char *irlap_state[];
void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
struct sk_buff *skb, struct irlap_info *info); struct sk_buff *skb, struct irlap_info *info);
void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state);
void irlap_print_event(IRLAP_EVENT event); void irlap_print_event(IRLAP_EVENT event);
extern int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb); extern int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb);
......
...@@ -131,7 +131,7 @@ struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos, ...@@ -131,7 +131,7 @@ struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos,
/* FIXME: should we get our own field? */ /* FIXME: should we get our own field? */
dev->atalk_ptr = self; dev->atalk_ptr = self;
irlap_next_state(self, LAP_OFFLINE); self->state = LAP_OFFLINE;
/* Initialize transmit queue */ /* Initialize transmit queue */
skb_queue_head_init(&self->txq); skb_queue_head_init(&self->txq);
...@@ -155,7 +155,7 @@ struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos, ...@@ -155,7 +155,7 @@ struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos,
self->N3 = 3; /* # connections attemts to try before giving up */ self->N3 = 3; /* # connections attemts to try before giving up */
irlap_next_state(self, LAP_NDM); self->state = LAP_NDM;
hashbin_insert(irlap, (irda_queue_t *) self, self->saddr, NULL); hashbin_insert(irlap, (irda_queue_t *) self, self->saddr, NULL);
...@@ -346,25 +346,21 @@ void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb, ...@@ -346,25 +346,21 @@ void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
else else
skb->data[1] = I_FRAME; skb->data[1] = I_FRAME;
/* Add at the end of the queue (keep ordering) - Jean II */
skb_queue_tail(&self->txq, skb);
/* /*
* Send event if this frame only if we are in the right state * Send event if this frame only if we are in the right state
* FIXME: udata should be sent first! (skb_queue_head?) * FIXME: udata should be sent first! (skb_queue_head?)
*/ */
if ((self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) { if ((self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) {
/* /* If we are not already processing the Tx queue, trigger
* Check if the transmit queue contains some unsent frames, * transmission immediately - Jean II */
* and if so, make sure they are sent first if((skb_queue_len(&self->txq) <= 1) && (!self->local_busy))
*/ irlap_do_event(self, DATA_REQUEST, skb, NULL);
if (!skb_queue_empty(&self->txq)) { /* Otherwise, the packets will be sent normally at the
skb_queue_tail(&self->txq, skb); * next pf-poll - Jean II */
skb = skb_dequeue(&self->txq);
ASSERT(skb != NULL, return;);
} }
irlap_do_event(self, SEND_I_CMD, skb, NULL);
kfree_skb(skb);
} else
skb_queue_tail(&self->txq, skb);
} }
/* /*
...@@ -1013,6 +1009,7 @@ void irlap_apply_connection_parameters(struct irlap_cb *self, int now) ...@@ -1013,6 +1009,7 @@ void irlap_apply_connection_parameters(struct irlap_cb *self, int now)
self->window_size = self->qos_tx.window_size.value; self->window_size = self->qos_tx.window_size.value;
self->window = self->qos_tx.window_size.value; self->window = self->qos_tx.window_size.value;
#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
/* /*
* Calculate how many bytes it is possible to transmit before the * Calculate how many bytes it is possible to transmit before the
* link must be turned around * link must be turned around
...@@ -1020,6 +1017,8 @@ void irlap_apply_connection_parameters(struct irlap_cb *self, int now) ...@@ -1020,6 +1017,8 @@ void irlap_apply_connection_parameters(struct irlap_cb *self, int now)
self->line_capacity = self->line_capacity =
irlap_max_line_capacity(self->qos_tx.baud_rate.value, irlap_max_line_capacity(self->qos_tx.baud_rate.value,
self->qos_tx.max_turn_time.value); self->qos_tx.max_turn_time.value);
self->bytes_left = self->line_capacity;
#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
/* /*
...@@ -1082,24 +1081,6 @@ void irlap_apply_connection_parameters(struct irlap_cb *self, int now) ...@@ -1082,24 +1081,6 @@ void irlap_apply_connection_parameters(struct irlap_cb *self, int now)
IRDA_DEBUG(4, "Setting N2 = %d\n", self->N2); IRDA_DEBUG(4, "Setting N2 = %d\n", self->N2);
} }
/*
* Function irlap_set_local_busy (self, status)
*
*
*
*/
void irlap_set_local_busy(struct irlap_cb *self, int status)
{
IRDA_DEBUG(0, __FUNCTION__ "()\n");
self->local_busy = status;
if (status)
IRDA_DEBUG(0, __FUNCTION__ "(), local busy ON\n");
else
IRDA_DEBUG(0, __FUNCTION__ "(), local busy OFF\n");
}
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
/* /*
* Function irlap_proc_read (buf, start, offset, len, unused) * Function irlap_proc_read (buf, start, offset, len, unused)
......
...@@ -252,6 +252,9 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, ...@@ -252,6 +252,9 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
* that will change the state away form XMIT * that will change the state away form XMIT
*/ */
if (skb_queue_len(&self->txq)) { if (skb_queue_len(&self->txq)) {
/* Prevent race conditions with irlap_data_request() */
self->local_busy = TRUE;
/* Try to send away all queued data frames */ /* Try to send away all queued data frames */
while ((skb = skb_dequeue(&self->txq)) != NULL) { while ((skb = skb_dequeue(&self->txq)) != NULL) {
ret = (*state[self->state])(self, SEND_I_CMD, ret = (*state[self->state])(self, SEND_I_CMD,
...@@ -260,6 +263,8 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, ...@@ -260,6 +263,8 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
if (ret == -EPROTO) if (ret == -EPROTO)
break; /* Try again later! */ break; /* Try again later! */
} }
/* Finished transmitting */
self->local_busy = FALSE;
} else if (self->disconnect_pending) { } else if (self->disconnect_pending) {
self->disconnect_pending = FALSE; self->disconnect_pending = FALSE;
...@@ -282,25 +287,15 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, ...@@ -282,25 +287,15 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
* Switches state and provides debug information * Switches state and provides debug information
* *
*/ */
void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state) static inline void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state)
{ {
/*
if (!self || self->magic != LAP_MAGIC) if (!self || self->magic != LAP_MAGIC)
return; return;
IRDA_DEBUG(4, "next LAP state = %s\n", irlap_state[state]); IRDA_DEBUG(4, "next LAP state = %s\n", irlap_state[state]);
self->state = state;
#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
/*
* If we are swithing away from a XMIT state then we are allowed to
* transmit a maximum number of bytes again when we enter the XMIT
* state again. Since its possible to "switch" from XMIT to XMIT,
* we cannot do this when swithing into the XMIT state :-)
*/ */
if ((state != LAP_XMIT_P) && (state != LAP_XMIT_S)) self->state = state;
self->bytes_left = self->line_capacity;
#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
} }
/* /*
...@@ -1017,6 +1012,12 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event, ...@@ -1017,6 +1012,12 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
IRDA_DEBUG(3, __FUNCTION__ "(), POLL_TIMER_EXPIRED (%ld)\n", IRDA_DEBUG(3, __FUNCTION__ "(), POLL_TIMER_EXPIRED (%ld)\n",
jiffies); jiffies);
irlap_send_rr_frame(self, CMD_FRAME); irlap_send_rr_frame(self, CMD_FRAME);
/* Return to NRM properly - Jean II */
self->window = self->window_size;
#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
/* Allowed to transmit a maximum number of bytes again. */
self->bytes_left = self->line_capacity;
#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
irlap_start_final_timer(self, self->final_timeout); irlap_start_final_timer(self, self->final_timeout);
irlap_next_state(self, LAP_NRM_P); irlap_next_state(self, LAP_NRM_P);
break; break;
...@@ -1029,6 +1030,10 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event, ...@@ -1029,6 +1030,10 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
self->retry_count = 0; self->retry_count = 0;
irlap_next_state(self, LAP_PCLOSE); irlap_next_state(self, LAP_PCLOSE);
break; break;
case DATA_REQUEST:
/* Nothing to do, irlap_do_event() will send the packet
* when we return... - Jean II */
break;
default: default:
IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
irlap_event[event]); irlap_event[event]);
...@@ -1645,12 +1650,17 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event, ...@@ -1645,12 +1650,17 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
*/ */
if (skb->len > self->bytes_left) { if (skb->len > self->bytes_left) {
skb_queue_head(&self->txq, skb_get(skb)); skb_queue_head(&self->txq, skb_get(skb));
/* /*
* Switch to NRM_S, this is only possible * Switch to NRM_S, this is only possible
* when we are in secondary mode, since we * when we are in secondary mode, since we
* must be sure that we don't miss any RR * must be sure that we don't miss any RR
* frames * frames
*/ */
self->window = self->window_size;
self->bytes_left = self->line_capacity;
irlap_start_wd_timer(self, self->wd_timeout);
irlap_next_state(self, LAP_NRM_S); irlap_next_state(self, LAP_NRM_S);
return -EPROTO; /* Try again later */ return -EPROTO; /* Try again later */
...@@ -1688,6 +1698,10 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event, ...@@ -1688,6 +1698,10 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
irlap_start_wd_timer(self, self->wd_timeout); irlap_start_wd_timer(self, self->wd_timeout);
irlap_next_state(self, LAP_SCLOSE); irlap_next_state(self, LAP_SCLOSE);
break; break;
case DATA_REQUEST:
/* Nothing to do, irlap_do_event() will send the packet
* when we return... - Jean II */
break;
default: default:
IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n",
irlap_event[event]); irlap_event[event]);
......
...@@ -768,6 +768,9 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) ...@@ -768,6 +768,9 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
{ {
struct sk_buff *tx_skb; struct sk_buff *tx_skb;
/* Stop P timer */
del_timer(&self->poll_timer);
/* Is this reliable or unreliable data? */ /* Is this reliable or unreliable data? */
if (skb->data[1] == I_FRAME) { if (skb->data[1] == I_FRAME) {
...@@ -793,23 +796,15 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) ...@@ -793,23 +796,15 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
* skb, since retransmitted need to set or clear the poll * skb, since retransmitted need to set or clear the poll
* bit depending on when they are sent. * bit depending on when they are sent.
*/ */
/* Stop P timer */
del_timer(&self->poll_timer);
tx_skb->data[1] |= PF_BIT; tx_skb->data[1] |= PF_BIT;
self->vs = (self->vs + 1) % 8; self->vs = (self->vs + 1) % 8;
self->ack_required = FALSE; self->ack_required = FALSE;
self->window = self->window_size;
irlap_start_final_timer(self, self->final_timeout);
irlap_send_i_frame(self, tx_skb, CMD_FRAME); irlap_send_i_frame(self, tx_skb, CMD_FRAME);
} else { } else {
IRDA_DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n"); IRDA_DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
del_timer(&self->poll_timer);
if (self->ack_required) { if (self->ack_required) {
irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
irlap_send_rr_frame(self, CMD_FRAME); irlap_send_rr_frame(self, CMD_FRAME);
...@@ -818,9 +813,15 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) ...@@ -818,9 +813,15 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
skb->data[1] |= PF_BIT; skb->data[1] |= PF_BIT;
irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
} }
}
self->window = self->window_size; self->window = self->window_size;
#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
/* We are allowed to transmit a maximum number of bytes again. */
self->bytes_left = self->line_capacity;
#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
irlap_start_final_timer(self, self->final_timeout); irlap_start_final_timer(self, self->final_timeout);
}
} }
/* /*
...@@ -858,11 +859,8 @@ void irlap_send_data_secondary_final(struct irlap_cb *self, ...@@ -858,11 +859,8 @@ void irlap_send_data_secondary_final(struct irlap_cb *self,
tx_skb->data[1] |= PF_BIT; tx_skb->data[1] |= PF_BIT;
self->vs = (self->vs + 1) % 8; self->vs = (self->vs + 1) % 8;
self->window = self->window_size;
self->ack_required = FALSE; self->ack_required = FALSE;
irlap_start_wd_timer(self, self->wd_timeout);
irlap_send_i_frame(self, tx_skb, RSP_FRAME); irlap_send_i_frame(self, tx_skb, RSP_FRAME);
} else { } else {
if (self->ack_required) { if (self->ack_required) {
...@@ -873,10 +871,15 @@ void irlap_send_data_secondary_final(struct irlap_cb *self, ...@@ -873,10 +871,15 @@ void irlap_send_data_secondary_final(struct irlap_cb *self,
skb->data[1] |= PF_BIT; skb->data[1] |= PF_BIT;
irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
} }
}
self->window = self->window_size; self->window = self->window_size;
#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
/* We are allowed to transmit a maximum number of bytes again. */
self->bytes_left = self->line_capacity;
#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
irlap_start_wd_timer(self, self->wd_timeout); irlap_start_wd_timer(self, self->wd_timeout);
}
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment