0001
0002
0003
0004
0005
0006
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
0050 if (timeo < rto)
0051 timeo = rto;
0052
0053 if (state == DCCP_TIME_WAIT)
0054 timeo = DCCP_TIMEWAIT_LEN;
0055
0056
0057
0058
0059
0060 local_bh_disable();
0061 inet_twsk_schedule(tw, timeo);
0062
0063
0064
0065 inet_twsk_hashdance(tw, sk, &dccp_hashinfo);
0066 local_bh_enable();
0067 } else {
0068
0069
0070
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
0084
0085
0086
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
0108
0109
0110
0111
0112
0113
0114
0115
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
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
0141
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
0151
0152
0153
0154
0155 spin_lock_bh(&dreq->dreq_lock);
0156
0157
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
0165
0166
0167
0168 inet_rtx_syn_ack(sk, req);
0169 }
0170
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
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
0217
0218
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
0232 if (state == DCCP_RESPOND && child->sk_state != state)
0233 parent->sk_data_ready(parent);
0234 } else {
0235
0236
0237
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
0269 return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
0270 }
0271
0272 EXPORT_SYMBOL_GPL(dccp_reqsk_init);