.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * DCCP over IPv6 |
---|
3 | 4 | * Linux INET6 implementation |
---|
.. | .. |
---|
5 | 6 | * Based on net/dccp6/ipv6.c |
---|
6 | 7 | * |
---|
7 | 8 | * Arnaldo Carvalho de Melo <acme@ghostprotocols.net> |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or |
---|
10 | | - * modify it under the terms of the GNU General Public License |
---|
11 | | - * as published by the Free Software Foundation; either version |
---|
12 | | - * 2 of the License, or (at your option) any later version. |
---|
13 | 9 | */ |
---|
14 | 10 | |
---|
15 | 11 | #include <linux/module.h> |
---|
.. | .. |
---|
68 | 64 | |
---|
69 | 65 | } |
---|
70 | 66 | |
---|
71 | | -static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
---|
| 67 | +static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
---|
72 | 68 | u8 type, u8 code, int offset, __be32 info) |
---|
73 | 69 | { |
---|
74 | | - const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; |
---|
| 70 | + const struct ipv6hdr *hdr; |
---|
75 | 71 | const struct dccp_hdr *dh; |
---|
76 | 72 | struct dccp_sock *dp; |
---|
77 | 73 | struct ipv6_pinfo *np; |
---|
.. | .. |
---|
80 | 76 | __u64 seq; |
---|
81 | 77 | struct net *net = dev_net(skb->dev); |
---|
82 | 78 | |
---|
83 | | - /* Only need dccph_dport & dccph_sport which are the first |
---|
84 | | - * 4 bytes in dccp header. |
---|
85 | | - * Our caller (icmpv6_notify()) already pulled 8 bytes for us. |
---|
86 | | - */ |
---|
87 | | - BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8); |
---|
88 | | - BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8); |
---|
| 79 | + if (!pskb_may_pull(skb, offset + sizeof(*dh))) |
---|
| 80 | + return -EINVAL; |
---|
| 81 | + dh = (struct dccp_hdr *)(skb->data + offset); |
---|
| 82 | + if (!pskb_may_pull(skb, offset + __dccp_basic_hdr_len(dh))) |
---|
| 83 | + return -EINVAL; |
---|
| 84 | + hdr = (const struct ipv6hdr *)skb->data; |
---|
89 | 85 | dh = (struct dccp_hdr *)(skb->data + offset); |
---|
90 | 86 | |
---|
91 | 87 | sk = __inet6_lookup_established(net, &dccp_hashinfo, |
---|
.. | .. |
---|
96 | 92 | if (!sk) { |
---|
97 | 93 | __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), |
---|
98 | 94 | ICMP6_MIB_INERRORS); |
---|
99 | | - return; |
---|
| 95 | + return -ENOENT; |
---|
100 | 96 | } |
---|
101 | 97 | |
---|
102 | 98 | if (sk->sk_state == DCCP_TIME_WAIT) { |
---|
103 | 99 | inet_twsk_put(inet_twsk(sk)); |
---|
104 | | - return; |
---|
| 100 | + return 0; |
---|
105 | 101 | } |
---|
106 | 102 | seq = dccp_hdr_seq(dh); |
---|
107 | | - if (sk->sk_state == DCCP_NEW_SYN_RECV) |
---|
108 | | - return dccp_req_err(sk, seq); |
---|
| 103 | + if (sk->sk_state == DCCP_NEW_SYN_RECV) { |
---|
| 104 | + dccp_req_err(sk, seq); |
---|
| 105 | + return 0; |
---|
| 106 | + } |
---|
109 | 107 | |
---|
110 | 108 | bh_lock_sock(sk); |
---|
111 | 109 | if (sock_owned_by_user(sk)) |
---|
.. | .. |
---|
183 | 181 | out: |
---|
184 | 182 | bh_unlock_sock(sk); |
---|
185 | 183 | sock_put(sk); |
---|
| 184 | + return 0; |
---|
186 | 185 | } |
---|
187 | 186 | |
---|
188 | 187 | |
---|
.. | .. |
---|
204 | 203 | fl6.flowi6_oif = ireq->ir_iif; |
---|
205 | 204 | fl6.fl6_dport = ireq->ir_rmt_port; |
---|
206 | 205 | fl6.fl6_sport = htons(ireq->ir_num); |
---|
207 | | - security_req_classify_flow(req, flowi6_to_flowi(&fl6)); |
---|
| 206 | + security_req_classify_flow(req, flowi6_to_flowi_common(&fl6)); |
---|
208 | 207 | |
---|
209 | 208 | |
---|
210 | 209 | rcu_read_lock(); |
---|
.. | .. |
---|
231 | 230 | opt = ireq->ipv6_opt; |
---|
232 | 231 | if (!opt) |
---|
233 | 232 | opt = rcu_dereference(np->opt); |
---|
234 | | - err = ip6_xmit(sk, skb, &fl6, sk->sk_mark, opt, np->tclass); |
---|
| 233 | + err = ip6_xmit(sk, skb, &fl6, sk->sk_mark, opt, np->tclass, |
---|
| 234 | + sk->sk_priority); |
---|
235 | 235 | rcu_read_unlock(); |
---|
236 | 236 | err = net_xmit_eval(err); |
---|
237 | 237 | } |
---|
.. | .. |
---|
279 | 279 | fl6.flowi6_oif = inet6_iif(rxskb); |
---|
280 | 280 | fl6.fl6_dport = dccp_hdr(skb)->dccph_dport; |
---|
281 | 281 | fl6.fl6_sport = dccp_hdr(skb)->dccph_sport; |
---|
282 | | - security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6)); |
---|
| 282 | + security_skb_classify_flow(rxskb, flowi6_to_flowi_common(&fl6)); |
---|
283 | 283 | |
---|
284 | 284 | /* sk = NULL, but it is safe for now. RST socket required. */ |
---|
285 | 285 | dst = ip6_dst_lookup_flow(sock_net(ctl_sk), ctl_sk, &fl6, NULL); |
---|
286 | 286 | if (!IS_ERR(dst)) { |
---|
287 | 287 | skb_dst_set(skb, dst); |
---|
288 | | - ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0); |
---|
| 288 | + ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0, 0); |
---|
289 | 289 | DCCP_INC_STATS(DCCP_MIB_OUTSEGS); |
---|
290 | 290 | DCCP_INC_STATS(DCCP_MIB_OUTRSTS); |
---|
291 | 291 | return; |
---|
.. | .. |
---|
538 | 538 | dccp_done(newsk); |
---|
539 | 539 | goto out; |
---|
540 | 540 | } |
---|
541 | | - *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); |
---|
| 541 | + *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), NULL); |
---|
542 | 542 | /* Clone pktoptions received with SYN, if we own the req */ |
---|
543 | 543 | if (*own_req && ireq->pktopts) { |
---|
544 | | - newnp->pktoptions = skb_clone(ireq->pktopts, GFP_ATOMIC); |
---|
| 544 | + newnp->pktoptions = skb_clone_and_charge_r(ireq->pktopts, newsk); |
---|
545 | 545 | consume_skb(ireq->pktopts); |
---|
546 | 546 | ireq->pktopts = NULL; |
---|
547 | | - if (newnp->pktoptions) |
---|
548 | | - skb_set_owner_r(newnp->pktoptions, newsk); |
---|
549 | 547 | } |
---|
550 | 548 | |
---|
551 | 549 | return newsk; |
---|
.. | .. |
---|
605 | 603 | --ANK (980728) |
---|
606 | 604 | */ |
---|
607 | 605 | if (np->rxopt.all) |
---|
608 | | - opt_skb = skb_clone(skb, GFP_ATOMIC); |
---|
| 606 | + opt_skb = skb_clone_and_charge_r(skb, sk); |
---|
609 | 607 | |
---|
610 | 608 | if (sk->sk_state == DCCP_OPEN) { /* Fast path */ |
---|
611 | 609 | if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len)) |
---|
.. | .. |
---|
669 | 667 | np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb)); |
---|
670 | 668 | if (ipv6_opt_accepted(sk, opt_skb, |
---|
671 | 669 | &DCCP_SKB_CB(opt_skb)->header.h6)) { |
---|
672 | | - skb_set_owner_r(opt_skb, sk); |
---|
673 | 670 | memmove(IP6CB(opt_skb), |
---|
674 | 671 | &DCCP_SKB_CB(opt_skb)->header.h6, |
---|
675 | 672 | sizeof(struct inet6_skb_parm)); |
---|
.. | .. |
---|
836 | 833 | if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) { |
---|
837 | 834 | struct ip6_flowlabel *flowlabel; |
---|
838 | 835 | flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); |
---|
839 | | - if (flowlabel == NULL) |
---|
| 836 | + if (IS_ERR(flowlabel)) |
---|
840 | 837 | return -EINVAL; |
---|
841 | 838 | fl6_sock_release(flowlabel); |
---|
842 | 839 | } |
---|
.. | .. |
---|
912 | 909 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
---|
913 | 910 | fl6.fl6_dport = usin->sin6_port; |
---|
914 | 911 | fl6.fl6_sport = inet->inet_sport; |
---|
915 | | - security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
---|
| 912 | + security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6)); |
---|
916 | 913 | |
---|
917 | 914 | opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk)); |
---|
918 | 915 | final_p = fl6_update_dst(&fl6, opt, &final); |
---|
.. | .. |
---|
957 | 954 | |
---|
958 | 955 | late_failure: |
---|
959 | 956 | dccp_set_state(sk, DCCP_CLOSED); |
---|
| 957 | + if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) |
---|
| 958 | + inet_reset_saddr(sk); |
---|
960 | 959 | __sk_dst_reset(sk); |
---|
961 | 960 | failure: |
---|
962 | 961 | inet->inet_dport = 0; |
---|
.. | .. |
---|
975 | 974 | .getsockopt = ipv6_getsockopt, |
---|
976 | 975 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
---|
977 | 976 | .sockaddr_len = sizeof(struct sockaddr_in6), |
---|
978 | | -#ifdef CONFIG_COMPAT |
---|
979 | | - .compat_setsockopt = compat_ipv6_setsockopt, |
---|
980 | | - .compat_getsockopt = compat_ipv6_getsockopt, |
---|
981 | | -#endif |
---|
982 | 977 | }; |
---|
983 | 978 | |
---|
984 | 979 | /* |
---|
.. | .. |
---|
995 | 990 | .getsockopt = ipv6_getsockopt, |
---|
996 | 991 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
---|
997 | 992 | .sockaddr_len = sizeof(struct sockaddr_in6), |
---|
998 | | -#ifdef CONFIG_COMPAT |
---|
999 | | - .compat_setsockopt = compat_ipv6_setsockopt, |
---|
1000 | | - .compat_getsockopt = compat_ipv6_getsockopt, |
---|
1001 | | -#endif |
---|
1002 | 993 | }; |
---|
| 994 | + |
---|
| 995 | +static void dccp_v6_sk_destruct(struct sock *sk) |
---|
| 996 | +{ |
---|
| 997 | + dccp_destruct_common(sk); |
---|
| 998 | + inet6_sock_destruct(sk); |
---|
| 999 | +} |
---|
1003 | 1000 | |
---|
1004 | 1001 | /* NOTE: A lot of things set to zero explicitly by call to |
---|
1005 | 1002 | * sk_alloc() so need not be done here. |
---|
.. | .. |
---|
1013 | 1010 | if (unlikely(!dccp_v6_ctl_sock_initialized)) |
---|
1014 | 1011 | dccp_v6_ctl_sock_initialized = 1; |
---|
1015 | 1012 | inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops; |
---|
| 1013 | + sk->sk_destruct = dccp_v6_sk_destruct; |
---|
1016 | 1014 | } |
---|
1017 | 1015 | |
---|
1018 | 1016 | return err; |
---|
1019 | | -} |
---|
1020 | | - |
---|
1021 | | -static void dccp_v6_destroy_sock(struct sock *sk) |
---|
1022 | | -{ |
---|
1023 | | - dccp_destroy_sock(sk); |
---|
1024 | | - inet6_destroy_sock(sk); |
---|
1025 | 1017 | } |
---|
1026 | 1018 | |
---|
1027 | 1019 | static struct timewait_sock_ops dccp6_timewait_sock_ops = { |
---|
.. | .. |
---|
1046 | 1038 | .accept = inet_csk_accept, |
---|
1047 | 1039 | .get_port = inet_csk_get_port, |
---|
1048 | 1040 | .shutdown = dccp_shutdown, |
---|
1049 | | - .destroy = dccp_v6_destroy_sock, |
---|
| 1041 | + .destroy = dccp_destroy_sock, |
---|
1050 | 1042 | .orphan_count = &dccp_orphan_count, |
---|
1051 | 1043 | .max_header = MAX_DCCP_HEADER, |
---|
1052 | 1044 | .obj_size = sizeof(struct dccp6_sock), |
---|
.. | .. |
---|
1054 | 1046 | .rsk_prot = &dccp6_request_sock_ops, |
---|
1055 | 1047 | .twsk_prot = &dccp6_timewait_sock_ops, |
---|
1056 | 1048 | .h.hashinfo = &dccp_hashinfo, |
---|
1057 | | -#ifdef CONFIG_COMPAT |
---|
1058 | | - .compat_setsockopt = compat_dccp_setsockopt, |
---|
1059 | | - .compat_getsockopt = compat_dccp_getsockopt, |
---|
1060 | | -#endif |
---|
1061 | 1049 | }; |
---|
1062 | 1050 | |
---|
1063 | 1051 | static const struct inet6_protocol dccp_v6_protocol = { |
---|
.. | .. |
---|
1077 | 1065 | .getname = inet6_getname, |
---|
1078 | 1066 | .poll = dccp_poll, |
---|
1079 | 1067 | .ioctl = inet6_ioctl, |
---|
| 1068 | + .gettstamp = sock_gettstamp, |
---|
1080 | 1069 | .listen = inet_dccp_listen, |
---|
1081 | 1070 | .shutdown = inet_shutdown, |
---|
1082 | 1071 | .setsockopt = sock_common_setsockopt, |
---|
.. | .. |
---|
1086 | 1075 | .mmap = sock_no_mmap, |
---|
1087 | 1076 | .sendpage = sock_no_sendpage, |
---|
1088 | 1077 | #ifdef CONFIG_COMPAT |
---|
1089 | | - .compat_setsockopt = compat_sock_common_setsockopt, |
---|
1090 | | - .compat_getsockopt = compat_sock_common_getsockopt, |
---|
| 1078 | + .compat_ioctl = inet6_compat_ioctl, |
---|
1091 | 1079 | #endif |
---|
1092 | 1080 | }; |
---|
1093 | 1081 | |
---|