summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ax25/af_ax25.c30
-rw-r--r--net/ax25/ax25_ds_subr.c1
-rw-r--r--net/ax25/ax25_in.c1
-rw-r--r--net/ax25/ax25_ip.c1
-rw-r--r--net/ax25/ax25_out.c3
-rw-r--r--net/ax25/ax25_subr.c3
-rw-r--r--net/ax25/ax25_timer.c7
-rw-r--r--net/core/iovec.c36
-rw-r--r--net/decnet/Config.in3
-rw-r--r--net/decnet/Makefile2
-rw-r--r--net/decnet/TODO38
-rw-r--r--net/decnet/af_decnet.c89
-rw-r--r--net/decnet/dn_dev.c315
-rw-r--r--net/decnet/dn_fib.c1027
-rw-r--r--net/decnet/dn_neigh.c7
-rw-r--r--net/decnet/dn_nsp_in.c35
-rw-r--r--net/decnet/dn_nsp_out.c102
-rw-r--r--net/decnet/dn_route.c289
-rw-r--r--net/decnet/dn_rules.c372
-rw-r--r--net/decnet/dn_table.c907
-rw-r--r--net/decnet/sysctl_net_decnet.c124
-rw-r--r--net/ipv4/af_inet.c6
-rw-r--r--net/ipv4/devinet.c9
-rw-r--r--net/ipv4/icmp.c89
-rw-r--r--net/ipv4/ip_forward.c6
-rw-r--r--net/ipv4/ip_fragment.c14
-rw-r--r--net/ipv4/ip_gre.c2
-rw-r--r--net/ipv4/ip_input.c14
-rw-r--r--net/ipv4/ip_output.c23
-rw-r--r--net/ipv4/ip_sockglue.c4
-rw-r--r--net/ipv4/ipconfig.c6
-rw-r--r--net/ipv4/ipmr.c4
-rw-r--r--net/ipv4/proc.c130
-rw-r--r--net/ipv4/raw.c16
-rw-r--r--net/ipv4/route.c11
-rw-r--r--net/ipv4/syncookies.c8
-rw-r--r--net/ipv4/sysctl_net_ipv4.c4
-rw-r--r--net/ipv4/tcp.c4
-rw-r--r--net/ipv4/tcp_input.c16
-rw-r--r--net/ipv4/tcp_ipv4.c52
-rw-r--r--net/ipv4/tcp_output.c20
-rw-r--r--net/ipv4/udp.c42
-rw-r--r--net/ipv6/addrconf.c7
-rw-r--r--net/ipv6/exthdrs.c6
-rw-r--r--net/ipv6/icmp.c22
-rw-r--r--net/ipv6/ip6_input.c14
-rw-r--r--net/ipv6/ip6_output.c32
-rw-r--r--net/ipv6/ipv6_sockglue.c15
-rw-r--r--net/ipv6/mcast.c8
-rw-r--r--net/ipv6/ndisc.c38
-rw-r--r--net/ipv6/proc.c46
-rw-r--r--net/ipv6/raw.c14
-rw-r--r--net/ipv6/reassembly.c18
-rw-r--r--net/ipv6/route.c4
-rw-r--r--net/ipv6/tcp_ipv6.c42
-rw-r--r--net/ipv6/udp.c34
-rw-r--r--net/khttpd/security.c2
-rw-r--r--net/netrom/nr_loopback.c9
-rw-r--r--net/netsyms.c1
-rw-r--r--net/rose/af_rose.c34
-rw-r--r--net/sched/Config.in4
-rw-r--r--net/sched/cls_tcindex.c1
-rw-r--r--net/sched/sch_ingress.c19
-rw-r--r--net/socket.c4
-rw-r--r--net/sunrpc/svc.c2
-rw-r--r--net/sunrpc/svcsock.c33
-rw-r--r--net/sunrpc/xprt.c2
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);