diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
commit | beb116954b9b7f3bb56412b2494b562f02b864b1 (patch) | |
tree | 120e997879884e1b9d93b265221b939d2ef1ade1 /net/netrom/nr_out.c | |
parent | 908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff) |
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'net/netrom/nr_out.c')
-rw-r--r-- | net/netrom/nr_out.c | 198 |
1 files changed, 123 insertions, 75 deletions
diff --git a/net/netrom/nr_out.c b/net/netrom/nr_out.c index 2ebdd743d..61935f30c 100644 --- a/net/netrom/nr_out.c +++ b/net/netrom/nr_out.c @@ -1,5 +1,5 @@ /* - * NET/ROM release 002 + * NET/ROM release 004 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -14,10 +14,12 @@ * * History * NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_out.c + * NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragmentation. + * Darryl(G7LED) Fixed NAK, to give out correct reponse. */ #include <linux/config.h> -#ifdef CONFIG_NETROM +#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE) #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> @@ -33,38 +35,82 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> +#include <asm/uaccess.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> #include <net/netrom.h> -int nr_output(struct sock *sk, struct sk_buff *skb) +/* + * This is where all NET/ROM frames pass, except for IP-over-NET/ROM which + * cannot be fragmented in this manner. + */ +void nr_output(struct sock *sk, struct sk_buff *skb) { - skb_queue_tail(&sk->write_queue, skb); /* Throw it on the queue */ + struct sk_buff *skbn; + unsigned char transport[NR_TRANSPORT_LEN]; + int err, frontlen, len, mtu; - if (sk->nr->state == NR_STATE_3) - nr_kick(sk); + mtu = sk->protinfo.nr->paclen; + + if (skb->len - NR_TRANSPORT_LEN > mtu) { + /* Save a copy of the Transport Header */ + memcpy(transport, skb->data, NR_TRANSPORT_LEN); + skb_pull(skb, NR_TRANSPORT_LEN); + + frontlen = skb_headroom(skb); + + while (skb->len > 0) { + if ((skbn = sock_alloc_send_skb(sk, frontlen + mtu, 0, 0, &err)) == NULL) + return; + + skbn->sk = sk; + skbn->free = 1; + skbn->arp = 1; + + skb_reserve(skbn, frontlen); + + len = (mtu > skb->len) ? skb->len : mtu; + + /* Copy the user data */ + memcpy(skb_put(skbn, len), skb->data, len); + skb_pull(skb, len); + + /* Duplicate the Transport Header */ + skb_push(skbn, NR_TRANSPORT_LEN); + memcpy(skbn->data, transport, NR_TRANSPORT_LEN); + + if (skb->len > 0) + skbn->data[4] |= NR_MORE_FLAG; + + skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */ + } + + skb->free = 1; + kfree_skb(skb, FREE_WRITE); + } else { + skb_queue_tail(&sk->write_queue, skb); /* Throw it on the queue */ + } - return 0; + if (sk->protinfo.nr->state == NR_STATE_3) + nr_kick(sk); } /* - * This procedure is passed a buffer descriptor for an iframe. It builds - * the rest of the control part of the frame and then writes it out. + * This procedure is passed a buffer descriptor for an iframe. It builds + * the rest of the control part of the frame and then writes it out. */ static void nr_send_iframe(struct sock *sk, struct sk_buff *skb) { - unsigned char *dptr; - if (skb == NULL) return; - dptr = skb->data + 34; - - *dptr++ = sk->nr->vs; - *dptr++ = sk->nr->vr; + skb->data[2] = sk->protinfo.nr->vs; + skb->data[3] = sk->protinfo.nr->vr; + + if (sk->protinfo.nr->condition & OWN_RX_BUSY_CONDITION) + skb->data[4] |= NR_CHOKE_FLAG; nr_transmit_buffer(sk, skb); } @@ -73,17 +119,23 @@ void nr_send_nak_frame(struct sock *sk) { struct sk_buff *skb, *skbn; - if ((skb = skb_peek(&sk->nr->ack_queue)) == NULL) + if ((skb = skb_peek(&sk->protinfo.nr->ack_queue)) == NULL) return; if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) return; - nr_send_iframe(sk, skbn); + skbn->data[2] = sk->protinfo.nr->va; + skbn->data[3] = sk->protinfo.nr->vr; - sk->nr->condition &= ~ACK_PENDING_CONDITION; - sk->nr->vl = sk->nr->vr; - sk->nr->t1timer = 0; + if (sk->protinfo.nr->condition & OWN_RX_BUSY_CONDITION) + skbn->data[4] |= NR_CHOKE_FLAG; + + nr_transmit_buffer(sk, skbn); + + sk->protinfo.nr->condition &= ~ACK_PENDING_CONDITION; + sk->protinfo.nr->vl = sk->protinfo.nr->vr; + sk->protinfo.nr->t1timer = 0; } void nr_kick(struct sock *sk) @@ -94,31 +146,32 @@ void nr_kick(struct sock *sk) del_timer(&sk->timer); - start = (skb_peek(&sk->nr->ack_queue) == NULL) ? sk->nr->va : sk->nr->vs; - end = (sk->nr->va + sk->window) % NR_MODULUS; + start = (skb_peek(&sk->protinfo.nr->ack_queue) == NULL) ? sk->protinfo.nr->va : sk->protinfo.nr->vs; + end = (sk->protinfo.nr->va + sk->window) % NR_MODULUS; - if (!(sk->nr->condition & PEER_RX_BUSY_CONDITION) && - start != end && + if (!(sk->protinfo.nr->condition & PEER_RX_BUSY_CONDITION) && + start != end && skb_peek(&sk->write_queue) != NULL) { - sk->nr->vs = start; + sk->protinfo.nr->vs = start; /* * Transmit data until either we're out of data to send or * the window is full. */ - do { - /* - * Dequeue the frame and copy it. - */ - skb = skb_dequeue(&sk->write_queue); + /* + * Dequeue the frame and copy it. + */ + skb = skb_dequeue(&sk->write_queue); + + do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { skb_queue_head(&sk->write_queue, skb); - return; + break; } - next = (sk->nr->vs + 1) % NR_MODULUS; + next = (sk->protinfo.nr->vs + 1) % NR_MODULUS; last = (next == end); /* @@ -126,20 +179,20 @@ void nr_kick(struct sock *sk) */ nr_send_iframe(sk, skbn); - sk->nr->vs = next; + sk->protinfo.nr->vs = next; /* * Requeue the original data frame. */ - skb_queue_tail(&sk->nr->ack_queue, skb); + skb_queue_tail(&sk->protinfo.nr->ack_queue, skb); - } while (!last && skb_peek(&sk->write_queue) != NULL); + } while (!last && (skb = skb_dequeue(&sk->write_queue)) != NULL); - sk->nr->vl = sk->nr->vr; - sk->nr->condition &= ~ACK_PENDING_CONDITION; + sk->protinfo.nr->vl = sk->protinfo.nr->vr; + sk->protinfo.nr->condition &= ~ACK_PENDING_CONDITION; - if (sk->nr->t1timer == 0) { - sk->nr->t1timer = sk->nr->t1 = nr_calculate_t1(sk); + if (sk->protinfo.nr->t1timer == 0) { + sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk); } } @@ -150,34 +203,36 @@ void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb) { unsigned char *dptr; - dptr = skb->data + 16; + /* + * Add the protocol byte and network header. + */ + dptr = skb_push(skb, NR_NETWORK_LEN); - *dptr++ = AX25_P_NETROM; - - memcpy(dptr, &sk->nr->source_addr, sizeof(ax25_address)); + memcpy(dptr, &sk->protinfo.nr->source_addr, AX25_ADDR_LEN); dptr[6] &= ~LAPB_C; dptr[6] &= ~LAPB_E; - dptr[6] |= SSID_SPARE; - dptr += 7; + dptr[6] |= SSSID_SPARE; + dptr += AX25_ADDR_LEN; - memcpy(dptr, &sk->nr->dest_addr, sizeof(ax25_address)); + memcpy(dptr, &sk->protinfo.nr->dest_addr, AX25_ADDR_LEN); dptr[6] &= ~LAPB_C; dptr[6] |= LAPB_E; - dptr[6] |= SSID_SPARE; - dptr += 7; + dptr[6] |= SSSID_SPARE; + dptr += AX25_ADDR_LEN; - *dptr++ = nr_default.ttl; + *dptr++ = sysctl_netrom_network_ttl_initialiser; skb->arp = 1; if (!nr_route_frame(skb, NULL)) { kfree_skb(skb, FREE_WRITE); - sk->state = TCP_CLOSE; - sk->err = ENETUNREACH; + sk->state = TCP_CLOSE; + sk->err = ENETUNREACH; + sk->shutdown |= SEND_SHUTDOWN; if (!sk->dead) sk->state_change(sk); - sk->dead = 1; + sk->dead = 1; } } @@ -186,20 +241,15 @@ void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb) * Networking Conference paper, as is the whole state machine. */ -void nr_nr_error_recovery(struct sock *sk) -{ - nr_establish_data_link(sk); -} - void nr_establish_data_link(struct sock *sk) { - sk->nr->condition = 0x00; - sk->nr->n2count = 0; + sk->protinfo.nr->condition = 0x00; + sk->protinfo.nr->n2count = 0; nr_write_internal(sk, NR_CONNREQ); - sk->nr->t2timer = 0; - sk->nr->t1timer = sk->nr->t1 = nr_calculate_t1(sk); + sk->protinfo.nr->t2timer = 0; + sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk); } /* @@ -209,33 +259,31 @@ void nr_enquiry_response(struct sock *sk) { int frametype = NR_INFOACK; - if (sk->nr->condition & OWN_RX_BUSY_CONDITION) { - frametype += NR_CHOKE_FLAG; + if (sk->protinfo.nr->condition & OWN_RX_BUSY_CONDITION) { + frametype |= NR_CHOKE_FLAG; } else { - if (skb_peek(&sk->nr->reseq_queue) != NULL) { - frametype += NR_NAK_FLAG; + if (skb_peek(&sk->protinfo.nr->reseq_queue) != NULL) { + frametype |= NR_NAK_FLAG; } } nr_write_internal(sk, frametype); - sk->nr->vl = sk->nr->vr; - sk->nr->condition &= ~ACK_PENDING_CONDITION; + sk->protinfo.nr->vl = sk->protinfo.nr->vr; + sk->protinfo.nr->condition &= ~ACK_PENDING_CONDITION; } void nr_check_iframes_acked(struct sock *sk, unsigned short nr) { - if (sk->nr->vs == nr) { + if (sk->protinfo.nr->vs == nr) { nr_frames_acked(sk, nr); - nr_requeue_frames(sk); nr_calculate_rtt(sk); - sk->nr->t1timer = 0; - sk->nr->n2count = 0; + sk->protinfo.nr->t1timer = 0; + sk->protinfo.nr->n2count = 0; } else { - if (sk->nr->va != nr) { + if (sk->protinfo.nr->va != nr) { nr_frames_acked(sk, nr); - nr_requeue_frames(sk); - sk->nr->t1timer = sk->nr->t1 = nr_calculate_t1(sk); + sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk); } } } |