patch-2.1.68 linux/net/ipv6/addrconf.c
Next file: linux/net/ipv6/af_inet6.c
Previous file: linux/net/ipv6/Config.in
Back to the patch index
Back to the overall index
- Lines: 973
- Date:
Sun Nov 30 14:00:39 1997
- Orig file:
v2.1.67/linux/net/ipv6/addrconf.c
- Orig date:
Thu Sep 4 17:07:32 1997
diff -u --recursive --new-file v2.1.67/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: addrconf.c,v 1.21 1997/08/09 03:44:24 davem Exp $
+ * $Id: addrconf.c,v 1.28 1997/11/05 20:20:43 kuznet Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -31,6 +31,7 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/route.h>
+#include <linux/inetdevice.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
@@ -42,7 +43,8 @@
#include <net/ndisc.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
-#include <net/sit.h>
+#include <net/ip.h>
+#include <linux/if_tunnel.h>
#include <asm/uaccess.h>
@@ -92,12 +94,11 @@
st = addr->s6_addr32[0];
- /*
- * UCast Provider Based Address
- * 0x4/3
+ /* Consider all addresses with the first three bits different of
+ 000 and 111 as unicasts.
*/
-
- if ((st & __constant_htonl(0xE0000000)) == __constant_htonl(0x40000000))
+ if ((st & __constant_htonl(0xE0000000)) != __constant_htonl(0x00000000) &&
+ (st & __constant_htonl(0xE0000000)) != __constant_htonl(0xE0000000))
return IPV6_ADDR_UNICAST;
if ((st & __constant_htonl(0xFF000000)) == __constant_htonl(0xFF000000)) {
@@ -184,6 +185,8 @@
printk(KERN_DEBUG "joining all-routers\n");
#endif
idev->router = 1;
+
+ /* Wrong. It is user level function. */
ipv6_addr_all_routers(&maddr);
ipv6_dev_mc_inc(idev->dev, &maddr);
}
@@ -222,6 +225,7 @@
memcpy(&ifa->addr, addr, sizeof(struct in6_addr));
init_timer(&ifa->timer);
+ ifa->timer.data = (unsigned long) ifa;
ifa->scope = scope;
ifa->idev = idev;
@@ -361,7 +365,7 @@
}
out:
- if (ifp == NULL && match)
+ if (ifp == NULL)
ifp = match;
atomic_dec(&addr_list_lock);
return ifp;
@@ -410,6 +414,157 @@
return ifp;
}
+/* Join to solicited addr multicast group. */
+
+static void addrconf_join_solict(struct device *dev, struct in6_addr *addr)
+{
+ struct in6_addr maddr;
+
+ addrconf_addr_solict_mult(addr, &maddr);
+ ipv6_dev_mc_inc(dev, &maddr);
+}
+
+#ifdef CONFIG_IPV6_EUI64
+static int ipv6_generate_eui64(u8 *eui, struct device *dev)
+{
+ switch (dev->type) {
+ case ARPHRD_ETHER:
+ if (dev->addr_len != ETH_ALEN)
+ return -1;
+ memcpy(eui, dev->dev_addr, 3);
+ memcpy(eui + 5, dev->dev_addr+3, 3);
+ eui[3] = 0xFF;
+ eui[4] = 0xFE;
+ eui[0] ^= 2;
+ return 0;
+ }
+ return -1;
+}
+#endif
+
+/*
+ * Add prefix route.
+ */
+
+static void
+addrconf_prefix_route(struct in6_addr *pfx, int plen, struct device *dev,
+ unsigned long info)
+{
+ struct in6_rtmsg rtmsg;
+ int err;
+
+ memset(&rtmsg, 0, sizeof(rtmsg));
+ memcpy(&rtmsg.rtmsg_dst, pfx, sizeof(struct in6_addr));
+ rtmsg.rtmsg_dst_len = plen;
+ rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+ rtmsg.rtmsg_ifindex = dev->ifindex;
+ rtmsg.rtmsg_info = info;
+ rtmsg.rtmsg_flags = RTF_UP|RTF_ADDRCONF;
+
+ /* Prevent useless cloning on PtP SIT.
+ This thing is done here expecting that the whole
+ class of non-broadcast devices need not cloning.
+ */
+ if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT))
+ rtmsg.rtmsg_flags |= RTF_NONEXTHOP;
+ rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+
+ ip6_route_add(&rtmsg, &err);
+
+ if (err)
+ printk(KERN_DEBUG "IPv6: error %d adding prefix route\n", err);
+}
+
+/* Create "default" multicast route to the interface */
+
+static void addrconf_add_mroute(struct device *dev)
+{
+ struct in6_rtmsg rtmsg;
+ struct rt6_info *rt;
+ 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|RTF_ADDRCONF;
+ rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+
+ rt = ip6_route_add(&rtmsg, &err);
+
+ /*
+ * Pedro makes interesting thing here, he attached
+ * fake nexthop to multicast route.
+ * It is trick to avoid cloning, ugly, but efficient. --ANK
+ */
+
+ if (err)
+ printk(KERN_DEBUG "IPv6: error %d adding mroute\n", err);
+ else
+ rt->rt6i_nexthop = ndisc_get_neigh(dev, &rtmsg.rtmsg_dst);
+}
+
+static void sit_route_add(struct device *dev)
+{
+ struct in6_rtmsg rtmsg;
+ struct rt6_info *rt;
+ int err;
+
+ memset(&rtmsg, 0, sizeof(rtmsg));
+
+ rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+ rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+
+ /* prefix length - 96 bytes "::d.d.d.d" */
+ rtmsg.rtmsg_dst_len = 96;
+ rtmsg.rtmsg_flags = RTF_UP;
+ rtmsg.rtmsg_ifindex = dev->ifindex;
+
+ rt = ip6_route_add(&rtmsg, &err);
+
+ /* See comment in addrconf_add_mroute.
+ * It is the same trick, but to avoid cloning for direct
+ * sit routes i.e. IPv4 comaptible destinations.
+ */
+ if (err)
+ printk(KERN_DEBUG "sit_route_add: error %d in route_add\n", err);
+ else
+ rt->rt6i_nexthop = ndisc_get_neigh(dev, &rtmsg.rtmsg_dst);
+}
+
+static void addrconf_add_lroute(struct device *dev)
+{
+ struct in6_addr addr;
+
+ ipv6_addr_set(&addr, __constant_htonl(0xFE800000), 0, 0, 0);
+ addrconf_prefix_route(&addr, 10, dev, 0);
+}
+
+static struct inet6_dev *addrconf_add_dev(struct device *dev)
+{
+ struct in6_addr maddr;
+ struct inet6_dev *idev;
+
+ if ((idev = ipv6_get_idev(dev)) == NULL) {
+ idev = ipv6_add_dev(dev);
+ if (idev == NULL)
+ return NULL;
+ }
+
+ /* Add default multicast route */
+ addrconf_add_mroute(dev);
+
+ /* Add link local route */
+ addrconf_add_lroute(dev);
+
+ /* Join to all nodes multicast group. */
+ ipv6_addr_all_nodes(&maddr);
+ ipv6_dev_mc_inc(dev, &maddr);
+ return idev;
+}
+
void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len)
{
struct prefix_info *pinfo;
@@ -432,7 +587,7 @@
addr_type = ipv6_addr_type(&pinfo->prefix);
- if (addr_type & IPV6_ADDR_LINKLOCAL)
+ if (addr_type & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL))
return;
valid_lft = ntohl(pinfo->valid);
@@ -470,23 +625,12 @@
rt->rt6i_expires = rt_expires;
}
} else if (pinfo->onlink && valid_lft) {
- struct in6_rtmsg rtmsg;
- int err;
-
- memset(&rtmsg, 0, sizeof(rtmsg));
-
- printk(KERN_DEBUG "adding on link route\n");
-
- 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;
-
- ip6_route_add(&rtmsg, &err);
+ addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,
+ dev, rt_expires);
}
+ /* Try to figure out our local address for this prefix */
+
if (pinfo->autoconf && ipv6_config.autoconf) {
struct inet6_ifaddr * ifp;
struct in6_addr addr;
@@ -494,33 +638,41 @@
plen = pinfo->prefix_len >> 3;
- if (plen + dev->addr_len == sizeof(struct in6_addr)) {
+#ifdef CONFIG_IPV6_EUI64
+ if (pinfo->prefix_len == 64) {
+ memcpy(&addr, &pinfo->prefix, 8);
+ if (ipv6_generate_eui64(addr.s6_addr + 8, dev))
+ return;
+ goto ok;
+ }
+#endif
+#ifndef CONFIG_IPV6_NO_PB
+ if (pinfo->prefix_len == ((sizeof(struct in6_addr) - dev->addr_len)<<3)) {
memcpy(&addr, &pinfo->prefix, plen);
memcpy(addr.s6_addr + plen, dev->dev_addr,
dev->addr_len);
- } else {
- ADBG(("addrconf: prefix_len invalid\n"));
- return;
+ goto ok;
}
+#endif
+ printk(KERN_DEBUG "IPv6 addrconf: prefix with wrong length %d\n", pinfo->prefix_len);
+ return;
+ok:
ifp = ipv6_chk_addr(&addr);
if (ifp == NULL && valid_lft) {
struct inet6_dev *in6_dev = ipv6_get_idev(dev);
- if (in6_dev == NULL)
- ADBG(("addrconf: device not configured\n"));
-
+ if (in6_dev == NULL) {
+ printk(KERN_DEBUG "addrconf: device %s not configured\n", dev->name);
+ return;
+ }
+
ifp = ipv6_add_addr(in6_dev, &addr,
addr_type & IPV6_ADDR_SCOPE_MASK);
- if (dev->flags & IFF_MULTICAST) {
- struct in6_addr maddr;
-
- /* Join to solicited addr multicast group. */
- addrconf_addr_solict_mult(&addr, &maddr);
- ipv6_dev_mc_inc(dev, &maddr);
- }
+ if (ifp == NULL)
+ return;
ifp->prefix_len = pinfo->prefix_len;
@@ -564,17 +716,32 @@
}
if (dev->type == ARPHRD_SIT) {
- struct device *dev;
-
+ struct ifreq ifr;
+ mm_segment_t oldfs;
+ struct ip_tunnel_parm p;
+
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;
+
+ memset(&p, 0, sizeof(p));
+ p.iph.daddr = ireq.ifr6_addr.s6_addr32[3];
+ p.iph.saddr = 0;
+ p.iph.version = 4;
+ p.iph.ihl = 5;
+ p.iph.protocol = IPPROTO_IPV6;
+ p.iph.ttl = 64;
+ ifr.ifr_ifru.ifru_data = (void*)&p;
+
+ oldfs = get_fs(); set_fs(KERNEL_DS);
+ err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL);
+ set_fs(oldfs);
+
+ if (err == 0) {
+ err = -ENOBUFS;
+ if ((dev = dev_get(p.name)) == NULL)
+ goto err_exit;
+ err = dev_open(dev);
+ }
}
err_exit:
@@ -595,38 +762,27 @@
if (!suser())
return -EPERM;
- if(copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
+ if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
return -EFAULT;
- if((dev = dev_get_by_index(ireq.ifr6_ifindex)) == NULL)
- return -EINVAL;
+ if ((dev = dev_get_by_index(ireq.ifr6_ifindex)) == NULL)
+ return -ENODEV;
+
+ if (!(dev->flags&IFF_UP))
+ return -ENETDOWN;
- if ((idev = ipv6_get_idev(dev)) == NULL)
- return -EINVAL;
+ if ((idev = addrconf_add_dev(dev)) == NULL)
+ return -ENOBUFS;
scope = ipv6_addr_scope(&ireq.ifr6_addr);
if((ifp = ipv6_add_addr(idev, &ireq.ifr6_addr, scope)) == NULL)
return -ENOMEM;
- ifp->prefix_len = 128;
-
- if (dev->flags & IFF_MULTICAST) {
- struct in6_addr maddr;
-
- /* 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)))
- addrconf_dad_start(ifp);
- else
- ip6_rt_addr_add(&ifp->addr, dev);
-
+ addrconf_dad_start(ifp);
return 0;
}
@@ -645,90 +801,22 @@
return -EFAULT;
if ((dev = dev_get_by_index(ireq.ifr6_ifindex)) == NULL)
- return -EINVAL;
+ return -ENODEV;
if ((idev = ipv6_get_idev(dev)) == NULL)
- return -EINVAL;
+ return -ENXIO;
scope = ipv6_addr_scope(&ireq.ifr6_addr);
for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
- if (ifp->scope == scope &&
- (!memcmp(&ireq.ifr6_addr, &ifp->addr, sizeof(struct in6_addr)))) {
- ipv6_del_addr(ifp);
- break;
- }
- }
-
- return 0;
-}
-
-static void sit_route_add(struct device *dev)
-{
- 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");
+ if (ifp->scope == scope &&
+ (!memcmp(&ireq.ifr6_addr, &ifp->addr, sizeof(struct in6_addr)))) {
+ ipv6_del_addr(ifp);
+ break;
}
-
- /*
- * 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"));
}
+
+ return 0;
}
static void sit_add_v4_addrs(struct inet6_dev *idev)
@@ -739,34 +827,55 @@
int scope;
memset(&addr, 0, sizeof(struct in6_addr));
+ memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4);
- if (idev->dev->pa_dstaddr) {
+ if (idev->dev->flags&IFF_POINTOPOINT) {
addr.s6_addr32[0] = __constant_htonl(0xfe800000);
scope = IFA_LINK;
} else {
scope = IPV6_ADDR_COMPATv4;
}
+ if (addr.s6_addr32[3]) {
+ ifp = ipv6_add_addr(idev, &addr, scope);
+ if (ifp) {
+ ifp->flags |= ADDR_PERMANENT;
+ ifp->prefix_len = 128;
+ ip6_rt_addr_add(&ifp->addr, idev->dev);
+ }
+ return;
+ }
+
for (dev = dev_base; dev != NULL; dev = dev->next) {
- if (dev->family == AF_INET && (dev->flags & IFF_UP)) {
+ if (dev->ip_ptr && (dev->flags & IFF_UP)) {
+ struct in_device * in_dev = dev->ip_ptr;
+ struct in_ifaddr * ifa;
+
int flag = scope;
-
- addr.s6_addr32[3] = dev->pa_addr;
- if (dev->flags & IFF_LOOPBACK) {
- if (idev->dev->pa_dstaddr)
- continue;
+ for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
+ addr.s6_addr32[3] = ifa->ifa_local;
- flag |= IFA_HOST;
- }
-
- ifp = ipv6_add_addr(idev, &addr, flag);
+ if (ifa->ifa_scope == RT_SCOPE_LINK)
+ continue;
+ if (ifa->ifa_scope >= RT_SCOPE_HOST) {
+ if (idev->dev->flags&IFF_POINTOPOINT)
+ continue;
+ flag |= IFA_HOST;
+ }
- if (ifp == NULL)
- continue;
+ ifp = ipv6_add_addr(idev, &addr, flag);
+
+ if (ifp == NULL)
+ continue;
- ifp->flags |= ADDR_PERMANENT;
- ip6_rt_addr_add(&ifp->addr, dev);
+ if (idev->dev->flags&IFF_POINTOPOINT)
+ ifp->prefix_len = 10;
+ else
+ ifp->prefix_len = 96;
+ ifp->flags |= ADDR_PERMANENT;
+ ip6_rt_addr_add(&ifp->addr, dev);
+ }
}
}
}
@@ -804,56 +913,98 @@
printk(KERN_DEBUG "init_loopback: error in route_add\n");
}
-static void addrconf_eth_config(struct device *dev)
+static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr)
+{
+ struct inet6_ifaddr * ifp;
+
+ ifp = ipv6_add_addr(idev, addr, IFA_LINK);
+ if (ifp == NULL)
+ return;
+
+ ifp->flags = ADDR_PERMANENT;
+ ifp->prefix_len = 10;
+
+ addrconf_dad_start(ifp);
+}
+
+static void addrconf_dev_config(struct device *dev)
{
struct in6_addr addr;
struct in6_addr maddr;
- struct inet6_ifaddr * ifp;
struct inet6_dev * idev;
+ if (dev->type != ARPHRD_ETHER) {
+ /* Alas, we support only ethernet autoconfiguration. */
+ return;
+ }
+
+ idev = addrconf_add_dev(dev);
+ if (idev == NULL)
+ return;
+
+#ifdef CONFIG_IPV6_EUI64
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);
+ if (ipv6_generate_eui64(addr.s6_addr + 8, dev) == 0)
+ addrconf_add_linklocal(idev, &addr);
+#endif
- idev = ipv6_add_dev(dev);
- if (idev == NULL)
- return;
-
- ifp = ipv6_add_addr(idev, &addr, IFA_LINK);
- if (ifp == NULL)
- return;
+#ifndef CONFIG_IPV6_NO_PB
+ memset(&addr, 0, sizeof(struct in6_addr));
- ifp->flags = ADDR_PERMANENT;
- ifp->prefix_len = 10;
+ addr.s6_addr[0] = 0xFE;
+ addr.s6_addr[1] = 0x80;
- /* Join to all nodes multicast group. */
- ipv6_addr_all_nodes(&maddr);
- ipv6_dev_mc_inc(dev, &maddr);
+ memcpy(addr.s6_addr + (sizeof(struct in6_addr) - dev->addr_len),
+ dev->dev_addr, dev->addr_len);
+ addrconf_add_linklocal(idev, &addr);
+#endif
if (ipv6_config.forwarding) {
idev->router = 1;
+
+ /* It is wrong.
+ It is routing daemon or radvd that must make it,
+ rather than kernel.
+ */
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);
+static void addrconf_sit_config(struct device *dev)
+{
+ struct inet6_dev *idev;
- /* Start duplicate address detection. */
- addrconf_dad_start(ifp);
+ /*
+ * Configure the tunnel with one of our IPv4
+ * addresses... we should configure all of
+ * our v4 addrs in the tunnel
+ */
+
+ idev = ipv6_add_dev(dev);
+ if (idev == NULL) {
+ printk(KERN_DEBUG "init sit: add_dev failed\n");
+ return;
+ }
+
+ sit_add_v4_addrs(idev);
+
+ if (dev->flags&IFF_POINTOPOINT) {
+ addrconf_add_mroute(dev);
+ addrconf_add_lroute(dev);
+ } else
+ sit_route_add(dev);
}
+
int addrconf_notify(struct notifier_block *this, unsigned long event,
void * data)
{
struct device *dev;
- struct inet6_dev * idev;
dev = (struct device *) data;
@@ -861,34 +1012,15 @@
case NETDEV_UP:
switch(dev->type) {
case ARPHRD_SIT:
-
- printk(KERN_DEBUG "sit device up: %s\n", dev->name);
-
- /*
- * Configure the tunnel with one of our IPv4
- * addresses... we should configure all of
- * our v4 addrs in the tunnel
- */
-
- idev = ipv6_add_dev(dev);
-
- sit_add_v4_addrs(idev);
-
- /*
- * we do an hack for now to configure the tunnel
- * route.
- */
-
- sit_route_add(dev);
+ addrconf_sit_config(dev);
break;
case ARPHRD_LOOPBACK:
init_loopback(dev);
break;
- case ARPHRD_ETHER:
- printk(KERN_DEBUG "Configuring eth interface\n");
- addrconf_eth_config(dev);
+ default:
+ addrconf_dev_config(dev);
break;
};
@@ -934,7 +1066,6 @@
}
if (idev == NULL) {
- printk(KERN_DEBUG "addrconf_ifdown: device not found\n");
end_bh_atomic();
return -ENODEV;
}
@@ -958,8 +1089,8 @@
ifa = *bifa;
continue;
}
- ifa = ifa->lst_next;
bifa = &ifa->lst_next;
+ ifa = *bifa;
}
}
@@ -968,6 +1099,7 @@
return 0;
}
+
static void addrconf_rs_timer(unsigned long data)
{
struct inet6_ifaddr *ifp;
@@ -1003,10 +1135,8 @@
struct in6_rtmsg rtmsg;
int err;
-#if ACONF_DEBUG >= 2
printk(KERN_DEBUG "%s: no IPv6 routers present\n",
ifp->idev->dev->name);
-#endif
memset(&rtmsg, 0, sizeof(struct in6_rtmsg));
rtmsg.rtmsg_type = RTMSG_NEWROUTE;
@@ -1031,27 +1161,17 @@
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;
+ addrconf_join_solict(dev, &ifp->addr);
- mrt = ip6_route_add(&rtmsg, &err);
+ if (ifp->prefix_len != 128)
+ addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0);
- if (err)
- printk(KERN_DEBUG "dad_start: mcast route add failed\n");
- else
- mrt->rt6i_nexthop = ndisc_get_neigh(dev, &rtmsg.rtmsg_dst);
+ if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
+ start_bh_atomic();
+ ifp->flags &= ~DAD_INCOMPLETE;
+ addrconf_dad_completed(ifp);
+ end_bh_atomic();
+ return;
}
if (rand_seed) {
@@ -1059,15 +1179,12 @@
nd_rand_seed = ifp->addr.s6_addr32[3];
}
- init_timer(&ifp->timer);
-
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;
ifp->timer.expires = jiffies + rand_num;
add_timer(&ifp->timer);
@@ -1105,62 +1222,41 @@
static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
{
- struct device *dev;
- int err;
-
- dev = ifp->idev->dev;
+ struct device * dev = ifp->idev->dev;
- if (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL) {
- struct in6_rtmsg rtmsg;
- struct in6_addr all_routers;
+ /*
+ * Configure the address for reception. Now it is valid.
+ */
- /*
- * 1) configure a link route for this interface
- * 2) send a (delayed) router solicitation
- */
+ ip6_rt_addr_add(&ifp->addr, dev);
- memset(&rtmsg, 0, sizeof(rtmsg));
-
- memcpy(&rtmsg.rtmsg_dst, &ifp->addr, sizeof(struct in6_addr));
+ /* If added prefix is link local and forwarding is off,
+ start sending router solicitations.
+ */
- rtmsg.rtmsg_dst_len = ifp->prefix_len;
- rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
- rtmsg.rtmsg_ifindex = dev->ifindex;
+ if (ipv6_config.forwarding == 0 &&
+ (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) == 0 &&
+ (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
+ struct in6_addr all_routers;
- rtmsg.rtmsg_flags = RTF_UP;
+ ipv6_addr_set(&all_routers,
+ __constant_htonl(0xff020000U), 0, 0,
+ __constant_htonl(0x2U));
- ip6_route_add(&rtmsg, &err);
-
- if (err)
- printk(KERN_DEBUG "dad_complete: error in route_add\n");
+ /*
+ * 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);
- 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);
- }
+ 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
@@ -1251,7 +1347,9 @@
__initfunc(void addrconf_init(void))
{
+#ifdef MODULE
struct device *dev;
+#endif
/*
* init address and device hash lists
@@ -1263,24 +1361,25 @@
memset(inet6_dev_lst, 0, IN6_ADDR_HSIZE * sizeof(struct inet6_dev *));
- /*
- * Init loopback device
- */
-
- dev = dev_get("lo");
-
- if (dev && (dev->flags & IFF_UP))
- init_loopback(dev);
+#ifdef MODULE
+ /* This takes sense only during module load. */
- /*
- * and maybe:
- * search availiable AF_INET devs and try to configure them
- */
-
- dev = dev_get("eth0");
+ for (dev = dev_base; dev; dev = dev->next) {
+ if (!(dev->flags&IFF_UP))
+ continue;
- if (dev && (dev->flags & IFF_UP))
- addrconf_eth_config(dev);
+ switch (dev->type) {
+ case ARPHRD_LOOPBACK:
+ init_loopback(dev);
+ break;
+ case ARPHRD_ETHER:
+ addrconf_dev_config(dev);
+ break;
+ default:
+ /* Ignore all other */
+ }
+ }
+#endif
#ifdef CONFIG_PROC_FS
proc_net_register(&iface_proc_entry);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov