cregit-Linux how code gets into the kernel

Release 4.8 net/ipv6/addrconf.c

Directory: net/ipv6
/*
 *      IPv6 Address [auto]configuration
 *      Linux INET6 implementation
 *
 *      Authors:
 *      Pedro Roque             <roque@di.fc.ul.pt>
 *      Alexey Kuznetsov        <kuznet@ms2.inr.ac.ru>
 *
 *      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:
 *
 *      Janos Farkas                    :       delete timer on ifdown
 *      <chexum@bankinf.banki.hu>
 *      Andi Kleen                      :       kill double kfree on module
 *                                              unload.
 *      Maciej W. Rozycki               :       FDDI support
 *      sekiya@USAGI                    :       Don't send too many RS
 *                                              packets.
 *      yoshfuji@USAGI                  :       Fixed interval between DAD
 *                                              packets.
 *      YOSHIFUJI Hideaki @USAGI        :       improved accuracy of
 *                                              address validation timer.
 *      YOSHIFUJI Hideaki @USAGI        :       Privacy Extensions (RFC3041)
 *                                              support.
 *      Yuji SEKIYA @USAGI              :       Don't assign a same IPv6
 *                                              address on a same interface.
 *      YOSHIFUJI Hideaki @USAGI        :       ARCnet support
 *      YOSHIFUJI Hideaki @USAGI        :       convert /proc/net/if_inet6 to
 *                                              seq_file.
 *      YOSHIFUJI Hideaki @USAGI        :       improved source address
 *                                              selection; consider scope,
 *                                              status etc.
 */


#define pr_fmt(fmt) "IPv6: " fmt

#include <linux/errno.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/inet.h>
#include <linux/in6.h>
#include <linux/netdevice.h>
#include <linux/if_addr.h>
#include <linux/if_arp.h>
#include <linux/if_arcnet.h>
#include <linux/if_infiniband.h>
#include <linux/route.h>
#include <linux/inetdevice.h>
#include <linux/init.h>
#include <linux/slab.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
#include <linux/capability.h>
#include <linux/delay.h>
#include <linux/notifier.h>
#include <linux/string.h>
#include <linux/hash.h>

#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/snmp.h>

#include <net/6lowpan.h>
#include <net/firewire.h>
#include <net/ipv6.h>
#include <net/protocol.h>
#include <net/ndisc.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
#include <net/tcp.h>
#include <net/ip.h>
#include <net/netlink.h>
#include <net/pkt_sched.h>
#include <net/l3mdev.h>
#include <linux/if_tunnel.h>
#include <linux/rtnetlink.h>
#include <linux/netconf.h>
#include <linux/random.h>
#include <linux/uaccess.h>
#include <asm/unaligned.h>

#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/export.h>

/* Set to 3 to get tracing... */

#define ACONF_DEBUG 2

#if ACONF_DEBUG >= 3

#define ADBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
#else

#define ADBG(fmt, ...) do { if (0) printk(fmt, ##__VA_ARGS__); } while (0)
#endif


#define	INFINITY_LIFE_TIME	0xFFFFFFFF


#define IPV6_MAX_STRLEN \
	sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")


static inline u32 cstamp_delta(unsigned long cstamp) { return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; }

Contributors

PersonTokensPropCommitsCommitProp
thomas grafthomas graf2090.91%150.00%
shirley mashirley ma29.09%150.00%
Total22100.00%2100.00%

#ifdef CONFIG_SYSCTL static int addrconf_sysctl_register(struct inet6_dev *idev); static void addrconf_sysctl_unregister(struct inet6_dev *idev); #else
static inline int addrconf_sysctl_register(struct inet6_dev *idev) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov960.00%150.00%
americo wangamerico wang640.00%150.00%
Total15100.00%2100.00%


static inline void addrconf_sysctl_unregister(struct inet6_dev *idev) { }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov11100.00%1100.00%
Total11100.00%1100.00%

#endif static void __ipv6_regen_rndid(struct inet6_dev *idev); static void __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr); static void ipv6_regen_rndid(unsigned long data); static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); static int ipv6_count_addresses(struct inet6_dev *idev); static int ipv6_generate_stable_address(struct in6_addr *addr, u8 dad_count, const struct inet6_dev *idev); /* * Configured unicast address hash table */ static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE]; static DEFINE_SPINLOCK(addrconf_hash_lock); static void addrconf_verify(void); static void addrconf_verify_rtnl(void); static void addrconf_verify_work(struct work_struct *); static struct workqueue_struct *addrconf_wq; static DECLARE_DELAYED_WORK(addr_chk_work, addrconf_verify_work); static void addrconf_join_anycast(struct inet6_ifaddr *ifp); static void addrconf_leave_anycast(struct inet6_ifaddr *ifp); static void addrconf_type_change(struct net_device *dev, unsigned long event); static int addrconf_ifdown(struct net_device *dev, int how); static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, int plen, const struct net_device *dev, u32 flags, u32 noflags); static void addrconf_dad_start(struct inet6_ifaddr *ifp); static void addrconf_dad_work(struct work_struct *w); static void addrconf_dad_completed(struct inet6_ifaddr *ifp); static void addrconf_dad_run(struct inet6_dev *idev); static void addrconf_rs_timer(unsigned long data); static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); static void inet6_prefix_notify(int event, struct inet6_dev *idev, struct prefix_info *pinfo); static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, struct net_device *dev); static struct ipv6_devconf ipv6_devconf __read_mostly = { .forwarding = 0, .hop_limit = IPV6_DEFAULT_HOPLIMIT, .mtu6 = IPV6_MIN_MTU, .accept_ra = 1, .accept_redirects = 1, .autoconf = 1, .force_mld_version = 0, .mldv1_unsolicited_report_interval = 10 * HZ, .mldv2_unsolicited_report_interval = HZ, .dad_transmits = 1, .rtr_solicits = MAX_RTR_SOLICITATIONS, .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, .use_tempaddr = 0, .temp_valid_lft = TEMP_VALID_LIFETIME, .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, .regen_max_retry = REGEN_MAX_RETRY, .max_desync_factor = MAX_DESYNC_FACTOR, .max_addresses = IPV6_MAX_ADDRESSES, .accept_ra_defrtr = 1, .accept_ra_from_local = 0, .accept_ra_min_hop_limit= 1, .accept_ra_pinfo = 1, #ifdef CONFIG_IPV6_ROUTER_PREF .accept_ra_rtr_pref = 1, .rtr_probe_interval = 60 * HZ, #ifdef CONFIG_IPV6_ROUTE_INFO .accept_ra_rt_info_max_plen = 0, #endif #endif .proxy_ndp = 0, .accept_source_route = 0, /* we do not accept RH0 by default. */ .disable_ipv6 = 0, .accept_dad = 1, .suppress_frag_ndisc = 1, .accept_ra_mtu = 1, .stable_secret = { .initialized = false, }, .use_oif_addrs_only = 0, .ignore_routes_with_linkdown = 0, .keep_addr_on_down = 0, }; static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { .forwarding = 0, .hop_limit = IPV6_DEFAULT_HOPLIMIT, .mtu6 = IPV6_MIN_MTU, .accept_ra = 1, .accept_redirects = 1, .autoconf = 1, .force_mld_version = 0, .mldv1_unsolicited_report_interval = 10 * HZ, .mldv2_unsolicited_report_interval = HZ, .dad_transmits = 1, .rtr_solicits = MAX_RTR_SOLICITATIONS, .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, .use_tempaddr = 0, .temp_valid_lft = TEMP_VALID_LIFETIME, .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, .regen_max_retry = REGEN_MAX_RETRY, .max_desync_factor = MAX_DESYNC_FACTOR, .max_addresses = IPV6_MAX_ADDRESSES, .accept_ra_defrtr = 1, .accept_ra_from_local = 0, .accept_ra_min_hop_limit= 1, .accept_ra_pinfo = 1, #ifdef CONFIG_IPV6_ROUTER_PREF .accept_ra_rtr_pref = 1, .rtr_probe_interval = 60 * HZ, #ifdef CONFIG_IPV6_ROUTE_INFO .accept_ra_rt_info_max_plen = 0, #endif #endif .proxy_ndp = 0, .accept_source_route = 0, /* we do not accept RH0 by default. */ .disable_ipv6 = 0, .accept_dad = 1, .suppress_frag_ndisc = 1, .accept_ra_mtu = 1, .stable_secret = { .initialized = false, }, .use_oif_addrs_only = 0, .ignore_routes_with_linkdown = 0, .keep_addr_on_down = 0, }; /* Check if a valid qdisc is available */
static inline bool addrconf_qdisc_ok(const struct net_device *dev) { return !qdisc_tx_is_noop(dev); }

Contributors

PersonTokensPropCommitsCommitProp
mitsuru chinenmitsuru chinen1365.00%150.00%
david s. millerdavid s. miller735.00%150.00%
Total20100.00%2100.00%


static void addrconf_del_rs_timer(struct inet6_dev *idev) { if (del_timer(&idev->rs_timer)) __in6_dev_put(idev); }

Contributors

PersonTokensPropCommitsCommitProp
hannes frederic sowahannes frederic sowa2492.31%150.00%
pre-gitpre-git27.69%150.00%
Total26100.00%2100.00%


static void addrconf_del_dad_work(struct inet6_ifaddr *ifp) { if (cancel_delayed_work(&ifp->dad_work)) __in6_ifa_put(ifp); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2180.77%133.33%
hannes frederic sowahannes frederic sowa519.23%266.67%
Total26100.00%3100.00%


static void addrconf_mod_rs_timer(struct inet6_dev *idev, unsigned long when) { if (!timer_pending(&idev->rs_timer)) in6_dev_hold(idev); mod_timer(&idev->rs_timer, jiffies + when); }

Contributors

PersonTokensPropCommitsCommitProp
hannes frederic sowahannes frederic sowa4297.67%150.00%
pre-gitpre-git12.33%150.00%
Total43100.00%2100.00%


static void addrconf_mod_dad_work(struct inet6_ifaddr *ifp, unsigned long delay) { if (!delayed_work_pending(&ifp->dad_work)) in6_ifa_hold(ifp); mod_delayed_work(addrconf_wq, &ifp->dad_work, delay); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3172.09%133.33%
hannes frederic sowahannes frederic sowa1227.91%266.67%
Total43100.00%3100.00%


static int snmp6_alloc_dev(struct inet6_dev *idev) { int i; idev->stats.ipv6 = alloc_percpu(struct ipstats_mib); if (!idev->stats.ipv6) goto err_ip; for_each_possible_cpu(i) { struct ipstats_mib *addrconf_stats; addrconf_stats = per_cpu_ptr(idev->stats.ipv6, i); u64_stats_init(&addrconf_stats->syncp); } idev->stats.icmpv6dev = kzalloc(sizeof(struct icmpv6_mib_device), GFP_KERNEL); if (!idev->stats.icmpv6dev) goto err_icmp; idev->stats.icmpv6msgdev = kzalloc(sizeof(struct icmpv6msg_mib_device), GFP_KERNEL); if (!idev->stats.icmpv6msgdev) goto err_icmpmsg; return 0; err_icmpmsg: kfree(idev->stats.icmpv6dev); err_icmp: free_percpu(idev->stats.ipv6); err_ip: return -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu5031.45%114.29%
eric dumazeteric dumazet3823.90%228.57%
john stultzjohn stultz3522.01%114.29%
david l stevensdavid l stevens2213.84%114.29%
americo wangamerico wang127.55%114.29%
pavel emelianovpavel emelianov21.26%114.29%
Total159100.00%7100.00%


static struct inet6_dev *ipv6_add_dev(struct net_device *dev) { struct inet6_dev *ndev; int err = -ENOMEM; ASSERT_RTNL(); if (dev->mtu < IPV6_MIN_MTU) return ERR_PTR(-EINVAL); ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL); if (!ndev) return ERR_PTR(err); rwlock_init(&ndev->lock); ndev->dev = dev; INIT_LIST_HEAD(&ndev->addr_list); setup_timer(&ndev->rs_timer, addrconf_rs_timer, (unsigned long)ndev); memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf)); if (ndev->cnf.stable_secret.initialized) ndev->addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; else ndev->addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64; ndev->cnf.mtu6 = dev->mtu; ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); if (!ndev->nd_parms) { kfree(ndev); return ERR_PTR(err); } if (ndev->cnf.forwarding) dev_disable_lro(dev); /* We refer to the device */ dev_hold(dev); if (snmp6_alloc_dev(ndev) < 0) { ADBG(KERN_WARNING "%s: cannot allocate memory for statistics; dev=%s.\n", __func__, dev->name); neigh_parms_release(&nd_tbl, ndev->nd_parms); dev_put(dev); kfree(ndev); return ERR_PTR(err); } if (snmp6_register_dev(ndev) < 0) { ADBG(KERN_WARNING "%s: cannot create /proc/net/dev_snmp6/%s\n", __func__, dev->name); goto err_release; } /* One reference from device. We must do this before * we invoke __ipv6_regen_rndid(). */ in6_dev_hold(ndev); if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) ndev->cnf.accept_dad = -1; #if IS_ENABLED(CONFIG_IPV6_SIT) if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) { pr_info("%s: Disabled Multicast RS\n", dev->name); ndev->cnf.rtr_solicits = 0; } #endif INIT_LIST_HEAD(&ndev->tempaddr_list); setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev); if ((dev->flags&IFF_LOOPBACK) || dev->type == ARPHRD_TUNNEL || dev->type == ARPHRD_TUNNEL6 || dev->type == ARPHRD_SIT || dev->type == ARPHRD_NONE) { ndev->cnf.use_tempaddr = -1; } else { in6_dev_hold(ndev); ipv6_regen_rndid((unsigned long) ndev); } ndev->token = in6addr_any; if (netif_running(dev) && addrconf_qdisc_ok(dev)) ndev->if_flags |= IF_READY; ipv6_mc_init_dev(ndev); ndev->tstamp = jiffies; err = addrconf_sysctl_register(ndev); if (err) { ipv6_mc_destroy_dev(ndev); del_timer(&ndev->regen_timer); snmp6_unregister_dev(ndev); goto err_release; } /* protected by rtnl_lock */ rcu_assign_pointer(dev->ip6_ptr, ndev); /* Join interface-local all-node multicast group */ ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allnodes); /* Join all-node multicast group */ ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); /* Join all-router multicast group if forwarding is set */ if (ndev->cnf.forwarding && (dev->flags & IFF_MULTICAST)) ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); return ndev; err_release: neigh_parms_release(&nd_tbl, ndev->nd_parms); ndev->dead = 1; in6_dev_finish_destroy(ndev); return ERR_PTR(err); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji18530.99%918.75%
pre-gitpre-git12420.77%816.67%
americo wangamerico wang8013.40%24.17%
hannes frederic sowahannes frederic sowa488.04%36.25%
herbert xuherbert xu274.52%24.17%
li weili wei254.19%12.08%
stephen hemmingerstephen hemminger162.68%24.17%
ben hutchingsben hutchings132.18%12.08%
pavel emelianovpavel emelianov91.51%24.17%
david l stevensdavid l stevens91.51%12.08%
shirley mashirley ma61.01%12.08%
daniel borkmanndaniel borkmann61.01%24.17%
david s. millerdavid s. miller50.84%12.08%
sabrina dubrocasabrina dubroca50.84%12.08%
roy liroy li50.84%12.08%
linus torvaldslinus torvalds50.84%12.08%
remi denis-courmontremi denis-courmont50.84%12.08%
andrew mortonandrew morton40.67%12.08%
ding tianhongding tianhong40.67%12.08%
ingo oeseringo oeser40.67%12.08%
joerg roedeljoerg roedel30.50%12.08%
joe perchesjoe perches30.50%12.08%
harvey harrisonharvey harrison20.34%12.08%
ian morrisian morris20.34%12.08%
mitsuru chinenmitsuru chinen10.17%12.08%
eric dumazeteric dumazet10.17%12.08%
Total597100.00%48100.00%


