cregit-Linux how code gets into the kernel

Release 4.11 net/ipv6/icmp.c

Directory: net/ipv6
/*
 *      Internet Control Message Protocol (ICMPv6)
 *      Linux INET6 implementation
 *
 *      Authors:
 *      Pedro Roque             <roque@di.fc.ul.pt>
 *
 *      Based on net/ipv4/icmp.c
 *
 *      RFC 1885
 *
 *      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:
 *
 *      Andi Kleen              :       exception handling
 *      Andi Kleen                      add rate limits. never reply to a icmp.
 *                                      add more length checks and other fixes.
 *      yoshfuji                :       ensure to sent parameter problem for
 *                                      fragments.
 *      YOSHIFUJI Hideaki @USAGI:       added sysctl for icmp rate limit.
 *      Randy Dunlap and
 *      YOSHIFUJI Hideaki @USAGI:       Per-interface statistics support
 *      Kazunori MIYAZAWA @USAGI:       change output process to use ip6_append_data
 */


#define pr_fmt(fmt) "IPv6: " fmt

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/netfilter.h>
#include <linux/slab.h>

#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif

#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/icmpv6.h>

#include <net/ip.h>
#include <net/sock.h>

#include <net/ipv6.h>
#include <net/ip6_checksum.h>
#include <net/ping.h>
#include <net/protocol.h>
#include <net/raw.h>
#include <net/rawv6.h>
#include <net/transp_v6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
#include <net/icmp.h>
#include <net/xfrm.h>
#include <net/inet_common.h>
#include <net/dsfield.h>
#include <net/l3mdev.h>

#include <linux/uaccess.h>

/*
 *      The ICMP socket(s). This is the most convenient way to flow control
 *      our ICMP output as well as maintain a clean interface throughout
 *      all layers. All Socketless IP sends will soon be gone.
 *
 *      On SMP we have one ICMP socket per-cpu.
 */

static inline struct sock *icmpv6_sk(struct net *net) { return net->ipv6.icmp_sk[smp_processor_id()]; }

Contributors

PersonTokensPropCommitsCommitProp
Denis V. Lunev2496.00%375.00%
David S. Miller14.00%125.00%
Total25100.00%4100.00%


static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, u8 type, u8 code, int offset, __be32 info) { /* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */ struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset); struct net *net = dev_net(skb->dev); if (type == ICMPV6_PKT_TOOBIG) ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL)); else if (type == NDISC_REDIRECT) ip6_redirect(skb, net, skb->dev->ifindex, 0, sock_net_uid(net, NULL)); if (!(type & ICMPV6_INFOMSG_MASK)) if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST) ping_err(skb, offset, ntohl(info)); }

Contributors

PersonTokensPropCommitsCommitProp
Steffen Klassert7653.15%120.00%
Lorenzo Colitti5941.26%240.00%
Duan Jiong53.50%120.00%
Hannes Frederic Sowa32.10%120.00%
Total143100.00%5100.00%

