summaryrefslogtreecommitdiffstats
path: root/net/x25
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-12-16 05:34:03 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-12-16 05:34:03 +0000
commit967c65a99059fd459b956c1588ce0ba227912c4e (patch)
tree8224d013ff5d255420713d05610c7efebd204d2a /net/x25
parente20c1cc1656a66a2773bca4591a895cbc12696ff (diff)
Merge with Linux 2.1.72, part 1.
Diffstat (limited to 'net/x25')
-rw-r--r--net/x25/af_x25.c1
-rw-r--r--net/x25/x25_dev.c3
-rw-r--r--net/x25/x25_in.c16
-rw-r--r--net/x25/x25_out.c37
-rw-r--r--net/x25/x25_subr.c46
5 files changed, 74 insertions, 29 deletions
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 2970a82b9..bc473e317 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -440,6 +440,7 @@ static struct sock *x25_alloc_socket(void)
sock_init_data(NULL, sk);
+ skb_queue_head_init(&x25->ack_queue);
skb_queue_head_init(&x25->fragment_queue);
skb_queue_head_init(&x25->interrupt_in_queue);
skb_queue_head_init(&x25->interrupt_out_queue);
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index e4cd99ae7..c8ffb33ef 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -177,7 +177,6 @@ void x25_establish_link(struct x25_neigh *neigh)
}
skb->protocol = htons(ETH_P_X25);
- skb->priority = SOPRI_NORMAL;
skb->dev = neigh->dev;
skb->arp = 1;
@@ -208,7 +207,6 @@ void x25_terminate_link(struct x25_neigh *neigh)
}
skb->protocol = htons(ETH_P_X25);
- skb->priority = SOPRI_NORMAL;
skb->dev = neigh->dev;
skb->arp = 1;
@@ -236,7 +234,6 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *neigh)
}
skb->protocol = htons(ETH_P_X25);
- skb->priority = SOPRI_NORMAL;
skb->dev = neigh->dev;
skb->arp = 1;
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
index 96b459a4e..1c4cb3bc7 100644
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -174,6 +174,7 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
sk->protinfo.x25->vr = 0;
sk->protinfo.x25->va = 0;
sk->protinfo.x25->vl = 0;
+ x25_requeue_frames(sk);
break;
case X25_CLEAR_REQUEST:
@@ -199,11 +200,9 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
sk->protinfo.x25->vl = 0;
sk->protinfo.x25->state = X25_STATE_4;
} else {
- if (sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) {
- sk->protinfo.x25->va = nr;
- } else {
- x25_check_iframes_acked(sk, nr);
- }
+ x25_frames_acked(sk, nr);
+ if (frametype == X25_RNR)
+ x25_requeue_frames(sk);
}
break;
@@ -221,11 +220,7 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
sk->protinfo.x25->state = X25_STATE_4;
break;
}
- if (sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) {
- sk->protinfo.x25->va = nr;
- } else {
- x25_check_iframes_acked(sk, nr);
- }
+ x25_frames_acked(sk, nr);
if (sk->protinfo.x25->condition & X25_COND_OWN_RX_BUSY)
break;
if (ns == sk->protinfo.x25->vr) {
@@ -298,6 +293,7 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
sk->protinfo.x25->vs = 0;
sk->protinfo.x25->vl = 0;
sk->protinfo.x25->state = X25_STATE_3;
+ x25_requeue_frames(sk);
break;
case X25_CLEAR_REQUEST:
diff --git a/net/x25/x25_out.c b/net/x25/x25_out.c
index aa8fc2c1b..5283092a1 100644
--- a/net/x25/x25_out.c
+++ b/net/x25/x25_out.c
@@ -126,8 +126,8 @@ static void x25_send_iframe(struct sock *sk, struct sk_buff *skb)
void x25_kick(struct sock *sk)
{
- struct sk_buff *skb;
- unsigned short end;
+ struct sk_buff *skb, *skbn;
+ unsigned short start, end;
int modulus;
if (sk->protinfo.x25->state != X25_STATE_3)
@@ -149,11 +149,15 @@ void x25_kick(struct sock *sk)
return;
modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
+
+ start = (skb_peek(&sk->protinfo.x25->ack_queue) == NULL) ? sk->protinfo.x25->va : sk->protinfo.x25->vs;
end = (sk->protinfo.x25->va + sk->protinfo.x25->facilities.winsize_out) % modulus;
- if (sk->protinfo.x25->vs == end)
+ if (start == end)
return;
+ sk->protinfo.x25->vs = start;
+
/*
* Transmit data until either we're out of data to send or
* the window is full.
@@ -162,13 +166,25 @@ void x25_kick(struct sock *sk)
skb = skb_dequeue(&sk->write_queue);
do {
+ if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+ skb_queue_head(&sk->write_queue, skb);
+ break;
+ }
+
+ skb_set_owner_w(skbn, sk);
+
/*
- * Transmit the frame.
+ * Transmit the frame copy.
*/
- x25_send_iframe(sk, skb);
+ x25_send_iframe(sk, skbn);
sk->protinfo.x25->vs = (sk->protinfo.x25->vs + 1) % modulus;
+ /*
+ * Requeue the original data frame.
+ */
+ skb_queue_tail(&sk->protinfo.x25->ack_queue, skb);
+
} while (sk->protinfo.x25->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
sk->protinfo.x25->vl = sk->protinfo.x25->vr;
@@ -195,15 +211,4 @@ void x25_enquiry_response(struct sock *sk)
x25_stop_timer(sk);
}
-void x25_check_iframes_acked(struct sock *sk, unsigned short nr)
-{
- if (sk->protinfo.x25->vs == nr) {
- sk->protinfo.x25->va = nr;
- } else {
- if (sk->protinfo.x25->va != nr) {
- sk->protinfo.x25->va = nr;
- }
- }
-}
-
#endif
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
index f2aff6d12..52e5be0cb 100644
--- a/net/x25/x25_subr.c
+++ b/net/x25/x25_subr.c
@@ -50,6 +50,9 @@ void x25_clear_queues(struct sock *sk)
while ((skb = skb_dequeue(&sk->write_queue)) != NULL)
kfree_skb(skb, FREE_WRITE);
+ while ((skb = skb_dequeue(&sk->protinfo.x25->ack_queue)) != NULL)
+ kfree_skb(skb, FREE_WRITE);
+
while ((skb = skb_dequeue(&sk->protinfo.x25->interrupt_in_queue)) != NULL)
kfree_skb(skb, FREE_READ);
@@ -60,6 +63,49 @@ void x25_clear_queues(struct sock *sk)
kfree_skb(skb, FREE_READ);
}
+
+/*
+ * This routine purges the input queue of those frames that have been
+ * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
+ * SDL diagram.
+*/
+void x25_frames_acked(struct sock *sk, unsigned short nr)
+{
+ struct sk_buff *skb;
+ int modulus;
+
+ modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
+
+ /*
+ * Remove all the ack-ed frames from the ack queue.
+ */
+ if (sk->protinfo.x25->va != nr) {
+ while (skb_peek(&sk->protinfo.x25->ack_queue) != NULL && sk->protinfo.x25->va != nr) {
+ skb = skb_dequeue(&sk->protinfo.x25->ack_queue);
+ kfree_skb(skb, FREE_WRITE);
+ sk->protinfo.x25->va = (sk->protinfo.x25->va + 1) % modulus;
+ }
+ }
+}
+
+void x25_requeue_frames(struct sock *sk)
+{
+ struct sk_buff *skb, *skb_prev = NULL;
+
+ /*
+ * Requeue all the un-ack-ed frames on the output queue to be picked
+ * up by x25_kick. This arrangement handles the possibility of an empty
+ * output queue.
+ */
+ while ((skb = skb_dequeue(&sk->protinfo.x25->ack_queue)) != NULL) {
+ if (skb_prev == NULL)
+ skb_queue_head(&sk->write_queue, skb);
+ else
+ skb_append(skb_prev, skb);
+ skb_prev = skb;
+ }
+}
+
/*
* Validate that the value of nr is between va and vs. Return true or
* false for testing.