diff options
Diffstat (limited to 'net/ipv6')
| -rw-r--r-- | net/ipv6/addrconf.c | 11 | ||||
| -rw-r--r-- | net/ipv6/af_inet6.c | 14 | ||||
| -rw-r--r-- | net/ipv6/datagram.c | 11 | ||||
| -rw-r--r-- | net/ipv6/esp6.c | 2 | ||||
| -rw-r--r-- | net/ipv6/fou6.c | 19 | ||||
| -rw-r--r-- | net/ipv6/icmp.c | 8 | ||||
| -rw-r--r-- | net/ipv6/ip6_gre.c | 92 | ||||
| -rw-r--r-- | net/ipv6/ip6mr.c | 7 | ||||
| -rw-r--r-- | net/ipv6/netfilter.c | 4 | ||||
| -rw-r--r-- | net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | 1 | ||||
| -rw-r--r-- | net/ipv6/route.c | 46 | ||||
| -rw-r--r-- | net/ipv6/seg6.c | 4 | ||||
| -rw-r--r-- | net/ipv6/seg6_iptunnel.c | 2 | ||||
| -rw-r--r-- | net/ipv6/sit.c | 3 | ||||
| -rw-r--r-- | net/ipv6/udp.c | 38 | ||||
| -rw-r--r-- | net/ipv6/udp_impl.h | 1 | ||||
| -rw-r--r-- | net/ipv6/udplite.c | 1 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_tunnel.c | 2 |
18 files changed, 167 insertions, 99 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 8eeec6eb2bd3..72ffd3d760ff 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -1165,7 +1165,8 @@ check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires) | |||
| 1165 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | 1165 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
| 1166 | if (ifa == ifp) | 1166 | if (ifa == ifp) |
| 1167 | continue; | 1167 | continue; |
| 1168 | if (!ipv6_prefix_equal(&ifa->addr, &ifp->addr, | 1168 | if (ifa->prefix_len != ifp->prefix_len || |
| 1169 | !ipv6_prefix_equal(&ifa->addr, &ifp->addr, | ||
| 1169 | ifp->prefix_len)) | 1170 | ifp->prefix_len)) |
| 1170 | continue; | 1171 | continue; |
| 1171 | if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE)) | 1172 | if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE)) |
| @@ -3495,8 +3496,8 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 3495 | 3496 | ||
| 3496 | if (!addrconf_link_ready(dev)) { | 3497 | if (!addrconf_link_ready(dev)) { |
| 3497 | /* device is not ready yet. */ | 3498 | /* device is not ready yet. */ |
| 3498 | pr_info("ADDRCONF(NETDEV_UP): %s: link is not ready\n", | 3499 | pr_debug("ADDRCONF(NETDEV_UP): %s: link is not ready\n", |
| 3499 | dev->name); | 3500 | dev->name); |
| 3500 | break; | 3501 | break; |
| 3501 | } | 3502 | } |
| 3502 | 3503 | ||
| @@ -5120,6 +5121,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, | |||
| 5120 | if (idev) { | 5121 | if (idev) { |
| 5121 | err = in6_dump_addrs(idev, skb, cb, s_ip_idx, | 5122 | err = in6_dump_addrs(idev, skb, cb, s_ip_idx, |
| 5122 | &fillargs); | 5123 | &fillargs); |
| 5124 | if (err > 0) | ||
| 5125 | err = 0; | ||
| 5123 | } | 5126 | } |
| 5124 | goto put_tgt_net; | 5127 | goto put_tgt_net; |
| 5125 | } | 5128 | } |
| @@ -5154,7 +5157,7 @@ put_tgt_net: | |||
| 5154 | if (fillargs.netnsid >= 0) | 5157 | if (fillargs.netnsid >= 0) |
| 5155 | put_net(tgt_net); | 5158 | put_net(tgt_net); |
| 5156 | 5159 | ||
| 5157 | return err < 0 ? err : skb->len; | 5160 | return skb->len ? : err; |
| 5158 | } | 5161 | } |
| 5159 | 5162 | ||
| 5160 | static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | 5163 | static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 0bfb6cc0a30a..d99753b5e39b 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
| @@ -310,6 +310,7 @@ static int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len, | |||
| 310 | 310 | ||
| 311 | /* Check if the address belongs to the host. */ | 311 | /* Check if the address belongs to the host. */ |
| 312 | if (addr_type == IPV6_ADDR_MAPPED) { | 312 | if (addr_type == IPV6_ADDR_MAPPED) { |
| 313 | struct net_device *dev = NULL; | ||
| 313 | int chk_addr_ret; | 314 | int chk_addr_ret; |
| 314 | 315 | ||
| 315 | /* Binding to v4-mapped address on a v6-only socket | 316 | /* Binding to v4-mapped address on a v6-only socket |
| @@ -320,9 +321,20 @@ static int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len, | |||
| 320 | goto out; | 321 | goto out; |
| 321 | } | 322 | } |
| 322 | 323 | ||
| 324 | rcu_read_lock(); | ||
| 325 | if (sk->sk_bound_dev_if) { | ||
| 326 | dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); | ||
| 327 | if (!dev) { | ||
| 328 | err = -ENODEV; | ||
| 329 | goto out_unlock; | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 323 | /* Reproduce AF_INET checks to make the bindings consistent */ | 333 | /* Reproduce AF_INET checks to make the bindings consistent */ |
| 324 | v4addr = addr->sin6_addr.s6_addr32[3]; | 334 | v4addr = addr->sin6_addr.s6_addr32[3]; |
| 325 | chk_addr_ret = inet_addr_type(net, v4addr); | 335 | chk_addr_ret = inet_addr_type_dev_table(net, dev, v4addr); |
| 336 | rcu_read_unlock(); | ||
| 337 | |||
| 326 | if (!inet_can_nonlocal_bind(net, inet) && | 338 | if (!inet_can_nonlocal_bind(net, inet) && |
| 327 | v4addr != htonl(INADDR_ANY) && | 339 | v4addr != htonl(INADDR_ANY) && |
| 328 | chk_addr_ret != RTN_LOCAL && | 340 | chk_addr_ret != RTN_LOCAL && |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index bde08aa549f3..ee4a4e54d016 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
| @@ -341,6 +341,7 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info) | |||
| 341 | skb_reset_network_header(skb); | 341 | skb_reset_network_header(skb); |
| 342 | iph = ipv6_hdr(skb); | 342 | iph = ipv6_hdr(skb); |
| 343 | iph->daddr = fl6->daddr; | 343 | iph->daddr = fl6->daddr; |
| 344 | ip6_flow_hdr(iph, 0, 0); | ||
| 344 | 345 | ||
| 345 | serr = SKB_EXT_ERR(skb); | 346 | serr = SKB_EXT_ERR(skb); |
| 346 | serr->ee.ee_errno = err; | 347 | serr->ee.ee_errno = err; |
| @@ -700,17 +701,15 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, | |||
| 700 | } | 701 | } |
| 701 | if (np->rxopt.bits.rxorigdstaddr) { | 702 | if (np->rxopt.bits.rxorigdstaddr) { |
| 702 | struct sockaddr_in6 sin6; | 703 | struct sockaddr_in6 sin6; |
| 703 | __be16 *ports; | 704 | __be16 _ports[2], *ports; |
| 704 | int end; | ||
| 705 | 705 | ||
| 706 | end = skb_transport_offset(skb) + 4; | 706 | ports = skb_header_pointer(skb, skb_transport_offset(skb), |
| 707 | if (end <= 0 || pskb_may_pull(skb, end)) { | 707 | sizeof(_ports), &_ports); |
| 708 | if (ports) { | ||
| 708 | /* All current transport protocols have the port numbers in the | 709 | /* All current transport protocols have the port numbers in the |
| 709 | * first four bytes of the transport header and this function is | 710 | * first four bytes of the transport header and this function is |
| 710 | * written with this assumption in mind. | 711 | * written with this assumption in mind. |
| 711 | */ | 712 | */ |
| 712 | ports = (__be16 *)skb_transport_header(skb); | ||
| 713 | |||
| 714 | sin6.sin6_family = AF_INET6; | 713 | sin6.sin6_family = AF_INET6; |
| 715 | sin6.sin6_addr = ipv6_hdr(skb)->daddr; | 714 | sin6.sin6_addr = ipv6_hdr(skb)->daddr; |
| 716 | sin6.sin6_port = ports[1]; | 715 | sin6.sin6_port = ports[1]; |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 5afe9f83374d..239d4a65ad6e 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
| @@ -296,7 +296,7 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info | |||
| 296 | skb->len += tailen; | 296 | skb->len += tailen; |
| 297 | skb->data_len += tailen; | 297 | skb->data_len += tailen; |
| 298 | skb->truesize += tailen; | 298 | skb->truesize += tailen; |
| 299 | if (sk) | 299 | if (sk && sk_fullsock(sk)) |
| 300 | refcount_add(tailen, &sk->sk_wmem_alloc); | 300 | refcount_add(tailen, &sk->sk_wmem_alloc); |
| 301 | 301 | ||
| 302 | goto out; | 302 | goto out; |
diff --git a/net/ipv6/fou6.c b/net/ipv6/fou6.c index bd675c61deb1..867474abe269 100644 --- a/net/ipv6/fou6.c +++ b/net/ipv6/fou6.c | |||
| @@ -72,7 +72,7 @@ static int gue6_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | |||
| 72 | 72 | ||
| 73 | static int gue6_err_proto_handler(int proto, struct sk_buff *skb, | 73 | static int gue6_err_proto_handler(int proto, struct sk_buff *skb, |
| 74 | struct inet6_skb_parm *opt, | 74 | struct inet6_skb_parm *opt, |
| 75 | u8 type, u8 code, int offset, u32 info) | 75 | u8 type, u8 code, int offset, __be32 info) |
| 76 | { | 76 | { |
| 77 | const struct inet6_protocol *ipprot; | 77 | const struct inet6_protocol *ipprot; |
| 78 | 78 | ||
| @@ -90,10 +90,11 @@ static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 90 | { | 90 | { |
| 91 | int transport_offset = skb_transport_offset(skb); | 91 | int transport_offset = skb_transport_offset(skb); |
| 92 | struct guehdr *guehdr; | 92 | struct guehdr *guehdr; |
| 93 | size_t optlen; | 93 | size_t len, optlen; |
| 94 | int ret; | 94 | int ret; |
| 95 | 95 | ||
| 96 | if (skb->len < sizeof(struct udphdr) + sizeof(struct guehdr)) | 96 | len = sizeof(struct udphdr) + sizeof(struct guehdr); |
| 97 | if (!pskb_may_pull(skb, len)) | ||
| 97 | return -EINVAL; | 98 | return -EINVAL; |
| 98 | 99 | ||
| 99 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; | 100 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; |
| @@ -128,9 +129,21 @@ static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 128 | 129 | ||
| 129 | optlen = guehdr->hlen << 2; | 130 | optlen = guehdr->hlen << 2; |
| 130 | 131 | ||
| 132 | if (!pskb_may_pull(skb, len + optlen)) | ||
| 133 | return -EINVAL; | ||
| 134 | |||
| 135 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; | ||
| 131 | if (validate_gue_flags(guehdr, optlen)) | 136 | if (validate_gue_flags(guehdr, optlen)) |
| 132 | return -EINVAL; | 137 | return -EINVAL; |
| 133 | 138 | ||
| 139 | /* Handling exceptions for direct UDP encapsulation in GUE would lead to | ||
| 140 | * recursion. Besides, this kind of encapsulation can't even be | ||
| 141 | * configured currently. Discard this. | ||
| 142 | */ | ||
| 143 | if (guehdr->proto_ctype == IPPROTO_UDP || | ||
| 144 | guehdr->proto_ctype == IPPROTO_UDPLITE) | ||
| 145 | return -EOPNOTSUPP; | ||
| 146 | |||
| 134 | skb_set_transport_header(skb, -(int)sizeof(struct icmp6hdr)); | 147 | skb_set_transport_header(skb, -(int)sizeof(struct icmp6hdr)); |
| 135 | ret = gue6_err_proto_handler(guehdr->proto_ctype, skb, | 148 | ret = gue6_err_proto_handler(guehdr->proto_ctype, skb, |
| 136 | opt, type, code, offset, info); | 149 | opt, type, code, offset, info); |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 5d7aa2c2770c..bbcdfd299692 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
| @@ -423,10 +423,10 @@ static int icmp6_iif(const struct sk_buff *skb) | |||
| 423 | static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, | 423 | static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, |
| 424 | const struct in6_addr *force_saddr) | 424 | const struct in6_addr *force_saddr) |
| 425 | { | 425 | { |
| 426 | struct net *net = dev_net(skb->dev); | ||
| 427 | struct inet6_dev *idev = NULL; | 426 | struct inet6_dev *idev = NULL; |
| 428 | struct ipv6hdr *hdr = ipv6_hdr(skb); | 427 | struct ipv6hdr *hdr = ipv6_hdr(skb); |
| 429 | struct sock *sk; | 428 | struct sock *sk; |
| 429 | struct net *net; | ||
| 430 | struct ipv6_pinfo *np; | 430 | struct ipv6_pinfo *np; |
| 431 | const struct in6_addr *saddr = NULL; | 431 | const struct in6_addr *saddr = NULL; |
| 432 | struct dst_entry *dst; | 432 | struct dst_entry *dst; |
| @@ -437,12 +437,16 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, | |||
| 437 | int iif = 0; | 437 | int iif = 0; |
| 438 | int addr_type = 0; | 438 | int addr_type = 0; |
| 439 | int len; | 439 | int len; |
| 440 | u32 mark = IP6_REPLY_MARK(net, skb->mark); | 440 | u32 mark; |
| 441 | 441 | ||
| 442 | if ((u8 *)hdr < skb->head || | 442 | if ((u8 *)hdr < skb->head || |
| 443 | (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) | 443 | (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) |
| 444 | return; | 444 | return; |
| 445 | 445 | ||
| 446 | if (!skb->dev) | ||
| 447 | return; | ||
| 448 | net = dev_net(skb->dev); | ||
| 449 | mark = IP6_REPLY_MARK(net, skb->mark); | ||
| 446 | /* | 450 | /* |
| 447 | * Make sure we respect the rules | 451 | * Make sure we respect the rules |
| 448 | * i.e. RFC 1885 2.4(e) | 452 | * i.e. RFC 1885 2.4(e) |
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 09d0826742f8..26f25b6e2833 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
| @@ -534,13 +534,9 @@ static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len, | |||
| 534 | struct ip6_tnl *tunnel; | 534 | struct ip6_tnl *tunnel; |
| 535 | u8 ver; | 535 | u8 ver; |
| 536 | 536 | ||
| 537 | if (unlikely(!pskb_may_pull(skb, sizeof(*ershdr)))) | ||
| 538 | return PACKET_REJECT; | ||
| 539 | |||
| 540 | ipv6h = ipv6_hdr(skb); | 537 | ipv6h = ipv6_hdr(skb); |
| 541 | ershdr = (struct erspan_base_hdr *)skb->data; | 538 | ershdr = (struct erspan_base_hdr *)skb->data; |
| 542 | ver = ershdr->ver; | 539 | ver = ershdr->ver; |
| 543 | tpi->key = cpu_to_be32(get_session_id(ershdr)); | ||
| 544 | 540 | ||
| 545 | tunnel = ip6gre_tunnel_lookup(skb->dev, | 541 | tunnel = ip6gre_tunnel_lookup(skb->dev, |
| 546 | &ipv6h->saddr, &ipv6h->daddr, tpi->key, | 542 | &ipv6h->saddr, &ipv6h->daddr, tpi->key, |
| @@ -922,6 +918,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, | |||
| 922 | __u8 dsfield = false; | 918 | __u8 dsfield = false; |
| 923 | struct flowi6 fl6; | 919 | struct flowi6 fl6; |
| 924 | int err = -EINVAL; | 920 | int err = -EINVAL; |
| 921 | __be16 proto; | ||
| 925 | __u32 mtu; | 922 | __u32 mtu; |
| 926 | int nhoff; | 923 | int nhoff; |
| 927 | int thoff; | 924 | int thoff; |
| @@ -1035,8 +1032,9 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, | |||
| 1035 | } | 1032 | } |
| 1036 | 1033 | ||
| 1037 | /* Push GRE header. */ | 1034 | /* Push GRE header. */ |
| 1038 | gre_build_header(skb, 8, TUNNEL_SEQ, | 1035 | proto = (t->parms.erspan_ver == 1) ? htons(ETH_P_ERSPAN) |
| 1039 | htons(ETH_P_ERSPAN), 0, htonl(t->o_seqno++)); | 1036 | : htons(ETH_P_ERSPAN2); |
| 1037 | gre_build_header(skb, 8, TUNNEL_SEQ, proto, 0, htonl(t->o_seqno++)); | ||
| 1040 | 1038 | ||
| 1041 | /* TooBig packet may have updated dst->dev's mtu */ | 1039 | /* TooBig packet may have updated dst->dev's mtu */ |
| 1042 | if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu) | 1040 | if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu) |
| @@ -1169,6 +1167,10 @@ static void ip6gre_tnl_copy_tnl_parm(struct ip6_tnl *t, | |||
| 1169 | t->parms.i_flags = p->i_flags; | 1167 | t->parms.i_flags = p->i_flags; |
| 1170 | t->parms.o_flags = p->o_flags; | 1168 | t->parms.o_flags = p->o_flags; |
| 1171 | t->parms.fwmark = p->fwmark; | 1169 | t->parms.fwmark = p->fwmark; |
| 1170 | t->parms.erspan_ver = p->erspan_ver; | ||
| 1171 | t->parms.index = p->index; | ||
| 1172 | t->parms.dir = p->dir; | ||
| 1173 | t->parms.hwid = p->hwid; | ||
| 1172 | dst_cache_reset(&t->dst_cache); | 1174 | dst_cache_reset(&t->dst_cache); |
| 1173 | } | 1175 | } |
| 1174 | 1176 | ||
| @@ -1717,6 +1719,27 @@ static int ip6erspan_tap_validate(struct nlattr *tb[], struct nlattr *data[], | |||
| 1717 | return 0; | 1719 | return 0; |
| 1718 | } | 1720 | } |
| 1719 | 1721 | ||
| 1722 | static void ip6erspan_set_version(struct nlattr *data[], | ||
| 1723 | struct __ip6_tnl_parm *parms) | ||
| 1724 | { | ||
| 1725 | if (!data) | ||
| 1726 | return; | ||
| 1727 | |||
| 1728 | parms->erspan_ver = 1; | ||
| 1729 | if (data[IFLA_GRE_ERSPAN_VER]) | ||
| 1730 | parms->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]); | ||
| 1731 | |||
| 1732 | if (parms->erspan_ver == 1) { | ||
| 1733 | if (data[IFLA_GRE_ERSPAN_INDEX]) | ||
| 1734 | parms->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]); | ||
| 1735 | } else if (parms->erspan_ver == 2) { | ||
| 1736 | if (data[IFLA_GRE_ERSPAN_DIR]) | ||
| 1737 | parms->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]); | ||
| 1738 | if (data[IFLA_GRE_ERSPAN_HWID]) | ||
| 1739 | parms->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]); | ||
| 1740 | } | ||
| 1741 | } | ||
| 1742 | |||
| 1720 | static void ip6gre_netlink_parms(struct nlattr *data[], | 1743 | static void ip6gre_netlink_parms(struct nlattr *data[], |
| 1721 | struct __ip6_tnl_parm *parms) | 1744 | struct __ip6_tnl_parm *parms) |
| 1722 | { | 1745 | { |
| @@ -1765,20 +1788,6 @@ static void ip6gre_netlink_parms(struct nlattr *data[], | |||
| 1765 | 1788 | ||
| 1766 | if (data[IFLA_GRE_COLLECT_METADATA]) | 1789 | if (data[IFLA_GRE_COLLECT_METADATA]) |
| 1767 | parms->collect_md = true; | 1790 | parms->collect_md = true; |
| 1768 | |||
| 1769 | parms->erspan_ver = 1; | ||
| 1770 | if (data[IFLA_GRE_ERSPAN_VER]) | ||
| 1771 | parms->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]); | ||
| 1772 | |||
| 1773 | if (parms->erspan_ver == 1) { | ||
| 1774 | if (data[IFLA_GRE_ERSPAN_INDEX]) | ||
| 1775 | parms->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]); | ||
| 1776 | } else if (parms->erspan_ver == 2) { | ||
| 1777 | if (data[IFLA_GRE_ERSPAN_DIR]) | ||
| 1778 | parms->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]); | ||
| 1779 | if (data[IFLA_GRE_ERSPAN_HWID]) | ||
| 1780 | parms->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]); | ||
| 1781 | } | ||
| 1782 | } | 1791 | } |
| 1783 | 1792 | ||
| 1784 | static int ip6gre_tap_init(struct net_device *dev) | 1793 | static int ip6gre_tap_init(struct net_device *dev) |
| @@ -2025,9 +2034,9 @@ static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[], | |||
| 2025 | struct nlattr *data[], | 2034 | struct nlattr *data[], |
| 2026 | struct netlink_ext_ack *extack) | 2035 | struct netlink_ext_ack *extack) |
| 2027 | { | 2036 | { |
| 2028 | struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); | 2037 | struct ip6_tnl *t = netdev_priv(dev); |
| 2038 | struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id); | ||
| 2029 | struct __ip6_tnl_parm p; | 2039 | struct __ip6_tnl_parm p; |
| 2030 | struct ip6_tnl *t; | ||
| 2031 | 2040 | ||
| 2032 | t = ip6gre_changelink_common(dev, tb, data, &p, extack); | 2041 | t = ip6gre_changelink_common(dev, tb, data, &p, extack); |
| 2033 | if (IS_ERR(t)) | 2042 | if (IS_ERR(t)) |
| @@ -2096,12 +2105,31 @@ static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
| 2096 | { | 2105 | { |
| 2097 | struct ip6_tnl *t = netdev_priv(dev); | 2106 | struct ip6_tnl *t = netdev_priv(dev); |
| 2098 | struct __ip6_tnl_parm *p = &t->parms; | 2107 | struct __ip6_tnl_parm *p = &t->parms; |
| 2108 | __be16 o_flags = p->o_flags; | ||
| 2109 | |||
| 2110 | if (p->erspan_ver == 1 || p->erspan_ver == 2) { | ||
| 2111 | if (!p->collect_md) | ||
| 2112 | o_flags |= TUNNEL_KEY; | ||
| 2113 | |||
| 2114 | if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, p->erspan_ver)) | ||
| 2115 | goto nla_put_failure; | ||
| 2116 | |||
| 2117 | if (p->erspan_ver == 1) { | ||
| 2118 | if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index)) | ||
| 2119 | goto nla_put_failure; | ||
| 2120 | } else { | ||
| 2121 | if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, p->dir)) | ||
| 2122 | goto nla_put_failure; | ||
| 2123 | if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, p->hwid)) | ||
| 2124 | goto nla_put_failure; | ||
| 2125 | } | ||
| 2126 | } | ||
| 2099 | 2127 | ||
| 2100 | if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || | 2128 | if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || |
| 2101 | nla_put_be16(skb, IFLA_GRE_IFLAGS, | 2129 | nla_put_be16(skb, IFLA_GRE_IFLAGS, |
| 2102 | gre_tnl_flags_to_gre_flags(p->i_flags)) || | 2130 | gre_tnl_flags_to_gre_flags(p->i_flags)) || |
| 2103 | nla_put_be16(skb, IFLA_GRE_OFLAGS, | 2131 | nla_put_be16(skb, IFLA_GRE_OFLAGS, |
| 2104 | gre_tnl_flags_to_gre_flags(p->o_flags)) || | 2132 | gre_tnl_flags_to_gre_flags(o_flags)) || |
| 2105 | nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || | 2133 | nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || |
| 2106 | nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || | 2134 | nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || |
| 2107 | nla_put_in6_addr(skb, IFLA_GRE_LOCAL, &p->laddr) || | 2135 | nla_put_in6_addr(skb, IFLA_GRE_LOCAL, &p->laddr) || |
| @@ -2110,8 +2138,7 @@ static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
| 2110 | nla_put_u8(skb, IFLA_GRE_ENCAP_LIMIT, p->encap_limit) || | 2138 | nla_put_u8(skb, IFLA_GRE_ENCAP_LIMIT, p->encap_limit) || |
| 2111 | nla_put_be32(skb, IFLA_GRE_FLOWINFO, p->flowinfo) || | 2139 | nla_put_be32(skb, IFLA_GRE_FLOWINFO, p->flowinfo) || |
| 2112 | nla_put_u32(skb, IFLA_GRE_FLAGS, p->flags) || | 2140 | nla_put_u32(skb, IFLA_GRE_FLAGS, p->flags) || |
| 2113 | nla_put_u32(skb, IFLA_GRE_FWMARK, p->fwmark) || | 2141 | nla_put_u32(skb, IFLA_GRE_FWMARK, p->fwmark)) |
| 2114 | nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index)) | ||
| 2115 | goto nla_put_failure; | 2142 | goto nla_put_failure; |
| 2116 | 2143 | ||
| 2117 | if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE, | 2144 | if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE, |
| @@ -2129,19 +2156,6 @@ static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
| 2129 | goto nla_put_failure; | 2156 | goto nla_put_failure; |
| 2130 | } | 2157 | } |
| 2131 | 2158 | ||
| 2132 | if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, p->erspan_ver)) | ||
| 2133 | goto nla_put_failure; | ||
| 2134 | |||
| 2135 | if (p->erspan_ver == 1) { | ||
| 2136 | if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index)) | ||
| 2137 | goto nla_put_failure; | ||
| 2138 | } else if (p->erspan_ver == 2) { | ||
| 2139 | if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, p->dir)) | ||
| 2140 | goto nla_put_failure; | ||
| 2141 | if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, p->hwid)) | ||
| 2142 | goto nla_put_failure; | ||
| 2143 | } | ||
| 2144 | |||
| 2145 | return 0; | 2159 | return 0; |
| 2146 | 2160 | ||
| 2147 | nla_put_failure: | 2161 | nla_put_failure: |
| @@ -2196,6 +2210,7 @@ static int ip6erspan_newlink(struct net *src_net, struct net_device *dev, | |||
| 2196 | int err; | 2210 | int err; |
| 2197 | 2211 | ||
| 2198 | ip6gre_netlink_parms(data, &nt->parms); | 2212 | ip6gre_netlink_parms(data, &nt->parms); |
| 2213 | ip6erspan_set_version(data, &nt->parms); | ||
| 2199 | ign = net_generic(net, ip6gre_net_id); | 2214 | ign = net_generic(net, ip6gre_net_id); |
| 2200 | 2215 | ||
| 2201 | if (nt->parms.collect_md) { | 2216 | if (nt->parms.collect_md) { |
| @@ -2241,6 +2256,7 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], | |||
| 2241 | if (IS_ERR(t)) | 2256 | if (IS_ERR(t)) |
| 2242 | return PTR_ERR(t); | 2257 | return PTR_ERR(t); |
| 2243 | 2258 | ||
| 2259 | ip6erspan_set_version(data, &p); | ||
| 2244 | ip6gre_tunnel_unlink_md(ign, t); | 2260 | ip6gre_tunnel_unlink_md(ign, t); |
| 2245 | ip6gre_tunnel_unlink(ign, t); | 2261 | ip6gre_tunnel_unlink(ign, t); |
| 2246 | ip6erspan_tnl_change(t, &p, !tb[IFLA_MTU]); | 2262 | ip6erspan_tnl_change(t, &p, !tb[IFLA_MTU]); |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 30337b38274b..cc01aa3f2b5e 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
| @@ -1516,6 +1516,9 @@ static void mroute_clean_tables(struct mr_table *mrt, bool all) | |||
| 1516 | continue; | 1516 | continue; |
| 1517 | rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params); | 1517 | rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params); |
| 1518 | list_del_rcu(&c->list); | 1518 | list_del_rcu(&c->list); |
| 1519 | call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), | ||
| 1520 | FIB_EVENT_ENTRY_DEL, | ||
| 1521 | (struct mfc6_cache *)c, mrt->id); | ||
| 1519 | mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE); | 1522 | mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE); |
| 1520 | mr_cache_put(c); | 1523 | mr_cache_put(c); |
| 1521 | } | 1524 | } |
| @@ -1524,10 +1527,6 @@ static void mroute_clean_tables(struct mr_table *mrt, bool all) | |||
| 1524 | spin_lock_bh(&mfc_unres_lock); | 1527 | spin_lock_bh(&mfc_unres_lock); |
| 1525 | list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { | 1528 | list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { |
| 1526 | list_del(&c->list); | 1529 | list_del(&c->list); |
| 1527 | call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), | ||
| 1528 | FIB_EVENT_ENTRY_DEL, | ||
| 1529 | (struct mfc6_cache *)c, | ||
| 1530 | mrt->id); | ||
| 1531 | mr6_netlink_event(mrt, (struct mfc6_cache *)c, | 1530 | mr6_netlink_event(mrt, (struct mfc6_cache *)c, |
| 1532 | RTM_DELROUTE); | 1531 | RTM_DELROUTE); |
| 1533 | ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c); | 1532 | ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c); |
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 8b075f0bc351..6d0b1f3e927b 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
| @@ -23,9 +23,11 @@ int ip6_route_me_harder(struct net *net, struct sk_buff *skb) | |||
| 23 | struct sock *sk = sk_to_full_sk(skb->sk); | 23 | struct sock *sk = sk_to_full_sk(skb->sk); |
| 24 | unsigned int hh_len; | 24 | unsigned int hh_len; |
| 25 | struct dst_entry *dst; | 25 | struct dst_entry *dst; |
| 26 | int strict = (ipv6_addr_type(&iph->daddr) & | ||
| 27 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); | ||
| 26 | struct flowi6 fl6 = { | 28 | struct flowi6 fl6 = { |
| 27 | .flowi6_oif = sk && sk->sk_bound_dev_if ? sk->sk_bound_dev_if : | 29 | .flowi6_oif = sk && sk->sk_bound_dev_if ? sk->sk_bound_dev_if : |
| 28 | rt6_need_strict(&iph->daddr) ? skb_dst(skb)->dev->ifindex : 0, | 30 | strict ? skb_dst(skb)->dev->ifindex : 0, |
| 29 | .flowi6_mark = skb->mark, | 31 | .flowi6_mark = skb->mark, |
| 30 | .flowi6_uid = sock_net_uid(net, sk), | 32 | .flowi6_uid = sock_net_uid(net, sk), |
| 31 | .daddr = iph->daddr, | 33 | .daddr = iph->daddr, |
diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c index 23022447eb49..7a41ee3c11b4 100644 --- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | |||
| @@ -226,6 +226,7 @@ int nf_nat_icmpv6_reply_translation(struct sk_buff *skb, | |||
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); | 228 | nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); |
| 229 | target.dst.protonum = IPPROTO_ICMPV6; | ||
| 229 | if (!nf_nat_ipv6_manip_pkt(skb, 0, &target, manip)) | 230 | if (!nf_nat_ipv6_manip_pkt(skb, 0, &target, manip)) |
| 230 | return 0; | 231 | return 0; |
| 231 | 232 | ||
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 40b225f87d5e..ce15dc4ccbfa 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -1274,18 +1274,29 @@ static DEFINE_SPINLOCK(rt6_exception_lock); | |||
| 1274 | static void rt6_remove_exception(struct rt6_exception_bucket *bucket, | 1274 | static void rt6_remove_exception(struct rt6_exception_bucket *bucket, |
| 1275 | struct rt6_exception *rt6_ex) | 1275 | struct rt6_exception *rt6_ex) |
| 1276 | { | 1276 | { |
| 1277 | struct fib6_info *from; | ||
| 1277 | struct net *net; | 1278 | struct net *net; |
| 1278 | 1279 | ||
| 1279 | if (!bucket || !rt6_ex) | 1280 | if (!bucket || !rt6_ex) |
| 1280 | return; | 1281 | return; |
| 1281 | 1282 | ||
| 1282 | net = dev_net(rt6_ex->rt6i->dst.dev); | 1283 | net = dev_net(rt6_ex->rt6i->dst.dev); |
| 1284 | net->ipv6.rt6_stats->fib_rt_cache--; | ||
| 1285 | |||
| 1286 | /* purge completely the exception to allow releasing the held resources: | ||
| 1287 | * some [sk] cache may keep the dst around for unlimited time | ||
| 1288 | */ | ||
| 1289 | from = rcu_dereference_protected(rt6_ex->rt6i->from, | ||
| 1290 | lockdep_is_held(&rt6_exception_lock)); | ||
| 1291 | rcu_assign_pointer(rt6_ex->rt6i->from, NULL); | ||
| 1292 | fib6_info_release(from); | ||
| 1293 | dst_dev_put(&rt6_ex->rt6i->dst); | ||
| 1294 | |||
| 1283 | hlist_del_rcu(&rt6_ex->hlist); | 1295 | hlist_del_rcu(&rt6_ex->hlist); |
| 1284 | dst_release(&rt6_ex->rt6i->dst); | 1296 | dst_release(&rt6_ex->rt6i->dst); |
| 1285 | kfree_rcu(rt6_ex, rcu); | 1297 | kfree_rcu(rt6_ex, rcu); |
| 1286 | WARN_ON_ONCE(!bucket->depth); | 1298 | WARN_ON_ONCE(!bucket->depth); |
| 1287 | bucket->depth--; | 1299 | bucket->depth--; |
| 1288 | net->ipv6.rt6_stats->fib_rt_cache--; | ||
| 1289 | } | 1300 | } |
| 1290 | 1301 | ||
| 1291 | /* Remove oldest rt6_ex in bucket and free the memory | 1302 | /* Remove oldest rt6_ex in bucket and free the memory |
| @@ -1599,15 +1610,15 @@ static int rt6_remove_exception_rt(struct rt6_info *rt) | |||
| 1599 | static void rt6_update_exception_stamp_rt(struct rt6_info *rt) | 1610 | static void rt6_update_exception_stamp_rt(struct rt6_info *rt) |
| 1600 | { | 1611 | { |
| 1601 | struct rt6_exception_bucket *bucket; | 1612 | struct rt6_exception_bucket *bucket; |
| 1602 | struct fib6_info *from = rt->from; | ||
| 1603 | struct in6_addr *src_key = NULL; | 1613 | struct in6_addr *src_key = NULL; |
| 1604 | struct rt6_exception *rt6_ex; | 1614 | struct rt6_exception *rt6_ex; |
| 1605 | 1615 | struct fib6_info *from; | |
| 1606 | if (!from || | ||
| 1607 | !(rt->rt6i_flags & RTF_CACHE)) | ||
| 1608 | return; | ||
| 1609 | 1616 | ||
| 1610 | rcu_read_lock(); | 1617 | rcu_read_lock(); |
| 1618 | from = rcu_dereference(rt->from); | ||
| 1619 | if (!from || !(rt->rt6i_flags & RTF_CACHE)) | ||
| 1620 | goto unlock; | ||
| 1621 | |||
| 1611 | bucket = rcu_dereference(from->rt6i_exception_bucket); | 1622 | bucket = rcu_dereference(from->rt6i_exception_bucket); |
| 1612 | 1623 | ||
| 1613 | #ifdef CONFIG_IPV6_SUBTREES | 1624 | #ifdef CONFIG_IPV6_SUBTREES |
| @@ -1626,6 +1637,7 @@ static void rt6_update_exception_stamp_rt(struct rt6_info *rt) | |||
| 1626 | if (rt6_ex) | 1637 | if (rt6_ex) |
| 1627 | rt6_ex->stamp = jiffies; | 1638 | rt6_ex->stamp = jiffies; |
| 1628 | 1639 | ||
| 1640 | unlock: | ||
| 1629 | rcu_read_unlock(); | 1641 | rcu_read_unlock(); |
| 1630 | } | 1642 | } |
| 1631 | 1643 | ||
| @@ -2742,20 +2754,24 @@ static int ip6_route_check_nh_onlink(struct net *net, | |||
| 2742 | u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN; | 2754 | u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN; |
| 2743 | const struct in6_addr *gw_addr = &cfg->fc_gateway; | 2755 | const struct in6_addr *gw_addr = &cfg->fc_gateway; |
| 2744 | u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT; | 2756 | u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT; |
| 2757 | struct fib6_info *from; | ||
| 2745 | struct rt6_info *grt; | 2758 | struct rt6_info *grt; |
| 2746 | int err; | 2759 | int err; |
| 2747 | 2760 | ||
| 2748 | err = 0; | 2761 | err = 0; |
| 2749 | grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0); | 2762 | grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0); |
| 2750 | if (grt) { | 2763 | if (grt) { |
| 2764 | rcu_read_lock(); | ||
| 2765 | from = rcu_dereference(grt->from); | ||
| 2751 | if (!grt->dst.error && | 2766 | if (!grt->dst.error && |
| 2752 | /* ignore match if it is the default route */ | 2767 | /* ignore match if it is the default route */ |
| 2753 | grt->from && !ipv6_addr_any(&grt->from->fib6_dst.addr) && | 2768 | from && !ipv6_addr_any(&from->fib6_dst.addr) && |
| 2754 | (grt->rt6i_flags & flags || dev != grt->dst.dev)) { | 2769 | (grt->rt6i_flags & flags || dev != grt->dst.dev)) { |
| 2755 | NL_SET_ERR_MSG(extack, | 2770 | NL_SET_ERR_MSG(extack, |
| 2756 | "Nexthop has invalid gateway or device mismatch"); | 2771 | "Nexthop has invalid gateway or device mismatch"); |
| 2757 | err = -EINVAL; | 2772 | err = -EINVAL; |
| 2758 | } | 2773 | } |
| 2774 | rcu_read_unlock(); | ||
| 2759 | 2775 | ||
| 2760 | ip6_rt_put(grt); | 2776 | ip6_rt_put(grt); |
| 2761 | } | 2777 | } |
| @@ -4251,17 +4267,6 @@ struct rt6_nh { | |||
| 4251 | struct list_head next; | 4267 | struct list_head next; |
| 4252 | }; | 4268 | }; |
| 4253 | 4269 | ||
| 4254 | static void ip6_print_replace_route_err(struct list_head *rt6_nh_list) | ||
| 4255 | { | ||
| 4256 | struct rt6_nh *nh; | ||
| 4257 | |||
| 4258 | list_for_each_entry(nh, rt6_nh_list, next) { | ||
| 4259 | pr_warn("IPV6: multipath route replace failed (check consistency of installed routes): %pI6c nexthop %pI6c ifi %d\n", | ||
| 4260 | &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway, | ||
| 4261 | nh->r_cfg.fc_ifindex); | ||
| 4262 | } | ||
| 4263 | } | ||
| 4264 | |||
| 4265 | static int ip6_route_info_append(struct net *net, | 4270 | static int ip6_route_info_append(struct net *net, |
| 4266 | struct list_head *rt6_nh_list, | 4271 | struct list_head *rt6_nh_list, |
| 4267 | struct fib6_info *rt, | 4272 | struct fib6_info *rt, |
| @@ -4407,7 +4412,8 @@ static int ip6_route_multipath_add(struct fib6_config *cfg, | |||
| 4407 | nh->fib6_info = NULL; | 4412 | nh->fib6_info = NULL; |
| 4408 | if (err) { | 4413 | if (err) { |
| 4409 | if (replace && nhn) | 4414 | if (replace && nhn) |
| 4410 | ip6_print_replace_route_err(&rt6_nh_list); | 4415 | NL_SET_ERR_MSG_MOD(extack, |
| 4416 | "multipath route replace failed (check consistency of installed routes)"); | ||
| 4411 | err_nh = nh; | 4417 | err_nh = nh; |
| 4412 | goto add_errout; | 4418 | goto add_errout; |
| 4413 | } | 4419 | } |
| @@ -4659,7 +4665,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, | |||
| 4659 | table = rt->fib6_table->tb6_id; | 4665 | table = rt->fib6_table->tb6_id; |
| 4660 | else | 4666 | else |
| 4661 | table = RT6_TABLE_UNSPEC; | 4667 | table = RT6_TABLE_UNSPEC; |
| 4662 | rtm->rtm_table = table; | 4668 | rtm->rtm_table = table < 256 ? table : RT_TABLE_COMPAT; |
| 4663 | if (nla_put_u32(skb, RTA_TABLE, table)) | 4669 | if (nla_put_u32(skb, RTA_TABLE, table)) |
| 4664 | goto nla_put_failure; | 4670 | goto nla_put_failure; |
| 4665 | 4671 | ||
diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c index 8d0ba757a46c..9b2f272ca164 100644 --- a/net/ipv6/seg6.c +++ b/net/ipv6/seg6.c | |||
| @@ -221,9 +221,7 @@ static int seg6_genl_get_tunsrc(struct sk_buff *skb, struct genl_info *info) | |||
| 221 | rcu_read_unlock(); | 221 | rcu_read_unlock(); |
| 222 | 222 | ||
| 223 | genlmsg_end(msg, hdr); | 223 | genlmsg_end(msg, hdr); |
| 224 | genlmsg_reply(msg, info); | 224 | return genlmsg_reply(msg, info); |
| 225 | |||
| 226 | return 0; | ||
| 227 | 225 | ||
| 228 | nla_put_failure: | 226 | nla_put_failure: |
| 229 | rcu_read_unlock(); | 227 | rcu_read_unlock(); |
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index 8181ee7e1e27..ee5403cbe655 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c | |||
| @@ -146,6 +146,8 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto) | |||
| 146 | } else { | 146 | } else { |
| 147 | ip6_flow_hdr(hdr, 0, flowlabel); | 147 | ip6_flow_hdr(hdr, 0, flowlabel); |
| 148 | hdr->hop_limit = ip6_dst_hoplimit(skb_dst(skb)); | 148 | hdr->hop_limit = ip6_dst_hoplimit(skb_dst(skb)); |
| 149 | |||
| 150 | memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); | ||
| 149 | } | 151 | } |
| 150 | 152 | ||
| 151 | hdr->nexthdr = NEXTHDR_ROUTING; | 153 | hdr->nexthdr = NEXTHDR_ROUTING; |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 1e03305c0549..e8a1dabef803 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
| @@ -546,7 +546,8 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
| 546 | } | 546 | } |
| 547 | 547 | ||
| 548 | err = 0; | 548 | err = 0; |
| 549 | if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type, data_len)) | 549 | if (__in6_dev_get(skb->dev) && |
| 550 | !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type, data_len)) | ||
| 550 | goto out; | 551 | goto out; |
| 551 | 552 | ||
| 552 | if (t->parms.iph.daddr == 0) | 553 | if (t->parms.iph.daddr == 0) |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 9cbf363172bd..b444483cdb2b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -102,7 +102,7 @@ int udp_v6_get_port(struct sock *sk, unsigned short snum) | |||
| 102 | return udp_lib_get_port(sk, snum, hash2_nulladdr); | 102 | return udp_lib_get_port(sk, snum, hash2_nulladdr); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static void udp_v6_rehash(struct sock *sk) | 105 | void udp_v6_rehash(struct sock *sk) |
| 106 | { | 106 | { |
| 107 | u16 new_hash = ipv6_portaddr_hash(sock_net(sk), | 107 | u16 new_hash = ipv6_portaddr_hash(sock_net(sk), |
| 108 | &sk->sk_v6_rcv_saddr, | 108 | &sk->sk_v6_rcv_saddr, |
| @@ -288,8 +288,8 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, | |||
| 288 | int peeked, peeking, off; | 288 | int peeked, peeking, off; |
| 289 | int err; | 289 | int err; |
| 290 | int is_udplite = IS_UDPLITE(sk); | 290 | int is_udplite = IS_UDPLITE(sk); |
| 291 | struct udp_mib __percpu *mib; | ||
| 291 | bool checksum_valid = false; | 292 | bool checksum_valid = false; |
| 292 | struct udp_mib *mib; | ||
| 293 | int is_udp4; | 293 | int is_udp4; |
| 294 | 294 | ||
| 295 | if (flags & MSG_ERRQUEUE) | 295 | if (flags & MSG_ERRQUEUE) |
| @@ -420,17 +420,19 @@ EXPORT_SYMBOL(udpv6_encap_enable); | |||
| 420 | */ | 420 | */ |
| 421 | static int __udp6_lib_err_encap_no_sk(struct sk_buff *skb, | 421 | static int __udp6_lib_err_encap_no_sk(struct sk_buff *skb, |
| 422 | struct inet6_skb_parm *opt, | 422 | struct inet6_skb_parm *opt, |
| 423 | u8 type, u8 code, int offset, u32 info) | 423 | u8 type, u8 code, int offset, __be32 info) |
| 424 | { | 424 | { |
| 425 | int i; | 425 | int i; |
| 426 | 426 | ||
| 427 | for (i = 0; i < MAX_IPTUN_ENCAP_OPS; i++) { | 427 | for (i = 0; i < MAX_IPTUN_ENCAP_OPS; i++) { |
| 428 | int (*handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, | 428 | int (*handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, |
| 429 | u8 type, u8 code, int offset, u32 info); | 429 | u8 type, u8 code, int offset, __be32 info); |
| 430 | const struct ip6_tnl_encap_ops *encap; | ||
| 430 | 431 | ||
| 431 | if (!ip6tun_encaps[i]) | 432 | encap = rcu_dereference(ip6tun_encaps[i]); |
| 433 | if (!encap) | ||
| 432 | continue; | 434 | continue; |
| 433 | handler = rcu_dereference(ip6tun_encaps[i]->err_handler); | 435 | handler = encap->err_handler; |
| 434 | if (handler && !handler(skb, opt, type, code, offset, info)) | 436 | if (handler && !handler(skb, opt, type, code, offset, info)) |
| 435 | return 0; | 437 | return 0; |
| 436 | } | 438 | } |
| @@ -1132,15 +1134,23 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6, | |||
| 1132 | const int hlen = skb_network_header_len(skb) + | 1134 | const int hlen = skb_network_header_len(skb) + |
| 1133 | sizeof(struct udphdr); | 1135 | sizeof(struct udphdr); |
| 1134 | 1136 | ||
| 1135 | if (hlen + cork->gso_size > cork->fragsize) | 1137 | if (hlen + cork->gso_size > cork->fragsize) { |
| 1138 | kfree_skb(skb); | ||
| 1136 | return -EINVAL; | 1139 | return -EINVAL; |
| 1137 | if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) | 1140 | } |
| 1141 | if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) { | ||
| 1142 | kfree_skb(skb); | ||
| 1138 | return -EINVAL; | 1143 | return -EINVAL; |
| 1139 | if (udp_sk(sk)->no_check6_tx) | 1144 | } |
| 1145 | if (udp_sk(sk)->no_check6_tx) { | ||
| 1146 | kfree_skb(skb); | ||
| 1140 | return -EINVAL; | 1147 | return -EINVAL; |
| 1148 | } | ||
| 1141 | if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite || | 1149 | if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite || |
| 1142 | dst_xfrm(skb_dst(skb))) | 1150 | dst_xfrm(skb_dst(skb))) { |
| 1151 | kfree_skb(skb); | ||
| 1143 | return -EIO; | 1152 | return -EIO; |
| 1153 | } | ||
| 1144 | 1154 | ||
| 1145 | skb_shinfo(skb)->gso_size = cork->gso_size; | 1155 | skb_shinfo(skb)->gso_size = cork->gso_size; |
| 1146 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4; | 1156 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4; |
| @@ -1390,10 +1400,7 @@ do_udp_sendmsg: | |||
| 1390 | ipc6.opt = opt; | 1400 | ipc6.opt = opt; |
| 1391 | 1401 | ||
| 1392 | fl6.flowi6_proto = sk->sk_protocol; | 1402 | fl6.flowi6_proto = sk->sk_protocol; |
| 1393 | if (!ipv6_addr_any(daddr)) | 1403 | fl6.daddr = *daddr; |
| 1394 | fl6.daddr = *daddr; | ||
| 1395 | else | ||
| 1396 | fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ | ||
| 1397 | if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr)) | 1404 | if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr)) |
| 1398 | fl6.saddr = np->saddr; | 1405 | fl6.saddr = np->saddr; |
| 1399 | fl6.fl6_sport = inet->inet_sport; | 1406 | fl6.fl6_sport = inet->inet_sport; |
| @@ -1421,6 +1428,9 @@ do_udp_sendmsg: | |||
| 1421 | } | 1428 | } |
| 1422 | } | 1429 | } |
| 1423 | 1430 | ||
| 1431 | if (ipv6_addr_any(&fl6.daddr)) | ||
| 1432 | fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ | ||
| 1433 | |||
| 1424 | final_p = fl6_update_dst(&fl6, opt, &final); | 1434 | final_p = fl6_update_dst(&fl6, opt, &final); |
| 1425 | if (final_p) | 1435 | if (final_p) |
| 1426 | connected = false; | 1436 | connected = false; |
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 5730e6503cb4..20e324b6f358 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h | |||
| @@ -13,6 +13,7 @@ int __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, | |||
| 13 | __be32, struct udp_table *); | 13 | __be32, struct udp_table *); |
| 14 | 14 | ||
| 15 | int udp_v6_get_port(struct sock *sk, unsigned short snum); | 15 | int udp_v6_get_port(struct sock *sk, unsigned short snum); |
| 16 | void udp_v6_rehash(struct sock *sk); | ||
| 16 | 17 | ||
| 17 | int udpv6_getsockopt(struct sock *sk, int level, int optname, | 18 | int udpv6_getsockopt(struct sock *sk, int level, int optname, |
| 18 | char __user *optval, int __user *optlen); | 19 | char __user *optval, int __user *optlen); |
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index a125aebc29e5..f35907836444 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c | |||
| @@ -49,6 +49,7 @@ struct proto udplitev6_prot = { | |||
| 49 | .recvmsg = udpv6_recvmsg, | 49 | .recvmsg = udpv6_recvmsg, |
| 50 | .hash = udp_lib_hash, | 50 | .hash = udp_lib_hash, |
| 51 | .unhash = udp_lib_unhash, | 51 | .unhash = udp_lib_unhash, |
| 52 | .rehash = udp_v6_rehash, | ||
| 52 | .get_port = udp_v6_get_port, | 53 | .get_port = udp_v6_get_port, |
| 53 | .memory_allocated = &udp_memory_allocated, | 54 | .memory_allocated = &udp_memory_allocated, |
| 54 | .sysctl_mem = sysctl_udp_mem, | 55 | .sysctl_mem = sysctl_udp_mem, |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index f5b4febeaa25..bc65db782bfb 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
| @@ -344,8 +344,8 @@ static void __net_exit xfrm6_tunnel_net_exit(struct net *net) | |||
| 344 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | 344 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); |
| 345 | unsigned int i; | 345 | unsigned int i; |
| 346 | 346 | ||
| 347 | xfrm_state_flush(net, IPSEC_PROTO_ANY, false); | ||
| 348 | xfrm_flush_gc(); | 347 | xfrm_flush_gc(); |
| 348 | xfrm_state_flush(net, IPSEC_PROTO_ANY, false, true); | ||
| 349 | 349 | ||
| 350 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) | 350 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) |
| 351 | WARN_ON_ONCE(!hlist_empty(&xfrm6_tn->spi_byaddr[i])); | 351 | WARN_ON_ONCE(!hlist_empty(&xfrm6_tn->spi_byaddr[i])); |
