18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux INET6 implementation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: 68c2ecf20Sopenharmony_ci * Pedro Roque <roque@di.fc.ul.pt> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#ifndef _NET_IPV6_H 108c2ecf20Sopenharmony_ci#define _NET_IPV6_H 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 138c2ecf20Sopenharmony_ci#include <linux/hardirq.h> 148c2ecf20Sopenharmony_ci#include <linux/jhash.h> 158c2ecf20Sopenharmony_ci#include <linux/refcount.h> 168c2ecf20Sopenharmony_ci#include <linux/jump_label_ratelimit.h> 178c2ecf20Sopenharmony_ci#include <net/if_inet6.h> 188c2ecf20Sopenharmony_ci#include <net/ndisc.h> 198c2ecf20Sopenharmony_ci#include <net/flow.h> 208c2ecf20Sopenharmony_ci#include <net/flow_dissector.h> 218c2ecf20Sopenharmony_ci#include <net/snmp.h> 228c2ecf20Sopenharmony_ci#include <net/netns/hash.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define SIN6_LEN_RFC2133 24 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define IPV6_MAXPLEN 65535 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * NextHeader field of IPv6 header 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define NEXTHDR_HOP 0 /* Hop-by-hop option header. */ 338c2ecf20Sopenharmony_ci#define NEXTHDR_TCP 6 /* TCP segment. */ 348c2ecf20Sopenharmony_ci#define NEXTHDR_UDP 17 /* UDP message. */ 358c2ecf20Sopenharmony_ci#define NEXTHDR_IPV6 41 /* IPv6 in IPv6 */ 368c2ecf20Sopenharmony_ci#define NEXTHDR_ROUTING 43 /* Routing header. */ 378c2ecf20Sopenharmony_ci#define NEXTHDR_FRAGMENT 44 /* Fragmentation/reassembly header. */ 388c2ecf20Sopenharmony_ci#define NEXTHDR_GRE 47 /* GRE header. */ 398c2ecf20Sopenharmony_ci#define NEXTHDR_ESP 50 /* Encapsulating security payload. */ 408c2ecf20Sopenharmony_ci#define NEXTHDR_AUTH 51 /* Authentication header. */ 418c2ecf20Sopenharmony_ci#define NEXTHDR_ICMP 58 /* ICMP for IPv6. */ 428c2ecf20Sopenharmony_ci#define NEXTHDR_NONE 59 /* No next header */ 438c2ecf20Sopenharmony_ci#define NEXTHDR_DEST 60 /* Destination options header. */ 448c2ecf20Sopenharmony_ci#define NEXTHDR_SCTP 132 /* SCTP message. */ 458c2ecf20Sopenharmony_ci#define NEXTHDR_MOBILITY 135 /* Mobility header. */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define NEXTHDR_MAX 255 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define IPV6_DEFAULT_HOPLIMIT 64 508c2ecf20Sopenharmony_ci#define IPV6_DEFAULT_MCASTHOPS 1 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* Limits on Hop-by-Hop and Destination options. 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * Per RFC8200 there is no limit on the maximum number or lengths of options in 558c2ecf20Sopenharmony_ci * Hop-by-Hop or Destination options other then the packet must fit in an MTU. 568c2ecf20Sopenharmony_ci * We allow configurable limits in order to mitigate potential denial of 578c2ecf20Sopenharmony_ci * service attacks. 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * There are three limits that may be set: 608c2ecf20Sopenharmony_ci * - Limit the number of options in a Hop-by-Hop or Destination options 618c2ecf20Sopenharmony_ci * extension header 628c2ecf20Sopenharmony_ci * - Limit the byte length of a Hop-by-Hop or Destination options extension 638c2ecf20Sopenharmony_ci * header 648c2ecf20Sopenharmony_ci * - Disallow unknown options 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * The limits are expressed in corresponding sysctls: 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * ipv6.sysctl.max_dst_opts_cnt 698c2ecf20Sopenharmony_ci * ipv6.sysctl.max_hbh_opts_cnt 708c2ecf20Sopenharmony_ci * ipv6.sysctl.max_dst_opts_len 718c2ecf20Sopenharmony_ci * ipv6.sysctl.max_hbh_opts_len 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * max_*_opts_cnt is the number of TLVs that are allowed for Destination 748c2ecf20Sopenharmony_ci * options or Hop-by-Hop options. If the number is less than zero then unknown 758c2ecf20Sopenharmony_ci * TLVs are disallowed and the number of known options that are allowed is the 768c2ecf20Sopenharmony_ci * absolute value. Setting the value to INT_MAX indicates no limit. 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * max_*_opts_len is the length limit in bytes of a Destination or 798c2ecf20Sopenharmony_ci * Hop-by-Hop options extension header. Setting the value to INT_MAX 808c2ecf20Sopenharmony_ci * indicates no length limit. 818c2ecf20Sopenharmony_ci * 828c2ecf20Sopenharmony_ci * If a limit is exceeded when processing an extension header the packet is 838c2ecf20Sopenharmony_ci * silently discarded. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* Default limits for Hop-by-Hop and Destination options */ 878c2ecf20Sopenharmony_ci#define IP6_DEFAULT_MAX_DST_OPTS_CNT 8 888c2ecf20Sopenharmony_ci#define IP6_DEFAULT_MAX_HBH_OPTS_CNT 8 898c2ecf20Sopenharmony_ci#define IP6_DEFAULT_MAX_DST_OPTS_LEN INT_MAX /* No limit */ 908c2ecf20Sopenharmony_ci#define IP6_DEFAULT_MAX_HBH_OPTS_LEN INT_MAX /* No limit */ 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* 938c2ecf20Sopenharmony_ci * Addr type 948c2ecf20Sopenharmony_ci * 958c2ecf20Sopenharmony_ci * type - unicast | multicast 968c2ecf20Sopenharmony_ci * scope - local | site | global 978c2ecf20Sopenharmony_ci * v4 - compat 988c2ecf20Sopenharmony_ci * v4mapped 998c2ecf20Sopenharmony_ci * any 1008c2ecf20Sopenharmony_ci * loopback 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define IPV6_ADDR_ANY 0x0000U 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#define IPV6_ADDR_UNICAST 0x0001U 1068c2ecf20Sopenharmony_ci#define IPV6_ADDR_MULTICAST 0x0002U 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#define IPV6_ADDR_LOOPBACK 0x0010U 1098c2ecf20Sopenharmony_ci#define IPV6_ADDR_LINKLOCAL 0x0020U 1108c2ecf20Sopenharmony_ci#define IPV6_ADDR_SITELOCAL 0x0040U 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define IPV6_ADDR_COMPATv4 0x0080U 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci#define IPV6_ADDR_SCOPE_MASK 0x00f0U 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#define IPV6_ADDR_MAPPED 0x1000U 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* 1198c2ecf20Sopenharmony_ci * Addr scopes 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci#define IPV6_ADDR_MC_SCOPE(a) \ 1228c2ecf20Sopenharmony_ci ((a)->s6_addr[1] & 0x0f) /* nonstandard */ 1238c2ecf20Sopenharmony_ci#define __IPV6_ADDR_SCOPE_INVALID -1 1248c2ecf20Sopenharmony_ci#define IPV6_ADDR_SCOPE_NODELOCAL 0x01 1258c2ecf20Sopenharmony_ci#define IPV6_ADDR_SCOPE_LINKLOCAL 0x02 1268c2ecf20Sopenharmony_ci#define IPV6_ADDR_SCOPE_SITELOCAL 0x05 1278c2ecf20Sopenharmony_ci#define IPV6_ADDR_SCOPE_ORGLOCAL 0x08 1288c2ecf20Sopenharmony_ci#define IPV6_ADDR_SCOPE_GLOBAL 0x0e 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* 1318c2ecf20Sopenharmony_ci * Addr flags 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci#define IPV6_ADDR_MC_FLAG_TRANSIENT(a) \ 1348c2ecf20Sopenharmony_ci ((a)->s6_addr[1] & 0x10) 1358c2ecf20Sopenharmony_ci#define IPV6_ADDR_MC_FLAG_PREFIX(a) \ 1368c2ecf20Sopenharmony_ci ((a)->s6_addr[1] & 0x20) 1378c2ecf20Sopenharmony_ci#define IPV6_ADDR_MC_FLAG_RENDEZVOUS(a) \ 1388c2ecf20Sopenharmony_ci ((a)->s6_addr[1] & 0x40) 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* 1418c2ecf20Sopenharmony_ci * fragmentation header 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistruct frag_hdr { 1458c2ecf20Sopenharmony_ci __u8 nexthdr; 1468c2ecf20Sopenharmony_ci __u8 reserved; 1478c2ecf20Sopenharmony_ci __be16 frag_off; 1488c2ecf20Sopenharmony_ci __be32 identification; 1498c2ecf20Sopenharmony_ci}; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#define IP6_MF 0x0001 1528c2ecf20Sopenharmony_ci#define IP6_OFFSET 0xFFF8 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistruct ip6_fraglist_iter { 1558c2ecf20Sopenharmony_ci struct ipv6hdr *tmp_hdr; 1568c2ecf20Sopenharmony_ci struct sk_buff *frag; 1578c2ecf20Sopenharmony_ci int offset; 1588c2ecf20Sopenharmony_ci unsigned int hlen; 1598c2ecf20Sopenharmony_ci __be32 frag_id; 1608c2ecf20Sopenharmony_ci u8 nexthdr; 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ciint ip6_fraglist_init(struct sk_buff *skb, unsigned int hlen, u8 *prevhdr, 1648c2ecf20Sopenharmony_ci u8 nexthdr, __be32 frag_id, 1658c2ecf20Sopenharmony_ci struct ip6_fraglist_iter *iter); 1668c2ecf20Sopenharmony_civoid ip6_fraglist_prepare(struct sk_buff *skb, struct ip6_fraglist_iter *iter); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic inline struct sk_buff *ip6_fraglist_next(struct ip6_fraglist_iter *iter) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct sk_buff *skb = iter->frag; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci iter->frag = skb->next; 1738c2ecf20Sopenharmony_ci skb_mark_not_on_list(skb); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci return skb; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistruct ip6_frag_state { 1798c2ecf20Sopenharmony_ci u8 *prevhdr; 1808c2ecf20Sopenharmony_ci unsigned int hlen; 1818c2ecf20Sopenharmony_ci unsigned int mtu; 1828c2ecf20Sopenharmony_ci unsigned int left; 1838c2ecf20Sopenharmony_ci int offset; 1848c2ecf20Sopenharmony_ci int ptr; 1858c2ecf20Sopenharmony_ci int hroom; 1868c2ecf20Sopenharmony_ci int troom; 1878c2ecf20Sopenharmony_ci __be32 frag_id; 1888c2ecf20Sopenharmony_ci u8 nexthdr; 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_civoid ip6_frag_init(struct sk_buff *skb, unsigned int hlen, unsigned int mtu, 1928c2ecf20Sopenharmony_ci unsigned short needed_tailroom, int hdr_room, u8 *prevhdr, 1938c2ecf20Sopenharmony_ci u8 nexthdr, __be32 frag_id, struct ip6_frag_state *state); 1948c2ecf20Sopenharmony_cistruct sk_buff *ip6_frag_next(struct sk_buff *skb, 1958c2ecf20Sopenharmony_ci struct ip6_frag_state *state); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#define IP6_REPLY_MARK(net, mark) \ 1988c2ecf20Sopenharmony_ci ((net)->ipv6.sysctl.fwmark_reflect ? (mark) : 0) 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci#include <net/sock.h> 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* sysctls */ 2038c2ecf20Sopenharmony_ciextern int sysctl_mld_max_msf; 2048c2ecf20Sopenharmony_ciextern int sysctl_mld_qrv; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci#define _DEVINC(net, statname, mod, idev, field) \ 2078c2ecf20Sopenharmony_ci({ \ 2088c2ecf20Sopenharmony_ci struct inet6_dev *_idev = (idev); \ 2098c2ecf20Sopenharmony_ci if (likely(_idev != NULL)) \ 2108c2ecf20Sopenharmony_ci mod##SNMP_INC_STATS64((_idev)->stats.statname, (field));\ 2118c2ecf20Sopenharmony_ci mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\ 2128c2ecf20Sopenharmony_ci}) 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* per device counters are atomic_long_t */ 2158c2ecf20Sopenharmony_ci#define _DEVINCATOMIC(net, statname, mod, idev, field) \ 2168c2ecf20Sopenharmony_ci({ \ 2178c2ecf20Sopenharmony_ci struct inet6_dev *_idev = (idev); \ 2188c2ecf20Sopenharmony_ci if (likely(_idev != NULL)) \ 2198c2ecf20Sopenharmony_ci SNMP_INC_STATS_ATOMIC_LONG((_idev)->stats.statname##dev, (field)); \ 2208c2ecf20Sopenharmony_ci mod##SNMP_INC_STATS((net)->mib.statname##_statistics, (field));\ 2218c2ecf20Sopenharmony_ci}) 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* per device and per net counters are atomic_long_t */ 2248c2ecf20Sopenharmony_ci#define _DEVINC_ATOMIC_ATOMIC(net, statname, idev, field) \ 2258c2ecf20Sopenharmony_ci({ \ 2268c2ecf20Sopenharmony_ci struct inet6_dev *_idev = (idev); \ 2278c2ecf20Sopenharmony_ci if (likely(_idev != NULL)) \ 2288c2ecf20Sopenharmony_ci SNMP_INC_STATS_ATOMIC_LONG((_idev)->stats.statname##dev, (field)); \ 2298c2ecf20Sopenharmony_ci SNMP_INC_STATS_ATOMIC_LONG((net)->mib.statname##_statistics, (field));\ 2308c2ecf20Sopenharmony_ci}) 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci#define _DEVADD(net, statname, mod, idev, field, val) \ 2338c2ecf20Sopenharmony_ci({ \ 2348c2ecf20Sopenharmony_ci struct inet6_dev *_idev = (idev); \ 2358c2ecf20Sopenharmony_ci if (likely(_idev != NULL)) \ 2368c2ecf20Sopenharmony_ci mod##SNMP_ADD_STATS((_idev)->stats.statname, (field), (val)); \ 2378c2ecf20Sopenharmony_ci mod##SNMP_ADD_STATS((net)->mib.statname##_statistics, (field), (val));\ 2388c2ecf20Sopenharmony_ci}) 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#define _DEVUPD(net, statname, mod, idev, field, val) \ 2418c2ecf20Sopenharmony_ci({ \ 2428c2ecf20Sopenharmony_ci struct inet6_dev *_idev = (idev); \ 2438c2ecf20Sopenharmony_ci if (likely(_idev != NULL)) \ 2448c2ecf20Sopenharmony_ci mod##SNMP_UPD_PO_STATS((_idev)->stats.statname, field, (val)); \ 2458c2ecf20Sopenharmony_ci mod##SNMP_UPD_PO_STATS((net)->mib.statname##_statistics, field, (val));\ 2468c2ecf20Sopenharmony_ci}) 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/* MIBs */ 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci#define IP6_INC_STATS(net, idev,field) \ 2518c2ecf20Sopenharmony_ci _DEVINC(net, ipv6, , idev, field) 2528c2ecf20Sopenharmony_ci#define __IP6_INC_STATS(net, idev,field) \ 2538c2ecf20Sopenharmony_ci _DEVINC(net, ipv6, __, idev, field) 2548c2ecf20Sopenharmony_ci#define IP6_ADD_STATS(net, idev,field,val) \ 2558c2ecf20Sopenharmony_ci _DEVADD(net, ipv6, , idev, field, val) 2568c2ecf20Sopenharmony_ci#define __IP6_ADD_STATS(net, idev,field,val) \ 2578c2ecf20Sopenharmony_ci _DEVADD(net, ipv6, __, idev, field, val) 2588c2ecf20Sopenharmony_ci#define IP6_UPD_PO_STATS(net, idev,field,val) \ 2598c2ecf20Sopenharmony_ci _DEVUPD(net, ipv6, , idev, field, val) 2608c2ecf20Sopenharmony_ci#define __IP6_UPD_PO_STATS(net, idev,field,val) \ 2618c2ecf20Sopenharmony_ci _DEVUPD(net, ipv6, __, idev, field, val) 2628c2ecf20Sopenharmony_ci#define ICMP6_INC_STATS(net, idev, field) \ 2638c2ecf20Sopenharmony_ci _DEVINCATOMIC(net, icmpv6, , idev, field) 2648c2ecf20Sopenharmony_ci#define __ICMP6_INC_STATS(net, idev, field) \ 2658c2ecf20Sopenharmony_ci _DEVINCATOMIC(net, icmpv6, __, idev, field) 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci#define ICMP6MSGOUT_INC_STATS(net, idev, field) \ 2688c2ecf20Sopenharmony_ci _DEVINC_ATOMIC_ATOMIC(net, icmpv6msg, idev, field +256) 2698c2ecf20Sopenharmony_ci#define ICMP6MSGIN_INC_STATS(net, idev, field) \ 2708c2ecf20Sopenharmony_ci _DEVINC_ATOMIC_ATOMIC(net, icmpv6msg, idev, field) 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistruct ip6_ra_chain { 2738c2ecf20Sopenharmony_ci struct ip6_ra_chain *next; 2748c2ecf20Sopenharmony_ci struct sock *sk; 2758c2ecf20Sopenharmony_ci int sel; 2768c2ecf20Sopenharmony_ci void (*destructor)(struct sock *); 2778c2ecf20Sopenharmony_ci}; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ciextern struct ip6_ra_chain *ip6_ra_chain; 2808c2ecf20Sopenharmony_ciextern rwlock_t ip6_ra_lock; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* 2838c2ecf20Sopenharmony_ci This structure is prepared by protocol, when parsing 2848c2ecf20Sopenharmony_ci ancillary data and passed to IPv6. 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistruct ipv6_txoptions { 2888c2ecf20Sopenharmony_ci refcount_t refcnt; 2898c2ecf20Sopenharmony_ci /* Length of this structure */ 2908c2ecf20Sopenharmony_ci int tot_len; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* length of extension headers */ 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci __u16 opt_flen; /* after fragment hdr */ 2958c2ecf20Sopenharmony_ci __u16 opt_nflen; /* before fragment hdr */ 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci struct ipv6_opt_hdr *hopopt; 2988c2ecf20Sopenharmony_ci struct ipv6_opt_hdr *dst0opt; 2998c2ecf20Sopenharmony_ci struct ipv6_rt_hdr *srcrt; /* Routing Header */ 3008c2ecf20Sopenharmony_ci struct ipv6_opt_hdr *dst1opt; 3018c2ecf20Sopenharmony_ci struct rcu_head rcu; 3028c2ecf20Sopenharmony_ci /* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */ 3038c2ecf20Sopenharmony_ci}; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/* flowlabel_reflect sysctl values */ 3068c2ecf20Sopenharmony_cienum flowlabel_reflect { 3078c2ecf20Sopenharmony_ci FLOWLABEL_REFLECT_ESTABLISHED = 1, 3088c2ecf20Sopenharmony_ci FLOWLABEL_REFLECT_TCP_RESET = 2, 3098c2ecf20Sopenharmony_ci FLOWLABEL_REFLECT_ICMPV6_ECHO_REPLIES = 4, 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistruct ip6_flowlabel { 3138c2ecf20Sopenharmony_ci struct ip6_flowlabel __rcu *next; 3148c2ecf20Sopenharmony_ci __be32 label; 3158c2ecf20Sopenharmony_ci atomic_t users; 3168c2ecf20Sopenharmony_ci struct in6_addr dst; 3178c2ecf20Sopenharmony_ci struct ipv6_txoptions *opt; 3188c2ecf20Sopenharmony_ci unsigned long linger; 3198c2ecf20Sopenharmony_ci struct rcu_head rcu; 3208c2ecf20Sopenharmony_ci u8 share; 3218c2ecf20Sopenharmony_ci union { 3228c2ecf20Sopenharmony_ci struct pid *pid; 3238c2ecf20Sopenharmony_ci kuid_t uid; 3248c2ecf20Sopenharmony_ci } owner; 3258c2ecf20Sopenharmony_ci unsigned long lastuse; 3268c2ecf20Sopenharmony_ci unsigned long expires; 3278c2ecf20Sopenharmony_ci struct net *fl_net; 3288c2ecf20Sopenharmony_ci}; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci#define IPV6_FLOWINFO_MASK cpu_to_be32(0x0FFFFFFF) 3318c2ecf20Sopenharmony_ci#define IPV6_FLOWLABEL_MASK cpu_to_be32(0x000FFFFF) 3328c2ecf20Sopenharmony_ci#define IPV6_FLOWLABEL_STATELESS_FLAG cpu_to_be32(0x00080000) 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) 3358c2ecf20Sopenharmony_ci#define IPV6_TCLASS_SHIFT 20 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistruct ipv6_fl_socklist { 3388c2ecf20Sopenharmony_ci struct ipv6_fl_socklist __rcu *next; 3398c2ecf20Sopenharmony_ci struct ip6_flowlabel *fl; 3408c2ecf20Sopenharmony_ci struct rcu_head rcu; 3418c2ecf20Sopenharmony_ci}; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistruct ipcm6_cookie { 3448c2ecf20Sopenharmony_ci struct sockcm_cookie sockc; 3458c2ecf20Sopenharmony_ci __s16 hlimit; 3468c2ecf20Sopenharmony_ci __s16 tclass; 3478c2ecf20Sopenharmony_ci __s8 dontfrag; 3488c2ecf20Sopenharmony_ci struct ipv6_txoptions *opt; 3498c2ecf20Sopenharmony_ci __u16 gso_size; 3508c2ecf20Sopenharmony_ci}; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic inline void ipcm6_init(struct ipcm6_cookie *ipc6) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci *ipc6 = (struct ipcm6_cookie) { 3558c2ecf20Sopenharmony_ci .hlimit = -1, 3568c2ecf20Sopenharmony_ci .tclass = -1, 3578c2ecf20Sopenharmony_ci .dontfrag = -1, 3588c2ecf20Sopenharmony_ci }; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic inline void ipcm6_init_sk(struct ipcm6_cookie *ipc6, 3628c2ecf20Sopenharmony_ci const struct ipv6_pinfo *np) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci *ipc6 = (struct ipcm6_cookie) { 3658c2ecf20Sopenharmony_ci .hlimit = -1, 3668c2ecf20Sopenharmony_ci .tclass = np->tclass, 3678c2ecf20Sopenharmony_ci .dontfrag = np->dontfrag, 3688c2ecf20Sopenharmony_ci }; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct ipv6_txoptions *opt; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci rcu_read_lock(); 3768c2ecf20Sopenharmony_ci opt = rcu_dereference(np->opt); 3778c2ecf20Sopenharmony_ci if (opt) { 3788c2ecf20Sopenharmony_ci if (!refcount_inc_not_zero(&opt->refcnt)) 3798c2ecf20Sopenharmony_ci opt = NULL; 3808c2ecf20Sopenharmony_ci else 3818c2ecf20Sopenharmony_ci opt = rcu_pointer_handoff(opt); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci rcu_read_unlock(); 3848c2ecf20Sopenharmony_ci return opt; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic inline void txopt_put(struct ipv6_txoptions *opt) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci if (opt && refcount_dec_and_test(&opt->refcnt)) 3908c2ecf20Sopenharmony_ci kfree_rcu(opt, rcu); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 3948c2ecf20Sopenharmony_cistruct ip6_flowlabel *__fl6_sock_lookup(struct sock *sk, __be32 label); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ciextern struct static_key_false_deferred ipv6_flowlabel_exclusive; 3978c2ecf20Sopenharmony_cistatic inline struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, 3988c2ecf20Sopenharmony_ci __be32 label) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci if (static_branch_unlikely(&ipv6_flowlabel_exclusive.key) && 4018c2ecf20Sopenharmony_ci READ_ONCE(sock_net(sk)->ipv6.flowlabel_has_excl)) 4028c2ecf20Sopenharmony_ci return __fl6_sock_lookup(sk, label) ? : ERR_PTR(-ENOENT); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return NULL; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci#endif 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistruct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space, 4098c2ecf20Sopenharmony_ci struct ip6_flowlabel *fl, 4108c2ecf20Sopenharmony_ci struct ipv6_txoptions *fopt); 4118c2ecf20Sopenharmony_civoid fl6_free_socklist(struct sock *sk); 4128c2ecf20Sopenharmony_ciint ipv6_flowlabel_opt(struct sock *sk, sockptr_t optval, int optlen); 4138c2ecf20Sopenharmony_ciint ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq, 4148c2ecf20Sopenharmony_ci int flags); 4158c2ecf20Sopenharmony_ciint ip6_flowlabel_init(void); 4168c2ecf20Sopenharmony_civoid ip6_flowlabel_cleanup(void); 4178c2ecf20Sopenharmony_cibool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic inline void fl6_sock_release(struct ip6_flowlabel *fl) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci if (fl) 4228c2ecf20Sopenharmony_ci atomic_dec(&fl->users); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_civoid icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_civoid icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, 4288c2ecf20Sopenharmony_ci struct icmp6hdr *thdr, int len); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ciint ip6_ra_control(struct sock *sk, int sel); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ciint ipv6_parse_hopopts(struct sk_buff *skb); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistruct ipv6_txoptions *ipv6_dup_options(struct sock *sk, 4358c2ecf20Sopenharmony_ci struct ipv6_txoptions *opt); 4368c2ecf20Sopenharmony_cistruct ipv6_txoptions *ipv6_renew_options(struct sock *sk, 4378c2ecf20Sopenharmony_ci struct ipv6_txoptions *opt, 4388c2ecf20Sopenharmony_ci int newtype, 4398c2ecf20Sopenharmony_ci struct ipv6_opt_hdr *newopt); 4408c2ecf20Sopenharmony_cistruct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space, 4418c2ecf20Sopenharmony_ci struct ipv6_txoptions *opt); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cibool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb, 4448c2ecf20Sopenharmony_ci const struct inet6_skb_parm *opt); 4458c2ecf20Sopenharmony_cistruct ipv6_txoptions *ipv6_update_options(struct sock *sk, 4468c2ecf20Sopenharmony_ci struct ipv6_txoptions *opt); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic inline bool ipv6_accept_ra(struct inet6_dev *idev) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci /* If forwarding is enabled, RA are not accepted unless the special 4518c2ecf20Sopenharmony_ci * hybrid mode (accept_ra=2) is enabled. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci return idev->cnf.forwarding ? idev->cnf.accept_ra == 2 : 4548c2ecf20Sopenharmony_ci idev->cnf.accept_ra; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci#define IPV6_FRAG_HIGH_THRESH (4 * 1024*1024) /* 4194304 */ 4588c2ecf20Sopenharmony_ci#define IPV6_FRAG_LOW_THRESH (3 * 1024*1024) /* 3145728 */ 4598c2ecf20Sopenharmony_ci#define IPV6_FRAG_TIMEOUT (60 * HZ) /* 60 seconds */ 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ciint __ipv6_addr_type(const struct in6_addr *addr); 4628c2ecf20Sopenharmony_cistatic inline int ipv6_addr_type(const struct in6_addr *addr) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci return __ipv6_addr_type(addr) & 0xffff; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic inline int ipv6_addr_scope(const struct in6_addr *addr) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci return __ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic inline int __ipv6_addr_src_scope(int type) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci return (type == IPV6_ADDR_ANY) ? __IPV6_ADDR_SCOPE_INVALID : (type >> 16); 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic inline int ipv6_addr_src_scope(const struct in6_addr *addr) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci return __ipv6_addr_src_scope(__ipv6_addr_type(addr)); 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic inline bool __ipv6_addr_needs_scope_id(int type) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci return type & IPV6_ADDR_LINKLOCAL || 4858c2ecf20Sopenharmony_ci (type & IPV6_ADDR_MULTICAST && 4868c2ecf20Sopenharmony_ci (type & (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL))); 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic inline __u32 ipv6_iface_scope_id(const struct in6_addr *addr, int iface) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci return __ipv6_addr_needs_scope_id(__ipv6_addr_type(addr)) ? iface : 0; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci return memcmp(a1, a2, sizeof(struct in6_addr)); 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic inline bool 5008c2ecf20Sopenharmony_ciipv6_masked_addr_cmp(const struct in6_addr *a1, const struct in6_addr *m, 5018c2ecf20Sopenharmony_ci const struct in6_addr *a2) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 5048c2ecf20Sopenharmony_ci const unsigned long *ul1 = (const unsigned long *)a1; 5058c2ecf20Sopenharmony_ci const unsigned long *ulm = (const unsigned long *)m; 5068c2ecf20Sopenharmony_ci const unsigned long *ul2 = (const unsigned long *)a2; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci return !!(((ul1[0] ^ ul2[0]) & ulm[0]) | 5098c2ecf20Sopenharmony_ci ((ul1[1] ^ ul2[1]) & ulm[1])); 5108c2ecf20Sopenharmony_ci#else 5118c2ecf20Sopenharmony_ci return !!(((a1->s6_addr32[0] ^ a2->s6_addr32[0]) & m->s6_addr32[0]) | 5128c2ecf20Sopenharmony_ci ((a1->s6_addr32[1] ^ a2->s6_addr32[1]) & m->s6_addr32[1]) | 5138c2ecf20Sopenharmony_ci ((a1->s6_addr32[2] ^ a2->s6_addr32[2]) & m->s6_addr32[2]) | 5148c2ecf20Sopenharmony_ci ((a1->s6_addr32[3] ^ a2->s6_addr32[3]) & m->s6_addr32[3])); 5158c2ecf20Sopenharmony_ci#endif 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic inline void ipv6_addr_prefix(struct in6_addr *pfx, 5198c2ecf20Sopenharmony_ci const struct in6_addr *addr, 5208c2ecf20Sopenharmony_ci int plen) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci /* caller must guarantee 0 <= plen <= 128 */ 5238c2ecf20Sopenharmony_ci int o = plen >> 3, 5248c2ecf20Sopenharmony_ci b = plen & 0x7; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci memset(pfx->s6_addr, 0, sizeof(pfx->s6_addr)); 5278c2ecf20Sopenharmony_ci memcpy(pfx->s6_addr, addr, o); 5288c2ecf20Sopenharmony_ci if (b != 0) 5298c2ecf20Sopenharmony_ci pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic inline void ipv6_addr_prefix_copy(struct in6_addr *addr, 5338c2ecf20Sopenharmony_ci const struct in6_addr *pfx, 5348c2ecf20Sopenharmony_ci int plen) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci /* caller must guarantee 0 <= plen <= 128 */ 5378c2ecf20Sopenharmony_ci int o = plen >> 3, 5388c2ecf20Sopenharmony_ci b = plen & 0x7; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci memcpy(addr->s6_addr, pfx, o); 5418c2ecf20Sopenharmony_ci if (b != 0) { 5428c2ecf20Sopenharmony_ci addr->s6_addr[o] &= ~(0xff00 >> b); 5438c2ecf20Sopenharmony_ci addr->s6_addr[o] |= (pfx->s6_addr[o] & (0xff00 >> b)); 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic inline void __ipv6_addr_set_half(__be32 *addr, 5488c2ecf20Sopenharmony_ci __be32 wh, __be32 wl) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 5518c2ecf20Sopenharmony_ci#if defined(__BIG_ENDIAN) 5528c2ecf20Sopenharmony_ci if (__builtin_constant_p(wh) && __builtin_constant_p(wl)) { 5538c2ecf20Sopenharmony_ci *(__force u64 *)addr = ((__force u64)(wh) << 32 | (__force u64)(wl)); 5548c2ecf20Sopenharmony_ci return; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci#elif defined(__LITTLE_ENDIAN) 5578c2ecf20Sopenharmony_ci if (__builtin_constant_p(wl) && __builtin_constant_p(wh)) { 5588c2ecf20Sopenharmony_ci *(__force u64 *)addr = ((__force u64)(wl) << 32 | (__force u64)(wh)); 5598c2ecf20Sopenharmony_ci return; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci#endif 5628c2ecf20Sopenharmony_ci#endif 5638c2ecf20Sopenharmony_ci addr[0] = wh; 5648c2ecf20Sopenharmony_ci addr[1] = wl; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic inline void ipv6_addr_set(struct in6_addr *addr, 5688c2ecf20Sopenharmony_ci __be32 w1, __be32 w2, 5698c2ecf20Sopenharmony_ci __be32 w3, __be32 w4) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci __ipv6_addr_set_half(&addr->s6_addr32[0], w1, w2); 5728c2ecf20Sopenharmony_ci __ipv6_addr_set_half(&addr->s6_addr32[2], w3, w4); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_equal(const struct in6_addr *a1, 5768c2ecf20Sopenharmony_ci const struct in6_addr *a2) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 5798c2ecf20Sopenharmony_ci const unsigned long *ul1 = (const unsigned long *)a1; 5808c2ecf20Sopenharmony_ci const unsigned long *ul2 = (const unsigned long *)a2; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci return ((ul1[0] ^ ul2[0]) | (ul1[1] ^ ul2[1])) == 0UL; 5838c2ecf20Sopenharmony_ci#else 5848c2ecf20Sopenharmony_ci return ((a1->s6_addr32[0] ^ a2->s6_addr32[0]) | 5858c2ecf20Sopenharmony_ci (a1->s6_addr32[1] ^ a2->s6_addr32[1]) | 5868c2ecf20Sopenharmony_ci (a1->s6_addr32[2] ^ a2->s6_addr32[2]) | 5878c2ecf20Sopenharmony_ci (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0; 5888c2ecf20Sopenharmony_ci#endif 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 5928c2ecf20Sopenharmony_cistatic inline bool __ipv6_prefix_equal64_half(const __be64 *a1, 5938c2ecf20Sopenharmony_ci const __be64 *a2, 5948c2ecf20Sopenharmony_ci unsigned int len) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci if (len && ((*a1 ^ *a2) & cpu_to_be64((~0UL) << (64 - len)))) 5978c2ecf20Sopenharmony_ci return false; 5988c2ecf20Sopenharmony_ci return true; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic inline bool ipv6_prefix_equal(const struct in6_addr *addr1, 6028c2ecf20Sopenharmony_ci const struct in6_addr *addr2, 6038c2ecf20Sopenharmony_ci unsigned int prefixlen) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci const __be64 *a1 = (const __be64 *)addr1; 6068c2ecf20Sopenharmony_ci const __be64 *a2 = (const __be64 *)addr2; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (prefixlen >= 64) { 6098c2ecf20Sopenharmony_ci if (a1[0] ^ a2[0]) 6108c2ecf20Sopenharmony_ci return false; 6118c2ecf20Sopenharmony_ci return __ipv6_prefix_equal64_half(a1 + 1, a2 + 1, prefixlen - 64); 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci return __ipv6_prefix_equal64_half(a1, a2, prefixlen); 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci#else 6168c2ecf20Sopenharmony_cistatic inline bool ipv6_prefix_equal(const struct in6_addr *addr1, 6178c2ecf20Sopenharmony_ci const struct in6_addr *addr2, 6188c2ecf20Sopenharmony_ci unsigned int prefixlen) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci const __be32 *a1 = addr1->s6_addr32; 6218c2ecf20Sopenharmony_ci const __be32 *a2 = addr2->s6_addr32; 6228c2ecf20Sopenharmony_ci unsigned int pdw, pbi; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* check complete u32 in prefix */ 6258c2ecf20Sopenharmony_ci pdw = prefixlen >> 5; 6268c2ecf20Sopenharmony_ci if (pdw && memcmp(a1, a2, pdw << 2)) 6278c2ecf20Sopenharmony_ci return false; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* check incomplete u32 in prefix */ 6308c2ecf20Sopenharmony_ci pbi = prefixlen & 0x1f; 6318c2ecf20Sopenharmony_ci if (pbi && ((a1[pdw] ^ a2[pdw]) & htonl((0xffffffff) << (32 - pbi)))) 6328c2ecf20Sopenharmony_ci return false; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci return true; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci#endif 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_any(const struct in6_addr *a) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 6418c2ecf20Sopenharmony_ci const unsigned long *ul = (const unsigned long *)a; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci return (ul[0] | ul[1]) == 0UL; 6448c2ecf20Sopenharmony_ci#else 6458c2ecf20Sopenharmony_ci return (a->s6_addr32[0] | a->s6_addr32[1] | 6468c2ecf20Sopenharmony_ci a->s6_addr32[2] | a->s6_addr32[3]) == 0; 6478c2ecf20Sopenharmony_ci#endif 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic inline u32 ipv6_addr_hash(const struct in6_addr *a) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 6538c2ecf20Sopenharmony_ci const unsigned long *ul = (const unsigned long *)a; 6548c2ecf20Sopenharmony_ci unsigned long x = ul[0] ^ ul[1]; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci return (u32)(x ^ (x >> 32)); 6578c2ecf20Sopenharmony_ci#else 6588c2ecf20Sopenharmony_ci return (__force u32)(a->s6_addr32[0] ^ a->s6_addr32[1] ^ 6598c2ecf20Sopenharmony_ci a->s6_addr32[2] ^ a->s6_addr32[3]); 6608c2ecf20Sopenharmony_ci#endif 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci/* more secured version of ipv6_addr_hash() */ 6648c2ecf20Sopenharmony_cistatic inline u32 __ipv6_addr_jhash(const struct in6_addr *a, const u32 initval) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci return jhash2((__force const u32 *)a->s6_addr32, 6678c2ecf20Sopenharmony_ci ARRAY_SIZE(a->s6_addr32), initval); 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_loopback(const struct in6_addr *a) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 6738c2ecf20Sopenharmony_ci const __be64 *be = (const __be64 *)a; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci return (be[0] | (be[1] ^ cpu_to_be64(1))) == 0UL; 6768c2ecf20Sopenharmony_ci#else 6778c2ecf20Sopenharmony_ci return (a->s6_addr32[0] | a->s6_addr32[1] | 6788c2ecf20Sopenharmony_ci a->s6_addr32[2] | (a->s6_addr32[3] ^ cpu_to_be32(1))) == 0; 6798c2ecf20Sopenharmony_ci#endif 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci/* 6838c2ecf20Sopenharmony_ci * Note that we must __force cast these to unsigned long to make sparse happy, 6848c2ecf20Sopenharmony_ci * since all of the endian-annotated types are fixed size regardless of arch. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_v4mapped(const struct in6_addr *a) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci return ( 6898c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 6908c2ecf20Sopenharmony_ci *(unsigned long *)a | 6918c2ecf20Sopenharmony_ci#else 6928c2ecf20Sopenharmony_ci (__force unsigned long)(a->s6_addr32[0] | a->s6_addr32[1]) | 6938c2ecf20Sopenharmony_ci#endif 6948c2ecf20Sopenharmony_ci (__force unsigned long)(a->s6_addr32[2] ^ 6958c2ecf20Sopenharmony_ci cpu_to_be32(0x0000ffff))) == 0UL; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_v4mapped_loopback(const struct in6_addr *a) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci return ipv6_addr_v4mapped(a) && ipv4_is_loopback(a->s6_addr32[3]); 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic inline u32 ipv6_portaddr_hash(const struct net *net, 7048c2ecf20Sopenharmony_ci const struct in6_addr *addr6, 7058c2ecf20Sopenharmony_ci unsigned int port) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci unsigned int hash, mix = net_hash_mix(net); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (ipv6_addr_any(addr6)) 7108c2ecf20Sopenharmony_ci hash = jhash_1word(0, mix); 7118c2ecf20Sopenharmony_ci else if (ipv6_addr_v4mapped(addr6)) 7128c2ecf20Sopenharmony_ci hash = jhash_1word((__force u32)addr6->s6_addr32[3], mix); 7138c2ecf20Sopenharmony_ci else 7148c2ecf20Sopenharmony_ci hash = jhash2((__force u32 *)addr6->s6_addr32, 4, mix); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci return hash ^ port; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci/* 7208c2ecf20Sopenharmony_ci * Check for a RFC 4843 ORCHID address 7218c2ecf20Sopenharmony_ci * (Overlay Routable Cryptographic Hash Identifiers) 7228c2ecf20Sopenharmony_ci */ 7238c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_orchid(const struct in6_addr *a) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci return (a->s6_addr32[0] & htonl(0xfffffff0)) == htonl(0x20010010); 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_is_multicast(const struct in6_addr *addr) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci return (addr->s6_addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000); 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic inline void ipv6_addr_set_v4mapped(const __be32 addr, 7348c2ecf20Sopenharmony_ci struct in6_addr *v4mapped) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci ipv6_addr_set(v4mapped, 7378c2ecf20Sopenharmony_ci 0, 0, 7388c2ecf20Sopenharmony_ci htonl(0x0000FFFF), 7398c2ecf20Sopenharmony_ci addr); 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci/* 7438c2ecf20Sopenharmony_ci * find the first different bit between two addresses 7448c2ecf20Sopenharmony_ci * length of address must be a multiple of 32bits 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_cistatic inline int __ipv6_addr_diff32(const void *token1, const void *token2, int addrlen) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci const __be32 *a1 = token1, *a2 = token2; 7498c2ecf20Sopenharmony_ci int i; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci addrlen >>= 2; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci for (i = 0; i < addrlen; i++) { 7548c2ecf20Sopenharmony_ci __be32 xb = a1[i] ^ a2[i]; 7558c2ecf20Sopenharmony_ci if (xb) 7568c2ecf20Sopenharmony_ci return i * 32 + 31 - __fls(ntohl(xb)); 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* 7608c2ecf20Sopenharmony_ci * we should *never* get to this point since that 7618c2ecf20Sopenharmony_ci * would mean the addrs are equal 7628c2ecf20Sopenharmony_ci * 7638c2ecf20Sopenharmony_ci * However, we do get to it 8) And exacly, when 7648c2ecf20Sopenharmony_ci * addresses are equal 8) 7658c2ecf20Sopenharmony_ci * 7668c2ecf20Sopenharmony_ci * ip route add 1111::/128 via ... 7678c2ecf20Sopenharmony_ci * ip route add 1111::/64 via ... 7688c2ecf20Sopenharmony_ci * and we are here. 7698c2ecf20Sopenharmony_ci * 7708c2ecf20Sopenharmony_ci * Ideally, this function should stop comparison 7718c2ecf20Sopenharmony_ci * at prefix length. It does not, but it is still OK, 7728c2ecf20Sopenharmony_ci * if returned value is greater than prefix length. 7738c2ecf20Sopenharmony_ci * --ANK (980803) 7748c2ecf20Sopenharmony_ci */ 7758c2ecf20Sopenharmony_ci return addrlen << 5; 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 7798c2ecf20Sopenharmony_cistatic inline int __ipv6_addr_diff64(const void *token1, const void *token2, int addrlen) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci const __be64 *a1 = token1, *a2 = token2; 7828c2ecf20Sopenharmony_ci int i; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci addrlen >>= 3; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci for (i = 0; i < addrlen; i++) { 7878c2ecf20Sopenharmony_ci __be64 xb = a1[i] ^ a2[i]; 7888c2ecf20Sopenharmony_ci if (xb) 7898c2ecf20Sopenharmony_ci return i * 64 + 63 - __fls(be64_to_cpu(xb)); 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci return addrlen << 6; 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci#endif 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic inline int __ipv6_addr_diff(const void *token1, const void *token2, int addrlen) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 7998c2ecf20Sopenharmony_ci if (__builtin_constant_p(addrlen) && !(addrlen & 7)) 8008c2ecf20Sopenharmony_ci return __ipv6_addr_diff64(token1, token2, addrlen); 8018c2ecf20Sopenharmony_ci#endif 8028c2ecf20Sopenharmony_ci return __ipv6_addr_diff32(token1, token2, addrlen); 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_addr *a2) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci__be32 ipv6_select_ident(struct net *net, 8118c2ecf20Sopenharmony_ci const struct in6_addr *daddr, 8128c2ecf20Sopenharmony_ci const struct in6_addr *saddr); 8138c2ecf20Sopenharmony_ci__be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ciint ip6_dst_hoplimit(struct dst_entry *dst); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6, 8188c2ecf20Sopenharmony_ci struct dst_entry *dst) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci int hlimit; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (ipv6_addr_is_multicast(&fl6->daddr)) 8238c2ecf20Sopenharmony_ci hlimit = np->mcast_hops; 8248c2ecf20Sopenharmony_ci else 8258c2ecf20Sopenharmony_ci hlimit = np->hop_limit; 8268c2ecf20Sopenharmony_ci if (hlimit < 0) 8278c2ecf20Sopenharmony_ci hlimit = ip6_dst_hoplimit(dst); 8288c2ecf20Sopenharmony_ci return hlimit; 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci/* copy IPv6 saddr & daddr to flow_keys, possibly using 64bit load/store 8328c2ecf20Sopenharmony_ci * Equivalent to : flow->v6addrs.src = iph->saddr; 8338c2ecf20Sopenharmony_ci * flow->v6addrs.dst = iph->daddr; 8348c2ecf20Sopenharmony_ci */ 8358c2ecf20Sopenharmony_cistatic inline void iph_to_flow_copy_v6addrs(struct flow_keys *flow, 8368c2ecf20Sopenharmony_ci const struct ipv6hdr *iph) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(typeof(flow->addrs), v6addrs.dst) != 8398c2ecf20Sopenharmony_ci offsetof(typeof(flow->addrs), v6addrs.src) + 8408c2ecf20Sopenharmony_ci sizeof(flow->addrs.v6addrs.src)); 8418c2ecf20Sopenharmony_ci memcpy(&flow->addrs.v6addrs, &iph->addrs, sizeof(flow->addrs.v6addrs)); 8428c2ecf20Sopenharmony_ci flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic inline bool ipv6_can_nonlocal_bind(struct net *net, 8488c2ecf20Sopenharmony_ci struct inet_sock *inet) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci return net->ipv6.sysctl.ip_nonlocal_bind || 8518c2ecf20Sopenharmony_ci inet->freebind || inet->transparent; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci/* Sysctl settings for net ipv6.auto_flowlabels */ 8558c2ecf20Sopenharmony_ci#define IP6_AUTO_FLOW_LABEL_OFF 0 8568c2ecf20Sopenharmony_ci#define IP6_AUTO_FLOW_LABEL_OPTOUT 1 8578c2ecf20Sopenharmony_ci#define IP6_AUTO_FLOW_LABEL_OPTIN 2 8588c2ecf20Sopenharmony_ci#define IP6_AUTO_FLOW_LABEL_FORCED 3 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci#define IP6_AUTO_FLOW_LABEL_MAX IP6_AUTO_FLOW_LABEL_FORCED 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci#define IP6_DEFAULT_AUTO_FLOW_LABELS IP6_AUTO_FLOW_LABEL_OPTOUT 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, 8658c2ecf20Sopenharmony_ci __be32 flowlabel, bool autolabel, 8668c2ecf20Sopenharmony_ci struct flowi6 *fl6) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci u32 hash; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci /* @flowlabel may include more than a flow label, eg, the traffic class. 8718c2ecf20Sopenharmony_ci * Here we want only the flow label value. 8728c2ecf20Sopenharmony_ci */ 8738c2ecf20Sopenharmony_ci flowlabel &= IPV6_FLOWLABEL_MASK; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci if (flowlabel || 8768c2ecf20Sopenharmony_ci net->ipv6.sysctl.auto_flowlabels == IP6_AUTO_FLOW_LABEL_OFF || 8778c2ecf20Sopenharmony_ci (!autolabel && 8788c2ecf20Sopenharmony_ci net->ipv6.sysctl.auto_flowlabels != IP6_AUTO_FLOW_LABEL_FORCED)) 8798c2ecf20Sopenharmony_ci return flowlabel; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci hash = skb_get_hash_flowi6(skb, fl6); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* Since this is being sent on the wire obfuscate hash a bit 8848c2ecf20Sopenharmony_ci * to minimize possbility that any useful information to an 8858c2ecf20Sopenharmony_ci * attacker is leaked. Only lower 20 bits are relevant. 8868c2ecf20Sopenharmony_ci */ 8878c2ecf20Sopenharmony_ci hash = rol32(hash, 16); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (net->ipv6.sysctl.flowlabel_state_ranges) 8928c2ecf20Sopenharmony_ci flowlabel |= IPV6_FLOWLABEL_STATELESS_FLAG; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return flowlabel; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic inline int ip6_default_np_autolabel(struct net *net) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci switch (net->ipv6.sysctl.auto_flowlabels) { 9008c2ecf20Sopenharmony_ci case IP6_AUTO_FLOW_LABEL_OFF: 9018c2ecf20Sopenharmony_ci case IP6_AUTO_FLOW_LABEL_OPTIN: 9028c2ecf20Sopenharmony_ci default: 9038c2ecf20Sopenharmony_ci return 0; 9048c2ecf20Sopenharmony_ci case IP6_AUTO_FLOW_LABEL_OPTOUT: 9058c2ecf20Sopenharmony_ci case IP6_AUTO_FLOW_LABEL_FORCED: 9068c2ecf20Sopenharmony_ci return 1; 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci#else 9108c2ecf20Sopenharmony_cistatic inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, 9118c2ecf20Sopenharmony_ci __be32 flowlabel, bool autolabel, 9128c2ecf20Sopenharmony_ci struct flowi6 *fl6) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci return flowlabel; 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_cistatic inline int ip6_default_np_autolabel(struct net *net) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci return 0; 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci#endif 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 9238c2ecf20Sopenharmony_cistatic inline int ip6_multipath_hash_policy(const struct net *net) 9248c2ecf20Sopenharmony_ci{ 9258c2ecf20Sopenharmony_ci return net->ipv6.sysctl.multipath_hash_policy; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci#else 9288c2ecf20Sopenharmony_cistatic inline int ip6_multipath_hash_policy(const struct net *net) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci return 0; 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci#endif 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci/* 9358c2ecf20Sopenharmony_ci * Header manipulation 9368c2ecf20Sopenharmony_ci */ 9378c2ecf20Sopenharmony_cistatic inline void ip6_flow_hdr(struct ipv6hdr *hdr, unsigned int tclass, 9388c2ecf20Sopenharmony_ci __be32 flowlabel) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | flowlabel; 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cistatic inline __be32 ip6_flowinfo(const struct ipv6hdr *hdr) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci return *(__be32 *)hdr & IPV6_FLOWINFO_MASK; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK; 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic inline u8 ip6_tclass(__be32 flowinfo) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci return ntohl(flowinfo & IPV6_TCLASS_MASK) >> IPV6_TCLASS_SHIFT; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic inline __be32 ip6_make_flowinfo(unsigned int tclass, __be32 flowlabel) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci return htonl(tclass << IPV6_TCLASS_SHIFT) | flowlabel; 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic inline __be32 flowi6_get_flowlabel(const struct flowi6 *fl6) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci return fl6->flowlabel & IPV6_FLOWLABEL_MASK; 9668c2ecf20Sopenharmony_ci} 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci/* 9698c2ecf20Sopenharmony_ci * Prototypes exported by ipv6 9708c2ecf20Sopenharmony_ci */ 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci/* 9738c2ecf20Sopenharmony_ci * rcv function (called from netdevice level) 9748c2ecf20Sopenharmony_ci */ 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ciint ipv6_rcv(struct sk_buff *skb, struct net_device *dev, 9778c2ecf20Sopenharmony_ci struct packet_type *pt, struct net_device *orig_dev); 9788c2ecf20Sopenharmony_civoid ipv6_list_rcv(struct list_head *head, struct packet_type *pt, 9798c2ecf20Sopenharmony_ci struct net_device *orig_dev); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ciint ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci/* 9848c2ecf20Sopenharmony_ci * upper-layer output functions 9858c2ecf20Sopenharmony_ci */ 9868c2ecf20Sopenharmony_ciint ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, 9878c2ecf20Sopenharmony_ci __u32 mark, struct ipv6_txoptions *opt, int tclass, u32 priority); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ciint ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ciint ip6_append_data(struct sock *sk, 9928c2ecf20Sopenharmony_ci int getfrag(void *from, char *to, int offset, int len, 9938c2ecf20Sopenharmony_ci int odd, struct sk_buff *skb), 9948c2ecf20Sopenharmony_ci void *from, int length, int transhdrlen, 9958c2ecf20Sopenharmony_ci struct ipcm6_cookie *ipc6, struct flowi6 *fl6, 9968c2ecf20Sopenharmony_ci struct rt6_info *rt, unsigned int flags); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ciint ip6_push_pending_frames(struct sock *sk); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_civoid ip6_flush_pending_frames(struct sock *sk); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ciint ip6_send_skb(struct sk_buff *skb); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistruct sk_buff *__ip6_make_skb(struct sock *sk, struct sk_buff_head *queue, 10058c2ecf20Sopenharmony_ci struct inet_cork_full *cork, 10068c2ecf20Sopenharmony_ci struct inet6_cork *v6_cork); 10078c2ecf20Sopenharmony_cistruct sk_buff *ip6_make_skb(struct sock *sk, 10088c2ecf20Sopenharmony_ci int getfrag(void *from, char *to, int offset, 10098c2ecf20Sopenharmony_ci int len, int odd, struct sk_buff *skb), 10108c2ecf20Sopenharmony_ci void *from, int length, int transhdrlen, 10118c2ecf20Sopenharmony_ci struct ipcm6_cookie *ipc6, struct flowi6 *fl6, 10128c2ecf20Sopenharmony_ci struct rt6_info *rt, unsigned int flags, 10138c2ecf20Sopenharmony_ci struct inet_cork_full *cork); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cistatic inline struct sk_buff *ip6_finish_skb(struct sock *sk) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci return __ip6_make_skb(sk, &sk->sk_write_queue, &inet_sk(sk)->cork, 10188c2ecf20Sopenharmony_ci &inet6_sk(sk)->cork); 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ciint ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst, 10228c2ecf20Sopenharmony_ci struct flowi6 *fl6); 10238c2ecf20Sopenharmony_cistruct dst_entry *ip6_dst_lookup_flow(struct net *net, const struct sock *sk, struct flowi6 *fl6, 10248c2ecf20Sopenharmony_ci const struct in6_addr *final_dst); 10258c2ecf20Sopenharmony_cistruct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, 10268c2ecf20Sopenharmony_ci const struct in6_addr *final_dst, 10278c2ecf20Sopenharmony_ci bool connected); 10288c2ecf20Sopenharmony_cistruct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, 10298c2ecf20Sopenharmony_ci struct net_device *dev, 10308c2ecf20Sopenharmony_ci struct net *net, struct socket *sock, 10318c2ecf20Sopenharmony_ci struct in6_addr *saddr, 10328c2ecf20Sopenharmony_ci const struct ip_tunnel_info *info, 10338c2ecf20Sopenharmony_ci u8 protocol, bool use_cache); 10348c2ecf20Sopenharmony_cistruct dst_entry *ip6_blackhole_route(struct net *net, 10358c2ecf20Sopenharmony_ci struct dst_entry *orig_dst); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci/* 10388c2ecf20Sopenharmony_ci * skb processing functions 10398c2ecf20Sopenharmony_ci */ 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ciint ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb); 10428c2ecf20Sopenharmony_ciint ip6_forward(struct sk_buff *skb); 10438c2ecf20Sopenharmony_ciint ip6_input(struct sk_buff *skb); 10448c2ecf20Sopenharmony_ciint ip6_mc_input(struct sk_buff *skb); 10458c2ecf20Sopenharmony_civoid ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, 10468c2ecf20Sopenharmony_ci bool have_final); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ciint __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb); 10498c2ecf20Sopenharmony_ciint ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci/* 10528c2ecf20Sopenharmony_ci * Extension header (options) processing 10538c2ecf20Sopenharmony_ci */ 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_civoid ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, 10568c2ecf20Sopenharmony_ci u8 *proto, struct in6_addr **daddr_p, 10578c2ecf20Sopenharmony_ci struct in6_addr *saddr); 10588c2ecf20Sopenharmony_civoid ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, 10598c2ecf20Sopenharmony_ci u8 *proto); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ciint ipv6_skip_exthdr(const struct sk_buff *, int start, u8 *nexthdrp, 10628c2ecf20Sopenharmony_ci __be16 *frag_offp); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cibool ipv6_ext_hdr(u8 nexthdr); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_cienum { 10678c2ecf20Sopenharmony_ci IP6_FH_F_FRAG = (1 << 0), 10688c2ecf20Sopenharmony_ci IP6_FH_F_AUTH = (1 << 1), 10698c2ecf20Sopenharmony_ci IP6_FH_F_SKIP_RH = (1 << 2), 10708c2ecf20Sopenharmony_ci}; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci/* find specified header and get offset to it */ 10738c2ecf20Sopenharmony_ciint ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, int target, 10748c2ecf20Sopenharmony_ci unsigned short *fragoff, int *fragflg); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ciint ipv6_find_tlv(const struct sk_buff *skb, int offset, int type); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_cistruct in6_addr *fl6_update_dst(struct flowi6 *fl6, 10798c2ecf20Sopenharmony_ci const struct ipv6_txoptions *opt, 10808c2ecf20Sopenharmony_ci struct in6_addr *orig); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci/* 10838c2ecf20Sopenharmony_ci * socket options (ipv6_sockglue.c) 10848c2ecf20Sopenharmony_ci */ 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ciint ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval, 10878c2ecf20Sopenharmony_ci unsigned int optlen); 10888c2ecf20Sopenharmony_ciint ipv6_getsockopt(struct sock *sk, int level, int optname, 10898c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ciint __ip6_datagram_connect(struct sock *sk, struct sockaddr *addr, 10928c2ecf20Sopenharmony_ci int addr_len); 10938c2ecf20Sopenharmony_ciint ip6_datagram_connect(struct sock *sk, struct sockaddr *addr, int addr_len); 10948c2ecf20Sopenharmony_ciint ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *addr, 10958c2ecf20Sopenharmony_ci int addr_len); 10968c2ecf20Sopenharmony_ciint ip6_datagram_dst_update(struct sock *sk, bool fix_sk_saddr); 10978c2ecf20Sopenharmony_civoid ip6_datagram_release_cb(struct sock *sk); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ciint ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, 11008c2ecf20Sopenharmony_ci int *addr_len); 11018c2ecf20Sopenharmony_ciint ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len, 11028c2ecf20Sopenharmony_ci int *addr_len); 11038c2ecf20Sopenharmony_civoid ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, __be16 port, 11048c2ecf20Sopenharmony_ci u32 info, u8 *payload); 11058c2ecf20Sopenharmony_civoid ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info); 11068c2ecf20Sopenharmony_civoid ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_civoid inet6_cleanup_sock(struct sock *sk); 11098c2ecf20Sopenharmony_civoid inet6_sock_destruct(struct sock *sk); 11108c2ecf20Sopenharmony_ciint inet6_release(struct socket *sock); 11118c2ecf20Sopenharmony_ciint inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len); 11128c2ecf20Sopenharmony_ciint inet6_getname(struct socket *sock, struct sockaddr *uaddr, 11138c2ecf20Sopenharmony_ci int peer); 11148c2ecf20Sopenharmony_ciint inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); 11158c2ecf20Sopenharmony_ciint inet6_compat_ioctl(struct socket *sock, unsigned int cmd, 11168c2ecf20Sopenharmony_ci unsigned long arg); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ciint inet6_hash_connect(struct inet_timewait_death_row *death_row, 11198c2ecf20Sopenharmony_ci struct sock *sk); 11208c2ecf20Sopenharmony_ciint inet6_sendmsg(struct socket *sock, struct msghdr *msg, size_t size); 11218c2ecf20Sopenharmony_ciint inet6_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, 11228c2ecf20Sopenharmony_ci int flags); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci/* 11258c2ecf20Sopenharmony_ci * reassembly.c 11268c2ecf20Sopenharmony_ci */ 11278c2ecf20Sopenharmony_ciextern const struct proto_ops inet6_stream_ops; 11288c2ecf20Sopenharmony_ciextern const struct proto_ops inet6_dgram_ops; 11298c2ecf20Sopenharmony_ciextern const struct proto_ops inet6_sockraw_ops; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistruct group_source_req; 11328c2ecf20Sopenharmony_cistruct group_filter; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ciint ip6_mc_source(int add, int omode, struct sock *sk, 11358c2ecf20Sopenharmony_ci struct group_source_req *pgsr); 11368c2ecf20Sopenharmony_ciint ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf, 11378c2ecf20Sopenharmony_ci struct sockaddr_storage *list); 11388c2ecf20Sopenharmony_ciint ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, 11398c2ecf20Sopenharmony_ci struct sockaddr_storage __user *p); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 11428c2ecf20Sopenharmony_ciint ac6_proc_init(struct net *net); 11438c2ecf20Sopenharmony_civoid ac6_proc_exit(struct net *net); 11448c2ecf20Sopenharmony_ciint raw6_proc_init(void); 11458c2ecf20Sopenharmony_civoid raw6_proc_exit(void); 11468c2ecf20Sopenharmony_ciint tcp6_proc_init(struct net *net); 11478c2ecf20Sopenharmony_civoid tcp6_proc_exit(struct net *net); 11488c2ecf20Sopenharmony_ciint udp6_proc_init(struct net *net); 11498c2ecf20Sopenharmony_civoid udp6_proc_exit(struct net *net); 11508c2ecf20Sopenharmony_ciint udplite6_proc_init(void); 11518c2ecf20Sopenharmony_civoid udplite6_proc_exit(void); 11528c2ecf20Sopenharmony_ciint ipv6_misc_proc_init(void); 11538c2ecf20Sopenharmony_civoid ipv6_misc_proc_exit(void); 11548c2ecf20Sopenharmony_ciint snmp6_register_dev(struct inet6_dev *idev); 11558c2ecf20Sopenharmony_ciint snmp6_unregister_dev(struct inet6_dev *idev); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci#else 11588c2ecf20Sopenharmony_cistatic inline int ac6_proc_init(struct net *net) { return 0; } 11598c2ecf20Sopenharmony_cistatic inline void ac6_proc_exit(struct net *net) { } 11608c2ecf20Sopenharmony_cistatic inline int snmp6_register_dev(struct inet6_dev *idev) { return 0; } 11618c2ecf20Sopenharmony_cistatic inline int snmp6_unregister_dev(struct inet6_dev *idev) { return 0; } 11628c2ecf20Sopenharmony_ci#endif 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSCTL 11658c2ecf20Sopenharmony_cistruct ctl_table *ipv6_icmp_sysctl_init(struct net *net); 11668c2ecf20Sopenharmony_cistruct ctl_table *ipv6_route_sysctl_init(struct net *net); 11678c2ecf20Sopenharmony_ciint ipv6_sysctl_register(void); 11688c2ecf20Sopenharmony_civoid ipv6_sysctl_unregister(void); 11698c2ecf20Sopenharmony_ci#endif 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ciint ipv6_sock_mc_join(struct sock *sk, int ifindex, 11728c2ecf20Sopenharmony_ci const struct in6_addr *addr); 11738c2ecf20Sopenharmony_ciint ipv6_sock_mc_join_ssm(struct sock *sk, int ifindex, 11748c2ecf20Sopenharmony_ci const struct in6_addr *addr, unsigned int mode); 11758c2ecf20Sopenharmony_ciint ipv6_sock_mc_drop(struct sock *sk, int ifindex, 11768c2ecf20Sopenharmony_ci const struct in6_addr *addr); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_cistatic inline int ip6_sock_set_v6only(struct sock *sk) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci if (inet_sk(sk)->inet_num) 11818c2ecf20Sopenharmony_ci return -EINVAL; 11828c2ecf20Sopenharmony_ci lock_sock(sk); 11838c2ecf20Sopenharmony_ci sk->sk_ipv6only = true; 11848c2ecf20Sopenharmony_ci release_sock(sk); 11858c2ecf20Sopenharmony_ci return 0; 11868c2ecf20Sopenharmony_ci} 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_cistatic inline void ip6_sock_set_recverr(struct sock *sk) 11898c2ecf20Sopenharmony_ci{ 11908c2ecf20Sopenharmony_ci lock_sock(sk); 11918c2ecf20Sopenharmony_ci inet6_sk(sk)->recverr = true; 11928c2ecf20Sopenharmony_ci release_sock(sk); 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic inline int __ip6_sock_set_addr_preferences(struct sock *sk, int val) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci unsigned int pref = 0; 11988c2ecf20Sopenharmony_ci unsigned int prefmask = ~0; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */ 12018c2ecf20Sopenharmony_ci switch (val & (IPV6_PREFER_SRC_PUBLIC | 12028c2ecf20Sopenharmony_ci IPV6_PREFER_SRC_TMP | 12038c2ecf20Sopenharmony_ci IPV6_PREFER_SRC_PUBTMP_DEFAULT)) { 12048c2ecf20Sopenharmony_ci case IPV6_PREFER_SRC_PUBLIC: 12058c2ecf20Sopenharmony_ci pref |= IPV6_PREFER_SRC_PUBLIC; 12068c2ecf20Sopenharmony_ci prefmask &= ~(IPV6_PREFER_SRC_PUBLIC | 12078c2ecf20Sopenharmony_ci IPV6_PREFER_SRC_TMP); 12088c2ecf20Sopenharmony_ci break; 12098c2ecf20Sopenharmony_ci case IPV6_PREFER_SRC_TMP: 12108c2ecf20Sopenharmony_ci pref |= IPV6_PREFER_SRC_TMP; 12118c2ecf20Sopenharmony_ci prefmask &= ~(IPV6_PREFER_SRC_PUBLIC | 12128c2ecf20Sopenharmony_ci IPV6_PREFER_SRC_TMP); 12138c2ecf20Sopenharmony_ci break; 12148c2ecf20Sopenharmony_ci case IPV6_PREFER_SRC_PUBTMP_DEFAULT: 12158c2ecf20Sopenharmony_ci prefmask &= ~(IPV6_PREFER_SRC_PUBLIC | 12168c2ecf20Sopenharmony_ci IPV6_PREFER_SRC_TMP); 12178c2ecf20Sopenharmony_ci break; 12188c2ecf20Sopenharmony_ci case 0: 12198c2ecf20Sopenharmony_ci break; 12208c2ecf20Sopenharmony_ci default: 12218c2ecf20Sopenharmony_ci return -EINVAL; 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci /* check HOME/COA conflicts */ 12258c2ecf20Sopenharmony_ci switch (val & (IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_COA)) { 12268c2ecf20Sopenharmony_ci case IPV6_PREFER_SRC_HOME: 12278c2ecf20Sopenharmony_ci prefmask &= ~IPV6_PREFER_SRC_COA; 12288c2ecf20Sopenharmony_ci break; 12298c2ecf20Sopenharmony_ci case IPV6_PREFER_SRC_COA: 12308c2ecf20Sopenharmony_ci pref |= IPV6_PREFER_SRC_COA; 12318c2ecf20Sopenharmony_ci break; 12328c2ecf20Sopenharmony_ci case 0: 12338c2ecf20Sopenharmony_ci break; 12348c2ecf20Sopenharmony_ci default: 12358c2ecf20Sopenharmony_ci return -EINVAL; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* check CGA/NONCGA conflicts */ 12398c2ecf20Sopenharmony_ci switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) { 12408c2ecf20Sopenharmony_ci case IPV6_PREFER_SRC_CGA: 12418c2ecf20Sopenharmony_ci case IPV6_PREFER_SRC_NONCGA: 12428c2ecf20Sopenharmony_ci case 0: 12438c2ecf20Sopenharmony_ci break; 12448c2ecf20Sopenharmony_ci default: 12458c2ecf20Sopenharmony_ci return -EINVAL; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci inet6_sk(sk)->srcprefs = (inet6_sk(sk)->srcprefs & prefmask) | pref; 12498c2ecf20Sopenharmony_ci return 0; 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_cistatic inline int ip6_sock_set_addr_preferences(struct sock *sk, int val) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci int ret; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci lock_sock(sk); 12578c2ecf20Sopenharmony_ci ret = __ip6_sock_set_addr_preferences(sk, val); 12588c2ecf20Sopenharmony_ci release_sock(sk); 12598c2ecf20Sopenharmony_ci return ret; 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_cistatic inline void ip6_sock_set_recvpktinfo(struct sock *sk) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci lock_sock(sk); 12658c2ecf20Sopenharmony_ci inet6_sk(sk)->rxopt.bits.rxinfo = true; 12668c2ecf20Sopenharmony_ci release_sock(sk); 12678c2ecf20Sopenharmony_ci} 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci#endif /* _NET_IPV6_H */ 1270