static struct inet6_dev *ipv6_find_idev(struct net_device *dev) { struct inet6_dev *idev; ASSERT_RTNL(); idev = __in6_dev_get(dev); if (!idev) { idev = ipv6_add_dev(dev); if (IS_ERR(idev)) return NULL; } if (dev->flags&IFF_UP) ipv6_mc_up(idev); return idev; }

Contributors

PersonTokensPropCommitsCommitProp
david l stevensdavid l stevens3652.94%114.29%
pre-gitpre-git1927.94%342.86%
stephen hemmingerstephen hemminger913.24%114.29%
americo wangamerico wang34.41%114.29%
hideaki yoshifujihideaki yoshifuji11.47%114.29%
Total68100.00%7100.00%


static int inet6_netconf_msgsize_devconf(int type) { int size = NLMSG_ALIGN(sizeof(struct netconfmsg)) + nla_total_size(4); /* NETCONFA_IFINDEX */ bool all = false; if (type == NETCONFA_ALL) all = true; if (all || type == NETCONFA_FORWARDING) size += nla_total_size(4); #ifdef CONFIG_IPV6_MROUTE if (all || type == NETCONFA_MC_FORWARDING) size += nla_total_size(4); #endif if (all || type == NETCONFA_PROXY_NEIGH) size += nla_total_size(4); if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) size += nla_total_size(4); return size; }

Contributors

PersonTokensPropCommitsCommitProp
nicolas dichtelnicolas dichtel6054.55%342.86%
zhang shengjuzhang shengju1715.45%114.29%
andy gospodarekandy gospodarek1412.73%114.29%
stephen hemmingerstephen hemminger1412.73%114.29%
david s. millerdavid s. miller54.55%114.29%
Total110100.00%7100.00%


static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, struct ipv6_devconf *devconf, u32 portid, u32 seq, int event, unsigned int flags, int type) { struct nlmsghdr *nlh; struct netconfmsg *ncm; bool all = false; nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg), flags); if (!nlh) return -EMSGSIZE; if (type == NETCONFA_ALL) all = true; ncm = nlmsg_data(nlh); ncm->ncm_family = AF_INET6; if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0) goto nla_put_failure; if ((all || type == NETCONFA_FORWARDING) && nla_put_s32(skb, NETCONFA_FORWARDING, devconf->forwarding) < 0) goto nla_put_failure; #ifdef CONFIG_IPV6_MROUTE if ((all || type == NETCONFA_MC_FORWARDING) && nla_put_s32(skb, NETCONFA_MC_FORWARDING, devconf->mc_forwarding) < 0) goto nla_put_failure; #endif if ((all || type == NETCONFA_PROXY_NEIGH) && nla_put_s32(skb, NETCONFA_PROXY_NEIGH, devconf->proxy_ndp) < 0) goto nla_put_failure; if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) && nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, devconf->ignore_routes_with_linkdown) < 0) goto nla_put_failure; nlmsg_end(skb, nlh); return 0; nla_put_failure: nlmsg_cancel(skb, nlh); return -EMSGSIZE; }

Contributors

PersonTokensPropCommitsCommitProp
nicolas dichtelnicolas dichtel17368.92%333.33%
andy gospodarekandy gospodarek259.96%111.11%
stephen hemmingerstephen hemminger259.96%111.11%
zhang shengjuzhang shengju197.57%111.11%
david s. millerdavid s. miller51.99%111.11%
johannes bergjohannes berg31.20%111.11%
ian morrisian morris10.40%111.11%
Total251100.00%9100.00%


void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex, struct ipv6_devconf *devconf) { struct sk_buff *skb; int err = -ENOBUFS; skb = nlmsg_new(inet6_netconf_msgsize_devconf(type), GFP_KERNEL); if (!skb) goto errout; err = inet6_netconf_fill_devconf(skb, ifindex, devconf, 0, 0, RTM_NEWNETCONF, 0, type); if (err < 0) { /* -EMSGSIZE implies BUG in inet6_netconf_msgsize_devconf() */ WARN_ON(err == -EMSGSIZE); kfree_skb(skb); goto errout; } rtnl_notify(skb, net, 0, RTNLGRP_IPV6_NETCONF, NULL, GFP_KERNEL); return; errout: rtnl_set_sk_err(net, RTNLGRP_IPV6_NETCONF, err); }

Contributors

PersonTokensPropCommitsCommitProp
nicolas dichtelnicolas dichtel12297.60%133.33%
eric dumazeteric dumazet21.60%133.33%
ian morrisian morris10.80%133.33%
Total125100.00%3100.00%

static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = { [NETCONFA_IFINDEX] = { .len = sizeof(int) }, [NETCONFA_FORWARDING] = { .len = sizeof(int) }, [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) }, [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) }, };
static int inet6_netconf_get_devconf(struct sk_buff *in_skb, struct nlmsghdr *nlh) { struct net *net = sock_net(in_skb->sk); struct nlattr *tb[NETCONFA_MAX+1]; struct netconfmsg *ncm; struct sk_buff *skb; struct ipv6_devconf *devconf; struct inet6_dev *in6_dev; struct net_device *dev; int ifindex; int err; err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX, devconf_ipv6_policy); if (err < 0) goto errout; err = -EINVAL; if (!tb[NETCONFA_IFINDEX]) goto errout; ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]); switch (ifindex) { case NETCONFA_IFINDEX_ALL: devconf = net->ipv6.devconf_all; break; case NETCONFA_IFINDEX_DEFAULT: devconf = net->ipv6.devconf_dflt; break; default: dev = __dev_get_by_index(net, ifindex); if (!dev) goto errout; in6_dev = __in6_dev_get(dev); if (!in6_dev) goto errout; devconf = &in6_dev->cnf; break; } err = -ENOBUFS; skb = nlmsg_new(inet6_netconf_msgsize_devconf(NETCONFA_ALL), GFP_ATOMIC); if (!skb) goto errout; err = inet6_netconf_fill_devconf(skb, ifindex, devconf, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, RTM_NEWNETCONF, 0, NETCONFA_ALL); if (err < 0) { /* -EMSGSIZE implies BUG in inet6_netconf_msgsize_devconf() */ WARN_ON(err == -EMSGSIZE); kfree_skb(skb); goto errout; } err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); errout: return err; }

Contributors

PersonTokensPropCommitsCommitProp
nicolas dichtelnicolas dichtel28797.95%125.00%
ian morrisian morris31.02%125.00%
zhang shengjuzhang shengju20.68%125.00%
anton protopopovanton protopopov10.34%125.00%
Total293100.00%4100.00%


static int inet6_netconf_dump_devconf(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); int h, s_h; int idx, s_idx; struct net_device *dev; struct inet6_dev *idev; struct hlist_head *head; s_h = cb->args[0]; s_idx = idx = cb->args[1]; for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { idx = 0; head = &net->dev_index_head[h]; rcu_read_lock(); cb->seq = atomic_read(&net->ipv6.dev_addr_genid) ^ net->dev_base_seq; hlist_for_each_entry_rcu(dev, head, index_hlist) { if (idx < s_idx) goto cont; idev = __in6_dev_get(dev); if (!idev) goto cont; if (inet6_netconf_fill_devconf(skb, dev->ifindex, &idev->cnf, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_NEWNETCONF, NLM_F_MULTI, NETCONFA_ALL) < 0) { rcu_read_unlock(); goto done; } nl_dump_check_consistent(cb, nlmsg_hdr(skb)); cont: idx++; } rcu_read_unlock(); } if (h == NETDEV_HASHENTRIES) { if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, net->ipv6.devconf_all, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_NEWNETCONF, NLM_F_MULTI, NETCONFA_ALL) < 0) goto done; else h++; } if (h == NETDEV_HASHENTRIES + 1) { if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, net->ipv6.devconf_dflt, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_NEWNETCONF, NLM_F_MULTI, NETCONFA_ALL) < 0) goto done; else h++; } done: cb->args[0] = h; cb->args[1] = idx; return skb->len; }

Contributors

PersonTokensPropCommitsCommitProp
nicolas dichtelnicolas dichtel35398.33%250.00%
johannes bergjohannes berg30.84%125.00%
zhang shengjuzhang shengju30.84%125.00%
Total359100.00%4100.00%

#ifdef CONFIG_SYSCTL
static void dev_forward_change(struct inet6_dev *idev) { struct net_device *dev; struct inet6_ifaddr *ifa; if (!idev) return; dev = idev->dev; if (idev->cnf.forwarding) dev_disable_lro(dev); if (dev->flags & IFF_MULTICAST) { if (idev->cnf.forwarding) { ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allrouters); ipv6_dev_mc_inc(dev, &in6addr_sitelocal_allrouters); } else { ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters); ipv6_dev_mc_dec(dev, &in6addr_interfacelocal_allrouters); ipv6_dev_mc_dec(dev, &in6addr_sitelocal_allrouters); } } list_for_each_entry(ifa, &idev->addr_list, if_list) { if (ifa->flags&IFA_F_TENTATIVE) continue; if (idev->cnf.forwarding) addrconf_join_anycast(ifa); else addrconf_leave_anycast(ifa); } inet6_netconf_notify_devconf(dev_net(dev), NETCONFA_FORWARDING, dev->ifindex, &idev->cnf); }

Contributors

PersonTokensPropCommitsCommitProp
david l stevensdavid l stevens7241.38%111.11%
hannes frederic sowahannes frederic sowa3620.69%111.11%
nicolas dichtelnicolas dichtel1910.92%111.11%
ben hutchingsben hutchings137.47%111.11%
pre-gitpre-git116.32%111.11%
michal wrobelmichal wrobel95.17%111.11%
stephen hemmingerstephen hemminger84.60%111.11%
hideaki yoshifujihideaki yoshifuji63.45%222.22%
Total174100.00%9100.00%


static void addrconf_forward_change(struct net *net, __s32 newf) { struct net_device *dev; struct inet6_dev *idev; for_each_netdev(net, dev) { idev = __in6_dev_get(dev); if (idev) { int changed = (!idev->cnf.forwarding) ^ (!newf); idev->cnf.forwarding = newf; if (changed) dev_forward_change(idev); } } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3139.24%433.33%
hideaki yoshifujihideaki yoshifuji2430.38%18.33%
pavel emelianovpavel emelianov1316.46%325.00%
david l stevensdavid l stevens810.13%18.33%
ben hutchingsben hutchings11.27%18.33%
eric dumazeteric dumazet11.27%18.33%
eric w. biedermaneric w. biederman11.27%18.33%
Total79100.00%12100.00%


static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) { struct net *net; int old; if (!rtnl_trylock()) return restart_syscall(); net = (struct net *)table->extra2; old = *p; *p = newf; if (p == &net->ipv6.devconf_dflt->forwarding) { if ((!newf) ^ (!old)) inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING, NETCONFA_IFINDEX_DEFAULT, net->ipv6.devconf_dflt); rtnl_unlock(); return 0; } if (p == &net->ipv6.devconf_all->forwarding) { int old_dflt = net->ipv6.devconf_dflt->forwarding; net->ipv6.devconf_dflt->forwarding = newf; if ((!newf) ^ (!old_dflt)) inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING, NETCONFA_IFINDEX_DEFAULT, net->ipv6.devconf_dflt); addrconf_forward_change(net, newf); if ((!newf) ^ (!old)) inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING, NETCONFA_IFINDEX_ALL, net->ipv6.devconf_all); } else if ((!newf) ^ (!old)) dev_forward_change((struct inet6_dev *)table->extra1); rtnl_unlock(); if (newf) rt6_purge_dflt_routers(net); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov10643.80%436.36%
nicolas dichtelnicolas dichtel9238.02%218.18%
francesco ruggerifrancesco ruggeri2911.98%19.09%
stephen hemmingerstephen hemminger62.48%19.09%
daniel lezcanodaniel lezcano31.24%19.09%
ben hutchingsben hutchings31.24%19.09%
eric w. biedermaneric w. biederman31.24%19.09%
Total242100.00%11100.00%


