[Linux-decnet-user] DECnet routing fixes etc.
Brought to you by:
chrissie_c,
ph3-der-loewe
|
From: Steven W. <st...@gw...> - 2003-04-17 18:08:36
|
Hi,
Here is the much promised patch for DECnet routing in 2.5. My initial tests
have all been positive although I do know there are a few more things left
to do. This makes a big improvement (I think :-) and I'd therefore like to
submit this to the 2.5 kernel now. Its pretty much as it was when you last saw
it except for a few minor changes (including the name changes in dn_fib.h).
Feature list:
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 New module interface functions
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
Some notes to people using iproute2 and DECnet:
- If you list the addresses, don't be surprised to see that you get a
"peer" address appearing seemingly randomly. Just ignore it. Its down
to the iproute2 code comparing two addresses with a length of 4 bytes
where it should be using 2 bytes and I'll try and get it patched shortly,
its otherwise harmless.
- The kernel code supplies "cache info" for routing cache entries which
is never displayed. Again a patch to iproute2 will enable this
information but it makes no other difference to the operation.
Steve.
------------------------------------------------------------------------------
diff -Nru linux-2.5.67/include/net/dn.h linux/include/net/dn.h
--- linux-2.5.67/include/net/dn.h Wed Jan 1 19:21:08 2003
+++ linux/include/net/dn.h Tue Apr 1 16:56:58 2003
@@ -171,17 +171,17 @@
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;
@@ -190,6 +190,19 @@
ethaddr[4] = (unsigned char)(addr & 0xff);
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
diff -Nru linux-2.5.67/include/net/dn_dev.h linux/include/net/dn_dev.h
--- linux-2.5.67/include/net/dn_dev.h Thu Mar 6 16:38:53 2003
+++ linux/include/net/dn_dev.h Thu Apr 3 20:28:46 2003
@@ -8,6 +8,7 @@
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 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;
diff -Nru linux-2.5.67/include/net/dn_fib.h linux/include/net/dn_fib.h
--- linux-2.5.67/include/net/dn_fib.h Wed Jan 1 19:22:03 2003
+++ linux/include/net/dn_fib.h Wed Apr 9 14:30:36 2003
@@ -1,12 +1,6 @@
#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 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 @@
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 @@
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 @@
unsigned char data[0];
};
-
+#ifdef CONFIG_DECNET_ROUTER
/*
* dn_fib.c
*/
@@ -132,11 +124,12 @@
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_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_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 @@
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 */
diff -Nru linux-2.5.67/include/net/dn_neigh.h linux/include/net/dn_neigh.h
--- linux-2.5.67/include/net/dn_neigh.h Wed Jan 1 19:22:00 2003
+++ linux/include/net/dn_neigh.h Sun Mar 9 19:27:48 2003
@@ -18,7 +18,7 @@
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);
diff -Nru linux-2.5.67/include/net/dn_nsp.h linux/include/net/dn_nsp.h
--- linux-2.5.67/include/net/dn_nsp.h Wed Jan 1 19:22:43 2003
+++ linux/include/net/dn_nsp.h Tue Apr 1 11:23:50 2003
@@ -204,4 +204,6 @@
return atomic_read(&sk->rmem_alloc) > (sk->rcvbuf >> 1);
}
+#define DN_MAX_NSP_DATA_HEADER (11)
+
#endif /* _NET_DN_NSP_H */
diff -Nru linux-2.5.67/include/net/dn_route.h linux/include/net/dn_route.h
--- linux-2.5.67/include/net/dn_route.h Fri Mar 21 17:43:43 2003
+++ linux/include/net/dn_route.h Tue Apr 1 16:56:18 2003
@@ -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 @@
#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 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);
@@ -108,34 +107,6 @@
dn_rt_send(skb);
else
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 */
diff -Nru linux-2.5.67/include/net/flow.h linux/include/net/flow.h
--- linux-2.5.67/include/net/flow.h Wed Jan 1 19:23:03 2003
+++ linux/include/net/flow.h Tue Mar 25 14:48:50 2003
@@ -25,7 +25,18 @@
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
@@ -47,6 +58,14 @@
__u8 type;
__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;
diff -Nru linux-2.5.67/include/net/sock.h linux/include/net/sock.h
--- linux-2.5.67/include/net/sock.h Mon Apr 7 15:36:52 2003
+++ linux/include/net/sock.h Mon Apr 7 15:36:34 2003
@@ -868,6 +868,9 @@
* 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; \
diff -Nru linux-2.5.67/net/decnet/TODO linux/net/decnet/TODO
--- linux-2.5.67/net/decnet/TODO Wed Jan 1 19:22:34 2003
+++ linux/net/decnet/TODO Thu Apr 3 21:54:00 2003
@@ -26,25 +26,16 @@
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
@@ -53,4 +44,6 @@
o DECnet sendpages() function
o AIO for DECnet
+
+ o Eliminate dn_db->parms.blksize
diff -Nru linux-2.5.67/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- linux-2.5.67/net/decnet/af_decnet.c Fri Mar 21 17:43:44 2003
+++ linux/net/decnet/af_decnet.c Wed Apr 9 06:15:21 2003
@@ -118,6 +118,7 @@
#include <linux/netfilter.h>
#include <net/sock.h>
#include <net/tcp.h>
+#include <net/flow.h>
#include <asm/system.h>
#include <asm/ioctls.h>
#include <linux/mm.h>
@@ -146,6 +147,7 @@
#define DN_SK_HASH_SIZE (1 << DN_SK_HASH_SHIFT)
#define DN_SK_HASH_MASK (DN_SK_HASH_SIZE - 1)
+
static kmem_cache_t *dn_sk_cachep;
static struct proto_ops dn_proto_ops;
static rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;
@@ -273,7 +275,7 @@
if (hash == 0) {
hash = addr->sdn_objnamel;
- for(i = 0; i < addr->sdn_objnamel; i++) {
+ for(i = 0; i < dn_ntohs(addr->sdn_objnamel); i++) {
hash ^= addr->sdn_objname[i];
hash ^= (hash << 3);
}
@@ -468,7 +470,7 @@
dst_release(xchg(&sk->dst_cache, NULL));
- MOD_DEC_USE_COUNT;
+ module_put(THIS_MODULE);
}
struct sock *dn_alloc_sock(struct socket *sock, int gfp)
@@ -512,8 +514,7 @@
scp->services_loc = 1 | NSP_FC_NONE;
scp->info_rem = 0;
scp->info_loc = 0x03; /* NSP version 4.1 */
- scp->segsize_rem = 230; /* Default: Updated by remote segsize */
- scp->segsize_loc = 1450; /* Best guess for ethernet */
+ scp->segsize_rem = 230 - DN_MAX_NSP_DATA_HEADER; /* Default: Updated by remote segsize */
scp->nonagle = 0;
scp->multi_ireq = 1;
scp->accept_mode = ACC_IMMED;
@@ -543,7 +544,7 @@
dn_start_slow_timer(sk);
- MOD_INC_USE_COUNT;
+ try_module_get(THIS_MODULE);
return sk;
@@ -788,8 +789,8 @@
return -EINVAL;
#if 1
- if ((!capable(CAP_NET_BIND_SERVICE) && saddr->sdn_objnum) ||
- (saddr->sdn_flags & SDF_WILD))
+ if (!capable(CAP_NET_BIND_SERVICE) && (saddr->sdn_objnum ||
+ (saddr->sdn_flags & SDF_WILD)))
return -EACCES;
#else
/*
@@ -877,18 +878,18 @@
static int dn_confirm_accept(struct sock *sk, long *timeo, int allocation)
{
struct dn_scp *scp = DN_SK(sk);
- DECLARE_WAITQUEUE(wait, current);
+ DEFINE_WAIT(wait);
int err;
if (scp->state != DN_CR)
return -EINVAL;
scp->state = DN_CC;
+ scp->segsize_loc = dst_path_metric(__sk_dst_get(sk), RTAX_ADVMSS);
dn_send_conn_conf(sk, allocation);
- add_wait_queue(sk->sleep, &wait);
+ prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
for(;;) {
- set_current_state(TASK_INTERRUPTIBLE);
release_sock(sk);
if (scp->state == DN_CC)
*timeo = schedule_timeout(*timeo);
@@ -905,16 +906,21 @@
err = -EAGAIN;
if (!*timeo)
break;
+ prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
+ }
+ finish_wait(sk->sleep, &wait);
+ if (err == 0) {
+ sk->socket->state = SS_CONNECTED;
+ } else if (scp->state != DN_CC) {
+ sk->socket->state = SS_UNCONNECTED;
}
- remove_wait_queue(sk->sleep, &wait);
- current->state = TASK_RUNNING;
return err;
}
static int dn_wait_run(struct sock *sk, long *timeo)
{
struct dn_scp *scp = DN_SK(sk);
- DECLARE_WAITQUEUE(wait, current);
+ DEFINE_WAIT(wait);
int err = 0;
if (scp->state == DN_RUN)
@@ -923,9 +929,8 @@
if (!*timeo)
return -EALREADY;
- add_wait_queue(sk->sleep, &wait);
+ prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
for(;;) {
- set_current_state(TASK_INTERRUPTIBLE);
release_sock(sk);
if (scp->state == DN_CI || scp->state == DN_CC)
*timeo = schedule_timeout(*timeo);
@@ -942,12 +947,14 @@
err = -ETIMEDOUT;
if (!*timeo)
break;
+ prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
}
- remove_wait_queue(sk->sleep, &wait);
- current->state = TASK_RUNNING;
+ finish_wait(sk->sleep, &wait);
out:
if (err == 0) {
sk->socket->state = SS_CONNECTED;
+ } else if (scp->state != DN_CI && scp->state != DN_CC) {
+ sk->socket->state = SS_UNCONNECTED;
}
return err;
}
@@ -957,6 +964,7 @@
struct socket *sock = sk->socket;
struct dn_scp *scp = DN_SK(sk);
int err = -EISCONN;
+ struct flowi fl;
if (sock->state == SS_CONNECTED)
goto out;
@@ -995,12 +1003,17 @@
memcpy(&scp->peer, addr, sizeof(struct sockaddr_dn));
err = -EHOSTUNREACH;
- if (dn_route_output(&sk->dst_cache, dn_saddr2dn(&scp->peer),
- dn_saddr2dn(&scp->addr), flags & MSG_TRYHARD) < 0)
+ memset(&fl, 0, sizeof(fl));
+ fl.oif = sk->bound_dev_if;
+ fl.fld_dst = dn_saddr2dn(&scp->peer);
+ fl.fld_src = dn_saddr2dn(&scp->addr);
+ dn_sk_ports_copy(&fl, scp);
+ if (dn_route_output_sock(&sk->dst_cache, &fl, sk, flags) < 0)
goto out;
-
+ sk->route_caps = sk->dst_cache->dev->features;
sock->state = SS_CONNECTING;
scp->state = DN_CI;
+ scp->segsize_loc = dst_path_metric(sk->dst_cache, RTAX_ADVMSS);
dn_nsp_send_conninit(sk, NSP_CI);
err = -EINPROGRESS;
@@ -1077,13 +1090,12 @@
static struct sk_buff *dn_wait_for_connect(struct sock *sk, long *timeo)
{
- DECLARE_WAITQUEUE(wait, current);
+ DEFINE_WAIT(wait);
struct sk_buff *skb = NULL;
int err = 0;
- add_wait_queue_exclusive(sk->sleep, &wait);
+ prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
for(;;) {
- set_current_state(TASK_INTERRUPTIBLE);
release_sock(sk);
skb = skb_dequeue(&sk->receive_queue);
if (skb == NULL) {
@@ -1102,9 +1114,10 @@
err = -EAGAIN;
if (!*timeo)
break;
+ prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
}
- remove_wait_queue(sk->sleep, &wait);
- current->state = TASK_RUNNING;
+ finish_wait(sk->sleep, &wait);
+
return skb == NULL ? ERR_PTR(err) : skb;
}
@@ -1276,12 +1289,6 @@
release_sock(sk);
return val;
-#ifdef CONFIG_DECNET_ROUTER
- case SIOCADDRT:
- case SIOCDELRT:
- return dn_fib_ioctl(sock, cmd, arg);
-#endif /* CONFIG_DECNET_ROUTER */
-
case TIOCOUTQ:
amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
if (amount < 0)
@@ -1888,6 +1895,64 @@
return 0;
}
+/*
+ * The DECnet spec requires the the "routing layer" accepts packets which
+ * are at least 230 bytes in size. This excludes any headers which the NSP
+ * layer might add, so we always assume that we'll be using the maximal
+ * length header on data packets. The variation in length is due to the
+ * inclusion (or not) of the two 16 bit acknowledgement fields so it doesn't
+ * make much practical difference.
+ */
+unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu)
+{
+ unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER;
+ if (dev) {
+ struct dn_dev *dn_db = dev->dn_ptr;
+ mtu -= LL_RESERVED_SPACE(dev);
+ if (dn_db->use_long)
+ mtu -= 21;
+ else
+ mtu -= 6;
+ mtu -= DN_MAX_NSP_DATA_HEADER;
+ } else {
+ /*
+ * 21 = long header, 16 = guess at MAC header length
+ */
+ mtu -= (21 + DN_MAX_NSP_DATA_HEADER + 16);
+ }
+ if (mtu > mss)
+ mss = mtu;
+ return mss;
+}
+
+static inline unsigned int dn_current_mss(struct sock *sk, int flags)
+{
+ struct dst_entry *dst = __sk_dst_get(sk);
+ struct dn_scp *scp = DN_SK(sk);
+ int mss_now = min_t(int, scp->segsize_loc, scp->segsize_rem);
+
+ /* Other data messages are limited to 16 bytes per packet */
+ if (flags & MSG_OOB)
+ return 16;
+
+ /* This works out the maximum size of segment we can send out */
+ if (dst) {
+ u32 mtu = dst_pmtu(dst);
+ mss_now = min_t(int, dn_mss_from_pmtu(dst->dev, mtu), mss_now);
+ }
+
+ return mss_now;
+}
+
+static int dn_error(struct sock *sk, int flags, int err)
+{
+ if (err == -EPIPE)
+ err = sock_error(sk) ? : -EPIPE;
+ if (err == -EPIPE && !(flags & MSG_NOSIGNAL))
+ send_sig(SIGPIPE, current, 0);
+ return err;
+}
+
static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, int size)
{
@@ -1902,9 +1967,6 @@
struct sockaddr_dn *addr = (struct sockaddr_dn *)msg->msg_name;
struct sk_buff *skb = NULL;
struct dn_skb_cb *cb;
- unsigned char msgflg;
- unsigned char *ptr;
- unsigned short ack;
int len;
unsigned char fctype;
long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
@@ -1915,17 +1977,26 @@
if (addr_len && (addr_len != sizeof(struct sockaddr_dn)))
return -EINVAL;
+ /*
+ * The only difference between stream sockets and sequenced packet
+ * sockets is that the stream sockets always behave as if MSG_EOR
+ * has been set.
+ */
+ if (sock->type == SOCK_STREAM) {
+ if (flags & MSG_EOR)
+ return -EINVAL;
+ flags |= MSG_EOR;
+ }
+
lock_sock(sk);
err = dn_check_state(sk, addr, addr_len, &timeo, flags);
if (err)
- goto out;
+ goto out_err;
if (sk->shutdown & SEND_SHUTDOWN) {
- if (!(flags & MSG_NOSIGNAL))
- send_sig(SIGPIPE, current, 0);
err = -EPIPE;
- goto out;
+ goto out_err;
}
if ((flags & MSG_TRYHARD) && sk->dst_cache)
@@ -1934,20 +2005,9 @@
mss = scp->segsize_rem;
fctype = scp->services_rem & NSP_FC_MASK;
- if (sk->dst_cache && sk->dst_cache->neighbour) {
- struct dn_neigh *dn = (struct dn_neigh *)sk->dst_cache->neighbour;
- if (dn->blksize < (mss + 11))
- mss = dn->blksize - 11;
- }
-
- /*
- * The only difference between SEQPACKET & STREAM sockets under DECnet
- * is that SEQPACKET sockets set the MSG_EOR flag for the last
- * session control message segment.
- */
+ mss = dn_current_mss(sk, flags);
if (flags & MSG_OOB) {
- mss = 16;
queue = &scp->other_xmit_queue;
if (size > mss) {
err = -EMSGSIZE;
@@ -2008,7 +2068,7 @@
cb = DN_SKB_CB(skb);
- ptr = skb_put(skb, 9);
+ skb_reserve(skb, DN_MAX_NSP_DATA_HEADER);
if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
err = -EFAULT;
@@ -2016,45 +2076,26 @@
}
if (flags & MSG_OOB) {
- cb->segnum = scp->numoth;
- seq_add(&scp->numoth, 1);
- msgflg = 0x30;
- ack = (scp->numoth_rcv & 0x0FFF) | 0x8000;
- scp->ackxmt_oth = scp->numoth_rcv;
+ cb->nsp_flags = 0x30;
if (fctype != NSP_FC_NONE)
scp->flowrem_oth--;
} else {
- cb->segnum = scp->numdat;
- seq_add(&scp->numdat, 1);
- msgflg = 0x00;
- if (sock->type == SOCK_STREAM)
- msgflg = 0x60;
+ cb->nsp_flags = 0x00;
if (scp->seg_total == 0)
- msgflg |= 0x20;
+ cb->nsp_flags |= 0x20;
scp->seg_total += len;
if (((sent + len) == size) && (flags & MSG_EOR)) {
- msgflg |= 0x40;
+ cb->nsp_flags |= 0x40;
scp->seg_total = 0;
if (fctype == NSP_FC_SCMC)
scp->flowrem_dat--;
}
- ack = (scp->numdat_rcv & 0x0FFF) | 0x8000;
- scp->ackxmt_dat = scp->numdat_rcv;
if (fctype == NSP_FC_SRC)
scp->flowrem_dat--;
}
- *ptr++ = msgflg;
- *(__u16 *)ptr = scp->addrrem;
- ptr += 2;
- *(__u16 *)ptr = scp->addrloc;
- ptr += 2;
- *(__u16 *)ptr = dn_htons(ack);
- ptr += 2;
- *(__u16 *)ptr = dn_htons(cb->segnum);
-
sent += len;
dn_nsp_queue_xmit(sk, skb, sk->allocation, flags & MSG_OOB);
skb = NULL;
@@ -2070,6 +2111,11 @@
release_sock(sk);
return sent ? sent : err;
+
+out_err:
+ err = dn_error(sk, flags, err);
+ release_sock(sk);
+ return err;
}
static int dn_device_event(struct notifier_block *this, unsigned long event,
@@ -2215,10 +2261,8 @@
.sendpage = sock_no_sendpage,
};
-#ifdef CONFIG_SYSCTL
void dn_register_sysctl(void);
void dn_unregister_sysctl(void);
-#endif
MODULE_DESCRIPTION("The Linux DECnet Network Protocol");
@@ -2226,7 +2270,7 @@
MODULE_LICENSE("GPL");
-static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.40s (C) 1995-2002 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)
{
@@ -2253,16 +2297,14 @@
dn_fib_init();
#endif /* CONFIG_DECNET_ROUTER */
-#ifdef CONFIG_SYSCTL
dn_register_sysctl();
-#endif /* CONFIG_SYSCTL */
/*
* Prevent DECnet module unloading until its fixed properly.
* Requires an audit of the code to check for memory leaks and
* initialisation problems etc.
*/
- MOD_INC_USE_COUNT;
+ try_module_get(THIS_MODULE);
return 0;
@@ -2273,9 +2315,7 @@
sock_unregister(AF_DECnet);
dev_remove_pack(&dn_dix_packet_type);
-#ifdef CONFIG_SYSCTL
dn_unregister_sysctl();
-#endif /* CONFIG_SYSCTL */
unregister_netdevice_notifier(&dn_dev_notifier);
diff -Nru linux-2.5.67/net/decnet/dn_dev.c linux/net/decnet/dn_dev.c
--- linux-2.5.67/net/decnet/dn_dev.c Thu Mar 6 16:38:53 2003
+++ linux/net/decnet/dn_dev.c Thu Apr 3 23:26:31 2003
@@ -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 @@
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 @@
}
rtmsg_ifa(RTM_DELADDR, ifa1);
-
+ notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1);
if (destroy) {
dn_dev_free_ifa(ifa1);
@@ -513,6 +516,7 @@
dn_db->ifa_list = ifa;
rtmsg_ifa(RTM_NEWADDR, ifa);
+ notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
return 0;
}
@@ -609,7 +613,7 @@
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 @@
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,7 +723,10 @@
ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT;
ifm->ifa_scope = ifa->ifa_scope;
ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
- RTA_PUT(skb, IFA_LOCAL, 2, &ifa->ifa_local);
+ 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);
nlh->nlmsg_len = skb->tail - b;
@@ -758,10 +768,7 @@
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 @@
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 @@
}
-#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 @@
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 @@
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 @@
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 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
diff -Nru linux-2.5.67/net/decnet/dn_fib.c linux/net/decnet/dn_fib.c
--- linux-2.5.67/net/decnet/dn_fib.c Wed Jan 1 19:23:31 2003
+++ linux/net/decnet/dn_fib.c Mon Apr 7 11:37:06 2003
@@ -12,6 +12,9 @@
* Alexey Kuznetsov : SMP locking changes
* Steve Whitehouse : Rewrote it... Well to be more correct, I
* copied most of it from the ipv4 fib code.
+ * Steve Whitehouse : Updated it in style and fixed a few bugs
+ * which were fixed in the ipv4 code since
+ * this code was copied from it.
*
*/
#include <linux/config.h>
@@ -31,12 +34,14 @@
#include <asm/uaccess.h>
#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>
#include <net/dn_neigh.h>
#include <net/dn_dev.h>
+#define RT_MIN_TABLE 1
#define for_fib_info() { struct dn_fib_info *fi;\
for(fi = dn_fib_info_list; fi; fi = fi->fib_next)
@@ -52,7 +57,7 @@
extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
-
+static spinlock_t dn_fib_multipath_lock = SPIN_LOCK_UNLOCKED;
static struct dn_fib_info *dn_fib_info_list;
static rwlock_t dn_fib_info_lock = RW_LOCK_UNLOCKED;
int dn_fib_info_cnt;
@@ -62,18 +67,18 @@
int error;
u8 scope;
} dn_fib_props[RTA_MAX+1] = {
- { 0, RT_SCOPE_NOWHERE }, /* RTN_UNSPEC */
- { 0, RT_SCOPE_UNIVERSE }, /* RTN_UNICAST */
- { 0, RT_SCOPE_HOST }, /* RTN_LOCAL */
- { -EINVAL, RT_SCOPE_NOWHERE }, /* RTN_BROADCAST */
- { -EINVAL, RT_SCOPE_NOWHERE }, /* RTN_ANYCAST */
- { -EINVAL, RT_SCOPE_NOWHERE }, /* RTN_MULTICAST */
- { -EINVAL, RT_SCOPE_UNIVERSE }, /* RTN_BLACKHOLE */
- { -EHOSTUNREACH, RT_SCOPE_UNIVERSE }, /* RTN_UNREACHABLE */
- { -EACCES, RT_SCOPE_UNIVERSE }, /* RTN_PROHIBIT */
- { -EAGAIN, RT_SCOPE_UNIVERSE }, /* RTN_THROW */
- { -EINVAL, RT_SCOPE_NOWHERE }, /* RTN_NAT */
- { -EINVAL, RT_SCOPE_NOWHERE } /* RTN_XRESOLVE */
+ { .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 */
};
void dn_fib_free_info(struct dn_fib_info *fi)
@@ -108,7 +113,7 @@
write_unlock(&dn_fib_info_lock);
}
-static __inline__ int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
+static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
{
const struct dn_fib_nh *onh = ofi->fib_nh;
@@ -124,7 +129,7 @@
return 0;
}
-static __inline__ struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi)
+static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi)
{
for_fib_info() {
if (fi->fib_nhs != nfi->fib_nhs)
@@ -132,6 +137,7 @@
if (nfi->fib_protocol == fi->fib_protocol &&
nfi->fib_prefsrc == fi->fib_prefsrc &&
nfi->fib_priority == fi->fib_priority &&
+ memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 &&
((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
(nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0))
return fi;
@@ -195,14 +201,18 @@
int err;
if (nh->nh_gw) {
- struct dn_fib_key key;
+ struct flowi fl;
struct dn_fib_res res;
+ memset(&fl, 0, sizeof(fl));
+
if (nh->nh_flags&RTNH_F_ONLINK) {
struct net_device *dev;
if (r->rtm_scope >= RT_SCOPE_LINK)
return -EINVAL;
+ if (dnet_addr_type(nh->nh_gw) != RTN_UNICAST)
+ return -EINVAL;
if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)
return -ENODEV;
if (!(dev->flags&IFF_UP))
@@ -213,23 +223,33 @@
return 0;
}
- memset(&key, 0, sizeof(key));
- key.dst = nh->nh_gw;
- key.oif = nh->nh_oif;
- key.scope = r->rtm_scope + 1;
+ memset(&fl, 0, sizeof(fl));
+ fl.fld_dst = nh->nh_gw;
+ fl.oif = nh->nh_oif;
+ fl.fld_scope = r->rtm_scope + 1;
- if (key.scope < RT_SCOPE_LINK)
- key.scope = RT_SCOPE_LINK;
+ if (fl.fld_scope < RT_SCOPE_LINK)
+ fl.fld_scope = RT_SCOPE_LINK;
- if ((err = dn_fib_lookup(&key, &res)) != 0)
+ if ((err = dn_fib_lookup(&fl, &res)) != 0)
return err;
+ err = -EINVAL;
+ if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
+ goto out;
nh->nh_scope = res.scope;
nh->nh_oif = DN_FIB_RES_OIF(res);
nh->nh_dev = DN_FIB_RES_DEV(res);
- if (nh->nh_dev)
- atomic_inc(&nh->nh_dev->refcnt);
+ if (nh->nh_dev == NULL)
+ goto out;
+ atomic_inc(&nh->nh_dev->refcnt);
+ err = -ENETDOWN;
+ if (!(nh->nh_dev->flags & IFF_UP))
+ goto out;
+ err = 0;
+out:
dn_fib_res_put(&res);
+ return err;
} else {
struct net_device *dev;
@@ -277,6 +297,20 @@
fi->fib_flags = r->rtm_flags;
if (rta->rta_priority)
fi->fib_priority = *rta->rta_priority;
+ if (rta->rta_mx) {
+ int attrlen = RTA_PAYLOAD(rta->rta_mx);
+ struct rtattr *attr = RTA_DATA(rta->rta_mx);
+
+ while(RTA_OK(attr, attrlen)) {
+ unsigned flavour = attr->rta_type;
+ if (flavour) {
+ if (flavour > RTAX_MAX)
+ goto err_inval;
+ fi->fib_metrics[flavour-1] = *(unsigned*)RTA_DATA(attr);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+ }
if (rta->rta_prefsrc)
memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2);
@@ -297,6 +331,13 @@
nh->nh_weight = 1;
}
+ if (r->rtm_type == RTN_NAT) {
+ if (rta->rta_gw == NULL || nhs != 1 || rta->rta_oif)
+ goto err_inval;
+ memcpy(&fi->fib_nh->nh_gw, rta->rta_gw, 2);
+ goto link_it;
+ }
+
if (dn_fib_props[r->rtm_type].error) {
if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
goto err_inval;
@@ -324,14 +365,12 @@
} endfor_nexthops(fi)
}
-#if I_GET_AROUND_TO_FIXING_PREFSRC
if (fi->fib_prefsrc) {
if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
memcmp(&fi->fib_prefsrc, rta->rta_dst, 2))
- if (dn_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
+ if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
goto err_inval;
}
-#endif
link_it:
if ((ofi = dn_fib_find_info(fi)) != NULL) {
@@ -366,12 +405,53 @@
return NULL;
}
+int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowi *fl, struct dn_fib_res *res)
+{
+ int err = dn_fib_props[type].error;
+
+ if (err == 0) {
+ if (fi->fib_flags & RTNH_F_DEAD)
+ return 1;
+
+ res->fi = fi;
+
+ switch(type) {
+ case RTN_NAT:
+ DN_FIB_RES_RESET(*res);
+ atomic_inc(&fi->fib_clntref);
+ return 0;
+ case RTN_UNICAST:
+ case RTN_LOCAL:
+ for_nexthops(fi) {
+ if (nh->nh_flags & RTNH_F_DEAD)
+ continue;
+ if (!fl->oif || fl->oif == nh->nh_oif)
+ break;
+ }
+ if (nhsel < fi->fib_nhs) {
+ res->nh_sel = nhsel;
+ atomic_inc(&fi->fib_clntref);
+ return 0;
+ }
+ endfor_nexthops(fi);
+ res->fi = NULL;
+ return 1;
+ default:
+ if (net_ratelimit())
+ printk("DECnet: impossible routing event : dn_fib_semantic_match type=%d\n", type);
+ res->fi = NULL;
+ return -EINVAL;
+ }
+ }
+ return err;
+}
-void dn_fib_select_multipath(const struct dn_fib_key *key, struct dn_fib_res *res)
+void dn_fib_select_multipath(const struct flowi *fl, struct dn_fib_res *res)
{
struct dn_fib_info *fi = res->fi;
int w;
+ spin_lock_bh(&dn_fib_multipath_lock);
if (fi->fib_power <= 0) {
int power = 0;
change_nexthops(fi) {
@@ -381,6 +461,11 @@
}
} endfor_nexthops(fi);
fi->fib_power = power;
+ if (power < 0) {
+ spin_unlock_bh(&dn_fib_multipath_lock);
+ res->nh_sel = 0;
+ return;
+ }
}
w = jiffies % fi->fib_power;
@@ -391,16 +476,16 @@
nh->nh_power--;
fi->fib_power--;
res->nh_sel = nhsel;
+ spin_unlock_bh(&dn_fib_multipath_lock);
return;
}
}
} endfor_nexthops(fi);
-
- printk(KERN_DEBUG "DECnet: BUG! dn_fib_select_multipath\n");
+ res->nh_sel = 0;
+ spin_unlock_bh(&dn_fib_multipath_lock);
}
-
/*
* Punt to user via netlink for example, but for now
* we just drop it.
@@ -475,9 +560,9 @@
s_t = cb->args[0];
if (s_t == 0)
- s_t = cb->args[0] = DN_MIN_TABLE;
+ s_t = cb->args[0] = RT_MIN_TABLE;
- for(t = s_t; t < DN_NUM_TABLES; t++) {
+ for(t = s_t; t <= RT_TABLE_MAX; t++) {
if (t < s_t)
continue;
if (t > s_t)
@@ -494,6 +579,125 @@
return skb->len;
}
+static void fib_magic(int cmd, int type, __u16 dst, int dst_len, struct dn_ifaddr *ifa)
+{
+ struct dn_fib_table *tb;
+ struct {
+ struct nlmsghdr nlh;
+ struct rtmsg rtm;
+ } req;
+ struct dn_kern_rta rta;
+
+ memset(&req.rtm, 0, sizeof(req.rtm));
+ memset(&rta, 0, sizeof(rta));
+
+ if (type == RTN_UNICAST)
+ tb = dn_fib_get_table(RT_MIN_TABLE, 1);
+ else
+ tb = dn_fib_get_table(RT_TABLE_LOCAL, 1);
+
+ if (tb == NULL)
+ return;
+
+ req.nlh.nlmsg_len = sizeof(req);
+ req.nlh.nlmsg_type = cmd;
+ req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
+ req.nlh.nlmsg_pid = 0;
+ req.nlh.nlmsg_seq = 0;
+
+ req.rtm.rtm_dst_len = dst_len;
+ req.rtm.rtm_table = tb->n;
+ req.rtm.rtm_protocol = RTPROT_KERNEL;
+ req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
+ req.rtm.rtm_type = type;
+
+ rta.rta_dst = &dst;
+ rta.rta_prefsrc = &ifa->ifa_local;
+ rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
+
+ if (cmd == RTM_NEWROUTE)
+ tb->insert(tb, &req.rtm, &rta, &req.nlh, NULL);
+ else
+ tb->delete(tb, &req.rtm, &rta, &req.nlh, NULL);
+}
+
+static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa)
+{
+
+ fib_magic(RTM_NEWROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
+
+#if 0
+ if (!(dev->flags&IFF_UP))
+ return;
+ /* In the future, we will want to add default routes here */
+
+#endif
+}
+
+static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa)
+{
+ int found_it = 0;
+ struct net_device *dev;
+ struct dn_dev *dn_db;
+ struct dn_ifaddr *ifa2;
+
+ ASSERT_RTNL();
+
+ /* Scan device list */
+ read_lock(&dev_base_lock);
+ for(dev = dev_base; dev; dev = dev->next) {
+ dn_db = dev->dn_ptr;
+ if (dn_db == NULL)
+ continue;
+ for(ifa2 = dn_db->ifa_list; ifa2; ifa2 = ifa2->ifa_next) {
+ if (ifa2->ifa_local == ifa->ifa_local) {
+ found_it = 1;
+ break;
+ }
+ }
+ }
+ read_unlock(&dev_base_lock);
+
+ if (found_it == 0) {
+ fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
+
+ if (dnet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
+ if (dn_fib_sync_down(ifa->ifa_local, NULL, 0))
+ dn_fib_flush();
+ }
+ }
+}
+
+static void dn_fib_disable_addr(struct net_device *dev, int force)
+{
+ if (dn_fib_sync_down(0, dev, force))
+ dn_fib_flush();
+ dn_rt_cache_flush(0);
+ neigh_ifdown(&dn_neigh_table, dev);
+}
+
+static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct dn_ifaddr *ifa = (struct dn_ifaddr *)ptr;
+
+ switch(event) {
+ case NETDEV_UP:
+ dn_fib_add_ifaddr(ifa);
+ dn_fib_sync_up(ifa->ifa_dev->dev);
+ dn_rt_cache_flush(-1);
+ break;
+ case NETDEV_DOWN:
+ dn_fib_del_ifaddr(ifa);
+ if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
+ dn_fib_disable_addr(ifa->ifa_dev->dev, 1);
+ } else {
+ dn_rt_cache_flush(-1);
+ }
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
int dn_fib_sync_down(dn_address local, struct net_device *dev, int force)
{
int ret = 0;
@@ -520,9 +724,11 @@
dead++;
else if (nh->nh_dev == dev &&
nh->nh_scope != scope) {
+ spin_lock_bh(&dn_fib_multipath_lock);
nh->nh_flags |= RTNH_F_DEAD;
fi->fib_power -= nh->nh_power;
nh->nh_power = 0;
+ spin_unlock_bh(&dn_fib_multipath_lock);
dead++;
}
} endfor_nexthops(fi)
@@ -556,11 +762,13 @@
if (nh->nh_dev != dev || dev->dn_ptr == NULL)
continue;
alive++;
+ spin_lock_bh(&dn_fib_multipath_lock);
nh->nh_power = 0;
nh->nh_flags &= ~RTNH_F_DEAD;
+ spin_unlock_bh(&dn_fib_multipath_lock);
} endfor_nexthops(fi);
- if (alive == fi->fib_nhs) {
+ if (alive > 0) {
fi->fib_flags &= ~RTNH_F_DEAD;
ret++;
}
@@ -574,7 +782,7 @@
struct dn_fib_table *tb;
int id;
- for(id = DN_NUM_TABLES; id > 0; id--) {
+ for(id = RT_TABLE_MAX; id > 0; id--) {
if ((tb = dn_fib_get_table(id, 0)) == NULL)
continue;
flushed += tb->flush(tb);
@@ -584,21 +792,6 @@
dn_rt_cache_flush(-1);
}
-int dn_fib_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- switch(cmd) {
- case SIOCADDRT:
- case SIOCDELRT:
- return 0;
- }
-
- return -EINVAL;
-}
-
#ifdef CONFIG_PROC_FS
static int decnet_rt_get_info(char *buffer, char **start, off_t offset, int length)
@@ -620,7 +813,7 @@
}
- for(i = DN_MIN_TABLE; (i <= DN_NUM_TABLES) && (count > 0); i++) {
+ 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;
@@ -638,12 +831,18 @@
}
#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();
+
+ unregister_dnaddr_notifier(&dn_fib_dnaddr_notifier);
}
@@ -656,6 +855,8 @@
dn_fib_table_init();
dn_fib_rules_init();
+
+ register_dnaddr_notifier(&dn_fib_dnaddr_notifier);
}
diff -Nru linux-2.5.67/net/decnet/dn_neigh.c linux/net/decnet/dn_neigh.c
--- linux-2.5.67/net/decnet/dn_neigh.c Wed Jan 1 19:22:30 2003
+++ linux/net/decnet/dn_neigh.c Tue Apr 8 08:44:19 2003
@@ -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 @@
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 @@
* 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 @@
return 0;
}
-
-#ifdef CONFIG_DECNET_ROUTER
static char *dn_find_slot(char *base, int max, int priority)
{
int i;
@@ -526,78 +540,200 @@
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;
+ }
- len += sprintf(buffer + len, "Addr Flags State Use Blksize Dev\n");
+ return n;
+}
- for(i=0;i <= NEIGH_HASHMASK; i++) {
- read_lock_bh(&dn_neigh_table.lock);
- n = dn_neigh_table.hash_buckets[i];
- for(; n != NULL; n = n->next) {
- struct dn_neigh *dn = (struct dn_neigh *)n;
-
- read_lock(&n->lock);
- len += sprintf(buffer+len, "%-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" : "-",
- (dn->flags&DN_NDFLAG_P3) ? "3" : "-",
- dn->n.nud_state,
- atomic_read(&dn->n.refcnt),
- dn->blksize,
- (dn->n.dev) ? dn->n.dev->name : "?");
- read_unlock(&n->lock);
-
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
-
- if (pos > offset + length) {
- read_unlock_bh(&dn_neigh_table.lock);
- goto done;
- }
- }
+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);
+
+ 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);
+ rc = neigh_get_idx(seq, &pos);
+ if (!rc) {
read_unlock_bh(&dn_neigh_table.lock);
}
+ return rc;
+}
-done:
+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;
- *start = buffer + (offset - begin);
- len -= offset - begin;
- if (len > length) len = length;
+ if (v == (void*)1) {
+ rc = dn_neigh_get_idx(seq, 0);
+ goto out;
+ }
- return len;
+ 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);
+ 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" : "-",
+ (dn->flags&DN_NDFLAG_P3) ? "3" : "-",
+ dn->n.nud_state,
+ atomic_read(&dn->n.refcnt),
+ dn->blksize,
+ (dn->n.dev) ? dn->n.dev->name : "?");
+ read_unlock(&n->lock);
+}
+
+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);
+ }
+
+ 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,
+};
+
+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;
+
+ 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,
+};
+
+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);
}
diff -Nru linux-2.5.67/net/decnet/dn_nsp_in.c linux/net/decnet/dn_nsp_in.c
--- linux-2.5.67/net/decnet/dn_nsp_in.c Fri Mar 21 17:43:44 2003
+++ linux/net/decnet/dn_nsp_in.c Fri Mar 21 17:43:27 2003
@@ -434,7 +434,15 @@
sk->state_change(sk);
}
- dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);
+ /*
+ * 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);
diff -Nru linux-2.5.67/net/decnet/dn_nsp_out.c linux/net/decnet/dn_nsp_out.c
--- linux-2.5.67/net/decnet/dn_nsp_out.c Tue Feb 25 05:12:25 2003
+++ linux/net/decnet/dn_nsp_out.c Tue Apr 1 14:09:26 2003
@@ -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 @@
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 @@
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 @@
{
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;
diff -Nru linux-2.5.67/net/decnet/dn_route.c linux/net/decnet/dn_route.c
--- linux-2.5.67/net/decnet/dn_route.c Tue Feb 25 05:12:25 2003
+++ linux/net/decnet/dn_route.c Thu Apr 17 09:12:07 2003
@@ -37,7 +37,8 @@
* backlog congestion level return codes.
* Steve Whitehouse : Fixed bug where routes were set up with
* no ref count on net devices.
- *
+ * Steve Whitehouse : RCU for the route cache
+ * Steve Whitehouse : Preparations for the flow cache
*/
/******************************************************************************
@@ -65,17 +66,19 @@
#include <linux/netdevice.h>
#include <linux/inet.h>
#include <linux/route.h>
+#include <linux/in_route.h>
#include <net/sock.h>
-#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/rtnetlink.h>
#include <linux/string.h>
#include <linux/netfilter_decnet.h>
+#include <linux/rcupdate.h>
#include <asm/errno.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_nsp.h>
@@ -86,7 +89,7 @@
struct dn_rt_hash_bucket
{
struct dn_route *chain;
- rwlock_t lock;
+ spinlock_t lock;
} __attrib...
[truncated message content] |