static int icmpv6_rcv(struct sk_buff *skb); static const struct inet6_protocol icmpv6_protocol = { .handler = icmpv6_rcv, .err_handler = icmpv6_err, .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; /* Called with BH disabled */ static __inline__ struct sock *icmpv6_xmit_lock(struct net *net) { struct sock *sk; sk = icmpv6_sk(net); if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { /* This can happen if the output path (f.e. SIT or * ip6ip6 tunnel) signals dst_link_failure() for an * outgoing ICMP6 packet. */ return NULL; } return sk;
} static __inline__ void icmpv6_xmit_unlock(struct sock *sk) { spin_unlock(&sk->sk_lock.slock); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1254.55%116.67%
Denis V. Lunev627.27%233.33%
David S. Miller29.09%116.67%
Jesper Dangaard Brouer14.55%116.67%
Arnaldo Carvalho de Melo14.55%116.67%
Total22100.00%6100.00%

/* * Figure out, may we reply to this packet with icmp error. * * We do not reply, if: * - it was icmp error message. * - it is truncated, so that it is known, that protocol is ICMPV6 * (i.e. in the middle of some exthdr) * * --ANK (980726) */
static bool is_ineligible(const struct sk_buff *skb) { int ptr = (u8 *)(ipv6_hdr(skb) + 1) - skb->data; int len = skb->len - ptr; __u8 nexthdr = ipv6_hdr(skb)->nexthdr; __be16 frag_off; if (len < 0) return true; ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, &frag_off); if (ptr < 0) return false; if (nexthdr == IPPROTO_ICMPV6) { u8 _type, *tp; tp = skb_header_pointer(skb, ptr+offsetof(struct icmp6hdr, icmp6_type), sizeof(_type), &_type); if (!tp || !(*tp & ICMPV6_INFOMSG_MASK)) return true; } return false; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5739.31%222.22%
Linus Torvalds4933.79%111.11%
David S. Miller1913.10%111.11%
Jesse Gross64.14%111.11%
Arnaldo Carvalho de Melo64.14%111.11%
Eric Dumazet64.14%111.11%
Ian Morris10.69%111.11%
Hideaki Yoshifuji / 吉藤英明10.69%111.11%
Total145100.00%9100.00%


static bool icmpv6_mask_allow(int type) { /* Informational messages are not limited. */ if (type & ICMPV6_INFOMSG_MASK) return true; /* Do not limit pmtu discovery, it would break it. */ if (type == ICMPV6_PKT_TOOBIG) return true; return false; }

Contributors

PersonTokensPropCommitsCommitProp
Jesper Dangaard Brouer32100.00%1100.00%
Total32100.00%1100.00%


static bool icmpv6_global_allow(int type) { if (icmpv6_mask_allow(type)) return true; if (icmp_global_allow()) return true; return false; }

Contributors

PersonTokensPropCommitsCommitProp
Jesper Dangaard Brouer30100.00%1100.00%
Total30100.00%1100.00%

/* * Check the ICMP output rate limit */
static bool icmpv6_xrlim_allow(struct sock *sk, u8 type, struct flowi6 *fl6) { struct net *net = sock_net(sk); struct dst_entry *dst; bool res = false; if (icmpv6_mask_allow(type)) return true; /* * Look up the output route. * XXX: perhaps the expire for routing entries cloned by * this lookup should be more aggressive (not longer than timeout). */ dst = ip6_route_output(net, sk, fl6); if (dst->error) { IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) { res = true; } else { struct rt6_info *rt = (struct rt6_info *)dst; int tmo = net->ipv6.sysctl.icmpv6_time; struct inet_peer *peer; /* Give more bandwidth to wider prefixes. */ if (rt->rt6i_dst.plen < 128) tmo >>= ((128 - rt->rt6i_dst.plen)>>5); peer = inet_getpeer_v6(net->ipv6.peers, &fl6->daddr, 1); res = inet_peer_xrlim_allow(peer, tmo); if (peer) inet_putpeer(peer); } dst_release(dst); return res; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)12862.14%420.00%
David S. Miller3516.99%420.00%
Hideaki Yoshifuji / 吉藤英明104.85%420.00%
Benjamin Thery94.37%15.00%
Jesper Dangaard Brouer83.88%15.00%
Daniel Lezcano62.91%210.00%
Eric Dumazet52.43%15.00%
Martin KaFai Lau20.97%15.00%
Denis V. Lunev20.97%15.00%
Brian Haley10.49%15.00%
Total206100.00%20100.00%

/* * an inline helper for the "simple" if statement below * checks if parameter problem report is caused by an * unrecognized IPv6 option that has the Option Type * highest-order two bits set to 10 */
static bool opt_unrec(struct sk_buff *skb, __u32 offset) { u8 _optval, *op; offset += skb_network_offset(skb); op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval); if (!op) return true; return (*op & 0xC0) == 0x80; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2337.10%228.57%
David S. Miller1930.65%114.29%
Linus Torvalds1422.58%114.29%
Arnaldo Carvalho de Melo34.84%114.29%
Eric Dumazet23.23%114.29%
Ian Morris11.61%114.29%
Total62100.00%7100.00%


int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, struct icmp6hdr *thdr, int len) { struct sk_buff *skb; struct icmp6hdr *icmp6h; int err = 0; skb = skb_peek(&sk->sk_write_queue); if (!skb) goto out; icmp6h = icmp6_hdr(skb); memcpy(icmp6h, thdr, sizeof(struct icmp6hdr)); icmp6h->icmp6_cksum = 0; if (skb_queue_len(&sk->sk_write_queue) == 1) { skb->csum = csum_partial(icmp6h, sizeof(struct icmp6hdr), skb->csum); icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, len, fl6->flowi6_proto, skb->csum); } else { __wsum tmp_csum = 0; skb_queue_walk(&sk->sk_write_queue, skb) { tmp_csum = csum_add(tmp_csum, skb->csum); } tmp_csum = csum_partial(icmp6h, sizeof(struct icmp6hdr), tmp_csum); icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, len, fl6->flowi6_proto, tmp_csum); } ip6_push_pending_frames(sk); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Kazunori Miyazawa16474.89%110.00%
Linus Torvalds (pre-git)2210.05%220.00%
David S. Miller188.22%220.00%
Arnaldo Carvalho de Melo62.74%220.00%
Ian Morris52.28%220.00%
Al Viro41.83%110.00%
Total219100.00%10100.00%

