summaryrefslogtreecommitdiffstats
path: root/net/rose
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/rose
parente20c1cc1656a66a2773bca4591a895cbc12696ff (diff)
Merge with Linux 2.1.72, part 1.
Diffstat (limited to 'net/rose')
-rw-r--r--net/rose/af_rose.c19
-rw-r--r--net/rose/rose_dev.c8
-rw-r--r--net/rose/rose_in.c57
-rw-r--r--net/rose/rose_link.c2
-rw-r--r--net/rose/rose_out.c84
-rw-r--r--net/rose/rose_route.c70
-rw-r--r--net/rose/rose_subr.c43
7 files changed, 107 insertions, 176 deletions
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 69b77a9f2..5ae64334d 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -548,6 +548,8 @@ static int rose_create(struct socket *sock, int protocol)
sock_init_data(sock, sk);
+ skb_queue_head_init(&rose->ack_queue);
+
sock->ops = &rose_proto_ops;
sk->protocol = protocol;
sk->mtu = ROSE_MTU; /* 253 */
@@ -555,8 +557,6 @@ static int rose_create(struct socket *sock, int protocol)
init_timer(&rose->timer);
init_timer(&rose->idletimer);
- skb_queue_head_init(&rose->frag_queue);
-
rose->t1 = sysctl_rose_call_request_timeout;
rose->t2 = sysctl_rose_reset_request_timeout;
rose->t3 = sysctl_rose_clear_request_timeout;
@@ -583,6 +583,8 @@ static struct sock *rose_make_new(struct sock *osk)
sock_init_data(NULL, sk);
+ skb_queue_head_init(&rose->ack_queue);
+
sk->type = osk->type;
sk->socket = osk->socket;
sk->priority = osk->priority;
@@ -598,8 +600,6 @@ static struct sock *rose_make_new(struct sock *osk)
init_timer(&rose->timer);
init_timer(&rose->idletimer);
- skb_queue_head_init(&rose->frag_queue);
-
rose->t1 = osk->protinfo.rose->t1;
rose->t2 = osk->protinfo.rose->t2;
rose->t3 = osk->protinfo.rose->t3;
@@ -1068,7 +1068,9 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
return -ENOTCONN;
}
- rose_output(sk, skb); /* Shove it onto the queue */
+ skb_queue_tail(&sk->write_queue, skb); /* Shove it onto the queue */
+
+ rose_kick(sk);
return len;
}
@@ -1210,7 +1212,7 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return 0;
}
- case SIOCRSL2CALL:
+ case SIOCRSSL2CALL:
if (!suser()) return -EPERM;
if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
ax25_listen_release(&rose_callsign, NULL);
@@ -1220,6 +1222,11 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
ax25_listen_register(&rose_callsign, NULL);
return 0;
+ case SIOCRSGL2CALL:
+ if (copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address)))
+ return -EFAULT;
+ return 0;
+
case SIOCRSACCEPT:
if (sk->protinfo.rose->state == ROSE_STATE_5) {
rose_write_internal(sk, ROSE_CALL_ACCEPTED);
diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c
index 7861220ee..bc2097cda 100644
--- a/net/rose/rose_dev.c
+++ b/net/rose/rose_dev.c
@@ -221,14 +221,6 @@ int rose_init(struct device *dev)
/* New-style flags. */
dev->flags = 0;
- dev->family = AF_INET;
-
-#ifdef CONFIG_INET
- dev->pa_addr = in_aton("192.168.0.1");
- dev->pa_brdaddr = in_aton("192.168.0.255");
- dev->pa_mask = in_aton("255.255.255.0");
- dev->pa_alen = 4;
-#endif
if ((dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL)) == NULL)
return -ENOMEM;
diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c
index 1ac11528d..de412d3c4 100644
--- a/net/rose/rose_in.c
+++ b/net/rose/rose_in.c
@@ -19,6 +19,7 @@
* ROSE 001 Jonathan(G4KLX) Cloned from nr_in.c
* ROSE 002 Jonathan(G4KLX) Return cause and diagnostic codes from Clear Requests.
* ROSE 003 Jonathan(G4KLX) New timer architecture.
+ * Removed M bit processing.
*/
#include <linux/config.h>
@@ -46,43 +47,6 @@
#include <linux/interrupt.h>
#include <net/rose.h>
-static int rose_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
-{
- struct sk_buff *skbo, *skbn = skb;
-
- rose_start_idletimer(sk);
-
- if (more) {
- sk->protinfo.rose->fraglen += skb->len;
- skb_queue_tail(&sk->protinfo.rose->frag_queue, skb);
- return 0;
- }
-
- if (!more && sk->protinfo.rose->fraglen > 0) { /* End of fragment */
- sk->protinfo.rose->fraglen += skb->len;
- skb_queue_tail(&sk->protinfo.rose->frag_queue, skb);
-
- if ((skbn = alloc_skb(sk->protinfo.rose->fraglen, GFP_ATOMIC)) == NULL)
- return 1;
-
- skbn->h.raw = skbn->data;
-
- skbo = skb_dequeue(&sk->protinfo.rose->frag_queue);
- memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
- kfree_skb(skbo, FREE_READ);
-
- while ((skbo = skb_dequeue(&sk->protinfo.rose->frag_queue)) != NULL) {
- skb_pull(skbo, ROSE_MIN_LEN);
- memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
- kfree_skb(skbo, FREE_READ);
- }
-
- sk->protinfo.rose->fraglen = 0;
- }
-
- return sock_queue_rcv_skb(sk, skbn);
-}
-
/*
* State machine for state 1, Awaiting Call Accepted State.
* The handling of the timer(s) is in file rose_timer.c.
@@ -166,6 +130,7 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
sk->protinfo.rose->vr = 0;
sk->protinfo.rose->va = 0;
sk->protinfo.rose->vl = 0;
+ rose_requeue_frames(sk);
break;
case ROSE_CLEAR_REQUEST:
@@ -191,11 +156,9 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_start_t2timer(sk);
rose_stop_idletimer(sk);
} else {
- if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) {
- sk->protinfo.rose->va = nr;
- } else {
- rose_check_iframes_acked(sk, nr);
- }
+ rose_frames_acked(sk, nr);
+ if (frametype == ROSE_RNR)
+ rose_requeue_frames(sk);
}
break;
@@ -213,15 +176,12 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_stop_idletimer(sk);
break;
}
- if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) {
- sk->protinfo.rose->va = nr;
- } else {
- rose_check_iframes_acked(sk, nr);
- }
+ rose_frames_acked(sk, nr);
if (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)
break;
if (ns == sk->protinfo.rose->vr) {
- if (rose_queue_rx_frame(sk, skb, m) == 0) {
+ rose_start_idletimer(sk);
+ if (sock_queue_rcv_skb(sk, skb) == 0) {
sk->protinfo.rose->vr = (sk->protinfo.rose->vr + 1) % ROSE_MODULUS;
queued = 1;
} else {
@@ -270,6 +230,7 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
sk->protinfo.rose->vs = 0;
sk->protinfo.rose->vl = 0;
sk->protinfo.rose->state = ROSE_STATE_3;
+ rose_requeue_frames(sk);
break;
case ROSE_CLEAR_REQUEST:
diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c
index b481e485f..8ee27147a 100644
--- a/net/rose/rose_link.c
+++ b/net/rose/rose_link.c
@@ -113,7 +113,7 @@ static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
else
rose_call = &rose_callsign;
- neigh->ax25 = ax25_send_frame(skb, 256, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+ neigh->ax25 = ax25_send_frame(skb, 0, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
return (neigh->ax25 != NULL);
}
diff --git a/net/rose/rose_out.c b/net/rose/rose_out.c
index 0ed9f7480..aea1d9f68 100644
--- a/net/rose/rose_out.c
+++ b/net/rose/rose_out.c
@@ -12,6 +12,7 @@
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_out.c
* ROSE 003 Jonathan(G4KLX) New timer architecture.
+ * Removed M bit processing.
*/
#include <linux/config.h>
@@ -38,52 +39,6 @@
#include <linux/interrupt.h>
#include <net/rose.h>
-/*
- * This is where all ROSE frames pass;
- */
-void rose_output(struct sock *sk, struct sk_buff *skb)
-{
- struct sk_buff *skbn;
- unsigned char header[ROSE_MIN_LEN];
- int err, frontlen, len;
-
- if (skb->len - ROSE_MIN_LEN > ROSE_MAX_PACKET_SIZE) {
- /* Save a copy of the Header */
- memcpy(header, skb->data, ROSE_MIN_LEN);
- skb_pull(skb, ROSE_MIN_LEN);
-
- frontlen = skb_headroom(skb);
-
- while (skb->len > 0) {
- if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_MAX_PACKET_SIZE, 0, 0, &err)) == NULL)
- return;
-
- skb_reserve(skbn, frontlen);
-
- len = (ROSE_MAX_PACKET_SIZE > skb->len) ? skb->len : ROSE_MAX_PACKET_SIZE;
-
- /* Copy the user data */
- memcpy(skb_put(skbn, len), skb->data, len);
- skb_pull(skb, len);
-
- /* Duplicate the Header */
- skb_push(skbn, ROSE_MIN_LEN);
- memcpy(skbn->data, header, ROSE_MIN_LEN);
-
- if (skb->len > 0)
- skbn->data[2] |= ROSE_M_BIT;
-
- skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */
- }
-
- kfree_skb(skb, FREE_WRITE);
- } else {
- skb_queue_tail(&sk->write_queue, skb); /* Throw it on the queue */
- }
-
- rose_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.
@@ -103,8 +58,8 @@ static void rose_send_iframe(struct sock *sk, struct sk_buff *skb)
void rose_kick(struct sock *sk)
{
- struct sk_buff *skb;
- unsigned short end;
+ struct sk_buff *skb, *skbn;
+ unsigned short start, end;
if (sk->protinfo.rose->state != ROSE_STATE_3)
return;
@@ -115,11 +70,14 @@ void rose_kick(struct sock *sk)
if (skb_peek(&sk->write_queue) == NULL)
return;
- end = (sk->protinfo.rose->va + sysctl_rose_window_size) % ROSE_MODULUS;
+ start = (skb_peek(&sk->protinfo.rose->ack_queue) == NULL) ? sk->protinfo.rose->va : sk->protinfo.rose->vs;
+ end = (sk->protinfo.rose->va + sysctl_rose_window_size) % ROSE_MODULUS;
- if (sk->protinfo.rose->vs == end)
+ if (start == end)
return;
+ sk->protinfo.rose->vs = start;
+
/*
* Transmit data until either we're out of data to send or
* the window is full.
@@ -128,13 +86,25 @@ void rose_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.
*/
- rose_send_iframe(sk, skb);
+ rose_send_iframe(sk, skbn);
sk->protinfo.rose->vs = (sk->protinfo.rose->vs + 1) % ROSE_MODULUS;
+ /*
+ * Requeue the original data frame.
+ */
+ skb_queue_tail(&sk->protinfo.rose->ack_queue, skb);
+
} while (sk->protinfo.rose->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
sk->protinfo.rose->vl = sk->protinfo.rose->vr;
@@ -161,14 +131,4 @@ void rose_enquiry_response(struct sock *sk)
rose_stop_timer(sk);
}
-void rose_check_iframes_acked(struct sock *sk, unsigned short nr)
-{
- if (sk->protinfo.rose->vs == nr) {
- sk->protinfo.rose->va = nr;
- } else {
- if (sk->protinfo.rose->va != nr)
- sk->protinfo.rose->va = nr;
- }
-}
-
#endif
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index 43358644c..d9145cdea 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -63,7 +63,7 @@ static void rose_remove_neigh(struct rose_neigh *);
*/
static int rose_add_node(struct rose_route_struct *rose_route, struct device *dev)
{
- struct rose_node *rose_node, *rose_tmpn, *rose_tmpp;
+ struct rose_node *rose_node;
struct rose_neigh *rose_neigh;
unsigned long flags;
int i;
@@ -116,55 +116,18 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de
restore_flags(flags);
}
- /*
- * This is a new node to be inserted into the list. Find where it needs
- * to be inserted into the list, and insert it. We want to be sure
- * to order the list in descending order of mask size to ensure that
- * later when we are searching this list the first match will be the
- * best match.
- */
if (rose_node == NULL) {
- rose_tmpn = rose_node_list;
- rose_tmpp = NULL;
-
- while (rose_tmpn != NULL) {
- if (rose_tmpn->mask > rose_route->mask) {
- rose_tmpp = rose_tmpn;
- rose_tmpn = rose_tmpn->next;
- } else {
- break;
- }
- }
-
- /* create new node */
if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)
return -ENOMEM;
- rose_node->address = rose_route->address;
- rose_node->mask = rose_route->mask;
- rose_node->count = 1;
+ rose_node->address = rose_route->address;
+ rose_node->mask = rose_route->mask;
+ rose_node->count = 1;
rose_node->neighbour[0] = rose_neigh;
save_flags(flags); cli();
-
- if (rose_tmpn == NULL) {
- if (rose_tmpp == NULL) { /* Empty list */
- rose_node_list = rose_node;
- rose_node->next = NULL;
- } else {
- rose_tmpp->next = rose_node;
- rose_node->next = NULL;
- }
- } else {
- if (rose_tmpp == NULL) { /* 1st node */
- rose_node->next = rose_node_list;
- rose_node_list = rose_node;
- } else {
- rose_tmpp->next = rose_node;
- rose_node->next = rose_tmpn;
- }
- }
-
+ rose_node->next = rose_node_list;
+ rose_node_list = rose_node;
restore_flags(flags);
rose_neigh->count++;
@@ -487,20 +450,29 @@ struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neig
struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsigned char *diagnostic)
{
struct rose_node *node;
+ struct rose_neigh *neigh;
int failed = 0;
+ int mask = 0;
int i;
- for (node = rose_node_list; node != NULL; node = node->next) {
+ for (neigh = NULL, node = rose_node_list; node != NULL; node = node->next) {
if (rosecmpm(addr, &node->address, node->mask) == 0) {
- for (i = 0; i < node->count; i++) {
- if (!rose_ftimer_running(node->neighbour[i]))
- return node->neighbour[i];
- else
- failed = 1;
+ if (node->mask > mask) {
+ mask = node->mask;
+
+ for (i = 0; i < node->count; i++) {
+ if (!rose_ftimer_running(node->neighbour[i]))
+ neigh = node->neighbour[i];
+ else
+ failed = 1;
+ }
}
}
}
+ if (neigh != NULL)
+ return neigh;
+
if (failed) {
*cause = ROSE_OUT_OF_ORDER;
*diagnostic = 0;
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c
index ee710bd6e..e7709726c 100644
--- a/net/rose/rose_subr.c
+++ b/net/rose/rose_subr.c
@@ -49,8 +49,47 @@ void rose_clear_queues(struct sock *sk)
while ((skb = skb_dequeue(&sk->write_queue)) != NULL)
kfree_skb(skb, FREE_WRITE);
- while ((skb = skb_dequeue(&sk->protinfo.rose->frag_queue)) != NULL)
- kfree_skb(skb, FREE_READ);
+ while ((skb = skb_dequeue(&sk->protinfo.rose->ack_queue)) != NULL)
+ kfree_skb(skb, FREE_WRITE);
+}
+
+/*
+ * 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 rose_frames_acked(struct sock *sk, unsigned short nr)
+{
+ struct sk_buff *skb;
+
+ /*
+ * Remove all the ack-ed frames from the ack queue.
+ */
+ if (sk->protinfo.rose->va != nr) {
+ while (skb_peek(&sk->protinfo.rose->ack_queue) != NULL && sk->protinfo.rose->va != nr) {
+ skb = skb_dequeue(&sk->protinfo.rose->ack_queue);
+ kfree_skb(skb, FREE_WRITE);
+ sk->protinfo.rose->va = (sk->protinfo.rose->va + 1) % ROSE_MODULUS;
+ }
+ }
+}
+
+void rose_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 rose_kick. This arrangement handles the possibility of an
+ * empty output queue.
+ */
+ while ((skb = skb_dequeue(&sk->protinfo.rose->ack_queue)) != NULL) {
+ if (skb_prev == NULL)
+ skb_queue_head(&sk->write_queue, skb);
+ else
+ skb_append(skb_prev, skb);
+ skb_prev = skb;
+ }
}
/*