static void addrconf_linkdown_change(struct net *net, __s32 newf) { struct net_device *dev; struct inet6_dev *idev; for_each_netdev(net, dev) { idev = __in6_dev_get(dev); if (idev) { int changed = (!idev->cnf.ignore_routes_with_linkdown) ^ (!newf); idev->cnf.ignore_routes_with_linkdown = newf; if (changed) inet6_netconf_notify_devconf(dev_net(dev), NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, dev->ifindex, &idev->cnf); } } }

Contributors

PersonTokensPropCommitsCommitProp
andy gospodarekandy gospodarek93100.00%1100.00%
Total93100.00%1100.00%


static int addrconf_fixup_linkdown(struct ctl_table *table, int *p, int newf) { struct net *net; int old; if (!rtnl_trylock()) return restart_syscall(); net = (struct net *)table->extra2; old = *p; *p = newf; if (p == &net->ipv6.devconf_dflt->ignore_routes_with_linkdown) { if ((!newf) ^ (!old)) inet6_netconf_notify_devconf(net, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, NETCONFA_IFINDEX_DEFAULT, net->ipv6.devconf_dflt); rtnl_unlock(); return 0; } if (p == &net->ipv6.devconf_all->ignore_routes_with_linkdown) { net->ipv6.devconf_dflt->ignore_routes_with_linkdown = newf; addrconf_linkdown_change(net, newf); if ((!newf) ^ (!old)) inet6_netconf_notify_devconf(net, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, NETCONFA_IFINDEX_ALL, net->ipv6.devconf_all); } rtnl_unlock(); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
andy gospodarekandy gospodarek170100.00%1100.00%
Total170100.00%1100.00%

#endif /* Nobody refers to this ifaddr, destroy it */
void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) { WARN_ON(!hlist_unhashed(&ifp->addr_lst)); #ifdef NET_REFCNT_DEBUG pr_debug("%s\n", __func__); #endif in6_dev_put(ifp->idev); if (cancel_delayed_work(&ifp->dad_work)) pr_notice("delayed DAD work was pending while freeing ifa=%p\n", ifp); if (ifp->state != INET6_IFADDR_STATE_DEAD) { pr_warn("Freeing alive inet6 address %p\n", ifp); return; } ip6_rt_put(ifp->rt); kfree_rcu(ifp, rcu); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git5662.22%320.00%
stephen hemmingerstephen hemminger88.89%320.00%
hideaki yoshifujihideaki yoshifuji66.67%16.67%
linus torvaldslinus torvalds55.56%16.67%
joe perchesjoe perches55.56%213.33%
hannes frederic sowahannes frederic sowa33.33%16.67%
herbert xuherbert xu33.33%16.67%
lai jiangshanlai jiangshan22.22%16.67%
americo wangamerico wang11.11%16.67%
ilpo jarvinenilpo jarvinen11.11%16.67%
Total90100.00%15100.00%


static void ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) { struct list_head *p; int ifp_scope = ipv6_addr_src_scope(&ifp->addr); /* * Each device address list is sorted in order of scope - * global before linklocal. */ list_for_each(p, &idev->addr_list) { struct inet6_ifaddr *ifa = list_entry(p, struct inet6_ifaddr, if_list); if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr)) break; } list_add_tail(&ifp->if_list, p); }

Contributors

PersonTokensPropCommitsCommitProp
brian haleybrian haley3139.24%125.00%
stephen hemmingerstephen hemminger2936.71%125.00%
hideaki yoshifujihideaki yoshifuji1822.78%125.00%
david s. millerdavid s. miller11.27%125.00%
Total79100.00%4100.00%


static u32 inet6_addr_hash(const struct in6_addr *addr) { return hash_32(ipv6_addr_hash(addr), IN6_ADDR_HSIZE_SHIFT); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji1460.87%133.33%
eric dumazeteric dumazet626.09%133.33%
stephen hemmingerstephen hemminger313.04%133.33%
Total23100.00%3100.00%

/* On success it returns ifp with increased reference count */
static struct inet6_ifaddr * ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, const struct in6_addr *peer_addr, int pfxlen, int scope, u32 flags, u32 valid_lft, u32 prefered_lft) { struct inet6_ifaddr *ifa = NULL; struct rt6_info *rt; unsigned int hash; int err = 0; int addr_type = ipv6_addr_type(addr); if (addr_type == IPV6_ADDR_ANY || addr_type & IPV6_ADDR_MULTICAST || (!(idev->dev->flags & IFF_LOOPBACK) && addr_type & IPV6_ADDR_LOOPBACK)) return ERR_PTR(-EADDRNOTAVAIL); rcu_read_lock_bh(); if (idev->dead) { err = -ENODEV; /*XXX*/ goto out2; } if (idev->cnf.disable_ipv6) { err = -EACCES; goto out2; } spin_lock(&addrconf_hash_lock); /* Ignore adding duplicate addresses on an interface */ if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) { ADBG("ipv6_add_addr: already assigned\n"); err = -EEXIST; goto out; } ifa = kzalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC); if (!ifa) { ADBG("ipv6_add_addr: malloc failed\n"); err = -ENOBUFS; goto out; } rt = addrconf_dst_alloc(idev, addr, false); if (IS_ERR(rt)) { err = PTR_ERR(rt); goto out; } neigh_parms_data_state_setall(idev->nd_parms); ifa->addr = *addr; if (peer_addr) ifa->peer_addr = *peer_addr; spin_lock_init(&ifa->lock); INIT_DELAYED_WORK(&ifa->dad_work, addrconf_dad_work); INIT_HLIST_NODE(&ifa->addr_lst); ifa->scope = scope; ifa->prefix_len = pfxlen; ifa->flags = flags | IFA_F_TENTATIVE; ifa->valid_lft = valid_lft; ifa->prefered_lft = prefered_lft; ifa->cstamp = ifa->tstamp = jiffies; ifa->tokenized = false; ifa->rt = rt; ifa->idev = idev; in6_dev_hold(idev); /* For caller */ in6_ifa_hold(ifa); /* Add to big hash table */ hash = inet6_addr_hash(addr); hlist_add_head_rcu(&ifa->addr_lst, &inet6_addr_lst[hash]); spin_unlock(&addrconf_hash_lock); write_lock(&idev->lock); /* Add to inet6_dev unicast addr list. */ ipv6_link_dev_addr(idev, ifa); if (ifa->flags&IFA_F_TEMPORARY) { list_add(&ifa->tmp_list, &idev->tempaddr_list); in6_ifa_hold(ifa); } in6_ifa_hold(ifa); write_unlock(&idev->lock); out2: rcu_read_unlock_bh(); if (likely(err == 0)) inet6addr_notifier_call_chain(NETDEV_UP, ifa); else { kfree(ifa); ifa = ERR_PTR(err); } return ifa; out: spin_unlock(&addrconf_hash_lock); goto out2; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji21843.51%924.32%
pre-gitpre-git15029.94%410.81%
stephen hemmingerstephen hemminger265.19%410.81%
jiri pirkojiri pirko244.79%25.41%
brian haleybrian haley224.39%25.41%
jiri bencjiri benc183.59%12.70%
shirley mashirley ma102.00%12.70%
keir fraserkeir fraser61.20%12.70%
daniel borkmanndaniel borkmann61.20%12.70%
linus torvaldslinus torvalds51.00%12.70%
hannes frederic sowahannes frederic sowa40.80%25.41%
benjamin therybenjamin thery30.60%12.70%
alexey dobriyanalexey dobriyan20.40%12.70%
jamal hadi salimjamal hadi salim10.20%12.70%
americo wangamerico wang10.20%12.70%
eric dumazeteric dumazet10.20%12.70%
daniel lezcanodaniel lezcano10.20%12.70%
ian morrisian morris10.20%12.70%
david s. millerdavid s. miller10.20%12.70%
ingo oeseringo oeser10.20%12.70%
Total501100.00%37100.00%

enum cleanup_prefix_rt_t { CLEANUP_PREFIX_RT_NOP, /* no cleanup action for prefix route */ CLEANUP_PREFIX_RT_DEL, /* delete the prefix route */ CLEANUP_PREFIX_RT_EXPIRE, /* update the lifetime of the prefix route */ }; /* * Check, whether the prefix for ifp would still need a prefix route * after deleting ifp. The function returns one of the CLEANUP_PREFIX_RT_* * constants. * * 1) we don't purge prefix if address was not permanent. * prefix is managed by its own lifetime. * 2) we also don't purge, if the address was IFA_F_NOPREFIXROUTE. * 3) if there are no addresses, delete prefix. * 4) if there are still other permanent address(es), * corresponding prefix is still permanent. * 5) if there are still other addresses with IFA_F_NOPREFIXROUTE, * don't purge the prefix, assume user space is managing it. * 6) otherwise, update prefix lifetime to the * longest valid lifetime among the corresponding * addresses on the device. * Note: subsequent RA will update lifetime. **/
static enum cleanup_prefix_rt_t check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires) { struct inet6_ifaddr *ifa; struct inet6_dev *idev = ifp->idev; unsigned long lifetime; enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_DEL; *expires = jiffies; list_for_each_entry(ifa, &idev->addr_list, if_list) { if (ifa == ifp) continue; if (!ipv6_prefix_equal(&ifa->addr, &ifp->addr, ifp->prefix_len)) continue; if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE)) return CLEANUP_PREFIX_RT_NOP; action = CLEANUP_PREFIX_RT_EXPIRE; spin_lock(&ifa->lock); lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ); /* * Note: Because this address is * not permanent, lifetime < * LONG_MAX / HZ here. */ if (time_before(*expires, ifa->tstamp + lifetime * HZ)) *expires = ifa->tstamp + lifetime * HZ; spin_unlock(&ifa->lock); } return action; }

Contributors

PersonTokensPropCommitsCommitProp
thomas hallerthomas haller10565.22%114.29%
pre-gitpre-git3924.22%342.86%
herbert xuherbert xu116.83%114.29%
hideaki yoshifujihideaki yoshifuji42.48%114.29%
stephen hemmingerstephen hemminger21.24%114.29%
Total161100.00%7100.00%


static void cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt) { struct rt6_info *rt; rt = addrconf_get_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, 0, RTF_GATEWAY | RTF_DEFAULT); if (rt) { if (del_rt) ip6_del_rt(rt); else { if (!(rt->rt6i_flags & RTF_EXPIRES)) rt6_set_expires(rt, expires); ip6_rt_put(rt); } } }

Contributors

PersonTokensPropCommitsCommitProp
thomas hallerthomas haller5965.56%114.29%
hideaki yoshifujihideaki yoshifuji2022.22%228.57%
pre-gitpre-git77.78%228.57%
stephen hemmingerstephen hemminger44.44%228.57%
Total90100.00%7100.00%

/* This function wants to get referenced ifp and releases it before return */
static void ipv6_del_addr(struct inet6_ifaddr *ifp) { int state; enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_NOP; unsigned long expires; ASSERT_RTNL(); spin_lock_bh(&ifp->lock); state = ifp->state; ifp->state = INET6_IFADDR_STATE_DEAD; spin_unlock_bh(&ifp->lock); if (state == INET6_IFADDR_STATE_DEAD) goto out; spin_lock_bh(&addrconf_hash_lock); hlist_del_init_rcu(&ifp->addr_lst); spin_unlock_bh(&addrconf_hash_lock); write_lock_bh(&ifp->idev->lock); if (ifp->flags&IFA_F_TEMPORARY) { list_del(&ifp->tmp_list); if (ifp->ifpub) { in6_ifa_put(ifp->ifpub); ifp->ifpub = NULL; } __in6_ifa_put(ifp); } if (ifp->flags & IFA_F_PERMANENT && !(ifp->flags & IFA_F_NOPREFIXROUTE)) action = check_cleanup_prefix_route(ifp, &expires); list_del_init(&ifp->if_list); __in6_ifa_put(ifp); write_unlock_bh(&ifp->idev->lock); addrconf_del_dad_work(ifp); ipv6_ifa_notify(RTM_DELADDR, ifp); inet6addr_notifier_call_chain(NETDEV_DOWN, ifp); if (action != CLEANUP_PREFIX_RT_NOP) { cleanup_prefix_route(ifp, expires, action == CLEANUP_PREFIX_RT_DEL); } /* clean up prefsrc entries */ rt6_remove_prefsrc(ifp); out: in6_ifa_put(ifp); }

Contributors

PersonTokensPropCommitsCommitProp
thomas hallerthomas haller13857.74%17.14%
hideaki yoshifujihideaki yoshifuji5523.01%17.14%
pre-gitpre-git177.11%321.43%
hannes frederic sowahannes frederic sowa62.51%214.29%
daniel walterdaniel walter62.51%17.14%
linus torvaldslinus torvalds41.67%17.14%
romain kuntzromain kuntz41.67%17.14%
andrey vaginandrey vagin41.67%17.14%
gao fenggao feng20.84%17.14%
herbert xuherbert xu20.84%17.14%
li rongqingli rongqing10.42%17.14%
Total239100.00%14100.00%


