| .. | .. |
|---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-or-later */ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Linux INET6 implementation |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Authors: |
|---|
| 5 | 6 | * Pedro Roque <roque@di.fc.ul.pt> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or |
|---|
| 8 | | - * modify it under the terms of the GNU General Public License |
|---|
| 9 | | - * as published by the Free Software Foundation; either version |
|---|
| 10 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 11 | 7 | */ |
|---|
| 12 | 8 | |
|---|
| 13 | 9 | #ifndef _NET_IPV6_H |
|---|
| .. | .. |
|---|
| 17 | 13 | #include <linux/hardirq.h> |
|---|
| 18 | 14 | #include <linux/jhash.h> |
|---|
| 19 | 15 | #include <linux/refcount.h> |
|---|
| 16 | +#include <linux/jump_label_ratelimit.h> |
|---|
| 20 | 17 | #include <net/if_inet6.h> |
|---|
| 21 | 18 | #include <net/ndisc.h> |
|---|
| 22 | 19 | #include <net/flow.h> |
|---|
| .. | .. |
|---|
| 154 | 151 | #define IP6_MF 0x0001 |
|---|
| 155 | 152 | #define IP6_OFFSET 0xFFF8 |
|---|
| 156 | 153 | |
|---|
| 154 | +struct ip6_fraglist_iter { |
|---|
| 155 | + struct ipv6hdr *tmp_hdr; |
|---|
| 156 | + struct sk_buff *frag; |
|---|
| 157 | + int offset; |
|---|
| 158 | + unsigned int hlen; |
|---|
| 159 | + __be32 frag_id; |
|---|
| 160 | + u8 nexthdr; |
|---|
| 161 | +}; |
|---|
| 162 | + |
|---|
| 163 | +int ip6_fraglist_init(struct sk_buff *skb, unsigned int hlen, u8 *prevhdr, |
|---|
| 164 | + u8 nexthdr, __be32 frag_id, |
|---|
| 165 | + struct ip6_fraglist_iter *iter); |
|---|
| 166 | +void ip6_fraglist_prepare(struct sk_buff *skb, struct ip6_fraglist_iter *iter); |
|---|
| 167 | + |
|---|
| 168 | +static inline struct sk_buff *ip6_fraglist_next(struct ip6_fraglist_iter *iter) |
|---|
| 169 | +{ |
|---|
| 170 | + struct sk_buff *skb = iter->frag; |
|---|
| 171 | + |
|---|
| 172 | + iter->frag = skb->next; |
|---|
| 173 | + skb_mark_not_on_list(skb); |
|---|
| 174 | + |
|---|
| 175 | + return skb; |
|---|
| 176 | +} |
|---|
| 177 | + |
|---|
| 178 | +struct ip6_frag_state { |
|---|
| 179 | + u8 *prevhdr; |
|---|
| 180 | + unsigned int hlen; |
|---|
| 181 | + unsigned int mtu; |
|---|
| 182 | + unsigned int left; |
|---|
| 183 | + int offset; |
|---|
| 184 | + int ptr; |
|---|
| 185 | + int hroom; |
|---|
| 186 | + int troom; |
|---|
| 187 | + __be32 frag_id; |
|---|
| 188 | + u8 nexthdr; |
|---|
| 189 | +}; |
|---|
| 190 | + |
|---|
| 191 | +void ip6_frag_init(struct sk_buff *skb, unsigned int hlen, unsigned int mtu, |
|---|
| 192 | + unsigned short needed_tailroom, int hdr_room, u8 *prevhdr, |
|---|
| 193 | + u8 nexthdr, __be32 frag_id, struct ip6_frag_state *state); |
|---|
| 194 | +struct sk_buff *ip6_frag_next(struct sk_buff *skb, |
|---|
| 195 | + struct ip6_frag_state *state); |
|---|
| 196 | + |
|---|
| 157 | 197 | #define IP6_REPLY_MARK(net, mark) \ |
|---|
| 158 | 198 | ((net)->ipv6.sysctl.fwmark_reflect ? (mark) : 0) |
|---|
| 159 | 199 | |
|---|
| .. | .. |
|---|
| 262 | 302 | /* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */ |
|---|
| 263 | 303 | }; |
|---|
| 264 | 304 | |
|---|
| 305 | +/* flowlabel_reflect sysctl values */ |
|---|
| 306 | +enum flowlabel_reflect { |
|---|
| 307 | + FLOWLABEL_REFLECT_ESTABLISHED = 1, |
|---|
| 308 | + FLOWLABEL_REFLECT_TCP_RESET = 2, |
|---|
| 309 | + FLOWLABEL_REFLECT_ICMPV6_ECHO_REPLIES = 4, |
|---|
| 310 | +}; |
|---|
| 311 | + |
|---|
| 265 | 312 | struct ip6_flowlabel { |
|---|
| 266 | 313 | struct ip6_flowlabel __rcu *next; |
|---|
| 267 | 314 | __be32 label; |
|---|
| .. | .. |
|---|
| 343 | 390 | kfree_rcu(opt, rcu); |
|---|
| 344 | 391 | } |
|---|
| 345 | 392 | |
|---|
| 346 | | -struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label); |
|---|
| 393 | +struct ip6_flowlabel *__fl6_sock_lookup(struct sock *sk, __be32 label); |
|---|
| 394 | + |
|---|
| 395 | +extern struct static_key_false_deferred ipv6_flowlabel_exclusive; |
|---|
| 396 | +static inline struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, |
|---|
| 397 | + __be32 label) |
|---|
| 398 | +{ |
|---|
| 399 | + if (static_branch_unlikely(&ipv6_flowlabel_exclusive.key)) |
|---|
| 400 | + return __fl6_sock_lookup(sk, label) ? : ERR_PTR(-ENOENT); |
|---|
| 401 | + |
|---|
| 402 | + return NULL; |
|---|
| 403 | +} |
|---|
| 404 | + |
|---|
| 347 | 405 | struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space, |
|---|
| 348 | 406 | struct ip6_flowlabel *fl, |
|---|
| 349 | 407 | struct ipv6_txoptions *fopt); |
|---|
| 350 | 408 | void fl6_free_socklist(struct sock *sk); |
|---|
| 351 | | -int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen); |
|---|
| 409 | +int ipv6_flowlabel_opt(struct sock *sk, sockptr_t optval, int optlen); |
|---|
| 352 | 410 | int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq, |
|---|
| 353 | 411 | int flags); |
|---|
| 354 | 412 | int ip6_flowlabel_init(void); |
|---|
| .. | .. |
|---|
| 602 | 660 | /* more secured version of ipv6_addr_hash() */ |
|---|
| 603 | 661 | static inline u32 __ipv6_addr_jhash(const struct in6_addr *a, const u32 initval) |
|---|
| 604 | 662 | { |
|---|
| 605 | | - u32 v = (__force u32)a->s6_addr32[0] ^ (__force u32)a->s6_addr32[1]; |
|---|
| 606 | | - |
|---|
| 607 | | - return jhash_3words(v, |
|---|
| 608 | | - (__force u32)a->s6_addr32[2], |
|---|
| 609 | | - (__force u32)a->s6_addr32[3], |
|---|
| 610 | | - initval); |
|---|
| 663 | + return jhash2((__force const u32 *)a->s6_addr32, |
|---|
| 664 | + ARRAY_SIZE(a->s6_addr32), initval); |
|---|
| 611 | 665 | } |
|---|
| 612 | 666 | |
|---|
| 613 | 667 | static inline bool ipv6_addr_loopback(const struct in6_addr *a) |
|---|
| .. | .. |
|---|
| 636 | 690 | #endif |
|---|
| 637 | 691 | (__force unsigned long)(a->s6_addr32[2] ^ |
|---|
| 638 | 692 | cpu_to_be32(0x0000ffff))) == 0UL; |
|---|
| 693 | +} |
|---|
| 694 | + |
|---|
| 695 | +static inline bool ipv6_addr_v4mapped_loopback(const struct in6_addr *a) |
|---|
| 696 | +{ |
|---|
| 697 | + return ipv6_addr_v4mapped(a) && ipv4_is_loopback(a->s6_addr32[3]); |
|---|
| 639 | 698 | } |
|---|
| 640 | 699 | |
|---|
| 641 | 700 | static inline u32 ipv6_portaddr_hash(const struct net *net, |
|---|
| .. | .. |
|---|
| 776 | 835 | BUILD_BUG_ON(offsetof(typeof(flow->addrs), v6addrs.dst) != |
|---|
| 777 | 836 | offsetof(typeof(flow->addrs), v6addrs.src) + |
|---|
| 778 | 837 | sizeof(flow->addrs.v6addrs.src)); |
|---|
| 779 | | - memcpy(&flow->addrs.v6addrs, &iph->saddr, sizeof(flow->addrs.v6addrs)); |
|---|
| 838 | + memcpy(&flow->addrs.v6addrs, &iph->addrs, sizeof(flow->addrs.v6addrs)); |
|---|
| 780 | 839 | flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; |
|---|
| 781 | 840 | } |
|---|
| 782 | 841 | |
|---|
| .. | .. |
|---|
| 845 | 904 | } |
|---|
| 846 | 905 | } |
|---|
| 847 | 906 | #else |
|---|
| 848 | | -static inline void ip6_set_txhash(struct sock *sk) { } |
|---|
| 849 | 907 | static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, |
|---|
| 850 | 908 | __be32 flowlabel, bool autolabel, |
|---|
| 851 | 909 | struct flowi6 *fl6) |
|---|
| .. | .. |
|---|
| 923 | 981 | * upper-layer output functions |
|---|
| 924 | 982 | */ |
|---|
| 925 | 983 | int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, |
|---|
| 926 | | - __u32 mark, struct ipv6_txoptions *opt, int tclass); |
|---|
| 984 | + __u32 mark, struct ipv6_txoptions *opt, int tclass, u32 priority); |
|---|
| 927 | 985 | |
|---|
| 928 | 986 | int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr); |
|---|
| 929 | 987 | |
|---|
| .. | .. |
|---|
| 964 | 1022 | struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, |
|---|
| 965 | 1023 | const struct in6_addr *final_dst, |
|---|
| 966 | 1024 | bool connected); |
|---|
| 1025 | +struct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, |
|---|
| 1026 | + struct net_device *dev, |
|---|
| 1027 | + struct net *net, struct socket *sock, |
|---|
| 1028 | + struct in6_addr *saddr, |
|---|
| 1029 | + const struct ip_tunnel_info *info, |
|---|
| 1030 | + u8 protocol, bool use_cache); |
|---|
| 967 | 1031 | struct dst_entry *ip6_blackhole_route(struct net *net, |
|---|
| 968 | 1032 | struct dst_entry *orig_dst); |
|---|
| 969 | 1033 | |
|---|
| .. | .. |
|---|
| 975 | 1039 | int ip6_forward(struct sk_buff *skb); |
|---|
| 976 | 1040 | int ip6_input(struct sk_buff *skb); |
|---|
| 977 | 1041 | int ip6_mc_input(struct sk_buff *skb); |
|---|
| 1042 | +void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, |
|---|
| 1043 | + bool have_final); |
|---|
| 978 | 1044 | |
|---|
| 979 | 1045 | int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb); |
|---|
| 980 | 1046 | int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb); |
|---|
| .. | .. |
|---|
| 1014 | 1080 | * socket options (ipv6_sockglue.c) |
|---|
| 1015 | 1081 | */ |
|---|
| 1016 | 1082 | |
|---|
| 1017 | | -int ipv6_setsockopt(struct sock *sk, int level, int optname, |
|---|
| 1018 | | - char __user *optval, unsigned int optlen); |
|---|
| 1083 | +int ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval, |
|---|
| 1084 | + unsigned int optlen); |
|---|
| 1019 | 1085 | int ipv6_getsockopt(struct sock *sk, int level, int optname, |
|---|
| 1020 | 1086 | char __user *optval, int __user *optlen); |
|---|
| 1021 | | -int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, |
|---|
| 1022 | | - char __user *optval, unsigned int optlen); |
|---|
| 1023 | | -int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, |
|---|
| 1024 | | - char __user *optval, int __user *optlen); |
|---|
| 1025 | 1087 | |
|---|
| 1026 | 1088 | int __ip6_datagram_connect(struct sock *sk, struct sockaddr *addr, |
|---|
| 1027 | 1089 | int addr_len); |
|---|
| .. | .. |
|---|
| 1040 | 1102 | void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info); |
|---|
| 1041 | 1103 | void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu); |
|---|
| 1042 | 1104 | |
|---|
| 1105 | +void inet6_cleanup_sock(struct sock *sk); |
|---|
| 1106 | +void inet6_sock_destruct(struct sock *sk); |
|---|
| 1043 | 1107 | int inet6_release(struct socket *sock); |
|---|
| 1044 | 1108 | int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len); |
|---|
| 1045 | 1109 | int inet6_getname(struct socket *sock, struct sockaddr *uaddr, |
|---|
| 1046 | 1110 | int peer); |
|---|
| 1047 | 1111 | int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); |
|---|
| 1112 | +int inet6_compat_ioctl(struct socket *sock, unsigned int cmd, |
|---|
| 1113 | + unsigned long arg); |
|---|
| 1048 | 1114 | |
|---|
| 1049 | 1115 | int inet6_hash_connect(struct inet_timewait_death_row *death_row, |
|---|
| 1050 | 1116 | struct sock *sk); |
|---|
| 1117 | +int inet6_sendmsg(struct socket *sock, struct msghdr *msg, size_t size); |
|---|
| 1118 | +int inet6_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, |
|---|
| 1119 | + int flags); |
|---|
| 1051 | 1120 | |
|---|
| 1052 | 1121 | /* |
|---|
| 1053 | 1122 | * reassembly.c |
|---|
| .. | .. |
|---|
| 1061 | 1130 | |
|---|
| 1062 | 1131 | int ip6_mc_source(int add, int omode, struct sock *sk, |
|---|
| 1063 | 1132 | struct group_source_req *pgsr); |
|---|
| 1064 | | -int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf); |
|---|
| 1133 | +int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf, |
|---|
| 1134 | + struct sockaddr_storage *list); |
|---|
| 1065 | 1135 | int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, |
|---|
| 1066 | | - struct group_filter __user *optval, int __user *optlen); |
|---|
| 1136 | + struct sockaddr_storage __user *p); |
|---|
| 1067 | 1137 | |
|---|
| 1068 | 1138 | #ifdef CONFIG_PROC_FS |
|---|
| 1069 | 1139 | int ac6_proc_init(struct net *net); |
|---|
| .. | .. |
|---|
| 1089 | 1159 | #endif |
|---|
| 1090 | 1160 | |
|---|
| 1091 | 1161 | #ifdef CONFIG_SYSCTL |
|---|
| 1092 | | -extern struct ctl_table ipv6_route_table_template[]; |
|---|
| 1093 | | - |
|---|
| 1094 | 1162 | struct ctl_table *ipv6_icmp_sysctl_init(struct net *net); |
|---|
| 1095 | 1163 | struct ctl_table *ipv6_route_sysctl_init(struct net *net); |
|---|
| 1096 | 1164 | int ipv6_sysctl_register(void); |
|---|
| .. | .. |
|---|
| 1103 | 1171 | const struct in6_addr *addr, unsigned int mode); |
|---|
| 1104 | 1172 | int ipv6_sock_mc_drop(struct sock *sk, int ifindex, |
|---|
| 1105 | 1173 | const struct in6_addr *addr); |
|---|
| 1174 | + |
|---|
| 1175 | +static inline int ip6_sock_set_v6only(struct sock *sk) |
|---|
| 1176 | +{ |
|---|
| 1177 | + if (inet_sk(sk)->inet_num) |
|---|
| 1178 | + return -EINVAL; |
|---|
| 1179 | + lock_sock(sk); |
|---|
| 1180 | + sk->sk_ipv6only = true; |
|---|
| 1181 | + release_sock(sk); |
|---|
| 1182 | + return 0; |
|---|
| 1183 | +} |
|---|
| 1184 | + |
|---|
| 1185 | +static inline void ip6_sock_set_recverr(struct sock *sk) |
|---|
| 1186 | +{ |
|---|
| 1187 | + lock_sock(sk); |
|---|
| 1188 | + inet6_sk(sk)->recverr = true; |
|---|
| 1189 | + release_sock(sk); |
|---|
| 1190 | +} |
|---|
| 1191 | + |
|---|
| 1192 | +static inline int __ip6_sock_set_addr_preferences(struct sock *sk, int val) |
|---|
| 1193 | +{ |
|---|
| 1194 | + unsigned int pref = 0; |
|---|
| 1195 | + unsigned int prefmask = ~0; |
|---|
| 1196 | + |
|---|
| 1197 | + /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */ |
|---|
| 1198 | + switch (val & (IPV6_PREFER_SRC_PUBLIC | |
|---|
| 1199 | + IPV6_PREFER_SRC_TMP | |
|---|
| 1200 | + IPV6_PREFER_SRC_PUBTMP_DEFAULT)) { |
|---|
| 1201 | + case IPV6_PREFER_SRC_PUBLIC: |
|---|
| 1202 | + pref |= IPV6_PREFER_SRC_PUBLIC; |
|---|
| 1203 | + prefmask &= ~(IPV6_PREFER_SRC_PUBLIC | |
|---|
| 1204 | + IPV6_PREFER_SRC_TMP); |
|---|
| 1205 | + break; |
|---|
| 1206 | + case IPV6_PREFER_SRC_TMP: |
|---|
| 1207 | + pref |= IPV6_PREFER_SRC_TMP; |
|---|
| 1208 | + prefmask &= ~(IPV6_PREFER_SRC_PUBLIC | |
|---|
| 1209 | + IPV6_PREFER_SRC_TMP); |
|---|
| 1210 | + break; |
|---|
| 1211 | + case IPV6_PREFER_SRC_PUBTMP_DEFAULT: |
|---|
| 1212 | + prefmask &= ~(IPV6_PREFER_SRC_PUBLIC | |
|---|
| 1213 | + IPV6_PREFER_SRC_TMP); |
|---|
| 1214 | + break; |
|---|
| 1215 | + case 0: |
|---|
| 1216 | + break; |
|---|
| 1217 | + default: |
|---|
| 1218 | + return -EINVAL; |
|---|
| 1219 | + } |
|---|
| 1220 | + |
|---|
| 1221 | + /* check HOME/COA conflicts */ |
|---|
| 1222 | + switch (val & (IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_COA)) { |
|---|
| 1223 | + case IPV6_PREFER_SRC_HOME: |
|---|
| 1224 | + prefmask &= ~IPV6_PREFER_SRC_COA; |
|---|
| 1225 | + break; |
|---|
| 1226 | + case IPV6_PREFER_SRC_COA: |
|---|
| 1227 | + pref |= IPV6_PREFER_SRC_COA; |
|---|
| 1228 | + break; |
|---|
| 1229 | + case 0: |
|---|
| 1230 | + break; |
|---|
| 1231 | + default: |
|---|
| 1232 | + return -EINVAL; |
|---|
| 1233 | + } |
|---|
| 1234 | + |
|---|
| 1235 | + /* check CGA/NONCGA conflicts */ |
|---|
| 1236 | + switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) { |
|---|
| 1237 | + case IPV6_PREFER_SRC_CGA: |
|---|
| 1238 | + case IPV6_PREFER_SRC_NONCGA: |
|---|
| 1239 | + case 0: |
|---|
| 1240 | + break; |
|---|
| 1241 | + default: |
|---|
| 1242 | + return -EINVAL; |
|---|
| 1243 | + } |
|---|
| 1244 | + |
|---|
| 1245 | + inet6_sk(sk)->srcprefs = (inet6_sk(sk)->srcprefs & prefmask) | pref; |
|---|
| 1246 | + return 0; |
|---|
| 1247 | +} |
|---|
| 1248 | + |
|---|
| 1249 | +static inline int ip6_sock_set_addr_preferences(struct sock *sk, int val) |
|---|
| 1250 | +{ |
|---|
| 1251 | + int ret; |
|---|
| 1252 | + |
|---|
| 1253 | + lock_sock(sk); |
|---|
| 1254 | + ret = __ip6_sock_set_addr_preferences(sk, val); |
|---|
| 1255 | + release_sock(sk); |
|---|
| 1256 | + return ret; |
|---|
| 1257 | +} |
|---|
| 1258 | + |
|---|
| 1259 | +static inline void ip6_sock_set_recvpktinfo(struct sock *sk) |
|---|
| 1260 | +{ |
|---|
| 1261 | + lock_sock(sk); |
|---|
| 1262 | + inet6_sk(sk)->rxopt.bits.rxinfo = true; |
|---|
| 1263 | + release_sock(sk); |
|---|
| 1264 | +} |
|---|
| 1265 | + |
|---|
| 1106 | 1266 | #endif /* _NET_IPV6_H */ |
|---|