.. | .. |
---|
| 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 */ |
---|