static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *ift) { struct inet6_dev *idev = ifp->idev; struct in6_addr addr, *tmpaddr; unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_tstamp, age; unsigned long regen_advance; int tmp_plen; int ret = 0; u32 addr_flags; unsigned long now = jiffies; write_lock_bh(&idev->lock); if (ift) { spin_lock_bh(&ift->lock); memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8); spin_unlock_bh(&ift->lock); tmpaddr = &addr; } else { tmpaddr = NULL; } retry: in6_dev_hold(idev); if (idev->cnf.use_tempaddr <= 0) { write_unlock_bh(&idev->lock); pr_info("%s: use_tempaddr is disabled\n", __func__); in6_dev_put(idev); ret = -1; goto out; } spin_lock_bh(&ifp->lock); if (ifp->regen_count++ >= idev->cnf.regen_max_retry) { idev->cnf.use_tempaddr = -1; /*XXX*/ spin_unlock_bh(&ifp->lock); write_unlock_bh(&idev->lock); pr_warn("%s: regeneration time exceeded - disabled temporary address support\n", __func__); in6_dev_put(idev); ret = -1; goto out; } in6_ifa_hold(ifp); memcpy(addr.s6_addr, ifp->addr.s6_addr, 8); __ipv6_try_regen_rndid(idev, tmpaddr); memcpy(&addr.s6_addr[8], idev->rndid, 8); age = (now - ifp->tstamp) / HZ; tmp_valid_lft = min_t(__u32, ifp->valid_lft, idev->cnf.temp_valid_lft + age); tmp_prefered_lft = min_t(__u32, ifp->prefered_lft, idev->cnf.temp_prefered_lft + age - idev->cnf.max_desync_factor); tmp_plen = ifp->prefix_len; tmp_tstamp = ifp->tstamp; spin_unlock_bh(&ifp->lock); regen_advance = idev->cnf.regen_max_retry * idev->cnf.dad_transmits * NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ; write_unlock_bh(&idev->lock); /* A temporary address is created only if this calculated Preferred * Lifetime is greater than REGEN_ADVANCE time units. In particular, * an implementation must not create a temporary address with a zero * Preferred Lifetime. * Use age calculation as in addrconf_verify to avoid unnecessary * temporary addresses being generated. */ age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ; if (tmp_prefered_lft <= regen_advance + age) { in6_ifa_put(ifp); in6_dev_put(idev); ret = -1; goto out; } addr_flags = IFA_F_TEMPORARY; /* set in addrconf_prefix_rcv() */ if (ifp->flags & IFA_F_OPTIMISTIC) addr_flags |= IFA_F_OPTIMISTIC; ift = ipv6_add_addr(idev, &addr, NULL, tmp_plen, ipv6_addr_scope(&addr), addr_flags, tmp_valid_lft, tmp_prefered_lft); if (IS_ERR(ift)) { in6_ifa_put(ifp); in6_dev_put(idev); pr_info("%s: retry temporary address regeneration\n", __func__); tmpaddr = &addr; write_lock_bh(&idev->lock); goto retry; } spin_lock_bh(&ift->lock); ift->ifpub = ifp; ift->cstamp = now; ift->tstamp = tmp_tstamp; spin_unlock_bh(&ift->lock); addrconf_dad_start(ift); in6_ifa_put(ift); in6_dev_put(idev); out: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji30252.34%314.29%
pre-gitpre-git12421.49%419.05%
benoit boissinotbenoit boissinot508.67%14.76%
neil hormanneil horman213.64%14.76%
glenn wursterglenn wurster172.95%14.76%
heiner kallweitheiner kallweit152.60%14.76%
joe perchesjoe perches122.08%14.76%
jiri pirkojiri pirko122.08%314.29%
lorenzo colittilorenzo colitti81.39%14.76%
ben hutchingsben hutchings50.87%14.76%
shirley mashirley ma50.87%14.76%
jiri bencjiri benc40.69%14.76%
hannes frederic sowahannes frederic sowa10.17%14.76%
americo wangamerico wang10.17%14.76%
Total577100.00%21100.00%

/* * Choose an appropriate source address (RFC3484) */ enum { IPV6_SADDR_RULE_INIT = 0, IPV6_SADDR_RULE_LOCAL, IPV6_SADDR_RULE_SCOPE, IPV6_SADDR_RULE_PREFERRED, #ifdef CONFIG_IPV6_MIP6 IPV6_SADDR_RULE_HOA, #endif IPV6_SADDR_RULE_OIF, IPV6_SADDR_RULE_LABEL, IPV6_SADDR_RULE_PRIVACY, IPV6_SADDR_RULE_ORCHID, IPV6_SADDR_RULE_PREFIX, #ifdef CONFIG_IPV6_OPTIMISTIC_DAD IPV6_SADDR_RULE_NOT_OPTIMISTIC, #endif IPV6_SADDR_RULE_MAX }; struct ipv6_saddr_score { int rule; int addr_type; struct inet6_ifaddr *ifa; DECLARE_BITMAP(scorebits, IPV6_SADDR_RULE_MAX); int scopedist; int matchlen; }; struct ipv6_saddr_dst { const struct in6_addr *addr; int ifindex; int scope; int label; unsigned int prefs; };
static inline int ipv6_saddr_preferred(int type) { if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|IPV6_ADDR_LOOPBACK)) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji2796.43%150.00%
dave jonesdave jones13.57%150.00%
Total28100.00%2100.00%


static inline bool ipv6_use_optimistic_addr(struct inet6_dev *idev) { #ifdef CONFIG_IPV6_OPTIMISTIC_DAD return idev && idev->cnf.optimistic_dad && idev->cnf.use_optimistic; #else return false; #endif }

Contributors

PersonTokensPropCommitsCommitProp
erik klineerik kline37100.00%1100.00%
Total37100.00%1100.00%


static int ipv6_get_saddr_eval(struct net *net, struct ipv6_saddr_score *score, struct ipv6_saddr_dst *dst, int i) { int ret; if (i <= score->rule) { switch (i) { case IPV6_SADDR_RULE_SCOPE: ret = score->scopedist; break; case IPV6_SADDR_RULE_PREFIX: ret = score->matchlen; break; default: ret = !!test_bit(i, score->scorebits); } goto out; } switch (i) { case IPV6_SADDR_RULE_INIT: /* Rule 0: remember if hiscore is not ready yet */ ret = !!score->ifa; break; case IPV6_SADDR_RULE_LOCAL: /* Rule 1: Prefer same address */ ret = ipv6_addr_equal(&score->ifa->addr, dst->addr); break; case IPV6_SADDR_RULE_SCOPE: /* Rule 2: Prefer appropriate scope * * ret * ^ * -1 | d 15 * ---+--+-+---> scope * | * | d is scope of the destination. * B-d | \ * | \ <- smaller scope is better if * B-15 | \ if scope is enough for destination. * | ret = B - scope (-1 <= scope >= d <= 15). * d-C-1 | / * |/ <- greater is better * -C / if scope is not enough for destination. * /| ret = scope - C (-1 <= d < scope <= 15). * * d - C - 1 < B -15 (for all -1 <= d <= 15). * C > d + 14 - B >= 15 + 14 - B = 29 - B. * Assume B = 0 and we get C > 29. */ ret = __ipv6_addr_src_scope(score->addr_type); if (ret >= dst->scope) ret = -ret; else ret -= 128; /* 30 is enough */ score->scopedist = ret; break; case IPV6_SADDR_RULE_PREFERRED: { /* Rule 3: Avoid deprecated and optimistic addresses */ u8 avoid = IFA_F_DEPRECATED; if (!ipv6_use_optimistic_addr(score->ifa->idev)) avoid |= IFA_F_OPTIMISTIC; ret = ipv6_saddr_preferred(score->addr_type) || !(score->ifa->flags & avoid); break; } #ifdef CONFIG_IPV6_MIP6 case IPV6_SADDR_RULE_HOA: { /* Rule 4: Prefer home address */ int prefhome = !(dst->prefs & IPV6_PREFER_SRC_COA); ret = !(score->ifa->flags & IFA_F_HOMEADDRESS) ^ prefhome; break; } #endif case IPV6_SADDR_RULE_OIF: /* Rule 5: Prefer outgoing interface */ ret = (!dst->ifindex || dst->ifindex == score->ifa->idev->dev->ifindex); break; case IPV6_SADDR_RULE_LABEL: /* Rule 6: Prefer matching label */ ret = ipv6_addr_label(net, &score->ifa->addr, score->addr_type, score->ifa->idev->dev->ifindex) == dst->label; break; case IPV6_SADDR_RULE_PRIVACY: { /* Rule 7: Prefer public address * Note: prefer temporary address if use_tempaddr >= 2 */ int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ? !!(dst->prefs & IPV6_PREFER_SRC_TMP) : score->ifa->idev->cnf.use_tempaddr >= 2; ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ preftmp; break; } case IPV6_SADDR_RULE_ORCHID: /* Rule 8-: Prefer ORCHID vs ORCHID or * non-ORCHID vs non-ORCHID */ ret = !(ipv6_addr_orchid(&score->ifa->addr) ^ ipv6_addr_orchid(dst->addr)); break; case IPV6_SADDR_RULE_PREFIX: /* Rule 8: Use longest matching prefix */ ret = ipv6_addr_diff(&score->ifa->addr, dst->addr); if (ret > score->ifa->prefix_len) ret = score->ifa->prefix_len; score->matchlen = ret; break; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD case IPV6_SADDR_RULE_NOT_OPTIMISTIC: /* Optimistic addresses still have lower precedence than other * preferred addresses. */ ret = !(score->ifa->flags & IFA_F_OPTIMISTIC); break; #endif default: ret = 0; } if (ret) __set_bit(i, score->scorebits); score->rule = i; out: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji41183.20%743.75%
erik klineerik kline479.51%16.25%
pre-gitpre-git183.64%318.75%
benjamin therybenjamin thery71.42%16.25%
neil hormanneil horman61.21%16.25%
alexey kuznetsovalexey kuznetsov30.61%16.25%
lucas de marchilucas de marchi10.20%16.25%
stephen hemmingerstephen hemminger10.20%16.25%
Total494100.00%16100.00%


static int __ipv6_dev_get_saddr(struct net *net, struct ipv6_saddr_dst *dst, struct inet6_dev *idev, struct ipv6_saddr_score *scores, int hiscore_idx) { struct ipv6_saddr_score *score = &scores[1 - hiscore_idx], *hiscore = &scores[hiscore_idx]; read_lock_bh(&idev->lock); list_for_each_entry(score->ifa, &idev->addr_list, if_list) { int i; /* * - Tentative Address (RFC2462 section 5.4) * - A tentative address is not considered * "assigned to an interface" in the traditional * sense, unless it is also flagged as optimistic. * - Candidate Source Address (section 4) * - In any case, anycast addresses, multicast * addresses, and the unspecified address MUST * NOT be included in a candidate set. */ if ((score->ifa->flags & IFA_F_TENTATIVE) && (!(score->ifa->flags & IFA_F_OPTIMISTIC))) continue; score->addr_type = __ipv6_addr_type(&score->ifa->addr); if (unlikely(score->addr_type == IPV6_ADDR_ANY || score->addr_type & IPV6_ADDR_MULTICAST)) { net_dbg_ratelimited("ADDRCONF: unspecified / multicast address assigned as unicast address on %s", idev->dev->name); continue; } score->rule = -1; bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX); for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) { int minihiscore, miniscore; minihiscore = ipv6_get_saddr_eval(net, hiscore, dst, i); miniscore = ipv6_get_saddr_eval(net, score, dst, i); if (minihiscore > miniscore) { if (i == IPV6_SADDR_RULE_SCOPE && score->scopedist > 0) { /* * special case: * each remaining entry * has too small (not enough) * scope, because ifa entries * are sorted by their scope * values. */ goto out; } break; } else if (minihiscore < miniscore) { if (hiscore->ifa) in6_ifa_put(hiscore->ifa); in6_ifa_hold(score->ifa); swap(hiscore, score); hiscore_idx = 1 - hiscore_idx; /* restore our iterator */ score->ifa = hiscore->ifa; break; } } } out: read_unlock_bh(&idev->lock); return hiscore_idx; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji20970.13%420.00%
yoshifuji hideakiyoshifuji hideaki3612.08%210.00%
pre-gitpre-git186.04%315.00%
stephen hemmingerstephen hemminger82.68%15.00%
brian haleybrian haley51.68%15.00%
benjamin therybenjamin thery41.34%15.00%
ilpo jarvinenilpo jarvinen41.34%15.00%
juha-matti tapiojuha-matti tapio31.01%15.00%
noriaki takamiyanoriaki takamiya31.01%15.00%
linus torvaldslinus torvalds31.01%15.00%
joe perchesjoe perches20.67%15.00%
masahide nakamuramasahide nakamura10.34%15.00%
alexey kuznetsovalexey kuznetsov10.34%15.00%
yan zhengyan zheng10.34%15.00%
Total298100.00%20100.00%


static int ipv6_get_saddr_master(struct net *net, const struct net_device *dst_dev, const struct net_device *master, struct ipv6_saddr_dst *dst, struct ipv6_saddr_score *scores, int hiscore_idx) { struct inet6_dev *idev; idev = __in6_dev_get(dst_dev); if (idev) hiscore_idx = __ipv6_dev_get_saddr(net, dst, idev, scores, hiscore_idx); idev = __in6_dev_get(master); if (idev) hiscore_idx = __ipv6_dev_get_saddr(net, dst, idev, scores, hiscore_idx); return hiscore_idx; }

Contributors

PersonTokensPropCommitsCommitProp
david aherndavid ahern96100.00%1100.00%
Total96100.00%1100.00%


int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, const struct in6_addr *daddr, unsigned int prefs, struct in6_addr *saddr) { struct ipv6_saddr_score scores[2], *hiscore; struct ipv6_saddr_dst dst; struct inet6_dev *idev; struct net_device *dev; int dst_type; bool use_oif_addr = false; int hiscore_idx = 0; dst_type = __ipv6_addr_type(daddr); dst.addr = daddr; dst.ifindex = dst_dev ? dst_dev->ifindex : 0; dst.scope = __ipv6_addr_src_scope(dst_type); dst.label = ipv6_addr_label(net, daddr, dst_type, dst.ifindex); dst.prefs = prefs; scores[hiscore_idx].rule = -1; scores[hiscore_idx].ifa = NULL; rcu_read_lock(); /* Candidate Source Address (section 4) * - multicast and link-local destination address, * the set of candidate source address MUST only * include addresses assigned to interfaces * belonging to the same link as the outgoing * interface. * (- For site-local destination addresses, the * set of candidate source addresses MUST only * include addresses assigned to interfaces * belonging to the same site as the outgoing * interface.) * - "It is RECOMMENDED that the candidate source addresses * be the set of unicast addresses assigned to the * interface that will be used to send to the destination * (the 'outgoing' interface)." (RFC 6724) */ if (dst_dev) { idev = __in6_dev_get(dst_dev); if ((dst_type & IPV6_ADDR_MULTICAST) || dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL || (idev && idev->cnf.use_oif_addrs_only)) { use_oif_addr = true; } } if (use_oif_addr) { if (idev) hiscore_idx = __ipv6_dev_get_saddr(net, &dst, idev, scores, hiscore_idx); } else { const struct net_device *master; int master_idx = 0; /* if dst_dev exists and is enslaved to an L3 device, then * prefer addresses from dst_dev and then the master over * any other enslaved devices in the L3 domain. */ master = l3mdev_master_dev_rcu(dst_dev); if (master) { master_idx = master->ifindex; hiscore_idx = ipv6_get_saddr_master(net, dst_dev, master, &dst, scores, hiscore_idx); if (scores[hiscore_idx].ifa) goto out; } for_each_netdev_rcu(net, dev) { /* only consider addresses on devices in the * same L3 domain */ if (l3mdev_master_ifindex_rcu(dev) != master_idx) continue; idev = __in6_dev_get(dev); if (!idev) continue; hiscore_idx = __ipv6_dev_get_saddr(net, &dst, idev, scores, hiscore_idx); } } out: rcu_read_unlock(); hiscore = &scores[hiscore_idx]; if (!hiscore->ifa) return -EADDRNOTAVAIL; *saddr = hiscore->ifa->addr; in6_ifa_put(hiscore->ifa); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
yoshifuji hideakiyoshifuji hideaki24666.13%220.00%
david aherndavid ahern7419.89%110.00%
erik klineerik kline184.84%110.00%
hideaki yoshifujihideaki yoshifuji174.57%330.00%
david l stevensdavid l stevens143.76%110.00%
alexey dobriyanalexey dobriyan20.54%110.00%
pre-gitpre-git10.27%110.00%
Total372100.00%10100.00%

EXPORT_SYMBOL(ipv6_dev_get_saddr);
int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, u32 banned_flags) { struct inet6_ifaddr *ifp; int err = -EADDRNOTAVAIL; list_for_each_entry_reverse(ifp, &idev->addr_list, if_list) { if (ifp->scope > IFA_LINK) break; if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) { *addr = ifp->addr; err = 0; break; } } return err; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji3643.90%112.50%
hannes frederic sowahannes frederic sowa1923.17%225.00%
pre-gitpre-git1417.07%112.50%
stephen hemmingerstephen hemminger78.54%112.50%
neil hormanneil horman33.66%112.50%
alexey dobriyanalexey dobriyan22.44%112.50%
jiri pirkojiri pirko11.22%112.50%
Total82100.00%8100.00%


int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, u32 banned_flags) { struct inet6_dev *idev; int err = -EADDRNOTAVAIL; rcu_read_lock(); idev = __in6_dev_get(dev); if (idev) { read_lock_bh(&idev->lock); err = __ipv6_get_lladdr(idev, addr, banned_flags); read_unlock_bh(&idev->lock); } rcu_read_unlock(); return err; }

