patch-2.1.30 linux/net/ipv6/addrconf.c
Next file: linux/net/ipv6/af_inet6.c
Previous file: linux/net/ipv6/Makefile
Back to the patch index
Back to the overall index
- Lines: 1813
- Date:
Thu Mar 20 18:17:14 1997
- Orig file:
v2.1.29/linux/net/ipv6/addrconf.c
- Orig date:
Mon Mar 17 14:54:36 1997
diff -u --recursive --new-file v2.1.29/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
@@ -5,12 +5,14 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
+ * $Id: addrconf.c,v 1.15 1997/03/18 18:24:23 davem Exp $
*
* 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 (at your option) any later version.
*/
+
/*
* Changes:
*
@@ -36,27 +38,35 @@
#include <net/ipv6.h>
#include <net/protocol.h>
#include <net/ndisc.h>
-#include <net/ipv6_route.h>
+#include <net/ip6_route.h>
#include <net/addrconf.h>
#include <net/sit.h>
#include <asm/uaccess.h>
-#define HASH_SIZE 16
+/* Set to 3 to get tracing... */
+#define ACONF_DEBUG 2
+
+#if ACONF_DEBUG >= 3
+#define ADBG(x) printk x
+#else
+#define ADBG(x)
+#endif
+
/*
* Configured unicast address list
*/
-struct inet6_ifaddr *inet6_addr_lst[HASH_SIZE];
+struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE];
/*
* Hash list of configured multicast addresses
*/
-struct ipv6_mc_list *inet6_mcast_lst[HASH_SIZE];
+struct ifmcaddr6 *inet6_mcast_lst[IN6_ADDR_HSIZE];
/*
* AF_INET6 device list
*/
-struct inet6_dev *inet6_dev_lst;
+struct inet6_dev *inet6_dev_lst[IN6_ADDR_HSIZE];
atomic_t addr_list_lock = 0;
@@ -67,15 +77,11 @@
0, 0, addrconf_verify
};
-
-int DupAddrDetectTransmits = 1;
-
-/*
- * /proc/sys switch for autoconf (enabled by default)
- */
-int addrconf_sys_autoconf = 1;
+static int addrconf_ifdown(struct device *dev);
static void addrconf_dad_start(struct inet6_ifaddr *ifp);
+static void addrconf_dad_timer(unsigned long data);
+static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
static void addrconf_rs_timer(unsigned long data);
int ipv6_addr_type(struct in6_addr *addr)
@@ -89,58 +95,41 @@
* 0x4/3
*/
- if ((st & __constant_htonl(0xE0000000)) ==
- __constant_htonl(0x40000000))
- {
+ if ((st & __constant_htonl(0xE0000000)) == __constant_htonl(0x40000000))
return IPV6_ADDR_UNICAST;
- }
- if ((st & __constant_htonl(0xFF000000)) ==
- __constant_htonl(0xFF000000))
- {
+ if ((st & __constant_htonl(0xFF000000)) == __constant_htonl(0xFF000000)) {
int type = IPV6_ADDR_MULTICAST;
- switch((st >> 16) & 0x0f)
- {
- case 0x01:
+ switch((st & __constant_htonl(0x00FF0000))) {
+ case __constant_htonl(0x00010000):
type |= IPV6_ADDR_LOOPBACK;
break;
- case 0x02:
+
+ case __constant_htonl(0x00020000):
type |= IPV6_ADDR_LINKLOCAL;
break;
- case 0x05:
+
+ case __constant_htonl(0x00050000):
type |= IPV6_ADDR_SITELOCAL;
break;
- }
+ };
return type;
}
- if ((st & __constant_htonl(0xFFC00000)) ==
- __constant_htonl(0xFE800000))
- {
+ if ((st & __constant_htonl(0xFFC00000)) == __constant_htonl(0xFE800000))
return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST);
- }
- if ((st & __constant_htonl(0xFFC00000)) ==
- __constant_htonl(0xFEC00000))
- {
+ if ((st & __constant_htonl(0xFFC00000)) == __constant_htonl(0xFEC00000))
return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST);
- }
- if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0)
- {
- if (addr->s6_addr32[2] == 0)
- {
+ if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
+ if (addr->s6_addr32[2] == 0) {
if (addr->in6_u.u6_addr32[3] == 0)
- {
return IPV6_ADDR_ANY;
- }
if (addr->s6_addr32[3] == __constant_htonl(0x00000001))
- {
- return (IPV6_ADDR_LOOPBACK |
- IPV6_ADDR_UNICAST);
- }
+ return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST);
return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST);
}
@@ -152,81 +141,64 @@
return IPV6_ADDR_RESERVED;
}
-struct inet6_dev * ipv6_add_dev(struct device *dev)
+static struct inet6_dev * ipv6_add_dev(struct device *dev)
{
- struct inet6_dev *dev6;
-
- /*
- * called by netdev notifier from a syscall
- */
- dev6 = (struct inet6_dev *) kmalloc(sizeof(struct inet6_dev),
- GFP_ATOMIC);
-
- if (dev6 == NULL)
- return NULL;
-
- memset(dev6, 0, sizeof(struct inet6_dev));
- dev6->dev = dev;
- dev6->if_index = dev->ifindex;
+ struct inet6_dev *ndev, **bptr, *iter;
+ int hash;
- /*
- * insert at head.
- */
+ ndev = kmalloc(sizeof(struct inet6_dev), gfp_any());
- dev6->next = inet6_dev_lst;
- inet6_dev_lst = dev6;
+ if (ndev) {
+ memset(ndev, 0, sizeof(struct inet6_dev));
- return dev6;
-}
+ ndev->dev = dev;
+ hash = ipv6_devindex_hash(dev->ifindex);
+ bptr = &inet6_dev_lst[hash];
+ iter = *bptr;
-struct inet6_dev * ipv6_dev_by_index(int index)
-{
- struct inet6_dev *in6_dev;
+ for (; iter; iter = iter->next)
+ bptr = &iter->next;
- for (in6_dev = inet6_dev_lst; in6_dev; in6_dev = in6_dev->next)
- {
- if (in6_dev->if_index == index)
- return in6_dev;
+ *bptr = ndev;
}
-
- return NULL;
+ return ndev;
}
void addrconf_forwarding_on(void)
{
- struct inet6_dev *in6_dev;
- struct in6_addr maddr;
+ struct inet6_dev *idev;
+ int i;
- for (in6_dev = inet6_dev_lst; in6_dev; in6_dev = in6_dev->next)
- {
- printk(KERN_DEBUG "dev %s\n", in6_dev->dev->name);
-
- if (in6_dev->dev->type == ARPHRD_ETHER)
- {
- printk(KERN_DEBUG "joining all-routers\n");
- in6_dev->router = 1;
- ipv6_addr_all_routers(&maddr);
- ipv6_dev_mc_inc(in6_dev->dev, &maddr);
- }
- }
+ for (i = 0; i < IN6_ADDR_HSIZE; i++) {
+ for (idev = inet6_dev_lst[i]; idev; idev = idev->next) {
+#if ACONF_DEBUG >= 2
+ printk(KERN_DEBUG "dev %s\n", idev->dev->name);
+#endif
+
+ if (idev->dev->type == ARPHRD_ETHER) {
+ struct in6_addr maddr;
- if (last_resort_rt && (last_resort_rt->rt_flags & RTI_ALLONLINK))
- {
- rt_release(last_resort_rt);
- last_resort_rt = NULL;
+#if ACONF_DEBUG >= 2
+ printk(KERN_DEBUG "joining all-routers\n");
+#endif
+ idev->router = 1;
+ ipv6_addr_all_routers(&maddr);
+ ipv6_dev_mc_inc(idev->dev, &maddr);
+ }
+ }
}
}
struct inet6_dev * ipv6_get_idev(struct device *dev)
{
- struct inet6_dev *in6_dev;
+ struct inet6_dev *idev;
+ int hash;
- for (in6_dev = inet6_dev_lst; in6_dev; in6_dev = in6_dev->next)
- {
- if (in6_dev->dev == dev)
- {
- return in6_dev;
- }
+ hash = ipv6_devindex_hash(dev->ifindex);
+
+ for (idev = inet6_dev_lst[hash]; idev; idev = idev->next) {
+ if (idev->dev == dev)
+ return idev;
}
return NULL;
}
@@ -234,45 +206,34 @@
struct inet6_ifaddr * ipv6_add_addr(struct inet6_dev *idev,
struct in6_addr *addr, int scope)
{
- struct inet6_ifaddr * ifaddr;
+ struct inet6_ifaddr *ifa;
int hash;
- unsigned long flags;
- save_flags(flags);
- cli();
+ ifa = kmalloc(sizeof(struct inet6_ifaddr), gfp_any());
- ifaddr = (struct inet6_ifaddr *) kmalloc(sizeof(struct inet6_ifaddr),
- GFP_ATOMIC);
-
- if (ifaddr == NULL)
- {
- printk(KERN_DEBUG "ipv6_add_addr: malloc failed\n");
- restore_flags(flags);
+ if (ifa == NULL) {
+ ADBG(("ipv6_add_addr: malloc failed\n"));
return NULL;
}
- memset(ifaddr, 0, sizeof(struct inet6_ifaddr));
- memcpy(&ifaddr->addr, addr, sizeof(struct in6_addr));
-
- ifaddr->scope = scope;
- ifaddr->idev = idev;
-
+ memset(ifa, 0, sizeof(struct inet6_ifaddr));
+ memcpy(&ifa->addr, addr, sizeof(struct in6_addr));
- /* add to list */
+ init_timer(&ifa->timer);
+ ifa->scope = scope;
+ ifa->idev = idev;
+ /* Add to list. */
hash = ipv6_addr_hash(addr);
- ifaddr->lst_next = inet6_addr_lst[hash];
- inet6_addr_lst[hash] = ifaddr;
-
+ ifa->lst_next = inet6_addr_lst[hash];
+ inet6_addr_lst[hash] = ifa;
- /* add to inet6_dev unicast addr list */
- ifaddr->if_next = idev->addr_list;
- idev->addr_list = ifaddr;
+ /* Add to inet6_dev unicast addr list. */
+ ifa->if_next = idev->addr_list;
+ idev->addr_list = ifa;
- restore_flags(flags);
- return ifaddr;
-
+ return ifa;
}
void ipv6_del_addr(struct inet6_ifaddr *ifp)
@@ -280,8 +241,7 @@
struct inet6_ifaddr *iter, **back;
int hash;
- if (addr_list_lock)
- {
+ if (addr_list_lock) {
ifp->flags |= ADDR_INVALID;
return;
}
@@ -291,10 +251,8 @@
iter = inet6_addr_lst[hash];
back = &inet6_addr_lst[hash];
- for (; iter; iter = iter->lst_next)
- {
- if (iter == ifp)
- {
+ for (; iter; iter = iter->lst_next) {
+ if (iter == ifp) {
*back = ifp->lst_next;
ifp->lst_next = NULL;
break;
@@ -305,10 +263,8 @@
iter = ifp->idev->addr_list;
back = &ifp->idev->addr_list;
- for (; iter; iter = iter->if_next)
- {
- if (iter == ifp)
- {
+ for (; iter; iter = iter->if_next) {
+ if (iter == ifp) {
*back = ifp->if_next;
ifp->if_next = NULL;
break;
@@ -327,30 +283,26 @@
* an address of the attached interface
* iii) don't use deprecated addresses
*
- * at the moment i believe only iii) is missing.
+ * at the moment I believe only iii) is missing.
*/
-struct inet6_ifaddr * ipv6_get_saddr(struct rt6_info *rt, struct in6_addr *daddr)
+struct inet6_ifaddr * ipv6_get_saddr(struct dst_entry *dst,
+ struct in6_addr *daddr)
{
int scope;
- struct inet6_ifaddr * ifp = NULL;
- struct inet6_dev * i6dev;
- struct inet6_ifaddr * match = NULL;
+ struct inet6_ifaddr *ifp = NULL;
+ struct inet6_ifaddr *match = NULL;
struct device *dev = NULL;
+ struct rt6_info *rt;
int i;
+ rt = (struct rt6_info *) dst;
if (rt)
- {
- dev = rt->rt_dev;
- }
+ dev = rt->rt6i_dev;
atomic_inc(&addr_list_lock);
- scope = ipv6_addr_type(daddr);
-
- scope &= IPV6_ADDR_SCOPE_MASK;
-
- if (rt && (rt->rt_flags & RTI_ALLONLINK))
- {
+ scope = ipv6_addr_scope(daddr);
+ if (rt && (rt->rt6i_flags & RTF_ALLONLINK)) {
/*
* route for the "all destinations on link" rule
* when no routers are present
@@ -363,30 +315,23 @@
* search dev and walk through dev addresses
*/
- if (dev)
- {
+ if (dev) {
+ struct inet6_dev *idev;
+ int hash;
+
if (dev->flags & IFF_LOOPBACK)
- {
scope = IFA_HOST;
- }
- for (i6dev = inet6_dev_lst; i6dev; i6dev=i6dev->next)
- {
- if (i6dev->dev == dev)
- {
- for (ifp=i6dev->addr_list; ifp;
- ifp=ifp->if_next)
- {
- if (ifp->scope == scope)
- {
+ hash = ipv6_devindex_hash(dev->ifindex);
+ for (idev = inet6_dev_lst[hash]; idev; idev=idev->next) {
+ if (idev->dev == dev) {
+ for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
+ if (ifp->scope == scope) {
if (!(ifp->flags & ADDR_STATUS))
- {
goto out;
- }
+
if (!(ifp->flags & ADDR_INVALID))
- {
match = ifp;
- }
}
}
break;
@@ -395,37 +340,27 @@
}
if (scope == IFA_LINK)
- {
goto out;
- }
/*
* dev == NULL or search failed for specified dev
*/
- for (i=0; i < HASH_SIZE; i++)
- {
- for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next)
- {
- if (ifp->scope == scope)
- {
+ for (i=0; i < IN6_ADDR_HSIZE; i++) {
+ for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
+ if (ifp->scope == scope) {
if (!(ifp->flags & ADDR_STATUS))
- {
goto out;
- }
+
if (!(ifp->flags & ADDR_INVALID))
- {
match = ifp;
- }
}
}
}
- out:
+out:
if (ifp == NULL && match)
- {
ifp = match;
- }
atomic_dec(&addr_list_lock);
return ifp;
}
@@ -433,14 +368,14 @@
struct inet6_ifaddr * ipv6_get_lladdr(struct device *dev)
{
struct inet6_ifaddr *ifp;
- struct inet6_dev *i6dev;
+ struct inet6_dev *idev;
+ int hash;
- for (i6dev = inet6_dev_lst; i6dev; i6dev=i6dev->next)
- {
- if (i6dev->dev == dev)
- {
- for (ifp=i6dev->addr_list; ifp; ifp=ifp->if_next)
- {
+ hash = ipv6_devindex_hash(dev->ifindex);
+
+ for (idev = inet6_dev_lst[hash]; idev; idev=idev->next) {
+ if (idev->dev == dev) {
+ for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
if (ifp->scope == IFA_LINK)
return ifp;
}
@@ -464,154 +399,15 @@
atomic_inc(&addr_list_lock);
hash = ipv6_addr_hash(addr);
-
- for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next)
- {
+ for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
if (ipv6_addr_cmp(&ifp->addr, addr) == 0)
- {
break;
- }
}
atomic_dec(&addr_list_lock);
return ifp;
}
-static void sit_route_add(struct inet6_dev *idev)
-{
- struct in6_rtmsg rtmsg;
- struct device *dev = idev->dev;
- int err;
-
- rtmsg.rtmsg_type = RTMSG_NEWROUTE;
-
- memset(&rtmsg.rtmsg_dst, 0, sizeof(struct in6_addr));
- memset(&rtmsg.rtmsg_gateway, 0, sizeof(struct in6_addr));
-
- if (dev->pa_dstaddr == 0)
- {
- /* prefix length - 96 bytes "::d.d.d.d" */
- rtmsg.rtmsg_prefixlen = 96;
- rtmsg.rtmsg_metric = 1;
- rtmsg.rtmsg_flags = RTF_NEXTHOP|RTF_UP;
- }
- else
- {
- rtmsg.rtmsg_prefixlen = 10;
- rtmsg.rtmsg_dst.s6_addr32[0] = __constant_htonl(0xfe800000);
- rtmsg.rtmsg_dst.s6_addr32[3] = dev->pa_dstaddr;
- rtmsg.rtmsg_metric = 1;
- rtmsg.rtmsg_flags = RTF_NEXTHOP|RTF_UP;
- }
-
- rtmsg.rtmsg_ifindex = idev->if_index;
-
- err = ipv6_route_add(&rtmsg);
-
- if (err)
- {
- printk(KERN_DEBUG "sit_route_add: error in route_add\n");
- }
-}
-
-static void init_loopback(struct device *dev)
-{
- struct in6_addr addr;
- struct inet6_dev *idev;
- struct inet6_ifaddr * ifp;
- struct in6_rtmsg rtmsg;
- int err;
-
- /* ::1 */
-
- memset(&addr, 0, sizeof(struct in6_addr));
- addr.s6_addr[15] = 1;
-
- idev = ipv6_add_dev(dev);
-
- if (idev == NULL)
- {
- printk(KERN_DEBUG "init loopback: add_dev failed\n");
- return;
- }
-
- ifp = ipv6_add_addr(idev, &addr, IFA_HOST);
-
- if (ifp == NULL)
- {
- printk(KERN_DEBUG "init_loopback: add_addr failed\n");
- return;
- }
-
- ifp->flags |= ADDR_PERMANENT;
-
- memcpy(&rtmsg.rtmsg_dst, &addr, sizeof(struct in6_addr));
- memset(&rtmsg.rtmsg_gateway, 0, sizeof(struct in6_addr));
-
- rtmsg.rtmsg_prefixlen = 128;
- rtmsg.rtmsg_metric = 1;
- rtmsg.rtmsg_ifindex = idev->if_index;
-
- rtmsg.rtmsg_flags = RTF_NEXTHOP|RTF_HOST|RTF_UP;
-
- err = ipv6_route_add(&rtmsg);
-
- if (err)
- {
- printk(KERN_DEBUG "init_loopback: error in route_add\n");
- }
-
- /* add route for ::127.0.0.1 */
-}
-
-static void addrconf_eth_config(struct device *dev)
-{
- struct in6_addr addr;
- struct in6_addr maddr;
- struct inet6_ifaddr * ifp;
- struct inet6_dev * idev;
-
- memset(&addr, 0, sizeof(struct in6_addr));
-
- /* generate link local address*/
- addr.s6_addr[0] = 0xFE;
- addr.s6_addr[1] = 0x80;
-
- memcpy(addr.s6_addr + (sizeof(struct in6_addr) - dev->addr_len),
- dev->dev_addr, dev->addr_len);
-
- idev = ipv6_add_dev(dev);
-
- if (idev == NULL)
- return;
-
- ifp = ipv6_add_addr(idev, &addr, IFA_LINK);
-
- if (ifp == NULL)
- return;
-
- ifp->flags |= (DAD_INCOMPLETE | ADDR_PERMANENT);
- ifp->prefix_len = 10;
-
- /* join to all nodes multicast group */
- ipv6_addr_all_nodes(&maddr);
- ipv6_dev_mc_inc(dev, &maddr);
-
- if (ipv6_forwarding)
- {
- idev->router = 1;
- ipv6_addr_all_routers(&maddr);
- ipv6_dev_mc_inc(dev, &maddr);
- }
-
- /* join to solicited addr multicast group */
- addrconf_addr_solict_mult(&addr, &maddr);
- ipv6_dev_mc_inc(dev, &maddr);
-
- /* start dad */
- addrconf_dad_start(ifp);
-}
-
void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len)
{
struct prefix_info *pinfo;
@@ -623,9 +419,8 @@
pinfo = (struct prefix_info *) opt;
- if (len < sizeof(struct prefix_info))
- {
- printk(KERN_DEBUG "addrconf: prefix option too short\n");
+ if (len < sizeof(struct prefix_info)) {
+ ADBG(("addrconf: prefix option too short\n"));
return;
}
@@ -636,17 +431,13 @@
addr_type = ipv6_addr_type(&pinfo->prefix);
if (addr_type & IPV6_ADDR_LINKLOCAL)
- {
return;
- }
valid_lft = ntohl(pinfo->valid);
prefered_lft = ntohl(pinfo->prefered);
- if (prefered_lft > valid_lft)
- {
- printk(KERN_WARNING
- "addrconf: prefix option has invalid lifetime\n");
+ if (prefered_lft > valid_lft) {
+ printk(KERN_WARNING "addrconf: prefix option has invalid lifetime\n");
return;
}
@@ -655,11 +446,7 @@
* delete it
*/
- if (last_resort_rt && (last_resort_rt->rt_flags & RTI_ALLONLINK))
- {
- rt_release(last_resort_rt);
- last_resort_rt = NULL;
- }
+ rt6_purge_dflt_routers(RTF_ALLONLINK);
/*
* Two things going on here:
@@ -669,178 +456,86 @@
rt_expires = jiffies + valid_lft * HZ;
if (rt_expires < jiffies)
- {
rt_expires = ~0;
- }
- rt = fibv6_lookup(&pinfo->prefix, dev, RTI_DYNAMIC|RTI_GATEWAY);
-
- if (rt)
- {
- if (pinfo->onlink == 0 || valid_lft == 0)
- {
- /*
- * delete route
- */
- fib6_del_rt(rt);
+ rt = rt6_lookup(&pinfo->prefix, NULL, dev, RTF_LINKRT);
+
+ if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
+ if (pinfo->onlink == 0 || valid_lft == 0) {
+ ip6_del_rt(rt);
rt = NULL;
+ } else {
+ rt->rt6i_expires = rt_expires;
}
- else
- {
- rt->rt_expires = rt_expires;
- }
- }
- else if (pinfo->onlink && valid_lft)
- {
+ } else if (pinfo->onlink && valid_lft) {
struct in6_rtmsg rtmsg;
- struct inet6_dev *idev;
+ int err;
+
+ memset(&rtmsg, 0, sizeof(rtmsg));
printk(KERN_DEBUG "adding on link route\n");
- ipv6_addr_copy(&rtmsg.rtmsg_dst, &pinfo->prefix);
- memset(&rtmsg.rtmsg_gateway, 0, sizeof(struct in6_addr));
- rtmsg.rtmsg_prefixlen = pinfo->prefix_len;
- rtmsg.rtmsg_metric = 1;
-
- if ((idev = ipv6_get_idev(dev)))
- {
- rtmsg.rtmsg_ifindex = idev->if_index;
- }
- rtmsg.rtmsg_flags = RTF_UP | RTF_ADDRCONF;
- rtmsg.rtmsg_info = rt_expires;
+ ipv6_addr_copy(&rtmsg.rtmsg_dst, &pinfo->prefix);
+ rtmsg.rtmsg_dst_len = pinfo->prefix_len;
+ rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+ rtmsg.rtmsg_ifindex = dev->ifindex;
+ rtmsg.rtmsg_flags = RTF_UP | RTF_ADDRCONF;
+ rtmsg.rtmsg_info = rt_expires;
- ipv6_route_add(&rtmsg);
+ ip6_route_add(&rtmsg, &err);
}
- if (pinfo->autoconf && addrconf_sys_autoconf)
- {
+ if (pinfo->autoconf && ipv6_config.autoconf) {
struct inet6_ifaddr * ifp;
struct in6_addr addr;
int plen;
plen = pinfo->prefix_len >> 3;
- if (plen + dev->addr_len == sizeof(struct in6_addr))
- {
+ if (plen + dev->addr_len == sizeof(struct in6_addr)) {
memcpy(&addr, &pinfo->prefix, plen);
memcpy(addr.s6_addr + plen, dev->dev_addr,
dev->addr_len);
- }
- else
- {
- printk(KERN_DEBUG
- "addrconf: prefix_len invalid\n");
+ } else {
+ ADBG(("addrconf: prefix_len invalid\n"));
return;
}
ifp = ipv6_chk_addr(&addr);
- if (ifp == NULL && valid_lft)
- {
- /* create */
-
- struct inet6_dev *in6_dev;
-
- in6_dev = ipv6_get_idev(dev);
+ if (ifp == NULL && valid_lft) {
+ struct inet6_dev *in6_dev = ipv6_get_idev(dev);
if (in6_dev == NULL)
- {
- printk(KERN_DEBUG
- "addrconf: device not configured\n");
- }
+ ADBG(("addrconf: device not configured\n"));
ifp = ipv6_add_addr(in6_dev, &addr,
addr_type & IPV6_ADDR_SCOPE_MASK);
- if (dev->flags & IFF_MULTICAST)
- {
+ if (dev->flags & IFF_MULTICAST) {
struct in6_addr maddr;
- /* join to solicited addr multicast group */
+ /* Join to solicited addr multicast group. */
addrconf_addr_solict_mult(&addr, &maddr);
ipv6_dev_mc_inc(dev, &maddr);
}
- ifp->flags |= DAD_INCOMPLETE;
ifp->prefix_len = pinfo->prefix_len;
addrconf_dad_start(ifp);
-
}
- if (ifp && valid_lft == 0)
- {
+ if (ifp && valid_lft == 0) {
ipv6_del_addr(ifp);
ifp = NULL;
}
- if (ifp)
- {
+ if (ifp) {
ifp->valid_lft = valid_lft;
ifp->prefered_lft = prefered_lft;
ifp->tstamp = jiffies;
}
}
-
-}
-
-static int addrconf_ifdown(struct device *dev)
-{
- struct inet6_dev *idev, **bidev;
- struct inet6_ifaddr *ifa, **bifa;
- int i;
-
- start_bh_atomic();
-
- bidev = &inet6_dev_lst;
-
- for (idev = inet6_dev_lst; idev; idev = idev->next)
- {
- if (idev->dev == dev)
- {
- *bidev = idev->next;
- break;
- }
- bidev = &idev;
- }
-
- if (idev == NULL)
- {
- printk(KERN_DEBUG "addrconf_ifdown: device not found\n");
- end_bh_atomic();
- return -ENODEV;
- }
-
- /*
- * FIXME: clear multicast group membership
- */
-
- /*
- * clean addr_list
- */
-
- for (i=0; i<16; i++)
- {
- bifa = &inet6_addr_lst[i];
-
- for (ifa=inet6_addr_lst[i]; ifa; )
- {
- if (ifa->idev == idev)
- {
- *bifa = ifa->lst_next;
- del_timer(&ifa->timer);
- kfree(ifa);
- ifa = *bifa;
- continue;
- }
- bifa = &ifa;
- ifa = ifa->lst_next;
- }
- }
-
- kfree(idev);
- end_bh_atomic();
- return 0;
}
/*
@@ -851,41 +546,31 @@
int addrconf_set_dstaddr(void *arg)
{
struct in6_ifreq ireq;
- struct inet6_dev *idev;
struct device *dev;
int err = -EINVAL;
- if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
- {
+ if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) {
err = -EFAULT;
goto err_exit;
}
- idev = ipv6_dev_by_index(ireq.ifr6_ifindex);
+ dev = dev_get_by_index(ireq.ifr6_ifindex);
- if (idev == NULL)
- {
+ if (dev == NULL) {
err = -ENODEV;
goto err_exit;
}
- dev = idev->dev;
-
- if (dev->type == ARPHRD_SIT)
- {
+ if (dev->type == ARPHRD_SIT) {
struct device *dev;
if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4))
- {
return -EADDRNOTAVAIL;
- }
dev = sit_add_tunnel(ireq.ifr6_addr.s6_addr32[3]);
if (dev == NULL)
- {
err = -ENODEV;
- }
else
err = 0;
}
@@ -899,87 +584,141 @@
*/
int addrconf_add_ifaddr(void *arg)
{
- struct inet6_dev *in6_dev;
+ struct inet6_dev *idev;
struct in6_ifreq ireq;
struct inet6_ifaddr *ifp;
struct device *dev;
- int addr_type;
- int err;
+ int scope;
if (!suser())
return -EPERM;
- err = copy_from_user(&ireq, arg, sizeof(struct in6_ifreq));
- if (err)
+ if(copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
return -EFAULT;
- in6_dev = ipv6_dev_by_index(ireq.ifr6_ifindex);
+ if((dev = dev_get_by_index(ireq.ifr6_ifindex)) == NULL)
+ return -EINVAL;
- if (in6_dev == NULL)
+ if ((idev = ipv6_get_idev(dev)) == NULL)
return -EINVAL;
- dev = in6_dev->dev;
-
- addr_type = ipv6_addr_type(&ireq.ifr6_addr);
- addr_type &= IPV6_ADDR_SCOPE_MASK;
-
- ifp = ipv6_add_addr(in6_dev, &ireq.ifr6_addr, addr_type);
+ scope = ipv6_addr_scope(&ireq.ifr6_addr);
- if (ifp == NULL)
+ if((ifp = ipv6_add_addr(idev, &ireq.ifr6_addr, scope)) == NULL)
return -ENOMEM;
ifp->prefix_len = 128;
- if (dev->flags & IFF_MULTICAST)
- {
+ if (dev->flags & IFF_MULTICAST) {
struct in6_addr maddr;
- /* join to solicited addr multicast group */
+ /* Join to solicited addr multicast group. */
addrconf_addr_solict_mult(&ireq.ifr6_addr, &maddr);
ipv6_dev_mc_inc(dev, &maddr);
}
-
ifp->prefix_len = ireq.ifr6_prefixlen;
ifp->flags |= ADDR_PERMANENT;
if (!(dev->flags & (IFF_NOARP|IFF_LOOPBACK)))
- {
- ifp->flags |= DAD_INCOMPLETE;
addrconf_dad_start(ifp);
- }
+ else
+ ip6_rt_addr_add(&ifp->addr, dev);
+
return 0;
}
-static void sit_add_v4_addrs(struct inet6_dev *idev)
+static void sit_route_add(struct device *dev)
{
- struct inet6_ifaddr * ifp;
- struct in6_addr addr;
- struct device *dev;
- int scope;
-
+ struct in6_rtmsg rtmsg;
+ struct rt6_info *rt;
+ int err;
+
+ ADBG(("sit_route_add(%s): ", dev->name));
+ memset(&rtmsg, 0, sizeof(rtmsg));
+
+ rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+ rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+
+ if (dev->pa_dstaddr == 0) {
+ ADBG(("pa_dstaddr=0, "));
+ /* prefix length - 96 bytes "::d.d.d.d" */
+ rtmsg.rtmsg_dst_len = 96;
+ rtmsg.rtmsg_flags = RTF_NONEXTHOP|RTF_UP;
+ } else {
+ ADBG(("pa_dstaddr=%08x, ", dev->pa_dstaddr));
+ rtmsg.rtmsg_dst_len = 10;
+ rtmsg.rtmsg_dst.s6_addr32[0] = __constant_htonl(0xfe800000);
+ rtmsg.rtmsg_dst.s6_addr32[3] = dev->pa_dstaddr;
+ rtmsg.rtmsg_gateway.s6_addr32[3]= dev->pa_dstaddr;
+ rtmsg.rtmsg_flags = RTF_UP;
+ }
+
+ rtmsg.rtmsg_ifindex = dev->ifindex;
+ ADBG(("doing ip6_route_add()\n"));
+ rt = ip6_route_add(&rtmsg, &err);
+
+ if (err) {
+#if ACONF_DEBUG >= 1
+ printk(KERN_DEBUG "sit_route_add: error %d in route_add\n", err);
+#endif
+ }
+
+ ADBG(("sit_route_add(cont): "));
+ if (dev->pa_dstaddr) {
+ struct rt6_info *mrt;
+
+ ADBG(("pa_dstaddr != 0, "));
+ rt->rt6i_nexthop = ndisc_get_neigh(dev, &rtmsg.rtmsg_gateway);
+ if (rt->rt6i_nexthop == NULL) {
+ ADBG(("can't get neighbour\n"));
+ printk(KERN_DEBUG "sit_route: get_neigh failed\n");
+ }
+
+ /*
+ * Add multicast route.
+ */
+ ADBG(("add MULT, "));
+ ipv6_addr_set(&rtmsg.rtmsg_dst, __constant_htonl(0xFF000000), 0, 0, 0);
+
+ rtmsg.rtmsg_dst_len = 8;
+ rtmsg.rtmsg_flags = RTF_UP;
+ rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+
+ memset(&rtmsg.rtmsg_gateway, 0, sizeof(struct in6_addr));
+ ADBG(("doing ip6_route_add()\n"));
+ mrt = ip6_route_add(&rtmsg, &err);
+
+ if (mrt)
+ mrt->rt6i_nexthop = ndisc_get_neigh(dev, &rtmsg.rtmsg_dst);
+ } else {
+ ADBG(("pa_dstaddr==0\n"));
+ }
+}
+
+static void sit_add_v4_addrs(struct inet6_dev *idev)
+{
+ struct inet6_ifaddr * ifp;
+ struct in6_addr addr;
+ struct device *dev;
+ int scope;
+
memset(&addr, 0, sizeof(struct in6_addr));
- if (idev->dev->pa_dstaddr)
- {
+ if (idev->dev->pa_dstaddr) {
addr.s6_addr32[0] = __constant_htonl(0xfe800000);
scope = IFA_LINK;
- }
- else
- {
+ } else {
scope = IPV6_ADDR_COMPATv4;
}
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- if (dev->family == AF_INET && (dev->flags & IFF_UP))
- {
+ for (dev = dev_base; dev != NULL; dev = dev->next) {
+ if (dev->family == AF_INET && (dev->flags & IFF_UP)) {
int flag = scope;
addr.s6_addr32[3] = dev->pa_addr;
- if (dev->flags & IFF_LOOPBACK)
- {
+ if (dev->flags & IFF_LOOPBACK) {
if (idev->dev->pa_dstaddr)
continue;
@@ -987,15 +726,94 @@
}
ifp = ipv6_add_addr(idev, &addr, flag);
-
+
if (ifp == NULL)
continue;
ifp->flags |= ADDR_PERMANENT;
+ ip6_rt_addr_add(&ifp->addr, dev);
}
}
}
+static void init_loopback(struct device *dev)
+{
+ struct in6_addr addr;
+ struct inet6_dev *idev;
+ struct inet6_ifaddr * ifp;
+ int err;
+
+ /* ::1 */
+
+ memset(&addr, 0, sizeof(struct in6_addr));
+ addr.s6_addr[15] = 1;
+
+ idev = ipv6_add_dev(dev);
+
+ if (idev == NULL) {
+ printk(KERN_DEBUG "init loopback: add_dev failed\n");
+ return;
+ }
+
+ ifp = ipv6_add_addr(idev, &addr, IFA_HOST);
+
+ if (ifp == NULL) {
+ printk(KERN_DEBUG "init_loopback: add_addr failed\n");
+ return;
+ }
+
+ ifp->flags |= ADDR_PERMANENT;
+
+ err = ip6_rt_addr_add(&addr, dev);
+ if (err)
+ printk(KERN_DEBUG "init_loopback: error in route_add\n");
+}
+
+static void addrconf_eth_config(struct device *dev)
+{
+ struct in6_addr addr;
+ struct in6_addr maddr;
+ struct inet6_ifaddr * ifp;
+ struct inet6_dev * idev;
+
+ memset(&addr, 0, sizeof(struct in6_addr));
+
+ /* Generate link local address. */
+ addr.s6_addr[0] = 0xFE;
+ addr.s6_addr[1] = 0x80;
+
+ memcpy(addr.s6_addr + (sizeof(struct in6_addr) - dev->addr_len),
+ dev->dev_addr, dev->addr_len);
+
+ idev = ipv6_add_dev(dev);
+ if (idev == NULL)
+ return;
+
+ ifp = ipv6_add_addr(idev, &addr, IFA_LINK);
+ if (ifp == NULL)
+ return;
+
+ ifp->flags = ADDR_PERMANENT;
+ ifp->prefix_len = 10;
+
+ /* Join to all nodes multicast group. */
+ ipv6_addr_all_nodes(&maddr);
+ ipv6_dev_mc_inc(dev, &maddr);
+
+ if (ipv6_config.forwarding) {
+ idev->router = 1;
+ ipv6_addr_all_routers(&maddr);
+ ipv6_dev_mc_inc(dev, &maddr);
+ }
+
+ /* Join to solicited addr multicast group. */
+ addrconf_addr_solict_mult(&addr, &maddr);
+ ipv6_dev_mc_inc(dev, &maddr);
+
+ /* Start duplicate address detection. */
+ addrconf_dad_start(ifp);
+}
+
int addrconf_notify(struct notifier_block *this, unsigned long event,
void * data)
{
@@ -1026,7 +844,7 @@
* route.
*/
- sit_route_add(idev);
+ sit_route_add(dev);
break;
case ARPHRD_LOOPBACK:
@@ -1034,12 +852,12 @@
break;
case ARPHRD_ETHER:
-
printk(KERN_DEBUG "Configuring eth interface\n");
addrconf_eth_config(dev);
break;
- }
- rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, 0, dev, 0, 0);
+ };
+
+ rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, NULL, dev, 0, 0, 0, 0);
break;
case NETDEV_DOWN:
@@ -1047,104 +865,72 @@
* Remove all addresses from this interface
* and take the interface out of the list.
*/
- if (addrconf_ifdown(dev) == 0)
- {
+ if (addrconf_ifdown(dev) == 0) {
+#if 0
rt6_ifdown(dev);
- rt6_sndmsg(RTMSG_DELDEVICE, NULL, NULL, 0, dev, 0, 0);
+#endif
+ rt6_sndmsg(RTMSG_DELDEVICE, NULL, NULL, NULL, dev, 0, 0, 0, 0);
}
break;
- }
+ };
return NOTIFY_OK;
}
-static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
-{
- struct in6_rtmsg rtmsg;
- struct device *dev;
- int err;
-
-
- if (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)
- {
- struct in6_addr all_routers;
- /*
- * 1) configure a link route for this interface
- * 2) send a (delayed) router solicitation
- */
-
- memcpy(&rtmsg.rtmsg_dst, &ifp->addr, sizeof(struct in6_addr));
- memset(&rtmsg.rtmsg_gateway, 0, sizeof(struct in6_addr));
-
- dev = ifp->idev->dev;
-
- rtmsg.rtmsg_prefixlen = ifp->prefix_len;
- rtmsg.rtmsg_metric = 1;
- rtmsg.rtmsg_ifindex = ifp->idev->if_index;
-
- rtmsg.rtmsg_flags = RTF_UP;
-
- err = ipv6_route_add(&rtmsg);
-
- if (err)
- {
- printk(KERN_DEBUG "dad_complete: error in route_add\n");
- }
+static int addrconf_ifdown(struct device *dev)
+{
+ struct inet6_dev *idev, **bidev;
+ struct inet6_ifaddr *ifa, **bifa;
+ int i, hash;
- if (ipv6_forwarding == 0)
- {
- ipv6_addr_set(&all_routers,
- __constant_htonl(0xff020000U), 0, 0,
- __constant_htonl(0x2U));
+ start_bh_atomic();
- /*
- * If a host as already performed a random delay
- * [...] as part of DAD [...] there is no need
- * to delay again before sending the first RS
- */
- ndisc_send_rs(ifp->idev->dev, &ifp->addr,
- &all_routers);
+ hash = ipv6_devindex_hash(dev->ifindex);
+ bidev = &inet6_dev_lst[hash];
- ifp->probes = 1;
- ifp->timer.function = addrconf_rs_timer;
- ifp->timer.expires = (jiffies +
- RTR_SOLICITATION_INTERVAL);
- ifp->idev->if_flags |= IF_RS_SENT;
- add_timer(&ifp->timer);
+ for (idev = inet6_dev_lst[hash]; idev; idev = idev->next) {
+ if (idev->dev == dev) {
+ *bidev = idev->next;
+ break;
}
+ bidev = &idev->next;
}
-}
+ if (idev == NULL) {
+ printk(KERN_DEBUG "addrconf_ifdown: device not found\n");
+ end_bh_atomic();
+ return -ENODEV;
+ }
-static void addrconf_dad_timer(unsigned long data)
-{
- struct inet6_ifaddr *ifp;
- struct in6_addr unspec;
- struct in6_addr mcaddr;
+ /*
+ * FIXME: clear multicast group membership
+ */
- ifp = (struct inet6_ifaddr *) data;
+ /*
+ * clean addr_list
+ */
- if (--ifp->probes == 0)
- {
- /*
- * DAD was successful
- */
+ for (i=0; i<16; i++) {
+ bifa = &inet6_addr_lst[i];
- ifp->flags &= ~DAD_INCOMPLETE;
- addrconf_dad_completed(ifp);
- return;
+ for (ifa=inet6_addr_lst[i]; ifa; ) {
+ if (ifa->idev == idev) {
+ *bifa = ifa->lst_next;
+ del_timer(&ifa->timer);
+ kfree(ifa);
+ ifa = *bifa;
+ continue;
+ }
+ ifa = ifa->lst_next;
+ bifa = &ifa->lst_next;
+ }
}
- /* send a neighbour solicitation for our addr */
- memset(&unspec, 0, sizeof(unspec));
- addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
-
- ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec);
-
- ifp->timer.expires = jiffies + RETRANS_TIMER;
- add_timer(&ifp->timer);
+ kfree(idev);
+ end_bh_atomic();
+ return 0;
}
static void addrconf_rs_timer(unsigned long data)
@@ -1153,11 +939,10 @@
ifp = (struct inet6_ifaddr *) data;
- if (ipv6_forwarding)
+ if (ipv6_config.forwarding)
return;
- if (ifp->idev->if_flags & IF_RA_RCVD)
- {
+ if (ifp->idev->if_flags & IF_RA_RCVD) {
/*
* Announcement received after solicitation
* was sent
@@ -1165,8 +950,7 @@
return;
}
- if (ifp->probes++ <= MAX_RTR_SOLICITATIONS)
- {
+ if (ifp->probes++ <= ipv6_config.rtr_solicits) {
struct in6_addr all_routers;
ipv6_addr_set(&all_routers,
@@ -1175,54 +959,77 @@
ndisc_send_rs(ifp->idev->dev, &ifp->addr,
&all_routers);
-
ifp->timer.function = addrconf_rs_timer;
- ifp->timer.expires = jiffies + RTR_SOLICITATION_INTERVAL;
+ ifp->timer.expires = (jiffies +
+ ipv6_config.rtr_solicit_interval);
add_timer(&ifp->timer);
- }
- else
- {
+ } else {
+ struct in6_rtmsg rtmsg;
+ int err;
+
+#if ACONF_DEBUG >= 2
printk(KERN_DEBUG "%s: no IPv6 routers present\n",
ifp->idev->dev->name);
+#endif
- if (!default_rt_list && !last_resort_rt)
- {
- struct rt6_info *rt;
+ memset(&rtmsg, 0, sizeof(struct in6_rtmsg));
+ rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+ rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+ rtmsg.rtmsg_flags = (RTF_ALLONLINK | RTF_ADDRCONF |
+ RTF_DEFAULT | RTF_UP);
- /*
- * create a last resort route with all
- * destinations on link
- */
- rt = kmalloc(sizeof(struct rt6_info), GFP_ATOMIC);
+ rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex;
- if (rt)
- {
- memset(rt, 0, sizeof(struct rt6_info));
- rt->rt_dev = ifp->idev->dev;
- rt->rt_ref = 1;
- rt->rt_flags = (RTI_ALLONLINK | RTF_UP);
- last_resort_rt = rt;
- }
- }
+ ip6_route_add(&rtmsg, &err);
}
}
+/*
+ * Duplicate Address Detection
+ */
static void addrconf_dad_start(struct inet6_ifaddr *ifp)
{
static int rand_seed = 1;
- int rand_num;
+ struct device *dev;
+ unsigned long rand_num;
+
+ dev = ifp->idev->dev;
+
+ if (dev->flags & IFF_MULTICAST) {
+ struct in6_rtmsg rtmsg;
+ struct rt6_info *mrt;
+ int err;
+
+ memset(&rtmsg, 0, sizeof(rtmsg));
+ ipv6_addr_set(&rtmsg.rtmsg_dst,
+ __constant_htonl(0xFF000000), 0, 0, 0);
+
+ rtmsg.rtmsg_dst_len = 8;
+ rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+ rtmsg.rtmsg_ifindex = dev->ifindex;
+
+ rtmsg.rtmsg_flags = RTF_UP;
+
+ mrt = ip6_route_add(&rtmsg, &err);
+
+ if (err)
+ printk(KERN_DEBUG "dad_start: mcast route add failed\n");
+ else
+ mrt->rt6i_nexthop = ndisc_get_neigh(dev, &rtmsg.rtmsg_dst);
+ }
- if (rand_seed)
- {
+ if (rand_seed) {
rand_seed = 0;
nd_rand_seed = ifp->addr.s6_addr32[3];
}
init_timer(&ifp->timer);
- ifp->probes = DupAddrDetectTransmits;
- rand_num = ipv6_random() % MAX_RTR_SOLICITATION_DELAY;
+ ifp->probes = ipv6_config.dad_transmits;
+ ifp->flags |= DAD_INCOMPLETE;
+
+ rand_num = ipv6_random() % ipv6_config.rtr_solicit_delay;
ifp->timer.function = addrconf_dad_timer;
ifp->timer.data = (unsigned long) ifp;
@@ -1231,6 +1038,97 @@
add_timer(&ifp->timer);
}
+static void addrconf_dad_timer(unsigned long data)
+{
+ struct inet6_ifaddr *ifp;
+ struct in6_addr unspec;
+ struct in6_addr mcaddr;
+
+ ifp = (struct inet6_ifaddr *) data;
+
+ if (ifp->probes == 0) {
+ /*
+ * DAD was successful
+ */
+
+ ifp->flags &= ~DAD_INCOMPLETE;
+ addrconf_dad_completed(ifp);
+ return;
+ }
+
+ ifp->probes--;
+
+ /* send a neighbour solicitation for our addr */
+ memset(&unspec, 0, sizeof(unspec));
+ addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
+
+ ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec);
+
+ ifp->timer.expires = jiffies + ipv6_config.rtr_solicit_interval;
+ add_timer(&ifp->timer);
+}
+
+static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
+{
+ struct device *dev;
+ int err;
+
+ dev = ifp->idev->dev;
+
+ if (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL) {
+ struct in6_rtmsg rtmsg;
+ struct in6_addr all_routers;
+
+ /*
+ * 1) configure a link route for this interface
+ * 2) send a (delayed) router solicitation
+ */
+
+ memset(&rtmsg, 0, sizeof(rtmsg));
+
+ memcpy(&rtmsg.rtmsg_dst, &ifp->addr, sizeof(struct in6_addr));
+
+ rtmsg.rtmsg_dst_len = ifp->prefix_len;
+ rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+ rtmsg.rtmsg_ifindex = dev->ifindex;
+
+ rtmsg.rtmsg_flags = RTF_UP;
+
+ ip6_route_add(&rtmsg, &err);
+
+ if (err)
+ printk(KERN_DEBUG "dad_complete: error in route_add\n");
+
+ if (ipv6_config.forwarding == 0) {
+ ipv6_addr_set(&all_routers,
+ __constant_htonl(0xff020000U), 0, 0,
+ __constant_htonl(0x2U));
+
+ /*
+ * If a host as already performed a random delay
+ * [...] as part of DAD [...] there is no need
+ * to delay again before sending the first RS
+ */
+ ndisc_send_rs(ifp->idev->dev, &ifp->addr,
+ &all_routers);
+
+ ifp->probes = 1;
+ ifp->timer.function = addrconf_rs_timer;
+ ifp->timer.expires = (jiffies +
+ ipv6_config.rtr_solicit_interval);
+ ifp->idev->if_flags |= IF_RS_SENT;
+ add_timer(&ifp->timer);
+ }
+ }
+
+ /*
+ * configure the address for reception
+ */
+
+ ip6_rt_addr_add(&ifp->addr, dev);
+}
+
+#ifdef CONFIG_PROC_FS
static int iface_proc_info(char *buffer, char **start, off_t offset,
int length, int dummy)
{
@@ -1238,13 +1136,11 @@
int i;
int len = 0;
- for (i=0; i < HASH_SIZE; i++)
- for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next)
- {
+ for (i=0; i < IN6_ADDR_HSIZE; i++)
+ for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
int j;
- for (j=0; j<16; j++)
- {
+ for (j=0; j<16; j++) {
sprintf(buffer + len, "%02x",
ifp->addr.s6_addr[j]);
len += 2;
@@ -1252,7 +1148,7 @@
len += sprintf(buffer + len,
" %02x %02x %02x %02x %8s\n",
- ifp->idev->if_index,
+ ifp->idev->dev->ifindex,
ifp->prefix_len,
ifp->scope,
ifp->flags,
@@ -1275,7 +1171,7 @@
0, NULL,
&iface_proc_info
};
-
+#endif /* CONFIG_PROC_FS */
/*
* Periodic address status verification
@@ -1287,29 +1183,23 @@
unsigned long now = jiffies;
int i;
- for (i=0; i < HASH_SIZE; i++)
- {
- for (ifp=inet6_addr_lst[i]; ifp;)
- {
- if (!(ifp->flags & ADDR_PERMANENT))
- {
+ for (i=0; i < IN6_ADDR_HSIZE; i++) {
+ for (ifp=inet6_addr_lst[i]; ifp;) {
+ if (!(ifp->flags & ADDR_PERMANENT)) {
struct inet6_ifaddr *bp;
unsigned long age;
age = (now - ifp->tstamp) / HZ;
if (age > ifp->prefered_lft)
- {
ifp->flags |= ADDR_DEPRECATED;
- }
bp = ifp;
ifp=ifp->lst_next;
if (age > bp->valid_lft)
- {
ipv6_del_addr(bp);
- }
+
continue;
}
ifp=ifp->lst_next;
@@ -1320,18 +1210,25 @@
add_timer(&addr_chk_timer);
}
+/*
+ * Init / cleanup code
+ */
+
void addrconf_init()
{
struct device *dev;
- /* init addr hash list */
- memset(inet6_addr_lst, 0, 16 * sizeof(struct inet6_ifaddr *));
+ /*
+ * init address and device hash lists
+ */
- memset(inet6_mcast_lst, 0, 16 * sizeof(struct ipv6_mc_list *));
+ memset(inet6_addr_lst, 0, IN6_ADDR_HSIZE * sizeof(struct inet6_ifaddr *));
- inet6_dev_lst = NULL;
+ memset(inet6_mcast_lst, 0, IN6_ADDR_HSIZE * sizeof(struct ifmcaddr6 *));
- /*
+ memset(inet6_dev_lst, 0, IN6_ADDR_HSIZE * sizeof(struct inet6_dev *));
+
+ /*
* Init loopback device
*/
@@ -1350,16 +1247,19 @@
if (dev && (dev->flags & IFF_UP))
addrconf_eth_config(dev);
- proc_register(&proc_net, &iface_proc_entry);
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&iface_proc_entry);
+#endif
addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY;
add_timer(&addr_chk_timer);
}
+#ifdef MODULE
void addrconf_cleanup(void)
{
- struct inet6_dev *idev, *bidev;
- struct inet6_ifaddr *ifa, *bifa;
+ struct inet6_dev *idev;
+ struct inet6_ifaddr *ifa;
int i;
del_timer(&addr_chk_timer);
@@ -1368,26 +1268,32 @@
* clean dev list.
*/
- for (idev = inet6_dev_lst; idev; )
- {
- bidev = idev;
- idev = idev->next;
- kfree(bidev);
+ for (i=0; i < IN6_ADDR_HSIZE; i++) {
+ for (idev = inet6_dev_lst[i]; idev; ) {
+ struct inet6_dev *back;
+
+ back = idev;
+ idev = idev->next;
+ kfree(back);
+ }
}
/*
* clean addr_list
*/
- for (i=0; i<16; i++)
- {
- for (ifa=inet6_addr_lst[i]; ifa; )
- {
+ for (i=0; i < IN6_ADDR_HSIZE; i++) {
+ for (ifa=inet6_addr_lst[i]; ifa; ) {
+ struct inet6_ifaddr *bifa;
+
bifa = ifa;
ifa = ifa->lst_next;
kfree(bifa);
}
}
- proc_unregister(&proc_net, iface_proc_entry.low_ino);
+#ifdef CONFIG_PROC_FS
+ proc_net_unregister(iface_proc_entry.low_ino);
+#endif
}
+#endif /* MODULE */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov