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 {
#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 */
......
......@@ -101,10 +101,6 @@ struct dn_fib_table {
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];
......@@ -184,6 +180,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)
#define dn_fib_select_multipath(fl, res) do { } while(0)
......
......@@ -74,7 +74,7 @@ struct dn_route {
__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;
......
......@@ -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 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
......@@ -45,5 +39,3 @@ Steve's quick list of things that need finishing off:
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
#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>
......@@ -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)
{
......@@ -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_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;
......@@ -1964,7 +1927,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
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)))
......@@ -2143,6 +2106,95 @@ static struct packet_type dn_dix_packet_type = {
.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)
......@@ -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;
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");
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",
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,
......@@ -2206,27 +2287,55 @@ static int dn_get_info(char *buffer, char **start, off_t offset, int length)
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;
}
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 = seq_release_private,
};
#endif
static struct net_proto_family dn_family_ops = {
.family = AF_DECnet,
......@@ -2258,13 +2367,11 @@ static struct proto_ops dn_proto_ops = {
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)
{
......@@ -2281,15 +2388,12 @@ static int __init decnet_init(void)
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();
......@@ -2316,10 +2420,7 @@ static void __exit decnet_exit(void)
dn_route_cleanup();
dn_dev_cleanup();
dn_neigh_cleanup();
#ifdef CONFIG_DECNET_ROUTER
dn_fib_cleanup();
#endif /* CONFIG_DECNET_ROUTER */
proc_net_remove("decnet");
......
......@@ -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 void rtmsg_ifa(int event, struct dn_ifaddr *ifa);
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 @@ static struct dn_dev_parms dn_dev_list[] = {
.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 @@ static struct dn_dev_parms dn_dev_list[] = {
.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 @@ static struct dn_dev_parms dn_dev_list[] = {
.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 @@ static struct dn_dev_parms dn_dev_list[] = {
.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 @@ static struct dn_dev_sysctl_table {
}, {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 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
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 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
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 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
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 @@ static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
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 @@ static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
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 @@ int dnet_gifconf(struct net_device *dev, char *buf, int len)
#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 @@ static char *dn_type2asc(char type)
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;
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) : "");
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);
return 0;
}
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 */
static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
......@@ -1448,9 +1503,7 @@ void __init dn_dev_init(void)
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
{
......
......@@ -67,18 +67,18 @@ static struct
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 @@ void dn_fib_flush(void)
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();
......@@ -849,10 +808,6 @@ void __exit dn_fib_cleanup(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_rules_init();
......
......@@ -202,7 +202,7 @@ static int dn_neigh_output_packet(struct sk_buff *skb)
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 @@ static int dn_neigh_seq_open(struct inode *inode, struct file *file)
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 = 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
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);
}
......@@ -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 @@ static struct sock *dn_find_listener(struct sk_buff *skb, unsigned short *reason
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,33 +722,18 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
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
*/
......@@ -759,12 +745,14 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
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,12 +765,25 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
/*
* 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.
*/
......@@ -795,6 +796,15 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
/* 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 @@ int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
struct dn_skb_cb *cb = DN_SKB_CB(skb);
if (cb->rt_flags & DN_RT_F_RTS) {
if (cb->nsp_flags == 0x18 || cb->nsp_flags == 0x68)
dn_returned_conn_init(sk, skb);
else
kfree_skb(skb);
return NET_RX_SUCCESS;
}
......
......@@ -96,6 +96,7 @@ static void dn_nsp_send(struct sk_buff *skb)
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 @@ static inline unsigned char *dn_mk_common_header(struct dn_scp *scp, struct sk_b
{
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 @@ static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, un
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 @@ 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
* 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
......
This diff is collapsed.
......@@ -744,86 +744,6 @@ static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct flowi *flp,
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 @@ struct dn_fib_table *dn_fib_get_table(int n, int create)
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;
......
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