summaryrefslogtreecommitdiffstats
path: root/net/netrom/nr_out.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
committer <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
commitbeb116954b9b7f3bb56412b2494b562f02b864b1 (patch)
tree120e997879884e1b9d93b265221b939d2ef1ade1 /net/netrom/nr_out.c
parent908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff)
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'net/netrom/nr_out.c')
-rw-r--r--net/netrom/nr_out.c198
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);
}
}
}