📄 addrconf.c
字号:
ipv6_del_addr(ifp); /* If the last address is deleted administratively, disable IPv6 on this interface. */ if (idev->addr_list == NULL) addrconf_ifdown(idev->dev, 1); return 0; } } read_unlock_bh(&idev->lock); return -EADDRNOTAVAIL;}int addrconf_add_ifaddr(void *arg){ struct in6_ifreq ireq; int err; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) return -EFAULT; rtnl_lock(); err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen); rtnl_unlock(); return err;}int addrconf_del_ifaddr(void *arg){ struct in6_ifreq ireq; int err; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) return -EFAULT; rtnl_lock(); err = inet6_addr_del(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen); rtnl_unlock(); return err;}static void sit_add_v4_addrs(struct inet6_dev *idev){ struct inet6_ifaddr * ifp; struct in6_addr addr; struct net_device *dev; int scope; ASSERT_RTNL(); memset(&addr, 0, sizeof(struct in6_addr)); memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4); 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, 128, scope, IFA_F_PERMANENT); if (ifp) { spin_lock_bh(&ifp->lock); ifp->flags &= ~IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); ipv6_ifa_notify(RTM_NEWADDR, ifp); in6_ifa_put(ifp); } return; } for (dev = dev_base; dev != NULL; dev = dev->next) { struct in_device * in_dev = __in_dev_get(dev); if (in_dev && (dev->flags & IFF_UP)) { struct in_ifaddr * ifa; int flag = scope; for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { int plen; addr.s6_addr32[3] = ifa->ifa_local; 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 (idev->dev->flags&IFF_POINTOPOINT) plen = 10; else plen = 96; ifp = ipv6_add_addr(idev, &addr, plen, flag, IFA_F_PERMANENT); if (ifp) { spin_lock_bh(&ifp->lock); ifp->flags &= ~IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); ipv6_ifa_notify(RTM_NEWADDR, ifp); in6_ifa_put(ifp); } } } }}static void init_loopback(struct net_device *dev){ struct in6_addr addr; struct inet6_dev *idev; struct inet6_ifaddr * ifp; /* ::1 */ ASSERT_RTNL(); memset(&addr, 0, sizeof(struct in6_addr)); addr.s6_addr[15] = 1; if ((idev = ipv6_find_idev(dev)) == NULL) { printk(KERN_DEBUG "init loopback: add_dev failed\n"); return; } ifp = ipv6_add_addr(idev, &addr, 128, IFA_HOST, IFA_F_PERMANENT); if (ifp) { spin_lock_bh(&ifp->lock); ifp->flags &= ~IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); ipv6_ifa_notify(RTM_NEWADDR, ifp); in6_ifa_put(ifp); }}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); if (ifp) { addrconf_dad_start(ifp); in6_ifa_put(ifp); }}static void addrconf_dev_config(struct net_device *dev){ struct in6_addr addr; struct inet6_dev * idev; ASSERT_RTNL(); if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_FDDI) && (dev->type != ARPHRD_IEEE802_TR)) { /* Alas, we support only Ethernet autoconfiguration. */ return; } idev = addrconf_add_dev(dev); if (idev == NULL) return; memset(&addr, 0, sizeof(struct in6_addr)); addr.s6_addr[0] = 0xFE; addr.s6_addr[1] = 0x80; if (ipv6_generate_eui64(addr.s6_addr + 8, dev) == 0) addrconf_add_linklocal(idev, &addr);}static void addrconf_sit_config(struct net_device *dev){ struct inet6_dev *idev; ASSERT_RTNL(); /* * Configure the tunnel with one of our IPv4 * addresses... we should configure all of * our v4 addrs in the tunnel */ if ((idev = ipv6_find_idev(dev)) == 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 net_device *dev; dev = (struct net_device *) data; switch(event) { case NETDEV_UP: switch(dev->type) { case ARPHRD_SIT: addrconf_sit_config(dev); break; case ARPHRD_LOOPBACK: init_loopback(dev); break; default: addrconf_dev_config(dev); break; }; break; case NETDEV_CHANGEMTU: if (dev->mtu >= IPV6_MIN_MTU) { struct inet6_dev *idev; if ((idev = __in6_dev_get(dev)) == NULL) break; idev->cnf.mtu6 = dev->mtu; rt6_mtu_change(dev, dev->mtu); break; } /* MTU falled under IPV6_MIN_MTU. Stop IPv6 on this interface. */ case NETDEV_DOWN: case NETDEV_UNREGISTER: /* * Remove all addresses from this interface. */ addrconf_ifdown(dev, event != NETDEV_DOWN); break; case NETDEV_CHANGE: break; }; return NOTIFY_OK;}static int addrconf_ifdown(struct net_device *dev, int how){ struct inet6_dev *idev; struct inet6_ifaddr *ifa, **bifa; int i; ASSERT_RTNL(); rt6_ifdown(dev); neigh_ifdown(&nd_tbl, dev); idev = __in6_dev_get(dev); if (idev == NULL) return -ENODEV; /* Step 1: remove reference to ipv6 device from parent device. Do not dev_put! */ if (how == 1) { write_lock_bh(&addrconf_lock); dev->ip6_ptr = NULL; idev->dead = 1; write_unlock_bh(&addrconf_lock); } /* Step 2: clear hash table */ for (i=0; i<IN6_ADDR_HSIZE; i++) { bifa = &inet6_addr_lst[i]; write_lock_bh(&addrconf_hash_lock); while ((ifa = *bifa) != NULL) { if (ifa->idev == idev) { *bifa = ifa->lst_next; ifa->lst_next = NULL; addrconf_del_timer(ifa); in6_ifa_put(ifa); continue; } bifa = &ifa->lst_next; } write_unlock_bh(&addrconf_hash_lock); } /* Step 3: clear address list */ write_lock_bh(&idev->lock); while ((ifa = idev->addr_list) != NULL) { idev->addr_list = ifa->if_next; ifa->if_next = NULL; ifa->dead = 1; addrconf_del_timer(ifa); write_unlock_bh(&idev->lock); ipv6_ifa_notify(RTM_DELADDR, ifa); in6_ifa_put(ifa); write_lock_bh(&idev->lock); } write_unlock_bh(&idev->lock); /* Step 4: Discard multicast list */ if (how == 1) ipv6_mc_destroy_dev(idev); else ipv6_mc_down(idev); /* Shot the device (if unregistered) */ if (how == 1) { neigh_parms_release(&nd_tbl, idev->nd_parms);#ifdef CONFIG_SYSCTL addrconf_sysctl_unregister(&idev->cnf);#endif in6_dev_put(idev); } return 0;}static void addrconf_rs_timer(unsigned long data){ struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; if (ifp->idev->cnf.forwarding) goto out; if (ifp->idev->if_flags & IF_RA_RCVD) { /* * Announcement received after solicitation * was sent */ goto out; } spin_lock(&ifp->lock); if (ifp->probes++ < ifp->idev->cnf.rtr_solicits) { struct in6_addr all_routers; /* The wait after the last probe can be shorter */ addrconf_mod_timer(ifp, AC_RS, (ifp->probes == ifp->idev->cnf.rtr_solicits) ? ifp->idev->cnf.rtr_solicit_delay : ifp->idev->cnf.rtr_solicit_interval); spin_unlock(&ifp->lock); ipv6_addr_all_routers(&all_routers); ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers); } else { struct in6_rtmsg rtmsg; spin_unlock(&ifp->lock); printk(KERN_DEBUG "%s: no IPv6 routers present\n", ifp->idev->dev->name); 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); rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex; ip6_route_add(&rtmsg); }out: in6_ifa_put(ifp);}/* * Duplicate Address Detection */static void addrconf_dad_start(struct inet6_ifaddr *ifp){ struct net_device *dev; unsigned long rand_num; dev = ifp->idev->dev; addrconf_join_solict(dev, &ifp->addr); if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT)) addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0, RTF_ADDRCONF); net_srandom(ifp->addr.s6_addr32[3]); rand_num = net_random() % (ifp->idev->cnf.rtr_solicit_delay ? : 1); spin_lock_bh(&ifp->lock); if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || !(ifp->flags&IFA_F_TENTATIVE)) { ifp->flags &= ~IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); addrconf_dad_completed(ifp); return; } ifp->probes = ifp->idev->cnf.dad_transmits; addrconf_mod_timer(ifp, AC_DAD, rand_num); spin_unlock_bh(&ifp->lock);}static void addrconf_dad_timer(unsigned long data){ struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; struct in6_addr unspec; struct in6_addr mcaddr; spin_lock_bh(&ifp->lock); if (ifp->probes == 0) { /* * DAD was successful */ ifp->flags &= ~IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); addrconf_dad_completed(ifp); in6_ifa_put(ifp); return; } ifp->probes--; addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); spin_unlock_bh(&ifp->lock); /* 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); in6_ifa_put(ifp);}static void addrconf_dad_completed(struct inet6_ifaddr *ifp){ struct net_device * dev = ifp->idev->dev; /* * Configure the address for reception. Now it is valid. */ ipv6_ifa_notify(RTM_NEWADDR, ifp); /* If added prefix is link local and forwarding is off, start sending router solicitations. */ if (ifp->idev->cnf.forwarding == 0 && (dev->flags&IFF_LOOPBACK) == 0 && (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { struct in6_addr all_routers; ipv6_addr_all_routers(&all_routers); /* * 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); spin_lock_bh(&ifp->lock); ifp->probes = 1; ifp->idev->if_flags |= IF_RS_SENT; addrconf_mod_timer(ifp, AC_RS, ifp->idev->cnf.rtr_solicit_interval); spin_unlock_bh(&ifp->lock); }}#ifdef CONFIG_PROC_FSstatic int iface_proc_info(char *buffer, char **start, off_t offset, int length){ struct inet6_ifaddr *ifp; int i; int len = 0; off_t pos=0; off_t begin=0; for (i=0; i < IN6_ADDR_HSIZE; i++) { read_lock_bh(&addrconf_hash_lock); for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) { int j; for (j=0; j<16; j++) { sprintf(buffer + len, "%02x", ifp->addr.s6_addr[j]); len += 2; } len += sprintf(buffer + len, " %02x %02x %02x %02x %8s\n", ifp->idev->dev->ifindex,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -