summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-07-20 14:56:40 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-07-20 14:56:40 +0000
commite308faf24f68e262d92d294a01ddca7a17e76762 (patch)
tree22c47cb315811834861f013067878ff664e95abd /net
parent30c6397ce63178fcb3e7963ac247f0a03132aca9 (diff)
Sync with Linux 2.1.46.
Diffstat (limited to 'net')
-rw-r--r--net/Config.in2
-rw-r--r--net/README10
-rw-r--r--net/appletalk/ddp.c32
-rw-r--r--net/appletalk/sysctl_net_atalk.c16
-rw-r--r--net/ax25/af_ax25.c308
-rw-r--r--net/ax25/ax25_addr.c46
-rw-r--r--net/ax25/ax25_dev.c2
-rw-r--r--net/ax25/ax25_ds_in.c86
-rw-r--r--net/ax25/ax25_ds_subr.c14
-rw-r--r--net/ax25/ax25_ds_timer.c172
-rw-r--r--net/ax25/ax25_iface.c21
-rw-r--r--net/ax25/ax25_in.c17
-rw-r--r--net/ax25/ax25_ip.c31
-rw-r--r--net/ax25/ax25_out.c152
-rw-r--r--net/ax25/ax25_route.c80
-rw-r--r--net/ax25/ax25_std_in.c132
-rw-r--r--net/ax25/ax25_std_subr.c14
-rw-r--r--net/ax25/ax25_std_timer.c139
-rw-r--r--net/ax25/ax25_subr.c34
-rw-r--r--net/ax25/ax25_timer.c202
-rw-r--r--net/ax25/ax25_uid.c2
-rw-r--r--net/ax25/sysctl_net_ax25.c10
-rw-r--r--net/core/scm.c4
-rw-r--r--net/core/sysctl_net_core.c4
-rw-r--r--net/ipv4/Config.in1
-rw-r--r--net/ipv4/Makefile5
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/route.c9
-rw-r--r--net/ipv4/syncookies.c218
-rw-r--r--net/ipv4/sysctl_net_ipv4.c8
-rw-r--r--net/ipv4/tcp_input.c44
-rw-r--r--net/ipv4/tcp_ipv4.c196
-rw-r--r--net/ipv4/utils.c23
-rw-r--r--net/ipv6/icmp.c20
-rw-r--r--net/ipv6/tcp_ipv6.c54
-rw-r--r--net/lapb/lapb_iface.c55
-rw-r--r--net/lapb/lapb_in.c110
-rw-r--r--net/lapb/lapb_out.c22
-rw-r--r--net/lapb/lapb_subr.c8
-rw-r--r--net/lapb/lapb_timer.c123
-rw-r--r--net/netlink.c2
-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
-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
-rw-r--r--net/socket.c33
-rw-r--r--net/unix/af_unix.c53
-rw-r--r--net/unix/garbage.c2
-rw-r--r--net/unix/sysctl_net_unix.c4
-rw-r--r--net/wanrouter/patchlevel3
-rw-r--r--net/wanrouter/wanmain.c20
-rw-r--r--net/wanrouter/wanproc.c190
-rw-r--r--net/x25/af_x25.c168
-rw-r--r--net/x25/sysctl_net_x25.c4
-rw-r--r--net/x25/x25_dev.c4
-rw-r--r--net/x25/x25_facilities.c2
-rw-r--r--net/x25/x25_in.c62
-rw-r--r--net/x25/x25_link.c79
-rw-r--r--net/x25/x25_out.c52
-rw-r--r--net/x25/x25_route.c16
-rw-r--r--net/x25/x25_subr.c24
-rw-r--r--net/x25/x25_timer.c134
75 files changed, 2735 insertions, 2066 deletions
diff --git a/net/Config.in b/net/Config.in
index 4cd3619c3..d9ec19354 100644
--- a/net/Config.in
+++ b/net/Config.in
@@ -53,6 +53,6 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
# if [ "$CONFIG_LLC" = "y" ]; then
# bool 'Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI
# fi
- tristate 'WAN router' CONFIG_WAN_ROUTER
+ bool 'WAN router' CONFIG_WAN_ROUTER
fi
endmenu
diff --git a/net/README b/net/README
index a88ccfc5a..1cd7f5331 100644
--- a/net/README
+++ b/net/README
@@ -6,19 +6,19 @@ Code Section Bug Report Contact
802 [other ] alan@lxorguk.ukuu.org.uk
[token ring ] pnorton@cts.com
appletalk alan@lxorguk.ukuu.org.uk and netatalk@umich.edu
-ax25 jsn@cs.nott.ac.uk
+ax25 g4klx@g4klx.demon.co.uk
core alan@lxorguk.ukuu.org.uk
decnet SteveW@ACM.org
ethernet alan@lxorguk.ukuu.org.uk
ipv4 davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se
ipv6 davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se
ipx alan@lxorguk.ukuu.org.uk,greg@caldera.com
-lapb jsn@cs.nott.ac.uk
-netrom jsn@cs.nott.ac.uk
-rose jsn@cs.nott.ac.uk
+lapb g4klx@g4klx.demon.co.uk
+netrom g4klx@g4klx.demon.co.uk
+rose g4klx@g4klx.demon.co.uk
wanrouter genek@compuserve.com and dm@sangoma.com
unix alan@lxorguk.ukuu.org.uk
-x25 jsn@cs.nott.ac.uk
+x25 g4klx@g4klx.demon.co.uk
If in doubt contact me <alan@lxorguk.ukuu.org.uk> first.
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index de05f7047..a98ed27d3 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1540,11 +1540,33 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
ddp_dl->header_length + ddp->deh_len));
*((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* Mend the byte order */
+
/*
* Send the buffer onwards
*/
- skb=skb_unshare(skb, GFP_ATOMIC, FREE_READ);
+ /*
+ * Now we must always be careful. If it's come from
+ * localtalk to ethertalk it might not fit
+ *
+ * Order matters here: If a packet has to be copied
+ * to make a new headroom (rare hopefully) then it
+ * won't need unsharing.
+ *
+ * Note. ddp-> becomes invalid at the realloc.
+ */
+
+ if(skb_headroom(skb)<22)
+ /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */
+ skb=skb_realloc_headroom(skb, 32);
+ else
+ skb=skb_unshare(skb, GFP_ATOMIC, FREE_READ);
+
+ /*
+ * If the buffer didnt vanish into the lack of
+ * space bitbucket we can send it.
+ */
+
if(skb)
{
skb->arp = 1; /* Resolved */
@@ -1702,10 +1724,14 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
return(-EINVAL);
if(usat->sat_family != AF_APPLETALK)
return -EINVAL;
-#if 0 /* netatalk doesn't implement this check */
+ /* netatalk doesn't implement this check */
if(usat->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast)
+ {
+ printk(KERN_INFO "SO_BROADCAST: Fix your netatalk as it will break before 2.2\n");
+#if 0
return -EPERM;
#endif
+ }
}
else
{
@@ -1806,7 +1832,7 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
{
if((!(rt->flags&RTF_GATEWAY))&&(!(dev->flags&IFF_LOOPBACK)))
{
- struct sk_buff *skb2=skb_clone(skb, GFP_KERNEL);
+ struct sk_buff *skb2=skb_copy(skb, GFP_KERNEL);
if(skb2)
{
loopback=1;
diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c
index 6d5159ddc..c2c1a8c64 100644
--- a/net/appletalk/sysctl_net_atalk.c
+++ b/net/appletalk/sysctl_net_atalk.c
@@ -6,6 +6,7 @@
* Dynamic registration, added aarp entries. (5/30/97 Chris Horn)
*/
+#include <linux/config.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
@@ -14,7 +15,7 @@ extern int sysctl_aarp_tick_time;
extern int sysctl_aarp_retransmit_limit;
extern int sysctl_aarp_resolve_time;
-
+#ifdef CONFIG_SYSCTL
static ctl_table atalk_table[] = {
{NET_ATALK_AARP_EXPIRY_TIME, "aarp-expiry-time",
&sysctl_aarp_expiry_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
@@ -39,16 +40,25 @@ static ctl_table atalk_root_table[] = {
static struct ctl_table_header *atalk_table_header;
-inline void atalk_register_sysctl(void)
+void atalk_register_sysctl(void)
{
atalk_table_header = register_sysctl_table(atalk_root_table, 1);
}
-inline void atalk_unregister_sysctl(void)
+void atalk_unregister_sysctl(void)
{
unregister_sysctl_table(atalk_table_header);
}
+#else
+void atalk_register_sysctl(void)
+{
+}
+
+void atalk_unregister_sysctl(void)
+{
+}
+#endif
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 37b679600..8e5992747 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -92,6 +92,7 @@
* AX.25 036 Jonathan(G4KLX) Major restructuring.
* Joerg(DL1BKE) Fixed DAMA Slave.
* Jonathan(G4KLX) Fix widlcard listen parameter setting.
+ * AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -161,8 +162,7 @@ static void ax25_remove_socket(ax25_cb *ax25)
ax25_cb *s;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
if ((s = ax25_list) == ax25) {
ax25_list = s->next;
@@ -196,16 +196,8 @@ static void ax25_kill_by_device(struct device *dev)
for (s = ax25_list; s != NULL; s = s->next) {
if (s->ax25_dev == ax25_dev) {
- s->state = AX25_STATE_0;
s->ax25_dev = NULL;
- if (s->sk != NULL) {
- s->sk->state = TCP_CLOSE;
- s->sk->err = ENETUNREACH;
- s->sk->shutdown |= SEND_SHUTDOWN;
- if (!s->sk->dead)
- s->sk->state_change(s->sk);
- s->sk->dead = 1;
- }
+ ax25_disconnect(s, ENETUNREACH);
}
}
}
@@ -308,7 +300,7 @@ struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, in
* Find an AX.25 control block given both ends. It will only pick up
* floating AX.25 control blocks or non Raw socket bound control blocks.
*/
-ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, ax25_digi *digi, struct device *dev)
+ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi *digi, struct device *dev)
{
ax25_cb *s;
unsigned long flags;
@@ -319,11 +311,16 @@ ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, ax25_digi
for (s = ax25_list; s != NULL; s = s->next) {
if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET)
continue;
- if (ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->ax25_dev->dev == dev) {
- if (digi != NULL) {
- if (s->digipeat == NULL && digi->ndigi != 0)
+ if (s->ax25_dev == NULL)
+ continue;
+ if (ax25cmp(&s->source_addr, src_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->ax25_dev->dev == dev) {
+ if (digi != NULL && digi->ndigi != 0) {
+ if (s->digipeat == NULL)
continue;
- if (s->digipeat != NULL && ax25digicmp(s->digipeat, digi) != 0)
+ if (ax25digicmp(s->digipeat, digi) != 0)
+ continue;
+ } else {
+ if (s->digipeat != NULL && s->digipeat->ndigi != 0)
continue;
}
restore_flags(flags);
@@ -402,10 +399,13 @@ void ax25_destroy_socket(ax25_cb *ax25) /* 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(&ax25->timer);
+ ax25_stop_heartbeat(ax25);
+ ax25_stop_t1timer(ax25);
+ ax25_stop_t2timer(ax25);
+ ax25_stop_t3timer(ax25);
+ ax25_stop_idletimer(ax25);
ax25_remove_socket(ax25);
ax25_clear_queues(ax25); /* Flush the queues */
@@ -414,7 +414,7 @@ void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer
while ((skb = skb_dequeue(&ax25->sk->receive_queue)) != NULL) {
if (skb->sk != ax25->sk) { /* A pending connection */
skb->sk->dead = 1; /* Queue the unaccepted socket for death */
- ax25_set_timer(skb->sk->protinfo.ax25);
+ ax25_start_heartbeat(skb->sk->protinfo.ax25);
skb->sk->protinfo.ax25->state = AX25_STATE_0;
}
@@ -451,13 +451,9 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
struct ax25_ctl_struct ax25_ctl;
ax25_dev *ax25_dev;
ax25_cb *ax25;
- unsigned long flags;
- int err;
-
- if ((err = verify_area(VERIFY_READ, arg, sizeof(ax25_ctl))) != 0)
- return err;
- copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl));
+ if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)))
+ return -EFAULT;
if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL)
return -ENODEV;
@@ -467,22 +463,12 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
switch (ax25_ctl.cmd) {
case AX25_KILL:
- ax25_clear_queues(ax25);
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- ax25->state = AX25_STATE_0;
#ifdef CONFIG_AX25_DAMA_SLAVE
if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
ax25_dama_off(ax25);
#endif
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ENETRESET;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
- ax25_set_timer(ax25);
+ ax25_disconnect(ax25, ENETRESET);
break;
case AX25_WINDOW:
@@ -499,22 +485,14 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
case AX25_T1:
if (ax25_ctl.arg < 1)
return -EINVAL;
- ax25->rtt = (ax25_ctl.arg * AX25_SLOWHZ) / 2;
- ax25->t1 = ax25_ctl.arg * AX25_SLOWHZ;
- save_flags(flags); cli();
- if (ax25->t1timer > ax25->t1)
- ax25->t1timer = ax25->t1;
- restore_flags(flags);
+ ax25->rtt = (ax25_ctl.arg * HZ) / 2;
+ ax25->t1 = ax25_ctl.arg * HZ;
break;
case AX25_T2:
if (ax25_ctl.arg < 1)
return -EINVAL;
- save_flags(flags); cli();
- ax25->t2 = ax25_ctl.arg * AX25_SLOWHZ;
- if (ax25->t2timer > ax25->t2)
- ax25->t2timer = ax25->t2;
- restore_flags(flags);
+ ax25->t2 = ax25_ctl.arg * HZ;
break;
case AX25_N2:
@@ -527,21 +505,13 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
case AX25_T3:
if (ax25_ctl.arg < 0)
return -EINVAL;
- save_flags(flags); cli();
- ax25->t3 = ax25_ctl.arg * AX25_SLOWHZ;
- if (ax25->t3timer != 0)
- ax25->t3timer = ax25->t3;
- restore_flags(flags);
+ ax25->t3 = ax25_ctl.arg * HZ;
break;
case AX25_IDLE:
if (ax25_ctl.arg < 0)
return -EINVAL;
- save_flags(flags); cli();
- ax25->idle = ax25_ctl.arg * AX25_SLOWHZ * 60;
- if (ax25->idletimer != 0)
- ax25->idletimer = ax25->idle;
- restore_flags(flags);
+ ax25->idle = ax25_ctl.arg * 60 * HZ;
break;
case AX25_PACLEN:
@@ -622,6 +592,10 @@ ax25_cb *ax25_create_cb(void)
skb_queue_head_init(&ax25->reseq_queue);
init_timer(&ax25->timer);
+ init_timer(&ax25->t1timer);
+ init_timer(&ax25->t2timer);
+ init_timer(&ax25->t3timer);
+ init_timer(&ax25->idletimer);
ax25_fillin_cb(ax25, NULL);
@@ -664,13 +638,14 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op
case AX25_T1:
if (opt < 1)
return -EINVAL;
- sk->protinfo.ax25->rtt = (opt * AX25_SLOWHZ) / 2;
+ sk->protinfo.ax25->rtt = (opt * HZ) / 2;
+ sk->protinfo.ax25->t1 = opt * HZ;
return 0;
case AX25_T2:
if (opt < 1)
return -EINVAL;
- sk->protinfo.ax25->t2 = opt * AX25_SLOWHZ;
+ sk->protinfo.ax25->t2 = opt * HZ;
return 0;
case AX25_N2:
@@ -682,13 +657,13 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op
case AX25_T3:
if (opt < 1)
return -EINVAL;
- sk->protinfo.ax25->t3 = opt * AX25_SLOWHZ;
+ sk->protinfo.ax25->t3 = opt * HZ;
return 0;
case AX25_IDLE:
if (opt < 0)
return -EINVAL;
- sk->protinfo.ax25->idle = opt * AX25_SLOWHZ * 60;
+ sk->protinfo.ax25->idle = opt * 60 * HZ;
return 0;
case AX25_BACKOFF:
@@ -738,11 +713,11 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
break;
case AX25_T1:
- val = (sk->protinfo.ax25->t1 * 2) / AX25_SLOWHZ;
+ val = sk->protinfo.ax25->t1 / HZ;
break;
case AX25_T2:
- val = sk->protinfo.ax25->t2 / AX25_SLOWHZ;
+ val = sk->protinfo.ax25->t2 / HZ;
break;
case AX25_N2:
@@ -750,11 +725,11 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
break;
case AX25_T3:
- val = sk->protinfo.ax25->t3 / AX25_SLOWHZ;
+ val = sk->protinfo.ax25->t3 / HZ;
break;
case AX25_IDLE:
- val = sk->protinfo.ax25->idle / (AX25_SLOWHZ * 60);
+ val = sk->protinfo.ax25->idle / (60 * HZ);
break;
case AX25_BACKOFF:
@@ -963,22 +938,14 @@ static int ax25_release(struct socket *sock, struct socket *peer)
if (sk->type == SOCK_SEQPACKET) {
switch (sk->protinfo.ax25->state) {
case AX25_STATE_0:
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
- sk->state_change(sk);
- sk->dead = 1;
+ ax25_disconnect(sk->protinfo.ax25, 0);
ax25_destroy_socket(sk->protinfo.ax25);
break;
case AX25_STATE_1:
case AX25_STATE_2:
- ax25_clear_queues(sk->protinfo.ax25);
ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- sk->protinfo.ax25->state = AX25_STATE_0;
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
- sk->state_change(sk);
- sk->dead = 1;
+ ax25_disconnect(sk->protinfo.ax25, 0);
ax25_destroy_socket(sk->protinfo.ax25);
break;
@@ -990,31 +957,34 @@ static int ax25_release(struct socket *sock, struct socket *peer)
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- sk->protinfo.ax25->t3timer = 0;
+ ax25_stop_t2timer(sk->protinfo.ax25);
+ ax25_stop_t3timer(sk->protinfo.ax25);
+ ax25_stop_idletimer(sk->protinfo.ax25);
break;
#ifdef AX25_CONFIG_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
- sk->protinfo.ax25->t3timer = 0;
+ ax25_stop_t3timer(sk->protinfo.ax25);
break;
#endif
}
- sk->protinfo.ax25->t1timer = sk->protinfo.ax25->t1 = ax25_calculate_t1(sk->protinfo.ax25);
- sk->protinfo.ax25->state = AX25_STATE_2;
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
+ ax25_calculate_t1(sk->protinfo.ax25);
+ ax25_start_t1timer(sk->protinfo.ax25);
+ sk->protinfo.ax25->state = AX25_STATE_2;
+ sk->state = TCP_CLOSE;
+ sk->shutdown |= SEND_SHUTDOWN;
sk->state_change(sk);
- sk->dead = 1;
- sk->destroy = 1;
+ sk->dead = 1;
+ sk->destroy = 1;
break;
default:
break;
}
} else {
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
+ sk->state = TCP_CLOSE;
+ sk->shutdown |= SEND_SHUTDOWN;
sk->state_change(sk);
- sk->dead = 1;
+ sk->dead = 1;
ax25_destroy_socket(sk->protinfo.ax25);
}
@@ -1092,8 +1062,9 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
{
struct sock *sk = sock->sk;
- struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr;
- int err;
+ struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
+ ax25_digi *digi = NULL;
+ int ct = 0, err;
if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
sock->state = SS_CONNECTED;
@@ -1114,36 +1085,36 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
return -EINVAL;
- if (addr->sax25_family != AF_AX25)
+ if (fsa->fsa_ax25.sax25_family != AF_AX25)
return -EINVAL;
+ if (sk->protinfo.ax25->digipeat != NULL) {
+ kfree(sk->protinfo.ax25->digipeat);
+ sk->protinfo.ax25->digipeat = NULL;
+ }
+
/*
* Handle digi-peaters to be used.
*/
- if (addr_len == sizeof(struct full_sockaddr_ax25) && addr->sax25_ndigis != 0) {
- int ct = 0;
- struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)addr;
-
+ if (addr_len == sizeof(struct full_sockaddr_ax25) && fsa->fsa_ax25.sax25_ndigis != 0) {
/* Valid number of digipeaters ? */
- if (addr->sax25_ndigis < 1 || addr->sax25_ndigis > AX25_MAX_DIGIS)
+ if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS)
return -EINVAL;
- if (sk->protinfo.ax25->digipeat == NULL) {
- if ((sk->protinfo.ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL)
- return -ENOBUFS;
- }
+ if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL)
+ return -ENOBUFS;
- sk->protinfo.ax25->digipeat->ndigi = addr->sax25_ndigis;
- sk->protinfo.ax25->digipeat->lastrepeat = -1;
+ digi->ndigi = fsa->fsa_ax25.sax25_ndigis;
+ digi->lastrepeat = -1;
- while (ct < addr->sax25_ndigis) {
+ while (ct < fsa->fsa_ax25.sax25_ndigis) {
if ((fsa->fsa_digipeater[ct].ax25_call[6] & AX25_HBIT) && sk->protinfo.ax25->iamdigi) {
- sk->protinfo.ax25->digipeat->repeated[ct] = 1;
- sk->protinfo.ax25->digipeat->lastrepeat = ct;
+ digi->repeated[ct] = 1;
+ digi->lastrepeat = ct;
} else {
- sk->protinfo.ax25->digipeat->repeated[ct] = 0;
+ digi->repeated[ct] = 0;
}
- sk->protinfo.ax25->digipeat->calls[ct] = fsa->fsa_digipeater[ct];
+ digi->calls[ct] = fsa->fsa_digipeater[ct];
ct++;
}
}
@@ -1154,7 +1125,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
* been filled in, error if it hasn't.
*/
if (sk->zapped) {
- if ((err = ax25_rt_autobind(sk->protinfo.ax25, &addr->sax25_call)) < 0)
+ if ((err = ax25_rt_autobind(sk->protinfo.ax25, &fsa->fsa_ax25.sax25_call)) < 0)
return err;
ax25_fillin_cb(sk->protinfo.ax25, sk->protinfo.ax25->ax25_dev);
ax25_insert_socket(sk->protinfo.ax25);
@@ -1163,10 +1134,13 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
return -EHOSTUNREACH;
}
- if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &addr->sax25_call, NULL, sk->protinfo.ax25->ax25_dev->dev) != NULL)
+ if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi, sk->protinfo.ax25->ax25_dev->dev) != NULL) {
+ if (digi != NULL) kfree(digi);
return -EADDRINUSE; /* Already such a connection */
+ }
- sk->protinfo.ax25->dest_addr = addr->sax25_call;
+ sk->protinfo.ax25->dest_addr = fsa->fsa_ax25.sax25_call;
+ sk->protinfo.ax25->digipeat = digi;
/* First the easy one */
if (sk->type != SOCK_SEQPACKET) {
@@ -1198,7 +1172,8 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
}
sk->protinfo.ax25->state = AX25_STATE_1;
- ax25_set_timer(sk->protinfo.ax25); /* Start going SABM SABM until a UA or a give up and DM */
+
+ ax25_start_heartbeat(sk->protinfo.ax25);
/* Now the loop */
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
@@ -1532,38 +1507,35 @@ static int ax25_shutdown(struct socket *sk, int how)
static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
- struct ax25_info_struct ax25_info;
- 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;
- if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0)
- return err;
- put_user(amount, (int *)arg);
+ 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;
@@ -1572,22 +1544,22 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */
case SIOCAX25GETUID: {
struct sockaddr_ax25 sax25;
- if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(struct sockaddr_ax25))) != 0)
- return err;
- copy_from_user(&sax25, (void *)arg, sizeof(sax25));
+ if (copy_from_user(&sax25, (void *)arg, sizeof(sax25)))
+ return -EFAULT;
return ax25_uid_ioctl(cmd, &sax25);
}
- case SIOCAX25NOUID: /* Set the default policy (default/bar) */
- if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(unsigned long))) != 0)
- return err;
+ case SIOCAX25NOUID: { /* Set the default policy (default/bar) */
+ long amount;
if (!suser())
return -EPERM;
- get_user(amount, (long *)arg);
+ if (get_user(amount, (long *)arg))
+ return -EFAULT;
if (amount > AX25_NOUID_BLOCK)
return -EINVAL;
ax25_uid_policy = amount;
return 0;
+ }
case SIOCADDRT:
case SIOCDELRT:
@@ -1601,33 +1573,33 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return -EPERM;
return ax25_ctl_ioctl(cmd, (void *)arg);
- case SIOCAX25GETINFO:
- if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(ax25_info))) != 0)
- return err;
- ax25_info.t1 = sk->protinfo.ax25->t1;
- ax25_info.t2 = sk->protinfo.ax25->t2;
- ax25_info.t3 = sk->protinfo.ax25->t3;
- ax25_info.idle = sk->protinfo.ax25->idle;
+ case SIOCAX25GETINFO: {
+ struct ax25_info_struct ax25_info;
+ ax25_info.t1 = sk->protinfo.ax25->t1 / HZ;
+ ax25_info.t2 = sk->protinfo.ax25->t2 / HZ;
+ ax25_info.t3 = sk->protinfo.ax25->t3 / HZ;
+ ax25_info.idle = sk->protinfo.ax25->idle / (60 * HZ);
ax25_info.n2 = sk->protinfo.ax25->n2;
- ax25_info.t1timer = sk->protinfo.ax25->t1timer;
- ax25_info.t2timer = sk->protinfo.ax25->t2timer;
- ax25_info.t3timer = sk->protinfo.ax25->t3timer;
- ax25_info.idletimer = sk->protinfo.ax25->idletimer;
+ ax25_info.t1timer = ax25_display_timer(&sk->protinfo.ax25->t1timer) / HZ;
+ ax25_info.t2timer = ax25_display_timer(&sk->protinfo.ax25->t2timer) / HZ;
+ ax25_info.t3timer = ax25_display_timer(&sk->protinfo.ax25->t3timer) / HZ;
+ ax25_info.idletimer = ax25_display_timer(&sk->protinfo.ax25->idletimer) / (60 * HZ);
ax25_info.n2count = sk->protinfo.ax25->n2count;
ax25_info.state = sk->protinfo.ax25->state;
ax25_info.rcv_q = atomic_read(&sk->rmem_alloc);
ax25_info.snd_q = atomic_read(&sk->wmem_alloc);
- copy_to_user((void *)arg, &ax25_info, sizeof(ax25_info));
+ if (copy_to_user((void *)arg, &ax25_info, sizeof(ax25_info)))
+ return -EFAULT;
return 0;
+ }
case SIOCAX25ADDFWD:
case SIOCAX25DELFWD: {
struct ax25_fwd_struct ax25_fwd;
if (!suser())
return -EPERM;
- if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_fwd))) != 0)
- return err;
- copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd));
+ if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd)))
+ return -EFAULT;
return ax25_fwd_ioctl(cmd, &ax25_fwd);
}
@@ -1655,13 +1627,14 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length, i
{
ax25_cb *ax25;
const char *devname;
+ char callbuf[15];
int len = 0;
off_t pos = 0;
off_t begin = 0;
cli();
- len += sprintf(buffer, "dest_addr src_addr dev st vs vr va t1 t2 t3 idle n2 rtt wnd paclen Snd-Q Rcv-Q\n");
+ len += sprintf(buffer, "dest_addr src_addr dev st vs vr va t1 t2 t3 idle n2 rtt wnd paclen Snd-Q Rcv-Q\n");
for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) {
if (ax25->ax25_dev == NULL)
@@ -1671,20 +1644,28 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length, i
len += sprintf(buffer + len, "%-9s ",
ax2asc(&ax25->dest_addr));
- len += sprintf(buffer + len, "%-9s %-4s %2d %3d %3d %3d %3d/%03d %2d/%02d %3d/%03d %3d/%03d %2d/%02d %3d %3d %5d",
- ax2asc(&ax25->source_addr), devname,
+
+ sprintf(callbuf, "%s%c", ax2asc(&ax25->source_addr),
+ (ax25->iamdigi) ? '*' : ' ');
+
+ len += sprintf(buffer + len, "%-10s %-4s %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3lu %3d %5d",
+ callbuf,
+ devname,
ax25->state,
- ax25->vs, ax25->vr, ax25->va,
- ax25->t1timer / AX25_SLOWHZ,
- ax25->t1 / AX25_SLOWHZ,
- ax25->t2timer / AX25_SLOWHZ,
- ax25->t2 / AX25_SLOWHZ,
- ax25->t3timer / AX25_SLOWHZ,
- ax25->t3 / AX25_SLOWHZ,
- ax25->idletimer / (AX25_SLOWHZ * 60),
- ax25->idle / (AX25_SLOWHZ * 60),
- ax25->n2count, ax25->n2,
- ax25->rtt / AX25_SLOWHZ,
+ ax25->vs,
+ ax25->vr,
+ ax25->va,
+ ax25_display_timer(&ax25->t1timer) / HZ,
+ ax25->t1 / HZ,
+ ax25_display_timer(&ax25->t2timer) / HZ,
+ ax25->t2 / HZ,
+ ax25_display_timer(&ax25->t3timer) / HZ,
+ ax25->t3 / HZ,
+ ax25_display_timer(&ax25->idletimer) / (60 * HZ),
+ ax25->idle / (60 * HZ),
+ ax25->n2count,
+ ax25->n2,
+ ax25->rtt / HZ,
ax25->window,
ax25->paclen);
@@ -1764,7 +1745,7 @@ static struct notifier_block ax25_dev_notifier = {
EXPORT_SYMBOL(ax25_encapsulate);
EXPORT_SYMBOL(ax25_rebuild_header);
EXPORT_SYMBOL(ax25_findbyuid);
-EXPORT_SYMBOL(ax25_link_up);
+EXPORT_SYMBOL(ax25_find_cb);
EXPORT_SYMBOL(ax25_linkfail_register);
EXPORT_SYMBOL(ax25_linkfail_release);
EXPORT_SYMBOL(ax25_listen_register);
@@ -1777,6 +1758,7 @@ EXPORT_SYMBOL(ax25cmp);
EXPORT_SYMBOL(ax2asc);
EXPORT_SYMBOL(asc2ax);
EXPORT_SYMBOL(null_ax25_address);
+EXPORT_SYMBOL(ax25_display_timer);
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry proc_ax25_route = {
@@ -1815,7 +1797,7 @@ __initfunc(void ax25_proto_init(struct net_proto *pro))
proc_net_register(&proc_ax25_calls);
#endif
- printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.36 for Linux NET3.038 (Linux 2.1)\n");
+ printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.37 for Linux NET3.038 (Linux 2.1)\n");
}
#ifdef MODULE
diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c
index 77bfabe73..5daf92fa5 100644
--- a/net/ax25/ax25_addr.c
+++ b/net/ax25/ax25_addr.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -165,27 +165,23 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a
if (len < 14) return NULL;
- if (flags != NULL) {
- *flags = 0;
+ *flags = 0;
- if (buf[6] & AX25_CBIT)
- *flags = AX25_COMMAND;
- if (buf[13] & AX25_CBIT)
- *flags = AX25_RESPONSE;
- }
+ if (buf[6] & AX25_CBIT)
+ *flags = AX25_COMMAND;
+ if (buf[13] & AX25_CBIT)
+ *flags = AX25_RESPONSE;
if (dama != NULL)
*dama = ~buf[13] & AX25_DAMA_FLAG;
/* Copy to, from */
- if (dest != NULL)
- memcpy(dest, buf + 0, AX25_ADDR_LEN);
-
- if (src != NULL)
- memcpy(src, buf + 7, AX25_ADDR_LEN);
+ memcpy(dest, buf + 0, AX25_ADDR_LEN);
+ memcpy(src, buf + 7, AX25_ADDR_LEN);
buf += 2 * AX25_ADDR_LEN;
len -= 2 * AX25_ADDR_LEN;
+
digi->lastrepeat = -1;
digi->ndigi = 0;
@@ -193,15 +189,14 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a
if (d >= AX25_MAX_DIGIS) return NULL; /* Max of 6 digis */
if (len < 7) return NULL; /* Short packet */
- if (digi != NULL) {
- memcpy(&digi->calls[d], buf, AX25_ADDR_LEN);
- digi->ndigi = d + 1;
- if (buf[6] & AX25_HBIT) {
- digi->repeated[d] = 1;
- digi->lastrepeat = d;
- } else {
- digi->repeated[d] = 0;
- }
+ memcpy(&digi->calls[d], buf, AX25_ADDR_LEN);
+ digi->ndigi = d + 1;
+
+ if (buf[6] & AX25_HBIT) {
+ digi->repeated[d] = 1;
+ digi->lastrepeat = d;
+ } else {
+ digi->repeated[d] = 0;
}
buf += AX25_ADDR_LEN;
@@ -285,15 +280,15 @@ int ax25_addr_size(ax25_digi *dp)
*/
void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
{
- int ct = 0;
+ int ct;
out->ndigi = in->ndigi;
out->lastrepeat = in->ndigi - in->lastrepeat - 2;
/* Invert the digipeaters */
+ for (ct = 0; ct < in->ndigi; ct++) {
+ out->calls[ct] = in->calls[in->ndigi - ct - 1];
- while (ct < in->ndigi) {
- out->calls[ct] = in->calls[in->ndigi - ct - 1];
if (ct <= out->lastrepeat) {
out->calls[ct].ax25_call[6] |= AX25_HBIT;
out->repeated[ct] = 1;
@@ -301,7 +296,6 @@ void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
out->calls[ct].ax25_call[6] &= ~AX25_HBIT;
out->repeated[ct] = 0;
}
- ct++;
}
}
diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c
index 6468faf77..3f4f46ad4 100644
--- a/net/ax25/ax25_dev.c
+++ b/net/ax25/ax25_dev.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
diff --git a/net/ax25/ax25_ds_in.c b/net/ax25/ax25_ds_in.c
index 1394c9ab7..6b5e68236 100644
--- a/net/ax25/ax25_ds_in.c
+++ b/net/ax25/ax25_ds_in.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -18,6 +18,7 @@
* History
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_in.c
* Joerg(DL1BKE) Fixed it.
+ * AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -64,9 +65,9 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
case AX25_UA:
ax25_calculate_rtt(ax25);
- ax25->t1timer = 0;
- ax25->t3timer = ax25->t3;
- ax25->idletimer = ax25->idle;
+ ax25_stop_t1timer(ax25);
+ ax25_start_t3timer(ax25);
+ ax25_start_idletimer(ax25);
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
@@ -90,23 +91,11 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
break;
case AX25_DM:
- if (pf) {
- ax25_clear_queues(ax25);
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ECONNREFUSED;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
- }
+ if (pf) ax25_disconnect(ax25, ECONNREFUSED);
break;
default:
- if (pf)
- ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
+ if (pf) ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
break;
}
@@ -128,31 +117,15 @@ static int ax25_ds_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
case AX25_DISC:
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- ax25->state = AX25_STATE_0;
ax25_dama_off(ax25);
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = 0;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, 0);
break;
case AX25_DM:
case AX25_UA:
if (pf) {
- ax25->state = AX25_STATE_0;
ax25_dama_off(ax25);
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = 0;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, 0);
}
break;
@@ -187,10 +160,10 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ ax25_stop_t1timer(ax25);
+ ax25_start_t3timer(ax25);
+ ax25_start_idletimer(ax25);
ax25->condition = 0x00;
- ax25->t1timer = 0;
- ax25->t3timer = ax25->t3;
- ax25->idletimer = ax25->idle;
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
@@ -199,34 +172,14 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
break;
case AX25_DISC:
- ax25_clear_queues(ax25);
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- ax25->t3timer = 0;
- ax25->state = AX25_STATE_0;
ax25_dama_off(ax25);
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = 0;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, 0);
break;
case AX25_DM:
- ax25_clear_queues(ax25);
- ax25->t3timer = 0;
- ax25->state = AX25_STATE_0;
ax25_dama_off(ax25);
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ECONNRESET;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, ECONNRESET);
break;
case AX25_RR:
@@ -250,9 +203,9 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
ax25_calculate_rtt(ax25);
+ ax25_stop_t1timer(ax25);
+ ax25_start_t3timer(ax25);
ax25->n2count = 0;
- ax25->t1timer = 0;
- ax25->t3timer = ax25->t3;
ax25_requeue_frames(ax25);
if (type == AX25_COMMAND && pf)
ax25_ds_enquiry_response(ax25);
@@ -281,18 +234,15 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
if (ns == ax25->vr) {
ax25->vr = (ax25->vr + 1) % AX25_MODULUS;
queued = ax25_rx_iframe(ax25, skb);
- if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+ if (ax25->condition & AX25_COND_OWN_RX_BUSY)
ax25->vr = ns; /* ax25->vr - 1 */
- if (pf) ax25_ds_enquiry_response(ax25);
- break;
- }
ax25->condition &= ~AX25_COND_REJECT;
if (pf) {
ax25_ds_enquiry_response(ax25);
} else {
if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
- ax25->t2timer = ax25->t2;
ax25->condition |= AX25_COND_ACK_PENDING;
+ ax25_start_t2timer(ax25);
}
}
} else {
diff --git a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c
index 6037f16b4..89ca64f3f 100644
--- a/net/ax25/ax25_ds_subr.c
+++ b/net/ax25/ax25_ds_subr.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -19,6 +19,7 @@
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_out.c and ax25_subr.c.
* Joerg(DL1BKE) Changed ax25_ds_enquiry_response(),
* fixed ax25_dama_on() and ax25_dama_off().
+ * AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -91,7 +92,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
else
ax25->n2count = 0;
- ax25->t3timer = ax25->t3;
+ ax25_start_t3timer(ax25);
ax25_ds_set_timer(ax25->ax25_dev);
for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) {
@@ -114,7 +115,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2 || skb_peek(&ax25o->ack_queue) != NULL)
ax25_ds_t1_timeout(ax25o);
- ax25o->t3timer = ax25o->t3;
+ ax25_start_t3timer(ax25o);
}
}
@@ -122,9 +123,10 @@ void ax25_ds_establish_data_link(ax25_cb *ax25)
{
ax25->condition &= AX25_COND_DAMA_MODE;
ax25->n2count = 0;
- ax25->t3timer = ax25->t3;
- ax25->t2timer = 0;
- ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+ ax25_calculate_t1(ax25);
+ ax25_start_t1timer(ax25);
+ ax25_stop_t2timer(ax25);
+ ax25_start_t3timer(ax25);
}
/*
diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c
index 847be5790..841149996 100644
--- a/net/ax25/ax25_ds_timer.c
+++ b/net/ax25/ax25_ds_timer.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -12,6 +12,7 @@
* History
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_timer.c.
* Joerg(DL1BKE) Added DAMA Slave Timeout timer
+ * AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -93,41 +94,21 @@ static void ax25_ds_timeout(unsigned long arg)
if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE))
continue;
- ax25_link_failed(&ax25->dest_addr, ax25_dev->dev);
- ax25_clear_queues(ax25);
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- ax25->state = AX25_STATE_0;
-
- if (ax25->sk != NULL) {
- SOCK_DEBUG(ax25->sk, "AX.25 DAMA Slave Timeout\n");
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ETIMEDOUT;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
-
- ax25_set_timer(ax25); /* notify socket... */
+ ax25_disconnect(ax25, ETIMEDOUT);
}
ax25_dev_dama_off(ax25_dev);
}
-/*
- * AX.25 TIMER
- *
- * This routine is called every 100ms. Decrement timer by this
- * amount - if expired then process the event.
- */
-void ax25_ds_timer(ax25_cb *ax25)
+void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
{
switch (ax25->state) {
+
case AX25_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 (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
- del_timer(&ax25->timer);
ax25_destroy_socket(ax25);
return;
}
@@ -144,71 +125,51 @@ void ax25_ds_timer(ax25_cb *ax25)
}
}
break;
-
- default:
- break;
- }
-
- /* dl1bke 960114: T3 works much like the IDLE timeout, but
- * gets reloaded with every frame for this
- * connection.
- */
-
- if (ax25->t3timer > 0 && --ax25->t3timer == 0) {
- ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
- ax25_clear_queues(ax25);
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-
- ax25->state = AX25_STATE_0;
- ax25_dama_off(ax25);
-
- if (ax25->sk != NULL) {
- SOCK_DEBUG(ax25->sk, "AX.25 T3 Timeout\n");
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ETIMEDOUT;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
-
- ax25_set_timer(ax25);
-
- return;
}
- /* dl1bke 960228: close the connection when IDLE expires.
- * unlike T3 this timer gets reloaded only on
- * I frames.
- */
-
- if (ax25->idletimer > 0 && --ax25->idletimer == 0) {
- ax25_clear_queues(ax25);
-
- ax25->n2count = 0;
- ax25->t3timer = ax25->t3;
+ ax25_start_heartbeat(ax25);
+}
+
+/* dl1bke 960114: T3 works much like the IDLE timeout, but
+ * gets reloaded with every frame for this
+ * connection.
+ */
+void ax25_ds_t3timer_expiry(ax25_cb *ax25)
+{
+ ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+ ax25_dama_off(ax25);
+ ax25_disconnect(ax25, ETIMEDOUT);
+}
- /* state 1 or 2 should not happen, but... */
+/* dl1bke 960228: close the connection when IDLE expires.
+ * unlike T3 this timer gets reloaded only on
+ * I frames.
+ */
+void ax25_ds_idletimer_expiry(ax25_cb *ax25)
+{
+ ax25_clear_queues(ax25);
- if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2)
- ax25->state = AX25_STATE_0;
- else
- ax25->state = AX25_STATE_2;
+ ax25->n2count = 0;
- ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+ /* state 1 or 2 should not happen, but... */
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = 0;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- ax25->sk->destroy = 1;
- }
+ if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2)
+ ax25->state = AX25_STATE_0;
+ else
+ ax25->state = AX25_STATE_2;
+
+ ax25_calculate_t1(ax25);
+ ax25_start_t1timer(ax25);
+ ax25_start_t3timer(ax25);
+
+ if (ax25->sk != NULL) {
+ ax25->sk->state = TCP_CLOSE;
+ ax25->sk->err = 0;
+ ax25->sk->shutdown |= SEND_SHUTDOWN;
+ if (!ax25->sk->dead)
+ ax25->sk->state_change(ax25->sk);
+ ax25->sk->dead = 1;
}
-
- ax25_set_timer(ax25);
}
/* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC
@@ -222,20 +183,12 @@ void ax25_ds_timer(ax25_cb *ax25)
void ax25_ds_t1_timeout(ax25_cb *ax25)
{
switch (ax25->state) {
+
case AX25_STATE_1:
if (ax25->n2count == ax25->n2) {
if (ax25->modulus == AX25_MODULUS) {
- ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
- ax25_clear_queues(ax25);
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ETIMEDOUT;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, ETIMEDOUT);
+ return;
} else {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
@@ -253,19 +206,9 @@ void ax25_ds_t1_timeout(ax25_cb *ax25)
case AX25_STATE_2:
if (ax25->n2count == ax25->n2) {
- ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
- ax25_clear_queues(ax25);
- ax25->state = AX25_STATE_0;
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ETIMEDOUT;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, ETIMEDOUT);
+ return;
} else {
ax25->n2count++;
}
@@ -273,28 +216,17 @@ void ax25_ds_t1_timeout(ax25_cb *ax25)
case AX25_STATE_3:
if (ax25->n2count == ax25->n2) {
- ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
- ax25_clear_queues(ax25);
ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- SOCK_DEBUG(ax25->sk, "AX.25 link Failure\n");
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ETIMEDOUT;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, ETIMEDOUT);
+ return;
} else {
ax25->n2count++;
}
break;
}
- ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
-
- ax25_set_timer(ax25);
+ ax25_calculate_t1(ax25);
+ ax25_start_t1timer(ax25);
}
#endif
diff --git a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c
index d27a3af23..7e6ad845c 100644
--- a/net/ax25/ax25_iface.c
+++ b/net/ax25/ax25_iface.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -44,7 +44,7 @@ static struct protocol_struct {
static struct linkfail_struct {
struct linkfail_struct *next;
- void (*func)(ax25_address *, struct device *);
+ void (*func)(ax25_cb *, int);
} *linkfail_list = NULL;
static struct listen_struct {
@@ -114,7 +114,7 @@ void ax25_protocol_release(unsigned int pid)
restore_flags(flags);
}
-int ax25_linkfail_register(void (*func)(ax25_address *, struct device *))
+int ax25_linkfail_register(void (*func)(ax25_cb *, int))
{
struct linkfail_struct *linkfail;
unsigned long flags;
@@ -135,7 +135,7 @@ int ax25_linkfail_register(void (*func)(ax25_address *, struct device *))
return 1;
}
-void ax25_linkfail_release(void (*func)(ax25_address *, struct device *))
+void ax25_linkfail_release(void (*func)(ax25_cb *, int))
{
struct linkfail_struct *s, *linkfail = linkfail_list;
unsigned long flags;
@@ -248,21 +248,12 @@ int ax25_listen_mine(ax25_address *callsign, struct device *dev)
return 0;
}
-void ax25_link_failed(ax25_address *callsign, struct device *dev)
+void ax25_link_failed(ax25_cb *ax25, int reason)
{
struct linkfail_struct *linkfail;
for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next)
- (linkfail->func)(callsign, dev);
-}
-
-/*
- * Return the state of an AX.25 link given source, destination, and
- * device.
- */
-int ax25_link_up(ax25_address *src, ax25_address *dest, ax25_digi *digi, struct device *dev)
-{
- return ax25_find_cb(src, dest, digi, dev) != NULL;
+ (linkfail->func)(ax25, reason);
}
int ax25_protocol_is_registered(unsigned int pid)
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
index 2e6090d76..a17109bff 100644
--- a/net/ax25/ax25_in.c
+++ b/net/ax25/ax25_in.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -35,6 +35,7 @@
* AX.25 035 Hans(PE1AYX) Fixed interface to IP layer.
* AX.25 036 Jonathan(G4KLX) Move DAMA code into own file.
* Joerg(DL1BKE) Fixed DAMA Slave.
+ * AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -136,7 +137,7 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
if (skb == NULL) return 0;
- ax25->idletimer = ax25->idle;
+ ax25_start_idletimer(ax25);
pid = *skb->data;
@@ -193,8 +194,6 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i
if (ax25->state == AX25_STATE_0)
return 0;
- del_timer(&ax25->timer);
-
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
@@ -211,8 +210,6 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i
#endif
}
- ax25_set_timer(ax25);
-
return queued;
}
@@ -413,7 +410,6 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
}
ax25_fillin_cb(ax25, ax25_dev);
- ax25->idletimer = ax25->idle;
}
ax25->source_addr = dest;
@@ -453,12 +449,13 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
ax25_dama_on(ax25);
#endif
- ax25->t3timer = ax25->t3;
- ax25->state = AX25_STATE_3;
+ ax25->state = AX25_STATE_3;
ax25_insert_socket(ax25);
- ax25_set_timer(ax25);
+ ax25_start_heartbeat(ax25);
+ ax25_start_t3timer(ax25);
+ ax25_start_idletimer(ax25);
if (sk != NULL) {
if (!sk->dead)
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
index 009428fa9..d26f008dd 100644
--- a/net/ax25/ax25_ip.c
+++ b/net/ax25/ax25_ip.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -105,20 +105,25 @@ int ax25_encapsulate(struct sk_buff *skb, struct device *dev, unsigned short typ
int ax25_rebuild_header(struct sk_buff *skb)
{
struct sk_buff *ourskb;
- int mode;
unsigned char *bp = skb->data;
struct device *dev = skb->dev;
+ ax25_address *src, *dst;
+ ax25_route *route;
ax25_dev *ax25_dev;
+ dst = (ax25_address *)(bp + 1);
+ src = (ax25_address *)(bp + 8);
+
if (arp_find(bp + 1, skb))
return 1;
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
return 1;
+ route = ax25_rt_find_route(dst, dev);
+
if (bp[16] == AX25_P_IP) {
- mode = ax25_ip_mode_get((ax25_address *)(bp + 1), dev);
- if (mode == 'V' || (mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
+ if (route->ip_mode == 'V' || (route->ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
/*
* We copy the buffer and release the original thereby
* keeping it straight
@@ -146,7 +151,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */
- ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev);
+ ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], src, dst, route->digipeat, dev);
return 1;
}
@@ -160,15 +165,19 @@ int ax25_rebuild_header(struct sk_buff *skb)
bp[14] |= AX25_EBIT;
bp[14] |= AX25_SSSID_SPARE;
- if ((ourskb = ax25_dg_build_path(skb, (ax25_address *)(bp + 1), dev)) == NULL) {
- kfree_skb(skb, FREE_WRITE);
- return 1;
+ if (route->digipeat != NULL) {
+ if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
+ kfree_skb(skb, FREE_WRITE);
+ return 1;
+ }
+
+ skb = ourskb;
}
- ourskb->dev = dev;
- ourskb->priority = SOPRI_NORMAL;
+ skb->dev = dev;
+ skb->priority = SOPRI_NORMAL;
- ax25_queue_xmit(ourskb);
+ ax25_queue_xmit(skb);
return 1;
}
diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c
index db7207b28..4550302d7 100644
--- a/net/ax25/ax25_out.c
+++ b/net/ax25/ax25_out.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -26,6 +26,7 @@
* AX.25 I-Frames. Added PACLEN parameter.
* Joerg(DL1BKE) Fixed a problem with buffer allocation
* for fragments.
+ * AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -52,7 +53,7 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
-int ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct device *dev)
+ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct device *dev)
{
ax25_dev *ax25_dev;
ax25_cb *ax25;
@@ -65,15 +66,14 @@ int ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_add
*/
if ((ax25 = ax25_find_cb(src, dest, digi, dev)) != NULL) {
ax25_output(ax25, paclen, skb);
- ax25->idletimer = ax25->idle;
- return 1; /* It already existed */
+ return ax25; /* It already existed */
}
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
- return 0;
+ return NULL;
if ((ax25 = ax25_create_cb()) == NULL)
- return 0;
+ return NULL;
ax25_fillin_cb(ax25, ax25_dev);
@@ -83,11 +83,9 @@ int ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_add
if (digi != NULL) {
if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
ax25_free_cb(ax25);
- return 0;
+ return NULL;
}
*ax25->digipeat = *digi;
- } else {
- ax25_rt_build_path(ax25, dest, dev);
}
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
@@ -106,19 +104,15 @@ int ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_add
#endif
}
- /* idle timeouts only for mode vc connections */
-
- ax25->idletimer = ax25->idle;
-
ax25_insert_socket(ax25);
ax25->state = AX25_STATE_1;
- ax25_set_timer(ax25);
+ ax25_start_heartbeat(ax25);
ax25_output(ax25, paclen, skb);
- return 1; /* We had to create it */
+ return ax25; /* We had to create it */
}
/*
@@ -195,10 +189,8 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
}
if (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_STD_SIMPLEX ||
- ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_STD_DUPLEX) {
- if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4)
- ax25_kick(ax25);
- }
+ ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_STD_DUPLEX)
+ ax25_kick(ax25);
}
/*
@@ -228,6 +220,8 @@ static void ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit)
frame[1] |= (ax25->vr << 1);
}
+ ax25_start_idletimer(ax25);
+
ax25_transmit_buffer(ax25, skb, AX25_COMMAND);
}
@@ -237,76 +231,80 @@ void ax25_kick(ax25_cb *ax25)
int last = 1;
unsigned short start, end, next;
- del_timer(&ax25->timer);
+ if (ax25->state != AX25_STATE_3 && ax25->state != AX25_STATE_4)
+ return;
+
+ if (ax25->condition & AX25_COND_PEER_RX_BUSY)
+ return;
+
+ if (skb_peek(&ax25->write_queue) == NULL)
+ return;
start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs;
end = (ax25->va + ax25->window) % ax25->modulus;
- if (!(ax25->condition & AX25_COND_PEER_RX_BUSY) &&
- start != end &&
- skb_peek(&ax25->write_queue) != NULL) {
+ if (start == end)
+ return;
- ax25->vs = start;
+ ax25->vs = start;
- /*
- * Transmit data until either we're out of data to send or
- * the window is full. Send a poll on the final I frame if
- * the window is filled.
- */
+ /*
+ * Transmit data until either we're out of data to send or
+ * the window is full. Send a poll on the final I frame if
+ * the window is filled.
+ */
- /*
- * Dequeue the frame and copy it.
- */
- skb = skb_dequeue(&ax25->write_queue);
+ /*
+ * Dequeue the frame and copy it.
+ */
+ skb = skb_dequeue(&ax25->write_queue);
- do {
- if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
- skb_queue_head(&ax25->write_queue, skb);
- break;
- }
+ do {
+ if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+ skb_queue_head(&ax25->write_queue, skb);
+ break;
+ }
- if (skb->sk != NULL)
- skb_set_owner_w(skbn, skb->sk);
+ if (skb->sk != NULL)
+ skb_set_owner_w(skbn, skb->sk);
- next = (ax25->vs + 1) % ax25->modulus;
- last = (next == end);
+ next = (ax25->vs + 1) % ax25->modulus;
+ last = (next == end);
- /*
- * Transmit the frame copy.
- * bke 960114: do not set the Poll bit on the last frame
- * in DAMA mode.
- */
- switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
- break;
+ /*
+ * Transmit the frame copy.
+ * bke 960114: do not set the Poll bit on the last frame
+ * in DAMA mode.
+ */
+ switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
+ break;
#ifdef CONFIG_AX25_DAMA_SLAVE
- case AX25_PROTO_DAMA_SLAVE:
- ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
- break;
+ case AX25_PROTO_DAMA_SLAVE:
+ ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
+ break;
#endif
- }
+ }
- ax25->vs = next;
+ ax25->vs = next;
- /*
- * Requeue the original data frame.
- */
- skb_queue_tail(&ax25->ack_queue, skb);
+ /*
+ * Requeue the original data frame.
+ */
+ skb_queue_tail(&ax25->ack_queue, skb);
- } while (!last && (skb = skb_dequeue(&ax25->write_queue)) != NULL);
+ } while (!last && (skb = skb_dequeue(&ax25->write_queue)) != NULL);
- ax25->condition &= ~AX25_COND_ACK_PENDING;
+ ax25->condition &= ~AX25_COND_ACK_PENDING;
- if (ax25->t1timer == 0) {
- ax25->t3timer = 0;
- ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
- }
+ if (!ax25_t1timer_running(ax25)) {
+ ax25_stop_t3timer(ax25);
+ ax25_calculate_t1(ax25);
+ ax25_start_t1timer(ax25);
}
-
- ax25_set_timer(ax25);
}
void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
@@ -316,14 +314,7 @@ void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
int headroom;
if (ax25->ax25_dev == NULL) {
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ENETUNREACH;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, ENETUNREACH);
return;
}
@@ -381,12 +372,13 @@ void ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr)
if (ax25->vs == nr) {
ax25_frames_acked(ax25, nr);
ax25_calculate_rtt(ax25);
- ax25->t1timer = 0;
- ax25->t3timer = ax25->t3;
+ ax25_stop_t1timer(ax25);
+ ax25_start_t3timer(ax25);
} else {
if (ax25->va != nr) {
ax25_frames_acked(ax25, nr);
- ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+ ax25_calculate_t1(ax25);
+ ax25_start_t1timer(ax25);
}
}
}
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index 3cda48a17..2c7d082a9 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -120,13 +120,12 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg)
struct ax25_routes_struct route;
struct ax25_route_opt_struct rt_option;
ax25_dev *ax25_dev;
- int i, err;
+ int i;
switch (cmd) {
case SIOCADDRT:
- if ((err = verify_area(VERIFY_READ, arg, sizeof(route))) != 0)
- return err;
- copy_from_user(&route, arg, sizeof(route));
+ if (copy_from_user(&route, arg, sizeof(route)))
+ return -EFAULT;
if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
return -EINVAL;
if (route.digi_count > AX25_MAX_DIGIS)
@@ -175,9 +174,8 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg)
break;
case SIOCDELRT:
- if ((err = verify_area(VERIFY_READ, arg, sizeof(route))) != 0)
- return err;
- copy_from_user(&route, arg, sizeof(route));
+ if (copy_from_user(&route, arg, sizeof(route)))
+ return -EFAULT;
if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
return -EINVAL;
ax25_rt = ax25_route_list;
@@ -206,9 +204,8 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg)
break;
case SIOCAX25OPTRT:
- if ((err = verify_area(VERIFY_READ, arg, sizeof(rt_option))) != 0)
- return err;
- copy_from_user(&rt_option, arg, sizeof(rt_option));
+ if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
+ return -EFAULT;
if ((ax25_dev = ax25_addr_ax25dev(&rt_option.port_addr)) == NULL)
return -EINVAL;
for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
@@ -390,48 +387,32 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
* dl1bke 960117: build digipeater path
* dl1bke 960301: use the default route if it exists
*/
-void ax25_rt_build_path(ax25_cb *ax25, ax25_address *addr, struct device *dev)
+ax25_route *ax25_rt_find_route(ax25_address *addr, struct device *dev)
{
+ static ax25_route route;
ax25_route *ax25_rt;
- if ((ax25_rt = ax25_find_route(addr, dev)) == NULL)
- return;
-
- if (ax25_rt->digipeat == NULL)
- return;
-
- if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
- return;
-
- if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL)
- return;
+ if ((ax25_rt = ax25_find_route(addr, dev)) == NULL) {
+ route.next = NULL;
+ route.callsign = *addr;
+ route.dev = dev;
+ route.digipeat = NULL;
+ route.ip_mode = ' ';
+ return &route;
+ }
- *ax25->digipeat = *ax25_rt->digipeat;
- ax25_adjust_path(addr, ax25->digipeat);
+ return ax25_rt;
}
-struct sk_buff *ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *dev)
+struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, ax25_address *dest, ax25_digi *digi)
{
struct sk_buff *skbn;
- ax25_route *ax25_rt;
- ax25_digi digipeat;
- ax25_address src, dest;
unsigned char *bp;
int len;
skb_pull(skb, 1); /* skip KISS command */
- if ((ax25_rt = ax25_find_route(addr, dev)) == NULL)
- return skb;
-
- if (ax25_rt->digipeat == NULL)
- return skb;
-
- digipeat = *ax25_rt->digipeat;
-
- ax25_adjust_path(addr, &digipeat);
-
- len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN;
+ len = digi->ndigi * AX25_ADDR_LEN;
if (skb_headroom(skb) < len) {
if ((skbn = skb_realloc_headroom(skb, len)) == NULL) {
@@ -447,30 +428,13 @@ struct sk_buff *ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, stru
skb = skbn;
}
- memcpy(&dest, skb->data + 0, AX25_ADDR_LEN);
- memcpy(&src, skb->data + 7, AX25_ADDR_LEN);
-
bp = skb_push(skb, len);
- ax25_addr_build(bp, &src, &dest, ax25_rt->digipeat, AX25_COMMAND, AX25_MODULUS);
+ ax25_addr_build(bp, src, dest, digi, AX25_COMMAND, AX25_MODULUS);
return skb;
}
-/*
- * Return the IP mode of a given callsign/device pair.
- */
-char ax25_ip_mode_get(ax25_address *callsign, struct device *dev)
-{
- ax25_route *ax25_rt;
-
- for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next)
- if (ax25cmp(&ax25_rt->callsign, callsign) == 0 && ax25_rt->dev == dev)
- return ax25_rt->ip_mode;
-
- return ' ';
-}
-
#ifdef MODULE
/*
diff --git a/net/ax25/ax25_std_in.c b/net/ax25/ax25_std_in.c
index 1efe08366..7b7d437e8 100644
--- a/net/ax25/ax25_std_in.c
+++ b/net/ax25/ax25_std_in.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -34,6 +34,7 @@
* Modularisation changes.
* AX.25 035 Hans(PE1AYX) Fixed interface to IP layer.
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_in.c.
+ * AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -87,9 +88,9 @@ static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
case AX25_UA:
if (pf) {
ax25_calculate_rtt(ax25);
- ax25->t1timer = 0;
- ax25->t3timer = ax25->t3;
- ax25->idletimer = ax25->idle;
+ ax25_stop_t1timer(ax25);
+ ax25_start_t3timer(ax25);
+ ax25_start_idletimer(ax25);
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
@@ -107,16 +108,7 @@ static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
case AX25_DM:
if (pf) {
if (ax25->modulus == AX25_MODULUS) {
- ax25_clear_queues(ax25);
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ECONNREFUSED;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, ECONNREFUSED);
} else {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
@@ -146,30 +138,12 @@ static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
case AX25_DISC:
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = 0;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, 0);
break;
case AX25_DM:
case AX25_UA:
- if (pf) {
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = 0;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
- }
+ if (pf) ax25_disconnect(ax25, 0);
break;
case AX25_I:
@@ -206,10 +180,11 @@ static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
}
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ ax25_stop_t1timer(ax25);
+ ax25_stop_t2timer(ax25);
+ ax25_start_t3timer(ax25);
+ ax25_start_idletimer(ax25);
ax25->condition = 0x00;
- ax25->t1timer = 0;
- ax25->t3timer = ax25->t3;
- ax25->idletimer = ax25->idle;
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
@@ -217,32 +192,12 @@ static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
break;
case AX25_DISC:
- ax25_clear_queues(ax25);
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- ax25->t3timer = 0;
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = 0;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, 0);
break;
case AX25_DM:
- ax25_clear_queues(ax25);
- ax25->t3timer = 0;
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ECONNRESET;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, ECONNRESET);
break;
case AX25_RR:
@@ -268,8 +223,8 @@ static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
ax25_calculate_rtt(ax25);
- ax25->t1timer = 0;
- ax25->t3timer = ax25->t3;
+ ax25_stop_t1timer(ax25);
+ ax25_start_t3timer(ax25);
ax25_requeue_frames(ax25);
} else {
ax25_std_nr_error_recovery(ax25);
@@ -295,18 +250,15 @@ static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
if (ns == ax25->vr) {
ax25->vr = (ax25->vr + 1) % ax25->modulus;
queued = ax25_rx_iframe(ax25, skb);
- if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+ if (ax25->condition & AX25_COND_OWN_RX_BUSY)
ax25->vr = ns; /* ax25->vr - 1 */
- if (pf) ax25_std_enquiry_response(ax25);
- break;
- }
ax25->condition &= ~AX25_COND_REJECT;
if (pf) {
ax25_std_enquiry_response(ax25);
} else {
if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
- ax25->t2timer = ax25->t2;
ax25->condition |= AX25_COND_ACK_PENDING;
+ ax25_start_t2timer(ax25);
}
}
} else {
@@ -353,10 +305,11 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
}
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ ax25_stop_t1timer(ax25);
+ ax25_stop_t2timer(ax25);
+ ax25_start_t3timer(ax25);
+ ax25_start_idletimer(ax25);
ax25->condition = 0x00;
- ax25->t1timer = 0;
- ax25->t3timer = ax25->t3;
- ax25->idletimer = ax25->idle;
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
@@ -366,32 +319,12 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
break;
case AX25_DISC:
- ax25_clear_queues(ax25);
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- ax25->t3timer = 0;
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = 0;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, 0);
break;
case AX25_DM:
- ax25_clear_queues(ax25);
- ax25->t3timer = 0;
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ECONNRESET;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, ECONNRESET);
break;
case AX25_RR:
@@ -401,11 +334,11 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
else
ax25->condition |= AX25_COND_PEER_RX_BUSY;
if (type == AX25_RESPONSE && pf) {
- ax25->t1timer = 0;
+ ax25_stop_t1timer(ax25);
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
if (ax25->vs == ax25->va) {
- ax25->t3timer = ax25->t3;
+ ax25_start_t3timer(ax25);
ax25->n2count = 0;
ax25->state = AX25_STATE_3;
} else {
@@ -430,11 +363,11 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
case AX25_REJ:
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
if (pf && type == AX25_RESPONSE) {
- ax25->t1timer = 0;
+ ax25_stop_t1timer(ax25);
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
if (ax25->vs == ax25->va) {
- ax25->t3timer = ax25->t3;
+ ax25_start_t3timer(ax25);
ax25->n2count = 0;
ax25->state = AX25_STATE_3;
} else {
@@ -471,18 +404,15 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
if (ns == ax25->vr) {
ax25->vr = (ax25->vr + 1) % ax25->modulus;
queued = ax25_rx_iframe(ax25, skb);
- if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+ if (ax25->condition & AX25_COND_OWN_RX_BUSY)
ax25->vr = ns; /* ax25->vr - 1 */
- if (pf) ax25_std_enquiry_response(ax25);
- break;
- }
ax25->condition &= ~AX25_COND_REJECT;
if (pf) {
ax25_std_enquiry_response(ax25);
} else {
if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
- ax25->t2timer = ax25->t2;
ax25->condition |= AX25_COND_ACK_PENDING;
+ ax25_start_t2timer(ax25);
}
}
} else {
@@ -533,6 +463,8 @@ int ax25_std_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
break;
}
+ ax25_kick(ax25);
+
return queued;
}
diff --git a/net/ax25/ax25_std_subr.c b/net/ax25/ax25_std_subr.c
index 3661a63fb..1b1d1c8bb 100644
--- a/net/ax25/ax25_std_subr.c
+++ b/net/ax25/ax25_std_subr.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -17,6 +17,7 @@
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_out.c.
+ * AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -62,9 +63,11 @@ void ax25_std_establish_data_link(ax25_cb *ax25)
else
ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
- ax25->t3timer = 0;
- ax25->t2timer = 0;
- ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+ ax25_calculate_t1(ax25);
+ ax25_stop_idletimer(ax25);
+ ax25_stop_t3timer(ax25);
+ ax25_stop_t2timer(ax25);
+ ax25_start_t1timer(ax25);
}
void ax25_std_transmit_enquiry(ax25_cb *ax25)
@@ -76,7 +79,8 @@ void ax25_std_transmit_enquiry(ax25_cb *ax25)
ax25->condition &= ~AX25_COND_ACK_PENDING;
- ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+ ax25_calculate_t1(ax25);
+ ax25_start_t1timer(ax25);
}
void ax25_std_enquiry_response(ax25_cb *ax25)
diff --git a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c
index 9a4a34c0f..4e97c51b8 100644
--- a/net/ax25/ax25_std_timer.c
+++ b/net/ax25/ax25_std_timer.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -19,6 +19,7 @@
* AX.25 033 Jonathan(G4KLX) Modularisation functions.
* AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
* AX.25 036 Jonathan(G4KLX) Split from ax25_timer.c.
+ * AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -44,14 +45,14 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
-void ax25_std_timer(ax25_cb *ax25)
+void ax25_std_heartbeat_expiry(ax25_cb *ax25)
{
switch (ax25->state) {
+
case AX25_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 (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
- del_timer(&ax25->timer);
ax25_destroy_socket(ax25);
return;
}
@@ -71,78 +72,57 @@ void ax25_std_timer(ax25_cb *ax25)
break;
}
}
- /*
- * Check for frames to transmit.
- */
- ax25_kick(ax25);
- break;
-
- default:
- break;
}
- if (ax25->t2timer > 0 && --ax25->t2timer == 0) {
- if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4) {
- if (ax25->condition & AX25_COND_ACK_PENDING) {
- ax25->condition &= ~AX25_COND_ACK_PENDING;
- ax25_std_timeout_response(ax25);
- }
- }
- }
+ ax25_start_heartbeat(ax25);
+}
- if (ax25->t3timer > 0 && --ax25->t3timer == 0) {
- if (ax25->state == AX25_STATE_3) {
- ax25->n2count = 0;
- ax25_std_transmit_enquiry(ax25);
- ax25->state = AX25_STATE_4;
- }
- ax25->t3timer = ax25->t3;
+void ax25_std_t2timer_expiry(ax25_cb *ax25)
+{
+ if (ax25->condition & AX25_COND_ACK_PENDING) {
+ ax25->condition &= ~AX25_COND_ACK_PENDING;
+ ax25_std_timeout_response(ax25);
}
+}
- if (ax25->idletimer > 0 && --ax25->idletimer == 0) {
- /* dl1bke 960228: close the connection when IDLE expires */
- /* similar to DAMA T3 timeout but with */
- /* a "clean" disconnect of the connection */
-
- ax25_clear_queues(ax25);
-
- ax25->n2count = 0;
- ax25->t3timer = 0;
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- ax25->state = AX25_STATE_2;
- ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
-
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = 0;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- ax25->sk->destroy = 1;
- }
- }
+void ax25_std_t3timer_expiry(ax25_cb *ax25)
+{
+ ax25->n2count = 0;
+ ax25_std_transmit_enquiry(ax25);
+ ax25->state = AX25_STATE_4;
+}
- if (ax25->t1timer == 0 || --ax25->t1timer > 0) {
- ax25_set_timer(ax25);
- return;
+void ax25_std_idletimer_expiry(ax25_cb *ax25)
+{
+ ax25_clear_queues(ax25);
+
+ ax25->n2count = 0;
+ ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+ ax25->state = AX25_STATE_2;
+
+ ax25_calculate_t1(ax25);
+ ax25_start_t1timer(ax25);
+ ax25_stop_t2timer(ax25);
+ ax25_stop_t3timer(ax25);
+
+ if (ax25->sk != NULL) {
+ ax25->sk->state = TCP_CLOSE;
+ ax25->sk->err = 0;
+ ax25->sk->shutdown |= SEND_SHUTDOWN;
+ if (!ax25->sk->dead)
+ ax25->sk->state_change(ax25->sk);
+ ax25->sk->dead = 1;
}
+}
+void ax25_std_t1timer_expiry(ax25_cb *ax25)
+{
switch (ax25->state) {
case AX25_STATE_1:
if (ax25->n2count == ax25->n2) {
if (ax25->modulus == AX25_MODULUS) {
- ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
- ax25_clear_queues(ax25);
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ETIMEDOUT;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, ETIMEDOUT);
+ return;
} else {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
@@ -160,19 +140,9 @@ void ax25_std_timer(ax25_cb *ax25)
case AX25_STATE_2:
if (ax25->n2count == ax25->n2) {
- ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
- ax25_clear_queues(ax25);
- ax25->state = AX25_STATE_0;
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ETIMEDOUT;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, ETIMEDOUT);
+ return;
} else {
ax25->n2count++;
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
@@ -187,19 +157,9 @@ void ax25_std_timer(ax25_cb *ax25)
case AX25_STATE_4:
if (ax25->n2count == ax25->n2) {
- ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
- ax25_clear_queues(ax25);
ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- SOCK_DEBUG(ax25->sk, "AX.25 link Failure\n");
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ETIMEDOUT;
- ax25->sk->shutdown |= SEND_SHUTDOWN;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
- }
+ ax25_disconnect(ax25, ETIMEDOUT);
+ return;
} else {
ax25->n2count++;
ax25_std_transmit_enquiry(ax25);
@@ -207,9 +167,8 @@ void ax25_std_timer(ax25_cb *ax25)
break;
}
- ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
-
- ax25_set_timer(ax25);
+ ax25_calculate_t1(ax25);
+ ax25_start_t1timer(ax25);
}
#endif
diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c
index ba2c72297..39dfd7d42 100644
--- a/net/ax25/ax25_subr.c
+++ b/net/ax25/ax25_subr.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -30,6 +30,7 @@
* AX.25 032 Joerg(DL1BKE) Added ax25_queue_length to count the number of
* enqueued buffers of a socket..
* AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
+ * AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -259,7 +260,7 @@ void ax25_return_dm(struct device *dev, ax25_address *src, ax25_address *dest, a
/*
* Exponential backoff for AX.25
*/
-unsigned short ax25_calculate_t1(ax25_cb *ax25)
+void ax25_calculate_t1(ax25_cb *ax25)
{
int n, t = 2;
@@ -278,7 +279,7 @@ unsigned short ax25_calculate_t1(ax25_cb *ax25)
break;
}
- return t * ax25->rtt;
+ ax25->t1 = t * ax25->rtt;
}
/*
@@ -289,8 +290,8 @@ void ax25_calculate_rtt(ax25_cb *ax25)
if (ax25->backoff == 0)
return;
- if (ax25->t1timer > 0 && ax25->n2count == 0)
- ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25->t1timer) / 10;
+ if (ax25_t1timer_running(ax25) && ax25->n2count == 0)
+ ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25_display_timer(&ax25->t1timer)) / 10;
if (ax25->rtt < AX25_T1CLAMPLO)
ax25->rtt = AX25_T1CLAMPLO;
@@ -299,4 +300,27 @@ void ax25_calculate_rtt(ax25_cb *ax25)
ax25->rtt = AX25_T1CLAMPHI;
}
+void ax25_disconnect(ax25_cb *ax25, int reason)
+{
+ ax25_clear_queues(ax25);
+
+ ax25_stop_t1timer(ax25);
+ ax25_stop_t2timer(ax25);
+ ax25_stop_t3timer(ax25);
+ ax25_stop_idletimer(ax25);
+
+ ax25->state = AX25_STATE_0;
+
+ ax25_link_failed(ax25, reason);
+
+ if (ax25->sk != NULL) {
+ ax25->sk->state = TCP_CLOSE;
+ ax25->sk->err = reason;
+ ax25->sk->shutdown |= SEND_SHUTDOWN;
+ if (!ax25->sk->dead)
+ ax25->sk->state_change(ax25->sk);
+ ax25->sk->dead = 1;
+ }
+}
+
#endif
diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c
index c0a54da11..8a384b58b 100644
--- a/net/ax25/ax25_timer.c
+++ b/net/ax25/ax25_timer.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -21,6 +21,7 @@
* AX.25 036 Jonathan(G4KLX) Split Standard and DAMA code into seperate files.
* Joerg(DL1BKE) Fixed DAMA Slave. We are *required* to start with
* standard AX.25 mode.
+ * AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
#include <linux/config.h>
@@ -46,48 +47,205 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
-static void ax25_timer(unsigned long);
+static void ax25_heartbeat_expiry(unsigned long);
+static void ax25_t1timer_expiry(unsigned long);
+static void ax25_t2timer_expiry(unsigned long);
+static void ax25_t3timer_expiry(unsigned long);
+static void ax25_idletimer_expiry(unsigned long);
-/*
- * Linux set timer
- */
-void ax25_set_timer(ax25_cb *ax25)
+void ax25_start_heartbeat(ax25_cb *ax25)
{
- unsigned long flags;
-
- save_flags(flags); cli();
del_timer(&ax25->timer);
- restore_flags(flags);
ax25->timer.data = (unsigned long)ax25;
- ax25->timer.function = &ax25_timer;
- ax25->timer.expires = jiffies + (HZ / 10);
+ ax25->timer.function = &ax25_heartbeat_expiry;
+ ax25->timer.expires = jiffies + 5 * HZ;
add_timer(&ax25->timer);
}
-/*
- * AX.25 TIMER
- *
- * This routine is called every 100ms. Decrement timer by this
- * amount - if expired then process the event.
- */
-static void ax25_timer(unsigned long param)
+void ax25_start_t1timer(ax25_cb *ax25)
+{
+ del_timer(&ax25->t1timer);
+
+ ax25->t1timer.data = (unsigned long)ax25;
+ ax25->t1timer.function = &ax25_t1timer_expiry;
+ ax25->t1timer.expires = jiffies + ax25->t1;
+
+ add_timer(&ax25->t1timer);
+}
+
+void ax25_start_t2timer(ax25_cb *ax25)
+{
+ del_timer(&ax25->t2timer);
+
+ ax25->t2timer.data = (unsigned long)ax25;
+ ax25->t2timer.function = &ax25_t2timer_expiry;
+ ax25->t2timer.expires = jiffies + ax25->t2;
+
+ add_timer(&ax25->t2timer);
+}
+
+void ax25_start_t3timer(ax25_cb *ax25)
+{
+ del_timer(&ax25->t3timer);
+
+ if (ax25->t3 > 0) {
+ ax25->t3timer.data = (unsigned long)ax25;
+ ax25->t3timer.function = &ax25_t3timer_expiry;
+ ax25->t3timer.expires = jiffies + ax25->t3;
+
+ add_timer(&ax25->t3timer);
+ }
+}
+
+void ax25_start_idletimer(ax25_cb *ax25)
+{
+ del_timer(&ax25->idletimer);
+
+ if (ax25->idle > 0) {
+ ax25->idletimer.data = (unsigned long)ax25;
+ ax25->idletimer.function = &ax25_idletimer_expiry;
+ ax25->idletimer.expires = jiffies + ax25->idle;
+
+ add_timer(&ax25->idletimer);
+ }
+}
+
+void ax25_stop_heartbeat(ax25_cb *ax25)
+{
+ del_timer(&ax25->timer);
+}
+
+void ax25_stop_t1timer(ax25_cb *ax25)
+{
+ del_timer(&ax25->t1timer);
+}
+
+void ax25_stop_t2timer(ax25_cb *ax25)
+{
+ del_timer(&ax25->t2timer);
+}
+
+void ax25_stop_t3timer(ax25_cb *ax25)
+{
+ del_timer(&ax25->t3timer);
+}
+
+void ax25_stop_idletimer(ax25_cb *ax25)
+{
+ del_timer(&ax25->idletimer);
+}
+
+int ax25_t1timer_running(ax25_cb *ax25)
+{
+ return (ax25->t1timer.prev != NULL || ax25->t1timer.next != NULL);
+}
+
+unsigned long ax25_display_timer(struct timer_list *timer)
+{
+ if (timer->prev == NULL && timer->next == NULL)
+ return 0;
+
+ return timer->expires - jiffies;
+}
+
+static void ax25_heartbeat_expiry(unsigned long param)
+{
+ ax25_cb *ax25 = (ax25_cb *)param;
+
+ switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_std_heartbeat_expiry(ax25);
+ break;
+
+#ifdef CONFIG_AX25_DAMA_SLAVE
+ case AX25_PROTO_DAMA_SLAVE:
+ if (ax25->ax25_dev->dama.slave)
+ ax25_ds_heartbeat_expiry(ax25);
+ else
+ ax25_std_heartbeat_expiry(ax25);
+ break;
+#endif
+ }
+}
+
+static void ax25_t1timer_expiry(unsigned long param)
+{
+ ax25_cb *ax25 = (ax25_cb *)param;
+
+ switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_std_t1timer_expiry(ax25);
+ break;
+
+#ifdef CONFIG_AX25_DAMA_SLAVE
+ case AX25_PROTO_DAMA_SLAVE:
+ if (!ax25->ax25_dev->dama.slave)
+ ax25_std_t1timer_expiry(ax25);
+ break;
+#endif
+ }
+}
+
+static void ax25_t2timer_expiry(unsigned long param)
+{
+ ax25_cb *ax25 = (ax25_cb *)param;
+
+ switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_std_t2timer_expiry(ax25);
+ break;
+
+#ifdef CONFIG_AX25_DAMA_SLAVE
+ case AX25_PROTO_DAMA_SLAVE:
+ if (!ax25->ax25_dev->dama.slave)
+ ax25_std_t2timer_expiry(ax25);
+ break;
+#endif
+ }
+}
+
+static void ax25_t3timer_expiry(unsigned long param)
+{
+ ax25_cb *ax25 = (ax25_cb *)param;
+
+ switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_std_t3timer_expiry(ax25);
+ break;
+
+#ifdef CONFIG_AX25_DAMA_SLAVE
+ case AX25_PROTO_DAMA_SLAVE:
+ if (ax25->ax25_dev->dama.slave)
+ ax25_ds_t3timer_expiry(ax25);
+ else
+ ax25_std_t3timer_expiry(ax25);
+ break;
+#endif
+ }
+}
+
+static void ax25_idletimer_expiry(unsigned long param)
{
ax25_cb *ax25 = (ax25_cb *)param;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
- ax25_std_timer(ax25);
+ ax25_std_idletimer_expiry(ax25);
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
if (ax25->ax25_dev->dama.slave)
- ax25_ds_timer(ax25);
+ ax25_ds_idletimer_expiry(ax25);
else
- ax25_std_timer(ax25);
+ ax25_std_idletimer_expiry(ax25);
break;
#endif
}
diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c
index c5113fce8..5f33147cf 100644
--- a/net/ax25/ax25_uid.c
+++ b/net/ax25/ax25_uid.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 036
+ * AX.25 release 037
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c
index 1cf2bab65..000203aaf 100644
--- a/net/ax25/sysctl_net_ax25.c
+++ b/net/ax25/sysctl_net_ax25.c
@@ -17,14 +17,14 @@ static int min_backoff[] = {0}, max_backoff[] = {2};
static int min_conmode[] = {0}, max_conmode[] = {2};
static int min_window[] = {1}, max_window[] = {7};
static int min_ewindow[] = {1}, max_ewindow[] = {63};
-static int min_t1[] = {1}, max_t1[] = {30 * AX25_SLOWHZ};
-static int min_t2[] = {1}, max_t2[] = {20 * AX25_SLOWHZ};
-static int min_t3[] = {0}, max_t3[] = {3600 * AX25_SLOWHZ};
-static int min_idle[] = {0}, max_idle[] = {65535 * AX25_SLOWHZ};
+static int min_t1[] = {1}, max_t1[] = {30 * HZ};
+static int min_t2[] = {1}, max_t2[] = {20 * HZ};
+static int min_t3[] = {0}, max_t3[] = {3600 * HZ};
+static int min_idle[] = {0}, max_idle[] = {65535 * HZ};
static int min_n2[] = {1}, max_n2[] = {31};
static int min_paclen[] = {1}, max_paclen[] = {512};
static int min_proto[] = {0}, max_proto[] = {3};
-static int min_ds_timeout[] = {0}, max_ds_timeout[] = {65535 * AX25_SLOWHZ};
+static int min_ds_timeout[] = {0}, max_ds_timeout[] = {65535 * HZ};
static struct ctl_table_header *ax25_table_header;
diff --git a/net/core/scm.c b/net/core/scm.c
index d88ab0ae7..e5fa793a7 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -172,9 +172,9 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
if (acc_fd < 0 || acc_fd >= NR_OPEN ||
(file=current->files->fd[acc_fd])==NULL)
return -EBADF;
- if (!file->f_inode || !file->f_inode->i_sock)
+ if (!file->f_dentry->d_inode || !file->f_dentry->d_inode->i_sock)
return -ENOTSOCK;
- p->sock = &file->f_inode->u.socket_i;
+ p->sock = &file->f_dentry->d_inode->u.socket_i;
if (p->sock->state != SS_UNCONNECTED)
return -EINVAL;
}
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index c912e8b2e..b684fba33 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -7,6 +7,9 @@
#include <linux/mm.h>
#include <linux/sysctl.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_SYSCTL
extern __u32 sysctl_wmem_max;
extern __u32 sysctl_rmem_max;
@@ -33,3 +36,4 @@ ctl_table core_table[] = {
&proc_dointvec_jiffies},
{ 0 }
};
+#endif
diff --git a/net/ipv4/Config.in b/net/ipv4/Config.in
index 489598994..3a5ac3b04 100644
--- a/net/ipv4/Config.in
+++ b/net/ipv4/Config.in
@@ -31,6 +31,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD
fi
fi
+bool 'IP: TCP syncookie support (not enabled per default) ' CONFIG_SYN_COOKIES
comment '(it is safe to leave these untouched)'
bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP
tristate 'IP: Reverse ARP' CONFIG_INET_RARP
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 9ce538dc4..2428ccc55 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -52,6 +52,11 @@ else
endif
endif
+ifeq ($(CONFIG_SYN_COOKIES),y)
+IPV4_OBJS += syncookies.o
+# module not supported, because it would be too messy.
+endif
+
ifdef CONFIG_INET
O_OBJS := $(IPV4_OBJS)
OX_OBJS := $(IPV4X_OBJS)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index db54b567a..0d51af255 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -388,7 +388,7 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int len)
err = memcpy_fromiovec(buf, msg->msg_iov, len);
if (!err)
{
- unsigned short fs;
+ unsigned long fs;
fs=get_fs();
set_fs(get_ds());
err=raw_sendto(sk,buf,len, msg);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 4a4c5321c..b55fb7666 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -45,6 +45,7 @@
* Pavel Krauz : Limited broadcast fixed
* Alexey Kuznetsov : End of old history. Splitted to fib.c and
* route.c and rewritten from scratch.
+ * Andi Kleen : Load-limit warning messages.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -568,7 +569,7 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
return;
reject_redirect:
- if (ipv4_config.log_martians)
+ if (ipv4_config.log_martians && net_ratelimit())
printk(KERN_INFO "Redirect from %lX/%s to %lX ignored."
"Path = %lX -> %lX, tos %02x\n",
ntohl(old_gw), dev->name, ntohl(new_gw),
@@ -636,7 +637,7 @@ void ip_rt_send_redirect(struct sk_buff *skb)
if (jiffies - rt->last_error > (RT_REDIRECT_LOAD<<rt->errors)) {
icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
rt->last_error = jiffies;
- if (ipv4_config.log_martians && ++rt->errors == RT_REDIRECT_NUMBER)
+ if (ipv4_config.log_martians && ++rt->errors == RT_REDIRECT_NUMBER && net_ratelimit())
printk(KERN_WARNING "host %08x/%s ignores redirects for %08x to %08x.\n",
rt->rt_src, rt->rt_src_dev->name, rt->rt_dst, rt->rt_gateway);
}
@@ -1083,12 +1084,12 @@ no_route:
* Do not cache martian addresses: they should be logged (RFC1812)
*/
martian_destination:
- if (ipv4_config.log_martians)
+ if (ipv4_config.log_martians && net_ratelimit())
printk(KERN_WARNING "martian destination %08x from %08x, dev %s\n", daddr, saddr, dev->name);
return -EINVAL;
martian_source:
- if (ipv4_config.log_martians) {
+ if (ipv4_config.log_martians && net_ratelimit()) {
/*
* RFC1812 recommenadtion, if source is martian,
* the only hint is MAC header.
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
new file mode 100644
index 000000000..c18b209f0
--- /dev/null
+++ b/net/ipv4/syncookies.c
@@ -0,0 +1,218 @@
+/*
+ * Syncookies implementation for the Linux kernel
+ *
+ * Copyright (C) 1997 Andi Kleen
+ * Based on ideas by D.J.Bernstein and Eric Schenk.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * $Id: syncookies.c,v 1.1 1997/07/18 06:30:06 ralf Exp $
+ *
+ * Missing: IPv6 support.
+ * Some counter so that the Administrator can see when the machine
+ * is under a syn flood attack.
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_SYN_COOKIES)
+#include <linux/tcp.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+#include <net/tcp.h>
+
+extern int sysctl_tcp_syncookies;
+
+static unsigned long tcp_lastsynq_overflow;
+
+/*
+ * This table has to be sorted. Only 8 entries are allowed and the
+ * last entry has to be duplicated.
+ * XXX generate a better table.
+ * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
+ */
+static __u16 const msstab[] = {
+ 64,
+ 256,
+ 512,
+ 536,
+ 1024,
+ 1440,
+ 1460,
+ 4312,
+ 4312
+};
+
+static __u32 make_syncookie(struct sk_buff *skb, __u32 counter, __u32 seq)
+{
+ __u32 z;
+
+ z = secure_tcp_syn_cookie(skb->nh.iph->saddr, skb->nh.iph->daddr,
+ skb->h.th->source, skb->h.th->dest,
+ seq,
+ counter);
+
+#if 0
+ printk(KERN_DEBUG
+ "msc: z=%u,cnt=%u,seq=%u,sadr=%u,dadr=%u,sp=%u,dp=%u\n",
+ z,counter,seq,
+ skb->nh.iph->saddr,skb->nh.iph->daddr,
+ ntohs(skb->h.th->source), ntohs(skb->h.th->dest));
+#endif
+
+ return z;
+}
+
+/*
+ * Generate a syncookie.
+ */
+__u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
+ __u16 *mssp)
+{
+ int i;
+ __u32 isn;
+ const __u16 mss = *mssp, *w;
+
+ tcp_lastsynq_overflow = jiffies;
+
+ isn = make_syncookie(skb, (jiffies/HZ) >> 6, ntohl(skb->h.th->seq));
+
+ /* XXX sort msstab[] by probability? */
+ w = msstab;
+ for (i = 0; i < 8; i++)
+ if (mss >= *w && mss < *++w)
+ goto found;
+ i--;
+found:
+ *mssp = w[-1];
+
+ isn |= i;
+ return isn;
+}
+
+/* This value should be dependant on TCP_TIMEOUT_INIT and
+ * sysctl_tcp_retries1. It's a rather complicated formula
+ * (exponential backoff) to compute at runtime so it's currently hardcoded
+ * here.
+ */
+#define COUNTER_TRIES 4
+
+/*
+ * Check if a ack sequence number is a valid syncookie.
+ */
+static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
+{
+ int mssind;
+ int i;
+ __u32 counter;
+ __u32 seq;
+
+ if ((jiffies - tcp_lastsynq_overflow) > TCP_TIMEOUT_INIT
+ && tcp_lastsynq_overflow)
+ return 0;
+
+ mssind = cookie & 7;
+ cookie &= ~7;
+
+ counter = (jiffies/HZ)>>6;
+ seq = ntohl(skb->h.th->seq)-1;
+ for (i = 0; i < COUNTER_TRIES; i++)
+ if (make_syncookie(skb, counter-i, seq) == cookie)
+ return msstab[mssind];
+
+ return 0;
+}
+
+extern struct or_calltable or_ipv4;
+
+static inline struct sock *
+get_cookie_sock(struct sock *sk, struct sk_buff *skb, struct open_request *req,
+ struct dst_entry *dst)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+ sk = tp->af_specific->syn_recv_sock(sk, skb, req, dst);
+ req->sk = sk;
+
+ /* Queue up for accept() */
+ tcp_synq_queue(tp, req);
+
+ return sk;
+}
+
+struct sock *
+cookie_v4_check(struct sock *sk, struct sk_buff *skb, struct ip_options *opt)
+{
+ __u32 cookie = ntohl(skb->h.th->ack_seq)-1;
+ struct open_request *req;
+ int mss;
+ struct rtable *rt;
+
+ if (!sysctl_tcp_syncookies)
+ return sk;
+ if (!skb->h.th->ack)
+ return sk;
+
+ mss = cookie_check(skb, cookie);
+ if (mss == 0)
+ return sk;
+
+ req = tcp_openreq_alloc();
+ if (req == NULL)
+ return NULL;
+
+ req->rcv_isn = htonl(skb->h.th->seq)-1;
+ req->snt_isn = cookie;
+ req->mss = mss;
+ req->rmt_port = skb->h.th->source;
+ req->af.v4_req.loc_addr = skb->nh.iph->daddr;
+ req->af.v4_req.rmt_addr = skb->nh.iph->saddr;
+ req->class = &or_ipv4; /* for savety */
+
+ /* We throwed the options of the initial SYN away, so we hope
+ * the ACK carries the same options again (see RFC1122 4.2.3.8)
+ */
+ if (opt && opt->optlen) {
+ int opt_size = sizeof(struct ip_options) + opt->optlen;
+
+ req->af.v4_req.opt = kmalloc(opt_size, GFP_ATOMIC);
+ if (req->af.v4_req.opt) {
+ if (ip_options_echo(req->af.v4_req.opt, skb)) {
+ kfree_s(req->af.v4_req.opt, opt_size);
+ req->af.v4_req.opt = NULL;
+ }
+ }
+ }
+
+ req->af.v4_req.opt = NULL;
+ req->snd_wscale = req->rcv_wscale = req->tstamp_ok = 0;
+ req->wscale_ok = 0;
+ req->expires = 0UL;
+ req->retrans = 0;
+
+ /*
+ * We need to lookup the route here to get at the correct
+ * window size. We should better make sure that the window size
+ * hasn't changed since we received the original syn, but I see
+ * no easy way to do this.
+ */
+ if (ip_route_output(&rt,
+ opt && opt->srr ? opt->faddr :
+ req->af.v4_req.rmt_addr,req->af.v4_req.loc_addr,
+ sk->ip_tos, NULL)) {
+ tcp_openreq_free(req);
+ return NULL;
+ }
+
+ /* Try to redo what tcp_v4_send_synack did. */
+ req->window_clamp = rt->u.dst.window;
+ tcp_select_initial_window(sock_rspace(sk)/2,req->mss,
+ &req->rcv_wnd, &req->window_clamp,
+ 0, &req->rcv_wscale);
+
+ return get_cookie_sock(sk, skb, req, &rt->u.dst);
+}
+
+#endif
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 6d7ba591f..5f804f343 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -60,8 +60,8 @@ extern int sysctl_tcp_retries2;
extern int sysctl_tcp_max_delay_acks;
extern int sysctl_tcp_fin_timeout;
extern int sysctl_tcp_syncookies;
-extern int sysctl_tcp_always_syncookie;
extern int sysctl_tcp_syn_retries;
+extern int sysctl_tcp_stdurg;
extern int tcp_sysctl_congavoid(ctl_table *ctl, int write, struct file * filp,
void *buffer, size_t *lenp);
@@ -203,10 +203,12 @@ ctl_table ipv4_table[] = {
{NET_IPV4_IGMP_AGE_THRESHOLD, "igmp_age_threshold",
&sysctl_igmp_age_threshold, sizeof(int), 0644, NULL, &proc_dointvec},
#endif
+#ifdef CONFIG_SYN_COOKIES
{NET_TCP_SYNCOOKIES, "tcp_syncookies",
&sysctl_tcp_syncookies, sizeof(int), 0644, NULL, &proc_dointvec},
- {NET_TCP_ALWAYS_SYNCOOKIE, "tcp_always_syncookie",
- &sysctl_tcp_always_syncookie, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
+ {NET_TCP_STDURG, "tcp_stdurg", &sysctl_tcp_stdurg,
+ sizeof(int), 0644, NULL, &proc_dointvec},
{0}
};
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 604bd1c84..7a6b8f55f 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.52 1997/05/31 12:36:42 freitag Exp $
+ * Version: $Id: tcp_input.c,v 1.2 1997/06/17 13:31:29 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -56,15 +56,21 @@ static void tcp_cong_avoid_vanj(struct sock *sk, u32 seq, u32 ack,
static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
u32 seq_rtt);
+#ifdef CONFIG_SYSCTL
+#define SYNC_INIT 0 /* let the user enable it */
+#else
+#define SYNC_INIT 1
+#endif
+
int sysctl_tcp_cong_avoidance;
int sysctl_tcp_hoe_retransmits;
int sysctl_tcp_sack;
int sysctl_tcp_tsack;
int sysctl_tcp_timestamps;
int sysctl_tcp_window_scaling;
-int sysctl_tcp_syncookies;
-int sysctl_tcp_always_syncookie;
+int sysctl_tcp_syncookies = SYNC_INIT;
int sysctl_tcp_max_delay_acks = MAX_DELAY_ACK;
+int sysctl_tcp_stdurg;
static tcp_sys_cong_ctl_t tcp_sys_cong_ctl_f = &tcp_cong_avoid_vanj;
@@ -288,7 +294,7 @@ static int tcp_reset(struct sock *sk, struct sk_buff *skb)
* FIXME: surely this can be more efficient. -- erics
*/
-void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp)
+void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy)
{
unsigned char *ptr;
int length=(th->doff*4)-sizeof(struct tcphdr);
@@ -323,21 +329,21 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp)
break;
case TCPOPT_WINDOW:
if(opsize==TCPOLEN_WINDOW && th->syn)
- if (sysctl_tcp_window_scaling) {
+ if (!no_fancy && sysctl_tcp_window_scaling) {
tp->wscale_ok = 1;
tp->snd_wscale = *(__u8 *)ptr;
}
break;
case TCPOPT_SACK_PERM:
if(opsize==TCPOLEN_SACK_PERM && th->syn)
- if (sysctl_tcp_sack)
+ if (sysctl_tcp_sack && !no_fancy)
tp->sack_ok = 1;
case TCPOPT_TIMESTAMP:
if(opsize==TCPOLEN_TIMESTAMP) {
/* Cheaper to set again then to
* test syn. Optimize this?
*/
- if (sysctl_tcp_timestamps)
+ if (sysctl_tcp_timestamps && !no_fancy)
tp->tstamp_ok = 1;
tp->saw_tstamp = 1;
tp->rcv_tsval = ntohl(*(__u32 *)ptr);
@@ -345,6 +351,8 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp)
}
break;
case TCPOPT_SACK:
+ if (no_fancy)
+ break;
tp->sacks = (opsize-2)>>3;
if (tp->sacks<<3 == opsize-2) {
int i;
@@ -385,7 +393,7 @@ static __inline__ int tcp_fast_parse_options(struct tcphdr *th, struct tcp_opt *
return 1;
}
}
- tcp_parse_options(th,tp);
+ tcp_parse_options(th,tp,0);
return 1;
}
@@ -1233,7 +1241,7 @@ static __inline__ void tcp_ack_snd_check(struct sock *sk)
* place. We handle URGent data wrong. We have to - as
* BSD still doesn't use the correction from RFC961.
* For 1003.1g we should support a new option TCP_STDURG to permit
- * either form.
+ * either form (or just set the sysctl tcp_stdurg).
*/
static void tcp_check_urg(struct sock * sk, struct tcphdr * th)
@@ -1241,7 +1249,7 @@ static void tcp_check_urg(struct sock * sk, struct tcphdr * th)
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
u32 ptr = ntohs(th->urg_ptr);
- if (ptr)
+ if (ptr && !sysctl_tcp_stdurg)
ptr--;
ptr += ntohl(th->seq);
@@ -1459,13 +1467,11 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
/* These use the socket TOS..
* might want to be the received TOS
*/
- if(th->ack)
+ if(th->ack)
return 1; /* send reset */
if(th->syn) {
- __u32 isn = tp->af_specific->init_sequence(sk, skb);
-
- if(tp->af_specific->conn_request(sk, skb, opt, isn) < 0)
+ if(tp->af_specific->conn_request(sk, skb, opt, 0) < 0)
return 1;
/* Now we have several options: In theory there is
@@ -1531,7 +1537,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
tp->fin_seq = skb->seq;
tcp_set_state(sk, TCP_ESTABLISHED);
- tcp_parse_options(th,tp);
+ tcp_parse_options(th,tp,0);
/* FIXME: need to make room for SACK still */
if (tp->wscale_ok == 0) {
tp->snd_wscale = tp->rcv_wscale = 0;
@@ -1574,7 +1580,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
* tcp_connect.
*/
tcp_set_state(sk, TCP_SYN_RECV);
- tcp_parse_options(th,tp);
+ tcp_parse_options(th,tp,0);
if (tp->saw_tstamp) {
tp->ts_recent = tp->rcv_tsval;
tp->ts_recent_stamp = jiffies;
@@ -1616,6 +1622,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
sk->shutdown = SHUTDOWN_MASK;
isn = tp->rcv_nxt + 128000;
+ if (isn == 0)
+ isn++;
sk = tp->af_specific->get_sock(skb, th);
@@ -1710,8 +1718,10 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
tp->snd_wl1 = skb->seq;
tp->snd_wl2 = skb->ack_seq;
- } else
+ } else {
+ SOCK_DEBUG(sk, "bad ack\n");
return 1;
+ }
break;
case TCP_FIN_WAIT1:
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index c4d12a54f..d89624175 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.43 1997/05/06 09:31:44 davem Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.1.1.1 1997/06/01 03:16:26 ralf Exp $
*
* IPv4 specific functions
*
@@ -30,6 +30,9 @@
* David S. Miller : Change semantics of established hash,
* half is devoted to TIME_WAIT sockets
* and the rest go in the other half.
+ * Andi Kleen : Add support for syncookies and fixed
+ * some bugs: ip options weren't passed to
+ * the TCP layer, missed a check for an ACK bit.
*/
#include <linux/config.h>
@@ -48,6 +51,7 @@ extern int sysctl_tcp_sack;
extern int sysctl_tcp_tsack;
extern int sysctl_tcp_timestamps;
extern int sysctl_tcp_window_scaling;
+extern int sysctl_tcp_syncookies;
static void tcp_v4_send_reset(struct sk_buff *skb);
@@ -403,7 +407,7 @@ struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
#endif
-static __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
+static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
{
return secure_tcp_sequence_number(sk->saddr, sk->daddr,
skb->h.th->dest,
@@ -697,6 +701,12 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp)
}
/* FIXME: What about the IP layer options size here? */
+ /* FIXME: add a timeout here, to cope with broken devices that
+ drop all DF=1 packets. Do some more sanity checking
+ here to prevent DOS attacks?
+ This code should kick the tcp_output routine to
+ retransmit a packet immediately because we know that
+ the last packet has been dropped. -AK */
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
if (sk->ip_pmtudisc != IP_PMTUDISC_DONT) {
int new_mtu = sk->dst_cache->pmtu - sizeof(struct iphdr) - tp->tcp_header_len;
@@ -835,6 +845,8 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
/* Don't offer more than they did.
* This way we don't have to memorize who said what.
+ * FIXME: maybe this should be changed for better performance
+ * with syncookies.
*/
req->mss = min(mss, req->mss);
@@ -891,17 +903,13 @@ static void tcp_v4_or_free(struct open_request *req)
sizeof(struct ip_options) + req->af.v4_req.opt->optlen);
}
-static struct or_calltable or_ipv4 = {
+struct or_calltable or_ipv4 = {
tcp_v4_send_synack,
tcp_v4_or_free
};
-static int tcp_v4_syn_filter(struct sock *sk, struct sk_buff *skb, __u32 saddr)
-{
- return 0;
-}
-
-int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 isn)
+int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
+ __u32 isn)
{
struct ip_options *opt = (struct ip_options *) ptr;
struct tcp_opt tp;
@@ -909,23 +917,39 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 i
struct tcphdr *th = skb->h.th;
__u32 saddr = skb->nh.iph->saddr;
__u32 daddr = skb->nh.iph->daddr;
+#ifdef CONFIG_SYN_COOKIES
+ int want_cookie = 0;
+#else
+#define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */
+#endif
/* If the socket is dead, don't accept the connection. */
- if (sk->dead) {
- SOCK_DEBUG(sk, "Reset on %p: Connect on dead socket.\n",sk);
- tcp_statistics.TcpAttemptFails++;
- return -ENOTCONN;
- }
-
- if (sk->ack_backlog >= sk->max_ack_backlog ||
- tcp_v4_syn_filter(sk, skb, saddr)) {
- SOCK_DEBUG(sk, "dropping syn ack:%d max:%d\n", sk->ack_backlog,
- sk->max_ack_backlog);
-#ifdef CONFIG_IP_TCPSF
- tcp_v4_random_drop(sk);
+ if (sk->dead)
+ goto dead;
+
+ if (sk->ack_backlog >= sk->max_ack_backlog) {
+#ifdef CONFIG_SYN_COOKIES
+ if (sysctl_tcp_syncookies) {
+ static unsigned long warntime;
+
+ if (jiffies - warntime > HZ*60) {
+ warntime = jiffies;
+ printk(KERN_INFO
+ "possible SYN flooding on port %d. Sending cookies.\n", ntohs(skb->h.th->dest));
+ }
+ want_cookie = 1;
+ } else
#endif
- tcp_statistics.TcpAttemptFails++;
- goto exit;
+ {
+ SOCK_DEBUG(sk, "dropping syn ack:%d max:%d\n", sk->ack_backlog,
+ sk->max_ack_backlog);
+ tcp_statistics.TcpAttemptFails++;
+ goto exit;
+ }
+ } else {
+ if (isn == 0)
+ isn = tcp_v4_init_sequence(sk, skb);
+ sk->ack_backlog++;
}
req = tcp_openreq_alloc();
@@ -934,15 +958,12 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 i
goto exit;
}
- sk->ack_backlog++;
-
req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */
req->rcv_isn = skb->seq;
- req->snt_isn = isn;
- tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
+ tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
tp.in_mss = 536;
- tcp_parse_options(th,&tp);
+ tcp_parse_options(th,&tp, want_cookie);
if (tp.saw_tstamp)
req->ts_recent = tp.rcv_tsval;
req->mss = tp.in_mss;
@@ -954,8 +975,17 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 i
req->af.v4_req.loc_addr = daddr;
req->af.v4_req.rmt_addr = saddr;
+ /* Note that we ignore the isn passed from the TIME_WAIT
+ * state here. That's the price we pay for cookies.
+ */
+ if (want_cookie)
+ isn = cookie_v4_init_sequence(sk, skb, &req->mss);
+
+ req->snt_isn = isn;
+
/* IPv4 options */
req->af.v4_req.opt = NULL;
+
if (opt && opt->optlen) {
int opt_size = sizeof(struct ip_options) + opt->optlen;
@@ -973,36 +1003,50 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 i
tcp_v4_send_synack(sk, req);
- req->expires = jiffies + TCP_TIMEOUT_INIT;
- tcp_inc_slow_timer(TCP_SLT_SYNACK);
- tcp_synq_queue(&sk->tp_pinfo.af_tcp, req);
+ if (want_cookie) {
+ if (req->af.v4_req.opt)
+ kfree(req->af.v4_req.opt);
+ tcp_openreq_free(req);
+ } else {
+ req->expires = jiffies + TCP_TIMEOUT_INIT;
+ tcp_inc_slow_timer(TCP_SLT_SYNACK);
+ tcp_synq_queue(&sk->tp_pinfo.af_tcp, req);
+ }
sk->data_ready(sk, 0);
exit:
kfree_skb(skb, FREE_READ);
return 0;
+
+dead:
+ SOCK_DEBUG(sk, "Reset on %p: Connect on dead socket.\n",sk);
+ tcp_statistics.TcpAttemptFails++;
+ return -ENOTCONN;
}
struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
- struct open_request *req)
+ struct open_request *req,
+ struct dst_entry *dst)
{
struct tcp_opt *newtp;
struct sock *newsk;
- struct rtable *rt;
int snd_mss;
newsk = sk_alloc(GFP_ATOMIC);
- if (newsk == NULL)
+ if (newsk == NULL) {
+ if (dst)
+ dst_release(dst);
return NULL;
+ }
memcpy(newsk, sk, sizeof(*newsk));
/* Or else we die! -DaveM */
newsk->sklist_next = NULL;
- newsk->opt = NULL;
- newsk->dst_cache = NULL;
+ newsk->opt = req->af.v4_req.opt;
+
skb_queue_head_init(&newsk->write_queue);
skb_queue_head_init(&newsk->receive_queue);
skb_queue_head_init(&newsk->out_of_order_queue);
@@ -1072,17 +1116,21 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newsk->rcv_saddr = req->af.v4_req.loc_addr;
/* options / mss / route_cache */
- newsk->opt = req->af.v4_req.opt;
- if (ip_route_output(&rt,
- newsk->opt && newsk->opt->srr ? newsk->opt->faddr : newsk->daddr,
- newsk->saddr, newsk->ip_tos, NULL)) {
- kfree(newsk);
- return NULL;
- }
-
- newsk->dst_cache = &rt->u.dst;
-
- snd_mss = rt->u.dst.pmtu;
+ if (dst == NULL) {
+ struct rtable *rt;
+
+ if (ip_route_output(&rt,
+ newsk->opt && newsk->opt->srr ?
+ newsk->opt->faddr : newsk->daddr,
+ newsk->saddr, newsk->ip_tos, NULL)) {
+ kfree(newsk);
+ return NULL;
+ }
+ dst = &rt->u.dst;
+ }
+ newsk->dst_cache = dst;
+
+ snd_mss = dst->pmtu;
/* FIXME: is mtu really the same as snd_mss? */
newsk->mtu = snd_mss;
@@ -1124,7 +1172,7 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
return newsk;
}
-struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb)
+static inline struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb, struct ip_options *opt)
{
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
struct open_request *req = tp->syn_wait_queue;
@@ -1133,8 +1181,13 @@ struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb)
* as we checked the user count on tcp_rcv and we're
* running from a soft interrupt.
*/
- if(!req)
+ if(!req) {
+#ifdef CONFIG_SYN_COOKIES
+ goto checkcookie;
+#else
return sk;
+#endif
+ }
while(req) {
if (req->af.v4_req.rmt_addr == skb->nh.iph->saddr &&
@@ -1147,7 +1200,7 @@ struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb)
* yet accepted()...
*/
sk = req->sk;
- break;
+ goto ende;
}
/* Check for syn retransmission */
@@ -1161,20 +1214,28 @@ struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb)
return NULL;
}
- sk = tp->af_specific->syn_recv_sock(sk, skb, req);
+ if (!skb->h.th->ack)
+ return sk;
+
+ sk = tp->af_specific->syn_recv_sock(sk, skb, req, NULL);
tcp_dec_slow_timer(TCP_SLT_SYNACK);
if (sk == NULL)
return NULL;
req->expires = 0UL;
req->sk = sk;
- break;
+ goto ende;
}
req = req->dl_next;
}
- skb_orphan(skb);
- skb_set_owner_r(skb, sk);
+#ifdef CONFIG_SYN_COOKIES
+checkcookie:
+ sk = cookie_v4_check(sk, skb, opt);
+#endif
+ende: skb_orphan(skb);
+ if (sk)
+ skb_set_owner_r(skb, sk);
return sk;
}
@@ -1195,20 +1256,28 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
goto ok;
}
- if (sk->state == TCP_LISTEN) {
- struct sock *nsk;
+ /*
+ * We check packets with only the SYN bit set against the
+ * open_request queue too: This increases connection latency a bit,
+ * but is required to detect retransmitted SYNs.
+ *
+ * The ACK/SYN bit check is probably not needed here because
+ * it is checked later again (we play save now).
+ */
+ if (sk->state == TCP_LISTEN && (skb->h.th->ack || skb->h.th->syn)) {
+ struct sock *nsk;
- /* Find possible connection requests. */
- nsk = tcp_v4_check_req(sk, skb);
- if (nsk == NULL)
+ /* Find possible connection requests. */
+ nsk = tcp_v4_check_req(sk, skb, &(IPCB(skb)->opt));
+ if (nsk == NULL)
goto discard_it;
-
- release_sock(sk);
- lock_sock(nsk);
+
+ release_sock(sk);
+ lock_sock(nsk);
sk = nsk;
}
- if (tcp_rcv_state_process(sk, skb, skb->h.th, NULL, skb->len) == 0)
+ if (tcp_rcv_state_process(sk, skb, skb->h.th, &(IPCB(skb)->opt), skb->len) == 0)
goto ok;
reset:
@@ -1352,7 +1421,6 @@ struct tcp_func ipv4_specific = {
tcp_v4_rebuild_header,
tcp_v4_conn_request,
tcp_v4_syn_recv_sock,
- tcp_v4_init_sequence,
tcp_v4_get_sock,
ip_setsockopt,
ip_getsockopt,
diff --git a/net/ipv4/utils.c b/net/ipv4/utils.c
index 4253c85db..d2b8e0089 100644
--- a/net/ipv4/utils.c
+++ b/net/ipv4/utils.c
@@ -13,7 +13,7 @@
* Fixes:
* Alan Cox : verify_area check.
* Alan Cox : removed old debugging.
- *
+ * Andi Kleen : add net_ratelimit()
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -89,3 +89,24 @@ __u32 in_aton(const char *str)
return(htonl(l));
}
+/*
+ * This enforces a rate limit: not more than one kernel message
+ * every 5secs to make a denial-of-service attack impossible.
+ *
+ * All warning printk()s should be guarded by this function.
+ */
+int net_ratelimit(void)
+{
+ static unsigned long last_msg;
+ static int missed;
+
+ if ((jiffies - last_msg) >= 5*HZ) {
+ if (missed)
+ printk(KERN_WARNING "ipv4: (%d messages suppressed. Flood?)\n", missed);
+ missed = 0;
+ last_msg = jiffies;
+ return 1;
+ }
+ missed++;
+ return 0;
+}
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 71ff84b4b..a5a884646 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: icmp.c,v 1.9 1997/04/29 09:38:42 mj Exp $
+ * $Id: icmp.c,v 1.1.1.1 1997/06/01 03:16:27 ralf Exp $
*
* Based on net/ipv4/icmp.c
*
@@ -405,7 +405,23 @@ int icmpv6_rcv(struct sk_buff *skb, struct device *dev,
case CHECKSUM_HW:
if (csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6,
skb->csum)) {
- printk(KERN_DEBUG "icmpv6 checksum failed\n");
+ printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
+ ntohs(saddr->in6_u.u6_addr16[0]),
+ ntohs(saddr->in6_u.u6_addr16[1]),
+ ntohs(saddr->in6_u.u6_addr16[2]),
+ ntohs(saddr->in6_u.u6_addr16[3]),
+ ntohs(saddr->in6_u.u6_addr16[4]),
+ ntohs(saddr->in6_u.u6_addr16[5]),
+ ntohs(saddr->in6_u.u6_addr16[6]),
+ ntohs(saddr->in6_u.u6_addr16[7]),
+ ntohs(daddr->in6_u.u6_addr16[0]),
+ ntohs(daddr->in6_u.u6_addr16[1]),
+ ntohs(daddr->in6_u.u6_addr16[2]),
+ ntohs(daddr->in6_u.u6_addr16[3]),
+ ntohs(daddr->in6_u.u6_addr16[4]),
+ ntohs(daddr->in6_u.u6_addr16[5]),
+ ntohs(daddr->in6_u.u6_addr16[6]),
+ ntohs(daddr->in6_u.u6_addr16[7]));
goto discard_it;
}
default:
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 4bf0207d9..51b9eff4c 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.32 1997/06/04 08:28:58 davem Exp $
+ * $Id: tcp_ipv6.c,v 1.2 1997/06/17 13:31:32 ralf Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
@@ -695,7 +695,7 @@ static struct or_calltable or_ipv6 = {
* Can some kind of merge be done? -- erics
*/
static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
- __u32 isn)
+ __u32 isn)
{
struct tcp_opt tp;
struct open_request *req;
@@ -711,6 +711,9 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
if (skb->protocol == __constant_htons(ETH_P_IP))
return tcp_v4_conn_request(sk, skb, ptr, isn);
+ if (isn == 0)
+ isn = tcp_v6_init_sequence(sk,skb);
+
/*
* There are no SYN attacks on IPv6, yet...
*/
@@ -735,7 +738,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
req->snt_isn = isn;
tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
tp.in_mss = 536;
- tcp_parse_options(skb->h.th,&tp);
+ tcp_parse_options(skb->h.th,&tp,0);
if (tp.saw_tstamp)
req->ts_recent = tp.rcv_tsval;
req->mss = tp.in_mss;
@@ -778,10 +781,10 @@ static void tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len,
}
static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
- struct open_request *req)
+ struct open_request *req,
+ struct dst_entry *dst)
{
struct ipv6_pinfo *np;
- struct dst_entry *dst;
struct flowi fl;
struct tcp_opt *newtp;
struct sock *newsk;
@@ -791,11 +794,11 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
* v6 mapped
*/
- newsk = tcp_v4_syn_recv_sock(sk, skb, req);
+ newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
- if (newsk == NULL)
+ if (newsk == NULL)
return NULL;
-
+
np = &newsk->net_pinfo.af_inet6;
ipv6_addr_set(&np->daddr, 0, 0, __constant_htonl(0x0000FFFF),
@@ -813,8 +816,11 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
}
newsk = sk_alloc(GFP_ATOMIC);
- if (newsk == NULL)
+ if (newsk == NULL) {
+ if (dst)
+ dst_release(dst);
return NULL;
+ }
memcpy(newsk, sk, sizeof(*newsk));
@@ -902,18 +908,20 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
ipv6_addr_copy(&np->rcv_saddr, &req->af.v6_req.loc_addr);
np->oif = req->af.v6_req.dev;
- /*
- * options / mss / route cache
- */
-
- fl.proto = IPPROTO_TCP;
- fl.nl_u.ip6_u.daddr = &np->daddr;
- fl.nl_u.ip6_u.saddr = &np->saddr;
- fl.dev = np->oif;
- fl.uli_u.ports.dport = newsk->dummy_th.dest;
- fl.uli_u.ports.sport = newsk->dummy_th.source;
-
- dst = ip6_route_output(newsk, &fl);
+ if (dst == NULL) {
+ /*
+ * options / mss / route cache
+ */
+
+ fl.proto = IPPROTO_TCP;
+ fl.nl_u.ip6_u.daddr = &np->daddr;
+ fl.nl_u.ip6_u.saddr = &np->saddr;
+ fl.dev = np->oif;
+ fl.uli_u.ports.dport = newsk->dummy_th.dest;
+ fl.uli_u.ports.sport = newsk->dummy_th.source;
+
+ dst = ip6_route_output(newsk, &fl);
+ }
ip6_dst_store(newsk, dst);
@@ -1051,7 +1059,7 @@ struct sock *tcp_v6_check_req(struct sock *sk, struct sk_buff *skb)
}
skb_orphan(skb);
- sk = tp->af_specific->syn_recv_sock(sk, skb, req);
+ sk = tp->af_specific->syn_recv_sock(sk, skb, req, NULL);
tcp_dec_slow_timer(TCP_SLT_SYNACK);
@@ -1308,7 +1316,6 @@ static struct tcp_func ipv6_specific = {
tcp_v6_rebuild_header,
tcp_v6_conn_request,
tcp_v6_syn_recv_sock,
- tcp_v6_init_sequence,
tcp_v6_get_sock,
ipv6_setsockopt,
ipv6_getsockopt,
@@ -1328,7 +1335,6 @@ static struct tcp_func ipv6_mapped = {
tcp_v4_rebuild_header,
tcp_v6_conn_request,
tcp_v6_syn_recv_sock,
- tcp_v6_init_sequence,
tcp_v6_get_sock,
ipv6_setsockopt,
ipv6_getsockopt,
diff --git a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c
index 2be6e565e..77382683c 100644
--- a/net/lapb/lapb_iface.c
+++ b/net/lapb/lapb_iface.c
@@ -1,8 +1,5 @@
/*
- * LAPB release 001
- *
- * This is ALPHA test software. This code may break your machine, randomly fail to work with new
- * releases, misbehave and/or generally screw up. It might even work.
+ * LAPB release 002
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -14,6 +11,7 @@
*
* History
* LAPB 001 Jonathan Naylor Started Coding
+ * LAPB 002 Jonathan Naylor New timer architecture.
*/
#include <linux/config.h>
@@ -63,8 +61,7 @@ static void lapb_remove_cb(lapb_cb *lapb)
lapb_cb *s;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
if ((s = lapb_list) == lapb) {
lapb_list = s->next;
@@ -92,8 +89,7 @@ static void lapb_insert_cb(lapb_cb *lapb)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
lapb->next = lapb_list;
lapb_list = lapb;
@@ -130,11 +126,11 @@ static lapb_cb *lapb_create_cb(void)
memset(lapb, 0x00, sizeof(*lapb));
- skb_queue_head_init(&lapb->input_queue);
skb_queue_head_init(&lapb->write_queue);
skb_queue_head_init(&lapb->ack_queue);
- init_timer(&lapb->timer);
+ init_timer(&lapb->t1timer);
+ init_timer(&lapb->t2timer);
lapb->t1 = LAPB_DEFAULT_T1;
lapb->t2 = LAPB_DEFAULT_T2;
@@ -161,9 +157,7 @@ int lapb_register(void *token, struct lapb_register_struct *callbacks)
lapb_insert_cb(lapb);
- lapb->t1timer = lapb->t1;
-
- lapb_set_timer(lapb);
+ lapb_start_t1timer(lapb);
return LAPB_OK;
}
@@ -175,7 +169,8 @@ int lapb_unregister(void *token)
if ((lapb = lapb_tokentostruct(token)) == NULL)
return LAPB_BADTOKEN;
- del_timer(&lapb->timer);
+ lapb_stop_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
lapb_clear_queues(lapb);
@@ -193,16 +188,24 @@ int lapb_getparms(void *token, struct lapb_parms_struct *parms)
if ((lapb = lapb_tokentostruct(token)) == NULL)
return LAPB_BADTOKEN;
- parms->t1 = lapb->t1;
- parms->t1timer = lapb->t1timer;
- parms->t2 = lapb->t2;
- parms->t2timer = lapb->t2timer;
+ parms->t1 = lapb->t1 / HZ;
+ parms->t2 = lapb->t2 / HZ;
parms->n2 = lapb->n2;
parms->n2count = lapb->n2count;
parms->state = lapb->state;
parms->window = lapb->window;
parms->mode = lapb->mode;
+ if (lapb->t1timer.prev == NULL && lapb->t1timer.next == NULL)
+ parms->t1timer = 0;
+ else
+ parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ;
+
+ if (lapb->t2timer.prev == NULL && lapb->t2timer.next == NULL)
+ parms->t2timer = 0;
+ else
+ parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ;
+
return LAPB_OK;
}
@@ -235,8 +238,8 @@ int lapb_setparms(void *token, struct lapb_parms_struct *parms)
lapb->window = parms->window;
}
- lapb->t1 = parms->t1;
- lapb->t2 = parms->t2;
+ lapb->t1 = parms->t1 * HZ;
+ lapb->t2 = parms->t2 * HZ;
lapb->n2 = parms->n2;
return LAPB_OK;
@@ -287,8 +290,8 @@ int lapb_disconnect_request(void *token)
printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token);
#endif
lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
- lapb->state = LAPB_STATE_0;
- lapb->t1timer = lapb->t1;
+ lapb->state = LAPB_STATE_0;
+ lapb_start_t1timer(lapb);
return LAPB_NOTCONNECTED;
case LAPB_STATE_2:
@@ -298,9 +301,9 @@ int lapb_disconnect_request(void *token)
lapb_clear_queues(lapb);
lapb->n2count = 0;
lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
- lapb->t1timer = lapb->t1;
- lapb->t2timer = 0;
- lapb->state = LAPB_STATE_2;
+ lapb_start_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
+ lapb->state = LAPB_STATE_2;
#if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->token);
@@ -336,7 +339,7 @@ int lapb_data_received(void *token, struct sk_buff *skb)
if ((lapb = lapb_tokentostruct(token)) == NULL)
return LAPB_BADTOKEN;
- skb_queue_tail(&lapb->input_queue, skb);
+ lapb_data_input(lapb, skb);
return LAPB_OK;
}
diff --git a/net/lapb/lapb_in.c b/net/lapb/lapb_in.c
index 9aa367115..126b93673 100644
--- a/net/lapb/lapb_in.c
+++ b/net/lapb/lapb_in.c
@@ -1,8 +1,5 @@
/*
- * LAPB release 001
- *
- * This is ALPHA test software. This code may break your machine, randomly fail to work with new
- * releases, misbehave and/or generally screw up. It might even work.
+ * LAPB release 002
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -14,6 +11,7 @@
*
* History
* LAPB 001 Jonathan Naulor Started Coding
+ * LAPB 002 Jonathan Naylor New timer architecture.
*/
#include <linux/config.h>
@@ -63,10 +61,10 @@ static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", lapb->token);
#endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+ lapb_stop_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
lapb->state = LAPB_STATE_3;
lapb->condition = 0x00;
- lapb->t1timer = 0;
- lapb->t2timer = 0;
lapb->n2count = 0;
lapb->vs = 0;
lapb->vr = 0;
@@ -87,10 +85,10 @@ static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", lapb->token);
#endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+ lapb_stop_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
lapb->state = LAPB_STATE_3;
lapb->condition = 0x00;
- lapb->t1timer = 0;
- lapb->t2timer = 0;
lapb->n2count = 0;
lapb->vs = 0;
lapb->vr = 0;
@@ -176,10 +174,10 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S1 -> S3\n", lapb->token);
#endif
+ lapb_stop_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
lapb->state = LAPB_STATE_3;
lapb->condition = 0x00;
- lapb->t1timer = 0;
- lapb->t2timer = 0;
lapb->n2count = 0;
lapb->vs = 0;
lapb->vr = 0;
@@ -197,9 +195,9 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token);
#endif
lapb_clear_queues(lapb);
- lapb->state = LAPB_STATE_0;
- lapb->t1timer = lapb->t1;
- lapb->t2timer = 0;
+ lapb->state = LAPB_STATE_0;
+ lapb_start_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
lapb_disconnect_indication(lapb, LAPB_REFUSED);
}
break;
@@ -243,9 +241,9 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
#endif
- lapb->state = LAPB_STATE_0;
- lapb->t1timer = lapb->t1;
- lapb->t2timer = 0;
+ lapb->state = LAPB_STATE_0;
+ lapb_start_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
lapb_disconnect_confirmation(lapb, LAPB_OK);
}
break;
@@ -258,9 +256,9 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
#endif
- lapb->state = LAPB_STATE_0;
- lapb->t1timer = lapb->t1;
- lapb->t2timer = 0;
+ lapb->state = LAPB_STATE_0;
+ lapb_start_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED);
}
break;
@@ -309,9 +307,9 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, frame->pf);
#endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+ lapb_stop_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
lapb->condition = 0x00;
- lapb->t1timer = 0;
- lapb->t2timer = 0;
lapb->n2count = 0;
lapb->vs = 0;
lapb->vr = 0;
@@ -329,9 +327,9 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, frame->pf);
#endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+ lapb_stop_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
lapb->condition = 0x00;
- lapb->t1timer = 0;
- lapb->t2timer = 0;
lapb->n2count = 0;
lapb->vs = 0;
lapb->vr = 0;
@@ -354,9 +352,9 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
#endif
lapb_clear_queues(lapb);
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
- lapb->state = LAPB_STATE_0;
- lapb->t1timer = lapb->t1;
- lapb->t2timer = 0;
+ lapb_start_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
+ lapb->state = LAPB_STATE_0;
lapb_disconnect_indication(lapb, LAPB_OK);
break;
@@ -368,9 +366,9 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token);
#endif
lapb_clear_queues(lapb);
- lapb->state = LAPB_STATE_0;
- lapb->t1timer = lapb->t1;
- lapb->t2timer = 0;
+ lapb->state = LAPB_STATE_0;
+ lapb_start_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED);
break;
@@ -389,10 +387,10 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
#endif
- lapb->state = LAPB_STATE_4;
- lapb->t1timer = lapb->t1;
- lapb->t2timer = 0;
- lapb->n2count = 0;
+ lapb_start_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
+ lapb->state = LAPB_STATE_4;
+ lapb->n2count = 0;
}
break;
@@ -411,10 +409,10 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
#endif
- lapb->state = LAPB_STATE_4;
- lapb->t1timer = lapb->t1;
- lapb->t2timer = 0;
- lapb->n2count = 0;
+ lapb_start_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
+ lapb->state = LAPB_STATE_4;
+ lapb->n2count = 0;
}
break;
@@ -426,7 +424,7 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_check_need_response(lapb, frame->cr, frame->pf);
if (lapb_validate_nr(lapb, frame->nr)) {
lapb_frames_acked(lapb, frame->nr);
- lapb->t1timer = 0;
+ lapb_stop_t1timer(lapb);
lapb->n2count = 0;
lapb_requeue_frames(lapb);
} else {
@@ -436,10 +434,10 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
#endif
- lapb->state = LAPB_STATE_4;
- lapb->t1timer = lapb->t1;
- lapb->t2timer = 0;
- lapb->n2count = 0;
+ lapb_start_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
+ lapb->state = LAPB_STATE_4;
+ lapb->n2count = 0;
}
break;
@@ -454,10 +452,10 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
#endif
- lapb->state = LAPB_STATE_4;
- lapb->t1timer = lapb->t1;
- lapb->t2timer = 0;
- lapb->n2count = 0;
+ lapb_start_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
+ lapb->state = LAPB_STATE_4;
+ lapb->n2count = 0;
break;
}
if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) {
@@ -473,8 +471,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_enquiry_response(lapb);
} else {
if (!(lapb->condition & LAPB_ACK_PENDING_CONDITION)) {
- lapb->t2timer = lapb->t2;
lapb->condition |= LAPB_ACK_PENDING_CONDITION;
+ lapb_start_t2timer(lapb);
}
}
} else {
@@ -514,10 +512,10 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
#endif
- lapb->state = LAPB_STATE_4;
- lapb->t1timer = lapb->t1;
- lapb->t2timer = 0;
- lapb->n2count = 0;
+ lapb_start_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
+ lapb->state = LAPB_STATE_4;
+ lapb->n2count = 0;
break;
default:
@@ -552,10 +550,10 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token);
#endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+ lapb_stop_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
lapb->state = LAPB_STATE_3;
lapb->condition = 0x00;
- lapb->t1timer = 0;
- lapb->t2timer = 0;
lapb->n2count = 0;
lapb->vs = 0;
lapb->vr = 0;
@@ -576,10 +574,10 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token);
#endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+ lapb_stop_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
lapb->state = LAPB_STATE_3;
lapb->condition = 0x00;
- lapb->t1timer = 0;
- lapb->t2timer = 0;
lapb->n2count = 0;
lapb->vs = 0;
lapb->vr = 0;
@@ -626,6 +624,8 @@ void lapb_data_input(lapb_cb *lapb, struct sk_buff *skb)
lapb_state4_machine(lapb, skb, &frame);
break;
}
+
+ lapb_kick(lapb);
}
#endif
diff --git a/net/lapb/lapb_out.c b/net/lapb/lapb_out.c
index 1256e3a3c..9e1cdf475 100644
--- a/net/lapb/lapb_out.c
+++ b/net/lapb/lapb_out.c
@@ -1,8 +1,5 @@
/*
- * LAPB release 001
- *
- * This is ALPHA test software. This code may break your machine, randomly fail to work with new
- * releases, misbehave and/or generally screw up. It might even work.
+ * LAPB release 002
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -14,6 +11,7 @@
*
* History
* LAPB 001 Jonathan Naylor Started Coding
+ * LAPB 002 Jonathan Naylor New timer architecture.
*/
#include <linux/config.h>
@@ -77,8 +75,6 @@ void lapb_kick(lapb_cb *lapb)
struct sk_buff *skb, *skbn;
unsigned short modulus, start, end;
- del_timer(&lapb->timer);
-
modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
start = (skb_peek(&lapb->ack_queue) == NULL) ? lapb->va : lapb->vs;
@@ -120,11 +116,9 @@ void lapb_kick(lapb_cb *lapb)
lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
- if (lapb->t1timer == 0)
- lapb->t1timer = lapb->t1;
+ if (!lapb_t1timer_running(lapb))
+ lapb_start_t1timer(lapb);
}
-
- lapb_set_timer(lapb);
}
void lapb_transmit_buffer(lapb_cb *lapb, struct sk_buff *skb, int type)
@@ -184,8 +178,8 @@ void lapb_establish_data_link(lapb_cb *lapb)
lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
}
- lapb->t2timer = 0;
- lapb->t1timer = lapb->t1;
+ lapb_start_t1timer(lapb);
+ lapb_stop_t2timer(lapb);
}
void lapb_enquiry_response(lapb_cb *lapb)
@@ -214,12 +208,12 @@ void lapb_check_iframes_acked(lapb_cb *lapb, unsigned short nr)
{
if (lapb->vs == nr) {
lapb_frames_acked(lapb, nr);
- lapb->t1timer = 0;
+ lapb_stop_t1timer(lapb);
lapb->n2count = 0;
} else {
if (lapb->va != nr) {
lapb_frames_acked(lapb, nr);
- lapb->t1timer = lapb->t1;
+ lapb_start_t1timer(lapb);
}
}
}
diff --git a/net/lapb/lapb_subr.c b/net/lapb/lapb_subr.c
index 626e08927..3f7f0a84e 100644
--- a/net/lapb/lapb_subr.c
+++ b/net/lapb/lapb_subr.c
@@ -1,8 +1,5 @@
/*
- * LAPB release 001
- *
- * This is ALPHA test software. This code may break your machine, randomly fail to work with new
- * releases, misbehave and/or generally screw up. It might even work.
+ * LAPB release 002
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -45,9 +42,6 @@ void lapb_clear_queues(lapb_cb *lapb)
{
struct sk_buff *skb;
- while ((skb = skb_dequeue(&lapb->input_queue)) != NULL)
- kfree_skb(skb, FREE_READ);
-
while ((skb = skb_dequeue(&lapb->write_queue)) != NULL)
kfree_skb(skb, FREE_WRITE);
diff --git a/net/lapb/lapb_timer.c b/net/lapb/lapb_timer.c
index 2679ff514..757fd10d9 100644
--- a/net/lapb/lapb_timer.c
+++ b/net/lapb/lapb_timer.c
@@ -1,8 +1,5 @@
/*
- * LAPB release 001
- *
- * This is ALPHA test software. This code may break your machine, randomly fail to work with new
- * releases, misbehave and/or generally screw up. It might even work.
+ * LAPB release 002
*
* This code REQUIRES 2.1.15 or higher/ NET3.038
*
@@ -14,6 +11,7 @@
*
* History
* LAPB 001 Jonathan Naylor Started Coding
+ * LAPB 002 Jonathan Naylor New timer architecture.
*/
#include <linux/config.h>
@@ -38,72 +36,60 @@
#include <linux/interrupt.h>
#include <net/lapb.h>
-static void lapb_timer(unsigned long);
+static void lapb_t1timer_expiry(unsigned long);
+static void lapb_t2timer_expiry(unsigned long);
-/*
- * Linux set timer
- */
-void lapb_set_timer(lapb_cb *lapb)
+void lapb_start_t1timer(lapb_cb *lapb)
{
- unsigned long flags;
+ del_timer(&lapb->t1timer);
+
+ lapb->t1timer.data = (unsigned long)lapb;
+ lapb->t1timer.function = &lapb_t1timer_expiry;
+ lapb->t1timer.expires = jiffies + lapb->t1;
- save_flags(flags); cli();
- del_timer(&lapb->timer);
- restore_flags(flags);
+ add_timer(&lapb->t1timer);
+}
+
+void lapb_start_t2timer(lapb_cb *lapb)
+{
+ del_timer(&lapb->t2timer);
- lapb->timer.data = (unsigned long)lapb;
- lapb->timer.function = &lapb_timer;
- lapb->timer.expires = jiffies + (HZ / 10);
+ lapb->t2timer.data = (unsigned long)lapb;
+ lapb->t2timer.function = &lapb_t2timer_expiry;
+ lapb->t2timer.expires = jiffies + lapb->t2;
- add_timer(&lapb->timer);
+ add_timer(&lapb->t2timer);
}
-/*
- * LAPB TIMER
- *
- * This routine is called every 100ms. Decrement timer by this
- * amount - if expired then process the event.
- */
-static void lapb_timer(unsigned long param)
+void lapb_stop_t1timer(lapb_cb *lapb)
+{
+ del_timer(&lapb->t1timer);
+}
+
+void lapb_stop_t2timer(lapb_cb *lapb)
+{
+ del_timer(&lapb->t2timer);
+}
+
+int lapb_t1timer_running(lapb_cb *lapb)
+{
+ return (lapb->t1timer.prev != NULL || lapb->t1timer.next != NULL);
+}
+
+static void lapb_t2timer_expiry(unsigned long param)
{
lapb_cb *lapb = (lapb_cb *)param;
- struct sk_buff *skb;
-
- /*
- * Process all packet received since the last clock tick.
- */
- while ((skb = skb_dequeue(&lapb->input_queue)) != NULL)
- lapb_data_input(lapb, skb);
-
- /*
- * If in a data transfer state, transmit any data.
- */
- if (lapb->state == LAPB_STATE_3)
- lapb_kick(lapb);
-
- /*
- * T2 expiry code.
- */
- if (lapb->t2timer > 0 && --lapb->t2timer == 0) {
- if (lapb->state == LAPB_STATE_3) {
- if (lapb->condition & LAPB_ACK_PENDING_CONDITION) {
- lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
- lapb_timeout_response(lapb);
- }
- }
- }
- /*
- * If T1 isn't running, or hasn't timed out yet, keep going.
- */
- if (lapb->t1timer == 0 || --lapb->t1timer > 0) {
- lapb_set_timer(lapb);
- return;
+ if (lapb->condition & LAPB_ACK_PENDING_CONDITION) {
+ lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
+ lapb_timeout_response(lapb);
}
+}
+
+static void lapb_t1timer_expiry(unsigned long param)
+{
+ lapb_cb *lapb = (lapb_cb *)param;
- /*
- * T1 has expired.
- */
switch (lapb->state) {
/*
@@ -120,12 +106,12 @@ static void lapb_timer(unsigned long param)
case LAPB_STATE_1:
if (lapb->n2count == lapb->n2) {
lapb_clear_queues(lapb);
- lapb->state = LAPB_STATE_0;
- lapb->t2timer = 0;
+ lapb->state = LAPB_STATE_0;
lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token);
#endif
+ return;
} else {
lapb->n2count++;
if (lapb->mode & LAPB_EXTENDED) {
@@ -148,12 +134,12 @@ static void lapb_timer(unsigned long param)
case LAPB_STATE_2:
if (lapb->n2count == lapb->n2) {
lapb_clear_queues(lapb);
- lapb->state = LAPB_STATE_0;
- lapb->t2timer = 0;
+ lapb->state = LAPB_STATE_0;
lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT);
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
#endif
+ return;
} else {
lapb->n2count++;
#if LAPB_DEBUG > 1
@@ -169,12 +155,13 @@ static void lapb_timer(unsigned long param)
case LAPB_STATE_3:
if (lapb->n2count == lapb->n2) {
lapb_clear_queues(lapb);
- lapb->state = LAPB_STATE_0;
- lapb->t2timer = 0;
+ lapb->state = LAPB_STATE_0;
+ lapb_stop_t2timer(lapb);
lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token);
#endif
+ return;
} else {
lapb->n2count++;
lapb_requeue_frames(lapb);
@@ -187,12 +174,12 @@ static void lapb_timer(unsigned long param)
case LAPB_STATE_4:
if (lapb->n2count == lapb->n2) {
lapb_clear_queues(lapb);
- lapb->state = LAPB_STATE_0;
- lapb->t2timer = 0;
+ lapb->state = LAPB_STATE_0;
lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->token);
#endif
+ return;
} else {
lapb->n2count++;
lapb_transmit_frmr(lapb);
@@ -200,9 +187,7 @@ static void lapb_timer(unsigned long param)
break;
}
- lapb->t1timer = lapb->t1;
-
- lapb_set_timer(lapb);
+ lapb_start_t1timer(lapb);
}
#endif
diff --git a/net/netlink.c b/net/netlink.c
index 539ec4295..2c7eb9dd0 100644
--- a/net/netlink.c
+++ b/net/netlink.c
@@ -68,7 +68,7 @@ int netlink_donothing(int minor, struct sk_buff *skb)
static unsigned int netlink_poll(struct file *file, poll_table * wait)
{
unsigned int mask;
- unsigned int minor = MINOR(file->f_inode->i_rdev);
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
poll_wait(&read_space_wait[minor], wait);
mask = POLLOUT | POLLWRNORM;
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};
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};
diff --git a/net/socket.c b/net/socket.c
index 2587083bc..4b722e127 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -149,7 +149,11 @@ static int sockets_in_use = 0;
#define MAX_SOCK_ADDR 128 /* 108 for Unix domain -
16 for IP, 16 for IPX,
24 for IPv6,
- about 80 for AX.25 */
+ about 80 for AX.25
+ must be at least one bigger than
+ the AF_UNIX size (see net/unix/af_unix.c
+ :unix_mkname()).
+ */
int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr)
{
@@ -206,13 +210,23 @@ static int get_fd(struct inode *inode)
return -ENFILE;
}
+ file->f_dentry = d_alloc_root(inode, NULL);
+ if (!file->f_dentry) {
+ put_filp(file);
+ put_unused_fd(fd);
+ return -ENOMEM;
+ }
+
+ /*
+ * The socket maintains a reference to the inode, so we
+ * have to increment the count.
+ */
+ inode->i_count++;
+
current->files->fd[fd] = file;
file->f_op = &socket_file_ops;
file->f_mode = 3;
file->f_flags = O_RDWR;
- file->f_inode = inode;
- if (inode)
- atomic_inc(&inode->i_count);
file->f_pos = 0;
}
return fd;
@@ -238,11 +252,11 @@ extern __inline__ struct socket *sockfd_lookup(int fd, int *err)
return NULL;
}
- inode = file->f_inode;
+ inode = file->f_dentry->d_inode;
if (!inode || !inode->i_sock || !socki_lookup(inode))
{
*err = -ENOTSOCK;
- fput(file,inode);
+ fput(file);
return NULL;
}
@@ -251,7 +265,7 @@ extern __inline__ struct socket *sockfd_lookup(int fd, int *err)
extern __inline__ void sockfd_put(struct socket *sock)
{
- fput(sock->file,sock->inode);
+ fput(sock->file);
}
/*
@@ -266,6 +280,7 @@ struct socket *sock_alloc(void)
inode = get_empty_inode();
if (!inode)
return NULL;
+
sock = socki_lookup(inode);
inode->i_mode = S_IFSOCK;
@@ -459,7 +474,7 @@ static unsigned int sock_poll(struct file *file, poll_table * wait)
{
struct socket *sock;
- sock = socki_lookup(file->f_inode);
+ sock = socki_lookup(file->f_dentry->d_inode);
/*
* We can't return errors to poll, so it's either yes or no.
@@ -1291,7 +1306,7 @@ int sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct socket *sock;
- sock = socki_lookup (filp->f_inode);
+ sock = socki_lookup (filp->f_dentry->d_inode);
if (sock && sock->ops && sock->ops->fcntl)
return sock->ops->fcntl(sock, cmd, arg);
return(-EINVAL);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 1dfdf1832..f41213ad6 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -162,8 +162,16 @@ static int unix_mkname(struct sockaddr_un * sunaddr, int len, unsigned *hashp)
return -EINVAL;
if (sunaddr->sun_path[0])
{
- if (len >= sizeof(*sunaddr))
- len = sizeof(*sunaddr)-1;
+ /*
+ * This may look like an off by one error but it is
+ * a bit more subtle. 108 is the longest valid AF_UNIX
+ * path for a binding. sun_path[108] doesnt as such
+ * exist. However in kernel space we are guaranteed that
+ * it is a valid memory location in our kernel
+ * address buffer.
+ */
+ if (len > sizeof(*sunaddr))
+ len = sizeof(*sunaddr);
((char *)sunaddr)[len]=0;
len = strlen(sunaddr->sun_path)+1+sizeof(short);
return len;
@@ -450,24 +458,18 @@ retry:
static unix_socket *unix_find_other(struct sockaddr_un *sunname, int len,
int type, unsigned hash, int *error)
{
- int old_fs;
- int err;
- struct inode *inode;
unix_socket *u;
if (sunname->sun_path[0])
{
- old_fs=get_fs();
- set_fs(get_ds());
- err = open_namei(sunname->sun_path, 2, S_IFSOCK, &inode, NULL);
- set_fs(old_fs);
- if(err<0)
- {
- *error=err;
+ struct dentry *dentry;
+ dentry = open_namei(sunname->sun_path, 2, S_IFSOCK);
+ if (IS_ERR(dentry)) {
+ *error = PTR_ERR(dentry);
return NULL;
}
- u=unix_find_socket_byinode(inode);
- iput(inode);
+ u=unix_find_socket_byinode(dentry->d_inode);
+ dput(dentry);
if (u && u->type != type)
{
*error=-EPROTOTYPE;
@@ -491,8 +493,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sock *sk = sock->sk;
struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
- struct inode * inode;
- int old_fs;
+ struct dentry * dentry;
+ struct inode * inode = NULL;
int err;
unsigned hash;
struct unix_address *addr;
@@ -545,15 +547,16 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
addr->hash = UNIX_HASH_SIZE;
sk->protinfo.af_unix.addr = addr;
- old_fs=get_fs();
- set_fs(get_ds());
- err=do_mknod(sunaddr->sun_path, S_IFSOCK|S_IRWXUGO, 0);
- if (!err)
- err=open_namei(sunaddr->sun_path, 2, S_IFSOCK, &inode, NULL);
-
- set_fs(old_fs);
-
+ dentry = do_mknod(sunaddr->sun_path, S_IFSOCK|S_IRWXUGO, 0);
+ err = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ inode = dentry->d_inode;
+ inode->i_count++; /* HATEFUL - we should use the dentry */
+ dput(dentry);
+ err = 0;
+ }
+
if(err<0)
{
unix_release_addr(addr);
@@ -799,7 +802,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
}
if (sk->protinfo.af_unix.inode)
{
- atomic_inc(&sk->protinfo.af_unix.inode->i_count);
+ sk->protinfo.af_unix.inode->i_count++; /* Should use dentry */
newsk->protinfo.af_unix.inode=sk->protinfo.af_unix.inode;
}
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 2a10304df..cf0d634bc 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -68,7 +68,7 @@ static int in_stack = 0; /* first free entry in stack */
extern inline unix_socket *unix_get_socket(struct file *filp)
{
unix_socket * u_sock = NULL;
- struct inode *inode = filp->f_inode;
+ struct inode *inode = filp->f_dentry->d_inode;
/*
* Socket ?
diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c
index 18ce57684..f487ae95a 100644
--- a/net/unix/sysctl_net_unix.c
+++ b/net/unix/sysctl_net_unix.c
@@ -13,6 +13,9 @@
#include <linux/mm.h>
#include <linux/sysctl.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_SYSCTL
extern int sysctl_unix_destroy_delay;
extern int sysctl_unix_delete_delay;
@@ -26,3 +29,4 @@ ctl_table unix_table[] = {
&proc_dointvec_jiffies},
{0}
};
+#endif
diff --git a/net/wanrouter/patchlevel b/net/wanrouter/patchlevel
index 3eefcb9dd..b2292bed7 100644
--- a/net/wanrouter/patchlevel
+++ b/net/wanrouter/patchlevel
@@ -1 +1,2 @@
-1.0.0
+1.0.3-modified
+
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 4c0042082..66b99dedc 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -11,15 +11,17 @@
*
* Author: Gene Kozin <genek@compuserve.com>
*
-* Copyright: (c) 1995-1996 Sangoma Technologies Inc.
+* Copyright: (c) 1995-1997 Sangoma Technologies Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
-* Dec 27, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE)
+* Jun 27, 1997 Alan Cox realigned with vendor code
+* Jan 16, 1997 Gene Kozin router_devlist made public
* Jan 31, 1997 Alan Cox Hacked it about a bit for 2.1
+* Dec 27, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE)
*****************************************************************************/
#include <linux/stddef.h> /* offsetof(), etc. */
@@ -78,9 +80,9 @@ static int delete_interface (wan_device_t* wandev, char* name, int forse);
*/
static char fullname[] = "WAN Router";
-static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc.";
+static char copyright[] = "(c) 1995-1997 Sangoma Technologies Inc.";
static char modname[] = ROUTER_NAME; /* short module name */
-static wan_device_t* devlist = NULL; /* list of registered devices */
+wan_device_t * router_devlist = NULL; /* list of registered devices */
static int devcnt = 0;
/*
@@ -199,8 +201,8 @@ int register_wan_device(wan_device_t* wandev)
wandev->ndev = 0;
wandev->dev = NULL;
- wandev->next = devlist;
- devlist = wandev;
+ wandev->next = router_devlist;
+ router_devlist = wandev;
++devcnt;
MOD_INC_USE_COUNT; /* prevent module from unloading */
return 0;
@@ -225,7 +227,7 @@ int unregister_wan_device(char* name)
if (name == NULL)
return -EINVAL;
- for (wandev = devlist, prev = NULL;
+ for (wandev = router_devlist, prev = NULL;
wandev && strcmp(wandev->name, name);
prev = wandev, wandev = wandev->next)
;
@@ -246,7 +248,7 @@ int unregister_wan_device(char* name)
if (prev)
prev->next = wandev->next;
else
- devlist = wandev->next;
+ router_devlist = wandev->next;
--devcnt;
wanrouter_proc_delete(wandev);
MOD_DEC_USE_COUNT;
@@ -613,7 +615,7 @@ static wan_device_t* find_device (char* name)
{
wan_device_t* wandev;
- for (wandev = devlist;wandev && strcmp(wandev->name, name);
+ for (wandev = router_devlist;wandev && strcmp(wandev->name, name);
wandev = wandev->next);
return wandev;
}
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
index 04a49d803..9c3fe9b2a 100644
--- a/net/wanrouter/wanproc.c
+++ b/net/wanrouter/wanproc.c
@@ -1,20 +1,22 @@
/*****************************************************************************
-* wanproc.c WAN Multiprotocol Router Module. proc filesystem interface.
+* wanproc.c WAN Router Module. /proc filesystem interface.
*
* This module is completely hardware-independent and provides
* access to the router using Linux /proc filesystem.
*
* Author: Gene Kozin <genek@compuserve.com>
*
-* Copyright: (c) 1995-1996 Sangoma Technologies Inc.
+* Copyright: (c) 1995-1997 Sangoma Technologies Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
-* Dec 13, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE)
+* Jun 29, 1997 Alan Cox Merged with 1.0.3 vendor code
+* Jan 29, 1997 Gene Kozin v1.0.1. Implemented /proc read routines
* Jan 30, 1997 Alan Cox Hacked around for 2.1
+* Dec 13, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE)
*****************************************************************************/
#include <linux/stddef.h> /* offsetof(), etc. */
@@ -39,7 +41,7 @@
#define max(a,b) (((a)>(b))?(a):(b))
#endif
-#define ROUTER_PAGE_SZ 4000 /* buffer size for printing proc info */
+#define PROC_BUFSZ 4000 /* buffer size for printing proc info */
/****** Data Types **********************************************************/
@@ -60,7 +62,6 @@ static long router_proc_read(struct inode* inode, struct file* file, char* buf,
/* Methods for preparing data for reading proc entries */
-static int about_get_info(char* buf, char** start, off_t offs, int len, int dummy);
static int config_get_info(char* buf, char** start, off_t offs, int len, int dummy);
static int status_get_info(char* buf, char** start, off_t offs, int len, int dummy);
static int wandev_get_info(char* buf, char** start, off_t offs, int len, int dummy);
@@ -76,7 +77,6 @@ static int wandev_get_info(char* buf, char** start, off_t offs, int len, int dum
*/
static char name_root[] = ROUTER_NAME;
-static char name_info[] = "about";
static char name_conf[] = "config";
static char name_stat[] = "status";
@@ -84,9 +84,8 @@ static char name_stat[] = "status";
* Structures for interfacing with the /proc filesystem.
* Router creates its own directory /proc/net/router with the folowing
* entries:
- * About general information (version, copyright, etc.)
- * Conf device configuration
- * Stat global device statistics
+ * config device configuration
+ * status global device statistics
* <device> entry for each WAN device
*/
@@ -194,29 +193,6 @@ static struct proc_dir_entry proc_router =
};
/*
- * /proc/net/router/about
- */
-
-static struct proc_dir_entry proc_router_info =
-{
- 0, /* .low_ino */
- sizeof(name_info) - 1, /* .namelen */
- name_info, /* .name */
- 0444 | S_IFREG, /* .mode */
- 1, /* .nlink */
- 0, /* .uid */
- 0, /* .gid */
- 0, /* .size */
- &router_inode, /* .ops */
- &about_get_info, /* .get_info */
- NULL, /* .fill_node */
- NULL, /* .next */
- NULL, /* .parent */
- NULL, /* .subdir */
- NULL, /* .data */
-};
-
-/*
* /proc/net/router/config
*/
@@ -262,6 +238,16 @@ static struct proc_dir_entry proc_router_stat =
NULL, /* .data */
};
+/* Strings */
+static char conf_hdr[] =
+ "Device name | port |IRQ|DMA|mem.addr|mem.size|"
+ "option1|option2|option3|option4\n";
+
+static char stat_hdr[] =
+ "Device name |station|interface|clocking|baud rate| MTU |ndev"
+ "|link state\n";
+
+
/*
* Interface functions
*/
@@ -272,11 +258,10 @@ static struct proc_dir_entry proc_router_stat =
__initfunc(int wanrouter_proc_init (void))
{
- int err = proc_register(&proc_net, &proc_router);
+ int err = proc_register(proc_net, &proc_router);
if (!err)
{
- proc_register(&proc_router, &proc_router_info);
proc_register(&proc_router, &proc_router_conf);
proc_register(&proc_router, &proc_router_stat);
}
@@ -289,10 +274,9 @@ __initfunc(int wanrouter_proc_init (void))
void wanrouter_proc_cleanup (void)
{
- proc_unregister(&proc_router, proc_router_info.low_ino);
proc_unregister(&proc_router, proc_router_conf.low_ino);
proc_unregister(&proc_router, proc_router_stat.low_ino);
- proc_unregister(&proc_net, proc_router.low_ino);
+ proc_unregister(proc_net, proc_router.low_ino);
}
/*
@@ -367,7 +351,7 @@ static long router_proc_read(struct inode* inode, struct file* file,
if ((dent == NULL) || (dent->get_info == NULL))
return 0;
- page = kmalloc(ROUTER_PAGE_SZ, GFP_KERNEL);
+ page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
if (page == NULL)
return -ENOBUFS;
@@ -387,49 +371,86 @@ static long router_proc_read(struct inode* inode, struct file* file,
}
/*
- * Prepare data for reading 'About' entry.
- * Return length of data.
- */
-
-static int about_get_info(char* buf, char** start, off_t offs, int len,
- int dummy)
-{
- int cnt = 0;
-
- cnt += sprintf(&buf[cnt], "%12s : %u.%u\n",
- "version", ROUTER_VERSION, ROUTER_RELEASE);
- return cnt;
-}
-
-/*
* Prepare data for reading 'Config' entry.
* Return length of data.
- * NOT YET IMPLEMENTED
*/
static int config_get_info(char* buf, char** start, off_t offs, int len,
int dummy)
{
- int cnt = 0;
+ int cnt = sizeof(conf_hdr) - 1;
+ wan_device_t* wandev;
+ strcpy(buf, conf_hdr);
+ for (wandev = router_devlist;
+ wandev && (cnt < (PROC_BUFSZ - 80));
+ wandev = wandev->next)
+ {
+ if (wandev->state) cnt += sprintf(&buf[cnt],
+ "%-15s|0x%-4X|%3u|%3u|0x%-6lX|0x%-6X|%7u|%7u|%7u|%7u\n",
+ wandev->name,
+ wandev->ioport,
+ wandev->irq,
+ wandev->dma,
+ wandev->maddr,
+ wandev->msize,
+ wandev->hw_opt[0],
+ wandev->hw_opt[1],
+ wandev->hw_opt[2],
+ wandev->hw_opt[3]);
+ }
- cnt += sprintf(&buf[cnt], "%12s : %u.%u\n",
- "version", ROUTER_VERSION, ROUTER_RELEASE);
return cnt;
}
/*
* Prepare data for reading 'Status' entry.
* Return length of data.
- * NOT YET IMPLEMENTED
*/
static int status_get_info(char* buf, char** start, off_t offs, int len,
int dummy)
{
- int cnt = 0;
-
- cnt += sprintf(&buf[cnt], "%12s : %u.%u\n",
- "version", ROUTER_VERSION, ROUTER_RELEASE);
+ int cnt = sizeof(stat_hdr) - 1;
+ wan_device_t* wandev;
+ strcpy(buf, stat_hdr);
+ for (wandev = router_devlist;
+ wandev && (cnt < (PROC_BUFSZ - 80));
+ wandev = wandev->next)
+ {
+ if (!wandev->state) continue;
+ cnt += sprintf(&buf[cnt],
+ "%-15s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
+ wandev->name,
+ wandev->station ? " DCE" : " DTE",
+ wandev->interface ? " V.35" : " RS-232",
+ wandev->clocking ? "internal" : "external",
+ wandev->bps,
+ wandev->mtu,
+ wandev->ndev)
+ ;
+ switch (wandev->state)
+ {
+ case WAN_UNCONFIGURED:
+ cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured");
+ break;
+
+ case WAN_DISCONNECTED:
+ cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected");
+ break;
+
+ case WAN_CONNECTING:
+ cnt += sprintf(&buf[cnt], "%-12s\n", "connecting");
+ break;
+
+ case WAN_CONNECTED:
+ cnt += sprintf(&buf[cnt], "%-12s\n", "connected");
+ break;
+
+ default:
+ cnt += sprintf(&buf[cnt], "%-12s\n", "invalid");
+ break;
+ }
+ }
return cnt;
}
@@ -449,7 +470,52 @@ static int wandev_get_info(char* buf, char** start, off_t offs, int len,
if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
return 0;
- cnt += sprintf(&buf[cnt], "%12s : %s\n", "name", wandev->name);
+ if (!wandev->state)
+ return sprintf(&buf[cnt], "device is not configured!\n")
+ ;
+
+ /* Update device statistics */
+ if (wandev->update) wandev->update(wandev);
+
+ cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+ "total frames received", wandev->stats.rx_packets)
+ ;
+ cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+ "receiver overrun errors", wandev->stats.rx_over_errors)
+ ;
+ cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+ "CRC errors", wandev->stats.rx_crc_errors)
+ ;
+ cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+ "frame length errors", wandev->stats.rx_length_errors)
+ ;
+ cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+ "frame format errors", wandev->stats.rx_frame_errors)
+ ;
+ cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+ "aborted frames received", wandev->stats.rx_missed_errors)
+ ;
+ cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+ "reveived frames dropped", wandev->stats.rx_dropped)
+ ;
+ cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+ "other receive errors", wandev->stats.rx_errors)
+ ;
+ cnt += sprintf(&buf[cnt], "\n%30s: %12lu\n",
+ "total frames transmitted", wandev->stats.tx_packets)
+ ;
+ cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+ "aborted frames transmitted", wandev->stats.tx_aborted_errors)
+ ;
+ cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+ "transmit frames dropped", wandev->stats.tx_dropped)
+ ;
+ cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+ "transmit collisions", wandev->stats.collisions)
+ ;
+ cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+ "other transmit errors", wandev->stats.tx_errors)
+ ;
return cnt;
}
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index a77380648..f59dd3a51 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1,5 +1,5 @@
/*
- * X.25 Packet Layer release 001
+ * X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
@@ -14,6 +14,8 @@
*
* History
* X.25 001 Jonathan Naylor Started coding.
+ * X.25 002 Jonathan Naylor Centralised disconnect handling.
+ * New timer architecture.
*/
#include <linux/config.h>
@@ -54,8 +56,6 @@ int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22;
int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23;
int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2;
-static unsigned int lci = 1;
-
static struct sock *volatile x25_list = NULL;
static struct proto_ops x25_proto_ops;
@@ -173,16 +173,9 @@ static void x25_kill_by_device(struct device *dev)
{
struct sock *s;
- for (s = x25_list; s != NULL; s = s->next) {
- if (s->protinfo.x25->neighbour->dev == dev) {
- s->protinfo.x25->state = X25_STATE_0;
- s->state = TCP_CLOSE;
- s->err = ENETUNREACH;
- s->shutdown |= SEND_SHUTDOWN;
- s->state_change(s);
- s->dead = 1;
- }
- }
+ for (s = x25_list; s != NULL; s = s->next)
+ if (s->protinfo.x25->neighbour->dev == dev)
+ x25_disconnect(s, ENETUNREACH, 0, 0);
}
/*
@@ -254,9 +247,9 @@ static struct sock *x25_find_listener(x25_address *addr)
}
/*
- * Find a connected X.25 socket given my LCI.
+ * Find a connected X.25 socket given my LCI and neighbour.
*/
-struct sock *x25_find_socket(unsigned int lci)
+struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh)
{
struct sock *s;
unsigned long flags;
@@ -265,7 +258,7 @@ struct sock *x25_find_socket(unsigned int lci)
cli();
for (s = x25_list; s != NULL; s = s->next) {
- if (s->protinfo.x25->lci == lci) {
+ if (s->protinfo.x25->lci == lci && s->protinfo.x25->neighbour == neigh) {
restore_flags(flags);
return s;
}
@@ -278,14 +271,13 @@ struct sock *x25_find_socket(unsigned int lci)
/*
* Find a unique LCI for a given device.
*/
-unsigned int x25_new_lci(void)
+unsigned int x25_new_lci(struct x25_neigh *neigh)
{
- lci++;
- if (lci > 4095) lci = 1;
+ unsigned int lci = 1;
- while (x25_find_socket(lci) != NULL) {
+ while (x25_find_socket(lci, neigh) != NULL) {
lci++;
- if (lci > 4095) lci = 1;
+ if (lci == 4096) return 0;
}
return lci;
@@ -318,7 +310,8 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
save_flags(flags);
cli();
- del_timer(&sk->timer);
+ x25_stop_heartbeat(sk);
+ x25_stop_timer(sk);
x25_remove_socket(sk);
x25_clear_queues(sk); /* Flush the queues */
@@ -326,7 +319,7 @@ void x25_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 */
- x25_set_timer(skb->sk);
+ x25_start_heartbeat(skb->sk);
skb->sk->protinfo.x25->state = X25_STATE_0;
}
@@ -469,6 +462,8 @@ static int x25_create(struct socket *sock, int protocol)
sock_init_data(sock, sk);
+ init_timer(&x25->timer);
+
sock->ops = &x25_proto_ops;
sk->protocol = protocol;
sk->mtu = X25_DEFAULT_PACKET_SIZE; /* X25_PS128 */
@@ -523,6 +518,8 @@ static struct sock *x25_make_new(struct sock *osk)
x25->qbitincl = osk->protinfo.x25->qbitincl;
+ init_timer(&x25->timer);
+
return sk;
}
@@ -545,28 +542,17 @@ static int x25_release(struct socket *sock, struct socket *peer)
switch (sk->protinfo.x25->state) {
case X25_STATE_0:
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
- sk->state_change(sk);
- sk->dead = 1;
- x25_destroy_socket(sk);
- break;
-
case X25_STATE_2:
- sk->protinfo.x25->state = X25_STATE_0;
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
- sk->state_change(sk);
- sk->dead = 1;
+ x25_disconnect(sk, 0, 0, 0);
x25_destroy_socket(sk);
- break;
+ break;
case X25_STATE_1:
case X25_STATE_3:
case X25_STATE_4:
x25_clear_queues(sk);
x25_write_internal(sk, X25_CLEAR_REQUEST);
- sk->protinfo.x25->timer = sk->protinfo.x25->t23;
+ x25_start_t23timer(sk);
sk->protinfo.x25->state = X25_STATE_2;
sk->state = TCP_CLOSE;
sk->shutdown |= SEND_SHUTDOWN;
@@ -644,6 +630,9 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
if ((sk->protinfo.x25->neighbour = x25_get_neigh(dev)) == NULL)
return -ENETUNREACH;
+ if ((sk->protinfo.x25->lci = x25_new_lci(sk->protinfo.x25->neighbour)) == 0)
+ return -ENETUNREACH;
+
if (sk->zapped) /* Must bind first - autobinding does not work */
return -EINVAL;
@@ -651,17 +640,17 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
memset(&sk->protinfo.x25->source_addr, '\0', X25_ADDR_LEN);
sk->protinfo.x25->dest_addr = addr->sx25_addr;
- sk->protinfo.x25->lci = x25_new_lci();
/* Move to connecting socket, start sending Connect Requests */
sock->state = SS_CONNECTING;
sk->state = TCP_SYN_SENT;
sk->protinfo.x25->state = X25_STATE_1;
- sk->protinfo.x25->timer = sk->protinfo.x25->t21;
+
x25_write_internal(sk, X25_CALL_REQUEST);
- x25_set_timer(sk);
+ x25_start_heartbeat(sk);
+ x25_start_t21timer(sk);
/* Now the loop */
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
@@ -850,7 +839,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
skb_queue_head(&sk->receive_queue, skb);
- x25_set_timer(make);
+ x25_start_heartbeat(make);
if (!sk->dead)
sk->data_ready(sk, skb->len);
@@ -987,8 +976,7 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
x25_output(sk, skb);
}
- if (sk->protinfo.x25->state == X25_STATE_3)
- x25_kick(sk);
+ x25_kick(sk);
return len;
}
@@ -1072,30 +1060,27 @@ static int x25_shutdown(struct socket *sk, int how)
static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
- struct x25_facilities facilities;
- struct x25_calluserdata calluserdata;
struct sock *sk = sock->sk;
- int err;
- long amount = 0;
switch (cmd) {
- case TIOCOUTQ:
- if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0)
- return err;
+ case TIOCOUTQ: {
+ long amount;
amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
if (amount < 0)
amount = 0;
- put_user(amount, (unsigned long *)arg);
+ if (put_user(amount, (unsigned long *)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 long))) != 0)
- return err;
- put_user(amount, (unsigned long *)arg);
+ amount = skb->len;
+ if (put_user(amount, (unsigned long *)arg))
+ return -EFAULT;
return 0;
}
@@ -1103,9 +1088,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
if (sk != NULL) {
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;
@@ -1134,17 +1118,18 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
if (!suser()) return -EPERM;
return x25_subscr_ioctl(cmd, (void *)arg);
- case SIOCX25GFACILITIES:
- if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(facilities))) != 0)
- return err;
+ case SIOCX25GFACILITIES: {
+ struct x25_facilities facilities;
facilities = sk->protinfo.x25->facilities;
- copy_to_user((void *)arg, &facilities, sizeof(facilities));
+ if (copy_to_user((void *)arg, &facilities, sizeof(facilities)))
+ return -EFAULT;
return 0;
+ }
- case SIOCX25SFACILITIES:
- if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(facilities))) != 0)
- return err;
- copy_from_user(&facilities, (void *)arg, sizeof(facilities));
+ case SIOCX25SFACILITIES: {
+ struct x25_facilities facilities;
+ if (copy_from_user(&facilities, (void *)arg, sizeof(facilities)))
+ return -EFAULT;
if (sk->state != TCP_LISTEN)
return -EINVAL;
if (facilities.pacsize_in < X25_PS16 || facilities.pacsize_in > X25_PS4096)
@@ -1168,22 +1153,33 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return -EINVAL;
sk->protinfo.x25->facilities = facilities;
return 0;
+ }
- case SIOCX25GCALLUSERDATA:
- if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(calluserdata))) != 0)
- return err;
+ case SIOCX25GCALLUSERDATA: {
+ struct x25_calluserdata calluserdata;
calluserdata = sk->protinfo.x25->calluserdata;
- copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata));
+ if (copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata)))
+ return -EFAULT;
return 0;
+ }
- case SIOCX25SCALLUSERDATA:
- if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(calluserdata))) != 0)
- return err;
- copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata));
+ case SIOCX25SCALLUSERDATA: {
+ struct x25_calluserdata calluserdata;
+ if (copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata)))
+ return -EFAULT;
if (calluserdata.cudlength > X25_MAX_CUD_LEN)
return -EINVAL;
sk->protinfo.x25->calluserdata = calluserdata;
return 0;
+ }
+
+ case SIOCX25GCAUSEDIAG: {
+ struct x25_causediag causediag;
+ causediag = sk->protinfo.x25->causediag;
+ if (copy_to_user((void *)arg, &causediag, sizeof(causediag)))
+ return -EFAULT;
+ return 0;
+ }
default:
return dev_ioctl(cmd, (void *)arg);
@@ -1212,18 +1208,22 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length, in
else
devname = s->protinfo.x25->neighbour->dev->name;
- len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X %d %d %d %d %3d %3d %3d %3d %3d %5d %5d\n",
+ len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X %d %d %d %d %3lu %3lu %3lu %3lu %3lu %5d %5d\n",
(s->protinfo.x25->dest_addr.x25_addr[0] == '\0') ? "*" : s->protinfo.x25->dest_addr.x25_addr,
(s->protinfo.x25->source_addr.x25_addr[0] == '\0') ? "*" : s->protinfo.x25->source_addr.x25_addr,
- devname, s->protinfo.x25->lci & 0x0FFF,
+ devname,
+ s->protinfo.x25->lci & 0x0FFF,
s->protinfo.x25->state,
- s->protinfo.x25->vs, s->protinfo.x25->vr, s->protinfo.x25->va,
- s->protinfo.x25->timer / X25_SLOWHZ,
- s->protinfo.x25->t2 / X25_SLOWHZ,
- s->protinfo.x25->t21 / X25_SLOWHZ,
- s->protinfo.x25->t22 / X25_SLOWHZ,
- s->protinfo.x25->t23 / X25_SLOWHZ,
- atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc));
+ s->protinfo.x25->vs,
+ s->protinfo.x25->vr,
+ s->protinfo.x25->va,
+ x25_display_timer(s) / HZ,
+ s->protinfo.x25->t2 / HZ,
+ s->protinfo.x25->t21 / HZ,
+ s->protinfo.x25->t22 / HZ,
+ s->protinfo.x25->t23 / HZ,
+ atomic_read(&s->wmem_alloc),
+ atomic_read(&s->rmem_alloc));
pos = begin + len;
@@ -1310,7 +1310,7 @@ __initfunc(void x25_proto_init(struct net_proto *pro))
register_netdevice_notifier(&x25_dev_notifier);
- printk(KERN_INFO "X.25 for Linux. Version 0.1 for Linux 2.1.15\n");
+ printk(KERN_INFO "X.25 for Linux. Version 0.2 for Linux 2.1.15\n");
#ifdef CONFIG_SYSCTL
x25_register_sysctl();
diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c
index 8454ac9d9..42893df32 100644
--- a/net/x25/sysctl_net_x25.c
+++ b/net/x25/sysctl_net_x25.c
@@ -13,8 +13,8 @@
#include <linux/init.h>
#include <net/x25.h>
-static int min_timer[] = {1 * X25_SLOWHZ};
-static int max_timer[] = {300 * X25_SLOWHZ};
+static int min_timer[] = {1 * HZ};
+static int max_timer[] = {300 * HZ};
static struct ctl_table_header *x25_table_header;
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index 6b02a9441..e4cd99ae7 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -1,5 +1,5 @@
/*
- * X.25 Packet Layer release 001
+ * X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
@@ -73,7 +73,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
/*
* Find an existing socket.
*/
- if ((sk = x25_find_socket(lci)) != NULL) {
+ if ((sk = x25_find_socket(lci, neigh)) != NULL) {
skb->h.raw = skb->data;
return x25_process_rx_frame(sk, skb);
}
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
index 13759d1ea..af072ce22 100644
--- a/net/x25/x25_facilities.c
+++ b/net/x25/x25_facilities.c
@@ -1,5 +1,5 @@
/*
- * X.25 Packet Layer release 001
+ * X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
index 82e5c0817..96b459a4e 100644
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -1,5 +1,5 @@
/*
- * X.25 Packet Layer release 001
+ * X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
@@ -14,6 +14,8 @@
*
* History
* X.25 001 Jonathan Naylor Started coding.
+ * X.25 002 Jonathan Naylor Centralised disconnection code.
+ * New timer architecture.
*/
#include <linux/config.h>
@@ -88,8 +90,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
switch (frametype) {
case X25_CALL_ACCEPTED:
+ x25_stop_timer(sk);
sk->protinfo.x25->condition = 0x00;
- sk->protinfo.x25->timer = 0;
sk->protinfo.x25->vs = 0;
sk->protinfo.x25->va = 0;
sk->protinfo.x25->vr = 0;
@@ -114,15 +116,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
break;
case X25_CLEAR_REQUEST:
- x25_clear_queues(sk);
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
- sk->protinfo.x25->state = X25_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = ECONNREFUSED;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
break;
default:
@@ -143,15 +138,11 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp
case X25_CLEAR_REQUEST:
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
+ x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
+ break;
+
case X25_CLEAR_CONFIRMATION:
- x25_clear_queues(sk);
- sk->protinfo.x25->state = X25_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = 0;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ x25_disconnect(sk, 0, 0, 0);
break;
default:
@@ -177,8 +168,8 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
case X25_RESET_REQUEST:
x25_write_internal(sk, X25_RESET_CONFIRMATION);
+ x25_stop_timer(sk);
sk->protinfo.x25->condition = 0x00;
- sk->protinfo.x25->timer = 0;
sk->protinfo.x25->vs = 0;
sk->protinfo.x25->vr = 0;
sk->protinfo.x25->va = 0;
@@ -186,15 +177,8 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
break;
case X25_CLEAR_REQUEST:
- x25_clear_queues(sk);
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
- sk->protinfo.x25->state = X25_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = 0;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
break;
case X25_RR:
@@ -207,13 +191,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
if (!x25_validate_nr(sk, nr)) {
x25_clear_queues(sk);
x25_write_internal(sk, X25_RESET_REQUEST);
+ x25_start_t22timer(sk);
sk->protinfo.x25->condition = 0x00;
sk->protinfo.x25->vs = 0;
sk->protinfo.x25->vr = 0;
sk->protinfo.x25->va = 0;
sk->protinfo.x25->vl = 0;
sk->protinfo.x25->state = X25_STATE_4;
- sk->protinfo.x25->timer = sk->protinfo.x25->t22;
} else {
if (sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) {
sk->protinfo.x25->va = nr;
@@ -228,13 +212,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
if (!x25_validate_nr(sk, nr)) {
x25_clear_queues(sk);
x25_write_internal(sk, X25_RESET_REQUEST);
+ x25_start_t22timer(sk);
sk->protinfo.x25->condition = 0x00;
sk->protinfo.x25->vs = 0;
sk->protinfo.x25->vr = 0;
sk->protinfo.x25->va = 0;
sk->protinfo.x25->vl = 0;
sk->protinfo.x25->state = X25_STATE_4;
- sk->protinfo.x25->timer = sk->protinfo.x25->t22;
break;
}
if (sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) {
@@ -258,11 +242,11 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
*/
if (((sk->protinfo.x25->vl + sk->protinfo.x25->facilities.winsize_in) % modulus) == sk->protinfo.x25->vr) {
sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
- sk->protinfo.x25->timer = 0;
+ x25_stop_timer(sk);
x25_enquiry_response(sk);
} else {
sk->protinfo.x25->condition |= X25_COND_ACK_PENDING;
- sk->protinfo.x25->timer = sk->protinfo.x25->t2;
+ x25_start_t2timer(sk);
}
break;
@@ -307,7 +291,7 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
case X25_RESET_REQUEST:
x25_write_internal(sk, X25_RESET_CONFIRMATION);
case X25_RESET_CONFIRMATION:
- sk->protinfo.x25->timer = 0;
+ x25_stop_timer(sk);
sk->protinfo.x25->condition = 0x00;
sk->protinfo.x25->va = 0;
sk->protinfo.x25->vr = 0;
@@ -317,16 +301,8 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
break;
case X25_CLEAR_REQUEST:
- x25_clear_queues(sk);
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
- sk->protinfo.x25->timer = 0;
- sk->protinfo.x25->state = X25_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = 0;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
break;
default:
@@ -344,8 +320,6 @@ int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
if (sk->protinfo.x25->state == X25_STATE_0)
return 0;
- del_timer(&sk->timer);
-
frametype = x25_decode(sk, skb, &ns, &nr, &q, &d, &m);
switch (sk->protinfo.x25->state) {
@@ -363,7 +337,7 @@ int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
break;
}
- x25_set_timer(sk);
+ x25_kick(sk);
return queued;
}
diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c
index f44c0a2c5..1742d802f 100644
--- a/net/x25/x25_link.c
+++ b/net/x25/x25_link.c
@@ -1,5 +1,5 @@
/*
- * X.25 Packet Layer release 001
+ * X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
@@ -14,6 +14,7 @@
*
* History
* X.25 001 Jonathan Naylor Started coding.
+ * X.25 002 Jonathan Naylor New timer architecture.
*/
#include <linux/config.h>
@@ -43,49 +44,34 @@
static struct x25_neigh *x25_neigh_list = NULL;
-static void x25_link_timer(unsigned long);
+static void x25_t20timer_expiry(unsigned long);
/*
* Linux set/reset timer routines
*/
-static void x25_link_set_timer(struct x25_neigh *neigh)
+static void x25_start_t20timer(struct x25_neigh *neigh)
{
- unsigned long flags;
-
- save_flags(flags); cli();
- del_timer(&neigh->timer);
- restore_flags(flags);
+ del_timer(&neigh->t20timer);
- neigh->timer.data = (unsigned long)neigh;
- neigh->timer.function = &x25_link_timer;
- neigh->timer.expires = jiffies + (HZ / 1);
+ neigh->t20timer.data = (unsigned long)neigh;
+ neigh->t20timer.function = &x25_t20timer_expiry;
+ neigh->t20timer.expires = jiffies + neigh->t20;
- add_timer(&neigh->timer);
+ add_timer(&neigh->t20timer);
}
-/*
- * X.25 Link TIMER
- *
- * This routine is called every second. Decrement timer by this
- * amount - if expired then process the event.
- */
-static void x25_link_timer(unsigned long param)
+static void x25_t20timer_expiry(unsigned long param)
{
struct x25_neigh *neigh = (struct x25_neigh *)param;
- if (neigh->t20timer == 0 || --neigh->t20timer > 0) {
- x25_link_set_timer(neigh);
- return;
- }
-
- /*
- * T20 for a link has expired.
- */
x25_transmit_restart_request(neigh);
- neigh->t20timer = neigh->t20;
+ x25_start_t20timer(neigh);
+}
- x25_link_set_timer(neigh);
+static void x25_stop_t20timer(struct x25_neigh *neigh)
+{
+ del_timer(&neigh->t20timer);
}
/*
@@ -97,16 +83,14 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *neigh, unsigned sho
switch (frametype) {
case X25_RESTART_REQUEST:
- neigh->t20timer = 0;
- neigh->state = X25_LINK_STATE_3;
- del_timer(&neigh->timer);
+ x25_stop_t20timer(neigh);
+ neigh->state = X25_LINK_STATE_3;
x25_transmit_restart_confirmation(neigh);
break;
case X25_RESTART_CONFIRMATION:
- neigh->t20timer = 0;
- neigh->state = X25_LINK_STATE_3;
- del_timer(&neigh->timer);
+ x25_stop_t20timer(neigh);
+ neigh->state = X25_LINK_STATE_3;
break;
case X25_DIAGNOSTIC:
@@ -272,9 +256,8 @@ void x25_link_established(struct x25_neigh *neigh)
break;
case X25_LINK_STATE_1:
x25_transmit_restart_request(neigh);
- neigh->state = X25_LINK_STATE_2;
- neigh->t20timer = neigh->t20;
- x25_link_set_timer(neigh);
+ neigh->state = X25_LINK_STATE_2;
+ x25_start_t20timer(neigh);
break;
}
}
@@ -300,12 +283,12 @@ void x25_link_device_up(struct device *dev)
return;
skb_queue_head_init(&x25_neigh->queue);
- init_timer(&x25_neigh->timer);
+
+ init_timer(&x25_neigh->t20timer);
x25_neigh->dev = dev;
x25_neigh->state = X25_LINK_STATE_0;
x25_neigh->extended = 0;
- x25_neigh->t20timer = 0;
x25_neigh->t20 = sysctl_x25_restart_request_timeout;
save_flags(flags); cli();
@@ -323,10 +306,9 @@ static void x25_remove_neigh(struct x25_neigh *x25_neigh)
while ((skb = skb_dequeue(&x25_neigh->queue)) != NULL)
kfree_skb(skb, FREE_WRITE);
- del_timer(&x25_neigh->timer);
+ x25_stop_t20timer(x25_neigh);
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
if ((s = x25_neigh_list) == x25_neigh) {
x25_neigh_list = x25_neigh->next;
@@ -387,25 +369,22 @@ int x25_subscr_ioctl(unsigned int cmd, void *arg)
struct x25_subscrip_struct x25_subscr;
struct x25_neigh *x25_neigh;
struct device *dev;
- int err;
switch (cmd) {
case SIOCX25GSUBSCRIP:
- if ((err = verify_area(VERIFY_WRITE, arg, sizeof(struct x25_subscrip_struct))) != 0)
- return err;
if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
return -EINVAL;
if ((x25_neigh = x25_get_neigh(dev)) == NULL)
return -EINVAL;
x25_subscr.extended = x25_neigh->extended;
- copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct));
+ if (copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct)))
+ return -EFAULT;
break;
case SIOCX25SSUBSCRIP:
- if ((err = verify_area(VERIFY_READ, arg, sizeof(struct x25_subscrip_struct))) != 0)
- return err;
- copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct));
+ if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
+ return -EFAULT;
if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
return -EINVAL;
if ((x25_neigh = x25_get_neigh(dev)) == NULL)
diff --git a/net/x25/x25_out.c b/net/x25/x25_out.c
index 321baa5d6..aa8fc2c1b 100644
--- a/net/x25/x25_out.c
+++ b/net/x25/x25_out.c
@@ -1,5 +1,5 @@
/*
- * X.25 Packet Layer release 001
+ * X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
@@ -14,6 +14,7 @@
*
* History
* X.25 001 Jonathan Naylor Started coding.
+ * X.25 002 Jonathan Naylor New timer architecture.
*/
#include <linux/config.h>
@@ -129,7 +130,8 @@ void x25_kick(struct sock *sk)
unsigned short end;
int modulus;
- del_timer(&sk->timer);
+ if (sk->protinfo.x25->state != X25_STATE_3)
+ return;
/*
* Transmit interrupt data.
@@ -140,38 +142,39 @@ void x25_kick(struct sock *sk)
x25_transmit_link(skb, sk->protinfo.x25->neighbour);
}
+ if (sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY)
+ return;
+
+ if (skb_peek(&sk->write_queue) == NULL)
+ return;
+
modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
end = (sk->protinfo.x25->va + sk->protinfo.x25->facilities.winsize_out) % modulus;
+ if (sk->protinfo.x25->vs == end)
+ return;
+
/*
- * Transmit normal stream data.
+ * Transmit data until either we're out of data to send or
+ * the window is full.
*/
- if (!(sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) &&
- sk->protinfo.x25->vs != end &&
- skb_peek(&sk->write_queue) != NULL) {
- /*
- * Transmit data until either we're out of data to send or
- * the window is full.
- */
- skb = skb_dequeue(&sk->write_queue);
+ skb = skb_dequeue(&sk->write_queue);
- do {
- /*
- * Transmit the frame.
- */
- x25_send_iframe(sk, skb);
+ do {
+ /*
+ * Transmit the frame.
+ */
+ x25_send_iframe(sk, skb);
- sk->protinfo.x25->vs = (sk->protinfo.x25->vs + 1) % modulus;
+ sk->protinfo.x25->vs = (sk->protinfo.x25->vs + 1) % modulus;
- } while (sk->protinfo.x25->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
+ } while (sk->protinfo.x25->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
- sk->protinfo.x25->vl = sk->protinfo.x25->vr;
- sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
- sk->protinfo.x25->timer = 0;
- }
+ sk->protinfo.x25->vl = sk->protinfo.x25->vr;
+ sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
- x25_set_timer(sk);
+ x25_stop_timer(sk);
}
/*
@@ -188,7 +191,8 @@ void x25_enquiry_response(struct sock *sk)
sk->protinfo.x25->vl = sk->protinfo.x25->vr;
sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
- sk->protinfo.x25->timer = 0;
+
+ x25_stop_timer(sk);
}
void x25_check_iframes_acked(struct sock *sk, unsigned short nr)
diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c
index 820c11cd4..9c3204537 100644
--- a/net/x25/x25_route.c
+++ b/net/x25/x25_route.c
@@ -1,5 +1,5 @@
/*
- * X.25 Packet Layer release 001
+ * X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
@@ -183,14 +183,12 @@ int x25_route_ioctl(unsigned int cmd, void *arg)
{
struct x25_route_struct x25_route;
struct device *dev;
- int err;
switch (cmd) {
case SIOCADDRT:
- if ((err = verify_area(VERIFY_READ, arg, sizeof(struct x25_route_struct))) != 0)
- return err;
- copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct));
+ if (copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct)))
+ return -EFAULT;
if (x25_route.sigdigits < 0 || x25_route.sigdigits > 15)
return -EINVAL;
if ((dev = x25_dev_get(x25_route.device)) == NULL)
@@ -198,9 +196,8 @@ int x25_route_ioctl(unsigned int cmd, void *arg)
return x25_add_route(&x25_route.address, x25_route.sigdigits, dev);
case SIOCDELRT:
- if ((err = verify_area(VERIFY_READ, arg, sizeof(struct x25_route_struct))) != 0)
- return err;
- copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct));
+ if (copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct)))
+ return -EFAULT;
if (x25_route.sigdigits < 0 || x25_route.sigdigits > 15)
return -EINVAL;
if ((dev = x25_dev_get(x25_route.device)) == NULL)
@@ -227,7 +224,8 @@ int x25_routes_get_info(char *buffer, char **start, off_t offset, int length, in
for (x25_route = x25_route_list; x25_route != NULL; x25_route = x25_route->next) {
len += sprintf(buffer + len, "%-15s %-6d %-5s\n",
- x25_route->address.x25_addr, x25_route->sigdigits,
+ x25_route->address.x25_addr,
+ x25_route->sigdigits,
(x25_route->dev != NULL) ? x25_route->dev->name : "???");
pos = begin + len;
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
index 75e58af98..f2aff6d12 100644
--- a/net/x25/x25_subr.c
+++ b/net/x25/x25_subr.c
@@ -1,5 +1,5 @@
/*
- * X.25 Packet Layer release 001
+ * X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
@@ -14,6 +14,7 @@
*
* History
* X.25 001 Jonathan Naylor Started coding.
+ * X.25 002 Jonathan Naylor Centralised disconnection processing.
*/
#include <linux/config.h>
@@ -281,4 +282,25 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, i
return X25_ILLEGAL;
}
+void x25_disconnect(struct sock *sk, int reason, unsigned char cause, unsigned char diagnostic)
+{
+ x25_clear_queues(sk);
+ x25_stop_timer(sk);
+
+ sk->protinfo.x25->lci = 0;
+ sk->protinfo.x25->state = X25_STATE_0;
+
+ sk->protinfo.x25->causediag.cause = cause;
+ sk->protinfo.x25->causediag.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/x25/x25_timer.c b/net/x25/x25_timer.c
index e625c41ed..90b6513c9 100644
--- a/net/x25/x25_timer.c
+++ b/net/x25/x25_timer.c
@@ -1,5 +1,5 @@
/*
- * X.25 Packet Layer release 001
+ * X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
@@ -14,6 +14,8 @@
*
* History
* X.25 001 Jonathan Naylor Started coding.
+ * X.25 002 Jonathan Naylor New timer architecture.
+ * Centralised disconnection processing.
*/
#include <linux/config.h>
@@ -39,42 +41,93 @@
#include <linux/interrupt.h>
#include <net/x25.h>
-static void x25_timer(unsigned long);
+static void x25_heartbeat_expiry(unsigned long);
+static void x25_timer_expiry(unsigned long);
-/*
- * Linux set timer
- */
-void x25_set_timer(struct sock *sk)
+void x25_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 = &x25_timer;
- sk->timer.expires = jiffies + (HZ / 1);
+ sk->timer.function = &x25_heartbeat_expiry;
+ sk->timer.expires = jiffies + 5 * HZ;
add_timer(&sk->timer);
}
-/*
- * X.25 TIMER
- *
- * This routine is called every second. Decrement timer by this
- * amount - if expired then process the event.
- */
-static void x25_timer(unsigned long param)
+void x25_stop_heartbeat(struct sock *sk)
+{
+ del_timer(&sk->timer);
+}
+
+void x25_start_t2timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.x25->timer);
+
+ sk->protinfo.x25->timer.data = (unsigned long)sk;
+ sk->protinfo.x25->timer.function = &x25_timer_expiry;
+ sk->protinfo.x25->timer.expires = jiffies + sk->protinfo.x25->t2;
+
+ add_timer(&sk->protinfo.x25->timer);
+}
+
+void x25_start_t21timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.x25->timer);
+
+ sk->protinfo.x25->timer.data = (unsigned long)sk;
+ sk->protinfo.x25->timer.function = &x25_timer_expiry;
+ sk->protinfo.x25->timer.expires = jiffies + sk->protinfo.x25->t21;
+
+ add_timer(&sk->protinfo.x25->timer);
+}
+
+void x25_start_t22timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.x25->timer);
+
+ sk->protinfo.x25->timer.data = (unsigned long)sk;
+ sk->protinfo.x25->timer.function = &x25_timer_expiry;
+ sk->protinfo.x25->timer.expires = jiffies + sk->protinfo.x25->t22;
+
+ add_timer(&sk->protinfo.x25->timer);
+}
+
+void x25_start_t23timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.x25->timer);
+
+ sk->protinfo.x25->timer.data = (unsigned long)sk;
+ sk->protinfo.x25->timer.function = &x25_timer_expiry;
+ sk->protinfo.x25->timer.expires = jiffies + sk->protinfo.x25->t23;
+
+ add_timer(&sk->protinfo.x25->timer);
+}
+
+void x25_stop_timer(struct sock *sk)
+{
+ del_timer(&sk->protinfo.x25->timer);
+}
+
+unsigned long x25_display_timer(struct sock *sk)
+{
+ if (sk->protinfo.x25->timer.prev == NULL &&
+ sk->protinfo.x25->timer.next == NULL)
+ return 0;
+
+ return sk->protinfo.x25->timer.expires - jiffies;
+}
+
+static void x25_heartbeat_expiry(unsigned long param)
{
struct sock *sk = (struct sock *)param;
switch (sk->protinfo.x25->state) {
+
case X25_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);
x25_destroy_socket(sk);
return;
}
@@ -89,30 +142,26 @@ static void x25_timer(unsigned long param)
sk->protinfo.x25->condition &= ~X25_COND_OWN_RX_BUSY;
sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
sk->protinfo.x25->vl = sk->protinfo.x25->vr;
- sk->protinfo.x25->timer = 0;
x25_write_internal(sk, X25_RR);
+ x25_stop_timer(sk);
break;
}
- /*
- * Check for frames to transmit.
- */
- x25_kick(sk);
- break;
-
- default:
break;
}
- if (sk->protinfo.x25->timer == 0 || --sk->protinfo.x25->timer > 0) {
- x25_set_timer(sk);
- return;
- }
+ x25_start_heartbeat(sk);
+}
+
+/*
+ * Timer has expired, it may have been T2, T21, T22, or T23. We can tell
+ * by the state machine state.
+ */
+static void x25_timer_expiry(unsigned long param)
+{
+ struct sock *sk = (struct sock *)param;
- /*
- * Timer has expired, it may have been T2, T21, T22, or T23. We can tell
- * by the state machine state.
- */
switch (sk->protinfo.x25->state) {
+
case X25_STATE_3: /* T2 */
if (sk->protinfo.x25->condition & X25_COND_ACK_PENDING) {
sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
@@ -124,22 +173,13 @@ static void x25_timer(unsigned long param)
case X25_STATE_4: /* T22 */
x25_write_internal(sk, X25_CLEAR_REQUEST);
sk->protinfo.x25->state = X25_STATE_2;
- sk->protinfo.x25->timer = sk->protinfo.x25->t23;
+ x25_start_t23timer(sk);
break;
case X25_STATE_2: /* T23 */
- x25_clear_queues(sk);
- sk->protinfo.x25->state = X25_STATE_0;
- sk->state = TCP_CLOSE;
- sk->err = ETIMEDOUT;
- sk->shutdown |= SEND_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- sk->dead = 1;
+ x25_disconnect(sk, ETIMEDOUT, 0, 0);
break;
}
-
- x25_set_timer(sk);
}
#endif