diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-16 01:07:24 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-16 01:07:24 +0000 |
commit | 95db6b748fc86297827fbd9c9ef174d491c9ad89 (patch) | |
tree | 27a92a942821cde1edda9a1b088718d436b3efe4 /net | |
parent | 45b27b0a0652331d104c953a5b192d843fff88f8 (diff) |
Merge with Linux 2.3.40.
Diffstat (limited to 'net')
67 files changed, 2739 insertions, 1544 deletions
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index ba93e1ba1..51e74cab8 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -95,6 +95,7 @@ * AX.25 037 Jonathan(G4KLX) New timer architecture. * AX.25 038 Matthias(DG2FEF) Small fixes to the syscall interface to make kernel * independent of AX25_MAX_DIGIS used by applications. + * Tomi(OH2BNS) Fixed ax25_getname(). */ #include <linux/config.h> @@ -1256,8 +1257,6 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) newsk->sleep = &newsock->wait; /* Now attach up the new socket */ - skb->sk = NULL; - skb->destructor = NULL; kfree_skb(skb); sk->ack_backlog--; newsock->sk = newsk; @@ -1269,37 +1268,34 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sock *sk = sock->sk; + struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr; unsigned char ndigi, i; - struct full_sockaddr_ax25 fsa; if (peer != 0) { if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; - fsa.fsa_ax25.sax25_family = AF_AX25; - fsa.fsa_ax25.sax25_call = sk->protinfo.ax25->dest_addr; - fsa.fsa_ax25.sax25_ndigis = 0; + fsa->fsa_ax25.sax25_family = AF_AX25; + fsa->fsa_ax25.sax25_call = sk->protinfo.ax25->dest_addr; + fsa->fsa_ax25.sax25_ndigis = 0; if (sk->protinfo.ax25->digipeat != NULL) { ndigi = sk->protinfo.ax25->digipeat->ndigi; - fsa.fsa_ax25.sax25_ndigis = ndigi; + fsa->fsa_ax25.sax25_ndigis = ndigi; for (i = 0; i < ndigi; i++) - fsa.fsa_digipeater[i] = sk->protinfo.ax25->digipeat->calls[i]; + fsa->fsa_digipeater[i] = sk->protinfo.ax25->digipeat->calls[i]; } } else { - fsa.fsa_ax25.sax25_family = AF_AX25; - fsa.fsa_ax25.sax25_call = sk->protinfo.ax25->source_addr; - fsa.fsa_ax25.sax25_ndigis = 1; + fsa->fsa_ax25.sax25_family = AF_AX25; + fsa->fsa_ax25.sax25_call = sk->protinfo.ax25->source_addr; + fsa->fsa_ax25.sax25_ndigis = 1; if (sk->protinfo.ax25->ax25_dev != NULL) { - memcpy(&fsa.fsa_digipeater[0], sk->protinfo.ax25->ax25_dev->dev->dev_addr, AX25_ADDR_LEN); + memcpy(&fsa->fsa_digipeater[0], sk->protinfo.ax25->ax25_dev->dev->dev_addr, AX25_ADDR_LEN); } else { - fsa.fsa_digipeater[0] = null_ax25_address; + fsa->fsa_digipeater[0] = null_ax25_address; } } - if (*uaddr_len > sizeof (struct full_sockaddr_ax25)) - *uaddr_len = sizeof (struct full_sockaddr_ax25); - memcpy(uaddr, &fsa, *uaddr_len); - + *uaddr_len = sizeof (struct full_sockaddr_ax25); return 0; } diff --git a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c index 3844f3964..3a6f6c259 100644 --- a/net/ax25/ax25_ds_subr.c +++ b/net/ax25/ax25_ds_subr.c @@ -150,6 +150,7 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p if ((skb = alloc_skb(2, GFP_ATOMIC)) == NULL) return; + skb->nh.raw = skb->data; p = skb_put(skb, 2); *p++ = cmd; diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 497022f23..f4b5e1a75 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -93,6 +93,7 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) skbn->dev = ax25->ax25_dev->dev; skbn->h.raw = skbn->data; + skbn->nh.raw = skbn->data; /* Copy data from the fragments */ while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) { diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c index ec00babd5..a298fb59d 100644 --- a/net/ax25/ax25_ip.c +++ b/net/ax25/ax25_ip.c @@ -161,6 +161,7 @@ int ax25_rebuild_header(struct sk_buff *skb) dst_c = *dst; skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */ + skb->nh.raw = skb->data; ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c, &dst_c, route->digipeat, dev); diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c index fe5125def..719059b21 100644 --- a/net/ax25/ax25_out.c +++ b/net/ax25/ax25_out.c @@ -174,7 +174,7 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) if (ka9qfrag == 1) { skb_reserve(skbn, frontlen + 2); - + skbn->nh.raw = skbn->data + (skb->nh.raw - skb->data); memcpy(skb_put(skbn, len), skb->data, len); p = skb_push(skbn, 2); @@ -187,6 +187,7 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) } } else { skb_reserve(skbn, frontlen + 1); + skbn->nh.raw = skbn->data + (skb->nh.raw - skb->data); memcpy(skb_put(skbn, len), skb->data, len); p = skb_push(skbn, 1); *p = AX25_P_TEXT; diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c index c3ddc6fc0..97ef02d08 100644 --- a/net/ax25/ax25_subr.c +++ b/net/ax25/ax25_subr.c @@ -240,7 +240,8 @@ void ax25_return_dm(struct net_device *dev, ax25_address *src, ax25_address *des return; /* Next SABM will get DM'd */ skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(digi)); - + skb->nh.raw = skb->data; + ax25_digi_invert(digi, &retdigi); dptr = skb_put(skb, 1); diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c index ed6fd7fc2..1aa76359b 100644 --- a/net/ax25/ax25_timer.c +++ b/net/ax25/ax25_timer.c @@ -22,6 +22,7 @@ * Joerg(DL1BKE) Fixed DAMA Slave. We are *required* to start with * standard AX.25 mode. * AX.25 037 Jonathan(G4KLX) New timer architecture. + * Tomi(OH2BNS) Fixed heartbeat expiry (check ax25_dev). */ #include <linux/config.h> @@ -153,8 +154,12 @@ unsigned long ax25_display_timer(struct timer_list *timer) static void ax25_heartbeat_expiry(unsigned long param) { ax25_cb *ax25 = (ax25_cb *)param; + int proto = AX25_PROTO_STD_SIMPLEX; - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { + if (ax25->ax25_dev) + proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]; + + switch (proto) { case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_DUPLEX: ax25_std_heartbeat_expiry(ax25); diff --git a/net/core/iovec.c b/net/core/iovec.c index 07970a18e..5ba18150d 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -99,7 +99,41 @@ int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) } err = 0; out: - return err; + return err; +} + +/* Copy and checkum skb to user iovec. Caller _must_ check that + skb will fit to this iovec. + */ + +int copy_and_csum_toiovec(struct iovec *iov, struct sk_buff *skb, int hlen) +{ + unsigned int csum; + int chunk = skb->len - hlen; + + /* Skip filled elements. Pretty silly, look at mecpy_toiove, though 8) */ + while (iov->iov_len == 0) + iov++; + + if (iov->iov_len < chunk) { + if ((unsigned short)csum_fold(csum_partial(skb->h.raw, chunk+hlen, skb->csum))) + goto csum_error; + if (memcpy_toiovec(iov, skb->h.raw + hlen, chunk)) + goto csum_error; + } else { + int err = 0; + csum = csum_partial(skb->h.raw, hlen, skb->csum); + csum = csum_and_copy_to_user(skb->h.raw+hlen, iov->iov_base, + chunk, csum, &err); + if (err || ((unsigned short)csum_fold(csum))) + goto csum_error; + iov->iov_len -= chunk; + iov->iov_base += chunk; + } + return 0; + +csum_error: + return -EFAULT; } /* diff --git a/net/decnet/Config.in b/net/decnet/Config.in index 323ae86f7..b11cdfa22 100644 --- a/net/decnet/Config.in +++ b/net/decnet/Config.in @@ -4,5 +4,8 @@ bool ' DECnet: SIOCGIFCONF support' CONFIG_DECNET_SIOCGIFCONF if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' DECnet: router support (EXPERIMENTAL)' CONFIG_DECNET_ROUTER + if [ "$CONFIG_DECNET_ROUTER" = "y" ]; then + bool ' DECnet: use FWMARK value as routing key' CONFIG_DECNET_ROUTE_FWMARK + fi fi bool ' DECnet: raw socket support' CONFIG_DECNET_RAW diff --git a/net/decnet/Makefile b/net/decnet/Makefile index 8a44ccac8..1eeef6b40 100644 --- a/net/decnet/Makefile +++ b/net/decnet/Makefile @@ -5,7 +5,7 @@ O_OBJS := af_decnet.o dn_nsp_in.o dn_nsp_out.o dn_route.o dn_dev.o dn_neigh.o M_OBJS := $(O_TARGET) ifeq ($(CONFIG_DECNET_ROUTER),y) -O_OBJS += dn_fib.o +O_OBJS += dn_fib.o dn_rules.o dn_table.o endif ifeq ($(CONFIG_DECNET_RAW),y) diff --git a/net/decnet/TODO b/net/decnet/TODO index fe8184e03..c2e8cf47b 100644 --- a/net/decnet/TODO +++ b/net/decnet/TODO @@ -4,8 +4,6 @@ Steve's quick list of things that need finishing off: o Proper timeouts on each neighbour (in routing mode) rather than just the 60 second On-Ethernet cache value. - o Routing stuff in dn_fib.c - o Misc. get/set_sockopt() functions [done for the time being, more later] o Support for X.25 linklayer @@ -16,9 +14,11 @@ Steve's quick list of things that need finishing off: o PPP support (rfc1762) - o sendmsg() in the raw socket layer + o sendmsg() in the raw socket layer (yes, its for sending routing messages) - o Better filtering of traffic in raw sockets + o Better filtering of traffic in raw sockets. Aside from receiving routing + messages, there really doesn't seem to be a lot else that raw sockets + could be useful for... suggestions on a postcard please :-) o Fix /proc for raw sockets @@ -33,19 +33,31 @@ Steve's quick list of things that need finishing off: o check MSG_TRUNC, MSG_CTRUNC are set where they should be. - o Work out if I really need support for rtnetlink "link" messages and if - so how they should be handled. - - o More rtnetlink "route" message support & testing of this code - - o Routing ioctl() support - o Start to hack together user level software and add more DECnet support in ifconfig for example. - o Fix conninit_rx to check out each CI before queuing it + o Fix conninit_rx to check out each CI before queuing it. Support code is + now in place, so this should be easy. - o Work out which errors we can return from conninit_rx, and how to do it + o Work out which errors we can return from conninit_rx. Support code is + now in place, so this should be easy. o Check out receiving of errors in the light of what conninit_rx can return + o Test adding/deleting of routes + + o Test route lookup + + o Test /proc/net/decnet_route route listing works correctly (maybe I'll + change the format of this file... atm its very similar to the IPv4 route + file) + + o Find all the commonality between DECnet and IPv4 routing code and extract + it into a small library of routines. [probably a project for 2.5.xx] + + o Test ip_gre tunneling works... it did the last time I tested it and it + will have to if I'm to test routing properly. + + o Hello messages should be generated for each primary address on each + interface. + diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index c4a9c44dd..a5237a712 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -135,7 +135,6 @@ static void dn_keepalive(struct sock *sk); */ dn_address decnet_address = 0; unsigned char decnet_ether_address[ETH_ALEN] = { 0xAA, 0x00, 0x04, 0x00, 0x00, 0x00 }; -int decnet_node_type = DN_RT_INFO_ENDN; static struct proto_ops dn_proto_ops; rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED; @@ -484,10 +483,9 @@ static void dn_keepalive(struct sock *sk) * When socket is dead & no packets have been sent for a * certain amount of time, they are removed by this * routine. Also takes care of sending out DI & DC - * frames at correct times. This is called by both - * socket level and interrupt driven code. + * frames at correct times. */ -static int dn_destroy_timer(struct sock *sk) +int dn_destroy_timer(struct sock *sk) { struct dn_scp *scp = &sk->protinfo.dn; @@ -495,13 +493,13 @@ static int dn_destroy_timer(struct sock *sk) switch(scp->state) { case DN_DI: - dn_send_disc(sk, NSP_DISCINIT, 0); + dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC); if (scp->nsp_rxtshift >= decnet_di_count) scp->state = DN_CN; return 0; case DN_DR: - dn_send_disc(sk, NSP_DISCINIT, 0); + dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC); if (scp->nsp_rxtshift >= decnet_dr_count) scp->state = DN_DRC; return 0; @@ -509,7 +507,7 @@ static int dn_destroy_timer(struct sock *sk) case DN_DN: if (scp->nsp_rxtshift < decnet_dn_count) { /* printk(KERN_DEBUG "dn_destroy_timer: DN\n"); */ - dn_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC); + dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC); return 0; } } @@ -529,7 +527,7 @@ static int dn_destroy_timer(struct sock *sk) return 0; } -void dn_destroy_sock(struct sock *sk) +static void dn_destroy_sock(struct sock *sk) { struct dn_scp *scp = &sk->protinfo.dn; @@ -548,11 +546,10 @@ void dn_destroy_sock(struct sock *sk) switch(scp->state) { case DN_DN: - dn_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC); + dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_KERNEL); scp->persist_fxn = dn_destroy_timer; scp->persist = dn_nsp_persist(sk); break; - case DN_CD: case DN_CR: scp->state = DN_DR; goto disc_reject; @@ -561,7 +558,7 @@ void dn_destroy_sock(struct sock *sk) case DN_DI: case DN_DR: disc_reject: - dn_send_disc(sk, NSP_DISCINIT, 0); + dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_KERNEL); case DN_NC: case DN_NR: case DN_RJ: @@ -569,6 +566,7 @@ disc_reject: case DN_CN: case DN_DRC: case DN_CI: + case DN_CD: scp->persist_fxn = dn_destroy_timer; scp->persist = dn_nsp_persist(sk); break; @@ -1041,7 +1039,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) if (newsk->protinfo.dn.accept_mode == ACC_IMMED) { newsk->protinfo.dn.state = DN_CC; - dn_send_conn_conf(newsk); + dn_send_conn_conf(newsk, GFP_KERNEL); err = dn_wait_accept(newsock, flags); } @@ -1392,7 +1390,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char *opt return -EINVAL; scp->state = DN_CC; - dn_send_conn_conf(sk); + dn_send_conn_conf(sk, GFP_KERNEL); err = dn_wait_accept(sock, sock->file->f_flags); return err; @@ -1403,7 +1401,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char *opt scp->state = DN_DR; sk->shutdown = SHUTDOWN_MASK; - dn_send_disc(sk, 0x38, 0); + dn_nsp_send_disc(sk, 0x38, 0, GFP_KERNEL); break; #ifdef CONFIG_DECNET_FW @@ -1426,7 +1424,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char *opt if (copy_from_user(&tmp_fw, optval, optlen)) return -EFAULT; err = dn_fw_ctl(optname, &tmp_fw, optlen); - return -err; /* -0 is 0 after all */ + return err; #endif default: case DSO_LINKINFO: @@ -1540,7 +1538,7 @@ static int dn_wait_run(struct sock *sk, int flags) case DN_CR: scp->state = DN_CC; - dn_send_conn_conf(sk); + dn_send_conn_conf(sk, GFP_KERNEL); return dn_wait_accept(sk->socket, (flags & MSG_DONTWAIT) ? O_NONBLOCK : 0); case DN_CI: case DN_CC: @@ -2072,6 +2070,8 @@ void dn_unregister_sysctl(void); void __init decnet_proto_init(struct net_proto *pro) { + printk(KERN_INFO "NET4: DECnet for Linux: V.2.3.38s (C) 1995-1999 Linux DECnet Project Team\n"); + sock_register(&dn_family_ops); dev_add_pack(&dn_dix_packet_type); register_netdevice_notifier(&dn_dev_notifier); @@ -2084,10 +2084,6 @@ void __init decnet_proto_init(struct net_proto *pro) dn_neigh_init(); dn_route_init(); -#ifdef CONFIG_DECNET_FW - dn_fw_init(); -#endif /* CONFIG_DECNET_FW */ - #ifdef CONFIG_DECNET_ROUTER dn_fib_init(); #endif /* CONFIG_DECNET_ROUTER */ @@ -2095,7 +2091,6 @@ void __init decnet_proto_init(struct net_proto *pro) #ifdef CONFIG_SYSCTL dn_register_sysctl(); #endif /* CONFIG_SYSCTL */ - printk(KERN_INFO "NET4: DECnet for Linux: V.2.3.15s (C) 1995-1999 Linux DECnet Project Team\n"); } @@ -2104,27 +2099,11 @@ static int __init decnet_setup(char *str) { unsigned short area = simple_strtoul(str, &str, 0); unsigned short node = simple_strtoul(*str > 0 ? ++str : str, &str, 0); - unsigned short type = simple_strtoul(*str > 0 ? ++str : str, &str, 0); + /* unsigned short type = simple_strtoul(*str > 0 ? ++str : str, &str, 0); */ decnet_address = dn_htons(area << 10 | node); dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address)); - switch(type) { - default: - printk(KERN_INFO "Invalid DECnet node type, switching to EndNode\n"); - case 0: - decnet_node_type = DN_RT_INFO_ENDN; - break; -#ifdef CONFIG_DECNET_ROUTER - case 1: - decnet_node_type = DN_RT_INFO_L1RT; - break; - case 2: - decnet_node_type = DN_RT_INFO_L2RT; - break; -#endif /* CONFIG_DECNET_ROUTER */ - } - return 0; } @@ -2137,18 +2116,11 @@ MODULE_DESCRIPTION("The Linux DECnet Network Protocol"); MODULE_AUTHOR("Linux DECnet Project Team"); static int addr[2] = {0, 0}; -#ifdef CONFIG_DECNET_ROUTER -static int type = 0; -#endif MODULE_PARM(addr, "2i"); MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node"); -#ifdef CONFIG_DECNET_ROUTER -MODULE_PARM(type, "i"); -MODULE_PARM_DESC(type, "The type of this DECnet node: 0=EndNode, 1,2=Router"); -#endif -int init_module(void) +int __init init_module(void) { if (addr[0] > 63 || addr[0] < 0) { printk(KERN_ERR "DECnet: Area must be between 0 and 63"); @@ -2163,31 +2135,12 @@ int init_module(void) decnet_address = dn_htons((addr[0] << 10) | addr[1]); dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address)); -#ifdef CONFIG_DECNET_ROUTER - switch(type) { - case 0: - decnet_node_type = DN_RT_INFO_ENDN; - break; - case 1: - decnet_node_type = DN_RT_INFO_L1RT; - break; - case 2: - decnet_node_type = DN_RT_INFO_L2RT; - break; - default: - printk(KERN_ERR "DECnet: Node type must be between 0 and 2 inclusive\n"); - return 1; - } -#else - decnet_node_type = DN_RT_INFO_ENDN; -#endif - decnet_proto_init(NULL); return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { #ifdef CONFIG_SYSCTL dn_unregister_sysctl(); @@ -2199,10 +2152,6 @@ void cleanup_module(void) dn_neigh_cleanup(); dn_dev_cleanup(); -#ifdef CONFIG_DECNET_FW - /* dn_fw_cleanup(); */ -#endif /* CONFIG_DECNET_FW */ - #ifdef CONFIG_DECNET_ROUTER dn_fib_cleanup(); #endif /* CONFIG_DECNET_ROUTER */ diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index f024b8cf9..80bf05b5f 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -17,6 +17,8 @@ * Steve Whitehouse : Fixed bug which sometimes killed timer * Steve Whitehouse : Multiple ifaddr support * Steve Whitehouse : SIOCGIFCONF is now a compile time option + * Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding + * Steve Whitehouse : Removed timer1 - its a user space issue now */ #include <linux/config.h> @@ -59,16 +61,17 @@ static void rtmsg_ifa(int event, struct dn_ifaddr *ifa); static int dn_eth_up(struct net_device *); static void dn_send_brd_hello(struct net_device *dev); +#if 0 static void dn_send_ptp_hello(struct net_device *dev); +#endif static struct dn_dev_parms dn_dev_list[] = { { ARPHRD_ETHER, /* Ethernet */ DN_DEV_BCAST, DN_DEV_S_RU, - 1, + 0, 1498, - 10, 1, 10, 0, @@ -76,7 +79,6 @@ static struct dn_dev_parms dn_dev_list[] = { NET_DECNET_CONF_ETHER, dn_eth_up, NULL, - NULL, dn_send_brd_hello, NULL }, @@ -84,9 +86,8 @@ static struct dn_dev_parms dn_dev_list[] = { ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */ DN_DEV_BCAST, DN_DEV_S_RU, - 2, + 0, 1400, - 10, 1, 10, 0, @@ -94,7 +95,6 @@ static struct dn_dev_parms dn_dev_list[] = { NET_DECNET_CONF_GRE, NULL, NULL, - NULL, dn_send_brd_hello, NULL }, @@ -103,9 +103,8 @@ static struct dn_dev_parms dn_dev_list[] = { ARPHRD_X25, /* Bog standard X.25 */ DN_DEV_UCAST, DN_DEV_S_DS, - 5, + 0, 230, - 10 * 60, 1, 120, 0, @@ -113,7 +112,6 @@ static struct dn_dev_parms dn_dev_list[] = { NET_DECNET_CONF_X25, NULL, NULL, - NULL, dn_send_ptp_hello, NULL }, @@ -123,9 +121,8 @@ static struct dn_dev_parms dn_dev_list[] = { ARPHRD_PPP, /* DECnet over PPP */ DN_DEV_BCAST, DN_DEV_S_RU, - 5, + 0, 230, - 10, 1, 10, 0, @@ -133,7 +130,6 @@ static struct dn_dev_parms dn_dev_list[] = { NET_DECNET_CONF_PPP, NULL, NULL, - NULL, dn_send_brd_hello, NULL }, @@ -143,9 +139,8 @@ static struct dn_dev_parms dn_dev_list[] = { ARPHRD_DDCMP, /* DECnet over DDCMP */ DN_DEV_UCAST, DN_DEV_S_DS, - 5, + 0, 230, - 10 * 60, 1, 120, 0, @@ -153,7 +148,6 @@ static struct dn_dev_parms dn_dev_list[] = { NET_DECNET_CONF_DDCMP, NULL, NULL, - NULL, dn_send_ptp_hello, NULL }, @@ -164,7 +158,6 @@ static struct dn_dev_parms dn_dev_list[] = { DN_DEV_S_RU, 0, 1498, - 10, 1, 10, 0, @@ -172,7 +165,6 @@ static struct dn_dev_parms dn_dev_list[] = { NET_DECNET_CONF_LOOPBACK, NULL, NULL, - NULL, dn_send_brd_hello, NULL } @@ -188,22 +180,20 @@ static int min_t2[] = { 1 }; static int max_t2[] = { 60 }; /* No max specified, but this seems sensible */ static int min_t3[] = { 1 }; static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MULT or T3MULT */ -#ifdef CONFIG_DECNET_ROUTER -static int min_t1[] = { 1 }; -static int max_t1[] = { 8191 }; /* No max specified, so made it the same as t3 */ -static int min_cost[] = { 0 }; -static int max_cost[] = { 25 }; /* From DECnet spec */ + static int min_priority[] = { 0 }; static int max_priority[] = { 127 }; /* From DECnet spec */ -#endif /* CONFIG_DECNET_ROUTER */ + +static int dn_forwarding_proc(ctl_table *, int, struct file *, + void *, size_t *); +static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, + void **context); static struct dn_dev_sysctl_table { struct ctl_table_header *sysctl_header; -#ifdef CONFIG_DECNET_ROUTER - ctl_table dn_dev_vars[6]; -#else - ctl_table dn_dev_vars[3]; -#endif + ctl_table dn_dev_vars[5]; ctl_table dn_dev_dev[2]; ctl_table dn_dev_conf_dir[2]; ctl_table dn_dev_proto_dir[2]; @@ -211,20 +201,16 @@ static struct dn_dev_sysctl_table { } dn_dev_sysctl = { NULL, { -#ifdef CONFIG_DECNET_ROUTER - {NET_DECNET_CONF_DEV_COST, "cost", (void *)DN_DEV_PARMS_OFFSET(cost), + {NET_DECNET_CONF_DEV_FORWARDING, "forwarding", + (void *)DN_DEV_PARMS_OFFSET(forwarding), sizeof(int), 0644, NULL, - proc_dointvec_minmax, sysctl_intvec, - NULL, &min_cost, &max_cost}, - {NET_DECNET_CONF_DEV_PRIORITY, "priority", (void *)DN_DEV_PARMS_OFFSET(priority), + dn_forwarding_proc, dn_forwarding_sysctl, + NULL, NULL, NULL}, + {NET_DECNET_CONF_DEV_PRIORITY, "priority", + (void *)DN_DEV_PARMS_OFFSET(priority), sizeof(int), 0644, NULL, proc_dointvec_minmax, sysctl_intvec, NULL, &min_priority, &max_priority}, - {NET_DECNET_CONF_DEV_T1, "t1", (void *)DN_DEV_PARMS_OFFSET(t1), - sizeof(int), 0644, NULL, - proc_dointvec_minmax, sysctl_intvec, - NULL, &min_t1, &max_t1}, -#endif {NET_DECNET_CONF_DEV_T2, "t2", (void *)DN_DEV_PARMS_OFFSET(t2), sizeof(int), 0644, NULL, proc_dointvec_minmax, sysctl_intvec, @@ -274,6 +260,7 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms * t->dn_dev_proto_dir[0].de = NULL; t->dn_dev_root_dir[0].child = t->dn_dev_proto_dir; t->dn_dev_root_dir[0].de = NULL; + t->dn_dev_vars[0].extra1 = (void *)dev; t->sysctl_header = register_sysctl_table(t->dn_dev_root_dir, 0); if (t->sysctl_header == NULL) @@ -291,6 +278,90 @@ static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms) kfree(t); } } + + +static int dn_forwarding_proc(ctl_table *table, int write, + struct file *filep, + void *buffer, size_t *lenp) +{ +#ifdef CONFIG_DECNET_ROUTER + struct net_device *dev = table->extra1; + struct dn_dev *dn_db; + int err; + int tmp, old; + + if (table->extra1 == NULL) + return -EINVAL; + + dn_db = dev->dn_ptr; + old = dn_db->parms.forwarding; + + err = proc_dointvec(table, write, filep, buffer, lenp); + + if ((err >= 0) && write) { + if (dn_db->parms.forwarding < 0) + dn_db->parms.forwarding = 0; + if (dn_db->parms.forwarding > 2) + dn_db->parms.forwarding = 2; + /* + * What an ugly hack this is... its works, just. It + * would be nice if sysctl/proc were just that little + * bit more flexible so I don't have to write a special + * routine, or suffer hacks like this - SJW + */ + tmp = dn_db->parms.forwarding; + dn_db->parms.forwarding = old; + if (dn_db->parms.down) + dn_db->parms.down(dev); + dn_db->parms.forwarding = tmp; + if (dn_db->parms.up) + dn_db->parms.up(dev); + } + + return err; +#else + return -EINVAL; +#endif +} + +static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, + void **context) +{ +#ifdef CONFIG_DECNET_ROUTER + struct net_device *dev = table->extra1; + struct dn_dev *dn_db; + int value; + + if (table->extra1 == NULL) + return -EINVAL; + + dn_db = dev->dn_ptr; + + if (newval && newlen) { + if (newlen != sizeof(int)) + return -EINVAL; + + get_user(value, (int *)newval); + if (value < 0) + return -EINVAL; + if (value > 2) + return -EINVAL; + + if (dn_db->parms.down) + dn_db->parms.down(dev); + dn_db->parms.forwarding = value; + if (dn_db->parms.up) + dn_db->parms.up(dev); + } + + return 0; +#else + return -EINVAL; +#endif +} + #else /* CONFIG_SYSCTL */ static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms) { @@ -372,19 +443,6 @@ static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa) return dn_dev_insert_ifa(dn_db, ifa); } -static struct dn_dev *dn_dev_by_index(int ifindex) -{ - struct net_device *dev; - struct dn_dev *dn_dev = NULL; - dev = dev_get_by_index(ifindex); - if (dev) { - dn_dev = dev->dn_ptr; - dev_put(dev); - } - - return dn_dev; -} - int dn_dev_ioctl(unsigned int cmd, void *arg) { @@ -471,6 +529,18 @@ rarok: } #ifdef CONFIG_RTNETLINK +static struct dn_dev *dn_dev_by_index(int ifindex) +{ + struct net_device *dev; + struct dn_dev *dn_dev = NULL; + dev = dev_get_by_index(ifindex); + if (dev) { + dn_dev = dev->dn_ptr; + dev_put(dev); + } + + return dn_dev; +} static int dn_dev_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { @@ -577,39 +647,6 @@ static void rtmsg_ifa(int event, struct dn_ifaddr *ifa) netlink_broadcast(rtnl, skb, 0, RTMGRP_DECnet_IFADDR, GFP_KERNEL); } -static int dn_dev_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, - int type, u32 pid, u32 seq) -{ - struct ifinfomsg *r; - struct nlmsghdr *nlh; - unsigned char *b = skb->tail; - struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; - unsigned char priority = dn_db->parms.priority; - unsigned short cost = dn_db->parms.cost; - - nlh = NLMSG_PUT(skb, pid, seq, type, sizeof(*r)); - if (pid) nlh->nlmsg_flags |= NLM_F_MULTI; - r = NLMSG_DATA(nlh); - - r->ifi_family = AF_DECnet; - r->ifi_type = dev->type; - r->ifi_index = dev->ifindex; - r->ifi_flags = dev->flags; - r->ifi_change = ~0U; - - RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name); - RTA_PUT(skb, IFLA_COST, sizeof(unsigned short), &cost); - RTA_PUT(skb, IFLA_PRIORITY, sizeof(unsigned char), &priority); - - nlh->nlmsg_len = skb->tail - b; - return skb->len; - -nlmsg_failure: -rtattr_failure: - skb_trim(skb, b - skb->data); - return -1; -} - static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) { int idx, dn_idx; @@ -648,45 +685,6 @@ done: return skb->len; } -static int dn_dev_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) -{ - int idx; - int s_idx = cb->args[0]; - struct net_device *dev; - - read_lock(&dev_base_lock); - for(dev=dev_base, idx=0; dev; dev = dev->next) { - if (!dev->dn_ptr) - continue; - idx++; - if (idx < s_idx) - continue; - if (dn_dev_fill_ifinfo(skb, dev, RTM_NEWLINK, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq) <= 0) - break; - } - read_unlock(&dev_base_lock); - cb->args[0] = idx; - - return skb->len; -} - -static void dn_dev_ifinfo(int type, struct net_device *dev) -{ - struct sk_buff *skb; - int size = NLMSG_GOODSIZE; - - skb = alloc_skb(size, GFP_KERNEL); - if (!skb) - return; - - if (dn_dev_fill_ifinfo(skb, dev, type, 0, 0) < 0) { - kfree_skb(skb); - return; - } - - NETLINK_CB(skb).dst_groups = RTMGRP_LINK; - netlink_broadcast(rtnl, skb, 0, NETLINK_CB(skb).dst_groups, GFP_KERNEL); -} #endif /* CONFIG_RTNETLINK */ static void dn_send_endnode_hello(struct net_device *dev) @@ -793,7 +791,8 @@ static void dn_send_router_hello(struct net_device *dev) *ptr++ = 0; memcpy(ptr, decnet_ether_address, ETH_ALEN); ptr += ETH_ALEN; - *ptr++ = (unsigned char)decnet_node_type; + *ptr++ = dn_db->parms.forwarding == 1 ? + DN_RT_INFO_L1RT : DN_RT_INFO_L2RT; *((unsigned short *)ptr) = dn_htons(dn_db->parms.blksize); ptr += 2; *ptr++ = 0; /* Priority */ @@ -829,7 +828,9 @@ static void dn_send_router_hello(struct net_device *dev) static void dn_send_brd_hello(struct net_device *dev) { - if (decnet_node_type == DN_RT_INFO_ENDN) + struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; + + if (dn_db->parms.forwarding == 0) dn_send_endnode_hello(dev); else dn_send_router_hello(dev); @@ -841,14 +842,16 @@ static void dn_send_brd_hello(struct net_device *dev) } #endif +#if 0 static void dn_send_ptp_hello(struct net_device *dev) { int tdlen = 16; int size = dev->hard_header_len + 2 + 4 + tdlen; struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC); - /* struct dn_dev *dn_db = dev->dn_ptr; */ - unsigned char *ptr; + struct dn_dev *dn_db = dev->dn_ptr; int i; + unsigned char *ptr; + struct dn_neigh *dn = (struct dn_neigh *)dn_db->router; if (skb == NULL) return ; @@ -865,27 +868,24 @@ static void dn_send_ptp_hello(struct net_device *dev) for(i = 0; i < tdlen; i++) *ptr++ = 0252; -#if 0 - if (dn_db->router) { - struct dn_neigh *dn = (struct dn_neigh *)dn_db->router; - if (memcmp(dn->addr, decnet_ether_address, ETH_ALEN) == 0) { - struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + if (dn_am_i_a_router(dn, dn_db)) { + struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); + if (skb2) { dn_rt_finish_output(skb2, dn_rt_all_end_mcast); } } -#endif dn_rt_finish_output(skb, dn_rt_all_rt_mcast); } +#endif static int dn_eth_up(struct net_device *dev) { struct dn_dev *dn_db = dev->dn_ptr; - if (decnet_node_type == DN_RT_INFO_ENDN) + if (dn_db->parms.forwarding == 0) dev_mc_add(dev, dn_rt_all_end_mcast, ETH_ALEN, 0); - - if (decnet_node_type == DN_RT_INFO_L1RT || decnet_node_type == DN_RT_INFO_L2RT) + else dev_mc_add(dev, dn_rt_all_rt_mcast, ETH_ALEN, 0); dev_mc_upload(dev); @@ -902,18 +902,6 @@ static void dn_dev_timer_func(unsigned long arg) struct net_device *dev = (struct net_device *)arg; struct dn_dev *dn_db = dev->dn_ptr; -#ifdef CONFIG_DECNET_ROUTER - if (decnet_node_type == DN_RT_INFO_L1RT || decnet_node_type == DN_RT_INFO_L2RT) { - if (dn_db->t1 <= dn_db->parms.t2) { - if (dn_db->parms.timer1) - dn_db->parms.timer1(dev); - dn_db->t1 = dn_db->parms.t1; - } else { - dn_db->t1 -= dn_db->parms.t2; - } - } -#endif /* CONFIG_DECNET_ROUTER */ - if (dn_db->t3 <= dn_db->parms.t2) { if (dn_db->parms.timer3) dn_db->parms.timer3(dev); @@ -929,11 +917,6 @@ static void dn_dev_set_timer(struct net_device *dev) { struct dn_dev *dn_db = dev->dn_ptr; -#ifdef CONFIG_DECNET_ROUTER - if (dn_db->parms.t2 > dn_db->parms.t1) - dn_db->parms.t2 = dn_db->parms.t1; -#endif - if (dn_db->parms.t2 > dn_db->parms.t3) dn_db->parms.t2 = dn_db->parms.t3; @@ -987,10 +970,6 @@ struct dn_dev *dn_dev_create(struct net_device *dev, int *err) dn_dev_set_timer(dev); -#ifdef CONFIG_RTNETLINK - dn_dev_ifinfo(RTM_NEWLINK, dev); -#endif - *err = 0; return dn_db; } @@ -1034,10 +1013,6 @@ static void dn_dev_delete(struct net_device *dev) del_timer(&dn_db->timer); synchronize_bh(); -#ifdef CONFIG_RTNETLINK - dn_dev_ifinfo(RTM_DELLINK, dev); -#endif - dn_dev_sysctl_unregister(&dn_db->parms); neigh_ifdown(&dn_neigh_table, dev); @@ -1190,10 +1165,10 @@ static int decnet_dev_get_info(char *buffer, char **start, off_t offset, int len if ((dn_db = (struct dn_dev *)dev->dn_ptr) == NULL) continue; - len += sprintf(buffer + len, "%-8s %1s %04lu %04lu %04lu %04lu %04hu %03d %02x %-10s %-7s %-7s\n", + len += sprintf(buffer + len, "%-8s %1s %04u %04u %04lu %04lu %04hu %03d %02x %-10s %-7s %-7s\n", dev->name ? dev->name : "???", dn_type2asc(dn_db->parms.mode), - dn_db->t1, dn_db->parms.t1, + 0, 0, dn_db->t3, dn_db->parms.t3, dn_db->parms.blksize, dn_db->parms.priority, @@ -1229,13 +1204,14 @@ static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = { { NULL, NULL, }, { NULL, NULL, }, - { NULL, dn_dev_dump_ifinfo, }, + { NULL, NULL, }, { NULL, NULL, }, { dn_dev_rtm_newaddr, NULL, }, { dn_dev_rtm_deladdr, NULL, }, { NULL, dn_dev_dump_ifaddr, }, { NULL, NULL, }, + #ifdef CONFIG_DECNET_ROUTER { dn_fib_rtm_newroute, NULL, }, { dn_fib_rtm_delroute, NULL, }, @@ -1252,10 +1228,17 @@ static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = { NULL, NULL, }, { NULL, NULL, }, +#ifdef CONFIG_DECNET_ROUTER + { dn_fib_rtm_newrule, NULL, }, + { dn_fib_rtm_delrule, NULL, }, + { NULL, dn_fib_dump_rules, }, + { NULL, NULL, } +#else { NULL, NULL, }, { NULL, NULL, }, { NULL, NULL, }, { NULL, NULL, } +#endif }; #endif /* CONFIG_RTNETLINK */ @@ -1284,8 +1267,7 @@ void __init dn_dev_init(void) #endif /* CONFIG_SYSCTL */ } -#if defined(CONFIG_DECNET_MODULE) -void dn_dev_cleanup(void) +void __exit dn_dev_cleanup(void) { #ifdef CONFIG_RTNETLINK rtnetlink_links[PF_DECnet] = NULL; @@ -1309,4 +1291,3 @@ void dn_dev_cleanup(void) dn_dev_devices_off(); } -#endif /* CONFIG_DECNET_MODULE */ diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index 358e9a184..aff2dc05d 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c @@ -3,13 +3,15 @@ * operating system. DECnet is implemented using the BSD Socket * interface as the means of communication with the user level. * - * DECnet Routing Forwarding Information Base + * DECnet Routing Forwarding Information Base (Glue/Info List) * * Author: Steve Whitehouse <SteveW@ACM.org> * * * Changes: * Alexey Kuznetsov : SMP locking changes + * Steve Whitehouse : Rewrote it... Well to be more correct, I + * copied most of it from the ipv4 fib code. * */ #include <linux/config.h> @@ -30,451 +32,376 @@ #include <net/neighbour.h> #include <net/dst.h> #include <net/dn.h> +#include <net/dn_route.h> #include <net/dn_fib.h> #include <net/dn_neigh.h> #include <net/dn_dev.h> -/* - * N.B. Some of the functions here should really be inlines, but - * I'll sort out that when its all working properly, for now the - * stack frames will be useful for debugging. - */ -#define DN_NUM_TABLES 255 -#define DN_MIN_TABLE 1 -#define DN_L1_TABLE 1 -#define DN_L2_TABLE 2 - -#ifdef CONFIG_RTNETLINK -static int dn_fib_table_dump(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb); -static void dn_rtmsg_fib(int event, int table, struct dn_fib_action *fa, struct nlmsghdr *nlh, struct netlink_skb_parms *req); -extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb); -#endif /* CONFIG_RTNETLINK */ - -static void dn_fib_del_tree(struct dn_fib_table *t); -static struct dn_fib_table *dn_fib_tables[DN_NUM_TABLES + 1]; -static int dn_fib_allocs = 0; -static int dn_fib_actions = 0; +#define for_fib_info() { struct dn_fib_info *fi;\ + for(fi = dn_fib_info_list; fi; fi = fi->fib_next) +#define endfor_fib_info() } -static struct dn_fib_node *dn_fib_alloc(void) -{ - struct dn_fib_node *fn; +#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\ + for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++) - fn = kmalloc(sizeof(struct dn_fib_node), GFP_KERNEL); +#define change_nexthops(fi) { int nhsel; struct dn_fib_nh *nh;\ + for(nhsel = 0, nh = (struct dn_fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++) - if (fn) { - memset(fn, 0, sizeof(struct dn_fib_node)); - dn_fib_allocs++; - } +#define endfor_nexthops(fi) } - return fn; -} +#ifdef CONFIG_RTNETLINK +extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb); +#endif /* CONFIG_RTNETLINK */ -static __inline__ void dn_fib_free(struct dn_fib_node *fn) -{ - kfree_s(fn, sizeof(struct dn_fib_node)); - dn_fib_allocs--; -} +static struct dn_fib_info *dn_fib_info_list = NULL; +static rwlock_t dn_fib_info_lock = RW_LOCK_UNLOCKED; +int dn_fib_info_cnt; + +static struct +{ + int error; + u8 scope; +} dn_fib_props[RTA_MAX+1] = { + { 0, RT_SCOPE_NOWHERE }, /* RTN_UNSPEC */ + { 0, RT_SCOPE_UNIVERSE }, /* RTN_UNICAST */ + { 0, RT_SCOPE_HOST }, /* RTN_LOCAL */ + { -EINVAL, RT_SCOPE_NOWHERE }, /* RTN_BROADCAST */ + { -EINVAL, RT_SCOPE_NOWHERE }, /* RTN_ANYCAST */ + { -EINVAL, RT_SCOPE_NOWHERE }, /* RTN_MULTICAST */ + { -EINVAL, RT_SCOPE_UNIVERSE }, /* RTN_BLACKHOLE */ + { -EHOSTUNREACH, RT_SCOPE_UNIVERSE }, /* RTN_UNREACHABLE */ + { -EACCES, RT_SCOPE_UNIVERSE }, /* RTN_PROHIBIT */ + { -EAGAIN, RT_SCOPE_UNIVERSE }, /* RTN_THROW */ + { -EINVAL, RT_SCOPE_NOWHERE }, /* RTN_NAT */ + { -EINVAL, RT_SCOPE_NOWHERE } /* RTN_XRESOLVE */ +}; -static struct dn_fib_action *dn_fib_new_action(void) +void dn_fib_free_info(struct dn_fib_info *fi) { - struct dn_fib_action *fa; - - fa = kmalloc(sizeof(struct dn_fib_action), GFP_KERNEL); - - if (fa) { - memset(fa, 0, sizeof(struct dn_fib_action)); - dn_fib_actions++; + if (fi->fib_dead == 0) { + printk(KERN_DEBUG "DECnet: BUG! Attempt to free alive dn_fib_info\n"); + return; } - return fa; -} - -static __inline__ void dn_fib_del_action(struct dn_fib_action *fa) -{ - if ((fa->fa_type == RTN_UNICAST) && fa->fa_neigh) - neigh_release(fa->fa_neigh); - - kfree_s(fa, sizeof(struct dn_fib_action)); - dn_fib_actions--; -} - -static struct dn_fib_node *dn_fib_follow(struct dn_fib_node *fn, dn_address key) -{ - while(fn->fn_action == NULL) - fn = DN_FIB_NEXT(fn, key); - - return fn; -} - - -static struct dn_fib_node *dn_fib_follow1(struct dn_fib_node *fn, dn_address key) -{ - while((fn->fn_action == NULL) && (((key ^ fn->fn_key) >> fn->fn_shift) == 0)) - fn = DN_FIB_NEXT(fn, key); - - return fn; + change_nexthops(fi) { + if (nh->nh_dev) + dev_put(nh->nh_dev); + nh->nh_dev = NULL; + } endfor_nexthops(fi); + dn_fib_info_cnt--; + kfree(fi); +} + +void dn_fib_release_info(struct dn_fib_info *fi) +{ + write_lock(&dn_fib_info_lock); + if (fi && --fi->fib_treeref == 0) { + if (fi->fib_next) + fi->fib_next->fib_prev = fi->fib_prev; + if (fi->fib_prev) + fi->fib_prev->fib_next = fi->fib_next; + if (fi == dn_fib_info_list) + dn_fib_info_list = fi->fib_next; + fi->fib_dead = 1; + dn_fib_info_put(fi); + } + write_unlock(&dn_fib_info_lock); } - -static int dn_fib_table_insert1(struct dn_fib_table *t, struct dn_fib_node *leaf) +static __inline__ int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi) { - struct dn_fib_node *fn, *fn1, *fn2; - int shift = -1; - dn_address match; - dn_address cmpmask = 1; - - if (!t->root) { - t->root = leaf; - t->count++; - return 0; - } - - fn1 = dn_fib_follow1(t->root, leaf->fn_key); - fn2 = fn1->fn_up; - - if (fn1->fn_key == leaf->fn_key) - return -EEXIST; - - if ((fn = dn_fib_alloc()) == NULL) - return -ENOBUFS; - - fn->fn_key = leaf->fn_key; - match = fn1->fn_key ^ fn->fn_key; - - while(match) { - match >>= 1; - shift++; - } - cmpmask <<= shift; - - fn->fn_cmpmask = cmpmask; - fn->fn_shift = shift; - - if (fn2) { - DN_FIB_NEXT(fn2, fn->fn_key) = fn; - } else { - t->root = fn; - } - - t->count++; - fn->fn_up = fn2; - DN_FIB_NEXT(fn, fn1->fn_key) = fn1; - DN_FIB_NEXT(fn, leaf->fn_key) = leaf; + const struct dn_fib_nh *onh = ofi->fib_nh; + for_nexthops(fi) { + if (nh->nh_oif != onh->nh_oif || + nh->nh_gw != onh->nh_gw || + nh->nh_scope != onh->nh_scope || + nh->nh_weight != onh->nh_weight || + ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD)) + return -1; + onh++; + } endfor_nexthops(fi); return 0; } -static __inline__ int dn_maskcmp(dn_address m1, dn_address m2) +static __inline__ struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi) { - int cmp = 0; - - while(m1 || m2) { - if (m1 & 0x8000) - cmp++; - if (m2 & 0x8000) - cmp--; - m1 <<= 1; - m2 <<= 1; + for_fib_info() { + if (fi->fib_nhs != nfi->fib_nhs) + continue; + if (nfi->fib_protocol == fi->fib_protocol && + nfi->fib_prefsrc == fi->fib_prefsrc && + nfi->fib_priority == fi->fib_priority && + ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 && + (nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0)) + return fi; + } endfor_fib_info(); + return NULL; +} + +u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type) +{ + while(RTA_OK(attr,attrlen)) { + if (attr->rta_type == type) + return *(u16*)RTA_DATA(attr); + attr = RTA_NEXT(attr, attrlen); } - return cmp; + return 0; } - -static int dn_fib_table_insert(struct dn_fib_table *t, struct dn_fib_action *fa) +static int dn_fib_count_nhs(struct rtattr *rta) { - struct dn_fib_node *fn; - struct dn_fib_action **fap; - int err; - int cmp; - - if (t->root && ((fn = dn_fib_follow(t->root, fa->fa_key)) != NULL) && - (fn->fn_key == fa->fa_key)) - goto add_action; - - if ((fn = dn_fib_alloc()) == NULL) - return -ENOBUFS; - - fn->fn_key = fa->fa_key; - fn->fn_action = fa; - - if ((err = dn_fib_table_insert1(t, fn)) < 0) - dn_fib_free(fn); + int nhs = 0; + struct rtnexthop *nhp = RTA_DATA(rta); + int nhlen = RTA_PAYLOAD(rta); -#ifdef CONFIG_RTNETLINK - if (!err) - dn_rtmsg_fib(RTM_NEWROUTE, t->n, fa, NULL, NULL); -#endif /* CONFIG_RTNETLINK */ - - return err; - -add_action: - fap = &fn->fn_action; - - for(; *fap; fap = &((*fap)->fa_next)) { - if ((cmp = dn_maskcmp((*fap)->fa_mask, fa->fa_mask)) > 0) - break; - if (cmp < 0) - continue; - if ((*fap)->fa_cost > fa->fa_cost) - break; + while(nhlen >= (int)sizeof(struct rtnexthop)) { + if ((nhlen -= nhp->rtnh_len) < 0) + return 0; + nhs++; + nhp = RTNH_NEXT(nhp); } - fa->fa_next = *fap; - *fap = fa; - -#ifdef CONFIG_RTNETLINK - dn_rtmsg_fib(RTM_NEWROUTE, t->n, fa, NULL, NULL); -#endif /* CONFIG_RTNETLINK */ - - return 0; + return nhs; } -static int dn_fib_table_delete1(struct dn_fib_table *t, struct dn_fib_node *fn) +static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, const struct rtmsg *r) { - struct dn_fib_node *fn1 = fn->fn_up; - struct dn_fib_node *fn2; - struct dn_fib_node *fn3; - - if (fn == t->root) { - t->root = NULL; - t->count--; - return 0; - } - - if (fn1 == NULL) - return -EINVAL; + struct rtnexthop *nhp = RTA_DATA(rta); + int nhlen = RTA_PAYLOAD(rta); - fn2 = fn1->fn_up; - fn3 = DN_FIB_NEXT(fn1, ~fn->fn_key); + change_nexthops(fi) { + int attrlen = nhlen - sizeof(struct rtnexthop); + if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) + return -EINVAL; - if (fn2) - DN_FIB_NEXT(fn2, fn1->fn_key) = fn3; - else - t->root = fn3; + nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags; + nh->nh_oif = nhp->rtnh_ifindex; + nh->nh_weight = nhp->rtnh_hops + 1; - fn3->fn_up = fn2; + if (attrlen) { + nh->nh_gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); + } + nhp = RTNH_NEXT(nhp); + } endfor_nexthops(fi); - dn_fib_free(fn1); - t->count--; return 0; } -static int dn_fib_table_delete(struct dn_fib_table *t, struct dn_fib_action *fa) + +static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct dn_fib_nh *nh) { - struct dn_fib_res res; - struct dn_fib_node *fn; - struct dn_fib_action **fap, *old; int err; - res.res_type = 0; - res.res_addr = fa->fa_key; - res.res_mask = fa->fa_mask; - res.res_ifindex = fa->fa_ifindex; - res.res_proto = fa->fa_proto; - res.res_cost = fa->fa_cost; - - if ((err = t->lookup(t, &res)) < 0) - return err; - - fn = res.res_fn; - fap = &fn->fn_action; - while((*fap) != res.res_fa) - fap = &((*fap)->fa_next); - old = *fap; - *fap = (*fap)->fa_next; + if (nh->nh_gw) { + struct dn_fib_key key; + struct dn_fib_res res; - if (fn->fn_action == NULL) - dn_fib_table_delete1(t, fn); + if (nh->nh_flags&RTNH_F_ONLINK) { + struct net_device *dev; - if (t->root == NULL) - dn_fib_del_tree(t); - -#ifdef CONFIG_RTNETLINK - dn_rtmsg_fib(RTM_DELROUTE, t->n, old, NULL, NULL); -#endif /* CONFIG_RTNETLINK */ - - dn_fib_del_action(old); + if (r->rtm_scope >= RT_SCOPE_LINK) + return -EINVAL; + if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL) + return -ENODEV; + if (!(dev->flags&IFF_UP)) + return -ENETDOWN; + nh->nh_dev = dev; + atomic_inc(&dev->refcnt); + nh->nh_scope = RT_SCOPE_LINK; + return 0; + } - return 0; -} + memset(&key, 0, sizeof(key)); + key.dst = nh->nh_gw; + key.oif = nh->nh_oif; + key.scope = r->rtm_scope + 1; -static int dn_fib_search(struct dn_fib_node *fn, struct dn_fib_res *res) -{ - struct dn_fib_action *fa = fn->fn_action; + if (key.scope < RT_SCOPE_LINK) + key.scope = RT_SCOPE_LINK; - for(; fa; fa = fa->fa_next) { - if ((fa->fa_key ^ res->res_addr) & fa->fa_mask) - continue; - if (res->res_ifindex && (res->res_ifindex != fa->fa_ifindex)) - continue; - if (res->res_mask && (res->res_mask != fa->fa_mask)) - continue; - if (res->res_proto && (res->res_proto != fa->fa_proto)) - continue; - if (res->res_cost && (res->res_cost != fa->fa_cost)) - continue; + if ((err = dn_fib_lookup(&key, &res)) != 0) + return err; - res->res_fn = fn; - res->res_fa = fa; - return 1; + nh->nh_scope = res.scope; + nh->nh_oif = DN_FIB_RES_OIF(res); + nh->nh_dev = DN_FIB_RES_DEV(res); + if (nh->nh_dev) + atomic_inc(&nh->nh_dev->refcnt); + dn_fib_res_put(&res); + } else { + struct net_device *dev; + + if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK)) + return -EINVAL; + + dev = __dev_get_by_index(nh->nh_oif); + if (dev == NULL || dev->dn_ptr == NULL) + return -ENODEV; + if (!(dev->flags&IFF_UP)) + return -ENETDOWN; + nh->nh_dev = dev; + atomic_inc(&nh->nh_dev->refcnt); + nh->nh_scope = RT_SCOPE_HOST; } return 0; } -static int dn_fib_recurse(struct dn_fib_node *fn, struct dn_fib_res *res) -{ - struct dn_fib_node *fn1; - int err = -ENOENT; - - fn1 = dn_fib_follow(fn, res->res_addr); - - if (dn_fib_search(fn1, res)) - return 0; - while((fn1 = fn1->fn_up) != fn) - if ((err = dn_fib_recurse(DN_FIB_NEXT(fn1, ~res->res_addr), res)) == 0) - break; - - return err; -} - -static int dn_fib_table_lookup(struct dn_fib_table *t, struct dn_fib_res *res) +struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta *rta, const struct nlmsghdr *nlh, int *errp) { - struct dn_fib_node *fn = t->root; - int err = -ENOENT; - - if (t->root == NULL) - return err; - - fn = dn_fib_follow(t->root, res->res_addr); - - if (dn_fib_search(fn, res)) - return 0; - - while((fn = fn->fn_up) != NULL) - if ((err = dn_fib_recurse(DN_FIB_NEXT(fn, ~res->res_addr), res)) == 0) - break; + int err; + struct dn_fib_info *fi = NULL; + struct dn_fib_info *ofi; + int nhs = 1; - return err; -} + if (dn_fib_props[r->rtm_type].scope > r->rtm_scope) + goto err_inval; -static int dn_fib_table_walk_recurse(struct dn_fib_walker_t *fwt, struct dn_fib_node *fn) -{ - struct dn_fib_table *t = fwt->table; + if (rta->rta_mp) { + nhs = dn_fib_count_nhs(rta->rta_mp); + if (nhs == 0) + goto err_inval; + } - if (fn->fn_action) { - fwt->fxn(fwt, fn); + fi = kmalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL); + err = -ENOBUFS; + if (fi == NULL) + goto failure; + memset(fi, 0, sizeof(*fi)+nhs*sizeof(struct dn_fib_nh)); + + fi->fib_protocol = r->rtm_protocol; + fi->fib_nhs = nhs; + fi->fib_flags = r->rtm_flags; + if (rta->rta_priority) + fi->fib_priority = *rta->rta_priority; + if (rta->rta_prefsrc) + memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2); + + if (rta->rta_mp) { + if ((err = dn_fib_get_nhs(fi, rta->rta_mp, r)) != 0) + goto failure; + if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif) + goto err_inval; + if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 2)) + goto err_inval; } else { - dn_fib_table_walk_recurse(fwt, t->root->fn_children[0]); - dn_fib_table_walk_recurse(fwt, t->root->fn_children[1]); + struct dn_fib_nh *nh = fi->fib_nh; + if (rta->rta_oif) + nh->nh_oif = *rta->rta_oif; + if (rta->rta_gw) + memcpy(&nh->nh_gw, rta->rta_gw, 2); + nh->nh_flags = r->rtm_flags; + nh->nh_weight = 1; } - return 0; -} - -static int dn_fib_table_walk(struct dn_fib_walker_t *fwt) -{ - struct dn_fib_table *t = fwt->table; - - if (t->root != NULL) { - if (t->root->fn_action) { - fwt->fxn(fwt, t->root); - } else { - dn_fib_table_walk_recurse(fwt, t->root->fn_children[0]); - dn_fib_table_walk_recurse(fwt, t->root->fn_children[1]); - } + if (dn_fib_props[r->rtm_type].error) { + if (rta->rta_gw || rta->rta_oif || rta->rta_mp) + goto err_inval; + goto link_it; } - return 0; -} - -static struct dn_fib_table *dn_fib_get_tree(int n, int create) -{ - struct dn_fib_table *t; - - if (n < DN_MIN_TABLE) - return NULL; - - if (n > DN_NUM_TABLES) - return NULL; + if (r->rtm_scope > RT_SCOPE_HOST) + goto err_inval; - if (dn_fib_tables[n]) - return dn_fib_tables[n]; + if (r->rtm_scope == RT_SCOPE_HOST) { + struct dn_fib_nh *nh = fi->fib_nh; - if (!create) - return NULL; - - if ((t = kmalloc(sizeof(struct dn_fib_table), GFP_KERNEL)) == NULL) - return NULL; - - dn_fib_tables[n] = t; - memset(t, 0, sizeof(struct dn_fib_table)); + /* Local address is added */ + if (nhs != 1 || nh->nh_gw) + goto err_inval; + nh->nh_scope = RT_SCOPE_NOWHERE; + nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif); + err = -ENODEV; + if (nh->nh_dev == NULL) + goto failure; + } else { + change_nexthops(fi) { + if ((err = dn_fib_check_nh(r, fi, nh)) != 0) + goto failure; + } endfor_nexthops(fi) + } - t->n = n; - t->insert = dn_fib_table_insert; - t->delete = dn_fib_table_delete; - t->lookup = dn_fib_table_lookup; - t->walk = dn_fib_table_walk; -#ifdef CONFIG_RTNETLINK - t->dump = dn_fib_table_dump; +#if I_GET_AROUND_TO_FIXING_PREFSRC + if (fi->fib_prefsrc) { + if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || + memcmp(&fi->fib_prefsrc, rta->rta_dst, 2)) + if (dn_addr_type(fi->fib_prefsrc) != RTN_LOCAL) + goto err_inval; + } #endif - return t; -} - -static void dn_fib_del_tree(struct dn_fib_table *t) -{ - dn_fib_tables[t->n] = NULL; +link_it: + if ((ofi = dn_fib_find_info(fi)) != NULL) { + fi->fib_dead = 1; + dn_fib_free_info(fi); + ofi->fib_treeref++; + return ofi; + } - if (t) { - kfree_s(t, sizeof(struct dn_fib_table)); + fi->fib_treeref++; + atomic_inc(&fi->fib_clntref); + write_lock(&dn_fib_info_lock); + fi->fib_next = dn_fib_info_list; + fi->fib_prev = NULL; + if (dn_fib_info_list) + dn_fib_info_list->fib_prev = fi; + dn_fib_info_list = fi; + dn_fib_info_cnt++; + write_unlock(&dn_fib_info_lock); + return fi; + +err_inval: + err = -EINVAL; + +failure: + *errp = err; + if (fi) { + fi->fib_dead = 1; + dn_fib_free_info(fi); } + + return NULL; } -int dn_fib_resolve(struct dn_fib_res *res) +void dn_fib_select_multipath(const struct dn_fib_key *key, struct dn_fib_res *res) { - int table = DN_L1_TABLE; - int count = 0; - struct dn_fib_action *fa; - int err; - - if ((res->res_addr ^ dn_ntohs(decnet_address)) & 0xfc00) - table = DN_L2_TABLE; - - for(;;) { - struct dn_fib_table *t = dn_fib_get_tree(table, 0); - - if (t == NULL) - return -ENOENT; - - if ((err = t->lookup(t, res)) < 0) - return err; + struct dn_fib_info *fi = res->fi; + int w; - if ((fa = res->res_fa) == NULL) - return -ENOENT; + if (fi->fib_power <= 0) { + int power = 0; + change_nexthops(fi) { + if (!(nh->nh_flags&RTNH_F_DEAD)) { + power += nh->nh_weight; + nh->nh_power = nh->nh_weight; + } + } endfor_nexthops(fi); + fi->fib_power = power; + } - if (fa->fa_type != RTN_THROW) - break; + w = jiffies % fi->fib_power; - table = fa->fa_table; + change_nexthops(fi) { + if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) { + if ((w -= nh->nh_power) <= 0) { + nh->nh_power--; + fi->fib_power--; + res->nh_sel = nhsel; + return; + } + } + } endfor_nexthops(fi); - if (count++ > DN_NUM_TABLES) - return -ENOENT; - } + printk(KERN_DEBUG "DECnet: BUG! dn_fib_select_multipath\n"); +} - switch(fa->fa_type) { - case RTN_PROHIBIT: - case RTN_UNREACHABLE: - return -fa->fa_error; - } - return 0; -} /* * Punt to user via netlink for example, but for now @@ -489,72 +416,19 @@ int dn_fib_rt_message(struct sk_buff *skb) #ifdef CONFIG_RTNETLINK -static int dn_fib_convert_rtm(struct dn_fib_action *fa, - struct rtmsg *r, struct rtattr **rta, - struct nlmsghdr *n, - struct netlink_skb_parms *req) -{ - dn_address dst, gw, mask = 0xffff; - int ifindex = 0; - struct neighbour *neigh; - struct net_device *dev; - unsigned char addr[ETH_ALEN]; - - if (r->rtm_family != AF_DECnet) - return -EINVAL; - - if (rta[RTA_DST-1]) - memcpy(&dst, RTA_DATA(rta[RTA_DST-1]), 2); - - if (rta[RTA_OIF-1]) - memcpy(&ifindex, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); - - if (rta[RTA_GATEWAY-1]) - memcpy(&gw, RTA_DATA(rta[RTA_GATEWAY-1]), 2); - - fa->fa_key = dn_ntohs(dst); - fa->fa_mask = dn_ntohs(mask); - fa->fa_ifindex = ifindex; - fa->fa_proto = r->rtm_protocol; - fa->fa_type = r->rtm_type; - - switch(fa->fa_type) { - case RTN_UNICAST: - if ((dev = __dev_get_by_index(ifindex)) == NULL) - return -ENODEV; - dn_dn2eth(addr, dn_ntohs(gw)); - if ((neigh = __neigh_lookup(&dn_neigh_table, &addr, dev, 1)) == NULL) - return -EHOSTUNREACH; - fa->fa_neigh = neigh; - break; - case RTN_THROW: - fa->fa_table = 0; - break; - case RTN_PROHIBIT: - fa->fa_error = EPERM; - break; - case RTN_UNREACHABLE: - fa->fa_error = EHOSTUNREACH; - break; - case RTN_BLACKHOLE: - fa->fa_error = EINVAL; - break; - } - - return 0; -} static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta) { - switch(r->rtm_type) { - case RTN_UNICAST: - case RTN_BLACKHOLE: - case RTN_PROHIBIT: - case RTN_UNREACHABLE: - case RTN_THROW: - break; - default: - return -1; + int i; + + for(i = 1; i <= RTA_MAX; i++) { + struct rtattr *attr = rta[i-1]; + if (attr) { + if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2) + return -EINVAL; + if (i != RTA_MULTIPATH && i != RTA_METRICS) + rta[i-1] = (struct rtattr *)RTA_DATA(attr); + } } return 0; @@ -562,114 +436,36 @@ static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta) int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct dn_fib_table *t; + struct dn_fib_table *tb; struct rtattr **rta = arg; struct rtmsg *r = NLMSG_DATA(nlh); - struct dn_fib_action *fa; - int err; if (dn_fib_check_attr(r, rta)) return -EINVAL; - if ((fa = dn_fib_new_action()) == NULL) - return -ENOBUFS; + tb = dn_fib_get_table(r->rtm_table, 0); + if (tb) + return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); - t = dn_fib_get_tree(r->rtm_table, 0); - if (t) { - if ((err = dn_fib_convert_rtm(fa, r, rta, nlh, &NETLINK_CB(skb))) < 0) { - dn_fib_del_action(fa); - return err; - } - err = t->delete(t, fa); - dn_fib_del_action(fa); - return err; - } return -ESRCH; } int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct dn_fib_table *t; + struct dn_fib_table *tb; struct rtattr **rta = arg; struct rtmsg *r = NLMSG_DATA(nlh); - struct dn_fib_action *fa; - int err; if (dn_fib_check_attr(r, rta)) return -EINVAL; - if ((fa = dn_fib_new_action()) == NULL) - return -ENOBUFS; + tb = dn_fib_get_table(r->rtm_table, 1); + if (tb) + return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); - t = dn_fib_get_tree(r->rtm_table, 1); - if (t) { - if ((err = dn_fib_convert_rtm(fa, r, rta, nlh, &NETLINK_CB(skb))) < 0) { - dn_fib_del_action(fa); - return err; - } - return t->insert(t, fa); - } return -ENOBUFS; } -int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, - int table, struct dn_fib_action *fa) -{ - struct rtmsg *rtm; - struct nlmsghdr *nlh; - unsigned char *b = skb->tail; - - nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*rtm)); - rtm = NLMSG_DATA(nlh); - rtm->rtm_family = AF_DECnet; - rtm->rtm_dst_len = 16; - rtm->rtm_src_len = 16; - rtm->rtm_tos = 0; - rtm->rtm_table = table; - rtm->rtm_type = fa->fa_type; - rtm->rtm_flags = 0; - rtm->rtm_protocol = fa->fa_proto; - RTA_PUT(skb, RTA_DST, 2, &fa->fa_key); - if (fa->fa_ifindex) - RTA_PUT(skb, RTA_OIF, sizeof(int), &fa->fa_ifindex); - - nlh->nlmsg_len = skb->tail - b; - return skb->len; - -nlmsg_failure: -rtattr_failure: - skb_trim(skb, b - skb->data); - return -1; -} - -static void dn_rtmsg_fib(int event, int table, struct dn_fib_action *fa, - struct nlmsghdr *nlh, struct netlink_skb_parms *req) -{ - struct sk_buff *skb; - u32 pid = req ? req->pid : 0; - int size = NLMSG_SPACE(sizeof(struct rtmsg) + 256); - - skb = alloc_skb(size, GFP_KERNEL); - if (!skb) - return; - - if (dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, table, fa) < 0) { - kfree_skb(skb); - return; - } - NETLINK_CB(skb).dst_groups = RTMGRP_DECnet_ROUTE; - if (nlh->nlmsg_flags & NLM_F_ECHO) - atomic_inc(&skb->users); - netlink_broadcast(rtnl, skb, pid, RTMGRP_DECnet_ROUTE, GFP_KERNEL); - if (nlh->nlmsg_flags & NLM_F_ECHO) - netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); -} - -static int dn_fib_table_dump(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb) -{ - - return skb->len; -} int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb) { @@ -690,7 +486,7 @@ int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb) continue; if (t > s_t) memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(int)); - tb = dn_fib_get_tree(t, 0); + tb = dn_fib_get_table(t, 0); if (tb == NULL) continue; if (tb->dump(tb, skb, cb) < 0) @@ -703,6 +499,96 @@ int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb) } #endif /* CONFIG_RTNETLINK */ +int dn_fib_sync_down(dn_address local, struct net_device *dev, int force) +{ + int ret = 0; + int scope = RT_SCOPE_NOWHERE; + + if (force) + scope = -1; + + for_fib_info() { + /* + * This makes no sense for DECnet.... we will almost + * certainly have more than one local address the same + * over all our interfaces. It needs thinking about + * some more. + */ + if (local && fi->fib_prefsrc == local) { + fi->fib_flags |= RTNH_F_DEAD; + ret++; + } else if (dev && fi->fib_nhs) { + int dead = 0; + + change_nexthops(fi) { + if (nh->nh_flags&RTNH_F_DEAD) + dead++; + else if (nh->nh_dev == dev && + nh->nh_scope != scope) { + nh->nh_flags |= RTNH_F_DEAD; + fi->fib_power -= nh->nh_power; + nh->nh_power = 0; + dead++; + } + } endfor_nexthops(fi) + if (dead == fi->fib_nhs) { + fi->fib_flags |= RTNH_F_DEAD; + ret++; + } + } + } endfor_fib_info(); + return ret; +} + + +int dn_fib_sync_up(struct net_device *dev) +{ + int ret = 0; + + if (!(dev->flags&IFF_UP)) + return 0; + + for_fib_info() { + int alive = 0; + + change_nexthops(fi) { + if (!(nh->nh_flags&RTNH_F_DEAD)) { + alive++; + continue; + } + if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP)) + continue; + if (nh->nh_dev != dev || dev->dn_ptr == NULL) + continue; + alive++; + nh->nh_power = 0; + nh->nh_flags &= ~RTNH_F_DEAD; + } endfor_nexthops(fi); + + if (alive == fi->fib_nhs) { + fi->fib_flags &= ~RTNH_F_DEAD; + ret++; + } + } endfor_fib_info(); + return ret; +} + +void dn_fib_flush(void) +{ + int flushed = 0; + struct dn_fib_table *tb; + int id; + + for(id = DN_NUM_TABLES; id > 0; id--) { + if ((tb = dn_fib_get_table(id, 0)) == NULL) + continue; + flushed += tb->flush(tb); + } + + if (flushed) + dn_rt_cache_flush(-1); +} + int dn_fib_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { @@ -720,104 +606,65 @@ int dn_fib_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) #ifdef CONFIG_PROC_FS -struct dn_fib_procfs { - int len; - off_t pos; - off_t begin; - off_t offset; - int length; - char *buffer; -}; - -static int dn_proc_action_list(struct dn_fib_walker_t *fwt, struct dn_fib_node *fn) -{ - struct dn_fib_procfs *pinfo = (struct dn_fib_procfs *)fwt->arg; - struct dn_fib_action *fa; - char ab[DN_ASCBUF_LEN]; - - if (pinfo->pos > pinfo->offset + pinfo->length) - return 0; - - for(fa = fn->fn_action; fa; fa = fa->fa_next) { - - pinfo->len += sprintf(pinfo->buffer + pinfo->len, - "%s/%04hx %02x %02x\n", - dn_addr2asc(fa->fa_key, ab), - fa->fa_mask, - fa->fa_type, - fa->fa_proto); - - pinfo->pos = pinfo->begin + pinfo->len; - if (pinfo->pos < pinfo->offset) { - pinfo->len = 0; - pinfo->begin = pinfo->pos; - } - if (pinfo->pos > pinfo->offset + pinfo->length) - break; - } - - return 0; -} - static int decnet_rt_get_info(char *buffer, char **start, off_t offset, int length) { - struct dn_fib_procfs pinfo; - int i; - struct dn_fib_table *t; - struct dn_fib_walker_t fwt; - - pinfo.pos = 0; - pinfo.len = 0; - pinfo.begin = 0; - pinfo.offset = offset; - pinfo.length = length; - pinfo.buffer = buffer; - - fwt.arg = &pinfo; - fwt.fxn = dn_proc_action_list; - - start_bh_atomic(); - for(i = 0; i < DN_NUM_TABLES; i++) { - if ((t = dn_fib_get_tree(i, 0)) == NULL) - continue; + int first = offset / 128; + char *ptr = buffer; + int count = (length + 127) / 128; + int len; + int i; + struct dn_fib_table *tb; - fwt.table = t; - t->walk(&fwt); + *start = buffer + (offset % 128); + + if (--first < 0) { + sprintf(buffer, "%-127s\n", "Iface\tDest\tGW \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT"); + --count; + ptr += 128; + first = 0; + } - if (pinfo.pos > pinfo.offset + pinfo.length) - break; - } - end_bh_atomic(); - *start = pinfo.buffer + (pinfo.offset - pinfo.begin); - pinfo.len -= (pinfo.offset - pinfo.begin); + for(i = DN_MIN_TABLE; (i <= DN_NUM_TABLES) && (count > 0); i++) { + if ((tb = dn_fib_get_table(i, 0)) != NULL) { + int n = tb->get_info(tb, ptr, first, count); + count -= n; + ptr += n * 128; + } + } - if (pinfo.len > pinfo.length) - pinfo.len = pinfo.length; + len = ptr - *start; + if (len >= length) + return length; + if (len >= 0) + return len; - return pinfo.len; + return 0; } #endif /* CONFIG_PROC_FS */ -#ifdef CONFIG_DECNET_MODULE -void dn_fib_cleanup(void) + +void __exit dn_fib_cleanup(void) { #ifdef CONFIG_PROC_FS - proc_net_create("decnet_route",0,decnet_rt_get_info); -#endif /* CONFIG_PROC_FS */ + proc_net_remove("decnet_route"); +#endif + + dn_fib_table_cleanup(); + dn_fib_rules_cleanup(); } -#endif /* CONFIG_DECNET_MODULE */ void __init dn_fib_init(void) { - memset(dn_fib_tables, 0, DN_NUM_TABLES * sizeof(struct dn_fib_table *)); #ifdef CONFIG_PROC_FS - proc_net_remove("decnet_route"); + proc_net_create("decnet_route", 0, decnet_rt_get_info); #endif + dn_fib_table_init(); + dn_fib_rules_init(); } diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index bddf4b049..eb50c8c54 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -554,6 +554,7 @@ int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n) struct dn_neigh *dn; struct neigh_table *tbl = &dn_neigh_table; unsigned char *rs = ptr; + struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; read_lock_bh(&tbl->lock); @@ -564,7 +565,7 @@ int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n) dn = (struct dn_neigh *)neigh; if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2))) continue; - if (decnet_node_type == DN_RT_INFO_L1RT && (dn->flags & DN_NDFLAG_R2)) + if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2)) continue; if (t == n) rs = dn_find_slot(ptr, n, dn->priority); @@ -654,12 +655,10 @@ void __init dn_neigh_init(void) #endif /* CONFIG_PROC_FS */ } -#ifdef CONFIG_DECNET_MODULE -void dn_neigh_cleanup(void) +void __exit dn_neigh_cleanup(void) { #ifdef CONFIG_PROC_FS proc_net_remove("decnet_neigh"); #endif /* CONFIG_PROC_FS */ neigh_table_clear(&dn_neigh_table); } -#endif /* CONFIG_DECNET_MODULE */ diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c index a997d253e..5603c1d1f 100644 --- a/net/decnet/dn_nsp_in.c +++ b/net/decnet/dn_nsp_in.c @@ -260,8 +260,6 @@ static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb) struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; unsigned short reason; - /* printk(KERN_DEBUG "DECnet: discinit %d\n", skb->len); */ - if (skb->len < 2) goto out; @@ -283,8 +281,6 @@ static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb) scp->addrrem = cb->src_port; sk->state = TCP_CLOSE; - /* printk(KERN_DEBUG "DECnet: discinit\n"); */ - switch(scp->state) { case DN_CI: case DN_CD: @@ -299,10 +295,15 @@ static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb) break; } - if (!sk->dead) + if (!sk->dead) { + if (sk->socket->state != SS_UNCONNECTED) + sk->socket->state = SS_DISCONNECTING; sk->state_change(sk); + } - dn_destroy_sock(sk); + dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC); + scp->persist_fxn = dn_destroy_timer; + scp->persist = dn_nsp_persist(sk); out: kfree_skb(skb); @@ -343,10 +344,14 @@ static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb) scp->state = DN_CN; } - if (!sk->dead) + if (!sk->dead) { + if (sk->socket->state != SS_UNCONNECTED) + sk->socket->state = SS_DISCONNECTING; sk->state_change(sk); + } - dn_destroy_sock(sk); + scp->persist_fxn = dn_destroy_timer; + scp->persist = dn_nsp_persist(sk); out: kfree_skb(skb); @@ -519,6 +524,18 @@ static void dn_returned_conn_init(struct sock *sk, struct sk_buff *skb) kfree_skb(skb); } +static void dn_nsp_no_socket(struct sk_buff *skb) +{ + struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; + + switch(cb->nsp_flags) { + case 0x28: /* Connect Confirm */ + dn_nsp_return_disc(skb, NSP_DISCCONF, NSP_REASON_NL); + } + + kfree_skb(skb); +} + static int dn_nsp_rx_packet(struct sk_buff *skb) { struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; @@ -615,6 +632,8 @@ got_it: return ret; } + + dn_nsp_no_socket(skb); return 1; free_out: diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c index 2630c5c07..3b487617d 100644 --- a/net/decnet/dn_nsp_out.c +++ b/net/decnet/dn_nsp_out.c @@ -18,6 +18,7 @@ * Steve Whitehouse: Fixes to check alloc'd skbs are non NULL! * Moved output state machine into one function * Steve Whitehouse: New output state machine + * Paul Koning: Connect Confirm message fix. */ /****************************************************************************** @@ -463,14 +464,24 @@ void dn_nsp_delayed_ack(struct sock *sk) dn_nsp_send_data_ack(sk); } -void dn_send_conn_conf (struct sock *sk) +static int dn_nsp_retrans_conn_conf(struct sock *sk) +{ + struct dn_scp *scp = &sk->protinfo.dn; + + if (scp->state == DN_CC) + dn_send_conn_conf(sk, GFP_ATOMIC); + + return 0; +} + +void dn_send_conn_conf(struct sock *sk, int gfp) { struct dn_scp *scp = &sk->protinfo.dn; struct sk_buff *skb = NULL; struct nsp_conn_init_msg *msg; - unsigned short int aux; + unsigned char len = scp->conndata_out.opt_optl; - if ((skb = dn_alloc_skb(sk, 50 + scp->conndata_out.opt_optl, GFP_KERNEL)) == NULL) + if ((skb = dn_alloc_skb(sk, 50 + scp->conndata_out.opt_optl, gfp)) == NULL) return; msg = (struct nsp_conn_init_msg *)skb_put(skb, sizeof(*msg)); @@ -481,46 +492,89 @@ void dn_send_conn_conf (struct sock *sk) msg->info = 0x03; msg->segsize = dn_htons(0x05B3); - if (scp->conndata_out.opt_optl > 0) { - aux = scp->conndata_out.opt_optl; - *skb_put(skb,1) = aux; - memcpy(skb_put(skb, aux), scp->conndata_out.opt_data, aux); - } + *skb_put(skb,1) = len; + + if (len > 0) + memcpy(skb_put(skb, len), scp->conndata_out.opt_data, len); - dn_nsp_send(skb); + dn_nsp_send(skb); + + scp->persist = dn_nsp_persist(sk); + scp->persist_fxn = dn_nsp_retrans_conn_conf; } -void dn_send_disc (struct sock *sk, unsigned char msgflg, unsigned short reason) + +static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg, + unsigned short reason, int gfp, struct dst_entry *dst, + int ddl, unsigned char *dd, __u16 rem, __u16 loc) { - struct dn_scp *scp = &sk->protinfo.dn; struct sk_buff *skb = NULL; - int ddl = (msgflg == NSP_DISCINIT || msgflg == 0x38) ? (1 + scp->discdata_out.opt_optl) : 0; - int size = 7 + ddl; + int size = 7 + (ddl ? (ddl + 1) : 0); unsigned char *msg; - if ((skb = dn_alloc_skb(sk, size, GFP_ATOMIC)) == NULL) + if ((dst == NULL) || (rem == 0)) { + if (net_ratelimit()) + printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", (unsigned)rem, dst); + return; + } + + if ((skb = dn_alloc_skb(sk, size, gfp)) == NULL) return; - if (reason == 0) reason = scp->discdata_out.opt_status; - msg = skb_put(skb, size); *msg++ = msgflg; - *(__u16 *)msg = scp->addrrem; + *(__u16 *)msg = rem; msg += 2; - *(__u16 *)msg = scp->addrloc; + *(__u16 *)msg = loc; msg += 2; *(__u16 *)msg = dn_htons(reason); msg += 2; if (ddl) { - *msg++ = scp->discdata_out.opt_optl; - memcpy(msg, scp->discdata_out.opt_data, scp->discdata_out.opt_optl); + *msg++ = ddl; + memcpy(msg, dd, ddl); } - dn_nsp_send(skb); + /* + * This doesn't go via the dn_nsp_send() fucntion since we need + * to be able to send disc packets out which have no socket + * associations. + */ + skb->dst = dst_clone(dst); + skb->dst->output(skb); +} + + +void dn_nsp_send_disc(struct sock *sk, unsigned char msgflg, + unsigned short reason, int gfp) +{ + struct dn_scp *scp = &sk->protinfo.dn; + int ddl = 0; + + if (msgflg == NSP_DISCINIT) + ddl = scp->discdata_out.opt_optl; + + if (reason == 0) + reason = scp->discdata_out.opt_status; + + dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->dst_cache, ddl, + scp->discdata_out.opt_data, scp->addrrem, scp->addrloc); } + +void dn_nsp_return_disc(struct sk_buff *skb, unsigned char msgflg, + unsigned short reason) +{ + struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; + int ddl = 0; + int gfp = GFP_ATOMIC; + + dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb->dst, ddl, + NULL, cb->src_port, cb->dst_port); +} + + void dn_nsp_send_lnk(struct sock *sk, unsigned short flgs) { struct dn_scp *scp = &sk->protinfo.dn; @@ -543,8 +597,6 @@ void dn_nsp_send_lnk(struct sock *sk, unsigned short flgs) msg1->segnum = dn_htons(cb->segnum = (scp->numoth++ & 0x0FFF)); msg1->lsflgs = flgs; - /* printk(KERN_DEBUG "dn_nsp_send_lnk: %02x\n", flgs); */ - dn_nsp_queue_xmit(sk, skb, 1); scp->persist = dn_nsp_persist(sk); @@ -556,10 +608,8 @@ static int dn_nsp_retrans_conninit(struct sock *sk) { struct dn_scp *scp = &sk->protinfo.dn; - if (scp->state == DN_CI) { + if (scp->state == DN_CI) dn_nsp_send_conninit(sk, NSP_RCI); - scp->persist = dn_nsp_persist(sk); - } return 0; } diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index c4f834157..6f842d465 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -25,6 +25,11 @@ * Steve Whitehouse : Dave Miller's dynamic hash table sizing and * Alexey Kuznetsov's finer grained locking * from ipv4/route.c. + * Steve Whitehouse : Routing is now starting to look like a + * sensible set of code now, mainly due to + * my copying the IPv4 routing code. The + * hooks here are modified and will continue + * to evolve for a while. */ /****************************************************************************** @@ -82,17 +87,23 @@ extern struct neigh_table dn_neigh_table; static unsigned char dn_hiord_addr[6] = {0xAA,0x00,0x04,0x00,0x00,0x00}; +int dn_rt_min_delay = 2*HZ; +int dn_rt_max_delay = 10*HZ; +static unsigned long dn_rt_deadline = 0; + static int dn_dst_gc(void); static struct dst_entry *dn_dst_check(struct dst_entry *, __u32); static struct dst_entry *dn_dst_reroute(struct dst_entry *, struct sk_buff *skb); static struct dst_entry *dn_dst_negative_advice(struct dst_entry *); static void dn_dst_link_failure(struct sk_buff *); static int dn_route_input(struct sk_buff *); +static void dn_run_flush(unsigned long dummy); static struct dn_rt_hash_bucket *dn_rt_hash_table; static unsigned dn_rt_hash_mask; static struct timer_list dn_route_timer = { NULL, NULL, 0, 0L, NULL }; +static struct timer_list dn_rt_flush_timer = { NULL, NULL, 0, 0L, dn_run_flush }; int decnet_dst_gc_interval = 2; static struct dst_ops dn_dst_ops = { @@ -109,12 +120,12 @@ static struct dst_ops dn_dst_ops = { ATOMIC_INIT(0) }; -static __inline__ unsigned dn_hash(unsigned short dest) +static __inline__ unsigned dn_hash(unsigned short src, unsigned short dst) { - unsigned short tmp = dest; - tmp ^= (dest >> 3); - tmp ^= (dest >> 5); - tmp ^= (dest >> 10); + unsigned short tmp = src ^ dst; + tmp ^= (tmp >> 3); + tmp ^= (tmp >> 5); + tmp ^= (tmp >> 10); return dn_rt_hash_mask & (unsigned)tmp; } @@ -155,8 +166,10 @@ static int dn_dst_gc(void) unsigned long expire = 10 * HZ; for(i = 0; i <= dn_rt_hash_mask; i++) { + write_lock_bh(&dn_rt_hash_table[i].lock); rtp = &dn_rt_hash_table[i].chain; + for(; (rt=*rtp); rtp = &rt->u.rt_next) { if (atomic_read(&rt->u.dst.__refcnt) || (now - rt->u.dst.lastuse) < expire) @@ -199,9 +212,8 @@ static void dn_dst_link_failure(struct sk_buff *skb) return; } -static void dn_insert_route(struct dn_route *rt) +static void dn_insert_route(struct dn_route *rt, unsigned hash) { - unsigned hash = dn_hash(rt->rt_daddr); unsigned long now = jiffies; write_lock_bh(&dn_rt_hash_table[hash].lock); @@ -237,6 +249,43 @@ nothing_to_declare: } } +static spinlock_t dn_rt_flush_lock = SPIN_LOCK_UNLOCKED; + +void dn_rt_cache_flush(int delay) +{ + unsigned long now = jiffies; + int user_mode = !in_interrupt(); + + if (delay < 0) + delay = dn_rt_min_delay; + + spin_lock_bh(&dn_rt_flush_lock); + + if (del_timer(&dn_rt_flush_timer) && delay > 0 && dn_rt_deadline) { + long tmo = (long)(dn_rt_deadline - now); + + if (user_mode && tmo < dn_rt_max_delay - dn_rt_min_delay) + tmo = 0; + + if (delay > tmo) + delay = tmo; + } + + if (delay <= 0) { + spin_unlock_bh(&dn_rt_flush_lock); + dn_run_flush(0); + return; + } + + if (dn_rt_deadline == 0) + dn_rt_deadline = now + dn_rt_max_delay; + + dn_rt_flush_timer.expires = now + delay; + add_timer(&dn_rt_flush_timer); + spin_unlock_bh(&dn_rt_flush_lock); +} + + static int dn_route_rx_packet(struct sk_buff *skb) { int err; @@ -531,33 +580,49 @@ static int dn_route_output_slow(struct dst_entry **pprt, dn_address dst, dn_addr struct net_device *dev = decnet_default_device; struct neighbour *neigh = NULL; struct dn_dev *dn_db; - - + unsigned hash; #ifdef CONFIG_DECNET_ROUTER - if (decnet_node_type != DN_RT_INFO_ENDN) { - struct dn_fib_res res; - int err = 0; - - res.res_addr = dst; - res.res_mask = 0; - res.res_ifindex = 0; - res.res_proto = RTN_UNSPEC; - res.res_cost = 0; - - if ((err = dn_fib_resolve(&res)) == 0) { - - if (!res.res_fa || (res.res_fa->fa_type != RTN_UNICAST)) - return -EPROTO; - - if ((neigh = neigh_clone(res.res_fa->fa_neigh)) != NULL) - goto got_route; + struct dn_fib_key key; + struct dn_fib_res res; + int err; - return -ENOBUFS; + key.src = src; + key.dst = dst; + key.iif = 0; + key.oif = 0; + key.fwmark = 0; + key.scope = RT_SCOPE_UNIVERSE; + + if ((err = dn_fib_lookup(&key, &res)) == 0) { + switch(res.type) { + case RTN_UNICAST: + /* + * This method of handling multipath + * routes is a hack and will change. + * It works for now though. + */ + if (res.fi->fib_nhs) + dn_fib_select_multipath(&key, &res); + neigh = __neigh_lookup(&dn_neigh_table, &DN_FIB_RES_GW(res), DN_FIB_RES_DEV(res), 1); + err = -ENOBUFS; + if (!neigh) + break; + err = 0; + break; + case RTN_UNREACHABLE: + err = -EHOSTUNREACH; + break; + default: + err = -EINVAL; } - - if (err != -ENOENT) + dn_fib_res_put(&res); + if (err < 0) return err; + goto got_route; } + + if (err != -ESRCH) + return err; #endif /* Look in On-Ethernet cache first */ @@ -594,13 +659,16 @@ got_route: dn_db = (struct dn_dev *)neigh->dev->dn_ptr; - rt->rt_saddr = src; - rt->rt_daddr = dst; - rt->rt_oif = neigh->dev->ifindex; - rt->rt_iif = 0; + rt->key.saddr = src; + rt->rt_saddr = src; + rt->key.daddr = dst; + rt->rt_daddr = dst; + rt->key.oif = neigh ? neigh->dev->ifindex : -1; + rt->key.iif = 0; + rt->key.fwmark = 0; rt->u.dst.neighbour = neigh; - rt->u.dst.dev = neigh->dev; + rt->u.dst.dev = neigh ? neigh->dev : NULL; rt->u.dst.lastuse = jiffies; rt->u.dst.output = dn_output; rt->u.dst.input = dn_rt_bug; @@ -608,7 +676,8 @@ got_route: if (dn_dev_islocal(neigh->dev, rt->rt_daddr)) rt->u.dst.input = dn_nsp_rx; - dn_insert_route(rt); + hash = dn_hash(rt->key.saddr, rt->key.daddr); + dn_insert_route(rt, hash); *pprt = &rt->u.dst; return 0; @@ -616,16 +685,16 @@ got_route: int dn_route_output(struct dst_entry **pprt, dn_address dst, dn_address src, int flags) { - unsigned hash = dn_hash(dst); + unsigned hash = dn_hash(src, dst); struct dn_route *rt = NULL; if (!(flags & MSG_TRYHARD)) { read_lock_bh(&dn_rt_hash_table[hash].lock); for(rt = dn_rt_hash_table[hash].chain; rt; rt = rt->u.rt_next) { - if ((dst == rt->rt_daddr) && - (src == rt->rt_saddr) && - (rt->rt_iif == 0) && - (rt->rt_oif != 0)) { + if ((dst == rt->key.daddr) && + (src == rt->key.saddr) && + (rt->key.iif == 0) && + (rt->key.oif != 0)) { rt->u.dst.lastuse = jiffies; dst_hold(&rt->u.dst); rt->u.dst.__use++; @@ -649,6 +718,15 @@ static int dn_route_input_slow(struct sk_buff *skb) struct neighbour *neigh = NULL; int (*dnrt_input)(struct sk_buff *skb); int (*dnrt_output)(struct sk_buff *skb); + u32 fwmark = 0; + unsigned hash; + dn_address saddr = cb->src; + dn_address daddr = cb->dst; +#ifdef CONFIG_DECNET_ROUTER + struct dn_fib_key key; + struct dn_fib_res res; + int err; +#endif if (dev == NULL) return -EINVAL; @@ -683,6 +761,8 @@ static int dn_route_input_slow(struct sk_buff *skb) */ dnrt_input = dn_nsp_rx; dnrt_output = dn_output; + saddr = cb->dst; + daddr = cb->src; if ((neigh = neigh_lookup(&dn_neigh_table, &cb->src, dev)) != NULL) goto add_entry; @@ -705,9 +785,49 @@ non_local_input: * Destination is another node... find next hop in * routing table here. */ - if (decnet_node_type == DN_RT_INFO_ENDN) + + key.src = cb->src; + key.dst = cb->dst; + key.iif = dev->ifindex; + key.oif = 0; + key.scope = RT_SCOPE_UNIVERSE; + +#ifdef CONFIG_DECNET_ROUTE_FWMASK + if (skb->nfreason == NF_REASON_FOR_ROUTING) + key.fwmark = skb->fwmark; + else + key.fwmark = 0; +#else + key.fwmark = 0; +#endif + + if ((err = dn_fib_lookup(&key, &res)) == 0) { + switch(res.type) { + case RTN_UNICAST: + if (res.fi->fib_nhs) + dn_fib_select_multipath(&key, &res); + neigh = __neigh_lookup(&dn_neigh_table, &DN_FIB_RES_GW(res), DN_FIB_RES_DEV(res), 1); + err = -ENOBUFS; + if (!neigh) + break; + err = 0; + dnrt_input = dn_forward; + fwmark = key.fwmark; + break; + case RTN_UNREACHABLE: + dnrt_input = dn_blackhole; + fwmark = key.fwmark; + break; + default: + err = -EINVAL; + } + dn_fib_res_put(&res); + if (err < 0) + return err; goto add_entry; + } + return err; #endif /* CONFIG_DECNET_ROUTER */ @@ -718,18 +838,22 @@ add_entry: return -EINVAL; } - rt->rt_saddr = cb->dst; - rt->rt_daddr = cb->src; - rt->rt_oif = 0; - rt->rt_iif = dev->ifindex; + rt->key.saddr = cb->src; + rt->rt_saddr = saddr; + rt->key.daddr = cb->dst; + rt->rt_daddr = daddr; + rt->key.oif = 0; + rt->key.iif = dev->ifindex; + rt->key.fwmark = fwmark; rt->u.dst.neighbour = neigh; - rt->u.dst.dev = dev; + rt->u.dst.dev = neigh ? neigh->dev : NULL; rt->u.dst.lastuse = jiffies; rt->u.dst.output = dnrt_output; rt->u.dst.input = dnrt_input; - dn_insert_route(rt); + hash = dn_hash(rt->key.saddr, rt->key.daddr); + dn_insert_route(rt, hash); skb->dst = (struct dst_entry *)rt; return 0; @@ -739,17 +863,22 @@ int dn_route_input(struct sk_buff *skb) { struct dn_route *rt; struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb; - unsigned hash = dn_hash(cb->src); + unsigned hash = dn_hash(cb->src, cb->dst); if (skb->dst) return 0; read_lock(&dn_rt_hash_table[hash].lock); for(rt = dn_rt_hash_table[hash].chain; rt != NULL; rt = rt->u.rt_next) { - if ((rt->rt_saddr == cb->dst) && - (rt->rt_daddr == cb->src) && - (rt->rt_oif == 0) && - (rt->rt_iif == cb->iif)) { + if ((rt->key.saddr == cb->src) && + (rt->key.daddr == cb->dst) && + (rt->key.oif == 0) && +#ifdef CONFIG_DECNET_ROUTE_FWMASK + (rt->key.fwmark == (skb->nfreason == + NF_REASON_FOR_ROUTING + ? skb->nfmark : 0)) && +#endif + (rt->key.iif == cb->iif)) { rt->u.dst.lastuse = jiffies; dst_hold(&rt->u.dst); rt->u.dst.__use++; @@ -953,6 +1082,7 @@ static int decnet_cache_get_info(char *buffer, char **start, off_t offset, int l ); + pos = begin + len; if (pos < offset) { @@ -998,48 +1128,51 @@ void __init dn_route_init(void) for(order = 0; (1UL << order) < goal; order++) /* NOTHING */; - /* - * Only want 1024 entries max, since the table is very, very unlikely - * to be larger than that. - */ - while(order && ((((1UL << order) * PAGE_SIZE) / - sizeof(struct dn_rt_hash_bucket)) >= 2048)) - order--; - - do { - dn_rt_hash_mask = (1UL << order) * PAGE_SIZE / - sizeof(struct dn_rt_hash_bucket); - while(dn_rt_hash_mask & (dn_rt_hash_mask - 1)) - dn_rt_hash_mask--; - dn_rt_hash_table = (struct dn_rt_hash_bucket *) - __get_free_pages(GFP_ATOMIC, order); - } while (dn_rt_hash_table == NULL && --order > 0); + /* + * Only want 1024 entries max, since the table is very, very unlikely + * to be larger than that. + */ + while(order && ((((1UL << order) * PAGE_SIZE) / + sizeof(struct dn_rt_hash_bucket)) >= 2048)) + order--; + + do { + dn_rt_hash_mask = (1UL << order) * PAGE_SIZE / + sizeof(struct dn_rt_hash_bucket); + while(dn_rt_hash_mask & (dn_rt_hash_mask - 1)) + dn_rt_hash_mask--; + dn_rt_hash_table = (struct dn_rt_hash_bucket *) + __get_free_pages(GFP_ATOMIC, order); + } while (dn_rt_hash_table == NULL && --order > 0); if (!dn_rt_hash_table) - panic("Failed to allocate DECnet route cache hash table\n"); + panic("Failed to allocate DECnet route cache hash table\n"); - printk(KERN_INFO "DECnet: Routing cache hash table of %u buckets, %dKbytes\n", dn_rt_hash_mask, (dn_rt_hash_mask*sizeof(struct dn_rt_hash_bucket))/1024); + printk(KERN_INFO + "DECnet: Routing cache hash table of %u buckets, %dKbytes\n", + dn_rt_hash_mask, + (dn_rt_hash_mask*sizeof(struct dn_rt_hash_bucket))/1024); dn_rt_hash_mask--; - for(i = 0; i <= dn_rt_hash_mask; i++) { - dn_rt_hash_table[i].lock = RW_LOCK_UNLOCKED; - dn_rt_hash_table[i].chain = NULL; - } + for(i = 0; i <= dn_rt_hash_mask; i++) { + dn_rt_hash_table[i].lock = RW_LOCK_UNLOCKED; + dn_rt_hash_table[i].chain = NULL; + } - dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1); + dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1); #ifdef CONFIG_PROC_FS proc_net_create("decnet_cache",0,decnet_cache_get_info); #endif /* CONFIG_PROC_FS */ } -#ifdef CONFIG_DECNET_MODULE -void dn_route_cleanup(void) +void __exit dn_route_cleanup(void) { del_timer(&dn_route_timer); dn_run_flush(0); + #ifdef CONFIG_PROC_FS proc_net_remove("decnet_cache"); #endif /* CONFIG_PROC_FS */ } -#endif /* CONFIG_DECNET_MODULE */ + diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c new file mode 100644 index 000000000..133591f0b --- /dev/null +++ b/net/decnet/dn_rules.c @@ -0,0 +1,372 @@ + +/* + * DECnet An implementation of the DECnet protocol suite for the LINUX + * operating system. DECnet is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * DECnet Routing Forwarding Information Base (Rules) + * + * Author: Steve Whitehouse <SteveW@ACM.org> + * Mostly copied from Alexey Kuznetsov's ipv4/fib_rules.c + * + * + * Changes: + * + */ +#include <linux/config.h> +#include <linux/string.h> +#include <linux/net.h> +#include <linux/socket.h> +#include <linux/sockios.h> +#include <linux/init.h> +#include <linux/skbuff.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <linux/proc_fs.h> +#include <linux/netdevice.h> +#include <linux/timer.h> +#include <linux/spinlock.h> +#include <asm/atomic.h> +#include <asm/uaccess.h> +#include <net/neighbour.h> +#include <net/dst.h> +#include <net/dn.h> +#include <net/dn_fib.h> +#include <net/dn_neigh.h> +#include <net/dn_dev.h> + +struct dn_fib_rule +{ + struct dn_fib_rule *r_next; + atomic_t r_clntref; + u32 r_preference; + unsigned char r_table; + unsigned char r_action; + unsigned char r_dst_len; + unsigned char r_src_len; + dn_address r_src; + dn_address r_srcmask; + dn_address r_dst; + dn_address r_dstmask; + u8 r_flags; +#ifdef CONFIG_DECNET_ROUTE_FWMARK + u32 r_fwmark; +#endif + int r_ifindex; + char r_ifname[IFNAMSIZ]; + int r_dead; +}; + +static struct dn_fib_rule default_rule = { NULL, ATOMIC_INIT(2), 0x7fff, DN_DEFAULT_TABLE, RTN_UNICAST }; + +static struct dn_fib_rule *dn_fib_rules = &default_rule; +static rwlock_t dn_fib_rules_lock = RW_LOCK_UNLOCKED; + + +int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +{ + struct rtattr **rta = arg; + struct rtmsg *rtm = NLMSG_DATA(nlh); + struct dn_fib_rule *r, **rp; + int err = -ESRCH; + + for(rp=&dn_fib_rules; (r=*rp) != NULL; rp = &r->r_next) { + if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 2) == 0) && + rtm->rtm_src_len == r->r_src_len && + rtm->rtm_dst_len == r->r_dst_len && + (!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 2) == 0) && +#ifdef CONFIG_DECNET_ROUTE_FWMARK + (!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) && +#endif + (!rtm->rtm_type || rtm->rtm_type == r->r_action) && + (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) && + (!rta[RTA_IIF-1] || strcmp(RTA_DATA(rta[RTA_IIF-1]), r->r_ifname) == 0) && + (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) { + + err = -EPERM; + if (r == &default_rule) + break; + + write_lock_bh(&dn_fib_rules_lock); + *rp = r->r_next; + r->r_dead = 1; + write_unlock_bh(&dn_fib_rules_lock); + dn_fib_rule_put(r); + err = 0; + break; + } + } + + return err; +} + +void dn_fib_rule_put(struct dn_fib_rule *r) +{ + if (atomic_dec_and_test(&r->r_clntref)) { + if (r->r_dead) + kfree(r); + else + printk(KERN_DEBUG "Attempt to free alive dn_fib_rule\n"); + } +} + + +int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +{ + struct rtattr **rta = arg; + struct rtmsg *rtm = NLMSG_DATA(nlh); + struct dn_fib_rule *r, *new_r, **rp; + unsigned char table_id; + + if (rtm->rtm_src_len > 16 || rtm->rtm_dst_len > 16) + return -EINVAL; + + if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ) + return -EINVAL; + + if (rtm->rtm_type == RTN_NAT) + return -EINVAL; + + table_id = rtm->rtm_table; + if (table_id == RT_TABLE_UNSPEC) { + struct dn_fib_table *tb; + if (rtm->rtm_type == RTN_UNICAST) { + if ((tb = dn_fib_empty_table()) == NULL) + return -ENOBUFS; + table_id = tb->n; + } + } + + new_r = kmalloc(sizeof(*new_r), GFP_KERNEL); + if (!new_r) + return -ENOMEM; + memset(new_r, 0, sizeof(*new_r)); + if (rta[RTA_SRC-1]) + memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2); + if (rta[RTA_DST-1]) + memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 2); + new_r->r_src_len = rtm->rtm_src_len; + new_r->r_dst_len = rtm->rtm_dst_len; + new_r->r_srcmask = dnet_make_mask(rtm->rtm_src_len); + new_r->r_dstmask = dnet_make_mask(rtm->rtm_dst_len); +#ifdef CONFIG_DECNET_ROUTE_FWMARK + if (rta[RTA_PROTOINFO-1]) + memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4); +#endif + new_r->r_action = rtm->rtm_type; + new_r->r_flags = rtm->rtm_flags; + if (rta[RTA_PRIORITY-1]) + memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4); + new_r->r_table = table_id; + if (rta[RTA_IIF-1]) { + struct net_device *dev; + memcpy(new_r->r_ifname, RTA_DATA(rta[RTA_IIF-1]), IFNAMSIZ); + new_r->r_ifname[IFNAMSIZ-1] = 0; + new_r->r_ifindex = -1; + dev = __dev_get_by_name(new_r->r_ifname); + if (dev) + new_r->r_ifindex = dev->ifindex; + } + + rp = &dn_fib_rules; + if (!new_r->r_preference) { + r = dn_fib_rules; + if (r && (r = r->r_next) != NULL) { + rp = &dn_fib_rules->r_next; + if (r->r_preference) + new_r->r_preference = r->r_preference - 1; + } + } + + while((r=*rp) != NULL) { + if (r->r_preference > new_r->r_preference) + break; + rp = &r->r_next; + } + + new_r->r_next = r; + atomic_inc(&new_r->r_clntref); + write_lock_bh(&dn_fib_rules_lock); + *rp = new_r; + write_unlock_bh(&dn_fib_rules_lock); + return 0; +} + + +int dn_fib_lookup(struct dn_fib_key *key, struct dn_fib_res *res) +{ + struct dn_fib_rule *r, *policy; + struct dn_fib_table *tb; + dn_address saddr = key->src; + dn_address daddr = key->dst; + int err; + + read_lock(&dn_fib_rules_lock); + for(r = dn_fib_rules; r; r = r->r_next) { + if (((saddr^r->r_src) & r->r_srcmask) || + ((daddr^r->r_dst) & r->r_dstmask) || +#ifdef CONFIG_DECNET_ROUTE_FWMARK + (r->r_fwmark && r->r_fwmark != key->fwmark) || +#endif + (r->r_ifindex && r->r_ifindex != key->iif)) + continue; + + switch(r->r_action) { + case RTN_UNICAST: + policy = r; + break; + case RTN_UNREACHABLE: + read_unlock(&dn_fib_rules_lock); + return -ENETUNREACH; + default: + case RTN_BLACKHOLE: + read_unlock(&dn_fib_rules_lock); + return -EINVAL; + case RTN_PROHIBIT: + read_unlock(&dn_fib_rules_lock); + return -EACCES; + } + + if ((tb = dn_fib_get_table(r->r_table, 0)) == NULL) + continue; + err = tb->lookup(tb, key, res); + if (err == 0) { + res->r = policy; + if (policy) + atomic_inc(&policy->r_clntref); + read_unlock(&dn_fib_rules_lock); + return 0; + } + if (err < 0 && err != -EAGAIN) { + read_unlock(&dn_fib_rules_lock); + return err; + } + } + + read_unlock(&dn_fib_rules_lock); + return -ESRCH; +} + +static void dn_fib_rules_detach(struct net_device *dev) +{ + struct dn_fib_rule *r; + + for(r = dn_fib_rules; r; r = r->r_next) { + if (r->r_ifindex == dev->ifindex) { + write_lock_bh(&dn_fib_rules_lock); + r->r_ifindex = -1; + write_unlock_bh(&dn_fib_rules_lock); + } + } +} + +static void dn_fib_rules_attach(struct net_device *dev) +{ + struct dn_fib_rule *r; + + for(r = dn_fib_rules; r; r = r->r_next) { + if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) { + write_lock_bh(&dn_fib_rules_lock); + r->r_ifindex = dev->ifindex; + write_unlock_bh(&dn_fib_rules_lock); + } + } +} + +static int dn_fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = ptr; + + switch(event) { + case NETDEV_UNREGISTER: + dn_fib_rules_detach(dev); + dn_fib_sync_down(0, dev, 1); + case NETDEV_REGISTER: + dn_fib_rules_attach(dev); + dn_fib_sync_up(dev); + } + + return NOTIFY_DONE; +} + + +static struct notifier_block dn_fib_rules_notifier = { + dn_fib_rules_event, + NULL, + 0 +}; + +#ifdef CONFIG_RTNETLINK + +static int dn_fib_fill_rule(struct sk_buff *skb, struct dn_fib_rule *r, struct netlink_callback *cb) +{ + struct rtmsg *rtm; + struct nlmsghdr *nlh; + unsigned char *b = skb->tail; + + + nlh = NLMSG_PUT(skb, NETLINK_CREDS(cb->skb)->pid, cb->nlh->nlmsg_seq, RTM_NEWRULE, sizeof(*rtm)); + rtm = NLMSG_DATA(nlh); + rtm->rtm_family = AF_DECnet; + rtm->rtm_dst_len = r->r_dst_len; + rtm->rtm_src_len = r->r_src_len; + rtm->rtm_tos = 0; +#ifdef CONFIG_DECNET_ROUTE_FWMARK + if (r->r_fwmark) + RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark); +#endif + rtm->rtm_table = r->r_table; + rtm->rtm_protocol = 0; + rtm->rtm_scope = 0; + rtm->rtm_type = r->r_action; + rtm->rtm_flags = r->r_flags; + + if (r->r_dst_len) + RTA_PUT(skb, RTA_DST, 2, &r->r_dst); + if (r->r_src_len) + RTA_PUT(skb, RTA_SRC, 2, &r->r_src); + if (r->r_ifname[0]) + RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname); + if (r->r_preference) + RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference); + nlh->nlmsg_len = skb->tail - b; + return skb->len; + +nlmsg_failure: +rtattr_failure: + skb_put(skb, b - skb->tail); + return -1; +} + +int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) +{ + int idx; + int s_idx = cb->args[0]; + struct dn_fib_rule *r; + + read_lock(&dn_fib_rules_lock); + for(r = dn_fib_rules, idx = 0; r; r = r->r_next, idx++) { + if (idx < s_idx) + continue; + if (dn_fib_fill_rule(skb, r, cb) < 0) + break; + } + read_unlock(&dn_fib_rules_lock); + cb->args[0] = idx; + + return skb->len; +} + +#endif /* CONFIG_RTNETLINK */ + +void __init dn_fib_rules_init(void) +{ + register_netdevice_notifier(&dn_fib_rules_notifier); +} + +void __exit dn_fib_rules_cleanup(void) +{ + unregister_netdevice_notifier(&dn_fib_rules_notifier); +} + + diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c new file mode 100644 index 000000000..48c319c8a --- /dev/null +++ b/net/decnet/dn_table.c @@ -0,0 +1,907 @@ +/* + * DECnet An implementation of the DECnet protocol suite for the LINUX + * operating system. DECnet is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * DECnet Routing Forwarding Information Base (Routing Tables) + * + * Author: Steve Whitehouse <SteveW@ACM.org> + * Mostly copied from the IPv4 routing code + * + * + * Changes: + * + */ +#include <linux/config.h> +#include <linux/string.h> +#include <linux/net.h> +#include <linux/socket.h> +#include <linux/sockios.h> +#include <linux/init.h> +#include <linux/skbuff.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <linux/proc_fs.h> +#include <linux/netdevice.h> +#include <linux/timer.h> +#include <linux/spinlock.h> +#include <asm/atomic.h> +#include <asm/uaccess.h> +#include <linux/route.h> /* RTF_xxx */ +#include <net/neighbour.h> +#include <net/dst.h> +#include <net/dn.h> +#include <net/dn_route.h> +#include <net/dn_fib.h> +#include <net/dn_neigh.h> +#include <net/dn_dev.h> + +struct dn_zone +{ + struct dn_zone *dz_next; + struct dn_fib_node **dz_hash; + int dz_nent; + int dz_divisor; + u32 dz_hashmask; +#define DZ_HASHMASK(dz) ((dz)->dz_hashmask) + int dz_order; + u32 dz_mask; +#define DZ_MASK(dz) ((dz)->dz_mask) +}; + +struct dn_hash +{ + struct dn_zone *dh_zones[17]; + struct dn_zone *dh_zone_list; +}; + +#define dz_key_0(key) ((key).datum = 0) +#define dz_prefix(key,dz) ((key).datum) + +#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\ + for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++) + +#define endfor_nexthops(fi) } + +#define DN_MAX_DIVISOR 1024 +#define DN_S_ZOMBIE 1 +#define DN_S_ACCESSED 2 + +#define DN_FIB_SCAN(f, fp) \ +for( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next) + +#define DN_FIB_SCAN_KEY(f, fp, key) \ +for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next) + + +static rwlock_t dn_fib_tables_lock = RW_LOCK_UNLOCKED; +static struct dn_fib_table *dn_fib_tables[DN_NUM_TABLES + 1]; + +static kmem_cache_t *dn_hash_kmem; +static int dn_fib_hash_zombies = 0; + +static __inline__ dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz) +{ + u32 h = ntohs(key.datum)>>(16 - dz->dz_order); + h ^= (h >> 10); + h ^= (h >> 6); + h ^= (h >> 3); + h &= DZ_HASHMASK(dz); + return *(dn_fib_idx_t *)&h; +} + +static __inline__ dn_fib_key_t dz_key(u16 dst, struct dn_zone *dz) +{ + dn_fib_key_t k; + k.datum = dst & DZ_MASK(dz); + return k; +} + +static __inline__ struct dn_fib_node **dn_chain_p(dn_fib_key_t key, struct dn_zone *dz) +{ + return &dz->dz_hash[dn_hash(key, dz).datum]; +} + +static __inline__ struct dn_fib_node *dz_chain(dn_fib_key_t key, struct dn_zone *dz) +{ + return dz->dz_hash[dn_hash(key, dz).datum]; +} + +static __inline__ int dn_key_eq(dn_fib_key_t a, dn_fib_key_t b) +{ + return a.datum == b.datum; +} + +static __inline__ int dn_key_leq(dn_fib_key_t a, dn_fib_key_t b) +{ + return a.datum <= b.datum; +} + +static __inline__ void dn_rebuild_zone(struct dn_zone *dz, + struct dn_fib_node **old_ht, + int old_divisor) +{ + int i; + struct dn_fib_node *f, **fp, *next; + + for(i = 0; i < old_divisor; i++) { + for(f = old_ht[i]; f; f = f->fn_next) { + next = f->fn_next; + for(fp = dn_chain_p(f->fn_key, dz); + *fp && dn_key_leq((*fp)->fn_key, f->fn_key); + fp = &(*fp)->fn_next) + /* NOTHING */; + f->fn_next = *fp; + *fp = f; + } + } +} + +static void dn_rehash_zone(struct dn_zone *dz) +{ + struct dn_fib_node **ht, **old_ht; + int old_divisor, new_divisor; + u32 new_hashmask; + + old_divisor = dz->dz_divisor; + + switch(old_divisor) { + case 16: + new_divisor = 256; + new_hashmask = 0xFF; + break; + default: + printk(KERN_DEBUG "DECnet: dn_rehash_zone: BUG! %d\n", old_divisor); + case 256: + new_divisor = 1024; + new_hashmask = 0x3FF; + break; + } + + ht = kmalloc(new_divisor*sizeof(struct dn_fib_node*), GFP_KERNEL); + + if (ht == NULL) + return; + + memset(ht, 0, new_divisor*sizeof(struct dn_fib_node *)); + write_lock_bh(&dn_fib_tables_lock); + old_ht = dz->dz_hash; + dz->dz_hash = ht; + dz->dz_hashmask = new_hashmask; + dz->dz_divisor = new_divisor; + dn_rebuild_zone(dz, old_ht, old_divisor); + write_unlock_bh(&dn_fib_tables_lock); + kfree(old_ht); +} + +static void dn_free_node(struct dn_fib_node *f) +{ + dn_fib_release_info(DN_FIB_INFO(f)); + kmem_cache_free(dn_hash_kmem, f); +} + + +static struct dn_zone *dn_new_zone(struct dn_hash *table, int z) +{ + int i; + struct dn_zone *dz = kmalloc(sizeof(struct dn_zone), GFP_KERNEL); + if (!dz) + return NULL; + + memset(dz, 0, sizeof(struct dn_zone)); + if (z) { + dz->dz_divisor = 16; + dz->dz_hashmask = 0x0F; + } else { + dz->dz_divisor = 1; + dz->dz_hashmask = 0; + } + + dz->dz_hash = kmalloc(dz->dz_divisor*sizeof(struct dn_fib_node *), GFP_KERNEL); + + if (!dz->dz_hash) { + kfree(dz); + return NULL; + } + + memset(dz->dz_hash, 0, dz->dz_divisor*sizeof(struct dn_fib_node*)); + dz->dz_order = z; + dz->dz_mask = dnet_make_mask(z); + + for(i = z + 1; i <= 16; i++) + if (table->dh_zones[i]) + break; + + write_lock_bh(&dn_fib_tables_lock); + if (i>16) { + dz->dz_next = table->dh_zone_list; + table->dh_zone_list = dz; + } else { + dz->dz_next = table->dh_zones[i]->dz_next; + table->dh_zones[i]->dz_next = dz; + } + table->dh_zones[z] = dz; + write_unlock_bh(&dn_fib_tables_lock); + return dz; +} + + +static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern_rta *rta, struct dn_fib_info *fi) +{ + struct rtnexthop *nhp; + int nhlen; + + if (rta->rta_priority && *rta->rta_priority != fi->fib_priority) + return 1; + + if (rta->rta_oif || rta->rta_gw) { + if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) && + (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 2) == 0)) + return 0; + return 1; + } + + if (rta->rta_mp == NULL) + return 0; + + nhp = RTA_DATA(rta->rta_mp); + nhlen = RTA_PAYLOAD(rta->rta_mp); + + for_nexthops(fi) { + int attrlen = nhlen - sizeof(struct rtnexthop); + dn_address gw; + + if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) + return -EINVAL; + if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif) + return 1; + if (attrlen) { + gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); + + if (gw && gw != nh->nh_gw) + return 1; + } + nhp = RTNH_NEXT(nhp); + } endfor_nexthops(fi); + + return 0; +} + +#ifdef CONFIG_RTNETLINK +static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, + u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, + struct dn_fib_info *fi) +{ + struct rtmsg *rtm; + struct nlmsghdr *nlh; + unsigned char *b = skb->tail; + + nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*rtm)); + rtm = NLMSG_DATA(nlh); + rtm->rtm_family = AF_DECnet; + rtm->rtm_dst_len = dst_len; + rtm->rtm_src_len = 0; + rtm->rtm_tos = 0; + rtm->rtm_table = tb_id; + rtm->rtm_flags = fi->fib_flags; + rtm->rtm_scope = scope; + rtm->rtm_type = type; + if (rtm->rtm_dst_len) + RTA_PUT(skb, RTA_DST, 2, dst); + rtm->rtm_protocol = fi->fib_protocol; + if (fi->fib_priority) + RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority); + if (fi->fib_nhs == 1) { + if (fi->fib_nh->nh_gw) + RTA_PUT(skb, RTA_GATEWAY, 2, &fi->fib_nh->nh_gw); + if (fi->fib_nh->nh_oif) + RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif); + } + if (fi->fib_nhs > 1) { + struct rtnexthop *nhp; + struct rtattr *mp_head; + if (skb_tailroom(skb) <= RTA_SPACE(0)) + goto rtattr_failure; + mp_head = (struct rtattr *)skb_put(skb, RTA_SPACE(0)); + + for_nexthops(fi) { + if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) + goto rtattr_failure; + nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); + nhp->rtnh_flags = nh->nh_flags & 0xFF; + nhp->rtnh_hops = nh->nh_weight - 1; + nhp->rtnh_ifindex = nh->nh_oif; + if (nh->nh_gw) + RTA_PUT(skb, RTA_GATEWAY, 2, &nh->nh_gw); + nhp->rtnh_len = skb->tail - (unsigned char *)nhp; + } endfor_nexthops(fi); + mp_head->rta_type = RTA_MULTIPATH; + mp_head->rta_len = skb->tail - (u8*)mp_head; + } + + nlh->nlmsg_len = skb->tail - b; + return skb->len; + + +nlmsg_failure: +rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + + +static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, int tb_id, + struct nlmsghdr *nlh, struct netlink_skb_parms *req) +{ + struct sk_buff *skb; + u32 pid = req ? req->pid : 0; + int size = NLMSG_SPACE(sizeof(struct rtmsg) + 256); + + skb = alloc_skb(size, GFP_KERNEL); + if (!skb) + return; + + if (dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id, + f->fn_type, f->fn_scope, &f->fn_key, z, + DN_FIB_INFO(f)) < 0) { + kfree_skb(skb); + return; + } + NETLINK_CB(skb).dst_groups = RTMGRP_DECnet_ROUTE; + if (nlh->nlmsg_flags & NLM_F_ECHO) + atomic_inc(&skb->users); + netlink_broadcast(rtnl, skb, pid, RTMGRP_DECnet_ROUTE, GFP_KERNEL); + if (nlh->nlmsg_flags & NLM_F_ECHO) + netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); +} + +static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb, + struct netlink_callback *cb, + struct dn_fib_table *tb, + struct dn_zone *dz, + struct dn_fib_node *f) +{ + int i, s_i; + + s_i = cb->args[3]; + for(i = 0; f; i++, f = f->fn_next) { + if (i < s_i) + continue; + if (f->fn_state & DN_S_ZOMBIE) + continue; + if (dn_fib_dump_info(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + RTM_NEWROUTE, + tb->n, + (f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type, + f->fn_scope, &f->fn_key, dz->dz_order, + f->fn_info) < 0) { + cb->args[3] = i; + return -1; + } + } + cb->args[3] = i; + return skb->len; +} + +static __inline__ int dn_hash_dump_zone(struct sk_buff *skb, + struct netlink_callback *cb, + struct dn_fib_table *tb, + struct dn_zone *dz) +{ + int h, s_h; + + s_h = cb->args[2]; + for(h = 0; h < dz->dz_divisor; h++) { + if (h < s_h) + continue; + if (h > s_h) + memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0])); + if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL) + continue; + if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) { + cb->args[2] = h; + return -1; + } + } + cb->args[2] = h; + return skb->len; +} + +static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb, + struct netlink_callback *cb) +{ + int m, s_m; + struct dn_zone *dz; + struct dn_hash *table = (struct dn_hash *)tb->data; + + s_m = cb->args[1]; + read_lock(&dn_fib_tables_lock); + for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) { + if (m < s_m) + continue; + if (m > s_m) + memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0])); + + if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) { + cb->args[1] = m; + read_unlock(&dn_fib_tables_lock); + return -1; + } + } + read_unlock(&dn_fib_tables_lock); + cb->args[1] = m; + + return skb->len; +} + +#else /* no CONFIG_RTNETLINK */ + +#define dn_rt_msg_fib(event,f,z,tb_id,nlh,req) + +#endif /* CONFIG_RTNETLINK */ + +static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) +{ + struct dn_hash *table = (struct dn_hash *)tb->data; + struct dn_fib_node *new_f, *f, **fp, **del_fp; + struct dn_zone *dz; + struct dn_fib_info *fi; + int z = r->rtm_dst_len; + int type = r->rtm_type; + dn_fib_key_t key; + int err; + + if (z > 16) + return -EINVAL; + + dz = table->dh_zones[z]; + if (!dz && !(dz = dn_new_zone(table, z))) + return -ENOBUFS; + + dz_key_0(key); + if (rta->rta_dst) { + dn_address dst; + memcpy(&dst, rta->rta_dst, 2); + if (dst & ~DZ_MASK(dz)) + return -EINVAL; + key = dz_key(dst, dz); + } + + if ((fi = dn_fib_create_info(r, rta, n, &err)) == NULL) + return err; + + if (dz->dz_nent > (dz->dz_divisor << 2) && + dz->dz_divisor > DN_MAX_DIVISOR && + (z==16 || (1<<z) > dz->dz_divisor)) + dn_rehash_zone(dz); + + fp = dn_chain_p(key, dz); + + DN_FIB_SCAN(f, fp) { + if (dn_key_leq(key, f->fn_key)) + break; + } + + del_fp = NULL; + + if (f && (f->fn_state & DN_S_ZOMBIE) && + dn_key_eq(f->fn_key, key)) { + del_fp = fp; + fp = &f->fn_next; + f = *fp; + goto create; + } + + DN_FIB_SCAN_KEY(f, fp, key) { + if (fi->fib_priority <= DN_FIB_INFO(f)->fib_priority) + break; + } + + if (f && dn_key_eq(f->fn_key, key) && + fi->fib_priority == DN_FIB_INFO(f)->fib_priority) { + struct dn_fib_node **ins_fp; + + err = -EEXIST; + if (n->nlmsg_flags & NLM_F_EXCL) + goto out; + + if (n->nlmsg_flags & NLM_F_REPLACE) { + del_fp = fp; + fp = &f->fn_next; + f = *fp; + goto replace; + } + + ins_fp = fp; + err = -EEXIST; + + DN_FIB_SCAN_KEY(f, fp, key) { + if (fi->fib_priority != DN_FIB_INFO(f)->fib_priority) + break; + if (f->fn_type == type && f->fn_scope == r->rtm_scope + && DN_FIB_INFO(f) == fi) + goto out; + } + + if (!(n->nlmsg_flags & NLM_F_APPEND)) { + fp = ins_fp; + f = *fp; + } + } + +create: + err = -ENOENT; + if (!(n->nlmsg_flags & NLM_F_CREATE)) + goto out; + +replace: + err = -ENOBUFS; + new_f = kmem_cache_alloc(dn_hash_kmem, SLAB_KERNEL); + if (new_f == NULL) + goto out; + + memset(new_f, 0, sizeof(struct dn_fib_node)); + + new_f->fn_key = key; + new_f->fn_type = type; + new_f->fn_scope = r->rtm_scope; + DN_FIB_INFO(new_f) = fi; + + new_f->fn_next = f; + write_lock_bh(&dn_fib_tables_lock); + *fp = new_f; + write_unlock_bh(&dn_fib_tables_lock); + dz->dz_nent++; + + if (del_fp) { + f = *del_fp; + write_lock_bh(&dn_fib_tables_lock); + *del_fp = f->fn_next; + write_unlock_bh(&dn_fib_tables_lock); + + if (!(f->fn_state & DN_S_ZOMBIE)) + dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req); + if (f->fn_state & DN_S_ACCESSED) + dn_rt_cache_flush(-1); + dn_free_node(f); + dz->dz_nent--; + } else { + dn_rt_cache_flush(-1); + } + + dn_rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->n, n, req); + + return 0; +out: + dn_fib_release_info(fi); + return err; +} + + +static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) +{ + struct dn_hash *table = (struct dn_hash*)tb->data; + struct dn_fib_node **fp, **del_fp, *f; + int z = r->rtm_dst_len; + struct dn_zone *dz; + dn_fib_key_t key; + int matched; + + + if (z > 16) + return -EINVAL; + + if ((dz = table->dh_zones[z]) == NULL) + return -ESRCH; + + dz_key_0(key); + if (rta->rta_dst) { + dn_address dst; + memcpy(&dst, rta->rta_dst, 2); + if (dst & ~DZ_MASK(dz)) + return -EINVAL; + key = dz_key(dst, dz); + } + + fp = dn_chain_p(key, dz); + + DN_FIB_SCAN(f, fp) { + if (dn_key_eq(f->fn_key, key)) + break; + if (dn_key_leq(key, f->fn_key)) + return -ESRCH; + } + + matched = 0; + del_fp = NULL; + DN_FIB_SCAN_KEY(f, fp, key) { + struct dn_fib_info *fi = DN_FIB_INFO(f); + + if (f->fn_state & DN_S_ZOMBIE) + return -ESRCH; + + matched++; + + if (del_fp == NULL && + (!r->rtm_type || f->fn_type == r->rtm_type) && + (r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) && + (!r->rtm_protocol || + fi->fib_protocol == r->rtm_protocol) && + dn_fib_nh_match(r, n, rta, fi) == 0) + del_fp = fp; + } + + if (del_fp) { + f = *del_fp; + dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req); + + if (matched != 1) { + write_lock_bh(&dn_fib_tables_lock); + *del_fp = f->fn_next; + write_unlock_bh(&dn_fib_tables_lock); + + if (f->fn_state & DN_S_ACCESSED) + dn_rt_cache_flush(-1); + dn_free_node(f); + dz->dz_nent--; + } else { + f->fn_state |= DN_S_ZOMBIE; + if (f->fn_state & DN_S_ACCESSED) { + f->fn_state &= ~DN_S_ACCESSED; + dn_rt_cache_flush(-1); + } + if (++dn_fib_hash_zombies > 128) + dn_fib_flush(); + } + + return 0; + } + + return -ESRCH; +} + +static __inline__ int dn_flush_list(struct dn_fib_node **fp, int z, struct dn_hash *table) +{ + int found = 0; + struct dn_fib_node *f; + + while((f = *fp) != NULL) { + struct dn_fib_info *fi = DN_FIB_INFO(f); + + if (fi && ((f->fn_state & DN_S_ZOMBIE) || (fi->fib_flags & RTNH_F_DEAD))) { + write_lock_bh(&dn_fib_tables_lock); + *fp = f->fn_next; + write_unlock_bh(&dn_fib_tables_lock); + + dn_free_node(f); + found++; + continue; + } + fp = &f->fn_next; + } + + return found; +} + +static int dn_fib_table_flush(struct dn_fib_table *tb) +{ + struct dn_hash *table = (struct dn_hash *)tb->data; + struct dn_zone *dz; + int found = 0; + + dn_fib_hash_zombies = 0; + for(dz = table->dh_zone_list; dz; dz = dz->dz_next) { + int i; + int tmp = 0; + for(i = dz->dz_divisor-1; i >= 0; i--) + tmp += dn_flush_list(&dz->dz_hash[i], dz->dz_order, table); + dz->dz_nent -= tmp; + found += tmp; + } + + return found; +} + +static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct dn_fib_key * +key, struct dn_fib_res *res) +{ + int err; + struct dn_zone *dz; + struct dn_hash *t = (struct dn_hash *)tb->data; + + read_lock(&dn_fib_tables_lock); + for(dz = t->dh_zone_list; dz; dz = dz->dz_next) { + struct dn_fib_node *f; + dn_fib_key_t k = dz_key(key->dst, dz); + + for(f = dz_chain(k, dz); f; f = f->fn_next) { + if (!dn_key_leq(k, f->fn_key)) + break; + else + continue; + + f->fn_state |= DN_S_ACCESSED; + + if (f->fn_state&DN_S_ZOMBIE) + continue; + if (f->fn_scope < key->scope) + continue; + + err = dn_fib_semantic_match(f->fn_type, DN_FIB_INFO(f), key, res); + if (err == 0) { + res->type = f->fn_type; + res->scope = f->fn_scope; + res->prefixlen = dz->dz_order; + goto out; + } + if (err < 0) + goto out; + } + } + err = 1; +out: + read_unlock(&dn_fib_tables_lock); + return err; +} + +#ifdef CONFIG_PROC_FS + +static unsigned dn_fib_flag_trans(int type, int dead, u16 mask, struct dn_fib_info *fi) +{ + static unsigned type2flags[RTN_MAX+1] = { + 0, 0, 0, 0, 0, 0, 0, RTF_REJECT, RTF_REJECT, 0, 0, 0 + }; + unsigned flags = type2flags[type]; + + if (fi && fi->fib_nh->nh_gw) + flags |= RTF_GATEWAY; + if (mask == 0xFFFF) + flags |= RTF_HOST; + if (dead) + flags |= RTF_UP; + return flags; +} + +static void dn_fib_node_get_info(int type, int dead, struct dn_fib_info *fi, u16 prefix, u16 mask, char *buffer) +{ + int len; + unsigned flags = dn_fib_flag_trans(type, dead, mask, fi); + + if (fi) { + len = sprintf(buffer, "%s\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u", + fi->fib_dev ? fi->fib_dev->name : "*", prefix, + fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority, + mask, 0, 0, 0); + } else { + len = sprintf(buffer, "*\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u", + prefix, 0, + flags, 0, 0, 0, + mask, 0, 0, 0); + } + memset(buffer+len, ' ', 127-len); + buffer[127] = '\n'; +} + +static int dn_fib_table_get_info(struct dn_fib_table *tb, char *buffer, int first, int count) +{ + struct dn_hash *table = (struct dn_hash *)tb->data; + struct dn_zone *dz; + int pos = 0; + int n = 0; + + read_lock(&dn_fib_tables_lock); + for(dz = table->dh_zone_list; dz; dz = dz->dz_next) { + int i; + struct dn_fib_node *f; + int maxslot = dz->dz_divisor; + struct dn_fib_node **fp = dz->dz_hash; + + if (dz->dz_nent == 0) + continue; + + if (pos + dz->dz_nent < first) { + pos += dz->dz_nent; + continue; + } + + for(i = 0; i < maxslot; i++, fp++) { + for(f = *fp; f ; f = f->fn_next) { + if (++pos <= first) + continue; + dn_fib_node_get_info(f->fn_type, + f->fn_state & DN_S_ZOMBIE, + DN_FIB_INFO(f), + dz_prefix(f->fn_key, dz), + DZ_MASK(dz), buffer); + buffer += 128; + if (++n >= count) + goto out; + } + } + } +out: + read_unlock(&dn_fib_tables_lock); + return n; +} +#endif /* CONFIG_PROC_FS */ + +struct dn_fib_table *dn_fib_get_table(int n, int create) +{ + struct dn_fib_table *t; + + if (n < DN_MIN_TABLE) + return NULL; + + if (n > DN_NUM_TABLES) + return NULL; + + if (dn_fib_tables[n]) + return dn_fib_tables[n]; + + if (!create) + return NULL; + + if (in_interrupt() && net_ratelimit()) { + printk(KERN_DEBUG "DECnet: BUG! Attempt to create routing table +from interrupt\n"); + return NULL; + } + if ((t = kmalloc(sizeof(struct dn_fib_table), GFP_KERNEL)) == NULL) + return NULL; + + memset(t, 0, sizeof(struct dn_fib_table)); + + t->n = n; + t->insert = dn_fib_table_insert; + t->delete = dn_fib_table_delete; + t->lookup = dn_fib_table_lookup; + t->flush = dn_fib_table_flush; +#ifdef CONFIG_PROC_FS + t->get_info = dn_fib_table_get_info; +#endif +#ifdef CONFIG_RTNETLINK + t->dump = dn_fib_table_dump; +#endif + dn_fib_tables[n] = t; + + return t; +} + +static void dn_fib_del_tree(int n) +{ + struct dn_fib_table *t; + + write_lock(&dn_fib_tables_lock); + t = dn_fib_tables[n]; + dn_fib_tables[n] = NULL; + write_unlock(&dn_fib_tables_lock); + + if (t) { + kfree_s(t, sizeof(struct dn_fib_table)); + } +} + +struct dn_fib_table *dn_fib_empty_table(void) +{ + int id; + + for(id = DN_MIN_TABLE; id <= DN_NUM_TABLES; id++) + if (dn_fib_tables[id] == NULL) + return dn_fib_get_table(id, 1); + return NULL; +} + +void __init dn_fib_table_init(void) +{ + dn_hash_kmem = kmem_cache_create("dn_fib_info_cache", + sizeof(struct dn_fib_info), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); +} + +void __exit dn_fib_table_cleanup(void) +{ + return; +} + diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c index 5dcb0ef49..f80e5afc1 100644 --- a/net/decnet/sysctl_net_decnet.c +++ b/net/decnet/sysctl_net_decnet.c @@ -104,123 +104,6 @@ static int parse_addr(dn_address *addr, char *str) return 0; } -static char *node2str(int n) -{ - switch(n) { - case DN_RT_INFO_ENDN: - return "EndNode\n"; - case DN_RT_INFO_L1RT: - return "Level 1 Router\n"; - case DN_RT_INFO_L2RT: - return "Level 2 Router\n"; - } - - return "Unknown\n"; -} - -static int dn_node_type_strategy(ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen, - void **context) -{ - int len; - int type; - - if (oldval && oldlenp) { - if (get_user(len, oldlenp)) - return -EFAULT; - if (len) { - if (len != sizeof(int)) - return -EINVAL; - if (put_user(decnet_node_type, (int *)oldval)) - return -EFAULT; - } - } - - if (newval && newlen) { - if (newlen != sizeof(int)) - return -EINVAL; - - if (get_user(type, (int *)newval)) - return -EFAULT; - - switch(type) { - case DN_RT_INFO_ENDN: /* EndNode */ -#ifdef CONFIG_DECNET_ROUTER - case DN_RT_INFO_L1RT: /* Level 1 Router */ - case DN_RT_INFO_L2RT: /* Level 2 Router */ -#endif - break; - default: - return -EINVAL; - } - - if (decnet_node_type != type) { - dn_dev_devices_off(); - decnet_node_type = type; - dn_dev_devices_on(); - } - } - return 0; -} - -static int dn_node_type_handler(ctl_table *table, int write, - struct file * filp, - void *buffer, size_t *lenp) -{ - char *s = node2str(decnet_node_type); - int len = strlen(s); - - if (!*lenp || (filp->f_pos && !write)) { - *lenp = 0; - return 0; - } - - if (write) { - char c = *(char *)buffer; - int type = 0; - - switch(c) { - case 'e': - case 'E': - case '0': - type = DN_RT_INFO_ENDN; - break; -#ifdef CONFIG_DECNET_ROUTER - case 'r': - case '1': - type = DN_RT_INFO_L1RT; - break; - case 'R': - case '2': - type = DN_RT_INFO_L2RT; - break; -#endif /* CONFIG_DECNET_ROUTER */ - default: - return -EINVAL; - } - - if (decnet_node_type != type) { - dn_dev_devices_off(); - decnet_node_type = type; - dn_dev_devices_on(); - } - - filp->f_pos += 1; - - return 0; - } - - if (len > *lenp) len = *lenp; - - if (copy_to_user(buffer, s, len)) - return -EFAULT; - - *lenp = len; - filp->f_pos += len; - - return 0; -} static int dn_node_address_strategy(ctl_table *table, int *name, int nlen, void *oldval, size_t *oldlenp, @@ -374,6 +257,7 @@ static int dn_def_dev_handler(ctl_table *table, int write, } if (write) { + int i; if (*lenp > 16) return -E2BIG; @@ -382,6 +266,9 @@ static int dn_def_dev_handler(ctl_table *table, int write, return -EFAULT; devname[*lenp] = 0; + for(i = 0; i < (*lenp); i++) + if (devname[i] == '\n') + devname[i] = 0; if ((dev = __dev_get_by_name(devname)) == NULL) return -ENODEV; @@ -416,9 +303,6 @@ static int dn_def_dev_handler(ctl_table *table, int write, } static ctl_table dn_table[] = { - {NET_DECNET_NODE_TYPE, "node_type", NULL, 1, 0644, NULL, - dn_node_type_handler, dn_node_type_strategy, NULL, - NULL, NULL}, {NET_DECNET_NODE_ADDRESS, "node_address", NULL, 7, 0644, NULL, dn_node_address_handler, dn_node_address_strategy, NULL, NULL, NULL}, diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index b0d08ebe7..94fb19f92 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.100 1999/12/21 04:05:02 davem Exp $ + * Version: $Id: af_inet.c,v 1.101 2000/01/09 02:19:38 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -115,7 +115,7 @@ #define min(a,b) ((a)<(b)?(a):(b)) -struct linux_mib net_statistics; +struct linux_mib net_statistics[NR_CPUS*2]; atomic_t inet_sock_nr; @@ -397,7 +397,7 @@ static int inet_create(struct socket *sock, int protocol) sk->timer.data = (unsigned long)sk; sk->timer.function = &tcp_keepalive_timer; - sk->protinfo.af_inet.ttl=ip_statistics.IpDefaultTTL; + sk->protinfo.af_inet.ttl=sysctl_ip_default_ttl; sk->protinfo.af_inet.mc_loop=1; sk->protinfo.af_inet.mc_ttl=1; diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 2c2da8eee..d50b56ea9 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1,7 +1,7 @@ /* * NET3 IP device support routines. * - * Version: $Id: devinet.c,v 1.35 1999/08/31 07:03:20 davem Exp $ + * Version: $Id: devinet.c,v 1.36 2000/01/09 02:19:46 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -730,7 +730,7 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope) read_unlock(&in_dev->lock); read_unlock(&inetdev_lock); - if (addr || scope >= RT_SCOPE_LINK) + if (addr) return addr; /* Not loopback addresses on loopback should be preferred @@ -745,7 +745,8 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope) read_lock(&in_dev->lock); for_primary_ifa(in_dev) { - if (ifa->ifa_scope <= scope) { + if (ifa->ifa_scope != RT_SCOPE_LINK && + ifa->ifa_scope <= scope) { read_unlock(&in_dev->lock); read_unlock(&inetdev_lock); read_unlock(&dev_base_lock); @@ -1001,8 +1002,6 @@ void inet_forward_change() read_unlock(&dev_base_lock); rt_cache_flush(0); - - ip_statistics.IpForwarding = on ? 1 : 2; } static diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 24ee69e05..2b61c67af 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -3,7 +3,7 @@ * * Alan Cox, <alan@redhat.com> * - * Version: $Id: icmp.c,v 1.62 1999/12/23 01:43:37 davem Exp $ + * Version: $Id: icmp.c,v 1.63 2000/01/09 02:19:45 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -285,7 +285,7 @@ * Statistics */ -struct icmp_mib icmp_statistics; +struct icmp_mib icmp_statistics[NR_CPUS*2]; /* An array of errno for error messages from dest unreach. */ /* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOS_UNREACH and SR_FAIELD MUST be considered 'transient errs'. */ @@ -468,8 +468,8 @@ static void icmp_out_count(int type) { if (type>NR_ICMP_TYPES) return; - (*icmp_pointers[type].output)++; - icmp_statistics.IcmpOutMsgs++; + (icmp_pointers[type].output)[(smp_processor_id()*2+!in_interrupt())*sizeof(struct icmp_mib)/sizeof(unsigned long)]++; + ICMP_INC_STATS(IcmpOutMsgs); } /* @@ -527,9 +527,12 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) sk->protinfo.af_inet.tos = skb->nh.iph->tos; daddr = ipc.addr = rt->rt_src; - ipc.opt = &icmp_param->replyopts; - if (ipc.opt->srr) - daddr = icmp_param->replyopts.faddr; + ipc.opt = NULL; + if (icmp_param->replyopts.optlen) { + ipc.opt = &icmp_param->replyopts; + if (ipc.opt->srr) + daddr = icmp_param->replyopts.faddr; + } if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0)) goto out; ip_build_xmit(sk, icmp_glue_bits, icmp_param, @@ -561,49 +564,41 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info) struct ipcm_cookie ipc; u32 saddr; u8 tos; - + + if (!rt) + return; + /* * Find the original header */ - iph = skb_in->nh.iph; - + /* * No replies to physical multicast/broadcast */ - if (skb_in->pkt_type!=PACKET_HOST) return; - + /* * Now check at the protocol level */ - if (!rt) { - if (net_ratelimit()) - printk(KERN_DEBUG "icmp_send: destinationless packet\n"); - return; - } if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST)) return; - - + /* * Only reply to fragment 0. We byte re-order the constant * mask for efficiency. */ - if (iph->frag_off&htons(IP_OFFSET)) return; - + /* * If we send an ICMP error to an ICMP error a mess would result.. */ - if (icmp_pointers[type].error) { /* * We are an error, check if we are replying to an ICMP error */ - if (iph->protocol==IPPROTO_ICMP) { icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); /* @@ -649,7 +644,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info) */ if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0)) goto out; - + if (ip_options_echo(&icmp_param.replyopts, skb_in)) goto ende; @@ -719,7 +714,7 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len) */ if(len<sizeof(struct iphdr)) { - icmp_statistics.IcmpInErrors++; + ICMP_INC_STATS_BH(IcmpInErrors); return; } @@ -841,7 +836,7 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, int len) unsigned long ip; if (len < sizeof(struct iphdr)) { - icmp_statistics.IcmpInErrors++; + ICMP_INC_STATS_BH(IcmpInErrors); return; } @@ -910,7 +905,7 @@ static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, int len) */ if(len<12) { - icmp_statistics.IcmpInErrors++; + ICMP_INC_STATS_BH(IcmpInErrors); return; } @@ -1024,7 +1019,7 @@ int icmp_rcv(struct sk_buff *skb, unsigned short len) struct icmphdr *icmph = skb->h.icmph; struct rtable *rt = (struct rtable*)skb->dst; - icmp_statistics.IcmpInMsgs++; + ICMP_INC_STATS_BH(IcmpInMsgs); /* * 18 is the highest 'known' ICMP type. Anything else is a mystery @@ -1060,14 +1055,14 @@ int icmp_rcv(struct sk_buff *skb, unsigned short len) } len -= sizeof(struct icmphdr); - (*icmp_pointers[icmph->type].input)++; + icmp_pointers[icmph->type].input[smp_processor_id()*2*sizeof(struct icmp_mib)/sizeof(unsigned long)]++; (icmp_pointers[icmph->type].handler)(icmph, skb, len); drop: kfree_skb(skb); return 0; error: - icmp_statistics.IcmpInErrors++; + ICMP_INC_STATS_BH(IcmpInErrors); goto drop; } @@ -1096,37 +1091,37 @@ int sysctl_icmp_echoreply_time = 0; /* don't limit it per default. */ static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1] = { /* ECHO REPLY (0) */ - { &icmp_statistics.IcmpOutEchoReps, &icmp_statistics.IcmpInEchoReps, icmp_discard, 0, &sysctl_icmp_echoreply_time}, - { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, }, - { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, }, + { &icmp_statistics[0].IcmpOutEchoReps, &icmp_statistics[0].IcmpInEchoReps, icmp_discard, 0, &sysctl_icmp_echoreply_time}, + { &dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, }, + { &dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, }, /* DEST UNREACH (3) */ - { &icmp_statistics.IcmpOutDestUnreachs, &icmp_statistics.IcmpInDestUnreachs, icmp_unreach, 1, &sysctl_icmp_destunreach_time }, + { &icmp_statistics[0].IcmpOutDestUnreachs, &icmp_statistics[0].IcmpInDestUnreachs, icmp_unreach, 1, &sysctl_icmp_destunreach_time }, /* SOURCE QUENCH (4) */ - { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1, }, + { &icmp_statistics[0].IcmpOutSrcQuenchs, &icmp_statistics[0].IcmpInSrcQuenchs, icmp_unreach, 1, }, /* REDIRECT (5) */ - { &icmp_statistics.IcmpOutRedirects, &icmp_statistics.IcmpInRedirects, icmp_redirect, 1, }, - { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, }, - { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, }, + { &icmp_statistics[0].IcmpOutRedirects, &icmp_statistics[0].IcmpInRedirects, icmp_redirect, 1, }, + { &dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, }, + { &dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, }, /* ECHO (8) */ - { &icmp_statistics.IcmpOutEchos, &icmp_statistics.IcmpInEchos, icmp_echo, 0, }, - { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, }, - { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, }, + { &icmp_statistics[0].IcmpOutEchos, &icmp_statistics[0].IcmpInEchos, icmp_echo, 0, }, + { &dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, }, + { &dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, }, /* TIME EXCEEDED (11) */ - { &icmp_statistics.IcmpOutTimeExcds, &icmp_statistics.IcmpInTimeExcds, icmp_unreach, 1, &sysctl_icmp_timeexceed_time }, + { &icmp_statistics[0].IcmpOutTimeExcds, &icmp_statistics[0].IcmpInTimeExcds, icmp_unreach, 1, &sysctl_icmp_timeexceed_time }, /* PARAMETER PROBLEM (12) */ - { &icmp_statistics.IcmpOutParmProbs, &icmp_statistics.IcmpInParmProbs, icmp_unreach, 1, &sysctl_icmp_paramprob_time }, + { &icmp_statistics[0].IcmpOutParmProbs, &icmp_statistics[0].IcmpInParmProbs, icmp_unreach, 1, &sysctl_icmp_paramprob_time }, /* TIMESTAMP (13) */ - { &icmp_statistics.IcmpOutTimestamps, &icmp_statistics.IcmpInTimestamps, icmp_timestamp, 0, }, + { &icmp_statistics[0].IcmpOutTimestamps, &icmp_statistics[0].IcmpInTimestamps, icmp_timestamp, 0, }, /* TIMESTAMP REPLY (14) */ - { &icmp_statistics.IcmpOutTimestampReps, &icmp_statistics.IcmpInTimestampReps, icmp_discard, 0, }, + { &icmp_statistics[0].IcmpOutTimestampReps, &icmp_statistics[0].IcmpInTimestampReps, icmp_discard, 0, }, /* INFO (15) */ { &dummy, &dummy, icmp_discard, 0, }, /* INFO REPLY (16) */ { &dummy, &dummy, icmp_discard, 0, }, /* ADDR MASK (17) */ - { &icmp_statistics.IcmpOutAddrMasks, &icmp_statistics.IcmpInAddrMasks, icmp_address, 0, }, + { &icmp_statistics[0].IcmpOutAddrMasks, &icmp_statistics[0].IcmpInAddrMasks, icmp_address, 0, }, /* ADDR MASK REPLY (18) */ - { &icmp_statistics.IcmpOutAddrMaskReps, &icmp_statistics.IcmpInAddrMaskReps, icmp_address_reply, 0, } + { &icmp_statistics[0].IcmpOutAddrMaskReps, &icmp_statistics[0].IcmpInAddrMaskReps, icmp_address_reply, 0, } }; void __init icmp_init(struct net_proto_family *ops) diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index b4afbc85a..7d8efb6dd 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -5,7 +5,7 @@ * * The IP forwarding functionality. * - * Version: $Id: ip_forward.c,v 1.45 1999/08/20 11:05:16 davem Exp $ + * Version: $Id: ip_forward.c,v 1.46 2000/01/09 02:19:37 davem Exp $ * * Authors: see ip.c * @@ -45,7 +45,7 @@ static inline int ip_forward_finish(struct sk_buff *skb) { struct ip_options * opt = &(IPCB(skb)->opt); - ip_statistics.IpForwDatagrams++; + IP_INC_STATS_BH(IpForwDatagrams); if (opt->optlen == 0) { #ifdef CONFIG_NET_FASTROUTE @@ -147,7 +147,7 @@ int ip_forward(struct sk_buff *skb) ip_forward_finish); frag_needed: - ip_statistics.IpFragFails++; + IP_INC_STATS_BH(IpFragFails); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); goto drop; diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 4e6ffef06..1c0b9dae7 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -5,7 +5,7 @@ * * The IP fragmentation functionality. * - * Version: $Id: ip_fragment.c,v 1.45 1999/08/30 10:17:10 davem Exp $ + * Version: $Id: ip_fragment.c,v 1.46 2000/01/09 02:19:36 davem Exp $ * * Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG> * Alan Cox <Alan.Cox@linux.org> @@ -211,8 +211,8 @@ static void ip_expire(unsigned long arg) } /* Send an ICMP "Fragment Reassembly Timeout" message. */ - ip_statistics.IpReasmTimeout++; - ip_statistics.IpReasmFails++; + IP_INC_STATS_BH(IpReasmTimeout); + IP_INC_STATS_BH(IpReasmFails); icmp_send(qp->fragments->skb, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); out: @@ -395,7 +395,7 @@ static struct sk_buff *ip_glue(struct ipq *qp) iph = skb->nh.iph; iph->frag_off = 0; iph->tot_len = htons(count); - ip_statistics.IpReasmOKs++; + IP_INC_STATS_BH(IpReasmOKs); return skb; out_invalid: @@ -414,7 +414,7 @@ out_oversize: "Oversized IP packet from %d.%d.%d.%d.\n", NIPQUAD(qp->iph->saddr)); out_fail: - ip_statistics.IpReasmFails++; + IP_INC_STATS_BH(IpReasmFails); return NULL; } @@ -428,7 +428,7 @@ struct sk_buff *ip_defrag(struct sk_buff *skb) int flags, offset; int i, ihl, end; - ip_statistics.IpReasmReqds++; + IP_INC_STATS_BH(IpReasmReqds); spin_lock(&ipfrag_lock); @@ -599,7 +599,7 @@ out_oversize: /* the skb isn't in a fragment, so fall through to free it */ out_freeskb: kfree_skb(skb); - ip_statistics.IpReasmFails++; + IP_INC_STATS_BH(IpReasmFails); if (qp) goto out_timer; goto out; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index b00584e59..8d651b042 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -790,7 +790,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) iph->ttl = ((struct ipv6hdr*)old_iph)->hop_limit; #endif else - iph->ttl = ip_statistics.IpDefaultTTL; + iph->ttl = sysctl_ip_default_ttl; } ((u16*)(iph+1))[0] = tunnel->parms.o_flags; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 4ebdbdfb4..11a8c319b 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) module. * - * Version: $Id: ip_input.c,v 1.42 1999/08/20 11:05:27 davem Exp $ + * Version: $Id: ip_input.c,v 1.44 2000/01/09 02:19:30 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -148,7 +148,7 @@ * SNMP management statistics */ -struct ip_mib ip_statistics={2,IPDEFTTL,}; /* Forwarding=No, Default TTL=64 */ +struct ip_mib ip_statistics[NR_CPUS*2]; /* * Process Router Attention IP option @@ -368,7 +368,7 @@ static inline int ip_rcv_finish(struct sk_buff *skb) return skb->dst->input(skb); inhdr_error: - ip_statistics.IpInHdrErrors++; + IP_INC_STATS_BH(IpInHdrErrors); drop: kfree_skb(skb); return(0); @@ -387,7 +387,7 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) if (skb->pkt_type == PACKET_OTHERHOST) goto drop; - ip_statistics.IpInReceives++; + IP_INC_STATS_BH(IpInReceives); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) goto out; @@ -403,14 +403,14 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) * 4. Doesn't have a bogus length */ - if (skb->len < sizeof(struct iphdr)) + if (skb->len < sizeof(struct iphdr) || skb->len < (iph->ihl<<2)) goto inhdr_error; if (iph->ihl < 5 || iph->version != 4 || ip_fast_csum((u8 *)iph, iph->ihl) != 0) goto inhdr_error; { __u32 len = ntohs(iph->tot_len); - if (skb->len < len) + if (skb->len < len || len < (iph->ihl<<2)) goto inhdr_error; /* Our transport medium may have padded the buffer out. Now we know it @@ -424,7 +424,7 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) ip_rcv_finish); inhdr_error: - ip_statistics.IpInHdrErrors++; + IP_INC_STATS_BH(IpInHdrErrors); drop: kfree_skb(skb); out: diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index f89109f15..59e6ff865 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) output module. * - * Version: $Id: ip_output.c,v 1.76 2000/01/06 00:41:57 davem Exp $ + * Version: $Id: ip_output.c,v 1.77 2000/01/09 02:19:31 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -82,6 +82,7 @@ */ int sysctl_ip_dynaddr = 0; +int sysctl_ip_default_ttl = IPDEFTTL; /* Generate a checksum for an outgoing IP datagram. */ __inline__ void ip_send_check(struct iphdr *iph) @@ -228,7 +229,7 @@ int ip_mc_output(struct sk_buff *skb) /* * If the indicated interface is up and running, send the packet. */ - ip_statistics.IpOutRequests++; + IP_INC_STATS(IpOutRequests); #ifdef CONFIG_IP_ROUTE_NAT if (rt->rt_flags & RTCF_NAT) ip_do_nat(skb); @@ -285,7 +286,7 @@ int ip_output(struct sk_buff *skb) struct rtable *rt = (struct rtable*)skb->dst; #endif - ip_statistics.IpOutRequests++; + IP_INC_STATS(IpOutRequests); #ifdef CONFIG_IP_ROUTE_NAT if (rt->rt_flags&RTCF_NAT) @@ -436,7 +437,7 @@ int ip_queue_xmit(struct sk_buff *skb) ip_queue_xmit2); no_route: - ip_statistics.IpOutNoRoutes++; + IP_INC_STATS(IpOutNoRoutes); kfree_skb(skb); return -EHOSTUNREACH; } @@ -644,14 +645,14 @@ static int ip_build_xmit_slow(struct sock *sk, } while (offset >= 0); if (nfrags>1) - ip_statistics.IpFragCreates += nfrags; + ip_statistics[smp_processor_id()*2 + !in_interrupt()].IpFragCreates += nfrags; out: return 0; error: - ip_statistics.IpOutDiscards++; + IP_INC_STATS(IpOutDiscards); if (nfrags>1) - ip_statistics.IpFragCreates += nfrags; + ip_statistics[smp_processor_id()*2 + !in_interrupt()].IpFragCreates += nfrags; return err; } @@ -757,7 +758,7 @@ error_fault: err = -EFAULT; kfree_skb(skb); error: - ip_statistics.IpOutDiscards++; + IP_INC_STATS(IpOutDiscards); return err; } @@ -893,7 +894,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) * Put this fragment into the sending queue. */ - ip_statistics.IpFragCreates++; + IP_INC_STATS(IpFragCreates); iph->tot_len = htons(len + hlen); @@ -904,12 +905,12 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) goto fail; } kfree_skb(skb); - ip_statistics.IpFragOKs++; + IP_INC_STATS(IpFragOKs); return err; fail: kfree_skb(skb); - ip_statistics.IpFragFails++; + IP_INC_STATS(IpFragFails); return err; } diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 7278a0b4a..c618689b2 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -5,7 +5,7 @@ * * The IP to API glue. * - * Version: $Id: ip_sockglue.c,v 1.45 1999/09/06 04:58:03 davem Exp $ + * Version: $Id: ip_sockglue.c,v 1.46 2000/01/09 02:19:32 davem Exp $ * * Authors: see ip.c * @@ -479,7 +479,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt if (optlen<1) goto e_inval; if(val==-1) - val = ip_statistics.IpDefaultTTL; + val = sysctl_ip_default_ttl; if(val<1||val>255) goto e_inval; sk->protinfo.af_inet.ttl=val; diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 37b41e93a..4d2195312 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -1,5 +1,5 @@ /* - * $Id: ipconfig.c,v 1.24 1999/08/20 00:35:14 davem Exp $ + * $Id: ipconfig.c,v 1.25 2000/01/09 02:19:31 davem Exp $ * * Automatic Configuration of IP -- use BOOTP or RARP or user-supplied * information to configure own IP address and routes. @@ -116,7 +116,7 @@ static int __init ic_open_devs(void) unsigned short oflags; last = &ic_first_dev; - read_lock(&dev_base_lock); + rtnl_shlock(); for (dev = dev_base; dev; dev = dev->next) { if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) : (!(dev->flags & IFF_LOOPBACK) && @@ -148,7 +148,7 @@ static int __init ic_open_devs(void) DBG(("IP-Config: Opened %s (able=%d)\n", dev->name, able)); } } - read_unlock(&dev_base_lock); + rtnl_shunlock(); *last = NULL; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index cba4995cc..fce5a43f8 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -9,7 +9,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: ipmr.c,v 1.49 2000/01/06 00:41:56 davem Exp $ + * Version: $Id: ipmr.c,v 1.50 2000/01/09 02:19:32 davem Exp $ * * Fixes: * Michael Chastain : Incorrect size of copying. @@ -1157,7 +1157,7 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, to blackhole. */ - ip_statistics.IpFragFails++; + IP_INC_STATS_BH(IpFragFails); ip_rt_put(rt); return; } diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 520f6ef81..b3e86f58c 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -7,7 +7,7 @@ * PROC file system. It is mainly used for debugging and * statistics. * - * Version: $Id: proc.c,v 1.37 1999/12/15 22:39:19 davem Exp $ + * Version: $Id: proc.c,v 1.38 2000/01/09 02:19:30 davem Exp $ * * Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de> @@ -50,6 +50,17 @@ #include <net/sock.h> #include <net/raw.h> +static int fold_prot_inuse(struct proto *proto) +{ + int res = 0; + int cpu; + + for (cpu=0; cpu<smp_num_cpus; cpu++) + res += proto->stats[cpu].inuse; + + return res; +} + /* * Report socket allocation statistics [mea@utu.fi] */ @@ -60,12 +71,12 @@ int afinet_get_info(char *buffer, char **start, off_t offset, int length) int len = socket_get_info(buffer,start,offset,length); - len += sprintf(buffer+len,"TCP: inuse %d highest %d\n", - tcp_prot.inuse, tcp_prot.highestinuse); - len += sprintf(buffer+len,"UDP: inuse %d highest %d\n", - udp_prot.inuse, udp_prot.highestinuse); - len += sprintf(buffer+len,"RAW: inuse %d highest %d\n", - raw_prot.inuse, raw_prot.highestinuse); + len += sprintf(buffer+len,"TCP: inuse %d\n", + fold_prot_inuse(&tcp_prot)); + len += sprintf(buffer+len,"UDP: inuse %d\n", + fold_prot_inuse(&udp_prot)); + len += sprintf(buffer+len,"RAW: inuse %d\n", + fold_prot_inuse(&raw_prot)); if (offset >= len) { *start = buffer; @@ -80,6 +91,17 @@ int afinet_get_info(char *buffer, char **start, off_t offset, int length) return len; } +static unsigned long fold_field(unsigned long *begin, int sz, int nr) +{ + unsigned long res = 0; + int i; + + sz /= sizeof(unsigned long); + + for (i=0; i<2*smp_num_cpus; i++) + res += begin[i*sz + nr]; + return res; +} /* * Called from the PROCfs module. This outputs /proc/net/snmp. @@ -87,65 +109,35 @@ int afinet_get_info(char *buffer, char **start, off_t offset, int length) int snmp_get_info(char *buffer, char **start, off_t offset, int length) { - extern struct tcp_mib tcp_statistics; - extern struct udp_mib udp_statistics; - int len; -/* - extern unsigned long tcp_rx_miss, tcp_rx_hit1,tcp_rx_hit2; -*/ + extern int sysctl_ip_default_ttl; + int len, i; len = sprintf (buffer, "Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates\n" - "Ip: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", - ip_statistics.IpForwarding, ip_statistics.IpDefaultTTL, - ip_statistics.IpInReceives, ip_statistics.IpInHdrErrors, - ip_statistics.IpInAddrErrors, ip_statistics.IpForwDatagrams, - ip_statistics.IpInUnknownProtos, ip_statistics.IpInDiscards, - ip_statistics.IpInDelivers, ip_statistics.IpOutRequests, - ip_statistics.IpOutDiscards, ip_statistics.IpOutNoRoutes, - ip_statistics.IpReasmTimeout, ip_statistics.IpReasmReqds, - ip_statistics.IpReasmOKs, ip_statistics.IpReasmFails, - ip_statistics.IpFragOKs, ip_statistics.IpFragFails, - ip_statistics.IpFragCreates); - + "Ip: %d %d", ipv4_devconf.forwarding ? 1 : 2, sysctl_ip_default_ttl); + for (i=0; i<offsetof(struct ip_mib, __pad)/sizeof(unsigned long); i++) + len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)ip_statistics, sizeof(struct ip_mib), i)); + len += sprintf (buffer + len, - "Icmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps\n" - "Icmp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", - icmp_statistics.IcmpInMsgs, icmp_statistics.IcmpInErrors, - icmp_statistics.IcmpInDestUnreachs, icmp_statistics.IcmpInTimeExcds, - icmp_statistics.IcmpInParmProbs, icmp_statistics.IcmpInSrcQuenchs, - icmp_statistics.IcmpInRedirects, icmp_statistics.IcmpInEchos, - icmp_statistics.IcmpInEchoReps, icmp_statistics.IcmpInTimestamps, - icmp_statistics.IcmpInTimestampReps, icmp_statistics.IcmpInAddrMasks, - icmp_statistics.IcmpInAddrMaskReps, icmp_statistics.IcmpOutMsgs, - icmp_statistics.IcmpOutErrors, icmp_statistics.IcmpOutDestUnreachs, - icmp_statistics.IcmpOutTimeExcds, icmp_statistics.IcmpOutParmProbs, - icmp_statistics.IcmpOutSrcQuenchs, icmp_statistics.IcmpOutRedirects, - icmp_statistics.IcmpOutEchos, icmp_statistics.IcmpOutEchoReps, - icmp_statistics.IcmpOutTimestamps, icmp_statistics.IcmpOutTimestampReps, - icmp_statistics.IcmpOutAddrMasks, icmp_statistics.IcmpOutAddrMaskReps); - + "\nIcmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps\n" + "Icmp:"); + for (i=0; i<offsetof(struct icmp_mib, __pad)/sizeof(unsigned long); i++) + len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)icmp_statistics, sizeof(struct icmp_mib), i)); + len += sprintf (buffer + len, - "Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts\n" - "Tcp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", - tcp_statistics.TcpRtoAlgorithm, tcp_statistics.TcpRtoMin, - tcp_statistics.TcpRtoMax, tcp_statistics.TcpMaxConn, - tcp_statistics.TcpActiveOpens, tcp_statistics.TcpPassiveOpens, - tcp_statistics.TcpAttemptFails, tcp_statistics.TcpEstabResets, - tcp_statistics.TcpCurrEstab, tcp_statistics.TcpInSegs, - tcp_statistics.TcpOutSegs, tcp_statistics.TcpRetransSegs, - tcp_statistics.TcpInErrs, tcp_statistics.TcpOutRsts); - + "\nTcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts\n" + "Tcp:"); + for (i=0; i<offsetof(struct tcp_mib, __pad)/sizeof(unsigned long); i++) + len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)tcp_statistics, sizeof(struct tcp_mib), i)); + len += sprintf (buffer + len, - "Udp: InDatagrams NoPorts InErrors OutDatagrams\nUdp: %lu %lu %lu %lu\n", - udp_statistics.UdpInDatagrams, udp_statistics.UdpNoPorts, - udp_statistics.UdpInErrors, udp_statistics.UdpOutDatagrams); -/* - len += sprintf( buffer + len, - "TCP fast path RX: H2: %ul H1: %ul L: %ul\n", - tcp_rx_hit2,tcp_rx_hit1,tcp_rx_miss); -*/ - + "\nUdp: InDatagrams NoPorts InErrors OutDatagrams\n" + "Udp:"); + for (i=0; i<offsetof(struct udp_mib, __pad)/sizeof(unsigned long); i++) + len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)udp_statistics, sizeof(struct udp_mib), i)); + + len += sprintf (buffer + len, "\n"); + if (offset >= len) { *start = buffer; @@ -166,23 +158,17 @@ int snmp_get_info(char *buffer, char **start, off_t offset, int length) int netstat_get_info(char *buffer, char **start, off_t offset, int length) { - extern struct linux_mib net_statistics; - int len; + int len, i; len = sprintf(buffer, "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed" " EmbryonicRsts PruneCalled RcvPruned OfoPruned" " OutOfWindowIcmps LockDroppedIcmps\n" - "TcpExt: %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", - net_statistics.SyncookiesSent, - net_statistics.SyncookiesRecv, - net_statistics.SyncookiesFailed, - net_statistics.EmbryonicRsts, - net_statistics.PruneCalled, - net_statistics.RcvPruned, - net_statistics.OfoPruned, - net_statistics.OutOfWindowIcmps, - net_statistics.LockDroppedIcmps); + "TcpExt:"); + for (i=0; i<offsetof(struct linux_mib, __pad)/sizeof(unsigned long); i++) + len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)net_statistics, sizeof(struct linux_mib), i)); + + len += sprintf (buffer + len, "\n"); if (offset >= len) { diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 78e1455c1..6fc5e59c5 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -5,7 +5,7 @@ * * RAW - implementation of IP "raw" sockets. * - * Version: $Id: raw.c,v 1.45 2000/01/06 00:41:58 davem Exp $ + * Version: $Id: raw.c,v 1.46 2000/01/09 02:19:30 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -75,9 +75,7 @@ static void raw_v4_hash(struct sock *sk) (*skp)->pprev = &sk->next; *skp = sk; sk->pprev = skp; - sk->prot->inuse++; - if(sk->prot->highestinuse < sk->prot->inuse) - sk->prot->highestinuse = sk->prot->inuse; + sock_prot_inc_use(sk->prot); sock_hold(sk); write_unlock_bh(&raw_v4_lock); } @@ -90,7 +88,7 @@ static void raw_v4_unhash(struct sock *sk) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; - sk->prot->inuse--; + sock_prot_dec_use(sk->prot); __sock_put(sk); } write_unlock_bh(&raw_v4_lock); @@ -214,7 +212,7 @@ void raw_err (struct sock *sk, struct sk_buff *skb) if (sk->protinfo.af_inet.recverr) ip_icmp_error(sk, skb, err, 0, info, (u8 *)(skb->h.icmph + 1)); - + if (sk->protinfo.af_inet.recverr || harderr) { sk->err = err; sk->error_report(sk); @@ -227,12 +225,12 @@ static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb) if (sock_queue_rcv_skb(sk,skb)<0) { - ip_statistics.IpInDiscards++; + IP_INC_STATS(IpInDiscards); kfree_skb(skb); return -1; } - ip_statistics.IpInDelivers++; + IP_INC_STATS(IpInDelivers); return 0; } @@ -674,6 +672,4 @@ struct proto raw_prot = { 128, /* max_header */ 0, /* retransmits */ "RAW", /* name */ - 0, /* inuse */ - 0 /* highestinuse */ }; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 5acfa8953..add42730d 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -5,7 +5,7 @@ * * ROUTE - implementation of the IP router. * - * Version: $Id: route.c,v 1.77 2000/01/06 00:41:59 davem Exp $ + * Version: $Id: route.c,v 1.78 2000/01/13 00:06:58 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -816,8 +816,8 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw, reject_redirect: #ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) - printk(KERN_INFO "Redirect from %lX/%s to %lX ignored." - "Path = %lX -> %lX, tos %02x\n", + printk(KERN_INFO "Redirect from %X/%s to %X ignored." + "Path = %X -> %X, tos %02x\n", ntohl(old_gw), dev->name, ntohl(new_gw), ntohl(saddr), ntohl(daddr), tos); #endif @@ -2261,8 +2261,9 @@ void __init ip_rt_init(void) if (!rt_hash_table) panic("Failed to allocate IP route cache hash table\n"); - printk("IP: routing cache hash table of %u buckets, %dKbytes\n", - rt_hash_mask, (rt_hash_mask*sizeof(struct rt_hash_bucket))/1024); + printk("IP: routing cache hash table of %u buckets, %ldKbytes\n", + rt_hash_mask, + (long) (rt_hash_mask*sizeof(struct rt_hash_bucket))/1024); for (rt_hash_log=0; (1<<rt_hash_log) != rt_hash_mask; rt_hash_log++) /* NOTHING */; diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 086da77c2..e82233cfd 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -9,7 +9,7 @@ * 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.9 1999/08/23 06:30:34 davem Exp $ + * $Id: syncookies.c,v 1.10 2000/01/09 02:19:35 davem Exp $ * * Missing: IPv6 support. */ @@ -60,7 +60,7 @@ __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, ; *mssp = msstab[mssind]+1; - net_statistics.SyncookiesSent++; + NET_INC_STATS_BH(SyncookiesSent); return secure_tcp_syn_cookie(skb->nh.iph->saddr, skb->nh.iph->daddr, skb->h.th->source, skb->h.th->dest, @@ -137,11 +137,11 @@ cookie_v4_check(struct sock *sk, struct sk_buff *skb, struct ip_options *opt) mss = cookie_check(skb, cookie); if (mss == 0) { - net_statistics.SyncookiesFailed++; + NET_INC_STATS_BH(SyncookiesFailed); return sk; } - net_statistics.SyncookiesRecv++; + NET_INC_STATS_BH(SyncookiesRecv); req = tcp_openreq_alloc(); if (req == NULL) diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 1557974c5..9465e4021 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -1,7 +1,7 @@ /* * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem. * - * $Id: sysctl_net_ipv4.c,v 1.41 2000/01/06 00:42:03 davem Exp $ + * $Id: sysctl_net_ipv4.c,v 1.42 2000/01/09 02:19:37 davem Exp $ * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS] @@ -132,7 +132,7 @@ ctl_table ipv4_table[] = { &ipv4_devconf.forwarding, sizeof(int), 0644, NULL, &ipv4_sysctl_forward,&ipv4_sysctl_forward_strategy}, {NET_IPV4_DEFAULT_TTL, "ip_default_ttl", - &ip_statistics.IpDefaultTTL, sizeof(int), 0644, NULL, + &sysctl_ip_default_ttl, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_AUTOCONFIG, "ip_autoconfig", &ipv4_config.autoconfig, sizeof(int), 0644, NULL, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index a8654f0ae..8e24e19a4 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.152 1999/11/23 08:57:03 davem Exp $ + * Version: $Id: tcp.c,v 1.153 2000/01/09 02:19:33 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -426,7 +426,7 @@ int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT; -struct tcp_mib tcp_statistics; +struct tcp_mib tcp_statistics[NR_CPUS*2]; kmem_cache_t *tcp_openreq_cachep; kmem_cache_t *tcp_bucket_cachep; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 45e094b3e..3b4ae64a2 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.176 1999/12/20 05:19:46 davem Exp $ + * Version: $Id: tcp_input.c,v 1.177 2000/01/09 02:19:39 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -1314,7 +1314,7 @@ static void __tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw) spin_unlock(&bhead->lock); /* Step 4: Un-charge protocol socket in-use count. */ - sk->prot->inuse--; + sock_prot_dec_use(sk->prot); } /* @@ -1365,7 +1365,7 @@ void tcp_time_wait(struct sock *sk) /* CLOSE the SK. */ if(sk->state == TCP_ESTABLISHED) - tcp_statistics.TcpCurrEstab--; + tcp_statistics[smp_processor_id()*2].TcpCurrEstab--; sk->state = TCP_CLOSE; } else { /* Sorry, we're out of memory, just CLOSE this @@ -2018,13 +2018,13 @@ static int prune_queue(struct sock *sk) SOCK_DEBUG(sk, "prune_queue: c=%x\n", tp->copied_seq); - net_statistics.PruneCalled++; + NET_INC_STATS_BH(PruneCalled); /* First, purge the out_of_order queue. */ skb = __skb_dequeue_tail(&tp->out_of_order_queue); if(skb != NULL) { /* Free it all. */ - do { net_statistics.OfoPruned += skb->len; + do { net_statistics[smp_processor_id()*2].OfoPruned += skb->len; kfree_skb(skb); skb = __skb_dequeue_tail(&tp->out_of_order_queue); } while(skb != NULL); @@ -2179,7 +2179,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, tcp_data_snd_check(sk); return 0; } else { /* Header too small */ - tcp_statistics.TcpInErrs++; + TCP_INC_STATS_BH(TcpInErrs); goto discard; } } else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una && @@ -2267,7 +2267,7 @@ slow_path: if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) { SOCK_DEBUG(sk, "syn in established state\n"); - tcp_statistics.TcpInErrs++; + TCP_INC_STATS_BH(TcpInErrs); tcp_reset(sk); return 1; } @@ -2592,7 +2592,7 @@ embryonic_reset: tp->syn_backlog--; tcp_dec_slow_timer(TCP_SLT_SYNACK); - net_statistics.EmbryonicRsts++; + NET_INC_STATS_BH(EmbryonicRsts); if (!(flg & TCP_FLAG_RST)) req->class->send_reset(skb); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index e1b6d70ab..22c35a191 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.193 2000/01/06 00:42:01 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.194 2000/01/09 02:19:41 davem Exp $ * * IPv4 specific functions * @@ -443,9 +443,7 @@ static __inline__ void __tcp_v4_hash(struct sock *sk) (*skp)->pprev = &sk->next; *skp = sk; sk->pprev = skp; - sk->prot->inuse++; - if(sk->prot->highestinuse < sk->prot->inuse) - sk->prot->highestinuse = sk->prot->inuse; + sock_prot_inc_use(sk->prot); write_unlock(lock); } @@ -477,7 +475,7 @@ void tcp_unhash(struct sock *sk) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; - sk->prot->inuse--; + sock_prot_dec_use(sk->prot); } write_unlock_bh(lock); } @@ -670,9 +668,7 @@ unique: *skp = sk; sk->pprev = skp; - sk->prot->inuse++; - if(sk->prot->highestinuse < sk->prot->inuse) - sk->prot->highestinuse = sk->prot->inuse; + sock_prot_inc_use(sk->prot); write_unlock_bh(&head->lock); #ifdef CONFIG_TCP_TW_RECYCLE @@ -978,7 +974,7 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len) int err; if (len < (iph->ihl << 2) + ICMP_MIN_LENGTH) { - icmp_statistics.IcmpInErrors++; + ICMP_INC_STATS_BH(IcmpInErrors); return; } #if ICMP_MIN_LENGTH < 14 @@ -990,7 +986,7 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len) sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev->ifindex); if (sk == NULL) { - icmp_statistics.IcmpInErrors++; + ICMP_INC_STATS_BH(IcmpInErrors); return; } if (sk->state == TCP_TIME_WAIT) { @@ -1003,12 +999,12 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len) * servers this needs to be solved differently. */ if (sk->lock.users != 0) - net_statistics.LockDroppedIcmps++; + NET_INC_STATS_BH(LockDroppedIcmps); tp = &sk->tp_pinfo.af_tcp; seq = ntohl(th->seq); if (sk->state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) { - net_statistics.OutOfWindowIcmps++; + NET_INC_STATS(OutOfWindowIcmps); goto out; } @@ -1082,12 +1078,12 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len) BUG_TRAP(sk->lock.users == 0); tp = &sk->tp_pinfo.af_tcp; if (!between(seq, tp->snd_una, tp->snd_nxt)) { - net_statistics.OutOfWindowIcmps++; + NET_INC_STATS(OutOfWindowIcmps); goto out; } } else { if (seq != req->snt_isn) { - net_statistics.OutOfWindowIcmps++; + NET_INC_STATS(OutOfWindowIcmps); goto out; } @@ -1112,7 +1108,7 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len) if (!no_flags && !th->syn) goto out; if (sk->lock.users == 0) { - tcp_statistics.TcpAttemptFails++; + TCP_INC_STATS_BH(TcpAttemptFails); sk->err = err; /* Wake people up to see the error (see connect in sock.c) */ sk->error_report(sk); @@ -1216,8 +1212,8 @@ static void tcp_v4_send_reset(struct sk_buff *skb) ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth); - tcp_statistics.TcpOutSegs++; - tcp_statistics.TcpOutRsts++; + TCP_INC_STATS_BH(TcpOutSegs); + TCP_INC_STATS_BH(TcpOutRsts); } /* The code following below sending ACKs in SYN-RECV and TIME-WAIT states @@ -1267,7 +1263,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len); - tcp_statistics.TcpOutSegs++; + TCP_INC_STATS_BH(TcpOutSegs); } static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) @@ -1303,12 +1299,12 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req) req->af.v4_req.loc_addr, RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute, sk->bound_dev_if)) { - ip_statistics.IpOutNoRoutes++; + IP_INC_STATS_BH(IpOutNoRoutes); return; } if(opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) { ip_rt_put(rt); - ip_statistics.IpOutNoRoutes++; + IP_INC_STATS_BH(IpOutNoRoutes); return; } @@ -1488,7 +1484,7 @@ dropbacklog: if (!want_cookie) BACKLOG(sk)--; drop: - tcp_statistics.TcpAttemptFails++; + TCP_INC_STATS_BH(TcpAttemptFails); return 0; } @@ -1692,7 +1688,7 @@ discard: return 0; csum_err: - tcp_statistics.TcpInErrs++; + TCP_INC_STATS_BH(TcpInErrs); goto discard; } @@ -1715,7 +1711,7 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len) __skb_pull(skb, skb->h.raw - skb->data); /* Count it even if it's bad */ - tcp_statistics.TcpInSegs++; + TCP_INC_STATS_BH(TcpInSegs); if (len < sizeof(struct tcphdr)) goto bad_packet; @@ -1755,7 +1751,7 @@ process: no_tcp_socket: if (tcp_csum_verify(skb)) { bad_packet: - tcp_statistics.TcpInErrs++; + TCP_INC_STATS_BH(TcpInErrs); } else { tcp_v4_send_reset(skb); } @@ -1771,7 +1767,7 @@ discard_and_relse: do_time_wait: if (tcp_csum_verify(skb)) { - tcp_statistics.TcpInErrs++; + TCP_INC_STATS_BH(TcpInErrs); goto discard_and_relse; } switch(tcp_timewait_state_process((struct tcp_tw_bucket *)sk, @@ -1878,7 +1874,7 @@ do_rewrite: /* Ouch!, this should not happen. */ if (!sk->saddr || !sk->rcv_saddr) { printk(KERN_WARNING "tcp_v4_rebuild_header(): not valid sock addrs: " - "saddr=%08lX rcv_saddr=%08lX\n", + "saddr=%08X rcv_saddr=%08X\n", ntohl(sk->saddr), ntohl(sk->rcv_saddr)); return 0; @@ -2218,12 +2214,8 @@ struct proto tcp_prot = { 128, /* max_header */ 0, /* retransmits */ "TCP", /* name */ - 0, /* inuse */ - 0 /* highestinuse */ }; - - void __init tcp_v4_init(struct net_proto_family *ops) { int err; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 77f8b98ca..e3d884dda 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.113 1999/09/07 02:31:39 davem Exp $ + * Version: $Id: tcp_output.c,v 1.116 2000/01/13 00:19:49 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -192,7 +192,7 @@ void tcp_transmit_skb(struct sock *sk, struct sk_buff *skb) clear_delayed_acks(sk); tp->last_ack_sent = tp->rcv_nxt; - tcp_statistics.TcpOutSegs++; + TCP_INC_STATS(TcpOutSegs); tp->af_specific->queue_xmit(skb); } #undef SYSCTL_FLAG_TSTAMPS @@ -677,7 +677,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) /* Update global TCP statistics and return success. */ sk->prot->retransmits++; - tcp_statistics.TcpRetransSegs++; + TCP_INC_STATS(TcpRetransSegs); return 0; } @@ -941,7 +941,7 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, skb->csum = 0; th->doff = (tcp_header_size >> 2); - tcp_statistics.TcpOutSegs++; + TCP_INC_STATS(TcpOutSegs); return skb; } @@ -1009,7 +1009,7 @@ int tcp_connect(struct sock *sk, struct sk_buff *buff) __skb_queue_tail(&sk->write_queue, buff); tp->packets_out++; tcp_transmit_skb(sk, skb_clone(buff, GFP_KERNEL)); - tcp_statistics.TcpActiveOpens++; + TCP_INC_STATS(TcpActiveOpens); /* Timer for repeating the SYN until an answer. */ tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto); @@ -1031,7 +1031,7 @@ void tcp_send_delayed_ack(struct sock *sk, int max_timeout) unsigned long timeout; /* Stay within the limit we were given */ - timeout = tp->ato; + timeout = (tp->ato << 1) >> 1; if (timeout > max_timeout) timeout = max_timeout; timeout += jiffies; @@ -1070,10 +1070,14 @@ void tcp_send_ack(struct sock *sk) * * This is the one possible way that we can delay an * ACK and have tp->ato indicate that we are in - * quick ack mode, so clear it. + * quick ack mode, so clear it. It is also the only + * possible way for ato to be zero, when ACK'ing a + * SYNACK because we've taken no ATO measurement yet. */ - if(tcp_in_quickack_mode(tp)) + if (tcp_in_quickack_mode(tp)) tcp_exit_quickack_mode(tp); + if (!tp->ato) + tp->ato = tp->rto; tcp_send_delayed_ack(sk, HZ/2); return; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 27df3243d..9ace56abd 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -5,7 +5,7 @@ * * The User Datagram Protocol (UDP). * - * Version: $Id: udp.c,v 1.76 2000/01/05 21:27:51 davem Exp $ + * Version: $Id: udp.c,v 1.77 2000/01/09 02:19:44 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -120,7 +120,7 @@ * Snmp MIB for the UDP layer */ -struct udp_mib udp_statistics; +struct udp_mib udp_statistics[NR_CPUS*2]; struct sock *udp_hash[UDP_HTABLE_SIZE]; rwlock_t udp_hash_lock = RW_LOCK_UNLOCKED; @@ -205,9 +205,7 @@ static void udp_v4_hash(struct sock *sk) (*skp)->pprev = &sk->next; *skp = sk; sk->pprev = skp; - sk->prot->inuse++; - if(sk->prot->highestinuse < sk->prot->inuse) - sk->prot->highestinuse = sk->prot->inuse; + sock_prot_inc_use(sk->prot); sock_hold(sk); write_unlock_bh(&udp_hash_lock); } @@ -220,7 +218,7 @@ static void udp_v4_unhash(struct sock *sk) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; - sk->prot->inuse--; + sock_prot_dec_use(sk->prot); __sock_put(sk); } write_unlock_bh(&udp_hash_lock); @@ -326,13 +324,13 @@ void udp_err(struct sk_buff *skb, unsigned char *dp, int len) int err; if (len < (iph->ihl<<2)+sizeof(struct udphdr)) { - icmp_statistics.IcmpInErrors++; + ICMP_INC_STATS_BH(IcmpInErrors); return; } sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex); if (sk == NULL) { - icmp_statistics.IcmpInErrors++; + ICMP_INC_STATS_BH(IcmpInErrors); return; /* No socket for error */ } @@ -610,7 +608,7 @@ out: if (free) kfree(ipc.opt); if (!err) { - udp_statistics.UdpOutDatagrams++; + UDP_INC_STATS_USER(UdpOutDatagrams); return len; } return err; @@ -748,7 +746,7 @@ out: #ifdef CONFIG_UDP_DELAY_CSUM csum_copy_err: - udp_statistics.UdpInErrors++; + UDP_INC_STATS_BH(UdpInErrors); /* Clear queue. */ if (flags&MSG_PEEK) { @@ -836,9 +834,9 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) #if defined(CONFIG_FILTER) && defined(CONFIG_UDP_DELAY_CSUM) if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) { - udp_statistics.UdpInErrors++; - ip_statistics.IpInDiscards++; - ip_statistics.IpInDelivers--; + UDP_INC_STATS_BH(UdpInErrors); + IP_INC_STATS_BH(IpInDiscards); + ip_statistics[smp_processor_id()*2].IpInDelivers--; kfree_skb(skb); return -1; } @@ -847,13 +845,13 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) #endif if (sock_queue_rcv_skb(sk,skb)<0) { - udp_statistics.UdpInErrors++; - ip_statistics.IpInDiscards++; - ip_statistics.IpInDelivers--; + UDP_INC_STATS_BH(UdpInErrors); + IP_INC_STATS_BH(IpInDiscards); + ip_statistics[smp_processor_id()*2].IpInDelivers--; kfree_skb(skb); return -1; } - udp_statistics.UdpInDatagrams++; + UDP_INC_STATS_BH(UdpInDatagrams); return 0; } @@ -947,7 +945,7 @@ int udp_rcv(struct sk_buff *skb, unsigned short len) uh = skb->h.uh; __skb_pull(skb, skb->h.raw - skb->data); - ip_statistics.IpInDelivers++; + IP_INC_STATS_BH(IpInDelivers); /* * Validate the packet and the UDP length. @@ -957,7 +955,7 @@ int udp_rcv(struct sk_buff *skb, unsigned short len) if (ulen > len || ulen < sizeof(*uh)) { NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len)); - udp_statistics.UdpInErrors++; + UDP_INC_STATS_BH(UdpInErrors); kfree_skb(skb); return(0); } @@ -983,7 +981,7 @@ int udp_rcv(struct sk_buff *skb, unsigned short len) if (udp_checksum_verify(skb, uh, ulen, saddr, daddr, 0)) goto csum_error; - udp_statistics.UdpNoPorts++; + UDP_INC_STATS_BH(UdpNoPorts); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); /* @@ -1019,7 +1017,7 @@ csum_error: NIPQUAD(daddr), ntohs(uh->dest), ulen)); - udp_statistics.UdpInErrors++; + UDP_INC_STATS_BH(UdpInErrors); kfree_skb(skb); return(0); } @@ -1112,6 +1110,4 @@ struct proto udp_prot = { 128, /* max_header */ 0, /* retransmits */ "UDP", /* name */ - 0, /* inuse */ - 0 /* highestinuse */ }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d82ef3846..8430729e5 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -670,6 +670,7 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) { switch (dev->type) { case ARPHRD_ETHER: + case ARPHRD_IEEE802_TR: if (dev->addr_len != ETH_ALEN) return -1; memcpy(eui, dev->dev_addr, 3); @@ -1191,7 +1192,8 @@ static void addrconf_dev_config(struct net_device *dev) ASSERT_RTNL(); - if (dev->type != ARPHRD_ETHER) { + if ((dev->type != ARPHRD_ETHER) && + (dev->type != ARPHRD_IEEE802_TR)) { /* Alas, we support only Ethernet autoconfiguration. */ return; } @@ -1990,7 +1992,8 @@ void __init addrconf_init(void) case ARPHRD_LOOPBACK: init_loopback(dev); break; - case ARPHRD_ETHER: + case ARPHRD_ETHER: + case ARPHRD_IEEE802_TR: addrconf_dev_config(dev); break; default: diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 5fb915390..ee9f18102 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -7,7 +7,7 @@ * Andi Kleen <ak@muc.de> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> * - * $Id: exthdrs.c,v 1.9 1999/05/17 23:47:35 davem Exp $ + * $Id: exthdrs.c,v 1.10 2000/01/09 02:19:55 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -198,7 +198,7 @@ static u8* ipv6_routing_header(struct sk_buff **skb_ptr, u8 *nhptr) struct rt0_hdr *rthdr; if (((hdr->hdrlen+1)<<3) > skb->tail - skb->h.raw) { - ipv6_statistics.Ip6InHdrErrors++; + IP6_INC_STATS_BH(Ip6InHdrErrors); kfree_skb(skb); return NULL; } @@ -468,7 +468,7 @@ static int ipv6_hop_jumbo(struct sk_buff *skb, u8 *ptr) } if (pkt_len > skb->len - sizeof(struct ipv6hdr)) { - ipv6_statistics.Ip6InTruncatedPkts++; + IP6_INC_STATS_BH(Ip6InTruncatedPkts); goto drop; } skb_trim(skb, pkt_len + sizeof(struct ipv6hdr)); diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 211db2544..cfa18eee8 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: icmp.c,v 1.24 1999/08/20 11:06:18 davem Exp $ + * $Id: icmp.c,v 1.25 2000/01/09 02:19:54 davem Exp $ * * Based on net/ipv4/icmp.c * @@ -58,7 +58,7 @@ #include <asm/uaccess.h> #include <asm/system.h> -struct icmpv6_mib icmpv6_statistics; +struct icmpv6_mib icmpv6_statistics[NR_CPUS*2]; /* * ICMP socket for flow control. @@ -237,7 +237,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type, */ dst = ip6_route_output(sk, fl); if (dst->error) { - ipv6_statistics.Ip6OutNoRoutes++; + IP6_INC_STATS(Ip6OutNoRoutes); } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) { res = 1; } else { @@ -388,8 +388,8 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1, MSG_DONTWAIT); if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) - (&icmpv6_statistics.Icmp6OutDestUnreachs)[type-1]++; - icmpv6_statistics.Icmp6OutMsgs++; + (&(icmpv6_statistics[smp_processor_id()*2].Icmp6OutDestUnreachs))[type-1]++; + ICMP6_INC_STATS_BH(Icmp6OutMsgs); out: icmpv6_xmit_unlock(); } @@ -439,8 +439,8 @@ static void icmpv6_echo_reply(struct sk_buff *skb) ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1, MSG_DONTWAIT); - icmpv6_statistics.Icmp6OutEchoReplies++; - icmpv6_statistics.Icmp6OutMsgs++; + ICMP6_INC_STATS_BH(Icmp6OutEchoReplies); + ICMP6_INC_STATS_BH(Icmp6OutMsgs); icmpv6_xmit_unlock_bh(); } @@ -513,7 +513,7 @@ int icmpv6_rcv(struct sk_buff *skb, unsigned long len) int ulen; int type; - icmpv6_statistics.Icmp6InMsgs++; + ICMP6_INC_STATS_BH(Icmp6InMsgs); if (len < sizeof(struct icmp6hdr)) goto discard_it; @@ -556,9 +556,9 @@ int icmpv6_rcv(struct sk_buff *skb, unsigned long len) type = hdr->icmp6_type; if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) - (&icmpv6_statistics.Icmp6InDestUnreachs)[type-ICMPV6_DEST_UNREACH]++; + (&icmpv6_statistics[smp_processor_id()*2].Icmp6InDestUnreachs)[type-ICMPV6_DEST_UNREACH]++; else if (type >= ICMPV6_ECHO_REQUEST && type <= NDISC_REDIRECT) - (&icmpv6_statistics.Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++; + (&icmpv6_statistics[smp_processor_id()*2].Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++; switch (type) { @@ -631,7 +631,7 @@ int icmpv6_rcv(struct sk_buff *skb, unsigned long len) return 0; discard_it: - icmpv6_statistics.Icmp6InErrors++; + ICMP6_INC_STATS_BH(Icmp6InErrors); kfree_skb(skb); return 0; } diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index d8ec7bd95..709443749 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -6,7 +6,7 @@ * Pedro Roque <roque@di.fc.ul.pt> * Ian P. Morris <I.P.Morris@soton.ac.uk> * - * $Id: ip6_input.c,v 1.14 1999/08/30 12:14:56 davem Exp $ + * $Id: ip6_input.c,v 1.15 2000/01/09 02:19:54 davem Exp $ * * Based in linux/net/ipv4/ip_input.c * @@ -46,7 +46,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt if (skb->pkt_type == PACKET_OTHERHOST) goto drop; - ipv6_statistics.Ip6InReceives++; + IP6_INC_STATS_BH(Ip6InReceives); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) goto out; @@ -73,7 +73,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt if (hdr->nexthdr == NEXTHDR_HOP) { skb->h.raw = (u8*)(hdr+1); if (!ipv6_parse_hopopts(skb, &hdr->nexthdr)) { - ipv6_statistics.Ip6InHdrErrors++; + IP6_INC_STATS_BH(Ip6InHdrErrors); return 0; } } @@ -84,9 +84,9 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt return skb->dst->input(skb); truncated: - ipv6_statistics.Ip6InTruncatedPkts++; + IP6_INC_STATS_BH(Ip6InTruncatedPkts); err: - ipv6_statistics.Ip6InHdrErrors++; + IP6_INC_STATS_BH(Ip6InHdrErrors); drop: kfree_skb(skb); out: @@ -175,7 +175,7 @@ int ip6_input(struct sk_buff *skb) * not found: send ICMP parameter problem back */ if (!found) { - ipv6_statistics.Ip6InUnknownProtos++; + IP6_INC_STATS_BH(Ip6InUnknownProtos); icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhptr); } @@ -188,7 +188,7 @@ int ip6_mc_input(struct sk_buff *skb) int deliver = 0; int discard = 1; - ipv6_statistics.Ip6InMcastPkts++; + IP6_INC_STATS_BH(Ip6InMcastPkts); hdr = skb->nh.ipv6h; if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr)) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 2f1d8800e..d902692bd 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_output.c,v 1.23 2000/01/06 00:42:07 davem Exp $ + * $Id: ip6_output.c,v 1.24 2000/01/09 02:19:49 davem Exp $ * * Based on linux/net/ipv4/ip_output.c * @@ -81,7 +81,7 @@ int ip6_output(struct sk_buff *skb) } } - ipv6_statistics.Ip6OutMcastPkts++; + IP6_INC_STATS(Ip6OutMcastPkts); } if (hh) { @@ -158,7 +158,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, ipv6_addr_copy(&hdr->daddr, first_hop); if (skb->len <= dst->pmtu) { - ipv6_statistics.Ip6OutRequests++; + IP6_INC_STATS(Ip6OutRequests); return dst->output(skb); } @@ -358,7 +358,7 @@ static int ip6_frag_xmit(struct sock *sk, inet_getfrag_t getfrag, skb = skb_copy(last_skb, sk->allocation); if (skb == NULL) { - ipv6_statistics.Ip6FragFails++; + IP6_INC_STATS(Ip6FragFails); kfree_skb(last_skb); return -ENOMEM; } @@ -386,8 +386,8 @@ static int ip6_frag_xmit(struct sock *sk, inet_getfrag_t getfrag, break; } - ipv6_statistics.Ip6FragCreates++; - ipv6_statistics.Ip6OutRequests++; + IP6_INC_STATS(Ip6FragCreates); + IP6_INC_STATS(Ip6OutRequests); err = dst->output(skb); if (err) { kfree_skb(last_skb); @@ -397,7 +397,7 @@ static int ip6_frag_xmit(struct sock *sk, inet_getfrag_t getfrag, } if (err) { - ipv6_statistics.Ip6FragFails++; + IP6_INC_STATS(Ip6FragFails); kfree_skb(last_skb); return -EFAULT; } @@ -411,9 +411,9 @@ static int ip6_frag_xmit(struct sock *sk, inet_getfrag_t getfrag, skb_put(last_skb, last_len); - ipv6_statistics.Ip6FragCreates++; - ipv6_statistics.Ip6FragOKs++; - ipv6_statistics.Ip6OutRequests++; + IP6_INC_STATS(Ip6FragCreates); + IP6_INC_STATS(Ip6FragOKs); + IP6_INC_STATS(Ip6OutRequests); return dst->output(last_skb); } @@ -473,7 +473,7 @@ int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data, dst = ip6_route_output(sk, fl); if (dst->error) { - ipv6_statistics.Ip6OutNoRoutes++; + IP6_INC_STATS(Ip6OutNoRoutes); dst_release(dst); return -ENETUNREACH; } @@ -552,7 +552,7 @@ int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data, flags & MSG_DONTWAIT, &err); if (skb == NULL) { - ipv6_statistics.Ip6OutDiscards++; + IP6_INC_STATS(Ip6OutDiscards); goto out; } @@ -581,7 +581,7 @@ int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data, 0, length); if (!err) { - ipv6_statistics.Ip6OutRequests++; + IP6_INC_STATS(Ip6OutRequests); err = dst->output(skb); } else { err = -EFAULT; @@ -711,7 +711,7 @@ int ip6_forward(struct sk_buff *skb) /* Again, force OUTPUT device used as source address */ skb->dev = dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev); - ipv6_statistics.Ip6InTooBigErrors++; + IP6_INC_STATS_BH(Ip6InTooBigErrors); kfree_skb(skb); return -EMSGSIZE; } @@ -725,11 +725,11 @@ int ip6_forward(struct sk_buff *skb) hdr->hop_limit--; - ipv6_statistics.Ip6OutForwDatagrams++; + IP6_INC_STATS_BH(Ip6OutForwDatagrams); return dst->output(skb); drop: - ipv6_statistics.Ip6InAddrErrors++; + IP6_INC_STATS_BH(Ip6InAddrErrors); kfree_skb(skb); return -EINVAL; } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index f76c22870..eddf935a0 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -7,7 +7,7 @@ * * Based on linux/net/ipv4/ip_sockglue.c * - * $Id: ipv6_sockglue.c,v 1.29 1999/08/31 07:04:06 davem Exp $ + * $Id: ipv6_sockglue.c,v 1.30 2000/01/09 02:19:49 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -50,7 +50,8 @@ #include <asm/uaccess.h> -struct ipv6_mib ipv6_statistics={0, }; +struct ipv6_mib ipv6_statistics[NR_CPUS*2]; + struct packet_type ipv6_packet_type = { __constant_htons(ETH_P_IPV6), @@ -165,13 +166,21 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, if (sk->protocol == IPPROTO_TCP) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - + + local_bh_disable(); + sock_prot_dec_use(sk->prot); + sock_prot_inc_use(&tcp_prot); + local_bh_enable(); sk->prot = &tcp_prot; tp->af_specific = &ipv4_specific; sk->socket->ops = &inet_stream_ops; sk->family = PF_INET; tcp_sync_mss(sk, tp->pmtu_cookie); } else { + local_bh_disable(); + sock_prot_dec_use(sk->prot); + sock_prot_inc_use(&udp_prot); + local_bh_enable(); sk->prot = &udp_prot; sk->socket->ops = &inet_dgram_ops; } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index f8be2fb92..ce9f17adc 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: mcast.c,v 1.27 1999/12/09 00:52:49 davem Exp $ + * $Id: mcast.c,v 1.28 2000/01/09 02:19:50 davem Exp $ * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c * @@ -528,10 +528,10 @@ void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) dev_queue_xmit(skb); if (type == ICMPV6_MGM_REDUCTION) - icmpv6_statistics.Icmp6OutGroupMembReductions++; + ICMP6_INC_STATS(Icmp6OutGroupMembReductions); else - icmpv6_statistics.Icmp6OutGroupMembResponses++; - icmpv6_statistics.Icmp6OutMsgs++; + ICMP6_INC_STATS(Icmp6OutGroupMembResponses); + ICMP6_INC_STATS(Icmp6OutMsgs); } static void igmp6_join_group(struct ifmcaddr6 *ma) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 9c3cce05d..4a9af93e1 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -161,6 +161,9 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d case ARPHRD_FDDI: ipv6_eth_mc_map(addr, buf); return 0; + case ARPHRD_IEEE802_TR: + ipv6_tr_mc_map(addr,buf); + return 0; default: if (dir) { memcpy(buf, dev->broadcast, dev->addr_len); @@ -374,8 +377,8 @@ void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, dev_queue_xmit(skb); - icmpv6_statistics.Icmp6OutNeighborAdvertisements++; - icmpv6_statistics.Icmp6OutMsgs++; + ICMP6_INC_STATS(Icmp6OutNeighborAdvertisements); + ICMP6_INC_STATS(Icmp6OutMsgs); } void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, @@ -436,8 +439,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, /* send it! */ dev_queue_xmit(skb); - icmpv6_statistics.Icmp6OutNeighborSolicits++; - icmpv6_statistics.Icmp6OutMsgs++; + ICMP6_INC_STATS(Icmp6OutNeighborSolicits); + ICMP6_INC_STATS(Icmp6OutMsgs); } void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, @@ -487,8 +490,8 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, /* send it! */ dev_queue_xmit(skb); - icmpv6_statistics.Icmp6OutRouterSolicits++; - icmpv6_statistics.Icmp6OutMsgs++; + ICMP6_INC_STATS(Icmp6OutRouterSolicits); + ICMP6_INC_STATS(Icmp6OutMsgs); } @@ -912,8 +915,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, dev_queue_xmit(buff); - icmpv6_statistics.Icmp6OutRedirects++; - icmpv6_statistics.Icmp6OutMsgs++; + ICMP6_INC_STATS(Icmp6OutRedirects); + ICMP6_INC_STATS(Icmp6OutMsgs); } static __inline__ struct neighbour * @@ -968,9 +971,22 @@ int ndisc_rcv(struct sk_buff *skb, unsigned long len) does DAD, otherwise we ignore solicitations until DAD timer expires. */ - if (addr_type == IPV6_ADDR_ANY) - addrconf_dad_failure(ifp); - else + if (addr_type == IPV6_ADDR_ANY) { + if (dev->type == ARPHRD_IEEE802_TR) { + unsigned char *sadr = skb->mac.raw ; + if (((sadr[8] &0x7f) != (dev->dev_addr[0] & 0x7f)) || + (sadr[9] != dev->dev_addr[1]) || + (sadr[10] != dev->dev_addr[2]) || + (sadr[11] != dev->dev_addr[3]) || + (sadr[12] != dev->dev_addr[4]) || + (sadr[13] != dev->dev_addr[5])) + { + addrconf_dad_failure(ifp) ; + } + } else { + addrconf_dad_failure(ifp); + } + } else in6_ifa_put(ifp); return 0; } diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 999ac75fe..c9be23990 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -7,7 +7,7 @@ * PROC file system. This is very similar to the IPv4 version, * except it reports the sockets in the INET6 address family. * - * Version: $Id: proc.c,v 1.12 1999/12/15 22:39:48 davem Exp $ + * Version: $Id: proc.c,v 1.13 2000/01/09 02:19:55 davem Exp $ * * Authors: David S. Miller (davem@caip.rutgers.edu) * @@ -26,15 +26,26 @@ #include <net/transp_v6.h> #include <net/ipv6.h> -int afinet6_get_info(char *buffer, char **start, off_t offset, int length) +static int fold_prot_inuse(struct proto *proto) +{ + int res = 0; + int cpu; + + for (cpu=0; cpu<smp_num_cpus; cpu++) + res += proto->stats[cpu].inuse; + + return res; +} + +int afinet6_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { int len = 0; - len += sprintf(buffer+len, "TCP6: inuse %d highest %d\n", - tcpv6_prot.inuse, tcpv6_prot.highestinuse); - len += sprintf(buffer+len, "UDP6: inuse %d highest %d\n", - udpv6_prot.inuse, udpv6_prot.highestinuse); - len += sprintf(buffer+len, "RAW6: inuse %d highest %d\n", - rawv6_prot.inuse, rawv6_prot.highestinuse); + len += sprintf(buffer+len, "TCP6: inuse %d\n", + fold_prot_inuse(&tcpv6_prot)); + len += sprintf(buffer+len, "UDP6: inuse %d\n", + fold_prot_inuse(&udpv6_prot)); + len += sprintf(buffer+len, "RAW6: inuse %d\n", + fold_prot_inuse(&rawv6_prot)); *start = buffer + offset; len -= offset; if(len > length) @@ -47,9 +58,10 @@ struct snmp6_item { char *name; unsigned long *ptr; + int mibsize; } snmp6_list[] = { /* ipv6 mib according to draft-ietf-ipngwg-ipv6-mib-04 */ -#define SNMP6_GEN(x) { #x , &ipv6_statistics.x } +#define SNMP6_GEN(x) { #x , &ipv6_statistics[0].x, sizeof(struct ipv6_mib)/sizeof(unsigned long) } SNMP6_GEN(Ip6InReceives), SNMP6_GEN(Ip6InHdrErrors), SNMP6_GEN(Ip6InTooBigErrors), @@ -83,7 +95,7 @@ struct snmp6_item OutRouterAdvertisements too. OutGroupMembQueries too. */ -#define SNMP6_GEN(x) { #x , &icmpv6_statistics.x } +#define SNMP6_GEN(x) { #x , &icmpv6_statistics[0].x, sizeof(struct icmpv6_mib)/sizeof(unsigned long) } SNMP6_GEN(Icmp6InMsgs), SNMP6_GEN(Icmp6InErrors), SNMP6_GEN(Icmp6InDestUnreachs), @@ -113,7 +125,7 @@ struct snmp6_item SNMP6_GEN(Icmp6OutGroupMembResponses), SNMP6_GEN(Icmp6OutGroupMembReductions), #undef SNMP6_GEN -#define SNMP6_GEN(x) { "Udp6" #x , &udp_stats_in6.Udp##x } +#define SNMP6_GEN(x) { "Udp6" #x , &udp_stats_in6[0].Udp##x, sizeof(struct udp_mib)/sizeof(unsigned long) } SNMP6_GEN(InDatagrams), SNMP6_GEN(NoPorts), SNMP6_GEN(InErrors), @@ -121,6 +133,16 @@ struct snmp6_item #undef SNMP6_GEN }; +static unsigned long fold_field(unsigned long *ptr, int size) +{ + unsigned long res = 0; + int i; + + for (i=0; i<smp_num_cpus; i++) + res += ptr[i*size]; + + return res; +} int afinet6_get_snmp(char *buffer, char **start, off_t offset, int length) { @@ -129,7 +151,7 @@ int afinet6_get_snmp(char *buffer, char **start, off_t offset, int length) for (i=0; i<sizeof(snmp6_list)/sizeof(snmp6_list[0]); i++) len += sprintf(buffer+len, "%-32s\t%ld\n", snmp6_list[i].name, - *(snmp6_list[i].ptr)); + fold_field(snmp6_list[i].ptr, snmp6_list[i].mibsize)); len -= offset; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index baa6611b4..04ecdea9c 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/raw.c * - * $Id: raw.c,v 1.30 1999/12/15 22:39:51 davem Exp $ + * $Id: raw.c,v 1.31 2000/01/09 02:19:50 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -53,9 +53,7 @@ static void raw_v6_hash(struct sock *sk) (*skp)->pprev = &sk->next; *skp = sk; sk->pprev = skp; - sk->prot->inuse++; - if(sk->prot->highestinuse < sk->prot->inuse) - sk->prot->highestinuse = sk->prot->inuse; + sock_prot_inc_use(sk->prot); sock_hold(sk); write_unlock_bh(&raw_v6_lock); } @@ -68,7 +66,7 @@ static void raw_v6_unhash(struct sock *sk) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; - sk->prot->inuse--; + sock_prot_dec_use(sk->prot); __sock_put(sk); } write_unlock_bh(&raw_v6_lock); @@ -259,12 +257,12 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) { /* Charge it to the socket. */ if (sock_queue_rcv_skb(sk,skb)<0) { - ipv6_statistics.Ip6InDiscards++; + IP6_INC_STATS_BH(Ip6InDiscards); kfree_skb(skb); return 0; } - ipv6_statistics.Ip6InDelivers++; + IP6_INC_STATS_BH(Ip6InDelivers); return 0; } @@ -785,6 +783,4 @@ struct proto rawv6_prot = { 128, /* max_header */ 0, /* retransmits */ "RAW", /* name */ - 0, /* inuse */ - 0 /* highestinuse */ }; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 53a241b3f..a0a56700a 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: reassembly.c,v 1.15 1999/08/20 11:06:27 davem Exp $ + * $Id: reassembly.c,v 1.16 2000/01/09 02:19:51 davem Exp $ * * Based on: net/ipv4/ip_fragment.c * @@ -135,7 +135,7 @@ static void frag_prune(void) spin_lock(&ip6_frag_lock); while ((fq = ipv6_frag_queue.next) != &ipv6_frag_queue) { - ipv6_statistics.Ip6ReasmFails++; + IP6_INC_STATS_BH(Ip6ReasmFails); fq_free(fq); if (atomic_read(&ip6_frag_mem) <= sysctl_ip6frag_low_thresh) { spin_unlock(&ip6_frag_lock); @@ -158,7 +158,7 @@ u8* ipv6_reassembly(struct sk_buff **skbp, __u8 *nhptr) hdr = skb->nh.ipv6h; - ipv6_statistics.Ip6ReasmReqds++; + IP6_INC_STATS_BH(Ip6ReasmReqds); /* Jumbo payload inhibits frag. header */ if (hdr->payload_len==0) { @@ -228,8 +228,8 @@ static void frag_expire(unsigned long data) frag = fq->fragments; - ipv6_statistics.Ip6ReasmTimeout++; - ipv6_statistics.Ip6ReasmFails++; + IP6_INC_STATS_BH(Ip6ReasmTimeout); + IP6_INC_STATS_BH(Ip6ReasmFails); if (frag == NULL) { spin_unlock(&ip6_frag_lock); @@ -272,7 +272,7 @@ static void create_frag_entry(struct sk_buff *skb, GFP_ATOMIC); if (fq == NULL) { - ipv6_statistics.Ip6ReasmFails++; + IP6_INC_STATS_BH(Ip6ReasmFails); kfree_skb(skb); return; } @@ -450,7 +450,7 @@ static u8* reasm_frag(struct frag_queue *fq, struct sk_buff **skb_in) if (payload_len > 65535) { if (net_ratelimit()) printk(KERN_DEBUG "reasm_frag: payload len = %d\n", payload_len); - ipv6_statistics.Ip6ReasmFails++; + IP6_INC_STATS_BH(Ip6ReasmFails); fq_free(fq); return NULL; } @@ -458,7 +458,7 @@ static u8* reasm_frag(struct frag_queue *fq, struct sk_buff **skb_in) if ((skb = dev_alloc_skb(sizeof(struct ipv6hdr) + payload_len))==NULL) { if (net_ratelimit()) printk(KERN_DEBUG "reasm_frag: no memory for reassembly\n"); - ipv6_statistics.Ip6ReasmFails++; + IP6_INC_STATS_BH(Ip6ReasmFails); fq_free(fq); return NULL; } @@ -505,6 +505,6 @@ static u8* reasm_frag(struct frag_queue *fq, struct sk_buff **skb_in) frag_kfree_s(fq, sizeof(*fq)); - ipv6_statistics.Ip6ReasmOKs++; + IP6_INC_STATS_BH(Ip6ReasmOKs); return nhptr; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b39959f4f..668f61bfb 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: route.c,v 1.43 2000/01/06 00:42:08 davem Exp $ + * $Id: route.c,v 1.44 2000/01/09 02:19:51 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1176,7 +1176,7 @@ int ipv6_route_ioctl(unsigned int cmd, void *arg) int ip6_pkt_discard(struct sk_buff *skb) { - ipv6_statistics.Ip6OutNoRoutes++; + IP6_INC_STATS(Ip6OutNoRoutes); icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev); kfree_skb(skb); return 0; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 6e71f5479..e87ef0c3e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: tcp_ipv6.c,v 1.115 2000/01/06 00:42:09 davem Exp $ + * $Id: tcp_ipv6.c,v 1.116 2000/01/09 02:19:52 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -219,9 +219,7 @@ static __inline__ void __tcp_v6_hash(struct sock *sk) (*skp)->pprev = &sk->next; *skp = sk; sk->pprev = skp; - sk->prot->inuse++; - if(sk->prot->highestinuse < sk->prot->inuse) - sk->prot->highestinuse = sk->prot->inuse; + sock_prot_inc_use(sk->prot); write_unlock(lock); } @@ -410,9 +408,7 @@ unique: *skp = sk; sk->pprev = skp; - sk->prot->inuse++; - if(sk->prot->highestinuse < sk->prot->inuse) - sk->prot->highestinuse = sk->prot->inuse; + sock_prot_inc_use(sk->prot); write_unlock_bh(&head->lock); #ifdef CONFIG_TCP_TW_RECYCLE @@ -692,7 +688,7 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr, sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source, skb->dev->ifindex); if (sk == NULL) { - icmpv6_statistics.Icmp6InErrors++; + ICMP6_INC_STATS_BH(Icmp6InErrors); return; } @@ -703,12 +699,12 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr, bh_lock_sock(sk); if (sk->lock.users) - net_statistics.LockDroppedIcmps++; + NET_INC_STATS_BH(LockDroppedIcmps); tp = &sk->tp_pinfo.af_tcp; seq = ntohl(th->seq); if (sk->state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) { - net_statistics.OutOfWindowIcmps++; + NET_INC_STATS_BH(OutOfWindowIcmps); goto out; } @@ -781,12 +777,12 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr, tp = &sk->tp_pinfo.af_tcp; if (!between(seq, tp->snd_una, tp->snd_nxt)) { - net_statistics.OutOfWindowIcmps++; + NET_INC_STATS_BH(OutOfWindowIcmps); goto out; } } else { if (seq != req->snt_isn) { - net_statistics.OutOfWindowIcmps++; + NET_INC_STATS_BH(OutOfWindowIcmps); goto out; } @@ -802,7 +798,7 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr, case TCP_SYN_RECV: /* Cannot happen. It can, it SYNs are crossed. --ANK */ if (sk->lock.users == 0) { - tcp_statistics.TcpAttemptFails++; + TCP_INC_STATS_BH(TcpAttemptFails); sk->err = err; sk->error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ @@ -996,7 +992,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) return 0; drop: - tcp_statistics.TcpAttemptFails++; + TCP_INC_STATS_BH(TcpAttemptFails); return 0; /* don't send reset */ } @@ -1238,8 +1234,8 @@ static void tcp_v6_send_reset(struct sk_buff *skb) if (buff->dst->error == 0) { ip6_xmit(NULL, buff, &fl, NULL); - tcp_statistics.TcpOutSegs++; - tcp_statistics.TcpOutRsts++; + TCP_INC_STATS_BH(TcpOutSegs); + TCP_INC_STATS_BH(TcpOutRsts); return; } @@ -1304,7 +1300,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 if (buff->dst->error == 0) { ip6_xmit(NULL, buff, &fl, NULL); - tcp_statistics.TcpOutSegs++; + TCP_INC_STATS_BH(TcpOutSegs); return; } @@ -1437,7 +1433,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) * is currently called with bh processing disabled. */ - ipv6_statistics.Ip6InDelivers++; + IP6_INC_STATS_BH(Ip6InDelivers); /* * This doesn't check if the socket has enough room for the packet. @@ -1526,7 +1522,7 @@ discard: kfree_skb(skb); return 0; csum_err: - tcp_statistics.TcpInErrs++; + TCP_INC_STATS_BH(TcpInErrs); goto discard; @@ -1587,7 +1583,7 @@ int tcp_v6_rcv(struct sk_buff *skb, unsigned long len) * Count it even if it's bad. */ - tcp_statistics.TcpInSegs++; + TCP_INC_STATS_BH(TcpInSegs); if (len < sizeof(struct tcphdr)) goto bad_packet; @@ -1624,7 +1620,7 @@ process: no_tcp_socket: if (tcp_v6_csum_verify(skb)) { bad_packet: - tcp_statistics.TcpInErrs++; + TCP_INC_STATS_BH(TcpInErrs); } else { tcp_v6_send_reset(skb); } @@ -1644,7 +1640,7 @@ discard_and_relse: do_time_wait: if (tcp_v6_csum_verify(skb)) { - tcp_statistics.TcpInErrs++; + TCP_INC_STATS_BH(TcpInErrs); sock_put(sk); goto discard_it; } @@ -2124,8 +2120,6 @@ struct proto tcpv6_prot = { 128, /* max_header */ 0, /* retransmits */ "TCPv6", /* name */ - 0, /* inuse */ - 0 /* highestinuse */ }; static struct inet6_protocol tcpv6_protocol = diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 7bc3a3914..3ecc55030 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.47 2000/01/05 21:27:54 davem Exp $ + * $Id: udp.c,v 1.48 2000/01/09 02:19:53 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -45,7 +45,7 @@ #include <net/checksum.h> -struct udp_mib udp_stats_in6; +struct udp_mib udp_stats_in6[NR_CPUS*2]; /* Grrr, addr_type already calculated by caller, but I don't want * to add some silly "cookie" argument to this method just for that. @@ -130,9 +130,7 @@ static void udp_v6_hash(struct sock *sk) (*skp)->pprev = &sk->next; *skp = sk; sk->pprev = skp; - sk->prot->inuse++; - if(sk->prot->highestinuse < sk->prot->inuse) - sk->prot->highestinuse = sk->prot->inuse; + sock_prot_inc_use(sk->prot); sock_hold(sk); write_unlock_bh(&udp_hash_lock); } @@ -145,7 +143,7 @@ static void udp_v6_unhash(struct sock *sk) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; - sk->prot->inuse--; + sock_prot_dec_use(sk->prot); __sock_put(sk); } write_unlock_bh(&udp_hash_lock); @@ -494,8 +492,8 @@ static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) #if defined(CONFIG_FILTER) && defined(CONFIG_UDP_DELAY_CSUM) if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) { - udp_stats_in6.UdpInErrors++; - ipv6_statistics.Ip6InDiscards++; + UDP6_INC_STATS_BH(UdpInErrors); + IP6_INC_STATS_BH(Ip6InDiscards); kfree_skb(skb); return 0; } @@ -503,13 +501,13 @@ static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) } #endif if (sock_queue_rcv_skb(sk,skb)<0) { - udp_stats_in6.UdpInErrors++; - ipv6_statistics.Ip6InDiscards++; + UDP6_INC_STATS_BH(UdpInErrors); + IP6_INC_STATS_BH(Ip6InDiscards); kfree_skb(skb); return 0; } - ipv6_statistics.Ip6InDelivers++; - udp_stats_in6.UdpInDatagrams++; + IP6_INC_STATS_BH(Ip6InDelivers); + UDP6_INC_STATS_BH(UdpInDatagrams); return 0; } @@ -607,7 +605,7 @@ int udpv6_rcv(struct sk_buff *skb, unsigned long len) if (ulen > len || len < sizeof(*uh)) { if (net_ratelimit()) printk(KERN_DEBUG "UDP: short packet: %d/%ld\n", ulen, len); - udp_stats_in6.UdpInErrors++; + UDP6_INC_STATS_BH(UdpInErrors); kfree_skb(skb); return(0); } @@ -667,7 +665,7 @@ int udpv6_rcv(struct sk_buff *skb, unsigned long len) (unsigned short)csum_fold(csum_partial((char*)uh, len, skb->csum))) goto discard; #endif - udp_stats_in6.UdpNoPorts++; + UDP6_INC_STATS_BH(UdpNoPorts); icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); @@ -676,7 +674,7 @@ int udpv6_rcv(struct sk_buff *skb, unsigned long len) } if (0/*sk->user_callback && sk->user_callback(sk->user_data, skb) == 0*/) { - udp_stats_in6.UdpInDatagrams++; + UDP6_INC_STATS_BH(UdpInDatagrams); sock_put(sk); return(0); } @@ -688,7 +686,7 @@ int udpv6_rcv(struct sk_buff *skb, unsigned long len) return(0); discard: - udp_stats_in6.UdpInErrors++; + UDP6_INC_STATS_BH(UdpInErrors); kfree_skb(skb); return(0); } @@ -885,7 +883,7 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen) if (err < 0) return err; - udp_stats_in6.UdpOutDatagrams++; + UDP6_INC_STATS_USER(UdpOutDatagrams); return ulen; } @@ -1002,8 +1000,6 @@ struct proto udpv6_prot = { 128, /* max_header */ 0, /* retransmits */ "UDP", /* name */ - 0, /* inuse */ - 0 /* highestinuse */ }; void __init udpv6_init(void) diff --git a/net/khttpd/security.c b/net/khttpd/security.c index 9964f0a24..df346aadb 100644 --- a/net/khttpd/security.c +++ b/net/khttpd/security.c @@ -131,7 +131,7 @@ struct file *OpenFileForSecurity(char *Filename) if ((permission & sysctl_khttpd_permreq)==0) { - if (filp!=NULL); + if (filp!=NULL) fput(filp); filp=NULL; return NULL; diff --git a/net/netrom/nr_loopback.c b/net/netrom/nr_loopback.c index 9cf919ee6..af0e410f4 100644 --- a/net/netrom/nr_loopback.c +++ b/net/netrom/nr_loopback.c @@ -11,6 +11,7 @@ * * History * NET/ROM 007 Tomi(OH2BNS) Created this file. + * Small change in nr_loopback_queue(). * */ @@ -44,17 +45,17 @@ int nr_loopback_queue(struct sk_buff *skb) { struct sk_buff *skbn; - skbn = skb_clone(skb, GFP_ATOMIC); + if ((skbn = alloc_skb(skb->len, GFP_ATOMIC)) != NULL) { + memcpy(skb_put(skbn, skb->len), skb->data, skb->len); + skbn->h.raw = skbn->data; - kfree_skb(skb); - - if (skbn != NULL) { skb_queue_tail(&loopback_queue, skbn); if (!nr_loopback_running()) nr_set_loopback_timer(); } + kfree_skb(skb); return 1; } diff --git a/net/netsyms.c b/net/netsyms.c index 037d59d92..9891d5cb0 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -306,6 +306,7 @@ EXPORT_SYMBOL(tcp_destroy_sock); EXPORT_SYMBOL(ip_queue_xmit); EXPORT_SYMBOL(memcpy_fromiovecend); EXPORT_SYMBOL(csum_partial_copy_fromiovecend); +EXPORT_SYMBOL(copy_and_csum_toiovec); EXPORT_SYMBOL(tcp_keepalive_timer); EXPORT_SYMBOL(tcp_v4_lookup_listener); /* UDP/TCP exported functions for TCPv6 */ diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index ba8dd2041..0cab1224d 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -20,6 +20,7 @@ * ROSE 003 Jonathan(G4KLX) New timer architecture. * Implemented idle timer. * Added use count to neighbour. + * Tomi(OH2BNS) Fixed rose_getname(). */ #include <linux/config.h> @@ -893,7 +894,7 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags) static int rose_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { - struct sockaddr_rose *srose = (struct sockaddr_rose *)uaddr; + struct full_sockaddr_rose *srose = (struct full_sockaddr_rose *)uaddr; struct sock *sk = sock->sk; int n; @@ -901,42 +902,21 @@ static int rose_getname(struct socket *sock, struct sockaddr *uaddr, if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; srose->srose_family = AF_ROSE; - srose->srose_ndigis = 0; srose->srose_addr = sk->protinfo.rose->dest_addr; srose->srose_call = sk->protinfo.rose->dest_call; srose->srose_ndigis = sk->protinfo.rose->dest_ndigis; - if (*uaddr_len >= sizeof(struct full_sockaddr_rose)) { - struct full_sockaddr_rose *full_srose = (struct full_sockaddr_rose *)uaddr; - for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++) - full_srose->srose_digis[n] = sk->protinfo.rose->dest_digis[n]; - *uaddr_len = sizeof(struct full_sockaddr_rose); - } else { - if (sk->protinfo.rose->dest_ndigis >= 1) { - srose->srose_ndigis = 1; - srose->srose_digi = sk->protinfo.rose->dest_digis[0]; - } - *uaddr_len = sizeof(struct sockaddr_rose); - } + for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++) + srose->srose_digis[n] = sk->protinfo.rose->dest_digis[n]; } else { srose->srose_family = AF_ROSE; - srose->srose_ndigis = 0; srose->srose_addr = sk->protinfo.rose->source_addr; srose->srose_call = sk->protinfo.rose->source_call; srose->srose_ndigis = sk->protinfo.rose->source_ndigis; - if (*uaddr_len >= sizeof(struct full_sockaddr_rose)) { - struct full_sockaddr_rose *full_srose = (struct full_sockaddr_rose *)uaddr; - for (n = 0 ; n < sk->protinfo.rose->source_ndigis ; n++) - full_srose->srose_digis[n] = sk->protinfo.rose->source_digis[n]; - *uaddr_len = sizeof(struct full_sockaddr_rose); - } else { - if (sk->protinfo.rose->source_ndigis >= 1) { - srose->srose_ndigis = 1; - srose->srose_digi = sk->protinfo.rose->source_digis[sk->protinfo.rose->source_ndigis-1]; - } - *uaddr_len = sizeof(struct sockaddr_rose); - } + for (n = 0 ; n < sk->protinfo.rose->source_ndigis ; n++) + srose->srose_digis[n] = sk->protinfo.rose->source_digis[n]; } + *uaddr_len = sizeof(struct full_sockaddr_rose); return 0; } diff --git a/net/sched/Config.in b/net/sched/Config.in index f1d9059f4..bde82c341 100644 --- a/net/sched/Config.in +++ b/net/sched/Config.in @@ -17,7 +17,9 @@ tristate ' TEQL queue' CONFIG_NET_SCH_TEQL tristate ' TBF queue' CONFIG_NET_SCH_TBF tristate ' GRED queue' CONFIG_NET_SCH_GRED tristate ' Diffserv field marker' CONFIG_NET_SCH_DSMARK -tristate ' Ingress Qdisc' CONFIG_NET_SCH_INGRESS +if [ "$CONFIG_NETFILTER" = "y" ]; then + tristate ' Ingress Qdisc' CONFIG_NET_SCH_INGRESS +fi bool ' QoS support' CONFIG_NET_QOS if [ "$CONFIG_NET_QOS" = "y" ]; then bool ' Rate estimator' CONFIG_NET_ESTIMATOR diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 5aa6133cd..6aac88a17 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -4,6 +4,7 @@ * Written 1998,1999 by Werner Almesberger, EPFL ICA */ +#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index 852f56b22..64a915d7e 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -25,9 +25,9 @@ #include <linux/list.h> +#undef DEBUG_INGRESS - -#if 0 /* control */ +#ifdef DEBUG_INGRESS /* control */ #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) #else #define DPRINTK(format,args...) @@ -56,7 +56,9 @@ struct ingress_qdisc_data { static int ingress_graft(struct Qdisc *sch,unsigned long arg, struct Qdisc *new,struct Qdisc **old) { +#ifdef DEBUG_INGRESS struct ingress_qdisc_data *p = PRIV(sch); +#endif DPRINTK("ingress_graft(sch %p,[qdisc %p],new %p,old %p)\n", sch, p, new, old); @@ -73,8 +75,9 @@ static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg) static unsigned long ingress_get(struct Qdisc *sch,u32 classid) { +#ifdef DEBUG_INGRESS struct ingress_qdisc_data *p = PRIV(sch); - +#endif DPRINTK("ingress_get(sch %p,[qdisc %p],classid %x)\n", sch, p, classid); return TC_H_MIN(classid) + 1; } @@ -95,8 +98,9 @@ static void ingress_put(struct Qdisc *sch, unsigned long cl) static int ingress_change(struct Qdisc *sch, u32 classid, u32 parent, struct rtattr **tca, unsigned long *arg) { +#ifdef DEBUG_INGRESS struct ingress_qdisc_data *p = PRIV(sch); - +#endif DPRINTK("ingress_change(sch %p,[qdisc %p],classid %x,parent %x)," "arg 0x%lx\n", sch, p, classid, parent, *arg); DPRINTK("No effect. sch_ingress doesnt maintain classes at the moment"); @@ -107,8 +111,9 @@ static int ingress_change(struct Qdisc *sch, u32 classid, u32 parent, static void ingress_walk(struct Qdisc *sch,struct qdisc_walker *walker) { +#ifdef DEBUG_INGRESS struct ingress_qdisc_data *p = PRIV(sch); - +#endif DPRINTK("ingress_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); DPRINTK("No effect. sch_ingress doesnt maintain classes at the moment"); } @@ -180,8 +185,9 @@ static int ingress_requeue(struct sk_buff *skb,struct Qdisc *sch) static int ingress_drop(struct Qdisc *sch) { +#ifdef DEBUG_INGRESS struct ingress_qdisc_data *p = PRIV(sch); - +#endif DPRINTK("ingress_drop(sch %p,[qdisc %p])\n", sch, p); return 0; } @@ -218,7 +224,6 @@ used on the egress (might slow things for an iota) return fwres; } - /* after iptables */ static struct nf_hook_ops ing_ops = { diff --git a/net/socket.c b/net/socket.c index f709c03cd..4b4bc45b9 100644 --- a/net/socket.c +++ b/net/socket.c @@ -85,7 +85,7 @@ #include <linux/netfilter.h> static int sock_no_open(struct inode *irrelevant, struct file *dontcare); -static long long sock_lseek(struct file *file, long long offset, int whence); +static loff_t sock_lseek(struct file *file, loff_t offset, int whence); static ssize_t sock_read(struct file *file, char *buf, size_t size, loff_t *ppos); static ssize_t sock_write(struct file *file, const char *buf, @@ -419,7 +419,7 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags) * Sockets are not seekable. */ -static long long sock_lseek(struct file *file,long long offset, int whence) +static loff_t sock_lseek(struct file *file, loff_t offset, int whence) { return -ESPIPE; } diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 55bc69e55..8f5218082 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -358,7 +358,7 @@ err_bad_rpc: goto sendit; err_bad_auth: - dprintk("svc: authentication failed (%ld)\n", ntohl(auth_stat)); + dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat)); serv->sv_stats->rpcbadauth++; resp->buf[-1] = xdr_one; /* REJECT */ svc_putlong(resp, xdr_one); /* AUTH_ERROR */ diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 25ac47242..5e86578fd 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -266,10 +266,10 @@ svc_sendto(struct svc_rqst *rqstp, struct iovec *iov, int nr) set_fs(oldfs); #endif - dprintk("svc: socket %p sendto([%p %d... ], %d, %d) = %d\n", - rqstp->rq_sock, - iov[0].iov_base, iov[0].iov_len, nr, - buflen, len); + dprintk("svc: socket %p sendto([%p %lu... ], %d, %d) = %d\n", + rqstp->rq_sock, iov[0].iov_base, + (unsigned long) iov[0].iov_len, nr, + buflen, len); return len; } @@ -326,8 +326,8 @@ svc_recvfrom(struct svc_rqst *rqstp, struct iovec *iov, int nr, int buflen) set_fs(oldfs); #endif - dprintk("svc: socket %p recvfrom(%p, %d) = %d\n", rqstp->rq_sock, - iov[0].iov_base, iov[0].iov_len, len); + dprintk("svc: socket %p recvfrom(%p, %lu) = %d\n", rqstp->rq_sock, + iov[0].iov_base, (unsigned long) iov[0].iov_len, len); return len; } @@ -526,16 +526,18 @@ svc_tcp_accept(struct svc_sock *svsk) newsock->ops = ops = sock->ops; if ((err = ops->accept(sock, newsock, O_NONBLOCK)) < 0) { - printk(KERN_WARNING "%s: accept failed (err %d)!\n", - serv->sv_name, -err); + if (net_ratelimit()) + printk(KERN_WARNING "%s: accept failed (err %d)!\n", + serv->sv_name, -err); goto failed; /* aborted connection or whatever */ } slen = sizeof(sin); err = ops->getname(newsock, (struct sockaddr *) &sin, &slen, 1); if (err < 0) { - printk(KERN_WARNING "%s: peername failed (err %d)!\n", - serv->sv_name, -err); + if (net_ratelimit()) + printk(KERN_WARNING "%s: peername failed (err %d)!\n", + serv->sv_name, -err); goto failed; /* aborted connection or whatever */ } @@ -543,10 +545,11 @@ svc_tcp_accept(struct svc_sock *svsk) * hosts here, but we have no generic client tables. For now, * we just punt connects from unprivileged ports. */ if (ntohs(sin.sin_port) >= 1024) { - printk(KERN_WARNING - "%s: connect from unprivileged port: %s:%d", - serv->sv_name, - in_ntoa(sin.sin_addr.s_addr), ntohs(sin.sin_port)); + if (net_ratelimit()) + printk(KERN_WARNING + "%s: connect from unprivileged port: %s:%d", + serv->sv_name, + in_ntoa(sin.sin_addr.s_addr), ntohs(sin.sin_port)); goto failed; } @@ -913,7 +916,7 @@ svc_create_socket(struct svc_serv *serv, int protocol, struct sockaddr_in *sin) int error; int type; - dprintk("svc: svc_create_socket(%s, %d, %08lx:%d)\n", + dprintk("svc: svc_create_socket(%s, %d, %08x:%d)\n", serv->sv_program->pg_name, protocol, ntohl(sin->sin_addr.s_addr), ntohs(sin->sin_port)); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index fb09aac28..521152396 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1541,7 +1541,7 @@ xprt_create_socket(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) struct socket *sock; int type, err; - dprintk("RPC: xprt_create_socket(%08lx, %s %d)\n", + dprintk("RPC: xprt_create_socket(%08x, %s %d)\n", sap? ntohl(sap->sin_addr.s_addr) : 0, (proto == IPPROTO_UDP)? "udp" : "tcp", proto); |