summaryrefslogtreecommitdiffstats
path: root/net/netrom
diff options
context:
space:
mode:
Diffstat (limited to 'net/netrom')
-rw-r--r--net/netrom/af_netrom.c184
-rw-r--r--net/netrom/nr_dev.c2
-rw-r--r--net/netrom/nr_in.c60
-rw-r--r--net/netrom/nr_out.c104
-rw-r--r--net/netrom/nr_route.c27
-rw-r--r--net/netrom/nr_subr.c26
-rw-r--r--net/netrom/nr_timer.c208
-rw-r--r--net/netrom/sysctl_net_netrom.c16
8 files changed, 354 insertions, 273 deletions
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 22e1afbee..dd80a211b 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -1,5 +1,5 @@
/*
- * NET/ROM release 006
+ * NET/ROM release 007
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -28,6 +28,8 @@
* Alan(GW4PTS) Started POSIXisms
* NET/ROM 006 Alan(GW4PTS) Brought in line with the ANK changes
* Jonathan(G4KLX) Removed hdrincl.
+ * NET/ROM 007 Jonathan(G4KLX) New timer architecture.
+ * Impmented Idle timer.
*/
#include <linux/config.h>
@@ -122,8 +124,7 @@ static void nr_remove_socket(struct sock *sk)
struct sock *s;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
if ((s = nr_list) == sk) {
nr_list = s->next;
@@ -152,15 +153,8 @@ static void nr_kill_by_device(struct device *dev)
struct sock *s;
for (s = nr_list; s != NULL; s = s->next) {
- if (s->protinfo.nr->device == dev) {
- s->protinfo.nr->state = NR_STATE_0;
- s->protinfo.nr->device = NULL;
- s->state = TCP_CLOSE;
- s->err = ENETUNREACH;
- s->shutdown |= SEND_SHUTDOWN;
- s->state_change(s);
- s->dead = 1;
- }
+ if (s->protinfo.nr->device == dev)
+ nr_disconnect(s, ENETUNREACH);
}
}
@@ -187,8 +181,7 @@ static void nr_insert_socket(struct sock *sk)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
sk->next = nr_list;
nr_list = sk;
@@ -289,10 +282,13 @@ void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
struct sk_buff *skb;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
- del_timer(&sk->timer);
+ nr_stop_heartbeat(sk);
+ nr_stop_t1timer(sk);
+ nr_stop_t2timer(sk);
+ nr_stop_t4timer(sk);
+ nr_stop_idletimer(sk);
nr_remove_socket(sk);
nr_clear_queues(sk); /* Flush the queues */
@@ -300,7 +296,7 @@ void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
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 */
- nr_set_timer(skb->sk);
+ nr_start_heartbeat(skb->sk);
skb->sk->protinfo.nr->state = NR_STATE_0;
}
@@ -345,13 +341,13 @@ static int nr_setsockopt(struct socket *sock, int level, int optname,
case NETROM_T1:
if (opt < 1)
return -EINVAL;
- sk->protinfo.nr->t1 = opt * NR_SLOWHZ;
+ sk->protinfo.nr->t1 = opt * HZ;
return 0;
case NETROM_T2:
if (opt < 1)
return -EINVAL;
- sk->protinfo.nr->t2 = opt * NR_SLOWHZ;
+ sk->protinfo.nr->t2 = opt * HZ;
return 0;
case NETROM_N2:
@@ -363,13 +359,13 @@ static int nr_setsockopt(struct socket *sock, int level, int optname,
case NETROM_T4:
if (opt < 1)
return -EINVAL;
- sk->protinfo.nr->t4 = opt * NR_SLOWHZ;
+ sk->protinfo.nr->t4 = opt * HZ;
return 0;
case NETROM_IDLE:
- if (opt < 1)
+ if (opt < 0)
return -EINVAL;
- sk->protinfo.nr->idle = opt * 60 * NR_SLOWHZ;
+ sk->protinfo.nr->idle = opt * 60 * HZ;
return 0;
default:
@@ -392,11 +388,11 @@ static int nr_getsockopt(struct socket *sock, int level, int optname,
switch (optname) {
case NETROM_T1:
- val = (sk->protinfo.nr->t1 * 2) / NR_SLOWHZ;
+ val = sk->protinfo.nr->t1 / HZ;
break;
case NETROM_T2:
- val = sk->protinfo.nr->t2 / NR_SLOWHZ;
+ val = sk->protinfo.nr->t2 / HZ;
break;
case NETROM_N2:
@@ -404,11 +400,11 @@ static int nr_getsockopt(struct socket *sock, int level, int optname,
break;
case NETROM_T4:
- val = sk->protinfo.nr->t4 / NR_SLOWHZ;
+ val = sk->protinfo.nr->t4 / HZ;
break;
case NETROM_IDLE:
- val = sk->protinfo.nr->idle / (NR_SLOWHZ * 60);
+ val = sk->protinfo.nr->idle / (60 * HZ);
break;
default:
@@ -463,6 +459,11 @@ static int nr_create(struct socket *sock, int protocol)
skb_queue_head_init(&nr->reseq_queue);
skb_queue_head_init(&nr->frag_queue);
+ init_timer(&nr->t1timer);
+ init_timer(&nr->t2timer);
+ init_timer(&nr->t4timer);
+ init_timer(&nr->idletimer);
+
nr->t1 = sysctl_netrom_transport_timeout;
nr->t2 = sysctl_netrom_transport_acknowledge_delay;
nr->n2 = sysctl_netrom_transport_maximum_tries;
@@ -507,6 +508,11 @@ static struct sock *nr_make_new(struct sock *osk)
skb_queue_head_init(&nr->reseq_queue);
skb_queue_head_init(&nr->frag_queue);
+ init_timer(&nr->t1timer);
+ init_timer(&nr->t2timer);
+ init_timer(&nr->t4timer);
+ init_timer(&nr->idletimer);
+
nr->t1 = osk->protinfo.nr->t1;
nr->t2 = osk->protinfo.nr->t2;
nr->n2 = osk->protinfo.nr->n2;
@@ -539,39 +545,20 @@ static int nr_release(struct socket *sock, struct socket *peer)
switch (sk->protinfo.nr->state) {
case NR_STATE_0:
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
- sk->state_change(sk);
- sk->dead = 1;
+ case NR_STATE_2:
+ nr_disconnect(sk, 0);
nr_destroy_socket(sk);
break;
case NR_STATE_1:
- sk->protinfo.nr->state = NR_STATE_0;
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
- sk->state_change(sk);
- sk->dead = 1;
- nr_destroy_socket(sk);
- break;
-
- case NR_STATE_2:
- nr_write_internal(sk, NR_DISCACK);
- sk->protinfo.nr->state = NR_STATE_0;
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
- sk->state_change(sk);
- sk->dead = 1;
- nr_destroy_socket(sk);
- break;
-
case NR_STATE_3:
nr_clear_queues(sk);
sk->protinfo.nr->n2count = 0;
nr_write_internal(sk, NR_DISCREQ);
- sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
- sk->protinfo.nr->t2timer = 0;
- sk->protinfo.nr->t4timer = 0;
+ nr_start_t1timer(sk);
+ nr_stop_t2timer(sk);
+ nr_stop_t4timer(sk);
+ nr_stop_idletimer(sk);
sk->protinfo.nr->state = NR_STATE_2;
sk->state = TCP_CLOSE;
sk->shutdown |= SEND_SHUTDOWN;
@@ -704,9 +691,12 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
/* Move to connecting socket, start sending Connect Requests */
sock->state = SS_CONNECTING;
sk->state = TCP_SYN_SENT;
+
nr_establish_data_link(sk);
+
sk->protinfo.nr->state = NR_STATE_1;
- nr_set_timer(sk);
+
+ nr_start_heartbeat(sk);
/* Now the loop */
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
@@ -838,13 +828,13 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
circuit_index = skb->data[15];
circuit_id = skb->data[16];
- frametype = skb->data[19];
+ frametype = skb->data[19] & 0x0F;
#ifdef CONFIG_INET
/*
* Check for an incoming IP over NET/ROM frame.
*/
- if ((frametype & 0x0F) == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
+ if (frametype == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
skb->h.raw = skb->data;
@@ -856,11 +846,11 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
* Find an existing socket connection, based on circuit ID, if it's
* a Connect Request base it on their circuit ID.
*/
- if (((frametype & 0x0F) != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) ||
- ((frametype & 0x0F) == NR_CONNREQ && (sk = nr_find_peer(circuit_index, circuit_id)) != NULL)) {
+ if ((frametype != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) ||
+ (frametype == NR_CONNREQ && (sk = nr_find_peer(circuit_index, circuit_id)) != NULL)) {
skb->h.raw = skb->data;
- if ((frametype & 0x0F) == NR_CONNACK && skb->len == 22)
+ if (frametype == NR_CONNACK && skb->len == 22)
sk->protinfo.nr->bpqext = 1;
else
sk->protinfo.nr->bpqext = 0;
@@ -868,8 +858,16 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
return nr_process_rx_frame(sk, skb);
}
- if ((frametype & 0x0F) != NR_CONNREQ)
- return 0;
+ switch (frametype) {
+ case NR_CONNREQ:
+ break;
+ case NR_DISCREQ:
+ case NR_DISCACK:
+ return 0;
+ default:
+ nr_transmit_dm(skb);
+ return 0;
+ }
sk = nr_find_listener(dest);
@@ -905,8 +903,8 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
/* L4 timeout negotiation */
if (skb->len == 37) {
timeout = skb->data[36] * 256 + skb->data[35];
- if (timeout * NR_SLOWHZ < make->protinfo.nr->t1)
- make->protinfo.nr->t1 = timeout * NR_SLOWHZ;
+ if (timeout * HZ < make->protinfo.nr->t1)
+ make->protinfo.nr->t1 = timeout * HZ;
make->protinfo.nr->bpqext = 1;
} else {
make->protinfo.nr->bpqext = 0;
@@ -927,7 +925,8 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
skb_queue_head(&sk->receive_queue, skb);
- nr_set_timer(make);
+ nr_start_heartbeat(make);
+ nr_start_idletimer(make);
if (!sk->dead)
sk->data_ready(sk, skb->len);
@@ -973,6 +972,7 @@ static int nr_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct s
sax.sax25_family = AF_NETROM;
sax.sax25_call = sk->protinfo.nr->dest_addr;
}
+
SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n");
/* Build a packet */
@@ -1074,37 +1074,35 @@ static int nr_shutdown(struct socket *sk, int how)
static int nr_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(int))) != 0)
- return err;
+ case TIOCOUTQ: {
+ long amount;
amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
if (amount < 0)
amount = 0;
- put_user(amount, (int *)arg);
+ if (put_user(amount, (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(int))) != 0)
- return err;
- put_user(amount, (int *)arg);
+ amount = skb->len;
+ if (put_user(amount, (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;
@@ -1146,7 +1144,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
cli();
- len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 n2 wnd Snd-Q Rcv-Q\n");
+ len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q\n");
for (s = nr_list; s != NULL; s = s->next) {
if ((dev = s->protinfo.nr->device) == NULL)
@@ -1158,20 +1156,30 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int
ax2asc(&s->protinfo.nr->user_addr));
len += sprintf(buffer + len, "%-9s ",
ax2asc(&s->protinfo.nr->dest_addr));
- len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3d/%03d %2d/%02d %2d/%02d %3d %5d %5d\n",
+ len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d\n",
ax2asc(&s->protinfo.nr->source_addr),
- devname, s->protinfo.nr->my_index, s->protinfo.nr->my_id,
- s->protinfo.nr->your_index, s->protinfo.nr->your_id,
+ devname,
+ s->protinfo.nr->my_index,
+ s->protinfo.nr->my_id,
+ s->protinfo.nr->your_index,
+ s->protinfo.nr->your_id,
s->protinfo.nr->state,
- s->protinfo.nr->vs, s->protinfo.nr->vr, s->protinfo.nr->va,
- s->protinfo.nr->t1timer / NR_SLOWHZ,
- s->protinfo.nr->t1 / NR_SLOWHZ,
- s->protinfo.nr->t2timer / NR_SLOWHZ,
- s->protinfo.nr->t2 / NR_SLOWHZ,
+ s->protinfo.nr->vs,
+ s->protinfo.nr->vr,
+ s->protinfo.nr->va,
+ ax25_display_timer(&s->protinfo.nr->t1timer) / HZ,
+ s->protinfo.nr->t1 / HZ,
+ ax25_display_timer(&s->protinfo.nr->t2timer) / HZ,
+ s->protinfo.nr->t2 / HZ,
+ ax25_display_timer(&s->protinfo.nr->t4timer) / HZ,
+ s->protinfo.nr->t4 / HZ,
+ ax25_display_timer(&s->protinfo.nr->idletimer) / (60 * HZ),
+ s->protinfo.nr->idle / (60 * HZ),
s->protinfo.nr->n2count,
s->protinfo.nr->n2,
s->protinfo.nr->window,
- atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc));
+ atomic_read(&s->wmem_alloc),
+ atomic_read(&s->rmem_alloc));
pos = begin + len;
@@ -1269,7 +1277,7 @@ __initfunc(void nr_proto_init(struct net_proto *pro))
sock_register(&nr_family_ops);
register_netdevice_notifier(&nr_dev_notifier);
- printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.6 for AX25.035 Linux 2.1\n");
+ printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.1\n");
ax25_protocol_register(AX25_P_NETROM, nr_route_frame);
ax25_linkfail_register(nr_link_failed);
diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
index 2d88bec2b..f7b617dcc 100644
--- a/net/netrom/nr_dev.c
+++ b/net/netrom/nr_dev.c
@@ -1,5 +1,5 @@
/*
- * NET/ROM release 006
+ * NET/ROM release 007
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
diff --git a/net/netrom/nr_in.c b/net/netrom/nr_in.c
index c13e92666..a0d3148c2 100644
--- a/net/netrom/nr_in.c
+++ b/net/netrom/nr_in.c
@@ -1,5 +1,5 @@
/*
- * NET/ROM release 006
+ * NET/ROM release 007
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -21,6 +21,7 @@
* Darryl(G7LED) Added missing INFO with NAK case, optimized
* INFOACK handling, removed reconnect on error.
* NET/ROM 006 Jonathan(G4KLX) Hdrincl removal changes.
+ * NET/ROM 007 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -54,6 +55,8 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
+ nr_start_idletimer(sk);
+
if (more) {
sk->protinfo.nr->fraglen += skb->len;
skb_queue_tail(&sk->protinfo.nr->frag_queue, skb);
@@ -90,11 +93,10 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype
switch (frametype) {
case NR_CONNACK:
+ nr_stop_t1timer(sk);
+ nr_start_idletimer(sk);
sk->protinfo.nr->your_index = skb->data[17];
sk->protinfo.nr->your_id = skb->data[18];
- sk->protinfo.nr->t1timer = 0;
- sk->protinfo.nr->t2timer = 0;
- sk->protinfo.nr->t4timer = 0;
sk->protinfo.nr->vs = 0;
sk->protinfo.nr->va = 0;
sk->protinfo.nr->vr = 0;
@@ -103,20 +105,12 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype
sk->protinfo.nr->n2count = 0;
sk->protinfo.nr->window = skb->data[20];
sk->state = TCP_ESTABLISHED;
- /* For WAIT_SABM connections we will produce an accept ready socket here */
if (!sk->dead)
sk->state_change(sk);
break;
case NR_CONNACK | NR_CHOKE_FLAG:
- nr_clear_queues(sk);
- sk->protinfo.nr->state = NR_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = ECONNREFUSED;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ nr_disconnect(sk, ECONNREFUSED);
break;
default:
@@ -139,13 +133,7 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype
nr_write_internal(sk, NR_DISCACK);
case NR_DISCACK:
- sk->protinfo.nr->state = NR_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = 0;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ nr_disconnect(sk, 0);
break;
default:
@@ -178,26 +166,12 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
break;
case NR_DISCREQ:
- nr_clear_queues(sk);
nr_write_internal(sk, NR_DISCACK);
- sk->protinfo.nr->state = NR_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = 0;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ nr_disconnect(sk, 0);
break;
case NR_DISCACK:
- nr_clear_queues(sk);
- sk->protinfo.nr->state = NR_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = ECONNRESET;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ nr_disconnect(sk, ECONNRESET);
break;
case NR_INFOACK:
@@ -206,10 +180,10 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
if (frametype & NR_CHOKE_FLAG) {
sk->protinfo.nr->condition |= NR_COND_PEER_RX_BUSY;
- sk->protinfo.nr->t4timer = sk->protinfo.nr->t4;
+ nr_start_t4timer(sk);
} else {
sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
- sk->protinfo.nr->t4timer = 0;
+ nr_stop_t4timer(sk);
}
if (!nr_validate_nr(sk, nr)) {
break;
@@ -236,10 +210,10 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG:
if (frametype & NR_CHOKE_FLAG) {
sk->protinfo.nr->condition |= NR_COND_PEER_RX_BUSY;
- sk->protinfo.nr->t4timer = sk->protinfo.nr->t4;
+ nr_start_t4timer(sk);
} else {
sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
- sk->protinfo.nr->t4timer = 0;
+ nr_stop_t4timer(sk);
}
if (nr_validate_nr(sk, nr)) {
if (frametype & NR_NAK_FLAG) {
@@ -286,8 +260,8 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
nr_enquiry_response(sk);
} else {
if (!(sk->protinfo.nr->condition & NR_COND_ACK_PENDING)) {
- sk->protinfo.nr->t2timer = sk->protinfo.nr->t2;
sk->protinfo.nr->condition |= NR_COND_ACK_PENDING;
+ nr_start_t2timer(sk);
}
}
break;
@@ -307,8 +281,6 @@ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
if (sk->protinfo.nr->state == NR_STATE_0)
return 0;
- del_timer(&sk->timer);
-
frametype = skb->data[19];
switch (sk->protinfo.nr->state) {
@@ -323,7 +295,7 @@ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
break;
}
- nr_set_timer(sk);
+ nr_kick(sk);
return queued;
}
diff --git a/net/netrom/nr_out.c b/net/netrom/nr_out.c
index 7c053b482..4c3eb61d8 100644
--- a/net/netrom/nr_out.c
+++ b/net/netrom/nr_out.c
@@ -1,5 +1,5 @@
/*
- * NET/ROM release 006
+ * NET/ROM release 007
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -13,6 +13,7 @@
* 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.
+ * NET/ROM 007 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -83,8 +84,7 @@ void nr_output(struct sock *sk, struct sk_buff *skb)
skb_queue_tail(&sk->write_queue, skb); /* Throw it on the queue */
}
- if (sk->protinfo.nr->state == NR_STATE_3)
- nr_kick(sk);
+ nr_kick(sk);
}
/*
@@ -102,6 +102,8 @@ static void nr_send_iframe(struct sock *sk, struct sk_buff *skb)
if (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY)
skb->data[4] |= NR_CHOKE_FLAG;
+ nr_start_idletimer(sk);
+
nr_transmit_buffer(sk, skb);
}
@@ -125,7 +127,8 @@ void nr_send_nak_frame(struct sock *sk)
sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
sk->protinfo.nr->vl = sk->protinfo.nr->vr;
- sk->protinfo.nr->t1timer = 0;
+
+ nr_stop_t1timer(sk);
}
void nr_kick(struct sock *sk)
@@ -133,57 +136,60 @@ void nr_kick(struct sock *sk)
struct sk_buff *skb, *skbn;
unsigned short start, end;
- del_timer(&sk->timer);
+ if (sk->protinfo.nr->state != NR_STATE_3)
+ return;
+
+ if (sk->protinfo.nr->condition & NR_COND_PEER_RX_BUSY)
+ return;
+
+ if (skb_peek(&sk->write_queue) == NULL)
+ return;
start = (skb_peek(&sk->protinfo.nr->ack_queue) == NULL) ? sk->protinfo.nr->va : sk->protinfo.nr->vs;
end = (sk->protinfo.nr->va + sk->protinfo.nr->window) % NR_MODULUS;
- if (!(sk->protinfo.nr->condition & NR_COND_PEER_RX_BUSY) &&
- start != end &&
- skb_peek(&sk->write_queue) != NULL) {
-
- sk->protinfo.nr->vs = start;
+ if (start == end)
+ return;
- /*
- * Transmit data until either we're out of data to send or
- * the window is full.
- */
+ sk->protinfo.nr->vs = start;
- /*
- * Dequeue the frame and copy it.
- */
- skb = skb_dequeue(&sk->write_queue);
+ /*
+ * Transmit data until either we're out of data to send or
+ * the window is full.
+ */
- do {
- if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
- skb_queue_head(&sk->write_queue, skb);
- break;
- }
+ /*
+ * Dequeue the frame and copy it.
+ */
+ skb = skb_dequeue(&sk->write_queue);
- skb_set_owner_w(skbn, sk);
+ do {
+ if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+ skb_queue_head(&sk->write_queue, skb);
+ break;
+ }
- /*
- * Transmit the frame copy.
- */
- nr_send_iframe(sk, skbn);
+ skb_set_owner_w(skbn, sk);
- sk->protinfo.nr->vs = (sk->protinfo.nr->vs + 1) % NR_MODULUS;
+ /*
+ * Transmit the frame copy.
+ */
+ nr_send_iframe(sk, skbn);
- /*
- * Requeue the original data frame.
- */
- skb_queue_tail(&sk->protinfo.nr->ack_queue, skb);
+ sk->protinfo.nr->vs = (sk->protinfo.nr->vs + 1) % NR_MODULUS;
- } while (sk->protinfo.nr->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
+ /*
+ * Requeue the original data frame.
+ */
+ skb_queue_tail(&sk->protinfo.nr->ack_queue, skb);
- sk->protinfo.nr->vl = sk->protinfo.nr->vr;
- sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
+ } while (sk->protinfo.nr->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
- if (sk->protinfo.nr->t1timer == 0)
- sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
- }
+ sk->protinfo.nr->vl = sk->protinfo.nr->vr;
+ sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
- nr_set_timer(sk);
+ if (!nr_t1timer_running(sk))
+ nr_start_t1timer(sk);
}
void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb)
@@ -211,13 +217,7 @@ void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb)
if (!nr_route_frame(skb, NULL)) {
kfree_skb(skb, FREE_WRITE);
-
- sk->state = TCP_CLOSE;
- sk->err = ENETUNREACH;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ nr_disconnect(sk, ENETUNREACH);
}
}
@@ -233,8 +233,10 @@ void nr_establish_data_link(struct sock *sk)
nr_write_internal(sk, NR_CONNREQ);
- sk->protinfo.nr->t2timer = 0;
- sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
+ nr_stop_t2timer(sk);
+ nr_stop_t4timer(sk);
+ nr_stop_idletimer(sk);
+ nr_start_t1timer(sk);
}
/*
@@ -261,12 +263,12 @@ void nr_check_iframes_acked(struct sock *sk, unsigned short nr)
{
if (sk->protinfo.nr->vs == nr) {
nr_frames_acked(sk, nr);
- sk->protinfo.nr->t1timer = 0;
+ nr_stop_t1timer(sk);
sk->protinfo.nr->n2count = 0;
} else {
if (sk->protinfo.nr->va != nr) {
nr_frames_acked(sk, nr);
- sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
+ nr_start_t1timer(sk);
}
}
}
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index 41399a53c..ffbb240c4 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -1,5 +1,5 @@
/*
- * NET/ROM release 006
+ * NET/ROM release 007
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -93,6 +93,7 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
nr_neigh->callsign = *ax25;
nr_neigh->digipeat = NULL;
+ nr_neigh->ax25 = NULL;
nr_neigh->dev = dev;
nr_neigh->quality = sysctl_netrom_default_path_quality;
nr_neigh->locked = 0;
@@ -372,6 +373,7 @@ static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct dev
nr_neigh->callsign = *callsign;
nr_neigh->digipeat = NULL;
+ nr_neigh->ax25 = NULL;
nr_neigh->dev = dev;
nr_neigh->quality = quality;
nr_neigh->locked = 1;
@@ -582,7 +584,7 @@ static ax25_digi *nr_call_to_digi(int ndigis, ax25_address *digipeaters)
}
ax25_digi.ndigi = ndigis;
- ax25_digi.lastrepeat = 0;
+ ax25_digi.lastrepeat = -1;
return &ax25_digi;
}
@@ -594,14 +596,12 @@ int nr_rt_ioctl(unsigned int cmd, void *arg)
{
struct nr_route_struct nr_route;
struct device *dev;
- int err;
switch (cmd) {
case SIOCADDRT:
- if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
- return err;
- copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct));
+ if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
+ return -EFAULT;
if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
return -EINVAL;
if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS)
@@ -623,9 +623,8 @@ int nr_rt_ioctl(unsigned int cmd, void *arg)
}
case SIOCDELRT:
- if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0)
- return err;
- copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct));
+ if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
+ return -EFAULT;
if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
return -EINVAL;
switch (nr_route.type) {
@@ -653,17 +652,19 @@ int nr_rt_ioctl(unsigned int cmd, void *arg)
* A level 2 link has timed out, therefore it appears to be a poor link,
* then don't use that neighbour until it is reset.
*/
-void nr_link_failed(ax25_address *callsign, struct device *dev)
+void nr_link_failed(ax25_cb *ax25, int reason)
{
struct nr_neigh *nr_neigh;
struct nr_node *nr_node;
for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
- if (ax25cmp(&nr_neigh->callsign, callsign) == 0 && nr_neigh->dev == dev)
+ if (nr_neigh->ax25 == ax25)
break;
if (nr_neigh == NULL) return;
+ nr_neigh->ax25 = NULL;
+
if (++nr_neigh->failed < sysctl_netrom_link_fails_count) return;
for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
@@ -724,7 +725,9 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
dptr = skb_push(skb, 1);
*dptr = AX25_P_NETROM;
- return ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
+ nr_neigh->ax25 = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
+
+ return (nr_neigh->ax25 != NULL);
}
int nr_nodes_get_info(char *buffer, char **start, off_t offset,
diff --git a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c
index 5eae25279..d31141876 100644
--- a/net/netrom/nr_subr.c
+++ b/net/netrom/nr_subr.c
@@ -1,5 +1,5 @@
/*
- * NET/ROM release 006
+ * NET/ROM release 007
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -12,6 +12,7 @@
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_subr.c
* NET/ROM 003 Jonathan(G4KLX) Added G8BPQ NET/ROM extensions.
+ * NET/ROM 007 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -172,7 +173,7 @@ void nr_write_internal(struct sock *sk, int frametype)
switch (frametype & 0x0F) {
case NR_CONNREQ:
- timeout = sk->protinfo.nr->t1 / NR_SLOWHZ;
+ timeout = sk->protinfo.nr->t1 / HZ;
*dptr++ = sk->protinfo.nr->my_index;
*dptr++ = sk->protinfo.nr->my_id;
*dptr++ = 0;
@@ -268,4 +269,25 @@ void nr_transmit_dm(struct sk_buff *skb)
kfree_skb(skbn, FREE_WRITE);
}
+void nr_disconnect(struct sock *sk, int reason)
+{
+ nr_stop_t1timer(sk);
+ nr_stop_t2timer(sk);
+ nr_stop_t4timer(sk);
+ nr_stop_idletimer(sk);
+
+ nr_clear_queues(sk);
+
+ sk->protinfo.nr->state = NR_STATE_0;
+
+ 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/netrom/nr_timer.c b/net/netrom/nr_timer.c
index cc96f26dd..b3fbd012e 100644
--- a/net/netrom/nr_timer.c
+++ b/net/netrom/nr_timer.c
@@ -1,5 +1,5 @@
/*
- * NET/ROM release 006
+ * NET/ROM release 007
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -11,6 +11,8 @@
*
* History
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_timer.c
+ * NET/ROM 007 Jonathan(G4KLX) New timer architecture.
+ * Implemented idle timer.
*/
#include <linux/config.h>
@@ -37,42 +39,110 @@
#include <linux/interrupt.h>
#include <net/netrom.h>
-static void nr_timer(unsigned long);
+static void nr_heartbeat_expiry(unsigned long);
+static void nr_t1timer_expiry(unsigned long);
+static void nr_t2timer_expiry(unsigned long);
+static void nr_t4timer_expiry(unsigned long);
+static void nr_idletimer_expiry(unsigned long);
-/*
- * Linux set timer
- */
-void nr_set_timer(struct sock *sk)
+void nr_start_t1timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.nr->t1timer);
+
+ sk->protinfo.nr->t1timer.data = (unsigned long)sk;
+ sk->protinfo.nr->t1timer.function = &nr_t1timer_expiry;
+ sk->protinfo.nr->t1timer.expires = jiffies + sk->protinfo.nr->t1;
+
+ add_timer(&sk->protinfo.nr->t1timer);
+}
+
+void nr_start_t2timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.nr->t2timer);
+
+ sk->protinfo.nr->t2timer.data = (unsigned long)sk;
+ sk->protinfo.nr->t2timer.function = &nr_t2timer_expiry;
+ sk->protinfo.nr->t2timer.expires = jiffies + sk->protinfo.nr->t2;
+
+ add_timer(&sk->protinfo.nr->t2timer);
+}
+
+void nr_start_t4timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.nr->t4timer);
+
+ sk->protinfo.nr->t4timer.data = (unsigned long)sk;
+ sk->protinfo.nr->t4timer.function = &nr_t4timer_expiry;
+ sk->protinfo.nr->t4timer.expires = jiffies + sk->protinfo.nr->t4;
+
+ add_timer(&sk->protinfo.nr->t4timer);
+}
+
+void nr_start_idletimer(struct sock *sk)
{
- unsigned long flags;
+ del_timer(&sk->protinfo.nr->idletimer);
+
+ if (sk->protinfo.nr->idle > 0) {
+ sk->protinfo.nr->idletimer.data = (unsigned long)sk;
+ sk->protinfo.nr->idletimer.function = &nr_idletimer_expiry;
+ sk->protinfo.nr->idletimer.expires = jiffies + sk->protinfo.nr->idle;
+
+ add_timer(&sk->protinfo.nr->idletimer);
+ }
+}
- save_flags(flags); cli();
+void nr_start_heartbeat(struct sock *sk)
+{
del_timer(&sk->timer);
- restore_flags(flags);
sk->timer.data = (unsigned long)sk;
- sk->timer.function = &nr_timer;
- sk->timer.expires = jiffies + (HZ / 10);
+ sk->timer.function = &nr_heartbeat_expiry;
+ sk->timer.expires = jiffies + 5 * HZ;
add_timer(&sk->timer);
}
-/*
- * NET/ROM TIMER
- *
- * This routine is called every 100ms. Decrement timer by this
- * amount - if expired then process the event.
- */
-static void nr_timer(unsigned long param)
+void nr_stop_t1timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.nr->t1timer);
+}
+
+void nr_stop_t2timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.nr->t2timer);
+}
+
+void nr_stop_t4timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.nr->t4timer);
+}
+
+void nr_stop_idletimer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.nr->idletimer);
+}
+
+void nr_stop_heartbeat(struct sock *sk)
+{
+ del_timer(&sk->timer);
+}
+
+int nr_t1timer_running(struct sock *sk)
+{
+ return (sk->protinfo.nr->t1timer.prev != NULL ||
+ sk->protinfo.nr->t1timer.next != NULL);
+}
+
+static void nr_heartbeat_expiry(unsigned long param)
{
struct sock *sk = (struct sock *)param;
switch (sk->protinfo.nr->state) {
+
case NR_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);
nr_destroy_socket(sk);
return;
}
@@ -90,45 +160,63 @@ static void nr_timer(unsigned long param)
nr_write_internal(sk, NR_INFOACK);
break;
}
- /*
- * Check for frames to transmit.
- */
- nr_kick(sk);
- break;
-
- default:
break;
}
- if (sk->protinfo.nr->t2timer > 0 && --sk->protinfo.nr->t2timer == 0) {
- if (sk->protinfo.nr->state == NR_STATE_3) {
- if (sk->protinfo.nr->condition & NR_COND_ACK_PENDING) {
- sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
- nr_enquiry_response(sk);
- }
- }
- }
+ nr_start_heartbeat(sk);
+}
- if (sk->protinfo.nr->t4timer > 0 && --sk->protinfo.nr->t4timer == 0) {
- sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
- }
+static void nr_t2timer_expiry(unsigned long param)
+{
+ struct sock *sk = (struct sock *)param;
- if (sk->protinfo.nr->t1timer == 0 || --sk->protinfo.nr->t1timer > 0) {
- nr_set_timer(sk);
- return;
+ if (sk->protinfo.nr->condition & NR_COND_ACK_PENDING) {
+ sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
+ nr_enquiry_response(sk);
}
+}
+
+static void nr_t4timer_expiry(unsigned long param)
+{
+ struct sock *sk = (struct sock *)param;
+
+ sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
+}
+
+static void nr_idletimer_expiry(unsigned long param)
+{
+ struct sock *sk = (struct sock *)param;
+
+ nr_clear_queues(sk);
+
+ sk->protinfo.nr->n2count = 0;
+ nr_write_internal(sk, NR_DISCREQ);
+ sk->protinfo.nr->state = NR_STATE_2;
+
+ nr_start_t1timer(sk);
+ nr_stop_t2timer(sk);
+ nr_stop_t4timer(sk);
+
+ sk->state = TCP_CLOSE;
+ sk->err = 0;
+ sk->shutdown |= SEND_SHUTDOWN;
+
+ if (!sk->dead)
+ sk->state_change(sk);
+
+ sk->dead = 1;
+}
+
+static void nr_t1timer_expiry(unsigned long param)
+{
+ struct sock *sk = (struct sock *)param;
switch (sk->protinfo.nr->state) {
+
case NR_STATE_1:
if (sk->protinfo.nr->n2count == sk->protinfo.nr->n2) {
- nr_clear_queues(sk);
- sk->protinfo.nr->state = NR_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = ETIMEDOUT;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ nr_disconnect(sk, ETIMEDOUT);
+ return;
} else {
sk->protinfo.nr->n2count++;
nr_write_internal(sk, NR_CONNREQ);
@@ -137,14 +225,8 @@ static void nr_timer(unsigned long param)
case NR_STATE_2:
if (sk->protinfo.nr->n2count == sk->protinfo.nr->n2) {
- nr_clear_queues(sk);
- sk->protinfo.nr->state = NR_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = ETIMEDOUT;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ nr_disconnect(sk, ETIMEDOUT);
+ return;
} else {
sk->protinfo.nr->n2count++;
nr_write_internal(sk, NR_DISCREQ);
@@ -153,14 +235,8 @@ static void nr_timer(unsigned long param)
case NR_STATE_3:
if (sk->protinfo.nr->n2count == sk->protinfo.nr->n2) {
- nr_clear_queues(sk);
- sk->protinfo.nr->state = NR_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = ETIMEDOUT;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ nr_disconnect(sk, ETIMEDOUT);
+ return;
} else {
sk->protinfo.nr->n2count++;
nr_requeue_frames(sk);
@@ -168,9 +244,7 @@ static void nr_timer(unsigned long param)
break;
}
- sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
-
- nr_set_timer(sk);
+ nr_start_t1timer(sk);
}
#endif
diff --git a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c
index c6a415ee6..3ce3e71f2 100644
--- a/net/netrom/sysctl_net_netrom.c
+++ b/net/netrom/sysctl_net_netrom.c
@@ -17,16 +17,16 @@
static int min_quality[] = {0}, max_quality[] = {255};
static int min_obs[] = {0}, max_obs[] = {255};
static int min_ttl[] = {0}, max_ttl[] = {255};
-static int min_t1[] = {5 * NR_SLOWHZ};
-static int max_t1[] = {600 * NR_SLOWHZ};
+static int min_t1[] = {5 * HZ};
+static int max_t1[] = {600 * HZ};
static int min_n2[] = {2}, max_n2[] = {127};
-static int min_t2[] = {1 * NR_SLOWHZ};
-static int max_t2[] = {60 * NR_SLOWHZ};
-static int min_t4[] = {1 * NR_SLOWHZ};
-static int max_t4[] = {1000 * NR_SLOWHZ};
+static int min_t2[] = {1 * HZ};
+static int max_t2[] = {60 * HZ};
+static int min_t4[] = {1 * HZ};
+static int max_t4[] = {1000 * HZ};
static int min_window[] = {1}, max_window[] = {127};
-static int min_idle[] = {0 * NR_SLOWHZ};
-static int max_idle[] = {65535 * NR_SLOWHZ};
+static int min_idle[] = {0 * HZ};
+static int max_idle[] = {65535 * HZ};
static int min_route[] = {0}, max_route[] = {1};
static int min_fails[] = {1}, max_fails[] = {10};