From e308faf24f68e262d92d294a01ddca7a17e76762 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 20 Jul 1997 14:56:40 +0000 Subject: Sync with Linux 2.1.46. --- net/Config.in | 2 +- net/README | 10 +- net/appletalk/ddp.c | 32 +++- net/appletalk/sysctl_net_atalk.c | 16 +- net/ax25/af_ax25.c | 308 ++++++++++++++++++--------------------- net/ax25/ax25_addr.c | 46 +++--- net/ax25/ax25_dev.c | 2 +- net/ax25/ax25_ds_in.c | 86 +++-------- net/ax25/ax25_ds_subr.c | 14 +- net/ax25/ax25_ds_timer.c | 172 +++++++--------------- net/ax25/ax25_iface.c | 21 +-- net/ax25/ax25_in.c | 17 +-- net/ax25/ax25_ip.c | 31 ++-- net/ax25/ax25_out.c | 152 +++++++++---------- net/ax25/ax25_route.c | 80 +++------- net/ax25/ax25_std_in.c | 132 ++++------------- net/ax25/ax25_std_subr.c | 14 +- net/ax25/ax25_std_timer.c | 139 +++++++----------- net/ax25/ax25_subr.c | 34 ++++- net/ax25/ax25_timer.c | 202 ++++++++++++++++++++++--- net/ax25/ax25_uid.c | 2 +- net/ax25/sysctl_net_ax25.c | 10 +- net/core/scm.c | 4 +- net/core/sysctl_net_core.c | 4 + net/ipv4/Config.in | 1 + net/ipv4/Makefile | 5 + net/ipv4/raw.c | 2 +- net/ipv4/route.c | 9 +- net/ipv4/syncookies.c | 218 +++++++++++++++++++++++++++ net/ipv4/sysctl_net_ipv4.c | 8 +- net/ipv4/tcp_input.c | 44 +++--- net/ipv4/tcp_ipv4.c | 196 +++++++++++++++++-------- net/ipv4/utils.c | 23 ++- net/ipv6/icmp.c | 20 ++- net/ipv6/tcp_ipv6.c | 54 ++++--- net/lapb/lapb_iface.c | 55 +++---- net/lapb/lapb_in.c | 110 +++++++------- net/lapb/lapb_out.c | 22 +-- net/lapb/lapb_subr.c | 8 +- net/lapb/lapb_timer.c | 123 +++++++--------- net/netlink.c | 2 +- net/netrom/af_netrom.c | 184 ++++++++++++----------- net/netrom/nr_dev.c | 2 +- net/netrom/nr_in.c | 60 ++------ net/netrom/nr_out.c | 104 ++++++------- net/netrom/nr_route.c | 27 ++-- net/netrom/nr_subr.c | 26 +++- net/netrom/nr_timer.c | 208 +++++++++++++++++--------- net/netrom/sysctl_net_netrom.c | 16 +- net/rose/af_rose.c | 224 +++++++++++++++++----------- net/rose/rose_dev.c | 4 +- net/rose/rose_in.c | 95 ++++++------ net/rose/rose_link.c | 111 +++++++------- net/rose/rose_out.c | 58 ++++---- net/rose/rose_route.c | 162 ++++++++++++++------ net/rose/rose_subr.c | 56 ++++--- net/rose/rose_timer.c | 172 +++++++++++++++------- net/rose/sysctl_net_rose.c | 12 +- net/socket.c | 33 +++-- net/unix/af_unix.c | 53 +++---- net/unix/garbage.c | 2 +- net/unix/sysctl_net_unix.c | 4 + net/wanrouter/patchlevel | 3 +- net/wanrouter/wanmain.c | 20 +-- net/wanrouter/wanproc.c | 190 ++++++++++++++++-------- net/x25/af_x25.c | 168 ++++++++++----------- net/x25/sysctl_net_x25.c | 4 +- net/x25/x25_dev.c | 4 +- net/x25/x25_facilities.c | 2 +- net/x25/x25_in.c | 62 +++----- net/x25/x25_link.c | 79 ++++------ net/x25/x25_out.c | 52 ++++--- net/x25/x25_route.c | 16 +- net/x25/x25_subr.c | 24 ++- net/x25/x25_timer.c | 134 +++++++++++------ 75 files changed, 2735 insertions(+), 2066 deletions(-) create mode 100644 net/ipv4/syncookies.c (limited to 'net') 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 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 #include #include @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -52,7 +53,7 @@ #include #include -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 @@ -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 @@ -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 @@ -44,14 +45,14 @@ #include #include -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 @@ -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 @@ -46,48 +47,205 @@ #include #include -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 #include +#include + +#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<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 +#if defined(CONFIG_SYN_COOKIES) +#include +#include +#include +#include + +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, * Fred N. van Kempen, @@ -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 @@ -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 * - * $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 * - * $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 @@ -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 @@ -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 @@ -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 @@ -38,72 +36,60 @@ #include #include -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -37,42 +39,110 @@ #include #include -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 @@ -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 @@ -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 @@ -38,53 +39,64 @@ #include #include -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 @@ -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 @@ -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--; @@ -380,6 +395,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". */ @@ -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 @@ -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 @@ -37,42 +39,103 @@ #include #include -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 #include -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 #include +#include + +#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 * -* 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 /* 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 * -* 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 /* 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 * entry for each WAN device */ @@ -193,29 +192,6 @@ static struct proc_dir_entry proc_router = NULL, /* .data */ }; -/* - * /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; @@ -386,50 +370,87 @@ static long router_proc_read(struct inode* inode, struct file* file, return len; } -/* - * 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 @@ -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 #include -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -39,42 +41,93 @@ #include #include -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 -- cgit v1.2.3