18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * IPv6 input 48c2ecf20Sopenharmony_ci * Linux INET6 implementation 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Authors: 78c2ecf20Sopenharmony_ci * Pedro Roque <roque@di.fc.ul.pt> 88c2ecf20Sopenharmony_ci * Ian P. Morris <I.P.Morris@soton.ac.uk> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Based in linux/net/ipv4/ip_input.c 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci/* Changes 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Mitsuru KANDA @USAGI and 158c2ecf20Sopenharmony_ci * YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs(). 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/errno.h> 198c2ecf20Sopenharmony_ci#include <linux/types.h> 208c2ecf20Sopenharmony_ci#include <linux/socket.h> 218c2ecf20Sopenharmony_ci#include <linux/sockios.h> 228c2ecf20Sopenharmony_ci#include <linux/net.h> 238c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 248c2ecf20Sopenharmony_ci#include <linux/in6.h> 258c2ecf20Sopenharmony_ci#include <linux/icmpv6.h> 268c2ecf20Sopenharmony_ci#include <linux/mroute6.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <linux/indirect_call_wrapper.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/netfilter.h> 318c2ecf20Sopenharmony_ci#include <linux/netfilter_ipv6.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <net/sock.h> 348c2ecf20Sopenharmony_ci#include <net/snmp.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <net/ipv6.h> 378c2ecf20Sopenharmony_ci#include <net/protocol.h> 388c2ecf20Sopenharmony_ci#include <net/transp_v6.h> 398c2ecf20Sopenharmony_ci#include <net/rawv6.h> 408c2ecf20Sopenharmony_ci#include <net/ndisc.h> 418c2ecf20Sopenharmony_ci#include <net/ip6_route.h> 428c2ecf20Sopenharmony_ci#include <net/addrconf.h> 438c2ecf20Sopenharmony_ci#include <net/xfrm.h> 448c2ecf20Sopenharmony_ci#include <net/inet_ecn.h> 458c2ecf20Sopenharmony_ci#include <net/dst_metadata.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_civoid udp_v6_early_demux(struct sk_buff *); 488c2ecf20Sopenharmony_civoid tcp_v6_early_demux(struct sk_buff *); 498c2ecf20Sopenharmony_cistatic void ip6_rcv_finish_core(struct net *net, struct sock *sk, 508c2ecf20Sopenharmony_ci struct sk_buff *skb) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci if (READ_ONCE(net->ipv4.sysctl_ip_early_demux) && 538c2ecf20Sopenharmony_ci !skb_dst(skb) && !skb->sk) { 548c2ecf20Sopenharmony_ci switch (ipv6_hdr(skb)->nexthdr) { 558c2ecf20Sopenharmony_ci case IPPROTO_TCP: 568c2ecf20Sopenharmony_ci if (READ_ONCE(net->ipv4.sysctl_tcp_early_demux)) 578c2ecf20Sopenharmony_ci tcp_v6_early_demux(skb); 588c2ecf20Sopenharmony_ci break; 598c2ecf20Sopenharmony_ci case IPPROTO_UDP: 608c2ecf20Sopenharmony_ci if (READ_ONCE(net->ipv4.sysctl_udp_early_demux)) 618c2ecf20Sopenharmony_ci udp_v6_early_demux(skb); 628c2ecf20Sopenharmony_ci break; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (!skb_valid_dst(skb)) 678c2ecf20Sopenharmony_ci ip6_route_input(skb); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ciint ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci /* if ingress device is enslaved to an L3 master device pass the 738c2ecf20Sopenharmony_ci * skb to its handler for processing 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci skb = l3mdev_ip6_rcv(skb); 768c2ecf20Sopenharmony_ci if (!skb) 778c2ecf20Sopenharmony_ci return NET_RX_SUCCESS; 788c2ecf20Sopenharmony_ci ip6_rcv_finish_core(net, sk, skb); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return dst_input(skb); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void ip6_sublist_rcv_finish(struct list_head *head) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct sk_buff *skb, *next; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci list_for_each_entry_safe(skb, next, head, list) { 888c2ecf20Sopenharmony_ci skb_list_del_init(skb); 898c2ecf20Sopenharmony_ci dst_input(skb); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic bool ip6_can_use_hint(const struct sk_buff *skb, 948c2ecf20Sopenharmony_ci const struct sk_buff *hint) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci return hint && !skb_dst(skb) && 978c2ecf20Sopenharmony_ci ipv6_addr_equal(&ipv6_hdr(hint)->daddr, &ipv6_hdr(skb)->daddr); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic struct sk_buff *ip6_extract_route_hint(const struct net *net, 1018c2ecf20Sopenharmony_ci struct sk_buff *skb) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci if (fib6_routes_require_src(net) || fib6_has_custom_rules(net)) 1048c2ecf20Sopenharmony_ci return NULL; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return skb; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void ip6_list_rcv_finish(struct net *net, struct sock *sk, 1108c2ecf20Sopenharmony_ci struct list_head *head) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct sk_buff *skb, *next, *hint = NULL; 1138c2ecf20Sopenharmony_ci struct dst_entry *curr_dst = NULL; 1148c2ecf20Sopenharmony_ci struct list_head sublist; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sublist); 1178c2ecf20Sopenharmony_ci list_for_each_entry_safe(skb, next, head, list) { 1188c2ecf20Sopenharmony_ci struct dst_entry *dst; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci skb_list_del_init(skb); 1218c2ecf20Sopenharmony_ci /* if ingress device is enslaved to an L3 master device pass the 1228c2ecf20Sopenharmony_ci * skb to its handler for processing 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci skb = l3mdev_ip6_rcv(skb); 1258c2ecf20Sopenharmony_ci if (!skb) 1268c2ecf20Sopenharmony_ci continue; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (ip6_can_use_hint(skb, hint)) 1298c2ecf20Sopenharmony_ci skb_dst_copy(skb, hint); 1308c2ecf20Sopenharmony_ci else 1318c2ecf20Sopenharmony_ci ip6_rcv_finish_core(net, sk, skb); 1328c2ecf20Sopenharmony_ci dst = skb_dst(skb); 1338c2ecf20Sopenharmony_ci if (curr_dst != dst) { 1348c2ecf20Sopenharmony_ci hint = ip6_extract_route_hint(net, skb); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* dispatch old sublist */ 1378c2ecf20Sopenharmony_ci if (!list_empty(&sublist)) 1388c2ecf20Sopenharmony_ci ip6_sublist_rcv_finish(&sublist); 1398c2ecf20Sopenharmony_ci /* start new sublist */ 1408c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sublist); 1418c2ecf20Sopenharmony_ci curr_dst = dst; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci list_add_tail(&skb->list, &sublist); 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci /* dispatch final sublist */ 1468c2ecf20Sopenharmony_ci ip6_sublist_rcv_finish(&sublist); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, 1508c2ecf20Sopenharmony_ci struct net *net) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci const struct ipv6hdr *hdr; 1538c2ecf20Sopenharmony_ci u32 pkt_len; 1548c2ecf20Sopenharmony_ci struct inet6_dev *idev; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (skb->pkt_type == PACKET_OTHERHOST) { 1578c2ecf20Sopenharmony_ci kfree_skb(skb); 1588c2ecf20Sopenharmony_ci return NULL; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci rcu_read_lock(); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci idev = __in6_dev_get(skb->dev); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci __IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_IN, skb->len); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || 1688c2ecf20Sopenharmony_ci !idev || unlikely(idev->cnf.disable_ipv6)) { 1698c2ecf20Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); 1708c2ecf20Sopenharmony_ci goto drop; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* 1768c2ecf20Sopenharmony_ci * Store incoming device index. When the packet will 1778c2ecf20Sopenharmony_ci * be queued, we cannot refer to skb->dev anymore. 1788c2ecf20Sopenharmony_ci * 1798c2ecf20Sopenharmony_ci * BTW, when we send a packet for our own local address on a 1808c2ecf20Sopenharmony_ci * non-loopback interface (e.g. ethX), it is being delivered 1818c2ecf20Sopenharmony_ci * via the loopback interface (lo) here; skb->dev = loopback_dev. 1828c2ecf20Sopenharmony_ci * It, however, should be considered as if it is being 1838c2ecf20Sopenharmony_ci * arrived via the sending interface (ethX), because of the 1848c2ecf20Sopenharmony_ci * nature of scoping architecture. --yoshfuji 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci IP6CB(skb)->iif = skb_valid_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) 1898c2ecf20Sopenharmony_ci goto err; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci hdr = ipv6_hdr(skb); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (hdr->version != 6) 1948c2ecf20Sopenharmony_ci goto err; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci __IP6_ADD_STATS(net, idev, 1978c2ecf20Sopenharmony_ci IPSTATS_MIB_NOECTPKTS + 1988c2ecf20Sopenharmony_ci (ipv6_get_dsfield(hdr) & INET_ECN_MASK), 1998c2ecf20Sopenharmony_ci max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs)); 2008c2ecf20Sopenharmony_ci /* 2018c2ecf20Sopenharmony_ci * RFC4291 2.5.3 2028c2ecf20Sopenharmony_ci * The loopback address must not be used as the source address in IPv6 2038c2ecf20Sopenharmony_ci * packets that are sent outside of a single node. [..] 2048c2ecf20Sopenharmony_ci * A packet received on an interface with a destination address 2058c2ecf20Sopenharmony_ci * of loopback must be dropped. 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_ci if ((ipv6_addr_loopback(&hdr->saddr) || 2088c2ecf20Sopenharmony_ci ipv6_addr_loopback(&hdr->daddr)) && 2098c2ecf20Sopenharmony_ci !(dev->flags & IFF_LOOPBACK) && 2108c2ecf20Sopenharmony_ci !netif_is_l3_master(dev)) 2118c2ecf20Sopenharmony_ci goto err; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* RFC4291 Errata ID: 3480 2148c2ecf20Sopenharmony_ci * Interface-Local scope spans only a single interface on a 2158c2ecf20Sopenharmony_ci * node and is useful only for loopback transmission of 2168c2ecf20Sopenharmony_ci * multicast. Packets with interface-local scope received 2178c2ecf20Sopenharmony_ci * from another node must be discarded. 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci if (!(skb->pkt_type == PACKET_LOOPBACK || 2208c2ecf20Sopenharmony_ci dev->flags & IFF_LOOPBACK) && 2218c2ecf20Sopenharmony_ci ipv6_addr_is_multicast(&hdr->daddr) && 2228c2ecf20Sopenharmony_ci IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1) 2238c2ecf20Sopenharmony_ci goto err; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* If enabled, drop unicast packets that were encapsulated in link-layer 2268c2ecf20Sopenharmony_ci * multicast or broadcast to protected against the so-called "hole-196" 2278c2ecf20Sopenharmony_ci * attack in 802.11 wireless. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci if (!ipv6_addr_is_multicast(&hdr->daddr) && 2308c2ecf20Sopenharmony_ci (skb->pkt_type == PACKET_BROADCAST || 2318c2ecf20Sopenharmony_ci skb->pkt_type == PACKET_MULTICAST) && 2328c2ecf20Sopenharmony_ci idev->cnf.drop_unicast_in_l2_multicast) 2338c2ecf20Sopenharmony_ci goto err; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* RFC4291 2.7 2368c2ecf20Sopenharmony_ci * Nodes must not originate a packet to a multicast address whose scope 2378c2ecf20Sopenharmony_ci * field contains the reserved value 0; if such a packet is received, it 2388c2ecf20Sopenharmony_ci * must be silently dropped. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci if (ipv6_addr_is_multicast(&hdr->daddr) && 2418c2ecf20Sopenharmony_ci IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0) 2428c2ecf20Sopenharmony_ci goto err; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* 2458c2ecf20Sopenharmony_ci * RFC4291 2.7 2468c2ecf20Sopenharmony_ci * Multicast addresses must not be used as source addresses in IPv6 2478c2ecf20Sopenharmony_ci * packets or appear in any Routing header. 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_ci if (ipv6_addr_is_multicast(&hdr->saddr)) 2508c2ecf20Sopenharmony_ci goto err; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci skb->transport_header = skb->network_header + sizeof(*hdr); 2538c2ecf20Sopenharmony_ci IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci pkt_len = ntohs(hdr->payload_len); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* pkt_len may be zero if Jumbo payload option is present */ 2588c2ecf20Sopenharmony_ci if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { 2598c2ecf20Sopenharmony_ci if (pkt_len + sizeof(struct ipv6hdr) > skb->len) { 2608c2ecf20Sopenharmony_ci __IP6_INC_STATS(net, 2618c2ecf20Sopenharmony_ci idev, IPSTATS_MIB_INTRUNCATEDPKTS); 2628c2ecf20Sopenharmony_ci goto drop; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { 2658c2ecf20Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 2668c2ecf20Sopenharmony_ci goto drop; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci hdr = ipv6_hdr(skb); 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (hdr->nexthdr == NEXTHDR_HOP) { 2728c2ecf20Sopenharmony_ci if (ipv6_parse_hopopts(skb) < 0) { 2738c2ecf20Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 2748c2ecf20Sopenharmony_ci rcu_read_unlock(); 2758c2ecf20Sopenharmony_ci return NULL; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci rcu_read_unlock(); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* Must drop socket now because of tproxy. */ 2828c2ecf20Sopenharmony_ci if (!skb_sk_is_prefetched(skb)) 2838c2ecf20Sopenharmony_ci skb_orphan(skb); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci return skb; 2868c2ecf20Sopenharmony_cierr: 2878c2ecf20Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); 2888c2ecf20Sopenharmony_cidrop: 2898c2ecf20Sopenharmony_ci rcu_read_unlock(); 2908c2ecf20Sopenharmony_ci kfree_skb(skb); 2918c2ecf20Sopenharmony_ci return NULL; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciint ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct net *net = dev_net(skb->dev); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci skb = ip6_rcv_core(skb, dev, net); 2998c2ecf20Sopenharmony_ci if (skb == NULL) 3008c2ecf20Sopenharmony_ci return NET_RX_DROP; 3018c2ecf20Sopenharmony_ci return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, 3028c2ecf20Sopenharmony_ci net, NULL, skb, dev, NULL, 3038c2ecf20Sopenharmony_ci ip6_rcv_finish); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void ip6_sublist_rcv(struct list_head *head, struct net_device *dev, 3078c2ecf20Sopenharmony_ci struct net *net) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci NF_HOOK_LIST(NFPROTO_IPV6, NF_INET_PRE_ROUTING, net, NULL, 3108c2ecf20Sopenharmony_ci head, dev, NULL, ip6_rcv_finish); 3118c2ecf20Sopenharmony_ci ip6_list_rcv_finish(net, NULL, head); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/* Receive a list of IPv6 packets */ 3158c2ecf20Sopenharmony_civoid ipv6_list_rcv(struct list_head *head, struct packet_type *pt, 3168c2ecf20Sopenharmony_ci struct net_device *orig_dev) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct net_device *curr_dev = NULL; 3198c2ecf20Sopenharmony_ci struct net *curr_net = NULL; 3208c2ecf20Sopenharmony_ci struct sk_buff *skb, *next; 3218c2ecf20Sopenharmony_ci struct list_head sublist; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sublist); 3248c2ecf20Sopenharmony_ci list_for_each_entry_safe(skb, next, head, list) { 3258c2ecf20Sopenharmony_ci struct net_device *dev = skb->dev; 3268c2ecf20Sopenharmony_ci struct net *net = dev_net(dev); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci skb_list_del_init(skb); 3298c2ecf20Sopenharmony_ci skb = ip6_rcv_core(skb, dev, net); 3308c2ecf20Sopenharmony_ci if (skb == NULL) 3318c2ecf20Sopenharmony_ci continue; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (curr_dev != dev || curr_net != net) { 3348c2ecf20Sopenharmony_ci /* dispatch old sublist */ 3358c2ecf20Sopenharmony_ci if (!list_empty(&sublist)) 3368c2ecf20Sopenharmony_ci ip6_sublist_rcv(&sublist, curr_dev, curr_net); 3378c2ecf20Sopenharmony_ci /* start new sublist */ 3388c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sublist); 3398c2ecf20Sopenharmony_ci curr_dev = dev; 3408c2ecf20Sopenharmony_ci curr_net = net; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci list_add_tail(&skb->list, &sublist); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci /* dispatch final sublist */ 3458c2ecf20Sopenharmony_ci if (!list_empty(&sublist)) 3468c2ecf20Sopenharmony_ci ip6_sublist_rcv(&sublist, curr_dev, curr_net); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(int udpv6_rcv(struct sk_buff *)); 3508c2ecf20Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(int tcp_v6_rcv(struct sk_buff *)); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci/* 3538c2ecf20Sopenharmony_ci * Deliver the packet to the host 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_civoid ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, 3568c2ecf20Sopenharmony_ci bool have_final) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci const struct inet6_protocol *ipprot; 3598c2ecf20Sopenharmony_ci struct inet6_dev *idev; 3608c2ecf20Sopenharmony_ci unsigned int nhoff; 3618c2ecf20Sopenharmony_ci bool raw; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* 3648c2ecf20Sopenharmony_ci * Parse extension headers 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ciresubmit: 3688c2ecf20Sopenharmony_ci idev = ip6_dst_idev(skb_dst(skb)); 3698c2ecf20Sopenharmony_ci nhoff = IP6CB(skb)->nhoff; 3708c2ecf20Sopenharmony_ci if (!have_final) { 3718c2ecf20Sopenharmony_ci if (!pskb_pull(skb, skb_transport_offset(skb))) 3728c2ecf20Sopenharmony_ci goto discard; 3738c2ecf20Sopenharmony_ci nexthdr = skb_network_header(skb)[nhoff]; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ciresubmit_final: 3778c2ecf20Sopenharmony_ci raw = raw6_local_deliver(skb, nexthdr); 3788c2ecf20Sopenharmony_ci ipprot = rcu_dereference(inet6_protos[nexthdr]); 3798c2ecf20Sopenharmony_ci if (ipprot) { 3808c2ecf20Sopenharmony_ci int ret; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (have_final) { 3838c2ecf20Sopenharmony_ci if (!(ipprot->flags & INET6_PROTO_FINAL)) { 3848c2ecf20Sopenharmony_ci /* Once we've seen a final protocol don't 3858c2ecf20Sopenharmony_ci * allow encapsulation on any non-final 3868c2ecf20Sopenharmony_ci * ones. This allows foo in UDP encapsulation 3878c2ecf20Sopenharmony_ci * to work. 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ci goto discard; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci } else if (ipprot->flags & INET6_PROTO_FINAL) { 3928c2ecf20Sopenharmony_ci const struct ipv6hdr *hdr; 3938c2ecf20Sopenharmony_ci int sdif = inet6_sdif(skb); 3948c2ecf20Sopenharmony_ci struct net_device *dev; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* Only do this once for first final protocol */ 3978c2ecf20Sopenharmony_ci have_final = true; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* Free reference early: we don't need it any more, 4008c2ecf20Sopenharmony_ci and it may hold ip_conntrack module loaded 4018c2ecf20Sopenharmony_ci indefinitely. */ 4028c2ecf20Sopenharmony_ci nf_reset_ct(skb); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci skb_postpull_rcsum(skb, skb_network_header(skb), 4058c2ecf20Sopenharmony_ci skb_network_header_len(skb)); 4068c2ecf20Sopenharmony_ci hdr = ipv6_hdr(skb); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* skb->dev passed may be master dev for vrfs. */ 4098c2ecf20Sopenharmony_ci if (sdif) { 4108c2ecf20Sopenharmony_ci dev = dev_get_by_index_rcu(net, sdif); 4118c2ecf20Sopenharmony_ci if (!dev) 4128c2ecf20Sopenharmony_ci goto discard; 4138c2ecf20Sopenharmony_ci } else { 4148c2ecf20Sopenharmony_ci dev = skb->dev; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (ipv6_addr_is_multicast(&hdr->daddr) && 4188c2ecf20Sopenharmony_ci !ipv6_chk_mcast_addr(dev, &hdr->daddr, 4198c2ecf20Sopenharmony_ci &hdr->saddr) && 4208c2ecf20Sopenharmony_ci !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) 4218c2ecf20Sopenharmony_ci goto discard; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && 4248c2ecf20Sopenharmony_ci !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) 4258c2ecf20Sopenharmony_ci goto discard; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ret = INDIRECT_CALL_2(ipprot->handler, tcp_v6_rcv, udpv6_rcv, 4288c2ecf20Sopenharmony_ci skb); 4298c2ecf20Sopenharmony_ci if (ret > 0) { 4308c2ecf20Sopenharmony_ci if (ipprot->flags & INET6_PROTO_FINAL) { 4318c2ecf20Sopenharmony_ci /* Not an extension header, most likely UDP 4328c2ecf20Sopenharmony_ci * encapsulation. Use return value as nexthdr 4338c2ecf20Sopenharmony_ci * protocol not nhoff (which presumably is 4348c2ecf20Sopenharmony_ci * not set by handler). 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_ci nexthdr = ret; 4378c2ecf20Sopenharmony_ci goto resubmit_final; 4388c2ecf20Sopenharmony_ci } else { 4398c2ecf20Sopenharmony_ci goto resubmit; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci } else if (ret == 0) { 4428c2ecf20Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDELIVERS); 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci } else { 4458c2ecf20Sopenharmony_ci if (!raw) { 4468c2ecf20Sopenharmony_ci if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { 4478c2ecf20Sopenharmony_ci __IP6_INC_STATS(net, idev, 4488c2ecf20Sopenharmony_ci IPSTATS_MIB_INUNKNOWNPROTOS); 4498c2ecf20Sopenharmony_ci icmpv6_send(skb, ICMPV6_PARAMPROB, 4508c2ecf20Sopenharmony_ci ICMPV6_UNK_NEXTHDR, nhoff); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci kfree_skb(skb); 4538c2ecf20Sopenharmony_ci } else { 4548c2ecf20Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDELIVERS); 4558c2ecf20Sopenharmony_ci consume_skb(skb); 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci return; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cidiscard: 4618c2ecf20Sopenharmony_ci __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); 4628c2ecf20Sopenharmony_ci kfree_skb(skb); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int ip6_input_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci rcu_read_lock(); 4688c2ecf20Sopenharmony_ci ip6_protocol_deliver_rcu(net, skb, 0, false); 4698c2ecf20Sopenharmony_ci rcu_read_unlock(); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return 0; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ciint ip6_input(struct sk_buff *skb) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, 4788c2ecf20Sopenharmony_ci dev_net(skb->dev), NULL, skb, skb->dev, NULL, 4798c2ecf20Sopenharmony_ci ip6_input_finish); 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ip6_input); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ciint ip6_mc_input(struct sk_buff *skb) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci int sdif = inet6_sdif(skb); 4868c2ecf20Sopenharmony_ci const struct ipv6hdr *hdr; 4878c2ecf20Sopenharmony_ci struct net_device *dev; 4888c2ecf20Sopenharmony_ci bool deliver; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci __IP6_UPD_PO_STATS(dev_net(skb_dst(skb)->dev), 4918c2ecf20Sopenharmony_ci __in6_dev_get_safely(skb->dev), IPSTATS_MIB_INMCAST, 4928c2ecf20Sopenharmony_ci skb->len); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* skb->dev passed may be master dev for vrfs. */ 4958c2ecf20Sopenharmony_ci if (sdif) { 4968c2ecf20Sopenharmony_ci rcu_read_lock(); 4978c2ecf20Sopenharmony_ci dev = dev_get_by_index_rcu(dev_net(skb->dev), sdif); 4988c2ecf20Sopenharmony_ci if (!dev) { 4998c2ecf20Sopenharmony_ci rcu_read_unlock(); 5008c2ecf20Sopenharmony_ci kfree_skb(skb); 5018c2ecf20Sopenharmony_ci return -ENODEV; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci } else { 5048c2ecf20Sopenharmony_ci dev = skb->dev; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci hdr = ipv6_hdr(skb); 5088c2ecf20Sopenharmony_ci deliver = ipv6_chk_mcast_addr(dev, &hdr->daddr, NULL); 5098c2ecf20Sopenharmony_ci if (sdif) 5108c2ecf20Sopenharmony_ci rcu_read_unlock(); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci#ifdef CONFIG_IPV6_MROUTE 5138c2ecf20Sopenharmony_ci /* 5148c2ecf20Sopenharmony_ci * IPv6 multicast router mode is now supported ;) 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_ci if (atomic_read(&dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding) && 5178c2ecf20Sopenharmony_ci !(ipv6_addr_type(&hdr->daddr) & 5188c2ecf20Sopenharmony_ci (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)) && 5198c2ecf20Sopenharmony_ci likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) { 5208c2ecf20Sopenharmony_ci /* 5218c2ecf20Sopenharmony_ci * Okay, we try to forward - split and duplicate 5228c2ecf20Sopenharmony_ci * packets. 5238c2ecf20Sopenharmony_ci */ 5248c2ecf20Sopenharmony_ci struct sk_buff *skb2; 5258c2ecf20Sopenharmony_ci struct inet6_skb_parm *opt = IP6CB(skb); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* Check for MLD */ 5288c2ecf20Sopenharmony_ci if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) { 5298c2ecf20Sopenharmony_ci /* Check if this is a mld message */ 5308c2ecf20Sopenharmony_ci u8 nexthdr = hdr->nexthdr; 5318c2ecf20Sopenharmony_ci __be16 frag_off; 5328c2ecf20Sopenharmony_ci int offset; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* Check if the value of Router Alert 5358c2ecf20Sopenharmony_ci * is for MLD (0x0000). 5368c2ecf20Sopenharmony_ci */ 5378c2ecf20Sopenharmony_ci if (opt->ra == htons(IPV6_OPT_ROUTERALERT_MLD)) { 5388c2ecf20Sopenharmony_ci deliver = false; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (!ipv6_ext_hdr(nexthdr)) { 5418c2ecf20Sopenharmony_ci /* BUG */ 5428c2ecf20Sopenharmony_ci goto out; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci offset = ipv6_skip_exthdr(skb, sizeof(*hdr), 5458c2ecf20Sopenharmony_ci &nexthdr, &frag_off); 5468c2ecf20Sopenharmony_ci if (offset < 0) 5478c2ecf20Sopenharmony_ci goto out; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (ipv6_is_mld(skb, nexthdr, offset)) 5508c2ecf20Sopenharmony_ci deliver = true; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci goto out; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci /* unknown RA - process it normally */ 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (deliver) 5588c2ecf20Sopenharmony_ci skb2 = skb_clone(skb, GFP_ATOMIC); 5598c2ecf20Sopenharmony_ci else { 5608c2ecf20Sopenharmony_ci skb2 = skb; 5618c2ecf20Sopenharmony_ci skb = NULL; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (skb2) { 5658c2ecf20Sopenharmony_ci ip6_mr_input(skb2); 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ciout: 5698c2ecf20Sopenharmony_ci#endif 5708c2ecf20Sopenharmony_ci if (likely(deliver)) 5718c2ecf20Sopenharmony_ci ip6_input(skb); 5728c2ecf20Sopenharmony_ci else { 5738c2ecf20Sopenharmony_ci /* discard */ 5748c2ecf20Sopenharmony_ci kfree_skb(skb); 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return 0; 5788c2ecf20Sopenharmony_ci} 579