Re: Remains of seq_file conversion for DECnet, plus fixes (part 2)

Steven Whitehouse (steve@gw.chygwyn.com)
Thu, 1 May 2003 21:55:51 +0100 (BST)


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;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/