Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  net/dccp/minisocks.c
0004  *
0005  *  An implementation of the DCCP protocol
0006  *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
0007  */
0008 
0009 #include <linux/dccp.h>
0010 #include <linux/gfp.h>
0011 #include <linux/kernel.h>
0012 #include <linux/skbuff.h>
0013 #include <linux/timer.h>
0014 
0015 #include <net/sock.h>
0016 #include <net/xfrm.h>
0017 #include <net/inet_timewait_sock.h>
0018 
0019 #include "ackvec.h"
0020 #include "ccid.h"
0021 #include "dccp.h"
0022 #include "feat.h"
0023 
0024 struct inet_timewait_death_row dccp_death_row = {
0025     .tw_refcount = REFCOUNT_INIT(1),
0026     .sysctl_max_tw_buckets = NR_FILE * 2,
0027     .hashinfo   = &dccp_hashinfo,
0028 };
0029 
0030 EXPORT_SYMBOL_GPL(dccp_death_row);
0031 
0032 void dccp_time_wait(struct sock *sk, int state, int timeo)
0033 {
0034     struct inet_timewait_sock *tw;
0035 
0036     tw = inet_twsk_alloc(sk, &dccp_death_row, state);
0037 
0038     if (tw != NULL) {
0039         const struct inet_connection_sock *icsk = inet_csk(sk);
0040         const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
0041 #if IS_ENABLED(CONFIG_IPV6)
0042         if (tw->tw_family == PF_INET6) {
0043             tw->tw_v6_daddr = sk->sk_v6_daddr;
0044             tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
0045             tw->tw_ipv6only = sk->sk_ipv6only;
0046         }
0047 #endif
0048 
0049         /* Get the TIME_WAIT timeout firing. */
0050         if (timeo < rto)
0051             timeo = rto;
0052 
0053         if (state == DCCP_TIME_WAIT)
0054             timeo = DCCP_TIMEWAIT_LEN;
0055 
0056         /* tw_timer is pinned, so we need to make sure BH are disabled
0057          * in following section, otherwise timer handler could run before
0058          * we complete the initialization.
0059          */
0060         local_bh_disable();
0061         inet_twsk_schedule(tw, timeo);
0062         /* Linkage updates.
0063          * Note that access to tw after this point is illegal.
0064          */
0065         inet_twsk_hashdance(tw, sk, &dccp_hashinfo);
0066         local_bh_enable();
0067     } else {
0068         /* Sorry, if we're out of memory, just CLOSE this
0069          * socket up.  We've got bigger problems than
0070          * non-graceful socket closings.
0071          */
0072         DCCP_WARN("time wait bucket table overflow\n");
0073     }
0074 
0075     dccp_done(sk);
0076 }
0077 
0078 struct sock *dccp_create_openreq_child(const struct sock *sk,
0079                        const struct request_sock *req,
0080                        const struct sk_buff *skb)
0081 {
0082     /*
0083      * Step 3: Process LISTEN state
0084      *
0085      *   (* Generate a new socket and switch to that socket *)
0086      *   Set S := new socket for this port pair
0087      */
0088     struct sock *newsk = inet_csk_clone_lock(sk, req, GFP_ATOMIC);
0089 
0090     if (newsk != NULL) {
0091         struct dccp_request_sock *dreq = dccp_rsk(req);
0092         struct inet_connection_sock *newicsk = inet_csk(newsk);
0093         struct dccp_sock *newdp = dccp_sk(newsk);
0094 
0095         newdp->dccps_role       = DCCP_ROLE_SERVER;
0096         newdp->dccps_hc_rx_ackvec   = NULL;
0097         newdp->dccps_service_list   = NULL;
0098         newdp->dccps_hc_rx_ccid     = NULL;
0099         newdp->dccps_hc_tx_ccid     = NULL;
0100         newdp->dccps_service        = dreq->dreq_service;
0101         newdp->dccps_timestamp_echo = dreq->dreq_timestamp_echo;
0102         newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
0103         newicsk->icsk_rto       = DCCP_TIMEOUT_INIT;
0104 
0105         INIT_LIST_HEAD(&newdp->dccps_featneg);
0106         /*
0107          * Step 3: Process LISTEN state
0108          *
0109          *    Choose S.ISS (initial seqno) or set from Init Cookies
0110          *    Initialize S.GAR := S.ISS
0111          *    Set S.ISR, S.GSR from packet (or Init Cookies)
0112          *
0113          *    Setting AWL/AWH and SWL/SWH happens as part of the feature
0114          *    activation below, as these windows all depend on the local
0115          *    and remote Sequence Window feature values (7.5.2).
0116          */
0117         newdp->dccps_iss = dreq->dreq_iss;
0118         newdp->dccps_gss = dreq->dreq_gss;
0119         newdp->dccps_gar = newdp->dccps_iss;
0120         newdp->dccps_isr = dreq->dreq_isr;
0121         newdp->dccps_gsr = dreq->dreq_gsr;
0122 
0123         /*
0124          * Activate features: initialise CCIDs, sequence windows etc.
0125          */
0126         if (dccp_feat_activate_values(newsk, &dreq->dreq_featneg)) {
0127             sk_free_unlock_clone(newsk);
0128             return NULL;
0129         }
0130         dccp_init_xmit_timers(newsk);
0131 
0132         __DCCP_INC_STATS(DCCP_MIB_PASSIVEOPENS);
0133     }
0134     return newsk;
0135 }
0136 
0137 EXPORT_SYMBOL_GPL(dccp_create_openreq_child);
0138 
0139 /*
0140  * Process an incoming packet for RESPOND sockets represented
0141  * as an request_sock.
0142  */
0143 struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
0144                 struct request_sock *req)
0145 {
0146     struct sock *child = NULL;
0147     struct dccp_request_sock *dreq = dccp_rsk(req);
0148     bool own_req;
0149 
0150     /* TCP/DCCP listeners became lockless.
0151      * DCCP stores complex state in its request_sock, so we need
0152      * a protection for them, now this code runs without being protected
0153      * by the parent (listener) lock.
0154      */
0155     spin_lock_bh(&dreq->dreq_lock);
0156 
0157     /* Check for retransmitted REQUEST */
0158     if (dccp_hdr(skb)->dccph_type == DCCP_PKT_REQUEST) {
0159 
0160         if (after48(DCCP_SKB_CB(skb)->dccpd_seq, dreq->dreq_gsr)) {
0161             dccp_pr_debug("Retransmitted REQUEST\n");
0162             dreq->dreq_gsr = DCCP_SKB_CB(skb)->dccpd_seq;
0163             /*
0164              * Send another RESPONSE packet
0165              * To protect against Request floods, increment retrans
0166              * counter (backoff, monitored by dccp_response_timer).
0167              */
0168             inet_rtx_syn_ack(sk, req);
0169         }
0170         /* Network Duplicate, discard packet */
0171         goto out;
0172     }
0173 
0174     DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR;
0175 
0176     if (dccp_hdr(skb)->dccph_type != DCCP_PKT_ACK &&
0177         dccp_hdr(skb)->dccph_type != DCCP_PKT_DATAACK)
0178         goto drop;
0179 
0180     /* Invalid ACK */
0181     if (!between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
0182                 dreq->dreq_iss, dreq->dreq_gss)) {
0183         dccp_pr_debug("Invalid ACK number: ack_seq=%llu, "
0184                   "dreq_iss=%llu, dreq_gss=%llu\n",
0185                   (unsigned long long)
0186                   DCCP_SKB_CB(skb)->dccpd_ack_seq,
0187                   (unsigned long long) dreq->dreq_iss,
0188                   (unsigned long long) dreq->dreq_gss);
0189         goto drop;
0190     }
0191 
0192     if (dccp_parse_options(sk, dreq, skb))
0193          goto drop;
0194 
0195     child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL,
0196                              req, &own_req);
0197     if (child) {
0198         child = inet_csk_complete_hashdance(sk, child, req, own_req);
0199         goto out;
0200     }
0201 
0202     DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
0203 drop:
0204     if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET)
0205         req->rsk_ops->send_reset(sk, skb);
0206 
0207     inet_csk_reqsk_queue_drop(sk, req);
0208 out:
0209     spin_unlock_bh(&dreq->dreq_lock);
0210     return child;
0211 }
0212 
0213 EXPORT_SYMBOL_GPL(dccp_check_req);
0214 
0215 /*
0216  *  Queue segment on the new socket if the new socket is active,
0217  *  otherwise we just shortcircuit this and continue with
0218  *  the new socket.
0219  */
0220 int dccp_child_process(struct sock *parent, struct sock *child,
0221                struct sk_buff *skb)
0222     __releases(child)
0223 {
0224     int ret = 0;
0225     const int state = child->sk_state;
0226 
0227     if (!sock_owned_by_user(child)) {
0228         ret = dccp_rcv_state_process(child, skb, dccp_hdr(skb),
0229                          skb->len);
0230 
0231         /* Wakeup parent, send SIGIO */
0232         if (state == DCCP_RESPOND && child->sk_state != state)
0233             parent->sk_data_ready(parent);
0234     } else {
0235         /* Alas, it is possible again, because we do lookup
0236          * in main socket hash table and lock on listening
0237          * socket does not protect us more.
0238          */
0239         __sk_add_backlog(child, skb);
0240     }
0241 
0242     bh_unlock_sock(child);
0243     sock_put(child);
0244     return ret;
0245 }
0246 
0247 EXPORT_SYMBOL_GPL(dccp_child_process);
0248 
0249 void dccp_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
0250              struct request_sock *rsk)
0251 {
0252     DCCP_BUG("DCCP-ACK packets are never sent in LISTEN/RESPOND state");
0253 }
0254 
0255 EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
0256 
0257 int dccp_reqsk_init(struct request_sock *req,
0258             struct dccp_sock const *dp, struct sk_buff const *skb)
0259 {
0260     struct dccp_request_sock *dreq = dccp_rsk(req);
0261 
0262     spin_lock_init(&dreq->dreq_lock);
0263     inet_rsk(req)->ir_rmt_port = dccp_hdr(skb)->dccph_sport;
0264     inet_rsk(req)->ir_num      = ntohs(dccp_hdr(skb)->dccph_dport);
0265     inet_rsk(req)->acked       = 0;
0266     dreq->dreq_timestamp_echo  = 0;
0267 
0268     /* inherit feature negotiation options from listening socket */
0269     return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
0270 }
0271 
0272 EXPORT_SYMBOL_GPL(dccp_reqsk_init);