Contributors

PersonTokensPropCommitsCommitProp
hannes frederic sowahannes frederic sowa6178.21%116.67%
hideaki yoshifujihideaki yoshifuji1215.38%233.33%
pre-gitpre-git45.13%233.33%
jiri pirkojiri pirko11.28%116.67%
Total78100.00%6100.00%


static int ipv6_count_addresses(struct inet6_dev *idev) { int cnt = 0; struct inet6_ifaddr *ifp; read_lock_bh(&idev->lock); list_for_each_entry(ifp, &idev->addr_list, if_list) cnt++; read_unlock_bh(&idev->lock); return cnt; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji3976.47%133.33%
stephen hemmingerstephen hemminger815.69%133.33%
pre-gitpre-git47.84%133.33%
Total51100.00%3100.00%


int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, const struct net_device *dev, int strict) { return ipv6_chk_addr_and_flags(net, addr, dev, strict, IFA_F_TENTATIVE); }

Contributors

PersonTokensPropCommitsCommitProp
erik klineerik kline1538.46%112.50%
pre-gitpre-git717.95%225.00%
hideaki yoshifujihideaki yoshifuji717.95%112.50%
daniel lezcanodaniel lezcano512.82%112.50%
ville nuorvalaville nuorvala37.69%112.50%
eric dumazeteric dumazet12.56%112.50%
florian westphalflorian westphal12.56%112.50%
Total39100.00%8100.00%

