[NET]: Fix kfifo_alloc() error check.
[powerpc.git] / net / dccp / output.c
index 6f3a5f0..7102e3a 100644 (file)
@@ -10,7 +10,6 @@
  *     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>
@@ -49,7 +48,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
                struct dccp_hdr *dh;
                /* XXX For now we're using only 48 bits sequence numbers */
-               const int dccp_header_size = sizeof(*dh) +
+               const u32 dccp_header_size = sizeof(*dh) +
                                             sizeof(struct dccp_hdr_ext) +
                                          dccp_packet_hdr_len(dcb->dccpd_type);
                int err, set_ack = 1;
@@ -83,7 +82,11 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                }
 
                dcb->dccpd_seq = dp->dccps_gss;
-               dccp_insert_options(sk, skb);
+
+               if (dccp_insert_options(sk, skb)) {
+                       kfree_skb(skb);
+                       return -EPROTO;
+               }
                
                skb->h.raw = skb_push(skb, dccp_header_size);
                dh = dccp_hdr(skb);
@@ -195,7 +198,7 @@ static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb,
        while (1) {
                prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
 
-               if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
+               if (sk->sk_err)
                        goto do_error;
                if (!*timeo)
                        goto do_nonblock;
@@ -231,37 +234,72 @@ do_interrupted:
        goto out;
 }
 
-int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo)
+static void dccp_write_xmit_timer(unsigned long data) {
+       struct sock *sk = (struct sock *)data;
+       struct dccp_sock *dp = dccp_sk(sk);
+
+       bh_lock_sock(sk);
+       if (sock_owned_by_user(sk))
+               sk_reset_timer(sk, &dp->dccps_xmit_timer, jiffies+1);
+       else
+               dccp_write_xmit(sk, 0);
+       bh_unlock_sock(sk);
+       sock_put(sk);
+}
+
+void dccp_write_xmit(struct sock *sk, int block)
 {
-       const struct dccp_sock *dp = dccp_sk(sk);
-       int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb,
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct sk_buff *skb;
+       long timeo = 30000;     /* If a packet is taking longer than 2 secs
+                                  we have other issues */
+
+       while ((skb = skb_peek(&sk->sk_write_queue))) {
+               int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb,
                                         skb->len);
 
-       if (err > 0)
-               err = dccp_wait_for_ccid(sk, skb, timeo);
+               if (err > 0) {
+                       if (!block) {
+                               sk_reset_timer(sk, &dp->dccps_xmit_timer,
+                                               msecs_to_jiffies(err)+jiffies);
+                               break;
+                       } else
+                               err = dccp_wait_for_ccid(sk, skb, &timeo);
+                       if (err) {
+                               printk(KERN_CRIT "%s:err at dccp_wait_for_ccid"
+                                                " %d\n", __FUNCTION__, err);
+                               dump_stack();
+                       }
+               }
 
-       if (err == 0) {
-               struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
-               const int len = skb->len;
+               skb_dequeue(&sk->sk_write_queue);
+               if (err == 0) {
+                       struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
+                       const int len = skb->len;
 
-               if (sk->sk_state == DCCP_PARTOPEN) {
-                       /* See 8.1.5.  Handshake Completion */
-                       inet_csk_schedule_ack(sk);
-                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+                       if (sk->sk_state == DCCP_PARTOPEN) {
+                               /* See 8.1.5.  Handshake Completion */
+                               inet_csk_schedule_ack(sk);
+                               inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
                                                  inet_csk(sk)->icsk_rto,
                                                  DCCP_RTO_MAX);
-                       dcb->dccpd_type = DCCP_PKT_DATAACK;
-               } else if (dccp_ack_pending(sk))
-                       dcb->dccpd_type = DCCP_PKT_DATAACK;
-               else
-                       dcb->dccpd_type = DCCP_PKT_DATA;
-
-               err = dccp_transmit_skb(sk, skb);
-               ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len);
-       } else
-               kfree_skb(skb);
-
-       return err;
+                               dcb->dccpd_type = DCCP_PKT_DATAACK;
+                       } else if (dccp_ack_pending(sk))
+                               dcb->dccpd_type = DCCP_PKT_DATAACK;
+                       else
+                               dcb->dccpd_type = DCCP_PKT_DATA;
+
+                       err = dccp_transmit_skb(sk, skb);
+                       ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len);
+                       if (err) {
+                               printk(KERN_CRIT "%s:err from "
+                                                "ccid_hc_tx_packet_sent %d\n",
+                                                __FUNCTION__, err);
+                               dump_stack();
+                       }
+               } else
+                       kfree(skb);
+       }
 }
 
 int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
