Hi,
My latest DECnet patch for 2.5 has the following features:
o Introduce kfree_release() in seq_file.c for use of DECnet and eventually
IP as well (and other things...?)
o Added proc_net_fops_create() like proc_net_create() but with file_operations
argument to use with seq_file code (cleans up some #ifdefs). If there are
no objections, I'll send a patch for IPv4/6 shortly.
o Removed blksize from decnet device parameters - use the device mtu like we
ought to.
o Removed /proc/net/decnet_route file - I don't think anybody ever used it
and it was lacking a full enough description of the routes to be useful.
ip -D route list is much better :-)
o Added rt_local_src entry to decnet routes so that we get the local source
address right when forwarding.
o Added netfilter subdir for decnet and add the routing grabulator
o Added correct proto argument to struct flowi for routing
o MSG_MORE in sendmsg (ignored, but accepted whereas before we'd error)
o /proc/net/decnet converted to seq_file
o /proc/net/decnet_dev converted to seq_file
o /proc/net/decnet_cache converted to seq_file
o Use pskb_may_pull() and add code to linearize skbs on the input path
except for those containing data.
o Fixed returned packet code (mostly - some left to do)
o update_pmtu() method for decnet dst entries (ip_gre device assumes this
method exists)
o Fixed bug in forwarding to get IE bit set correctly
o Fixed compile bugs with CONFIG_DECNET_ROUTE_FWMARK pointed out by Adrian
Bunk
o Fixed zero dest code to grab an address from loopback
o Fixed local routes in dn_route_output_slow()
o Fixed error case in dn_route_input/output_slow() pointed out by Rusty
Its got big again, so I've put it here, if you'd like it in bits rather than
all one lump, just shout:
http://www.chygwyn.com/~steve/kpatch/decnet/decnet-2.5.68-bk10-seqfile.diff
If you've been wondering when the routing in DECnet would reach the
stage where its actually likely to be useful, now is that time :-) We
don't yet have full automatic routing, but all the kernel infrastructure
is now in place and the rest can be done in userspace. In the mean time,
iproute2 can set up manual routes.
I'm going to write some docs and post them somewhere in the next few weeks
to give more detailed info on how to use the various features.
Steve.
From: Steven Whitehouse <[email protected]>
Date: Thu, 1 May 2003 14:27:08 +0100 (BST)
Its got big again, so I've put it here, if you'd like it in bits rather than
all one lump, just shout:
Please do this because it's easier for me to evaluate small patches
doing one thing at a time and you're also making modifications to
things outside of decnet.
About update_pmtu(). You are not required to implement this.
All of these places you see dereferencing dst->update_mtu()
know that they have an ipv4/ipv6 route. Or do you know some
exception to this?
Hi,
>
> From: Steven Whitehouse <[email protected]>
> Date: Thu, 1 May 2003 14:27:08 +0100 (BST)
>
> Its got big again, so I've put it here, if you'd like it in bits rather than
> all one lump, just shout:
>
> Please do this because it's easier for me to evaluate small patches
> doing one thing at a time and you're also making modifications to
> things outside of decnet.
>
Ok. I'll do that later this afternoon.
> About update_pmtu(). You are not required to implement this.
> All of these places you see dereferencing dst->update_mtu()
> know that they have an ipv4/ipv6 route. Or do you know some
> exception to this?
>
I was thinking of that bit of code in ip_gre.c which I sent the fix for
recently. Unless I've missed something it calls update_pmtu on the dst
which is passed by the encapsulated protocol, although I've not actually
tested that.
Thats the reason I wasn't sure about the fix which I sent... it deleted the
duplicated call only for IPv4 rather than the one which appears to get called
for every protocol as I wasn't sure what was intended.
Either way it seems reasonable to pass this information back to the
protocol so perhaps it should say (in ipgre_tunnel_xmit()):
if (skb->dst && skb->dst->ops->update_pmtu)
skb->dst->ops->update_pmtu(skb->dst, mtu);
?
Steve.
From: Steven Whitehouse <[email protected]>
Date: Thu, 1 May 2003 15:04:00 +0100 (BST)
> About update_pmtu(). You are not required to implement this.
> All of these places you see dereferencing dst->update_mtu()
> know that they have an ipv4/ipv6 route. Or do you know some
> exception to this?
I was thinking of that bit of code in ip_gre.c which I sent the fix for
recently. Unless I've missed something it calls update_pmtu on the dst
which is passed by the encapsulated protocol, although I've not actually
tested that.
Thats the reason I wasn't sure about the fix which I sent... it deleted the
duplicated call only for IPv4 rather than the one which appears to get called
for every protocol as I wasn't sure what was intended.
No, this must be an IPV4 or an IPV6 route.
Right Alexey?
Hi,
I've split the patch into three. Any further splitting/changes will have to
wait until next week when I'll have time to work on it again.
- Part 1. Things outside DECnet
- Part 2. seq_file & fixes for DECnet depending on part 1
- Part 3. Addition of the DECnet routing grabulator (does not depend on other
patches)
Below is part 1 with the following features:
o Introduce kfree_release() in seq_file.c for use of DECnet and eventually
IP as well (and other things...?)
o Added proc_net_fops_create() like proc_net_create() but with file_operations argument to use with seq_file code (cleans up some #ifdefs). If there are
no objections, I'll send a patch for IPv4/6 shortly.
Steve.
--------------------------------------------------------------------------
diff -Nru linux-2.5.68-bk10/fs/seq_file.c linux/fs/seq_file.c
--- linux-2.5.68-bk10/fs/seq_file.c Sun Apr 20 03:27:58 2003
+++ linux/fs/seq_file.c Mon Apr 21 14:40:35 2003
@@ -338,3 +338,13 @@
kfree(op);
return res;
}
+
+int kfree_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+
+ kfree(seq->private);
+ seq->private = NULL;
+ return seq_release(inode, file);
+}
+
diff -Nru linux-2.5.68-bk10/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- linux-2.5.68-bk10/include/linux/proc_fs.h Wed Jan 1 19:20:49 2003
+++ linux/include/linux/proc_fs.h Tue Apr 22 01:32:43 2003
@@ -163,6 +163,15 @@
return create_proc_info_entry(name,mode,proc_net,get_info);
}
+static inline struct proc_dir_entry *proc_net_fops_create(const char *name,
+ mode_t mode, struct file_operations *fops)
+{
+ struct proc_dir_entry *res = create_proc_entry(name, mode, proc_net);
+ if (res)
+ res->proc_fops = fops;
+ return res;
+}
+
static inline void proc_net_remove(const char *name)
{
remove_proc_entry(name,proc_net);
@@ -171,7 +180,7 @@
#else
#define proc_root_driver NULL
-
+#define proc_net_fops_create(name,mode,fops) do {} while(0)
static inline struct proc_dir_entry *proc_net_create(const char *name, mode_t mode,
get_info_t *get_info) {return NULL;}
static inline void proc_net_remove(const char *name) {}
diff -Nru linux-2.5.68-bk10/include/linux/seq_file.h linux/include/linux/seq_file.h
--- linux-2.5.68-bk10/include/linux/seq_file.h Wed Jan 1 19:23:19 2003
+++ linux/include/linux/seq_file.h Mon Apr 21 14:41:12 2003
@@ -60,5 +60,6 @@
int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
int single_release(struct inode *, struct file *);
+int kfree_release(struct inode *, struct file *);
#endif
#endif
diff -Nru linux-2.5.68-bk10/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.5.68-bk10/kernel/ksyms.c Thu May 1 03:00:23 2003
+++ linux/kernel/ksyms.c Thu May 1 03:00:48 2003
@@ -539,6 +539,7 @@
EXPORT_SYMBOL(seq_lseek);
EXPORT_SYMBOL(single_open);
EXPORT_SYMBOL(single_release);
+EXPORT_SYMBOL(kfree_release);
/* Program loader interfaces */
#ifdef CONFIG_MMU
On Thu, May 01, 2003 at 09:52:01PM +0100, Steven Whitehouse wrote:
> --- linux-2.5.68-bk10/fs/seq_file.c Sun Apr 20 03:27:58 2003
> +++ linux/fs/seq_file.c Mon Apr 21 14:40:35 2003
> @@ -338,3 +338,13 @@
> kfree(op);
> return res;
> }
> +
> +int kfree_release(struct inode *inode, struct file *file)
> +{
> + struct seq_file *seq = file->private_data;
> +
> + kfree(seq->private);
> + seq->private = NULL;
> + return seq_release(inode, file);
> +}
The name is a bit generic for an export function. What about
seq_release_kfree?
Hi,
Here is part 3 (stands alone) with the following feature:
o Added netfilter subdir for decnet and add the routing grabulator
Steve.
------------------------------------------------------------------------------
diff -Nru linux-2.5.68-bk10/net/decnet/Makefile linux/net/decnet/Makefile
--- linux-2.5.68-bk10/net/decnet/Makefile Wed Jan 1 19:21:18 2003
+++ linux/net/decnet/Makefile Wed Apr 23 10:27:53 2003
@@ -1,7 +1,10 @@
obj-$(CONFIG_DECNET) += decnet.o
-decnet-y := af_decnet.o dn_nsp_in.o dn_nsp_out.o dn_route.o dn_dev.o dn_neigh.o dn_timer.o
+decnet-y := af_decnet.o dn_nsp_in.o dn_nsp_out.o \
+ dn_route.o dn_dev.o dn_neigh.o dn_timer.o
decnet-$(CONFIG_DECNET_ROUTER) += dn_fib.o dn_rules.o dn_table.o
-decnet-$(CONFIG_DECNET_FW) += dn_fw.o
decnet-y += sysctl_net_decnet.o
+
+obj-$(CONFIG_NETFILTER) += netfilter/
+
diff -Nru linux-2.5.68-bk10/net/decnet/Kconfig linux/net/decnet/Kconfig
--- linux-2.5.68-bk10/net/decnet/Kconfig Wed Jan 1 19:23:15 2003
+++ linux/net/decnet/Kconfig Wed Apr 23 10:29:31 2003
@@ -17,11 +17,11 @@
depends on DECNET && EXPERIMENTAL
---help---
Add support for turning your DECnet Endnode into a level 1 or 2
- router. This is an unfinished option for developers only. If you
+ router. This is an experimental, but functional option. If you
do say Y here, then make sure that you also say Y to "Kernel/User
network link driver", "Routing messages" and "Network packet
filtering". The first two are required to allow configuration via
- rtnetlink (currently you need Alexey Kuznetsov's iproute2 package
+ rtnetlink (you will need Alexey Kuznetsov's iproute2 package
from <ftp://ftp.inr.ac.ru/>). The "Network packet filtering" option
will be required for the forthcoming routing daemon to work.
@@ -34,4 +34,6 @@
If you say Y here, you will be able to specify different routes for
packets with different FWMARK ("firewalling mark") values
(see ipchains(8), "-m" argument).
+
+source "net/decnet/netfilter/Kconfig"
diff -Nru linux-2.5.68-bk10/net/decnet/netfilter/Kconfig linux/net/decnet/netfilter/Kconfig
--- linux-2.5.68-bk10/net/decnet/netfilter/Kconfig Wed Dec 31 16:00:00 1969
+++ linux/net/decnet/netfilter/Kconfig Wed Apr 23 13:02:25 2003
@@ -0,0 +1,15 @@
+#
+# DECnet netfilter configuration
+#
+
+menu "DECnet: Netfilter Configuration"
+ depends on DECNET && NETFILTER && EXPERIMENTAL
+
+config DECNET_NF_GRABULATOR
+ tristate "Routing message grabulator (for userland routing daemon)"
+ help
+ Enable this module if you want to use the userland DECnet routing
+ daemon. You will also need to enable routing support for DECnet
+ unless you just want to monitor routing messages from other nodes.
+
+endmenu
diff -Nru linux-2.5.68-bk10/net/decnet/netfilter/Makefile linux/net/decnet/netfilter/Makefile
--- linux-2.5.68-bk10/net/decnet/netfilter/Makefile Wed Dec 31 16:00:00 1969
+++ linux/net/decnet/netfilter/Makefile Wed Apr 23 10:25:21 2003
@@ -0,0 +1,6 @@
+#
+# Makefile for DECnet netfilter modules
+#
+
+obj-$(CONFIG_DECNET_NF_GRABULATOR) += dn_rtmsg.o
+
diff -Nru linux-2.5.68-bk10/net/decnet/netfilter/dn_rtmsg.c linux/net/decnet/netfilter/dn_rtmsg.c
--- linux-2.5.68-bk10/net/decnet/netfilter/dn_rtmsg.c Wed Dec 31 16:00:00 1969
+++ linux/net/decnet/netfilter/dn_rtmsg.c Wed Apr 23 14:05:10 2003
@@ -0,0 +1,167 @@
+/*
+ * 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 Message Grabulator
+ *
+ * (C) 2000 ChyGwyn Limited - http://www.chygwyn.com/
+ * This code may be copied under the GPL v.2 or at your option
+ * any later version.
+ *
+ * Author: Steven Whitehouse <[email protected]>
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/spinlock.h>
+#include <linux/netlink.h>
+
+#include <net/sock.h>
+#include <net/flow.h>
+#include <net/dn.h>
+#include <net/dn_route.h>
+
+#include <linux/netfilter_decnet.h>
+
+static struct sock *dnrmg = NULL;
+
+
+static struct sk_buff *dnrmg_build_message(struct sk_buff *rt_skb, int *errp)
+{
+ struct sk_buff *skb = NULL;
+ size_t size;
+ unsigned char *old_tail;
+ struct nlmsghdr *nlh;
+ unsigned char *ptr;
+ struct nf_dn_rtmsg *rtm;
+
+ size = NLMSG_SPACE(rt_skb->len);
+ size += NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg));
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (!skb)
+ goto nlmsg_failure;
+ old_tail = skb->tail;
+ nlh = NLMSG_PUT(skb, 0, 0, 0, size - sizeof(*nlh));
+ rtm = (struct nf_dn_rtmsg *)NLMSG_DATA(nlh);
+ rtm->nfdn_ifindex = rt_skb->dev->ifindex;
+ ptr = NFDN_RTMSG(rtm);
+ memcpy(ptr, rt_skb->data, rt_skb->len);
+ nlh->nlmsg_len = skb->tail - old_tail;
+ return skb;
+
+nlmsg_failure:
+ if (skb)
+ kfree(skb);
+ *errp = -ENOMEM;
+ if (net_ratelimit())
+ printk(KERN_ERR "dn_rtmsg: error creating netlink message\n");
+ return NULL;
+}
+
+static void dnrmg_send_peer(struct sk_buff *skb)
+{
+ struct sk_buff *skb2;
+ int status = 0;
+ int group = 0;
+ unsigned char flags = *skb->data;
+
+ switch(flags & DN_RT_CNTL_MSK) {
+ case DN_RT_PKT_L1RT:
+ group = DNRMG_L1_GROUP;
+ break;
+ case DN_RT_PKT_L2RT:
+ group = DNRMG_L2_GROUP;
+ break;
+ default:
+ return;
+ }
+
+ skb2 = dnrmg_build_message(skb, &status);
+ if (skb2 == NULL)
+ return;
+ NETLINK_CB(skb2).dst_groups = group;
+ netlink_broadcast(dnrmg, skb2, 0, group, GFP_ATOMIC);
+}
+
+
+static unsigned int dnrmg_hook(unsigned int hook,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ dnrmg_send_peer(*pskb);
+ return NF_ACCEPT;
+}
+
+
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
+
+static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
+
+ if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
+ return;
+
+ if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+ RCV_SKB_FAIL(-EPERM);
+
+ /* Eventually we might send routing messages too */
+
+ RCV_SKB_FAIL(-EINVAL);
+}
+
+static void dnrmg_receive_user_sk(struct sock *sk, int len)
+{
+ struct sk_buff *skb;
+
+ while((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+ dnrmg_receive_user_skb(skb);
+ kfree_skb(skb);
+ }
+}
+
+static struct nf_hook_ops dnrmg_ops = {
+ .hook = dnrmg_hook,
+ .pf = PF_DECnet,
+ .hooknum = NF_DN_ROUTE,
+ .priority = NF_DN_PRI_DNRTMSG,
+};
+
+static int __init init(void)
+{
+ int rv = 0;
+
+ dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, dnrmg_receive_user_sk);
+ if (dnrmg == NULL) {
+ printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket");
+ return -ENOMEM;
+ }
+
+ rv = nf_register_hook(&dnrmg_ops);
+ if (rv) {
+ sock_release(dnrmg->socket);
+ }
+
+ return rv;
+}
+
+static void __exit fini(void)
+{
+ nf_unregister_hook(&dnrmg_ops);
+ sock_release(dnrmg->socket);
+}
+
+
+MODULE_DESCRIPTION("DECnet Routing Message Grabulator");
+MODULE_AUTHOR("Steven Whitehouse <[email protected]>");
+MODULE_LICENSE("GPL");
+
+module_init(init);
+module_exit(fini);
+
Hi,
Here is part 2 (depends on part 1) with the following features:
o Removed blksize from decnet device parameters - use the device mtu like we
ought to.
o Removed /proc/net/decnet_route file - I don't think anybody ever used it
and it was lacking a full enough description of the routes to be useful.
ip -D route list is much better :-)
o Added rt_local_src entry to decnet routes so that we get the local source
address right when forwarding.
o Added correct proto argument to struct flowi for routing
o MSG_MORE in sendmsg (ignored, but accepted whereas before we'd error)
o /proc/net/decnet converted to seq_file
o /proc/net/decnet_dev converted to seq_file
o /proc/net/decnet_cache converted to seq_file
o Use pskb_may_pull() and add code to linearize skbs on the input path
except for those containing data.
o Fixed returned packet code (mostly - some left to do)
o update_pmtu() method for decnet dst entries (ip_gre device assumes this
method exists - well I think it does :-)
o Fixed bug in forwarding to get IE bit set correctly
o Fixed compile bugs with CONFIG_DECNET_ROUTE_FWMARK pointed out by Adrian
Bunk
o Fixed zero dest code to grab an address from loopback
o Fixed local routes in dn_route_output_slow()
o Fixed error case in dn_route_input/output_slow() pointed out by Rusty
Steve.
-----------------------------------------------------------------------------
diff -Nru linux-2.5.68-bk10/include/net/dn_dev.h linux/include/net/dn_dev.h
--- linux-2.5.68-bk10/include/net/dn_dev.h Sun Apr 20 03:28:00 2003
+++ linux/include/net/dn_dev.h Mon Apr 21 04:13:14 2003
@@ -71,7 +71,6 @@
#define DN_DEV_MPOINT 4
int state; /* Initial state */
int forwarding; /* 0=EndNode, 1=L1Router, 2=L2Router */
- unsigned short blksize; /* Block Size */
unsigned long t2; /* Default value of t2 */
unsigned long t3; /* Default value of t3 */
int priority; /* Priority to be a router */
diff -Nru linux-2.5.68-bk10/include/net/dn_fib.h linux/include/net/dn_fib.h
--- linux-2.5.68-bk10/include/net/dn_fib.h Sun Apr 20 03:28:00 2003
+++ linux/include/net/dn_fib.h Wed Apr 23 09:43:44 2003
@@ -101,10 +101,6 @@
int (*lookup)(struct dn_fib_table *t, const struct flowi *fl,
struct dn_fib_res *res);
int (*flush)(struct dn_fib_table *t);
-#ifdef CONFIG_PROC_FS
- int (*get_info)(struct dn_fib_table *table, char *buf,
- int first, int count);
-#endif /* CONFIG_PROC_FS */
int (*dump)(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb);
unsigned char data[0];
@@ -183,6 +179,9 @@
extern struct dn_fib_table *dn_fib_tables[];
#else /* Endnode */
+
+#define dn_fib_init() (0)
+#define dn_fib_cleanup() (0)
#define dn_fib_lookup(fl, res) (-ESRCH)
#define dn_fib_info_put(fi) do { } while(0)
diff -Nru linux-2.5.68-bk10/include/net/dn_route.h linux/include/net/dn_route.h
--- linux-2.5.68-bk10/include/net/dn_route.h Sun Apr 20 03:28:00 2003
+++ linux/include/net/dn_route.h Wed Apr 23 07:44:23 2003
@@ -74,7 +74,7 @@
__u16 rt_saddr;
__u16 rt_daddr;
__u16 rt_gateway;
- __u16 __padding;
+ __u16 rt_local_src; /* Source used for forwarding packets */
__u16 rt_src_map;
__u16 rt_dst_map;
diff -Nru linux-2.5.68-bk10/net/decnet/TODO linux/net/decnet/TODO
--- linux-2.5.68-bk10/net/decnet/TODO Sun Apr 20 03:28:01 2003
+++ linux/net/decnet/TODO Wed Apr 23 10:31:38 2003
@@ -23,15 +23,9 @@
o check MSG_CTRUNC is set where it should be.
- o Start to hack together user level software and add more DECnet support
- in ifconfig for example.
-
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.7.xx]
- o Add the routing message grabbing netfilter module [written, tested,
- awaiting merge]
-
o Add perfect socket hashing - an idea suggested by Paul Koning. Currently
we have a half-way house scheme which seems to work reasonably well, but
the full scheme is still worth implementing, its not not top of my list
@@ -44,6 +38,4 @@
o DECnet sendpages() function
o AIO for DECnet
-
- o Eliminate dn_db->parms.blksize
diff -Nru linux-2.5.68-bk10/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- linux-2.5.68-bk10/net/decnet/af_decnet.c Thu May 1 03:00:23 2003
+++ linux/net/decnet/af_decnet.c Thu May 1 05:34:36 2003
@@ -116,6 +116,7 @@
#include <linux/inet.h>
#include <linux/route.h>
#include <linux/netfilter.h>
+#include <linux/seq_file.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <net/flow.h>
@@ -675,45 +676,6 @@
}
-static char *dn_state2asc(unsigned char state)
-{
- switch(state) {
- case DN_O:
- return "OPEN";
- case DN_CR:
- return " CR";
- case DN_DR:
- return " DR";
- case DN_DRC:
- return " DRC";
- case DN_CC:
- return " CC";
- case DN_CI:
- return " CI";
- case DN_NR:
- return " NR";
- case DN_NC:
- return " NC";
- case DN_CD:
- return " CD";
- case DN_RJ:
- return " RJ";
- case DN_RUN:
- return " RUN";
- case DN_DI:
- return " DI";
- case DN_DIC:
- return " DIC";
- case DN_DN:
- return " DN";
- case DN_CL:
- return " CL";
- case DN_CN:
- return " CN";
- }
-
- return "????";
-}
static int dn_create(struct socket *sock, int protocol)
{
@@ -1000,6 +962,7 @@
fl.fld_dst = dn_saddr2dn(&scp->peer);
fl.fld_src = dn_saddr2dn(&scp->addr);
dn_sk_ports_copy(&fl, scp);
+ fl.proto = DNPROTO_NSP;
if (dn_route_output_sock(&sk->dst_cache, &fl, sk, flags) < 0)
goto out;
sk->route_caps = sk->dst_cache->dev->features;
@@ -1963,7 +1926,7 @@
unsigned char fctype;
long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
- if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL))
+ if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE))
return -EOPNOTSUPP;
if (addr_len && (addr_len != sizeof(struct sockaddr_dn)))
@@ -2142,6 +2105,95 @@
.data = (void*)1,
};
+#ifdef CONFIG_PROC_FS
+struct dn_iter_state {
+ int bucket;
+};
+
+static struct sock *dn_socket_get_first(struct seq_file *seq)
+{
+ struct dn_iter_state *state = seq->private;
+ struct sock *n = NULL;
+
+ for(state->bucket = 0;
+ state->bucket < DN_SK_HASH_SIZE;
+ ++state->bucket) {
+ n = dn_sk_hash[state->bucket];
+ if (n)
+ break;
+ }
+
+ return n;
+}
+
+static struct sock *dn_socket_get_next(struct seq_file *seq,
+ struct sock *n)
+{
+ struct dn_iter_state *state = seq->private;
+
+ n = n->next;
+try_again:
+ if (n)
+ goto out;
+ if (++state->bucket >= DN_SK_HASH_SIZE)
+ goto out;
+ n = dn_sk_hash[state->bucket];
+ goto try_again;
+out:
+ return n;
+}
+
+static struct sock *socket_get_idx(struct seq_file *seq, loff_t *pos)
+{
+ struct sock *sk = dn_socket_get_first(seq);
+
+ if (sk) {
+ while(*pos && (sk = dn_socket_get_next(seq, sk)))
+ --*pos;
+ }
+ return *pos ? NULL : sk;
+}
+
+static void *dn_socket_get_idx(struct seq_file *seq, loff_t pos)
+{
+ void *rc;
+ read_lock_bh(&dn_hash_lock);
+ rc = socket_get_idx(seq, &pos);
+ if (!rc) {
+ read_unlock_bh(&dn_hash_lock);
+ }
+ return rc;
+}
+
+static void *dn_socket_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return *pos ? dn_socket_get_idx(seq, *pos - 1) : (void*)1;
+}
+
+static void *dn_socket_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ void *rc;
+
+ if (v == (void*)1) {
+ rc = dn_socket_get_idx(seq, 0);
+ goto out;
+ }
+
+ rc = dn_socket_get_next(seq, v);
+ if (rc)
+ goto out;
+ read_unlock_bh(&dn_hash_lock);
+out:
+ ++*pos;
+ return rc;
+}
+
+static void dn_socket_seq_stop(struct seq_file *seq, void *v)
+{
+ if (v && v != (void*)1)
+ read_unlock_bh(&dn_hash_lock);
+}
+
#define IS_NOT_PRINTABLE(x) ((x) < 32 || (x) > 126)
static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf)
@@ -2162,70 +2214,127 @@
}
}
-static int dn_get_info(char *buffer, char **start, off_t offset, int length)
+static char *dn_state2asc(unsigned char state)
{
- struct sock *sk;
- struct dn_scp *scp;
- int len = 0;
- off_t pos = 0;
- off_t begin = 0;
+ switch(state) {
+ case DN_O:
+ return "OPEN";
+ case DN_CR:
+ return " CR";
+ case DN_DR:
+ return " DR";
+ case DN_DRC:
+ return " DRC";
+ case DN_CC:
+ return " CC";
+ case DN_CI:
+ return " CI";
+ case DN_NR:
+ return " NR";
+ case DN_NC:
+ return " NC";
+ case DN_CD:
+ return " CD";
+ case DN_RJ:
+ return " RJ";
+ case DN_RUN:
+ return " RUN";
+ case DN_DI:
+ return " DI";
+ case DN_DIC:
+ return " DIC";
+ case DN_DN:
+ return " DN";
+ case DN_CL:
+ return " CL";
+ case DN_CN:
+ return " CN";
+ }
+
+ return "????";
+}
+
+static inline void dn_socket_format_entry(struct seq_file *seq, struct sock *sk)
+{
+ struct dn_scp *scp = DN_SK(sk);
char buf1[DN_ASCBUF_LEN];
char buf2[DN_ASCBUF_LEN];
char local_object[DN_MAXOBJL+3];
char remote_object[DN_MAXOBJL+3];
- int i;
- len += sprintf(buffer + len, "Local Remote\n");
+ dn_printable_object(&scp->addr, local_object);
+ dn_printable_object(&scp->peer, remote_object);
- read_lock(&dn_hash_lock);
- for(i = 0; i < DN_SK_HASH_SIZE; i++) {
- for(sk = dn_sk_hash[i]; sk != NULL; sk = sk->next) {
- scp = DN_SK(sk);
-
- dn_printable_object(&scp->addr, local_object);
- dn_printable_object(&scp->peer, remote_object);
-
- len += sprintf(buffer + len,
- "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
- dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
- scp->addrloc,
- scp->numdat,
- scp->numoth,
- scp->ackxmt_dat,
- scp->ackxmt_oth,
- scp->flowloc_sw,
- local_object,
- dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
- scp->addrrem,
- scp->numdat_rcv,
- scp->numoth_rcv,
- scp->ackrcv_dat,
- scp->ackrcv_oth,
- scp->flowrem_sw,
- remote_object,
- dn_state2asc(scp->state),
- ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
-
- pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > (offset + length))
- break;
- }
+ seq_printf(seq,
+ "%6s/%04X %04d:%04d %04d:%04d %01d %-16s "
+ "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
+ dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
+ scp->addrloc,
+ scp->numdat,
+ scp->numoth,
+ scp->ackxmt_dat,
+ scp->ackxmt_oth,
+ scp->flowloc_sw,
+ local_object,
+ dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
+ scp->addrrem,
+ scp->numdat_rcv,
+ scp->numoth_rcv,
+ scp->ackrcv_dat,
+ scp->ackrcv_oth,
+ scp->flowrem_sw,
+ remote_object,
+ dn_state2asc(scp->state),
+ ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
+}
+
+static int dn_socket_seq_show(struct seq_file *seq, void *v)
+{
+ if (v == (void*)1) {
+ seq_puts(seq, "Local Remote\n");
+ } else {
+ dn_socket_format_entry(seq, v);
}
- read_unlock(&dn_hash_lock);
+ return 0;
+}
- *start = buffer + (offset - begin);
- len -= (offset - begin);
+static struct seq_operations dn_socket_seq_ops = {
+ .start = dn_socket_seq_start,
+ .next = dn_socket_seq_next,
+ .stop = dn_socket_seq_stop,
+ .show = dn_socket_seq_show,
+};
- if (len > length)
- len = length;
+static int dn_socket_seq_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq;
+ int rc = -ENOMEM;
+ struct dn_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
- return len;
+ if (!s)
+ goto out;
+
+ rc = seq_open(file, &dn_socket_seq_ops);
+ if (rc)
+ goto out_kfree;
+
+ seq = file->private_data;
+ seq->private = s;
+ memset(s, 0, sizeof(*s));
+out:
+ return rc;
+out_kfree:
+ kfree(s);
+ goto out;
}
+static struct file_operations dn_socket_seq_fops = {
+ .open = dn_socket_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = kfree_release,
+};
+#endif
static struct net_proto_family dn_family_ops = {
.family = AF_DECnet,
@@ -2257,13 +2366,11 @@
void dn_register_sysctl(void);
void dn_unregister_sysctl(void);
-
MODULE_DESCRIPTION("The Linux DECnet Network Protocol");
MODULE_AUTHOR("Linux DECnet Project Team");
MODULE_LICENSE("GPL");
-
-static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.67s (C) 1995-2003 Linux DECnet Project Team\n";
+static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.68s (C) 1995-2003 Linux DECnet Project Team\n";
static int __init decnet_init(void)
{
@@ -2280,15 +2387,12 @@
dev_add_pack(&dn_dix_packet_type);
register_netdevice_notifier(&dn_dev_notifier);
- proc_net_create("decnet", 0, dn_get_info);
+ proc_net_fops_create("decnet", S_IRUGO, &dn_socket_seq_fops);
dn_neigh_init();
dn_dev_init();
dn_route_init();
-
-#ifdef CONFIG_DECNET_ROUTER
dn_fib_init();
-#endif /* CONFIG_DECNET_ROUTER */
dn_register_sysctl();
@@ -2315,10 +2419,7 @@
dn_route_cleanup();
dn_dev_cleanup();
dn_neigh_cleanup();
-
-#ifdef CONFIG_DECNET_ROUTER
dn_fib_cleanup();
-#endif /* CONFIG_DECNET_ROUTER */
proc_net_remove("decnet");
diff -Nru linux-2.5.68-bk10/net/decnet/dn_dev.c linux/net/decnet/dn_dev.c
--- linux-2.5.68-bk10/net/decnet/dn_dev.c Sun Apr 20 03:28:01 2003
+++ linux/net/decnet/dn_dev.c Thu May 1 03:47:27 2003
@@ -20,6 +20,8 @@
* Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding
* Steve Whitehouse : Removed timer1 - it's a user space issue now
* Patrick Caulfield : Fixed router hello message format
+ * Steve Whitehouse : Got rid of constant sizes for blksize for
+ * devices. All mtu based now.
*/
#include <linux/config.h>
@@ -28,6 +30,7 @@
#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/if_arp.h>
@@ -72,16 +75,13 @@
static int dn_eth_up(struct net_device *);
static void dn_eth_down(struct net_device *);
static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa);
-#if 0
static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa);
-#endif
static struct dn_dev_parms dn_dev_list[] = {
{
.type = ARPHRD_ETHER, /* Ethernet */
.mode = DN_DEV_BCAST,
.state = DN_DEV_S_RU,
- .blksize = 1498,
.t2 = 1,
.t3 = 10,
.name = "ethernet",
@@ -94,7 +94,6 @@
.type = ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
.mode = DN_DEV_BCAST,
.state = DN_DEV_S_RU,
- .blksize = 1400,
.t2 = 1,
.t3 = 10,
.name = "ipgre",
@@ -106,7 +105,6 @@
.type = ARPHRD_X25, /* Bog standard X.25 */
.mode = DN_DEV_UCAST,
.state = DN_DEV_S_DS,
- .blksize = 230,
.t2 = 1,
.t3 = 120,
.name = "x25",
@@ -119,7 +117,6 @@
.type = ARPHRD_PPP, /* DECnet over PPP */
.mode = DN_DEV_BCAST,
.state = DN_DEV_S_RU,
- .blksize = 230,
.t2 = 1,
.t3 = 10,
.name = "ppp",
@@ -127,24 +124,20 @@
.timer3 = dn_send_brd_hello,
},
#endif
-#if 0
{
.type = ARPHRD_DDCMP, /* DECnet over DDCMP */
.mode = DN_DEV_UCAST,
.state = DN_DEV_S_DS,
- .blksize = 230,
.t2 = 1,
.t3 = 120,
.name = "ddcmp",
.ctl_name = NET_DECNET_CONF_DDCMP,
.timer3 = dn_send_ptp_hello,
},
-#endif
{
.type = ARPHRD_LOOPBACK, /* Loopback interface - always last */
.mode = DN_DEV_BCAST,
.state = DN_DEV_S_RU,
- .blksize = 1498,
.t2 = 1,
.t3 = 10,
.name = "loopback",
@@ -254,6 +247,21 @@
}, {0}}
};
+static inline __u16 mtu2blksize(struct net_device *dev)
+{
+ u32 blksize = dev->mtu;
+ if (blksize > 0xffff)
+ blksize = 0xffff;
+
+ if (dev->type == ARPHRD_ETHER ||
+ dev->type == ARPHRD_PPP ||
+ dev->type == ARPHRD_IPGRE ||
+ dev->type == ARPHRD_LOOPBACK)
+ blksize -= 2;
+
+ return (__u16)blksize;
+}
+
static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms)
{
struct dn_dev_sysctl_table *t;
@@ -858,7 +866,7 @@
memcpy(msg->tiver, dn_eco_version, 3);
dn_dn2eth(msg->id, ifa->ifa_local);
msg->iinfo = DN_RT_INFO_ENDN;
- msg->blksize = dn_htons(dn_db->parms.blksize);
+ msg->blksize = dn_htons(mtu2blksize(dev));
msg->area = 0x00;
memset(msg->seed, 0, 8);
memcpy(msg->neighbor, dn_hiord, ETH_ALEN);
@@ -920,10 +928,10 @@
unsigned short *pktlen;
char *src;
- if (dn_db->parms.blksize < (26 + 7))
+ if (mtu2blksize(dev) < (26 + 7))
return;
- n = dn_db->parms.blksize - 26;
+ n = mtu2blksize(dev) - 26;
n /= 7;
if (n > 32)
@@ -946,7 +954,7 @@
ptr += ETH_ALEN;
*ptr++ = dn_db->parms.forwarding == 1 ?
DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
- *((unsigned short *)ptr) = dn_htons(dn_db->parms.blksize);
+ *((unsigned short *)ptr) = dn_htons(mtu2blksize(dev));
ptr += 2;
*ptr++ = dn_db->parms.priority; /* Priority */
*ptr++ = 0; /* Area: Reserved */
@@ -990,16 +998,13 @@
dn_send_router_hello(dev, ifa);
}
-#if 0
static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
{
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;
int i;
unsigned char *ptr;
- struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
char src[ETH_ALEN];
if (skb == NULL)
@@ -1020,7 +1025,6 @@
dn_dn2eth(src, ifa->ifa_local);
dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);
}
-#endif
static int dn_eth_up(struct net_device *dev)
{
@@ -1332,6 +1336,63 @@
#ifdef CONFIG_PROC_FS
+static inline struct net_device *dn_dev_get_next(struct seq_file *seq, struct net_device *dev)
+{
+ do {
+ dev = dev->next;
+ } while(dev && !dev->dn_ptr);
+
+ return dev;
+}
+
+static struct net_device *dn_dev_get_idx(struct seq_file *seq, loff_t pos)
+{
+ struct net_device *dev;
+
+ dev = dev_base;
+ if (dev && !dev->dn_ptr)
+ dev = dn_dev_get_next(seq, dev);
+ if (pos) {
+ while(dev && (dev = dn_dev_get_next(seq, dev)))
+ --pos;
+ }
+ return dev;
+}
+
+static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ if (*pos) {
+ struct net_device *dev;
+ read_lock(&dev_base_lock);
+ dev = dn_dev_get_idx(seq, *pos - 1);
+ if (dev == NULL)
+ read_unlock(&dev_base_lock);
+ return dev;
+ }
+ return (void*)1;
+}
+
+static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct net_device *dev = v;
+ loff_t one = 1;
+
+ if (v == (void*)1) {
+ dev = dn_dev_seq_start(seq, &one);
+ } else {
+ dev = dn_dev_get_next(seq, dev);
+ if (dev == NULL)
+ read_unlock(&dev_base_lock);
+ }
+ ++*pos;
+ return dev;
+}
+
+static void dn_dev_seq_stop(struct seq_file *seq, void *v)
+{
+ if (v && v != (void*)1)
+ read_unlock(&dev_base_lock);
+}
static char *dn_type2asc(char type)
{
@@ -1347,56 +1408,50 @@
return "?";
}
-static int decnet_dev_get_info(char *buffer, char **start, off_t offset, int length)
+static int dn_dev_seq_show(struct seq_file *seq, void *v)
{
- struct dn_dev *dn_db;
- struct net_device *dev;
- int len = 0;
- off_t pos = 0;
- off_t begin = 0;
- char peer_buf[DN_ASCBUF_LEN];
- char router_buf[DN_ASCBUF_LEN];
-
+ if (v == (void*)1)
+ seq_puts(seq, "Name Flags T1 Timer1 T3 Timer3 BlkSize Pri State DevType Router Peer\n");
+ else {
+ struct net_device *dev = v;
+ char peer_buf[DN_ASCBUF_LEN];
+ char router_buf[DN_ASCBUF_LEN];
+ struct dn_dev *dn_db = dev->dn_ptr;
- len += sprintf(buffer, "Name Flags T1 Timer1 T3 Timer3 BlkSize Pri State DevType Router Peer\n");
-
- read_lock(&dev_base_lock);
- for (dev = dev_base; dev; dev = dev->next) {
- if ((dn_db = (struct dn_dev *)dev->dn_ptr) == NULL)
- continue;
-
- len += sprintf(buffer + len, "%-8s %1s %04u %04u %04lu %04lu %04hu %03d %02x %-10s %-7s %-7s\n",
+ seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu"
+ " %04hu %03d %02x %-10s %-7s %-7s\n",
dev->name ? dev->name : "???",
dn_type2asc(dn_db->parms.mode),
0, 0,
dn_db->t3, dn_db->parms.t3,
- dn_db->parms.blksize,
+ mtu2blksize(dev),
dn_db->parms.priority,
dn_db->parms.state, dn_db->parms.name,
dn_db->router ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->router->primary_key), router_buf) : "",
dn_db->peer ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->peer->primary_key), peer_buf) : "");
+ }
+ return 0;
+}
+static struct seq_operations dn_dev_seq_ops = {
+ .start = dn_dev_seq_start,
+ .next = dn_dev_seq_next,
+ .stop = dn_dev_seq_stop,
+ .show = dn_dev_seq_show,
+};
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- break;
- }
-
- read_unlock(&dev_base_lock);
-
- *start = buffer + (offset - begin);
- len -= (offset - begin);
-
- if (len > length) len = length;
-
- return(len);
+static int dn_dev_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &dn_dev_seq_ops);
}
+static struct file_operations dn_dev_seq_fops = {
+ .open = dn_dev_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
#endif /* CONFIG_PROC_FS */
static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
@@ -1448,9 +1503,7 @@
rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table;
-#ifdef CONFIG_PROC_FS
- proc_net_create("decnet_dev", 0, decnet_dev_get_info);
-#endif /* CONFIG_PROC_FS */
+ proc_net_fops_create("decnet_dev", S_IRUGO, &dn_dev_seq_fops);
#ifdef CONFIG_SYSCTL
{
diff -Nru linux-2.5.68-bk10/net/decnet/dn_fib.c linux/net/decnet/dn_fib.c
--- linux-2.5.68-bk10/net/decnet/dn_fib.c Sun Apr 20 03:28:01 2003
+++ linux/net/decnet/dn_fib.c Mon Apr 28 10:21:48 2003
@@ -67,18 +67,18 @@
int error;
u8 scope;
} dn_fib_props[RTA_MAX+1] = {
- { .error = 0, .scope = RT_SCOPE_NOWHERE }, /* RTN_UNSPEC */
- { .error = 0, .scope = RT_SCOPE_UNIVERSE }, /* RTN_UNICAST */
- { .error = 0, .scope = RT_SCOPE_HOST }, /* RTN_LOCAL */
- { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, /* RTN_BROADCAST */
- { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, /* RTN_ANYCAST */
- { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, /* RTN_MULTICAST */
- { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE }, /* RTN_BLACKHOLE */
- { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE }, /* RTN_UNREACHABLE */
- { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE }, /* RTN_PROHIBIT */
- { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE }, /* RTN_THROW */
- { .error = 0, .scope = RT_SCOPE_NOWHERE }, /* RTN_NAT */
- { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE } /* RTN_XRESOLVE */
+ [RTN_UNSPEC] = { .error = 0, .scope = RT_SCOPE_NOWHERE },
+ [RTN_UNICAST] = { .error = 0, .scope = RT_SCOPE_UNIVERSE },
+ [RTN_LOCAL] = { .error = 0, .scope = RT_SCOPE_HOST },
+ [RTN_BROADCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
+ [RTN_ANYCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
+ [RTN_MULTICAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
+ [RTN_BLACKHOLE] = { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE },
+ [RTN_UNREACHABLE] = { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE },
+ [RTN_PROHIBIT] = { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE },
+ [RTN_THROW] = { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE },
+ [RTN_NAT] = { .error = 0, .scope = RT_SCOPE_NOWHERE },
+ [RTN_XRESOLVE] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
};
void dn_fib_free_info(struct dn_fib_info *fi)
@@ -792,53 +792,12 @@
dn_rt_cache_flush(-1);
}
-#ifdef CONFIG_PROC_FS
-
-static int decnet_rt_get_info(char *buffer, char **start, off_t offset, int length)
-{
- int first = offset / 128;
- char *ptr = buffer;
- int count = (length + 127) / 128;
- int len;
- int i;
- struct dn_fib_table *tb;
-
- *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;
- }
-
-
- for(i = RT_MIN_TABLE; (i <= RT_TABLE_MAX) && (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;
- }
- }
-
- len = ptr - *start;
- if (len >= length)
- return length;
- if (len >= 0)
- return len;
-
- return 0;
-}
-#endif /* CONFIG_PROC_FS */
-
static struct notifier_block dn_fib_dnaddr_notifier = {
.notifier_call = dn_fib_dnaddr_event,
};
void __exit dn_fib_cleanup(void)
{
- proc_net_remove("decnet_route");
-
dn_fib_table_cleanup();
dn_fib_rules_cleanup();
@@ -848,10 +807,6 @@
void __init dn_fib_init(void)
{
-
-#ifdef CONFIG_PROC_FS
- proc_net_create("decnet_route", 0, decnet_rt_get_info);
-#endif
dn_fib_table_init();
dn_fib_rules_init();
diff -Nru linux-2.5.68-bk10/net/decnet/dn_neigh.c linux/net/decnet/dn_neigh.c
--- linux-2.5.68-bk10/net/decnet/dn_neigh.c Sun Apr 20 03:28:01 2003
+++ linux/net/decnet/dn_neigh.c Wed Apr 23 13:37:47 2003
@@ -202,7 +202,7 @@
struct net_device *dev = neigh->dev;
char mac_addr[ETH_ALEN];
- dn_dn2eth(mac_addr, rt->rt_saddr);
+ dn_dn2eth(mac_addr, rt->rt_local_src);
if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, mac_addr, skb->len) >= 0)
return neigh->ops->queue_xmit(skb);
@@ -692,48 +692,23 @@
goto out;
}
-static int dn_seq_release(struct inode *inode, struct file *file)
-{
- struct seq_file *seq = (struct seq_file *)file->private_data;
-
- kfree(seq->private);
- seq->private = NULL;
- return seq_release(inode, file);
-}
-
static struct file_operations dn_neigh_seq_fops = {
.open = dn_neigh_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = dn_seq_release,
+ .release = kfree_release,
};
-static int __init dn_neigh_proc_init(void)
-{
- int rc = 0;
- struct proc_dir_entry *p = create_proc_entry("decnet_neigh", S_IRUGO, proc_net);
- if (p)
- p->proc_fops = &dn_neigh_seq_fops;
- else
- rc = -ENOMEM;
- return rc;
-}
-
-#else
-static int __init dn_neigh_proc_init(void)
-{
- return 0;
-}
#endif
void __init dn_neigh_init(void)
{
neigh_table_init(&dn_neigh_table);
-
- dn_neigh_proc_init();
+ proc_net_fops_create("decnet_neigh", S_IRUGO, &dn_neigh_seq_fops);
}
void __exit dn_neigh_cleanup(void)
{
+ proc_net_remove("decnet_neigh");
neigh_table_clear(&dn_neigh_table);
}
diff -Nru linux-2.5.68-bk10/net/decnet/dn_nsp_in.c linux/net/decnet/dn_nsp_in.c
--- linux-2.5.68-bk10/net/decnet/dn_nsp_in.c Sun Apr 20 03:28:01 2003
+++ linux/net/decnet/dn_nsp_in.c Thu May 1 05:46:52 2003
@@ -28,6 +28,7 @@
* Steve Whitehouse: Added backlog congestion level return codes.
* Patrick Caulfield:
* Steve Whitehouse: Added flow control support (outbound)
+ * Steve Whitehouse: Prepare for nonlinear skbs
*/
/******************************************************************************
@@ -240,7 +241,7 @@
cb->info = msg->info;
cb->segsize = dn_ntohs(msg->segsize);
- if (skb->len < sizeof(*msg))
+ if (!pskb_may_pull(skb, sizeof(*msg)))
goto err_out;
skb_pull(skb, sizeof(*msg));
@@ -721,34 +722,19 @@
unsigned char *ptr = (unsigned char *)skb->data;
unsigned short reason = NSP_REASON_NL;
+ if (!pskb_may_pull(skb, 2))
+ goto free_out;
+
skb->h.raw = skb->data;
cb->nsp_flags = *ptr++;
if (decnet_debug_level & 2)
printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags);
- if (skb->len < 2)
- goto free_out;
-
if (cb->nsp_flags & 0x83)
goto free_out;
/*
- * Returned packets...
- * Swap src & dst and look up in the normal way.
- */
- if (cb->rt_flags & DN_RT_F_RTS) {
- unsigned short tmp = cb->dst_port;
- cb->dst_port = cb->src_port;
- cb->src_port = tmp;
- tmp = cb->dst;
- cb->dst = cb->src;
- cb->src = tmp;
- sk = dn_find_by_skb(skb);
- goto got_it;
- }
-
- /*
* Filter out conninits and useless packet types
*/
if ((cb->nsp_flags & 0x0c) == 0x08) {
@@ -759,12 +745,14 @@
goto free_out;
case 0x10:
case 0x60:
+ if (unlikely(cb->rt_flags & DN_RT_F_RTS))
+ goto free_out;
sk = dn_find_listener(skb, &reason);
goto got_it;
}
}
- if (skb->len < 3)
+ if (!pskb_may_pull(skb, 3))
goto free_out;
/*
@@ -777,13 +765,26 @@
/*
* If not a connack, grab the source address too.
*/
- if (skb->len >= 5) {
+ if (pskb_may_pull(skb, 5)) {
cb->src_port = *(unsigned short *)ptr;
ptr += 2;
skb_pull(skb, 5);
}
/*
+ * Returned packets...
+ * Swap src & dst and look up in the normal way.
+ */
+ if (unlikely(cb->rt_flags & DN_RT_F_RTS)) {
+ unsigned short tmp = cb->dst_port;
+ cb->dst_port = cb->src_port;
+ cb->src_port = tmp;
+ tmp = cb->dst;
+ cb->dst = cb->src;
+ cb->src = tmp;
+ }
+
+ /*
* Find the socket to which this skb is destined.
*/
sk = dn_find_by_skb(skb);
@@ -795,6 +796,15 @@
/* Reset backoff */
scp->nsp_rxtshift = 0;
+ /*
+ * We linearize everything except data segments here.
+ */
+ if (cb->nsp_flags & ~0x60) {
+ if (unlikely(skb_is_nonlinear(skb)) &&
+ skb_linearize(skb, GFP_ATOMIC) != 0)
+ goto free_out;
+ }
+
bh_lock_sock(sk);
ret = NET_RX_SUCCESS;
if (decnet_debug_level & 8)
@@ -835,7 +845,10 @@
struct dn_skb_cb *cb = DN_SKB_CB(skb);
if (cb->rt_flags & DN_RT_F_RTS) {
- dn_returned_conn_init(sk, skb);
+ if (cb->nsp_flags == 0x18 || cb->nsp_flags == 0x68)
+ dn_returned_conn_init(sk, skb);
+ else
+ kfree_skb(skb);
return NET_RX_SUCCESS;
}
diff -Nru linux-2.5.68-bk10/net/decnet/dn_nsp_out.c linux/net/decnet/dn_nsp_out.c
--- linux-2.5.68-bk10/net/decnet/dn_nsp_out.c Thu May 1 03:00:23 2003
+++ linux/net/decnet/dn_nsp_out.c Thu May 1 03:00:49 2003
@@ -96,6 +96,7 @@
fl.fld_src = dn_saddr2dn(&scp->addr);
fl.fld_dst = dn_saddr2dn(&scp->peer);
dn_sk_ports_copy(&fl, scp);
+ fl.proto = DNPROTO_NSP;
if (dn_route_output_sock(&sk->dst_cache, &fl, sk, 0) == 0) {
dst = sk_dst_get(sk);
sk->route_caps = dst->dev->features;
@@ -349,8 +350,7 @@
{
unsigned char *ptr = skb_push(skb, len);
- if (len < 5)
- BUG();
+ BUG_ON(len < 5);
*ptr++ = msgflag;
*((unsigned short *)ptr) = scp->addrrem;
@@ -367,8 +367,7 @@
unsigned short ackcrs = scp->numoth_rcv & 0x0FFF;
unsigned short *ptr;
- if (hlen < 9)
- BUG();
+ BUG_ON(hlen < 9);
scp->ackxmt_dat = acknum;
scp->ackxmt_oth = ackcrs;
@@ -485,8 +484,8 @@
* We don't expect to see acknowledgements for packets we
* haven't sent yet.
*/
- if (xmit_count == 0)
- BUG();
+ WARN_ON(xmit_count == 0);
+
/*
* If the packet has only been sent once, we can use it
* to calculate the RTT and also open the window a little
diff -Nru linux-2.5.68-bk10/net/decnet/dn_route.c linux/net/decnet/dn_route.c
--- linux-2.5.68-bk10/net/decnet/dn_route.c Thu May 1 03:00:23 2003
+++ linux/net/decnet/dn_route.c Thu May 1 05:21:11 2003
@@ -39,6 +39,7 @@
* no ref count on net devices.
* Steve Whitehouse : RCU for the route cache
* Steve Whitehouse : Preparations for the flow cache
+ * Steve Whitehouse : Prepare for nonlinear skbs
*/
/******************************************************************************
@@ -70,6 +71,7 @@
#include <net/sock.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/rtnetlink.h>
#include <linux/string.h>
@@ -97,14 +99,17 @@
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;
+int dn_rt_min_delay = 2 * HZ;
+int dn_rt_max_delay = 10 * HZ;
+int dn_rt_mtu_expires = 10 * 60 * HZ;
+
+static unsigned long dn_rt_deadline;
static int dn_dst_gc(void);
static struct dst_entry *dn_dst_check(struct dst_entry *, __u32);
static struct dst_entry *dn_dst_negative_advice(struct dst_entry *);
static void dn_dst_link_failure(struct sk_buff *);
+static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu);
static int dn_route_input(struct sk_buff *);
static void dn_run_flush(unsigned long dummy);
@@ -124,6 +129,7 @@
.check = dn_dst_check,
.negative_advice = dn_dst_negative_advice,
.link_failure = dn_dst_link_failure,
+ .update_pmtu = dn_dst_update_pmtu,
.entry_size = sizeof(struct dn_route),
.entries = ATOMIC_INIT(0),
};
@@ -210,16 +216,49 @@
return 0;
}
+/*
+ * The decnet standards don't impose a particular minimum mtu, what they
+ * do insist on is that the routing layer accepts a datagram of at least
+ * 230 bytes long. Here we have to subtract the routing header length from
+ * 230 to get the minimum acceptable mtu. If there is no neighbour, then we
+ * assume the worst and use a long header size.
+ *
+ * We update both the mtu and the advertised mss (i.e. the segment size we
+ * advertise to the other end).
+ */
+static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu)
+{
+ u32 min_mtu = 230;
+ struct dn_dev *dn = dst->neighbour ?
+ (struct dn_dev *)dst->neighbour->dev->dn_ptr : NULL;
+
+ if (dn && dn->use_long == 0)
+ min_mtu -= 6;
+ else
+ min_mtu -= 21;
+
+ if (dst->metrics[RTAX_MTU-1] > mtu && mtu >= min_mtu) {
+ if (!(dst_metric_locked(dst, RTAX_MTU))) {
+ dst->metrics[RTAX_MTU-1] = mtu;
+ dst_set_expires(dst, dn_rt_mtu_expires);
+ }
+ if (!(dst_metric_locked(dst, RTAX_ADVMSS))) {
+ u32 mss = mtu - DN_MAX_NSP_DATA_HEADER;
+ if (dst->metrics[RTAX_ADVMSS-1] > mss)
+ dst->metrics[RTAX_ADVMSS-1] = mss;
+ }
+ }
+}
+
+/*
+ * When a route has been marked obsolete. (e.g. routing cache flush)
+ */
static struct dst_entry *dn_dst_check(struct dst_entry *dst, __u32 cookie)
{
dst_release(dst);
return NULL;
}
-/*
- * This is called through sendmsg() when you specify MSG_TRYHARD
- * and there is already a route in cache.
- */
static struct dst_entry *dn_dst_negative_advice(struct dst_entry *dst)
{
dst_release(dst);
@@ -467,7 +506,7 @@
struct dn_skb_cb *cb = DN_SKB_CB(skb);
unsigned char *ptr = skb->data;
- if (skb->len < 21) /* 20 for long header, 1 for shortest nsp */
+ if (!pskb_may_pull(skb, 21)) /* 20 for long header, 1 for shortest nsp */
goto drop_it;
skb_pull(skb, 20);
@@ -505,7 +544,7 @@
struct dn_skb_cb *cb = DN_SKB_CB(skb);
unsigned char *ptr = skb->data;
- if (skb->len < 6) /* 5 for short header + 1 for shortest nsp */
+ if (!pskb_may_pull(skb, 6)) /* 5 for short header + 1 for shortest nsp */
goto drop_it;
skb_pull(skb, 5);
@@ -555,6 +594,9 @@
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
goto out;
+ if (!pskb_may_pull(skb, 3))
+ goto dump_it;
+
skb_pull(skb, 2);
if (len > skb->len)
@@ -573,6 +615,8 @@
*/
if (flags & DN_RT_F_PF) {
padlen = flags & ~DN_RT_F_PF;
+ if (!pskb_may_pull(skb, padlen + 1))
+ goto dump_it;
skb_pull(skb, padlen);
flags = *skb->data;
}
@@ -594,6 +638,10 @@
padlen);
if (flags & DN_RT_PKT_CNTL) {
+ if (unlikely(skb_is_nonlinear(skb)) &&
+ skb_linearize(skb, GFP_ATOMIC) != 0)
+ goto dump_it;
+
switch(flags & DN_RT_CNTL_MSK) {
case DN_RT_PKT_INIT:
dn_dev_init_pkt(skb);
@@ -712,7 +760,7 @@
* packets, so we don't need to test for them here.
*/
cb->rt_flags &= ~DN_RT_F_IE;
- if (rt->rt_flags | RTCF_DOREDIRECT)
+ if (rt->rt_flags & RTCF_DOREDIRECT)
cb->rt_flags |= DN_RT_F_IE;
return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output);
@@ -788,8 +836,10 @@
{
__u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2);
int match = 16;
- while(tmp)
- tmp >>= 1, match--;
+ while(tmp) {
+ tmp >>= 1;
+ match--;
+ }
return match;
}
@@ -899,17 +949,19 @@
/* No destination? Assume its local */
if (!fl.fld_dst) {
fl.fld_dst = fl.fld_src;
-#if 0
- if (!fl.fld_dst)
- /* grab an address from loopback? */
-#endif
+
err = -EADDRNOTAVAIL;
if (dev_out)
dev_put(dev_out);
- if (!fl.fld_dst)
- goto out;
dev_out = &loopback_dev;
dev_hold(dev_out);
+ if (!fl.fld_dst) {
+ fl.fld_dst =
+ fl.fld_src = dnet_select_source(dev_out, 0,
+ RT_SCOPE_HOST);
+ if (!fl.fld_dst)
+ goto out;
+ }
fl.oif = loopback_dev.ifindex;
res.type = RTN_LOCAL;
goto make_route;
@@ -1055,12 +1107,13 @@
rt->fl.oif = oldflp->oif;
rt->fl.iif = 0;
#ifdef CONFIG_DECNET_ROUTE_FWMARK
- rt->fl.fld_fwmark = flp->fld_fwmark;
+ rt->fl.fld_fwmark = oldflp->fld_fwmark;
#endif
rt->rt_saddr = fl.fld_src;
rt->rt_daddr = fl.fld_dst;
rt->rt_gateway = gateway ? gateway : fl.fld_dst;
+ rt->rt_local_src = fl.fld_src;
rt->rt_dst_map = fl.fld_dst;
rt->rt_src_map = fl.fld_src;
@@ -1075,14 +1128,14 @@
rt->u.dst.input = dn_rt_bug;
rt->rt_flags = flags;
if (flags & RTCF_LOCAL)
- rt->u.dst.output = dn_nsp_rx;
+ rt->u.dst.input = dn_nsp_rx;
- if (dn_rt_set_next_hop(rt, &res))
+ err = dn_rt_set_next_hop(rt, &res);
+ if (err)
goto e_neighbour;
hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
dn_insert_route(rt, hash, (struct dn_route **)pprt);
- err = 0;
done:
if (neigh)
@@ -1175,12 +1228,13 @@
unsigned hash;
int flags = 0;
__u16 gateway = 0;
+ __u16 local_src = 0;
struct flowi fl = { .nl_u = { .dn_u =
{ .daddr = cb->dst,
.saddr = cb->src,
.scope = RT_SCOPE_UNIVERSE,
#ifdef CONFIG_DECNET_ROUTE_FWMARK
- .fwmark = skb->fwmark
+ .fwmark = skb->nfmark
#endif
} },
.iif = skb->dev->ifindex };
@@ -1275,6 +1329,8 @@
if (out_dev == in_dev && !(flags & RTCF_NAT))
flags |= RTCF_DOREDIRECT;
+ local_src = DN_FIB_RES_PREFSRC(res);
+
case RTN_BLACKHOLE:
case RTN_UNREACHABLE:
break;
@@ -1319,6 +1375,8 @@
rt->rt_gateway = fl.fld_dst;
if (gateway)
rt->rt_gateway = gateway;
+ rt->rt_local_src = local_src ? local_src : rt->rt_saddr;
+
rt->rt_dst_map = fl.fld_dst;
rt->rt_src_map = fl.fld_src;
@@ -1352,12 +1410,12 @@
if (rt->u.dst.dev)
dev_hold(rt->u.dst.dev);
- if (dn_rt_set_next_hop(rt, &res))
+ err = dn_rt_set_next_hop(rt, &res);
+ if (err)
goto e_neighbour;
hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
dn_insert_route(rt, hash, (struct dn_route **)&skb->dst);
- err = 0;
done:
if (neigh)
@@ -1449,7 +1507,7 @@
* they deal only with inputs and not with replies like they do
* currently.
*/
- RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_saddr);
+ RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src);
if (rt->rt_daddr != rt->rt_gateway)
RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway);
if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
@@ -1490,6 +1548,7 @@
struct flowi fl;
memset(&fl, 0, sizeof(fl));
+ fl.proto = DNPROTO_NSP;
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (skb == NULL)
@@ -1609,54 +1668,114 @@
}
#ifdef CONFIG_PROC_FS
+struct dn_rt_cache_iter_state {
+ int bucket;
+};
-static int decnet_cache_get_info(char *buffer, char **start, off_t offset, int length)
+static struct dn_route *dn_rt_cache_get_first(struct seq_file *seq)
{
- int len = 0;
- off_t pos = 0;
- off_t begin = 0;
- struct dn_route *rt;
- int i;
- char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];
+ struct dn_route *rt = NULL;
+ struct dn_rt_cache_iter_state *s = seq->private;
- for(i = 0; i <= dn_rt_hash_mask; i++) {
+ for(s->bucket = dn_rt_hash_mask; s->bucket >= 0; --s->bucket) {
rcu_read_lock();
- rt = dn_rt_hash_table[i].chain;
- for(; rt != NULL; rt = rt->u.rt_next) {
- read_barrier_depends();
- len += sprintf(buffer + len, "%-8s %-7s %-7s %04d %04d %04d\n",
- rt->u.dst.dev ? rt->u.dst.dev->name : "*",
- dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1),
- dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2),
- atomic_read(&rt->u.dst.__refcnt),
- rt->u.dst.__use,
- (int) dst_metric(&rt->u.dst, RTAX_RTT)
- );
-
+ rt = dn_rt_hash_table[s->bucket].chain;
+ if (rt)
+ break;
+ rcu_read_unlock();
+ }
+ return rt;
+}
+static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_route *rt)
+{
+ struct dn_rt_cache_iter_state *s = seq->private;
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- break;
- }
+ smp_read_barrier_depends();
+ rt = rt->u.rt_next;
+ while(!rt) {
rcu_read_unlock();
- if (pos > offset + length)
+ if (--s->bucket < 0)
break;
+ rcu_read_lock();
+ rt = dn_rt_hash_table[s->bucket].chain;
}
+ return rt;
+}
+
+static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ struct dn_route *rt = dn_rt_cache_get_first(seq);
+
+ if (rt) {
+ while(*pos && (rt = dn_rt_cache_get_next(seq, rt)))
+ --*pos;
+ }
+ return *pos ? NULL : rt;
+}
+
+static void *dn_rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct dn_route *rt = dn_rt_cache_get_next(seq, v);
+ ++*pos;
+ return rt;
+}
- *start = buffer + (offset - begin);
- len -= (offset - begin);
+static void dn_rt_cache_seq_stop(struct seq_file *seq, void *v)
+{
+ rcu_read_unlock();
+}
- if (len > length) len = length;
+static int dn_rt_cache_seq_show(struct seq_file *seq, void *v)
+{
+ struct dn_route *rt = v;
+ char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];
- return(len);
+ seq_printf(seq, "%-8s %-7s %-7s %04d %04d %04d\n",
+ rt->u.dst.dev ? rt->u.dst.dev->name : "*",
+ dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1),
+ dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2),
+ atomic_read(&rt->u.dst.__refcnt),
+ rt->u.dst.__use,
+ (int) dst_metric(&rt->u.dst, RTAX_RTT));
+ return 0;
}
+static struct seq_operations dn_rt_cache_seq_ops = {
+ .start = dn_rt_cache_seq_start,
+ .next = dn_rt_cache_seq_next,
+ .stop = dn_rt_cache_seq_stop,
+ .show = dn_rt_cache_seq_show,
+};
+
+static int dn_rt_cache_seq_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq;
+ int rc = -ENOMEM;
+ struct dn_rt_cache_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+ if (!s)
+ goto out;
+ rc = seq_open(file, &dn_rt_cache_seq_ops);
+ if (rc)
+ goto out_kfree;
+ seq = file->private_data;
+ seq->private = s;
+ memset(s, 0, sizeof(*s));
+out:
+ return rc;
+out_kfree:
+ kfree(s);
+ goto out;
+}
+
+static struct file_operations dn_rt_cache_seq_fops = {
+ .open = dn_rt_cache_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = kfree_release,
+};
+
#endif /* CONFIG_PROC_FS */
void __init dn_route_init(void)
@@ -1714,9 +1833,7 @@
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 */
+ proc_net_fops_create("decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops);
}
void __exit dn_route_cleanup(void)
diff -Nru linux-2.5.68-bk10/net/decnet/dn_table.c linux/net/decnet/dn_table.c
--- linux-2.5.68-bk10/net/decnet/dn_table.c Sun Apr 20 03:28:01 2003
+++ linux/net/decnet/dn_table.c Wed Apr 23 09:43:16 2003
@@ -744,86 +744,6 @@
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->dn_fib_dev ? fi->dn_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)
{
@@ -855,9 +775,6 @@
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
t->dump = dn_fib_table_dump;
memset(t->data, 0, sizeof(struct dn_hash));
dn_fib_tables[n] = t;
Hi,
>
> On Thu, May 01, 2003 at 09:52:01PM +0100, Steven Whitehouse wrote:
> > --- linux-2.5.68-bk10/fs/seq_file.c Sun Apr 20 03:27:58 2003
> > +++ linux/fs/seq_file.c Mon Apr 21 14:40:35 2003
> > @@ -338,3 +338,13 @@
> > kfree(op);
> > return res;
> > }
> > +
> > +int kfree_release(struct inode *inode, struct file *file)
> > +{
> > + struct seq_file *seq = file->private_data;
> > +
> > + kfree(seq->private);
> > + seq->private = NULL;
> > + return seq_release(inode, file);
> > +}
>
> The name is a bit generic for an export function. What about
> seq_release_kfree?
>
Yes, I'd considered that and eventually settled for the non-prefixed version
since it followed the pattern set by single_release() which doesn't have
the seq_ prefix. I don't mind changing it though if the prefixed version is
preferred,
Steve.
From: Steven Whitehouse <[email protected]>
Date: Thu, 1 May 2003 22:35:46 +0100 (BST)
> The name is a bit generic for an export function. What about
> seq_release_kfree?
Yes, I'd considered that and eventually settled for the non-prefixed version
since it followed the pattern set by single_release() which doesn't have
the seq_ prefix. I don't mind changing it though if the prefixed version is
preferred,
I think a naming convention without a prefix is asking for
trouble. I'd ask that you add the prefix, the current convention
is troublesome and someone ought to clean that up.
Em Thu, May 01, 2003 at 02:22:35PM -0700, David S. Miller escreveu:
> From: Steven Whitehouse <[email protected]>
> Date: Thu, 1 May 2003 22:35:46 +0100 (BST)
> > The name is a bit generic for an export function. What about
> > seq_release_kfree?
> Yes, I'd considered that and eventually settled for the non-prefixed
> version since it followed the pattern set by single_release() which
> doesn't have the seq_ prefix. I don't mind changing it though if the
> prefixed version is preferred,
> I think a naming convention without a prefix is asking for
> trouble. I'd ask that you add the prefix, the current convention
> is troublesome and someone ought to clean that up.
Agreed, I also tought of adding it as a generic function, that is the spirit
of ip_seq_release, that is already used several net/ipv4 seq_file routines
and should be deleted in favour of seq_release_private, that is my preferred
name, as it is more general.
- Arnaldo
Hi,
Now that I'm back again, here is the first patch again with kfree_release
renamed as suggested to seq_release_private,
Steve.
-----------------------------------------------------------------------------
diff -Nru linux-2.5.68-bk12/fs/seq_file.c linux/fs/seq_file.c
--- linux-2.5.68-bk12/fs/seq_file.c Sat Apr 19 19:50:30 2003
+++ linux/fs/seq_file.c Sun May 4 11:45:16 2003
@@ -338,3 +338,13 @@
kfree(op);
return res;
}
+
+int seq_release_private(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+
+ kfree(seq->private);
+ seq->private = NULL;
+ return seq_release(inode, file);
+}
+
diff -Nru linux-2.5.68-bk12/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- linux-2.5.68-bk12/include/linux/proc_fs.h Sat Apr 19 19:48:46 2003
+++ linux/include/linux/proc_fs.h Sun May 4 11:45:16 2003
@@ -163,6 +163,15 @@
return create_proc_info_entry(name,mode,proc_net,get_info);
}
+static inline struct proc_dir_entry *proc_net_fops_create(const char *name,
+ mode_t mode, struct file_operations *fops)
+{
+ struct proc_dir_entry *res = create_proc_entry(name, mode, proc_net);
+ if (res)
+ res->proc_fops = fops;
+ return res;
+}
+
static inline void proc_net_remove(const char *name)
{
remove_proc_entry(name,proc_net);
@@ -171,7 +180,7 @@
#else
#define proc_root_driver NULL
-
+#define proc_net_fops_create(name,mode,fops) do {} while(0)
static inline struct proc_dir_entry *proc_net_create(const char *name, mode_t mode,
get_info_t *get_info) {return NULL;}
static inline void proc_net_remove(const char *name) {}
diff -Nru linux-2.5.68-bk12/include/linux/seq_file.h linux/include/linux/seq_file.h
--- linux-2.5.68-bk12/include/linux/seq_file.h Sat Apr 19 19:51:18 2003
+++ linux/include/linux/seq_file.h Sun May 4 11:45:16 2003
@@ -60,5 +60,6 @@
int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
int single_release(struct inode *, struct file *);
+int seq_release_private(struct inode *, struct file *);
#endif
#endif
diff -Nru linux-2.5.68-bk12/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.5.68-bk12/kernel/ksyms.c Sun May 4 11:37:41 2003
+++ linux/kernel/ksyms.c Sun May 4 11:45:16 2003
@@ -540,6 +540,7 @@
EXPORT_SYMBOL(seq_lseek);
EXPORT_SYMBOL(single_open);
EXPORT_SYMBOL(single_release);
+EXPORT_SYMBOL(seq_release_private);
/* Program loader interfaces */
#ifdef CONFIG_MMU
From: Steven Whitehouse <[email protected]>
Date: Sun, 4 May 2003 19:43:51 +0100 (BST)
Now that I'm back again, here is the first patch again with
kfree_release renamed as suggested to seq_release_private,
Since there have been no objections I'll apply this and
your decnet patch that makes use of the new interfaces.
Thanks.