EXPORT_SYMBOL(ipv6_chk_addr);
int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr, const struct net_device *dev, int strict, u32 banned_flags) { struct inet6_ifaddr *ifp; unsigned int hash = inet6_addr_hash(addr); u32 ifp_flags; rcu_read_lock_bh(); hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { if (!net_eq(dev_net(ifp->idev->dev), net)) continue; /* Decouple optimistic from tentative for evaluation here. * Ban optimistic addresses explicitly, when required. */ ifp_flags = (ifp->flags&IFA_F_OPTIMISTIC) ? (ifp->flags&~IFA_F_TENTATIVE) : ifp->flags; if (ipv6_addr_equal(&ifp->addr, addr) && !(ifp_flags&banned_flags) && (!dev || ifp->idev->dev == dev || !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) { rcu_read_unlock_bh(); return 1; } } rcu_read_unlock_bh(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
erik klineerik kline5634.78%16.25%
hideaki yoshifujihideaki yoshifuji5634.78%425.00%
stephen hemmingerstephen hemminger2616.15%425.00%
daniel lezcanodaniel lezcano106.21%16.25%
pre-gitpre-git95.59%318.75%
ville nuorvalaville nuorvala21.24%16.25%
ian morrisian morris10.62%16.25%
eric dumazeteric dumazet10.62%16.25%
Total161100.00%16100.00%

EXPORT_SYMBOL(ipv6_chk_addr_and_flags);
static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, struct net_device *dev) { unsigned int hash = inet6_addr_hash(addr); struct inet6_ifaddr *ifp; hlist_for_each_entry(ifp, &inet6_addr_lst[hash], addr_lst) { if (!net_eq(dev_net(ifp->idev->dev), net)) continue; if (ipv6_addr_equal(&ifp->addr, addr)) { if (!dev || ifp->idev->dev == dev) return true; } } return false; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji5859.79%444.44%
daniel lezcanodaniel lezcano1515.46%111.11%
david s. millerdavid s. miller1414.43%111.11%
stephen hemmingerstephen hemminger88.25%111.11%
eric dumazeteric dumazet11.03%111.11%
ian morrisian morris11.03%111.11%
Total97100.00%9100.00%

/* Compares an address/prefix_len with addresses on device @dev. * If one is found it returns true. */
bool ipv6_chk_custom_prefix(const struct in6_addr *addr, const unsigned int prefix_len, struct net_device *dev) { struct inet6_dev *idev; struct inet6_ifaddr *ifa; bool ret = false; rcu_read_lock(); idev = __in6_dev_get(dev); if (idev) { read_lock_bh(&idev->lock); list_for_each_entry(ifa, &idev->addr_list, if_list) { ret = ipv6_prefix_equal(addr, &ifa->addr, prefix_len); if (ret) break; } read_unlock_bh(&idev->lock); } rcu_read_unlock(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
catalin boiecatalin boie103100.00%1100.00%
Total103100.00%1100.00%

EXPORT_SYMBOL(ipv6_chk_custom_prefix);
int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev) { struct inet6_dev *idev; struct inet6_ifaddr *ifa; int onlink; onlink = 0; rcu_read_lock(); idev = __in6_dev_get(dev); if (idev) { read_lock_bh(&idev->lock); list_for_each_entry(ifa, &idev->addr_list, if_list) { onlink = ipv6_prefix_equal(addr, &ifa->addr, ifa->prefix_len); if (onlink) break; } read_unlock_bh(&idev->lock); } rcu_read_unlock(); return onlink; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji9391.18%133.33%
stephen hemmingerstephen hemminger87.84%133.33%
eric dumazeteric dumazet10.98%133.33%
Total102100.00%3100.00%

EXPORT_SYMBOL(ipv6_chk_prefix);
struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr, struct net_device *dev, int strict) { struct inet6_ifaddr *ifp, *result = NULL; unsigned int hash = inet6_addr_hash(addr); rcu_read_lock_bh(); hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[hash], addr_lst) { if (!net_eq(dev_net(ifp->idev->dev), net)) continue; if (ipv6_addr_equal(&ifp->addr, addr)) { if (!dev || ifp->idev->dev == dev || !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) { result = ifp; in6_ifa_hold(ifp); break; } } } rcu_read_unlock_bh(); return result; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji8965.44%535.71%
stephen hemmingerstephen hemminger1611.76%321.43%
daniel lezcanodaniel lezcano1511.03%17.14%
david s. millerdavid s. miller85.88%17.14%
ville nuorvalaville nuorvala53.68%17.14%
eric dumazeteric dumazet21.47%214.29%
ian morrisian morris10.74%17.14%
Total136100.00%14100.00%

/* Gets referenced address, destroys ifaddr */
static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) { if (dad_failed) ifp->flags |= IFA_F_DADFAILED; if (ifp->flags&IFA_F_PERMANENT) { spin_lock_bh(&ifp->lock); addrconf_del_dad_work(ifp); ifp->flags |= IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); if (dad_failed) ipv6_ifa_notify(0, ifp); in6_ifa_put(ifp); } else if (ifp->flags&IFA_F_TEMPORARY) { struct inet6_ifaddr *ifpub; spin_lock_bh(&ifp->lock); ifpub = ifp->ifpub; if (ifpub) { in6_ifa_hold(ifpub); spin_unlock_bh(&ifp->lock); ipv6_create_tempaddr(ifpub, ifp); in6_ifa_put(ifpub); } else { spin_unlock_bh(&ifp->lock); } ipv6_del_addr(ifp); } else { ipv6_del_addr(ifp); } }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji13482.72%228.57%
herbert xuherbert xu116.79%114.29%
lubomir rintellubomir rintel106.17%114.29%
brian haleybrian haley31.85%114.29%
hannes frederic sowahannes frederic sowa31.85%114.29%
adrian bunkadrian bunk10.62%114.29%
Total162100.00%7100.00%


static int addrconf_dad_end(struct inet6_ifaddr *ifp) { int err = -ENOENT; spin_lock_bh(&ifp->lock); if (ifp->state == INET6_IFADDR_STATE_DAD) { ifp->state = INET6_IFADDR_STATE_POSTDAD; err = 0; } spin_unlock_bh(&ifp->lock); return err; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu5292.86%133.33%
hannes frederic sowahannes frederic sowa47.14%266.67%
Total56100.00%3100.00%


void addrconf_dad_failure(struct inet6_ifaddr *ifp) { struct inet6_dev *idev = ifp->idev; struct net *net = dev_net(ifp->idev->dev); if (addrconf_dad_end(ifp)) { in6_ifa_put(ifp); return; } net_info_ratelimited("%s: IPv6 duplicate address %pI6c detected!\n", ifp->idev->dev->name, &ifp->addr); spin_lock_bh(&ifp->lock); if (ifp->flags & IFA_F_STABLE_PRIVACY) { int scope = ifp->scope; u32 flags = ifp->flags; struct in6_addr new_addr; struct inet6_ifaddr *ifp2; u32 valid_lft, preferred_lft; int pfxlen = ifp->prefix_len; int retries = ifp->stable_privacy_retry + 1; if (retries > net->ipv6.sysctl.idgen_retries) { net_info_ratelimited("%s: privacy stable address generation failed because of DAD conflicts!\n", ifp->idev->dev->name); goto errdad; } new_addr = ifp->addr; if (ipv6_generate_stable_address(&new_addr, retries, idev)) goto errdad; valid_lft = ifp->valid_lft; preferred_lft = ifp->prefered_lft; spin_unlock_bh(&ifp->lock); if (idev->cnf.max_addresses && ipv6_count_addresses(idev) >= idev->cnf.max_addresses) goto lock_errdad; net_info_ratelimited("%s: generating new stable privacy address because of DAD conflict\n", ifp->idev->dev->name); ifp2 = ipv6_add_addr(idev, &new_addr, NULL, pfxlen, scope, flags, valid_lft, preferred_lft); if (IS_ERR(ifp2)) goto lock_errdad; spin_lock_bh(&ifp2->lock); ifp2->stable_privacy_retry = retries; ifp2->state = INET6_IFADDR_STATE_PREDAD; spin_unlock_bh(&ifp2->lock); addrconf_mod_dad_work(ifp2, net->ipv6.sysctl.idgen_delay); in6_ifa_put(ifp2); lock_errdad: spin_lock_bh(&ifp->lock); } errdad: /* transition from _POSTDAD to _ERRDAD */ ifp->state = INET6_IFADDR_STATE_ERRDAD; spin_unlock_bh(&ifp->lock); addrconf_mod_dad_work(ifp, 0); in6_ifa_put(ifp); }

Contributors

PersonTokensPropCommitsCommitProp
hannes frederic sowahannes frederic sowa28982.34%430.77%
hideaki yoshifujihideaki yoshifuji257.12%215.38%
brian haleybrian haley123.42%215.38%
ursula braunursula braun71.99%17.69%
jens rosenboomjens rosenboom61.71%17.69%
herbert xuherbert xu61.71%17.69%
wei yongjunwei yongjun51.42%17.69%
joe perchesjoe perches10.28%17.69%
Total351100.00%13100.00%

/* Join to solicited addr multicast group. * caller must hold RTNL */
void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr) { struct in6_addr maddr; if (dev->flags&(IFF_LOOPBACK|IFF_NOARP)) return; addrconf_addr_solict_mult(addr, &maddr); ipv6_dev_mc_inc(dev, &maddr); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji4897.96%150.00%
eric dumazeteric dumazet12.04%150.00%
Total49100.00%2100.00%

/* caller must hold RTNL */
void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr) { struct in6_addr maddr; if (idev->dev->flags&(IFF_LOOPBACK|IFF_NOARP)) return; addrconf_addr_solict_mult(addr, &maddr); __ipv6_dev_mc_dec(idev, &maddr); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji5098.04%266.67%
eric dumazeteric dumazet11.96%133.33%
Total51100.00%3100.00%

/* caller must hold RTNL */
static void addrconf_join_anycast(struct inet6_ifaddr *ifp) { struct in6_addr addr; if (ifp->prefix_len >= 127) /* RFC 6164 */ return; ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len); if (ipv6_addr_any(&addr)) return; __ipv6_dev_ac_inc(ifp->idev, &addr); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji4779.66%120.00%
bjorn morkbjorn mork915.25%120.00%
americo wangamerico wang11.69%120.00%
hannes frederic sowahannes frederic sowa11.69%120.00%
arnaldo carvalho de meloarnaldo carvalho de melo11.69%120.00%
Total59100.00%5100.00%

/* caller must hold RTNL */
static void addrconf_leave_anycast(struct inet6_ifaddr *ifp) { struct in6_addr addr; if (ifp->prefix_len >= 127) /* RFC 6164 */ return; ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len); if (ipv6_addr_any(&addr)) return; __ipv6_dev_ac_dec(ifp->idev, &addr); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji5796.61%250.00%
arnaldo carvalho de meloarnaldo carvalho de melo11.69%125.00%
hannes frederic sowahannes frederic sowa11.69%125.00%
Total59100.00%4100.00%


static int addrconf_ifid_eui64(u8 *eui, struct net_device *dev) { if (dev->addr_len != EUI64_ADDR_LEN) return -1; memcpy(eui, dev->dev_addr, EUI64_ADDR_LEN); eui[0] ^= 2; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
alexander smirnovalexander smirnov3981.25%133.33%
hideaki yoshifujihideaki yoshifuji714.58%133.33%
alexander aringalexander aring24.17%133.33%
Total48100.00%3100.00%


static int addrconf_ifid_ieee1394(u8 *eui, struct net_device *dev) { union fwnet_hwaddr *ha; if (dev->addr_len != FWNET_ALEN) return -1; ha = (union fwnet_hwaddr *)dev->dev_addr; memcpy(eui, &ha->uc.uniq_id, sizeof(ha->uc.uniq_id)); eui[0] ^= 2; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji74100.00%1100.00%
Total74100.00%1100.00%


static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev) { /* XXX: inherit EUI-64 from other interface -- yoshfuji */ if (dev->addr_len != ARCNET_ALEN) return -1; memset(eui, 0, 7); eui[7] = *(u8 *)dev->dev_addr; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji54100.00%3100.00%
Total54100.00%3100.00%


static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev) { if (dev->addr_len != INFINIBAND_ALEN) return -1; memcpy(eui, dev->dev_addr + 12, 8); eui[0] |= 2; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
roland dreierroland dreier3570.00%133.33%
hideaki yoshifujihideaki yoshifuji1530.00%266.67%
Total50100.00%3100.00%


static int __ipv6_isatap_ifid(u8 *eui, __be32 addr) { if (addr == 0) return -1; eui[0] = (ipv4_is_zeronet(addr) || ipv4_is_private_10(addr) || ipv4_is_loopback(addr) || ipv4_is_linklocal_169(addr) || ipv4_is_private_172(addr) || ipv4_is_test_192(addr) || ipv4_is_anycast_6to4(addr) || ipv4_is_private_192(addr) || ipv4_is_test_198(addr) || ipv4_is_multicast(addr) || ipv4_is_lbcast(addr)) ? 0x00 : 0x02; eui[1] = 0; eui[2] = 0x5E; eui[3] = 0xFE; memcpy(eui + 4, &addr, 4); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji11491.20%133.33%
sascha hlusiaksascha hlusiak108.00%133.33%
stephen hemmingerstephen hemminger10.80%133.33%
Total125100.00%3100.00%


static int addrconf_ifid_sit(u8 *eui, struct net_device *dev) { if (dev->priv_flags & IFF_ISATAP) return __ipv6_isatap_ifid(eui, *(__be32 *)dev->dev_addr); return -1; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji42100.00%1100.00%
Total42100.00%1100.00%


static int addrconf_ifid_gre(u8 *eui, struct net_device *dev) { return __ipv6_isatap_ifid(eui, *(__be32 *)dev->dev_addr); }

Contributors

PersonTokensPropCommitsCommitProp
stephen hemmingerstephen hemminger30100.00%1100.00%
Total30100.00%1100.00%


static int addrconf_ifid_ip6tnl(u8 *eui, struct net_device *dev) { memcpy(eui, dev->perm_addr, 3); memcpy(eui + 5, dev->perm_addr + 3, 3); eui[3] = 0xFF; eui[4] = 0xFE; eui[0] ^= 2; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
nicolas dichtelnicolas dichtel65100.00%1100.00%
Total65100.00%1100.00%


static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) { switch (dev->type) { case ARPHRD_ETHER: case ARPHRD_FDDI: return addrconf_ifid_eui48(eui, dev); case ARPHRD_ARCNET: return addrconf_ifid_arcnet(eui, dev); case ARPHRD_INFINIBAND: return addrconf_ifid_infiniband(eui, dev); case ARPHRD_SIT: return addrconf_ifid_sit(eui, dev); case ARPHRD_IPGRE: return addrconf_ifid_gre(eui, dev); case ARPHRD_6LOWPAN: return addrconf_ifid_eui64(eui, dev); case ARPHRD_IEEE1394: return addrconf_ifid_ieee1394(eui, dev); case ARPHRD_TUNNEL6: return addrconf_ifid_ip6tnl(eui, dev); } return -1; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji7563.56%444.44%
nicolas dichtelnicolas dichtel119.32%111.11%
stephen hemmingerstephen hemminger119.32%111.11%
fred templinfred templin108.47%111.11%
alexander smirnovalexander smirnov97.63%111.11%
jukka rissanenjukka rissanen21.69%111.11%
Total118100.00%9100.00%


static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) { int err = -1; struct inet6_ifaddr *ifp; read_lock_bh(&idev->lock); list_for_each_entry_reverse(ifp, &idev->addr_list, if_list) { if (ifp->scope > IFA_LINK) break; if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { memcpy(eui, ifp->addr.s6_addr+8, 8); err = 0; break; } } read_unlock_bh(&idev->lock); return err; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji8582.52%125.00%
hannes frederic sowahannes frederic sowa109.71%125.00%
stephen hemmingerstephen hemminger76.80%125.00%
pre-gitpre-git10.97%125.00%
Total103100.00%4100.00%

/* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */
static void __ipv6_regen_rndid(struct inet6_dev *idev) { regen: get_random_bytes(idev->rndid, sizeof(idev->rndid)); idev->rndid[0] &= ~0x02; /* * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>: * check if generated address is not inappropriate * * - Reserved subnet anycast (RFC 2526) * 11111101 11....11 1xxxxxxx * - ISATAP (RFC4214) 6.1 * 00-00-5E-FE-xx-xx-xx-xx * - value 0 * - XXX: already assigned to an address on the device */ if (idev->rndid[0] == 0xfd && (idev->rndid[1]&idev->rndid[2]&idev->rndid[3]&idev->rndid[4]&idev->rndid[5]&idev->rndid[6]) == 0xff && (idev->rndid[7]&0x80)) goto regen; if ((idev->rndid[0]|idev->rndid[1]) == 0) { if (idev->rndid[2] == 0x5e && idev->rndid[3] == 0xfe) goto regen; if ((idev->rndid[2]|idev->rndid[3]|idev->rndid[4]|idev->rndid[5]|idev->rndid[6]|idev->rndid[7]) == 0x00) goto regen; } }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji19092.68%333.33%
pre-gitpre-git83.90%222.22%
david s. millerdavid s. miller41.95%111.11%
fred templinfred templin10.49%111.11%
sorin dumitrusorin dumitru10.49%111.11%
herbert xuherbert xu10.49%111.11%
Total205100.00%9100.00%


static void ipv6_regen_rndid(unsigned long data) { struct inet6_dev *idev = (struct inet6_dev *) data; unsigned long expires; rcu_read_lock_bh(); write_lock_bh(&idev->lock); if (idev->dead) goto out; __ipv6_regen_rndid(idev); expires = jiffies + idev->cnf.temp_prefered_lft * HZ - idev->cnf.regen_max_retry * idev->cnf.dad_transmits * NEIGH_VAR(idev->nd_parms, RETRANS_TIME) - idev->cnf.max_desync_factor * HZ; if (time_before(expires, jiffies)) { pr_warn("%s: too short regeneration interval; timer disabled for %s\n", __func__, idev->dev->name); goto out; } if (!mod_timer(&idev->regen_timer, expires)) in6_dev_hold(idev); out: write_unlock_bh(&idev->lock); rcu_read_unlock_bh(); in6_dev_put(idev); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji7447.74%330.00%
herbert xuherbert xu6240.00%110.00%
ben hutchingsben hutchings74.52%110.00%
jiri pirkojiri pirko53.23%110.00%
joe perchesjoe perches42.58%110.00%
pre-gitpre-git21.29%220.00%
sorin dumitrusorin dumitru10.65%110.00%
Total155100.00%10100.00%


static void __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) { if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0) __ipv6_regen_rndid(idev); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji2556.82%133.33%
pre-gitpre-git1840.91%133.33%
sorin dumitrusorin dumitru12.27%133.33%
Total44100.00%3100.00%

/* * Add prefix route. */
static void addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, unsigned long expires, u32 flags) { struct fib6_config cfg = { .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_PREFIX, .fc_metric = IP6_RT_PRIO_ADDRCONF, .fc_ifindex = dev->ifindex, .fc_expires = expires, .fc_dst_len = plen, .fc_flags = RTF_UP | flags, .fc_nlinfo.nl_net = dev_net(dev), .fc_protocol = RTPROT_KERNEL, }; cfg.fc_dst = *pfx; /* Prevent useless cloning on PtP SIT. This thing is done here expecting that the whole class of non-broadcast devices need not cloning. */ #if IS_ENABLED(CONFIG_IPV6_SIT) if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT)) cfg.fc_flags |= RTF_NONEXTHOP; #endif ip6_route_add(&cfg); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git7254.96%741.18%
thomas grafthomas graf2720.61%15.88%
benjamin therybenjamin thery75.34%211.76%
joerg roedeljoerg roedel75.34%15.88%
david aherndavid ahern64.58%15.88%
stephen hemmingerstephen hemminger53.82%15.88%
hideaki yoshifujihideaki yoshifuji32.29%15.88%
alexey dobriyanalexey dobriyan21.53%15.88%
americo wangamerico wang10.76%15.88%
jamal hadi salimjamal hadi salim10.76%15.88%
Total131100.00%17100.00%


static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, int plen, const struct net_device *dev, u32 flags, u32 noflags) { struct fib6_node *fn; struct rt6_info *rt = NULL; struct fib6_table *table; u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_PREFIX; table = fib6_get_table(dev_net(dev), tb_id); if (!table) return NULL; read_lock_bh(&table->tb6_lock); fn = fib6_locate(&table->tb6_root, pfx, plen, NULL, 0); if (!fn) goto out; noflags |= RTF_CACHE; for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { if (rt->dst.dev->ifindex != dev->ifindex) continue; if ((rt->rt6i_flags & flags) != flags) continue; if ((rt->rt6i_flags & noflags) != 0) continue; dst_hold(&rt->dst); break; } out: read_unlock_bh(&table->tb6_lock); return rt; }

Contributors

PersonTokensPropCommitsCommitProp
andreas hofmeisterandreas hofmeister17588.38%114.29%
david aherndavid ahern126.06%114.29%
martin kafai laumartin kafai lau42.02%114.29%
david s. millerdavid s. miller31.52%114.29%
li rongqingli rongqing21.01%114.29%
romain kuntzromain kuntz10.51%114.29%
ian morrisian morris10.51%114.29%
Total198100.00%7100.00%

/* Create "default" multicast route to the interface */
static void addrconf_add_mroute(struct net_device *dev) { struct fib6_config cfg = { .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_LOCAL, .fc_metric = IP6_RT_PRIO_ADDRCONF, .fc_ifindex = dev->ifindex, .fc_dst_len = 8, .fc_flags = RTF_UP, .fc_nlinfo.nl_net = dev_net(dev), }; ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0); ip6_route_add(&cfg); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3440.00%333.33%
thomas grafthomas graf3440.00%111.11%
benjamin therybenjamin thery78.24%222.22%
david aherndavid ahern67.06%111.11%
hideaki yoshifujihideaki yoshifuji44.71%222.22%
Total85100.00%9100.00%


static struct inet6_dev *addrconf_add_dev(struct net_device *dev) { struct inet6_dev *idev; ASSERT_RTNL(); idev = ipv6_find_idev(dev); if (!idev) return ERR_PTR(-ENOBUFS); if (idev->cnf.disable_ipv6) return ERR_PTR(-EACCES); /* Add default multicast route */ if (!(dev->flags & IFF_LOOPBACK) && !netif_is_l3_master(dev)) addrconf_add_mroute(dev); return idev; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3948.15%660.00%
brian haleybrian haley2024.69%110.00%
li weili wei1113.58%110.00%
david aherndavid ahern67.41%110.00%
stephen hemmingerstephen hemminger56.17%110.00%
Total81100.00%10100.00%


static void manage_tempaddrs(struct inet6_dev *idev, struct inet6_ifaddr *ifp, __u32 valid_lft, __u32 prefered_lft, bool create, unsigned long now) { u32 flags; struct inet6_ifaddr *ift; read_lock_bh(&idev->lock); /* update all temporary addresses in the list */ list_for_each_entry(ift, &idev->tempaddr_list, tmp_list) { int age, max_valid, max_prefered; if (ifp != ift->ifpub) continue; /* RFC 4941 section 3.3: * If a received option will extend the lifetime of a public * address, the lifetimes of temporary addresses should * be extended, subject to the overall constraint that no * temporary addresses should ever remain "valid" or "preferred" * for a time longer than (TEMP_VALID_LIFETIME) or * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), respectively. */ age = (now - ift->cstamp) / HZ; max_valid = idev->cnf.temp_valid_lft - age; if (max_valid < 0) max_valid = 0; max_prefered = idev->cnf.temp_prefered_lft - idev->cnf.max_desync_factor - age; if (max_prefered < 0) max_prefered = 0; if (valid_lft > max_valid) valid_lft = max_valid; if (prefered_lft > max_prefered) prefered_lft = max_prefered; spin_lock(&ift->lock); flags = ift->flags; ift->valid_lft = valid_lft; ift->prefered_lft = prefered_lft; ift->tstamp = now; if (prefered_lft > 0) ift->flags &= ~IFA_F_DEPRECATED; spin_unlock(&ift->lock); if (!(flags&IFA_F_TENTATIVE)) ipv6_ifa_notify(0, ift); } if ((create || list_empty(&idev->tempaddr_list)) && idev->cnf.use_tempaddr > 0) { /* When a new public address is created as described * in [ADDRCONF], also create a new temporary address. * Also create a temporary address if it's enabled but * no temporary address currently exists. */ read_unlock_bh(&idev->lock); ipv6_create_tempaddr(ifp, NULL); } else { read_unlock_bh(&idev->lock); } }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko271100.00%1100.00%
Total271100.00%1100.00%


static bool is_addr_mode_generate_stable(struct inet6_dev *idev) { return idev->addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY || idev->addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM; }

Contributors

PersonTokensPropCommitsCommitProp
bjorn morkbjorn mork24100.00%1100.00%
Total24100.00%1100.00%


int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev, const struct prefix_info *pinfo, struct inet6_dev *in6_dev, const struct in6_addr *addr, int addr_type, u32 addr_flags, bool sllao, bool tokenized, __u32 valid_lft, u32 prefered_lft) { struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1); int create = 0, update_lft = 0; if (!ifp && valid_lft) { int max_addresses = in6_dev->cnf.max_addresses; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD if (in6_dev->cnf.optimistic_dad && !net->ipv6.devconf_all->forwarding && sllao) addr_flags |= IFA_F_OPTIMISTIC; #endif /* Do not allow to create too much of autoconfigured * addresses; this would be too easy way to crash kernel. */ if (!max_addresses || ipv6_count_addresses(in6_dev) < max_addresses) ifp = ipv6_add_addr(in6_dev, addr, NULL, pinfo->prefix_len, addr_type&IPV6_ADDR_SCOPE_MASK, addr_flags, valid_lft, prefered_lft); if (IS_ERR_OR_NULL(ifp)) return -1; update_lft = 0; create = 1; spin_lock_bh(&ifp->lock); ifp->flags |= IFA_F_MANAGETEMPADDR; ifp->cstamp = jiffies; ifp->tokenized = tokenized; spin_unlock_bh(&ifp->lock); addrconf_dad_start(ifp); } if (ifp) { u32 flags; unsigned long now; u32 stored_lft; /* update lifetime (RFC2462 5.5.3 e) */ spin_lock_bh(&ifp->lock); now = jiffies; if (ifp->valid_lft > (now - ifp->tstamp) / HZ) stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ; else stored_lft = 0; if (!update_lft && !create && stored_lft) { const u32 minimum_lft = min_t(u32, stored_lft, MIN_VALID_LIFETIME); valid_lft = max(valid_lft, minimum_lft); /* RFC4862 Section 5.5.3e: * "Note that the preferred lifetime of the * corresponding address is always reset to * the Preferred Lifetime in the received * Prefix Information option, regardless of * whether the valid lifetime is also reset or * ignored." * * So we should always update prefered_lft here. */ update_lft = 1; } if (update_lft) { ifp->valid_lft = valid_lft; ifp->prefered_lft = prefered_lft; ifp->tstamp = now; flags = ifp->flags; ifp->flags &= ~IFA_F_DEPRECATED; spin_unlock_bh(&ifp->lock); if (!(flags&IFA_F_TENTATIVE)) ipv6_ifa_notify(0, ifp); } else spin_unlock_bh(&ifp->lock); manage_tempaddrs(in6_dev, ifp, valid_lft, prefered_lft, create, now); in6_ifa_put(ifp); addrconf_verify(); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
alexander aringalexander aring30372.49%15.00%
pre-gitpre-git8319.86%1050.00%
hideaki yoshifujihideaki yoshifuji225.26%420.00%
hannes frederic sowahannes frederic sowa30.72%15.00%
neil hormanneil horman30.72%15.00%
gao fenggao feng20.48%15.00%
brian haleybrian haley10.24%15.00%
andreas hofmeisterandreas hofmeister10.24%15.00%
Total418100.00%20100.00%

EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr);
void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) { struct prefix_info *pinfo; __u32 valid_lft; __u32 prefered_lft; int addr_type, err; u32 addr_flags = 0; struct inet6_dev *in6_dev; struct net *net = dev_net(dev); pinfo = (struct prefix_info *) opt; if (len < sizeof(struct prefix_info)) { ADBG("addrconf: prefix option too short\n"); return; } /* * Validation checks ([ADDRCONF], page 19) */ addr_type = ipv6_addr_type(&pinfo->prefix); if (addr_type & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL)) return; valid_lft = ntohl(pinfo->valid); prefered_lft = ntohl(pinfo->prefered); if (prefered_lft > valid_lft) { net_warn_ratelimited("addrconf: prefix option has invalid lifetime\n"); return; } in6_dev = in6_dev_get(dev); if (!in6_dev) { net_dbg_ratelimited("addrconf: device %s not configured\n", dev->name); return; } /* * Two things going on here: * 1) Add routes for on-link prefixes * 2) Configure prefixes with the auto flag set */ if (pinfo->onlink) { struct rt6_info *rt; unsigned long rt_expires; /* Avoid arithmetic overflow. Really, we could * save rt_expires in seconds, likely valid_lft, * but it would require division in fib gc, that it * not good. */ if (HZ > USER_HZ) rt_expires = addrconf_timeout_fixup(valid_lft, HZ); else rt_expires = addrconf_timeout_fixup(valid_lft, USER_HZ); if (addrconf_finite_timeout(rt_expires)) rt_expires *= HZ; rt = addrconf_get_prefix_route(&pinfo->prefix, pinfo->prefix_len, dev, RTF_ADDRCONF | RTF_PREFIX_RT, RTF_GATEWAY | RTF_DEFAULT); if (rt) { /* Autoconf prefix route */ if (valid_lft == 0) { ip6_del_rt(rt); rt = NULL; } else if (addrconf_finite_timeout(rt_expires)) { /* not infinity */ rt6_set_expires(rt, jiffies + rt_expires); } else { rt6_clean_expires(rt); } } else if (valid_lft) { clock_t expires = 0; int flags = RTF_ADDRCONF | RTF_PREFIX_RT; if (addrconf_finite_timeout(rt_expires)) { /* not infinity */ flags |= RTF_EXPIRES; expires = jiffies_to_clock_t(rt_expires); } addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, dev, expires, flags); } ip6_rt_put(rt); } /* Try to figure out our local address for this prefix */ if (pinfo->autoconf && in6_dev->cnf.autoconf) { struct in6_addr addr; bool tokenized = false, dev_addr_generated = false; if (pinfo->prefix_len == 64) { memcpy(&addr, &pinfo->prefix, 8); if (!ipv6_addr_any(&in6_dev->token)) { read_lock_bh(&in6_dev->lock); memcpy(addr.s6_addr + 8, in6_dev->token.s6_addr + 8, 8); read_unlock_bh(&in6_dev->lock); tokenized = true; } else if (is_addr_mode_generate_stable(in6_dev) && !ipv6_generate_stable_address(&addr, 0, in6_dev)) { addr_flags |= IFA_F_STABLE_PRIVACY; goto ok; } else if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) { goto put; } else { dev_addr_generated = true; } goto ok; } net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n", pinfo->prefix_len); goto put; ok: err = addrconf_prefix_rcv_add_addr(net, dev, pinfo, in6_dev, &addr, addr_type, addr_flags, sllao, tokenized, valid_lft, prefered_lft); if (err) goto put; /* Ignore error case here because previous prefix add addr was * successful which will be notified. */ ndisc_ops_prefix_rcv_add_addr(net, dev, pinfo, in6_dev, &addr, addr_type, addr_flags, sllao, tokenized, valid_lft, prefered_lft, dev_addr_generated); } inet6_prefix_notify(RTM_NEWPREFIX, in6_dev, pinfo); put: in6_dev_put(in6_dev); }

Contributors

PersonTokensPropCommitsCommitProp
alexander aringalexander aring44371.45%28.33%
pre-gitpre-git7812.58%625.00%
hideaki yoshifujihideaki yoshifuji264.19%312.50%
jiri pirkojiri pirko182.90%28.33%
daniel borkmanndaniel borkmann162.58%28.33%
hannes frederic sowahannes frederic sowa111.77%312.50%
shirley mashirley ma91.45%14.17%
lorenzo colittilorenzo colitti71.13%14.17%
alexey kuznetsovalexey kuznetsov50.81%14.17%
neil hormanneil horman40.65%14.17%
jiri bencjiri benc20.32%14.17%
joe perchesjoe perches10.16%14.17%
Total620100.00%24100.00%

/* * Set destination address. * Special case for SIT interfaces where we create a new "virtual" * device. */
int addrconf_set_dstaddr(struct net *net, void __user *arg) { struct in6_ifreq ireq; struct net_device *dev; int err = -EINVAL; rtnl_lock(); err = -EFAULT; if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) goto err_exit; dev = __dev_get_by_index(net, ireq.ifr6_ifindex); err = -ENODEV; if (!dev) goto err_exit; #if IS_ENABLED(CONFIG_IPV6_SIT) if (dev->type == ARPHRD_SIT) { const struct net_device_ops *ops = dev->netdev_ops; struct ifreq ifr; struct ip_tunnel_parm p; err = -EADDRNOTAVAIL; if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4)) goto err_exit; 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 = (__force void __user *)&p; if (ops->ndo_do_ioctl) { mm_segment_t oldfs = get_fs(); set_fs(KERNEL_DS); err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL); set_fs(oldfs); } else err = -EOPNOTSUPP; if (err == 0) { err = -ENOBUFS; dev = __dev_get_by_name(net, p.name); if (!dev) goto err_exit; err = dev_open(dev); } } #endif err_exit: rtnl_unlock(); return err; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git25882.17%428.57%
stephen hemmingerstephen hemminger319.87%321.43%
daniel lezcanodaniel lezcano123.82%17.14%
joerg roedeljoerg roedel72.23%17.14%
eric w. biedermaneric w. biederman20.64%17.14%
david s. millerdavid s. miller10.32%17.14%
ian morrisian morris10.32%17.14%
al viroal viro10.32%17.14%
americo wangamerico wang10.32%17.14%
Total314100.00%14100.00%


static int ipv6_mc_config(struct sock *sk, bool join, const struct in6_addr *addr, int ifindex) { int ret; ASSERT_RTNL(); lock_sock(sk); if (join) ret = ipv6_sock_mc_join(sk, ifindex, addr); else ret = ipv6_sock_mc_drop(sk, ifindex, addr); release_sock(sk); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
madhu challamadhu challa6797.10%150.00%
marcelo ricardo leitnermarcelo ricardo leitner22.90%150.00%
Total69100.00%2100.00%

/* * Manual configuration of address on an interface */
static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx, const struct in6_addr *peer_pfx, unsigned int plen, __u32 ifa_flags, __u32 prefered_lft, __u32 valid_lft) { struct inet6_ifaddr *ifp; struct inet6_dev *idev; struct net_device *dev; unsigned long timeout; clock_t expires; int scope; u32 flags; ASSERT_RTNL(); if (plen > 128) return -EINVAL; /* check the lifetime */ if (!valid_lft || prefered_lft > valid_lft) return -EINVAL; if (ifa_flags & IFA_F_MANAGETEMPADDR && plen != 64) return -EINVAL; dev = __dev_get_by_index(net, ifindex); if (!dev) return -ENODEV; idev = addrconf_add_dev(dev); if (IS_ERR(idev)) return PTR_ERR(idev); if (ifa_flags & IFA_F_MCAUTOJOIN) { int ret = ipv6_mc_config(net->ipv6.mc_autojoin_sk, true, pfx, ifindex); if (ret < 0) return ret; } scope = ipv6_addr_scope(pfx); timeout = addrconf_timeout_fixup(valid_lft, HZ); if (addrconf_finite_timeout(timeout)) { expires = jiffies_to_clock_t(timeout * HZ); valid_lft = timeout; flags = RTF_EXPIRES; } else { expires = 0; flags = 0; ifa_flags |= IFA_F_PERMANENT; } timeout = addrconf_timeout_fixup(prefered_lft, HZ); if (addrconf_finite_timeout(timeout)) { if (timeout == 0) ifa_flags |= IFA_F_DEPRECATED; prefered_lft = timeout; } ifp = ipv6_add_addr(idev, pfx, peer_pfx, plen, scope, ifa_flags, valid_lft, prefered_lft); if (!IS_ERR(ifp)) { if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) { addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, expires, flags); } /* * Note that section 3.1 of RFC 4429 indicates * that the Optimistic flag should not be set for * manually configured addresses */ addrconf_dad_start(ifp); if (ifa_flags & IFA_F_MANAGETEMPADDR) manage_tempaddrs(idev, ifp, valid_lft, prefered_lft, true, jiffies); in6_ifa_put(ifp); addrconf_verify_rtnl(); return 0; } else if (ifa_flags & IFA_F_MCAUTOJOIN) { ipv6_mc_config(net->ipv6.mc_autojoin_sk, false, pfx, ifindex); } return PTR_ERR(ifp); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji9724.37%416.00%
pre-gitpre-git9624.12%520.00%
madhu challamadhu challa6616.58%14.00%
noriaki takamiyanoriaki takamiya4210.55%28.00%
jiri pirkojiri pirko389.55%312.00%
brian haleybrian haley112.76%14.00%
thomas grafthomas graf112.76%14.00%
daniel lezcanodaniel lezcano112.76%14.00%
thomas hallerthomas haller112.76%14.00%
nicolas dichtelnicolas dichtel61.51%14.00%
jiri bencjiri benc41.01%14.00%
hannes frederic sowahannes frederic sowa20.50%14.00%
eric dumazeteric dumazet10.25%14.00%
neil hormanneil horman10.25%14.00%
eric w. biedermaneric w. biederman10.25%14.00%
Total398100.00%25100.00%


static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags, const struct in6_addr *pfx, unsigned int plen) { struct inet6_ifaddr *ifp; struct inet6_dev *idev; struct net_device *dev; if (plen > 128) return -EINVAL; dev = __dev_get_by_index(net, ifindex); if (!dev) return -ENODEV; idev = __in6_dev_get(dev); if (!idev) return -ENXIO; read_lock_bh(&idev->lock); list_for_each_entry(ifp, &idev->addr_list, if_list) { if (ifp->prefix_len == plen && ipv6_addr_equal(pfx, &ifp->addr)) { in6_ifa_hold(ifp); read_unlock_bh(&idev->lock); if (!(ifp->flags & IFA_F_TEMPORARY) && (ifa_flags & IFA_F_MANAGETEMPADDR)) manage_tempaddrs(idev, ifp, 0, 0, false, jiffies); ipv6_del_addr(ifp); addrconf_verify_rtnl(); if (ipv6_addr_is_multicast(pfx)) { ipv6_mc_config(net->ipv6.mc_autojoin_sk, false, pfx, dev->ifindex); } return 0; } } read_unlock_bh(&idev->lock); return -EADDRNOTAVAIL; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git11653.21%741.18%
heiner kallweitheiner kallweit3817.43%15.88%
madhu challamadhu challa2611.93%15.88%
daniel lezcanodaniel lezcano115.05%15.88%
thomas grafthomas graf115.05%15.88%
stephen hemmingerstephen hemminger83.67%15.88%
ian morrisian morris52.29%211.76%
hideaki yoshifujihideaki yoshifuji10.46%15.88%
eric w. biedermaneric w. biederman10.46%15.88%
eric dumazeteric dumazet10.46%15.88%
Total218100.00%17100.00%


int addrconf_add_ifaddr(struct net *net, void __user *arg) { struct in6_ifreq ireq; int err; if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) return -EFAULT; rtnl_lock(); err = inet6_addr_add(net, ireq.ifr6_ifindex, &ireq.ifr6_addr, NULL, ireq.ifr6_prefixlen, IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); rtnl_unlock(); return err; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git7376.84%222.22%
daniel lezcanodaniel lezcano77.37%111.11%
noriaki takamiyanoriaki takamiya66.32%222.22%
eric w. biedermaneric w. biederman55.26%111.11%
nicolas dichtelnicolas dichtel22.11%111.11%
david s. millerdavid s. miller11.05%111.11%
al viroal viro11.05%111.11%
Total95100.00%9100.00%


int addrconf_del_ifaddr(struct net *net, void __user *arg) { struct in6_ifreq ireq; int err; if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) return -EFAULT; rtnl_lock(); err = inet6_addr_del(net, ireq.ifr6_ifindex, 0, &ireq.ifr6_addr, ireq.ifr6_prefixlen); rtnl_unlock(); return err; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git7382.02%550.00%
daniel lezcanodaniel lezcano77.87%110.00%
eric w. biedermaneric w. biederman55.62%110.00%
heiner kallweitheiner kallweit22.25%110.00%
david s. millerdavid s. miller11.12%110.00%
al viroal viro11.12%110.00%
Total89100.00%10100.00%


static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int plen, int scope) { struct inet6_ifaddr *ifp; ifp = ipv6_add_addr(idev, addr, NULL, plen, scope, IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); if (!IS_ERR(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); } }

Contributors

PersonTokensPropCommitsCommitProp
ilpo jarvinenilpo jarvinen8893.62%125.00%
jiri bencjiri benc22.13%125.00%
hannes frederic sowahannes frederic sowa22.13%125.00%
jiri pirkojiri pirko22.13%125.00%
Total94100.00%4100.00%

#if IS_ENABLED(CONFIG_IPV6_SIT)
static void sit_add_v4_addrs(struct inet6_dev *idev) { struct in6_addr addr; struct net_device *dev; struct net *net = dev_net(idev->dev); int scope, plen; u32 pflags = 0; 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] = htonl(0xfe800000); scope = IFA_LINK; plen = 64; } else { scope = IPV6_ADDR_COMPATv4; plen = 96; pflags |= RTF_NONEXTHOP; } if (addr.s6_addr32[3]) { add_addr(idev, &addr, plen, scope); addrconf_prefix_route(&addr, plen, idev->dev, 0, pflags); return; } for_each_netdev(net, dev) { struct in_device *in_dev = __in_dev_get_rtnl(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) { 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; } add_addr(idev, &addr, plen, flag); addrconf_prefix_route(&addr, plen, idev->dev, 0, pflags); } } } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git22575.50%640.00%
nicolas dichtelnicolas dichtel5117.11%213.33%
benjamin therybenjamin thery103.36%16.67%
hideaki yoshifujihideaki yoshifuji41.34%213.33%
pavel emelianovpavel emelianov41.34%16.67%
ilpo jarvinenilpo jarvinen20.67%16.67%
eric w. biedermaneric w. biederman10.34%16.67%
herbert xuherbert xu10.34%16.67%
Total298100.00%15100.00%

#endif
static void init_loopback(struct net_device *dev) { struct inet6_dev *idev; struct net_device *sp_dev; struct inet6_ifaddr *sp_ifa; struct rt6_info *sp_rt; /* ::1 */ ASSERT_RTNL(); idev = ipv6_find_idev(dev); if (!idev) { pr_debug("%s: add_dev failed\n", __func__); return; } add_addr(idev, &in6addr_loopback, 128, IFA_HOST); /* Add routes to other interface's IPv6 addresses */ for_each_netdev(dev_net(dev), sp_dev) { if (!strcmp(sp_dev->name, dev->name)) continue; idev = __in6_dev_get(sp_dev); if (!idev) continue; read_lock_bh(&idev->lock); list_for_each_entry(sp_ifa, &idev->addr_list, if_list) { if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE)) continue; if (sp_ifa->rt) { /* This dst has been added to garbage list when * lo device down, release this obsolete dst and * reallocate a new router for ifa. */ if (sp_ifa->rt->dst.obsolete > 0) { ip6_rt_put(sp_ifa->rt); sp_ifa->rt = NULL; } else { continue; } } sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, false); /* Failure cases are ignored */ if (!IS_ERR(sp_rt)) { sp_ifa->rt = sp_rt; ip6_ins_rt(sp_rt); } } read_unlock_bh(&idev->lock); } }

Contributors

PersonTokensPropCommitsCommitProp
balakumaran kannanbalakumaran kannan11853.39%16.25%
gao fenggao feng4821.72%318.75%
pre-gitpre-git4319.46%637.50%
ian morrisian morris52.26%212.50%
joe perchesjoe perches41.81%16.25%
ilpo jarvinenilpo jarvinen10.45%16.25%
hideaki yoshifujihideaki yoshifuji10.45%16.25%
francois-xavier le bailfrancois-xavier le bail10.45%16.25%
Total221100.00%16100.00%


void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr, u32 flags) { struct inet6_ifaddr *ifp; u32 addr_flags = flags | IFA_F_PERMANENT; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD if (idev->cnf.optimistic_dad && !dev_net(idev->dev)->ipv6.devconf_all->forwarding) addr_flags |= IFA_F_OPTIMISTIC; #endif ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); if (!IS_ERR(ifp)) { addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); addrconf_dad_start(ifp); in6_ifa_put(ifp); } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git4939.84%321.43%
hideaki yoshifujihideaki yoshifuji2923.58%428.57%
neil hormanneil horman2721.95%17.14%
hannes frederic sowahannes frederic sowa75.69%214.29%
david s. millerdavid s. miller64.88%17.14%
jiri pirkojiri pirko21.63%17.14%
jiri bencjiri benc21.63%17.14%
eric dumazeteric dumazet10.81%17.14%
Total123100.00%14100.00%

EXPORT_SYMBOL_GPL(addrconf_add_linklocal);
static bool ipv6_reserved_interfaceid(struct in6_addr address) { if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0) return true; if (address.s6_addr32[2] == htonl(0x02005eff) && ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000))) return true; if (address.s6_addr32[2] == htonl(0xfdffffff) && ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80))) return true; return false; }

Contributors

PersonTokensPropCommitsCommitProp
hannes frederic sowahannes frederic sowa8777.68%125.00%
jiri pirkojiri pirko2017.86%125.00%
pre-gitpre-git54.46%250.00%
Total112100.00%4100.00%


static int ipv6_generate_stable_address(struct in6_addr *address, u8 dad_count, const struct inet6_dev *idev) { static DEFINE_SPINLOCK(lock); static __u32 digest[SHA_DIGEST_WORDS]; static __u32 workspace[SHA_WORKSPACE_WORDS]; static union { char __data[SHA_MESSAGE_BYTES]; struct { struct in6_addr secret; __be32 prefix[2]; unsigned char hwaddr[MAX_ADDR_LEN]; u8 dad_count; } __packed; } data; struct in6_addr secret; struct in6_addr temp; struct net *net = dev_net(idev->dev); BUILD_BUG_ON(sizeof(data.__data) != sizeof(data)); if (idev->cnf.stable_secret.initialized) secret = idev->cnf.stable_secret.secret; else if (net->ipv6.devconf_dflt->stable_secret.initialized) secret = net->ipv6.devconf_dflt->stable_secret.secret; else return -1; retry: spin_lock_bh(&lock); sha_init(digest); memset(&data, 0, sizeof(data)); memset(workspace, 0, sizeof(workspace)); memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len); data.prefix[0] = address->s6_addr32[0]; data.prefix[1] = address->s6_addr32[1]; data.secret = secret; data.dad_count = dad_count; sha_transform(digest, data.__data, workspace); temp = *address; temp.s6_addr32[2] = (__force __be32)digest[0]; temp.s6_addr32[3] = (__force __be32)digest[1]; spin_unlock_bh(&lock); if (ipv6_reserved_interfaceid(temp)) { dad_count++; if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries) return -1; goto retry; } *address = temp; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hannes frederic sowahannes frederic sowa34897.48%342.86%
pre-gitpre-git51.40%342.86%
jiri pirkojiri pirko41.12%114.29%
Total357100.00%7100.00%


static void ipv6_gen_mode_random_init(struct inet6_dev *idev) { struct ipv6_stable_secret *s = &idev->cnf.stable_secret; if (s->initialized) return; s = &idev->cnf.stable_secret; get_random_bytes(&s->secret, sizeof(s->secret)); s->initialized = true; }

Contributors

PersonTokensPropCommitsCommitProp
bjorn morkbjorn mork60100.00%1100.00%
Total60100.00%1100.00%


static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route) { struct in6_addr addr; /* no link local addresses on L3 master devices */