18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * net/dccp/ipv4.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * An implementation of the DCCP protocol 68c2ecf20Sopenharmony_ci * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/dccp.h> 108c2ecf20Sopenharmony_ci#include <linux/icmp.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 148c2ecf20Sopenharmony_ci#include <linux/random.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <net/icmp.h> 178c2ecf20Sopenharmony_ci#include <net/inet_common.h> 188c2ecf20Sopenharmony_ci#include <net/inet_hashtables.h> 198c2ecf20Sopenharmony_ci#include <net/inet_sock.h> 208c2ecf20Sopenharmony_ci#include <net/protocol.h> 218c2ecf20Sopenharmony_ci#include <net/sock.h> 228c2ecf20Sopenharmony_ci#include <net/timewait_sock.h> 238c2ecf20Sopenharmony_ci#include <net/tcp_states.h> 248c2ecf20Sopenharmony_ci#include <net/xfrm.h> 258c2ecf20Sopenharmony_ci#include <net/secure_seq.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "ackvec.h" 288c2ecf20Sopenharmony_ci#include "ccid.h" 298c2ecf20Sopenharmony_ci#include "dccp.h" 308c2ecf20Sopenharmony_ci#include "feat.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * The per-net dccp.v4_ctl_sk socket is used for responding to 348c2ecf20Sopenharmony_ci * the Out-of-the-blue (OOTB) packets. A control sock will be created 358c2ecf20Sopenharmony_ci * for this socket at the initialization time. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciint dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci const struct sockaddr_in *usin = (struct sockaddr_in *)uaddr; 418c2ecf20Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 428c2ecf20Sopenharmony_ci struct dccp_sock *dp = dccp_sk(sk); 438c2ecf20Sopenharmony_ci __be16 orig_sport, orig_dport; 448c2ecf20Sopenharmony_ci __be32 daddr, nexthop; 458c2ecf20Sopenharmony_ci struct flowi4 *fl4; 468c2ecf20Sopenharmony_ci struct rtable *rt; 478c2ecf20Sopenharmony_ci int err; 488c2ecf20Sopenharmony_ci struct ip_options_rcu *inet_opt; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci dp->dccps_role = DCCP_ROLE_CLIENT; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (addr_len < sizeof(struct sockaddr_in)) 538c2ecf20Sopenharmony_ci return -EINVAL; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (usin->sin_family != AF_INET) 568c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci nexthop = daddr = usin->sin_addr.s_addr; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci inet_opt = rcu_dereference_protected(inet->inet_opt, 618c2ecf20Sopenharmony_ci lockdep_sock_is_held(sk)); 628c2ecf20Sopenharmony_ci if (inet_opt != NULL && inet_opt->opt.srr) { 638c2ecf20Sopenharmony_ci if (daddr == 0) 648c2ecf20Sopenharmony_ci return -EINVAL; 658c2ecf20Sopenharmony_ci nexthop = inet_opt->opt.faddr; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci orig_sport = inet->inet_sport; 698c2ecf20Sopenharmony_ci orig_dport = usin->sin_port; 708c2ecf20Sopenharmony_ci fl4 = &inet->cork.fl.u.ip4; 718c2ecf20Sopenharmony_ci rt = ip_route_connect(fl4, nexthop, inet->inet_saddr, 728c2ecf20Sopenharmony_ci RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, 738c2ecf20Sopenharmony_ci IPPROTO_DCCP, 748c2ecf20Sopenharmony_ci orig_sport, orig_dport, sk); 758c2ecf20Sopenharmony_ci if (IS_ERR(rt)) 768c2ecf20Sopenharmony_ci return PTR_ERR(rt); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { 798c2ecf20Sopenharmony_ci ip_rt_put(rt); 808c2ecf20Sopenharmony_ci return -ENETUNREACH; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (inet_opt == NULL || !inet_opt->opt.srr) 848c2ecf20Sopenharmony_ci daddr = fl4->daddr; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (inet->inet_saddr == 0) 878c2ecf20Sopenharmony_ci inet->inet_saddr = fl4->saddr; 888c2ecf20Sopenharmony_ci sk_rcv_saddr_set(sk, inet->inet_saddr); 898c2ecf20Sopenharmony_ci inet->inet_dport = usin->sin_port; 908c2ecf20Sopenharmony_ci sk_daddr_set(sk, daddr); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci inet_csk(sk)->icsk_ext_hdr_len = 0; 938c2ecf20Sopenharmony_ci if (inet_opt) 948c2ecf20Sopenharmony_ci inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen; 958c2ecf20Sopenharmony_ci /* 968c2ecf20Sopenharmony_ci * Socket identity is still unknown (sport may be zero). 978c2ecf20Sopenharmony_ci * However we set state to DCCP_REQUESTING and not releasing socket 988c2ecf20Sopenharmony_ci * lock select source port, enter ourselves into the hash tables and 998c2ecf20Sopenharmony_ci * complete initialization after this. 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci dccp_set_state(sk, DCCP_REQUESTING); 1028c2ecf20Sopenharmony_ci err = inet_hash_connect(&dccp_death_row, sk); 1038c2ecf20Sopenharmony_ci if (err != 0) 1048c2ecf20Sopenharmony_ci goto failure; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci rt = ip_route_newports(fl4, rt, orig_sport, orig_dport, 1078c2ecf20Sopenharmony_ci inet->inet_sport, inet->inet_dport, sk); 1088c2ecf20Sopenharmony_ci if (IS_ERR(rt)) { 1098c2ecf20Sopenharmony_ci err = PTR_ERR(rt); 1108c2ecf20Sopenharmony_ci rt = NULL; 1118c2ecf20Sopenharmony_ci goto failure; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci /* OK, now commit destination to socket. */ 1148c2ecf20Sopenharmony_ci sk_setup_caps(sk, &rt->dst); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci dp->dccps_iss = secure_dccp_sequence_number(inet->inet_saddr, 1178c2ecf20Sopenharmony_ci inet->inet_daddr, 1188c2ecf20Sopenharmony_ci inet->inet_sport, 1198c2ecf20Sopenharmony_ci inet->inet_dport); 1208c2ecf20Sopenharmony_ci inet->inet_id = prandom_u32(); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci err = dccp_connect(sk); 1238c2ecf20Sopenharmony_ci rt = NULL; 1248c2ecf20Sopenharmony_ci if (err != 0) 1258c2ecf20Sopenharmony_ci goto failure; 1268c2ecf20Sopenharmony_ciout: 1278c2ecf20Sopenharmony_ci return err; 1288c2ecf20Sopenharmony_cifailure: 1298c2ecf20Sopenharmony_ci /* 1308c2ecf20Sopenharmony_ci * This unhashes the socket and releases the local port, if necessary. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci dccp_set_state(sk, DCCP_CLOSED); 1338c2ecf20Sopenharmony_ci if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) 1348c2ecf20Sopenharmony_ci inet_reset_saddr(sk); 1358c2ecf20Sopenharmony_ci ip_rt_put(rt); 1368c2ecf20Sopenharmony_ci sk->sk_route_caps = 0; 1378c2ecf20Sopenharmony_ci inet->inet_dport = 0; 1388c2ecf20Sopenharmony_ci goto out; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dccp_v4_connect); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* 1438c2ecf20Sopenharmony_ci * This routine does path mtu discovery as defined in RFC1191. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_cistatic inline void dccp_do_pmtu_discovery(struct sock *sk, 1468c2ecf20Sopenharmony_ci const struct iphdr *iph, 1478c2ecf20Sopenharmony_ci u32 mtu) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct dst_entry *dst; 1508c2ecf20Sopenharmony_ci const struct inet_sock *inet = inet_sk(sk); 1518c2ecf20Sopenharmony_ci const struct dccp_sock *dp = dccp_sk(sk); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* We are not interested in DCCP_LISTEN and request_socks (RESPONSEs 1548c2ecf20Sopenharmony_ci * send out by Linux are always < 576bytes so they should go through 1558c2ecf20Sopenharmony_ci * unfragmented). 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci if (sk->sk_state == DCCP_LISTEN) 1588c2ecf20Sopenharmony_ci return; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci dst = inet_csk_update_pmtu(sk, mtu); 1618c2ecf20Sopenharmony_ci if (!dst) 1628c2ecf20Sopenharmony_ci return; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* Something is about to be wrong... Remember soft error 1658c2ecf20Sopenharmony_ci * for the case, if this connection will not able to recover. 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_ci if (mtu < dst_mtu(dst) && ip_dont_fragment(sk, dst)) 1688c2ecf20Sopenharmony_ci sk->sk_err_soft = EMSGSIZE; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci mtu = dst_mtu(dst); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (inet->pmtudisc != IP_PMTUDISC_DONT && 1738c2ecf20Sopenharmony_ci ip_sk_accept_pmtu(sk) && 1748c2ecf20Sopenharmony_ci inet_csk(sk)->icsk_pmtu_cookie > mtu) { 1758c2ecf20Sopenharmony_ci dccp_sync_mss(sk, mtu); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* 1788c2ecf20Sopenharmony_ci * From RFC 4340, sec. 14.1: 1798c2ecf20Sopenharmony_ci * 1808c2ecf20Sopenharmony_ci * DCCP-Sync packets are the best choice for upward 1818c2ecf20Sopenharmony_ci * probing, since DCCP-Sync probes do not risk application 1828c2ecf20Sopenharmony_ci * data loss. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci dccp_send_sync(sk, dp->dccps_gsr, DCCP_PKT_SYNC); 1858c2ecf20Sopenharmony_ci } /* else let the usual retransmit timer handle it */ 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic void dccp_do_redirect(struct sk_buff *skb, struct sock *sk) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct dst_entry *dst = __sk_dst_check(sk, 0); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (dst) 1938c2ecf20Sopenharmony_ci dst->ops->redirect(dst, sk, skb); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_civoid dccp_req_err(struct sock *sk, u64 seq) 1978c2ecf20Sopenharmony_ci { 1988c2ecf20Sopenharmony_ci struct request_sock *req = inet_reqsk(sk); 1998c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * ICMPs are not backlogged, hence we cannot get an established 2038c2ecf20Sopenharmony_ci * socket here. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci if (!between48(seq, dccp_rsk(req)->dreq_iss, dccp_rsk(req)->dreq_gss)) { 2068c2ecf20Sopenharmony_ci __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS); 2078c2ecf20Sopenharmony_ci } else { 2088c2ecf20Sopenharmony_ci /* 2098c2ecf20Sopenharmony_ci * Still in RESPOND, just remove it silently. 2108c2ecf20Sopenharmony_ci * There is no good way to pass the error to the newly 2118c2ecf20Sopenharmony_ci * created socket, and POSIX does not want network 2128c2ecf20Sopenharmony_ci * errors returned from accept(). 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ci inet_csk_reqsk_queue_drop(req->rsk_listener, req); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci reqsk_put(req); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dccp_req_err); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* 2218c2ecf20Sopenharmony_ci * This routine is called by the ICMP module when it gets some sort of error 2228c2ecf20Sopenharmony_ci * condition. If err < 0 then the socket should be closed and the error 2238c2ecf20Sopenharmony_ci * returned to the user. If err > 0 it's just the icmp type << 8 | icmp code. 2248c2ecf20Sopenharmony_ci * After adjustment header points to the first 8 bytes of the tcp header. We 2258c2ecf20Sopenharmony_ci * need to find the appropriate port. 2268c2ecf20Sopenharmony_ci * 2278c2ecf20Sopenharmony_ci * The locking strategy used here is very "optimistic". When someone else 2288c2ecf20Sopenharmony_ci * accesses the socket the ICMP is just dropped and for some paths there is no 2298c2ecf20Sopenharmony_ci * check at all. A more general error queue to queue errors for later handling 2308c2ecf20Sopenharmony_ci * is probably better. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_cistatic int dccp_v4_err(struct sk_buff *skb, u32 info) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci const struct iphdr *iph = (struct iphdr *)skb->data; 2358c2ecf20Sopenharmony_ci const u8 offset = iph->ihl << 2; 2368c2ecf20Sopenharmony_ci const struct dccp_hdr *dh; 2378c2ecf20Sopenharmony_ci struct dccp_sock *dp; 2388c2ecf20Sopenharmony_ci struct inet_sock *inet; 2398c2ecf20Sopenharmony_ci const int type = icmp_hdr(skb)->type; 2408c2ecf20Sopenharmony_ci const int code = icmp_hdr(skb)->code; 2418c2ecf20Sopenharmony_ci struct sock *sk; 2428c2ecf20Sopenharmony_ci __u64 seq; 2438c2ecf20Sopenharmony_ci int err; 2448c2ecf20Sopenharmony_ci struct net *net = dev_net(skb->dev); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, offset + sizeof(*dh))) 2478c2ecf20Sopenharmony_ci return -EINVAL; 2488c2ecf20Sopenharmony_ci dh = (struct dccp_hdr *)(skb->data + offset); 2498c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, offset + __dccp_basic_hdr_len(dh))) 2508c2ecf20Sopenharmony_ci return -EINVAL; 2518c2ecf20Sopenharmony_ci iph = (struct iphdr *)skb->data; 2528c2ecf20Sopenharmony_ci dh = (struct dccp_hdr *)(skb->data + offset); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci sk = __inet_lookup_established(net, &dccp_hashinfo, 2558c2ecf20Sopenharmony_ci iph->daddr, dh->dccph_dport, 2568c2ecf20Sopenharmony_ci iph->saddr, ntohs(dh->dccph_sport), 2578c2ecf20Sopenharmony_ci inet_iif(skb), 0); 2588c2ecf20Sopenharmony_ci if (!sk) { 2598c2ecf20Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); 2608c2ecf20Sopenharmony_ci return -ENOENT; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (sk->sk_state == DCCP_TIME_WAIT) { 2648c2ecf20Sopenharmony_ci inet_twsk_put(inet_twsk(sk)); 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci seq = dccp_hdr_seq(dh); 2688c2ecf20Sopenharmony_ci if (sk->sk_state == DCCP_NEW_SYN_RECV) { 2698c2ecf20Sopenharmony_ci dccp_req_err(sk, seq); 2708c2ecf20Sopenharmony_ci return 0; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci bh_lock_sock(sk); 2748c2ecf20Sopenharmony_ci /* If too many ICMPs get dropped on busy 2758c2ecf20Sopenharmony_ci * servers this needs to be solved differently. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci if (sock_owned_by_user(sk)) 2788c2ecf20Sopenharmony_ci __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (sk->sk_state == DCCP_CLOSED) 2818c2ecf20Sopenharmony_ci goto out; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci dp = dccp_sk(sk); 2848c2ecf20Sopenharmony_ci if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) && 2858c2ecf20Sopenharmony_ci !between48(seq, dp->dccps_awl, dp->dccps_awh)) { 2868c2ecf20Sopenharmony_ci __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS); 2878c2ecf20Sopenharmony_ci goto out; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci switch (type) { 2918c2ecf20Sopenharmony_ci case ICMP_REDIRECT: 2928c2ecf20Sopenharmony_ci if (!sock_owned_by_user(sk)) 2938c2ecf20Sopenharmony_ci dccp_do_redirect(skb, sk); 2948c2ecf20Sopenharmony_ci goto out; 2958c2ecf20Sopenharmony_ci case ICMP_SOURCE_QUENCH: 2968c2ecf20Sopenharmony_ci /* Just silently ignore these. */ 2978c2ecf20Sopenharmony_ci goto out; 2988c2ecf20Sopenharmony_ci case ICMP_PARAMETERPROB: 2998c2ecf20Sopenharmony_ci err = EPROTO; 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci case ICMP_DEST_UNREACH: 3028c2ecf20Sopenharmony_ci if (code > NR_ICMP_UNREACH) 3038c2ecf20Sopenharmony_ci goto out; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */ 3068c2ecf20Sopenharmony_ci if (!sock_owned_by_user(sk)) 3078c2ecf20Sopenharmony_ci dccp_do_pmtu_discovery(sk, iph, info); 3088c2ecf20Sopenharmony_ci goto out; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci err = icmp_err_convert[code].errno; 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci case ICMP_TIME_EXCEEDED: 3148c2ecf20Sopenharmony_ci err = EHOSTUNREACH; 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci default: 3178c2ecf20Sopenharmony_ci goto out; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci switch (sk->sk_state) { 3218c2ecf20Sopenharmony_ci case DCCP_REQUESTING: 3228c2ecf20Sopenharmony_ci case DCCP_RESPOND: 3238c2ecf20Sopenharmony_ci if (!sock_owned_by_user(sk)) { 3248c2ecf20Sopenharmony_ci __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS); 3258c2ecf20Sopenharmony_ci sk->sk_err = err; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci sk->sk_error_report(sk); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci dccp_done(sk); 3308c2ecf20Sopenharmony_ci } else 3318c2ecf20Sopenharmony_ci sk->sk_err_soft = err; 3328c2ecf20Sopenharmony_ci goto out; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* If we've already connected we will keep trying 3368c2ecf20Sopenharmony_ci * until we time out, or the user gives up. 3378c2ecf20Sopenharmony_ci * 3388c2ecf20Sopenharmony_ci * rfc1122 4.2.3.9 allows to consider as hard errors 3398c2ecf20Sopenharmony_ci * only PROTO_UNREACH and PORT_UNREACH (well, FRAG_FAILED too, 3408c2ecf20Sopenharmony_ci * but it is obsoleted by pmtu discovery). 3418c2ecf20Sopenharmony_ci * 3428c2ecf20Sopenharmony_ci * Note, that in modern internet, where routing is unreliable 3438c2ecf20Sopenharmony_ci * and in each dark corner broken firewalls sit, sending random 3448c2ecf20Sopenharmony_ci * errors ordered by their masters even this two messages finally lose 3458c2ecf20Sopenharmony_ci * their original sense (even Linux sends invalid PORT_UNREACHs) 3468c2ecf20Sopenharmony_ci * 3478c2ecf20Sopenharmony_ci * Now we are in compliance with RFCs. 3488c2ecf20Sopenharmony_ci * --ANK (980905) 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci inet = inet_sk(sk); 3528c2ecf20Sopenharmony_ci if (!sock_owned_by_user(sk) && inet->recverr) { 3538c2ecf20Sopenharmony_ci sk->sk_err = err; 3548c2ecf20Sopenharmony_ci sk->sk_error_report(sk); 3558c2ecf20Sopenharmony_ci } else /* Only an error on timeout */ 3568c2ecf20Sopenharmony_ci sk->sk_err_soft = err; 3578c2ecf20Sopenharmony_ciout: 3588c2ecf20Sopenharmony_ci bh_unlock_sock(sk); 3598c2ecf20Sopenharmony_ci sock_put(sk); 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic inline __sum16 dccp_v4_csum_finish(struct sk_buff *skb, 3648c2ecf20Sopenharmony_ci __be32 src, __be32 dst) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci return csum_tcpudp_magic(src, dst, skb->len, IPPROTO_DCCP, skb->csum); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_civoid dccp_v4_send_check(struct sock *sk, struct sk_buff *skb) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci const struct inet_sock *inet = inet_sk(sk); 3728c2ecf20Sopenharmony_ci struct dccp_hdr *dh = dccp_hdr(skb); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci dccp_csum_outgoing(skb); 3758c2ecf20Sopenharmony_ci dh->dccph_checksum = dccp_v4_csum_finish(skb, 3768c2ecf20Sopenharmony_ci inet->inet_saddr, 3778c2ecf20Sopenharmony_ci inet->inet_daddr); 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dccp_v4_send_check); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic inline u64 dccp_v4_init_sequence(const struct sk_buff *skb) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci return secure_dccp_sequence_number(ip_hdr(skb)->daddr, 3848c2ecf20Sopenharmony_ci ip_hdr(skb)->saddr, 3858c2ecf20Sopenharmony_ci dccp_hdr(skb)->dccph_dport, 3868c2ecf20Sopenharmony_ci dccp_hdr(skb)->dccph_sport); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci/* 3908c2ecf20Sopenharmony_ci * The three way handshake has completed - we got a valid ACK or DATAACK - 3918c2ecf20Sopenharmony_ci * now create the new socket. 3928c2ecf20Sopenharmony_ci * 3938c2ecf20Sopenharmony_ci * This is the equivalent of TCP's tcp_v4_syn_recv_sock 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_cistruct sock *dccp_v4_request_recv_sock(const struct sock *sk, 3968c2ecf20Sopenharmony_ci struct sk_buff *skb, 3978c2ecf20Sopenharmony_ci struct request_sock *req, 3988c2ecf20Sopenharmony_ci struct dst_entry *dst, 3998c2ecf20Sopenharmony_ci struct request_sock *req_unhash, 4008c2ecf20Sopenharmony_ci bool *own_req) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct inet_request_sock *ireq; 4038c2ecf20Sopenharmony_ci struct inet_sock *newinet; 4048c2ecf20Sopenharmony_ci struct sock *newsk; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (sk_acceptq_is_full(sk)) 4078c2ecf20Sopenharmony_ci goto exit_overflow; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci newsk = dccp_create_openreq_child(sk, req, skb); 4108c2ecf20Sopenharmony_ci if (newsk == NULL) 4118c2ecf20Sopenharmony_ci goto exit_nonewsk; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci newinet = inet_sk(newsk); 4148c2ecf20Sopenharmony_ci ireq = inet_rsk(req); 4158c2ecf20Sopenharmony_ci sk_daddr_set(newsk, ireq->ir_rmt_addr); 4168c2ecf20Sopenharmony_ci sk_rcv_saddr_set(newsk, ireq->ir_loc_addr); 4178c2ecf20Sopenharmony_ci newinet->inet_saddr = ireq->ir_loc_addr; 4188c2ecf20Sopenharmony_ci RCU_INIT_POINTER(newinet->inet_opt, rcu_dereference(ireq->ireq_opt)); 4198c2ecf20Sopenharmony_ci newinet->mc_index = inet_iif(skb); 4208c2ecf20Sopenharmony_ci newinet->mc_ttl = ip_hdr(skb)->ttl; 4218c2ecf20Sopenharmony_ci newinet->inet_id = prandom_u32(); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (dst == NULL && (dst = inet_csk_route_child_sock(sk, newsk, req)) == NULL) 4248c2ecf20Sopenharmony_ci goto put_and_exit; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci sk_setup_caps(newsk, dst); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci dccp_sync_mss(newsk, dst_mtu(dst)); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (__inet_inherit_port(sk, newsk) < 0) 4318c2ecf20Sopenharmony_ci goto put_and_exit; 4328c2ecf20Sopenharmony_ci *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), NULL); 4338c2ecf20Sopenharmony_ci if (*own_req) 4348c2ecf20Sopenharmony_ci ireq->ireq_opt = NULL; 4358c2ecf20Sopenharmony_ci else 4368c2ecf20Sopenharmony_ci newinet->inet_opt = NULL; 4378c2ecf20Sopenharmony_ci return newsk; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ciexit_overflow: 4408c2ecf20Sopenharmony_ci __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); 4418c2ecf20Sopenharmony_ciexit_nonewsk: 4428c2ecf20Sopenharmony_ci dst_release(dst); 4438c2ecf20Sopenharmony_ciexit: 4448c2ecf20Sopenharmony_ci __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS); 4458c2ecf20Sopenharmony_ci return NULL; 4468c2ecf20Sopenharmony_ciput_and_exit: 4478c2ecf20Sopenharmony_ci newinet->inet_opt = NULL; 4488c2ecf20Sopenharmony_ci inet_csk_prepare_forced_close(newsk); 4498c2ecf20Sopenharmony_ci dccp_done(newsk); 4508c2ecf20Sopenharmony_ci goto exit; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dccp_v4_request_recv_sock); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, 4558c2ecf20Sopenharmony_ci struct sk_buff *skb) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci struct rtable *rt; 4588c2ecf20Sopenharmony_ci const struct iphdr *iph = ip_hdr(skb); 4598c2ecf20Sopenharmony_ci struct flowi4 fl4 = { 4608c2ecf20Sopenharmony_ci .flowi4_oif = inet_iif(skb), 4618c2ecf20Sopenharmony_ci .daddr = iph->saddr, 4628c2ecf20Sopenharmony_ci .saddr = iph->daddr, 4638c2ecf20Sopenharmony_ci .flowi4_tos = RT_CONN_FLAGS(sk), 4648c2ecf20Sopenharmony_ci .flowi4_proto = sk->sk_protocol, 4658c2ecf20Sopenharmony_ci .fl4_sport = dccp_hdr(skb)->dccph_dport, 4668c2ecf20Sopenharmony_ci .fl4_dport = dccp_hdr(skb)->dccph_sport, 4678c2ecf20Sopenharmony_ci }; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci security_skb_classify_flow(skb, flowi4_to_flowi_common(&fl4)); 4708c2ecf20Sopenharmony_ci rt = ip_route_output_flow(net, &fl4, sk); 4718c2ecf20Sopenharmony_ci if (IS_ERR(rt)) { 4728c2ecf20Sopenharmony_ci IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); 4738c2ecf20Sopenharmony_ci return NULL; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return &rt->dst; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic int dccp_v4_send_response(const struct sock *sk, struct request_sock *req) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci int err = -1; 4828c2ecf20Sopenharmony_ci struct sk_buff *skb; 4838c2ecf20Sopenharmony_ci struct dst_entry *dst; 4848c2ecf20Sopenharmony_ci struct flowi4 fl4; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci dst = inet_csk_route_req(sk, &fl4, req); 4878c2ecf20Sopenharmony_ci if (dst == NULL) 4888c2ecf20Sopenharmony_ci goto out; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci skb = dccp_make_response(sk, dst, req); 4918c2ecf20Sopenharmony_ci if (skb != NULL) { 4928c2ecf20Sopenharmony_ci const struct inet_request_sock *ireq = inet_rsk(req); 4938c2ecf20Sopenharmony_ci struct dccp_hdr *dh = dccp_hdr(skb); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci dh->dccph_checksum = dccp_v4_csum_finish(skb, ireq->ir_loc_addr, 4968c2ecf20Sopenharmony_ci ireq->ir_rmt_addr); 4978c2ecf20Sopenharmony_ci rcu_read_lock(); 4988c2ecf20Sopenharmony_ci err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, 4998c2ecf20Sopenharmony_ci ireq->ir_rmt_addr, 5008c2ecf20Sopenharmony_ci rcu_dereference(ireq->ireq_opt), 5018c2ecf20Sopenharmony_ci inet_sk(sk)->tos); 5028c2ecf20Sopenharmony_ci rcu_read_unlock(); 5038c2ecf20Sopenharmony_ci err = net_xmit_eval(err); 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ciout: 5078c2ecf20Sopenharmony_ci dst_release(dst); 5088c2ecf20Sopenharmony_ci return err; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic void dccp_v4_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci int err; 5148c2ecf20Sopenharmony_ci const struct iphdr *rxiph; 5158c2ecf20Sopenharmony_ci struct sk_buff *skb; 5168c2ecf20Sopenharmony_ci struct dst_entry *dst; 5178c2ecf20Sopenharmony_ci struct net *net = dev_net(skb_dst(rxskb)->dev); 5188c2ecf20Sopenharmony_ci struct sock *ctl_sk = net->dccp.v4_ctl_sk; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci /* Never send a reset in response to a reset. */ 5218c2ecf20Sopenharmony_ci if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) 5228c2ecf20Sopenharmony_ci return; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (skb_rtable(rxskb)->rt_type != RTN_LOCAL) 5258c2ecf20Sopenharmony_ci return; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci dst = dccp_v4_route_skb(net, ctl_sk, rxskb); 5288c2ecf20Sopenharmony_ci if (dst == NULL) 5298c2ecf20Sopenharmony_ci return; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci skb = dccp_ctl_make_reset(ctl_sk, rxskb); 5328c2ecf20Sopenharmony_ci if (skb == NULL) 5338c2ecf20Sopenharmony_ci goto out; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci rxiph = ip_hdr(rxskb); 5368c2ecf20Sopenharmony_ci dccp_hdr(skb)->dccph_checksum = dccp_v4_csum_finish(skb, rxiph->saddr, 5378c2ecf20Sopenharmony_ci rxiph->daddr); 5388c2ecf20Sopenharmony_ci skb_dst_set(skb, dst_clone(dst)); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci local_bh_disable(); 5418c2ecf20Sopenharmony_ci bh_lock_sock(ctl_sk); 5428c2ecf20Sopenharmony_ci err = ip_build_and_send_pkt(skb, ctl_sk, 5438c2ecf20Sopenharmony_ci rxiph->daddr, rxiph->saddr, NULL, 5448c2ecf20Sopenharmony_ci inet_sk(ctl_sk)->tos); 5458c2ecf20Sopenharmony_ci bh_unlock_sock(ctl_sk); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (net_xmit_eval(err) == 0) { 5488c2ecf20Sopenharmony_ci __DCCP_INC_STATS(DCCP_MIB_OUTSEGS); 5498c2ecf20Sopenharmony_ci __DCCP_INC_STATS(DCCP_MIB_OUTRSTS); 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci local_bh_enable(); 5528c2ecf20Sopenharmony_ciout: 5538c2ecf20Sopenharmony_ci dst_release(dst); 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic void dccp_v4_reqsk_destructor(struct request_sock *req) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg); 5598c2ecf20Sopenharmony_ci kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1)); 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_civoid dccp_syn_ack_timeout(const struct request_sock *req) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dccp_syn_ack_timeout); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic struct request_sock_ops dccp_request_sock_ops __read_mostly = { 5688c2ecf20Sopenharmony_ci .family = PF_INET, 5698c2ecf20Sopenharmony_ci .obj_size = sizeof(struct dccp_request_sock), 5708c2ecf20Sopenharmony_ci .rtx_syn_ack = dccp_v4_send_response, 5718c2ecf20Sopenharmony_ci .send_ack = dccp_reqsk_send_ack, 5728c2ecf20Sopenharmony_ci .destructor = dccp_v4_reqsk_destructor, 5738c2ecf20Sopenharmony_ci .send_reset = dccp_v4_ctl_send_reset, 5748c2ecf20Sopenharmony_ci .syn_ack_timeout = dccp_syn_ack_timeout, 5758c2ecf20Sopenharmony_ci}; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ciint dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci struct inet_request_sock *ireq; 5808c2ecf20Sopenharmony_ci struct request_sock *req; 5818c2ecf20Sopenharmony_ci struct dccp_request_sock *dreq; 5828c2ecf20Sopenharmony_ci const __be32 service = dccp_hdr_request(skb)->dccph_req_service; 5838c2ecf20Sopenharmony_ci struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ 5868c2ecf20Sopenharmony_ci if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) 5878c2ecf20Sopenharmony_ci return 0; /* discard, don't send a reset here */ 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (dccp_bad_service_code(sk, service)) { 5908c2ecf20Sopenharmony_ci dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; 5918c2ecf20Sopenharmony_ci goto drop; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci /* 5948c2ecf20Sopenharmony_ci * TW buckets are converted to open requests without 5958c2ecf20Sopenharmony_ci * limitations, they conserve resources and peer is 5968c2ecf20Sopenharmony_ci * evidently real one. 5978c2ecf20Sopenharmony_ci */ 5988c2ecf20Sopenharmony_ci dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; 5998c2ecf20Sopenharmony_ci if (inet_csk_reqsk_queue_is_full(sk)) 6008c2ecf20Sopenharmony_ci goto drop; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (sk_acceptq_is_full(sk)) 6038c2ecf20Sopenharmony_ci goto drop; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci req = inet_reqsk_alloc(&dccp_request_sock_ops, sk, true); 6068c2ecf20Sopenharmony_ci if (req == NULL) 6078c2ecf20Sopenharmony_ci goto drop; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (dccp_reqsk_init(req, dccp_sk(sk), skb)) 6108c2ecf20Sopenharmony_ci goto drop_and_free; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci dreq = dccp_rsk(req); 6138c2ecf20Sopenharmony_ci if (dccp_parse_options(sk, dreq, skb)) 6148c2ecf20Sopenharmony_ci goto drop_and_free; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci ireq = inet_rsk(req); 6178c2ecf20Sopenharmony_ci sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); 6188c2ecf20Sopenharmony_ci sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); 6198c2ecf20Sopenharmony_ci ireq->ir_mark = inet_request_mark(sk, skb); 6208c2ecf20Sopenharmony_ci ireq->ireq_family = AF_INET; 6218c2ecf20Sopenharmony_ci ireq->ir_iif = sk->sk_bound_dev_if; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (security_inet_conn_request(sk, skb, req)) 6248c2ecf20Sopenharmony_ci goto drop_and_free; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* 6278c2ecf20Sopenharmony_ci * Step 3: Process LISTEN state 6288c2ecf20Sopenharmony_ci * 6298c2ecf20Sopenharmony_ci * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie 6308c2ecf20Sopenharmony_ci * 6318c2ecf20Sopenharmony_ci * Setting S.SWL/S.SWH to is deferred to dccp_create_openreq_child(). 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_ci dreq->dreq_isr = dcb->dccpd_seq; 6348c2ecf20Sopenharmony_ci dreq->dreq_gsr = dreq->dreq_isr; 6358c2ecf20Sopenharmony_ci dreq->dreq_iss = dccp_v4_init_sequence(skb); 6368c2ecf20Sopenharmony_ci dreq->dreq_gss = dreq->dreq_iss; 6378c2ecf20Sopenharmony_ci dreq->dreq_service = service; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (dccp_v4_send_response(sk, req)) 6408c2ecf20Sopenharmony_ci goto drop_and_free; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); 6438c2ecf20Sopenharmony_ci reqsk_put(req); 6448c2ecf20Sopenharmony_ci return 0; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cidrop_and_free: 6478c2ecf20Sopenharmony_ci reqsk_free(req); 6488c2ecf20Sopenharmony_cidrop: 6498c2ecf20Sopenharmony_ci __DCCP_INC_STATS(DCCP_MIB_ATTEMPTFAILS); 6508c2ecf20Sopenharmony_ci return -1; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dccp_v4_conn_request); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ciint dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci struct dccp_hdr *dh = dccp_hdr(skb); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (sk->sk_state == DCCP_OPEN) { /* Fast path */ 6598c2ecf20Sopenharmony_ci if (dccp_rcv_established(sk, skb, dh, skb->len)) 6608c2ecf20Sopenharmony_ci goto reset; 6618c2ecf20Sopenharmony_ci return 0; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* 6658c2ecf20Sopenharmony_ci * Step 3: Process LISTEN state 6668c2ecf20Sopenharmony_ci * If P.type == Request or P contains a valid Init Cookie option, 6678c2ecf20Sopenharmony_ci * (* Must scan the packet's options to check for Init 6688c2ecf20Sopenharmony_ci * Cookies. Only Init Cookies are processed here, 6698c2ecf20Sopenharmony_ci * however; other options are processed in Step 8. This 6708c2ecf20Sopenharmony_ci * scan need only be performed if the endpoint uses Init 6718c2ecf20Sopenharmony_ci * Cookies *) 6728c2ecf20Sopenharmony_ci * (* Generate a new socket and switch to that socket *) 6738c2ecf20Sopenharmony_ci * Set S := new socket for this port pair 6748c2ecf20Sopenharmony_ci * S.state = RESPOND 6758c2ecf20Sopenharmony_ci * Choose S.ISS (initial seqno) or set from Init Cookies 6768c2ecf20Sopenharmony_ci * Initialize S.GAR := S.ISS 6778c2ecf20Sopenharmony_ci * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies 6788c2ecf20Sopenharmony_ci * Continue with S.state == RESPOND 6798c2ecf20Sopenharmony_ci * (* A Response packet will be generated in Step 11 *) 6808c2ecf20Sopenharmony_ci * Otherwise, 6818c2ecf20Sopenharmony_ci * Generate Reset(No Connection) unless P.type == Reset 6828c2ecf20Sopenharmony_ci * Drop packet and return 6838c2ecf20Sopenharmony_ci * 6848c2ecf20Sopenharmony_ci * NOTE: the check for the packet types is done in 6858c2ecf20Sopenharmony_ci * dccp_rcv_state_process 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (dccp_rcv_state_process(sk, skb, dh, skb->len)) 6898c2ecf20Sopenharmony_ci goto reset; 6908c2ecf20Sopenharmony_ci return 0; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cireset: 6938c2ecf20Sopenharmony_ci dccp_v4_ctl_send_reset(sk, skb); 6948c2ecf20Sopenharmony_ci kfree_skb(skb); 6958c2ecf20Sopenharmony_ci return 0; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dccp_v4_do_rcv); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci/** 7008c2ecf20Sopenharmony_ci * dccp_invalid_packet - check for malformed packets 7018c2ecf20Sopenharmony_ci * @skb: Packet to validate 7028c2ecf20Sopenharmony_ci * 7038c2ecf20Sopenharmony_ci * Implements RFC 4340, 8.5: Step 1: Check header basics 7048c2ecf20Sopenharmony_ci * Packets that fail these checks are ignored and do not receive Resets. 7058c2ecf20Sopenharmony_ci */ 7068c2ecf20Sopenharmony_ciint dccp_invalid_packet(struct sk_buff *skb) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci const struct dccp_hdr *dh; 7098c2ecf20Sopenharmony_ci unsigned int cscov; 7108c2ecf20Sopenharmony_ci u8 dccph_doff; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (skb->pkt_type != PACKET_HOST) 7138c2ecf20Sopenharmony_ci return 1; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* If the packet is shorter than 12 bytes, drop packet and return */ 7168c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(struct dccp_hdr))) { 7178c2ecf20Sopenharmony_ci DCCP_WARN("pskb_may_pull failed\n"); 7188c2ecf20Sopenharmony_ci return 1; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci dh = dccp_hdr(skb); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci /* If P.type is not understood, drop packet and return */ 7248c2ecf20Sopenharmony_ci if (dh->dccph_type >= DCCP_PKT_INVALID) { 7258c2ecf20Sopenharmony_ci DCCP_WARN("invalid packet type\n"); 7268c2ecf20Sopenharmony_ci return 1; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci /* 7308c2ecf20Sopenharmony_ci * If P.Data Offset is too small for packet type, drop packet and return 7318c2ecf20Sopenharmony_ci */ 7328c2ecf20Sopenharmony_ci dccph_doff = dh->dccph_doff; 7338c2ecf20Sopenharmony_ci if (dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) { 7348c2ecf20Sopenharmony_ci DCCP_WARN("P.Data Offset(%u) too small\n", dccph_doff); 7358c2ecf20Sopenharmony_ci return 1; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci /* 7388c2ecf20Sopenharmony_ci * If P.Data Offset is too large for packet, drop packet and return 7398c2ecf20Sopenharmony_ci */ 7408c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, dccph_doff * sizeof(u32))) { 7418c2ecf20Sopenharmony_ci DCCP_WARN("P.Data Offset(%u) too large\n", dccph_doff); 7428c2ecf20Sopenharmony_ci return 1; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci dh = dccp_hdr(skb); 7458c2ecf20Sopenharmony_ci /* 7468c2ecf20Sopenharmony_ci * If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet 7478c2ecf20Sopenharmony_ci * has short sequence numbers), drop packet and return 7488c2ecf20Sopenharmony_ci */ 7498c2ecf20Sopenharmony_ci if ((dh->dccph_type < DCCP_PKT_DATA || 7508c2ecf20Sopenharmony_ci dh->dccph_type > DCCP_PKT_DATAACK) && dh->dccph_x == 0) { 7518c2ecf20Sopenharmony_ci DCCP_WARN("P.type (%s) not Data || [Data]Ack, while P.X == 0\n", 7528c2ecf20Sopenharmony_ci dccp_packet_name(dh->dccph_type)); 7538c2ecf20Sopenharmony_ci return 1; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* 7578c2ecf20Sopenharmony_ci * If P.CsCov is too large for the packet size, drop packet and return. 7588c2ecf20Sopenharmony_ci * This must come _before_ checksumming (not as RFC 4340 suggests). 7598c2ecf20Sopenharmony_ci */ 7608c2ecf20Sopenharmony_ci cscov = dccp_csum_coverage(skb); 7618c2ecf20Sopenharmony_ci if (cscov > skb->len) { 7628c2ecf20Sopenharmony_ci DCCP_WARN("P.CsCov %u exceeds packet length %d\n", 7638c2ecf20Sopenharmony_ci dh->dccph_cscov, skb->len); 7648c2ecf20Sopenharmony_ci return 1; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci /* If header checksum is incorrect, drop packet and return. 7688c2ecf20Sopenharmony_ci * (This step is completed in the AF-dependent functions.) */ 7698c2ecf20Sopenharmony_ci skb->csum = skb_checksum(skb, 0, cscov, 0); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dccp_invalid_packet); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci/* this is called when real data arrives */ 7768c2ecf20Sopenharmony_cistatic int dccp_v4_rcv(struct sk_buff *skb) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci const struct dccp_hdr *dh; 7798c2ecf20Sopenharmony_ci const struct iphdr *iph; 7808c2ecf20Sopenharmony_ci bool refcounted; 7818c2ecf20Sopenharmony_ci struct sock *sk; 7828c2ecf20Sopenharmony_ci int min_cov; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* Step 1: Check header basics */ 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (dccp_invalid_packet(skb)) 7878c2ecf20Sopenharmony_ci goto discard_it; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci iph = ip_hdr(skb); 7908c2ecf20Sopenharmony_ci /* Step 1: If header checksum is incorrect, drop packet and return */ 7918c2ecf20Sopenharmony_ci if (dccp_v4_csum_finish(skb, iph->saddr, iph->daddr)) { 7928c2ecf20Sopenharmony_ci DCCP_WARN("dropped packet with invalid checksum\n"); 7938c2ecf20Sopenharmony_ci goto discard_it; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci dh = dccp_hdr(skb); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh); 7998c2ecf20Sopenharmony_ci DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci dccp_pr_debug("%8.8s src=%pI4@%-5d dst=%pI4@%-5d seq=%llu", 8028c2ecf20Sopenharmony_ci dccp_packet_name(dh->dccph_type), 8038c2ecf20Sopenharmony_ci &iph->saddr, ntohs(dh->dccph_sport), 8048c2ecf20Sopenharmony_ci &iph->daddr, ntohs(dh->dccph_dport), 8058c2ecf20Sopenharmony_ci (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci if (dccp_packet_without_ack(skb)) { 8088c2ecf20Sopenharmony_ci DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ; 8098c2ecf20Sopenharmony_ci dccp_pr_debug_cat("\n"); 8108c2ecf20Sopenharmony_ci } else { 8118c2ecf20Sopenharmony_ci DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb); 8128c2ecf20Sopenharmony_ci dccp_pr_debug_cat(", ack=%llu\n", (unsigned long long) 8138c2ecf20Sopenharmony_ci DCCP_SKB_CB(skb)->dccpd_ack_seq); 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cilookup: 8178c2ecf20Sopenharmony_ci sk = __inet_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh), 8188c2ecf20Sopenharmony_ci dh->dccph_sport, dh->dccph_dport, 0, &refcounted); 8198c2ecf20Sopenharmony_ci if (!sk) { 8208c2ecf20Sopenharmony_ci dccp_pr_debug("failed to look up flow ID in table and " 8218c2ecf20Sopenharmony_ci "get corresponding socket\n"); 8228c2ecf20Sopenharmony_ci goto no_dccp_socket; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci /* 8268c2ecf20Sopenharmony_ci * Step 2: 8278c2ecf20Sopenharmony_ci * ... or S.state == TIMEWAIT, 8288c2ecf20Sopenharmony_ci * Generate Reset(No Connection) unless P.type == Reset 8298c2ecf20Sopenharmony_ci * Drop packet and return 8308c2ecf20Sopenharmony_ci */ 8318c2ecf20Sopenharmony_ci if (sk->sk_state == DCCP_TIME_WAIT) { 8328c2ecf20Sopenharmony_ci dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n"); 8338c2ecf20Sopenharmony_ci inet_twsk_put(inet_twsk(sk)); 8348c2ecf20Sopenharmony_ci goto no_dccp_socket; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (sk->sk_state == DCCP_NEW_SYN_RECV) { 8388c2ecf20Sopenharmony_ci struct request_sock *req = inet_reqsk(sk); 8398c2ecf20Sopenharmony_ci struct sock *nsk; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci sk = req->rsk_listener; 8428c2ecf20Sopenharmony_ci if (unlikely(sk->sk_state != DCCP_LISTEN)) { 8438c2ecf20Sopenharmony_ci inet_csk_reqsk_queue_drop_and_put(sk, req); 8448c2ecf20Sopenharmony_ci goto lookup; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci sock_hold(sk); 8478c2ecf20Sopenharmony_ci refcounted = true; 8488c2ecf20Sopenharmony_ci nsk = dccp_check_req(sk, skb, req); 8498c2ecf20Sopenharmony_ci if (!nsk) { 8508c2ecf20Sopenharmony_ci reqsk_put(req); 8518c2ecf20Sopenharmony_ci goto discard_and_relse; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci if (nsk == sk) { 8548c2ecf20Sopenharmony_ci reqsk_put(req); 8558c2ecf20Sopenharmony_ci } else if (dccp_child_process(sk, nsk, skb)) { 8568c2ecf20Sopenharmony_ci dccp_v4_ctl_send_reset(sk, skb); 8578c2ecf20Sopenharmony_ci goto discard_and_relse; 8588c2ecf20Sopenharmony_ci } else { 8598c2ecf20Sopenharmony_ci sock_put(sk); 8608c2ecf20Sopenharmony_ci return 0; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci /* 8648c2ecf20Sopenharmony_ci * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage 8658c2ecf20Sopenharmony_ci * o if MinCsCov = 0, only packets with CsCov = 0 are accepted 8668c2ecf20Sopenharmony_ci * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_ci min_cov = dccp_sk(sk)->dccps_pcrlen; 8698c2ecf20Sopenharmony_ci if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) { 8708c2ecf20Sopenharmony_ci dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n", 8718c2ecf20Sopenharmony_ci dh->dccph_cscov, min_cov); 8728c2ecf20Sopenharmony_ci /* FIXME: "Such packets SHOULD be reported using Data Dropped 8738c2ecf20Sopenharmony_ci * options (Section 11.7) with Drop Code 0, Protocol 8748c2ecf20Sopenharmony_ci * Constraints." */ 8758c2ecf20Sopenharmony_ci goto discard_and_relse; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) 8798c2ecf20Sopenharmony_ci goto discard_and_relse; 8808c2ecf20Sopenharmony_ci nf_reset_ct(skb); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4, refcounted); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cino_dccp_socket: 8858c2ecf20Sopenharmony_ci if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) 8868c2ecf20Sopenharmony_ci goto discard_it; 8878c2ecf20Sopenharmony_ci /* 8888c2ecf20Sopenharmony_ci * Step 2: 8898c2ecf20Sopenharmony_ci * If no socket ... 8908c2ecf20Sopenharmony_ci * Generate Reset(No Connection) unless P.type == Reset 8918c2ecf20Sopenharmony_ci * Drop packet and return 8928c2ecf20Sopenharmony_ci */ 8938c2ecf20Sopenharmony_ci if (dh->dccph_type != DCCP_PKT_RESET) { 8948c2ecf20Sopenharmony_ci DCCP_SKB_CB(skb)->dccpd_reset_code = 8958c2ecf20Sopenharmony_ci DCCP_RESET_CODE_NO_CONNECTION; 8968c2ecf20Sopenharmony_ci dccp_v4_ctl_send_reset(sk, skb); 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cidiscard_it: 9008c2ecf20Sopenharmony_ci kfree_skb(skb); 9018c2ecf20Sopenharmony_ci return 0; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cidiscard_and_relse: 9048c2ecf20Sopenharmony_ci if (refcounted) 9058c2ecf20Sopenharmony_ci sock_put(sk); 9068c2ecf20Sopenharmony_ci goto discard_it; 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic const struct inet_connection_sock_af_ops dccp_ipv4_af_ops = { 9108c2ecf20Sopenharmony_ci .queue_xmit = ip_queue_xmit, 9118c2ecf20Sopenharmony_ci .send_check = dccp_v4_send_check, 9128c2ecf20Sopenharmony_ci .rebuild_header = inet_sk_rebuild_header, 9138c2ecf20Sopenharmony_ci .conn_request = dccp_v4_conn_request, 9148c2ecf20Sopenharmony_ci .syn_recv_sock = dccp_v4_request_recv_sock, 9158c2ecf20Sopenharmony_ci .net_header_len = sizeof(struct iphdr), 9168c2ecf20Sopenharmony_ci .setsockopt = ip_setsockopt, 9178c2ecf20Sopenharmony_ci .getsockopt = ip_getsockopt, 9188c2ecf20Sopenharmony_ci .addr2sockaddr = inet_csk_addr2sockaddr, 9198c2ecf20Sopenharmony_ci .sockaddr_len = sizeof(struct sockaddr_in), 9208c2ecf20Sopenharmony_ci}; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic int dccp_v4_init_sock(struct sock *sk) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci static __u8 dccp_v4_ctl_sock_initialized; 9258c2ecf20Sopenharmony_ci int err = dccp_init_sock(sk, dccp_v4_ctl_sock_initialized); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci if (err == 0) { 9288c2ecf20Sopenharmony_ci if (unlikely(!dccp_v4_ctl_sock_initialized)) 9298c2ecf20Sopenharmony_ci dccp_v4_ctl_sock_initialized = 1; 9308c2ecf20Sopenharmony_ci inet_csk(sk)->icsk_af_ops = &dccp_ipv4_af_ops; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci return err; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_cistatic struct timewait_sock_ops dccp_timewait_sock_ops = { 9378c2ecf20Sopenharmony_ci .twsk_obj_size = sizeof(struct inet_timewait_sock), 9388c2ecf20Sopenharmony_ci}; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic struct proto dccp_v4_prot = { 9418c2ecf20Sopenharmony_ci .name = "DCCP", 9428c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 9438c2ecf20Sopenharmony_ci .close = dccp_close, 9448c2ecf20Sopenharmony_ci .connect = dccp_v4_connect, 9458c2ecf20Sopenharmony_ci .disconnect = dccp_disconnect, 9468c2ecf20Sopenharmony_ci .ioctl = dccp_ioctl, 9478c2ecf20Sopenharmony_ci .init = dccp_v4_init_sock, 9488c2ecf20Sopenharmony_ci .setsockopt = dccp_setsockopt, 9498c2ecf20Sopenharmony_ci .getsockopt = dccp_getsockopt, 9508c2ecf20Sopenharmony_ci .sendmsg = dccp_sendmsg, 9518c2ecf20Sopenharmony_ci .recvmsg = dccp_recvmsg, 9528c2ecf20Sopenharmony_ci .backlog_rcv = dccp_v4_do_rcv, 9538c2ecf20Sopenharmony_ci .hash = inet_hash, 9548c2ecf20Sopenharmony_ci .unhash = inet_unhash, 9558c2ecf20Sopenharmony_ci .accept = inet_csk_accept, 9568c2ecf20Sopenharmony_ci .get_port = inet_csk_get_port, 9578c2ecf20Sopenharmony_ci .shutdown = dccp_shutdown, 9588c2ecf20Sopenharmony_ci .destroy = dccp_destroy_sock, 9598c2ecf20Sopenharmony_ci .orphan_count = &dccp_orphan_count, 9608c2ecf20Sopenharmony_ci .max_header = MAX_DCCP_HEADER, 9618c2ecf20Sopenharmony_ci .obj_size = sizeof(struct dccp_sock), 9628c2ecf20Sopenharmony_ci .slab_flags = SLAB_TYPESAFE_BY_RCU, 9638c2ecf20Sopenharmony_ci .rsk_prot = &dccp_request_sock_ops, 9648c2ecf20Sopenharmony_ci .twsk_prot = &dccp_timewait_sock_ops, 9658c2ecf20Sopenharmony_ci .h.hashinfo = &dccp_hashinfo, 9668c2ecf20Sopenharmony_ci}; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_cistatic const struct net_protocol dccp_v4_protocol = { 9698c2ecf20Sopenharmony_ci .handler = dccp_v4_rcv, 9708c2ecf20Sopenharmony_ci .err_handler = dccp_v4_err, 9718c2ecf20Sopenharmony_ci .no_policy = 1, 9728c2ecf20Sopenharmony_ci .netns_ok = 1, 9738c2ecf20Sopenharmony_ci .icmp_strict_tag_validation = 1, 9748c2ecf20Sopenharmony_ci}; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cistatic const struct proto_ops inet_dccp_ops = { 9778c2ecf20Sopenharmony_ci .family = PF_INET, 9788c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 9798c2ecf20Sopenharmony_ci .release = inet_release, 9808c2ecf20Sopenharmony_ci .bind = inet_bind, 9818c2ecf20Sopenharmony_ci .connect = inet_stream_connect, 9828c2ecf20Sopenharmony_ci .socketpair = sock_no_socketpair, 9838c2ecf20Sopenharmony_ci .accept = inet_accept, 9848c2ecf20Sopenharmony_ci .getname = inet_getname, 9858c2ecf20Sopenharmony_ci /* FIXME: work on tcp_poll to rename it to inet_csk_poll */ 9868c2ecf20Sopenharmony_ci .poll = dccp_poll, 9878c2ecf20Sopenharmony_ci .ioctl = inet_ioctl, 9888c2ecf20Sopenharmony_ci .gettstamp = sock_gettstamp, 9898c2ecf20Sopenharmony_ci /* FIXME: work on inet_listen to rename it to sock_common_listen */ 9908c2ecf20Sopenharmony_ci .listen = inet_dccp_listen, 9918c2ecf20Sopenharmony_ci .shutdown = inet_shutdown, 9928c2ecf20Sopenharmony_ci .setsockopt = sock_common_setsockopt, 9938c2ecf20Sopenharmony_ci .getsockopt = sock_common_getsockopt, 9948c2ecf20Sopenharmony_ci .sendmsg = inet_sendmsg, 9958c2ecf20Sopenharmony_ci .recvmsg = sock_common_recvmsg, 9968c2ecf20Sopenharmony_ci .mmap = sock_no_mmap, 9978c2ecf20Sopenharmony_ci .sendpage = sock_no_sendpage, 9988c2ecf20Sopenharmony_ci}; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_cistatic struct inet_protosw dccp_v4_protosw = { 10018c2ecf20Sopenharmony_ci .type = SOCK_DCCP, 10028c2ecf20Sopenharmony_ci .protocol = IPPROTO_DCCP, 10038c2ecf20Sopenharmony_ci .prot = &dccp_v4_prot, 10048c2ecf20Sopenharmony_ci .ops = &inet_dccp_ops, 10058c2ecf20Sopenharmony_ci .flags = INET_PROTOSW_ICSK, 10068c2ecf20Sopenharmony_ci}; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cistatic int __net_init dccp_v4_init_net(struct net *net) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci if (dccp_hashinfo.bhash == NULL) 10118c2ecf20Sopenharmony_ci return -ESOCKTNOSUPPORT; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci return inet_ctl_sock_create(&net->dccp.v4_ctl_sk, PF_INET, 10148c2ecf20Sopenharmony_ci SOCK_DCCP, IPPROTO_DCCP, net); 10158c2ecf20Sopenharmony_ci} 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_cistatic void __net_exit dccp_v4_exit_net(struct net *net) 10188c2ecf20Sopenharmony_ci{ 10198c2ecf20Sopenharmony_ci inet_ctl_sock_destroy(net->dccp.v4_ctl_sk); 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic void __net_exit dccp_v4_exit_batch(struct list_head *net_exit_list) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci inet_twsk_purge(&dccp_hashinfo, AF_INET); 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic struct pernet_operations dccp_v4_ops = { 10288c2ecf20Sopenharmony_ci .init = dccp_v4_init_net, 10298c2ecf20Sopenharmony_ci .exit = dccp_v4_exit_net, 10308c2ecf20Sopenharmony_ci .exit_batch = dccp_v4_exit_batch, 10318c2ecf20Sopenharmony_ci}; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cistatic int __init dccp_v4_init(void) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci int err = proto_register(&dccp_v4_prot, 1); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (err) 10388c2ecf20Sopenharmony_ci goto out; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci inet_register_protosw(&dccp_v4_protosw); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci err = register_pernet_subsys(&dccp_v4_ops); 10438c2ecf20Sopenharmony_ci if (err) 10448c2ecf20Sopenharmony_ci goto out_destroy_ctl_sock; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci err = inet_add_protocol(&dccp_v4_protocol, IPPROTO_DCCP); 10478c2ecf20Sopenharmony_ci if (err) 10488c2ecf20Sopenharmony_ci goto out_proto_unregister; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ciout: 10518c2ecf20Sopenharmony_ci return err; 10528c2ecf20Sopenharmony_ciout_proto_unregister: 10538c2ecf20Sopenharmony_ci unregister_pernet_subsys(&dccp_v4_ops); 10548c2ecf20Sopenharmony_ciout_destroy_ctl_sock: 10558c2ecf20Sopenharmony_ci inet_unregister_protosw(&dccp_v4_protosw); 10568c2ecf20Sopenharmony_ci proto_unregister(&dccp_v4_prot); 10578c2ecf20Sopenharmony_ci goto out; 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_cistatic void __exit dccp_v4_exit(void) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); 10638c2ecf20Sopenharmony_ci unregister_pernet_subsys(&dccp_v4_ops); 10648c2ecf20Sopenharmony_ci inet_unregister_protosw(&dccp_v4_protosw); 10658c2ecf20Sopenharmony_ci proto_unregister(&dccp_v4_prot); 10668c2ecf20Sopenharmony_ci} 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cimodule_init(dccp_v4_init); 10698c2ecf20Sopenharmony_cimodule_exit(dccp_v4_exit); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci/* 10728c2ecf20Sopenharmony_ci * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33) 10738c2ecf20Sopenharmony_ci * values directly, Also cover the case where the protocol is not specified, 10748c2ecf20Sopenharmony_ci * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP 10758c2ecf20Sopenharmony_ci */ 10768c2ecf20Sopenharmony_ciMODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 33, 6); 10778c2ecf20Sopenharmony_ciMODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 0, 6); 10788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 10798c2ecf20Sopenharmony_ciMODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>"); 10808c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol"); 1081