[TCP]: MD5 Signature Option (RFC2385) support.
[linux-drm-fsl-dcu.git] / net / dccp / minisocks.c
index 1393461898bbb277994c7707d009ddebbf68ac90..3975048d80946ac587b16a3011fa4f34425ac547 100644 (file)
@@ -10,8 +10,8 @@
  *     2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/dccp.h>
+#include <linux/kernel.h>
 #include <linux/skbuff.h>
 #include <linux/timer.h>
 
@@ -22,6 +22,7 @@
 #include "ackvec.h"
 #include "ccid.h"
 #include "dccp.h"
+#include "feat.h"
 
 struct inet_timewait_death_row dccp_death_row = {
        .sysctl_max_tw_buckets = NR_FILE * 2,
@@ -40,6 +41,8 @@ struct inet_timewait_death_row dccp_death_row = {
                                            (unsigned long)&dccp_death_row),
 };
 
+EXPORT_SYMBOL_GPL(dccp_death_row);
+
 void dccp_time_wait(struct sock *sk, int state, int timeo)
 {
        struct inet_timewait_sock *tw = NULL;
@@ -50,7 +53,18 @@ void dccp_time_wait(struct sock *sk, int state, int timeo)
        if (tw != NULL) {
                const struct inet_connection_sock *icsk = inet_csk(sk);
                const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
-
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               if (tw->tw_family == PF_INET6) {
+                       const struct ipv6_pinfo *np = inet6_sk(sk);
+                       struct inet6_timewait_sock *tw6;
+
+                       tw->tw_ipv6_offset = inet6_tw_offset(sk->sk_prot);
+                       tw6 = inet6_twsk((struct sock *)tw);
+                       ipv6_addr_copy(&tw6->tw_v6_daddr, &np->daddr);
+                       ipv6_addr_copy(&tw6->tw_v6_rcv_saddr, &np->rcv_saddr);
+                       tw->tw_ipv6only = np->ipv6only;
+               }
+#endif
                /* Linkage updates. */
                __inet_twsk_hashdance(tw, sk, &dccp_hashinfo);
 
@@ -84,8 +98,8 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
        /*
         * Step 3: Process LISTEN state
         *
-        * // Generate a new socket and switch to that socket
-        * Set S := new socket for this port pair
+        *   (* Generate a new socket and switch to that socket *)
+        *   Set S := new socket for this port pair
         */
        struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
 
@@ -93,6 +107,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
                const struct dccp_request_sock *dreq = dccp_rsk(req);
                struct inet_connection_sock *newicsk = inet_csk(sk);
                struct dccp_sock *newdp = dccp_sk(newsk);
+               struct dccp_minisock *newdmsk = dccp_msk(newsk);
 
                newdp->dccps_role          = DCCP_ROLE_SERVER;
                newdp->dccps_hc_rx_ackvec  = NULL;
@@ -101,27 +116,27 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
                newicsk->icsk_rto          = DCCP_TIMEOUT_INIT;
                do_gettimeofday(&newdp->dccps_epoch);
 
-               if (newdp->dccps_options.dccpo_send_ack_vector) {
+               if (dccp_feat_clone(sk, newsk))
+                       goto out_free;
+
+               if (newdmsk->dccpms_send_ack_vector) {
                        newdp->dccps_hc_rx_ackvec =
-                               dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN,
-                                                 GFP_ATOMIC);
-                       /*
-                        * XXX: We're using the same CCIDs set on the parent,
-                        * i.e. sk_clone copied the master sock and left the
-                        * CCID pointers for this child, that is why we do the
-                        * __ccid_get calls.
-                        */
+                                               dccp_ackvec_alloc(GFP_ATOMIC);
                        if (unlikely(newdp->dccps_hc_rx_ackvec == NULL))
                                goto out_free;
                }
 
-               if (unlikely(ccid_hc_rx_init(newdp->dccps_hc_rx_ccid,
-                                            newsk) != 0 ||
-                            ccid_hc_tx_init(newdp->dccps_hc_tx_ccid,
-                                            newsk) != 0)) {
+               newdp->dccps_hc_rx_ccid =
+                           ccid_hc_rx_new(newdmsk->dccpms_rx_ccid,
+                                          newsk, GFP_ATOMIC);
+               newdp->dccps_hc_tx_ccid =
+                           ccid_hc_tx_new(newdmsk->dccpms_tx_ccid,
+                                          newsk, GFP_ATOMIC);
+               if (unlikely(newdp->dccps_hc_rx_ccid == NULL ||
+                            newdp->dccps_hc_tx_ccid == NULL)) {
                        dccp_ackvec_free(newdp->dccps_hc_rx_ackvec);
-                       ccid_hc_rx_exit(newdp->dccps_hc_rx_ccid, newsk);
-                       ccid_hc_tx_exit(newdp->dccps_hc_tx_ccid, newsk);
+                       ccid_hc_rx_delete(newdp->dccps_hc_rx_ccid, newsk);
+                       ccid_hc_tx_delete(newdp->dccps_hc_tx_ccid, newsk);
 out_free:
                        /* It is still raw copy of parent, so invalidate
                         * destructor and make plain sk_free() */
@@ -130,19 +145,16 @@ out_free:
                        return NULL;
                }
 
-               __ccid_get(newdp->dccps_hc_rx_ccid);
-               __ccid_get(newdp->dccps_hc_tx_ccid);
-
                /*
                 * Step 3: Process LISTEN state
                 *
-                *      Choose S.ISS (initial seqno) or set from Init Cookie
-                *      Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init
-                *      Cookie
+                *    Choose S.ISS (initial seqno) or set from Init Cookies
+                *    Initialize S.GAR := S.ISS
+                *    Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
                 */
 
                /* See dccp_v4_conn_request */
-               newdp->dccps_options.dccpo_sequence_window = req->rcv_wnd;
+               newdmsk->dccpms_sequence_window = req->rcv_wnd;
 
                newdp->dccps_gar = newdp->dccps_isr = dreq->dreq_isr;
                dccp_update_gsr(newsk, dreq->dreq_isr);
@@ -170,6 +182,8 @@ out_free:
        return newsk;
 }
 
+EXPORT_SYMBOL_GPL(dccp_create_openreq_child);
+
 /* 
  * Process an incoming packet for RESPOND sockets represented
  * as an request_sock.
@@ -182,15 +196,17 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
 
        /* Check for retransmitted REQUEST */
        if (dccp_hdr(skb)->dccph_type == DCCP_PKT_REQUEST) {
-               if (after48(DCCP_SKB_CB(skb)->dccpd_seq,
-                           dccp_rsk(req)->dreq_isr)) {
-                       struct dccp_request_sock *dreq = dccp_rsk(req);
+               struct dccp_request_sock *dreq = dccp_rsk(req);
 
+               if (after48(DCCP_SKB_CB(skb)->dccpd_seq, dreq->dreq_isr)) {
                        dccp_pr_debug("Retransmitted REQUEST\n");
-                       /* Send another RESPONSE packet */
-                       dccp_set_seqno(&dreq->dreq_iss, dreq->dreq_iss + 1);
-                       dccp_set_seqno(&dreq->dreq_isr,
-                                      DCCP_SKB_CB(skb)->dccpd_seq);
+                       dreq->dreq_isr = DCCP_SKB_CB(skb)->dccpd_seq;
+                       /*
+                        * Send another RESPONSE packet
+                        * To protect against Request floods, increment retrans
+                        * counter (backoff, monitored by dccp_response_timer).
+                        */
+                       req->retrans++;
                        req->rsk_ops->rtx_syn_ack(sk, req, NULL);
                }
                /* Network Duplicate, discard packet */
@@ -214,7 +230,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
                goto drop;
        }
 
-       child = dccp_v4_request_recv_sock(sk, skb, req, NULL);
+       child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL);
        if (child == NULL)
                goto listen_overflow;
 
@@ -230,12 +246,14 @@ listen_overflow:
        DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
 drop:
        if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET)
-               req->rsk_ops->send_reset(skb);
+               req->rsk_ops->send_reset(sk, skb);
 
        inet_csk_reqsk_queue_drop(sk, req, prev);
        goto out;
 }
 
+EXPORT_SYMBOL_GPL(dccp_check_req);
+
 /*
  *  Queue segment on the new socket if the new socket is active,
  *  otherwise we just shortcircuit this and continue with
@@ -266,3 +284,23 @@ int dccp_child_process(struct sock *parent, struct sock *child,
        sock_put(child);
        return ret;
 }
+
+EXPORT_SYMBOL_GPL(dccp_child_process);
+
+void dccp_reqsk_send_ack(struct sk_buff *skb, struct request_sock *rsk)
+{
+       pr_info(KERN_WARNING "DCCP: ACK packets are never sent in "
+                            "LISTEN/RESPOND state\n");
+       dump_stack();
+}
+
+EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
+
+void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
+{
+       inet_rsk(req)->rmt_port = dccp_hdr(skb)->dccph_sport;
+       inet_rsk(req)->acked    = 0;
+       req->rcv_wnd            = sysctl_dccp_feat_sequence_window;
+}
+
+EXPORT_SYMBOL_GPL(dccp_reqsk_init);