xref: /OK3568_Linux_fs/kernel/net/dccp/minisocks.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  net/dccp/minisocks.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  An implementation of the DCCP protocol
6*4882a593Smuzhiyun  *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/dccp.h>
10*4882a593Smuzhiyun #include <linux/gfp.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/skbuff.h>
13*4882a593Smuzhiyun #include <linux/timer.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <net/sock.h>
16*4882a593Smuzhiyun #include <net/xfrm.h>
17*4882a593Smuzhiyun #include <net/inet_timewait_sock.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include "ackvec.h"
20*4882a593Smuzhiyun #include "ccid.h"
21*4882a593Smuzhiyun #include "dccp.h"
22*4882a593Smuzhiyun #include "feat.h"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun struct inet_timewait_death_row dccp_death_row = {
25*4882a593Smuzhiyun 	.sysctl_max_tw_buckets = NR_FILE * 2,
26*4882a593Smuzhiyun 	.hashinfo	= &dccp_hashinfo,
27*4882a593Smuzhiyun };
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(dccp_death_row);
30*4882a593Smuzhiyun 
dccp_time_wait(struct sock * sk,int state,int timeo)31*4882a593Smuzhiyun void dccp_time_wait(struct sock *sk, int state, int timeo)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	struct inet_timewait_sock *tw;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	tw = inet_twsk_alloc(sk, &dccp_death_row, state);
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	if (tw != NULL) {
38*4882a593Smuzhiyun 		const struct inet_connection_sock *icsk = inet_csk(sk);
39*4882a593Smuzhiyun 		const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
40*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
41*4882a593Smuzhiyun 		if (tw->tw_family == PF_INET6) {
42*4882a593Smuzhiyun 			tw->tw_v6_daddr = sk->sk_v6_daddr;
43*4882a593Smuzhiyun 			tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
44*4882a593Smuzhiyun 			tw->tw_ipv6only = sk->sk_ipv6only;
45*4882a593Smuzhiyun 		}
46*4882a593Smuzhiyun #endif
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 		/* Get the TIME_WAIT timeout firing. */
49*4882a593Smuzhiyun 		if (timeo < rto)
50*4882a593Smuzhiyun 			timeo = rto;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 		if (state == DCCP_TIME_WAIT)
53*4882a593Smuzhiyun 			timeo = DCCP_TIMEWAIT_LEN;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 		/* tw_timer is pinned, so we need to make sure BH are disabled
56*4882a593Smuzhiyun 		 * in following section, otherwise timer handler could run before
57*4882a593Smuzhiyun 		 * we complete the initialization.
58*4882a593Smuzhiyun 		 */
59*4882a593Smuzhiyun 		local_bh_disable();
60*4882a593Smuzhiyun 		inet_twsk_schedule(tw, timeo);
61*4882a593Smuzhiyun 		/* Linkage updates.
62*4882a593Smuzhiyun 		 * Note that access to tw after this point is illegal.
63*4882a593Smuzhiyun 		 */
64*4882a593Smuzhiyun 		inet_twsk_hashdance(tw, sk, &dccp_hashinfo);
65*4882a593Smuzhiyun 		local_bh_enable();
66*4882a593Smuzhiyun 	} else {
67*4882a593Smuzhiyun 		/* Sorry, if we're out of memory, just CLOSE this
68*4882a593Smuzhiyun 		 * socket up.  We've got bigger problems than
69*4882a593Smuzhiyun 		 * non-graceful socket closings.
70*4882a593Smuzhiyun 		 */
71*4882a593Smuzhiyun 		DCCP_WARN("time wait bucket table overflow\n");
72*4882a593Smuzhiyun 	}
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	dccp_done(sk);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
dccp_create_openreq_child(const struct sock * sk,const struct request_sock * req,const struct sk_buff * skb)77*4882a593Smuzhiyun struct sock *dccp_create_openreq_child(const struct sock *sk,
78*4882a593Smuzhiyun 				       const struct request_sock *req,
79*4882a593Smuzhiyun 				       const struct sk_buff *skb)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	/*
82*4882a593Smuzhiyun 	 * Step 3: Process LISTEN state
83*4882a593Smuzhiyun 	 *
84*4882a593Smuzhiyun 	 *   (* Generate a new socket and switch to that socket *)
85*4882a593Smuzhiyun 	 *   Set S := new socket for this port pair
86*4882a593Smuzhiyun 	 */
87*4882a593Smuzhiyun 	struct sock *newsk = inet_csk_clone_lock(sk, req, GFP_ATOMIC);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	if (newsk != NULL) {
90*4882a593Smuzhiyun 		struct dccp_request_sock *dreq = dccp_rsk(req);
91*4882a593Smuzhiyun 		struct inet_connection_sock *newicsk = inet_csk(newsk);
92*4882a593Smuzhiyun 		struct dccp_sock *newdp = dccp_sk(newsk);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 		newdp->dccps_role	    = DCCP_ROLE_SERVER;
95*4882a593Smuzhiyun 		newdp->dccps_hc_rx_ackvec   = NULL;
96*4882a593Smuzhiyun 		newdp->dccps_service_list   = NULL;
97*4882a593Smuzhiyun 		newdp->dccps_hc_rx_ccid     = NULL;
98*4882a593Smuzhiyun 		newdp->dccps_hc_tx_ccid     = NULL;
99*4882a593Smuzhiyun 		newdp->dccps_service	    = dreq->dreq_service;
100*4882a593Smuzhiyun 		newdp->dccps_timestamp_echo = dreq->dreq_timestamp_echo;
101*4882a593Smuzhiyun 		newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
102*4882a593Smuzhiyun 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 		INIT_LIST_HEAD(&newdp->dccps_featneg);
105*4882a593Smuzhiyun 		/*
106*4882a593Smuzhiyun 		 * Step 3: Process LISTEN state
107*4882a593Smuzhiyun 		 *
108*4882a593Smuzhiyun 		 *    Choose S.ISS (initial seqno) or set from Init Cookies
109*4882a593Smuzhiyun 		 *    Initialize S.GAR := S.ISS
110*4882a593Smuzhiyun 		 *    Set S.ISR, S.GSR from packet (or Init Cookies)
111*4882a593Smuzhiyun 		 *
112*4882a593Smuzhiyun 		 *    Setting AWL/AWH and SWL/SWH happens as part of the feature
113*4882a593Smuzhiyun 		 *    activation below, as these windows all depend on the local
114*4882a593Smuzhiyun 		 *    and remote Sequence Window feature values (7.5.2).
115*4882a593Smuzhiyun 		 */
116*4882a593Smuzhiyun 		newdp->dccps_iss = dreq->dreq_iss;
117*4882a593Smuzhiyun 		newdp->dccps_gss = dreq->dreq_gss;
118*4882a593Smuzhiyun 		newdp->dccps_gar = newdp->dccps_iss;
119*4882a593Smuzhiyun 		newdp->dccps_isr = dreq->dreq_isr;
120*4882a593Smuzhiyun 		newdp->dccps_gsr = dreq->dreq_gsr;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 		/*
123*4882a593Smuzhiyun 		 * Activate features: initialise CCIDs, sequence windows etc.
124*4882a593Smuzhiyun 		 */
125*4882a593Smuzhiyun 		if (dccp_feat_activate_values(newsk, &dreq->dreq_featneg)) {
126*4882a593Smuzhiyun 			sk_free_unlock_clone(newsk);
127*4882a593Smuzhiyun 			return NULL;
128*4882a593Smuzhiyun 		}
129*4882a593Smuzhiyun 		dccp_init_xmit_timers(newsk);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 		__DCCP_INC_STATS(DCCP_MIB_PASSIVEOPENS);
132*4882a593Smuzhiyun 	}
133*4882a593Smuzhiyun 	return newsk;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(dccp_create_openreq_child);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun /*
139*4882a593Smuzhiyun  * Process an incoming packet for RESPOND sockets represented
140*4882a593Smuzhiyun  * as an request_sock.
141*4882a593Smuzhiyun  */
dccp_check_req(struct sock * sk,struct sk_buff * skb,struct request_sock * req)142*4882a593Smuzhiyun struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
143*4882a593Smuzhiyun 			    struct request_sock *req)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun 	struct sock *child = NULL;
146*4882a593Smuzhiyun 	struct dccp_request_sock *dreq = dccp_rsk(req);
147*4882a593Smuzhiyun 	bool own_req;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	/* TCP/DCCP listeners became lockless.
150*4882a593Smuzhiyun 	 * DCCP stores complex state in its request_sock, so we need
151*4882a593Smuzhiyun 	 * a protection for them, now this code runs without being protected
152*4882a593Smuzhiyun 	 * by the parent (listener) lock.
153*4882a593Smuzhiyun 	 */
154*4882a593Smuzhiyun 	spin_lock_bh(&dreq->dreq_lock);
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	/* Check for retransmitted REQUEST */
157*4882a593Smuzhiyun 	if (dccp_hdr(skb)->dccph_type == DCCP_PKT_REQUEST) {
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 		if (after48(DCCP_SKB_CB(skb)->dccpd_seq, dreq->dreq_gsr)) {
160*4882a593Smuzhiyun 			dccp_pr_debug("Retransmitted REQUEST\n");
161*4882a593Smuzhiyun 			dreq->dreq_gsr = DCCP_SKB_CB(skb)->dccpd_seq;
162*4882a593Smuzhiyun 			/*
163*4882a593Smuzhiyun 			 * Send another RESPONSE packet
164*4882a593Smuzhiyun 			 * To protect against Request floods, increment retrans
165*4882a593Smuzhiyun 			 * counter (backoff, monitored by dccp_response_timer).
166*4882a593Smuzhiyun 			 */
167*4882a593Smuzhiyun 			inet_rtx_syn_ack(sk, req);
168*4882a593Smuzhiyun 		}
169*4882a593Smuzhiyun 		/* Network Duplicate, discard packet */
170*4882a593Smuzhiyun 		goto out;
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (dccp_hdr(skb)->dccph_type != DCCP_PKT_ACK &&
176*4882a593Smuzhiyun 	    dccp_hdr(skb)->dccph_type != DCCP_PKT_DATAACK)
177*4882a593Smuzhiyun 		goto drop;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	/* Invalid ACK */
180*4882a593Smuzhiyun 	if (!between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
181*4882a593Smuzhiyun 				dreq->dreq_iss, dreq->dreq_gss)) {
182*4882a593Smuzhiyun 		dccp_pr_debug("Invalid ACK number: ack_seq=%llu, "
183*4882a593Smuzhiyun 			      "dreq_iss=%llu, dreq_gss=%llu\n",
184*4882a593Smuzhiyun 			      (unsigned long long)
185*4882a593Smuzhiyun 			      DCCP_SKB_CB(skb)->dccpd_ack_seq,
186*4882a593Smuzhiyun 			      (unsigned long long) dreq->dreq_iss,
187*4882a593Smuzhiyun 			      (unsigned long long) dreq->dreq_gss);
188*4882a593Smuzhiyun 		goto drop;
189*4882a593Smuzhiyun 	}
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	if (dccp_parse_options(sk, dreq, skb))
192*4882a593Smuzhiyun 		 goto drop;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL,
195*4882a593Smuzhiyun 							 req, &own_req);
196*4882a593Smuzhiyun 	if (child) {
197*4882a593Smuzhiyun 		child = inet_csk_complete_hashdance(sk, child, req, own_req);
198*4882a593Smuzhiyun 		goto out;
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
202*4882a593Smuzhiyun drop:
203*4882a593Smuzhiyun 	if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET)
204*4882a593Smuzhiyun 		req->rsk_ops->send_reset(sk, skb);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	inet_csk_reqsk_queue_drop(sk, req);
207*4882a593Smuzhiyun out:
208*4882a593Smuzhiyun 	spin_unlock_bh(&dreq->dreq_lock);
209*4882a593Smuzhiyun 	return child;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(dccp_check_req);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun /*
215*4882a593Smuzhiyun  *  Queue segment on the new socket if the new socket is active,
216*4882a593Smuzhiyun  *  otherwise we just shortcircuit this and continue with
217*4882a593Smuzhiyun  *  the new socket.
218*4882a593Smuzhiyun  */
dccp_child_process(struct sock * parent,struct sock * child,struct sk_buff * skb)219*4882a593Smuzhiyun int dccp_child_process(struct sock *parent, struct sock *child,
220*4882a593Smuzhiyun 		       struct sk_buff *skb)
221*4882a593Smuzhiyun 	__releases(child)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	int ret = 0;
224*4882a593Smuzhiyun 	const int state = child->sk_state;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	if (!sock_owned_by_user(child)) {
227*4882a593Smuzhiyun 		ret = dccp_rcv_state_process(child, skb, dccp_hdr(skb),
228*4882a593Smuzhiyun 					     skb->len);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 		/* Wakeup parent, send SIGIO */
231*4882a593Smuzhiyun 		if (state == DCCP_RESPOND && child->sk_state != state)
232*4882a593Smuzhiyun 			parent->sk_data_ready(parent);
233*4882a593Smuzhiyun 	} else {
234*4882a593Smuzhiyun 		/* Alas, it is possible again, because we do lookup
235*4882a593Smuzhiyun 		 * in main socket hash table and lock on listening
236*4882a593Smuzhiyun 		 * socket does not protect us more.
237*4882a593Smuzhiyun 		 */
238*4882a593Smuzhiyun 		__sk_add_backlog(child, skb);
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	bh_unlock_sock(child);
242*4882a593Smuzhiyun 	sock_put(child);
243*4882a593Smuzhiyun 	return ret;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(dccp_child_process);
247*4882a593Smuzhiyun 
dccp_reqsk_send_ack(const struct sock * sk,struct sk_buff * skb,struct request_sock * rsk)248*4882a593Smuzhiyun void dccp_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
249*4882a593Smuzhiyun 			 struct request_sock *rsk)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	DCCP_BUG("DCCP-ACK packets are never sent in LISTEN/RESPOND state");
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
255*4882a593Smuzhiyun 
dccp_reqsk_init(struct request_sock * req,struct dccp_sock const * dp,struct sk_buff const * skb)256*4882a593Smuzhiyun int dccp_reqsk_init(struct request_sock *req,
257*4882a593Smuzhiyun 		    struct dccp_sock const *dp, struct sk_buff const *skb)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	struct dccp_request_sock *dreq = dccp_rsk(req);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	spin_lock_init(&dreq->dreq_lock);
262*4882a593Smuzhiyun 	inet_rsk(req)->ir_rmt_port = dccp_hdr(skb)->dccph_sport;
263*4882a593Smuzhiyun 	inet_rsk(req)->ir_num	   = ntohs(dccp_hdr(skb)->dccph_dport);
264*4882a593Smuzhiyun 	inet_rsk(req)->acked	   = 0;
265*4882a593Smuzhiyun 	dreq->dreq_timestamp_echo  = 0;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	/* inherit feature negotiation options from listening socket */
268*4882a593Smuzhiyun 	return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(dccp_reqsk_init);
272