| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * common UDP/RAW code |
|---|
| 3 | 4 | * Linux INET6 implementation |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * Authors: |
|---|
| 6 | 7 | * Pedro Roque <roque@di.fc.ul.pt> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or |
|---|
| 9 | | - * modify it under the terms of the GNU General Public License |
|---|
| 10 | | - * as published by the Free Software Foundation; either version |
|---|
| 11 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 12 | 8 | */ |
|---|
| 13 | 9 | |
|---|
| 14 | 10 | #include <linux/capability.h> |
|---|
| .. | .. |
|---|
| 23 | 19 | #include <linux/route.h> |
|---|
| 24 | 20 | #include <linux/slab.h> |
|---|
| 25 | 21 | #include <linux/export.h> |
|---|
| 22 | +#include <linux/icmp.h> |
|---|
| 26 | 23 | |
|---|
| 27 | 24 | #include <net/ipv6.h> |
|---|
| 28 | 25 | #include <net/ndisc.h> |
|---|
| .. | .. |
|---|
| 63 | 60 | if (!fl6->flowi6_oif && ipv6_addr_is_multicast(&fl6->daddr)) |
|---|
| 64 | 61 | fl6->flowi6_oif = np->mcast_oif; |
|---|
| 65 | 62 | |
|---|
| 66 | | - security_sk_classify_flow(sk, flowi6_to_flowi(fl6)); |
|---|
| 63 | + security_sk_classify_flow(sk, flowi6_to_flowi_common(fl6)); |
|---|
| 67 | 64 | } |
|---|
| 68 | 65 | |
|---|
| 69 | 66 | int ip6_datagram_dst_update(struct sock *sk, bool fix_sk_saddr) |
|---|
| .. | .. |
|---|
| 79 | 76 | |
|---|
| 80 | 77 | if (np->sndflow && (np->flow_label & IPV6_FLOWLABEL_MASK)) { |
|---|
| 81 | 78 | flowlabel = fl6_sock_lookup(sk, np->flow_label); |
|---|
| 82 | | - if (!flowlabel) |
|---|
| 79 | + if (IS_ERR(flowlabel)) |
|---|
| 83 | 80 | return -EINVAL; |
|---|
| 84 | 81 | } |
|---|
| 85 | 82 | ip6_datagram_flow_key_init(&fl6, sk); |
|---|
| .. | .. |
|---|
| 259 | 256 | goto out; |
|---|
| 260 | 257 | } |
|---|
| 261 | 258 | |
|---|
| 262 | | - reuseport_has_conns(sk, true); |
|---|
| 259 | + reuseport_has_conns_set(sk); |
|---|
| 263 | 260 | sk->sk_state = TCP_ESTABLISHED; |
|---|
| 264 | 261 | sk_set_txhash(sk); |
|---|
| 265 | 262 | out: |
|---|
| .. | .. |
|---|
| 287 | 284 | return ip6_datagram_connect(sk, uaddr, addr_len); |
|---|
| 288 | 285 | } |
|---|
| 289 | 286 | EXPORT_SYMBOL_GPL(ip6_datagram_connect_v6_only); |
|---|
| 287 | + |
|---|
| 288 | +static void ipv6_icmp_error_rfc4884(const struct sk_buff *skb, |
|---|
| 289 | + struct sock_ee_data_rfc4884 *out) |
|---|
| 290 | +{ |
|---|
| 291 | + switch (icmp6_hdr(skb)->icmp6_type) { |
|---|
| 292 | + case ICMPV6_TIME_EXCEED: |
|---|
| 293 | + case ICMPV6_DEST_UNREACH: |
|---|
| 294 | + ip_icmp_error_rfc4884(skb, out, sizeof(struct icmp6hdr), |
|---|
| 295 | + icmp6_hdr(skb)->icmp6_datagram_len * 8); |
|---|
| 296 | + } |
|---|
| 297 | +} |
|---|
| 290 | 298 | |
|---|
| 291 | 299 | void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, |
|---|
| 292 | 300 | __be16 port, u32 info, u8 *payload) |
|---|
| .. | .. |
|---|
| 317 | 325 | serr->port = port; |
|---|
| 318 | 326 | |
|---|
| 319 | 327 | __skb_pull(skb, payload - skb->data); |
|---|
| 328 | + |
|---|
| 329 | + if (inet6_sk(sk)->recverr_rfc4884) |
|---|
| 330 | + ipv6_icmp_error_rfc4884(skb, &serr->ee.ee_rfc4884); |
|---|
| 331 | + |
|---|
| 320 | 332 | skb_reset_transport_header(skb); |
|---|
| 321 | 333 | |
|---|
| 322 | 334 | if (sock_queue_err_skb(sk, skb)) |
|---|
| .. | .. |
|---|
| 773 | 785 | case IPV6_2292PKTINFO: |
|---|
| 774 | 786 | { |
|---|
| 775 | 787 | struct net_device *dev = NULL; |
|---|
| 788 | + int src_idx; |
|---|
| 776 | 789 | |
|---|
| 777 | 790 | if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) { |
|---|
| 778 | 791 | err = -EINVAL; |
|---|
| .. | .. |
|---|
| 780 | 793 | } |
|---|
| 781 | 794 | |
|---|
| 782 | 795 | src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); |
|---|
| 796 | + src_idx = src_info->ipi6_ifindex; |
|---|
| 783 | 797 | |
|---|
| 784 | | - if (src_info->ipi6_ifindex) { |
|---|
| 798 | + if (src_idx) { |
|---|
| 785 | 799 | if (fl6->flowi6_oif && |
|---|
| 786 | | - src_info->ipi6_ifindex != fl6->flowi6_oif) |
|---|
| 800 | + src_idx != fl6->flowi6_oif && |
|---|
| 801 | + (sk->sk_bound_dev_if != fl6->flowi6_oif || |
|---|
| 802 | + !sk_dev_equal_l3scope(sk, src_idx))) |
|---|
| 787 | 803 | return -EINVAL; |
|---|
| 788 | | - fl6->flowi6_oif = src_info->ipi6_ifindex; |
|---|
| 804 | + fl6->flowi6_oif = src_idx; |
|---|
| 789 | 805 | } |
|---|
| 790 | 806 | |
|---|
| 791 | 807 | addr_type = __ipv6_addr_type(&src_info->ipi6_addr); |
|---|
| .. | .. |
|---|
| 1032 | 1048 | src = &sp->sk_v6_rcv_saddr; |
|---|
| 1033 | 1049 | seq_printf(seq, |
|---|
| 1034 | 1050 | "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " |
|---|
| 1035 | | - "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d\n", |
|---|
| 1051 | + "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %u\n", |
|---|
| 1036 | 1052 | bucket, |
|---|
| 1037 | 1053 | src->s6_addr32[0], src->s6_addr32[1], |
|---|
| 1038 | 1054 | src->s6_addr32[2], src->s6_addr32[3], srcp, |
|---|