struct icmpv6_msg { struct sk_buff *skb; int offset; uint8_t type; };
static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) { struct icmpv6_msg *msg = (struct icmpv6_msg *) from; struct sk_buff *org_skb = msg->skb; __wsum csum = 0; csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset, to, len, csum); skb->csum = csum_block_add(skb->csum, csum, odd); if (!(msg->type & ICMPV6_INFOMSG_MASK)) nf_ct_attach(skb, org_skb); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kazunori Miyazawa7467.89%125.00%
Yasuyuki Kozakai1816.51%125.00%
David S. Miller1614.68%125.00%
Al Viro10.92%125.00%
Total109100.00%4100.00%

#if IS_ENABLED(CONFIG_IPV6_MIP6)
static void mip6_addr_swap(struct sk_buff *skb) { struct ipv6hdr *iph = ipv6_hdr(skb); struct inet6_skb_parm *opt = IP6CB(skb); struct ipv6_destopt_hao *hao; struct in6_addr tmp; int off; if (opt->dsthao) { off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO); if (likely(off >= 0)) { hao = (struct ipv6_destopt_hao *) (skb_network_header(skb) + off); tmp = iph->saddr; iph->saddr = hao->addr; hao->addr = tmp; } } }

Contributors

PersonTokensPropCommitsCommitProp
Masahide Nakamura10291.89%125.00%
Arnaldo Carvalho de Melo65.41%250.00%
Alexey Dobriyan32.70%125.00%
Total111100.00%4100.00%

#else
static inline void mip6_addr_swap(struct sk_buff *skb) {}

Contributors

PersonTokensPropCommitsCommitProp
Masahide Nakamura11100.00%1100.00%
Total11100.00%1100.00%

#endif
static struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb, struct sock *sk, struct flowi6 *fl6) { struct dst_entry *dst, *dst2; struct flowi6 fl2; int err; err = ip6_dst_lookup(net, sk, &dst, fl6); if (err) return ERR_PTR(err); /* * We won't send icmp if the destination is known * anycast. */ if (ipv6_anycast_destination(dst, &fl6->daddr)) { net_dbg_ratelimited("icmp6_send: acast source\n"); dst_release(dst); return ERR_PTR(-EINVAL); } /* No need to clone since we're just using its address. */ dst2 = dst; dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), sk, 0); if (!IS_ERR(dst)) { if (dst != dst2) return dst; } else { if (PTR_ERR(dst) == -EPERM) dst = NULL; else return dst; } err = xfrm_decode_session_reverse(skb, flowi6_to_flowi(&fl2), AF_INET6); if (err) goto relookup_failed; err = ip6_dst_lookup(net, sk, &dst2, &fl2); if (err) goto relookup_failed; dst2 = xfrm_lookup(net, dst2, flowi6_to_flowi(&fl2), sk, XFRM_LOOKUP_ICMP); if (!IS_ERR(dst2)) { dst_release(dst); dst = dst2; } else { err = PTR_ERR(dst2); if (err == -EPERM) { dst_release(dst); return dst2; } else goto relookup_failed; } relookup_failed: if (dst) return dst; return ERR_PTR(err); }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller27695.17%337.50%
Martin KaFai Lau72.41%112.50%
Roopa Prabhu41.38%112.50%
Pravin B Shelar10.34%112.50%
Stephen Hemminger10.34%112.50%
Joe Perches10.34%112.50%
Total290100.00%8100.00%

