Commit ac3ebbfb authored by David S. Miller's avatar David S. Miller

Merge nuts.ninka.net:/home/davem/src/BK/network-2.5

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents 225e7f58 e442c99d
......@@ -28,8 +28,36 @@ Don't turn on SIOCGIFCONF support for DECnet unless you are really sure
that you need it, in general you won't and it can cause ifconfig to
malfunction.
Run time configuration has changed slightly from the 2.4 system. If you
want to configure an endnode, then the simplified procedure is as follows:
o Set the MAC address on your ethernet card before starting _any_ other
network protocols.
As soon as your network card is brought into the UP state, DECnet should
start working. If you need something more complicated or are unsure how
to set the MAC address, see the next section. Also all configurations which
worked with 2.4 will work under 2.5 with no change.
3) Command line options
You can set a DECnet address on the kernel command line for compatibility
with the 2.4 configuration procedure, but in general its not needed any more.
If you do st a DECnet address on the command line, it has only one purpose
which is that its added to the addresses on the loopback device.
With 2.4 kernels, DECnet would only recognise addresses as local if they
were added to the loopback device. In 2.5, any local interface address
can be used to loop back to the local machine. Of course this does not
prevent you adding further addresses to the loopback device if you
want to.
N.B. Since the address list of an interface determines the addresses for
which "hello" messages are sent, if you don't set an address on the loopback
interface then you won't see any entries in /proc/net/neigh for the local
host until such time as you start a connection. This doesn't affect the
operation of the local communications in any other way though.
The kernel command line takes options looking like the following:
decnet=1,2
......@@ -51,7 +79,7 @@ parameters.
Currently the only supported devices are ethernet and ip_gre. The
ethernet address of your ethernet card has to be set according to the DECnet
address of the node in order for it to be recognised (and thus appear in
address of the node in order for it to be autoconfigured (and then appear in
/proc/net/decnet_dev). There is a utility available at the above
FTP sites called dn2ethaddr which can compute the correct ethernet
address to use. The address can be set by ifconfig either before at
......@@ -61,14 +89,22 @@ add the line:
MACADDR=AA:00:04:00:03:04
or something similar, to /etc/sysconfig/network-scripts/ifcfg-eth0 or
wherever your network card's configuration lives.
wherever your network card's configuration lives. Setting the MAC address
of your ethernet card to an address starting with "hi-ord" will cause a
DECnet address which matches to be added to the interface (which you can
verify with iproute2).
You will also need to set /proc/sys/net/decnet/default_device to the
The default device for routing can be set through the /proc filesystem
by setting /proc/sys/net/decnet/default_device to the
device you want DECnet to route packets out of when no specific route
is available. Usually this will be eth0, for example:
echo -n "eth0" >/proc/sys/net/decnet/default_device
If you don't set the default device, then it will default to the first
ethernet card which has been autoconfigured as described above. You can
confirm that by looking in the default_device file of course.
There is a list of what the other files under /proc/sys/net/decnet/ do
on the kernel patch web site (shown above).
......@@ -149,7 +185,36 @@ information (_most_ of which _is_ _essential_) includes:
You may also need to increase the length grabbed with the -s flag. The
-e flag also provides very useful information (ethernet MAC addresses))
7) Mailing list
7) MAC FAQ
A quick FAQ on ethernet MAC addresses to explain how Linux and DECnet
interact and how to get the best performance from your hardware.
Ethernet cards are designed to normally only pass received network frames
to a host computer when they are addressed to it, or to the broadcast address.
Linux has an interface which allows the setting of extra addresses for
an ethernet card to listen to. If the ethernet card supports it, the
filtering operation will be done in hardware, if not the extra unwanted packets
received will be discarded by the host computer. In the latter case,
significant processor time and bus bandwidth can be used up on a busy
network (see the NAPI documentation for a longer explanation of these
effects).
DECnet makes use of this interface to allow running DECnet on an ethernet
card which has already been configured using TCP/IP (presumably using the
built in MAC address of the card, as usual) and/or to allow multiple DECnet
addresses on each physical interface. If you do this, be aware that if your
ethernet card doesn't support perfect hashing in its MAC address filter
then your computer will be doing more work than required. Some cards
will simply set themselves into promiscuous mode in order to receive
packets from the DECnet specified addresses. So if you have one of these
cards its better to set the MAC address of the card as described above
to gain the best efficiency. Better still is to use a card which supports
NAPI as well.
8) Mailing list
If you are keen to get involved in development, or want to ask questions
about configuration, or even just report bugs, then there is a mailing
......@@ -157,7 +222,7 @@ list that you can join, details are at:
http://sourceforge.net/mail/?group_id=4993
8) Legal Info
9) Legal Info
The Linux DECnet project team have placed their code under the GPL. The
software is provided "as is" and without warranty express or implied.
......
......@@ -211,7 +211,6 @@ extern void dn_start_fast_timer(struct sock *sk);
extern void dn_stop_fast_timer(struct sock *sk);
extern dn_address decnet_address;
extern unsigned char decnet_ether_address[6];
extern int decnet_debug_level;
extern int decnet_time_wait;
extern int decnet_dn_count;
......
......@@ -57,7 +57,7 @@ struct dn_ifaddr {
* up() - Called to initialize device, return value can veto use of
* device with DECnet.
* down() - Called to turn device off when it goes down
* timer3() - Called when timer 3 goes off
* timer3() - Called once for each ifaddr when timer 3 goes off
*
* sysctl - Hook for sysctl things
*
......@@ -78,7 +78,7 @@ struct dn_dev_parms {
int ctl_name; /* Index for sysctl */
int (*up)(struct net_device *);
void (*down)(struct net_device *);
void (*timer3)(struct net_device *);
void (*timer3)(struct net_device *, struct dn_ifaddr *ifa);
void *sysctl;
};
......@@ -167,7 +167,9 @@ extern void dn_dev_hello(struct sk_buff *skb);
extern void dn_dev_up(struct net_device *);
extern void dn_dev_down(struct net_device *);
extern struct net_device *decnet_default_device;
extern int dn_dev_set_default(struct net_device *dev, int force);
extern struct net_device *dn_dev_get_default(void);
extern int dn_dev_bind_default(dn_address *addr);
static __inline__ int dn_dev_islocal(struct net_device *dev, dn_address addr)
{
......
......@@ -96,7 +96,7 @@ static inline void dn_rt_send(struct sk_buff *skb)
dev_queue_xmit(skb);
}
static inline void dn_rt_finish_output(struct sk_buff *skb, char *dst)
static inline void dn_rt_finish_output(struct sk_buff *skb, char *dst, char *src)
{
struct net_device *dev = skb->dev;
......@@ -104,7 +104,7 @@ static inline void dn_rt_finish_output(struct sk_buff *skb, char *dst)
dst = NULL;
if (!dev->hard_header || (dev->hard_header(skb, dev, ETH_P_DNA_RT,
dst, NULL, skb->len) >= 0))
dst, src, skb->len) >= 0))
dn_rt_send(skb);
else
kfree_skb(skb);
......
......@@ -30,7 +30,7 @@
#include <linux/ipv6.h>
#endif
#define MAX_INET_PROTOS 32 /* Must be a power of 2 */
#define MAX_INET_PROTOS 256 /* Must be a power of 2 */
/* This is used to register protocols. */
......@@ -38,11 +38,6 @@ struct inet_protocol
{
int (*handler)(struct sk_buff *skb);
void (*err_handler)(struct sk_buff *skb, u32 info);
struct inet_protocol *next;
unsigned char protocol;
unsigned char copy:1;
void *data;
const char *name;
};
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
......@@ -54,11 +49,6 @@ struct inet6_protocol
struct inet6_skb_parm *opt,
int type, int code, int offset,
__u32 info);
struct inet6_protocol *next;
unsigned char protocol;
unsigned char copy:1;
void *data;
const char *name;
};
#endif
......@@ -93,14 +83,14 @@ extern struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
extern struct list_head inetsw6[SOCK_MAX];
#endif
extern void inet_add_protocol(struct inet_protocol *prot);
extern int inet_del_protocol(struct inet_protocol *prot);
extern int inet_add_protocol(struct inet_protocol *prot, unsigned char num);
extern int inet_del_protocol(struct inet_protocol *prot, unsigned char num);
extern void inet_register_protosw(struct inet_protosw *p);
extern void inet_unregister_protosw(struct inet_protosw *p);
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
extern void inet6_add_protocol(struct inet6_protocol *prot);
extern int inet6_del_protocol(struct inet6_protocol *prot);
extern int inet6_add_protocol(struct inet6_protocol *prot, unsigned char num);
extern int inet6_del_protocol(struct inet6_protocol *prot, unsigned char num);
extern void inet6_register_protosw(struct inet_protosw *p);
extern void inet6_unregister_protosw(struct inet_protosw *p);
#endif
......
......@@ -37,6 +37,6 @@ extern struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
unsigned long raddr, unsigned long laddr,
int dif);
extern struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
extern void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
#endif /* _RAW_H */
......@@ -7,9 +7,7 @@
extern struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE];
extern rwlock_t raw_v6_lock;
extern struct sock * ipv6_raw_deliver(struct sk_buff *skb,
int nexthdr);
extern void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr);
extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
struct in6_addr *loc_addr, struct in6_addr *rmt_addr);
......
......@@ -35,14 +35,11 @@ Steve's quick list of things that need finishing off:
file)
o Find all the commonality between DECnet and IPv4 routing code and extract
it into a small library of routines. [probably a project for 2.5.xx]
it into a small library of routines. [probably a project for 2.7.xx]
o Test ip_gre tunneling works... it did the last time I tested it and it
will have to if I'm to test routing properly.
o Hello messages should be generated for each primary address on each
interface.
o Add the routing message grabbing netfilter module [written, tested,
awaiting merge]
......@@ -55,3 +52,5 @@ Steve's quick list of things that need finishing off:
o DECnet sendpages() function
o AIO for DECnet
......@@ -100,6 +100,7 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
......@@ -131,21 +132,20 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat
#include <net/dn_fib.h>
#include <net/dn_neigh.h>
static void dn_keepalive(struct sock *sk);
struct dn_sock {
struct sock sk;
struct dn_scp scp;
};
/*
* decnet_address is kept in network order, decnet_ether_address is kept
* as a string of bytes.
*/
dn_address decnet_address = 0;
unsigned char decnet_ether_address[ETH_ALEN] = { 0xAA, 0x00, 0x04, 0x00, 0x00, 0x00 };
static void dn_keepalive(struct sock *sk);
#define DN_SK_HASH_SHIFT 8
#define DN_SK_HASH_SIZE (1 << DN_SK_HASH_SHIFT)
#define DN_SK_HASH_MASK (DN_SK_HASH_SIZE - 1)
static kmem_cache_t *dn_sk_cachep;
static struct proto_ops dn_proto_ops;
rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;
static rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;
static struct sock *dn_sk_hash[DN_SK_HASH_SIZE];
static struct sock *dn_wild_sk;
......@@ -473,17 +473,16 @@ struct sock *dn_alloc_sock(struct socket *sock, int gfp)
struct sock *sk;
struct dn_scp *scp;
if ((sk = sk_alloc(PF_DECnet, gfp, 1, NULL)) == NULL)
if ((sk = sk_alloc(PF_DECnet, gfp, sizeof(struct dn_sock), dn_sk_cachep)) == NULL)
goto no_sock;
scp = kmalloc(sizeof(*scp), gfp);
if (!scp)
goto free_sock;
scp = (struct dn_scp *)(sk + 1);
DN_SK(sk) = scp;
if (sock) {
sock->ops = &dn_proto_ops;
}
sock_init_data(sock,sk);
DN_SK(sk) = scp;
sk->backlog_rcv = dn_nsp_backlog_rcv;
sk->destruct = dn_destruct;
......@@ -544,8 +543,7 @@ struct sock *dn_alloc_sock(struct socket *sock, int gfp)
MOD_INC_USE_COUNT;
return sk;
free_sock:
sk_free(sk);
no_sock:
return NULL;
}
......@@ -771,9 +769,6 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct net_device *dev;
int rv;
if (sk->zapped == 0)
return -EINVAL;
if (addr_len != sizeof(struct sockaddr_dn))
return -EINVAL;
......@@ -783,19 +778,30 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if (dn_ntohs(saddr->sdn_nodeaddrl) && (dn_ntohs(saddr->sdn_nodeaddrl) != 2))
return -EINVAL;
if (saddr->sdn_objnum && !capable(CAP_NET_BIND_SERVICE))
return -EPERM;
if (dn_ntohs(saddr->sdn_objnamel) > DN_MAXOBJL)
return -EINVAL;
if (saddr->sdn_flags & ~SDF_WILD)
return -EINVAL;
if (saddr->sdn_flags & SDF_WILD) {
if (!capable(CAP_NET_BIND_SERVICE))
return -EPERM;
} else {
#if 1
if ((!capable(CAP_NET_BIND_SERVICE) && saddr->sdn_objnum) ||
(saddr->sdn_flags & SDF_WILD))
return -EACCES;
#else
/*
* Maybe put the default actions in the default security ops for
* dn_prot_sock ? Would be nice if the capable call would go there
* too.
*/
if (security_ops->dn_prot_sock(saddr) &&
!capable(CAP_NET_BIND_SERVICE) ||
saddr->sdn_objnum || (saddr->sdn_flags & SDF_WILD))
return -EACCES;
#endif
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) {
......@@ -810,12 +816,18 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
}
}
rv = -EINVAL;
lock_sock(sk);
if (sk->zapped != 0) {
memcpy(&scp->addr, saddr, addr_len);
sk->zapped = 0;
memcpy(&scp->addr, saddr, addr_len);
sk->zapped = 0;
if ((rv = dn_hash_sock(sk)) != 0)
sk->zapped = 1;
rv = dn_hash_sock(sk);
if (rv) {
sk->zapped = 1;
}
}
release_sock(sk);
return rv;
}
......@@ -825,6 +837,7 @@ static int dn_auto_bind(struct socket *sock)
{
struct sock *sk = sock->sk;
struct dn_scp *scp = DN_SK(sk);
int rv;
sk->zapped = 0;
......@@ -844,13 +857,18 @@ static int dn_auto_bind(struct socket *sock)
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);
*(dn_address *)scp->addr.sdn_add.a_addr = decnet_address;
dn_hash_sock(sk);
rv = dn_dev_bind_default((dn_address *)scp->addr.sdn_add.a_addr);
if (rv == 0) {
rv = dn_hash_sock(sk);
if (rv) {
sk->zapped = 1;
}
}
return 0;
return rv;
}
......@@ -1209,6 +1227,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return dn_fib_ioctl(sock, cmd, arg);
#endif /* CONFIG_DECNET_ROUTER */
#if 0
case OSIOCSNETADDR:
if (!capable(CAP_NET_ADMIN)) {
err = -EPERM;
......@@ -1218,7 +1237,6 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
dn_dev_devices_off();
decnet_address = (unsigned short)arg;
dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
dn_dev_devices_on();
err = 0;
......@@ -1227,6 +1245,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case OSIOCGNETADDR:
err = put_user(decnet_address, (unsigned short *)arg);
break;
#endif
case SIOCGIFCONF:
case SIOCGIFFLAGS:
case SIOCGIFBRDADDR:
......@@ -2227,38 +2246,24 @@ void dn_unregister_sysctl(void);
#endif
#ifdef MODULE
MODULE_DESCRIPTION("The Linux DECnet Network Protocol");
MODULE_AUTHOR("Linux DECnet Project Team");
MODULE_LICENSE("GPL");
static int addr[2] = {0, 0};
MODULE_PARM(addr, "2i");
MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
#endif
static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.20-pre1s (C) 1995-2002 Linux DECnet Project Team\n";
static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.40s (C) 1995-2002 Linux DECnet Project Team\n";
static int __init decnet_init(void)
{
#ifdef MODULE
if (addr[0] > 63 || addr[0] < 0) {
printk(KERN_ERR "DECnet: Area must be between 0 and 63");
return 1;
}
if (addr[1] > 1023 || addr[1] < 0) {
printk(KERN_ERR "DECnet: Node must be between 0 and 1023");
return 1;
}
decnet_address = dn_htons((addr[0] << 10) | addr[1]);
dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
#endif
printk(banner);
dn_sk_cachep = kmem_cache_create("decnet_socket_cache",
sizeof(struct dn_sock),
0, SLAB_HWCACHE_ALIGN,
NULL, NULL);
if (!dn_sk_cachep)
return -ENOMEM;
sock_register(&dn_family_ops);
dev_add_pack(&dn_dix_packet_type);
register_netdevice_notifier(&dn_dev_notifier);
......@@ -2288,21 +2293,6 @@ static int __init decnet_init(void)
}
#ifndef MODULE
static int __init decnet_setup(char *str)
{
unsigned short area = simple_strtoul(str, &str, 0);
unsigned short node = simple_strtoul(*str > 0 ? ++str : str, &str, 0);
decnet_address = dn_htons(area << 10 | node);
dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
return 1;
}
__setup("decnet=", decnet_setup);
#endif
static void __exit decnet_exit(void)
{
sock_unregister(AF_DECnet);
......@@ -2323,6 +2313,8 @@ static void __exit decnet_exit(void)
#endif /* CONFIG_DECNET_ROUTER */
proc_net_remove("decnet");
kmem_cache_destroy(dn_sk_cachep);
}
module_init(decnet_init);
......
......@@ -23,6 +23,8 @@
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/proc_fs.h>
......@@ -52,16 +54,23 @@ static unsigned char dn_eco_version[3] = {0x02,0x00,0x00};
extern struct neigh_table dn_neigh_table;
struct net_device *decnet_default_device;
/*
* decnet_address is kept in network order.
*/
dn_address decnet_address = 0;
static rwlock_t dndev_lock = RW_LOCK_UNLOCKED;
static struct net_device *decnet_default_device;
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 int dn_eth_up(struct net_device *);
static void dn_send_brd_hello(struct net_device *dev);
static void dn_eth_down(struct net_device *);
static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa);
#if 0
static void dn_send_ptp_hello(struct net_device *dev);
static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa);
#endif
static struct dn_dev_parms dn_dev_list[] = {
......@@ -75,6 +84,7 @@ static struct dn_dev_parms dn_dev_list[] = {
.name = "ethernet",
.ctl_name = NET_DECNET_CONF_ETHER,
.up = dn_eth_up,
.down = dn_eth_down,
.timer3 = dn_send_brd_hello,
},
{
......@@ -249,6 +259,51 @@ static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
}
}
struct net_device *dn_dev_get_default(void)
{
struct net_device *dev;
read_lock(&dndev_lock);
dev = decnet_default_device;
if (dev) {
if (dev->dn_ptr)
dev_hold(dev);
else
dev = NULL;
}
read_unlock(&dndev_lock);
return dev;
}
int dn_dev_set_default(struct net_device *dev, int force)
{
struct net_device *old = NULL;
int rv = -EBUSY;
if (!dev->dn_ptr)
return -ENODEV;
write_lock(&dndev_lock);
if (force || decnet_default_device == NULL) {
old = decnet_default_device;
decnet_default_device = dev;
rv = 0;
}
write_unlock(&dndev_lock);
if (old)
dev_put(dev);
return rv;
}
static void dn_dev_check_default(struct net_device *dev)
{
write_lock(&dndev_lock);
if (dev == decnet_default_device) {
decnet_default_device = NULL;
} else {
dev = NULL;
}
write_unlock(&dndev_lock);
if (dev)
dev_put(dev);
}
static int dn_forwarding_proc(ctl_table *table, int write,
struct file *filep,
......@@ -364,9 +419,20 @@ static __inline__ void dn_dev_free_ifa(struct dn_ifaddr *ifa)
static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int destroy)
{
struct dn_ifaddr *ifa1 = *ifap;
unsigned char mac_addr[6];
struct net_device *dev = dn_db->dev;
ASSERT_RTNL();
*ifap = ifa1->ifa_next;
if (dn_db->dev->type == ARPHRD_ETHER) {
if (ifa1->ifa_local != dn_htons(dn_eth2dn(dev->dev_addr))) {
dn_dn2eth(mac_addr, ifa1->ifa_local);
dev_mc_delete(dev, mac_addr, ETH_ALEN, 0);
}
}
rtmsg_ifa(RTM_DELADDR, ifa1);
if (destroy) {
......@@ -379,9 +445,25 @@ static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int de
static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
{
/*
* FIXME: Duplicate check here.
*/
struct net_device *dev = dn_db->dev;
struct dn_ifaddr *ifa1;
unsigned char mac_addr[6];
ASSERT_RTNL();
/* Check for duplicates */
for(ifa1 = dn_db->ifa_list; ifa1; ifa1 = 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))) {
dn_dn2eth(mac_addr, ifa->ifa_local);
dev_mc_add(dev, mac_addr, ETH_ALEN, 0);
dev_mc_upload(dev);
}
}
ifa->ifa_next = dn_db->ifa_list;
dn_db->ifa_list = ifa;
......@@ -394,6 +476,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa)
{
struct dn_dev *dn_db = dev->dn_ptr;
int rv;
if (dn_db == NULL) {
int err;
......@@ -407,7 +490,10 @@ static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa)
if (dev->flags & IFF_LOOPBACK)
ifa->ifa_scope = RT_SCOPE_HOST;
return dn_dev_insert_ifa(dn_db, ifa);
rv = dn_dev_insert_ifa(dn_db, ifa);
if (rv)
dn_dev_free_ifa(ifa);
return rv;
}
......@@ -538,6 +624,7 @@ static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *a
struct dn_dev *dn_db;
struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
struct dn_ifaddr *ifa;
int rv;
if (rta[IFA_LOCAL-1] == NULL)
return -EINVAL;
......@@ -564,7 +651,10 @@ static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *a
else
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
return dn_dev_insert_ifa(dn_db, ifa);
rv = dn_dev_insert_ifa(dn_db, ifa);
if (rv)
dn_dev_free_ifa(ifa);
return rv;
}
static int dn_dev_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
......@@ -651,7 +741,52 @@ static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
static void dn_send_endnode_hello(struct net_device *dev)
static int dn_dev_get_first(struct net_device *dev, dn_address *addr)
{
struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
struct dn_ifaddr *ifa;
int rv = -ENODEV;
if (dn_db == NULL)
goto out;
ifa = dn_db->ifa_list;
if (ifa != NULL) {
*addr = ifa->ifa_local;
rv = 0;
}
out:
return rv;
}
/*
* Find a default address to bind to.
*
* This is one of those areas where the initial VMS concepts don't really
* map onto the Linux concepts, and since we introduced multiple addresses
* per interface we have to cope with slightly odd ways of finding out what
* "our address" really is. Mostly its not a problem; for this we just guess
* 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)
{
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)
return rv;
}
dev = &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;
......@@ -667,7 +802,7 @@ static void dn_send_endnode_hello(struct net_device *dev)
msg->msgflg = 0x0D;
memcpy(msg->tiver, dn_eco_version, 3);
memcpy(msg->id, decnet_ether_address, 6);
dn_dn2eth(msg->id, ifa->ifa_local);
msg->iinfo = DN_RT_INFO_ENDN;
msg->blksize = dn_htons(dn_db->parms.blksize);
msg->area = 0x00;
......@@ -689,7 +824,7 @@ static void dn_send_endnode_hello(struct net_device *dev)
skb->nh.raw = skb->data;
dn_rt_finish_output(skb, dn_rt_all_rt_mcast);
dn_rt_finish_output(skb, dn_rt_all_rt_mcast, msg->id);
}
......@@ -697,7 +832,7 @@ static void dn_send_endnode_hello(struct net_device *dev)
#define DRDELAY (5 * HZ)
static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db)
static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn_ifaddr *ifa)
{
/* First check time since device went up */
if ((jiffies - dn_db->uptime) < DRDELAY)
......@@ -715,13 +850,13 @@ static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db)
if (dn->priority != dn_db->parms.priority)
return 0;
if (dn_ntohs(dn->addr) < dn_ntohs(decnet_address))
if (dn_ntohs(dn->addr) < dn_ntohs(ifa->ifa_local))
return 1;
return 0;
}
static void dn_send_router_hello(struct net_device *dev)
static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
{
int n;
struct dn_dev *dn_db = dev->dn_ptr;
......@@ -731,6 +866,7 @@ static void dn_send_router_hello(struct net_device *dev)
unsigned char *ptr;
unsigned char *i1, *i2;
unsigned short *pktlen;
char *src;
if (dn_db->parms.blksize < (26 + 7))
return;
......@@ -753,7 +889,8 @@ static void dn_send_router_hello(struct net_device *dev)
*ptr++ = 2; /* ECO */
*ptr++ = 0;
*ptr++ = 0;
memcpy(ptr, decnet_ether_address, ETH_ALEN);
dn_dn2eth(ptr, ifa->ifa_local);
src = ptr;
ptr += ETH_ALEN;
*ptr++ = dn_db->parms.forwarding == 1 ?
DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
......@@ -781,34 +918,34 @@ static void dn_send_router_hello(struct net_device *dev)
skb->nh.raw = skb->data;
if (dn_am_i_a_router(dn, dn_db)) {
if (dn_am_i_a_router(dn, dn_db, ifa)) {
struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
if (skb2) {
dn_rt_finish_output(skb2, dn_rt_all_end_mcast);
dn_rt_finish_output(skb2, dn_rt_all_end_mcast, src);
}
}
dn_rt_finish_output(skb, dn_rt_all_rt_mcast);
dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);
}
static void dn_send_brd_hello(struct net_device *dev)
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;
if (dn_db->parms.forwarding == 0)
dn_send_endnode_hello(dev);
dn_send_endnode_hello(dev, ifa);
else
dn_send_router_hello(dev);
dn_send_router_hello(dev, ifa);
}
#else
static void dn_send_brd_hello(struct net_device *dev)
static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
{
dn_send_endnode_hello(dev);
dn_send_endnode_hello(dev, ifa);
}
#endif
#if 0
static void dn_send_ptp_hello(struct net_device *dev)
static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
{
int tdlen = 16;
int size = dev->hard_header_len + 2 + 4 + tdlen;
......@@ -817,6 +954,7 @@ static void dn_send_ptp_hello(struct net_device *dev)
int i;
unsigned char *ptr;
struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
char src[ETH_ALEN];
if (skb == NULL)
return ;
......@@ -826,21 +964,15 @@ static void dn_send_ptp_hello(struct net_device *dev)
ptr = skb_put(skb, 2 + 4 + tdlen);
*ptr++ = DN_RT_PKT_HELO;
*((dn_address *)ptr) = decnet_address;
*((dn_address *)ptr) = ifa->ifa_local;
ptr += 2;
*ptr++ = tdlen;
for(i = 0; i < tdlen; i++)
*ptr++ = 0252;
if (dn_am_i_a_router(dn, dn_db)) {
struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
if (skb2) {
dn_rt_finish_output(skb2, dn_rt_all_end_mcast);
}
}
dn_rt_finish_output(skb, dn_rt_all_rt_mcast);
dn_dn2eth(src, ifa->ifa_local);
dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);
}
#endif
......@@ -860,16 +992,31 @@ static int dn_eth_up(struct net_device *dev)
return 0;
}
static void dn_eth_down(struct net_device *dev)
{
struct dn_dev *dn_db = dev->dn_ptr;
if (dn_db->parms.forwarding == 0)
dev_mc_delete(dev, dn_rt_all_end_mcast, ETH_ALEN, 0);
else
dev_mc_delete(dev, dn_rt_all_rt_mcast, ETH_ALEN, 0);
}
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_ifaddr *ifa;
if (dn_db->t3 <= dn_db->parms.t2) {
if (dn_db->parms.timer3)
dn_db->parms.timer3(dev);
if (dn_db->parms.timer3) {
for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) {
if (!(ifa->ifa_flags & IFA_F_SECONDARY))
dn_db->parms.timer3(dev, ifa);
}
}
dn_db->t3 = dn_db->parms.t3;
} else {
dn_db->t3 -= dn_db->parms.t2;
......@@ -917,8 +1064,6 @@ struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
dn_db->dev = dev;
init_timer(&dn_db->timer);
memcpy(dn_db->addr, decnet_ether_address, ETH_ALEN); /* To go... */
dn_db->uptime = jiffies;
if (dn_db->parms.up) {
if (dn_db->parms.up(dev) < 0) {
......@@ -929,7 +1074,6 @@ struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
}
dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);
/* dn_db->neigh_parms->neigh_setup = dn_db->parms.neigh_setup; */
dn_dev_sysctl_register(dev, &dn_db->parms);
......@@ -945,27 +1089,64 @@ struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
* the loopback device & ethernet devices with correct
* MAC addreses automatically. Others must be started
* specifically.
*
* FIXME: How should we configure the loopback address ? If we could dispense
* with using decnet_address here and for autobind, it will be one less thing
* for users to worry about setting up.
*/
void dn_dev_up(struct net_device *dev)
{
struct dn_ifaddr *ifa;
dn_address addr = decnet_address;
int maybe_default = 0;
struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK))
return;
if (dev->type == ARPHRD_ETHER)
if (memcmp(dev->dev_addr, decnet_ether_address, ETH_ALEN) != 0)
/*
* Need to ensure that loopback device has a dn_db attached to it
* to allow creation of neighbours against it, even though it might
* not have a local address of its own. Might as well do the same for
* all autoconfigured interfaces.
*/
if (dn_db == NULL) {
int err;
dn_db = dn_dev_create(dev, &err);
if (dn_db == NULL)
return;
}
if (dev->type == ARPHRD_ETHER) {
if (memcmp(dev->dev_addr, dn_hiord, 4) != 0)
return;
addr = dn_htons(dn_eth2dn(dev->dev_addr));
maybe_default = 1;
}
if (addr == 0)
return;
if ((ifa = dn_dev_alloc_ifa()) == NULL)
return;
ifa->ifa_local = decnet_address;
ifa->ifa_local = addr;
ifa->ifa_flags = 0;
ifa->ifa_scope = RT_SCOPE_UNIVERSE;
strcpy(ifa->ifa_label, dev->name);
dn_dev_set_ifa(dev, ifa);
/*
* Automagically set the default device to the first automatically
* configured ethernet card in the system.
*/
if (maybe_default) {
dev_hold(dev);
if (dn_dev_set_default(dev, 0))
dev_put(dev);
}
}
static void dn_dev_delete(struct net_device *dev)
......@@ -976,14 +1157,10 @@ static void dn_dev_delete(struct net_device *dev)
return;
del_timer_sync(&dn_db->timer);
dn_dev_sysctl_unregister(&dn_db->parms);
dn_dev_check_default(dev);
neigh_ifdown(&dn_neigh_table, dev);
if (dev == decnet_default_device)
decnet_default_device = NULL;
if (dn_db->parms.down)
dn_db->parms.down(dev);
......@@ -1204,8 +1381,28 @@ static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
#endif
};
#ifdef MODULE
static int addr[2] = {0, 0};
MODULE_PARM(addr, "2i");
MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
#endif
void __init dn_dev_init(void)
{
#ifdef MODULE
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;
}
decnet_address = dn_htons((addr[0] << 10) | addr[1]);
#endif
dn_dev_devices_on();
#ifdef CONFIG_DECNET_SIOCGIFCONF
......@@ -1247,3 +1444,18 @@ void __exit dn_dev_cleanup(void)
dn_dev_devices_off();
}
#ifndef MODULE
static int __init decnet_setup(char *str)
{
unsigned short area = simple_strtoul(str, &str, 0);
unsigned short node = simple_strtoul(*str > 0 ? ++str : str, &str, 0);
decnet_address = dn_htons(area << 10 | node);
return 1;
}
__setup("decnet=", decnet_setup);
#endif
......@@ -181,10 +181,13 @@ 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 dn_route *rt = (struct dn_route *)dst;
struct neighbour *neigh = dst->neighbour;
struct net_device *dev = neigh->dev;
char mac_addr[ETH_ALEN];
if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len) >= 0)
dn_dn2eth(mac_addr, rt->rt_saddr);
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())
......
......@@ -334,7 +334,7 @@ static int dn_return_short(struct sk_buff *skb)
*dst = tmp;
skb->pkt_type = PACKET_OUTGOING;
dn_rt_finish_output(skb, NULL);
dn_rt_finish_output(skb, NULL, NULL);
return NET_RX_SUCCESS;
}
......@@ -380,7 +380,7 @@ static int dn_return_long(struct sk_buff *skb)
memcpy(dst_addr, tmp, ETH_ALEN);
skb->pkt_type = PACKET_OUTGOING;
dn_rt_finish_output(skb, tmp);
dn_rt_finish_output(skb, dst_addr, src_addr);
return NET_RX_SUCCESS;
}
......@@ -641,7 +641,9 @@ static int dn_forward(struct sk_buff *skb)
struct dn_skb_cb *cb = DN_SKB_CB(skb);
struct dst_entry *dst = skb->dst;
struct neighbour *neigh;
#ifdef CONFIG_NETFILTER
struct net_device *dev = skb->dev;
#endif
int err = -EINVAL;
if ((neigh = dst->neighbour) == NULL)
......@@ -711,10 +713,11 @@ static int dn_rt_bug(struct sk_buff *skb)
static int dn_route_output_slow(struct dst_entry **pprt, dn_address dst, dn_address src, int flags)
{
struct dn_route *rt = NULL;
struct net_device *dev = decnet_default_device;
struct net_device *dev = NULL;
struct neighbour *neigh = NULL;
struct dn_dev *dn_db;
unsigned hash;
#ifdef CONFIG_DECNET_ROUTER
struct dn_fib_key key;
struct dn_fib_res res;
......@@ -765,13 +768,25 @@ static int dn_route_output_slow(struct dst_entry **pprt, dn_address dst, dn_addr
goto got_route;
}
dev = dn_dev_get_default();
if (dev == NULL)
return -EINVAL;
dn_db = dev->dn_ptr;
if (dn_db == NULL)
/* Check to see if its one of our own local addresses */
if (dn_dev_islocal(dev, dst)) {
struct net_device *lo = &loopback_dev;
if (lo->dn_ptr) {
neigh = __neigh_lookup(&dn_neigh_table, &dst, lo, 1);
if (neigh)
goto got_route;
}
if (net_ratelimit())
printk("dn_route_output_slow: Dest is local interface address, but loopback device is not up\n");
dev_put(dev);
return -EINVAL;
}
/* Try default router */
if ((neigh = neigh_clone(dn_db->router)) != NULL)
......@@ -781,10 +796,12 @@ static int dn_route_output_slow(struct dst_entry **pprt, dn_address dst, dn_addr
if ((neigh = __neigh_lookup(&dn_neigh_table, &dst, dev, 1)) != NULL)
goto got_route;
dev_put(dev);
return -EINVAL;
got_route:
if (dev)
dev_put(dev);
if ((rt = dst_alloc(&dn_dst_ops)) == NULL) {
neigh_release(neigh);
......@@ -809,7 +826,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, dn_address dst, dn_addr
rt->u.dst.output = dn_output;
rt->u.dst.input = dn_rt_bug;
if (dn_dev_islocal(neigh->dev, rt->rt_daddr))
if (neigh->dev->flags & IFF_LOOPBACK)
rt->u.dst.input = dn_nsp_rx;
hash = dn_hash(rt->key.saddr, rt->key.daddr);
......
......@@ -9,6 +9,7 @@
*
*
* Changes:
* Steve Whitehouse - C99 changes and default device handling
*
*/
#include <linux/config.h>
......@@ -152,7 +153,6 @@ static int dn_node_address_strategy(ctl_table *table, int *name, int nlen,
dn_dev_devices_off();
decnet_address = addr;
dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
dn_dev_devices_on();
}
......@@ -187,7 +187,6 @@ static int dn_node_address_handler(ctl_table *table, int write,
dn_dev_devices_off();
decnet_address = dnaddr;
dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
dn_dev_devices_on();
......@@ -218,9 +217,10 @@ static int dn_def_dev_strategy(ctl_table *table, int *name, int nlen,
void **context)
{
size_t len;
struct net_device *dev = decnet_default_device;
struct net_device *dev;
char devname[17];
size_t namel;
int rv = 0;
devname[0] = 0;
......@@ -228,8 +228,11 @@ static int dn_def_dev_strategy(ctl_table *table, int *name, int nlen,
if (get_user(len, oldlenp))
return -EFAULT;
if (len) {
if (dev)
dev = dn_dev_get_default();
if (dev) {
strcpy(devname, dev->name);
dev_put(dev);
}
namel = strlen(devname) + 1;
if (len > namel) len = namel;
......@@ -251,16 +254,19 @@ static int dn_def_dev_strategy(ctl_table *table, int *name, int nlen,
devname[newlen] = 0;
if ((dev = __dev_get_by_name(devname)) == NULL)
dev = dev_get_by_name(devname);
if (dev == NULL)
return -ENODEV;
if (dev->dn_ptr == NULL)
return -ENODEV;
decnet_default_device = dev;
rv = -ENODEV;
if (dev->dn_ptr != NULL) {
rv = dn_dev_set_default(dev, 1);
if (rv)
dev_put(dev);
}
}
return 0;
return rv;
}
......@@ -269,7 +275,7 @@ static int dn_def_dev_handler(ctl_table *table, int write,
void *buffer, size_t *lenp)
{
size_t len;
struct net_device *dev = decnet_default_device;
struct net_device *dev;
char devname[17];
if (!*lenp || (filp->f_pos && !write)) {
......@@ -287,24 +293,32 @@ static int dn_def_dev_handler(ctl_table *table, int write,
devname[*lenp] = 0;
strip_it(devname);
if ((dev = __dev_get_by_name(devname)) == NULL)
dev = dev_get_by_name(devname);
if (dev == NULL)
return -ENODEV;
if (dev->dn_ptr == NULL)
if (dev->dn_ptr == NULL) {
dev_put(dev);
return -ENODEV;
}
decnet_default_device = dev;
if (dn_dev_set_default(dev, 1)) {
dev_put(dev);
return -ENODEV;
}
filp->f_pos += *lenp;
return 0;
}
dev = dn_dev_get_default();
if (dev == NULL) {
*lenp = 0;
return 0;
}
strcpy(devname, dev->name);
dev_put(dev);
len = strlen(devname);
devname[len++] = '\n';
......@@ -320,51 +334,125 @@ static int dn_def_dev_handler(ctl_table *table, int write,
}
static ctl_table dn_table[] = {
{NET_DECNET_NODE_ADDRESS, "node_address", NULL, 7, 0644, NULL,
dn_node_address_handler, dn_node_address_strategy, NULL,
NULL, NULL},
{NET_DECNET_NODE_NAME, "node_name", node_name, 7, 0644, NULL,
&proc_dostring, &sysctl_string, NULL, NULL, NULL},
{NET_DECNET_DEFAULT_DEVICE, "default_device", NULL, 16, 0644, NULL,
dn_def_dev_handler, dn_def_dev_strategy, NULL, NULL, NULL},
{NET_DECNET_TIME_WAIT, "time_wait", &decnet_time_wait,
sizeof(int), 0644,
NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
&min_decnet_time_wait, &max_decnet_time_wait},
{NET_DECNET_DN_COUNT, "dn_count", &decnet_dn_count,
sizeof(int), 0644,
NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
&min_state_count, &max_state_count},
{NET_DECNET_DI_COUNT, "di_count", &decnet_di_count,
sizeof(int), 0644,
NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
&min_state_count, &max_state_count},
{NET_DECNET_DR_COUNT, "dr_count", &decnet_dr_count,
sizeof(int), 0644,
NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
&min_state_count, &max_state_count},
{NET_DECNET_DST_GC_INTERVAL, "dst_gc_interval", &decnet_dst_gc_interval,
sizeof(int), 0644,
NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
&min_decnet_dst_gc_interval, &max_decnet_dst_gc_interval},
{NET_DECNET_NO_FC_MAX_CWND, "no_fc_max_cwnd", &decnet_no_fc_max_cwnd,
sizeof(int), 0644,
NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
&min_decnet_no_fc_max_cwnd, &max_decnet_no_fc_max_cwnd},
{NET_DECNET_DEBUG_LEVEL, "debug", &decnet_debug_level,
sizeof(int), 0644,
NULL, &proc_dointvec, &sysctl_intvec, NULL,
NULL, NULL},
{
.ctl_name = NET_DECNET_NODE_ADDRESS,
.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,
.maxlen = 7,
.mode = 0644,
.proc_handler = &proc_dostring,
.strategy = &sysctl_string,
},
{
.ctl_name = NET_DECNET_DEFAULT_DEVICE,
.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,
.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,
.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,
.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,
.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,
.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,
.extra1 = &min_decnet_no_fc_max_cwnd,
.extra2 = &max_decnet_no_fc_max_cwnd
},
{
.ctl_name = NET_DECNET_DEBUG_LEVEL,
.procname = "debug",
.data = &decnet_debug_level,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
.strategy = &sysctl_intvec,
},
{0}
};
static ctl_table dn_dir_table[] = {
{NET_DECNET, "decnet", NULL, 0, 0555, dn_table},
{
.ctl_name = NET_DECNET,
.procname = "decnet",
.mode = 0555,
.child = dn_table},
{0}
};
static ctl_table dn_root_table[] = {
{CTL_NET, "net", NULL, 0, 0555, dn_dir_table},
{
.ctl_name = CTL_NET,
.procname = "net",
.mode = 0555,
.child = dn_dir_table
},
{0}
};
......
......@@ -1093,6 +1093,25 @@ void inet_unregister_protosw(struct inet_protosw *p)
}
}
#ifdef CONFIG_IP_MULTICAST
static struct inet_protocol igmp_protocol = {
.handler = igmp_rcv,
};
#endif
static struct inet_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
};
static struct inet_protocol udp_protocol = {
.handler = udp_rcv,
.err_handler = udp_err,
};
static struct inet_protocol icmp_protocol = {
.handler = icmp_rcv,
};
/*
* Called by socket.c on kernel startup.
......@@ -1101,7 +1120,6 @@ void inet_unregister_protosw(struct inet_protosw *p)
static int __init inet_init(void)
{
struct sk_buff *dummy_skb;
struct inet_protocol *p;
struct inet_protosw *q;
struct list_head *r;
......@@ -1131,16 +1149,19 @@ static int __init inet_init(void)
(void)sock_register(&inet_family_ops);
/*
* Add all the protocols.
* Add all the base protocols.
*/
printk(KERN_INFO "IP Protocols: ");
for (p = inet_protocol_base; p;) {
struct inet_protocol *tmp = (struct inet_protocol *)p->next;
inet_add_protocol(p);
printk("%s%s", p->name, tmp ? ", " : "\n");
p = tmp;
}
if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");
if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");
if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
#ifdef CONFIG_IP_MULTICAST
if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)
printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
#endif
/* Register the socket-side information for inet_create. */
for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
......
......@@ -719,23 +719,10 @@ static void icmp_unreach(struct sk_buff *skb)
* we are OK.
*/
ipprot = (struct inet_protocol *)inet_protos[hash];
while (ipprot) {
struct inet_protocol *nextip;
ipprot = inet_protos[hash];
if (ipprot && ipprot->err_handler)
ipprot->err_handler(skb, info);
nextip = (struct inet_protocol *)ipprot->next;
/*
* Pass it off to everyone who wants it.
*/
/* RFC1122: OK. Passes appropriate ICMP errors to the */
/* appropriate protocol layer (MUST), as per 3.2.2. */
if (protocol == ipprot->protocol && ipprot->err_handler)
ipprot->err_handler(skb, info);
ipprot = nextip;
}
out:
return;
out_err:
......
......@@ -1259,13 +1259,8 @@ int __init ipgre_fb_tunnel_init(struct net_device *dev)
static struct inet_protocol ipgre_protocol = {
ipgre_rcv, /* GRE handler */
ipgre_err, /* TUNNEL error control */
0, /* next */
IPPROTO_GRE, /* protocol ID */
0, /* copy */
NULL, /* data */
"GRE" /* name */
.handler = ipgre_rcv,
.err_handler = ipgre_err,
};
......@@ -1281,9 +1276,13 @@ int __init ipgre_init(void)
{
printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
if (inet_add_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) {
printk(KERN_INFO "ipgre init: can't add protocol\n");
return -EAGAIN;
}
ipgre_fb_tunnel_dev.priv = (void*)&ipgre_fb_tunnel;
register_netdev(&ipgre_fb_tunnel_dev);
inet_add_protocol(&ipgre_protocol);
return 0;
}
......@@ -1291,7 +1290,7 @@ int __init ipgre_init(void)
void cleanup_module(void)
{
if ( inet_del_protocol(&ipgre_protocol) < 0 )
if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
printk(KERN_INFO "ipgre close: can't remove protocol\n");
unregister_netdev(&ipgre_fb_tunnel_dev);
......
......@@ -194,28 +194,6 @@ int ip_call_ra_chain(struct sk_buff *skb)
return 0;
}
/* Handle this out of line, it is rare. */
static int ip_run_ipprot(struct sk_buff *skb, struct iphdr *iph,
struct inet_protocol *ipprot, int force_copy)
{
int ret = 0;
do {
if (ipprot->protocol == iph->protocol) {
struct sk_buff *skb2 = skb;
if (ipprot->copy || force_copy)
skb2 = skb_clone(skb, GFP_ATOMIC);
if(skb2 != NULL) {
ret = 1;
ipprot->handler(skb2);
}
}
ipprot = (struct inet_protocol *) ipprot->next;
} while(ipprot != NULL);
return ret;
}
static inline int ip_local_deliver_finish(struct sk_buff *skb)
{
int ihl = skb->nh.iph->ihl*4;
......@@ -239,44 +217,31 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
{
/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
int protocol = skb->nh.iph->protocol;
int hash = protocol & (MAX_INET_PROTOS - 1);
struct sock *raw_sk = raw_v4_htable[hash];
int hash;
struct sock *raw_sk;
struct inet_protocol *ipprot;
int flag;
resubmit:
hash = protocol & (MAX_INET_PROTOS - 1);
raw_sk = raw_v4_htable[hash];
/* If there maybe a raw socket we must check - if not we
* don't care less
*/
if(raw_sk != NULL)
raw_sk = raw_v4_input(skb, skb->nh.iph, hash);
ipprot = (struct inet_protocol *) inet_protos[hash];
flag = 0;
if(ipprot != NULL) {
if(raw_sk == NULL &&
ipprot->next == NULL &&
ipprot->protocol == protocol) {
int ret;
/* Fast path... */
ret = ipprot->handler(skb);
return ret;
} else {
flag = ip_run_ipprot(skb, skb->nh.iph, ipprot, (raw_sk != NULL));
if (raw_sk)
raw_v4_input(skb, skb->nh.iph, hash);
if ((ipprot = inet_protos[hash]) != NULL) {
int ret = ipprot->handler(skb);
if (ret < 0) {
protocol = -ret;
goto resubmit;
}
} else {
if (!raw_sk) {
icmp_send(skb, ICMP_DEST_UNREACH,
ICMP_PROT_UNREACH, 0);
}
}
/* All protocols checked.
* If this packet was a broadcast, we may *not* reply to it, since that
* causes (proven, grin) ARP storms and a leakage of memory (i.e. all
* ICMP reply messages get queued up for transmission...)
*/
if(raw_sk != NULL) { /* Shift to last raw user */
raw_rcv(raw_sk, skb);
sock_put(raw_sk);
} else if (!flag) { /* Free and report errors */
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
kfree_skb(skb);
}
}
......
......@@ -877,10 +877,8 @@ int __init ipip_fb_tunnel_init(struct net_device *dev)
}
static struct inet_protocol ipip_protocol = {
.handler = ipip_rcv,
.err_handler = ipip_err,
.protocol = IPPROTO_IPIP,
.name = "IPIP"
.handler = ipip_rcv,
.err_handler = ipip_err,
};
static char banner[] __initdata =
......@@ -890,15 +888,19 @@ int __init ipip_init(void)
{
printk(banner);
if (inet_add_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) {
printk(KERN_INFO "ipip init: can't add protocol\n");
return -EAGAIN;
}
ipip_fb_tunnel_dev.priv = (void*)&ipip_fb_tunnel;
register_netdev(&ipip_fb_tunnel_dev);
inet_add_protocol(&ipip_protocol);
return 0;
}
static void __exit ipip_fini(void)
{
if ( inet_del_protocol(&ipip_protocol) < 0 )
if (inet_del_protocol(&ipip_protocol, IPPROTO_IPIP) < 0)
printk(KERN_INFO "ipip close: can't remove protocol\n");
unregister_netdev(&ipip_fb_tunnel_dev);
......
......@@ -108,7 +108,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert);
static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm);
extern struct inet_protocol pim_protocol;
static struct inet_protocol pim_protocol;
static struct timer_list ipmr_expire_timer;
......@@ -928,23 +928,28 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen)
#ifdef CONFIG_IP_PIMSM
case MRT_PIM:
{
int v;
int v, ret;
if(get_user(v,(int *)optval))
return -EFAULT;
v = (v)?1:0;
rtnl_lock();
ret = 0;
if (v != mroute_do_pim) {
mroute_do_pim = v;
mroute_do_assert = v;
#ifdef CONFIG_IP_PIMSM_V2
if (mroute_do_pim)
inet_add_protocol(&pim_protocol);
ret = inet_add_protocol(&pim_protocol,
IPPROTO_PIM);
else
inet_del_protocol(&pim_protocol);
ret = inet_del_protocol(&pim_protocol,
IPPROTO_PIM);
if (ret < 0)
ret = -EAGAIN;
#endif
}
rtnl_unlock();
return 0;
return ret;
}
#endif
/*
......@@ -1727,15 +1732,8 @@ static int ipmr_mfc_info(char *buffer, char **start, off_t offset, int length)
#endif
#ifdef CONFIG_IP_PIMSM_V2
struct inet_protocol pim_protocol =
{
pim_rcv, /* PIM handler */
NULL, /* PIM error control */
NULL, /* next */
IPPROTO_PIM, /* protocol ID */
0, /* copy */
NULL, /* data */
"PIM" /* name */
static struct inet_protocol pim_protocol = {
.handler = pim_rcv,
};
#endif
......
......@@ -48,134 +48,52 @@
#include <net/ipip.h>
#include <linux/igmp.h>
#define IPPROTO_PREVIOUS NULL
#ifdef CONFIG_IP_MULTICAST
static struct inet_protocol igmp_protocol = {
.handler = igmp_rcv,
.next = IPPROTO_PREVIOUS,
.protocol = IPPROTO_IGMP,
.name = "IGMP"
};
#undef IPPROTO_PREVIOUS
#define IPPROTO_PREVIOUS &igmp_protocol
#endif
static struct inet_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
.next = IPPROTO_PREVIOUS,
.protocol = IPPROTO_TCP,
.name = "TCP"
};
#undef IPPROTO_PREVIOUS
#define IPPROTO_PREVIOUS &tcp_protocol
static struct inet_protocol udp_protocol = {
.handler = udp_rcv,
.err_handler = udp_err,
.next = IPPROTO_PREVIOUS,
.protocol = IPPROTO_UDP,
.name = "UDP"
};
#undef IPPROTO_PREVIOUS
#define IPPROTO_PREVIOUS &udp_protocol
static struct inet_protocol icmp_protocol = {
.handler = icmp_rcv,
.next = IPPROTO_PREVIOUS,
.protocol = IPPROTO_ICMP,
.name = "ICMP"
};
#undef IPPROTO_PREVIOUS
#define IPPROTO_PREVIOUS &icmp_protocol
struct inet_protocol *inet_protocol_base = IPPROTO_PREVIOUS;
struct inet_protocol *inet_protos[MAX_INET_PROTOS];
/*
* Add a protocol handler to the hash tables
*/
void inet_add_protocol(struct inet_protocol *prot)
int inet_add_protocol(struct inet_protocol *prot, unsigned char protocol)
{
unsigned char hash;
struct inet_protocol *p2;
int hash, ret;
hash = protocol & (MAX_INET_PROTOS - 1);
hash = prot->protocol & (MAX_INET_PROTOS - 1);
br_write_lock_bh(BR_NETPROTO_LOCK);
prot ->next = inet_protos[hash];
inet_protos[hash] = prot;
prot->copy = 0;
/*
* Set the copy bit if we need to.
*/
p2 = (struct inet_protocol *) prot->next;
while (p2) {
if (p2->protocol == prot->protocol) {
prot->copy = 1;
break;
}
p2 = (struct inet_protocol *) p2->next;
if (inet_protos[hash]) {
ret = -1;
} else {
inet_protos[hash] = prot;
ret = 0;
}
br_write_unlock_bh(BR_NETPROTO_LOCK);
return ret;
}
/*
* Remove a protocol from the hash tables.
*/
int inet_del_protocol(struct inet_protocol *prot)
int inet_del_protocol(struct inet_protocol *prot, unsigned char protocol)
{
struct inet_protocol *p;
struct inet_protocol *lp = NULL;
unsigned char hash;
int hash, ret;
hash = prot->protocol & (MAX_INET_PROTOS - 1);
br_write_lock_bh(BR_NETPROTO_LOCK);
if (prot == inet_protos[hash]) {
inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
br_write_unlock_bh(BR_NETPROTO_LOCK);
return 0;
}
hash = protocol & (MAX_INET_PROTOS - 1);
p = (struct inet_protocol *) inet_protos[hash];
if (p != NULL && p->protocol == prot->protocol)
lp = p;
while (p) {
/*
* We have to worry if the protocol being deleted is
* the last one on the list, then we may need to reset
* someone's copied bit.
*/
if (p->next && p->next == prot) {
/*
* if we are the last one with this protocol and
* there is a previous one, reset its copy bit.
*/
if (prot->copy == 0 && lp != NULL)
lp->copy = 0;
p->next = prot->next;
br_write_unlock_bh(BR_NETPROTO_LOCK);
return 0;
}
if (p->next != NULL && p->next->protocol == prot->protocol)
lp = p->next;
br_write_lock_bh(BR_NETPROTO_LOCK);
p = (struct inet_protocol *) p->next;
if (inet_protos[hash] == prot) {
inet_protos[hash] = NULL;
ret = 0;
} else {
ret = -1;
}
br_write_unlock_bh(BR_NETPROTO_LOCK);
return -1;
return ret;
}
......@@ -135,13 +135,12 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
}
/* IP input processing comes here for RAW socket delivery.
* This is fun as to avoid copies we want to make no surplus
* copies.
* Caller owns SKB, so we must make clones.
*
* RFC 1122: SHOULD pass TOS value up to the transport layer.
* -> It does. And not only TOS, but all IP header.
*/
struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
{
struct sock *sk;
......@@ -153,28 +152,19 @@ struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
skb->dev->ifindex);
while (sk) {
struct sock *sknext = __raw_v4_lookup(sk->next, iph->protocol,
iph->saddr, iph->daddr,
skb->dev->ifindex);
if (iph->protocol != IPPROTO_ICMP ||
!icmp_filter(sk, skb)) {
struct sk_buff *clone;
if (!sknext)
break;
clone = skb_clone(skb, GFP_ATOMIC);
if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) {
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
/* Not releasing hash table! */
if (clone)
raw_rcv(sk, clone);
}
sk = sknext;
sk = __raw_v4_lookup(sk->next, iph->protocol,
iph->saddr, iph->daddr,
skb->dev->ifindex);
}
out:
if (sk)
sock_hold(sk);
read_unlock(&raw_v4_lock);
return sk;
}
void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
......
......@@ -152,15 +152,15 @@ int ipv6_addr_type(struct in6_addr *addr)
int type = IPV6_ADDR_MULTICAST;
switch((st & htonl(0x00FF0000))) {
case htonl(0x00010000):
case __constant_htonl(0x00010000):
type |= IPV6_ADDR_LOOPBACK;
break;
case htonl(0x00020000):
case __constant_htonl(0x00020000):
type |= IPV6_ADDR_LINKLOCAL;
break;
case htonl(0x00050000):
case __constant_htonl(0x00050000):
type |= IPV6_ADDR_SITELOCAL;
break;
};
......@@ -786,7 +786,7 @@ static void addrconf_add_lroute(struct net_device *dev)
struct in6_addr addr;
ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0);
addrconf_prefix_route(&addr, 10, dev, 0, RTF_ADDRCONF);
addrconf_prefix_route(&addr, 64, dev, 0, RTF_ADDRCONF);
}
static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
......@@ -1161,7 +1161,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
flag |= IFA_HOST;
}
if (idev->dev->flags&IFF_POINTOPOINT)
plen = 10;
plen = 64;
else
plen = 96;
......@@ -1211,7 +1211,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr
{
struct inet6_ifaddr * ifp;
ifp = ipv6_add_addr(idev, addr, 10, IFA_LINK, IFA_F_PERMANENT);
ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
if (ifp) {
addrconf_dad_start(ifp);
in6_ifa_put(ifp);
......
......@@ -70,15 +70,8 @@ struct socket *icmpv6_socket;
static int icmpv6_rcv(struct sk_buff *skb);
static struct inet6_protocol icmpv6_protocol =
{
icmpv6_rcv, /* handler */
NULL, /* error control */
NULL, /* next */
IPPROTO_ICMPV6, /* protocol ID */
0, /* copy */
NULL, /* data */
"ICMPv6" /* name */
static struct inet6_protocol icmpv6_protocol = {
.handler = icmpv6_rcv,
};
struct icmpv6_msg {
......@@ -467,15 +460,9 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
hash = nexthdr & (MAX_INET_PROTOS - 1);
for (ipprot = (struct inet6_protocol *) inet6_protos[hash];
ipprot != NULL;
ipprot=(struct inet6_protocol *)ipprot->next) {
if (ipprot->protocol != nexthdr)
continue;
if (ipprot->err_handler)
ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
}
ipprot = inet6_protos[hash];
if (ipprot && ipprot->err_handler)
ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
read_lock(&raw_v6_lock);
if ((sk = raw_v6_htable[hash]) != NULL) {
......@@ -651,7 +638,12 @@ int __init icmpv6_init(struct net_proto_family *ops)
sk->sndbuf = SK_WMEM_MAX*2;
sk->prot->unhash(sk);
inet6_add_protocol(&icmpv6_protocol);
if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) {
printk(KERN_ERR "Failed to register ICMP6 protocol\n");
sock_release(icmpv6_socket);
icmpv6_socket = NULL;
return -EAGAIN;
}
return 0;
}
......@@ -660,7 +652,7 @@ void icmpv6_cleanup(void)
{
sock_release(icmpv6_socket);
icmpv6_socket = NULL; /* For safety. */
inet6_del_protocol(&icmpv6_protocol);
inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
}
static struct icmp6_err {
......
......@@ -126,7 +126,6 @@ static inline int ip6_input_finish(struct sk_buff *skb)
struct sock *raw_sk;
int nhoff;
int nexthdr;
int found = 0;
u8 hash;
skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
......@@ -164,39 +163,24 @@ static inline int ip6_input_finish(struct sk_buff *skb)
skb->csum = csum_sub(skb->csum,
csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
raw_sk = raw_v6_htable[nexthdr&(MAX_INET_PROTOS-1)];
resubmit:
raw_sk = raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)];
if (raw_sk)
raw_sk = ipv6_raw_deliver(skb, nexthdr);
ipv6_raw_deliver(skb, nexthdr);
hash = nexthdr & (MAX_INET_PROTOS - 1);
for (ipprot = (struct inet6_protocol *) inet6_protos[hash];
ipprot != NULL;
ipprot = (struct inet6_protocol *) ipprot->next) {
struct sk_buff *buff = skb;
if (ipprot->protocol != nexthdr)
continue;
if (ipprot->copy || raw_sk)
buff = skb_clone(skb, GFP_ATOMIC);
if (buff)
ipprot->handler(buff);
found = 1;
}
if (raw_sk) {
rawv6_rcv(raw_sk, skb);
sock_put(raw_sk);
found = 1;
}
/*
* not found: send ICMP parameter problem back
*/
if (!found) {
IP6_INC_STATS_BH(Ip6InUnknownProtos);
icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
if ((ipprot = inet6_protos[hash]) != NULL) {
int ret = ipprot->handler(skb);
if (ret < 0) {
nexthdr = -ret;
goto resubmit;
}
} else {
if (!raw_sk) {
IP6_INC_STATS_BH(Ip6InUnknownProtos);
icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
}
kfree_skb(skb);
}
return 0;
......
......@@ -42,77 +42,42 @@
struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
void inet6_add_protocol(struct inet6_protocol *prot)
int inet6_add_protocol(struct inet6_protocol *prot, unsigned char protocol)
{
unsigned char hash;
struct inet6_protocol *p2;
int ret, hash = protocol & (MAX_INET_PROTOS - 1);
hash = prot->protocol & (MAX_INET_PROTOS - 1);
br_write_lock_bh(BR_NETPROTO_LOCK);
prot->next = inet6_protos[hash];
inet6_protos[hash] = prot;
prot->copy = 0;
/*
* Set the copy bit if we need to.
*/
p2 = (struct inet6_protocol *) prot->next;
while(p2 != NULL) {
if (p2->protocol == prot->protocol) {
prot->copy = 1;
break;
}
p2 = (struct inet6_protocol *) p2->next;
if (inet6_protos[hash]) {
ret = -1;
} else {
inet6_protos[hash] = prot;
ret = 0;
}
br_write_unlock_bh(BR_NETPROTO_LOCK);
return ret;
}
/*
* Remove a protocol from the hash tables.
*/
int inet6_del_protocol(struct inet6_protocol *prot)
int inet6_del_protocol(struct inet6_protocol *prot, unsigned char protocol)
{
struct inet6_protocol *p;
struct inet6_protocol *lp = NULL;
unsigned char hash;
int ret, hash = protocol & (MAX_INET_PROTOS - 1);
hash = prot->protocol & (MAX_INET_PROTOS - 1);
br_write_lock_bh(BR_NETPROTO_LOCK);
if (prot == inet6_protos[hash]) {
inet6_protos[hash] = (struct inet6_protocol *) inet6_protos[hash]->next;
br_write_unlock_bh(BR_NETPROTO_LOCK);
return(0);
}
p = (struct inet6_protocol *) inet6_protos[hash];
if (p != NULL && p->protocol == prot->protocol)
lp = p;
while(p != NULL) {
/*
* We have to worry if the protocol being deleted is
* the last one on the list, then we may need to reset
* someone's copied bit.
*/
if (p->next != NULL && p->next == prot) {
/*
* if we are the last one with this protocol and
* there is a previous one, reset its copy bit.
*/
if (prot->copy == 0 && lp != NULL)
lp->copy = 0;
p->next = prot->next;
br_write_unlock_bh(BR_NETPROTO_LOCK);
return(0);
}
if (p->next != NULL && p->next->protocol == prot->protocol)
lp = p->next;
p = (struct inet6_protocol *) p->next;
if (inet6_protos[hash] != prot) {
ret = -1;
} else {
inet6_protos[hash] = NULL;
ret = 0;
}
br_write_unlock_bh(BR_NETPROTO_LOCK);
return(-1);
return ret;
}
......@@ -133,12 +133,14 @@ static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
* demultiplex raw sockets.
* (should consider queueing the skb in the sock receive_queue
* without calling rawv6.c)
*
* Caller owns SKB so we must make clones.
*/
struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
{
struct in6_addr *saddr;
struct in6_addr *daddr;
struct sock *sk, *sk2;
struct sock *sk;
__u8 hash;
saddr = &skb->nh.ipv6h->saddr;
......@@ -159,30 +161,18 @@ struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr);
if (sk) {
sk2 = sk;
while ((sk2 = __raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) {
struct sk_buff *buff;
if (nexthdr == IPPROTO_ICMPV6 &&
icmpv6_filter(sk2, skb))
continue;
while (sk) {
if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) {
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
buff = skb_clone(skb, GFP_ATOMIC);
if (buff)
rawv6_rcv(sk2, buff);
/* Not releasing hash table! */
if (clone)
rawv6_rcv(sk, clone);
}
sk = __raw_v6_lookup(sk->next, nexthdr, daddr, saddr);
}
if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb))
sk = NULL;
out:
if (sk)
sock_hold(sk);
read_unlock(&raw_v6_lock);
return sk;
}
/* This cleans up af_inet6 a bit. -DaveM */
......
......@@ -835,19 +835,14 @@ int __init ipip6_fb_tunnel_init(struct net_device *dev)
}
static struct inet_protocol sit_protocol = {
ipip6_rcv,
ipip6_err,
0,
IPPROTO_IPV6,
0,
NULL,
"IPv6"
.handler = ipip6_rcv,
.err_handler = ipip6_err,
};
#ifdef MODULE
void sit_cleanup(void)
{
inet_del_protocol(&sit_protocol);
inet_del_protocol(&sit_protocol, IPPROTO_IPV6);
unregister_netdev(&ipip6_fb_tunnel_dev);
}
#endif
......@@ -856,9 +851,13 @@ int __init sit_init(void)
{
printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n");
if (inet_add_protocol(&sit_protocol, IPPROTO_IPV6) < 0) {
printk(KERN_INFO "sit init: Can't add protocol\n");
return -EAGAIN;
}
ipip6_fb_tunnel_dev.priv = (void*)&ipip6_fb_tunnel;
strcpy(ipip6_fb_tunnel_dev.name, ipip6_fb_tunnel.parms.name);
register_netdev(&ipip6_fb_tunnel_dev);
inet_add_protocol(&sit_protocol);
return 0;
}
......@@ -2156,12 +2156,9 @@ struct proto tcpv6_prot = {
.get_port = tcp_v6_get_port,
};
static struct inet6_protocol tcpv6_protocol =
{
.handler = tcp_v6_rcv,
.err_handler = tcp_v6_err,
.protocol = IPPROTO_TCP,
.name = "TCPv6",
static struct inet6_protocol tcpv6_protocol = {
.handler = tcp_v6_rcv,
.err_handler = tcp_v6_err,
};
extern struct proto_ops inet6_stream_ops;
......@@ -2179,6 +2176,7 @@ static struct inet_protosw tcpv6_protosw = {
void __init tcpv6_init(void)
{
/* register inet6 protocol */
inet6_add_protocol(&tcpv6_protocol);
if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0)
printk(KERN_ERR "tcpv6_init: Could not register protocol\n");
inet6_register_protosw(&tcpv6_protosw);
}
......@@ -907,10 +907,8 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
}
static struct inet6_protocol udpv6_protocol = {
.handler = udpv6_rcv,
.err_handler = udpv6_err,
.protocol = IPPROTO_UDP,
.name = "UDPv6",
.handler = udpv6_rcv,
.err_handler = udpv6_err,
};
#define LINE_LEN 190
......@@ -1020,6 +1018,7 @@ static struct inet_protosw udpv6_protosw = {
void __init udpv6_init(void)
{
inet6_add_protocol(&udpv6_protocol);
if (inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP) < 0)
printk(KERN_ERR "udpv6_init: Could not register protocol\n");
inet6_register_protosw(&udpv6_protosw);
}
......@@ -295,11 +295,6 @@ static struct inet_protosw sctpv6_protosw = {
static struct inet6_protocol sctpv6_protocol = {
.handler = sctp_rcv,
.err_handler = sctp_v6_err,
.next = NULL,
.protocol = IPPROTO_SCTP,
.copy = 0,
.data = NULL,
.name = "SCTPv6"
};
static sctp_func_t sctp_ipv6_specific = {
......@@ -320,10 +315,12 @@ static sctp_pf_t sctp_pf_inet6_specific = {
/* Initialize IPv6 support and register with inet6 stack. */
int sctp_v6_init(void)
{
/* Register inet6 protocol. */
if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
return -EAGAIN;
/* Add SCTPv6 to inetsw6 linked list. */
inet6_register_protosw(&sctpv6_protosw);
/* Register inet6 protocol. */
inet6_add_protocol(&sctpv6_protocol);
/* Register the SCTP specfic PF_INET6 functions. */
sctp_set_pf_specific(PF_INET6, &sctp_pf_inet6_specific);
......@@ -339,6 +336,6 @@ int sctp_v6_init(void)
void sctp_v6_exit(void)
{
list_del(&sctp_ipv6_specific.list);
inet6_del_protocol(&sctpv6_protocol);
inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
inet6_unregister_protosw(&sctpv6_protosw);
}
......@@ -434,10 +434,8 @@ struct inet_protosw sctp_protosw = {
/* Register with IP layer. */
static struct inet_protocol sctp_protocol = {
.handler = sctp_rcv, /* SCTP input handler. */
.err_handler = sctp_v4_err, /* SCTP error control */
.protocol = IPPROTO_SCTP, /* protocol ID */
.name = "SCTP" /* name */
.handler = sctp_rcv,
.err_handler = sctp_v4_err,
};
/* IPv4 address related functions. */
......@@ -485,12 +483,13 @@ int sctp_init(void)
int i;
int status = 0;
/* Add SCTP to inet_protos hash table. */
if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0)
return -EAGAIN;
/* Add SCTP to inetsw linked list. */
inet_register_protosw(&sctp_protosw);
/* Add SCTP to inet_protos hash table. */
inet_add_protocol(&sctp_protocol);
/* Initialize proc fs directory. */
sctp_proc_init();
......@@ -626,7 +625,7 @@ int sctp_init(void)
err_ahash_alloc:
sctp_dbg_objcnt_exit();
sctp_proc_exit();
inet_del_protocol(&sctp_protocol);
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
inet_unregister_protosw(&sctp_protosw);
return status;
}
......@@ -656,7 +655,7 @@ void sctp_exit(void)
sctp_dbg_objcnt_exit();
sctp_proc_exit();
inet_del_protocol(&sctp_protocol);
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
inet_unregister_protosw(&sctp_protosw);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment