162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * IPv6 input 462306a36Sopenharmony_ci * Linux INET6 implementation 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Authors: 762306a36Sopenharmony_ci * Pedro Roque <roque@di.fc.ul.pt> 862306a36Sopenharmony_ci * Ian P. Morris <I.P.Morris@soton.ac.uk> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Based in linux/net/ipv4/ip_input.c 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci/* Changes 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Mitsuru KANDA @USAGI and 1562306a36Sopenharmony_ci * YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs(). 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/errno.h> 1962306a36Sopenharmony_ci#include <linux/types.h> 2062306a36Sopenharmony_ci#include <linux/socket.h> 2162306a36Sopenharmony_ci#include <linux/sockios.h> 2262306a36Sopenharmony_ci#include <linux/net.h> 2362306a36Sopenharmony_ci#include <linux/netdevice.h> 2462306a36Sopenharmony_ci#include <linux/in6.h> 2562306a36Sopenharmony_ci#include <linux/icmpv6.h> 2662306a36Sopenharmony_ci#include <linux/mroute6.h> 2762306a36Sopenharmony_ci#include <linux/slab.h> 2862306a36Sopenharmony_ci#include <linux/indirect_call_wrapper.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <linux/netfilter.h> 3162306a36Sopenharmony_ci#include <linux/netfilter_ipv6.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <net/sock.h> 3462306a36Sopenharmony_ci#include <net/snmp.h> 3562306a36Sopenharmony_ci#include <net/udp.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <net/ipv6.h> 3862306a36Sopenharmony_ci#include <net/protocol.h> 3962306a36Sopenharmony_ci#include <net/transp_v6.h> 4062306a36Sopenharmony_ci#include <net/rawv6.h> 4162306a36Sopenharmony_ci#include <net/ndisc.h> 4262306a36Sopenharmony_ci#include <net/ip6_route.h> 4362306a36Sopenharmony_ci#include <net/addrconf.h> 4462306a36Sopenharmony_ci#include <net/xfrm.h> 4562306a36Sopenharmony_ci#include <net/inet_ecn.h> 4662306a36Sopenharmony_ci#include <net/dst_metadata.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic void ip6_rcv_finish_core(struct net *net, struct sock *sk, 4962306a36Sopenharmony_ci struct sk_buff *skb) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci if (READ_ONCE(net->ipv4.sysctl_ip_early_demux) && 5262306a36Sopenharmony_ci !skb_dst(skb) && !skb->sk) { 5362306a36Sopenharmony_ci switch (ipv6_hdr(skb)->nexthdr) { 5462306a36Sopenharmony_ci case IPPROTO_TCP: 5562306a36Sopenharmony_ci if (READ_ONCE(net->ipv4.sysctl_tcp_early_demux)) 5662306a36Sopenharmony_ci tcp_v6_early_demux(skb); 5762306a36Sopenharmony_ci break; 5862306a36Sopenharmony_ci case IPPROTO_UDP: 5962306a36Sopenharmony_ci if (READ_ONCE(net->ipv4.sysctl_udp_early_demux)) 6062306a36Sopenharmony_ci udp_v6_early_demux(skb); 6162306a36Sopenharmony_ci break; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (!skb_valid_dst(skb)) 6662306a36Sopenharmony_ci ip6_route_input(skb); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ciint ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci /* if ingress device is enslaved to an L3 master device pass the 7262306a36Sopenharmony_ci * skb to its handler for processing 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci skb = l3mdev_ip6_rcv(skb); 7562306a36Sopenharmony_ci if (!skb) 7662306a36Sopenharmony_ci return NET_RX_SUCCESS; 7762306a36Sopenharmony_ci ip6_rcv_finish_core(net, sk, skb); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return dst_input(skb); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic void ip6_sublist_rcv_finish(struct list_head *head) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct sk_buff *skb, *next; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci list_for_each_entry_safe(skb, next, head, list) { 8762306a36Sopenharmony_ci skb_list_del_init(skb); 8862306a36Sopenharmony_ci dst_input(skb); 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic bool ip6_can_use_hint(const struct sk_buff *skb, 9362306a36Sopenharmony_ci const struct sk_buff *hint) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci return hint && !skb_dst(skb) && 9662306a36Sopenharmony_ci ipv6_addr_equal(&ipv6_hdr(hint)->daddr, &ipv6_hdr(skb)->daddr); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic struct sk_buff *ip6_extract_route_hint(const struct net *net, 10062306a36Sopenharmony_ci struct sk_buff *skb) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci if (fib6_routes_require_src(net) || fib6_has_custom_rules(net) || 10362306a36Sopenharmony_ci IP6CB(skb)->flags & IP6SKB_MULTIPATH) 10462306a36Sopenharmony_ci return NULL; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return skb; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void ip6_list_rcv_finish(struct net *net, struct sock *sk, 11062306a36Sopenharmony_ci struct list_head *head) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct sk_buff *skb, *next, *hint = NULL; 11362306a36Sopenharmony_ci struct dst_entry *curr_dst = NULL; 11462306a36Sopenharmony_ci struct list_head sublist; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci INIT_LIST_HEAD(&sublist); 11762306a36Sopenharmony_ci list_for_each_entry_safe(skb, next, head, list) { 11862306a36Sopenharmony_ci struct dst_entry *dst; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci skb_list_del_init(skb); 12162306a36Sopenharmony_ci /* if ingress device is enslaved to an L3 master device pass the 12262306a36Sopenharmony_ci * skb to its handler for processing 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci skb = l3mdev_ip6_rcv(skb); 12562306a36Sopenharmony_ci if (!skb) 12662306a36Sopenharmony_ci continue; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (ip6_can_use_hint(skb, hint)) 12962306a36Sopenharmony_ci skb_dst_copy(skb, hint); 13062306a36Sopenharmony_ci else 13162306a36Sopenharmony_ci ip6_rcv_finish_core(net, sk, skb); 13262306a36Sopenharmony_ci dst = skb_dst(skb); 13362306a36Sopenharmony_ci if (curr_dst != dst) { 13462306a36Sopenharmony_ci hint = ip6_extract_route_hint(net, skb); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* dispatch old sublist */ 13762306a36Sopenharmony_ci if (!list_empty(&sublist)) 13862306a36Sopenharmony_ci ip6_sublist_rcv_finish(&sublist); 13962306a36Sopenharmony_ci /* start new sublist */ 14062306a36Sopenharmony_ci INIT_LIST_HEAD(&sublist); 14162306a36Sopenharmony_ci curr_dst = dst; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci list_add_tail(&skb->list, &sublist); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci /* dispatch final sublist */ 14662306a36Sopenharmony_ci ip6_sublist_rcv_finish(&sublist); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, 15062306a36Sopenharmony_ci struct net *net) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci enum skb_drop_reason reason; 15362306a36Sopenharmony_ci const struct ipv6hdr *hdr; 15462306a36Sopenharmony_ci u32 pkt_len; 15562306a36Sopenharmony_ci struct inet6_dev *idev; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (skb->pkt_type == PACKET_OTHERHOST) { 15862306a36Sopenharmony_ci dev_core_stats_rx_otherhost_dropped_inc(skb->dev); 15962306a36Sopenharmony_ci kfree_skb_reason(skb, SKB_DROP_REASON_OTHERHOST); 16062306a36Sopenharmony_ci return NULL; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci rcu_read_lock(); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci idev = __in6_dev_get(skb->dev); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci __IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_IN, skb->len); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci SKB_DR_SET(reason, NOT_SPECIFIED); 17062306a36Sopenharmony_ci if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || 17162306a36Sopenharmony_ci !idev || unlikely(idev->cnf.disable_ipv6)) { 17262306a36Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); 17362306a36Sopenharmony_ci if (idev && unlikely(idev->cnf.disable_ipv6)) 17462306a36Sopenharmony_ci SKB_DR_SET(reason, IPV6DISABLED); 17562306a36Sopenharmony_ci goto drop; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* 18162306a36Sopenharmony_ci * Store incoming device index. When the packet will 18262306a36Sopenharmony_ci * be queued, we cannot refer to skb->dev anymore. 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci * BTW, when we send a packet for our own local address on a 18562306a36Sopenharmony_ci * non-loopback interface (e.g. ethX), it is being delivered 18662306a36Sopenharmony_ci * via the loopback interface (lo) here; skb->dev = loopback_dev. 18762306a36Sopenharmony_ci * It, however, should be considered as if it is being 18862306a36Sopenharmony_ci * arrived via the sending interface (ethX), because of the 18962306a36Sopenharmony_ci * nature of scoping architecture. --yoshfuji 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ci IP6CB(skb)->iif = skb_valid_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) 19462306a36Sopenharmony_ci goto err; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci hdr = ipv6_hdr(skb); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (hdr->version != 6) { 19962306a36Sopenharmony_ci SKB_DR_SET(reason, UNHANDLED_PROTO); 20062306a36Sopenharmony_ci goto err; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci __IP6_ADD_STATS(net, idev, 20462306a36Sopenharmony_ci IPSTATS_MIB_NOECTPKTS + 20562306a36Sopenharmony_ci (ipv6_get_dsfield(hdr) & INET_ECN_MASK), 20662306a36Sopenharmony_ci max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs)); 20762306a36Sopenharmony_ci /* 20862306a36Sopenharmony_ci * RFC4291 2.5.3 20962306a36Sopenharmony_ci * The loopback address must not be used as the source address in IPv6 21062306a36Sopenharmony_ci * packets that are sent outside of a single node. [..] 21162306a36Sopenharmony_ci * A packet received on an interface with a destination address 21262306a36Sopenharmony_ci * of loopback must be dropped. 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_ci if ((ipv6_addr_loopback(&hdr->saddr) || 21562306a36Sopenharmony_ci ipv6_addr_loopback(&hdr->daddr)) && 21662306a36Sopenharmony_ci !(dev->flags & IFF_LOOPBACK) && 21762306a36Sopenharmony_ci !netif_is_l3_master(dev)) 21862306a36Sopenharmony_ci goto err; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* RFC4291 Errata ID: 3480 22162306a36Sopenharmony_ci * Interface-Local scope spans only a single interface on a 22262306a36Sopenharmony_ci * node and is useful only for loopback transmission of 22362306a36Sopenharmony_ci * multicast. Packets with interface-local scope received 22462306a36Sopenharmony_ci * from another node must be discarded. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci if (!(skb->pkt_type == PACKET_LOOPBACK || 22762306a36Sopenharmony_ci dev->flags & IFF_LOOPBACK) && 22862306a36Sopenharmony_ci ipv6_addr_is_multicast(&hdr->daddr) && 22962306a36Sopenharmony_ci IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1) 23062306a36Sopenharmony_ci goto err; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* If enabled, drop unicast packets that were encapsulated in link-layer 23362306a36Sopenharmony_ci * multicast or broadcast to protected against the so-called "hole-196" 23462306a36Sopenharmony_ci * attack in 802.11 wireless. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci if (!ipv6_addr_is_multicast(&hdr->daddr) && 23762306a36Sopenharmony_ci (skb->pkt_type == PACKET_BROADCAST || 23862306a36Sopenharmony_ci skb->pkt_type == PACKET_MULTICAST) && 23962306a36Sopenharmony_ci idev->cnf.drop_unicast_in_l2_multicast) { 24062306a36Sopenharmony_ci SKB_DR_SET(reason, UNICAST_IN_L2_MULTICAST); 24162306a36Sopenharmony_ci goto err; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* RFC4291 2.7 24562306a36Sopenharmony_ci * Nodes must not originate a packet to a multicast address whose scope 24662306a36Sopenharmony_ci * field contains the reserved value 0; if such a packet is received, it 24762306a36Sopenharmony_ci * must be silently dropped. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_ci if (ipv6_addr_is_multicast(&hdr->daddr) && 25062306a36Sopenharmony_ci IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0) 25162306a36Sopenharmony_ci goto err; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* 25462306a36Sopenharmony_ci * RFC4291 2.7 25562306a36Sopenharmony_ci * Multicast addresses must not be used as source addresses in IPv6 25662306a36Sopenharmony_ci * packets or appear in any Routing header. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci if (ipv6_addr_is_multicast(&hdr->saddr)) 25962306a36Sopenharmony_ci goto err; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci skb->transport_header = skb->network_header + sizeof(*hdr); 26262306a36Sopenharmony_ci IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci pkt_len = ntohs(hdr->payload_len); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* pkt_len may be zero if Jumbo payload option is present */ 26762306a36Sopenharmony_ci if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { 26862306a36Sopenharmony_ci if (pkt_len + sizeof(struct ipv6hdr) > skb->len) { 26962306a36Sopenharmony_ci __IP6_INC_STATS(net, 27062306a36Sopenharmony_ci idev, IPSTATS_MIB_INTRUNCATEDPKTS); 27162306a36Sopenharmony_ci SKB_DR_SET(reason, PKT_TOO_SMALL); 27262306a36Sopenharmony_ci goto drop; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) 27562306a36Sopenharmony_ci goto err; 27662306a36Sopenharmony_ci hdr = ipv6_hdr(skb); 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (hdr->nexthdr == NEXTHDR_HOP) { 28062306a36Sopenharmony_ci if (ipv6_parse_hopopts(skb) < 0) { 28162306a36Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 28262306a36Sopenharmony_ci rcu_read_unlock(); 28362306a36Sopenharmony_ci return NULL; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci rcu_read_unlock(); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* Must drop socket now because of tproxy. */ 29062306a36Sopenharmony_ci if (!skb_sk_is_prefetched(skb)) 29162306a36Sopenharmony_ci skb_orphan(skb); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return skb; 29462306a36Sopenharmony_cierr: 29562306a36Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 29662306a36Sopenharmony_ci SKB_DR_OR(reason, IP_INHDR); 29762306a36Sopenharmony_cidrop: 29862306a36Sopenharmony_ci rcu_read_unlock(); 29962306a36Sopenharmony_ci kfree_skb_reason(skb, reason); 30062306a36Sopenharmony_ci return NULL; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ciint ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci skb = ip6_rcv_core(skb, dev, net); 30862306a36Sopenharmony_ci if (skb == NULL) 30962306a36Sopenharmony_ci return NET_RX_DROP; 31062306a36Sopenharmony_ci return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, 31162306a36Sopenharmony_ci net, NULL, skb, dev, NULL, 31262306a36Sopenharmony_ci ip6_rcv_finish); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic void ip6_sublist_rcv(struct list_head *head, struct net_device *dev, 31662306a36Sopenharmony_ci struct net *net) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci NF_HOOK_LIST(NFPROTO_IPV6, NF_INET_PRE_ROUTING, net, NULL, 31962306a36Sopenharmony_ci head, dev, NULL, ip6_rcv_finish); 32062306a36Sopenharmony_ci ip6_list_rcv_finish(net, NULL, head); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci/* Receive a list of IPv6 packets */ 32462306a36Sopenharmony_civoid ipv6_list_rcv(struct list_head *head, struct packet_type *pt, 32562306a36Sopenharmony_ci struct net_device *orig_dev) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct net_device *curr_dev = NULL; 32862306a36Sopenharmony_ci struct net *curr_net = NULL; 32962306a36Sopenharmony_ci struct sk_buff *skb, *next; 33062306a36Sopenharmony_ci struct list_head sublist; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci INIT_LIST_HEAD(&sublist); 33362306a36Sopenharmony_ci list_for_each_entry_safe(skb, next, head, list) { 33462306a36Sopenharmony_ci struct net_device *dev = skb->dev; 33562306a36Sopenharmony_ci struct net *net = dev_net(dev); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci skb_list_del_init(skb); 33862306a36Sopenharmony_ci skb = ip6_rcv_core(skb, dev, net); 33962306a36Sopenharmony_ci if (skb == NULL) 34062306a36Sopenharmony_ci continue; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (curr_dev != dev || curr_net != net) { 34362306a36Sopenharmony_ci /* dispatch old sublist */ 34462306a36Sopenharmony_ci if (!list_empty(&sublist)) 34562306a36Sopenharmony_ci ip6_sublist_rcv(&sublist, curr_dev, curr_net); 34662306a36Sopenharmony_ci /* start new sublist */ 34762306a36Sopenharmony_ci INIT_LIST_HEAD(&sublist); 34862306a36Sopenharmony_ci curr_dev = dev; 34962306a36Sopenharmony_ci curr_net = net; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci list_add_tail(&skb->list, &sublist); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci /* dispatch final sublist */ 35462306a36Sopenharmony_ci if (!list_empty(&sublist)) 35562306a36Sopenharmony_ci ip6_sublist_rcv(&sublist, curr_dev, curr_net); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(int tcp_v6_rcv(struct sk_buff *)); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/* 36162306a36Sopenharmony_ci * Deliver the packet to the host 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_civoid ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, 36462306a36Sopenharmony_ci bool have_final) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci const struct inet6_protocol *ipprot; 36762306a36Sopenharmony_ci struct inet6_dev *idev; 36862306a36Sopenharmony_ci unsigned int nhoff; 36962306a36Sopenharmony_ci SKB_DR(reason); 37062306a36Sopenharmony_ci bool raw; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* 37362306a36Sopenharmony_ci * Parse extension headers 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ciresubmit: 37762306a36Sopenharmony_ci idev = ip6_dst_idev(skb_dst(skb)); 37862306a36Sopenharmony_ci nhoff = IP6CB(skb)->nhoff; 37962306a36Sopenharmony_ci if (!have_final) { 38062306a36Sopenharmony_ci if (!pskb_pull(skb, skb_transport_offset(skb))) 38162306a36Sopenharmony_ci goto discard; 38262306a36Sopenharmony_ci nexthdr = skb_network_header(skb)[nhoff]; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ciresubmit_final: 38662306a36Sopenharmony_ci raw = raw6_local_deliver(skb, nexthdr); 38762306a36Sopenharmony_ci ipprot = rcu_dereference(inet6_protos[nexthdr]); 38862306a36Sopenharmony_ci if (ipprot) { 38962306a36Sopenharmony_ci int ret; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (have_final) { 39262306a36Sopenharmony_ci if (!(ipprot->flags & INET6_PROTO_FINAL)) { 39362306a36Sopenharmony_ci /* Once we've seen a final protocol don't 39462306a36Sopenharmony_ci * allow encapsulation on any non-final 39562306a36Sopenharmony_ci * ones. This allows foo in UDP encapsulation 39662306a36Sopenharmony_ci * to work. 39762306a36Sopenharmony_ci */ 39862306a36Sopenharmony_ci goto discard; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci } else if (ipprot->flags & INET6_PROTO_FINAL) { 40162306a36Sopenharmony_ci const struct ipv6hdr *hdr; 40262306a36Sopenharmony_ci int sdif = inet6_sdif(skb); 40362306a36Sopenharmony_ci struct net_device *dev; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* Only do this once for first final protocol */ 40662306a36Sopenharmony_ci have_final = true; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci skb_postpull_rcsum(skb, skb_network_header(skb), 41062306a36Sopenharmony_ci skb_network_header_len(skb)); 41162306a36Sopenharmony_ci hdr = ipv6_hdr(skb); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* skb->dev passed may be master dev for vrfs. */ 41462306a36Sopenharmony_ci if (sdif) { 41562306a36Sopenharmony_ci dev = dev_get_by_index_rcu(net, sdif); 41662306a36Sopenharmony_ci if (!dev) 41762306a36Sopenharmony_ci goto discard; 41862306a36Sopenharmony_ci } else { 41962306a36Sopenharmony_ci dev = skb->dev; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (ipv6_addr_is_multicast(&hdr->daddr) && 42362306a36Sopenharmony_ci !ipv6_chk_mcast_addr(dev, &hdr->daddr, 42462306a36Sopenharmony_ci &hdr->saddr) && 42562306a36Sopenharmony_ci !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) { 42662306a36Sopenharmony_ci SKB_DR_SET(reason, IP_INADDRERRORS); 42762306a36Sopenharmony_ci goto discard; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci if (!(ipprot->flags & INET6_PROTO_NOPOLICY)) { 43162306a36Sopenharmony_ci if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { 43262306a36Sopenharmony_ci SKB_DR_SET(reason, XFRM_POLICY); 43362306a36Sopenharmony_ci goto discard; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci nf_reset_ct(skb); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci ret = INDIRECT_CALL_2(ipprot->handler, tcp_v6_rcv, udpv6_rcv, 43962306a36Sopenharmony_ci skb); 44062306a36Sopenharmony_ci if (ret > 0) { 44162306a36Sopenharmony_ci if (ipprot->flags & INET6_PROTO_FINAL) { 44262306a36Sopenharmony_ci /* Not an extension header, most likely UDP 44362306a36Sopenharmony_ci * encapsulation. Use return value as nexthdr 44462306a36Sopenharmony_ci * protocol not nhoff (which presumably is 44562306a36Sopenharmony_ci * not set by handler). 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_ci nexthdr = ret; 44862306a36Sopenharmony_ci goto resubmit_final; 44962306a36Sopenharmony_ci } else { 45062306a36Sopenharmony_ci goto resubmit; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci } else if (ret == 0) { 45362306a36Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDELIVERS); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci } else { 45662306a36Sopenharmony_ci if (!raw) { 45762306a36Sopenharmony_ci if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { 45862306a36Sopenharmony_ci __IP6_INC_STATS(net, idev, 45962306a36Sopenharmony_ci IPSTATS_MIB_INUNKNOWNPROTOS); 46062306a36Sopenharmony_ci icmpv6_send(skb, ICMPV6_PARAMPROB, 46162306a36Sopenharmony_ci ICMPV6_UNK_NEXTHDR, nhoff); 46262306a36Sopenharmony_ci SKB_DR_SET(reason, IP_NOPROTO); 46362306a36Sopenharmony_ci } else { 46462306a36Sopenharmony_ci SKB_DR_SET(reason, XFRM_POLICY); 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci kfree_skb_reason(skb, reason); 46762306a36Sopenharmony_ci } else { 46862306a36Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDELIVERS); 46962306a36Sopenharmony_ci consume_skb(skb); 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci return; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cidiscard: 47562306a36Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); 47662306a36Sopenharmony_ci kfree_skb_reason(skb, reason); 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic int ip6_input_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci skb_clear_delivery_time(skb); 48262306a36Sopenharmony_ci rcu_read_lock(); 48362306a36Sopenharmony_ci ip6_protocol_deliver_rcu(net, skb, 0, false); 48462306a36Sopenharmony_ci rcu_read_unlock(); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ciint ip6_input(struct sk_buff *skb) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, 49362306a36Sopenharmony_ci dev_net(skb->dev), NULL, skb, skb->dev, NULL, 49462306a36Sopenharmony_ci ip6_input_finish); 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ip6_input); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ciint ip6_mc_input(struct sk_buff *skb) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci int sdif = inet6_sdif(skb); 50162306a36Sopenharmony_ci const struct ipv6hdr *hdr; 50262306a36Sopenharmony_ci struct net_device *dev; 50362306a36Sopenharmony_ci bool deliver; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci __IP6_UPD_PO_STATS(dev_net(skb_dst(skb)->dev), 50662306a36Sopenharmony_ci __in6_dev_get_safely(skb->dev), IPSTATS_MIB_INMCAST, 50762306a36Sopenharmony_ci skb->len); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* skb->dev passed may be master dev for vrfs. */ 51062306a36Sopenharmony_ci if (sdif) { 51162306a36Sopenharmony_ci rcu_read_lock(); 51262306a36Sopenharmony_ci dev = dev_get_by_index_rcu(dev_net(skb->dev), sdif); 51362306a36Sopenharmony_ci if (!dev) { 51462306a36Sopenharmony_ci rcu_read_unlock(); 51562306a36Sopenharmony_ci kfree_skb(skb); 51662306a36Sopenharmony_ci return -ENODEV; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci } else { 51962306a36Sopenharmony_ci dev = skb->dev; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci hdr = ipv6_hdr(skb); 52362306a36Sopenharmony_ci deliver = ipv6_chk_mcast_addr(dev, &hdr->daddr, NULL); 52462306a36Sopenharmony_ci if (sdif) 52562306a36Sopenharmony_ci rcu_read_unlock(); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci#ifdef CONFIG_IPV6_MROUTE 52862306a36Sopenharmony_ci /* 52962306a36Sopenharmony_ci * IPv6 multicast router mode is now supported ;) 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_ci if (atomic_read(&dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding) && 53262306a36Sopenharmony_ci !(ipv6_addr_type(&hdr->daddr) & 53362306a36Sopenharmony_ci (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)) && 53462306a36Sopenharmony_ci likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) { 53562306a36Sopenharmony_ci /* 53662306a36Sopenharmony_ci * Okay, we try to forward - split and duplicate 53762306a36Sopenharmony_ci * packets. 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci struct sk_buff *skb2; 54062306a36Sopenharmony_ci struct inet6_skb_parm *opt = IP6CB(skb); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* Check for MLD */ 54362306a36Sopenharmony_ci if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) { 54462306a36Sopenharmony_ci /* Check if this is a mld message */ 54562306a36Sopenharmony_ci u8 nexthdr = hdr->nexthdr; 54662306a36Sopenharmony_ci __be16 frag_off; 54762306a36Sopenharmony_ci int offset; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* Check if the value of Router Alert 55062306a36Sopenharmony_ci * is for MLD (0x0000). 55162306a36Sopenharmony_ci */ 55262306a36Sopenharmony_ci if (opt->ra == htons(IPV6_OPT_ROUTERALERT_MLD)) { 55362306a36Sopenharmony_ci deliver = false; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (!ipv6_ext_hdr(nexthdr)) { 55662306a36Sopenharmony_ci /* BUG */ 55762306a36Sopenharmony_ci goto out; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci offset = ipv6_skip_exthdr(skb, sizeof(*hdr), 56062306a36Sopenharmony_ci &nexthdr, &frag_off); 56162306a36Sopenharmony_ci if (offset < 0) 56262306a36Sopenharmony_ci goto out; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (ipv6_is_mld(skb, nexthdr, offset)) 56562306a36Sopenharmony_ci deliver = true; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci goto out; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci /* unknown RA - process it normally */ 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (deliver) 57362306a36Sopenharmony_ci skb2 = skb_clone(skb, GFP_ATOMIC); 57462306a36Sopenharmony_ci else { 57562306a36Sopenharmony_ci skb2 = skb; 57662306a36Sopenharmony_ci skb = NULL; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (skb2) { 58062306a36Sopenharmony_ci ip6_mr_input(skb2); 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ciout: 58462306a36Sopenharmony_ci#endif 58562306a36Sopenharmony_ci if (likely(deliver)) 58662306a36Sopenharmony_ci ip6_input(skb); 58762306a36Sopenharmony_ci else { 58862306a36Sopenharmony_ci /* discard */ 58962306a36Sopenharmony_ci kfree_skb(skb); 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci} 594