/* * Send an ICMP message in response to a packet in error */
static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, const struct in6_addr *force_saddr) { struct net *net = dev_net(skb->dev); struct inet6_dev *idev = NULL; struct ipv6hdr *hdr = ipv6_hdr(skb); struct sock *sk; struct ipv6_pinfo *np; const struct in6_addr *saddr = NULL; struct dst_entry *dst; struct icmp6hdr tmp_hdr; struct flowi6 fl6; struct icmpv6_msg msg; struct sockcm_cookie sockc_unused = {0}; struct ipcm6_cookie ipc6; int iif = 0; int addr_type = 0; int len; int err = 0; u32 mark = IP6_REPLY_MARK(net, skb->mark); if ((u8 *)hdr < skb->head || (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) return; /* * Make sure we respect the rules * i.e. RFC 1885 2.4(e) * Rule (e.1) is enforced by not using icmp6_send * in any code that processes icmp errors. */ addr_type = ipv6_addr_type(&hdr->daddr); if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0) || ipv6_chk_acast_addr_src(net, skb->dev, &hdr->daddr)) saddr = &hdr->daddr; /* * Dest addr check */ if (addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST) { if (type != ICMPV6_PKT_TOOBIG && !(type == ICMPV6_PARAMPROB && code == ICMPV6_UNK_OPTION && (opt_unrec(skb, info)))) return; saddr = NULL; } addr_type = ipv6_addr_type(&hdr->saddr); /* * Source addr check */ if (__ipv6_addr_needs_scope_id(addr_type)) iif = skb->dev->ifindex; else { dst = skb_dst(skb); iif = l3mdev_master_ifindex(dst ? dst->dev : skb->dev); } /* * Must not send error if the source does not uniquely * identify a single node (RFC2463 Section 2.4). * We check unspecified / multicast addresses here, * and anycast addresses will be checked later. */ if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) { net_dbg_ratelimited("icmp6_send: addr_any/mcast source [%pI6c > %pI6c]\n", &hdr->saddr, &hdr->daddr); return; } /* * Never answer to a ICMP packet. */ if (is_ineligible(skb)) { net_dbg_ratelimited("icmp6_send: no reply to icmp error [%pI6c > %pI6c]\n", &hdr->saddr, &hdr->daddr); return; } /* Needed by both icmp_global_allow and icmpv6_xmit_lock */ local_bh_disable(); /* Check global sysctl_icmp_msgs_per_sec ratelimit */ if (!icmpv6_global_allow(type)) goto out_bh_enable; mip6_addr_swap(skb); memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_proto = IPPROTO_ICMPV6; fl6.daddr = hdr->saddr; if (force_saddr) saddr = force_saddr; if (saddr) fl6.saddr = *saddr; fl6.flowi6_mark = mark; fl6.flowi6_oif = iif; fl6.fl6_icmp_type = type; fl6.fl6_icmp_code = code; fl6.flowi6_uid = sock_net_uid(net, NULL); security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); sk = icmpv6_xmit_lock(net); if (!sk) goto out_bh_enable; sk->sk_mark = mark; np = inet6_sk(sk); if (!icmpv6_xrlim_allow(sk, type, &fl6)) goto out; tmp_hdr.icmp6_type = type; tmp_hdr.icmp6_code = code; tmp_hdr.icmp6_cksum = 0; tmp_hdr.icmp6_pointer = htonl(info); if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) fl6.flowi6_oif = np->mcast_oif; else if (!fl6.flowi6_oif) fl6.flowi6_oif = np->ucast_oif; ipc6.tclass = np->tclass; fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel); dst = icmpv6_route_lookup(net, skb, sk, &fl6); if (IS_ERR(dst)) goto out; ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); ipc6.dontfrag = np->dontfrag; ipc6.opt = NULL; msg.skb = skb; msg.offset = skb_network_offset(skb); msg.type = type; len = skb->len - msg.offset; len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr)); if (len < 0) { net_dbg_ratelimited("icmp: len problem [%pI6c > %pI6c]\n", &hdr->saddr, &hdr->daddr); goto out_dst_release; } rcu_read_lock(); idev = __in6_dev_get(skb->dev); err = ip6_append_data(sk, icmpv6_getfrag, &msg, len + sizeof(struct icmp6hdr), sizeof(struct icmp6hdr), &ipc6, &fl6, (struct rt6_info *)dst, MSG_DONTWAIT, &sockc_unused); if (err) { ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS); ip6_flush_pending_frames(sk); } else { err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr, len + sizeof(struct icmp6hdr)); } rcu_read_unlock(); out_dst_release: dst_release(dst); out: icmpv6_xmit_unlock(sk); out_bh_enable: local_bh_enable(); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)23727.65%79.72%
Kazunori Miyazawa16018.67%11.39%
David S. Miller758.75%79.72%
Lorenzo Colitti414.78%34.17%
Björn Mork333.85%11.39%
Eric Dumazet323.73%56.94%
Hannes Frederic Sowa273.15%34.17%
David Ahern252.92%34.17%
Jesper Dangaard Brouer242.80%22.78%
Wei Wang222.57%11.39%
Hideaki Yoshifuji / 吉藤英明212.45%79.72%
Herbert Xu161.87%11.39%
Erich E. Hoover161.87%11.39%
François-Xavier Le Bail141.63%22.78%
Linus Torvalds121.40%34.17%
Arnaldo Carvalho de Melo111.28%34.17%
Benjamin Thery111.28%11.39%
Soheil Hassas Yeganeh101.17%11.39%
Denis V. Lunev101.17%34.17%
Randy Dunlap91.05%11.39%
Venkat Yekkirala70.82%11.39%
Simon Horman60.70%11.39%
Yasuyuki Kozakai60.70%11.39%
Alexey Dobriyan50.58%22.78%
Masahide Nakamura50.58%11.39%
Jan Oravec40.47%11.39%
Brian Haley30.35%22.78%
Joe Perches30.35%11.39%
Andi Kleen30.35%11.39%
Pravin B Shelar30.35%11.39%
Ville Nuorvala20.23%11.39%
Ian Morris20.23%22.78%
Daniel Lezcano20.23%11.39%
Total857100.00%72100.00%

