aboutsummaryrefslogtreecommitdiff
path: root/net/decnet
diff options
context:
space:
mode:
Diffstat (limited to 'net/decnet')
-rw-r--r--net/decnet/Kconfig13
-rw-r--r--net/decnet/af_decnet.c1111
-rw-r--r--net/decnet/dn_dev.c834
-rw-r--r--net/decnet/dn_fib.c535
-rw-r--r--net/decnet/dn_neigh.c252
-rw-r--r--net/decnet/dn_nsp_in.c335
-rw-r--r--net/decnet/dn_nsp_out.c157
-rw-r--r--net/decnet/dn_route.c1217
-rw-r--r--net/decnet/dn_rules.c486
-rw-r--r--net/decnet/dn_table.c544
-rw-r--r--net/decnet/dn_timer.c19
-rw-r--r--net/decnet/netfilter/Kconfig3
-rw-r--r--net/decnet/netfilter/dn_rtmsg.c98
-rw-r--r--net/decnet/sysctl_net_decnet.c255
14 files changed, 2821 insertions, 3038 deletions
diff --git a/net/decnet/Kconfig b/net/decnet/Kconfig
index 92f2ec46fd2..f3393e154f0 100644
--- a/net/decnet/Kconfig
+++ b/net/decnet/Kconfig
@@ -25,8 +25,9 @@ config DECNET
The module is called decnet.
config DECNET_ROUTER
- bool "DECnet: router support (EXPERIMENTAL)"
- depends on DECNET && EXPERIMENTAL
+ bool "DECnet: router support"
+ depends on DECNET
+ select FIB_RULES
---help---
Add support for turning your DECnet Endnode into a level 1 or 2
router. This is an experimental, but functional option. If you
@@ -40,11 +41,3 @@ config DECNET_ROUTER
See <file:Documentation/networking/decnet.txt> for more information.
-config DECNET_ROUTE_FWMARK
- bool "DECnet: use FWMARK value as routing key (EXPERIMENTAL)"
- depends on DECNET_ROUTER && NETFILTER
- help
- If you say Y here, you will be able to specify different routes for
- packets with different FWMARK ("firewalling mark") values
- (see ipchains(8), "-m" argument).
-
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index ce4aaf94860..ae011b46c07 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -45,7 +45,7 @@
/******************************************************************************
(c) 1995-1998 E.M. Serrat emserrat@geocities.com
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -63,7 +63,7 @@ Version Kernel Date Author/Comments
Version 0.0.1 2.0.30 01-dic-97 Eduardo Marcelo Serrat
(emserrat@geocities.com)
- First Development of DECnet Socket La-
+ First Development of DECnet Socket La-
yer for Linux. Only supports outgoing
connections.
@@ -75,31 +75,30 @@ Version 0.0.2 2.1.105 20-jun-98 Patrick J. Caulfield
Version 0.0.3 2.1.106 25-jun-98 Eduardo Marcelo Serrat
(emserrat@geocities.com)
_
- Added support for incoming connections
- so we can start developing server apps
- on Linux.
+ Added support for incoming connections
+ so we can start developing server apps
+ on Linux.
-
Module Support
Version 0.0.4 2.1.109 21-jul-98 Eduardo Marcelo Serrat
- (emserrat@geocities.com)
- _
- Added support for X11R6.4. Now we can
- use DECnet transport for X on Linux!!!
- -
+ (emserrat@geocities.com)
+ _
+ Added support for X11R6.4. Now we can
+ use DECnet transport for X on Linux!!!
+ -
Version 0.0.5 2.1.110 01-aug-98 Eduardo Marcelo Serrat
- (emserrat@geocities.com)
- Removed bugs on flow control
- Removed bugs on incoming accessdata
- order
- -
+ (emserrat@geocities.com)
+ Removed bugs on flow control
+ Removed bugs on incoming accessdata
+ order
+ -
Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat
- dn_recvmsg fixes
+ dn_recvmsg fixes
- Patrick J. Caulfield
- dn_bind fixes
+ Patrick J. Caulfield
+ dn_bind fixes
*******************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
@@ -120,7 +119,6 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat
#include <net/sock.h>
#include <net/tcp_states.h>
#include <net/flow.h>
-#include <asm/system.h>
#include <asm/ioctls.h>
#include <linux/capability.h>
#include <linux/mm.h>
@@ -129,8 +127,10 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/poll.h>
+#include <net/net_namespace.h>
#include <net/neighbour.h>
#include <net/dst.h>
+#include <net/fib_rules.h>
#include <net/dn.h>
#include <net/dn_nsp.h>
#include <net/dn_dev.h>
@@ -154,9 +154,9 @@ static const struct proto_ops dn_proto_ops;
static DEFINE_RWLOCK(dn_hash_lock);
static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE];
static struct hlist_head dn_wild_sk;
-static atomic_t decnet_memory_allocated;
+static atomic_long_t decnet_memory_allocated;
-static int __dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen, int flags);
+static int __dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen, int flags);
static int __dn_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen, int flags);
static struct hlist_head *dn_find_list(struct sock *sk)
@@ -166,21 +166,20 @@ static struct hlist_head *dn_find_list(struct sock *sk)
if (scp->addr.sdn_flags & SDF_WILD)
return hlist_empty(&dn_wild_sk) ? &dn_wild_sk : NULL;
- return &dn_sk_hash[scp->addrloc & DN_SK_HASH_MASK];
+ return &dn_sk_hash[le16_to_cpu(scp->addrloc) & DN_SK_HASH_MASK];
}
-/*
+/*
* Valid ports are those greater than zero and not already in use.
*/
-static int check_port(unsigned short port)
+static int check_port(__le16 port)
{
struct sock *sk;
- struct hlist_node *node;
if (port == 0)
return -1;
- sk_for_each(sk, node, &dn_sk_hash[port & DN_SK_HASH_MASK]) {
+ sk_for_each(sk, &dn_sk_hash[le16_to_cpu(port) & DN_SK_HASH_MASK]) {
struct dn_scp *scp = DN_SK(sk);
if (scp->addrloc == port)
return -1;
@@ -194,12 +193,12 @@ static unsigned short port_alloc(struct sock *sk)
static unsigned short port = 0x2000;
unsigned short i_port = port;
- while(check_port(++port) != 0) {
+ while(check_port(cpu_to_le16(++port)) != 0) {
if (port == i_port)
return 0;
}
- scp->addrloc = port;
+ scp->addrloc = cpu_to_le16(port);
return 1;
}
@@ -218,7 +217,7 @@ static int dn_hash_sock(struct sock *sk)
BUG_ON(sk_hashed(sk));
write_lock_bh(&dn_hash_lock);
-
+
if (!scp->addrloc && !port_alloc(sk))
goto out;
@@ -250,11 +249,11 @@ static void dn_unhash_sock_bh(struct sock *sk)
static struct hlist_head *listen_hash(struct sockaddr_dn *addr)
{
int i;
- unsigned hash = addr->sdn_objnum;
+ unsigned int hash = addr->sdn_objnum;
if (hash == 0) {
hash = addr->sdn_objnamel;
- for(i = 0; i < dn_ntohs(addr->sdn_objnamel); i++) {
+ for(i = 0; i < le16_to_cpu(addr->sdn_objnamel); i++) {
hash ^= addr->sdn_objname[i];
hash ^= (hash << 3);
}
@@ -290,23 +289,23 @@ int dn_sockaddr2username(struct sockaddr_dn *sdn, unsigned char *buf, unsigned c
*buf++ = type;
- switch(type) {
- case 0:
- *buf++ = sdn->sdn_objnum;
- break;
- case 1:
- *buf++ = 0;
- *buf++ = dn_ntohs(sdn->sdn_objnamel);
- memcpy(buf, sdn->sdn_objname, dn_ntohs(sdn->sdn_objnamel));
- len = 3 + dn_ntohs(sdn->sdn_objnamel);
- break;
- case 2:
- memset(buf, 0, 5);
- buf += 5;
- *buf++ = dn_ntohs(sdn->sdn_objnamel);
- memcpy(buf, sdn->sdn_objname, dn_ntohs(sdn->sdn_objnamel));
- len = 7 + dn_ntohs(sdn->sdn_objnamel);
- break;
+ switch (type) {
+ case 0:
+ *buf++ = sdn->sdn_objnum;
+ break;
+ case 1:
+ *buf++ = 0;
+ *buf++ = le16_to_cpu(sdn->sdn_objnamel);
+ memcpy(buf, sdn->sdn_objname, le16_to_cpu(sdn->sdn_objnamel));
+ len = 3 + le16_to_cpu(sdn->sdn_objnamel);
+ break;
+ case 2:
+ memset(buf, 0, 5);
+ buf += 5;
+ *buf++ = le16_to_cpu(sdn->sdn_objnamel);
+ memcpy(buf, sdn->sdn_objname, le16_to_cpu(sdn->sdn_objnamel));
+ len = 7 + le16_to_cpu(sdn->sdn_objnamel);
+ break;
}
return len;
@@ -326,7 +325,7 @@ int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn *sdn,
int namel = 12;
sdn->sdn_objnum = 0;
- sdn->sdn_objnamel = dn_htons(0);
+ sdn->sdn_objnamel = cpu_to_le16(0);
memset(sdn->sdn_objname, 0, DN_MAXOBJL);
if (len < 2)
@@ -336,23 +335,23 @@ int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn *sdn,
*fmt = *data++;
type = *data++;
- switch(*fmt) {
- case 0:
- sdn->sdn_objnum = type;
- return 2;
- case 1:
- namel = 16;
- break;
- case 2:
- len -= 4;
- data += 4;
- break;
- case 4:
- len -= 8;
- data += 8;
- break;
- default:
- return -1;
+ switch (*fmt) {
+ case 0:
+ sdn->sdn_objnum = type;
+ return 2;
+ case 1:
+ namel = 16;
+ break;
+ case 2:
+ len -= 4;
+ data += 4;
+ break;
+ case 4:
+ len -= 8;
+ data += 8;
+ break;
+ default:
+ return -1;
}
len -= 1;
@@ -360,13 +359,13 @@ int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn *sdn,
if (len < 0)
return -1;
- sdn->sdn_objnamel = dn_htons(*data++);
- len -= dn_ntohs(sdn->sdn_objnamel);
+ sdn->sdn_objnamel = cpu_to_le16(*data++);
+ len -= le16_to_cpu(sdn->sdn_objnamel);
- if ((len < 0) || (dn_ntohs(sdn->sdn_objnamel) > namel))
+ if ((len < 0) || (le16_to_cpu(sdn->sdn_objnamel) > namel))
return -1;
- memcpy(sdn->sdn_objname, data, dn_ntohs(sdn->sdn_objnamel));
+ memcpy(sdn->sdn_objname, data, le16_to_cpu(sdn->sdn_objnamel));
return size - len;
}
@@ -374,11 +373,10 @@ int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn *sdn,
struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr)
{
struct hlist_head *list = listen_hash(addr);
- struct hlist_node *node;
struct sock *sk;
read_lock(&dn_hash_lock);
- sk_for_each(sk, node, list) {
+ sk_for_each(sk, list) {
struct dn_scp *scp = DN_SK(sk);
if (sk->sk_state != TCP_LISTEN)
continue;
@@ -390,7 +388,7 @@ struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr)
continue;
if (scp->addr.sdn_objnamel != addr->sdn_objnamel)
continue;
- if (memcmp(scp->addr.sdn_objname, addr->sdn_objname, dn_ntohs(addr->sdn_objnamel)) != 0)
+ if (memcmp(scp->addr.sdn_objname, addr->sdn_objname, le16_to_cpu(addr->sdn_objnamel)) != 0)
continue;
}
sock_hold(sk);
@@ -400,7 +398,7 @@ struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr)
sk = sk_head(&dn_wild_sk);
if (sk) {
- if (sk->sk_state == TCP_LISTEN)
+ if (sk->sk_state == TCP_LISTEN)
sock_hold(sk);
else
sk = NULL;
@@ -414,11 +412,10 @@ struct sock *dn_find_by_skb(struct sk_buff *skb)
{
struct dn_skb_cb *cb = DN_SKB_CB(skb);
struct sock *sk;
- struct hlist_node *node;
struct dn_scp *scp;
read_lock(&dn_hash_lock);
- sk_for_each(sk, node, &dn_sk_hash[cb->dst_port & DN_SK_HASH_MASK]) {
+ sk_for_each(sk, &dn_sk_hash[le16_to_cpu(cb->dst_port) & DN_SK_HASH_MASK]) {
scp = DN_SK(sk);
if (cb->src != dn_saddr2dn(&scp->peer))
continue;
@@ -445,12 +442,12 @@ static void dn_destruct(struct sock *sk)
skb_queue_purge(&scp->other_xmit_queue);
skb_queue_purge(&scp->other_receive_queue);
- dst_release(xchg(&sk->sk_dst_cache, NULL));
+ dst_release(rcu_dereference_check(sk->sk_dst_cache, 1));
}
static int dn_memory_pressure;
-static void dn_enter_memory_pressure(void)
+static void dn_enter_memory_pressure(struct sock *sk)
{
if (!dn_memory_pressure) {
dn_memory_pressure = 1;
@@ -470,10 +467,10 @@ static struct proto dn_proto = {
.obj_size = sizeof(struct dn_sock),
};
-static struct sock *dn_alloc_sock(struct socket *sock, gfp_t gfp)
+static struct sock *dn_alloc_sock(struct net *net, struct socket *sock, gfp_t gfp)
{
struct dn_scp *scp;
- struct sock *sk = sk_alloc(PF_DECnet, gfp, &dn_proto, 1);
+ struct sock *sk = sk_alloc(net, PF_DECnet, gfp, &dn_proto);
if (!sk)
goto out;
@@ -484,7 +481,7 @@ static struct sock *dn_alloc_sock(struct socket *sock, gfp_t gfp)
sk->sk_backlog_rcv = dn_nsp_backlog_rcv;
sk->sk_destruct = dn_destruct;
- sk->sk_no_check = 1;
+ sk->sk_no_check_tx = 1;
sk->sk_family = PF_DECnet;
sk->sk_protocol = 0;
sk->sk_allocation = gfp;
@@ -500,7 +497,7 @@ static struct sock *dn_alloc_sock(struct socket *sock, gfp_t gfp)
scp->ackxmt_oth = 0; /* Last oth data ack'ed */
scp->ackrcv_dat = 0; /* Highest data ack recv*/
scp->ackrcv_oth = 0; /* Last oth data ack rec*/
- scp->flowrem_sw = DN_SEND;
+ scp->flowrem_sw = DN_SEND;
scp->flowloc_sw = DN_SEND;
scp->flowrem_dat = 0;
scp->flowrem_oth = 1;
@@ -574,25 +571,26 @@ int dn_destroy_timer(struct sock *sk)
scp->persist = dn_nsp_persist(sk);
- switch(scp->state) {
- case DN_DI:
- dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC);
- if (scp->nsp_rxtshift >= decnet_di_count)
- scp->state = DN_CN;
- return 0;
+ switch (scp->state) {
+ case DN_DI:
+ dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC);
+ if (scp->nsp_rxtshift >= decnet_di_count)
+ scp->state = DN_CN;
+ return 0;
- case DN_DR:
- dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC);
- if (scp->nsp_rxtshift >= decnet_dr_count)
- scp->state = DN_DRC;
- return 0;
+ case DN_DR:
+ dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC);
+ if (scp->nsp_rxtshift >= decnet_dr_count)
+ scp->state = DN_DRC;
+ return 0;
- case DN_DN:
- if (scp->nsp_rxtshift < decnet_dn_count) {
- /* printk(KERN_DEBUG "dn_destroy_timer: DN\n"); */
- dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);
- return 0;
- }
+ case DN_DN:
+ if (scp->nsp_rxtshift < decnet_dn_count) {
+ /* printk(KERN_DEBUG "dn_destroy_timer: DN\n"); */
+ dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC,
+ GFP_ATOMIC);
+ return 0;
+ }
}
scp->persist = (HZ * decnet_time_wait);
@@ -622,46 +620,46 @@ static void dn_destroy_sock(struct sock *sk)
sk->sk_state = TCP_CLOSE;
- switch(scp->state) {
- case DN_DN:
- dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC,
- sk->sk_allocation);
- scp->persist_fxn = dn_destroy_timer;
- scp->persist = dn_nsp_persist(sk);
- break;
- case DN_CR:
- scp->state = DN_DR;
- goto disc_reject;
- case DN_RUN:
- scp->state = DN_DI;
- case DN_DI:
- case DN_DR:
+ switch (scp->state) {
+ case DN_DN:
+ dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC,
+ sk->sk_allocation);
+ scp->persist_fxn = dn_destroy_timer;
+ scp->persist = dn_nsp_persist(sk);
+ break;
+ case DN_CR:
+ scp->state = DN_DR;
+ goto disc_reject;
+ case DN_RUN:
+ scp->state = DN_DI;
+ case DN_DI:
+ case DN_DR:
disc_reject:
- dn_nsp_send_disc(sk, NSP_DISCINIT, 0, sk->sk_allocation);
- case DN_NC:
- case DN_NR:
- case DN_RJ:
- case DN_DIC:
- case DN_CN:
- case DN_DRC:
- case DN_CI:
- case DN_CD:
- scp->persist_fxn = dn_destroy_timer;
- scp->persist = dn_nsp_persist(sk);
- break;
- default:
- printk(KERN_DEBUG "DECnet: dn_destroy_sock passed socket in invalid state\n");
- case DN_O:
- dn_stop_slow_timer(sk);
+ dn_nsp_send_disc(sk, NSP_DISCINIT, 0, sk->sk_allocation);
+ case DN_NC:
+ case DN_NR:
+ case DN_RJ:
+ case DN_DIC:
+ case DN_CN:
+ case DN_DRC:
+ case DN_CI:
+ case DN_CD:
+ scp->persist_fxn = dn_destroy_timer;
+ scp->persist = dn_nsp_persist(sk);
+ break;
+ default:
+ printk(KERN_DEBUG "DECnet: dn_destroy_sock passed socket in invalid state\n");
+ case DN_O:
+ dn_stop_slow_timer(sk);
- dn_unhash_sock_bh(sk);
- sock_put(sk);
+ dn_unhash_sock_bh(sk);
+ sock_put(sk);
- break;
+ break;
}
}
-char *dn_addr2asc(dn_address addr, char *buf)
+char *dn_addr2asc(__u16 addr, char *buf)
{
unsigned short node, area;
@@ -674,23 +672,27 @@ char *dn_addr2asc(dn_address addr, char *buf)
-static int dn_create(struct socket *sock, int protocol)
+static int dn_create(struct net *net, struct socket *sock, int protocol,
+ int kern)
{
struct sock *sk;
- switch(sock->type) {
- case SOCK_SEQPACKET:
- if (protocol != DNPROTO_NSP)
- return -EPROTONOSUPPORT;
- break;
- case SOCK_STREAM:
- break;
- default:
- return -ESOCKTNOSUPPORT;
+ if (!net_eq(net, &init_net))
+ return -EAFNOSUPPORT;
+
+ switch (sock->type) {
+ case SOCK_SEQPACKET:
+ if (protocol != DNPROTO_NSP)
+ return -EPROTONOSUPPORT;
+ break;
+ case SOCK_STREAM:
+ break;
+ default:
+ return -ESOCKTNOSUPPORT;
}
- if ((sk = dn_alloc_sock(sock, GFP_KERNEL)) == NULL)
+ if ((sk = dn_alloc_sock(net, sock, GFP_KERNEL)) == NULL)
return -ENOBUFS;
sk->sk_protocol = protocol;
@@ -713,7 +715,7 @@ dn_release(struct socket *sock)
sock_put(sk);
}
- return 0;
+ return 0;
}
static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
@@ -721,7 +723,7 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sock *sk = sock->sk;
struct dn_scp *scp = DN_SK(sk);
struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr;
- struct net_device *dev;
+ struct net_device *dev, *ldev;
int rv;
if (addr_len != sizeof(struct sockaddr_dn))
@@ -730,10 +732,10 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if (saddr->sdn_family != AF_DECnet)
return -EINVAL;
- if (dn_ntohs(saddr->sdn_nodeaddrl) && (dn_ntohs(saddr->sdn_nodeaddrl) != 2))
+ if (le16_to_cpu(saddr->sdn_nodeaddrl) && (le16_to_cpu(saddr->sdn_nodeaddrl) != 2))
return -EINVAL;
- if (dn_ntohs(saddr->sdn_objnamel) > DN_MAXOBJL)
+ if (le16_to_cpu(saddr->sdn_objnamel) > DN_MAXOBJL)
return -EINVAL;
if (saddr->sdn_flags & ~SDF_WILD)
@@ -744,16 +746,19 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
return -EACCES;
if (!(saddr->sdn_flags & SDF_WILD)) {
- if (dn_ntohs(saddr->sdn_nodeaddrl)) {
- read_lock(&dev_base_lock);
- for(dev = dev_base; dev; dev = dev->next) {
+ if (le16_to_cpu(saddr->sdn_nodeaddrl)) {
+ rcu_read_lock();
+ ldev = NULL;
+ for_each_netdev_rcu(&init_net, dev) {
if (!dev->dn_ptr)
continue;
- if (dn_dev_islocal(dev, dn_saddr2dn(saddr)))
+ if (dn_dev_islocal(dev, dn_saddr2dn(saddr))) {
+ ldev = dev;
break;
+ }
}
- read_unlock(&dev_base_lock);
- if (dev == NULL)
+ rcu_read_unlock();
+ if (ldev == NULL)
return -EADDRNOTAVAIL;
}
}
@@ -770,7 +775,7 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
}
release_sock(sk);
- return rv;
+ return rv;
}
@@ -791,17 +796,17 @@ static int dn_auto_bind(struct socket *sock)
*/
if ((scp->accessdata.acc_accl != 0) &&
(scp->accessdata.acc_accl <= 12)) {
-
- scp->addr.sdn_objnamel = dn_htons(scp->accessdata.acc_accl);
- memcpy(scp->addr.sdn_objname, scp->accessdata.acc_acc, dn_ntohs(scp->addr.sdn_objnamel));
+
+ scp->addr.sdn_objnamel = cpu_to_le16(scp->accessdata.acc_accl);
+ memcpy(scp->addr.sdn_objname, scp->accessdata.acc_acc, le16_to_cpu(scp->addr.sdn_objnamel));
scp->accessdata.acc_accl = 0;
memset(scp->accessdata.acc_acc, 0, 40);
}
/* End of compatibility stuff */
- scp->addr.sdn_add.a_len = dn_htons(2);
- rv = dn_dev_bind_default((dn_address *)scp->addr.sdn_add.a_addr);
+ scp->addr.sdn_add.a_len = cpu_to_le16(2);
+ rv = dn_dev_bind_default((__le16 *)scp->addr.sdn_add.a_addr);
if (rv == 0) {
rv = dn_hash_sock(sk);
if (rv)
@@ -821,10 +826,10 @@ static int dn_confirm_accept(struct sock *sk, long *timeo, gfp_t allocation)
return -EINVAL;
scp->state = DN_CC;
- scp->segsize_loc = dst_metric(__sk_dst_get(sk), RTAX_ADVMSS);
+ scp->segsize_loc = dst_metric_advmss(__sk_dst_get(sk));
dn_send_conn_conf(sk, allocation);
- prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
for(;;) {
release_sock(sk);
if (scp->state == DN_CC)
@@ -842,9 +847,9 @@ static int dn_confirm_accept(struct sock *sk, long *timeo, gfp_t allocation)
err = -EAGAIN;
if (!*timeo)
break;
- prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
}
- finish_wait(sk->sk_sleep, &wait);
+ finish_wait(sk_sleep(sk), &wait);
if (err == 0) {
sk->sk_socket->state = SS_CONNECTED;
} else if (scp->state != DN_CC) {
@@ -865,7 +870,7 @@ static int dn_wait_run(struct sock *sk, long *timeo)
if (!*timeo)
return -EALREADY;
- prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
for(;;) {
release_sock(sk);
if (scp->state == DN_CI || scp->state == DN_CC)
@@ -883,9 +888,9 @@ static int dn_wait_run(struct sock *sk, long *timeo)
err = -ETIMEDOUT;
if (!*timeo)
break;
- prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
}
- finish_wait(sk->sk_sleep, &wait);
+ finish_wait(sk_sleep(sk), &wait);
out:
if (err == 0) {
sk->sk_socket->state = SS_CONNECTED;
@@ -900,7 +905,8 @@ static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen,
struct socket *sock = sk->sk_socket;
struct dn_scp *scp = DN_SK(sk);
int err = -EISCONN;
- struct flowi fl;
+ struct flowidn fld;
+ struct dst_entry *dst;
if (sock->state == SS_CONNECTED)
goto out;
@@ -939,18 +945,19 @@ static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen,
memcpy(&scp->peer, addr, sizeof(struct sockaddr_dn));
err = -EHOSTUNREACH;
- memset(&fl, 0, sizeof(fl));
- fl.oif = sk->sk_bound_dev_if;
- fl.fld_dst = dn_saddr2dn(&scp->peer);
- fl.fld_src = dn_saddr2dn(&scp->addr);
- dn_sk_ports_copy(&fl, scp);
- fl.proto = DNPROTO_NSP;
- if (dn_route_output_sock(&sk->sk_dst_cache, &fl, sk, flags) < 0)
+ memset(&fld, 0, sizeof(fld));
+ fld.flowidn_oif = sk->sk_bound_dev_if;
+ fld.daddr = dn_saddr2dn(&scp->peer);
+ fld.saddr = dn_saddr2dn(&scp->addr);
+ dn_sk_ports_copy(&fld, scp);
+ fld.flowidn_proto = DNPROTO_NSP;
+ if (dn_route_output_sock(&sk->sk_dst_cache, &fld, sk, flags) < 0)
goto out;
- sk->sk_route_caps = sk->sk_dst_cache->dev->features;
+ dst = __sk_dst_get(sk);
+ sk->sk_route_caps = dst->dev->features;
sock->state = SS_CONNECTING;
scp->state = DN_CI;
- scp->segsize_loc = dst_metric(sk->sk_dst_cache, RTAX_ADVMSS);
+ scp->segsize_loc = dst_metric_advmss(dst);
dn_nsp_send_conninit(sk, NSP_CI);
err = -EINPROGRESS;
@@ -979,16 +986,16 @@ static inline int dn_check_state(struct sock *sk, struct sockaddr_dn *addr, int
{
struct dn_scp *scp = DN_SK(sk);
- switch(scp->state) {
- case DN_RUN:
- return 0;
- case DN_CR:
- return dn_confirm_accept(sk, timeo, sk->sk_allocation);
- case DN_CI:
- case DN_CC:
- return dn_wait_run(sk, timeo);
- case DN_O:
- return __dn_connect(sk, addr, addrlen, timeo, flags);
+ switch (scp->state) {
+ case DN_RUN:
+ return 0;
+ case DN_CR:
+ return dn_confirm_accept(sk, timeo, sk->sk_allocation);
+ case DN_CI:
+ case DN_CC:
+ return dn_wait_run(sk, timeo);
+ case DN_O:
+ return __dn_connect(sk, addr, addrlen, timeo, flags);
}
return -EINVAL;
@@ -997,32 +1004,33 @@ static inline int dn_check_state(struct sock *sk, struct sockaddr_dn *addr, int
static void dn_access_copy(struct sk_buff *skb, struct accessdata_dn *acc)
{
- unsigned char *ptr = skb->data;
+ unsigned char *ptr = skb->data;
- acc->acc_userl = *ptr++;
- memcpy(&acc->acc_user, ptr, acc->acc_userl);
- ptr += acc->acc_userl;
+ acc->acc_userl = *ptr++;
+ memcpy(&acc->acc_user, ptr, acc->acc_userl);
+ ptr += acc->acc_userl;
- acc->acc_passl = *ptr++;
- memcpy(&acc->acc_pass, ptr, acc->acc_passl);
- ptr += acc->acc_passl;
+ acc->acc_passl = *ptr++;
+ memcpy(&acc->acc_pass, ptr, acc->acc_passl);
+ ptr += acc->acc_passl;
- acc->acc_accl = *ptr++;
- memcpy(&acc->acc_acc, ptr, acc->acc_accl);
+ acc->acc_accl = *ptr++;
+ memcpy(&acc->acc_acc, ptr, acc->acc_accl);
- skb_pull(skb, acc->acc_accl + acc->acc_passl + acc->acc_userl + 3);
+ skb_pull(skb, acc->acc_accl + acc->acc_passl + acc->acc_userl + 3);
}
static void dn_user_copy(struct sk_buff *skb, struct optdata_dn *opt)
{
- unsigned char *ptr = skb->data;
-
- opt->opt_optl = *ptr++;
- opt->opt_status = 0;
- memcpy(opt->opt_data, ptr, opt->opt_optl);
- skb_pull(skb, opt->opt_optl + 1);
-
+ unsigned char *ptr = skb->data;
+ u16 len = *ptr++; /* yes, it's 8bit on the wire */
+
+ BUG_ON(len > 16); /* we've checked the contents earlier */
+ opt->opt_optl = cpu_to_le16(len);
+ opt->opt_status = 0;
+ memcpy(opt->opt_data, ptr, len);
+ skb_pull(skb, len + 1);
}
static struct sk_buff *dn_wait_for_connect(struct sock *sk, long *timeo)
@@ -1031,7 +1039,7 @@ static struct sk_buff *dn_wait_for_connect(struct sock *sk, long *timeo)
struct sk_buff *skb = NULL;
int err = 0;
- prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
for(;;) {
release_sock(sk);
skb = skb_dequeue(&sk->sk_receive_queue);
@@ -1051,9 +1059,9 @@ static struct sk_buff *dn_wait_for_connect(struct sock *sk, long *timeo)
err = -EAGAIN;
if (!*timeo)
break;
- prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
}
- finish_wait(sk->sk_sleep, &wait);
+ finish_wait(sk_sleep(sk), &wait);
return skb == NULL ? ERR_PTR(err) : skb;
}
@@ -1067,10 +1075,11 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
int err = 0;
unsigned char type;
long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+ struct dst_entry *dst;
lock_sock(sk);
- if (sk->sk_state != TCP_LISTEN || DN_SK(sk)->state != DN_O) {
+ if (sk->sk_state != TCP_LISTEN || DN_SK(sk)->state != DN_O) {
release_sock(sk);
return -EINVAL;
}
@@ -1086,7 +1095,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
cb = DN_SKB_CB(skb);
sk->sk_ack_backlog--;
- newsk = dn_alloc_sock(newsock, sk->sk_allocation);
+ newsk = dn_alloc_sock(sock_net(sk), newsock, sk->sk_allocation);
if (newsk == NULL) {
release_sock(sk);
kfree_skb(skb);
@@ -1094,16 +1103,17 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
}
release_sock(sk);
- dst_release(xchg(&newsk->sk_dst_cache, skb->dst));
- skb->dst = NULL;
+ dst = skb_dst(skb);
+ sk_dst_set(newsk, dst);
+ skb_dst_set(skb, NULL);
- DN_SK(newsk)->state = DN_CR;
+ DN_SK(newsk)->state = DN_CR;
DN_SK(newsk)->addrrem = cb->src_port;
DN_SK(newsk)->services_rem = cb->services;
DN_SK(newsk)->info_rem = cb->info;
DN_SK(newsk)->segsize_rem = cb->segsize;
DN_SK(newsk)->accept_mode = DN_SK(sk)->accept_mode;
-
+
if (DN_SK(newsk)->segsize_rem < 230)
DN_SK(newsk)->segsize_rem = 230;
@@ -1121,8 +1131,8 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->addr), &type));
skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->peer), &type));
- *(dn_address *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src;
- *(dn_address *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst;
+ *(__le16 *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src;
+ *(__le16 *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst;
menuver = *skb->data;
skb_pull(skb, 1);
@@ -1153,15 +1163,15 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
dn_send_conn_ack(newsk);
/*
- * Here we use sk->sk_allocation since although the conn conf is
- * for the newsk, the context is the old socket.
- */
+ * Here we use sk->sk_allocation since although the conn conf is
+ * for the newsk, the context is the old socket.
+ */
if (DN_SK(newsk)->accept_mode == ACC_IMMED)
err = dn_confirm_accept(newsk, &timeo,
sk->sk_allocation);
}
release_sock(newsk);
- return err;
+ return err;
}
@@ -1176,10 +1186,12 @@ static int dn_getname(struct socket *sock, struct sockaddr *uaddr,int *uaddr_len
lock_sock(sk);
if (peer) {
- if ((sock->state != SS_CONNECTED &&
- sock->state != SS_CONNECTING) &&
- scp->accept_mode == ACC_IMMED)
+ if ((sock->state != SS_CONNECTED &&
+ sock->state != SS_CONNECTING) &&
+ scp->accept_mode == ACC_IMMED) {
+ release_sock(sk);
return -ENOTCONN;
+ }
memcpy(sa, &scp->peer, sizeof(struct sockaddr_dn));
} else {
@@ -1188,7 +1200,7 @@ static int dn_getname(struct socket *sock, struct sockaddr *uaddr,int *uaddr_len
release_sock(sk);
- return 0;
+ return 0;
}
@@ -1228,7 +1240,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return val;
case TIOCOUTQ:
- amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+ amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
if (amount < 0)
amount = 0;
err = put_user(amount, (int __user *)arg);
@@ -1236,17 +1248,12 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case TIOCINQ:
lock_sock(sk);
- if ((skb = skb_peek(&scp->other_receive_queue)) != NULL) {
+ skb = skb_peek(&scp->other_receive_queue);
+ if (skb) {
amount = skb->len;
} else {
- struct sk_buff *skb = sk->sk_receive_queue.next;
- for(;;) {
- if (skb ==
- (struct sk_buff *)&sk->sk_receive_queue)
- break;
+ skb_queue_walk(&sk->sk_receive_queue, skb)
amount += skb->len;
- skb = skb->next;
- }
}
release_sock(sk);
err = put_user(amount, (int __user *)arg);
@@ -1282,7 +1289,7 @@ static int dn_listen(struct socket *sock, int backlog)
out:
release_sock(sk);
- return err;
+ return err;
}
@@ -1305,10 +1312,10 @@ static int dn_shutdown(struct socket *sock, int how)
if (scp->state == DN_O)
goto out;
- if (how != SHUTDOWN_MASK)
+ if (how != SHUT_RDWR)
goto out;
- sk->sk_shutdown = how;
+ sk->sk_shutdown = SHUTDOWN_MASK;
dn_destroy_sock(sk);
err = 0;
@@ -1318,7 +1325,7 @@ out:
return err;
}
-static int dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
+static int dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
int err;
@@ -1330,7 +1337,7 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char __use
return err;
}
-static int __dn_setsockopt(struct socket *sock, int level,int optname, char __user *optval, int optlen, int flags)
+static int __dn_setsockopt(struct socket *sock, int level,int optname, char __user *optval, unsigned int optlen, int flags)
{
struct sock *sk = sock->sk;
struct dn_scp *scp = DN_SK(sk);
@@ -1355,141 +1362,140 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
if (copy_from_user(&u, optval, optlen))
return -EFAULT;
- switch(optname) {
- case DSO_CONDATA:
- if (sock->state == SS_CONNECTED)
- return -EISCONN;
- if ((scp->state != DN_O) && (scp->state != DN_CR))
- return -EINVAL;
+ switch (optname) {
+ case DSO_CONDATA:
+ if (sock->state == SS_CONNECTED)
+ return -EISCONN;
+ if ((scp->state != DN_O) && (scp->state != DN_CR))
+ return -EINVAL;
- if (optlen != sizeof(struct optdata_dn))
- return -EINVAL;
+ if (optlen != sizeof(struct optdata_dn))
+ return -EINVAL;
- if (u.opt.opt_optl > 16)
- return -EINVAL;
+ if (le16_to_cpu(u.opt.opt_optl) > 16)
+ return -EINVAL;
- memcpy(&scp->conndata_out, &u.opt, optlen);
- break;
+ memcpy(&scp->conndata_out, &u.opt, optlen);
+ break;
- case DSO_DISDATA:
- if (sock->state != SS_CONNECTED && scp->accept_mode == ACC_IMMED)
- return -ENOTCONN;
+ case DSO_DISDATA:
+ if (sock->state != SS_CONNECTED &&
+ scp->accept_mode == ACC_IMMED)
+ return -ENOTCONN;
- if (optlen != sizeof(struct optdata_dn))
- return -EINVAL;
+ if (optlen != sizeof(struct optdata_dn))
+ return -EINVAL;
- if (u.opt.opt_optl > 16)
- return -EINVAL;
+ if (le16_to_cpu(u.opt.opt_optl) > 16)
+ return -EINVAL;
- memcpy(&scp->discdata_out, &u.opt, optlen);
- break;
-
- case DSO_CONACCESS:
- if (sock->state == SS_CONNECTED)
- return -EISCONN;
- if (scp->state != DN_O)
- return -EINVAL;
+ memcpy(&scp->discdata_out, &u.opt, optlen);
+ break;
- if (optlen != sizeof(struct accessdata_dn))
- return -EINVAL;
+ case DSO_CONACCESS:
+ if (sock->state == SS_CONNECTED)
+ return -EISCONN;
+ if (scp->state != DN_O)
+ return -EINVAL;
- if ((u.acc.acc_accl > DN_MAXACCL) ||
- (u.acc.acc_passl > DN_MAXACCL) ||
- (u.acc.acc_userl > DN_MAXACCL))
- return -EINVAL;
+ if (optlen != sizeof(struct accessdata_dn))
+ return -EINVAL;
- memcpy(&scp->accessdata, &u.acc, optlen);
- break;
+ if ((u.acc.acc_accl > DN_MAXACCL) ||
+ (u.acc.acc_passl > DN_MAXACCL) ||
+ (u.acc.acc_userl > DN_MAXACCL))
+ return -EINVAL;
- case DSO_ACCEPTMODE:
- if (sock->state == SS_CONNECTED)
- return -EISCONN;
- if (scp->state != DN_O)
- return -EINVAL;
+ memcpy(&scp->accessdata, &u.acc, optlen);
+ break;
- if (optlen != sizeof(int))
- return -EINVAL;
+ case DSO_ACCEPTMODE:
+ if (sock->state == SS_CONNECTED)
+ return -EISCONN;
+ if (scp->state != DN_O)
+ return -EINVAL;
- if ((u.mode != ACC_IMMED) && (u.mode != ACC_DEFER))
- return -EINVAL;
+ if (optlen != sizeof(int))
+ return -EINVAL;
- scp->accept_mode = (unsigned char)u.mode;
- break;
+ if ((u.mode != ACC_IMMED) && (u.mode != ACC_DEFER))
+ return -EINVAL;
- case DSO_CONACCEPT:
-
- if (scp->state != DN_CR)
- return -EINVAL;
- timeo = sock_rcvtimeo(sk, 0);
- err = dn_confirm_accept(sk, &timeo, sk->sk_allocation);
- return err;
+ scp->accept_mode = (unsigned char)u.mode;
+ break;
- case DSO_CONREJECT:
+ case DSO_CONACCEPT:
+ if (scp->state != DN_CR)
+ return -EINVAL;
+ timeo = sock_rcvtimeo(sk, 0);
+ err = dn_confirm_accept(sk, &timeo, sk->sk_allocation);
+ return err;
- if (scp->state != DN_CR)
- return -EINVAL;
+ case DSO_CONREJECT:
+ if (scp->state != DN_CR)
+ return -EINVAL;
- scp->state = DN_DR;
- sk->sk_shutdown = SHUTDOWN_MASK;
- dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation);
- break;
+ scp->state = DN_DR;
+ sk->sk_shutdown = SHUTDOWN_MASK;
+ dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation);
+ break;
- default:
+ default:
#ifdef CONFIG_NETFILTER
return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
#endif
- case DSO_LINKINFO:
- case DSO_STREAM:
- case DSO_SEQPACKET:
- return -ENOPROTOOPT;
-
- case DSO_MAXWINDOW:
- if (optlen != sizeof(unsigned long))
- return -EINVAL;
- if (u.win > NSP_MAX_WINDOW)
- u.win = NSP_MAX_WINDOW;
- if (u.win == 0)
- return -EINVAL;
- scp->max_window = u.win;
- if (scp->snd_window > u.win)
- scp->snd_window = u.win;
- break;
+ case DSO_LINKINFO:
+ case DSO_STREAM:
+ case DSO_SEQPACKET:
+ return -ENOPROTOOPT;
+
+ case DSO_MAXWINDOW:
+ if (optlen != sizeof(unsigned long))
+ return -EINVAL;
+ if (u.win > NSP_MAX_WINDOW)
+ u.win = NSP_MAX_WINDOW;
+ if (u.win == 0)
+ return -EINVAL;
+ scp->max_window = u.win;
+ if (scp->snd_window > u.win)
+ scp->snd_window = u.win;
+ break;
- case DSO_NODELAY:
- if (optlen != sizeof(int))
- return -EINVAL;
- if (scp->nonagle == 2)
- return -EINVAL;
- scp->nonagle = (u.val == 0) ? 0 : 1;
- /* if (scp->nonagle == 1) { Push pending frames } */
- break;
+ case DSO_NODELAY:
+ if (optlen != sizeof(int))
+ return -EINVAL;
+ if (scp->nonagle == 2)
+ return -EINVAL;
+ scp->nonagle = (u.val == 0) ? 0 : 1;
+ /* if (scp->nonagle == 1) { Push pending frames } */
+ break;
- case DSO_CORK:
- if (optlen != sizeof(int))
- return -EINVAL;
- if (scp->nonagle == 1)
- return -EINVAL;
- scp->nonagle = (u.val == 0) ? 0 : 2;
- /* if (scp->nonagle == 0) { Push pending frames } */
- break;
+ case DSO_CORK:
+ if (optlen != sizeof(int))
+ return -EINVAL;
+ if (scp->nonagle == 1)
+ return -EINVAL;
+ scp->nonagle = (u.val == 0) ? 0 : 2;
+ /* if (scp->nonagle == 0) { Push pending frames } */
+ break;
- case DSO_SERVICES:
- if (optlen != sizeof(unsigned char))
- return -EINVAL;
- if ((u.services & ~NSP_FC_MASK) != 0x01)
- return -EINVAL;
- if ((u.services & NSP_FC_MASK) == NSP_FC_MASK)
- return -EINVAL;
- scp->services_loc = u.services;
- break;
+ case DSO_SERVICES:
+ if (optlen != sizeof(unsigned char))
+ return -EINVAL;
+ if ((u.services & ~NSP_FC_MASK) != 0x01)
+ return -EINVAL;
+ if ((u.services & NSP_FC_MASK) == NSP_FC_MASK)
+ return -EINVAL;
+ scp->services_loc = u.services;
+ break;
- case DSO_INFO:
- if (optlen != sizeof(unsigned char))
- return -EINVAL;
- if (u.info & 0xfc)
- return -EINVAL;
- scp->info_loc = u.info;
- break;
+ case DSO_INFO:
+ if (optlen != sizeof(unsigned char))
+ return -EINVAL;
+ if (u.info & 0xfc)
+ return -EINVAL;
+ scp->info_loc = u.info;
+ break;
}
return 0;
@@ -1518,106 +1524,107 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
if(get_user(r_len , optlen))
return -EFAULT;
-
- switch(optname) {
- case DSO_CONDATA:
- if (r_len > sizeof(struct optdata_dn))
- r_len = sizeof(struct optdata_dn);
- r_data = &scp->conndata_in;
- break;
- case DSO_DISDATA:
- if (r_len > sizeof(struct optdata_dn))
- r_len = sizeof(struct optdata_dn);
- r_data = &scp->discdata_in;
- break;
+ switch (optname) {
+ case DSO_CONDATA:
+ if (r_len > sizeof(struct optdata_dn))
+ r_len = sizeof(struct optdata_dn);
+ r_data = &scp->conndata_in;
+ break;
- case DSO_CONACCESS:
- if (r_len > sizeof(struct accessdata_dn))
- r_len = sizeof(struct accessdata_dn);
- r_data = &scp->accessdata;
- break;
+ case DSO_DISDATA:
+ if (r_len > sizeof(struct optdata_dn))
+ r_len = sizeof(struct optdata_dn);
+ r_data = &scp->discdata_in;
+ break;
- case DSO_ACCEPTMODE:
- if (r_len > sizeof(unsigned char))
- r_len = sizeof(unsigned char);
- r_data = &scp->accept_mode;
- break;
+ case DSO_CONACCESS:
+ if (r_len > sizeof(struct accessdata_dn))
+ r_len = sizeof(struct accessdata_dn);
+ r_data = &scp->accessdata;
+ break;
- case DSO_LINKINFO:
- if (r_len > sizeof(struct linkinfo_dn))
- r_len = sizeof(struct linkinfo_dn);
+ case DSO_ACCEPTMODE:
+ if (r_len > sizeof(unsigned char))
+ r_len = sizeof(unsigned char);
+ r_data = &scp->accept_mode;
+ break;
- switch(sock->state) {
- case SS_CONNECTING:
- link.idn_linkstate = LL_CONNECTING;
- break;
- case SS_DISCONNECTING:
- link.idn_linkstate = LL_DISCONNECTING;
- break;
- case SS_CONNECTED:
- link.idn_linkstate = LL_RUNNING;
- break;
- default:
- link.idn_linkstate = LL_INACTIVE;
- }
+ case DSO_LINKINFO:
+ if (r_len > sizeof(struct linkinfo_dn))
+ r_len = sizeof(struct linkinfo_dn);
- link.idn_segsize = scp->segsize_rem;
- r_data = &link;
- break;
+ memset(&link, 0, sizeof(link));
+ switch (sock->state) {
+ case SS_CONNECTING:
+ link.idn_linkstate = LL_CONNECTING;
+ break;
+ case SS_DISCONNECTING:
+ link.idn_linkstate = LL_DISCONNECTING;
+ break;
+ case SS_CONNECTED:
+ link.idn_linkstate = LL_RUNNING;
+ break;
default:
-#ifdef CONFIG_NETFILTER
- {
- int val, len;
-
- if(get_user(len, optlen))
- return -EFAULT;
-
- val = nf_getsockopt(sk, PF_DECnet, optname,
- optval, &len);
- if (val >= 0)
- val = put_user(len, optlen);
- return val;
+ link.idn_linkstate = LL_INACTIVE;
}
+
+ link.idn_segsize = scp->segsize_rem;
+ r_data = &link;
+ break;
+
+ default:
+#ifdef CONFIG_NETFILTER
+ {
+ int ret, len;
+
+ if (get_user(len, optlen))
+ return -EFAULT;
+
+ ret = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
+ if (ret >= 0)
+ ret = put_user(len, optlen);
+ return ret;
+ }
#endif
- case DSO_STREAM:
- case DSO_SEQPACKET:
- case DSO_CONACCEPT:
- case DSO_CONREJECT:
- return -ENOPROTOOPT;
-
- case DSO_MAXWINDOW:
- if (r_len > sizeof(unsigned long))
- r_len = sizeof(unsigned long);
- r_data = &scp->max_window;
- break;
+ case DSO_STREAM:
+ case DSO_SEQPACKET:
+ case DSO_CONACCEPT:
+ case DSO_CONREJECT:
+ return -ENOPROTOOPT;
+
+ case DSO_MAXWINDOW:
+ if (r_len > sizeof(unsigned long))
+ r_len = sizeof(unsigned long);
+ r_data = &scp->max_window;
+ break;
- case DSO_NODELAY:
- if (r_len > sizeof(int))
- r_len = sizeof(int);
- val = (scp->nonagle == 1);
- r_data = &val;
- break;
+ case DSO_NODELAY:
+ if (r_len > sizeof(int))
+ r_len = sizeof(int);
+ val = (scp->nonagle == 1);
+ r_data = &val;
+ break;
- case DSO_CORK:
- if (r_len > sizeof(int))
- r_len = sizeof(int);
- val = (scp->nonagle == 2);
- r_data = &val;
- break;
+ case DSO_CORK:
+ if (r_len > sizeof(int))
+ r_len = sizeof(int);
+ val = (scp->nonagle == 2);
+ r_data = &val;
+ break;
- case DSO_SERVICES:
- if (r_len > sizeof(unsigned char))
- r_len = sizeof(unsigned char);
- r_data = &scp->services_rem;
- break;
+ case DSO_SERVICES:
+ if (r_len > sizeof(unsigned char))
+ r_len = sizeof(unsigned char);
+ r_data = &scp->services_rem;
+ break;
- case DSO_INFO:
- if (r_len > sizeof(unsigned char))
- r_len = sizeof(unsigned char);
- r_data = &scp->info_rem;
- break;
+ case DSO_INFO:
+ if (r_len > sizeof(unsigned char))
+ r_len = sizeof(unsigned char);
+ r_data = &scp->info_rem;
+ break;
}
if (r_data) {
@@ -1633,13 +1640,13 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int target)
{
- struct sk_buff *skb = q->next;
+ struct sk_buff *skb;
int len = 0;
if (flags & MSG_OOB)
return !skb_queue_empty(q) ? 1 : 0;
- while(skb != (struct sk_buff *)q) {
+ skb_queue_walk(q, skb) {
struct dn_skb_cb *cb = DN_SKB_CB(skb);
len += skb->len;
@@ -1655,8 +1662,6 @@ static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int
/* minimum data length for read exceeded */
if (len >= target)
return 1;
-
- skb = skb->next;
}
return 0;
@@ -1672,7 +1677,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
size_t target = size > 1 ? 1 : 0;
size_t copied = 0;
int rv = 0;
- struct sk_buff *skb, *nskb;
+ struct sk_buff *skb, *n;
struct dn_skb_cb *cb = NULL;
unsigned char eor = 0;
long timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
@@ -1693,7 +1698,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
if (rv)
goto out;
- if (flags & ~(MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT|MSG_NOSIGNAL)) {
+ if (flags & ~(MSG_CMSG_COMPAT|MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT|MSG_NOSIGNAL)) {
rv = -EOPNOTSUPP;
goto out;
}
@@ -1709,6 +1714,8 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
* See if there is data ready to read, sleep if there isn't
*/
for(;;) {
+ DEFINE_WAIT(wait);
+
if (sk->sk_err)
goto out;
@@ -1721,7 +1728,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
}
}
}
-
+
if (scp->state != DN_RUN)
goto out;
@@ -1738,17 +1745,14 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
goto out;
}
- set_bit(SOCK_ASYNC_WAITDATA, &sock->flags);
- SOCK_SLEEP_PRE(sk)
-
- if (!dn_data_ready(sk, queue, flags, target))
- schedule();
-
- SOCK_SLEEP_POST(sk)
- clear_bit(SOCK_ASYNC_WAITDATA, &sock->flags);
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
+ set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_wait_event(sk, &timeo, dn_data_ready(sk, queue, flags, target));
+ clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ finish_wait(sk_sleep(sk), &wait);
}
- for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) {
+ skb_queue_walk_safe(queue, skb, n) {
unsigned int chunk = skb->len;
cb = DN_SKB_CB(skb);
@@ -1765,12 +1769,11 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
skb_pull(skb, chunk);
eor = cb->nsp_flags & 0x40;
- nskb = skb->next;
if (skb->len == 0) {
skb_unlink(skb, queue);
kfree_skb(skb);
- /*
+ /*
* N.B. Don't refer to skb or cb after this point
* in loop.
*/
@@ -1780,7 +1783,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
}
}
- if (eor) {
+ if (eor) {
if (sk->sk_type == SOCK_SEQPACKET)
break;
if (!(flags & MSG_WAITALL))
@@ -1805,6 +1808,7 @@ out:
rv = (flags & MSG_PEEK) ? -sk->sk_err : sock_error(sk);
if ((rv >= 0) && msg->msg_name) {
+ __sockaddr_check_size(sizeof(struct sockaddr_dn));
memcpy(msg->msg_name, &scp->peer, sizeof(struct sockaddr_dn));
msg->msg_namelen = sizeof(struct sockaddr_dn);
}
@@ -1833,18 +1837,18 @@ static inline int dn_queue_too_long(struct dn_scp *scp, struct sk_buff_head *que
}
/*
- * The DECnet spec requires the the "routing layer" accepts packets which
+ * The DECnet spec requires that 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 int dn_mss_from_pmtu(struct net_device *dev, int mtu)
{
- unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER;
+ unsigned int mss = 230 - DN_MAX_NSP_DATA_HEADER;
if (dev) {
- struct dn_dev *dn_db = dev->dn_ptr;
+ struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
mtu -= LL_RESERVED_SPACE(dev);
if (dn_db->use_long)
mtu -= 21;
@@ -1881,7 +1885,7 @@ static inline unsigned int dn_current_mss(struct sock *sk, int flags)
return mss_now;
}
-/*
+/*
* N.B. We get the timeout wrong here, but then we always did get it
* wrong before and this is another step along the road to correcting
* it. It ought to get updated each time we pass through the routine,
@@ -1894,7 +1898,7 @@ static inline struct sk_buff *dn_alloc_send_pskb(struct sock *sk,
struct sk_buff *skb = sock_alloc_send_skb(sk, datalen,
noblock, errcode);
if (skb) {
- skb->protocol = __constant_htons(ETH_P_DNA_RT);
+ skb->protocol = htons(ETH_P_DNA_RT);
skb->pkt_type = PACKET_OUTGOING;
}
return skb;
@@ -1911,7 +1915,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
int err = 0;
size_t sent = 0;
int addr_len = msg->msg_namelen;
- struct sockaddr_dn *addr = (struct sockaddr_dn *)msg->msg_name;
+ DECLARE_SOCKADDR(struct sockaddr_dn *, addr, msg->msg_name);
struct sk_buff *skb = NULL;
struct dn_skb_cb *cb;
size_t len;
@@ -1952,7 +1956,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
}
if ((flags & MSG_TRYHARD) && sk->sk_dst_cache)
- dst_negative_advice(&sk->sk_dst_cache);
+ dst_negative_advice(sk);
mss = scp->segsize_rem;
fctype = scp->services_rem & NSP_FC_MASK;
@@ -1992,18 +1996,19 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
* size.
*/
if (dn_queue_too_long(scp, queue, flags)) {
+ DEFINE_WAIT(wait);
+
if (flags & MSG_DONTWAIT) {
err = -EWOULDBLOCK;
goto out;
}
- SOCK_SLEEP_PRE(sk)
-
- if (dn_queue_too_long(scp, queue, flags))
- schedule();
-
- SOCK_SLEEP_POST(sk)
-
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
+ set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_wait_event(sk, &timeo,
+ !dn_queue_too_long(scp, queue, flags));
+ clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ finish_wait(sk_sleep(sk), &wait);
continue;
}
@@ -2041,7 +2046,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
cb->nsp_flags |= 0x20;
scp->seg_total += len;
-
+
if (((sent + len) == size) && (flags & MSG_EOR)) {
cb->nsp_flags |= 0x40;
scp->seg_total = 0;
@@ -2061,8 +2066,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
}
out:
- if (skb)
- kfree_skb(skb);
+ kfree_skb(skb);
release_sock(sk);
@@ -2075,19 +2079,22 @@ out_err:
}
static int dn_device_event(struct notifier_block *this, unsigned long event,
- void *ptr)
+ void *ptr)
{
- struct net_device *dev = (struct net_device *)ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- switch(event) {
- case NETDEV_UP:
- dn_dev_up(dev);
- break;
- case NETDEV_DOWN:
- dn_dev_down(dev);
- break;
- default:
- break;
+ if (!net_eq(dev_net(dev), &init_net))
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case NETDEV_UP:
+ dn_dev_up(dev);
+ break;
+ case NETDEV_DOWN:
+ dn_dev_down(dev);
+ break;
+ default:
+ break;
}
return NOTIFY_DONE;
@@ -2097,11 +2104,8 @@ static struct notifier_block dn_dev_notifier = {
.notifier_call = dn_device_event,
};
-extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
-
-static struct packet_type dn_dix_packet_type = {
- .type = __constant_htons(ETH_P_DNA_RT),
- .dev = NULL, /* All devices */
+static struct packet_type dn_dix_packet_type __read_mostly = {
+ .type = cpu_to_be16(ETH_P_DNA_RT),
.func = dn_route_rcv,
};
@@ -2199,56 +2203,56 @@ static void dn_socket_seq_stop(struct seq_file *seq, void *v)
static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf)
{
int i;
-
- switch (dn_ntohs(dn->sdn_objnamel)) {
- case 0:
- sprintf(buf, "%d", dn->sdn_objnum);
- break;
- default:
- for (i = 0; i < dn_ntohs(dn->sdn_objnamel); i++) {
- buf[i] = dn->sdn_objname[i];
- if (IS_NOT_PRINTABLE(buf[i]))
- buf[i] = '.';
- }
- buf[i] = 0;
- }
+
+ switch (le16_to_cpu(dn->sdn_objnamel)) {
+ case 0:
+ sprintf(buf, "%d", dn->sdn_objnum);
+ break;
+ default:
+ for (i = 0; i < le16_to_cpu(dn->sdn_objnamel); i++) {
+ buf[i] = dn->sdn_objname[i];
+ if (IS_NOT_PRINTABLE(buf[i]))
+ buf[i] = '.';
+ }
+ buf[i] = 0;
+ }
}
static char *dn_state2asc(unsigned char state)
{
- switch(state) {
- case DN_O:
- return "OPEN";
- case DN_CR:
- return " CR";
- case DN_DR:
- return " DR";
- case DN_DRC:
- return " DRC";
- case DN_CC:
- return " CC";
- case DN_CI:
- return " CI";
- case DN_NR:
- return " NR";
- case DN_NC:
- return " NC";
- case DN_CD:
- return " CD";
- case DN_RJ:
- return " RJ";
- case DN_RUN:
- return " RUN";
- case DN_DI:
- return " DI";
- case DN_DIC:
- return " DIC";
- case DN_DN:
- return " DN";
- case DN_CL:
- return " CL";
- case DN_CN:
- return " CN";
+ switch (state) {
+ case DN_O:
+ return "OPEN";
+ case DN_CR:
+ return " CR";
+ case DN_DR:
+ return " DR";
+ case DN_DRC:
+ return " DRC";
+ case DN_CC:
+ return " CC";
+ case DN_CI:
+ return " CI";
+ case DN_NR:
+ return " NR";
+ case DN_NC:
+ return " NC";
+ case DN_CD:
+ return " CD";
+ case DN_RJ:
+ return " RJ";
+ case DN_RUN:
+ return " RUN";
+ case DN_DI:
+ return " DI";
+ case DN_DIC:
+ return " DIC";
+ case DN_DN:
+ return " DN";
+ case DN_CL:
+ return " CL";
+ case DN_CN:
+ return " CN";
}
return "????";
@@ -2268,7 +2272,7 @@ static inline void dn_socket_format_entry(struct seq_file *seq, struct sock *sk)
seq_printf(seq,
"%6s/%04X %04d:%04d %04d:%04d %01d %-16s "
"%6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
- dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
+ dn_addr2asc(le16_to_cpu(dn_saddr2dn(&scp->addr)), buf1),
scp->addrloc,
scp->numdat,
scp->numoth,
@@ -2276,7 +2280,7 @@ static inline void dn_socket_format_entry(struct seq_file *seq, struct sock *sk)
scp->ackxmt_oth,
scp->flowloc_sw,
local_object,
- dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
+ dn_addr2asc(le16_to_cpu(dn_saddr2dn(&scp->peer)), buf2),
scp->addrrem,
scp->numdat_rcv,
scp->numoth_rcv,
@@ -2298,7 +2302,7 @@ static int dn_socket_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations dn_socket_seq_ops = {
+static const struct seq_operations dn_socket_seq_ops = {
.start = dn_socket_seq_start,
.next = dn_socket_seq_next,
.stop = dn_socket_seq_stop,
@@ -2307,28 +2311,11 @@ static struct seq_operations dn_socket_seq_ops = {
static int dn_socket_seq_open(struct inode *inode, struct file *file)
{
- struct seq_file *seq;
- int rc = -ENOMEM;
- struct dn_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
-
- if (!s)
- goto out;
-
- rc = seq_open(file, &dn_socket_seq_ops);
- if (rc)
- goto out_kfree;
-
- seq = file->private_data;
- seq->private = s;
- memset(s, 0, sizeof(*s));
-out:
- return rc;
-out_kfree:
- kfree(s);
- goto out;
+ return seq_open_private(file, &dn_socket_seq_ops,
+ sizeof(struct dn_iter_state));
}
-static struct file_operations dn_socket_seq_fops = {
+static const struct file_operations dn_socket_seq_fops = {
.owner = THIS_MODULE,
.open = dn_socket_seq_open,
.read = seq_read,
@@ -2337,7 +2324,7 @@ static struct file_operations dn_socket_seq_fops = {
};
#endif
-static struct net_proto_family dn_family_ops = {
+static const struct net_proto_family dn_family_ops = {
.family = AF_DECnet,
.create = dn_create,
.owner = THIS_MODULE,
@@ -2364,9 +2351,6 @@ static const struct proto_ops dn_proto_ops = {
.sendpage = sock_no_sendpage,
};
-void dn_register_sysctl(void);
-void dn_unregister_sysctl(void);
-
MODULE_DESCRIPTION("The Linux DECnet Network Protocol");
MODULE_AUTHOR("Linux DECnet Project Team");
MODULE_LICENSE("GPL");
@@ -2378,7 +2362,7 @@ static int __init decnet_init(void)
{
int rc;
- printk(banner);
+ printk(banner);
rc = proto_register(&dn_proto, 1);
if (rc != 0)
@@ -2393,7 +2377,7 @@ static int __init decnet_init(void)
dev_add_pack(&dn_dix_packet_type);
register_netdevice_notifier(&dn_dev_notifier);
- proc_net_fops_create("decnet", S_IRUGO, &dn_socket_seq_fops);
+ proc_create("decnet", S_IRUGO, init_net.proc_net, &dn_socket_seq_fops);
dn_register_sysctl();
out:
return rc;
@@ -2410,6 +2394,7 @@ module_init(decnet_init);
static void __exit decnet_exit(void)
{
sock_unregister(AF_DECnet);
+ rtnl_unregister_all(PF_DECnet);
dev_remove_pack(&dn_dix_packet_type);
dn_unregister_sysctl();
@@ -2421,9 +2406,11 @@ static void __exit decnet_exit(void)
dn_neigh_cleanup();
dn_fib_cleanup();
- proc_net_remove("decnet");
+ remove_proc_entry("decnet", init_net.proc_net);
proto_unregister(&dn_proto);
+
+ rcu_barrier_bh(); /* Wait for completion of call_rcu_bh()'s */
}
module_exit(decnet_exit);
#endif
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index efbead83ba7..3b726f31c64 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -24,7 +24,6 @@
* devices. All mtu based now.
*/
-#include <linux/config.h>
#include <linux/capability.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -35,17 +34,20 @@
#include <linux/seq_file.h>
#include <linux/timer.h>
#include <linux/string.h>
+#include <linux/if_addr.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/skbuff.h>
-#include <linux/rtnetlink.h>
#include <linux/sysctl.h>
#include <linux/notifier.h>
+#include <linux/slab.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
+#include <net/net_namespace.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/flow.h>
+#include <net/fib_rules.h>
+#include <net/netlink.h>
#include <net/dn.h>
#include <net/dn_dev.h>
#include <net/dn_route.h>
@@ -64,15 +66,15 @@ extern struct neigh_table dn_neigh_table;
/*
* decnet_address is kept in network order.
*/
-dn_address decnet_address = 0;
+__le16 decnet_address = 0;
-static DEFINE_RWLOCK(dndev_lock);
+static DEFINE_SPINLOCK(dndev_lock);
static struct net_device *decnet_default_device;
-static struct notifier_block *dnaddr_chain;
+static BLOCKING_NOTIFIER_HEAD(dnaddr_chain);
static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);
static void dn_dev_delete(struct net_device *dev);
-static void rtmsg_ifa(int event, struct dn_ifaddr *ifa);
+static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa);
static int dn_eth_up(struct net_device *);
static void dn_eth_down(struct net_device *);
@@ -87,7 +89,6 @@ static struct dn_dev_parms dn_dev_list[] = {
.t2 = 1,
.t3 = 10,
.name = "ethernet",
- .ctl_name = NET_DECNET_CONF_ETHER,
.up = dn_eth_up,
.down = dn_eth_down,
.timer3 = dn_send_brd_hello,
@@ -99,7 +100,6 @@ static struct dn_dev_parms dn_dev_list[] = {
.t2 = 1,
.t3 = 10,
.name = "ipgre",
- .ctl_name = NET_DECNET_CONF_GRE,
.timer3 = dn_send_brd_hello,
},
#if 0
@@ -110,7 +110,6 @@ static struct dn_dev_parms dn_dev_list[] = {
.t2 = 1,
.t3 = 120,
.name = "x25",
- .ctl_name = NET_DECNET_CONF_X25,
.timer3 = dn_send_ptp_hello,
},
#endif
@@ -122,7 +121,6 @@ static struct dn_dev_parms dn_dev_list[] = {
.t2 = 1,
.t3 = 10,
.name = "ppp",
- .ctl_name = NET_DECNET_CONF_PPP,
.timer3 = dn_send_brd_hello,
},
#endif
@@ -133,7 +131,6 @@ static struct dn_dev_parms dn_dev_list[] = {
.t2 = 1,
.t3 = 120,
.name = "ddcmp",
- .ctl_name = NET_DECNET_CONF_DDCMP,
.timer3 = dn_send_ptp_hello,
},
{
@@ -143,14 +140,13 @@ static struct dn_dev_parms dn_dev_list[] = {
.t2 = 1,
.t3 = 10,
.name = "loopback",
- .ctl_name = NET_DECNET_CONF_LOOPBACK,
.timer3 = dn_send_brd_hello,
}
};
-#define DN_DEV_LIST_SIZE (sizeof(dn_dev_list)/sizeof(struct dn_dev_parms))
+#define DN_DEV_LIST_SIZE ARRAY_SIZE(dn_dev_list)
-#define DN_DEV_PARMS_OFFSET(x) ((int) ((char *) &((struct dn_dev_parms *)0)->x))
+#define DN_DEV_PARMS_OFFSET(x) offsetof(struct dn_dev_parms, x)
#ifdef CONFIG_SYSCTL
@@ -162,91 +158,50 @@ static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MU
static int min_priority[1];
static int max_priority[] = { 127 }; /* From DECnet spec */
-static int dn_forwarding_proc(ctl_table *, int, struct file *,
+static int dn_forwarding_proc(struct ctl_table *, int,
void __user *, size_t *, loff_t *);
-static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,
- void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context);
-
static struct dn_dev_sysctl_table {
struct ctl_table_header *sysctl_header;
- ctl_table dn_dev_vars[5];
- ctl_table dn_dev_dev[2];
- ctl_table dn_dev_conf_dir[2];
- ctl_table dn_dev_proto_dir[2];
- ctl_table dn_dev_root_dir[2];
+ struct ctl_table dn_dev_vars[5];
} dn_dev_sysctl = {
NULL,
{
{
- .ctl_name = NET_DECNET_CONF_DEV_FORWARDING,
.procname = "forwarding",
.data = (void *)DN_DEV_PARMS_OFFSET(forwarding),
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = dn_forwarding_proc,
- .strategy = dn_forwarding_sysctl,
},
{
- .ctl_name = NET_DECNET_CONF_DEV_PRIORITY,
.procname = "priority",
.data = (void *)DN_DEV_PARMS_OFFSET(priority),
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .strategy = sysctl_intvec,
.extra1 = &min_priority,
.extra2 = &max_priority
},
{
- .ctl_name = NET_DECNET_CONF_DEV_T2,
.procname = "t2",
.data = (void *)DN_DEV_PARMS_OFFSET(t2),
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .strategy = sysctl_intvec,
.extra1 = &min_t2,
.extra2 = &max_t2
},
{
- .ctl_name = NET_DECNET_CONF_DEV_T3,
.procname = "t3",
.data = (void *)DN_DEV_PARMS_OFFSET(t3),
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .strategy = sysctl_intvec,
.extra1 = &min_t3,
.extra2 = &max_t3
},
{0}
},
- {{
- .ctl_name = 0,
- .procname = "",
- .mode = 0555,
- .child = dn_dev_sysctl.dn_dev_vars
- }, {0}},
- {{
- .ctl_name = NET_DECNET_CONF,
- .procname = "conf",
- .mode = 0555,
- .child = dn_dev_sysctl.dn_dev_dev
- }, {0}},
- {{
- .ctl_name = NET_DECNET,
- .procname = "decnet",
- .mode = 0555,
- .child = dn_dev_sysctl.dn_dev_conf_dir
- }, {0}},
- {{
- .ctl_name = CTL_NET,
- .procname = "net",
- .mode = 0555,
- .child = dn_dev_sysctl.dn_dev_proto_dir
- }, {0}}
};
static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms)
@@ -254,37 +209,23 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *
struct dn_dev_sysctl_table *t;
int i;
- t = kmalloc(sizeof(*t), GFP_KERNEL);
+ char path[sizeof("net/decnet/conf/") + IFNAMSIZ];
+
+ t = kmemdup(&dn_dev_sysctl, sizeof(*t), GFP_KERNEL);
if (t == NULL)
return;
- memcpy(t, &dn_dev_sysctl, sizeof(*t));
-
for(i = 0; i < ARRAY_SIZE(t->dn_dev_vars) - 1; i++) {
long offset = (long)t->dn_dev_vars[i].data;
t->dn_dev_vars[i].data = ((char *)parms) + offset;
- t->dn_dev_vars[i].de = NULL;
}
- if (dev) {
- t->dn_dev_dev[0].procname = dev->name;
- t->dn_dev_dev[0].ctl_name = dev->ifindex;
- } else {
- t->dn_dev_dev[0].procname = parms->name;
- t->dn_dev_dev[0].ctl_name = parms->ctl_name;
- }
+ snprintf(path, sizeof(path), "net/decnet/conf/%s",
+ dev? dev->name : parms->name);
- t->dn_dev_dev[0].child = t->dn_dev_vars;
- t->dn_dev_dev[0].de = NULL;
- t->dn_dev_conf_dir[0].child = t->dn_dev_dev;
- t->dn_dev_conf_dir[0].de = NULL;
- t->dn_dev_proto_dir[0].child = t->dn_dev_conf_dir;
- t->dn_dev_proto_dir[0].de = NULL;
- t->dn_dev_root_dir[0].child = t->dn_dev_proto_dir;
- t->dn_dev_root_dir[0].de = NULL;
t->dn_dev_vars[0].extra1 = (void *)dev;
- t->sysctl_header = register_sysctl_table(t->dn_dev_root_dir, 0);
+ t->sysctl_header = register_net_sysctl(&init_net, path, t->dn_dev_vars);
if (t->sysctl_header == NULL)
kfree(t);
else
@@ -296,13 +237,12 @@ static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
if (parms->sysctl) {
struct dn_dev_sysctl_table *t = parms->sysctl;
parms->sysctl = NULL;
- unregister_sysctl_table(t->sysctl_header);
+ unregister_net_sysctl_table(t->sysctl_header);
kfree(t);
}
}
-static int dn_forwarding_proc(ctl_table *table, int write,
- struct file *filep,
+static int dn_forwarding_proc(struct ctl_table *table, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
@@ -315,10 +255,10 @@ static int dn_forwarding_proc(ctl_table *table, int write,
if (table->extra1 == NULL)
return -EINVAL;
- dn_db = dev->dn_ptr;
+ dn_db = rcu_dereference_raw(dev->dn_ptr);
old = dn_db->parms.forwarding;
- err = proc_dointvec(table, write, filep, buffer, lenp, ppos);
+ err = proc_dointvec(table, write, buffer, lenp, ppos);
if ((err >= 0) && write) {
if (dn_db->parms.forwarding < 0)
@@ -346,45 +286,6 @@ static int dn_forwarding_proc(ctl_table *table, int write,
#endif
}
-static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,
- void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
-{
-#ifdef CONFIG_DECNET_ROUTER
- struct net_device *dev = table->extra1;
- struct dn_dev *dn_db;
- int value;
-
- if (table->extra1 == NULL)
- return -EINVAL;
-
- dn_db = dev->dn_ptr;
-
- if (newval && newlen) {
- if (newlen != sizeof(int))
- return -EINVAL;
-
- if (get_user(value, (int __user *)newval))
- return -EFAULT;
- if (value < 0)
- return -EINVAL;
- if (value > 2)
- return -EINVAL;
-
- if (dn_db->parms.down)
- dn_db->parms.down(dev);
- dn_db->parms.forwarding = value;
- if (dn_db->parms.up)
- dn_db->parms.up(dev);
- }
-
- return 0;
-#else
- return -EINVAL;
-#endif
-}
-
#else /* CONFIG_SYSCTL */
static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
{
@@ -414,23 +315,19 @@ static struct dn_ifaddr *dn_dev_alloc_ifa(void)
{
struct dn_ifaddr *ifa;
- ifa = kmalloc(sizeof(*ifa), GFP_KERNEL);
-
- if (ifa) {
- memset(ifa, 0, sizeof(*ifa));
- }
+ ifa = kzalloc(sizeof(*ifa), GFP_KERNEL);
return ifa;
}
-static __inline__ void dn_dev_free_ifa(struct dn_ifaddr *ifa)
+static void dn_dev_free_ifa(struct dn_ifaddr *ifa)
{
- kfree(ifa);
+ kfree_rcu(ifa, rcu);
}
-static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int destroy)
+static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr __rcu **ifap, int destroy)
{
- struct dn_ifaddr *ifa1 = *ifap;
+ struct dn_ifaddr *ifa1 = rtnl_dereference(*ifap);
unsigned char mac_addr[6];
struct net_device *dev = dn_db->dev;
@@ -439,14 +336,14 @@ static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int de
*ifap = ifa1->ifa_next;
if (dn_db->dev->type == ARPHRD_ETHER) {
- if (ifa1->ifa_local != dn_htons(dn_eth2dn(dev->dev_addr))) {
+ if (ifa1->ifa_local != dn_eth2dn(dev->dev_addr)) {
dn_dn2eth(mac_addr, ifa1->ifa_local);
- dev_mc_delete(dev, mac_addr, ETH_ALEN, 0);
+ dev_mc_del(dev, mac_addr);
}
}
- rtmsg_ifa(RTM_DELADDR, ifa1);
- notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1);
+ dn_ifaddr_notify(RTM_DELADDR, ifa1);
+ blocking_notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1);
if (destroy) {
dn_dev_free_ifa(ifa1);
@@ -463,32 +360,33 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
ASSERT_RTNL();
- /* Check for duplicates */
- for(ifa1 = dn_db->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
+ /* Check for duplicates */
+ for (ifa1 = rtnl_dereference(dn_db->ifa_list);
+ ifa1 != NULL;
+ ifa1 = rtnl_dereference(ifa1->ifa_next)) {
if (ifa1->ifa_local == ifa->ifa_local)
return -EEXIST;
}
if (dev->type == ARPHRD_ETHER) {
- if (ifa->ifa_local != dn_htons(dn_eth2dn(dev->dev_addr))) {
+ if (ifa->ifa_local != dn_eth2dn(dev->dev_addr)) {
dn_dn2eth(mac_addr, ifa->ifa_local);
- dev_mc_add(dev, mac_addr, ETH_ALEN, 0);
- dev_mc_upload(dev);
+ dev_mc_add(dev, mac_addr);
}
}
ifa->ifa_next = dn_db->ifa_list;
- dn_db->ifa_list = ifa;
+ rcu_assign_pointer(dn_db->ifa_list, ifa);
- rtmsg_ifa(RTM_NEWADDR, ifa);
- notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
+ dn_ifaddr_notify(RTM_NEWADDR, ifa);
+ blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
return 0;
}
static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa)
{
- struct dn_dev *dn_db = dev->dn_ptr;
+ struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
int rv;
if (dn_db == NULL) {
@@ -517,39 +415,40 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg)
struct sockaddr_dn *sdn = (struct sockaddr_dn *)&ifr->ifr_addr;
struct dn_dev *dn_db;
struct net_device *dev;
- struct dn_ifaddr *ifa = NULL, **ifap = NULL;
+ struct dn_ifaddr *ifa = NULL;
+ struct dn_ifaddr __rcu **ifap = NULL;
int ret = 0;
if (copy_from_user(ifr, arg, DN_IFREQ_SIZE))
return -EFAULT;
ifr->ifr_name[IFNAMSIZ-1] = 0;
-#ifdef CONFIG_KMOD
- dev_load(ifr->ifr_name);
-#endif
+ dev_load(&init_net, ifr->ifr_name);
- switch(cmd) {
- case SIOCGIFADDR:
- break;
- case SIOCSIFADDR:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- if (sdn->sdn_family != AF_DECnet)
- return -EINVAL;
- break;
- default:
+ switch (cmd) {
+ case SIOCGIFADDR:
+ break;
+ case SIOCSIFADDR:
+ if (!capable(CAP_NET_ADMIN))
+ return -EACCES;
+ if (sdn->sdn_family != AF_DECnet)
return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
}
rtnl_lock();
- if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) {
+ if ((dev = __dev_get_by_name(&init_net, ifr->ifr_name)) == NULL) {
ret = -ENODEV;
goto done;
}
- if ((dn_db = dev->dn_ptr) != NULL) {
- for (ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next)
+ if ((dn_db = rtnl_dereference(dev->dn_ptr)) != NULL) {
+ for (ifap = &dn_db->ifa_list;
+ (ifa = rtnl_dereference(*ifap)) != NULL;
+ ifap = &ifa->ifa_next)
if (strcmp(ifr->ifr_name, ifa->ifa_label) == 0)
break;
}
@@ -559,27 +458,27 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg)
goto done;
}
- switch(cmd) {
- case SIOCGIFADDR:
- *((dn_address *)sdn->sdn_nodeaddr) = ifa->ifa_local;
- goto rarok;
-
- case SIOCSIFADDR:
- if (!ifa) {
- if ((ifa = dn_dev_alloc_ifa()) == NULL) {
- ret = -ENOBUFS;
- break;
- }
- memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
- } else {
- if (ifa->ifa_local == dn_saddr2dn(sdn))
- break;
- dn_dev_del_ifa(dn_db, ifap, 0);
+ switch (cmd) {
+ case SIOCGIFADDR:
+ *((__le16 *)sdn->sdn_nodeaddr) = ifa->ifa_local;
+ goto rarok;
+
+ case SIOCSIFADDR:
+ if (!ifa) {
+ if ((ifa = dn_dev_alloc_ifa()) == NULL) {
+ ret = -ENOBUFS;
+ break;
}
+ memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
+ } else {
+ if (ifa->ifa_local == dn_saddr2dn(sdn))
+ break;
+ dn_dev_del_ifa(dn_db, ifap, 0);
+ }
- ifa->ifa_local = ifa->ifa_address = dn_saddr2dn(sdn);
+ ifa->ifa_local = ifa->ifa_address = dn_saddr2dn(sdn);
- ret = dn_dev_set_ifa(dev, ifa);
+ ret = dn_dev_set_ifa(dev, ifa);
}
done:
rtnl_unlock();
@@ -594,7 +493,8 @@ rarok:
struct net_device *dn_dev_get_default(void)
{
struct net_device *dev;
- read_lock(&dndev_lock);
+
+ spin_lock(&dndev_lock);
dev = decnet_default_device;
if (dev) {
if (dev->dn_ptr)
@@ -602,7 +502,8 @@ struct net_device *dn_dev_get_default(void)
else
dev = NULL;
}
- read_unlock(&dndev_lock);
+ spin_unlock(&dndev_lock);
+
return dev;
}
@@ -612,215 +513,295 @@ int dn_dev_set_default(struct net_device *dev, int force)
int rv = -EBUSY;
if (!dev->dn_ptr)
return -ENODEV;
- write_lock(&dndev_lock);
+
+ spin_lock(&dndev_lock);
if (force || decnet_default_device == NULL) {
old = decnet_default_device;
decnet_default_device = dev;
rv = 0;
}
- write_unlock(&dndev_lock);
+ spin_unlock(&dndev_lock);
+
if (old)
- dev_put(dev);
+ dev_put(old);
return rv;
}
static void dn_dev_check_default(struct net_device *dev)
{
- write_lock(&dndev_lock);
+ spin_lock(&dndev_lock);
if (dev == decnet_default_device) {
decnet_default_device = NULL;
} else {
dev = NULL;
}
- write_unlock(&dndev_lock);
+ spin_unlock(&dndev_lock);
+
if (dev)
dev_put(dev);
}
+/*
+ * Called with RTNL
+ */
static struct dn_dev *dn_dev_by_index(int ifindex)
{
struct net_device *dev;
struct dn_dev *dn_dev = NULL;
- dev = dev_get_by_index(ifindex);
- if (dev) {
- dn_dev = dev->dn_ptr;
- dev_put(dev);
- }
+
+ dev = __dev_get_by_index(&init_net, ifindex);
+ if (dev)
+ dn_dev = rtnl_dereference(dev->dn_ptr);
return dn_dev;
}
-static int dn_dev_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static const struct nla_policy dn_ifa_policy[IFA_MAX+1] = {
+ [IFA_ADDRESS] = { .type = NLA_U16 },
+ [IFA_LOCAL] = { .type = NLA_U16 },
+ [IFA_LABEL] = { .type = NLA_STRING,
+ .len = IFNAMSIZ - 1 },
+ [IFA_FLAGS] = { .type = NLA_U32 },
+};
+
+static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
{
- struct rtattr **rta = arg;
+ struct net *net = sock_net(skb->sk);
+ struct nlattr *tb[IFA_MAX+1];
struct dn_dev *dn_db;
- struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
- struct dn_ifaddr *ifa, **ifap;
+ struct ifaddrmsg *ifm;
+ struct dn_ifaddr *ifa;
+ struct dn_ifaddr __rcu **ifap;
+ int err = -EINVAL;
+
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (!net_eq(net, &init_net))
+ goto errout;
+ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy);
+ if (err < 0)
+ goto errout;
+
+ err = -ENODEV;
+ ifm = nlmsg_data(nlh);
if ((dn_db = dn_dev_by_index(ifm->ifa_index)) == NULL)
- return -EADDRNOTAVAIL;
+ goto errout;
+
+ err = -EADDRNOTAVAIL;
+ for (ifap = &dn_db->ifa_list;
+ (ifa = rtnl_dereference(*ifap)) != NULL;
+ ifap = &ifa->ifa_next) {
+ if (tb[IFA_LOCAL] &&
+ nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2))
+ continue;
- for(ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next) {
- void *tmp = rta[IFA_LOCAL-1];
- if ((tmp && memcmp(RTA_DATA(tmp), &ifa->ifa_local, 2)) ||
- (rta[IFA_LABEL-1] && rtattr_strcmp(rta[IFA_LABEL-1], ifa->ifa_label)))
+ if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
continue;
dn_dev_del_ifa(dn_db, ifap, 1);
return 0;
}
- return -EADDRNOTAVAIL;
+errout:
+ return err;
}
-static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
{
- struct rtattr **rta = arg;
+ struct net *net = sock_net(skb->sk);
+ struct nlattr *tb[IFA_MAX+1];
struct net_device *dev;
struct dn_dev *dn_db;
- struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
+ struct ifaddrmsg *ifm;
struct dn_ifaddr *ifa;
- int rv;
+ int err;
+
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
- if (rta[IFA_LOCAL-1] == NULL)
+ if (!net_eq(net, &init_net))
return -EINVAL;
- if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL)
+ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy);
+ if (err < 0)
+ return err;
+
+ if (tb[IFA_LOCAL] == NULL)
+ return -EINVAL;
+
+ ifm = nlmsg_data(nlh);
+ if ((dev = __dev_get_by_index(&init_net, ifm->ifa_index)) == NULL)
return -ENODEV;
- if ((dn_db = dev->dn_ptr) == NULL) {
- int err;
+ if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL) {
dn_db = dn_dev_create(dev, &err);
if (!dn_db)
return err;
}
-
+
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;
+ if (tb[IFA_ADDRESS] == NULL)
+ tb[IFA_ADDRESS] = tb[IFA_LOCAL];
+
+ ifa->ifa_local = nla_get_le16(tb[IFA_LOCAL]);
+ ifa->ifa_address = nla_get_le16(tb[IFA_ADDRESS]);
+ ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
+ ifm->ifa_flags;
ifa->ifa_scope = ifm->ifa_scope;
ifa->ifa_dev = dn_db;
- if (rta[IFA_LABEL-1])
- rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL-1], IFNAMSIZ);
+
+ if (tb[IFA_LABEL])
+ nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
else
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
- rv = dn_dev_insert_ifa(dn_db, ifa);
- if (rv)
+ err = dn_dev_insert_ifa(dn_db, ifa);
+ if (err)
dn_dev_free_ifa(ifa);
- return rv;
+
+ return err;
+}
+
+static inline size_t dn_ifaddr_nlmsg_size(void)
+{
+ return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
+ + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
+ + nla_total_size(2) /* IFA_ADDRESS */
+ + nla_total_size(2) /* IFA_LOCAL */
+ + nla_total_size(4); /* IFA_FLAGS */
}
-static int dn_dev_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
- u32 pid, u32 seq, int event, unsigned int flags)
+static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
+ u32 portid, u32 seq, int event, unsigned int flags)
{
struct ifaddrmsg *ifm;
struct nlmsghdr *nlh;
- unsigned char *b = skb->tail;
+ u32 ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT;
- nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags);
- ifm = NLMSG_DATA(nlh);
+ nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
+ if (nlh == NULL)
+ return -EMSGSIZE;
+ ifm = nlmsg_data(nlh);
ifm->ifa_family = AF_DECnet;
ifm->ifa_prefixlen = 16;
- ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT;
+ ifm->ifa_flags = ifa_flags;
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);
- nlh->nlmsg_len = skb->tail - b;
- return skb->len;
-nlmsg_failure:
-rtattr_failure:
- skb_trim(skb, b - skb->data);
- return -1;
+ if ((ifa->ifa_address &&
+ nla_put_le16(skb, IFA_ADDRESS, ifa->ifa_address)) ||
+ (ifa->ifa_local &&
+ nla_put_le16(skb, IFA_LOCAL, ifa->ifa_local)) ||
+ (ifa->ifa_label[0] &&
+ nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
+ nla_put_u32(skb, IFA_FLAGS, ifa_flags))
+ goto nla_put_failure;
+ return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
-static void rtmsg_ifa(int event, struct dn_ifaddr *ifa)
+static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
{
struct sk_buff *skb;
- int size = NLMSG_SPACE(sizeof(struct ifaddrmsg)+128);
+ int err = -ENOBUFS;
- skb = alloc_skb(size, GFP_KERNEL);
- if (!skb) {
- netlink_set_err(rtnl, 0, RTNLGRP_DECnet_IFADDR, ENOBUFS);
- return;
- }
- if (dn_dev_fill_ifaddr(skb, ifa, 0, 0, event, 0) < 0) {
+ skb = alloc_skb(dn_ifaddr_nlmsg_size(), GFP_KERNEL);
+ if (skb == NULL)
+ goto errout;
+
+ err = dn_nl_fill_ifaddr(skb, ifa, 0, 0, event, 0);
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in dn_ifaddr_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
- netlink_set_err(rtnl, 0, RTNLGRP_DECnet_IFADDR, EINVAL);
- return;
+ goto errout;
}
- NETLINK_CB(skb).dst_group = RTNLGRP_DECnet_IFADDR;
- netlink_broadcast(rtnl, skb, 0, RTNLGRP_DECnet_IFADDR, GFP_KERNEL);
+ rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
+ return;
+errout:
+ if (err < 0)
+ rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_IFADDR, err);
}
-static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
+static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
{
- int idx, dn_idx;
- int s_idx, s_dn_idx;
+ struct net *net = sock_net(skb->sk);
+ int idx, dn_idx = 0, skip_ndevs, skip_naddr;
struct net_device *dev;
struct dn_dev *dn_db;
struct dn_ifaddr *ifa;
- 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, idx++) {
- if (idx < s_idx)
- continue;
- if (idx > s_idx)
- s_dn_idx = 0;
- if ((dn_db = dev->dn_ptr) == NULL)
- continue;
+ if (!net_eq(net, &init_net))
+ return 0;
+
+ skip_ndevs = cb->args[0];
+ skip_naddr = cb->args[1];
+
+ idx = 0;
+ rcu_read_lock();
+ for_each_netdev_rcu(&init_net, dev) {
+ if (idx < skip_ndevs)
+ goto cont;
+ else if (idx > skip_ndevs) {
+ /* Only skip over addresses for first dev dumped
+ * in this iteration (idx == skip_ndevs) */
+ skip_naddr = 0;
+ }
- for(ifa = dn_db->ifa_list, dn_idx = 0; ifa; ifa = ifa->ifa_next, dn_idx++) {
- if (dn_idx < s_dn_idx)
+ if ((dn_db = rcu_dereference(dev->dn_ptr)) == NULL)
+ goto cont;
+
+ for (ifa = rcu_dereference(dn_db->ifa_list), dn_idx = 0; ifa;
+ ifa = rcu_dereference(ifa->ifa_next), dn_idx++) {
+ if (dn_idx < skip_naddr)
continue;
- if (dn_dev_fill_ifaddr(skb, ifa,
- NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq,
- RTM_NEWADDR,
- NLM_F_MULTI) <= 0)
+ if (dn_nl_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, RTM_NEWADDR,
+ NLM_F_MULTI) < 0)
goto done;
}
+cont:
+ idx++;
}
done:
- read_unlock(&dev_base_lock);
+ rcu_read_unlock();
cb->args[0] = idx;
cb->args[1] = dn_idx;
return skb->len;
}
-static int dn_dev_get_first(struct net_device *dev, dn_address *addr)
+static int dn_dev_get_first(struct net_device *dev, __le16 *addr)
{
- struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
+ struct dn_dev *dn_db;
struct dn_ifaddr *ifa;
int rv = -ENODEV;
+
+ rcu_read_lock();
+ dn_db = rcu_dereference(dev->dn_ptr);
if (dn_db == NULL)
goto out;
- ifa = dn_db->ifa_list;
+
+ ifa = rcu_dereference(dn_db->ifa_list);
if (ifa != NULL) {
*addr = ifa->ifa_local;
rv = 0;
}
out:
+ rcu_read_unlock();
return rv;
}
-/*
+/*
* Find a default address to bind to.
*
* This is one of those areas where the initial VMS concepts don't really
@@ -830,62 +811,60 @@ out:
* a sensible default. Eventually the routing code will take care of all the
* nasties for us I hope.
*/
-int dn_dev_bind_default(dn_address *addr)
+int dn_dev_bind_default(__le16 *addr)
{
struct net_device *dev;
int rv;
dev = dn_dev_get_default();
last_chance:
if (dev) {
- read_lock(&dev_base_lock);
rv = dn_dev_get_first(dev, addr);
- read_unlock(&dev_base_lock);
dev_put(dev);
- if (rv == 0 || dev == &loopback_dev)
+ if (rv == 0 || dev == init_net.loopback_dev)
return rv;
}
- dev = &loopback_dev;
+ dev = init_net.loopback_dev;
dev_hold(dev);
goto last_chance;
}
static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
{
- struct endnode_hello_message *msg;
- struct sk_buff *skb = NULL;
- unsigned short int *pktlen;
- struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
+ struct endnode_hello_message *msg;
+ struct sk_buff *skb = NULL;
+ __le16 *pktlen;
+ struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
- if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL)
+ if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL)
return;
- skb->dev = dev;
+ skb->dev = dev;
- msg = (struct endnode_hello_message *)skb_put(skb,sizeof(*msg));
+ msg = (struct endnode_hello_message *)skb_put(skb,sizeof(*msg));
- msg->msgflg = 0x0D;
- memcpy(msg->tiver, dn_eco_version, 3);
+ msg->msgflg = 0x0D;
+ memcpy(msg->tiver, dn_eco_version, 3);
dn_dn2eth(msg->id, ifa->ifa_local);
- msg->iinfo = DN_RT_INFO_ENDN;
- msg->blksize = dn_htons(mtu2blksize(dev));
- msg->area = 0x00;
- memset(msg->seed, 0, 8);
- memcpy(msg->neighbor, dn_hiord, ETH_ALEN);
+ msg->iinfo = DN_RT_INFO_ENDN;
+ msg->blksize = cpu_to_le16(mtu2blksize(dev));
+ msg->area = 0x00;
+ memset(msg->seed, 0, 8);
+ memcpy(msg->neighbor, dn_hiord, ETH_ALEN);
if (dn_db->router) {
struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
dn_dn2eth(msg->neighbor, dn->addr);
}
- msg->timer = dn_htons((unsigned short)dn_db->parms.t3);
- msg->mpd = 0x00;
- msg->datalen = 0x02;
- memset(msg->data, 0xAA, 2);
-
- pktlen = (unsigned short *)skb_push(skb,2);
- *pktlen = dn_htons(skb->len - 2);
+ msg->timer = cpu_to_le16((unsigned short)dn_db->parms.t3);
+ msg->mpd = 0x00;
+ msg->datalen = 0x02;
+ memset(msg->data, 0xAA, 2);
+
+ pktlen = (__le16 *)skb_push(skb,2);
+ *pktlen = cpu_to_le16(skb->len - 2);
- skb->nh.raw = skb->data;
+ skb_reset_network_header(skb);
dn_rt_finish_output(skb, dn_rt_all_rt_mcast, msg->id);
}
@@ -911,7 +890,7 @@ static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn
if (dn->priority != dn_db->parms.priority)
return 0;
- if (dn_ntohs(dn->addr) < dn_ntohs(ifa->ifa_local))
+ if (le16_to_cpu(dn->addr) < le16_to_cpu(ifa->ifa_local))
return 1;
return 0;
@@ -920,13 +899,13 @@ static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn
static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
{
int n;
- struct dn_dev *dn_db = dev->dn_ptr;
+ struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
struct sk_buff *skb;
size_t size;
unsigned char *ptr;
unsigned char *i1, *i2;
- unsigned short *pktlen;
+ __le16 *pktlen;
char *src;
if (mtu2blksize(dev) < (26 + 7))
@@ -953,13 +932,13 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
dn_dn2eth(ptr, ifa->ifa_local);
src = ptr;
ptr += ETH_ALEN;
- *ptr++ = dn_db->parms.forwarding == 1 ?
+ *ptr++ = dn_db->parms.forwarding == 1 ?
DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
- *((unsigned short *)ptr) = dn_htons(mtu2blksize(dev));
+ *((__le16 *)ptr) = cpu_to_le16(mtu2blksize(dev));
ptr += 2;
- *ptr++ = dn_db->parms.priority; /* Priority */
+ *ptr++ = dn_db->parms.priority; /* Priority */
*ptr++ = 0; /* Area: Reserved */
- *((unsigned short *)ptr) = dn_htons((unsigned short)dn_db->parms.t3);
+ *((__le16 *)ptr) = cpu_to_le16((unsigned short)dn_db->parms.t3);
ptr += 2;
*ptr++ = 0; /* MPD: Reserved */
i1 = ptr++;
@@ -974,10 +953,10 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
skb_trim(skb, (27 + *i2));
- pktlen = (unsigned short *)skb_push(skb, 2);
- *pktlen = dn_htons(skb->len - 2);
+ pktlen = (__le16 *)skb_push(skb, 2);
+ *pktlen = cpu_to_le16(skb->len - 2);
- skb->nh.raw = skb->data;
+ skb_reset_network_header(skb);
if (dn_am_i_a_router(dn, dn_db, ifa)) {
struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
@@ -991,7 +970,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
{
- struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
+ struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
if (dn_db->parms.forwarding == 0)
dn_send_endnode_hello(dev, ifa);
@@ -1016,7 +995,7 @@ static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
ptr = skb_put(skb, 2 + 4 + tdlen);
*ptr++ = DN_RT_PKT_HELO;
- *((dn_address *)ptr) = ifa->ifa_local;
+ *((__le16 *)ptr) = ifa->ifa_local;
ptr += 2;
*ptr++ = tdlen;
@@ -1029,14 +1008,12 @@ static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
static int dn_eth_up(struct net_device *dev)
{
- struct dn_dev *dn_db = dev->dn_ptr;
+ struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
if (dn_db->parms.forwarding == 0)
- dev_mc_add(dev, dn_rt_all_end_mcast, ETH_ALEN, 0);
+ dev_mc_add(dev, dn_rt_all_end_mcast);
else
- dev_mc_add(dev, dn_rt_all_rt_mcast, ETH_ALEN, 0);
-
- dev_mc_upload(dev);
+ dev_mc_add(dev, dn_rt_all_rt_mcast);
dn_db->use_long = 1;
@@ -1045,12 +1022,12 @@ static int dn_eth_up(struct net_device *dev)
static void dn_eth_down(struct net_device *dev)
{
- struct dn_dev *dn_db = dev->dn_ptr;
+ struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
if (dn_db->parms.forwarding == 0)
- dev_mc_delete(dev, dn_rt_all_end_mcast, ETH_ALEN, 0);
+ dev_mc_del(dev, dn_rt_all_end_mcast);
else
- dev_mc_delete(dev, dn_rt_all_rt_mcast, ETH_ALEN, 0);
+ dev_mc_del(dev, dn_rt_all_rt_mcast);
}
static void dn_dev_set_timer(struct net_device *dev);
@@ -1058,12 +1035,16 @@ static void dn_dev_set_timer(struct net_device *dev);
static void dn_dev_timer_func(unsigned long arg)
{
struct net_device *dev = (struct net_device *)arg;
- struct dn_dev *dn_db = dev->dn_ptr;
+ struct dn_dev *dn_db;
struct dn_ifaddr *ifa;
+ rcu_read_lock();
+ dn_db = rcu_dereference(dev->dn_ptr);
if (dn_db->t3 <= dn_db->parms.t2) {
if (dn_db->parms.timer3) {
- for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) {
+ for (ifa = rcu_dereference(dn_db->ifa_list);
+ ifa;
+ ifa = rcu_dereference(ifa->ifa_next)) {
if (!(ifa->ifa_flags & IFA_F_SECONDARY))
dn_db->parms.timer3(dev, ifa);
}
@@ -1072,13 +1053,13 @@ static void dn_dev_timer_func(unsigned long arg)
} else {
dn_db->t3 -= dn_db->parms.t2;
}
-
+ rcu_read_unlock();
dn_dev_set_timer(dev);
}
static void dn_dev_set_timer(struct net_device *dev)
{
- struct dn_dev *dn_db = dev->dn_ptr;
+ struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
if (dn_db->parms.t2 > dn_db->parms.t3)
dn_db->parms.t2 = dn_db->parms.t3;
@@ -1090,7 +1071,7 @@ static void dn_dev_set_timer(struct net_device *dev)
add_timer(&dn_db->timer);
}
-struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
+static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
{
int i;
struct dn_dev_parms *p = dn_dev_list;
@@ -1106,27 +1087,33 @@ struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
return NULL;
*err = -ENOBUFS;
- if ((dn_db = kmalloc(sizeof(struct dn_dev), GFP_ATOMIC)) == NULL)
+ if ((dn_db = kzalloc(sizeof(struct dn_dev), GFP_ATOMIC)) == NULL)
return NULL;
- memset(dn_db, 0, sizeof(struct dn_dev));
memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms));
- smp_wmb();
- dev->dn_ptr = dn_db;
+
+ rcu_assign_pointer(dev->dn_ptr, dn_db);
dn_db->dev = dev;
init_timer(&dn_db->timer);
dn_db->uptime = jiffies;
+
+ dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);
+ if (!dn_db->neigh_parms) {
+ RCU_INIT_POINTER(dev->dn_ptr, NULL);
+ kfree(dn_db);
+ return NULL;
+ }
+
if (dn_db->parms.up) {
if (dn_db->parms.up(dev) < 0) {
+ neigh_parms_release(&dn_neigh_table, dn_db->neigh_parms);
dev->dn_ptr = NULL;
kfree(dn_db);
return NULL;
}
}
- dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);
-
dn_dev_sysctl_register(dev, &dn_db->parms);
dn_dev_set_timer(dev);
@@ -1139,7 +1126,7 @@ struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
/*
* This processes a device up event. We only start up
* the loopback device & ethernet devices with correct
- * MAC addreses automatically. Others must be started
+ * MAC addresses automatically. Others must be started
* specifically.
*
* FIXME: How should we configure the loopback address ? If we could dispense
@@ -1150,9 +1137,9 @@ struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
void dn_dev_up(struct net_device *dev)
{
struct dn_ifaddr *ifa;
- dn_address addr = decnet_address;
+ __le16 addr = decnet_address;
int maybe_default = 0;
- struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
+ struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK))
return;
@@ -1173,7 +1160,7 @@ void dn_dev_up(struct net_device *dev)
if (dev->type == ARPHRD_ETHER) {
if (memcmp(dev->dev_addr, dn_hiord, 4) != 0)
return;
- addr = dn_htons(dn_eth2dn(dev->dev_addr));
+ addr = dn_eth2dn(dev->dev_addr);
maybe_default = 1;
}
@@ -1203,7 +1190,7 @@ void dn_dev_up(struct net_device *dev)
static void dn_dev_delete(struct net_device *dev)
{
- struct dn_dev *dn_db = dev->dn_ptr;
+ struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
if (dn_db == NULL)
return;
@@ -1231,13 +1218,13 @@ static void dn_dev_delete(struct net_device *dev)
void dn_dev_down(struct net_device *dev)
{
- struct dn_dev *dn_db = dev->dn_ptr;
+ struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
struct dn_ifaddr *ifa;
if (dn_db == NULL)
return;
- while((ifa = dn_db->ifa_list) != NULL) {
+ while ((ifa = rtnl_dereference(dn_db->ifa_list)) != NULL) {
dn_dev_del_ifa(dn_db, &dn_db->ifa_list, 0);
dn_dev_free_ifa(ifa);
}
@@ -1247,17 +1234,14 @@ void dn_dev_down(struct net_device *dev)
void dn_dev_init_pkt(struct sk_buff *skb)
{
- return;
}
void dn_dev_veri_pkt(struct sk_buff *skb)
{
- return;
}
void dn_dev_hello(struct sk_buff *skb)
{
- return;
}
void dn_dev_devices_off(void)
@@ -1265,7 +1249,7 @@ void dn_dev_devices_off(void)
struct net_device *dev;
rtnl_lock();
- for(dev = dev_base; dev; dev = dev->next)
+ for_each_netdev(&init_net, dev)
dn_dev_down(dev);
rtnl_unlock();
@@ -1276,7 +1260,7 @@ void dn_dev_devices_on(void)
struct net_device *dev;
rtnl_lock();
- for(dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(&init_net, dev) {
if (dev->flags & IFF_UP)
dn_dev_up(dev);
}
@@ -1285,82 +1269,78 @@ void dn_dev_devices_on(void)
int register_dnaddr_notifier(struct notifier_block *nb)
{
- return notifier_chain_register(&dnaddr_chain, nb);
+ return blocking_notifier_chain_register(&dnaddr_chain, nb);
}
int unregister_dnaddr_notifier(struct notifier_block *nb)
{
- return notifier_chain_unregister(&dnaddr_chain, nb);
+ return blocking_notifier_chain_unregister(&dnaddr_chain, nb);
}
#ifdef CONFIG_PROC_FS
-static inline struct net_device *dn_dev_get_next(struct seq_file *seq, struct net_device *dev)
+static inline int is_dn_dev(struct net_device *dev)
{
- do {
- dev = dev->next;
- } while(dev && !dev->dn_ptr);
-
- return dev;
+ return dev->dn_ptr != NULL;
}
-static struct net_device *dn_dev_get_idx(struct seq_file *seq, loff_t pos)
+static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
+ __acquires(RCU)
{
+ int i;
struct net_device *dev;
- dev = dev_base;
- if (dev && !dev->dn_ptr)
- dev = dn_dev_get_next(seq, dev);
- if (pos) {
- while(dev && (dev = dn_dev_get_next(seq, dev)))
- --pos;
- }
- return dev;
-}
+ rcu_read_lock();
-static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
-{
- if (*pos) {
- struct net_device *dev;
- read_lock(&dev_base_lock);
- dev = dn_dev_get_idx(seq, *pos - 1);
- if (dev == NULL)
- read_unlock(&dev_base_lock);
- return dev;
+ if (*pos == 0)
+ return SEQ_START_TOKEN;
+
+ i = 1;
+ for_each_netdev_rcu(&init_net, dev) {
+ if (!is_dn_dev(dev))
+ continue;
+
+ if (i++ == *pos)
+ return dev;
}
- return SEQ_START_TOKEN;
+
+ return NULL;
}
static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- struct net_device *dev = v;
- loff_t one = 1;
+ struct net_device *dev;
- if (v == SEQ_START_TOKEN) {
- dev = dn_dev_seq_start(seq, &one);
- } else {
- dev = dn_dev_get_next(seq, dev);
- if (dev == NULL)
- read_unlock(&dev_base_lock);
- }
++*pos;
- return dev;
+
+ dev = v;
+ if (v == SEQ_START_TOKEN)
+ dev = net_device_entry(&init_net.dev_base_head);
+
+ for_each_netdev_continue_rcu(&init_net, dev) {
+ if (!is_dn_dev(dev))
+ continue;
+
+ return dev;
+ }
+
+ return NULL;
}
static void dn_dev_seq_stop(struct seq_file *seq, void *v)
+ __releases(RCU)
{
- if (v && v != SEQ_START_TOKEN)
- read_unlock(&dev_base_lock);
+ rcu_read_unlock();
}
static char *dn_type2asc(char type)
{
- switch(type) {
- case DN_DEV_BCAST:
- return "B";
- case DN_DEV_UCAST:
- return "U";
- case DN_DEV_MPOINT:
- return "M";
+ switch (type) {
+ case DN_DEV_BCAST:
+ return "B";
+ case DN_DEV_UCAST:
+ return "U";
+ case DN_DEV_MPOINT:
+ return "M";
}
return "?";
@@ -1369,29 +1349,29 @@ static char *dn_type2asc(char type)
static int dn_dev_seq_show(struct seq_file *seq, void *v)
{
if (v == SEQ_START_TOKEN)
- seq_puts(seq, "Name Flags T1 Timer1 T3 Timer3 BlkSize Pri State DevType Router Peer\n");
+ seq_puts(seq, "Name Flags T1 Timer1 T3 Timer3 BlkSize Pri State DevType Router Peer\n");
else {
struct net_device *dev = v;
char peer_buf[DN_ASCBUF_LEN];
char router_buf[DN_ASCBUF_LEN];
- struct dn_dev *dn_db = dev->dn_ptr;
+ struct dn_dev *dn_db = rcu_dereference(dev->dn_ptr);
- seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu"
+ seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu"
" %04hu %03d %02x %-10s %-7s %-7s\n",
- dev->name ? dev->name : "???",
- dn_type2asc(dn_db->parms.mode),
- 0, 0,
+ dev->name ? dev->name : "???",
+ dn_type2asc(dn_db->parms.mode),
+ 0, 0,
dn_db->t3, dn_db->parms.t3,
mtu2blksize(dev),
dn_db->parms.priority,
dn_db->parms.state, dn_db->parms.name,
- dn_db->router ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->router->primary_key), router_buf) : "",
- dn_db->peer ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->peer->primary_key), peer_buf) : "");
+ dn_db->router ? dn_addr2asc(le16_to_cpu(*(__le16 *)dn_db->router->primary_key), router_buf) : "",
+ dn_db->peer ? dn_addr2asc(le16_to_cpu(*(__le16 *)dn_db->peer->primary_key), peer_buf) : "");
}
return 0;
}
-static struct seq_operations dn_dev_seq_ops = {
+static const struct seq_operations dn_dev_seq_ops = {
.start = dn_dev_seq_start,
.next = dn_dev_seq_next,
.stop = dn_dev_seq_stop,
@@ -1403,7 +1383,7 @@ static int dn_dev_seq_open(struct inode *inode, struct file *file)
return seq_open(file, &dn_dev_seq_ops);
}
-static struct file_operations dn_dev_seq_fops = {
+static const struct file_operations dn_dev_seq_fops = {
.owner = THIS_MODULE,
.open = dn_dev_seq_open,
.read = seq_read,
@@ -1413,49 +1393,31 @@ static struct file_operations dn_dev_seq_fops = {
#endif /* CONFIG_PROC_FS */
-static struct rtnetlink_link dnet_rtnetlink_table[RTM_NR_MSGTYPES] =
-{
- [RTM_NEWADDR - RTM_BASE] = { .doit = dn_dev_rtm_newaddr, },
- [RTM_DELADDR - RTM_BASE] = { .doit = dn_dev_rtm_deladdr, },
- [RTM_GETADDR - RTM_BASE] = { .dumpit = dn_dev_dump_ifaddr, },
-#ifdef CONFIG_DECNET_ROUTER
- [RTM_NEWROUTE - RTM_BASE] = { .doit = dn_fib_rtm_newroute, },
- [RTM_DELROUTE - RTM_BASE] = { .doit = dn_fib_rtm_delroute, },
- [RTM_GETROUTE - RTM_BASE] = { .doit = dn_cache_getroute,
- .dumpit = dn_fib_dump, },
- [RTM_NEWRULE - RTM_BASE] = { .doit = dn_fib_rtm_newrule, },
- [RTM_DELRULE - RTM_BASE] = { .doit = dn_fib_rtm_delrule, },
- [RTM_GETRULE - RTM_BASE] = { .dumpit = dn_fib_dump_rules, },
-#else
- [RTM_GETROUTE - RTM_BASE] = { .doit = dn_cache_getroute,
- .dumpit = dn_cache_dump, },
-#endif
-
-};
-
-static int __initdata addr[2];
+static int addr[2];
module_param_array(addr, int, NULL, 0444);
MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
void __init dn_dev_init(void)
{
- if (addr[0] > 63 || addr[0] < 0) {
- printk(KERN_ERR "DECnet: Area must be between 0 and 63");
- return;
- }
+ if (addr[0] > 63 || addr[0] < 0) {
+ printk(KERN_ERR "DECnet: Area must be between 0 and 63");
+ return;
+ }
- if (addr[1] > 1023 || addr[1] < 0) {
- printk(KERN_ERR "DECnet: Node must be between 0 and 1023");
- return;
- }
+ if (addr[1] > 1023 || addr[1] < 0) {
+ printk(KERN_ERR "DECnet: Node must be between 0 and 1023");
+ return;
+ }
- decnet_address = dn_htons((addr[0] << 10) | addr[1]);
+ decnet_address = cpu_to_le16((addr[0] << 10) | addr[1]);
dn_dev_devices_on();
- rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table;
+ rtnl_register(PF_DECnet, RTM_NEWADDR, dn_nl_newaddr, NULL, NULL);
+ rtnl_register(PF_DECnet, RTM_DELADDR, dn_nl_deladdr, NULL, NULL);
+ rtnl_register(PF_DECnet, RTM_GETADDR, NULL, dn_nl_dump_ifaddr, NULL);
- proc_net_fops_create("decnet_dev", S_IRUGO, &dn_dev_seq_fops);
+ proc_create("decnet_dev", S_IRUGO, init_net.proc_net, &dn_dev_seq_fops);
#ifdef CONFIG_SYSCTL
{
@@ -1468,8 +1430,6 @@ void __init dn_dev_init(void)
void __exit dn_dev_cleanup(void)
{
- rtnetlink_links[PF_DECnet] = NULL;
-
#ifdef CONFIG_SYSCTL
{
int i;
@@ -1478,7 +1438,7 @@ void __exit dn_dev_cleanup(void)
}
#endif /* CONFIG_SYSCTL */
- proc_net_remove("decnet_dev");
+ remove_proc_entry("decnet_dev", init_net.proc_net);
dn_dev_devices_off();
}
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
index 99bc061759c..d332aefb084 100644
--- a/net/decnet/dn_fib.c
+++ b/net/decnet/dn_fib.c
@@ -17,10 +17,10 @@
* this code was copied from it.
*
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/net.h>
#include <linux/socket.h>
+#include <linux/slab.h>
#include <linux/sockios.h>
#include <linux/init.h>
#include <linux/skbuff.h>
@@ -30,11 +30,12 @@
#include <linux/netdevice.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <asm/uaccess.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/flow.h>
+#include <net/fib_rules.h>
#include <net/dn.h>
#include <net/dn_route.h>
#include <net/dn_fib.h>
@@ -55,17 +56,15 @@
#define endfor_nexthops(fi) }
-extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
-
static DEFINE_SPINLOCK(dn_fib_multipath_lock);
static struct dn_fib_info *dn_fib_info_list;
-static DEFINE_RWLOCK(dn_fib_info_lock);
+static DEFINE_SPINLOCK(dn_fib_info_lock);
static struct
{
int error;
u8 scope;
-} dn_fib_props[RTA_MAX+1] = {
+} dn_fib_props[RTN_MAX+1] = {
[RTN_UNSPEC] = { .error = 0, .scope = RT_SCOPE_NOWHERE },
[RTN_UNICAST] = { .error = 0, .scope = RT_SCOPE_UNIVERSE },
[RTN_LOCAL] = { .error = 0, .scope = RT_SCOPE_HOST },
@@ -80,6 +79,9 @@ static struct
[RTN_XRESOLVE] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
};
+static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force);
+static int dn_fib_sync_up(struct net_device *dev);
+
void dn_fib_free_info(struct dn_fib_info *fi)
{
if (fi->fib_dead == 0) {
@@ -97,7 +99,7 @@ void dn_fib_free_info(struct dn_fib_info *fi)
void dn_fib_release_info(struct dn_fib_info *fi)
{
- write_lock(&dn_fib_info_lock);
+ spin_lock(&dn_fib_info_lock);
if (fi && --fi->fib_treeref == 0) {
if (fi->fib_next)
fi->fib_next->fib_prev = fi->fib_prev;
@@ -108,7 +110,7 @@ void dn_fib_release_info(struct dn_fib_info *fi)
fi->fib_dead = 1;
dn_fib_info_put(fi);
}
- write_unlock(&dn_fib_info_lock);
+ spin_unlock(&dn_fib_info_lock);
}
static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
@@ -143,22 +145,10 @@ static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi
return NULL;
}
-u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type)
+static int dn_fib_count_nhs(const struct nlattr *attr)
{
- while(RTA_OK(attr,attrlen)) {
- if (attr->rta_type == type)
- return *(u16*)RTA_DATA(attr);
- attr = RTA_NEXT(attr, attrlen);
- }
-
- return 0;
-}
-
-static int dn_fib_count_nhs(struct rtattr *rta)
-{
- int nhs = 0;
- struct rtnexthop *nhp = RTA_DATA(rta);
- int nhlen = RTA_PAYLOAD(rta);
+ struct rtnexthop *nhp = nla_data(attr);
+ int nhs = 0, nhlen = nla_len(attr);
while(nhlen >= (int)sizeof(struct rtnexthop)) {
if ((nhlen -= nhp->rtnh_len) < 0)
@@ -170,10 +160,11 @@ static int dn_fib_count_nhs(struct rtattr *rta)
return nhs;
}
-static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, const struct rtmsg *r)
+static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct nlattr *attr,
+ const struct rtmsg *r)
{
- struct rtnexthop *nhp = RTA_DATA(rta);
- int nhlen = RTA_PAYLOAD(rta);
+ struct rtnexthop *nhp = nla_data(attr);
+ int nhlen = nla_len(attr);
change_nexthops(fi) {
int attrlen = nhlen - sizeof(struct rtnexthop);
@@ -185,7 +176,10 @@ static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, cons
nh->nh_weight = nhp->rtnh_hops + 1;
if (attrlen) {
- nh->nh_gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
+ struct nlattr *gw_attr;
+
+ gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY);
+ nh->nh_gw = gw_attr ? nla_get_le16(gw_attr) : 0;
}
nhp = RTNH_NEXT(nhp);
} endfor_nexthops(fi);
@@ -199,11 +193,9 @@ static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct
int err;
if (nh->nh_gw) {
- struct flowi fl;
+ struct flowidn fld;
struct dn_fib_res res;
- memset(&fl, 0, sizeof(fl));
-
if (nh->nh_flags&RTNH_F_ONLINK) {
struct net_device *dev;
@@ -211,7 +203,7 @@ static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct
return -EINVAL;
if (dnet_addr_type(nh->nh_gw) != RTN_UNICAST)
return -EINVAL;
- if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)
+ if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL)
return -ENODEV;
if (!(dev->flags&IFF_UP))
return -ENETDOWN;
@@ -221,15 +213,15 @@ static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct
return 0;
}
- memset(&fl, 0, sizeof(fl));
- fl.fld_dst = nh->nh_gw;
- fl.oif = nh->nh_oif;
- fl.fld_scope = r->rtm_scope + 1;
+ memset(&fld, 0, sizeof(fld));
+ fld.daddr = nh->nh_gw;
+ fld.flowidn_oif = nh->nh_oif;
+ fld.flowidn_scope = r->rtm_scope + 1;
- if (fl.fld_scope < RT_SCOPE_LINK)
- fl.fld_scope = RT_SCOPE_LINK;
+ if (fld.flowidn_scope < RT_SCOPE_LINK)
+ fld.flowidn_scope = RT_SCOPE_LINK;
- if ((err = dn_fib_lookup(&fl, &res)) != 0)
+ if ((err = dn_fib_lookup(&fld, &res)) != 0)
return err;
err = -EINVAL;
@@ -254,7 +246,7 @@ out:
if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))
return -EINVAL;
- dev = __dev_get_by_index(nh->nh_oif);
+ dev = __dev_get_by_index(&init_net, nh->nh_oif);
if (dev == NULL || dev->dn_ptr == NULL)
return -ENODEV;
if (!(dev->flags&IFF_UP))
@@ -268,77 +260,91 @@ out:
}
-struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta *rta, const struct nlmsghdr *nlh, int *errp)
+struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct nlattr *attrs[],
+ const struct nlmsghdr *nlh, int *errp)
{
int err;
struct dn_fib_info *fi = NULL;
struct dn_fib_info *ofi;
int nhs = 1;
+ if (r->rtm_type > RTN_MAX)
+ goto err_inval;
+
if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
goto err_inval;
- if (rta->rta_mp) {
- nhs = dn_fib_count_nhs(rta->rta_mp);
- if (nhs == 0)
- goto err_inval;
- }
+ if (attrs[RTA_MULTIPATH] &&
+ (nhs = dn_fib_count_nhs(attrs[RTA_MULTIPATH])) == 0)
+ goto err_inval;
- fi = kmalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL);
+ fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL);
err = -ENOBUFS;
if (fi == NULL)
goto failure;
- memset(fi, 0, sizeof(*fi)+nhs*sizeof(struct dn_fib_nh));
fi->fib_protocol = r->rtm_protocol;
fi->fib_nhs = nhs;
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)
+
+ if (attrs[RTA_PRIORITY])
+ fi->fib_priority = nla_get_u32(attrs[RTA_PRIORITY]);
+
+ if (attrs[RTA_METRICS]) {
+ struct nlattr *attr;
+ int rem;
+
+ nla_for_each_nested(attr, attrs[RTA_METRICS], rem) {
+ int type = nla_type(attr);
+
+ if (type) {
+ if (type > RTAX_MAX || nla_len(attr) < 4)
goto err_inval;
- fi->fib_metrics[flavour-1] = *(unsigned*)RTA_DATA(attr);
+
+ fi->fib_metrics[type-1] = nla_get_u32(attr);
}
- attr = RTA_NEXT(attr, attrlen);
}
}
- if (rta->rta_prefsrc)
- memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2);
- if (rta->rta_mp) {
- if ((err = dn_fib_get_nhs(fi, rta->rta_mp, r)) != 0)
+ if (attrs[RTA_PREFSRC])
+ fi->fib_prefsrc = nla_get_le16(attrs[RTA_PREFSRC]);
+
+ if (attrs[RTA_MULTIPATH]) {
+ if ((err = dn_fib_get_nhs(fi, attrs[RTA_MULTIPATH], r)) != 0)
goto failure;
- if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif)
+
+ if (attrs[RTA_OIF] &&
+ fi->fib_nh->nh_oif != nla_get_u32(attrs[RTA_OIF]))
goto err_inval;
- if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 2))
+
+ if (attrs[RTA_GATEWAY] &&
+ fi->fib_nh->nh_gw != nla_get_le16(attrs[RTA_GATEWAY]))
goto err_inval;
} else {
struct dn_fib_nh *nh = fi->fib_nh;
- if (rta->rta_oif)
- nh->nh_oif = *rta->rta_oif;
- if (rta->rta_gw)
- memcpy(&nh->nh_gw, rta->rta_gw, 2);
+
+ if (attrs[RTA_OIF])
+ nh->nh_oif = nla_get_u32(attrs[RTA_OIF]);
+
+ if (attrs[RTA_GATEWAY])
+ nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
+
nh->nh_flags = r->rtm_flags;
nh->nh_weight = 1;
}
if (r->rtm_type == RTN_NAT) {
- if (rta->rta_gw == NULL || nhs != 1 || rta->rta_oif)
+ if (!attrs[RTA_GATEWAY] || nhs != 1 || attrs[RTA_OIF])
goto err_inval;
- memcpy(&fi->fib_nh->nh_gw, rta->rta_gw, 2);
+
+ fi->fib_nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
goto link_it;
}
if (dn_fib_props[r->rtm_type].error) {
- if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
+ if (attrs[RTA_GATEWAY] || attrs[RTA_OIF] || attrs[RTA_MULTIPATH])
goto err_inval;
+
goto link_it;
}
@@ -352,7 +358,7 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
if (nhs != 1 || nh->nh_gw)
goto err_inval;
nh->nh_scope = RT_SCOPE_NOWHERE;
- nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif);
+ nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif);
err = -ENODEV;
if (nh->nh_dev == NULL)
goto failure;
@@ -364,8 +370,8 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
}
if (fi->fib_prefsrc) {
- if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
- memcmp(&fi->fib_prefsrc, rta->rta_dst, 2))
+ if (r->rtm_type != RTN_LOCAL || !attrs[RTA_DST] ||
+ fi->fib_prefsrc != nla_get_le16(attrs[RTA_DST]))
if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
goto err_inval;
}
@@ -380,13 +386,13 @@ link_it:
fi->fib_treeref++;
atomic_inc(&fi->fib_clntref);
- write_lock(&dn_fib_info_lock);
+ spin_lock(&dn_fib_info_lock);
fi->fib_next = dn_fib_info_list;
fi->fib_prev = NULL;
if (dn_fib_info_list)
dn_fib_info_list->fib_prev = fi;
dn_fib_info_list = fi;
- write_unlock(&dn_fib_info_lock);
+ spin_unlock(&dn_fib_info_lock);
return fi;
err_inval:
@@ -402,7 +408,7 @@ failure:
return NULL;
}
-int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowi *fl, struct dn_fib_res *res)
+int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowidn *fld, struct dn_fib_res *res)
{
int err = dn_fib_props[type].error;
@@ -412,38 +418,39 @@ int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowi *
res->fi = fi;
- switch(type) {
- case RTN_NAT:
- DN_FIB_RES_RESET(*res);
+ 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 (!fld->flowidn_oif ||
+ fld->flowidn_oif == nh->nh_oif)
+ break;
+ }
+ if (nhsel < fi->fib_nhs) {
+ res->nh_sel = nhsel;
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;
+ }
+ endfor_nexthops(fi);
+ res->fi = NULL;
+ return 1;
+ default:
+ net_err_ratelimited("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 flowi *fl, struct dn_fib_res *res)
+void dn_fib_select_multipath(const struct flowidn *fld, struct dn_fib_res *res)
{
struct dn_fib_info *fi = res->fi;
int w;
@@ -482,100 +489,96 @@ void dn_fib_select_multipath(const struct flowi *fl, struct dn_fib_res *res)
spin_unlock_bh(&dn_fib_multipath_lock);
}
-
-static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
+static inline u32 rtm_get_table(struct nlattr *attrs[], u8 table)
{
- int i;
+ if (attrs[RTA_TABLE])
+ table = nla_get_u32(attrs[RTA_TABLE]);
- for(i = 1; i <= RTA_MAX; i++) {
- struct rtattr *attr = rta[i-1];
- if (attr) {
- if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2)
- return -EINVAL;
- if (i != RTA_MULTIPATH && i != RTA_METRICS)
- rta[i-1] = (struct rtattr *)RTA_DATA(attr);
- }
- }
-
- return 0;
+ return table;
}
-int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
{
+ struct net *net = sock_net(skb->sk);
struct dn_fib_table *tb;
- struct rtattr **rta = arg;
- struct rtmsg *r = NLMSG_DATA(nlh);
-
- if (dn_fib_check_attr(r, rta))
- return -EINVAL;
-
- tb = dn_fib_get_table(r->rtm_table, 0);
- if (tb)
- return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
+ struct rtmsg *r = nlmsg_data(nlh);
+ struct nlattr *attrs[RTA_MAX+1];
+ int err;
- return -ESRCH;
-}
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
-int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
-{
- struct dn_fib_table *tb;
- struct rtattr **rta = arg;
- struct rtmsg *r = NLMSG_DATA(nlh);
-
- if (dn_fib_check_attr(r, rta))
+ if (!net_eq(net, &init_net))
return -EINVAL;
- tb = dn_fib_get_table(r->rtm_table, 1);
- if (tb)
- return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
+ err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy);
+ if (err < 0)
+ return err;
- return -ENOBUFS;
-}
+ tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 0);
+ if (!tb)
+ return -ESRCH;
+ return tb->delete(tb, r, attrs, nlh, &NETLINK_CB(skb));
+}
-int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
+static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
{
- int t;
- int s_t;
+ struct net *net = sock_net(skb->sk);
struct dn_fib_table *tb;
+ struct rtmsg *r = nlmsg_data(nlh);
+ struct nlattr *attrs[RTA_MAX+1];
+ int err;
- if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
- ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
- return dn_cache_dump(skb, cb);
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
- s_t = cb->args[0];
- if (s_t == 0)
- s_t = cb->args[0] = RT_MIN_TABLE;
+ if (!net_eq(net, &init_net))
+ return -EINVAL;
- for(t = s_t; t <= RT_TABLE_MAX; t++) {
- if (t < s_t)
- continue;
- if (t > s_t)
- memset(&cb->args[1], 0,
- sizeof(cb->args) - sizeof(cb->args[0]));
- tb = dn_fib_get_table(t, 0);
- if (tb == NULL)
- continue;
- if (tb->dump(tb, skb, cb) < 0)
- break;
- }
+ err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy);
+ if (err < 0)
+ return err;
- cb->args[0] = t;
+ tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 1);
+ if (!tb)
+ return -ENOBUFS;
- return skb->len;
+ return tb->insert(tb, r, attrs, nlh, &NETLINK_CB(skb));
}
-static void fib_magic(int cmd, int type, __u16 dst, int dst_len, struct dn_ifaddr *ifa)
+static void fib_magic(int cmd, int type, __le16 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;
+ struct {
+ struct nlattr hdr;
+ __le16 dst;
+ } dst_attr = {
+ .dst = dst,
+ };
+ struct {
+ struct nlattr hdr;
+ __le16 prefsrc;
+ } prefsrc_attr = {
+ .prefsrc = ifa->ifa_local,
+ };
+ struct {
+ struct nlattr hdr;
+ u32 oif;
+ } oif_attr = {
+ .oif = ifa->ifa_dev->dev->ifindex,
+ };
+ struct nlattr *attrs[RTA_MAX+1] = {
+ [RTA_DST] = (struct nlattr *) &dst_attr,
+ [RTA_PREFSRC] = (struct nlattr * ) &prefsrc_attr,
+ [RTA_OIF] = (struct nlattr *) &oif_attr,
+ };
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);
@@ -597,14 +600,10 @@ static void fib_magic(int cmd, int type, __u16 dst, int dst_len, struct dn_ifadd
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);
+ tb->insert(tb, &req.rtm, attrs, &req.nlh, NULL);
else
- tb->delete(tb, &req.rtm, &rta, &req.nlh, NULL);
+ tb->delete(tb, &req.rtm, attrs, &req.nlh, NULL);
}
static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa)
@@ -630,19 +629,21 @@ static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa)
ASSERT_RTNL();
/* Scan device list */
- read_lock(&dev_base_lock);
- for(dev = dev_base; dev; dev = dev->next) {
- dn_db = dev->dn_ptr;
+ rcu_read_lock();
+ for_each_netdev_rcu(&init_net, dev) {
+ dn_db = rcu_dereference(dev->dn_ptr);
if (dn_db == NULL)
continue;
- for(ifa2 = dn_db->ifa_list; ifa2; ifa2 = ifa2->ifa_next) {
+ for (ifa2 = rcu_dereference(dn_db->ifa_list);
+ ifa2 != NULL;
+ ifa2 = rcu_dereference(ifa2->ifa_next)) {
if (ifa2->ifa_local == ifa->ifa_local) {
found_it = 1;
break;
}
}
}
- read_unlock(&dev_base_lock);
+ rcu_read_unlock();
if (found_it == 0) {
fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
@@ -666,116 +667,100 @@ static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event,
{
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);
+ 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;
- 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;
+ }
+ break;
}
return NOTIFY_DONE;
}
-int dn_fib_sync_down(dn_address local, struct net_device *dev, int force)
+static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force)
{
- int ret = 0;
- int scope = RT_SCOPE_NOWHERE;
-
- if (force)
- scope = -1;
-
- for_fib_info() {
- /*
- * This makes no sense for DECnet.... we will almost
- * certainly have more than one local address the same
- * over all our interfaces. It needs thinking about
- * some more.
- */
- if (local && fi->fib_prefsrc == local) {
- fi->fib_flags |= RTNH_F_DEAD;
- ret++;
- } else if (dev && fi->fib_nhs) {
- int dead = 0;
-
- change_nexthops(fi) {
- if (nh->nh_flags&RTNH_F_DEAD)
- dead++;
- else if (nh->nh_dev == dev &&
- nh->nh_scope != scope) {
+ int ret = 0;
+ int scope = RT_SCOPE_NOWHERE;
+
+ if (force)
+ scope = -1;
+
+ for_fib_info() {
+ /*
+ * This makes no sense for DECnet.... we will almost
+ * certainly have more than one local address the same
+ * over all our interfaces. It needs thinking about
+ * some more.
+ */
+ if (local && fi->fib_prefsrc == local) {
+ fi->fib_flags |= RTNH_F_DEAD;
+ ret++;
+ } else if (dev && fi->fib_nhs) {
+ int dead = 0;
+
+ change_nexthops(fi) {
+ if (nh->nh_flags&RTNH_F_DEAD)
+ 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;
+ 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)
- if (dead == fi->fib_nhs) {
- fi->fib_flags |= RTNH_F_DEAD;
- ret++;
- }
- }
- } endfor_fib_info();
- return ret;
+ dead++;
+ }
+ } endfor_nexthops(fi)
+ if (dead == fi->fib_nhs) {
+ fi->fib_flags |= RTNH_F_DEAD;
+ ret++;
+ }
+ }
+ } endfor_fib_info();
+ return ret;
}
-int dn_fib_sync_up(struct net_device *dev)
+static int dn_fib_sync_up(struct net_device *dev)
{
- int ret = 0;
-
- if (!(dev->flags&IFF_UP))
- return 0;
-
- for_fib_info() {
- int alive = 0;
-
- change_nexthops(fi) {
- if (!(nh->nh_flags&RTNH_F_DEAD)) {
- alive++;
- continue;
- }
- if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
- continue;
- if (nh->nh_dev != dev || dev->dn_ptr == NULL)
- continue;
- alive++;
+ int ret = 0;
+
+ if (!(dev->flags&IFF_UP))
+ return 0;
+
+ for_fib_info() {
+ int alive = 0;
+
+ change_nexthops(fi) {
+ if (!(nh->nh_flags&RTNH_F_DEAD)) {
+ alive++;
+ continue;
+ }
+ if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
+ continue;
+ 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;
+ nh->nh_power = 0;
+ nh->nh_flags &= ~RTNH_F_DEAD;
spin_unlock_bh(&dn_fib_multipath_lock);
- } endfor_nexthops(fi);
-
- if (alive > 0) {
- fi->fib_flags &= ~RTNH_F_DEAD;
- ret++;
- }
- } endfor_fib_info();
- return ret;
-}
+ } endfor_nexthops(fi);
-void dn_fib_flush(void)
-{
- int flushed = 0;
- struct dn_fib_table *tb;
- int id;
-
- for(id = RT_TABLE_MAX; id > 0; id--) {
- if ((tb = dn_fib_get_table(id, 0)) == NULL)
- continue;
- flushed += tb->flush(tb);
- }
-
- if (flushed)
- dn_rt_cache_flush(-1);
+ if (alive > 0) {
+ fi->fib_flags &= ~RTNH_F_DEAD;
+ ret++;
+ }
+ } endfor_fib_info();
+ return ret;
}
static struct notifier_block dn_fib_dnaddr_notifier = {
@@ -793,11 +778,13 @@ void __exit dn_fib_cleanup(void)
void __init dn_fib_init(void)
{
-
dn_fib_table_init();
dn_fib_rules_init();
register_dnaddr_notifier(&dn_fib_dnaddr_notifier);
+
+ rtnl_register(PF_DECnet, RTM_NEWROUTE, dn_fib_rtm_newroute, NULL, NULL);
+ rtnl_register(PF_DECnet, RTM_DELROUTE, dn_fib_rtm_delroute, NULL, NULL);
}
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index 33ab256cfd4..c8121ceddb9 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -3,7 +3,7 @@
* operating system. DECnet is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
- * DECnet Neighbour Functions (Adjacency Database and
+ * DECnet Neighbour Functions (Adjacency Database and
* On-Ethernet Cache)
*
* Author: Steve Whitehouse <SteveW@ACM.org>
@@ -24,11 +24,11 @@
*
*/
-#include <linux/config.h>
#include <linux/net.h>
#include <linux/module.h>
#include <linux/socket.h>
#include <linux/if_arp.h>
+#include <linux/slab.h>
#include <linux/if_ether.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
@@ -38,7 +38,8 @@
#include <linux/seq_file.h>
#include <linux/rcupdate.h>
#include <linux/jhash.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
+#include <net/net_namespace.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/flow.h>
@@ -47,73 +48,75 @@
#include <net/dn_neigh.h>
#include <net/dn_route.h>
-static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev);
static int dn_neigh_construct(struct neighbour *);
static void dn_long_error_report(struct neighbour *, struct sk_buff *);
static void dn_short_error_report(struct neighbour *, struct sk_buff *);
-static int dn_long_output(struct sk_buff *);
-static int dn_short_output(struct sk_buff *);
-static int dn_phase3_output(struct sk_buff *);
+static int dn_long_output(struct neighbour *, struct sk_buff *);
+static int dn_short_output(struct neighbour *, struct sk_buff *);
+static int dn_phase3_output(struct neighbour *, struct sk_buff *);
/*
* For talking to broadcast devices: Ethernet & PPP
*/
-static struct neigh_ops dn_long_ops = {
+static const struct neigh_ops dn_long_ops = {
.family = AF_DECnet,
.error_report = dn_long_error_report,
.output = dn_long_output,
.connected_output = dn_long_output,
- .hh_output = dev_queue_xmit,
- .queue_xmit = dev_queue_xmit,
};
/*
* For talking to pointopoint and multidrop devices: DDCMP and X.25
*/
-static struct neigh_ops dn_short_ops = {
+static const struct neigh_ops dn_short_ops = {
.family = AF_DECnet,
.error_report = dn_short_error_report,
.output = dn_short_output,
.connected_output = dn_short_output,
- .hh_output = dev_queue_xmit,
- .queue_xmit = dev_queue_xmit,
};
/*
* For talking to DECnet phase III nodes
*/
-static struct neigh_ops dn_phase3_ops = {
+static const struct neigh_ops dn_phase3_ops = {
.family = AF_DECnet,
.error_report = dn_short_error_report, /* Can use short version here */
.output = dn_phase3_output,
.connected_output = dn_phase3_output,
- .hh_output = dev_queue_xmit,
- .queue_xmit = dev_queue_xmit
};
+static u32 dn_neigh_hash(const void *pkey,
+ const struct net_device *dev,
+ __u32 *hash_rnd)
+{
+ return jhash_2words(*(__u16 *)pkey, 0, hash_rnd[0]);
+}
+
struct neigh_table dn_neigh_table = {
.family = PF_DECnet,
- .entry_size = sizeof(struct dn_neigh),
- .key_len = sizeof(dn_address),
+ .entry_size = NEIGH_ENTRY_SIZE(sizeof(struct dn_neigh)),
+ .key_len = sizeof(__le16),
.hash = dn_neigh_hash,
.constructor = dn_neigh_construct,
.id = "dn_neigh_cache",
.parms ={
.tbl = &dn_neigh_table,
- .base_reachable_time = 30 * HZ,
- .retrans_time = 1 * HZ,
- .gc_staletime = 60 * HZ,
- .reachable_time = 30 * HZ,
- .delay_probe_time = 5 * HZ,
- .queue_len = 3,
- .ucast_probes = 0,
- .app_probes = 0,
- .mcast_probes = 0,
- .anycast_delay = 0,
- .proxy_delay = 0,
- .proxy_qlen = 0,
- .locktime = 1 * HZ,
+ .reachable_time = 30 * HZ,
+ .data = {
+ [NEIGH_VAR_MCAST_PROBES] = 0,
+ [NEIGH_VAR_UCAST_PROBES] = 0,
+ [NEIGH_VAR_APP_PROBES] = 0,
+ [NEIGH_VAR_RETRANS_TIME] = 1 * HZ,
+ [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ,
+ [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
+ [NEIGH_VAR_GC_STALETIME] = 60 * HZ,
+ [NEIGH_VAR_QUEUE_LEN_BYTES] = 64*1024,
+ [NEIGH_VAR_PROXY_QLEN] = 0,
+ [NEIGH_VAR_ANYCAST_DELAY] = 0,
+ [NEIGH_VAR_PROXY_DELAY] = 0,
+ [NEIGH_VAR_LOCKTIME] = 1 * HZ,
+ },
},
.gc_interval = 30 * HZ,
.gc_thresh1 = 128,
@@ -121,11 +124,6 @@ struct neigh_table dn_neigh_table = {
.gc_thresh3 = 1024,
};
-static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev)
-{
- return jhash_2words(*(dn_address *)pkey, 0, dn_neigh_table.hash_rnd);
-}
-
static int dn_neigh_construct(struct neighbour *neigh)
{
struct net_device *dev = neigh->dev;
@@ -166,8 +164,8 @@ static int dn_neigh_construct(struct neighbour *neigh)
else if ((dev->type == ARPHRD_ETHER) || (dev->type == ARPHRD_LOOPBACK))
dn_dn2eth(neigh->ha, dn->addr);
else {
- if (net_ratelimit())
- printk(KERN_DEBUG "Trying to create neigh for hw %d\n", dev->type);
+ net_dbg_ratelimited("Trying to create neigh for hw %d\n",
+ dev->type);
return -EINVAL;
}
@@ -204,27 +202,32 @@ static void dn_short_error_report(struct neighbour *neigh, struct sk_buff *skb)
static int dn_neigh_output_packet(struct sk_buff *skb)
{
- struct dst_entry *dst = skb->dst;
+ struct dst_entry *dst = skb_dst(skb);
struct dn_route *rt = (struct dn_route *)dst;
- struct neighbour *neigh = dst->neighbour;
+ struct neighbour *neigh = rt->n;
struct net_device *dev = neigh->dev;
char mac_addr[ETH_ALEN];
+ unsigned int seq;
+ int err;
dn_dn2eth(mac_addr, rt->rt_local_src);
- if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, mac_addr, skb->len) >= 0)
- return neigh->ops->queue_xmit(skb);
-
- if (net_ratelimit())
- printk(KERN_DEBUG "dn_neigh_output_packet: oops, can't send packet\n");
-
- kfree_skb(skb);
- return -EINVAL;
+ do {
+ seq = read_seqbegin(&neigh->ha_lock);
+ err = dev_hard_header(skb, dev, ntohs(skb->protocol),
+ neigh->ha, mac_addr, skb->len);
+ } while (read_seqretry(&neigh->ha_lock, seq));
+
+ if (err >= 0)
+ err = dev_queue_xmit(skb);
+ else {
+ kfree_skb(skb);
+ err = -EINVAL;
+ }
+ return err;
}
-static int dn_long_output(struct sk_buff *skb)
+static int dn_long_output(struct neighbour *neigh, struct sk_buff *skb)
{
- struct dst_entry *dst = skb->dst;
- struct neighbour *neigh = dst->neighbour;
struct net_device *dev = neigh->dev;
int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3;
unsigned char *data;
@@ -235,42 +238,39 @@ static int dn_long_output(struct sk_buff *skb)
if (skb_headroom(skb) < headroom) {
struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
if (skb2 == NULL) {
- if (net_ratelimit())
- printk(KERN_CRIT "dn_long_output: no memory\n");
+ net_crit_ratelimited("dn_long_output: no memory\n");
kfree_skb(skb);
return -ENOBUFS;
}
- kfree_skb(skb);
+ consume_skb(skb);
skb = skb2;
- if (net_ratelimit())
- printk(KERN_INFO "dn_long_output: Increasing headroom\n");
+ net_info_ratelimited("dn_long_output: Increasing headroom\n");
}
data = skb_push(skb, sizeof(struct dn_long_packet) + 3);
lp = (struct dn_long_packet *)(data+3);
- *((unsigned short *)data) = dn_htons(skb->len - 2);
+ *((__le16 *)data) = cpu_to_le16(skb->len - 2);
*(data + 2) = 1 | DN_RT_F_PF; /* Padding */
lp->msgflg = DN_RT_PKT_LONG|(cb->rt_flags&(DN_RT_F_IE|DN_RT_F_RQR|DN_RT_F_RTS));
lp->d_area = lp->d_subarea = 0;
- dn_dn2eth(lp->d_id, dn_ntohs(cb->dst));
+ dn_dn2eth(lp->d_id, cb->dst);
lp->s_area = lp->s_subarea = 0;
- dn_dn2eth(lp->s_id, dn_ntohs(cb->src));
+ dn_dn2eth(lp->s_id, cb->src);
lp->nl2 = 0;
lp->visit_ct = cb->hops & 0x3f;
lp->s_class = 0;
lp->pt = 0;
- skb->nh.raw = skb->data;
+ skb_reset_network_header(skb);
- return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
+ return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, skb, NULL,
+ neigh->dev, dn_neigh_output_packet);
}
-static int dn_short_output(struct sk_buff *skb)
+static int dn_short_output(struct neighbour *neigh, struct sk_buff *skb)
{
- struct dst_entry *dst = skb->dst;
- struct neighbour *neigh = dst->neighbour;
struct net_device *dev = neigh->dev;
int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
struct dn_short_packet *sp;
@@ -278,22 +278,20 @@ static int dn_short_output(struct sk_buff *skb)
struct dn_skb_cb *cb = DN_SKB_CB(skb);
- if (skb_headroom(skb) < headroom) {
- struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
- if (skb2 == NULL) {
- if (net_ratelimit())
- printk(KERN_CRIT "dn_short_output: no memory\n");
- kfree_skb(skb);
- return -ENOBUFS;
- }
- kfree_skb(skb);
- skb = skb2;
- if (net_ratelimit())
- printk(KERN_INFO "dn_short_output: Increasing headroom\n");
- }
+ if (skb_headroom(skb) < headroom) {
+ struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
+ if (skb2 == NULL) {
+ net_crit_ratelimited("dn_short_output: no memory\n");
+ kfree_skb(skb);
+ return -ENOBUFS;
+ }
+ consume_skb(skb);
+ skb = skb2;
+ net_info_ratelimited("dn_short_output: Increasing headroom\n");
+ }
data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
- *((unsigned short *)data) = dn_htons(skb->len - 2);
+ *((__le16 *)data) = cpu_to_le16(skb->len - 2);
sp = (struct dn_short_packet *)(data+2);
sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
@@ -301,19 +299,18 @@ static int dn_short_output(struct sk_buff *skb)
sp->srcnode = cb->src;
sp->forward = cb->hops & 0x3f;
- skb->nh.raw = skb->data;
+ skb_reset_network_header(skb);
- return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
+ return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, skb, NULL,
+ neigh->dev, dn_neigh_output_packet);
}
/*
* Phase 3 output is the same is short output, execpt that
* it clears the area bits before transmission.
*/
-static int dn_phase3_output(struct sk_buff *skb)
+static int dn_phase3_output(struct neighbour *neigh, struct sk_buff *skb)
{
- struct dst_entry *dst = skb->dst;
- struct neighbour *neigh = dst->neighbour;
struct net_device *dev = neigh->dev;
int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
struct dn_short_packet *sp;
@@ -323,29 +320,28 @@ static int dn_phase3_output(struct sk_buff *skb)
if (skb_headroom(skb) < headroom) {
struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
if (skb2 == NULL) {
- if (net_ratelimit())
- printk(KERN_CRIT "dn_phase3_output: no memory\n");
+ net_crit_ratelimited("dn_phase3_output: no memory\n");
kfree_skb(skb);
return -ENOBUFS;
}
- kfree_skb(skb);
+ consume_skb(skb);
skb = skb2;
- if (net_ratelimit())
- printk(KERN_INFO "dn_phase3_output: Increasing headroom\n");
+ net_info_ratelimited("dn_phase3_output: Increasing headroom\n");
}
data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
- *((unsigned short *)data) = dn_htons(skb->len - 2);
+ *((__le16 *)data) = cpu_to_le16(skb->len - 2);
sp = (struct dn_short_packet *)(data + 2);
sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
- sp->dstnode = cb->dst & dn_htons(0x03ff);
- sp->srcnode = cb->src & dn_htons(0x03ff);
+ sp->dstnode = cb->dst & cpu_to_le16(0x03ff);
+ sp->srcnode = cb->src & cpu_to_le16(0x03ff);
sp->forward = cb->hops & 0x3f;
- skb->nh.raw = skb->data;
+ skb_reset_network_header(skb);
- return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
+ return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, skb, NULL,
+ neigh->dev, dn_neigh_output_packet);
}
/*
@@ -373,9 +369,9 @@ int dn_neigh_router_hello(struct sk_buff *skb)
struct neighbour *neigh;
struct dn_neigh *dn;
struct dn_dev *dn_db;
- dn_address src;
+ __le16 src;
- src = dn_htons(dn_eth2dn(msg->id));
+ src = dn_eth2dn(msg->id);
neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1);
@@ -385,7 +381,7 @@ int dn_neigh_router_hello(struct sk_buff *skb)
write_lock(&neigh->lock);
neigh->used = jiffies;
- dn_db = (struct dn_dev *)neigh->dev->dn_ptr;
+ dn_db = rcu_dereference(neigh->dev->dn_ptr);
if (!(neigh->nud_state & NUD_PERMANENT)) {
neigh->updated = jiffies;
@@ -393,23 +389,23 @@ int dn_neigh_router_hello(struct sk_buff *skb)
if (neigh->dev->type == ARPHRD_ETHER)
memcpy(neigh->ha, &eth_hdr(skb)->h_source, ETH_ALEN);
- dn->blksize = dn_ntohs(msg->blksize);
+ dn->blksize = le16_to_cpu(msg->blksize);
dn->priority = msg->priority;
dn->flags &= ~DN_NDFLAG_P3;
- switch(msg->iinfo & DN_RT_INFO_TYPE) {
- case DN_RT_INFO_L1RT:
- dn->flags &=~DN_NDFLAG_R2;
- dn->flags |= DN_NDFLAG_R1;
- break;
- case DN_RT_INFO_L2RT:
- dn->flags |= DN_NDFLAG_R2;
+ switch (msg->iinfo & DN_RT_INFO_TYPE) {
+ case DN_RT_INFO_L1RT:
+ dn->flags &=~DN_NDFLAG_R2;
+ dn->flags |= DN_NDFLAG_R1;
+ break;
+ case DN_RT_INFO_L2RT:
+ dn->flags |= DN_NDFLAG_R2;
}
}
/* Only use routers in our area */
- if ((dn_ntohs(src)>>10) == dn_ntohs((decnet_address)>>10)) {
+ if ((le16_to_cpu(src)>>10) == (le16_to_cpu((decnet_address))>>10)) {
if (!dn_db->router) {
dn_db->router = neigh_clone(neigh);
} else {
@@ -433,9 +429,9 @@ int dn_neigh_endnode_hello(struct sk_buff *skb)
struct endnode_hello_message *msg = (struct endnode_hello_message *)skb->data;
struct neighbour *neigh;
struct dn_neigh *dn;
- dn_address src;
+ __le16 src;
- src = dn_htons(dn_eth2dn(msg->id));
+ src = dn_eth2dn(msg->id);
neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1);
@@ -452,7 +448,7 @@ int dn_neigh_endnode_hello(struct sk_buff *skb)
if (neigh->dev->type == ARPHRD_ETHER)
memcpy(neigh->ha, &eth_hdr(skb)->h_source, ETH_ALEN);
dn->flags &= ~(DN_NDFLAG_R1 | DN_NDFLAG_R2);
- dn->blksize = dn_ntohs(msg->blksize);
+ dn->blksize = le16_to_cpu(msg->blksize);
dn->priority = 0;
}
@@ -493,7 +489,6 @@ struct elist_cb_state {
static void neigh_elist_cb(struct neighbour *neigh, void *_info)
{
struct elist_cb_state *s = _info;
- struct dn_dev *dn_db;
struct dn_neigh *dn;
if (neigh->dev != s->dev)
@@ -503,10 +498,6 @@ static void neigh_elist_cb(struct neighbour *neigh, void *_info)
if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2)))
return;
- dn_db = (struct dn_dev *) s->dev->dn_ptr;
- if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2))
- return;
-
if (s->t == s->n)
s->rs = dn_find_slot(s->ptr, s->n, dn->priority);
else
@@ -547,7 +538,7 @@ static inline void dn_neigh_format_entry(struct seq_file *seq,
read_lock(&n->lock);
seq_printf(seq, "%-7s %s%s%s %02x %02d %07ld %-8s\n",
- dn_addr2asc(dn_ntohs(dn->addr), buf),
+ dn_addr2asc(le16_to_cpu(dn->addr), buf),
(dn->flags&DN_NDFLAG_R1) ? "1" : "-",
(dn->flags&DN_NDFLAG_R2) ? "2" : "-",
(dn->flags&DN_NDFLAG_P3) ? "3" : "-",
@@ -575,7 +566,7 @@ static void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos)
NEIGH_SEQ_NEIGH_ONLY);
}
-static struct seq_operations dn_neigh_seq_ops = {
+static const struct seq_operations dn_neigh_seq_ops = {
.start = dn_neigh_seq_start,
.next = neigh_seq_next,
.stop = neigh_seq_stop,
@@ -584,34 +575,16 @@ static struct seq_operations dn_neigh_seq_ops = {
static int dn_neigh_seq_open(struct inode *inode, struct file *file)
{
- struct seq_file *seq;
- int rc = -ENOMEM;
- struct neigh_seq_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
-
- if (!s)
- goto out;
-
- memset(s, 0, sizeof(*s));
- 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;
+ return seq_open_net(inode, file, &dn_neigh_seq_ops,
+ sizeof(struct neigh_seq_state));
}
-static struct file_operations dn_neigh_seq_fops = {
+static const struct file_operations dn_neigh_seq_fops = {
.owner = THIS_MODULE,
.open = dn_neigh_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
#endif
@@ -619,11 +592,12 @@ static struct file_operations dn_neigh_seq_fops = {
void __init dn_neigh_init(void)
{
neigh_table_init(&dn_neigh_table);
- proc_net_fops_create("decnet_neigh", S_IRUGO, &dn_neigh_seq_fops);
+ proc_create("decnet_neigh", S_IRUGO, init_net.proc_net,
+ &dn_neigh_seq_fops);
}
void __exit dn_neigh_cleanup(void)
{
- proc_net_remove("decnet_neigh");
+ remove_proc_entry("decnet_neigh", init_net.proc_net);
neigh_table_clear(&dn_neigh_table);
}
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
index 44bda85e678..fe5f01485d3 100644
--- a/net/decnet/dn_nsp_in.c
+++ b/net/decnet/dn_nsp_in.c
@@ -33,7 +33,7 @@
/******************************************************************************
(c) 1995-1998 E.M. Serrat emserrat@geocities.com
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -45,13 +45,11 @@
GNU General Public License for more details.
*******************************************************************************/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
@@ -59,12 +57,12 @@
#include <linux/netdevice.h>
#include <linux/inet.h>
#include <linux/route.h>
+#include <linux/slab.h>
#include <net/sock.h>
#include <net/tcp_states.h>
-#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
-#include <linux/termios.h>
+#include <linux/termios.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
@@ -82,10 +80,15 @@ extern int decnet_log_martians;
static void dn_log_martian(struct sk_buff *skb, const char *msg)
{
- if (decnet_log_martians && net_ratelimit()) {
+ if (decnet_log_martians) {
char *devname = skb->dev ? skb->dev->name : "???";
struct dn_skb_cb *cb = DN_SKB_CB(skb);
- printk(KERN_INFO "DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", msg, devname, cb->src, cb->dst, cb->src_port, cb->dst_port);
+ net_info_ratelimited("DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n",
+ msg, devname,
+ le16_to_cpu(cb->src),
+ le16_to_cpu(cb->dst),
+ le16_to_cpu(cb->src_port),
+ le16_to_cpu(cb->dst_port));
}
}
@@ -100,23 +103,27 @@ static void dn_ack(struct sock *sk, struct sk_buff *skb, unsigned short ack)
unsigned short type = ((ack >> 12) & 0x0003);
int wakeup = 0;
- switch(type) {
- case 0: /* ACK - Data */
- if (dn_after(ack, scp->ackrcv_dat)) {
- scp->ackrcv_dat = ack & 0x0fff;
- wakeup |= dn_nsp_check_xmit_queue(sk, skb, &scp->data_xmit_queue, ack);
- }
- break;
- case 1: /* NAK - Data */
- break;
- case 2: /* ACK - OtherData */
- if (dn_after(ack, scp->ackrcv_oth)) {
- scp->ackrcv_oth = ack & 0x0fff;
- wakeup |= dn_nsp_check_xmit_queue(sk, skb, &scp->other_xmit_queue, ack);
- }
- break;
- case 3: /* NAK - OtherData */
- break;
+ switch (type) {
+ case 0: /* ACK - Data */
+ if (dn_after(ack, scp->ackrcv_dat)) {
+ scp->ackrcv_dat = ack & 0x0fff;
+ wakeup |= dn_nsp_check_xmit_queue(sk, skb,
+ &scp->data_xmit_queue,
+ ack);
+ }
+ break;
+ case 1: /* NAK - Data */
+ break;
+ case 2: /* ACK - OtherData */
+ if (dn_after(ack, scp->ackrcv_oth)) {
+ scp->ackrcv_oth = ack & 0x0fff;
+ wakeup |= dn_nsp_check_xmit_queue(sk, skb,
+ &scp->other_xmit_queue,
+ ack);
+ }
+ break;
+ case 3: /* NAK - OtherData */
+ break;
}
if (wakeup && !sock_flag(sk, SOCK_DEAD))
@@ -128,19 +135,19 @@ static void dn_ack(struct sock *sk, struct sk_buff *skb, unsigned short ack)
*/
static int dn_process_ack(struct sock *sk, struct sk_buff *skb, int oth)
{
- unsigned short *ptr = (unsigned short *)skb->data;
+ __le16 *ptr = (__le16 *)skb->data;
int len = 0;
unsigned short ack;
if (skb->len < 2)
return len;
- if ((ack = dn_ntohs(*ptr)) & 0x8000) {
+ if ((ack = le16_to_cpu(*ptr)) & 0x8000) {
skb_pull(skb, 2);
ptr++;
len += 2;
if ((ack & 0x4000) == 0) {
- if (oth)
+ if (oth)
ack ^= 0x2000;
dn_ack(sk, skb, ack);
}
@@ -149,11 +156,11 @@ static int dn_process_ack(struct sock *sk, struct sk_buff *skb, int oth)
if (skb->len < 2)
return len;
- if ((ack = dn_ntohs(*ptr)) & 0x8000) {
+ if ((ack = le16_to_cpu(*ptr)) & 0x8000) {
skb_pull(skb, 2);
len += 2;
if ((ack & 0x4000) == 0) {
- if (oth)
+ if (oth)
ack ^= 0x2000;
dn_ack(sk, skb, ack);
}
@@ -239,7 +246,7 @@ static struct sock *dn_find_listener(struct sk_buff *skb, unsigned short *reason
cb->dst_port = msg->dstaddr;
cb->services = msg->services;
cb->info = msg->info;
- cb->segsize = dn_ntohs(msg->segsize);
+ cb->segsize = le16_to_cpu(msg->segsize);
if (!pskb_may_pull(skb, sizeof(*msg)))
goto err_out;
@@ -346,13 +353,13 @@ static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb)
ptr = skb->data;
cb->services = *ptr++;
cb->info = *ptr++;
- cb->segsize = dn_ntohs(*(__u16 *)ptr);
+ cb->segsize = le16_to_cpu(*(__le16 *)ptr);
if ((scp->state == DN_CI) || (scp->state == DN_CD)) {
scp->persist = 0;
- scp->addrrem = cb->src_port;
- sk->sk_state = TCP_ESTABLISHED;
- scp->state = DN_RUN;
+ scp->addrrem = cb->src_port;
+ sk->sk_state = TCP_ESTABLISHED;
+ scp->state = DN_RUN;
scp->services_rem = cb->services;
scp->info_rem = cb->info;
scp->segsize_rem = cb->segsize;
@@ -361,19 +368,20 @@ static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb)
scp->max_window = decnet_no_fc_max_cwnd;
if (skb->len > 0) {
- unsigned char dlen = *skb->data;
+ u16 dlen = *skb->data;
if ((dlen <= 16) && (dlen <= skb->len)) {
- scp->conndata_in.opt_optl = dlen;
- memcpy(scp->conndata_in.opt_data, skb->data + 1, dlen);
+ scp->conndata_in.opt_optl = cpu_to_le16(dlen);
+ skb_copy_from_linear_data_offset(skb, 1,
+ scp->conndata_in.opt_data, dlen);
}
}
- dn_nsp_send_link(sk, DN_NOCHANGE, 0);
- if (!sock_flag(sk, SOCK_DEAD))
- sk->sk_state_change(sk);
- }
+ dn_nsp_send_link(sk, DN_NOCHANGE, 0);
+ if (!sock_flag(sk, SOCK_DEAD))
+ sk->sk_state_change(sk);
+ }
out:
- kfree_skb(skb);
+ kfree_skb(skb);
}
static void dn_nsp_conn_ack(struct sock *sk, struct sk_buff *skb)
@@ -397,37 +405,37 @@ static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb)
if (skb->len < 2)
goto out;
- reason = dn_ntohs(*(__u16 *)skb->data);
+ reason = le16_to_cpu(*(__le16 *)skb->data);
skb_pull(skb, 2);
- scp->discdata_in.opt_status = reason;
+ scp->discdata_in.opt_status = cpu_to_le16(reason);
scp->discdata_in.opt_optl = 0;
memset(scp->discdata_in.opt_data, 0, 16);
if (skb->len > 0) {
- unsigned char dlen = *skb->data;
+ u16 dlen = *skb->data;
if ((dlen <= 16) && (dlen <= skb->len)) {
- scp->discdata_in.opt_optl = dlen;
- memcpy(scp->discdata_in.opt_data, skb->data + 1, dlen);
+ scp->discdata_in.opt_optl = cpu_to_le16(dlen);
+ skb_copy_from_linear_data_offset(skb, 1, scp->discdata_in.opt_data, dlen);
}
}
scp->addrrem = cb->src_port;
sk->sk_state = TCP_CLOSE;
- switch(scp->state) {
- case DN_CI:
- case DN_CD:
- scp->state = DN_RJ;
- sk->sk_err = ECONNREFUSED;
- break;
- case DN_RUN:
- sk->sk_shutdown |= SHUTDOWN_MASK;
- scp->state = DN_DN;
- break;
- case DN_DI:
- scp->state = DN_DIC;
- break;
+ switch (scp->state) {
+ case DN_CI:
+ case DN_CD:
+ scp->state = DN_RJ;
+ sk->sk_err = ECONNREFUSED;
+ break;
+ case DN_RUN:
+ sk->sk_shutdown |= SHUTDOWN_MASK;
+ scp->state = DN_DN;
+ break;
+ case DN_DI:
+ scp->state = DN_DIC;
+ break;
}
if (!sock_flag(sk, SOCK_DEAD)) {
@@ -436,7 +444,7 @@ static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb)
sk->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
@@ -464,27 +472,27 @@ static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb)
if (skb->len != 2)
goto out;
- reason = dn_ntohs(*(__u16 *)skb->data);
+ reason = le16_to_cpu(*(__le16 *)skb->data);
sk->sk_state = TCP_CLOSE;
- switch(scp->state) {
- case DN_CI:
- scp->state = DN_NR;
- break;
- case DN_DR:
- if (reason == NSP_REASON_DC)
- scp->state = DN_DRC;
- if (reason == NSP_REASON_NL)
- scp->state = DN_CN;
- break;
- case DN_DI:
- scp->state = DN_DIC;
- break;
- case DN_RUN:
- sk->sk_shutdown |= SHUTDOWN_MASK;
- case DN_CC:
+ switch (scp->state) {
+ case DN_CI:
+ scp->state = DN_NR;
+ break;
+ case DN_DR:
+ if (reason == NSP_REASON_DC)
+ scp->state = DN_DRC;
+ if (reason == NSP_REASON_NL)
scp->state = DN_CN;
+ break;
+ case DN_DI:
+ scp->state = DN_DIC;
+ break;
+ case DN_RUN:
+ sk->sk_shutdown |= SHUTDOWN_MASK;
+ case DN_CC:
+ scp->state = DN_CN;
}
if (!sock_flag(sk, SOCK_DEAD)) {
@@ -513,14 +521,14 @@ static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb)
if (skb->len != 4)
goto out;
- segnum = dn_ntohs(*(__u16 *)ptr);
+ segnum = le16_to_cpu(*(__le16 *)ptr);
ptr += 2;
lsflags = *(unsigned char *)ptr++;
fcval = *ptr;
/*
* Here we ignore erronous packets which should really
- * should cause a connection abort. It is not critical
+ * should cause a connection abort. It is not critical
* for now though.
*/
if (lsflags & 0xf8)
@@ -531,7 +539,7 @@ static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb)
switch(lsflags & 0x04) { /* FCVAL INT */
case 0x00: /* Normal Request */
switch(lsflags & 0x03) { /* FCVAL MOD */
- case 0x00: /* Request count */
+ case 0x00: /* Request count */
if (fcval < 0) {
unsigned char p_fcval = -fcval;
if ((scp->flowrem_dat > p_fcval) &&
@@ -542,7 +550,7 @@ static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb)
scp->flowrem_dat += fcval;
wake_up = 1;
}
- break;
+ break;
case 0x01: /* Stop outgoing data */
scp->flowrem_sw = DN_DONTSEND;
break;
@@ -558,10 +566,10 @@ static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb)
wake_up = 1;
}
break;
- }
+ }
if (wake_up && !sock_flag(sk, SOCK_DEAD))
sk->sk_state_change(sk);
- }
+ }
dn_nsp_send_oth_ack(sk);
@@ -577,38 +585,27 @@ out:
static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig, struct sk_buff_head *queue)
{
int err;
-
- /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
- number of warnings when compiling with -W --ANK
- */
- if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
- (unsigned)sk->sk_rcvbuf) {
- err = -ENOMEM;
- goto out;
- }
-
- err = sk_filter(sk, skb, 0);
+
+ /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
+ number of warnings when compiling with -W --ANK
+ */
+ if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
+ (unsigned int)sk->sk_rcvbuf) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = sk_filter(sk, skb);
if (err)
goto out;
- skb_set_owner_r(skb, sk);
- skb_queue_tail(queue, skb);
+ skb_set_owner_r(skb, sk);
+ skb_queue_tail(queue, skb);
- /* This code only runs from BH or BH protected context.
- * Therefore the plain read_lock is ok here. -DaveM
- */
- read_lock(&sk->sk_callback_lock);
- if (!sock_flag(sk, SOCK_DEAD)) {
- struct socket *sock = sk->sk_socket;
- wake_up_interruptible(sk->sk_sleep);
- if (sock && sock->fasync_list &&
- !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
- __kill_fasync(sock->fasync_list, sig,
- (sig == SIGURG) ? POLL_PRI : POLL_IN);
- }
- read_unlock(&sk->sk_callback_lock);
+ if (!sock_flag(sk, SOCK_DEAD))
+ sk->sk_data_ready(sk);
out:
- return err;
+ return err;
}
static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb)
@@ -621,7 +618,7 @@ static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb)
if (skb->len < 2)
goto out;
- cb->segnum = segnum = dn_ntohs(*(__u16 *)skb->data);
+ cb->segnum = segnum = le16_to_cpu(*(__le16 *)skb->data);
skb_pull(skb, 2);
if (seq_next(scp->numoth_rcv, segnum)) {
@@ -649,20 +646,20 @@ static void dn_nsp_data(struct sock *sk, struct sk_buff *skb)
if (skb->len < 2)
goto out;
- cb->segnum = segnum = dn_ntohs(*(__u16 *)skb->data);
+ cb->segnum = segnum = le16_to_cpu(*(__le16 *)skb->data);
skb_pull(skb, 2);
if (seq_next(scp->numdat_rcv, segnum)) {
- if (dn_queue_skb(sk, skb, SIGIO, &sk->sk_receive_queue) == 0) {
+ if (dn_queue_skb(sk, skb, SIGIO, &sk->sk_receive_queue) == 0) {
seq_add(&scp->numdat_rcv, 1);
- queued = 1;
- }
+ queued = 1;
+ }
if ((scp->flowloc_sw == DN_SEND) && dn_congested(sk)) {
scp->flowloc_sw = DN_DONTSEND;
dn_nsp_send_link(sk, DN_DONTSEND, 0);
}
- }
+ }
dn_nsp_send_data_ack(sk);
out:
@@ -699,16 +696,16 @@ static int dn_nsp_no_socket(struct sk_buff *skb, unsigned short reason)
goto out;
if ((reason != NSP_REASON_OK) && ((cb->nsp_flags & 0x0c) == 0x08)) {
- switch(cb->nsp_flags & 0x70) {
- case 0x10:
- case 0x60: /* (Retransmitted) Connect Init */
- dn_nsp_return_disc(skb, NSP_DISCINIT, reason);
- ret = NET_RX_SUCCESS;
- break;
- case 0x20: /* Connect Confirm */
- dn_nsp_return_disc(skb, NSP_DISCCONF, reason);
- ret = NET_RX_SUCCESS;
- break;
+ switch (cb->nsp_flags & 0x70) {
+ case 0x10:
+ case 0x60: /* (Retransmitted) Connect Init */
+ dn_nsp_return_disc(skb, NSP_DISCINIT, reason);
+ ret = NET_RX_SUCCESS;
+ break;
+ case 0x20: /* Connect Confirm */
+ dn_nsp_return_disc(skb, NSP_DISCCONF, reason);
+ ret = NET_RX_SUCCESS;
+ break;
}
}
@@ -727,30 +724,30 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
if (!pskb_may_pull(skb, 2))
goto free_out;
- skb->h.raw = skb->data;
+ skb_reset_transport_header(skb);
cb->nsp_flags = *ptr++;
if (decnet_debug_level & 2)
printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags);
- if (cb->nsp_flags & 0x83)
+ if (cb->nsp_flags & 0x83)
goto free_out;
/*
* Filter out conninits and useless packet types
*/
if ((cb->nsp_flags & 0x0c) == 0x08) {
- switch(cb->nsp_flags & 0x70) {
- case 0x00: /* NOP */
- case 0x70: /* Reserved */
- case 0x50: /* Reserved, Phase II node init */
+ switch (cb->nsp_flags & 0x70) {
+ case 0x00: /* NOP */
+ case 0x70: /* Reserved */
+ case 0x50: /* Reserved, Phase II node init */
+ goto free_out;
+ case 0x10:
+ case 0x60:
+ if (unlikely(cb->rt_flags & DN_RT_F_RTS))
goto free_out;
- case 0x10:
- case 0x60:
- if (unlikely(cb->rt_flags & DN_RT_F_RTS))
- goto free_out;
- sk = dn_find_listener(skb, &reason);
- goto got_it;
+ sk = dn_find_listener(skb, &reason);
+ goto got_it;
}
}
@@ -760,7 +757,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
/*
* Grab the destination address.
*/
- cb->dst_port = *(unsigned short *)ptr;
+ cb->dst_port = *(__le16 *)ptr;
cb->src_port = 0;
ptr += 2;
@@ -768,7 +765,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
* If not a connack, grab the source address too.
*/
if (pskb_may_pull(skb, 5)) {
- cb->src_port = *(unsigned short *)ptr;
+ cb->src_port = *(__le16 *)ptr;
ptr += 2;
skb_pull(skb, 5);
}
@@ -778,7 +775,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
* Swap src & dst and look up in the normal way.
*/
if (unlikely(cb->rt_flags & DN_RT_F_RTS)) {
- unsigned short tmp = cb->dst_port;
+ __le16 tmp = cb->dst_port;
cb->dst_port = cb->src_port;
cb->src_port = tmp;
tmp = cb->dst;
@@ -801,12 +798,11 @@ got_it:
* We linearize everything except data segments here.
*/
if (cb->nsp_flags & ~0x60) {
- if (unlikely(skb_is_nonlinear(skb)) &&
- skb_linearize(skb, GFP_ATOMIC) != 0)
+ if (unlikely(skb_linearize(skb)))
goto free_out;
}
- return sk_receive_skb(sk, skb);
+ return sk_receive_skb(sk, skb, 0);
}
return dn_nsp_no_socket(skb, reason);
@@ -818,7 +814,8 @@ free_out:
int dn_nsp_rx(struct sk_buff *skb)
{
- return NF_HOOK(PF_DECnet, NF_DN_LOCAL_IN, skb, skb->dev, NULL, dn_nsp_rx_packet);
+ return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_IN, skb, skb->dev, NULL,
+ dn_nsp_rx_packet);
}
/*
@@ -843,20 +840,20 @@ int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
* Control packet.
*/
if ((cb->nsp_flags & 0x0c) == 0x08) {
- switch(cb->nsp_flags & 0x70) {
- case 0x10:
- case 0x60:
- dn_nsp_conn_init(sk, skb);
- break;
- case 0x20:
- dn_nsp_conn_conf(sk, skb);
- break;
- case 0x30:
- dn_nsp_disc_init(sk, skb);
- break;
- case 0x40:
- dn_nsp_disc_conf(sk, skb);
- break;
+ switch (cb->nsp_flags & 0x70) {
+ case 0x10:
+ case 0x60:
+ dn_nsp_conn_init(sk, skb);
+ break;
+ case 0x20:
+ dn_nsp_conn_conf(sk, skb);
+ break;
+ case 0x30:
+ dn_nsp_disc_init(sk, skb);
+ break;
+ case 0x40:
+ dn_nsp_disc_conf(sk, skb);
+ break;
}
} else if (cb->nsp_flags == 0x24) {
@@ -897,15 +894,15 @@ int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
if (scp->state != DN_RUN)
goto free_out;
- switch(cb->nsp_flags) {
- case 0x10: /* LS */
- dn_nsp_linkservice(sk, skb);
- break;
- case 0x30: /* OD */
- dn_nsp_otherdata(sk, skb);
- break;
- default:
- dn_nsp_data(sk, skb);
+ switch (cb->nsp_flags) {
+ case 0x10: /* LS */
+ dn_nsp_linkservice(sk, skb);
+ break;
+ case 0x30: /* OD */
+ dn_nsp_otherdata(sk, skb);
+ break;
+ default:
+ dn_nsp_data(sk, skb);
}
} else { /* Ack, chuck it out here */
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index c96c767b1f7..1aaa51ebbda 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -1,4 +1,3 @@
-
/*
* DECnet An implementation of the DECnet protocol suite for the LINUX
* operating system. DECnet is implemented using the BSD Socket
@@ -26,7 +25,7 @@
/******************************************************************************
(c) 1995-1998 E.M. Serrat emserrat@geocities.com
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -43,7 +42,6 @@
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
@@ -51,11 +49,11 @@
#include <linux/netdevice.h>
#include <linux/inet.h>
#include <linux/route.h>
+#include <linux/slab.h>
#include <net/sock.h>
-#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
-#include <linux/termios.h>
+#include <linux/termios.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
@@ -78,26 +76,26 @@ 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;
+ struct flowidn fld;
- skb->h.raw = skb->data;
+ skb_reset_transport_header(skb);
scp->stamp = jiffies;
dst = sk_dst_check(sk, 0);
if (dst) {
try_again:
- skb->dst = dst;
+ skb_dst_set(skb, dst);
dst_output(skb);
return;
}
- memset(&fl, 0, sizeof(fl));
- fl.oif = sk->sk_bound_dev_if;
- fl.fld_src = dn_saddr2dn(&scp->addr);
- fl.fld_dst = dn_saddr2dn(&scp->peer);
- dn_sk_ports_copy(&fl, scp);
- fl.proto = DNPROTO_NSP;
- if (dn_route_output_sock(&sk->sk_dst_cache, &fl, sk, 0) == 0) {
+ memset(&fld, 0, sizeof(fld));
+ fld.flowidn_oif = sk->sk_bound_dev_if;
+ fld.saddr = dn_saddr2dn(&scp->addr);
+ fld.daddr = dn_saddr2dn(&scp->peer);
+ dn_sk_ports_copy(&fld, scp);
+ fld.flowidn_proto = DNPROTO_NSP;
+ if (dn_route_output_sock(&sk->sk_dst_cache, &fld, sk, 0) == 0) {
dst = sk_dst_get(sk);
sk->sk_route_caps = dst->dev->features;
goto try_again;
@@ -125,7 +123,7 @@ struct sk_buff *dn_alloc_skb(struct sock *sk, int size, gfp_t pri)
if ((skb = alloc_skb(size + hdr, pri)) == NULL)
return NULL;
- skb->protocol = __constant_htons(ETH_P_DNA_RT);
+ skb->protocol = htons(ETH_P_DNA_RT);
skb->pkt_type = PACKET_OUTGOING;
if (sk)
@@ -176,14 +174,14 @@ static void dn_nsp_rtt(struct sock *sk, long rtt)
* gathering this value might turn out negative, so we make sure
* that is it always positive here.
*/
- if (rtt < 0)
+ if (rtt < 0)
rtt = -rtt;
/*
* Add new rtt to smoothed average
*/
delta = ((rtt << 3) - srtt);
srtt += (delta >> 3);
- if (srtt >= 1)
+ if (srtt >= 1)
scp->nsp_srtt = (unsigned long)srtt;
else
scp->nsp_srtt = 1;
@@ -193,7 +191,7 @@ static void dn_nsp_rtt(struct sock *sk, long rtt)
*/
delta >>= 1;
rttvar += ((((delta>0)?(delta):(-delta)) - rttvar) >> 2);
- if (rttvar >= 1)
+ if (rttvar >= 1)
scp->nsp_rttvar = (unsigned long)rttvar;
else
scp->nsp_rttvar = 1;
@@ -210,7 +208,7 @@ static void dn_nsp_rtt(struct sock *sk, long rtt)
*
* Returns: The number of times the packet has been sent previously
*/
-static inline unsigned dn_nsp_clone_and_send(struct sk_buff *skb,
+static inline unsigned int dn_nsp_clone_and_send(struct sk_buff *skb,
gfp_t gfp)
{
struct dn_skb_cb *cb = DN_SKB_CB(skb);
@@ -231,7 +229,6 @@ static inline unsigned dn_nsp_clone_and_send(struct sk_buff *skb,
/**
* dn_nsp_output - Try and send something from socket queues
* @sk: The socket whose queues are to be investigated
- * @gfp: The memory allocation flags
*
* Try and send the packet on the end of the data and other data queues.
* Other data gets priority over data, and if we retransmit a packet we
@@ -242,7 +239,7 @@ void dn_nsp_output(struct sock *sk)
{
struct dn_scp *scp = DN_SK(sk);
struct sk_buff *skb;
- unsigned reduce_win = 0;
+ unsigned int reduce_win = 0;
/*
* First we check for otherdata/linkservice messages
@@ -287,26 +284,26 @@ int dn_nsp_xmit_timeout(struct sock *sk)
return 0;
}
-static inline unsigned char *dn_mk_common_header(struct dn_scp *scp, struct sk_buff *skb, unsigned char msgflag, int len)
+static inline __le16 *dn_mk_common_header(struct dn_scp *scp, struct sk_buff *skb, unsigned char msgflag, int len)
{
unsigned char *ptr = skb_push(skb, len);
BUG_ON(len < 5);
*ptr++ = msgflag;
- *((unsigned short *)ptr) = scp->addrrem;
+ *((__le16 *)ptr) = scp->addrrem;
ptr += 2;
- *((unsigned short *)ptr) = scp->addrloc;
+ *((__le16 *)ptr) = scp->addrloc;
ptr += 2;
- return ptr;
+ return (__le16 __force *)ptr;
}
-static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, unsigned char msgflag, int hlen, int other)
+static __le16 *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, unsigned char msgflag, int hlen, int other)
{
struct dn_scp *scp = DN_SK(sk);
unsigned short acknum = scp->numdat_rcv & 0x0FFF;
unsigned short ackcrs = scp->numoth_rcv & 0x0FFF;
- unsigned short *ptr;
+ __le16 *ptr;
BUG_ON(hlen < 9);
@@ -325,19 +322,19 @@ static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, un
/* Set "cross subchannel" bit in ackcrs */
ackcrs |= 0x2000;
- ptr = (unsigned short *)dn_mk_common_header(scp, skb, msgflag, hlen);
+ ptr = dn_mk_common_header(scp, skb, msgflag, hlen);
- *ptr++ = dn_htons(acknum);
- *ptr++ = dn_htons(ackcrs);
+ *ptr++ = cpu_to_le16(acknum);
+ *ptr++ = cpu_to_le16(ackcrs);
return ptr;
}
-static unsigned short *dn_nsp_mk_data_header(struct sock *sk, struct sk_buff *skb, int oth)
+static __le16 *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);
+ __le16 *ptr = dn_mk_ack_header(sk, skb, cb->nsp_flags, 11, oth);
if (unlikely(oth)) {
cb->segnum = scp->numoth;
@@ -346,7 +343,7 @@ static unsigned short *dn_nsp_mk_data_header(struct sock *sk, struct sk_buff *sk
cb->segnum = scp->numdat;
seq_add(&scp->numdat, 1);
}
- *(ptr++) = dn_htons(cb->segnum);
+ *(ptr++) = cpu_to_le16(cb->segnum);
return ptr;
}
@@ -384,7 +381,7 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff
{
struct dn_skb_cb *cb = DN_SKB_CB(skb);
struct dn_scp *scp = DN_SK(sk);
- struct sk_buff *skb2, *list, *ack = NULL;
+ struct sk_buff *skb2, *n, *ack = NULL;
int wakeup = 0;
int try_retrans = 0;
unsigned long reftime = cb->stamp;
@@ -392,9 +389,7 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff
unsigned short xmit_count;
unsigned short segnum;
- skb2 = q->next;
- list = (struct sk_buff *)q;
- while(list != skb2) {
+ skb_queue_walk_safe(q, skb2, n) {
struct dn_skb_cb *cb2 = DN_SKB_CB(skb2);
if (dn_before_or_equal(cb2->segnum, acknum))
@@ -402,8 +397,6 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff
/* printk(KERN_DEBUG "ack: %s %04x %04x\n", ack ? "ACK" : "SKIP", (int)cb2->segnum, (int)acknum); */
- skb2 = skb2->next;
-
if (ack == NULL)
continue;
@@ -434,7 +427,7 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff
* further.
*/
if (xmit_count == 1) {
- if (dn_equal(segnum, acknum))
+ if (dn_equal(segnum, acknum))
dn_nsp_rtt(sk, (long)(pkttime - reftime));
if (scp->snd_window < scp->max_window)
@@ -486,16 +479,16 @@ void dn_send_conn_ack (struct sock *sk)
{
struct dn_scp *scp = DN_SK(sk);
struct sk_buff *skb = NULL;
- struct nsp_conn_ack_msg *msg;
+ struct nsp_conn_ack_msg *msg;
if ((skb = dn_alloc_skb(sk, 3, sk->sk_allocation)) == NULL)
return;
- msg = (struct nsp_conn_ack_msg *)skb_put(skb, 3);
- msg->msgflg = 0x24;
+ msg = (struct nsp_conn_ack_msg *)skb_put(skb, 3);
+ msg->msgflg = 0x24;
msg->dstaddr = scp->addrrem;
- dn_nsp_send(skb);
+ dn_nsp_send(skb);
}
void dn_nsp_delayed_ack(struct sock *sk)
@@ -523,25 +516,25 @@ void dn_send_conn_conf(struct sock *sk, gfp_t gfp)
{
struct dn_scp *scp = DN_SK(sk);
struct sk_buff *skb = NULL;
- struct nsp_conn_init_msg *msg;
- unsigned char len = scp->conndata_out.opt_optl;
+ struct nsp_conn_init_msg *msg;
+ __u8 len = (__u8)le16_to_cpu(scp->conndata_out.opt_optl);
- if ((skb = dn_alloc_skb(sk, 50 + scp->conndata_out.opt_optl, gfp)) == NULL)
+ if ((skb = dn_alloc_skb(sk, 50 + len, gfp)) == NULL)
return;
- msg = (struct nsp_conn_init_msg *)skb_put(skb, sizeof(*msg));
- msg->msgflg = 0x28;
+ msg = (struct nsp_conn_init_msg *)skb_put(skb, sizeof(*msg));
+ msg->msgflg = 0x28;
msg->dstaddr = scp->addrrem;
- msg->srcaddr = scp->addrloc;
- msg->services = scp->services_loc;
- msg->info = scp->info_loc;
- msg->segsize = dn_htons(scp->segsize_loc);
+ msg->srcaddr = scp->addrloc;
+ msg->services = scp->services_loc;
+ msg->info = scp->info_loc;
+ msg->segsize = cpu_to_le16(scp->segsize_loc);
*skb_put(skb,1) = len;
- if (len > 0)
+ if (len > 0)
memcpy(skb_put(skb, len), scp->conndata_out.opt_data, len);
-
+
dn_nsp_send(skb);
@@ -550,18 +543,18 @@ void dn_send_conn_conf(struct sock *sk, gfp_t gfp)
}
-static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
+static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
unsigned short reason, gfp_t gfp,
struct dst_entry *dst,
- int ddl, unsigned char *dd, __u16 rem, __u16 loc)
+ int ddl, unsigned char *dd, __le16 rem, __le16 loc)
{
struct sk_buff *skb = NULL;
int size = 7 + ddl + ((msgflg == NSP_DISCINIT) ? 1 : 0);
unsigned char *msg;
if ((dst == NULL) || (rem == 0)) {
- if (net_ratelimit())
- printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", (unsigned)rem, dst);
+ net_dbg_ratelimited("DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n",
+ le16_to_cpu(rem), dst);
return;
}
@@ -570,11 +563,11 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
msg = skb_put(skb, size);
*msg++ = msgflg;
- *(__u16 *)msg = rem;
+ *(__le16 *)msg = rem;
msg += 2;
- *(__u16 *)msg = loc;
+ *(__le16 *)msg = loc;
msg += 2;
- *(__u16 *)msg = dn_htons(reason);
+ *(__le16 *)msg = cpu_to_le16(reason);
msg += 2;
if (msgflg == NSP_DISCINIT)
*msg++ = ddl;
@@ -588,36 +581,36 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
* to be able to send disc packets out which have no socket
* associations.
*/
- skb->dst = dst_clone(dst);
+ skb_dst_set(skb, dst_clone(dst));
dst_output(skb);
}
-void dn_nsp_send_disc(struct sock *sk, unsigned char msgflg,
+void dn_nsp_send_disc(struct sock *sk, unsigned char msgflg,
unsigned short reason, gfp_t gfp)
{
struct dn_scp *scp = DN_SK(sk);
int ddl = 0;
if (msgflg == NSP_DISCINIT)
- ddl = scp->discdata_out.opt_optl;
+ ddl = le16_to_cpu(scp->discdata_out.opt_optl);
if (reason == 0)
- reason = scp->discdata_out.opt_status;
+ reason = le16_to_cpu(scp->discdata_out.opt_status);
- dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->sk_dst_cache, ddl,
+ dn_nsp_do_disc(sk, msgflg, reason, gfp, __sk_dst_get(sk), ddl,
scp->discdata_out.opt_data, scp->addrrem, scp->addrloc);
}
-void dn_nsp_return_disc(struct sk_buff *skb, unsigned char msgflg,
+void dn_nsp_return_disc(struct sk_buff *skb, unsigned char msgflg,
unsigned short reason)
{
struct dn_skb_cb *cb = DN_SKB_CB(skb);
int ddl = 0;
gfp_t gfp = GFP_ATOMIC;
- dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb->dst, ddl,
+ dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb_dst(skb), ddl,
NULL, cb->src_port, cb->dst_port);
}
@@ -676,14 +669,16 @@ void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg)
msg->srcaddr = scp->addrloc;
msg->services = scp->services_loc; /* Requested flow control */
- msg->info = scp->info_loc; /* Version Number */
- msg->segsize = dn_htons(scp->segsize_loc); /* Max segment size */
+ msg->info = scp->info_loc; /* Version Number */
+ msg->segsize = cpu_to_le16(scp->segsize_loc); /* Max segment size */
if (scp->peer.sdn_objnum)
type = 0;
- skb_put(skb, dn_sockaddr2username(&scp->peer, skb->tail, type));
- skb_put(skb, dn_sockaddr2username(&scp->addr, skb->tail, 2));
+ skb_put(skb, dn_sockaddr2username(&scp->peer,
+ skb_tail_pointer(skb), type));
+ skb_put(skb, dn_sockaddr2username(&scp->addr,
+ skb_tail_pointer(skb), 2));
menuver = DN_MENUVER_ACC | DN_MENUVER_USR;
if (scp->peer.sdn_flags & SDF_PROXY)
@@ -692,32 +687,32 @@ void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg)
menuver |= DN_MENUVER_UIC;
*skb_put(skb, 1) = menuver; /* Menu Version */
-
+
aux = scp->accessdata.acc_userl;
*skb_put(skb, 1) = aux;
if (aux > 0)
- memcpy(skb_put(skb, aux), scp->accessdata.acc_user, aux);
+ memcpy(skb_put(skb, aux), scp->accessdata.acc_user, aux);
aux = scp->accessdata.acc_passl;
*skb_put(skb, 1) = aux;
if (aux > 0)
- memcpy(skb_put(skb, aux), scp->accessdata.acc_pass, aux);
+ memcpy(skb_put(skb, aux), scp->accessdata.acc_pass, aux);
aux = scp->accessdata.acc_accl;
*skb_put(skb, 1) = aux;
if (aux > 0)
- memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux);
+ memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux);
- aux = scp->conndata_out.opt_optl;
+ aux = (__u8)le16_to_cpu(scp->conndata_out.opt_optl);
*skb_put(skb, 1) = aux;
if (aux > 0)
- memcpy(skb_put(skb,aux), scp->conndata_out.opt_data, aux);
+ memcpy(skb_put(skb, aux), scp->conndata_out.opt_data, aux);
scp->persist = dn_nsp_persist(sk);
scp->persist_fxn = dn_nsp_retrans_conninit;
cb->rt_flags = DN_RT_F_RQR;
- dn_nsp_send(skb);
+ dn_nsp_send(skb);
}
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 3407f190afe..daccc4a36d8 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -43,7 +43,7 @@
/******************************************************************************
(c) 1995-1998 E.M. Serrat emserrat@geocities.com
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -55,7 +55,6 @@
GNU General Public License for more details.
*******************************************************************************/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -67,6 +66,7 @@
#include <linux/inet.h>
#include <linux/route.h>
#include <linux/in_route.h>
+#include <linux/slab.h>
#include <net/sock.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
@@ -77,10 +77,14 @@
#include <linux/netfilter_decnet.h>
#include <linux/rcupdate.h>
#include <linux/times.h>
+#include <linux/export.h>
#include <asm/errno.h>
+#include <net/net_namespace.h>
+#include <net/netlink.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/flow.h>
+#include <net/fib_rules.h>
#include <net/dn.h>
#include <net/dn_dev.h>
#include <net/dn_nsp.h>
@@ -90,9 +94,9 @@
struct dn_rt_hash_bucket
{
- struct dn_route *chain;
+ struct dn_route __rcu *chain;
spinlock_t lock;
-} __attribute__((__aligned__(8)));
+};
extern struct neigh_table dn_neigh_table;
@@ -105,16 +109,26 @@ static const int dn_rt_mtu_expires = 10 * 60 * HZ;
static unsigned long dn_rt_deadline;
-static int dn_dst_gc(void);
+static int dn_dst_gc(struct dst_ops *ops);
static struct dst_entry *dn_dst_check(struct dst_entry *, __u32);
+static unsigned int dn_dst_default_advmss(const struct dst_entry *dst);
+static unsigned int dn_dst_mtu(const struct dst_entry *dst);
+static void dn_dst_destroy(struct dst_entry *);
+static void dn_dst_ifdown(struct dst_entry *, struct net_device *dev, int how);
static struct dst_entry *dn_dst_negative_advice(struct dst_entry *);
static void dn_dst_link_failure(struct sk_buff *);
-static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu);
+static void dn_dst_update_pmtu(struct dst_entry *dst, struct sock *sk,
+ struct sk_buff *skb , u32 mtu);
+static void dn_dst_redirect(struct dst_entry *dst, struct sock *sk,
+ struct sk_buff *skb);
+static struct neighbour *dn_dst_neigh_lookup(const struct dst_entry *dst,
+ struct sk_buff *skb,
+ const void *daddr);
static int dn_route_input(struct sk_buff *);
static void dn_run_flush(unsigned long dummy);
static struct dn_rt_hash_bucket *dn_rt_hash_table;
-static unsigned dn_rt_hash_mask;
+static unsigned int dn_rt_hash_mask;
static struct timer_list dn_route_timer;
static DEFINE_TIMER(dn_rt_flush_timer, dn_run_flush, 0, 0);
@@ -122,57 +136,86 @@ int decnet_dst_gc_interval = 2;
static struct dst_ops dn_dst_ops = {
.family = PF_DECnet,
- .protocol = __constant_htons(ETH_P_DNA_RT),
+ .protocol = cpu_to_be16(ETH_P_DNA_RT),
.gc_thresh = 128,
.gc = dn_dst_gc,
.check = dn_dst_check,
+ .default_advmss = dn_dst_default_advmss,
+ .mtu = dn_dst_mtu,
+ .cow_metrics = dst_cow_metrics_generic,
+ .destroy = dn_dst_destroy,
+ .ifdown = dn_dst_ifdown,
.negative_advice = dn_dst_negative_advice,
.link_failure = dn_dst_link_failure,
.update_pmtu = dn_dst_update_pmtu,
- .entry_size = sizeof(struct dn_route),
- .entries = ATOMIC_INIT(0),
+ .redirect = dn_dst_redirect,
+ .neigh_lookup = dn_dst_neigh_lookup,
};
-static __inline__ unsigned dn_hash(unsigned short src, unsigned short dst)
+static void dn_dst_destroy(struct dst_entry *dst)
+{
+ struct dn_route *rt = (struct dn_route *) dst;
+
+ if (rt->n)
+ neigh_release(rt->n);
+ dst_destroy_metrics_generic(dst);
+}
+
+static void dn_dst_ifdown(struct dst_entry *dst, struct net_device *dev, int how)
{
- unsigned short tmp = src ^ dst;
+ if (how) {
+ struct dn_route *rt = (struct dn_route *) dst;
+ struct neighbour *n = rt->n;
+
+ if (n && n->dev == dev) {
+ n->dev = dev_net(dev)->loopback_dev;
+ dev_hold(n->dev);
+ dev_put(dev);
+ }
+ }
+}
+
+static __inline__ unsigned int dn_hash(__le16 src, __le16 dst)
+{
+ __u16 tmp = (__u16 __force)(src ^ dst);
tmp ^= (tmp >> 3);
tmp ^= (tmp >> 5);
tmp ^= (tmp >> 10);
- return dn_rt_hash_mask & (unsigned)tmp;
+ return dn_rt_hash_mask & (unsigned int)tmp;
}
static inline void dnrt_free(struct dn_route *rt)
{
- call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
+ call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
}
static inline void dnrt_drop(struct dn_route *rt)
{
- if (rt)
- dst_release(&rt->u.dst);
- call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
+ dst_release(&rt->dst);
+ call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
}
static void dn_dst_check_expire(unsigned long dummy)
{
int i;
- struct dn_route *rt, **rtp;
+ struct dn_route *rt;
+ struct dn_route __rcu **rtp;
unsigned long now = jiffies;
unsigned long expire = 120 * HZ;
- for(i = 0; i <= dn_rt_hash_mask; i++) {
+ for (i = 0; i <= dn_rt_hash_mask; i++) {
rtp = &dn_rt_hash_table[i].chain;
spin_lock(&dn_rt_hash_table[i].lock);
- while((rt=*rtp) != NULL) {
- if (atomic_read(&rt->u.dst.__refcnt) ||
- (now - rt->u.dst.lastuse) < expire) {
- rtp = &rt->u.rt_next;
+ while ((rt = rcu_dereference_protected(*rtp,
+ lockdep_is_held(&dn_rt_hash_table[i].lock))) != NULL) {
+ if (atomic_read(&rt->dst.__refcnt) ||
+ (now - rt->dst.lastuse) < expire) {
+ rtp = &rt->dst.dn_next;
continue;
}
- *rtp = rt->u.rt_next;
- rt->u.rt_next = NULL;
+ *rtp = rt->dst.dn_next;
+ rt->dst.dn_next = NULL;
dnrt_free(rt);
}
spin_unlock(&dn_rt_hash_table[i].lock);
@@ -184,26 +227,28 @@ static void dn_dst_check_expire(unsigned long dummy)
mod_timer(&dn_route_timer, now + decnet_dst_gc_interval * HZ);
}
-static int dn_dst_gc(void)
+static int dn_dst_gc(struct dst_ops *ops)
{
- struct dn_route *rt, **rtp;
+ struct dn_route *rt;
+ struct dn_route __rcu **rtp;
int i;
unsigned long now = jiffies;
unsigned long expire = 10 * HZ;
- for(i = 0; i <= dn_rt_hash_mask; i++) {
+ for (i = 0; i <= dn_rt_hash_mask; i++) {
spin_lock_bh(&dn_rt_hash_table[i].lock);
rtp = &dn_rt_hash_table[i].chain;
- while((rt=*rtp) != NULL) {
- if (atomic_read(&rt->u.dst.__refcnt) ||
- (now - rt->u.dst.lastuse) < expire) {
- rtp = &rt->u.rt_next;
+ while ((rt = rcu_dereference_protected(*rtp,
+ lockdep_is_held(&dn_rt_hash_table[i].lock))) != NULL) {
+ if (atomic_read(&rt->dst.__refcnt) ||
+ (now - rt->dst.lastuse) < expire) {
+ rtp = &rt->dst.dn_next;
continue;
}
- *rtp = rt->u.rt_next;
- rt->u.rt_next = NULL;
+ *rtp = rt->dst.dn_next;
+ rt->dst.dn_next = NULL;
dnrt_drop(rt);
break;
}
@@ -223,31 +268,41 @@ static int dn_dst_gc(void)
* We update both the mtu and the advertised mss (i.e. the segment size we
* advertise to the other end).
*/
-static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu)
+static void dn_dst_update_pmtu(struct dst_entry *dst, struct sock *sk,
+ struct sk_buff *skb, u32 mtu)
{
+ struct dn_route *rt = (struct dn_route *) dst;
+ struct neighbour *n = rt->n;
u32 min_mtu = 230;
- struct dn_dev *dn = dst->neighbour ?
- (struct dn_dev *)dst->neighbour->dev->dn_ptr : NULL;
+ struct dn_dev *dn;
+
+ dn = n ? rcu_dereference_raw(n->dev->dn_ptr) : NULL;
if (dn && dn->use_long == 0)
min_mtu -= 6;
else
min_mtu -= 21;
- if (dst->metrics[RTAX_MTU-1] > mtu && mtu >= min_mtu) {
+ if (dst_metric(dst, RTAX_MTU) > mtu && mtu >= min_mtu) {
if (!(dst_metric_locked(dst, RTAX_MTU))) {
- dst->metrics[RTAX_MTU-1] = mtu;
+ dst_metric_set(dst, RTAX_MTU, mtu);
dst_set_expires(dst, dn_rt_mtu_expires);
}
if (!(dst_metric_locked(dst, RTAX_ADVMSS))) {
u32 mss = mtu - DN_MAX_NSP_DATA_HEADER;
- if (dst->metrics[RTAX_ADVMSS-1] > mss)
- dst->metrics[RTAX_ADVMSS-1] = mss;
+ u32 existing_mss = dst_metric_raw(dst, RTAX_ADVMSS);
+ if (!existing_mss || existing_mss > mss)
+ dst_metric_set(dst, RTAX_ADVMSS, mss);
}
}
}
-/*
+static void dn_dst_redirect(struct dst_entry *dst, struct sock *sk,
+ struct sk_buff *skb)
+{
+}
+
+/*
* When a route has been marked obsolete. (e.g. routing cache flush)
*/
static struct dst_entry *dn_dst_check(struct dst_entry *dst, __u32 cookie)
@@ -263,69 +318,69 @@ static struct dst_entry *dn_dst_negative_advice(struct dst_entry *dst)
static void dn_dst_link_failure(struct sk_buff *skb)
{
- return;
}
-static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
+static inline int compare_keys(struct flowidn *fl1, struct flowidn *fl2)
{
- return memcmp(&fl1->nl_u.dn_u, &fl2->nl_u.dn_u, sizeof(fl1->nl_u.dn_u)) == 0 &&
- fl1->oif == fl2->oif &&
- fl1->iif == fl2->iif;
+ return ((fl1->daddr ^ fl2->daddr) |
+ (fl1->saddr ^ fl2->saddr) |
+ (fl1->flowidn_mark ^ fl2->flowidn_mark) |
+ (fl1->flowidn_scope ^ fl2->flowidn_scope) |
+ (fl1->flowidn_oif ^ fl2->flowidn_oif) |
+ (fl1->flowidn_iif ^ fl2->flowidn_iif)) == 0;
}
-static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp)
+static int dn_insert_route(struct dn_route *rt, unsigned int hash, struct dn_route **rp)
{
- struct dn_route *rth, **rthp;
+ struct dn_route *rth;
+ struct dn_route __rcu **rthp;
unsigned long now = jiffies;
rthp = &dn_rt_hash_table[hash].chain;
spin_lock_bh(&dn_rt_hash_table[hash].lock);
- while((rth = *rthp) != NULL) {
- if (compare_keys(&rth->fl, &rt->fl)) {
+ while ((rth = rcu_dereference_protected(*rthp,
+ lockdep_is_held(&dn_rt_hash_table[hash].lock))) != NULL) {
+ if (compare_keys(&rth->fld, &rt->fld)) {
/* Put it first */
- *rthp = rth->u.rt_next;
- rcu_assign_pointer(rth->u.rt_next,
+ *rthp = rth->dst.dn_next;
+ rcu_assign_pointer(rth->dst.dn_next,
dn_rt_hash_table[hash].chain);
rcu_assign_pointer(dn_rt_hash_table[hash].chain, rth);
- rth->u.dst.__use++;
- dst_hold(&rth->u.dst);
- rth->u.dst.lastuse = now;
+ dst_use(&rth->dst, now);
spin_unlock_bh(&dn_rt_hash_table[hash].lock);
dnrt_drop(rt);
*rp = rth;
return 0;
}
- rthp = &rth->u.rt_next;
+ rthp = &rth->dst.dn_next;
}
- rcu_assign_pointer(rt->u.rt_next, dn_rt_hash_table[hash].chain);
+ rcu_assign_pointer(rt->dst.dn_next, dn_rt_hash_table[hash].chain);
rcu_assign_pointer(dn_rt_hash_table[hash].chain, rt);
-
- dst_hold(&rt->u.dst);
- rt->u.dst.__use++;
- rt->u.dst.lastuse = now;
+
+ dst_use(&rt->dst, now);
spin_unlock_bh(&dn_rt_hash_table[hash].lock);
*rp = rt;
return 0;
}
-void dn_run_flush(unsigned long dummy)
+static void dn_run_flush(unsigned long dummy)
{
int i;
struct dn_route *rt, *next;
- for(i = 0; i < dn_rt_hash_mask; i++) {
+ for (i = 0; i < dn_rt_hash_mask; i++) {
spin_lock_bh(&dn_rt_hash_table[i].lock);
- if ((rt = xchg(&dn_rt_hash_table[i].chain, NULL)) == NULL)
+ if ((rt = xchg((struct dn_route **)&dn_rt_hash_table[i].chain, NULL)) == NULL)
goto nothing_to_declare;
- for(; rt; rt=next) {
- next = rt->u.rt_next;
- rt->u.rt_next = NULL;
+ for(; rt; rt = next) {
+ next = rcu_dereference_raw(rt->dst.dn_next);
+ RCU_INIT_POINTER(rt->dst.dn_next, NULL);
dst_free((struct dst_entry *)rt);
}
@@ -379,12 +434,11 @@ static int dn_return_short(struct sk_buff *skb)
{
struct dn_skb_cb *cb;
unsigned char *ptr;
- dn_address *src;
- dn_address *dst;
- dn_address tmp;
+ __le16 *src;
+ __le16 *dst;
/* Add back headers */
- skb_push(skb, skb->data - skb->nh.raw);
+ skb_push(skb, skb->data - skb_network_header(skb));
if ((skb = skb_unshare(skb, GFP_ATOMIC)) == NULL)
return NET_RX_DROP;
@@ -394,16 +448,13 @@ static int dn_return_short(struct sk_buff *skb)
ptr = skb->data + 2;
*ptr++ = (cb->rt_flags & ~DN_RT_F_RQR) | DN_RT_F_RTS;
- dst = (dn_address *)ptr;
+ dst = (__le16 *)ptr;
ptr += 2;
- src = (dn_address *)ptr;
+ src = (__le16 *)ptr;
ptr += 2;
*ptr = 0; /* Zero hop count */
- /* Swap source and destination */
- tmp = *src;
- *src = *dst;
- *dst = tmp;
+ swap(*src, *dst);
skb->pkt_type = PACKET_OUTGOING;
dn_rt_finish_output(skb, NULL, NULL);
@@ -423,7 +474,7 @@ static int dn_return_long(struct sk_buff *skb)
unsigned char tmp[ETH_ALEN];
/* Add back all headers */
- skb_push(skb, skb->data - skb->nh.raw);
+ skb_push(skb, skb->data - skb_network_header(skb));
if ((skb = skb_unshare(skb, GFP_ATOMIC)) == NULL)
return NET_RX_DROP;
@@ -464,27 +515,29 @@ static int dn_return_long(struct sk_buff *skb)
*/
static int dn_route_rx_packet(struct sk_buff *skb)
{
- struct dn_skb_cb *cb = DN_SKB_CB(skb);
+ struct dn_skb_cb *cb;
int err;
if ((err = dn_route_input(skb)) == 0)
return dst_input(skb);
+ cb = DN_SKB_CB(skb);
if (decnet_debug_level & 4) {
char *devname = skb->dev ? skb->dev->name : "???";
- struct dn_skb_cb *cb = DN_SKB_CB(skb);
+
printk(KERN_DEBUG
"DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n",
- (int)cb->rt_flags, devname, skb->len, cb->src, cb->dst,
+ (int)cb->rt_flags, devname, skb->len,
+ le16_to_cpu(cb->src), le16_to_cpu(cb->dst),
err, skb->pkt_type);
}
if ((skb->pkt_type == PACKET_HOST) && (cb->rt_flags & DN_RT_F_RQR)) {
- switch(cb->rt_flags & DN_RT_PKT_MSK) {
- case DN_RT_PKT_SHORT:
- return dn_return_short(skb);
- case DN_RT_PKT_LONG:
- return dn_return_long(skb);
+ switch (cb->rt_flags & DN_RT_PKT_MSK) {
+ case DN_RT_PKT_SHORT:
+ return dn_return_short(skb);
+ case DN_RT_PKT_LONG:
+ return dn_return_long(skb);
}
}
@@ -501,27 +554,28 @@ static int dn_route_rx_long(struct sk_buff *skb)
goto drop_it;
skb_pull(skb, 20);
- skb->h.raw = skb->data;
+ skb_reset_transport_header(skb);
- /* Destination info */
- ptr += 2;
- cb->dst = dn_htons(dn_eth2dn(ptr));
- if (memcmp(ptr, dn_hiord_addr, 4) != 0)
- goto drop_it;
- ptr += 6;
+ /* Destination info */
+ ptr += 2;
+ cb->dst = dn_eth2dn(ptr);
+ if (memcmp(ptr, dn_hiord_addr, 4) != 0)
+ goto drop_it;
+ ptr += 6;
- /* Source info */
- ptr += 2;
- cb->src = dn_htons(dn_eth2dn(ptr));
- if (memcmp(ptr, dn_hiord_addr, 4) != 0)
- goto drop_it;
- ptr += 6;
- /* Other junk */
- ptr++;
- cb->hops = *ptr++; /* Visit Count */
+ /* Source info */
+ ptr += 2;
+ cb->src = dn_eth2dn(ptr);
+ if (memcmp(ptr, dn_hiord_addr, 4) != 0)
+ goto drop_it;
+ ptr += 6;
+ /* Other junk */
+ ptr++;
+ cb->hops = *ptr++; /* Visit Count */
- return NF_HOOK(PF_DECnet, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, dn_route_rx_packet);
+ return NF_HOOK(NFPROTO_DECNET, NF_DN_PRE_ROUTING, skb, skb->dev, NULL,
+ dn_route_rx_packet);
drop_it:
kfree_skb(skb);
@@ -539,19 +593,20 @@ static int dn_route_rx_short(struct sk_buff *skb)
goto drop_it;
skb_pull(skb, 5);
- skb->h.raw = skb->data;
+ skb_reset_transport_header(skb);
- cb->dst = *(dn_address *)ptr;
- ptr += 2;
- cb->src = *(dn_address *)ptr;
- ptr += 2;
- cb->hops = *ptr & 0x3f;
+ cb->dst = *(__le16 *)ptr;
+ ptr += 2;
+ cb->src = *(__le16 *)ptr;
+ ptr += 2;
+ cb->hops = *ptr & 0x3f;
- return NF_HOOK(PF_DECnet, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, dn_route_rx_packet);
+ return NF_HOOK(NFPROTO_DECNET, NF_DN_PRE_ROUTING, skb, skb->dev, NULL,
+ dn_route_rx_packet);
drop_it:
- kfree_skb(skb);
- return NET_RX_DROP;
+ kfree_skb(skb);
+ return NET_RX_DROP;
}
static int dn_route_discard(struct sk_buff *skb)
@@ -575,10 +630,13 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
{
struct dn_skb_cb *cb;
unsigned char flags = 0;
- __u16 len = dn_ntohs(*(__u16 *)skb->data);
- struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr;
+ __u16 len = le16_to_cpu(*(__le16 *)skb->data);
+ struct dn_dev *dn = rcu_dereference(dev->dn_ptr);
unsigned char padlen = 0;
+ if (!net_eq(dev_net(dev), &init_net))
+ goto dump_it;
+
if (dn == NULL)
goto dump_it;
@@ -612,7 +670,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
flags = *skb->data;
}
- skb->nh.raw = skb->data;
+ skb_reset_network_header(skb);
/*
* Weed out future version DECnet
@@ -623,54 +681,61 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
cb->rt_flags = flags;
if (decnet_debug_level & 1)
- printk(KERN_DEBUG
+ printk(KERN_DEBUG
"dn_route_rcv: got 0x%02x from %s [%d %d %d]\n",
- (int)flags, (dev) ? dev->name : "???", len, skb->len,
+ (int)flags, (dev) ? dev->name : "???", len, skb->len,
padlen);
- if (flags & DN_RT_PKT_CNTL) {
- if (unlikely(skb_is_nonlinear(skb)) &&
- skb_linearize(skb, GFP_ATOMIC) != 0)
+ if (flags & DN_RT_PKT_CNTL) {
+ if (unlikely(skb_linearize(skb)))
goto dump_it;
- switch(flags & DN_RT_CNTL_MSK) {
- case DN_RT_PKT_INIT:
- dn_dev_init_pkt(skb);
- break;
- case DN_RT_PKT_VERI:
- dn_dev_veri_pkt(skb);
- break;
+ switch (flags & DN_RT_CNTL_MSK) {
+ case DN_RT_PKT_INIT:
+ dn_dev_init_pkt(skb);
+ break;
+ case DN_RT_PKT_VERI:
+ dn_dev_veri_pkt(skb);
+ break;
}
if (dn->parms.state != DN_DEV_S_RU)
goto dump_it;
- switch(flags & DN_RT_CNTL_MSK) {
- case DN_RT_PKT_HELO:
- return NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_route_ptp_hello);
-
- case DN_RT_PKT_L1RT:
- case DN_RT_PKT_L2RT:
- return NF_HOOK(PF_DECnet, NF_DN_ROUTE, skb, skb->dev, NULL, dn_route_discard);
- case DN_RT_PKT_ERTH:
- return NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_neigh_router_hello);
-
- case DN_RT_PKT_EEDH:
- return NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_neigh_endnode_hello);
- }
- } else {
+ switch (flags & DN_RT_CNTL_MSK) {
+ case DN_RT_PKT_HELO:
+ return NF_HOOK(NFPROTO_DECNET, NF_DN_HELLO,
+ skb, skb->dev, NULL,
+ dn_route_ptp_hello);
+
+ case DN_RT_PKT_L1RT:
+ case DN_RT_PKT_L2RT:
+ return NF_HOOK(NFPROTO_DECNET, NF_DN_ROUTE,
+ skb, skb->dev, NULL,
+ dn_route_discard);
+ case DN_RT_PKT_ERTH:
+ return NF_HOOK(NFPROTO_DECNET, NF_DN_HELLO,
+ skb, skb->dev, NULL,
+ dn_neigh_router_hello);
+
+ case DN_RT_PKT_EEDH:
+ return NF_HOOK(NFPROTO_DECNET, NF_DN_HELLO,
+ skb, skb->dev, NULL,
+ dn_neigh_endnode_hello);
+ }
+ } else {
if (dn->parms.state != DN_DEV_S_RU)
goto dump_it;
skb_pull(skb, 1); /* Pull flags */
- switch(flags & DN_RT_PKT_MSK) {
- case DN_RT_PKT_LONG:
- return dn_route_rx_long(skb);
- case DN_RT_PKT_SHORT:
- return dn_route_rx_short(skb);
+ switch (flags & DN_RT_PKT_MSK) {
+ case DN_RT_PKT_LONG:
+ return dn_route_rx_long(skb);
+ case DN_RT_PKT_SHORT:
+ return dn_route_rx_short(skb);
}
- }
+ }
dump_it:
kfree_skb(skb);
@@ -678,17 +743,25 @@ out:
return NET_RX_DROP;
}
-static int dn_output(struct sk_buff *skb)
+static int dn_to_neigh_output(struct sk_buff *skb)
{
- struct dst_entry *dst = skb->dst;
+ struct dst_entry *dst = skb_dst(skb);
+ struct dn_route *rt = (struct dn_route *) dst;
+ struct neighbour *n = rt->n;
+
+ return n->output(n, skb);
+}
+
+static int dn_output(struct sock *sk, struct sk_buff *skb)
+{
+ struct dst_entry *dst = skb_dst(skb);
struct dn_route *rt = (struct dn_route *)dst;
struct net_device *dev = dst->dev;
struct dn_skb_cb *cb = DN_SKB_CB(skb);
- struct neighbour *neigh;
int err = -EINVAL;
- if ((neigh = dst->neighbour) == NULL)
+ if (rt->n == NULL)
goto error;
skb->dev = dev;
@@ -705,11 +778,11 @@ static int dn_output(struct sk_buff *skb)
cb->rt_flags |= DN_RT_F_IE;
cb->hops = 0;
- return NF_HOOK(PF_DECnet, NF_DN_LOCAL_OUT, skb, NULL, dev, neigh->output);
+ return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_OUT, skb, NULL, dev,
+ dn_to_neigh_output);
error:
- if (net_ratelimit())
- printk(KERN_DEBUG "dn_output: This should not happen\n");
+ net_dbg_ratelimited("dn_output: This should not happen\n");
kfree_skb(skb);
@@ -719,10 +792,9 @@ error:
static int dn_forward(struct sk_buff *skb)
{
struct dn_skb_cb *cb = DN_SKB_CB(skb);
- struct dst_entry *dst = skb->dst;
- struct dn_dev *dn_db = dst->dev->dn_ptr;
+ struct dst_entry *dst = skb_dst(skb);
+ struct dn_dev *dn_db = rcu_dereference(dst->dev->dn_ptr);
struct dn_route *rt;
- struct neighbour *neigh = dst->neighbour;
int header_len;
#ifdef CONFIG_NETFILTER
struct net_device *dev = skb->dev;
@@ -732,9 +804,9 @@ static int dn_forward(struct sk_buff *skb)
goto drop;
/* Ensure that we have enough space for headers */
- rt = (struct dn_route *)skb->dst;
+ rt = (struct dn_route *)skb_dst(skb);
header_len = dn_db->use_long ? 21 : 6;
- if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+header_len))
+ if (skb_cow(skb, LL_RESERVED_SPACE(rt->dst.dev)+header_len))
goto drop;
/*
@@ -743,7 +815,7 @@ static int dn_forward(struct sk_buff *skb)
if (++cb->hops > 30)
goto drop;
- skb->dev = rt->u.dst.dev;
+ skb->dev = rt->dst.dev;
/*
* If packet goes out same interface it came in on, then set
@@ -754,7 +826,8 @@ static int dn_forward(struct sk_buff *skb)
if (rt->rt_flags & RTCF_DOREDIRECT)
cb->rt_flags |= DN_RT_F_IE;
- return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output);
+ return NF_HOOK(NFPROTO_DECNET, NF_DN_FORWARD, skb, dev, skb->dev,
+ dn_to_neigh_output);
drop:
kfree_skb(skb);
@@ -762,70 +835,88 @@ drop:
}
/*
- * Drop packet. This is used for endnodes and for
- * when we should not be forwarding packets from
- * this dest.
+ * Used to catch bugs. This should never normally get
+ * called.
*/
-static int dn_blackhole(struct sk_buff *skb)
+static int dn_rt_bug_sk(struct sock *sk, struct sk_buff *skb)
{
+ struct dn_skb_cb *cb = DN_SKB_CB(skb);
+
+ net_dbg_ratelimited("dn_rt_bug: skb from:%04x to:%04x\n",
+ le16_to_cpu(cb->src), le16_to_cpu(cb->dst));
+
kfree_skb(skb);
+
return NET_RX_DROP;
}
-/*
- * Used to catch bugs. This should never normally get
- * called.
- */
static int dn_rt_bug(struct sk_buff *skb)
{
- if (net_ratelimit()) {
- struct dn_skb_cb *cb = DN_SKB_CB(skb);
+ struct dn_skb_cb *cb = DN_SKB_CB(skb);
- printk(KERN_DEBUG "dn_rt_bug: skb from:%04x to:%04x\n",
- cb->src, cb->dst);
- }
+ net_dbg_ratelimited("dn_rt_bug: skb from:%04x to:%04x\n",
+ le16_to_cpu(cb->src), le16_to_cpu(cb->dst));
kfree_skb(skb);
- return NET_RX_BAD;
+ return NET_RX_DROP;
+}
+
+static unsigned int dn_dst_default_advmss(const struct dst_entry *dst)
+{
+ return dn_mss_from_pmtu(dst->dev, dst_mtu(dst));
+}
+
+static unsigned int dn_dst_mtu(const struct dst_entry *dst)
+{
+ unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
+
+ return mtu ? : dst->dev->mtu;
+}
+
+static struct neighbour *dn_dst_neigh_lookup(const struct dst_entry *dst,
+ struct sk_buff *skb,
+ const void *daddr)
+{
+ return __neigh_lookup_errno(&dn_neigh_table, daddr, dst->dev);
}
static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
{
struct dn_fib_info *fi = res->fi;
- struct net_device *dev = rt->u.dst.dev;
+ struct net_device *dev = rt->dst.dev;
+ unsigned int mss_metric;
struct neighbour *n;
- unsigned mss;
if (fi) {
if (DN_FIB_RES_GW(*res) &&
DN_FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
rt->rt_gateway = DN_FIB_RES_GW(*res);
- memcpy(rt->u.dst.metrics, fi->fib_metrics,
- sizeof(rt->u.dst.metrics));
+ dst_init_metrics(&rt->dst, fi->fib_metrics, true);
}
rt->rt_type = res->type;
- if (dev != NULL && rt->u.dst.neighbour == NULL) {
+ if (dev != NULL && rt->n == NULL) {
n = __neigh_lookup_errno(&dn_neigh_table, &rt->rt_gateway, dev);
if (IS_ERR(n))
return PTR_ERR(n);
- rt->u.dst.neighbour = n;
+ rt->n = n;
}
- if (rt->u.dst.metrics[RTAX_MTU-1] == 0 ||
- rt->u.dst.metrics[RTAX_MTU-1] > rt->u.dst.dev->mtu)
- rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu;
- mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->u.dst));
- if (rt->u.dst.metrics[RTAX_ADVMSS-1] == 0 ||
- rt->u.dst.metrics[RTAX_ADVMSS-1] > mss)
- rt->u.dst.metrics[RTAX_ADVMSS-1] = mss;
+ if (dst_metric(&rt->dst, RTAX_MTU) > rt->dst.dev->mtu)
+ dst_metric_set(&rt->dst, RTAX_MTU, rt->dst.dev->mtu);
+ mss_metric = dst_metric_raw(&rt->dst, RTAX_ADVMSS);
+ if (mss_metric) {
+ unsigned int mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->dst));
+ if (mss_metric > mss)
+ dst_metric_set(&rt->dst, RTAX_ADVMSS, mss);
+ }
return 0;
}
-static inline int dn_match_addr(__u16 addr1, __u16 addr2)
+static inline int dn_match_addr(__le16 addr1, __le16 addr2)
{
- __u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2);
+ __u16 tmp = le16_to_cpu(addr1) ^ le16_to_cpu(addr2);
int match = 16;
while(tmp) {
tmp >>= 1;
@@ -834,16 +925,19 @@ static inline int dn_match_addr(__u16 addr1, __u16 addr2)
return match;
}
-static __u16 dnet_select_source(const struct net_device *dev, __u16 daddr, int scope)
+static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope)
{
- __u16 saddr = 0;
- struct dn_dev *dn_db = dev->dn_ptr;
+ __le16 saddr = 0;
+ struct dn_dev *dn_db;
struct dn_ifaddr *ifa;
int best_match = 0;
int ret;
- read_lock(&dev_base_lock);
- for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) {
+ rcu_read_lock();
+ dn_db = rcu_dereference(dev->dn_ptr);
+ for (ifa = rcu_dereference(dn_db->ifa_list);
+ ifa != NULL;
+ ifa = rcu_dereference(ifa->ifa_next)) {
if (ifa->ifa_scope > scope)
continue;
if (!daddr) {
@@ -856,53 +950,53 @@ static __u16 dnet_select_source(const struct net_device *dev, __u16 daddr, int s
if (best_match == 0)
saddr = ifa->ifa_local;
}
- read_unlock(&dev_base_lock);
+ rcu_read_unlock();
return saddr;
}
-static inline __u16 __dn_fib_res_prefsrc(struct dn_fib_res *res)
+static inline __le16 __dn_fib_res_prefsrc(struct dn_fib_res *res)
{
return dnet_select_source(DN_FIB_RES_DEV(*res), DN_FIB_RES_GW(*res), res->scope);
}
-static inline __u16 dn_fib_rules_map_destination(__u16 daddr, struct dn_fib_res *res)
+static inline __le16 dn_fib_rules_map_destination(__le16 daddr, struct dn_fib_res *res)
{
- __u16 mask = dnet_make_mask(res->prefixlen);
+ __le16 mask = dnet_make_mask(res->prefixlen);
return (daddr&~mask)|res->fi->fib_nh->nh_gw;
}
-static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *oldflp, int try_hard)
+static int dn_route_output_slow(struct dst_entry **pprt, const struct flowidn *oldflp, int try_hard)
{
- struct flowi fl = { .nl_u = { .dn_u =
- { .daddr = oldflp->fld_dst,
- .saddr = oldflp->fld_src,
- .scope = RT_SCOPE_UNIVERSE,
-#ifdef CONFIG_DECNET_ROUTE_FWMARK
- .fwmark = oldflp->fld_fwmark
-#endif
- } },
- .iif = loopback_dev.ifindex,
- .oif = oldflp->oif };
+ struct flowidn fld = {
+ .daddr = oldflp->daddr,
+ .saddr = oldflp->saddr,
+ .flowidn_scope = RT_SCOPE_UNIVERSE,
+ .flowidn_mark = oldflp->flowidn_mark,
+ .flowidn_iif = LOOPBACK_IFINDEX,
+ .flowidn_oif = oldflp->flowidn_oif,
+ };
struct dn_route *rt = NULL;
- struct net_device *dev_out = NULL;
+ struct net_device *dev_out = NULL, *dev;
struct neighbour *neigh = NULL;
- unsigned hash;
- unsigned flags = 0;
+ unsigned int hash;
+ unsigned int flags = 0;
struct dn_fib_res res = { .fi = NULL, .type = RTN_UNICAST };
int err;
int free_res = 0;
- __u16 gateway = 0;
+ __le16 gateway = 0;
if (decnet_debug_level & 16)
printk(KERN_DEBUG
"dn_route_output_slow: dst=%04x src=%04x mark=%d"
- " iif=%d oif=%d\n", oldflp->fld_dst, oldflp->fld_src,
- oldflp->fld_fwmark, loopback_dev.ifindex, oldflp->oif);
+ " iif=%d oif=%d\n", le16_to_cpu(oldflp->daddr),
+ le16_to_cpu(oldflp->saddr),
+ oldflp->flowidn_mark, LOOPBACK_IFINDEX,
+ oldflp->flowidn_oif);
/* If we have an output interface, verify its a DECnet device */
- if (oldflp->oif) {
- dev_out = dev_get_by_index(oldflp->oif);
+ if (oldflp->flowidn_oif) {
+ dev_out = dev_get_by_index(&init_net, oldflp->flowidn_oif);
err = -ENODEV;
if (dev_out && dev_out->dn_ptr == NULL) {
dev_put(dev_out);
@@ -913,23 +1007,30 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
}
/* If we have a source address, verify that its a local address */
- if (oldflp->fld_src) {
+ if (oldflp->saddr) {
err = -EADDRNOTAVAIL;
if (dev_out) {
- if (dn_dev_islocal(dev_out, oldflp->fld_src))
+ if (dn_dev_islocal(dev_out, oldflp->saddr))
goto source_ok;
dev_put(dev_out);
goto out;
}
- read_lock(&dev_base_lock);
- for(dev_out = dev_base; dev_out; dev_out = dev_out->next) {
- if (!dev_out->dn_ptr)
+ rcu_read_lock();
+ for_each_netdev_rcu(&init_net, dev) {
+ if (!dev->dn_ptr)
continue;
- if (dn_dev_islocal(dev_out, oldflp->fld_src))
- break;
+ if (!dn_dev_islocal(dev, oldflp->saddr))
+ continue;
+ if ((dev->flags & IFF_LOOPBACK) &&
+ oldflp->daddr &&
+ !dn_dev_islocal(dev, oldflp->daddr))
+ continue;
+
+ dev_out = dev;
+ break;
}
- read_unlock(&dev_base_lock);
+ rcu_read_unlock();
if (dev_out == NULL)
goto out;
dev_hold(dev_out);
@@ -938,22 +1039,22 @@ source_ok:
}
/* No destination? Assume its local */
- if (!fl.fld_dst) {
- fl.fld_dst = fl.fld_src;
+ if (!fld.daddr) {
+ fld.daddr = fld.saddr;
err = -EADDRNOTAVAIL;
if (dev_out)
dev_put(dev_out);
- dev_out = &loopback_dev;
+ dev_out = init_net.loopback_dev;
dev_hold(dev_out);
- if (!fl.fld_dst) {
- fl.fld_dst =
- fl.fld_src = dnet_select_source(dev_out, 0,
+ if (!fld.daddr) {
+ fld.daddr =
+ fld.saddr = dnet_select_source(dev_out, 0,
RT_SCOPE_HOST);
- if (!fl.fld_dst)
+ if (!fld.daddr)
goto out;
}
- fl.oif = loopback_dev.ifindex;
+ fld.flowidn_oif = LOOPBACK_IFINDEX;
res.type = RTN_LOCAL;
goto make_route;
}
@@ -961,8 +1062,9 @@ source_ok:
if (decnet_debug_level & 16)
printk(KERN_DEBUG
"dn_route_output_slow: initial checks complete."
- " dst=%o4x src=%04x oif=%d try_hard=%d\n", fl.fld_dst,
- fl.fld_src, fl.oif, try_hard);
+ " dst=%o4x src=%04x oif=%d try_hard=%d\n",
+ le16_to_cpu(fld.daddr), le16_to_cpu(fld.saddr),
+ fld.flowidn_oif, try_hard);
/*
* N.B. If the kernel is compiled without router support then
@@ -970,35 +1072,35 @@ source_ok:
* will always be executed.
*/
err = -ESRCH;
- if (try_hard || (err = dn_fib_lookup(&fl, &res)) != 0) {
+ if (try_hard || (err = dn_fib_lookup(&fld, &res)) != 0) {
struct dn_dev *dn_db;
if (err != -ESRCH)
goto out;
/*
- * Here the fallback is basically the standard algorithm for
+ * Here the fallback is basically the standard algorithm for
* routing in endnodes which is described in the DECnet routing
* docs
*
* If we are not trying hard, look in neighbour cache.
* The result is tested to ensure that if a specific output
- * device/source address was requested, then we honour that
+ * device/source address was requested, then we honour that
* here
*/
if (!try_hard) {
- neigh = neigh_lookup_nodev(&dn_neigh_table, &fl.fld_dst);
+ neigh = neigh_lookup_nodev(&dn_neigh_table, &init_net, &fld.daddr);
if (neigh) {
- if ((oldflp->oif &&
- (neigh->dev->ifindex != oldflp->oif)) ||
- (oldflp->fld_src &&
+ if ((oldflp->flowidn_oif &&
+ (neigh->dev->ifindex != oldflp->flowidn_oif)) ||
+ (oldflp->saddr &&
(!dn_dev_islocal(neigh->dev,
- oldflp->fld_src)))) {
+ oldflp->saddr)))) {
neigh_release(neigh);
neigh = NULL;
} else {
if (dev_out)
dev_put(dev_out);
- if (dn_dev_islocal(neigh->dev, fl.fld_dst)) {
- dev_out = &loopback_dev;
+ if (dn_dev_islocal(neigh->dev, fld.daddr)) {
+ dev_out = init_net.loopback_dev;
res.type = RTN_LOCAL;
} else {
dev_out = neigh->dev;
@@ -1015,11 +1117,11 @@ source_ok:
err = -ENODEV;
if (dev_out == NULL)
goto out;
- dn_db = dev_out->dn_ptr;
+ dn_db = rcu_dereference_raw(dev_out->dn_ptr);
/* Possible improvement - check all devices for local addr */
- if (dn_dev_islocal(dev_out, fl.fld_dst)) {
+ if (dn_dev_islocal(dev_out, fld.daddr)) {
dev_put(dev_out);
- dev_out = &loopback_dev;
+ dev_out = init_net.loopback_dev;
dev_hold(dev_out);
res.type = RTN_LOCAL;
goto select_source;
@@ -1033,16 +1135,16 @@ select_source:
if (neigh)
gateway = ((struct dn_neigh *)neigh)->addr;
if (gateway == 0)
- gateway = fl.fld_dst;
- if (fl.fld_src == 0) {
- fl.fld_src = dnet_select_source(dev_out, gateway,
- res.type == RTN_LOCAL ?
- RT_SCOPE_HOST :
- RT_SCOPE_LINK);
- if (fl.fld_src == 0 && res.type != RTN_LOCAL)
+ gateway = fld.daddr;
+ if (fld.saddr == 0) {
+ fld.saddr = dnet_select_source(dev_out, gateway,
+ res.type == RTN_LOCAL ?
+ RT_SCOPE_HOST :
+ RT_SCOPE_LINK);
+ if (fld.saddr == 0 && res.type != RTN_LOCAL)
goto e_addr;
}
- fl.oif = dev_out->ifindex;
+ fld.flowidn_oif = dev_out->ifindex;
goto make_route;
}
free_res = 1;
@@ -1051,81 +1153,75 @@ select_source:
goto e_inval;
if (res.type == RTN_LOCAL) {
- if (!fl.fld_src)
- fl.fld_src = fl.fld_dst;
+ if (!fld.saddr)
+ fld.saddr = fld.daddr;
if (dev_out)
dev_put(dev_out);
- dev_out = &loopback_dev;
+ dev_out = init_net.loopback_dev;
dev_hold(dev_out);
- fl.oif = dev_out->ifindex;
+ fld.flowidn_oif = dev_out->ifindex;
if (res.fi)
dn_fib_info_put(res.fi);
res.fi = NULL;
goto make_route;
}
- if (res.fi->fib_nhs > 1 && fl.oif == 0)
- dn_fib_select_multipath(&fl, &res);
+ if (res.fi->fib_nhs > 1 && fld.flowidn_oif == 0)
+ dn_fib_select_multipath(&fld, &res);
- /*
+ /*
* We could add some logic to deal with default routes here and
* get rid of some of the special casing above.
*/
- if (!fl.fld_src)
- fl.fld_src = DN_FIB_RES_PREFSRC(res);
-
+ if (!fld.saddr)
+ fld.saddr = DN_FIB_RES_PREFSRC(res);
+
if (dev_out)
dev_put(dev_out);
dev_out = DN_FIB_RES_DEV(res);
dev_hold(dev_out);
- fl.oif = dev_out->ifindex;
+ fld.flowidn_oif = dev_out->ifindex;
gateway = DN_FIB_RES_GW(res);
make_route:
if (dev_out->flags & IFF_LOOPBACK)
flags |= RTCF_LOCAL;
- rt = dst_alloc(&dn_dst_ops);
+ rt = dst_alloc(&dn_dst_ops, dev_out, 1, DST_OBSOLETE_NONE, DST_HOST);
if (rt == NULL)
goto e_nobufs;
- atomic_set(&rt->u.dst.__refcnt, 1);
- rt->u.dst.flags = DST_HOST;
-
- rt->fl.fld_src = oldflp->fld_src;
- rt->fl.fld_dst = oldflp->fld_dst;
- rt->fl.oif = oldflp->oif;
- rt->fl.iif = 0;
-#ifdef CONFIG_DECNET_ROUTE_FWMARK
- rt->fl.fld_fwmark = oldflp->fld_fwmark;
-#endif
+ memset(&rt->fld, 0, sizeof(rt->fld));
+ rt->fld.saddr = oldflp->saddr;
+ rt->fld.daddr = oldflp->daddr;
+ rt->fld.flowidn_oif = oldflp->flowidn_oif;
+ rt->fld.flowidn_iif = 0;
+ rt->fld.flowidn_mark = oldflp->flowidn_mark;
- rt->rt_saddr = fl.fld_src;
- rt->rt_daddr = fl.fld_dst;
- rt->rt_gateway = gateway ? gateway : fl.fld_dst;
- rt->rt_local_src = fl.fld_src;
+ rt->rt_saddr = fld.saddr;
+ rt->rt_daddr = fld.daddr;
+ rt->rt_gateway = gateway ? gateway : fld.daddr;
+ rt->rt_local_src = fld.saddr;
- rt->rt_dst_map = fl.fld_dst;
- rt->rt_src_map = fl.fld_src;
+ rt->rt_dst_map = fld.daddr;
+ rt->rt_src_map = fld.saddr;
- rt->u.dst.dev = dev_out;
- dev_hold(dev_out);
- rt->u.dst.neighbour = neigh;
+ rt->n = neigh;
neigh = NULL;
- rt->u.dst.lastuse = jiffies;
- rt->u.dst.output = dn_output;
- rt->u.dst.input = dn_rt_bug;
+ rt->dst.lastuse = jiffies;
+ rt->dst.output = dn_output;
+ rt->dst.input = dn_rt_bug;
rt->rt_flags = flags;
if (flags & RTCF_LOCAL)
- rt->u.dst.input = dn_nsp_rx;
+ rt->dst.input = dn_nsp_rx;
err = dn_rt_set_next_hop(rt, &res);
if (err)
goto e_neighbour;
- hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
+ hash = dn_hash(rt->fld.saddr, rt->fld.daddr);
dn_insert_route(rt, hash, (struct dn_route **)pprt);
done:
@@ -1139,8 +1235,8 @@ out:
return err;
e_addr:
- err = -EADDRNOTAVAIL;
- goto done;
+ err = -EADDRNOTAVAIL;
+ goto done;
e_inval:
err = -EINVAL;
goto done;
@@ -1148,7 +1244,7 @@ e_nobufs:
err = -ENOBUFS;
goto done;
e_neighbour:
- dst_free(&rt->u.dst);
+ dst_free(&rt->dst);
goto e_nobufs;
}
@@ -1156,27 +1252,23 @@ e_neighbour:
/*
* N.B. The flags may be moved into the flowi at some future stage.
*/
-static int __dn_route_output_key(struct dst_entry **pprt, const struct flowi *flp, int flags)
+static int __dn_route_output_key(struct dst_entry **pprt, const struct flowidn *flp, int flags)
{
- unsigned hash = dn_hash(flp->fld_src, flp->fld_dst);
+ unsigned int hash = dn_hash(flp->saddr, flp->daddr);
struct dn_route *rt = NULL;
if (!(flags & MSG_TRYHARD)) {
rcu_read_lock_bh();
- for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt;
- rt = rcu_dereference(rt->u.rt_next)) {
- if ((flp->fld_dst == rt->fl.fld_dst) &&
- (flp->fld_src == rt->fl.fld_src) &&
-#ifdef CONFIG_DECNET_ROUTE_FWMARK
- (flp->fld_fwmark == rt->fl.fld_fwmark) &&
-#endif
- (rt->fl.iif == 0) &&
- (rt->fl.oif == flp->oif)) {
- rt->u.dst.lastuse = jiffies;
- dst_hold(&rt->u.dst);
- rt->u.dst.__use++;
+ for (rt = rcu_dereference_bh(dn_rt_hash_table[hash].chain); rt;
+ rt = rcu_dereference_bh(rt->dst.dn_next)) {
+ if ((flp->daddr == rt->fld.daddr) &&
+ (flp->saddr == rt->fld.saddr) &&
+ (flp->flowidn_mark == rt->fld.flowidn_mark) &&
+ dn_is_output_route(rt) &&
+ (rt->fld.flowidn_oif == flp->flowidn_oif)) {
+ dst_use(&rt->dst, jiffies);
rcu_read_unlock_bh();
- *pprt = &rt->u.dst;
+ *pprt = &rt->dst;
return 0;
}
}
@@ -1186,24 +1278,34 @@ static int __dn_route_output_key(struct dst_entry **pprt, const struct flowi *fl
return dn_route_output_slow(pprt, flp, flags);
}
-static int dn_route_output_key(struct dst_entry **pprt, struct flowi *flp, int flags)
+static int dn_route_output_key(struct dst_entry **pprt, struct flowidn *flp, int flags)
{
int err;
err = __dn_route_output_key(pprt, flp, flags);
- if (err == 0 && flp->proto) {
- err = xfrm_lookup(pprt, flp, NULL, 0);
+ if (err == 0 && flp->flowidn_proto) {
+ *pprt = xfrm_lookup(&init_net, *pprt,
+ flowidn_to_flowi(flp), NULL, 0);
+ if (IS_ERR(*pprt)) {
+ err = PTR_ERR(*pprt);
+ *pprt = NULL;
+ }
}
return err;
}
-int dn_route_output_sock(struct dst_entry **pprt, struct flowi *fl, struct sock *sk, int flags)
+int dn_route_output_sock(struct dst_entry __rcu **pprt, struct flowidn *fl, struct sock *sk, int flags)
{
int err;
err = __dn_route_output_key(pprt, fl, flags & MSG_TRYHARD);
- if (err == 0 && fl->proto) {
- err = xfrm_lookup(pprt, fl, sk, !(flags & MSG_DONTWAIT));
+ if (err == 0 && fl->flowidn_proto) {
+ *pprt = xfrm_lookup(&init_net, *pprt,
+ flowidn_to_flowi(fl), sk, 0);
+ if (IS_ERR(*pprt)) {
+ err = PTR_ERR(*pprt);
+ *pprt = NULL;
+ }
}
return err;
}
@@ -1216,30 +1318,28 @@ static int dn_route_input_slow(struct sk_buff *skb)
struct net_device *out_dev = NULL;
struct dn_dev *dn_db;
struct neighbour *neigh = NULL;
- unsigned hash;
+ unsigned int hash;
int flags = 0;
- __u16 gateway = 0;
- __u16 local_src = 0;
- struct flowi fl = { .nl_u = { .dn_u =
- { .daddr = cb->dst,
- .saddr = cb->src,
- .scope = RT_SCOPE_UNIVERSE,
-#ifdef CONFIG_DECNET_ROUTE_FWMARK
- .fwmark = skb->nfmark
-#endif
- } },
- .iif = skb->dev->ifindex };
+ __le16 gateway = 0;
+ __le16 local_src = 0;
+ struct flowidn fld = {
+ .daddr = cb->dst,
+ .saddr = cb->src,
+ .flowidn_scope = RT_SCOPE_UNIVERSE,
+ .flowidn_mark = skb->mark,
+ .flowidn_iif = skb->dev->ifindex,
+ };
struct dn_fib_res res = { .fi = NULL, .type = RTN_UNREACHABLE };
int err = -EINVAL;
int free_res = 0;
dev_hold(in_dev);
- if ((dn_db = in_dev->dn_ptr) == NULL)
+ if ((dn_db = rcu_dereference(in_dev->dn_ptr)) == NULL)
goto out;
/* Zero source addresses are not allowed */
- if (fl.fld_src == 0)
+ if (fld.saddr == 0)
goto out;
/*
@@ -1253,7 +1353,7 @@ static int dn_route_input_slow(struct sk_buff *skb)
if (dn_dev_islocal(in_dev, cb->src))
goto out;
- err = dn_fib_lookup(&fl, &res);
+ err = dn_fib_lookup(&fld, &res);
if (err) {
if (err != -ESRCH)
goto out;
@@ -1264,37 +1364,34 @@ static int dn_route_input_slow(struct sk_buff *skb)
goto e_inval;
res.type = RTN_LOCAL;
- flags |= RTCF_DIRECTSRC;
} else {
- __u16 src_map = fl.fld_src;
+ __le16 src_map = fld.saddr;
free_res = 1;
out_dev = DN_FIB_RES_DEV(res);
if (out_dev == NULL) {
- if (net_ratelimit())
- printk(KERN_CRIT "Bug in dn_route_input_slow() "
- "No output device\n");
+ net_crit_ratelimited("Bug in dn_route_input_slow() No output device\n");
goto e_inval;
}
dev_hold(out_dev);
if (res.r)
- src_map = dn_fib_rules_policy(fl.fld_src, &res, &flags);
+ src_map = fld.saddr; /* no NAT support for now */
gateway = DN_FIB_RES_GW(res);
if (res.type == RTN_NAT) {
- fl.fld_dst = dn_fib_rules_map_destination(fl.fld_dst, &res);
+ fld.daddr = dn_fib_rules_map_destination(fld.daddr, &res);
dn_fib_res_put(&res);
free_res = 0;
- if (dn_fib_lookup(&fl, &res))
+ if (dn_fib_lookup(&fld, &res))
goto e_inval;
free_res = 1;
if (res.type != RTN_UNICAST)
goto e_inval;
flags |= RTCF_DNAT;
- gateway = fl.fld_dst;
+ gateway = fld.daddr;
}
- fl.fld_src = src_map;
+ fld.saddr = src_map;
}
switch(res.type) {
@@ -1308,10 +1405,10 @@ static int dn_route_input_slow(struct sk_buff *skb)
if (dn_db->parms.forwarding == 0)
goto e_inval;
- if (res.fi->fib_nhs > 1 && fl.oif == 0)
- dn_fib_select_multipath(&fl, &res);
+ if (res.fi->fib_nhs > 1 && fld.flowidn_oif == 0)
+ dn_fib_select_multipath(&fld, &res);
- /*
+ /*
* Check for out_dev == in_dev. We use the RTCF_DOREDIRECT
* flag as a hint to set the intra-ethernet bit when
* forwarding. If we've got NAT in operation, we don't do
@@ -1327,17 +1424,16 @@ static int dn_route_input_slow(struct sk_buff *skb)
break;
case RTN_LOCAL:
flags |= RTCF_LOCAL;
- fl.fld_src = cb->dst;
- fl.fld_dst = cb->src;
+ fld.saddr = cb->dst;
+ fld.daddr = cb->src;
/* Routing tables gave us a gateway */
if (gateway)
goto make_route;
/* Packet was intra-ethernet, so we know its on-link */
- if (cb->rt_flags | DN_RT_F_IE) {
+ if (cb->rt_flags & DN_RT_F_IE) {
gateway = cb->src;
- flags |= RTCF_DIRECTSRC;
goto make_route;
}
@@ -1350,63 +1446,60 @@ static int dn_route_input_slow(struct sk_buff *skb)
/* Close eyes and pray */
gateway = cb->src;
- flags |= RTCF_DIRECTSRC;
goto make_route;
default:
goto e_inval;
}
make_route:
- rt = dst_alloc(&dn_dst_ops);
+ rt = dst_alloc(&dn_dst_ops, out_dev, 0, DST_OBSOLETE_NONE, DST_HOST);
if (rt == NULL)
goto e_nobufs;
- rt->rt_saddr = fl.fld_src;
- rt->rt_daddr = fl.fld_dst;
- rt->rt_gateway = fl.fld_dst;
+ memset(&rt->fld, 0, sizeof(rt->fld));
+ rt->rt_saddr = fld.saddr;
+ rt->rt_daddr = fld.daddr;
+ rt->rt_gateway = fld.daddr;
if (gateway)
rt->rt_gateway = gateway;
rt->rt_local_src = local_src ? local_src : rt->rt_saddr;
- rt->rt_dst_map = fl.fld_dst;
- rt->rt_src_map = fl.fld_src;
+ rt->rt_dst_map = fld.daddr;
+ rt->rt_src_map = fld.saddr;
- rt->fl.fld_src = cb->src;
- rt->fl.fld_dst = cb->dst;
- rt->fl.oif = 0;
- rt->fl.iif = in_dev->ifindex;
- rt->fl.fld_fwmark = fl.fld_fwmark;
+ rt->fld.saddr = cb->src;
+ rt->fld.daddr = cb->dst;
+ rt->fld.flowidn_oif = 0;
+ rt->fld.flowidn_iif = in_dev->ifindex;
+ rt->fld.flowidn_mark = fld.flowidn_mark;
- rt->u.dst.flags = DST_HOST;
- rt->u.dst.neighbour = neigh;
- rt->u.dst.dev = out_dev;
- rt->u.dst.lastuse = jiffies;
- rt->u.dst.output = dn_rt_bug;
- switch(res.type) {
- case RTN_UNICAST:
- rt->u.dst.input = dn_forward;
- break;
- case RTN_LOCAL:
- rt->u.dst.output = dn_output;
- rt->u.dst.input = dn_nsp_rx;
- rt->u.dst.dev = in_dev;
- flags |= RTCF_LOCAL;
- break;
- default:
- case RTN_UNREACHABLE:
- case RTN_BLACKHOLE:
- rt->u.dst.input = dn_blackhole;
+ rt->n = neigh;
+ rt->dst.lastuse = jiffies;
+ rt->dst.output = dn_rt_bug_sk;
+ switch (res.type) {
+ case RTN_UNICAST:
+ rt->dst.input = dn_forward;
+ break;
+ case RTN_LOCAL:
+ rt->dst.output = dn_output;
+ rt->dst.input = dn_nsp_rx;
+ rt->dst.dev = in_dev;
+ flags |= RTCF_LOCAL;
+ break;
+ default:
+ case RTN_UNREACHABLE:
+ case RTN_BLACKHOLE:
+ rt->dst.input = dst_discard;
}
rt->rt_flags = flags;
- if (rt->u.dst.dev)
- dev_hold(rt->u.dst.dev);
err = dn_rt_set_next_hop(rt, &res);
if (err)
goto e_neighbour;
- hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
- dn_insert_route(rt, hash, (struct dn_route **)&skb->dst);
+ hash = dn_hash(rt->fld.saddr, rt->fld.daddr);
+ dn_insert_route(rt, hash, &rt);
+ skb_dst_set(skb, &rt->dst);
done:
if (neigh)
@@ -1428,34 +1521,30 @@ e_nobufs:
goto done;
e_neighbour:
- dst_free(&rt->u.dst);
+ dst_free(&rt->dst);
goto done;
}
-int dn_route_input(struct sk_buff *skb)
+static int dn_route_input(struct sk_buff *skb)
{
struct dn_route *rt;
struct dn_skb_cb *cb = DN_SKB_CB(skb);
- unsigned hash = dn_hash(cb->src, cb->dst);
+ unsigned int hash = dn_hash(cb->src, cb->dst);
- if (skb->dst)
+ if (skb_dst(skb))
return 0;
rcu_read_lock();
for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt != NULL;
- rt = rcu_dereference(rt->u.rt_next)) {
- if ((rt->fl.fld_src == cb->src) &&
- (rt->fl.fld_dst == cb->dst) &&
- (rt->fl.oif == 0) &&
-#ifdef CONFIG_DECNET_ROUTE_FWMARK
- (rt->fl.fld_fwmark == skb->nfmark) &&
-#endif
- (rt->fl.iif == cb->iif)) {
- rt->u.dst.lastuse = jiffies;
- dst_hold(&rt->u.dst);
- rt->u.dst.__use++;
+ rt = rcu_dereference(rt->dst.dn_next)) {
+ if ((rt->fld.saddr == cb->src) &&
+ (rt->fld.daddr == cb->dst) &&
+ (rt->fld.flowidn_oif == 0) &&
+ (rt->fld.flowidn_mark == skb->mark) &&
+ (rt->fld.flowidn_iif == cb->iif)) {
+ dst_use(&rt->dst, jiffies);
rcu_read_unlock();
- skb->dst = (struct dst_entry *)rt;
+ skb_dst_set(skb, (struct dst_entry *)rt);
return 0;
}
}
@@ -1464,17 +1553,19 @@ int dn_route_input(struct sk_buff *skb)
return dn_route_input_slow(skb);
}
-static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
+static int dn_rt_fill_info(struct sk_buff *skb, u32 portid, u32 seq,
int event, int nowait, unsigned int flags)
{
- struct dn_route *rt = (struct dn_route *)skb->dst;
+ struct dn_route *rt = (struct dn_route *)skb_dst(skb);
struct rtmsg *r;
struct nlmsghdr *nlh;
- unsigned char *b = skb->tail;
- struct rta_cacheinfo ci;
+ long expires;
- nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags);
- r = NLMSG_DATA(nlh);
+ nlh = nlmsg_put(skb, portid, seq, event, sizeof(*r), flags);
+ if (!nlh)
+ return -EMSGSIZE;
+
+ r = nlmsg_data(nlh);
r->rtm_family = AF_DECnet;
r->rtm_dst_len = 16;
r->rtm_src_len = 0;
@@ -1484,118 +1575,140 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED;
r->rtm_scope = RT_SCOPE_UNIVERSE;
r->rtm_protocol = RTPROT_UNSPEC;
+
if (rt->rt_flags & RTCF_NOTIFY)
r->rtm_flags |= RTM_F_NOTIFY;
- RTA_PUT(skb, RTA_DST, 2, &rt->rt_daddr);
- if (rt->fl.fld_src) {
+
+ if (nla_put_u32(skb, RTA_TABLE, RT_TABLE_MAIN) < 0 ||
+ nla_put_le16(skb, RTA_DST, rt->rt_daddr) < 0)
+ goto errout;
+
+ if (rt->fld.saddr) {
r->rtm_src_len = 16;
- RTA_PUT(skb, RTA_SRC, 2, &rt->fl.fld_src);
+ if (nla_put_le16(skb, RTA_SRC, rt->fld.saddr) < 0)
+ goto errout;
}
- if (rt->u.dst.dev)
- RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
+ if (rt->dst.dev &&
+ nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex) < 0)
+ goto errout;
+
/*
* Note to self - change this if input routes reverse direction when
* they deal only with inputs and not with replies like they do
* currently.
*/
- RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src);
- if (rt->rt_daddr != rt->rt_gateway)
- RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway);
- if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
- goto rtattr_failure;
- ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse);
- ci.rta_used = rt->u.dst.__use;
- ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt);
- if (rt->u.dst.expires)
- ci.rta_expires = jiffies_to_clock_t(rt->u.dst.expires - jiffies);
- else
- ci.rta_expires = 0;
- ci.rta_error = rt->u.dst.error;
- ci.rta_id = ci.rta_ts = ci.rta_tsage = 0;
- RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
- if (rt->fl.iif)
- RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif);
-
- nlh->nlmsg_len = skb->tail - b;
- return skb->len;
+ if (nla_put_le16(skb, RTA_PREFSRC, rt->rt_local_src) < 0)
+ goto errout;
+
+ if (rt->rt_daddr != rt->rt_gateway &&
+ nla_put_le16(skb, RTA_GATEWAY, rt->rt_gateway) < 0)
+ goto errout;
+
+ if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
+ goto errout;
+
+ expires = rt->dst.expires ? rt->dst.expires - jiffies : 0;
+ if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires,
+ rt->dst.error) < 0)
+ goto errout;
+
+ if (dn_is_input_route(rt) &&
+ nla_put_u32(skb, RTA_IIF, rt->fld.flowidn_iif) < 0)
+ goto errout;
-nlmsg_failure:
-rtattr_failure:
- skb_trim(skb, b - skb->data);
- return -1;
+ return nlmsg_end(skb, nlh);
+
+errout:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
+const struct nla_policy rtm_dn_policy[RTA_MAX + 1] = {
+ [RTA_DST] = { .type = NLA_U16 },
+ [RTA_SRC] = { .type = NLA_U16 },
+ [RTA_IIF] = { .type = NLA_U32 },
+ [RTA_OIF] = { .type = NLA_U32 },
+ [RTA_GATEWAY] = { .type = NLA_U16 },
+ [RTA_PRIORITY] = { .type = NLA_U32 },
+ [RTA_PREFSRC] = { .type = NLA_U16 },
+ [RTA_METRICS] = { .type = NLA_NESTED },
+ [RTA_MULTIPATH] = { .type = NLA_NESTED },
+ [RTA_TABLE] = { .type = NLA_U32 },
+ [RTA_MARK] = { .type = NLA_U32 },
+};
+
/*
* This is called by both endnodes and routers now.
*/
-int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
+static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
{
- struct rtattr **rta = arg;
- struct rtmsg *rtm = NLMSG_DATA(nlh);
+ struct net *net = sock_net(in_skb->sk);
+ struct rtmsg *rtm = nlmsg_data(nlh);
struct dn_route *rt = NULL;
struct dn_skb_cb *cb;
int err;
struct sk_buff *skb;
- struct flowi fl;
+ struct flowidn fld;
+ struct nlattr *tb[RTA_MAX+1];
+
+ if (!net_eq(net, &init_net))
+ return -EINVAL;
- memset(&fl, 0, sizeof(fl));
- fl.proto = DNPROTO_NSP;
+ err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_dn_policy);
+ if (err < 0)
+ return err;
- skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+ memset(&fld, 0, sizeof(fld));
+ fld.flowidn_proto = DNPROTO_NSP;
+
+ skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (skb == NULL)
return -ENOBUFS;
- skb->mac.raw = skb->data;
+ skb_reset_mac_header(skb);
cb = DN_SKB_CB(skb);
- if (rta[RTA_SRC-1])
- memcpy(&fl.fld_src, RTA_DATA(rta[RTA_SRC-1]), 2);
- if (rta[RTA_DST-1])
- memcpy(&fl.fld_dst, RTA_DATA(rta[RTA_DST-1]), 2);
- if (rta[RTA_IIF-1])
- memcpy(&fl.iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int));
+ if (tb[RTA_SRC])
+ fld.saddr = nla_get_le16(tb[RTA_SRC]);
+
+ if (tb[RTA_DST])
+ fld.daddr = nla_get_le16(tb[RTA_DST]);
+
+ if (tb[RTA_IIF])
+ fld.flowidn_iif = nla_get_u32(tb[RTA_IIF]);
- if (fl.iif) {
+ if (fld.flowidn_iif) {
struct net_device *dev;
- if ((dev = dev_get_by_index(fl.iif)) == NULL) {
+ dev = __dev_get_by_index(&init_net, fld.flowidn_iif);
+ if (!dev || !dev->dn_ptr) {
kfree_skb(skb);
return -ENODEV;
}
- if (!dev->dn_ptr) {
- dev_put(dev);
- kfree_skb(skb);
- return -ENODEV;
- }
- skb->protocol = __constant_htons(ETH_P_DNA_RT);
+ skb->protocol = htons(ETH_P_DNA_RT);
skb->dev = dev;
- cb->src = fl.fld_src;
- cb->dst = fl.fld_dst;
+ cb->src = fld.saddr;
+ cb->dst = fld.daddr;
local_bh_disable();
err = dn_route_input(skb);
local_bh_enable();
memset(cb, 0, sizeof(struct dn_skb_cb));
- rt = (struct dn_route *)skb->dst;
- if (!err && -rt->u.dst.error)
- err = rt->u.dst.error;
+ rt = (struct dn_route *)skb_dst(skb);
+ if (!err && -rt->dst.error)
+ err = rt->dst.error;
} else {
- int oif = 0;
- if (rta[RTA_OIF - 1])
- memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int));
- fl.oif = oif;
- err = dn_route_output_key((struct dst_entry **)&rt, &fl, 0);
+ if (tb[RTA_OIF])
+ fld.flowidn_oif = nla_get_u32(tb[RTA_OIF]);
+
+ err = dn_route_output_key((struct dst_entry **)&rt, &fld, 0);
}
- if (skb->dev)
- dev_put(skb->dev);
skb->dev = NULL;
if (err)
goto out_free;
- skb->dst = &rt->u.dst;
+ skb_dst_set(skb, &rt->dst);
if (rtm->rtm_flags & RTM_F_NOTIFY)
rt->rt_flags |= RTCF_NOTIFY;
- NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
-
- err = dn_rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0, 0);
+ err = dn_rt_fill_info(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, RTM_NEWROUTE, 0, 0);
if (err == 0)
goto out_free;
@@ -1604,9 +1717,7 @@ int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
goto out_free;
}
- err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
-
- return err;
+ return rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).portid);
out_free:
kfree_skb(skb);
@@ -1619,13 +1730,20 @@ out_free:
*/
int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
+ struct net *net = sock_net(skb->sk);
struct dn_route *rt;
int h, s_h;
int idx, s_idx;
+ struct rtmsg *rtm;
- if (NLMSG_PAYLOAD(cb->nlh, 0) < sizeof(struct rtmsg))
+ if (!net_eq(net, &init_net))
+ return 0;
+
+ if (nlmsg_len(cb->nlh) < sizeof(struct rtmsg))
return -EINVAL;
- if (!(((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED))
+
+ rtm = nlmsg_data(cb->nlh);
+ if (!(rtm->rtm_flags & RTM_F_CLONED))
return 0;
s_h = cb->args[0];
@@ -1636,20 +1754,20 @@ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb)
if (h > s_h)
s_idx = 0;
rcu_read_lock_bh();
- for(rt = rcu_dereference(dn_rt_hash_table[h].chain), idx = 0;
+ for(rt = rcu_dereference_bh(dn_rt_hash_table[h].chain), idx = 0;
rt;
- rt = rcu_dereference(rt->u.rt_next), idx++) {
+ rt = rcu_dereference_bh(rt->dst.dn_next), idx++) {
if (idx < s_idx)
continue;
- skb->dst = dst_clone(&rt->u.dst);
- if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq, RTM_NEWROUTE,
+ skb_dst_set(skb, dst_clone(&rt->dst));
+ if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, RTM_NEWROUTE,
1, NLM_F_MULTI) <= 0) {
- dst_release(xchg(&skb->dst, NULL));
+ skb_dst_drop(skb);
rcu_read_unlock_bh();
goto done;
}
- dst_release(xchg(&skb->dst, NULL));
+ skb_dst_drop(skb);
}
rcu_read_unlock_bh();
}
@@ -1672,7 +1790,7 @@ static struct dn_route *dn_rt_cache_get_first(struct seq_file *seq)
for(s->bucket = dn_rt_hash_mask; s->bucket >= 0; --s->bucket) {
rcu_read_lock_bh();
- rt = dn_rt_hash_table[s->bucket].chain;
+ rt = rcu_dereference_bh(dn_rt_hash_table[s->bucket].chain);
if (rt)
break;
rcu_read_unlock_bh();
@@ -1682,15 +1800,15 @@ static struct dn_route *dn_rt_cache_get_first(struct seq_file *seq)
static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_route *rt)
{
- struct dn_rt_cache_iter_state *s = rcu_dereference(seq->private);
+ struct dn_rt_cache_iter_state *s = seq->private;
- rt = rt->u.rt_next;
- while(!rt) {
+ rt = rcu_dereference_bh(rt->dst.dn_next);
+ while (!rt) {
rcu_read_unlock_bh();
if (--s->bucket < 0)
break;
rcu_read_lock_bh();
- rt = dn_rt_hash_table[s->bucket].chain;
+ rt = rcu_dereference_bh(dn_rt_hash_table[s->bucket].chain);
}
return rt;
}
@@ -1725,16 +1843,15 @@ static int dn_rt_cache_seq_show(struct seq_file *seq, void *v)
char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];
seq_printf(seq, "%-8s %-7s %-7s %04d %04d %04d\n",
- rt->u.dst.dev ? rt->u.dst.dev->name : "*",
- dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1),
- dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2),
- atomic_read(&rt->u.dst.__refcnt),
- rt->u.dst.__use,
- (int) dst_metric(&rt->u.dst, RTAX_RTT));
+ rt->dst.dev ? rt->dst.dev->name : "*",
+ dn_addr2asc(le16_to_cpu(rt->rt_daddr), buf1),
+ dn_addr2asc(le16_to_cpu(rt->rt_saddr), buf2),
+ atomic_read(&rt->dst.__refcnt),
+ rt->dst.__use, 0);
return 0;
-}
+}
-static struct seq_operations dn_rt_cache_seq_ops = {
+static const struct seq_operations dn_rt_cache_seq_ops = {
.start = dn_rt_cache_seq_start,
.next = dn_rt_cache_seq_next,
.stop = dn_rt_cache_seq_stop,
@@ -1743,26 +1860,11 @@ static struct seq_operations dn_rt_cache_seq_ops = {
static int dn_rt_cache_seq_open(struct inode *inode, struct file *file)
{
- struct seq_file *seq;
- int rc = -ENOMEM;
- struct dn_rt_cache_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
-
- if (!s)
- goto out;
- rc = seq_open(file, &dn_rt_cache_seq_ops);
- if (rc)
- goto out_kfree;
- seq = file->private_data;
- seq->private = s;
- memset(s, 0, sizeof(*s));
-out:
- return rc;
-out_kfree:
- kfree(s);
- goto out;
+ return seq_open_private(file, &dn_rt_cache_seq_ops,
+ sizeof(struct dn_rt_cache_iter_state));
}
-static struct file_operations dn_rt_cache_seq_fops = {
+static const struct file_operations dn_rt_cache_seq_fops = {
.owner = THIS_MODULE,
.open = dn_rt_cache_seq_open,
.read = seq_read,
@@ -1776,58 +1878,62 @@ void __init dn_route_init(void)
{
int i, goal, order;
- dn_dst_ops.kmem_cachep = kmem_cache_create("dn_dst_cache",
- sizeof(struct dn_route),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
-
- if (!dn_dst_ops.kmem_cachep)
- panic("DECnet: Failed to allocate dn_dst_cache\n");
-
- init_timer(&dn_route_timer);
- dn_route_timer.function = dn_dst_check_expire;
+ dn_dst_ops.kmem_cachep =
+ kmem_cache_create("dn_dst_cache", sizeof(struct dn_route), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+ dst_entries_init(&dn_dst_ops);
+ setup_timer(&dn_route_timer, dn_dst_check_expire, 0);
dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ;
add_timer(&dn_route_timer);
- goal = num_physpages >> (26 - PAGE_SHIFT);
+ goal = totalram_pages >> (26 - PAGE_SHIFT);
for(order = 0; (1UL << order) < goal; order++)
/* NOTHING */;
- /*
- * Only want 1024 entries max, since the table is very, very unlikely
- * to be larger than that.
- */
- while(order && ((((1UL << order) * PAGE_SIZE) /
- sizeof(struct dn_rt_hash_bucket)) >= 2048))
- order--;
-
- do {
- dn_rt_hash_mask = (1UL << order) * PAGE_SIZE /
- sizeof(struct dn_rt_hash_bucket);
- while(dn_rt_hash_mask & (dn_rt_hash_mask - 1))
- dn_rt_hash_mask--;
- dn_rt_hash_table = (struct dn_rt_hash_bucket *)
- __get_free_pages(GFP_ATOMIC, order);
- } while (dn_rt_hash_table == NULL && --order > 0);
+ /*
+ * Only want 1024 entries max, since the table is very, very unlikely
+ * to be larger than that.
+ */
+ while(order && ((((1UL << order) * PAGE_SIZE) /
+ sizeof(struct dn_rt_hash_bucket)) >= 2048))
+ order--;
+
+ do {
+ dn_rt_hash_mask = (1UL << order) * PAGE_SIZE /
+ sizeof(struct dn_rt_hash_bucket);
+ while(dn_rt_hash_mask & (dn_rt_hash_mask - 1))
+ dn_rt_hash_mask--;
+ dn_rt_hash_table = (struct dn_rt_hash_bucket *)
+ __get_free_pages(GFP_ATOMIC, order);
+ } while (dn_rt_hash_table == NULL && --order > 0);
if (!dn_rt_hash_table)
- panic("Failed to allocate DECnet route cache hash table\n");
+ panic("Failed to allocate DECnet route cache hash table\n");
- printk(KERN_INFO
- "DECnet: Routing cache hash table of %u buckets, %ldKbytes\n",
- dn_rt_hash_mask,
+ printk(KERN_INFO
+ "DECnet: Routing cache hash table of %u buckets, %ldKbytes\n",
+ dn_rt_hash_mask,
(long)(dn_rt_hash_mask*sizeof(struct dn_rt_hash_bucket))/1024);
dn_rt_hash_mask--;
- for(i = 0; i <= dn_rt_hash_mask; i++) {
- spin_lock_init(&dn_rt_hash_table[i].lock);
- dn_rt_hash_table[i].chain = NULL;
- }
+ for(i = 0; i <= dn_rt_hash_mask; i++) {
+ spin_lock_init(&dn_rt_hash_table[i].lock);
+ dn_rt_hash_table[i].chain = NULL;
+ }
- dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1);
+ dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1);
- proc_net_fops_create("decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops);
+ proc_create("decnet_cache", S_IRUGO, init_net.proc_net,
+ &dn_rt_cache_seq_fops);
+
+#ifdef CONFIG_DECNET_ROUTER
+ rtnl_register(PF_DECnet, RTM_GETROUTE, dn_cache_getroute,
+ dn_fib_dump, NULL);
+#else
+ rtnl_register(PF_DECnet, RTM_GETROUTE, dn_cache_getroute,
+ dn_cache_dump, NULL);
+#endif
}
void __exit dn_route_cleanup(void)
@@ -1835,6 +1941,7 @@ void __exit dn_route_cleanup(void)
del_timer(&dn_route_timer);
dn_run_flush(0);
- proc_net_remove("decnet_cache");
+ remove_proc_entry("decnet_cache", init_net.proc_net);
+ dst_entries_destroy(&dn_dst_ops);
}
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c
index 1060de70bc0..faf7cc3483f 100644
--- a/net/decnet/dn_rules.c
+++ b/net/decnet/dn_rules.c
@@ -11,265 +11,183 @@
*
*
* Changes:
+ * Steve Whitehouse <steve@chygwyn.com>
+ * Updated for Thomas Graf's generic rules
*
*/
-#include <linux/config.h>
-#include <linux/string.h>
#include <linux/net.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
#include <linux/init.h>
-#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
-#include <linux/proc_fs.h>
#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 <linux/list.h>
+#include <linux/rcupdate.h>
+#include <linux/export.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/flow.h>
+#include <net/fib_rules.h>
#include <net/dn.h>
#include <net/dn_fib.h>
#include <net/dn_neigh.h>
#include <net/dn_dev.h>
+#include <net/dn_route.h>
+
+static struct fib_rules_ops *dn_fib_rules_ops;
struct dn_fib_rule
{
- struct dn_fib_rule *r_next;
- atomic_t r_clntref;
- u32 r_preference;
- unsigned char r_table;
- unsigned char r_action;
- unsigned char r_dst_len;
- unsigned char r_src_len;
- dn_address r_src;
- 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;
-#endif
- int r_ifindex;
- char r_ifname[IFNAMSIZ];
- int r_dead;
+ struct fib_rule common;
+ unsigned char dst_len;
+ unsigned char src_len;
+ __le16 src;
+ __le16 srcmask;
+ __le16 dst;
+ __le16 dstmask;
+ __le16 srcmap;
+ u8 flags;
};
-static struct dn_fib_rule default_rule = {
- .r_clntref = ATOMIC_INIT(2),
- .r_preference = 0x7fff,
- .r_table = RT_TABLE_MAIN,
- .r_action = RTN_UNICAST
-};
-static struct dn_fib_rule *dn_fib_rules = &default_rule;
-static DEFINE_RWLOCK(dn_fib_rules_lock);
+int dn_fib_lookup(struct flowidn *flp, struct dn_fib_res *res)
+{
+ struct fib_lookup_arg arg = {
+ .result = res,
+ };
+ int err;
+
+ err = fib_rules_lookup(dn_fib_rules_ops,
+ flowidn_to_flowi(flp), 0, &arg);
+ res->r = arg.rule;
+ return err;
+}
-int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dn_fib_rule_action(struct fib_rule *rule, struct flowi *flp,
+ int flags, struct fib_lookup_arg *arg)
{
- struct rtattr **rta = arg;
- struct rtmsg *rtm = NLMSG_DATA(nlh);
- struct dn_fib_rule *r, **rp;
- int err = -ESRCH;
-
- for(rp=&dn_fib_rules; (r=*rp) != NULL; rp = &r->r_next) {
- if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 2) == 0) &&
- rtm->rtm_src_len == r->r_src_len &&
- rtm->rtm_dst_len == r->r_dst_len &&
- (!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 2) == 0) &&
-#ifdef CONFIG_DECNET_ROUTE_FWMARK
- (!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) &&
-#endif
- (!rtm->rtm_type || rtm->rtm_type == r->r_action) &&
- (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) &&
- (!rta[RTA_IIF-1] || rtattr_strcmp(rta[RTA_IIF-1], r->r_ifname) == 0) &&
- (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) {
-
- err = -EPERM;
- if (r == &default_rule)
- break;
-
- write_lock_bh(&dn_fib_rules_lock);
- *rp = r->r_next;
- r->r_dead = 1;
- write_unlock_bh(&dn_fib_rules_lock);
- dn_fib_rule_put(r);
- err = 0;
- break;
- }
+ struct flowidn *fld = &flp->u.dn;
+ int err = -EAGAIN;
+ struct dn_fib_table *tbl;
+
+ switch(rule->action) {
+ case FR_ACT_TO_TBL:
+ break;
+
+ case FR_ACT_UNREACHABLE:
+ err = -ENETUNREACH;
+ goto errout;
+
+ case FR_ACT_PROHIBIT:
+ err = -EACCES;
+ goto errout;
+
+ case FR_ACT_BLACKHOLE:
+ default:
+ err = -EINVAL;
+ goto errout;
}
+ tbl = dn_fib_get_table(rule->table, 0);
+ if (tbl == NULL)
+ goto errout;
+
+ err = tbl->lookup(tbl, fld, (struct dn_fib_res *)arg->result);
+ if (err > 0)
+ err = -EAGAIN;
+errout:
return err;
}
-void dn_fib_rule_put(struct dn_fib_rule *r)
+static const struct nla_policy dn_fib_rule_policy[FRA_MAX+1] = {
+ FRA_GENERIC_POLICY,
+};
+
+static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
{
- if (atomic_dec_and_test(&r->r_clntref)) {
- if (r->r_dead)
- kfree(r);
- else
- printk(KERN_DEBUG "Attempt to free alive dn_fib_rule\n");
- }
-}
+ struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
+ struct flowidn *fld = &fl->u.dn;
+ __le16 daddr = fld->daddr;
+ __le16 saddr = fld->saddr;
+
+ if (((saddr ^ r->src) & r->srcmask) ||
+ ((daddr ^ r->dst) & r->dstmask))
+ return 0;
+ return 1;
+}
-int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
+ struct fib_rule_hdr *frh,
+ struct nlattr **tb)
{
- struct rtattr **rta = arg;
- struct rtmsg *rtm = NLMSG_DATA(nlh);
- struct dn_fib_rule *r, *new_r, **rp;
- unsigned char table_id;
-
- if (rtm->rtm_src_len > 16 || rtm->rtm_dst_len > 16)
- return -EINVAL;
-
- if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ)
- return -EINVAL;
-
- if (rtm->rtm_type == RTN_NAT)
- return -EINVAL;
-
- table_id = rtm->rtm_table;
- if (table_id == RT_TABLE_UNSPEC) {
- struct dn_fib_table *tb;
- if (rtm->rtm_type == RTN_UNICAST) {
- if ((tb = dn_fib_empty_table()) == NULL)
- return -ENOBUFS;
- table_id = tb->n;
- }
- }
+ int err = -EINVAL;
+ struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
- new_r = kmalloc(sizeof(*new_r), GFP_KERNEL);
- if (!new_r)
- return -ENOMEM;
- memset(new_r, 0, sizeof(*new_r));
- if (rta[RTA_SRC-1])
- 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);
- new_r->r_dstmask = dnet_make_mask(rtm->rtm_dst_len);
-#ifdef CONFIG_DECNET_ROUTE_FWMARK
- if (rta[RTA_PROTOINFO-1])
- memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4);
-#endif
- new_r->r_action = rtm->rtm_type;
- new_r->r_flags = rtm->rtm_flags;
- if (rta[RTA_PRIORITY-1])
- memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4);
- new_r->r_table = table_id;
- if (rta[RTA_IIF-1]) {
- struct net_device *dev;
- rtattr_strlcpy(new_r->r_ifname, rta[RTA_IIF-1], IFNAMSIZ);
- new_r->r_ifindex = -1;
- dev = dev_get_by_name(new_r->r_ifname);
- if (dev) {
- new_r->r_ifindex = dev->ifindex;
- dev_put(dev);
- }
- }
+ if (frh->tos)
+ goto errout;
- rp = &dn_fib_rules;
- if (!new_r->r_preference) {
- r = dn_fib_rules;
- if (r && (r = r->r_next) != NULL) {
- rp = &dn_fib_rules->r_next;
- if (r->r_preference)
- new_r->r_preference = r->r_preference - 1;
+ if (rule->table == RT_TABLE_UNSPEC) {
+ if (rule->action == FR_ACT_TO_TBL) {
+ struct dn_fib_table *table;
+
+ table = dn_fib_empty_table();
+ if (table == NULL) {
+ err = -ENOBUFS;
+ goto errout;
+ }
+
+ rule->table = table->n;
}
}
- while((r=*rp) != NULL) {
- if (r->r_preference > new_r->r_preference)
- break;
- rp = &r->r_next;
- }
+ if (frh->src_len)
+ r->src = nla_get_le16(tb[FRA_SRC]);
- new_r->r_next = r;
- atomic_inc(&new_r->r_clntref);
- write_lock_bh(&dn_fib_rules_lock);
- *rp = new_r;
- write_unlock_bh(&dn_fib_rules_lock);
- return 0;
-}
+ if (frh->dst_len)
+ r->dst = nla_get_le16(tb[FRA_DST]);
+ r->src_len = frh->src_len;
+ r->srcmask = dnet_make_mask(r->src_len);
+ r->dst_len = frh->dst_len;
+ r->dstmask = dnet_make_mask(r->dst_len);
+ err = 0;
+errout:
+ return err;
+}
-int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res)
+static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
+ struct nlattr **tb)
{
- struct dn_fib_rule *r, *policy;
- struct dn_fib_table *tb;
- dn_address saddr = flp->fld_src;
- dn_address daddr = flp->fld_dst;
- int err;
+ struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
- read_lock(&dn_fib_rules_lock);
- for(r = dn_fib_rules; r; r = r->r_next) {
- 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 != flp->fld_fwmark) ||
-#endif
- (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:
- read_unlock(&dn_fib_rules_lock);
- return -ENETUNREACH;
- default:
- case RTN_BLACKHOLE:
- read_unlock(&dn_fib_rules_lock);
- return -EINVAL;
- case RTN_PROHIBIT:
- read_unlock(&dn_fib_rules_lock);
- return -EACCES;
- }
+ if (frh->src_len && (r->src_len != frh->src_len))
+ return 0;
- if ((tb = dn_fib_get_table(r->r_table, 0)) == NULL)
- continue;
- err = tb->lookup(tb, flp, res);
- if (err == 0) {
- res->r = policy;
- if (policy)
- atomic_inc(&policy->r_clntref);
- read_unlock(&dn_fib_rules_lock);
- return 0;
- }
- if (err < 0 && err != -EAGAIN) {
- read_unlock(&dn_fib_rules_lock);
- return err;
- }
- }
+ if (frh->dst_len && (r->dst_len != frh->dst_len))
+ return 0;
+
+ if (frh->src_len && (r->src != nla_get_le16(tb[FRA_SRC])))
+ return 0;
+
+ if (frh->dst_len && (r->dst != nla_get_le16(tb[FRA_DST])))
+ return 0;
- read_unlock(&dn_fib_rules_lock);
- return -ESRCH;
+ return 1;
}
-unsigned dnet_addr_type(__u16 addr)
+unsigned int dnet_addr_type(__le16 addr)
{
- struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } };
+ struct flowidn fld = { .daddr = addr };
struct dn_fib_res res;
- unsigned ret = RTN_UNICAST;
- struct dn_fib_table *tb = dn_fib_tables[RT_TABLE_LOCAL];
+ unsigned int ret = RTN_UNICAST;
+ struct dn_fib_table *tb = dn_fib_get_table(RT_TABLE_LOCAL, 0);
res.r = NULL;
if (tb) {
- if (!tb->lookup(tb, &fl, &res)) {
+ if (!tb->lookup(tb, &fld, &res)) {
ret = res.type;
dn_fib_res_put(&res);
}
@@ -277,141 +195,61 @@ unsigned dnet_addr_type(__u16 addr)
return ret;
}
-__u16 dn_fib_rules_policy(__u16 saddr, struct dn_fib_res *res, unsigned *flags)
+static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
+ struct fib_rule_hdr *frh)
{
- struct dn_fib_rule *r = res->r;
+ struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
- 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;
-}
+ frh->dst_len = r->dst_len;
+ frh->src_len = r->src_len;
+ frh->tos = 0;
-static void dn_fib_rules_detach(struct net_device *dev)
-{
- struct dn_fib_rule *r;
-
- for(r = dn_fib_rules; r; r = r->r_next) {
- if (r->r_ifindex == dev->ifindex) {
- write_lock_bh(&dn_fib_rules_lock);
- r->r_ifindex = -1;
- write_unlock_bh(&dn_fib_rules_lock);
- }
- }
-}
-
-static void dn_fib_rules_attach(struct net_device *dev)
-{
- struct dn_fib_rule *r;
+ if ((r->dst_len &&
+ nla_put_le16(skb, FRA_DST, r->dst)) ||
+ (r->src_len &&
+ nla_put_le16(skb, FRA_SRC, r->src)))
+ goto nla_put_failure;
+ return 0;
- for(r = dn_fib_rules; r; r = r->r_next) {
- if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) {
- write_lock_bh(&dn_fib_rules_lock);
- r->r_ifindex = dev->ifindex;
- write_unlock_bh(&dn_fib_rules_lock);
- }
- }
+nla_put_failure:
+ return -ENOBUFS;
}
-static int dn_fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr)
+static void dn_fib_rule_flush_cache(struct fib_rules_ops *ops)
{
- struct net_device *dev = ptr;
-
- switch(event) {
- case NETDEV_UNREGISTER:
- dn_fib_rules_detach(dev);
- dn_fib_sync_down(0, dev, 1);
- case NETDEV_REGISTER:
- dn_fib_rules_attach(dev);
- dn_fib_sync_up(dev);
- }
-
- return NOTIFY_DONE;
+ dn_rt_cache_flush(-1);
}
-
-static struct notifier_block dn_fib_rules_notifier = {
- .notifier_call = dn_fib_rules_event,
+static const struct fib_rules_ops __net_initconst dn_fib_rules_ops_template = {
+ .family = AF_DECnet,
+ .rule_size = sizeof(struct dn_fib_rule),
+ .addr_size = sizeof(u16),
+ .action = dn_fib_rule_action,
+ .match = dn_fib_rule_match,
+ .configure = dn_fib_rule_configure,
+ .compare = dn_fib_rule_compare,
+ .fill = dn_fib_rule_fill,
+ .default_pref = fib_default_rule_pref,
+ .flush_cache = dn_fib_rule_flush_cache,
+ .nlgroup = RTNLGRP_DECnet_RULE,
+ .policy = dn_fib_rule_policy,
+ .owner = THIS_MODULE,
+ .fro_net = &init_net,
};
-static int dn_fib_fill_rule(struct sk_buff *skb, struct dn_fib_rule *r,
- struct netlink_callback *cb, unsigned int flags)
-{
- struct rtmsg *rtm;
- struct nlmsghdr *nlh;
- unsigned char *b = skb->tail;
-
-
- nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWRULE, sizeof(*rtm), flags);
- rtm = NLMSG_DATA(nlh);
- rtm->rtm_family = AF_DECnet;
- rtm->rtm_dst_len = r->r_dst_len;
- rtm->rtm_src_len = r->r_src_len;
- rtm->rtm_tos = 0;
-#ifdef CONFIG_DECNET_ROUTE_FWMARK
- if (r->r_fwmark)
- RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark);
-#endif
- rtm->rtm_table = r->r_table;
- rtm->rtm_protocol = 0;
- rtm->rtm_scope = 0;
- rtm->rtm_type = r->r_action;
- rtm->rtm_flags = r->r_flags;
-
- if (r->r_dst_len)
- RTA_PUT(skb, RTA_DST, 2, &r->r_dst);
- if (r->r_src_len)
- RTA_PUT(skb, RTA_SRC, 2, &r->r_src);
- if (r->r_ifname[0])
- 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;
-
-nlmsg_failure:
-rtattr_failure:
- skb_trim(skb, b - skb->data);
- return -1;
-}
-
-int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
-{
- int idx;
- int s_idx = cb->args[0];
- struct dn_fib_rule *r;
-
- read_lock(&dn_fib_rules_lock);
- for(r = dn_fib_rules, idx = 0; r; r = r->r_next, idx++) {
- if (idx < s_idx)
- continue;
- if (dn_fib_fill_rule(skb, r, cb, NLM_F_MULTI) < 0)
- break;
- }
- read_unlock(&dn_fib_rules_lock);
- cb->args[0] = idx;
-
- return skb->len;
-}
-
void __init dn_fib_rules_init(void)
{
- register_netdevice_notifier(&dn_fib_rules_notifier);
+ dn_fib_rules_ops =
+ fib_rules_register(&dn_fib_rules_ops_template, &init_net);
+ BUG_ON(IS_ERR(dn_fib_rules_ops));
+ BUG_ON(fib_default_rule_add(dn_fib_rules_ops, 0x7fff,
+ RT_TABLE_MAIN, 0));
}
void __exit dn_fib_rules_cleanup(void)
{
- unregister_netdevice_notifier(&dn_fib_rules_notifier);
+ fib_rules_unregister(dn_fib_rules_ops);
+ rcu_barrier();
}
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index 6f8b5658cb4..86e3807052e 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -12,25 +12,26 @@
* Changes:
*
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/net.h>
#include <linux/socket.h>
+#include <linux/slab.h>
#include <linux/sockios.h>
#include <linux/init.h>
#include <linux/skbuff.h>
-#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/proc_fs.h>
#include <linux/netdevice.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <asm/uaccess.h>
#include <linux/route.h> /* RTF_xxx */
#include <net/neighbour.h>
+#include <net/netlink.h>
#include <net/dst.h>
#include <net/flow.h>
+#include <net/fib_rules.h>
#include <net/dn.h>
#include <net/dn_route.h>
#include <net/dn_fib.h>
@@ -46,7 +47,7 @@ struct dn_zone
u32 dz_hashmask;
#define DZ_HASHMASK(dz) ((dz)->dz_hashmask)
int dz_order;
- u16 dz_mask;
+ __le16 dz_mask;
#define DZ_MASK(dz) ((dz)->dz_mask)
};
@@ -57,10 +58,9 @@ struct dn_hash
};
#define dz_key_0(key) ((key).datum = 0)
-#define dz_prefix(key,dz) ((key).datum)
#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\
- for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
+ for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
#define endfor_nexthops(fi) }
@@ -75,23 +75,23 @@ for( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
#define RT_TABLE_MIN 1
-
+#define DN_FIB_TABLE_HASHSZ 256
+static struct hlist_head dn_fib_table_hash[DN_FIB_TABLE_HASHSZ];
static DEFINE_RWLOCK(dn_fib_tables_lock);
-struct dn_fib_table *dn_fib_tables[RT_TABLE_MAX + 1];
-static kmem_cache_t *dn_hash_kmem __read_mostly;
+static struct kmem_cache *dn_hash_kmem __read_mostly;
static int dn_fib_hash_zombies;
static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz)
{
- u16 h = ntohs(key.datum)>>(16 - dz->dz_order);
+ u16 h = le16_to_cpu(key.datum)>>(16 - dz->dz_order);
h ^= (h >> 10);
h ^= (h >> 6);
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(__le16 dst, struct dn_zone *dz)
{
dn_fib_key_t k;
k.datum = dst & DZ_MASK(dz);
@@ -122,11 +122,11 @@ static inline void dn_rebuild_zone(struct dn_zone *dz,
struct dn_fib_node **old_ht,
int old_divisor)
{
- int i;
struct dn_fib_node *f, **fp, *next;
+ int i;
for(i = 0; i < old_divisor; i++) {
- for(f = old_ht[i]; f; f = f->fn_next) {
+ for(f = old_ht[i]; f; f = next) {
next = f->fn_next;
for(fp = dn_chain_p(f->fn_key, dz);
*fp && dn_key_leq((*fp)->fn_key, f->fn_key);
@@ -146,25 +146,24 @@ static void dn_rehash_zone(struct dn_zone *dz)
old_divisor = dz->dz_divisor;
- switch(old_divisor) {
- case 16:
- new_divisor = 256;
- new_hashmask = 0xFF;
- break;
- default:
- printk(KERN_DEBUG "DECnet: dn_rehash_zone: BUG! %d\n", old_divisor);
- case 256:
- new_divisor = 1024;
- new_hashmask = 0x3FF;
- break;
+ switch (old_divisor) {
+ case 16:
+ new_divisor = 256;
+ new_hashmask = 0xFF;
+ break;
+ default:
+ printk(KERN_DEBUG "DECnet: dn_rehash_zone: BUG! %d\n",
+ old_divisor);
+ case 256:
+ new_divisor = 1024;
+ new_hashmask = 0x3FF;
+ break;
}
- ht = kmalloc(new_divisor*sizeof(struct dn_fib_node*), GFP_KERNEL);
-
+ ht = kcalloc(new_divisor, sizeof(struct dn_fib_node*), GFP_KERNEL);
if (ht == NULL)
return;
- memset(ht, 0, new_divisor*sizeof(struct dn_fib_node *));
write_lock_bh(&dn_fib_tables_lock);
old_ht = dz->dz_hash;
dz->dz_hash = ht;
@@ -185,11 +184,10 @@ static void dn_free_node(struct dn_fib_node *f)
static struct dn_zone *dn_new_zone(struct dn_hash *table, int z)
{
int i;
- struct dn_zone *dz = kmalloc(sizeof(struct dn_zone), GFP_KERNEL);
+ struct dn_zone *dz = kzalloc(sizeof(struct dn_zone), GFP_KERNEL);
if (!dz)
return NULL;
- memset(dz, 0, sizeof(struct dn_zone));
if (z) {
dz->dz_divisor = 16;
dz->dz_hashmask = 0x0F;
@@ -198,14 +196,12 @@ static struct dn_zone *dn_new_zone(struct dn_hash *table, int z)
dz->dz_hashmask = 0;
}
- dz->dz_hash = kmalloc(dz->dz_divisor*sizeof(struct dn_fib_node *), GFP_KERNEL);
-
+ dz->dz_hash = kcalloc(dz->dz_divisor, sizeof(struct dn_fib_node *), GFP_KERNEL);
if (!dz->dz_hash) {
kfree(dz);
return NULL;
}
- memset(dz->dz_hash, 0, dz->dz_divisor*sizeof(struct dn_fib_node*));
dz->dz_order = z;
dz->dz_mask = dnet_make_mask(z);
@@ -227,37 +223,41 @@ static struct dn_zone *dn_new_zone(struct dn_hash *table, int z)
}
-static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern_rta *rta, struct dn_fib_info *fi)
+static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct nlattr *attrs[], struct dn_fib_info *fi)
{
struct rtnexthop *nhp;
int nhlen;
- if (rta->rta_priority && *rta->rta_priority != fi->fib_priority)
+ if (attrs[RTA_PRIORITY] &&
+ nla_get_u32(attrs[RTA_PRIORITY]) != fi->fib_priority)
return 1;
- if (rta->rta_oif || rta->rta_gw) {
- if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) &&
- (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 2) == 0))
+ if (attrs[RTA_OIF] || attrs[RTA_GATEWAY]) {
+ if ((!attrs[RTA_OIF] || nla_get_u32(attrs[RTA_OIF]) == fi->fib_nh->nh_oif) &&
+ (!attrs[RTA_GATEWAY] || nla_get_le16(attrs[RTA_GATEWAY]) != fi->fib_nh->nh_gw))
return 0;
return 1;
}
- if (rta->rta_mp == NULL)
+ if (!attrs[RTA_MULTIPATH])
return 0;
- nhp = RTA_DATA(rta->rta_mp);
- nhlen = RTA_PAYLOAD(rta->rta_mp);
+ nhp = nla_data(attrs[RTA_MULTIPATH]);
+ nhlen = nla_len(attrs[RTA_MULTIPATH]);
for_nexthops(fi) {
int attrlen = nhlen - sizeof(struct rtnexthop);
- dn_address gw;
+ __le16 gw;
if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
return -EINVAL;
if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif)
return 1;
if (attrlen) {
- gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
+ struct nlattr *gw_attr;
+
+ gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY);
+ gw = gw_attr ? nla_get_le16(gw_attr) : 0;
if (gw && gw != nh->nh_gw)
return 1;
@@ -268,96 +268,139 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern
return 0;
}
-static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
- u8 tb_id, u8 type, u8 scope, void *dst, int dst_len,
- struct dn_fib_info *fi, unsigned int flags)
+static inline size_t dn_fib_nlmsg_size(struct dn_fib_info *fi)
{
- struct rtmsg *rtm;
- struct nlmsghdr *nlh;
- unsigned char *b = skb->tail;
-
- nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags);
- rtm = NLMSG_DATA(nlh);
- rtm->rtm_family = AF_DECnet;
- rtm->rtm_dst_len = dst_len;
- rtm->rtm_src_len = 0;
- rtm->rtm_tos = 0;
- rtm->rtm_table = tb_id;
- rtm->rtm_flags = fi->fib_flags;
- rtm->rtm_scope = scope;
+ size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg))
+ + nla_total_size(4) /* RTA_TABLE */
+ + nla_total_size(2) /* RTA_DST */
+ + nla_total_size(4); /* RTA_PRIORITY */
+
+ /* space for nested metrics */
+ payload += nla_total_size((RTAX_MAX * nla_total_size(4)));
+
+ if (fi->fib_nhs) {
+ /* Also handles the special case fib_nhs == 1 */
+
+ /* each nexthop is packed in an attribute */
+ size_t nhsize = nla_total_size(sizeof(struct rtnexthop));
+
+ /* may contain a gateway attribute */
+ nhsize += nla_total_size(4);
+
+ /* all nexthops are packed in a nested attribute */
+ payload += nla_total_size(fi->fib_nhs * nhsize);
+ }
+
+ return payload;
+}
+
+static int dn_fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
+ u32 tb_id, u8 type, u8 scope, void *dst, int dst_len,
+ struct dn_fib_info *fi, unsigned int flags)
+{
+ struct rtmsg *rtm;
+ struct nlmsghdr *nlh;
+
+ nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags);
+ if (!nlh)
+ return -EMSGSIZE;
+
+ rtm = nlmsg_data(nlh);
+ rtm->rtm_family = AF_DECnet;
+ rtm->rtm_dst_len = dst_len;
+ rtm->rtm_src_len = 0;
+ rtm->rtm_tos = 0;
+ rtm->rtm_table = tb_id;
+ rtm->rtm_flags = fi->fib_flags;
+ rtm->rtm_scope = scope;
rtm->rtm_type = type;
- if (rtm->rtm_dst_len)
- RTA_PUT(skb, RTA_DST, 2, dst);
- rtm->rtm_protocol = fi->fib_protocol;
- if (fi->fib_priority)
- RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority);
+ rtm->rtm_protocol = fi->fib_protocol;
+
+ if (nla_put_u32(skb, RTA_TABLE, tb_id) < 0)
+ goto errout;
+
+ if (rtm->rtm_dst_len &&
+ nla_put(skb, RTA_DST, 2, dst) < 0)
+ goto errout;
+
+ if (fi->fib_priority &&
+ nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority) < 0)
+ goto errout;
+
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);
- if (fi->fib_nh->nh_oif)
- RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif);
- }
- if (fi->fib_nhs > 1) {
- struct rtnexthop *nhp;
- struct rtattr *mp_head;
- if (skb_tailroom(skb) <= RTA_SPACE(0))
- goto rtattr_failure;
- mp_head = (struct rtattr *)skb_put(skb, RTA_SPACE(0));
-
- for_nexthops(fi) {
- if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
- goto rtattr_failure;
- nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
- nhp->rtnh_flags = nh->nh_flags & 0xFF;
- nhp->rtnh_hops = nh->nh_weight - 1;
- nhp->rtnh_ifindex = nh->nh_oif;
- if (nh->nh_gw)
- RTA_PUT(skb, RTA_GATEWAY, 2, &nh->nh_gw);
- nhp->rtnh_len = skb->tail - (unsigned char *)nhp;
- } endfor_nexthops(fi);
- mp_head->rta_type = RTA_MULTIPATH;
- mp_head->rta_len = skb->tail - (u8*)mp_head;
- }
-
- nlh->nlmsg_len = skb->tail - b;
- return skb->len;
-
-
-nlmsg_failure:
-rtattr_failure:
- skb_trim(skb, b - skb->data);
- return -1;
+ goto errout;
+
+ if (fi->fib_nhs == 1) {
+ if (fi->fib_nh->nh_gw &&
+ nla_put_le16(skb, RTA_GATEWAY, fi->fib_nh->nh_gw) < 0)
+ goto errout;
+
+ if (fi->fib_nh->nh_oif &&
+ nla_put_u32(skb, RTA_OIF, fi->fib_nh->nh_oif) < 0)
+ goto errout;
+ }
+
+ if (fi->fib_nhs > 1) {
+ struct rtnexthop *nhp;
+ struct nlattr *mp_head;
+
+ if (!(mp_head = nla_nest_start(skb, RTA_MULTIPATH)))
+ goto errout;
+
+ for_nexthops(fi) {
+ if (!(nhp = nla_reserve_nohdr(skb, sizeof(*nhp))))
+ goto errout;
+
+ nhp->rtnh_flags = nh->nh_flags & 0xFF;
+ nhp->rtnh_hops = nh->nh_weight - 1;
+ nhp->rtnh_ifindex = nh->nh_oif;
+
+ if (nh->nh_gw &&
+ nla_put_le16(skb, RTA_GATEWAY, nh->nh_gw) < 0)
+ goto errout;
+
+ nhp->rtnh_len = skb_tail_pointer(skb) - (unsigned char *)nhp;
+ } endfor_nexthops(fi);
+
+ nla_nest_end(skb, mp_head);
+ }
+
+ return nlmsg_end(skb, nlh);
+
+errout:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
-static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, int tb_id,
- struct nlmsghdr *nlh, struct netlink_skb_parms *req)
+static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
+ struct nlmsghdr *nlh, struct netlink_skb_parms *req)
{
- struct sk_buff *skb;
- u32 pid = req ? req->pid : 0;
- int size = NLMSG_SPACE(sizeof(struct rtmsg) + 256);
-
- skb = alloc_skb(size, GFP_KERNEL);
- if (!skb)
- return;
-
- if (dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id,
- f->fn_type, f->fn_scope, &f->fn_key, z,
- DN_FIB_INFO(f), 0) < 0) {
- kfree_skb(skb);
- return;
- }
- NETLINK_CB(skb).dst_group = RTNLGRP_DECnet_ROUTE;
- if (nlh->nlmsg_flags & NLM_F_ECHO)
- atomic_inc(&skb->users);
- netlink_broadcast(rtnl, skb, pid, RTNLGRP_DECnet_ROUTE, GFP_KERNEL);
- if (nlh->nlmsg_flags & NLM_F_ECHO)
- netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
+ struct sk_buff *skb;
+ u32 portid = req ? req->portid : 0;
+ int err = -ENOBUFS;
+
+ skb = nlmsg_new(dn_fib_nlmsg_size(DN_FIB_INFO(f)), GFP_KERNEL);
+ if (skb == NULL)
+ goto errout;
+
+ err = dn_fib_dump_info(skb, portid, nlh->nlmsg_seq, event, tb_id,
+ f->fn_type, f->fn_scope, &f->fn_key, z,
+ DN_FIB_INFO(f), 0);
+ if (err < 0) {
+ /* -EMSGSIZE implies BUG in dn_fib_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
+ rtnl_notify(skb, &init_net, portid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
+ return;
+errout:
+ if (err < 0)
+ rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_ROUTE, err);
}
-static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
+static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
struct netlink_callback *cb,
struct dn_fib_table *tb,
struct dn_zone *dz,
@@ -365,107 +408,147 @@ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
{
int i, s_i;
- s_i = cb->args[3];
+ s_i = cb->args[4];
for(i = 0; f; i++, f = f->fn_next) {
if (i < s_i)
continue;
if (f->fn_state & DN_S_ZOMBIE)
continue;
- if (dn_fib_dump_info(skb, NETLINK_CB(cb->skb).pid,
+ if (dn_fib_dump_info(skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
RTM_NEWROUTE,
- tb->n,
+ tb->n,
(f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type,
- f->fn_scope, &f->fn_key, dz->dz_order,
+ f->fn_scope, &f->fn_key, dz->dz_order,
f->fn_info, NLM_F_MULTI) < 0) {
- cb->args[3] = i;
+ cb->args[4] = i;
return -1;
}
}
- cb->args[3] = i;
+ cb->args[4] = i;
return skb->len;
}
-static __inline__ int dn_hash_dump_zone(struct sk_buff *skb,
+static __inline__ int dn_hash_dump_zone(struct sk_buff *skb,
struct netlink_callback *cb,
struct dn_fib_table *tb,
struct dn_zone *dz)
{
int h, s_h;
- s_h = cb->args[2];
+ s_h = cb->args[3];
for(h = 0; h < dz->dz_divisor; h++) {
if (h < s_h)
continue;
if (h > s_h)
- memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
+ memset(&cb->args[4], 0, sizeof(cb->args) - 4*sizeof(cb->args[0]));
if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL)
continue;
if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) {
- cb->args[2] = h;
+ cb->args[3] = h;
return -1;
}
}
- cb->args[2] = h;
+ cb->args[3] = h;
return skb->len;
}
-static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb,
- struct netlink_callback *cb)
+static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb,
+ struct netlink_callback *cb)
{
- int m, s_m;
+ int m, s_m;
struct dn_zone *dz;
struct dn_hash *table = (struct dn_hash *)tb->data;
- s_m = cb->args[1];
+ s_m = cb->args[2];
read_lock(&dn_fib_tables_lock);
for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) {
if (m < s_m)
continue;
if (m > s_m)
- memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0]));
+ memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) {
- cb->args[1] = m;
+ cb->args[2] = m;
read_unlock(&dn_fib_tables_lock);
return -1;
}
}
read_unlock(&dn_fib_tables_lock);
- cb->args[1] = m;
+ cb->args[2] = m;
- return skb->len;
+ return skb->len;
}
-static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
+int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct net *net = sock_net(skb->sk);
+ unsigned int h, s_h;
+ unsigned int e = 0, s_e;
+ struct dn_fib_table *tb;
+ int dumped = 0;
+
+ if (!net_eq(net, &init_net))
+ return 0;
+
+ if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) &&
+ ((struct rtmsg *)nlmsg_data(cb->nlh))->rtm_flags&RTM_F_CLONED)
+ return dn_cache_dump(skb, cb);
+
+ s_h = cb->args[0];
+ s_e = cb->args[1];
+
+ for (h = s_h; h < DN_FIB_TABLE_HASHSZ; h++, s_h = 0) {
+ e = 0;
+ hlist_for_each_entry(tb, &dn_fib_table_hash[h], hlist) {
+ if (e < s_e)
+ goto next;
+ if (dumped)
+ memset(&cb->args[2], 0, sizeof(cb->args) -
+ 2 * sizeof(cb->args[0]));
+ if (tb->dump(tb, skb, cb) < 0)
+ goto out;
+ dumped = 1;
+next:
+ e++;
+ }
+ }
+out:
+ cb->args[1] = e;
+ cb->args[0] = h;
+
+ return skb->len;
+}
+
+static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct nlattr *attrs[],
+ struct nlmsghdr *n, struct netlink_skb_parms *req)
{
struct dn_hash *table = (struct dn_hash *)tb->data;
struct dn_fib_node *new_f, *f, **fp, **del_fp;
struct dn_zone *dz;
struct dn_fib_info *fi;
- int z = r->rtm_dst_len;
+ int z = r->rtm_dst_len;
int type = r->rtm_type;
dn_fib_key_t key;
- int err;
+ int err;
- if (z > 16)
- return -EINVAL;
+ if (z > 16)
+ return -EINVAL;
dz = table->dh_zones[z];
if (!dz && !(dz = dn_new_zone(table, z)))
return -ENOBUFS;
dz_key_0(key);
- if (rta->rta_dst) {
- dn_address dst;
- memcpy(&dst, rta->rta_dst, 2);
+ if (attrs[RTA_DST]) {
+ __le16 dst = nla_get_le16(attrs[RTA_DST]);
if (dst & ~DZ_MASK(dz))
return -EINVAL;
key = dz_key(dst, dz);
}
- if ((fi = dn_fib_create_info(r, rta, n, &err)) == NULL)
- return err;
+ if ((fi = dn_fib_create_info(r, attrs, n, &err)) == NULL)
+ return err;
if (dz->dz_nent > (dz->dz_divisor << 2) &&
dz->dz_divisor > DN_MAX_DIVISOR &&
@@ -515,8 +598,9 @@ static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct
DN_FIB_SCAN_KEY(f, fp, key) {
if (fi->fib_priority != DN_FIB_INFO(f)->fib_priority)
break;
- if (f->fn_type == type && f->fn_scope == r->rtm_scope
- && DN_FIB_INFO(f) == fi)
+ if (f->fn_type == type &&
+ f->fn_scope == r->rtm_scope &&
+ DN_FIB_INFO(f) == fi)
goto out;
}
@@ -533,12 +617,10 @@ create:
replace:
err = -ENOBUFS;
- new_f = kmem_cache_alloc(dn_hash_kmem, SLAB_KERNEL);
+ new_f = kmem_cache_zalloc(dn_hash_kmem, GFP_KERNEL);
if (new_f == NULL)
goto out;
- memset(new_f, 0, sizeof(struct dn_fib_node));
-
new_f->fn_key = key;
new_f->fn_type = type;
new_f->fn_scope = r->rtm_scope;
@@ -566,35 +648,35 @@ replace:
dn_rt_cache_flush(-1);
}
- dn_rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->n, n, req);
+ dn_rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->n, n, req);
- return 0;
+ return 0;
out:
dn_fib_release_info(fi);
return err;
}
-static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
+static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct nlattr *attrs[],
+ struct nlmsghdr *n, struct netlink_skb_parms *req)
{
struct dn_hash *table = (struct dn_hash*)tb->data;
struct dn_fib_node **fp, **del_fp, *f;
- int z = r->rtm_dst_len;
+ int z = r->rtm_dst_len;
struct dn_zone *dz;
dn_fib_key_t key;
int matched;
- if (z > 16)
- return -EINVAL;
+ if (z > 16)
+ return -EINVAL;
if ((dz = table->dh_zones[z]) == NULL)
return -ESRCH;
dz_key_0(key);
- if (rta->rta_dst) {
- dn_address dst;
- memcpy(&dst, rta->rta_dst, 2);
+ if (attrs[RTA_DST]) {
+ __le16 dst = nla_get_le16(attrs[RTA_DST]);
if (dst & ~DZ_MASK(dz))
return -EINVAL;
key = dz_key(dst, dz);
@@ -622,15 +704,15 @@ static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct
if (del_fp == NULL &&
(!r->rtm_type || f->fn_type == r->rtm_type) &&
(r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) &&
- (!r->rtm_protocol ||
+ (!r->rtm_protocol ||
fi->fib_protocol == r->rtm_protocol) &&
- dn_fib_nh_match(r, n, rta, fi) == 0)
+ dn_fib_nh_match(r, n, attrs, fi) == 0)
del_fp = fp;
}
if (del_fp) {
f = *del_fp;
- dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req);
+ dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req);
if (matched != 1) {
write_lock_bh(&dn_fib_tables_lock);
@@ -654,7 +736,7 @@ static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct
return 0;
}
- return -ESRCH;
+ return -ESRCH;
}
static inline int dn_flush_list(struct dn_fib_node **fp, int z, struct dn_hash *table)
@@ -699,16 +781,16 @@ 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 flowi *flp, struct dn_fib_res *res)
+static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct flowidn *flp, struct dn_fib_res *res)
{
- int err;
+ int err;
struct dn_zone *dz;
struct dn_hash *t = (struct dn_hash *)tb->data;
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(flp->fld_dst, dz);
+ dn_fib_key_t k = dz_key(flp->daddr, dz);
for(f = dz_chain(k, dz); f; f = f->fn_next) {
if (!dn_key_eq(k, f->fn_key)) {
@@ -723,14 +805,14 @@ static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct flowi *flp,
if (f->fn_state&DN_S_ZOMBIE)
continue;
- if (f->fn_scope < flp->fld_scope)
+ if (f->fn_scope < flp->flowidn_scope)
continue;
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;
+ res->scope = f->fn_scope;
res->prefixlen = dz->dz_order;
goto out;
}
@@ -741,67 +823,78 @@ static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct flowi *flp,
err = 1;
out:
read_unlock(&dn_fib_tables_lock);
- return err;
+ return err;
}
-struct dn_fib_table *dn_fib_get_table(int n, int create)
+struct dn_fib_table *dn_fib_get_table(u32 n, int create)
{
- struct dn_fib_table *t;
+ struct dn_fib_table *t;
+ unsigned int h;
- if (n < RT_TABLE_MIN)
- return NULL;
+ if (n < RT_TABLE_MIN)
+ return NULL;
- if (n > RT_TABLE_MAX)
- return NULL;
+ if (n > RT_TABLE_MAX)
+ return NULL;
- if (dn_fib_tables[n])
- return dn_fib_tables[n];
+ h = n & (DN_FIB_TABLE_HASHSZ - 1);
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(t, &dn_fib_table_hash[h], hlist) {
+ if (t->n == n) {
+ rcu_read_unlock();
+ return t;
+ }
+ }
+ rcu_read_unlock();
- if (!create)
- return NULL;
+ if (!create)
+ return NULL;
- if (in_interrupt() && net_ratelimit()) {
- printk(KERN_DEBUG "DECnet: BUG! Attempt to create routing table from interrupt\n");
- return NULL;
- }
- if ((t = kmalloc(sizeof(struct dn_fib_table) + sizeof(struct dn_hash), GFP_KERNEL)) == NULL)
- return NULL;
+ if (in_interrupt()) {
+ net_dbg_ratelimited("DECnet: BUG! Attempt to create routing table from interrupt\n");
+ return NULL;
+ }
- memset(t, 0, sizeof(struct dn_fib_table));
+ t = kzalloc(sizeof(struct dn_fib_table) + sizeof(struct dn_hash),
+ GFP_KERNEL);
+ if (t == NULL)
+ return NULL;
- t->n = n;
- t->insert = dn_fib_table_insert;
- t->delete = dn_fib_table_delete;
- t->lookup = dn_fib_table_lookup;
- t->flush = dn_fib_table_flush;
- t->dump = dn_fib_table_dump;
- memset(t->data, 0, sizeof(struct dn_hash));
- dn_fib_tables[n] = t;
+ t->n = n;
+ t->insert = dn_fib_table_insert;
+ t->delete = dn_fib_table_delete;
+ t->lookup = dn_fib_table_lookup;
+ t->flush = dn_fib_table_flush;
+ t->dump = dn_fib_table_dump;
+ hlist_add_head_rcu(&t->hlist, &dn_fib_table_hash[h]);
- return t;
+ return t;
}
-static void dn_fib_del_tree(int n)
+struct dn_fib_table *dn_fib_empty_table(void)
{
- struct dn_fib_table *t;
+ u32 id;
- write_lock(&dn_fib_tables_lock);
- t = dn_fib_tables[n];
- dn_fib_tables[n] = NULL;
- write_unlock(&dn_fib_tables_lock);
-
- kfree(t);
+ for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++)
+ if (dn_fib_get_table(id, 0) == NULL)
+ return dn_fib_get_table(id, 1);
+ return NULL;
}
-struct dn_fib_table *dn_fib_empty_table(void)
+void dn_fib_flush(void)
{
- int id;
+ int flushed = 0;
+ struct dn_fib_table *tb;
+ unsigned int h;
+
+ for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
+ hlist_for_each_entry(tb, &dn_fib_table_hash[h], hlist)
+ flushed += tb->flush(tb);
+ }
- 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;
+ if (flushed)
+ dn_rt_cache_flush(-1);
}
void __init dn_fib_table_init(void)
@@ -809,15 +902,22 @@ void __init dn_fib_table_init(void)
dn_hash_kmem = kmem_cache_create("dn_fib_info_cache",
sizeof(struct dn_fib_info),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
}
void __exit dn_fib_table_cleanup(void)
{
- int i;
-
- for (i = RT_TABLE_MIN; i <= RT_TABLE_MAX; ++i)
- dn_fib_del_tree(i);
+ struct dn_fib_table *t;
+ struct hlist_node *next;
+ unsigned int h;
- return;
+ write_lock(&dn_fib_tables_lock);
+ for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
+ hlist_for_each_entry_safe(t, next, &dn_fib_table_hash[h],
+ hlist) {
+ hlist_del(&t->hlist);
+ kfree(t);
+ }
+ }
+ write_unlock(&dn_fib_tables_lock);
}
diff --git a/net/decnet/dn_timer.c b/net/decnet/dn_timer.c
index 09825711d58..d9c150cc59a 100644
--- a/net/decnet/dn_timer.c
+++ b/net/decnet/dn_timer.c
@@ -22,7 +22,7 @@
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <net/sock.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <net/flow.h>
#include <net/dn.h>
@@ -36,16 +36,13 @@ static void dn_slow_timer(unsigned long arg);
void dn_start_slow_timer(struct sock *sk)
{
- sk->sk_timer.expires = jiffies + SLOW_INTERVAL;
- sk->sk_timer.function = dn_slow_timer;
- sk->sk_timer.data = (unsigned long)sk;
-
- add_timer(&sk->sk_timer);
+ setup_timer(&sk->sk_timer, dn_slow_timer, (unsigned long)sk);
+ sk_reset_timer(sk, &sk->sk_timer, jiffies + SLOW_INTERVAL);
}
void dn_stop_slow_timer(struct sock *sk)
{
- del_timer(&sk->sk_timer);
+ sk_stop_timer(sk, &sk->sk_timer);
}
static void dn_slow_timer(unsigned long arg)
@@ -53,12 +50,10 @@ static void dn_slow_timer(unsigned long arg)
struct sock *sk = (struct sock *)arg;
struct dn_scp *scp = DN_SK(sk);
- sock_hold(sk);
bh_lock_sock(sk);
if (sock_owned_by_user(sk)) {
- sk->sk_timer.expires = jiffies + HZ / 10;
- add_timer(&sk->sk_timer);
+ sk_reset_timer(sk, &sk->sk_timer, jiffies + HZ / 10);
goto out;
}
@@ -100,9 +95,7 @@ static void dn_slow_timer(unsigned long arg)
scp->keepalive_fxn(sk);
}
- sk->sk_timer.expires = jiffies + SLOW_INTERVAL;
-
- add_timer(&sk->sk_timer);
+ sk_reset_timer(sk, &sk->sk_timer, jiffies + SLOW_INTERVAL);
out:
bh_unlock_sock(sk);
sock_put(sk);
diff --git a/net/decnet/netfilter/Kconfig b/net/decnet/netfilter/Kconfig
index ecdb3f9f14c..8d7c109d510 100644
--- a/net/decnet/netfilter/Kconfig
+++ b/net/decnet/netfilter/Kconfig
@@ -3,7 +3,8 @@
#
menu "DECnet: Netfilter Configuration"
- depends on DECNET && NETFILTER && EXPERIMENTAL
+ depends on DECNET && NETFILTER
+ depends on NETFILTER_ADVANCED
config DECNET_NF_GRABULATOR
tristate "Routing message grabulator (for userland routing daemon)"
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index 16a5a31e212..e4d9560a910 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -14,11 +14,12 @@
*/
#include <linux/module.h>
#include <linux/skbuff.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/spinlock.h>
-#include <linux/netlink.h>
+#include <net/netlink.h>
#include <linux/netfilter_decnet.h>
#include <net/sock.h>
@@ -33,32 +34,31 @@ static struct sk_buff *dnrmg_build_message(struct sk_buff *rt_skb, int *errp)
{
struct sk_buff *skb = NULL;
size_t size;
- unsigned char *old_tail;
+ sk_buff_data_t old_tail;
struct nlmsghdr *nlh;
unsigned char *ptr;
struct nf_dn_rtmsg *rtm;
- size = NLMSG_SPACE(rt_skb->len);
- size += NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg));
- skb = alloc_skb(size, GFP_ATOMIC);
- if (!skb)
- goto nlmsg_failure;
+ size = NLMSG_ALIGN(rt_skb->len) +
+ NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg));
+ skb = nlmsg_new(size, GFP_ATOMIC);
+ if (!skb) {
+ *errp = -ENOMEM;
+ return NULL;
+ }
old_tail = skb->tail;
- nlh = NLMSG_PUT(skb, 0, 0, 0, size - sizeof(*nlh));
- rtm = (struct nf_dn_rtmsg *)NLMSG_DATA(nlh);
+ nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
+ if (!nlh) {
+ kfree_skb(skb);
+ *errp = -ENOMEM;
+ return NULL;
+ }
+ rtm = (struct nf_dn_rtmsg *)nlmsg_data(nlh);
rtm->nfdn_ifindex = rt_skb->dev->ifindex;
ptr = NFDN_RTMSG(rtm);
- memcpy(ptr, rt_skb->data, rt_skb->len);
+ skb_copy_from_linear_data(rt_skb, ptr, rt_skb->len);
nlh->nlmsg_len = skb->tail - old_tail;
return skb;
-
-nlmsg_failure:
- if (skb)
- kfree_skb(skb);
- *errp = -ENOMEM;
- if (net_ratelimit())
- printk(KERN_ERR "dn_rtmsg: error creating netlink message\n");
- return NULL;
}
static void dnrmg_send_peer(struct sk_buff *skb)
@@ -68,15 +68,15 @@ static void dnrmg_send_peer(struct sk_buff *skb)
int group = 0;
unsigned char flags = *skb->data;
- switch(flags & DN_RT_CNTL_MSK) {
- case DN_RT_PKT_L1RT:
- group = DNRNG_NLGRP_L1;
- break;
- case DN_RT_PKT_L2RT:
- group = DNRNG_NLGRP_L2;
- break;
- default:
- return;
+ switch (flags & DN_RT_CNTL_MSK) {
+ case DN_RT_PKT_L1RT:
+ group = DNRNG_NLGRP_L1;
+ break;
+ case DN_RT_PKT_L2RT:
+ group = DNRNG_NLGRP_L2;
+ break;
+ default:
+ return;
}
skb2 = dnrmg_build_message(skb, &status);
@@ -87,13 +87,13 @@ static void dnrmg_send_peer(struct sk_buff *skb)
}
-static unsigned int dnrmg_hook(unsigned int hook,
- struct sk_buff **pskb,
+static unsigned int dnrmg_hook(const struct nf_hook_ops *ops,
+ struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- dnrmg_send_peer(*pskb);
+ dnrmg_send_peer(skb);
return NF_ACCEPT;
}
@@ -102,12 +102,12 @@ static unsigned int dnrmg_hook(unsigned int hook,
static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
{
- struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
+ struct nlmsghdr *nlh = nlmsg_hdr(skb);
if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
return;
- if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
RCV_SKB_FAIL(-EPERM);
/* Eventually we might send routing messages too */
@@ -115,30 +115,22 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
RCV_SKB_FAIL(-EINVAL);
}
-static void dnrmg_receive_user_sk(struct sock *sk, int len)
-{
- struct sk_buff *skb;
- unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
-
- for (; qlen && (skb = skb_dequeue(&sk->sk_receive_queue)); qlen--) {
- dnrmg_receive_user_skb(skb);
- kfree_skb(skb);
- }
-}
-
-static struct nf_hook_ops dnrmg_ops = {
+static struct nf_hook_ops dnrmg_ops __read_mostly = {
.hook = dnrmg_hook,
- .pf = PF_DECnet,
+ .pf = NFPROTO_DECNET,
.hooknum = NF_DN_ROUTE,
.priority = NF_DN_PRI_DNRTMSG,
};
-static int __init init(void)
+static int __init dn_rtmsg_init(void)
{
int rv = 0;
+ struct netlink_kernel_cfg cfg = {
+ .groups = DNRNG_NLGRP_MAX,
+ .input = dnrmg_receive_user_skb,
+ };
- dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, DNRNG_NLGRP_MAX,
- dnrmg_receive_user_sk, THIS_MODULE);
+ dnrmg = netlink_kernel_create(&init_net, NETLINK_DNRTMSG, &cfg);
if (dnrmg == NULL) {
printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket");
return -ENOMEM;
@@ -146,16 +138,16 @@ static int __init init(void)
rv = nf_register_hook(&dnrmg_ops);
if (rv) {
- sock_release(dnrmg->sk_socket);
+ netlink_kernel_release(dnrmg);
}
return rv;
}
-static void __exit fini(void)
+static void __exit dn_rtmsg_fini(void)
{
nf_unregister_hook(&dnrmg_ops);
- sock_release(dnrmg->sk_socket);
+ netlink_kernel_release(dnrmg);
}
@@ -164,6 +156,6 @@ MODULE_AUTHOR("Steven Whitehouse <steve@chygwyn.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_DNRTMSG);
-module_init(init);
-module_exit(fini);
+module_init(dn_rtmsg_init);
+module_exit(dn_rtmsg_fini);
diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c
index 0e9d2c57116..5325b541c52 100644
--- a/net/decnet/sysctl_net_decnet.c
+++ b/net/decnet/sysctl_net_decnet.c
@@ -13,7 +13,6 @@
* Steve Whitehouse - Memory buffer settings, like the tcp ones
*
*/
-#include <linux/config.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/fs.h>
@@ -39,7 +38,7 @@ int decnet_log_martians = 1;
int decnet_no_fc_max_cwnd = NSP_MIN_WINDOW;
/* Reasonable defaults, I hope, based on tcp's defaults */
-int sysctl_decnet_mem[3] = { 768 << 3, 1024 << 3, 1536 << 3 };
+long sysctl_decnet_mem[3] = { 768 << 3, 1024 << 3, 1536 << 3 };
int sysctl_decnet_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 };
int sysctl_decnet_rmem[3] = { 4 * 1024, 87380, 87380 * 2 };
@@ -69,14 +68,15 @@ static struct ctl_table_header *dn_table_header = NULL;
static void strip_it(char *str)
{
for(;;) {
- switch(*str) {
- case ' ':
- case '\n':
- case '\r':
- case ':':
- *str = 0;
- case 0:
- return;
+ switch (*str) {
+ case ' ':
+ case '\n':
+ case '\r':
+ case ':':
+ *str = 0;
+ /* Fallthrough */
+ case 0:
+ return;
}
str++;
}
@@ -86,9 +86,9 @@ static void strip_it(char *str)
* Simple routine to parse an ascii DECnet address
* into a network order address.
*/
-static int parse_addr(dn_address *addr, char *str)
+static int parse_addr(__le16 *addr, char *str)
{
- dn_address area, node;
+ __u16 area, node;
while(*str && !ISNUM(*str)) str++;
@@ -127,53 +127,18 @@ static int parse_addr(dn_address *addr, char *str)
if (INVALID_END_CHAR(*str))
return -1;
- *addr = dn_htons((area << 10) | node);
+ *addr = cpu_to_le16((area << 10) | node);
return 0;
}
-
-static int dn_node_address_strategy(ctl_table *table, int __user *name, int nlen,
- void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
-{
- size_t len;
- dn_address addr;
-
- if (oldval && oldlenp) {
- if (get_user(len, oldlenp))
- return -EFAULT;
- if (len) {
- if (len != sizeof(unsigned short))
- return -EINVAL;
- if (put_user(decnet_address, (unsigned short __user *)oldval))
- return -EFAULT;
- }
- }
- if (newval && newlen) {
- if (newlen != sizeof(unsigned short))
- return -EINVAL;
- if (get_user(addr, (unsigned short __user *)newval))
- return -EFAULT;
-
- dn_dev_devices_off();
-
- decnet_address = addr;
-
- dn_dev_devices_on();
- }
- return 0;
-}
-
-static int dn_node_address_handler(ctl_table *table, int write,
- struct file *filp,
+static int dn_node_address_handler(struct ctl_table *table, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
char addr[DN_ASCBUF_LEN];
size_t len;
- dn_address dnaddr;
+ __le16 dnaddr;
if (!*lenp || (*ppos && !write)) {
*lenp = 0;
@@ -181,7 +146,7 @@ static int dn_node_address_handler(ctl_table *table, int write,
}
if (write) {
- int len = (*lenp < DN_ASCBUF_LEN) ? *lenp : (DN_ASCBUF_LEN-1);
+ len = (*lenp < DN_ASCBUF_LEN) ? *lenp : (DN_ASCBUF_LEN-1);
if (copy_from_user(addr, buffer, len))
return -EFAULT;
@@ -203,7 +168,7 @@ static int dn_node_address_handler(ctl_table *table, int write,
return 0;
}
- dn_addr2asc(dn_ntohs(decnet_address), addr);
+ dn_addr2asc(le16_to_cpu(decnet_address), addr);
len = strlen(addr);
addr[len++] = '\n';
@@ -218,68 +183,7 @@ static int dn_node_address_handler(ctl_table *table, int write,
return 0;
}
-
-static int dn_def_dev_strategy(ctl_table *table, int __user *name, int nlen,
- void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
-{
- size_t len;
- struct net_device *dev;
- char devname[17];
- size_t namel;
- int rv = 0;
-
- devname[0] = 0;
-
- if (oldval && oldlenp) {
- if (get_user(len, oldlenp))
- return -EFAULT;
- if (len) {
- dev = dn_dev_get_default();
- if (dev) {
- strcpy(devname, dev->name);
- dev_put(dev);
- }
-
- namel = strlen(devname) + 1;
- if (len > namel) len = namel;
-
- if (copy_to_user(oldval, devname, len))
- return -EFAULT;
-
- if (put_user(len, oldlenp))
- return -EFAULT;
- }
- }
-
- if (newval && newlen) {
- if (newlen > 16)
- return -E2BIG;
-
- if (copy_from_user(devname, newval, newlen))
- return -EFAULT;
-
- devname[newlen] = 0;
-
- dev = dev_get_by_name(devname);
- if (dev == NULL)
- return -ENODEV;
-
- rv = -ENODEV;
- if (dev->dn_ptr != NULL) {
- rv = dn_dev_set_default(dev, 1);
- if (rv)
- dev_put(dev);
- }
- }
-
- return rv;
-}
-
-
-static int dn_def_dev_handler(ctl_table *table, int write,
- struct file * filp,
+static int dn_def_dev_handler(struct ctl_table *table, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
@@ -302,7 +206,7 @@ static int dn_def_dev_handler(ctl_table *table, int write,
devname[*lenp] = 0;
strip_it(devname);
- dev = dev_get_by_name(devname);
+ dev = dev_get_by_name(&init_net, devname);
if (dev == NULL)
return -ENODEV;
@@ -342,164 +246,119 @@ static int dn_def_dev_handler(ctl_table *table, int write,
return 0;
}
-static ctl_table dn_table[] = {
+static struct ctl_table dn_table[] = {
{
- .ctl_name = NET_DECNET_NODE_ADDRESS,
- .procname = "node_address",
- .maxlen = 7,
- .mode = 0644,
+ .procname = "node_address",
+ .maxlen = 7,
+ .mode = 0644,
.proc_handler = dn_node_address_handler,
- .strategy = dn_node_address_strategy,
},
{
- .ctl_name = NET_DECNET_NODE_NAME,
.procname = "node_name",
- .data = node_name,
+ .data = node_name,
.maxlen = 7,
.mode = 0644,
- .proc_handler = &proc_dostring,
- .strategy = &sysctl_string,
+ .proc_handler = proc_dostring,
},
{
- .ctl_name = NET_DECNET_DEFAULT_DEVICE,
- .procname = "default_device",
- .maxlen = 16,
+ .procname = "default_device",
+ .maxlen = 16,
.mode = 0644,
.proc_handler = dn_def_dev_handler,
- .strategy = dn_def_dev_strategy,
},
{
- .ctl_name = NET_DECNET_TIME_WAIT,
.procname = "time_wait",
.data = &decnet_time_wait,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
.extra1 = &min_decnet_time_wait,
.extra2 = &max_decnet_time_wait
},
{
- .ctl_name = NET_DECNET_DN_COUNT,
.procname = "dn_count",
.data = &decnet_dn_count,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
.extra1 = &min_state_count,
.extra2 = &max_state_count
},
{
- .ctl_name = NET_DECNET_DI_COUNT,
.procname = "di_count",
.data = &decnet_di_count,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
.extra1 = &min_state_count,
.extra2 = &max_state_count
},
{
- .ctl_name = NET_DECNET_DR_COUNT,
.procname = "dr_count",
.data = &decnet_dr_count,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
.extra1 = &min_state_count,
.extra2 = &max_state_count
},
{
- .ctl_name = NET_DECNET_DST_GC_INTERVAL,
.procname = "dst_gc_interval",
.data = &decnet_dst_gc_interval,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
.extra1 = &min_decnet_dst_gc_interval,
.extra2 = &max_decnet_dst_gc_interval
},
{
- .ctl_name = NET_DECNET_NO_FC_MAX_CWND,
.procname = "no_fc_max_cwnd",
.data = &decnet_no_fc_max_cwnd,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec_minmax,
.extra1 = &min_decnet_no_fc_max_cwnd,
.extra2 = &max_decnet_no_fc_max_cwnd
},
{
- .ctl_name = NET_DECNET_MEM,
- .procname = "decnet_mem",
- .data = &sysctl_decnet_mem,
- .maxlen = sizeof(sysctl_decnet_mem),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec,
- },
- {
- .ctl_name = NET_DECNET_RMEM,
- .procname = "decnet_rmem",
- .data = &sysctl_decnet_rmem,
- .maxlen = sizeof(sysctl_decnet_rmem),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec,
- },
- {
- .ctl_name = NET_DECNET_WMEM,
- .procname = "decnet_wmem",
- .data = &sysctl_decnet_wmem,
- .maxlen = sizeof(sysctl_decnet_wmem),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec,
- },
+ .procname = "decnet_mem",
+ .data = &sysctl_decnet_mem,
+ .maxlen = sizeof(sysctl_decnet_mem),
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_minmax
+ },
{
- .ctl_name = NET_DECNET_DEBUG_LEVEL,
- .procname = "debug",
- .data = &decnet_debug_level,
- .maxlen = sizeof(int),
+ .procname = "decnet_rmem",
+ .data = &sysctl_decnet_rmem,
+ .maxlen = sizeof(sysctl_decnet_rmem),
.mode = 0644,
- .proc_handler = &proc_dointvec,
- .strategy = &sysctl_intvec,
+ .proc_handler = proc_dointvec,
},
- {0}
-};
-
-static ctl_table dn_dir_table[] = {
{
- .ctl_name = NET_DECNET,
- .procname = "decnet",
- .mode = 0555,
- .child = dn_table},
- {0}
-};
-
-static ctl_table dn_root_table[] = {
+ .procname = "decnet_wmem",
+ .data = &sysctl_decnet_wmem,
+ .maxlen = sizeof(sysctl_decnet_wmem),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
{
- .ctl_name = CTL_NET,
- .procname = "net",
- .mode = 0555,
- .child = dn_dir_table
+ .procname = "debug",
+ .data = &decnet_debug_level,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
- {0}
+ { }
};
void dn_register_sysctl(void)
{
- dn_table_header = register_sysctl_table(dn_root_table, 1);
+ dn_table_header = register_net_sysctl(&init_net, "net/decnet", dn_table);
}
void dn_unregister_sysctl(void)
{
- unregister_sysctl_table(dn_table_header);
+ unregister_net_sysctl_table(dn_table_header);
}
#else /* CONFIG_SYSCTL */