| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * net/dccp/ipv4.c |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * An implementation of the DCCP protocol |
|---|
| 5 | 6 | * Arnaldo Carvalho de Melo <acme@conectiva.com.br> |
|---|
| 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 | #include <linux/dccp.h> |
|---|
| .. | .. |
|---|
| 134 | 130 | * This unhashes the socket and releases the local port, if necessary. |
|---|
| 135 | 131 | */ |
|---|
| 136 | 132 | dccp_set_state(sk, DCCP_CLOSED); |
|---|
| 133 | + if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) |
|---|
| 134 | + inet_reset_saddr(sk); |
|---|
| 137 | 135 | ip_rt_put(rt); |
|---|
| 138 | 136 | sk->sk_route_caps = 0; |
|---|
| 139 | 137 | inet->inet_dport = 0; |
|---|
| .. | .. |
|---|
| 231 | 229 | * check at all. A more general error queue to queue errors for later handling |
|---|
| 232 | 230 | * is probably better. |
|---|
| 233 | 231 | */ |
|---|
| 234 | | -static void dccp_v4_err(struct sk_buff *skb, u32 info) |
|---|
| 232 | +static int dccp_v4_err(struct sk_buff *skb, u32 info) |
|---|
| 235 | 233 | { |
|---|
| 236 | 234 | const struct iphdr *iph = (struct iphdr *)skb->data; |
|---|
| 237 | 235 | const u8 offset = iph->ihl << 2; |
|---|
| .. | .. |
|---|
| 245 | 243 | int err; |
|---|
| 246 | 244 | struct net *net = dev_net(skb->dev); |
|---|
| 247 | 245 | |
|---|
| 248 | | - /* Only need dccph_dport & dccph_sport which are the first |
|---|
| 249 | | - * 4 bytes in dccp header. |
|---|
| 250 | | - * Our caller (icmp_socket_deliver()) already pulled 8 bytes for us. |
|---|
| 251 | | - */ |
|---|
| 252 | | - BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8); |
|---|
| 253 | | - BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8); |
|---|
| 246 | + if (!pskb_may_pull(skb, offset + sizeof(*dh))) |
|---|
| 247 | + return -EINVAL; |
|---|
| 248 | + dh = (struct dccp_hdr *)(skb->data + offset); |
|---|
| 249 | + if (!pskb_may_pull(skb, offset + __dccp_basic_hdr_len(dh))) |
|---|
| 250 | + return -EINVAL; |
|---|
| 251 | + iph = (struct iphdr *)skb->data; |
|---|
| 254 | 252 | dh = (struct dccp_hdr *)(skb->data + offset); |
|---|
| 255 | 253 | |
|---|
| 256 | 254 | sk = __inet_lookup_established(net, &dccp_hashinfo, |
|---|
| .. | .. |
|---|
| 259 | 257 | inet_iif(skb), 0); |
|---|
| 260 | 258 | if (!sk) { |
|---|
| 261 | 259 | __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); |
|---|
| 262 | | - return; |
|---|
| 260 | + return -ENOENT; |
|---|
| 263 | 261 | } |
|---|
| 264 | 262 | |
|---|
| 265 | 263 | if (sk->sk_state == DCCP_TIME_WAIT) { |
|---|
| 266 | 264 | inet_twsk_put(inet_twsk(sk)); |
|---|
| 267 | | - return; |
|---|
| 265 | + return 0; |
|---|
| 268 | 266 | } |
|---|
| 269 | 267 | seq = dccp_hdr_seq(dh); |
|---|
| 270 | | - if (sk->sk_state == DCCP_NEW_SYN_RECV) |
|---|
| 271 | | - return dccp_req_err(sk, seq); |
|---|
| 268 | + if (sk->sk_state == DCCP_NEW_SYN_RECV) { |
|---|
| 269 | + dccp_req_err(sk, seq); |
|---|
| 270 | + return 0; |
|---|
| 271 | + } |
|---|
| 272 | 272 | |
|---|
| 273 | 273 | bh_lock_sock(sk); |
|---|
| 274 | 274 | /* If too many ICMPs get dropped on busy |
|---|
| .. | .. |
|---|
| 357 | 357 | out: |
|---|
| 358 | 358 | bh_unlock_sock(sk); |
|---|
| 359 | 359 | sock_put(sk); |
|---|
| 360 | + return 0; |
|---|
| 360 | 361 | } |
|---|
| 361 | 362 | |
|---|
| 362 | 363 | static inline __sum16 dccp_v4_csum_finish(struct sk_buff *skb, |
|---|
| .. | .. |
|---|
| 428 | 429 | |
|---|
| 429 | 430 | if (__inet_inherit_port(sk, newsk) < 0) |
|---|
| 430 | 431 | goto put_and_exit; |
|---|
| 431 | | - *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); |
|---|
| 432 | + *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), NULL); |
|---|
| 432 | 433 | if (*own_req) |
|---|
| 433 | 434 | ireq->ireq_opt = NULL; |
|---|
| 434 | 435 | else |
|---|
| .. | .. |
|---|
| 465 | 466 | .fl4_dport = dccp_hdr(skb)->dccph_sport, |
|---|
| 466 | 467 | }; |
|---|
| 467 | 468 | |
|---|
| 468 | | - security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); |
|---|
| 469 | + security_skb_classify_flow(skb, flowi4_to_flowi_common(&fl4)); |
|---|
| 469 | 470 | rt = ip_route_output_flow(net, &fl4, sk); |
|---|
| 470 | 471 | if (IS_ERR(rt)) { |
|---|
| 471 | 472 | IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); |
|---|
| .. | .. |
|---|
| 496 | 497 | rcu_read_lock(); |
|---|
| 497 | 498 | err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, |
|---|
| 498 | 499 | ireq->ir_rmt_addr, |
|---|
| 499 | | - rcu_dereference(ireq->ireq_opt)); |
|---|
| 500 | + rcu_dereference(ireq->ireq_opt), |
|---|
| 501 | + inet_sk(sk)->tos); |
|---|
| 500 | 502 | rcu_read_unlock(); |
|---|
| 501 | 503 | err = net_xmit_eval(err); |
|---|
| 502 | 504 | } |
|---|
| .. | .. |
|---|
| 538 | 540 | local_bh_disable(); |
|---|
| 539 | 541 | bh_lock_sock(ctl_sk); |
|---|
| 540 | 542 | err = ip_build_and_send_pkt(skb, ctl_sk, |
|---|
| 541 | | - rxiph->daddr, rxiph->saddr, NULL); |
|---|
| 543 | + rxiph->daddr, rxiph->saddr, NULL, |
|---|
| 544 | + inet_sk(ctl_sk)->tos); |
|---|
| 542 | 545 | bh_unlock_sock(ctl_sk); |
|---|
| 543 | 546 | |
|---|
| 544 | 547 | if (net_xmit_eval(err) == 0) { |
|---|
| .. | .. |
|---|
| 695 | 698 | |
|---|
| 696 | 699 | /** |
|---|
| 697 | 700 | * dccp_invalid_packet - check for malformed packets |
|---|
| 701 | + * @skb: Packet to validate |
|---|
| 702 | + * |
|---|
| 698 | 703 | * Implements RFC 4340, 8.5: Step 1: Check header basics |
|---|
| 699 | 704 | * Packets that fail these checks are ignored and do not receive Resets. |
|---|
| 700 | 705 | */ |
|---|
| .. | .. |
|---|
| 730 | 735 | return 1; |
|---|
| 731 | 736 | } |
|---|
| 732 | 737 | /* |
|---|
| 733 | | - * If P.Data Offset is too too large for packet, drop packet and return |
|---|
| 738 | + * If P.Data Offset is too large for packet, drop packet and return |
|---|
| 734 | 739 | */ |
|---|
| 735 | 740 | if (!pskb_may_pull(skb, dccph_doff * sizeof(u32))) { |
|---|
| 736 | 741 | DCCP_WARN("P.Data Offset(%u) too large\n", dccph_doff); |
|---|
| .. | .. |
|---|
| 872 | 877 | |
|---|
| 873 | 878 | if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) |
|---|
| 874 | 879 | goto discard_and_relse; |
|---|
| 875 | | - nf_reset(skb); |
|---|
| 880 | + nf_reset_ct(skb); |
|---|
| 876 | 881 | |
|---|
| 877 | 882 | return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4, refcounted); |
|---|
| 878 | 883 | |
|---|
| .. | .. |
|---|
| 912 | 917 | .getsockopt = ip_getsockopt, |
|---|
| 913 | 918 | .addr2sockaddr = inet_csk_addr2sockaddr, |
|---|
| 914 | 919 | .sockaddr_len = sizeof(struct sockaddr_in), |
|---|
| 915 | | -#ifdef CONFIG_COMPAT |
|---|
| 916 | | - .compat_setsockopt = compat_ip_setsockopt, |
|---|
| 917 | | - .compat_getsockopt = compat_ip_getsockopt, |
|---|
| 918 | | -#endif |
|---|
| 919 | 920 | }; |
|---|
| 920 | 921 | |
|---|
| 921 | 922 | static int dccp_v4_init_sock(struct sock *sk) |
|---|
| .. | .. |
|---|
| 962 | 963 | .rsk_prot = &dccp_request_sock_ops, |
|---|
| 963 | 964 | .twsk_prot = &dccp_timewait_sock_ops, |
|---|
| 964 | 965 | .h.hashinfo = &dccp_hashinfo, |
|---|
| 965 | | -#ifdef CONFIG_COMPAT |
|---|
| 966 | | - .compat_setsockopt = compat_dccp_setsockopt, |
|---|
| 967 | | - .compat_getsockopt = compat_dccp_getsockopt, |
|---|
| 968 | | -#endif |
|---|
| 969 | 966 | }; |
|---|
| 970 | 967 | |
|---|
| 971 | 968 | static const struct net_protocol dccp_v4_protocol = { |
|---|
| .. | .. |
|---|
| 988 | 985 | /* FIXME: work on tcp_poll to rename it to inet_csk_poll */ |
|---|
| 989 | 986 | .poll = dccp_poll, |
|---|
| 990 | 987 | .ioctl = inet_ioctl, |
|---|
| 988 | + .gettstamp = sock_gettstamp, |
|---|
| 991 | 989 | /* FIXME: work on inet_listen to rename it to sock_common_listen */ |
|---|
| 992 | 990 | .listen = inet_dccp_listen, |
|---|
| 993 | 991 | .shutdown = inet_shutdown, |
|---|
| .. | .. |
|---|
| 997 | 995 | .recvmsg = sock_common_recvmsg, |
|---|
| 998 | 996 | .mmap = sock_no_mmap, |
|---|
| 999 | 997 | .sendpage = sock_no_sendpage, |
|---|
| 1000 | | -#ifdef CONFIG_COMPAT |
|---|
| 1001 | | - .compat_setsockopt = compat_sock_common_setsockopt, |
|---|
| 1002 | | - .compat_getsockopt = compat_sock_common_getsockopt, |
|---|
| 1003 | | -#endif |
|---|
| 1004 | 998 | }; |
|---|
| 1005 | 999 | |
|---|
| 1006 | 1000 | static struct inet_protosw dccp_v4_protosw = { |
|---|