summaryrefslogtreecommitdiffstats
path: root/net/rose
diff options
context:
space:
mode:
Diffstat (limited to 'net/rose')
-rw-r--r--net/rose/af_rose.c224
-rw-r--r--net/rose/rose_dev.c4
-rw-r--r--net/rose/rose_in.c95
-rw-r--r--net/rose/rose_link.c111
-rw-r--r--net/rose/rose_out.c58
-rw-r--r--net/rose/rose_route.c162
-rw-r--r--net/rose/rose_subr.c56
-rw-r--r--net/rose/rose_timer.c172
-rw-r--r--net/rose/sysctl_net_rose.c12
9 files changed, 560 insertions, 334 deletions
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 9896de9cb..134eee17a 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1,5 +1,5 @@
/*
- * ROSE release 002
+ * ROSE release 003
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -17,6 +17,9 @@
* ROSE 002 Jonathan(G4KLX) Changed hdrincl to qbitincl.
* Added random number facilities entry.
* Variable number of ROSE devices.
+ * ROSE 003 Jonathan(G4KLX) New timer architecture.
+ * Implemented idle timer.
+ * Added use count to neighbour.
*/
#include <linux/config.h>
@@ -172,8 +175,7 @@ static void rose_remove_socket(struct sock *sk)
struct sock *s;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
if ((s = rose_list) == sk) {
rose_list = s->next;
@@ -204,13 +206,9 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
for (s = rose_list; s != NULL; s = s->next) {
if (s->protinfo.rose->neighbour == neigh) {
- s->protinfo.rose->state = ROSE_STATE_0;
+ rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
+ s->protinfo.rose->neighbour->use--;
s->protinfo.rose->neighbour = NULL;
- s->state = TCP_CLOSE;
- s->err = ENETUNREACH;
- s->shutdown |= SEND_SHUTDOWN;
- s->state_change(s);
- s->dead = 1;
}
}
}
@@ -224,13 +222,9 @@ static void rose_kill_by_device(struct device *dev)
for (s = rose_list; s != NULL; s = s->next) {
if (s->protinfo.rose->device == dev) {
- s->protinfo.rose->state = ROSE_STATE_0;
+ rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
+ s->protinfo.rose->neighbour->use--;
s->protinfo.rose->device = NULL;
- s->state = TCP_CLOSE;
- s->err = ENETUNREACH;
- s->shutdown |= SEND_SHUTDOWN;
- s->state_change(s);
- s->dead = 1;
}
}
}
@@ -265,8 +259,7 @@ static void rose_insert_socket(struct sock *sk)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
sk->next = rose_list;
rose_list = sk;
@@ -283,8 +276,7 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
unsigned long flags;
struct sock *s;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
for (s = rose_list; s != NULL; s = s->next) {
if (rosecmp(&s->protinfo.rose->source_addr, addr) == 0 && ax25cmp(&s->protinfo.rose->source_call, call) == 0 && s->protinfo.rose->source_ndigis == 0 && s->state == TCP_LISTEN) {
@@ -312,8 +304,7 @@ struct sock *rose_find_socket(unsigned int lci, struct rose_neigh *neigh)
struct sock *s;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
for (s = rose_list; s != NULL; s = s->next) {
if (s->protinfo.rose->lci == lci && s->protinfo.rose->neighbour == neigh) {
@@ -371,10 +362,11 @@ void rose_destroy_socket(struct sock *sk) /* Not static as it's used by the time
struct sk_buff *skb;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
- del_timer(&sk->timer);
+ rose_stop_heartbeat(sk);
+ rose_stop_idletimer(sk);
+ rose_stop_timer(sk);
rose_remove_socket(sk);
rose_clear_queues(sk); /* Flush the queues */
@@ -382,7 +374,7 @@ void rose_destroy_socket(struct sock *sk) /* Not static as it's used by the time
while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
if (skb->sk != sk) { /* A pending connection */
skb->sk->dead = 1; /* Queue the unaccepted socket for death */
- rose_set_timer(skb->sk);
+ rose_start_heartbeat(skb->sk);
skb->sk->protinfo.rose->state = ROSE_STATE_0;
}
@@ -424,34 +416,38 @@ static int rose_setsockopt(struct socket *sock, int level, int optname,
return -EFAULT;
switch (optname) {
+ case ROSE_DEFER:
+ sk->protinfo.rose->defer = opt ? 1 : 0;
+ return 0;
+
case ROSE_T1:
if (opt < 1)
return -EINVAL;
- sk->protinfo.rose->t1 = opt * ROSE_SLOWHZ;
+ sk->protinfo.rose->t1 = opt * HZ;
return 0;
case ROSE_T2:
if (opt < 1)
return -EINVAL;
- sk->protinfo.rose->t2 = opt * ROSE_SLOWHZ;
+ sk->protinfo.rose->t2 = opt * HZ;
return 0;
case ROSE_T3:
if (opt < 1)
return -EINVAL;
- sk->protinfo.rose->t3 = opt * ROSE_SLOWHZ;
+ sk->protinfo.rose->t3 = opt * HZ;
return 0;
case ROSE_HOLDBACK:
if (opt < 1)
return -EINVAL;
- sk->protinfo.rose->hb = opt * ROSE_SLOWHZ;
+ sk->protinfo.rose->hb = opt * HZ;
return 0;
case ROSE_IDLE:
- if (opt < 1)
+ if (opt < 0)
return -EINVAL;
- sk->protinfo.rose->idle = opt * 60 * ROSE_SLOWHZ;
+ sk->protinfo.rose->idle = opt * 60 * HZ;
return 0;
case ROSE_QBITINCL:
@@ -477,24 +473,28 @@ static int rose_getsockopt(struct socket *sock, int level, int optname,
return -EFAULT;
switch (optname) {
+ case ROSE_DEFER:
+ val = sk->protinfo.rose->defer;
+ break;
+
case ROSE_T1:
- val = sk->protinfo.rose->t1 / ROSE_SLOWHZ;
+ val = sk->protinfo.rose->t1 / HZ;
break;
case ROSE_T2:
- val = sk->protinfo.rose->t2 / ROSE_SLOWHZ;
+ val = sk->protinfo.rose->t2 / HZ;
break;
case ROSE_T3:
- val = sk->protinfo.rose->t3 / ROSE_SLOWHZ;
+ val = sk->protinfo.rose->t3 / HZ;
break;
case ROSE_HOLDBACK:
- val = sk->protinfo.rose->hb / ROSE_SLOWHZ;
+ val = sk->protinfo.rose->hb / HZ;
break;
case ROSE_IDLE:
- val = sk->protinfo.rose->idle / (ROSE_SLOWHZ * 60);
+ val = sk->protinfo.rose->idle / (60 * HZ);
break;
case ROSE_QBITINCL:
@@ -550,7 +550,10 @@ static int rose_create(struct socket *sock, int protocol)
sock->ops = &rose_proto_ops;
sk->protocol = protocol;
- sk->mtu = ROSE_MTU; /* 128 */
+ sk->mtu = ROSE_MTU; /* 253 */
+
+ init_timer(&rose->timer);
+ init_timer(&rose->idletimer);
skb_queue_head_init(&rose->frag_queue);
@@ -592,6 +595,9 @@ static struct sock *rose_make_new(struct sock *osk)
sk->sleep = osk->sleep;
sk->zapped = osk->zapped;
+ init_timer(&rose->timer);
+ init_timer(&rose->idletimer);
+
skb_queue_head_init(&rose->frag_queue);
rose->t1 = osk->protinfo.rose->t1;
@@ -600,6 +606,7 @@ static struct sock *rose_make_new(struct sock *osk)
rose->hb = osk->protinfo.rose->hb;
rose->idle = osk->protinfo.rose->idle;
+ rose->defer = osk->protinfo.rose->defer;
rose->device = osk->protinfo.rose->device;
rose->qbitincl = osk->protinfo.rose->qbitincl;
@@ -625,28 +632,24 @@ static int rose_release(struct socket *sock, struct socket *peer)
switch (sk->protinfo.rose->state) {
case ROSE_STATE_0:
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
- sk->state_change(sk);
- sk->dead = 1;
+ rose_disconnect(sk, 0, -1, -1);
rose_destroy_socket(sk);
break;
case ROSE_STATE_2:
- sk->protinfo.rose->state = ROSE_STATE_0;
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
- sk->state_change(sk);
- sk->dead = 1;
+ sk->protinfo.rose->neighbour->use--;
+ rose_disconnect(sk, 0, -1, -1);
rose_destroy_socket(sk);
- break;
+ break;
case ROSE_STATE_1:
case ROSE_STATE_3:
case ROSE_STATE_4:
+ case ROSE_STATE_5:
rose_clear_queues(sk);
+ rose_stop_idletimer(sk);
rose_write_internal(sk, ROSE_CLEAR_REQUEST);
- sk->protinfo.rose->timer = sk->protinfo.rose->t3;
+ rose_start_t3timer(sk);
sk->protinfo.rose->state = ROSE_STATE_2;
sk->state = TCP_CLOSE;
sk->shutdown |= SEND_SHUTDOWN;
@@ -714,6 +717,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
{
struct sock *sk = sock->sk;
struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
+ unsigned char cause, diagnostic;
ax25_address *user;
struct device *dev;
@@ -739,7 +743,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
if (addr->srose_family != AF_ROSE)
return -EINVAL;
- if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr)) == NULL)
+ if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic)) == NULL)
return -ENETUNREACH;
if ((sk->protinfo.rose->lci = rose_new_lci(sk->protinfo.rose->neighbour)) == 0)
@@ -775,10 +779,12 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
sk->state = TCP_SYN_SENT;
sk->protinfo.rose->state = ROSE_STATE_1;
- sk->protinfo.rose->timer = sk->protinfo.rose->t1;
- rose_write_internal(sk, ROSE_CALL_REQUEST);
- rose_set_timer(sk);
+ sk->protinfo.rose->neighbour->use++;
+
+ rose_write_internal(sk, ROSE_CALL_REQUEST);
+ rose_start_heartbeat(sk);
+ rose_start_t1timer(sk);
/* Now the loop */
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
@@ -911,11 +917,8 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne
/*
* skb->data points to the rose frame start
*/
-
- /*
- * XXX This is an error.
- */
if (!rose_parse_facilities(skb, &facilities)) {
+ rose_transmit_clear_request(neigh, lci, ROSE_INVALID_FACILITY, 76);
return 0;
}
@@ -925,7 +928,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne
* We can't accept the Call Request.
*/
if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog || (make = rose_make_new(sk)) == NULL) {
- rose_transmit_clear_request(neigh, lci, 0x01);
+ rose_transmit_clear_request(neigh, lci, ROSE_NETWORK_CONGESTION, 120);
return 0;
}
@@ -944,14 +947,21 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne
make->protinfo.rose->neighbour = neigh;
make->protinfo.rose->device = dev;
- rose_write_internal(make, ROSE_CALL_ACCEPTED);
+ make->protinfo.rose->neighbour->use++;
+
+ if (sk->protinfo.rose->defer) {
+ make->protinfo.rose->state = ROSE_STATE_5;
+ } else {
+ rose_write_internal(make, ROSE_CALL_ACCEPTED);
+ make->protinfo.rose->state = ROSE_STATE_3;
+ rose_start_idletimer(make);
+ }
make->protinfo.rose->condition = 0x00;
make->protinfo.rose->vs = 0;
make->protinfo.rose->va = 0;
make->protinfo.rose->vr = 0;
make->protinfo.rose->vl = 0;
- make->protinfo.rose->state = ROSE_STATE_3;
sk->ack_backlog++;
make->pair = sk;
@@ -959,7 +969,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne
skb_queue_head(&sk->receive_queue, skb);
- rose_set_timer(make);
+ rose_start_heartbeat(make);
if (!sk->dead)
sk->data_ready(sk, skb->len);
@@ -1146,37 +1156,35 @@ static int rose_shutdown(struct socket *sk, int how)
static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
- int err;
- long amount = 0;
switch (cmd) {
- case TIOCOUTQ:
- if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int))) != 0)
- return err;
+ case TIOCOUTQ: {
+ long amount;
amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
if (amount < 0)
amount = 0;
- put_user(amount, (unsigned int *)arg);
+ if (put_user(amount, (unsigned int *)arg))
+ return -EFAULT;
return 0;
+ }
case TIOCINQ: {
struct sk_buff *skb;
+ long amount = 0L;
/* These two are safe on a single CPU system as only user tasks fiddle here */
if ((skb = skb_peek(&sk->receive_queue)) != NULL)
- amount = skb->len - 20;
- if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int))) != 0)
- return err;
- put_user(amount, (unsigned int *)arg);
+ amount = skb->len;
+ if (put_user(amount, (unsigned int *)arg))
+ return -EFAULT;
return 0;
}
case SIOCGSTAMP:
if (sk != NULL) {
- if (sk->stamp.tv_sec==0)
+ if (sk->stamp.tv_sec == 0)
return -ENOENT;
- if ((err = verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval))) != 0)
- return err;
- copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval));
+ if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
+ return -EFAULT;
return 0;
}
return -EINVAL;
@@ -1195,20 +1203,51 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCADDRT:
case SIOCDELRT:
+ case SIOCRSCLRRT:
if (!suser()) return -EPERM;
return rose_rt_ioctl(cmd, (void *)arg);
+ case SIOCRSGCAUSE: {
+ struct rose_cause_struct rose_cause;
+ rose_cause.cause = sk->protinfo.rose->cause;
+ rose_cause.diagnostic = sk->protinfo.rose->diagnostic;
+ if (copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)))
+ return -EFAULT;
+ return 0;
+ }
+
+ case SIOCRSSCAUSE: {
+ struct rose_cause_struct rose_cause;
+ if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct)))
+ return -EFAULT;
+ sk->protinfo.rose->cause = rose_cause.cause;
+ sk->protinfo.rose->diagnostic = rose_cause.diagnostic;
+ return 0;
+ }
+
case SIOCRSL2CALL:
if (!suser()) return -EPERM;
- if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_address))) != 0)
- return err;
if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
ax25_listen_release(&rose_callsign, NULL);
- copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address));
+ if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address)))
+ return -EFAULT;
if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
ax25_listen_register(&rose_callsign, NULL);
return 0;
+ case SIOCRSACCEPT:
+ if (sk->protinfo.rose->state == ROSE_STATE_5) {
+ rose_write_internal(sk, ROSE_CALL_ACCEPTED);
+ rose_start_idletimer(sk);
+ sk->protinfo.rose->condition = 0x00;
+ sk->protinfo.rose->vs = 0;
+ sk->protinfo.rose->va = 0;
+ sk->protinfo.rose->vr = 0;
+ sk->protinfo.rose->vl = 0;
+ sk->protinfo.rose->state = ROSE_STATE_3;
+ }
+ return 0;
+
default:
return dev_ioctl(cmd, (void *)arg);
}
@@ -1228,7 +1267,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length, i
cli();
- len += sprintf(buffer, "dest_addr dest_call src_addr src_call dev lci st vs vr va t t1 t2 t3 hb Snd-Q Rcv-Q\n");
+ len += sprintf(buffer, "dest_addr dest_call src_addr src_call dev lci st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q\n");
for (s = rose_list; s != NULL; s = s->next) {
if ((dev = s->protinfo.rose->device) == NULL)
@@ -1245,17 +1284,24 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length, i
else
callsign = ax2asc(&s->protinfo.rose->source_call);
- len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X %d %d %d %d %3d %3d %3d %3d %3d %5d %5d\n",
- rose2asc(&s->protinfo.rose->source_addr), callsign,
- devname, s->protinfo.rose->lci & 0x0FFF,
+ len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d\n",
+ rose2asc(&s->protinfo.rose->source_addr),
+ callsign,
+ devname,
+ s->protinfo.rose->lci & 0x0FFF,
s->protinfo.rose->state,
- s->protinfo.rose->vs, s->protinfo.rose->vr, s->protinfo.rose->va,
- s->protinfo.rose->timer / ROSE_SLOWHZ,
- s->protinfo.rose->t1 / ROSE_SLOWHZ,
- s->protinfo.rose->t2 / ROSE_SLOWHZ,
- s->protinfo.rose->t3 / ROSE_SLOWHZ,
- s->protinfo.rose->hb / ROSE_SLOWHZ,
- atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc));
+ s->protinfo.rose->vs,
+ s->protinfo.rose->vr,
+ s->protinfo.rose->va,
+ ax25_display_timer(&s->protinfo.rose->timer) / HZ,
+ s->protinfo.rose->t1 / HZ,
+ s->protinfo.rose->t2 / HZ,
+ s->protinfo.rose->t3 / HZ,
+ s->protinfo.rose->hb / HZ,
+ ax25_display_timer(&s->protinfo.rose->idletimer) / (60 * HZ),
+ s->protinfo.rose->idle / (60 * HZ),
+ atomic_read(&s->wmem_alloc),
+ atomic_read(&s->rmem_alloc));
pos = begin + len;
@@ -1360,7 +1406,7 @@ __initfunc(void rose_proto_init(struct net_proto *pro))
sock_register(&rose_family_ops);
register_netdevice_notifier(&rose_dev_notifier);
- printk(KERN_INFO "G4KLX ROSE for Linux. Version 0.2 for AX25.035 Linux 2.1\n");
+ printk(KERN_INFO "G4KLX ROSE for Linux. Version 0.3 for AX25.037 Linux 2.1\n");
ax25_protocol_register(AX25_P_ROSE, rose_route_frame);
ax25_linkfail_register(rose_link_failed);
diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c
index 73d0aa552..7861220ee 100644
--- a/net/rose/rose_dev.c
+++ b/net/rose/rose_dev.c
@@ -1,5 +1,5 @@
/*
- * ROSE release 002
+ * ROSE release 003
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -101,7 +101,7 @@ static int rose_rebuild_header(struct sk_buff *skb)
unsigned char *bp = (unsigned char *)skb->data;
struct sk_buff *skbn;
- if (!arp_find(bp + 7, skb)) {
+ if (arp_find(bp + 7, skb)) {
kfree_skb(skb, FREE_WRITE);
return 1;
}
diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c
index 3c3e17b2b..1ac11528d 100644
--- a/net/rose/rose_in.c
+++ b/net/rose/rose_in.c
@@ -1,5 +1,5 @@
/*
- * ROSE release 002
+ * ROSE release 003
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -17,6 +17,8 @@
*
* History
* 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.
*/
#include <linux/config.h>
@@ -48,6 +50,8 @@ 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);
@@ -89,8 +93,9 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety
switch (frametype) {
case ROSE_CALL_ACCEPTED:
+ rose_stop_timer(sk);
+ rose_start_idletimer(sk);
sk->protinfo.rose->condition = 0x00;
- sk->protinfo.rose->timer = 0;
sk->protinfo.rose->vs = 0;
sk->protinfo.rose->va = 0;
sk->protinfo.rose->vr = 0;
@@ -102,15 +107,9 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety
break;
case ROSE_CLEAR_REQUEST:
- rose_clear_queues(sk);
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
- sk->protinfo.rose->state = ROSE_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = ECONNREFUSED;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
+ sk->protinfo.rose->neighbour->use--;
break;
default:
@@ -131,15 +130,13 @@ static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int framety
case ROSE_CLEAR_REQUEST:
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+ rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+ sk->protinfo.rose->neighbour->use--;
+ break;
+
case ROSE_CLEAR_CONFIRMATION:
- rose_clear_queues(sk);
- sk->protinfo.rose->state = ROSE_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = 0;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ rose_disconnect(sk, 0, -1, -1);
+ sk->protinfo.rose->neighbour->use--;
break;
default:
@@ -161,9 +158,10 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
switch (frametype) {
case ROSE_RESET_REQUEST:
+ rose_stop_timer(sk);
+ rose_start_idletimer(sk);
rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
sk->protinfo.rose->condition = 0x00;
- sk->protinfo.rose->timer = 0;
sk->protinfo.rose->vs = 0;
sk->protinfo.rose->vr = 0;
sk->protinfo.rose->va = 0;
@@ -171,15 +169,9 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
break;
case ROSE_CLEAR_REQUEST:
- rose_clear_queues(sk);
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
- sk->protinfo.rose->state = ROSE_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = 0;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+ sk->protinfo.rose->neighbour->use--;
break;
case ROSE_RR:
@@ -189,7 +181,6 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
else
sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
if (!rose_validate_nr(sk, nr)) {
- rose_clear_queues(sk);
rose_write_internal(sk, ROSE_RESET_REQUEST);
sk->protinfo.rose->condition = 0x00;
sk->protinfo.rose->vs = 0;
@@ -197,7 +188,8 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
sk->protinfo.rose->va = 0;
sk->protinfo.rose->vl = 0;
sk->protinfo.rose->state = ROSE_STATE_4;
- sk->protinfo.rose->timer = sk->protinfo.rose->t2;
+ rose_start_t2timer(sk);
+ rose_stop_idletimer(sk);
} else {
if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) {
sk->protinfo.rose->va = nr;
@@ -210,7 +202,6 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
case ROSE_DATA: /* XXX */
sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
if (!rose_validate_nr(sk, nr)) {
- rose_clear_queues(sk);
rose_write_internal(sk, ROSE_RESET_REQUEST);
sk->protinfo.rose->condition = 0x00;
sk->protinfo.rose->vs = 0;
@@ -218,7 +209,8 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
sk->protinfo.rose->va = 0;
sk->protinfo.rose->vl = 0;
sk->protinfo.rose->state = ROSE_STATE_4;
- sk->protinfo.rose->timer = sk->protinfo.rose->t2;
+ rose_start_t2timer(sk);
+ rose_stop_idletimer(sk);
break;
}
if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) {
@@ -242,11 +234,11 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
*/
if (((sk->protinfo.rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == sk->protinfo.rose->vr) {
sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
- sk->protinfo.rose->timer = 0;
+ rose_stop_timer(sk);
rose_enquiry_response(sk);
} else {
sk->protinfo.rose->condition |= ROSE_COND_ACK_PENDING;
- sk->protinfo.rose->timer = sk->protinfo.rose->hb;
+ rose_start_hbtimer(sk);
}
break;
@@ -270,7 +262,8 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
case ROSE_RESET_REQUEST:
rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
case ROSE_RESET_CONFIRMATION:
- sk->protinfo.rose->timer = 0;
+ rose_stop_timer(sk);
+ rose_start_idletimer(sk);
sk->protinfo.rose->condition = 0x00;
sk->protinfo.rose->va = 0;
sk->protinfo.rose->vr = 0;
@@ -280,16 +273,9 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
break;
case ROSE_CLEAR_REQUEST:
- rose_clear_queues(sk);
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
- sk->protinfo.rose->timer = 0;
- sk->protinfo.rose->state = ROSE_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = 0;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+ sk->protinfo.rose->neighbour->use--;
break;
default:
@@ -299,6 +285,22 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
return 0;
}
+/*
+ * State machine for state 5, Awaiting Call Acceptance State.
+ * The handling of the timer(s) is in file rose_timer.c
+ * Handling of state 0 and connection release is in af_rose.c.
+ */
+static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype)
+{
+ if (frametype == ROSE_CLEAR_REQUEST) {
+ rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+ rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+ sk->protinfo.rose->neighbour->use--;
+ }
+
+ return 0;
+}
+
/* Higher level upcall for a LAPB frame */
int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
{
@@ -307,8 +309,6 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
if (sk->protinfo.rose->state == ROSE_STATE_0)
return 0;
- del_timer(&sk->timer);
-
frametype = rose_decode(skb, &ns, &nr, &q, &d, &m);
switch (sk->protinfo.rose->state) {
@@ -324,9 +324,12 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
case ROSE_STATE_4:
queued = rose_state4_machine(sk, skb, frametype);
break;
+ case ROSE_STATE_5:
+ queued = rose_state5_machine(sk, skb, frametype);
+ break;
}
- rose_set_timer(sk);
+ rose_kick(sk);
return queued;
}
diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c
index 86626511e..b481e485f 100644
--- a/net/rose/rose_link.c
+++ b/net/rose/rose_link.c
@@ -1,5 +1,5 @@
/*
- * ROSE release 002
+ * ROSE release 003
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -11,6 +11,7 @@
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from rose_timer.c
+ * ROSE 003 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -38,53 +39,64 @@
#include <linux/firewall.h>
#include <net/rose.h>
-static void rose_link_timer(unsigned long);
+static void rose_ftimer_expiry(unsigned long);
+static void rose_t0timer_expiry(unsigned long);
-/*
- * Linux set timer
- */
-void rose_link_set_timer(struct rose_neigh *neigh)
+void rose_start_ftimer(struct rose_neigh *neigh)
{
- unsigned long flags;
+ del_timer(&neigh->ftimer);
- save_flags(flags); cli();
- del_timer(&neigh->timer);
- restore_flags(flags);
+ neigh->ftimer.data = (unsigned long)neigh;
+ neigh->ftimer.function = &rose_ftimer_expiry;
+ neigh->ftimer.expires = jiffies + sysctl_rose_link_fail_timeout;
- neigh->timer.data = (unsigned long)neigh;
- neigh->timer.function = &rose_link_timer;
- neigh->timer.expires = jiffies + (HZ / 10);
+ add_timer(&neigh->ftimer);
+}
+
+void rose_start_t0timer(struct rose_neigh *neigh)
+{
+ del_timer(&neigh->t0timer);
- add_timer(&neigh->timer);
+ neigh->t0timer.data = (unsigned long)neigh;
+ neigh->t0timer.function = &rose_t0timer_expiry;
+ neigh->t0timer.expires = jiffies + sysctl_rose_restart_request_timeout;
+
+ add_timer(&neigh->t0timer);
}
-/*
- * ROSE Link Timer
- *
- * This routine is called every 100ms. Decrement timer by this
- * amount - if expired then process the event.
- */
-static void rose_link_timer(unsigned long param)
+void rose_stop_ftimer(struct rose_neigh *neigh)
{
- struct rose_neigh *neigh = (struct rose_neigh *)param;
+ del_timer(&neigh->ftimer);
+}
- if (neigh->ftimer > 0)
- neigh->ftimer--;
+void rose_stop_t0timer(struct rose_neigh *neigh)
+{
+ del_timer(&neigh->t0timer);
+}
- if (neigh->t0timer > 0) {
- neigh->t0timer--;
+int rose_ftimer_running(struct rose_neigh *neigh)
+{
+ return (neigh->ftimer.prev != NULL || neigh->ftimer.next != NULL);
+}
- if (neigh->t0timer == 0) {
- rose_transmit_restart_request(neigh);
- neigh->dce_mode = 0;
- neigh->t0timer = sysctl_rose_restart_request_timeout;
- }
- }
+int rose_t0timer_running(struct rose_neigh *neigh)
+{
+ return (neigh->t0timer.prev != NULL || neigh->t0timer.next != NULL);
+}
- if (neigh->ftimer > 0 || neigh->t0timer > 0)
- rose_link_set_timer(neigh);
- else
- del_timer(&neigh->timer);
+static void rose_ftimer_expiry(unsigned long param)
+{
+}
+
+static void rose_t0timer_expiry(unsigned long param)
+{
+ struct rose_neigh *neigh = (struct rose_neigh *)param;
+
+ rose_transmit_restart_request(neigh);
+
+ neigh->dce_mode = 0;
+
+ rose_start_t0timer(neigh);
}
/*
@@ -101,7 +113,9 @@ static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
else
rose_call = &rose_callsign;
- return ax25_send_frame(skb, 256, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+ neigh->ax25 = ax25_send_frame(skb, 256, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+
+ return (neigh->ax25 != NULL);
}
/*
@@ -118,7 +132,9 @@ static int rose_link_up(struct rose_neigh *neigh)
else
rose_call = &rose_callsign;
- return ax25_link_up(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+ neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+
+ return (neigh->ax25 != NULL);
}
/*
@@ -130,17 +146,15 @@ void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigne
switch (frametype) {
case ROSE_RESTART_REQUEST:
- neigh->t0timer = 0;
+ rose_stop_t0timer(neigh);
neigh->restarted = 1;
- neigh->dce_mode = (skb->data[3] == 0x00);
- del_timer(&neigh->timer);
+ neigh->dce_mode = (skb->data[3] == ROSE_DTE_ORIGINATED);
rose_transmit_restart_confirmation(neigh);
break;
case ROSE_RESTART_CONFIRMATION:
- neigh->t0timer = 0;
+ rose_stop_t0timer(neigh);
neigh->restarted = 1;
- del_timer(&neigh->timer);
break;
case ROSE_DIAGNOSTIC:
@@ -181,7 +195,7 @@ void rose_transmit_restart_request(struct rose_neigh *neigh)
*dptr++ = ROSE_GFI;
*dptr++ = 0x00;
*dptr++ = ROSE_RESTART_REQUEST;
- *dptr++ = 0x00;
+ *dptr++ = ROSE_DTE_ORIGINATED;
*dptr++ = 0;
if (!rose_send_frame(skb, neigh))
@@ -247,7 +261,7 @@ void rose_transmit_diagnostic(struct rose_neigh *neigh, unsigned char diag)
* This routine is called when a Clear Request is needed outside of the context
* of a connected socket.
*/
-void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, unsigned char cause)
+void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, unsigned char cause, unsigned char diagnostic)
{
struct sk_buff *skb;
unsigned char *dptr;
@@ -267,7 +281,7 @@ void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, uns
*dptr++ = ((lci >> 0) & 0xFF);
*dptr++ = ROSE_CLEAR_REQUEST;
*dptr++ = cause;
- *dptr++ = 0x00;
+ *dptr++ = diagnostic;
if (!rose_send_frame(skb, neigh))
kfree_skb(skb, FREE_WRITE);
@@ -294,11 +308,10 @@ void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
} else {
skb_queue_tail(&neigh->queue, skb);
- if (neigh->t0timer == 0) {
+ if (!rose_t0timer_running(neigh)) {
rose_transmit_restart_request(neigh);
neigh->dce_mode = 0;
- neigh->t0timer = sysctl_rose_restart_request_timeout;
- rose_link_set_timer(neigh);
+ rose_start_t0timer(neigh);
}
}
}
diff --git a/net/rose/rose_out.c b/net/rose/rose_out.c
index f0e212dc3..0ed9f7480 100644
--- a/net/rose/rose_out.c
+++ b/net/rose/rose_out.c
@@ -1,5 +1,5 @@
/*
- * ROSE release 002
+ * ROSE release 003
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -11,6 +11,7 @@
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_out.c
+ * ROSE 003 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -80,8 +81,7 @@ void rose_output(struct sock *sk, struct sk_buff *skb)
skb_queue_tail(&sk->write_queue, skb); /* Throw it on the queue */
}
- if (sk->protinfo.rose->state == ROSE_STATE_3)
- rose_kick(sk);
+ rose_kick(sk);
}
/*
@@ -96,6 +96,8 @@ static void rose_send_iframe(struct sock *sk, struct sk_buff *skb)
skb->data[2] |= (sk->protinfo.rose->vr << 5) & 0xE0;
skb->data[2] |= (sk->protinfo.rose->vs << 1) & 0x0E;
+ rose_start_idletimer(sk);
+
rose_transmit_link(skb, sk->protinfo.rose->neighbour);
}
@@ -104,36 +106,41 @@ void rose_kick(struct sock *sk)
struct sk_buff *skb;
unsigned short end;
- del_timer(&sk->timer);
+ if (sk->protinfo.rose->state != ROSE_STATE_3)
+ return;
+
+ if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY)
+ return;
+
+ if (skb_peek(&sk->write_queue) == NULL)
+ return;
end = (sk->protinfo.rose->va + sysctl_rose_window_size) % ROSE_MODULUS;
- if (!(sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) &&
- sk->protinfo.rose->vs != end &&
- skb_peek(&sk->write_queue) != NULL) {
- /*
- * Transmit data until either we're out of data to send or
- * the window is full.
- */
+ if (sk->protinfo.rose->vs == end)
+ return;
- skb = skb_dequeue(&sk->write_queue);
+ /*
+ * Transmit data until either we're out of data to send or
+ * the window is full.
+ */
- do {
- /*
- * Transmit the frame.
- */
- rose_send_iframe(sk, skb);
+ skb = skb_dequeue(&sk->write_queue);
- sk->protinfo.rose->vs = (sk->protinfo.rose->vs + 1) % ROSE_MODULUS;
+ do {
+ /*
+ * Transmit the frame.
+ */
+ rose_send_iframe(sk, skb);
- } while (sk->protinfo.rose->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
+ sk->protinfo.rose->vs = (sk->protinfo.rose->vs + 1) % ROSE_MODULUS;
- sk->protinfo.rose->vl = sk->protinfo.rose->vr;
- sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
- sk->protinfo.rose->timer = 0;
- }
+ } while (sk->protinfo.rose->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
- rose_set_timer(sk);
+ sk->protinfo.rose->vl = sk->protinfo.rose->vr;
+ sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
+
+ rose_stop_timer(sk);
}
/*
@@ -150,7 +157,8 @@ void rose_enquiry_response(struct sock *sk)
sk->protinfo.rose->vl = sk->protinfo.rose->vr;
sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
- sk->protinfo.rose->timer = 0;
+
+ rose_stop_timer(sk);
}
void rose_check_iframes_acked(struct sock *sk, unsigned short nr)
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index 5b1338609..43358644c 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -1,5 +1,5 @@
/*
- * ROSE release 002
+ * ROSE release 003
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -15,6 +15,8 @@
* address masks.
* ROSE 002 Jonathan(G4KLX) Uprated through routing of packets.
* Routing loop detection.
+ * ROSE 003 Jonathan(G4KLX) New timer architecture.
+ * Added use count to neighbours.
*/
#include <linux/config.h>
@@ -80,24 +82,32 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de
rose_neigh->callsign = rose_route->neighbour;
rose_neigh->digipeat = NULL;
+ rose_neigh->ax25 = NULL;
rose_neigh->dev = dev;
rose_neigh->count = 0;
+ rose_neigh->use = 0;
rose_neigh->dce_mode = 0;
rose_neigh->number = rose_neigh_no++;
rose_neigh->restarted = 0;
+
skb_queue_head_init(&rose_neigh->queue);
- rose_neigh->t0timer = 0;
- rose_neigh->ftimer = 0;
- init_timer(&rose_neigh->timer);
+
+ init_timer(&rose_neigh->ftimer);
+ init_timer(&rose_neigh->t0timer);
if (rose_route->ndigis != 0) {
if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
kfree(rose_neigh);
return -ENOMEM;
}
- rose_neigh->digipeat->ndigi = rose_route->ndigis;
- for (i = 0; i < rose_route->ndigis; i++)
- rose_neigh->digipeat->calls[i] = rose_route->digipeaters[i];
+
+ rose_neigh->digipeat->ndigi = rose_route->ndigis;
+ rose_neigh->digipeat->lastrepeat = -1;
+
+ for (i = 0; i < rose_route->ndigis; i++) {
+ rose_neigh->digipeat->calls[i] = rose_route->digipeaters[i];
+ rose_neigh->digipeat->repeated[i] = 0;
+ }
}
save_flags(flags); cli();
@@ -207,13 +217,13 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
unsigned long flags;
struct sk_buff *skb;
- del_timer(&rose_neigh->timer);
+ rose_stop_ftimer(rose_neigh);
+ rose_stop_t0timer(rose_neigh);
while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
kfree_skb(skb, FREE_WRITE);
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
if ((s = rose_neigh_list) == rose_neigh) {
rose_neigh_list = rose_neigh->next;
@@ -244,9 +254,14 @@ static void rose_remove_route(struct rose_route *rose_route)
{
struct rose_route *s;
unsigned long flags;
-
- save_flags(flags);
- cli();
+
+ if (rose_route->neigh1 != NULL)
+ rose_route->neigh1->use--;
+
+ if (rose_route->neigh2 != NULL)
+ rose_route->neigh2->use--;
+
+ save_flags(flags); cli();
if ((s = rose_route_list) == rose_route) {
rose_route_list = rose_route->next;
@@ -295,7 +310,7 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct device *de
if (rose_node->neighbour[i] == rose_neigh) {
rose_neigh->count--;
- if (rose_neigh->count == 0)
+ if (rose_neigh->count == 0 && rose_neigh->use == 0)
rose_remove_neigh(rose_neigh);
rose_node->count--;
@@ -381,6 +396,35 @@ void rose_route_device_down(struct device *dev)
}
/*
+ * Clear all nodes and neighbours out, except for neighbours with
+ * active connections going through them.
+ */
+static int rose_clear_routes(void)
+{
+ struct rose_neigh *s, *rose_neigh = rose_neigh_list;
+ struct rose_node *t, *rose_node = rose_node_list;
+
+ while (rose_node != NULL) {
+ t = rose_node;
+ rose_node = rose_node->next;
+
+ rose_remove_node(t);
+ }
+
+ while (rose_neigh != NULL) {
+ s = rose_neigh;
+ rose_neigh = rose_neigh->next;
+
+ s->count = 0;
+
+ if (s->use == 0)
+ rose_remove_neigh(s);
+ }
+
+ return 0;
+}
+
+/*
* Check that the device given is a valid AX.25 interface that is "up".
*/
struct device *rose_ax25_dev_get(char *devname)
@@ -440,20 +484,31 @@ struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neig
/*
* Find a neighbour given a ROSE address.
*/
-struct rose_neigh *rose_get_neigh(rose_address *addr)
+struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsigned char *diagnostic)
{
struct rose_node *node;
+ int failed = 0;
int i;
for (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 (node->neighbour[i]->ftimer == 0)
+ if (!rose_ftimer_running(node->neighbour[i]))
return node->neighbour[i];
+ else
+ failed = 1;
}
}
}
+ if (failed) {
+ *cause = ROSE_OUT_OF_ORDER;
+ *diagnostic = 0;
+ } else {
+ *cause = ROSE_NOT_OBTAINABLE;
+ *diagnostic = 0;
+ }
+
return NULL;
}
@@ -464,14 +519,12 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
{
struct rose_route_struct rose_route;
struct device *dev;
- int err;
switch (cmd) {
case SIOCADDRT:
- if ((err = verify_area(VERIFY_READ, arg, sizeof(struct rose_route_struct))) != 0)
- return err;
- copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct));
+ if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
+ return -EFAULT;
if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
return -EINVAL;
if (rose_dev_get(&rose_route.address) != NULL) /* Can't add routes to ourself */
@@ -482,13 +535,15 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
return rose_add_node(&rose_route, dev);
case SIOCDELRT:
- if ((err = verify_area(VERIFY_READ, arg, sizeof(struct rose_route_struct))) != 0)
- return err;
- copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct));
+ if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
+ return -EFAULT;
if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
return -EINVAL;
return rose_del_node(&rose_route, dev);
+ case SIOCRSCLRRT:
+ return rose_clear_routes();
+
default:
return -EINVAL;
}
@@ -502,10 +557,9 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
struct sk_buff *skb;
rose_neigh->restarted = 0;
- rose_neigh->t0timer = 0;
- rose_neigh->ftimer = sysctl_rose_link_fail_timeout;
- rose_link_set_timer(rose_neigh);
+ rose_stop_t0timer(rose_neigh);
+ rose_start_ftimer(rose_neigh);
while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
kfree_skb(skb, FREE_WRITE);
@@ -523,13 +577,15 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
}
if (rose_route->neigh1 == rose_neigh) {
+ rose_route->neigh1->use--;
rose_route->neigh1 = NULL;
- rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, 0x0D);
+ rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, ROSE_OUT_OF_ORDER, 0);
}
if (rose_route->neigh2 == rose_neigh) {
+ rose_route->neigh2->use--;
rose_route->neigh2 = NULL;
- rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, 0x0D);
+ rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, ROSE_OUT_OF_ORDER, 0);
}
rose_route = rose_route->next;
@@ -541,16 +597,18 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
* then don't use that neighbour until it is reset. Blow away all through
* routes and connections using this route.
*/
-void rose_link_failed(ax25_address *callsign, struct device *dev)
+void rose_link_failed(ax25_cb *ax25, int reason)
{
struct rose_neigh *rose_neigh;
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
- if (ax25cmp(&rose_neigh->callsign, callsign) == 0 && rose_neigh->dev == dev)
+ if (rose_neigh->ax25 == ax25)
break;
if (rose_neigh == NULL) return;
+ rose_neigh->ax25 = NULL;
+
rose_del_route_by_neigh(rose_neigh);
rose_kill_by_neigh(rose_neigh);
}
@@ -583,6 +641,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
struct sock *sk;
unsigned short frametype;
unsigned int lci, new_lci;
+ unsigned char cause, diagnostic;
struct device *dev;
unsigned long flags;
@@ -604,7 +663,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
/*
* Obviously the link is working, halt the ftimer.
*/
- rose_neigh->ftimer = 0;
+ rose_stop_ftimer(rose_neigh);
/*
* LCI of zero is always for us, and its always a restart
@@ -631,7 +690,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
return rose_rx_call_request(skb, dev, rose_neigh, lci);
if (!sysctl_rose_routing_control) {
- rose_transmit_clear_request(rose_neigh, lci, 0x0D);
+ rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0);
return 0;
}
@@ -679,7 +738,10 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
if (frametype != ROSE_CALL_REQUEST) /* XXX */
return 0;
- rose_parse_facilities(skb, &facilities);
+ if (!rose_parse_facilities(skb, &facilities)) {
+ rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76);
+ return 0;
+ }
/*
* Check for routing loops.
@@ -691,25 +753,25 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) {
printk(KERN_DEBUG "ROSE: routing loop from %s\n", rose2asc(src_addr));
printk(KERN_DEBUG "ROSE: to %s\n", rose2asc(dest_addr));
- rose_transmit_clear_request(rose_neigh, lci, 0x0D);
+ rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 120);
return 0;
}
}
- if ((new_neigh = rose_get_neigh(dest_addr)) == NULL) {
- printk(KERN_DEBUG "ROSE: no route to %s\n", rose2asc(dest_addr));
- rose_transmit_clear_request(rose_neigh, lci, 0x0D);
+ if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) {
+ if (cause == ROSE_NOT_OBTAINABLE)
+ printk(KERN_DEBUG "ROSE: no route to %s\n", rose2asc(dest_addr));
+ rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic);
return 0;
}
if ((new_lci = rose_new_lci(new_neigh)) == 0) {
- printk(KERN_DEBUG "ROSE: no spare VCs to %s\n", rose2asc(dest_addr));
- rose_transmit_clear_request(rose_neigh, lci, 0x0D);
+ rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71);
return 0;
}
if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) {
- rose_transmit_clear_request(rose_neigh, lci, 0x0D);
+ rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120);
return 0;
}
@@ -723,6 +785,9 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_route->lci2 = new_lci;
rose_route->neigh2 = new_neigh;
+ rose_route->neigh1->use++;
+ rose_route->neigh2->use++;
+
save_flags(flags); cli();
rose_route->next = rose_route_list;
rose_route_list = rose_route;
@@ -790,21 +855,30 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset,
int len = 0;
off_t pos = 0;
off_t begin = 0;
+ int i;
cli();
- len += sprintf(buffer, "addr callsign dev count mode restart t0 tf\n");
+ len += sprintf(buffer, "addr callsign dev count use mode restart t0 tf digipeaters\n");
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
- len += sprintf(buffer + len, "%05d %-9s %-4s %3d %3s %3s %3d %3d\n",
+ len += sprintf(buffer + len, "%05d %-9s %-4s %3d %3d %3s %3s %3lu %3lu",
rose_neigh->number,
ax2asc(&rose_neigh->callsign),
rose_neigh->dev ? rose_neigh->dev->name : "???",
rose_neigh->count,
+ rose_neigh->use,
(rose_neigh->dce_mode) ? "DCE" : "DTE",
(rose_neigh->restarted) ? "yes" : "no",
- rose_neigh->t0timer / ROSE_SLOWHZ,
- rose_neigh->ftimer / ROSE_SLOWHZ);
+ ax25_display_timer(&rose_neigh->t0timer) / HZ,
+ ax25_display_timer(&rose_neigh->ftimer) / HZ);
+
+ if (rose_neigh->digipeat != NULL) {
+ for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
+ len += sprintf(buffer + len, " %s", ax2asc(&rose_neigh->digipeat->calls[i]));
+ }
+
+ len += sprintf(buffer + len, "\n");
pos = begin + len;
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c
index 4e0530cb4..ee710bd6e 100644
--- a/net/rose/rose_subr.c
+++ b/net/rose/rose_subr.c
@@ -1,5 +1,5 @@
/*
- * ROSE release 002
+ * ROSE release 003
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -11,6 +11,8 @@
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_subr.c
+ * ROSE 002 Jonathan(G4KLX) Centralised disconnect processing.
+ * ROSE 003 Jonathan(G4KLX) Added use count to neighbours.
*/
#include <linux/config.h>
@@ -92,12 +94,8 @@ void rose_write_internal(struct sock *sk, int frametype)
case ROSE_CALL_ACCEPTED:
case ROSE_CLEAR_REQUEST:
case ROSE_RESET_REQUEST:
- case ROSE_DIAGNOSTIC:
len += 2;
break;
- case ROSE_INTERRUPT:
- len += 1;
- break;
}
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
@@ -137,24 +135,23 @@ void rose_write_internal(struct sock *sk, int frametype)
break;
case ROSE_CLEAR_REQUEST:
- case ROSE_RESET_REQUEST:
*dptr++ = ROSE_GFI | lci1;
*dptr++ = lci2;
*dptr++ = frametype;
- *dptr++ = 0x00; /* XXX */
- *dptr++ = 0x00; /* XXX */
+ *dptr++ = sk->protinfo.rose->cause;
+ *dptr++ = sk->protinfo.rose->diagnostic;
break;
- case ROSE_INTERRUPT:
+ case ROSE_RESET_REQUEST:
*dptr++ = ROSE_GFI | lci1;
*dptr++ = lci2;
*dptr++ = frametype;
- *dptr++ = 0x00; /* XXX */
+ *dptr++ = ROSE_DTE_ORIGINATED;
+ *dptr++ = 0;
break;
case ROSE_RR:
case ROSE_RNR:
- case ROSE_REJ:
*dptr++ = ROSE_GFI | lci1;
*dptr++ = lci2;
*dptr = frametype;
@@ -162,7 +159,6 @@ void rose_write_internal(struct sock *sk, int frametype)
break;
case ROSE_CLEAR_CONFIRMATION:
- case ROSE_INTERRUPT_CONFIRMATION:
case ROSE_RESET_CONFIRMATION:
*dptr++ = ROSE_GFI | lci1;
*dptr++ = lci2;
@@ -191,23 +187,15 @@ int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
case ROSE_CALL_ACCEPTED:
case ROSE_CLEAR_REQUEST:
case ROSE_CLEAR_CONFIRMATION:
- case ROSE_INTERRUPT:
- case ROSE_INTERRUPT_CONFIRMATION:
case ROSE_RESET_REQUEST:
case ROSE_RESET_CONFIRMATION:
- case ROSE_RESTART_REQUEST:
- case ROSE_RESTART_CONFIRMATION:
- case ROSE_REGISTRATION_REQUEST:
- case ROSE_REGISTRATION_CONFIRMATION:
- case ROSE_DIAGNOSTIC:
return frame[2];
default:
break;
}
if ((frame[2] & 0x1F) == ROSE_RR ||
- (frame[2] & 0x1F) == ROSE_RNR ||
- (frame[2] & 0x1F) == ROSE_REJ) {
+ (frame[2] & 0x1F) == ROSE_RNR) {
*nr = (frame[2] >> 5) & 0x07;
return frame[2] & 0x1F;
}
@@ -437,4 +425,30 @@ int rose_create_facilities(unsigned char *buffer, rose_cb *rose)
return len;
}
+void rose_disconnect(struct sock *sk, int reason, int cause, int diagnostic)
+{
+ rose_stop_timer(sk);
+ rose_stop_idletimer(sk);
+
+ rose_clear_queues(sk);
+
+ sk->protinfo.rose->lci = 0;
+ sk->protinfo.rose->state = ROSE_STATE_0;
+
+ if (cause != -1)
+ sk->protinfo.rose->cause = cause;
+
+ if (diagnostic != -1)
+ sk->protinfo.rose->diagnostic = diagnostic;
+
+ sk->state = TCP_CLOSE;
+ sk->err = reason;
+ sk->shutdown |= SEND_SHUTDOWN;
+
+ if (!sk->dead)
+ sk->state_change(sk);
+
+ sk->dead = 1;
+}
+
#endif
diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c
index 572975e5d..718a64ec0 100644
--- a/net/rose/rose_timer.c
+++ b/net/rose/rose_timer.c
@@ -1,5 +1,5 @@
/*
- * ROSE release 002
+ * ROSE release 003
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -11,6 +11,8 @@
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_timer.c
+ * ROSE 003 Jonathan(G4KLX) New timer architecture.
+ * Implemented idle timer.
*/
#include <linux/config.h>
@@ -37,42 +39,103 @@
#include <linux/interrupt.h>
#include <net/rose.h>
-static void rose_timer(unsigned long);
+static void rose_heartbeat_expiry(unsigned long);
+static void rose_timer_expiry(unsigned long);
+static void rose_idletimer_expiry(unsigned long);
-/*
- * Linux set timer
- */
-void rose_set_timer(struct sock *sk)
+void rose_start_heartbeat(struct sock *sk)
{
- unsigned long flags;
-
- save_flags(flags); cli();
del_timer(&sk->timer);
- restore_flags(flags);
sk->timer.data = (unsigned long)sk;
- sk->timer.function = &rose_timer;
- sk->timer.expires = jiffies + (HZ / 10);
+ sk->timer.function = &rose_heartbeat_expiry;
+ sk->timer.expires = jiffies + 5 * HZ;
add_timer(&sk->timer);
}
-/*
- * ROSE Timer
- *
- * This routine is called every 100ms. Decrement timer by this
- * amount - if expired then process the event.
- */
-static void rose_timer(unsigned long param)
+void rose_start_t1timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.rose->timer);
+
+ sk->protinfo.rose->timer.data = (unsigned long)sk;
+ sk->protinfo.rose->timer.function = &rose_timer_expiry;
+ sk->protinfo.rose->timer.expires = jiffies + sk->protinfo.rose->t1;
+
+ add_timer(&sk->protinfo.rose->timer);
+}
+
+void rose_start_t2timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.rose->timer);
+
+ sk->protinfo.rose->timer.data = (unsigned long)sk;
+ sk->protinfo.rose->timer.function = &rose_timer_expiry;
+ sk->protinfo.rose->timer.expires = jiffies + sk->protinfo.rose->t2;
+
+ add_timer(&sk->protinfo.rose->timer);
+}
+
+void rose_start_t3timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.rose->timer);
+
+ sk->protinfo.rose->timer.data = (unsigned long)sk;
+ sk->protinfo.rose->timer.function = &rose_timer_expiry;
+ sk->protinfo.rose->timer.expires = jiffies + sk->protinfo.rose->t3;
+
+ add_timer(&sk->protinfo.rose->timer);
+}
+
+void rose_start_hbtimer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.rose->timer);
+
+ sk->protinfo.rose->timer.data = (unsigned long)sk;
+ sk->protinfo.rose->timer.function = &rose_timer_expiry;
+ sk->protinfo.rose->timer.expires = jiffies + sk->protinfo.rose->hb;
+
+ add_timer(&sk->protinfo.rose->timer);
+}
+
+void rose_start_idletimer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.rose->idletimer);
+
+ if (sk->protinfo.rose->idle > 0) {
+ sk->protinfo.rose->idletimer.data = (unsigned long)sk;
+ sk->protinfo.rose->idletimer.function = &rose_idletimer_expiry;
+ sk->protinfo.rose->idletimer.expires = jiffies + sk->protinfo.rose->idle;
+
+ add_timer(&sk->protinfo.rose->idletimer);
+ }
+}
+
+void rose_stop_heartbeat(struct sock *sk)
+{
+ del_timer(&sk->timer);
+}
+
+void rose_stop_timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.rose->timer);
+}
+
+void rose_stop_idletimer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.rose->idletimer);
+}
+
+static void rose_heartbeat_expiry(unsigned long param)
{
struct sock *sk = (struct sock *)param;
switch (sk->protinfo.rose->state) {
+
case ROSE_STATE_0:
/* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */
if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
- del_timer(&sk->timer);
rose_destroy_socket(sk);
return;
}
@@ -87,57 +150,62 @@ static void rose_timer(unsigned long param)
sk->protinfo.rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
sk->protinfo.rose->vl = sk->protinfo.rose->vr;
- sk->protinfo.rose->timer = 0;
rose_write_internal(sk, ROSE_RR);
+ rose_stop_timer(sk); /* HB */
break;
}
- /*
- * Check for frames to transmit.
- */
- rose_kick(sk);
- break;
-
- default:
break;
}
- if (sk->protinfo.rose->timer == 0 || --sk->protinfo.rose->timer > 0) {
- rose_set_timer(sk);
- return;
- }
+ rose_start_heartbeat(sk);
+}
+
+static void rose_timer_expiry(unsigned long param)
+{
+ struct sock *sk = (struct sock *)param;
- /*
- * Timer has expired, it may have been T1, T2, T3 or HB. We can tell
- * by the socket state.
- */
switch (sk->protinfo.rose->state) {
- case ROSE_STATE_3: /* HB */
- if (sk->protinfo.rose->condition & ROSE_COND_ACK_PENDING) {
- sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
- rose_enquiry_response(sk);
- }
- break;
case ROSE_STATE_1: /* T1 */
case ROSE_STATE_4: /* T2 */
rose_write_internal(sk, ROSE_CLEAR_REQUEST);
sk->protinfo.rose->state = ROSE_STATE_2;
- sk->protinfo.rose->timer = sk->protinfo.rose->t3;
+ rose_start_t3timer(sk);
break;
case ROSE_STATE_2: /* T3 */
- rose_clear_queues(sk);
- sk->protinfo.rose->state = ROSE_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = ETIMEDOUT;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ sk->protinfo.rose->neighbour->use--;
+ rose_disconnect(sk, ETIMEDOUT, -1, -1);
+ break;
+
+ case ROSE_STATE_3: /* HB */
+ if (sk->protinfo.rose->condition & ROSE_COND_ACK_PENDING) {
+ sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
+ rose_enquiry_response(sk);
+ }
break;
}
+}
+
+static void rose_idletimer_expiry(unsigned long param)
+{
+ struct sock *sk = (struct sock *)param;
+
+ rose_clear_queues(sk);
+
+ rose_write_internal(sk, ROSE_CLEAR_REQUEST);
+ sk->protinfo.rose->state = ROSE_STATE_2;
+
+ rose_start_t3timer(sk);
+
+ sk->state = TCP_CLOSE;
+ sk->err = 0;
+ sk->shutdown |= SEND_SHUTDOWN;
+
+ if (!sk->dead)
+ sk->state_change(sk);
- rose_set_timer(sk);
+ sk->dead = 1;
}
#endif
diff --git a/net/rose/sysctl_net_rose.c b/net/rose/sysctl_net_rose.c
index 409f79b52..ad45e3b47 100644
--- a/net/rose/sysctl_net_rose.c
+++ b/net/rose/sysctl_net_rose.c
@@ -11,13 +11,13 @@
#include <net/ax25.h>
#include <net/rose.h>
-static int min_timer[] = {1 * ROSE_SLOWHZ};
-static int max_timer[] = {300 * ROSE_SLOWHZ};
-static int min_idle[] = {0 * ROSE_SLOWHZ};
-static int max_idle[] = {65535 * ROSE_SLOWHZ};
+static int min_timer[] = {1 * HZ};
+static int max_timer[] = {300 * HZ};
+static int min_idle[] = {0 * HZ};
+static int max_idle[] = {65535 * HZ};
static int min_route[] = {0}, max_route[] = {1};
-static int min_ftimer[] = {60 * ROSE_SLOWHZ};
-static int max_ftimer[] = {600 * ROSE_SLOWHZ};
+static int min_ftimer[] = {60 * HZ};
+static int max_ftimer[] = {600 * HZ};
static int min_maxvcs[] = {1}, max_maxvcs[] = {254};
static int min_window[] = {1}, max_window[] = {7};