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

[DECNET]: DECnet routing fixes etc.

o As requested, macros in dn_fib.h changed to decnet specific names
o Two bugs fixed (only in 2.5 decnet stack) relating to bind and connection
  states.
o Numerous style changes: using C99 initialisers and inline rather
  than __inline__
o Use struct flowi as routing key (for forthcoming flow cache)
o Add metrics to routing table
o Many routing table bug fixes
o New wait code to improve efficiency
o We use real device MTUs now rather than saying "hmm... looks like ethernet
  must be 1500" as we used to (still one or two places to fix, but its
  mostly correct in this patch)
o Tidy up in af_decnet.c:dn_sendmsg() in preparation for zerocopy
o Updates to rtnetlink code to return more information
o Removed ioctl() for decnet fib. It never did anything and rtnetlink is
  a far better interface anyway.
o Converted /proc/decnet_neigh to seq_file (other /proc files to follow)
o DECnet route cache now uses RCU like the ipv4 route cache
o Misc bug fixes wherever I found them
o SO_BINDTODEVICE works for outgoing connections
parent bd9056f7
......@@ -171,17 +171,17 @@ struct dn_skb_cb {
int iif;
};
static __inline__ dn_address dn_eth2dn(unsigned char *ethaddr)
static inline dn_address dn_eth2dn(unsigned char *ethaddr)
{
return ethaddr[4] | (ethaddr[5] << 8);
}
static __inline__ dn_address dn_saddr2dn(struct sockaddr_dn *saddr)
static inline dn_address dn_saddr2dn(struct sockaddr_dn *saddr)
{
return *(dn_address *)saddr->sdn_nodeaddr;
}
static __inline__ void dn_dn2eth(unsigned char *ethaddr, dn_address addr)
static inline void dn_dn2eth(unsigned char *ethaddr, dn_address addr)
{
ethaddr[0] = 0xAA;
ethaddr[1] = 0x00;
......@@ -191,6 +191,19 @@ static __inline__ void dn_dn2eth(unsigned char *ethaddr, dn_address addr)
ethaddr[5] = (unsigned char)(addr >> 8);
}
static inline void dn_sk_ports_copy(struct flowi *fl, struct dn_scp *scp)
{
fl->uli_u.dnports.sport = scp->addrloc;
fl->uli_u.dnports.dport = scp->addrrem;
fl->uli_u.dnports.objnum = scp->addr.sdn_objnum;
if (fl->uli_u.dnports.objnum == 0) {
fl->uli_u.dnports.objnamel = scp->addr.sdn_objnamel;
memcpy(fl->uli_u.dnports.objname, scp->addr.sdn_objname, 16);
}
}
extern unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu);
#define DN_MENUVER_ACC 0x01
#define DN_MENUVER_USR 0x02
#define DN_MENUVER_PRX 0x04
......
......@@ -8,6 +8,7 @@ struct dn_ifaddr {
struct dn_ifaddr *ifa_next;
struct dn_dev *ifa_dev;
dn_address ifa_local;
dn_address ifa_address;
unsigned char ifa_flags;
unsigned char ifa_scope;
char ifa_label[IFNAMSIZ];
......@@ -171,7 +172,10 @@ extern int dn_dev_set_default(struct net_device *dev, int force);
extern struct net_device *dn_dev_get_default(void);
extern int dn_dev_bind_default(dn_address *addr);
static __inline__ int dn_dev_islocal(struct net_device *dev, dn_address addr)
extern int register_dnaddr_notifier(struct notifier_block *nb);
extern int unregister_dnaddr_notifier(struct notifier_block *nb);
static inline int dn_dev_islocal(struct net_device *dev, dn_address addr)
{
struct dn_dev *dn_db = dev->dn_ptr;
struct dn_ifaddr *ifa;
......
#ifndef _NET_DN_FIB_H
#define _NET_DN_FIB_H
#include <linux/config.h>
#ifdef CONFIG_DECNET_ROUTER
#include <linux/rtnetlink.h>
struct dn_kern_rta
{
void *rta_dst;
......@@ -23,15 +17,6 @@ struct dn_kern_rta
struct rta_cacheinfo *rta_ci;
};
struct dn_fib_key {
dn_address src;
dn_address dst;
int iif;
int oif;
u32 fwmark;
unsigned char scope;
};
struct dn_fib_res {
struct dn_fib_rule *r;
struct dn_fib_info *fi;
......@@ -60,16 +45,23 @@ struct dn_fib_info {
unsigned fib_flags;
int fib_protocol;
dn_address fib_prefsrc;
u32 fib_priority;
__u32 fib_priority;
__u32 fib_metrics[RTAX_MAX];
#define dn_fib_mtu fib_metrics[RTAX_MTU-1]
#define dn_fib_window fib_metrics[RTAX_WINDOW-1]
#define dn_fib_rtt fib_metrics[RTAX_RTT-1]
#define dn_fib_advmss fib_metrics[RTAX_ADVMSS-1]
int fib_nhs;
int fib_power;
struct dn_fib_nh fib_nh[0];
#define fib_dev fib_nh[0].nh_dev
#define dn_fib_dev fib_nh[0].nh_dev
};
#define DN_FIB_RES_NH(res) ((res).fi->fib_nh[(res).nh_sel])
#define DN_FIB_RES_RESET(res) ((res).nh_sel = 0)
#define DN_FIB_RES_NH(res) ((res).fi->fib_nh[(res).nh_sel])
#define DN_FIB_RES_PREFSRC(res) ((res).fi->fib_prefsrc ? : __dn_fib_res_prefsrc(&res))
#define DN_FIB_RES_GW(res) (DN_FIB_RES_NH(res).nh_gw)
#define DN_FIB_RES_DEV(res) (DN_FIB_RES_NH(res).nh_dev)
#define DN_FIB_RES_OIF(res) (DN_FIB_RES_NH(res).nh_oif)
......@@ -106,7 +98,7 @@ struct dn_fib_table {
int (*delete)(struct dn_fib_table *t, struct rtmsg *r,
struct dn_kern_rta *rta, struct nlmsghdr *n,
struct netlink_skb_parms *req);
int (*lookup)(struct dn_fib_table *t, const struct dn_fib_key *key,
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
......@@ -118,7 +110,7 @@ struct dn_fib_table {
unsigned char data[0];
};
#ifdef CONFIG_DECNET_ROUTER
/*
* dn_fib.c
*/
......@@ -132,11 +124,12 @@ extern struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r,
struct dn_kern_rta *rta,
const struct nlmsghdr *nlh, int *errp);
extern int dn_fib_semantic_match(int type, struct dn_fib_info *fi,
const struct dn_fib_key *key, struct dn_fib_res *res);
const struct flowi *fl,
struct dn_fib_res *res);
extern void dn_fib_release_info(struct dn_fib_info *fi);
extern u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type);
extern void dn_fib_flush(void);
extern void dn_fib_select_multipath(const struct dn_fib_key *key,
extern void dn_fib_select_multipath(const struct flowi *fl,
struct dn_fib_res *res);
extern int dn_fib_sync_down(dn_address local, struct net_device *dev,
int force);
......@@ -156,7 +149,9 @@ extern void dn_fib_table_cleanup(void);
extern void dn_fib_rules_init(void);
extern void dn_fib_rules_cleanup(void);
extern void dn_fib_rule_put(struct dn_fib_rule *);
extern int dn_fib_lookup(struct dn_fib_key *key, struct dn_fib_res *res);
extern __u16 dn_fib_rules_policy(__u16 saddr, struct dn_fib_res *res, unsigned *flags);
extern unsigned dnet_addr_type(__u16 addr);
extern int dn_fib_lookup(const struct flowi *fl, struct dn_fib_res *res);
/*
* rtnetlink interface
......@@ -169,21 +164,15 @@ extern int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *a
extern int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
extern int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb);
#define DN_NUM_TABLES 255
#define DN_MIN_TABLE 1
#define DN_DEFAULT_TABLE 1
#define DN_L1_TABLE 1
#define DN_L2_TABLE 2
extern void dn_fib_free_info(struct dn_fib_info *fi);
static __inline__ void dn_fib_info_put(struct dn_fib_info *fi)
static inline void dn_fib_info_put(struct dn_fib_info *fi)
{
if (atomic_dec_and_test(&fi->fib_clntref))
dn_fib_free_info(fi);
}
static __inline__ void dn_fib_res_put(struct dn_fib_res *res)
static inline void dn_fib_res_put(struct dn_fib_res *res)
{
if (res->fi)
dn_fib_info_put(res->fi);
......@@ -191,13 +180,23 @@ static __inline__ void dn_fib_res_put(struct dn_fib_res *res)
dn_fib_rule_put(res->r);
}
static __inline__ u16 dnet_make_mask(int n)
extern struct dn_fib_table *dn_fib_tables[];
#else /* Endnode */
#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)
#define dn_fib_rules_policy(saddr,res,flags) (0)
#define dn_fib_res_put(res) do { } while(0)
#endif /* CONFIG_DECNET_ROUTER */
static inline u16 dnet_make_mask(int n)
{
if (n)
return htons(~((1<<(16-n))-1));
return 0;
}
#endif /* CONFIG_DECNET_ROUTER */
#endif /* _NET_DN_FIB_H */
......@@ -18,7 +18,7 @@ struct dn_neigh {
extern void dn_neigh_init(void);
extern void dn_neigh_cleanup(void);
extern struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, void *ptr);
extern struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, const void *ptr);
extern int dn_neigh_router_hello(struct sk_buff *skb);
extern int dn_neigh_endnode_hello(struct sk_buff *skb);
extern void dn_neigh_pointopoint_hello(struct sk_buff *skb);
......
......@@ -204,4 +204,6 @@ static __inline__ int dn_congested(struct sock *sk)
return atomic_read(&sk->rmem_alloc) > (sk->rcvbuf >> 1);
}
#define DN_MAX_NSP_DATA_HEADER (11)
#endif /* _NET_DN_NSP_H */
......@@ -16,7 +16,7 @@
*******************************************************************************/
extern struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri);
extern int dn_route_output(struct dst_entry **pprt, dn_address dst, dn_address src, int flags);
extern int dn_route_output_sock(struct dst_entry **pprt, struct flowi *, struct sock *sk, int flags);
extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
extern int dn_cache_getroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
extern void dn_rt_cache_flush(int delay);
......@@ -59,10 +59,10 @@ extern void dn_rt_cache_flush(int delay);
#define DN_RT_INFO_BLKR 0x40 /* Blocking Requested */
/*
* The key structure is what we used to look up the route.
* The fl structure is what we used to look up the route.
* The rt_saddr & rt_daddr entries are the same as key.saddr & key.daddr
* except for local input routes, where the rt_saddr = key.daddr and
* rt_daddr = key.saddr to allow the route to be used for returning
* except for local input routes, where the rt_saddr = fl.fld_dst and
* rt_daddr = fl.fld_src to allow the route to be used for returning
* packets to the originating host.
*/
struct dn_route {
......@@ -70,19 +70,18 @@ struct dn_route {
struct dst_entry dst;
struct dn_route *rt_next;
} u;
struct {
unsigned short saddr;
unsigned short daddr;
int iif;
int oif;
u32 fwmark;
} key;
unsigned short rt_saddr;
unsigned short rt_daddr;
unsigned char rt_type;
unsigned char rt_scope;
unsigned char rt_protocol;
unsigned char rt_table;
__u16 rt_saddr;
__u16 rt_daddr;
__u16 rt_gateway;
__u16 __padding;
__u16 rt_src_map;
__u16 rt_dst_map;
unsigned rt_flags;
unsigned rt_type;
struct flowi fl;
};
extern void dn_route_init(void);
......@@ -110,32 +109,4 @@ static inline void dn_rt_finish_output(struct sk_buff *skb, char *dst, char *src
kfree_skb(skb);
}
static inline void dn_nsp_send(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
struct dn_scp *scp = DN_SK(sk);
struct dst_entry *dst;
skb->h.raw = skb->data;
scp->stamp = jiffies;
if ((dst = sk->dst_cache) && !dst->obsolete) {
try_again:
skb->dst = dst_clone(dst);
dst_output(skb);
return;
}
dst_release(xchg(&sk->dst_cache, NULL));
if (dn_route_output(&sk->dst_cache, dn_saddr2dn(&scp->peer), dn_saddr2dn(&scp->addr), 0) == 0) {
dst = sk->dst_cache;
goto try_again;
}
sk->err = EHOSTUNREACH;
if (!test_bit(SOCK_DEAD, &sk->flags))
sk->state_change(sk);
}
#endif /* _NET_DN_ROUTE_H */
......@@ -25,7 +25,18 @@ struct flowi {
struct in6_addr * saddr;
__u32 flowlabel;
} ip6_u;
struct {
__u16 daddr;
__u16 saddr;
__u32 fwmark;
__u8 scope;
} dn_u;
} nl_u;
#define fld_dst nl_u.dn_u.daddr
#define fld_src nl_u.dn_u.saddr
#define fld_fwmark nl_u.dn_u.fwmark
#define fld_scope nl_u.dn_u.scope
#define fl6_dst nl_u.ip6_u.daddr
#define fl6_src nl_u.ip6_u.saddr
#define fl6_flowlabel nl_u.ip6_u.flowlabel
......@@ -48,6 +59,14 @@ struct flowi {
__u8 code;
} icmpt;
struct {
__u16 sport;
__u16 dport;
__u8 objnum;
__u8 objnamel; /* Not 16 bits since max val is 16 */
__u8 objname[16]; /* Not zero terminated */
} dnports;
__u32 spi;
} uli_u;
#define fl_ip_sport uli_u.ports.sport
......
......@@ -859,6 +859,9 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
* schedule();
* SOCK_SLEEP_POST(sk)
*
* N.B. These are now obsolete and were, afaik, only ever used in DECnet
* and when the last use of them in DECnet has gone, I'm intending to
* remove them.
*/
#define SOCK_SLEEP_PRE(sk) { struct task_struct *tsk = current; \
......
......@@ -26,25 +26,16 @@ Steve's quick list of things that need finishing off:
o Start to hack together user level software and add more DECnet support
in ifconfig for example.
o Test adding/deleting of routes
o Test route lookup
o Test /proc/net/decnet_route route listing works correctly (maybe I'll
change the format of this file... atm its very similar to the IPv4 route
file)
o Find all the commonality between DECnet and IPv4 routing code and extract
it into a small library of routines. [probably a project for 2.7.xx]
o Test ip_gre tunneling works... it did the last time I tested it and it
will have to if I'm to test routing properly.
o Add the routing message grabbing netfilter module [written, tested,
awaiting merge]
o Add perfect socket hashing - an idea suggested by Paul Koning [part written,
awaiting debugging and 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
right now.
o Add session control message flow control
......@@ -54,3 +45,5 @@ Steve's quick list of things that need finishing off:
o AIO for DECnet
o Eliminate dn_db->parms.blksize
This diff is collapsed.
......@@ -36,9 +36,11 @@
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/sysctl.h>
#include <linux/notifier.h>
#include <asm/uaccess.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/flow.h>
#include <net/dn.h>
#include <net/dn_dev.h>
#include <net/dn_route.h>
......@@ -61,6 +63,7 @@ dn_address decnet_address = 0;
static rwlock_t dndev_lock = RW_LOCK_UNLOCKED;
static struct net_device *decnet_default_device;
static struct notifier_block *dnaddr_chain;
static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);
static void dn_dev_delete(struct net_device *dev);
......@@ -478,7 +481,7 @@ static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int de
}
rtmsg_ifa(RTM_DELADDR, ifa1);
notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1);
if (destroy) {
dn_dev_free_ifa(ifa1);
......@@ -513,6 +516,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
dn_db->ifa_list = ifa;
rtmsg_ifa(RTM_NEWADDR, ifa);
notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
return 0;
}
......@@ -609,7 +613,7 @@ int dn_dev_ioctl(unsigned int cmd, void *arg)
dn_dev_del_ifa(dn_db, ifap, 0);
}
ifa->ifa_local = dn_saddr2dn(sdn);
ifa->ifa_local = ifa->ifa_address = dn_saddr2dn(sdn);
ret = dn_dev_set_ifa(dev, ifa);
}
......@@ -686,7 +690,10 @@ static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *a
if ((ifa = dn_dev_alloc_ifa()) == NULL)
return -ENOBUFS;
if (!rta[IFA_ADDRESS - 1])
rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1];
memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL-1]), 2);
memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS-1]), 2);
ifa->ifa_flags = ifm->ifa_flags;
ifa->ifa_scope = ifm->ifa_scope;
ifa->ifa_dev = dn_db;
......@@ -716,6 +723,9 @@ static int dn_dev_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT;
ifm->ifa_scope = ifa->ifa_scope;
ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
if (ifa->ifa_address)
RTA_PUT(skb, IFA_ADDRESS, 2, &ifa->ifa_address);
if (ifa->ifa_local)
RTA_PUT(skb, IFA_LOCAL, 2, &ifa->ifa_local);
if (ifa->ifa_label[0])
RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label);
......@@ -758,10 +768,7 @@ static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
s_idx = cb->args[0];
s_dn_idx = dn_idx = cb->args[1];
read_lock(&dev_base_lock);
for(dev = dev_base, idx = 0; dev; dev = dev->next) {
if ((dn_db = dev->dn_ptr) == NULL)
continue;
idx++;
for(dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
if (idx < s_idx)
continue;
if (idx > s_idx)
......@@ -773,7 +780,10 @@ static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
if (dn_idx < s_dn_idx)
continue;
if (dn_dev_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0)
if (dn_dev_fill_ifaddr(skb, ifa,
NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq,
RTM_NEWADDR) <= 0)
goto done;
}
}
......@@ -872,8 +882,6 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
}
#ifdef CONFIG_DECNET_ROUTER
#define DRDELAY (5 * HZ)
static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn_ifaddr *ifa)
......@@ -981,12 +989,6 @@ static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
else
dn_send_router_hello(dev, ifa);
}
#else
static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
{
dn_send_endnode_hello(dev, ifa);
}
#endif
#if 0
static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
......@@ -1175,7 +1177,7 @@ void dn_dev_up(struct net_device *dev)
if ((ifa = dn_dev_alloc_ifa()) == NULL)
return;
ifa->ifa_local = addr;
ifa->ifa_local = ifa->ifa_address = addr;
ifa->ifa_flags = 0;
ifa->ifa_scope = RT_SCOPE_UNIVERSE;
strcpy(ifa->ifa_label, dev->name);
......@@ -1274,6 +1276,15 @@ void dn_dev_devices_on(void)
rtnl_unlock();
}
int register_dnaddr_notifier(struct notifier_block *nb)
{
return notifier_chain_register(&dnaddr_chain, nb);
}
int unregister_dnaddr_notifier(struct notifier_block *nb)
{
return notifier_chain_unregister(&dnaddr_chain, nb);
}
#ifdef CONFIG_DECNET_SIOCGIFCONF
/*
......@@ -1390,43 +1401,21 @@ static int decnet_dev_get_info(char *buffer, char **start, off_t offset, int len
static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
{
{ NULL, NULL, },
{ NULL, NULL, },
{ NULL, NULL, },
{ NULL, NULL, },
{ dn_dev_rtm_newaddr, NULL, },
{ dn_dev_rtm_deladdr, NULL, },
{ NULL, dn_dev_dump_ifaddr, },
{ NULL, NULL, },
[4] = { .doit = dn_dev_rtm_newaddr, },
[5] = { .doit = dn_dev_rtm_deladdr, },
[6] = { .dumpit = dn_dev_dump_ifaddr, },
#ifdef CONFIG_DECNET_ROUTER
{ dn_fib_rtm_newroute, NULL, },
{ dn_fib_rtm_delroute, NULL, },
{ dn_cache_getroute, dn_fib_dump, },
{ NULL, NULL, },
[8] = { .doit = dn_fib_rtm_newroute, },
[9] = { .doit = dn_fib_rtm_delroute, },
[10] = { .doit = dn_cache_getroute, .dumpit = dn_fib_dump, },
[16] = { .doit = dn_fib_rtm_newrule, },
[17] = { .doit = dn_fib_rtm_delrule, },
[18] = { .dumpit = dn_fib_dump_rules, },
#else
{ NULL, NULL, },
{ NULL, NULL, },
{ dn_cache_getroute, dn_cache_dump, },
{ NULL, NULL, },
[10] = { .doit = dn_cache_getroute, .dumpit = dn_cache_dump, },
#endif
{ NULL, NULL, },
{ NULL, NULL, },
{ NULL, NULL, },
{ NULL, NULL, },
#ifdef CONFIG_DECNET_ROUTER
{ dn_fib_rtm_newrule, NULL, },
{ dn_fib_rtm_delrule, NULL, },
{ NULL, dn_fib_dump_rules, },
{ NULL, NULL, }
#else
{ NULL, NULL, },
{ NULL, NULL, },
{ NULL, NULL, },
{ NULL, NULL, }
#endif
};
#ifdef MODULE
......
This diff is collapsed.
......@@ -20,6 +20,7 @@
* Steve Whitehouse : Fixed neighbour states (for now anyway).
* Steve Whitehouse : Made error_report functions dummies. This
* is not the right place to return skbs.
* Steve Whitehouse : Convert to seq_file
*
*/
......@@ -33,9 +34,11 @@
#include <linux/string.h>
#include <linux/netfilter_decnet.h>
#include <linux/spinlock.h>
#include <linux/seq_file.h>
#include <asm/atomic.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/flow.h>
#include <net/dn.h>
#include <net/dn_dev.h>
#include <net/dn_neigh.h>
......@@ -160,7 +163,20 @@ static int dn_neigh_construct(struct neighbour *neigh)
return -EINVAL;
}
dn->blksize = 230;
/*
* Make an estimate of the remote block size by assuming that its
* two less then the device mtu, which it true for ethernet (and
* other things which support long format headers) since there is
* an extra length field (of 16 bits) which isn't part of the
* ethernet headers and which the DECnet specs won't admit is part
* of the DECnet routing headers either.
*
* If we over estimate here its no big deal, the NSP negotiations
* will prevent us from sending packets which are too large for the
* remote node to handle. In any case this figure is normally updated
* by a hello message in most cases.
*/
dn->blksize = dev->mtu - 2;
return 0;
}
......@@ -330,7 +346,7 @@ static int dn_phase3_output(struct sk_buff *skb)
* basically does a neigh_lookup(), but without comparing the device
* field. This is required for the On-Ethernet cache
*/
struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, void *ptr)
struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, const void *ptr)
{
struct neighbour *neigh;
u32 hash_val;
......@@ -466,8 +482,6 @@ int dn_neigh_endnode_hello(struct sk_buff *skb)
return 0;
}
#ifdef CONFIG_DECNET_ROUTER
static char *dn_find_slot(char *base, int max, int priority)
{
int i;
......@@ -526,30 +540,106 @@ int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n)
return t;
}
#endif /* CONFIG_DECNET_ROUTER */
#ifdef CONFIG_PROC_FS
static int dn_neigh_get_info(char *buffer, char **start, off_t offset, int length)
struct dn_neigh_iter_state {
int bucket;
};
static struct neighbour *neigh_get_first(struct seq_file *seq)
{
int len = 0;
off_t pos = 0;
off_t begin = 0;
struct neighbour *n;
int i;
char buf[DN_ASCBUF_LEN];
struct dn_neigh_iter_state *state = seq->private;
struct neighbour *n = NULL;
for(state->bucket = 0;
state->bucket <= NEIGH_HASHMASK;
++state->bucket) {
n = dn_neigh_table.hash_buckets[state->bucket];
if (n)
break;
}
return n;
}
len += sprintf(buffer + len, "Addr Flags State Use Blksize Dev\n");
static struct neighbour *neigh_get_next(struct seq_file *seq,
struct neighbour *n)
{
struct dn_neigh_iter_state *state = seq->private;
n = n->next;
try_again:
if (n)
goto out;
if (++state->bucket > NEIGH_HASHMASK)
goto out;
n = dn_neigh_table.hash_buckets[state->bucket];
goto try_again;
out:
return n;
}
static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
{
struct neighbour *n = neigh_get_first(seq);
for(i=0;i <= NEIGH_HASHMASK; i++) {
if (n)
while(*pos && (n = neigh_get_next(seq, n)))
--*pos;
return *pos ? NULL : n;
}
static void *dn_neigh_get_idx(struct seq_file *seq, loff_t pos)
{
void *rc;
read_lock_bh(&dn_neigh_table.lock);
n = dn_neigh_table.hash_buckets[i];
for(; n != NULL; n = n->next) {
rc = neigh_get_idx(seq, &pos);
if (!rc) {
read_unlock_bh(&dn_neigh_table.lock);
}
return rc;
}
static void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos)
{
return *pos ? dn_neigh_get_idx(seq, *pos - 1) : (void*)1;
}
static void *dn_neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
void *rc;
if (v == (void*)1) {
rc = dn_neigh_get_idx(seq, 0);
goto out;
}
rc = neigh_get_next(seq, v);
if (rc)
goto out;
read_unlock_bh(&dn_neigh_table.lock);
out:
++*pos;
return rc;
}
static void dn_neigh_seq_stop(struct seq_file *seq, void *v)
{
if (v && v != (void*)1)
read_unlock_bh(&dn_neigh_table.lock);
}
static inline void dn_neigh_format_entry(struct seq_file *seq,
struct neighbour *n)
{
struct dn_neigh *dn = (struct dn_neigh *)n;
char buf[DN_ASCBUF_LEN];
read_lock(&n->lock);
len += sprintf(buffer+len, "%-7s %s%s%s %02x %02d %07ld %-8s\n",
seq_printf(seq, "%-7s %s%s%s %02x %02d %07ld %-8s\n",
dn_addr2asc(dn_ntohs(dn->addr), buf),
(dn->flags&DN_NDFLAG_R1) ? "1" : "-",
(dn->flags&DN_NDFLAG_R2) ? "2" : "-",
......@@ -559,45 +649,91 @@ static int dn_neigh_get_info(char *buffer, char **start, off_t offset, int lengt
dn->blksize,
(dn->n.dev) ? dn->n.dev->name : "?");
read_unlock(&n->lock);
}
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
static int dn_neigh_seq_show(struct seq_file *seq, void *v)
{
if (v == (void*)1) {
seq_puts(seq, "Addr Flags State Use Blksize Dev\n");
} else {
dn_neigh_format_entry(seq, v);
}
if (pos > offset + length) {
read_unlock_bh(&dn_neigh_table.lock);
goto done;
}
}
read_unlock_bh(&dn_neigh_table.lock);
}
return 0;
}
static struct seq_operations dn_neigh_seq_ops = {
.start = dn_neigh_seq_start,
.next = dn_neigh_seq_next,
.stop = dn_neigh_seq_stop,
.show = dn_neigh_seq_show,
};
done:
static int dn_neigh_seq_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
int rc = -ENOMEM;
struct dn_neigh_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &dn_neigh_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 int dn_seq_release(struct inode *inode, struct file *file)
{
struct seq_file *seq = (struct seq_file *)file->private_data;
*start = buffer + (offset - begin);
len -= offset - begin;
kfree(seq->private);
seq->private = NULL;
return seq_release(inode, file);
}
if (len > length) len = length;
static struct file_operations dn_neigh_seq_fops = {
.open = dn_neigh_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = dn_seq_release,
};
return len;
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);
#ifdef CONFIG_PROC_FS
proc_net_create("decnet_neigh",0,dn_neigh_get_info);
#endif /* CONFIG_PROC_FS */
dn_neigh_proc_init();
}
void __exit dn_neigh_cleanup(void)
{
proc_net_remove("decnet_neigh");
neigh_table_clear(&dn_neigh_table);
}
......@@ -434,7 +434,15 @@ static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb)
sk->state_change(sk);
}
/*
* It appears that its possible for remote machines to send disc
* init messages with no port identifier if we are in the CI and
* possibly also the CD state. Obviously we shouldn't reply with
* a message if we don't know what the end point is.
*/
if (scp->addrrem) {
dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);
}
scp->persist_fxn = dn_destroy_timer;
scp->persist = dn_nsp_persist(sk);
......
......@@ -21,6 +21,7 @@
* Paul Koning: Connect Confirm message fix.
* Eduardo Serrat: Fix to stop dn_nsp_do_disc() sending malformed packets.
* Steve Whitehouse: dn_nsp_output() and friends needed a spring clean
* Steve Whitehouse: Moved dn_nsp_send() in here from route.h
*/
/******************************************************************************
......@@ -63,6 +64,7 @@
#include <linux/if_packet.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/flow.h>
#include <net/dn.h>
#include <net/dn_nsp.h>
#include <net/dn_dev.h>
......@@ -71,6 +73,41 @@
static int nsp_backoff[NSP_MAXRXTSHIFT + 1] = { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
static void dn_nsp_send(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
struct dn_scp *scp = DN_SK(sk);
struct dst_entry *dst;
struct flowi fl;
skb->h.raw = skb->data;
scp->stamp = jiffies;
dst = sk_dst_check(sk, 0);
if (dst) {
try_again:
skb->dst = dst;
dst_output(skb);
return;
}
memset(&fl, 0, sizeof(fl));
fl.oif = sk->bound_dev_if;
fl.fld_src = dn_saddr2dn(&scp->addr);
fl.fld_dst = dn_saddr2dn(&scp->peer);
dn_sk_ports_copy(&fl, scp);
if (dn_route_output_sock(&sk->dst_cache, &fl, sk, 0) == 0) {
dst = sk_dst_get(sk);
sk->route_caps = dst->dev->features;
goto try_again;
}
sk->err = EHOSTUNREACH;
if (!test_bit(SOCK_DEAD, &sk->flags))
sk->state_change(sk);
}
/*
* If sk == NULL, then we assume that we are supposed to be making
* a routing layer skb. If sk != NULL, then we are supposed to be
......@@ -356,12 +393,33 @@ static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, un
return ptr;
}
static unsigned short *dn_nsp_mk_data_header(struct sock *sk, struct sk_buff *skb, int oth)
{
struct dn_scp *scp = DN_SK(sk);
struct dn_skb_cb *cb = DN_SKB_CB(skb);
unsigned short *ptr = dn_mk_ack_header(sk, skb, cb->nsp_flags, 11, oth);
if (unlikely(oth)) {
cb->segnum = scp->numoth;
seq_add(&scp->numoth, 1);
} else {
cb->segnum = scp->numdat;
seq_add(&scp->numdat, 1);
}
*(ptr++) = dn_htons(cb->segnum);
return ptr;
}
void dn_nsp_queue_xmit(struct sock *sk, struct sk_buff *skb, int gfp, int oth)
{
struct dn_scp *scp = DN_SK(sk);
struct dn_skb_cb *cb = DN_SKB_CB(skb);
unsigned long t = ((scp->nsp_srtt >> 2) + scp->nsp_rttvar) >> 1;
cb->xmit_count = 0;
dn_nsp_mk_data_header(sk, skb, oth);
/*
* Slow start: If we have been idle for more than
* one RTT, then reset window to min size.
......@@ -369,10 +427,6 @@ void dn_nsp_queue_xmit(struct sock *sk, struct sk_buff *skb, int gfp, int oth)
if ((jiffies - scp->stamp) > t)
scp->snd_window = NSP_MIN_WINDOW;
/* printk(KERN_DEBUG "Window: %lu\n", scp->snd_window); */
cb->xmit_count = 0;
if (oth)
skb_queue_tail(&scp->other_xmit_queue, skb);
else
......@@ -630,19 +684,15 @@ void dn_nsp_send_link(struct sock *sk, unsigned char lsflags, char fcval)
{
struct dn_scp *scp = DN_SK(sk);
struct sk_buff *skb;
unsigned short *segnum;
unsigned char *ptr;
int gfp = GFP_ATOMIC;
if ((skb = dn_alloc_skb(sk, 13, gfp)) == NULL)
if ((skb = dn_alloc_skb(sk, DN_MAX_NSP_DATA_HEADER + 2, gfp)) == NULL)
return;
skb_reserve(skb, 13);
segnum = dn_mk_ack_header(sk, skb, 0x10, 13, 1);
*segnum = dn_htons(scp->numoth);
DN_SKB_CB(skb)->segnum = scp->numoth;
seq_add(&scp->numoth, 1);
ptr = (unsigned char *)(segnum + 1);
skb_reserve(skb, DN_MAX_NSP_DATA_HEADER);
ptr = skb_put(skb, 2);
DN_SKB_CB(skb)->nsp_flags = 0x10;
*ptr++ = lsflags;
*ptr = fcval;
......
This diff is collapsed.
......@@ -26,10 +26,12 @@
#include <linux/netdevice.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/in_route.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/flow.h>
#include <net/dn.h>
#include <net/dn_fib.h>
#include <net/dn_neigh.h>
......@@ -48,6 +50,7 @@ struct dn_fib_rule
dn_address r_srcmask;
dn_address r_dst;
dn_address r_dstmask;
dn_address r_srcmap;
u8 r_flags;
#ifdef CONFIG_DECNET_ROUTE_FWMARK
u32 r_fwmark;
......@@ -60,7 +63,7 @@ struct dn_fib_rule
static struct dn_fib_rule default_rule = {
.r_clntref = ATOMIC_INIT(2),
.r_preference = 0x7fff,
.r_table = DN_DEFAULT_TABLE,
.r_table = RT_TABLE_MAIN,
.r_action = RTN_UNICAST
};
......@@ -150,6 +153,8 @@ int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2);
if (rta[RTA_DST-1])
memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 2);
if (rta[RTA_GATEWAY-1])
memcpy(&new_r->r_srcmap, RTA_DATA(rta[RTA_GATEWAY-1]), 2);
new_r->r_src_len = rtm->rtm_src_len;
new_r->r_dst_len = rtm->rtm_dst_len;
new_r->r_srcmask = dnet_make_mask(rtm->rtm_src_len);
......@@ -198,12 +203,12 @@ int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
}
int dn_fib_lookup(struct dn_fib_key *key, struct dn_fib_res *res)
int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res)
{
struct dn_fib_rule *r, *policy;
struct dn_fib_table *tb;
dn_address saddr = key->src;
dn_address daddr = key->dst;
dn_address saddr = flp->fld_src;
dn_address daddr = flp->fld_dst;
int err;
read_lock(&dn_fib_rules_lock);
......@@ -211,13 +216,14 @@ int dn_fib_lookup(struct dn_fib_key *key, struct dn_fib_res *res)
if (((saddr^r->r_src) & r->r_srcmask) ||
((daddr^r->r_dst) & r->r_dstmask) ||
#ifdef CONFIG_DECNET_ROUTE_FWMARK
(r->r_fwmark && r->r_fwmark != key->fwmark) ||
(r->r_fwmark && r->r_fwmark != flp->fld_fwmark) ||
#endif
(r->r_ifindex && r->r_ifindex != key->iif))
(r->r_ifindex && r->r_ifindex != flp->iif))
continue;
switch(r->r_action) {
case RTN_UNICAST:
case RTN_NAT:
policy = r;
break;
case RTN_UNREACHABLE:
......@@ -234,7 +240,7 @@ int dn_fib_lookup(struct dn_fib_key *key, struct dn_fib_res *res)
if ((tb = dn_fib_get_table(r->r_table, 0)) == NULL)
continue;
err = tb->lookup(tb, key, res);
err = tb->lookup(tb, flp, res);
if (err == 0) {
res->r = policy;
if (policy)
......@@ -252,6 +258,42 @@ int dn_fib_lookup(struct dn_fib_key *key, struct dn_fib_res *res)
return -ESRCH;
}
unsigned dnet_addr_type(__u16 addr)
{
struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } };
struct dn_fib_res res;
unsigned ret = RTN_UNICAST;
struct dn_fib_table *tb = dn_fib_tables[RT_TABLE_LOCAL];
res.r = NULL;
if (tb) {
if (!tb->lookup(tb, &fl, &res)) {
ret = res.type;
dn_fib_res_put(&res);
}
}
return ret;
}
__u16 dn_fib_rules_policy(__u16 saddr, struct dn_fib_res *res, unsigned *flags)
{
struct dn_fib_rule *r = res->r;
if (r->r_action == RTN_NAT) {
int addrtype = dnet_addr_type(r->r_srcmap);
if (addrtype == RTN_NAT) {
saddr = (saddr&~r->r_srcmask)|r->r_srcmap;
*flags |= RTCF_SNAT;
} else if (addrtype == RTN_LOCAL || r->r_srcmap == 0) {
saddr = r->r_srcmap;
*flags |= RTCF_MASQ;
}
}
return saddr;
}
static void dn_fib_rules_detach(struct net_device *dev)
{
struct dn_fib_rule *r;
......@@ -330,6 +372,8 @@ static int dn_fib_fill_rule(struct sk_buff *skb, struct dn_fib_rule *r, struct n
RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname);
if (r->r_preference)
RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference);
if (r->r_srcmap)
RTA_PUT(skb, RTA_GATEWAY, 2, &r->r_srcmap);
nlh->nlmsg_len = skb->tail - b;
return skb->len;
......
......@@ -30,6 +30,7 @@
#include <linux/route.h> /* RTF_xxx */
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/flow.h>
#include <net/dn.h>
#include <net/dn_route.h>
#include <net/dn_fib.h>
......@@ -45,7 +46,7 @@ struct dn_zone
u32 dz_hashmask;
#define DZ_HASHMASK(dz) ((dz)->dz_hashmask)
int dz_order;
u32 dz_mask;
u16 dz_mask;
#define DZ_MASK(dz) ((dz)->dz_mask)
};
......@@ -73,51 +74,51 @@ for( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
#define DN_FIB_SCAN_KEY(f, fp, key) \
for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
#define RT_TABLE_MIN 1
static rwlock_t dn_fib_tables_lock = RW_LOCK_UNLOCKED;
static struct dn_fib_table *dn_fib_tables[DN_NUM_TABLES + 1];
struct dn_fib_table *dn_fib_tables[RT_TABLE_MAX + 1];
static kmem_cache_t *dn_hash_kmem;
static int dn_fib_hash_zombies;
static __inline__ dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz)
static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz)
{
u32 h = ntohs(key.datum)>>(16 - dz->dz_order);
u16 h = ntohs(key.datum)>>(16 - dz->dz_order);
h ^= (h >> 10);
h ^= (h >> 6);
h ^= (h >> 3);
h &= DZ_HASHMASK(dz);
return *(dn_fib_idx_t *)&h;
}
static __inline__ dn_fib_key_t dz_key(u16 dst, struct dn_zone *dz)
static inline dn_fib_key_t dz_key(u16 dst, struct dn_zone *dz)
{
dn_fib_key_t k;
k.datum = dst & DZ_MASK(dz);
return k;
}
static __inline__ struct dn_fib_node **dn_chain_p(dn_fib_key_t key, struct dn_zone *dz)
static inline struct dn_fib_node **dn_chain_p(dn_fib_key_t key, struct dn_zone *dz)
{
return &dz->dz_hash[dn_hash(key, dz).datum];
}
static __inline__ struct dn_fib_node *dz_chain(dn_fib_key_t key, struct dn_zone *dz)
static inline struct dn_fib_node *dz_chain(dn_fib_key_t key, struct dn_zone *dz)
{
return dz->dz_hash[dn_hash(key, dz).datum];
}
static __inline__ int dn_key_eq(dn_fib_key_t a, dn_fib_key_t b)
static inline int dn_key_eq(dn_fib_key_t a, dn_fib_key_t b)
{
return a.datum == b.datum;
}
static __inline__ int dn_key_leq(dn_fib_key_t a, dn_fib_key_t b)
static inline int dn_key_leq(dn_fib_key_t a, dn_fib_key_t b)
{
return a.datum <= b.datum;
}
static __inline__ void dn_rebuild_zone(struct dn_zone *dz,
static inline void dn_rebuild_zone(struct dn_zone *dz,
struct dn_fib_node **old_ht,
int old_divisor)
{
......@@ -290,6 +291,8 @@ static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
rtm->rtm_protocol = fi->fib_protocol;
if (fi->fib_priority)
RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority);
if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0)
goto rtattr_failure;
if (fi->fib_nhs == 1) {
if (fi->fib_nh->nh_gw)
RTA_PUT(skb, RTA_GATEWAY, 2, &fi->fib_nh->nh_gw);
......@@ -654,7 +657,7 @@ static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct
return -ESRCH;
}
static __inline__ int dn_flush_list(struct dn_fib_node **fp, int z, struct dn_hash *table)
static inline int dn_flush_list(struct dn_fib_node **fp, int z, struct dn_hash *table)
{
int found = 0;
struct dn_fib_node *f;
......@@ -696,8 +699,7 @@ static int dn_fib_table_flush(struct dn_fib_table *tb)
return found;
}
static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct dn_fib_key *
key, struct dn_fib_res *res)
static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct flowi *flp, struct dn_fib_res *res)
{
int err;
struct dn_zone *dz;
......@@ -706,22 +708,26 @@ key, struct dn_fib_res *res)
read_lock(&dn_fib_tables_lock);
for(dz = t->dh_zone_list; dz; dz = dz->dz_next) {
struct dn_fib_node *f;
dn_fib_key_t k = dz_key(key->dst, dz);
dn_fib_key_t k = dz_key(flp->fld_dst, dz);
for(f = dz_chain(k, dz); f; f = f->fn_next) {
if (!dn_key_leq(k, f->fn_key))
if (!dn_key_eq(k, f->fn_key)) {
if (dn_key_leq(k, f->fn_key))
break;
else
continue;
}
f->fn_state |= DN_S_ACCESSED;
if (f->fn_state&DN_S_ZOMBIE)
continue;
if (f->fn_scope < key->scope)
if (f->fn_scope < flp->fld_scope)
continue;
err = dn_fib_semantic_match(f->fn_type, DN_FIB_INFO(f), key, res);
err = dn_fib_semantic_match(f->fn_type, DN_FIB_INFO(f), flp, res);
if (err == 0) {
res->type = f->fn_type;
res->scope = f->fn_scope;
......@@ -763,7 +769,7 @@ static void dn_fib_node_get_info(int type, int dead, struct dn_fib_info *fi, u16
if (fi) {
len = sprintf(buffer, "%s\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u",
fi->fib_dev ? fi->fib_dev->name : "*", prefix,
fi->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 {
......@@ -823,10 +829,10 @@ struct dn_fib_table *dn_fib_get_table(int n, int create)
{
struct dn_fib_table *t;
if (n < DN_MIN_TABLE)
if (n < RT_TABLE_MIN)
return NULL;
if (n > DN_NUM_TABLES)
if (n > RT_TABLE_MAX)
return NULL;
if (dn_fib_tables[n])
......@@ -839,7 +845,7 @@ struct dn_fib_table *dn_fib_get_table(int n, int create)
printk(KERN_DEBUG "DECnet: BUG! Attempt to create routing table from interrupt\n");
return NULL;
}
if ((t = kmalloc(sizeof(struct dn_fib_table), GFP_KERNEL)) == NULL)
if ((t = kmalloc(sizeof(struct dn_fib_table) + sizeof(struct dn_hash), GFP_KERNEL)) == NULL)
return NULL;
memset(t, 0, sizeof(struct dn_fib_table));
......@@ -853,6 +859,7 @@ struct dn_fib_table *dn_fib_get_table(int n, int create)
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;
return t;
......@@ -876,7 +883,7 @@ struct dn_fib_table *dn_fib_empty_table(void)
{
int id;
for(id = DN_MIN_TABLE; id <= DN_NUM_TABLES; id++)
for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++)
if (dn_fib_tables[id] == NULL)
return dn_fib_get_table(id, 1);
return NULL;
......@@ -894,7 +901,7 @@ void __exit dn_fib_table_cleanup(void)
{
int i;
for (i = 0; i < DN_NUM_TABLES + 1; ++i)
for (i = RT_TABLE_MIN; i <= RT_TABLE_MAX; ++i)
dn_fib_del_tree(i);
return;
......
......@@ -23,6 +23,7 @@
#include <linux/spinlock.h>
#include <net/sock.h>
#include <asm/atomic.h>
#include <net/flow.h>
#include <net/dn.h>
/*
......
......@@ -20,6 +20,7 @@
#include <linux/string.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/flow.h>
#include <asm/uaccess.h>
......
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