Commit 9652041d authored by Krzysztof Halasa's avatar Krzysztof Halasa Committed by David S. Miller

WAN: fix Cisco HDLC handshaking.

Cisco HDLC uses keepalive packets and sequence numbers to determine link
state. In rare cases both ends could transmit keepalive packets at the same
time, causing the received sequence numbers to be treated as incorrect.
Now we accept our current sequence number as well as the previous one.
Signed-off-by: default avatarKrzysztof Hałasa <khc@pm.waw.pl>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6d01a026
...@@ -58,8 +58,7 @@ struct cisco_state { ...@@ -58,8 +58,7 @@ struct cisco_state {
spinlock_t lock; spinlock_t lock;
unsigned long last_poll; unsigned long last_poll;
int up; int up;
int request_sent; u32 txseq; /* TX sequence number, 0 = none */
u32 txseq; /* TX sequence number */
u32 rxseq; /* RX sequence number */ u32 rxseq; /* RX sequence number */
}; };
...@@ -163,6 +162,7 @@ static int cisco_rx(struct sk_buff *skb) ...@@ -163,6 +162,7 @@ static int cisco_rx(struct sk_buff *skb)
struct cisco_packet *cisco_data; struct cisco_packet *cisco_data;
struct in_device *in_dev; struct in_device *in_dev;
__be32 addr, mask; __be32 addr, mask;
u32 ack;
if (skb->len < sizeof(struct hdlc_header)) if (skb->len < sizeof(struct hdlc_header))
goto rx_error; goto rx_error;
...@@ -223,8 +223,10 @@ static int cisco_rx(struct sk_buff *skb) ...@@ -223,8 +223,10 @@ static int cisco_rx(struct sk_buff *skb)
case CISCO_KEEPALIVE_REQ: case CISCO_KEEPALIVE_REQ:
spin_lock(&st->lock); spin_lock(&st->lock);
st->rxseq = ntohl(cisco_data->par1); st->rxseq = ntohl(cisco_data->par1);
if (st->request_sent && ack = ntohl(cisco_data->par2);
ntohl(cisco_data->par2) == st->txseq) { if (ack && (ack == st->txseq ||
/* our current REQ may be in transit */
ack == st->txseq - 1)) {
st->last_poll = jiffies; st->last_poll = jiffies;
if (!st->up) { if (!st->up) {
u32 sec, min, hrs, days; u32 sec, min, hrs, days;
...@@ -275,7 +277,6 @@ static void cisco_timer(unsigned long arg) ...@@ -275,7 +277,6 @@ static void cisco_timer(unsigned long arg)
cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, htonl(++st->txseq), cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, htonl(++st->txseq),
htonl(st->rxseq)); htonl(st->rxseq));
st->request_sent = 1;
spin_unlock(&st->lock); spin_unlock(&st->lock);
st->timer.expires = jiffies + st->settings.interval * HZ; st->timer.expires = jiffies + st->settings.interval * HZ;
...@@ -293,9 +294,7 @@ static void cisco_start(struct net_device *dev) ...@@ -293,9 +294,7 @@ static void cisco_start(struct net_device *dev)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&st->lock, flags); spin_lock_irqsave(&st->lock, flags);
st->up = 0; st->up = st->txseq = st->rxseq = 0;
st->request_sent = 0;
st->txseq = st->rxseq = 0;
spin_unlock_irqrestore(&st->lock, flags); spin_unlock_irqrestore(&st->lock, flags);
init_timer(&st->timer); init_timer(&st->timer);
...@@ -317,8 +316,7 @@ static void cisco_stop(struct net_device *dev) ...@@ -317,8 +316,7 @@ static void cisco_stop(struct net_device *dev)
spin_lock_irqsave(&st->lock, flags); spin_lock_irqsave(&st->lock, flags);
netif_dormant_on(dev); netif_dormant_on(dev);
st->up = 0; st->up = st->txseq = 0;
st->request_sent = 0;
spin_unlock_irqrestore(&st->lock, flags); spin_unlock_irqrestore(&st->lock, flags);
} }
......
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