diff options
Diffstat (limited to 'net/x25')
-rw-r--r-- | net/x25/af_x25.c | 1 | ||||
-rw-r--r-- | net/x25/x25_dev.c | 3 | ||||
-rw-r--r-- | net/x25/x25_in.c | 16 | ||||
-rw-r--r-- | net/x25/x25_out.c | 37 | ||||
-rw-r--r-- | net/x25/x25_subr.c | 46 |
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. |