Commit 6a83d262 authored by Steven Whitehouse's avatar Steven Whitehouse Committed by David S. Miller

[DECNET]: seq file conversions and fixes.

  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
parent acec7ca3
...@@ -71,7 +71,6 @@ struct dn_dev_parms { ...@@ -71,7 +71,6 @@ struct dn_dev_parms {
#define DN_DEV_MPOINT 4 #define DN_DEV_MPOINT 4
int state; /* Initial state */ int state; /* Initial state */
int forwarding; /* 0=EndNode, 1=L1Router, 2=L2Router */ int forwarding; /* 0=EndNode, 1=L1Router, 2=L2Router */
unsigned short blksize; /* Block Size */
unsigned long t2; /* Default value of t2 */ unsigned long t2; /* Default value of t2 */
unsigned long t3; /* Default value of t3 */ unsigned long t3; /* Default value of t3 */
int priority; /* Priority to be a router */ int priority; /* Priority to be a router */
......
...@@ -101,10 +101,6 @@ struct dn_fib_table { ...@@ -101,10 +101,6 @@ struct dn_fib_table {
int (*lookup)(struct dn_fib_table *t, const struct flowi *fl, int (*lookup)(struct dn_fib_table *t, const struct flowi *fl,
struct dn_fib_res *res); struct dn_fib_res *res);
int (*flush)(struct dn_fib_table *t); 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); int (*dump)(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb);
unsigned char data[0]; unsigned char data[0];
...@@ -184,6 +180,9 @@ extern struct dn_fib_table *dn_fib_tables[]; ...@@ -184,6 +180,9 @@ extern struct dn_fib_table *dn_fib_tables[];
#else /* Endnode */ #else /* Endnode */
#define dn_fib_init() (0)
#define dn_fib_cleanup() (0)
#define dn_fib_lookup(fl, res) (-ESRCH) #define dn_fib_lookup(fl, res) (-ESRCH)
#define dn_fib_info_put(fi) do { } while(0) #define dn_fib_info_put(fi) do { } while(0)
#define dn_fib_select_multipath(fl, res) do { } while(0) #define dn_fib_select_multipath(fl, res) do { } while(0)
......
...@@ -74,7 +74,7 @@ struct dn_route { ...@@ -74,7 +74,7 @@ struct dn_route {
__u16 rt_saddr; __u16 rt_saddr;
__u16 rt_daddr; __u16 rt_daddr;
__u16 rt_gateway; __u16 rt_gateway;
__u16 __padding; __u16 rt_local_src; /* Source used for forwarding packets */
__u16 rt_src_map; __u16 rt_src_map;
__u16 rt_dst_map; __u16 rt_dst_map;
......
...@@ -23,15 +23,9 @@ Steve's quick list of things that need finishing off: ...@@ -23,15 +23,9 @@ Steve's quick list of things that need finishing off:
o check MSG_CTRUNC is set where it should be. 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 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] 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 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 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 the full scheme is still worth implementing, its not not top of my list
...@@ -45,5 +39,3 @@ Steve's quick list of things that need finishing off: ...@@ -45,5 +39,3 @@ Steve's quick list of things that need finishing off:
o AIO for DECnet o AIO for DECnet
o Eliminate dn_db->parms.blksize
...@@ -116,6 +116,7 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat ...@@ -116,6 +116,7 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/route.h> #include <linux/route.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/seq_file.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/flow.h> #include <net/flow.h>
...@@ -676,45 +677,6 @@ char *dn_addr2asc(dn_address addr, char *buf) ...@@ -676,45 +677,6 @@ char *dn_addr2asc(dn_address addr, char *buf)
} }
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) static int dn_create(struct socket *sock, int protocol)
{ {
...@@ -1001,6 +963,7 @@ static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen, ...@@ -1001,6 +963,7 @@ static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen,
fl.fld_dst = dn_saddr2dn(&scp->peer); fl.fld_dst = dn_saddr2dn(&scp->peer);
fl.fld_src = dn_saddr2dn(&scp->addr); fl.fld_src = dn_saddr2dn(&scp->addr);
dn_sk_ports_copy(&fl, scp); dn_sk_ports_copy(&fl, scp);
fl.proto = DNPROTO_NSP;
if (dn_route_output_sock(&sk->dst_cache, &fl, sk, flags) < 0) if (dn_route_output_sock(&sk->dst_cache, &fl, sk, flags) < 0)
goto out; goto out;
sk->route_caps = sk->dst_cache->dev->features; sk->route_caps = sk->dst_cache->dev->features;
...@@ -1964,7 +1927,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -1964,7 +1927,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
unsigned char fctype; unsigned char fctype;
long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); 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; return -EOPNOTSUPP;
if (addr_len && (addr_len != sizeof(struct sockaddr_dn))) if (addr_len && (addr_len != sizeof(struct sockaddr_dn)))
...@@ -2143,6 +2106,95 @@ static struct packet_type dn_dix_packet_type = { ...@@ -2143,6 +2106,95 @@ static struct packet_type dn_dix_packet_type = {
.data = (void*)1, .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) #define IS_NOT_PRINTABLE(x) ((x) < 32 || (x) > 126)
static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf) static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf)
...@@ -2163,31 +2215,60 @@ static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf) ...@@ -2163,31 +2215,60 @@ static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf)
} }
} }
static int dn_get_info(char *buffer, char **start, off_t offset, int length) static char *dn_state2asc(unsigned char state)
{ {
struct sock *sk; switch(state) {
struct dn_scp *scp; case DN_O:
int len = 0; return "OPEN";
off_t pos = 0; case DN_CR:
off_t begin = 0; 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 buf1[DN_ASCBUF_LEN];
char buf2[DN_ASCBUF_LEN]; char buf2[DN_ASCBUF_LEN];
char local_object[DN_MAXOBJL+3]; char local_object[DN_MAXOBJL+3];
char remote_object[DN_MAXOBJL+3]; char remote_object[DN_MAXOBJL+3];
int i;
len += sprintf(buffer + len, "Local Remote\n");
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->addr, local_object);
dn_printable_object(&scp->peer, remote_object); dn_printable_object(&scp->peer, remote_object);
len += sprintf(buffer + len, seq_printf(seq,
"%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n", "%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), dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
scp->addrloc, scp->addrloc,
scp->numdat, scp->numdat,
...@@ -2206,27 +2287,55 @@ static int dn_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -2206,27 +2287,55 @@ static int dn_get_info(char *buffer, char **start, off_t offset, int length)
remote_object, remote_object,
dn_state2asc(scp->state), dn_state2asc(scp->state),
((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER")); ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
}
pos = begin + len; static int dn_socket_seq_show(struct seq_file *seq, void *v)
if (pos < offset) { {
len = 0; if (v == (void*)1) {
begin = pos; seq_puts(seq, "Local Remote\n");
} } else {
if (pos > (offset + length)) dn_socket_format_entry(seq, v);
break;
}
} }
read_unlock(&dn_hash_lock); return 0;
}
*start = buffer + (offset - begin); static struct seq_operations dn_socket_seq_ops = {
len -= (offset - begin); .start = dn_socket_seq_start,
.next = dn_socket_seq_next,
.stop = dn_socket_seq_stop,
.show = dn_socket_seq_show,
};
if (len > length) static int dn_socket_seq_open(struct inode *inode, struct file *file)
len = length; {
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 = seq_release_private,
};
#endif
static struct net_proto_family dn_family_ops = { static struct net_proto_family dn_family_ops = {
.family = AF_DECnet, .family = AF_DECnet,
...@@ -2258,13 +2367,11 @@ static struct proto_ops dn_proto_ops = { ...@@ -2258,13 +2367,11 @@ static struct proto_ops dn_proto_ops = {
void dn_register_sysctl(void); void dn_register_sysctl(void);
void dn_unregister_sysctl(void); void dn_unregister_sysctl(void);
MODULE_DESCRIPTION("The Linux DECnet Network Protocol"); MODULE_DESCRIPTION("The Linux DECnet Network Protocol");
MODULE_AUTHOR("Linux DECnet Project Team"); MODULE_AUTHOR("Linux DECnet Project Team");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.68s (C) 1995-2003 Linux DECnet Project Team\n";
static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.67s (C) 1995-2003 Linux DECnet Project Team\n";
static int __init decnet_init(void) static int __init decnet_init(void)
{ {
...@@ -2281,15 +2388,12 @@ static int __init decnet_init(void) ...@@ -2281,15 +2388,12 @@ static int __init decnet_init(void)
dev_add_pack(&dn_dix_packet_type); dev_add_pack(&dn_dix_packet_type);
register_netdevice_notifier(&dn_dev_notifier); 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_neigh_init();
dn_dev_init(); dn_dev_init();
dn_route_init(); dn_route_init();
#ifdef CONFIG_DECNET_ROUTER
dn_fib_init(); dn_fib_init();
#endif /* CONFIG_DECNET_ROUTER */
dn_register_sysctl(); dn_register_sysctl();
...@@ -2316,10 +2420,7 @@ static void __exit decnet_exit(void) ...@@ -2316,10 +2420,7 @@ static void __exit decnet_exit(void)
dn_route_cleanup(); dn_route_cleanup();
dn_dev_cleanup(); dn_dev_cleanup();
dn_neigh_cleanup(); dn_neigh_cleanup();
#ifdef CONFIG_DECNET_ROUTER
dn_fib_cleanup(); dn_fib_cleanup();
#endif /* CONFIG_DECNET_ROUTER */
proc_net_remove("decnet"); proc_net_remove("decnet");
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
* Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding * Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding
* Steve Whitehouse : Removed timer1 - it's a user space issue now * Steve Whitehouse : Removed timer1 - it's a user space issue now
* Patrick Caulfield : Fixed router hello message format * 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> #include <linux/config.h>
...@@ -28,6 +30,7 @@ ...@@ -28,6 +30,7 @@
#include <linux/net.h> #include <linux/net.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
...@@ -72,16 +75,13 @@ static void rtmsg_ifa(int event, struct dn_ifaddr *ifa); ...@@ -72,16 +75,13 @@ static void rtmsg_ifa(int event, struct dn_ifaddr *ifa);
static int dn_eth_up(struct net_device *); static int dn_eth_up(struct net_device *);
static void dn_eth_down(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); 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); static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa);
#endif
static struct dn_dev_parms dn_dev_list[] = { static struct dn_dev_parms dn_dev_list[] = {
{ {
.type = ARPHRD_ETHER, /* Ethernet */ .type = ARPHRD_ETHER, /* Ethernet */
.mode = DN_DEV_BCAST, .mode = DN_DEV_BCAST,
.state = DN_DEV_S_RU, .state = DN_DEV_S_RU,
.blksize = 1498,
.t2 = 1, .t2 = 1,
.t3 = 10, .t3 = 10,
.name = "ethernet", .name = "ethernet",
...@@ -94,7 +94,6 @@ static struct dn_dev_parms dn_dev_list[] = { ...@@ -94,7 +94,6 @@ static struct dn_dev_parms dn_dev_list[] = {
.type = ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */ .type = ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
.mode = DN_DEV_BCAST, .mode = DN_DEV_BCAST,
.state = DN_DEV_S_RU, .state = DN_DEV_S_RU,
.blksize = 1400,
.t2 = 1, .t2 = 1,
.t3 = 10, .t3 = 10,
.name = "ipgre", .name = "ipgre",
...@@ -106,7 +105,6 @@ static struct dn_dev_parms dn_dev_list[] = { ...@@ -106,7 +105,6 @@ static struct dn_dev_parms dn_dev_list[] = {
.type = ARPHRD_X25, /* Bog standard X.25 */ .type = ARPHRD_X25, /* Bog standard X.25 */
.mode = DN_DEV_UCAST, .mode = DN_DEV_UCAST,
.state = DN_DEV_S_DS, .state = DN_DEV_S_DS,
.blksize = 230,
.t2 = 1, .t2 = 1,
.t3 = 120, .t3 = 120,
.name = "x25", .name = "x25",
...@@ -119,7 +117,6 @@ static struct dn_dev_parms dn_dev_list[] = { ...@@ -119,7 +117,6 @@ static struct dn_dev_parms dn_dev_list[] = {
.type = ARPHRD_PPP, /* DECnet over PPP */ .type = ARPHRD_PPP, /* DECnet over PPP */
.mode = DN_DEV_BCAST, .mode = DN_DEV_BCAST,
.state = DN_DEV_S_RU, .state = DN_DEV_S_RU,
.blksize = 230,
.t2 = 1, .t2 = 1,
.t3 = 10, .t3 = 10,
.name = "ppp", .name = "ppp",
...@@ -127,24 +124,20 @@ static struct dn_dev_parms dn_dev_list[] = { ...@@ -127,24 +124,20 @@ static struct dn_dev_parms dn_dev_list[] = {
.timer3 = dn_send_brd_hello, .timer3 = dn_send_brd_hello,
}, },
#endif #endif
#if 0
{ {
.type = ARPHRD_DDCMP, /* DECnet over DDCMP */ .type = ARPHRD_DDCMP, /* DECnet over DDCMP */
.mode = DN_DEV_UCAST, .mode = DN_DEV_UCAST,
.state = DN_DEV_S_DS, .state = DN_DEV_S_DS,
.blksize = 230,
.t2 = 1, .t2 = 1,
.t3 = 120, .t3 = 120,
.name = "ddcmp", .name = "ddcmp",
.ctl_name = NET_DECNET_CONF_DDCMP, .ctl_name = NET_DECNET_CONF_DDCMP,
.timer3 = dn_send_ptp_hello, .timer3 = dn_send_ptp_hello,
}, },
#endif
{ {
.type = ARPHRD_LOOPBACK, /* Loopback interface - always last */ .type = ARPHRD_LOOPBACK, /* Loopback interface - always last */
.mode = DN_DEV_BCAST, .mode = DN_DEV_BCAST,
.state = DN_DEV_S_RU, .state = DN_DEV_S_RU,
.blksize = 1498,
.t2 = 1, .t2 = 1,
.t3 = 10, .t3 = 10,
.name = "loopback", .name = "loopback",
...@@ -254,6 +247,21 @@ static struct dn_dev_sysctl_table { ...@@ -254,6 +247,21 @@ static struct dn_dev_sysctl_table {
}, {0}} }, {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) static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms)
{ {
struct dn_dev_sysctl_table *t; struct dn_dev_sysctl_table *t;
...@@ -858,7 +866,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa) ...@@ -858,7 +866,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
memcpy(msg->tiver, dn_eco_version, 3); memcpy(msg->tiver, dn_eco_version, 3);
dn_dn2eth(msg->id, ifa->ifa_local); dn_dn2eth(msg->id, ifa->ifa_local);
msg->iinfo = DN_RT_INFO_ENDN; msg->iinfo = DN_RT_INFO_ENDN;
msg->blksize = dn_htons(dn_db->parms.blksize); msg->blksize = dn_htons(mtu2blksize(dev));
msg->area = 0x00; msg->area = 0x00;
memset(msg->seed, 0, 8); memset(msg->seed, 0, 8);
memcpy(msg->neighbor, dn_hiord, ETH_ALEN); memcpy(msg->neighbor, dn_hiord, ETH_ALEN);
...@@ -920,10 +928,10 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) ...@@ -920,10 +928,10 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
unsigned short *pktlen; unsigned short *pktlen;
char *src; char *src;
if (dn_db->parms.blksize < (26 + 7)) if (mtu2blksize(dev) < (26 + 7))
return; return;
n = dn_db->parms.blksize - 26; n = mtu2blksize(dev) - 26;
n /= 7; n /= 7;
if (n > 32) if (n > 32)
...@@ -946,7 +954,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) ...@@ -946,7 +954,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
ptr += ETH_ALEN; ptr += ETH_ALEN;
*ptr++ = dn_db->parms.forwarding == 1 ? *ptr++ = dn_db->parms.forwarding == 1 ?
DN_RT_INFO_L1RT : DN_RT_INFO_L2RT; 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 += 2;
*ptr++ = dn_db->parms.priority; /* Priority */ *ptr++ = dn_db->parms.priority; /* Priority */
*ptr++ = 0; /* Area: Reserved */ *ptr++ = 0; /* Area: Reserved */
...@@ -990,16 +998,13 @@ static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa) ...@@ -990,16 +998,13 @@ static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
dn_send_router_hello(dev, ifa); dn_send_router_hello(dev, ifa);
} }
#if 0
static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa) static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
{ {
int tdlen = 16; int tdlen = 16;
int size = dev->hard_header_len + 2 + 4 + tdlen; int size = dev->hard_header_len + 2 + 4 + tdlen;
struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC); struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC);
struct dn_dev *dn_db = dev->dn_ptr;
int i; int i;
unsigned char *ptr; unsigned char *ptr;
struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
char src[ETH_ALEN]; char src[ETH_ALEN];
if (skb == NULL) if (skb == NULL)
...@@ -1020,7 +1025,6 @@ static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa) ...@@ -1020,7 +1025,6 @@ static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
dn_dn2eth(src, ifa->ifa_local); dn_dn2eth(src, ifa->ifa_local);
dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src); dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);
} }
#endif
static int dn_eth_up(struct net_device *dev) static int dn_eth_up(struct net_device *dev)
{ {
...@@ -1332,6 +1336,63 @@ int dnet_gifconf(struct net_device *dev, char *buf, int len) ...@@ -1332,6 +1336,63 @@ int dnet_gifconf(struct net_device *dev, char *buf, int len)
#ifdef CONFIG_PROC_FS #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) static char *dn_type2asc(char type)
{ {
...@@ -1347,56 +1408,50 @@ static char *dn_type2asc(char type) ...@@ -1347,56 +1408,50 @@ static char *dn_type2asc(char type)
return "?"; 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; if (v == (void*)1)
struct net_device *dev; seq_puts(seq, "Name Flags T1 Timer1 T3 Timer3 BlkSize Pri State DevType Router Peer\n");
int len = 0; else {
off_t pos = 0; struct net_device *dev = v;
off_t begin = 0;
char peer_buf[DN_ASCBUF_LEN]; char peer_buf[DN_ASCBUF_LEN];
char router_buf[DN_ASCBUF_LEN]; char router_buf[DN_ASCBUF_LEN];
struct dn_dev *dn_db = dev->dn_ptr;
seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu"
len += sprintf(buffer, "Name Flags T1 Timer1 T3 Timer3 BlkSize Pri State DevType Router Peer\n"); " %04hu %03d %02x %-10s %-7s %-7s\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",
dev->name ? dev->name : "???", dev->name ? dev->name : "???",
dn_type2asc(dn_db->parms.mode), dn_type2asc(dn_db->parms.mode),
0, 0, 0, 0,
dn_db->t3, dn_db->parms.t3, dn_db->t3, dn_db->parms.t3,
dn_db->parms.blksize, mtu2blksize(dev),
dn_db->parms.priority, dn_db->parms.priority,
dn_db->parms.state, dn_db->parms.name, 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->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) : ""); dn_db->peer ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->peer->primary_key), peer_buf) : "");
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
} }
if (pos > offset + length) return 0;
break; }
}
read_unlock(&dev_base_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
if (len > length) len = length; 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,
};
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 */ #endif /* CONFIG_PROC_FS */
static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
...@@ -1448,9 +1503,7 @@ void __init dn_dev_init(void) ...@@ -1448,9 +1503,7 @@ void __init dn_dev_init(void)
rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table; rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table;
#ifdef CONFIG_PROC_FS proc_net_fops_create("decnet_dev", S_IRUGO, &dn_dev_seq_fops);
proc_net_create("decnet_dev", 0, decnet_dev_get_info);
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
{ {
......
...@@ -67,18 +67,18 @@ static struct ...@@ -67,18 +67,18 @@ static struct
int error; int error;
u8 scope; u8 scope;
} dn_fib_props[RTA_MAX+1] = { } dn_fib_props[RTA_MAX+1] = {
{ .error = 0, .scope = RT_SCOPE_NOWHERE }, /* RTN_UNSPEC */ [RTN_UNSPEC] = { .error = 0, .scope = RT_SCOPE_NOWHERE },
{ .error = 0, .scope = RT_SCOPE_UNIVERSE }, /* RTN_UNICAST */ [RTN_UNICAST] = { .error = 0, .scope = RT_SCOPE_UNIVERSE },
{ .error = 0, .scope = RT_SCOPE_HOST }, /* RTN_LOCAL */ [RTN_LOCAL] = { .error = 0, .scope = RT_SCOPE_HOST },
{ .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, /* RTN_BROADCAST */ [RTN_BROADCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
{ .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, /* RTN_ANYCAST */ [RTN_ANYCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
{ .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, /* RTN_MULTICAST */ [RTN_MULTICAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
{ .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE }, /* RTN_BLACKHOLE */ [RTN_BLACKHOLE] = { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE },
{ .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE }, /* RTN_UNREACHABLE */ [RTN_UNREACHABLE] = { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE },
{ .error = -EACCES, .scope = RT_SCOPE_UNIVERSE }, /* RTN_PROHIBIT */ [RTN_PROHIBIT] = { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE },
{ .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE }, /* RTN_THROW */ [RTN_THROW] = { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE },
{ .error = 0, .scope = RT_SCOPE_NOWHERE }, /* RTN_NAT */ [RTN_NAT] = { .error = 0, .scope = RT_SCOPE_NOWHERE },
{ .error = -EINVAL, .scope = RT_SCOPE_NOWHERE } /* RTN_XRESOLVE */ [RTN_XRESOLVE] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
}; };
void dn_fib_free_info(struct dn_fib_info *fi) void dn_fib_free_info(struct dn_fib_info *fi)
...@@ -792,53 +792,12 @@ void dn_fib_flush(void) ...@@ -792,53 +792,12 @@ void dn_fib_flush(void)
dn_rt_cache_flush(-1); 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 = { static struct notifier_block dn_fib_dnaddr_notifier = {
.notifier_call = dn_fib_dnaddr_event, .notifier_call = dn_fib_dnaddr_event,
}; };
void __exit dn_fib_cleanup(void) void __exit dn_fib_cleanup(void)
{ {
proc_net_remove("decnet_route");
dn_fib_table_cleanup(); dn_fib_table_cleanup();
dn_fib_rules_cleanup(); dn_fib_rules_cleanup();
...@@ -849,10 +808,6 @@ void __exit dn_fib_cleanup(void) ...@@ -849,10 +808,6 @@ void __exit dn_fib_cleanup(void)
void __init dn_fib_init(void) 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_table_init();
dn_fib_rules_init(); dn_fib_rules_init();
......
...@@ -202,7 +202,7 @@ static int dn_neigh_output_packet(struct sk_buff *skb) ...@@ -202,7 +202,7 @@ static int dn_neigh_output_packet(struct sk_buff *skb)
struct net_device *dev = neigh->dev; struct net_device *dev = neigh->dev;
char mac_addr[ETH_ALEN]; 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) 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); return neigh->ops->queue_xmit(skb);
...@@ -692,48 +692,23 @@ static int dn_neigh_seq_open(struct inode *inode, struct file *file) ...@@ -692,48 +692,23 @@ static int dn_neigh_seq_open(struct inode *inode, struct file *file)
goto out; 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 = { static struct file_operations dn_neigh_seq_fops = {
.open = dn_neigh_seq_open, .open = dn_neigh_seq_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = dn_seq_release, .release = seq_release_private,
}; };
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 #endif
void __init dn_neigh_init(void) void __init dn_neigh_init(void)
{ {
neigh_table_init(&dn_neigh_table); neigh_table_init(&dn_neigh_table);
proc_net_fops_create("decnet_neigh", S_IRUGO, &dn_neigh_seq_fops);
dn_neigh_proc_init();
} }
void __exit dn_neigh_cleanup(void) void __exit dn_neigh_cleanup(void)
{ {
proc_net_remove("decnet_neigh");
neigh_table_clear(&dn_neigh_table); neigh_table_clear(&dn_neigh_table);
} }
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
* Steve Whitehouse: Added backlog congestion level return codes. * Steve Whitehouse: Added backlog congestion level return codes.
* Patrick Caulfield: * Patrick Caulfield:
* Steve Whitehouse: Added flow control support (outbound) * Steve Whitehouse: Added flow control support (outbound)
* Steve Whitehouse: Prepare for nonlinear skbs
*/ */
/****************************************************************************** /******************************************************************************
...@@ -240,7 +241,7 @@ static struct sock *dn_find_listener(struct sk_buff *skb, unsigned short *reason ...@@ -240,7 +241,7 @@ static struct sock *dn_find_listener(struct sk_buff *skb, unsigned short *reason
cb->info = msg->info; cb->info = msg->info;
cb->segsize = dn_ntohs(msg->segsize); cb->segsize = dn_ntohs(msg->segsize);
if (skb->len < sizeof(*msg)) if (!pskb_may_pull(skb, sizeof(*msg)))
goto err_out; goto err_out;
skb_pull(skb, sizeof(*msg)); skb_pull(skb, sizeof(*msg));
...@@ -721,33 +722,18 @@ static int dn_nsp_rx_packet(struct sk_buff *skb) ...@@ -721,33 +722,18 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
unsigned char *ptr = (unsigned char *)skb->data; unsigned char *ptr = (unsigned char *)skb->data;
unsigned short reason = NSP_REASON_NL; unsigned short reason = NSP_REASON_NL;
if (!pskb_may_pull(skb, 2))
goto free_out;
skb->h.raw = skb->data; skb->h.raw = skb->data;
cb->nsp_flags = *ptr++; cb->nsp_flags = *ptr++;
if (decnet_debug_level & 2) if (decnet_debug_level & 2)
printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags); 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) if (cb->nsp_flags & 0x83)
goto free_out; 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 * Filter out conninits and useless packet types
*/ */
...@@ -759,12 +745,14 @@ static int dn_nsp_rx_packet(struct sk_buff *skb) ...@@ -759,12 +745,14 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
goto free_out; goto free_out;
case 0x10: case 0x10:
case 0x60: case 0x60:
if (unlikely(cb->rt_flags & DN_RT_F_RTS))
goto free_out;
sk = dn_find_listener(skb, &reason); sk = dn_find_listener(skb, &reason);
goto got_it; goto got_it;
} }
} }
if (skb->len < 3) if (!pskb_may_pull(skb, 3))
goto free_out; goto free_out;
/* /*
...@@ -777,12 +765,25 @@ static int dn_nsp_rx_packet(struct sk_buff *skb) ...@@ -777,12 +765,25 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
/* /*
* If not a connack, grab the source address too. * 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; cb->src_port = *(unsigned short *)ptr;
ptr += 2; ptr += 2;
skb_pull(skb, 5); 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. * Find the socket to which this skb is destined.
*/ */
...@@ -795,6 +796,15 @@ static int dn_nsp_rx_packet(struct sk_buff *skb) ...@@ -795,6 +796,15 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
/* Reset backoff */ /* Reset backoff */
scp->nsp_rxtshift = 0; 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); bh_lock_sock(sk);
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
if (decnet_debug_level & 8) if (decnet_debug_level & 8)
...@@ -835,7 +845,10 @@ int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -835,7 +845,10 @@ int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
struct dn_skb_cb *cb = DN_SKB_CB(skb); struct dn_skb_cb *cb = DN_SKB_CB(skb);
if (cb->rt_flags & DN_RT_F_RTS) { if (cb->rt_flags & DN_RT_F_RTS) {
if (cb->nsp_flags == 0x18 || cb->nsp_flags == 0x68)
dn_returned_conn_init(sk, skb); dn_returned_conn_init(sk, skb);
else
kfree_skb(skb);
return NET_RX_SUCCESS; return NET_RX_SUCCESS;
} }
......
...@@ -96,6 +96,7 @@ static void dn_nsp_send(struct sk_buff *skb) ...@@ -96,6 +96,7 @@ static void dn_nsp_send(struct sk_buff *skb)
fl.fld_src = dn_saddr2dn(&scp->addr); fl.fld_src = dn_saddr2dn(&scp->addr);
fl.fld_dst = dn_saddr2dn(&scp->peer); fl.fld_dst = dn_saddr2dn(&scp->peer);
dn_sk_ports_copy(&fl, scp); dn_sk_ports_copy(&fl, scp);
fl.proto = DNPROTO_NSP;
if (dn_route_output_sock(&sk->dst_cache, &fl, sk, 0) == 0) { if (dn_route_output_sock(&sk->dst_cache, &fl, sk, 0) == 0) {
dst = sk_dst_get(sk); dst = sk_dst_get(sk);
sk->route_caps = dst->dev->features; sk->route_caps = dst->dev->features;
...@@ -349,8 +350,7 @@ static inline unsigned char *dn_mk_common_header(struct dn_scp *scp, struct sk_b ...@@ -349,8 +350,7 @@ static inline unsigned char *dn_mk_common_header(struct dn_scp *scp, struct sk_b
{ {
unsigned char *ptr = skb_push(skb, len); unsigned char *ptr = skb_push(skb, len);
if (len < 5) BUG_ON(len < 5);
BUG();
*ptr++ = msgflag; *ptr++ = msgflag;
*((unsigned short *)ptr) = scp->addrrem; *((unsigned short *)ptr) = scp->addrrem;
...@@ -367,8 +367,7 @@ static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, un ...@@ -367,8 +367,7 @@ static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, un
unsigned short ackcrs = scp->numoth_rcv & 0x0FFF; unsigned short ackcrs = scp->numoth_rcv & 0x0FFF;
unsigned short *ptr; unsigned short *ptr;
if (hlen < 9) BUG_ON(hlen < 9);
BUG();
scp->ackxmt_dat = acknum; scp->ackxmt_dat = acknum;
scp->ackxmt_oth = ackcrs; scp->ackxmt_oth = ackcrs;
...@@ -485,8 +484,8 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff ...@@ -485,8 +484,8 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff
* We don't expect to see acknowledgements for packets we * We don't expect to see acknowledgements for packets we
* haven't sent yet. * haven't sent yet.
*/ */
if (xmit_count == 0) WARN_ON(xmit_count == 0);
BUG();
/* /*
* If the packet has only been sent once, we can use it * If the packet has only been sent once, we can use it
* to calculate the RTT and also open the window a little * to calculate the RTT and also open the window a little
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
* no ref count on net devices. * no ref count on net devices.
* Steve Whitehouse : RCU for the route cache * Steve Whitehouse : RCU for the route cache
* Steve Whitehouse : Preparations for the flow cache * Steve Whitehouse : Preparations for the flow cache
* Steve Whitehouse : Prepare for nonlinear skbs
*/ */
/****************************************************************************** /******************************************************************************
...@@ -70,6 +71,7 @@ ...@@ -70,6 +71,7 @@
#include <net/sock.h> #include <net/sock.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -97,14 +99,17 @@ extern struct neigh_table dn_neigh_table; ...@@ -97,14 +99,17 @@ extern struct neigh_table dn_neigh_table;
static unsigned char dn_hiord_addr[6] = {0xAA,0x00,0x04,0x00,0x00,0x00}; static unsigned char dn_hiord_addr[6] = {0xAA,0x00,0x04,0x00,0x00,0x00};
int dn_rt_min_delay = 2*HZ; int dn_rt_min_delay = 2 * HZ;
int dn_rt_max_delay = 10*HZ; int dn_rt_max_delay = 10 * HZ;
static unsigned long dn_rt_deadline = 0; int dn_rt_mtu_expires = 10 * 60 * HZ;
static unsigned long dn_rt_deadline;
static int dn_dst_gc(void); static int dn_dst_gc(void);
static struct dst_entry *dn_dst_check(struct dst_entry *, __u32); static struct dst_entry *dn_dst_check(struct dst_entry *, __u32);
static struct dst_entry *dn_dst_negative_advice(struct dst_entry *); static struct dst_entry *dn_dst_negative_advice(struct dst_entry *);
static void dn_dst_link_failure(struct sk_buff *); 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 int dn_route_input(struct sk_buff *);
static void dn_run_flush(unsigned long dummy); static void dn_run_flush(unsigned long dummy);
...@@ -124,6 +129,7 @@ static struct dst_ops dn_dst_ops = { ...@@ -124,6 +129,7 @@ static struct dst_ops dn_dst_ops = {
.check = dn_dst_check, .check = dn_dst_check,
.negative_advice = dn_dst_negative_advice, .negative_advice = dn_dst_negative_advice,
.link_failure = dn_dst_link_failure, .link_failure = dn_dst_link_failure,
.update_pmtu = dn_dst_update_pmtu,
.entry_size = sizeof(struct dn_route), .entry_size = sizeof(struct dn_route),
.entries = ATOMIC_INIT(0), .entries = ATOMIC_INIT(0),
}; };
...@@ -210,16 +216,49 @@ static int dn_dst_gc(void) ...@@ -210,16 +216,49 @@ static int dn_dst_gc(void)
return 0; 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) static struct dst_entry *dn_dst_check(struct dst_entry *dst, __u32 cookie)
{ {
dst_release(dst); dst_release(dst);
return NULL; 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) static struct dst_entry *dn_dst_negative_advice(struct dst_entry *dst)
{ {
dst_release(dst); dst_release(dst);
...@@ -467,7 +506,7 @@ static int dn_route_rx_long(struct sk_buff *skb) ...@@ -467,7 +506,7 @@ static int dn_route_rx_long(struct sk_buff *skb)
struct dn_skb_cb *cb = DN_SKB_CB(skb); struct dn_skb_cb *cb = DN_SKB_CB(skb);
unsigned char *ptr = skb->data; 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; goto drop_it;
skb_pull(skb, 20); skb_pull(skb, 20);
...@@ -505,7 +544,7 @@ static int dn_route_rx_short(struct sk_buff *skb) ...@@ -505,7 +544,7 @@ static int dn_route_rx_short(struct sk_buff *skb)
struct dn_skb_cb *cb = DN_SKB_CB(skb); struct dn_skb_cb *cb = DN_SKB_CB(skb);
unsigned char *ptr = skb->data; 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; goto drop_it;
skb_pull(skb, 5); skb_pull(skb, 5);
...@@ -555,6 +594,9 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type ...@@ -555,6 +594,9 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
goto out; goto out;
if (!pskb_may_pull(skb, 3))
goto dump_it;
skb_pull(skb, 2); skb_pull(skb, 2);
if (len > skb->len) if (len > skb->len)
...@@ -573,6 +615,8 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type ...@@ -573,6 +615,8 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
*/ */
if (flags & DN_RT_F_PF) { if (flags & DN_RT_F_PF) {
padlen = 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); skb_pull(skb, padlen);
flags = *skb->data; flags = *skb->data;
} }
...@@ -594,6 +638,10 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type ...@@ -594,6 +638,10 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
padlen); padlen);
if (flags & DN_RT_PKT_CNTL) { 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) { switch(flags & DN_RT_CNTL_MSK) {
case DN_RT_PKT_INIT: case DN_RT_PKT_INIT:
dn_dev_init_pkt(skb); dn_dev_init_pkt(skb);
...@@ -712,7 +760,7 @@ static int dn_forward(struct sk_buff *skb) ...@@ -712,7 +760,7 @@ static int dn_forward(struct sk_buff *skb)
* packets, so we don't need to test for them here. * packets, so we don't need to test for them here.
*/ */
cb->rt_flags &= ~DN_RT_F_IE; 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; cb->rt_flags |= DN_RT_F_IE;
return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output); return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output);
...@@ -788,8 +836,10 @@ static inline int dn_match_addr(__u16 addr1, __u16 addr2) ...@@ -788,8 +836,10 @@ static inline int dn_match_addr(__u16 addr1, __u16 addr2)
{ {
__u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2); __u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2);
int match = 16; int match = 16;
while(tmp) while(tmp) {
tmp >>= 1, match--; tmp >>= 1;
match--;
}
return match; return match;
} }
...@@ -899,17 +949,19 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old ...@@ -899,17 +949,19 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
/* No destination? Assume its local */ /* No destination? Assume its local */
if (!fl.fld_dst) { if (!fl.fld_dst) {
fl.fld_dst = fl.fld_src; fl.fld_dst = fl.fld_src;
#if 0
if (!fl.fld_dst)
/* grab an address from loopback? */
#endif
err = -EADDRNOTAVAIL; err = -EADDRNOTAVAIL;
if (dev_out) if (dev_out)
dev_put(dev_out); dev_put(dev_out);
if (!fl.fld_dst)
goto out;
dev_out = &loopback_dev; dev_out = &loopback_dev;
dev_hold(dev_out); 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; fl.oif = loopback_dev.ifindex;
res.type = RTN_LOCAL; res.type = RTN_LOCAL;
goto make_route; goto make_route;
...@@ -1061,6 +1113,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old ...@@ -1061,6 +1113,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
rt->rt_saddr = fl.fld_src; rt->rt_saddr = fl.fld_src;
rt->rt_daddr = fl.fld_dst; rt->rt_daddr = fl.fld_dst;
rt->rt_gateway = gateway ? gateway : 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_dst_map = fl.fld_dst;
rt->rt_src_map = fl.fld_src; rt->rt_src_map = fl.fld_src;
...@@ -1075,14 +1128,14 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old ...@@ -1075,14 +1128,14 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
rt->u.dst.input = dn_rt_bug; rt->u.dst.input = dn_rt_bug;
rt->rt_flags = flags; rt->rt_flags = flags;
if (flags & RTCF_LOCAL) 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; goto e_neighbour;
hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst); hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
dn_insert_route(rt, hash, (struct dn_route **)pprt); dn_insert_route(rt, hash, (struct dn_route **)pprt);
err = 0;
done: done:
if (neigh) if (neigh)
...@@ -1175,6 +1228,7 @@ static int dn_route_input_slow(struct sk_buff *skb) ...@@ -1175,6 +1228,7 @@ static int dn_route_input_slow(struct sk_buff *skb)
unsigned hash; unsigned hash;
int flags = 0; int flags = 0;
__u16 gateway = 0; __u16 gateway = 0;
__u16 local_src = 0;
struct flowi fl = { .nl_u = { .dn_u = struct flowi fl = { .nl_u = { .dn_u =
{ .daddr = cb->dst, { .daddr = cb->dst,
.saddr = cb->src, .saddr = cb->src,
...@@ -1275,6 +1329,8 @@ static int dn_route_input_slow(struct sk_buff *skb) ...@@ -1275,6 +1329,8 @@ static int dn_route_input_slow(struct sk_buff *skb)
if (out_dev == in_dev && !(flags & RTCF_NAT)) if (out_dev == in_dev && !(flags & RTCF_NAT))
flags |= RTCF_DOREDIRECT; flags |= RTCF_DOREDIRECT;
local_src = DN_FIB_RES_PREFSRC(res);
case RTN_BLACKHOLE: case RTN_BLACKHOLE:
case RTN_UNREACHABLE: case RTN_UNREACHABLE:
break; break;
...@@ -1319,6 +1375,8 @@ static int dn_route_input_slow(struct sk_buff *skb) ...@@ -1319,6 +1375,8 @@ static int dn_route_input_slow(struct sk_buff *skb)
rt->rt_gateway = fl.fld_dst; rt->rt_gateway = fl.fld_dst;
if (gateway) if (gateway)
rt->rt_gateway = 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_dst_map = fl.fld_dst;
rt->rt_src_map = fl.fld_src; rt->rt_src_map = fl.fld_src;
...@@ -1352,12 +1410,12 @@ static int dn_route_input_slow(struct sk_buff *skb) ...@@ -1352,12 +1410,12 @@ static int dn_route_input_slow(struct sk_buff *skb)
if (rt->u.dst.dev) if (rt->u.dst.dev)
dev_hold(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; goto e_neighbour;
hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst); hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
dn_insert_route(rt, hash, (struct dn_route **)&skb->dst); dn_insert_route(rt, hash, (struct dn_route **)&skb->dst);
err = 0;
done: done:
if (neigh) if (neigh)
...@@ -1449,7 +1507,7 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int ...@@ -1449,7 +1507,7 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int
* they deal only with inputs and not with replies like they do * they deal only with inputs and not with replies like they do
* currently. * 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) if (rt->rt_daddr != rt->rt_gateway)
RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway); RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway);
if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
...@@ -1490,6 +1548,7 @@ int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) ...@@ -1490,6 +1548,7 @@ int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
struct flowi fl; struct flowi fl;
memset(&fl, 0, sizeof(fl)); memset(&fl, 0, sizeof(fl));
fl.proto = DNPROTO_NSP;
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (skb == NULL) if (skb == NULL)
...@@ -1609,54 +1668,114 @@ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1609,54 +1668,114 @@ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb)
} }
#ifdef CONFIG_PROC_FS #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; struct dn_route *rt = NULL;
off_t pos = 0; struct dn_rt_cache_iter_state *s = seq->private;
off_t begin = 0;
struct dn_route *rt;
int i;
char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];
for(i = 0; i <= dn_rt_hash_mask; i++) { for(s->bucket = dn_rt_hash_mask; s->bucket >= 0; --s->bucket) {
rcu_read_lock(); rcu_read_lock();
rt = dn_rt_hash_table[i].chain; rt = dn_rt_hash_table[s->bucket].chain;
for(; rt != NULL; rt = rt->u.rt_next) { if (rt)
read_barrier_depends(); break;
len += sprintf(buffer + len, "%-8s %-7s %-7s %04d %04d %04d\n", rcu_read_unlock();
rt->u.dst.dev ? rt->u.dst.dev->name : "*", }
dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1), return rt;
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)
);
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;
smp_read_barrier_depends();
rt = rt->u.rt_next;
while(!rt) {
rcu_read_unlock();
if (--s->bucket < 0)
break;
rcu_read_lock();
rt = dn_rt_hash_table[s->bucket].chain;
}
return rt;
}
pos = begin + len; 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 (pos < offset) { if (rt) {
len = 0; while(*pos && (rt = dn_rt_cache_get_next(seq, rt)))
begin = pos; --*pos;
}
if (pos > offset + length)
break;
} }
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;
}
static void dn_rt_cache_seq_stop(struct seq_file *seq, void *v)
{
rcu_read_unlock(); rcu_read_unlock();
if (pos > offset + length) }
break;
}
*start = buffer + (offset - begin); static int dn_rt_cache_seq_show(struct seq_file *seq, void *v)
len -= (offset - begin); {
struct dn_route *rt = v;
char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];
if (len > length) len = length; 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;
}
return(len); 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 = seq_release_private,
};
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
void __init dn_route_init(void) void __init dn_route_init(void)
...@@ -1714,9 +1833,7 @@ void __init dn_route_init(void) ...@@ -1714,9 +1833,7 @@ void __init dn_route_init(void)
dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1); dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1);
#ifdef CONFIG_PROC_FS proc_net_fops_create("decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops);
proc_net_create("decnet_cache",0,decnet_cache_get_info);
#endif /* CONFIG_PROC_FS */
} }
void __exit dn_route_cleanup(void) void __exit dn_route_cleanup(void)
......
...@@ -744,86 +744,6 @@ static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct flowi *flp, ...@@ -744,86 +744,6 @@ static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct flowi *flp,
return err; 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) struct dn_fib_table *dn_fib_get_table(int n, int create)
{ {
...@@ -855,9 +775,6 @@ struct dn_fib_table *dn_fib_get_table(int n, int create) ...@@ -855,9 +775,6 @@ struct dn_fib_table *dn_fib_get_table(int n, int create)
t->delete = dn_fib_table_delete; t->delete = dn_fib_table_delete;
t->lookup = dn_fib_table_lookup; t->lookup = dn_fib_table_lookup;
t->flush = dn_fib_table_flush; 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; t->dump = dn_fib_table_dump;
memset(t->data, 0, sizeof(struct dn_hash)); memset(t->data, 0, sizeof(struct dn_hash));
dn_fib_tables[n] = t; dn_fib_tables[n] = t;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment