cregit-Linux how code gets into the kernel

Release 4.11 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/sched/signal.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 Graf2090.91%150.00%
Shirley Ma29.09%150.00%
Total22100.00%2100.00%


static inline s32 rfc3315_s14_backoff_init(s32 irt) { /* multiply 'initial retransmission time' by 0.9 .. 1.1 */ u64 tmp = (900000 + prandom_u32() % 200001) * (u64)irt; do_div(tmp, 1000000); return (s32)tmp; }

Contributors

PersonTokensPropCommitsCommitProp
Maciej Żenczykowski41100.00%1100.00%
Total41100.00%1100.00%


static inline s32 rfc3315_s14_backoff_update(s32 rt, s32 mrt) { /* multiply 'retransmission timeout' by 1.9 .. 2.1 */ u64 tmp = (1900000 + prandom_u32() % 200001) * (u64)rt; do_div(tmp, 1000000); if ((s32)tmp > mrt) { /* multiply 'maximum retransmission time' by 0.9 .. 1.1 */ tmp = (900000 + prandom_u32() % 200001) * (u64)mrt; do_div(tmp, 1000000); } return (s32)tmp; }

Contributors

PersonTokensPropCommitsCommitProp
Maciej Żenczykowski79100.00%1100.00%
Total79100.00%1100.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 Emelyanov960.00%150.00%
Américo Wang640.00%150.00%
Total15100.00%2100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Pavel Emelyanov11100.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 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, bool bump_id); 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_max_interval = RTR_SOLICITATION_MAX_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, .seg6_enabled = 0, #ifdef CONFIG_IPV6_SEG6_HMAC .seg6_require_hmac = 0, #endif .enhanced_dad = 1, .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64, }; 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_max_interval = RTR_SOLICITATION_MAX_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, .seg6_enabled = 0, #ifdef CONFIG_IPV6_SEG6_HMAC .seg6_require_hmac = 0, #endif .enhanced_dad = 1, .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64, }; /* 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 Chinen1365.00%150.00%
David 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 Sowa2492.31%150.00%
Linus Torvalds (pre-git)27.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
Linus Torvalds (pre-git)2180.77%133.33%
Hannes 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 Sowa4297.67%150.00%
Linus Torvalds (pre-git)12.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
Linus Torvalds (pre-git)3172.09%133.33%
Hannes 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 Xu5031.45%114.29%
Eric Dumazet3823.90%228.57%
John Stultz3522.01%114.29%
David L Stevens2213.84%114.29%
Américo Wang127.55%114.29%
Pavel Emelyanov21.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->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; else ndev->cnf.addr_gen_mode = ipv6_devconf_dflt.addr_gen_mode; 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. */ 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); ndev->desync_factor = U32_MAX; 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 ipv6_regen_rndid(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); 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 Yoshifuji / 吉藤英明16729.09%918.00%
Linus Torvalds (pre-git)12421.60%816.00%
Américo Wang7212.54%24.00%
Hannes Frederic Sowa478.19%36.00%
Li Wei254.36%12.00%
Herbert Xu223.83%24.00%
Stephen Hemminger162.79%24.00%
Ben Hutchings132.26%12.00%
David L Stevens91.57%12.00%
Jiri Bohac71.22%24.00%
Felix Jia71.22%12.00%
Daniel Borkmann61.05%24.00%
Shirley Ma61.05%12.00%
Sabrina Dubroca50.87%12.00%
David S. Miller50.87%12.00%
Roy Li50.87%12.00%
Rémi Denis-Courmont50.87%12.00%
Linus Torvalds50.87%12.00%
Pavel Emelyanov50.87%12.00%
Andrew Morton40.70%12.00%
Ding Tianhong40.70%12.00%
Joe Perches30.52%12.00%
Ingo Oeser30.52%12.00%
Joerg Roedel30.52%12.00%
Ian Morris20.35%12.00%
Harvey Harrison20.35%12.00%
Eric Dumazet10.17%12.00%
Mitsuru Chinen10.17%12.00%
Total574100.00%50100.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 Stevens3652.94%114.29%
Linus Torvalds (pre-git)1927.94%342.86%
Stephen Hemminger913.24%114.29%
Américo Wang34.41%114.29%
Hideaki Yoshifuji / 吉藤英明11.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 Dichtel6054.55%342.86%
Zhang Shengju1715.45%114.29%
Andy Gospodarek1412.73%114.29%
Stephen Hemminger1412.73%114.29%
David 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 Dichtel17368.92%333.33%
Andy Gospodarek259.96%111.11%
Stephen Hemminger259.96%111.11%
Zhang Shengju197.57%111.11%
David S. Miller51.99%111.11%
Johannes Berg31.20%111.11%
Ian 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 Dichtel12297.60%133.33%
Eric Dumazet21.60%133.33%
Ian 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