@@ -279,17 +317,16 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
 {
        struct dccp_hdr *dh;
        struct dccp_request_sock *dreq;
-       const int dccp_header_size = sizeof(struct dccp_hdr) +
+       const u32 dccp_header_size = sizeof(struct dccp_hdr) +
                                     sizeof(struct dccp_hdr_ext) +
                                     sizeof(struct dccp_hdr_response);
-       struct sk_buff *skb = sock_wmalloc(sk, MAX_HEADER + DCCP_MAX_OPT_LEN +
-                                              dccp_header_size, 1,
+       struct sk_buff *skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1,
                                           GFP_ATOMIC);
        if (skb == NULL)
                return NULL;
 
        /* Reserve space for headers. */
-       skb_reserve(skb, MAX_HEADER + DCCP_MAX_OPT_LEN + dccp_header_size);
+       skb_reserve(skb, sk->sk_prot->max_header);
 
        skb->dst = dst_clone(dst);
        skb->csum = 0;
@@ -297,7 +334,11 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
        dreq = dccp_rsk(req);
        DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
        DCCP_SKB_CB(skb)->dccpd_seq  = dreq->dreq_iss;
-       dccp_insert_options(sk, skb);
+
+       if (dccp_insert_options(sk, skb)) {
+               kfree_skb(skb);
+               return NULL;
+       }
 
        skb->h.raw = skb_push(skb, dccp_header_size);
 
@@ -326,17 +367,16 @@ static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
 {
        struct dccp_hdr *dh;
        struct dccp_sock *dp = dccp_sk(sk);
-       const int dccp_header_size = sizeof(struct dccp_hdr) +
+       const u32 dccp_header_size = sizeof(struct dccp_hdr) +
                                     sizeof(struct dccp_hdr_ext) +
                                     sizeof(struct dccp_hdr_reset);
-       struct sk_buff *skb = sock_wmalloc(sk, MAX_HEADER + DCCP_MAX_OPT_LEN +
-                                              dccp_header_size, 1,
+       struct sk_buff *skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1,
                                           GFP_ATOMIC);
        if (skb == NULL)
                return NULL;
 
        /* Reserve space for headers. */
-       skb_reserve(skb, MAX_HEADER + DCCP_MAX_OPT_LEN + dccp_header_size);
+       skb_reserve(skb, sk->sk_prot->max_header);
 
        skb->dst = dst_clone(dst);
        skb->csum = 0;
@@ -346,7 +386,11 @@ static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
        DCCP_SKB_CB(skb)->dccpd_reset_code = code;
        DCCP_SKB_CB(skb)->dccpd_type       = DCCP_PKT_RESET;
        DCCP_SKB_CB(skb)->dccpd_seq        = dp->dccps_gss;
-       dccp_insert_options(sk, skb);
+
+       if (dccp_insert_options(sk, skb)) {
+               kfree_skb(skb);
+               return NULL;
+       }
 
        skb->h.raw = skb_push(skb, dccp_header_size);
 
@@ -417,6 +461,9 @@ static inline void dccp_connect_init(struct sock *sk)
        dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss));
 
        icsk->icsk_retransmits = 0;
+       init_timer(&dp->dccps_xmit_timer);
+       dp->dccps_xmit_timer.data = (unsigned long)sk;
+       dp->dccps_xmit_timer.function = dccp_write_xmit_timer;
 }
 
 int dccp_connect(struct sock *sk)
@@ -426,12 +473,12 @@ int dccp_connect(struct sock *sk)
 
        dccp_connect_init(sk);
 
-       skb = alloc_skb(MAX_DCCP_HEADER + 15, sk->sk_allocation);
+       skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
        if (unlikely(skb == NULL))
                return -ENOBUFS;
 
        /* Reserve space for headers. */
-       skb_reserve(skb, MAX_DCCP_HEADER);
+       skb_reserve(skb, sk->sk_prot->max_header);
 
        DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST;
        skb->csum = 0;
@@ -452,7 +499,8 @@ void dccp_send_ack(struct sock *sk)
 {
        /* If we have been reset, we may not send again. */
        if (sk->sk_state != DCCP_CLOSED) {
-               struct sk_buff *skb = alloc_skb(MAX_DCCP_HEADER, GFP_ATOMIC);
+               struct sk_buff *skb = alloc_skb(sk->sk_prot->max_header,
+                                               GFP_ATOMIC);
 
                if (skb == NULL) {
                        inet_csk_schedule_ack(sk);
@@ -464,7 +512,7 @@ void dccp_send_ack(struct sock *sk)
                }
 
                /* Reserve space for headers */
-               skb_reserve(skb, MAX_DCCP_HEADER);
+               skb_reserve(skb, sk->sk_prot->max_header);
                skb->csum = 0;
                DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK;
                dccp_transmit_skb(sk, skb);
@@ -511,14 +559,14 @@ void dccp_send_sync(struct sock *sk, const u64 seq,
         * dccp_transmit_skb() will set the ownership to this
         * sock.
         */
-       struct sk_buff *skb = alloc_skb(MAX_DCCP_HEADER, GFP_ATOMIC);
+       struct sk_buff *skb = alloc_skb(sk->sk_prot->max_header, GFP_ATOMIC);
 
        if (skb == NULL)
                /* FIXME: how to make sure the sync is sent? */
                return;
 
        /* Reserve space for headers and prepare control bits. */
-       skb_reserve(skb, MAX_DCCP_HEADER);
+       skb_reserve(skb, sk->sk_prot->max_header);
        skb->csum = 0;
        DCCP_SKB_CB(skb)->dccpd_type = pkt_type;
        DCCP_SKB_CB(skb)->dccpd_seq = seq;
@@ -550,8 +598,10 @@ void dccp_send_close(struct sock *sk, const int active)
                                        DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ;
 
        if (active) {
+               dccp_write_xmit(sk, 1);
                dccp_skb_entail(sk, skb);
                dccp_transmit_skb(sk, skb_clone(skb, prio));
+               /* FIXME do we need a retransmit timer here? */
        } else
                dccp_transmit_skb(sk, skb);
 }