/* Slightly more convenient version of icmp6_send. */
void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) { icmp6_send(skb, ICMPV6_PARAMPROB, code, pos, NULL); kfree_skb(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Pravin B Shelar2985.29%133.33%
Hideaki Yoshifuji / 吉藤英明38.82%133.33%
Eric Dumazet25.88%133.33%
Total34100.00%3100.00%

/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH * if sufficient data bytes are available * @nhs is the size of the tunnel header(s) : * Either an IPv4 header for SIT encap * an IPv4 header + GRE header for GRE encap */
int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type, unsigned int data_len) { struct in6_addr temp_saddr; struct rt6_info *rt; struct sk_buff *skb2; u32 info = 0; if (!pskb_may_pull(skb, nhs + sizeof(struct ipv6hdr) + 8)) return 1; /* RFC 4884 (partial) support for ICMP extensions */ if (data_len < 128 || (data_len & 7) || skb->len < data_len) data_len = 0; skb2 = data_len ? skb_copy(skb, GFP_ATOMIC) : skb_clone(skb, GFP_ATOMIC); if (!skb2) return 1; skb_dst_drop(skb2); skb_pull(skb2, nhs); skb_reset_network_header(skb2); rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0, 0); if (rt && rt->dst.dev) skb2->dev = rt->dst.dev; ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, &temp_saddr); if (data_len) { /* RFC 4884 (partial) support : * insert 0 padding at the end, before the extensions */ __skb_push(skb2, nhs); skb_reset_network_header(skb2); memmove(skb2->data, skb2->data + nhs, data_len - nhs); memset(skb2->data + data_len - nhs, 0, nhs); /* RFC 4884 4.5 : Length is measured in 64-bit words, * and stored in reserved[0] */ info = (data_len/8) << 24; } if (type == ICMP_TIME_EXCEEDED) icmp6_send(skb2, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, info, &temp_saddr); else icmp6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, info, &temp_saddr); if (rt) ip6_rt_put(rt); kfree_skb(skb2); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet299100.00%3100.00%
Total299100.00%3100.00%

EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach);
static void icmpv6_echo_reply(struct sk_buff *skb) { struct net *net = dev_net(skb->dev); struct sock *sk; struct inet6_dev *idev; struct ipv6_pinfo *np; const struct in6_addr *saddr = NULL; struct icmp6hdr *icmph = icmp6_hdr(skb); struct icmp6hdr tmp_hdr; struct flowi6 fl6; struct icmpv6_msg msg; struct dst_entry *dst; struct ipcm6_cookie ipc6; int err = 0; u32 mark = IP6_REPLY_MARK(net, skb->mark); struct sockcm_cookie sockc_unused = {0}; saddr = &ipv6_hdr(skb)->daddr; if (!ipv6_unicast_destination(skb) && !(net->ipv6.sysctl.anycast_src_echo_reply && ipv6_anycast_destination(skb_dst(skb), saddr))) saddr =