Merge branch 'linus' into cont_syslog
[safe/jmp/linux-2.6] / net / sctp / output.c
index 7d08f52..a646681 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <net/inet_ecn.h>
 #include <net/ip.h>
 #include <net/icmp.h>
 #include <net/sctp/checksum.h>
 
 /* Forward declarations for private helpers. */
-static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
+static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
                                           struct sctp_chunk *chunk);
+static void sctp_packet_append_data(struct sctp_packet *packet,
+                                          struct sctp_chunk *chunk);
+static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet,
+                                       struct sctp_chunk *chunk,
+                                       u16 chunk_len);
+
+static void sctp_packet_reset(struct sctp_packet *packet)
+{
+       packet->size = packet->overhead;
+       packet->has_cookie_echo = 0;
+       packet->has_sack = 0;
+       packet->has_data = 0;
+       packet->has_auth = 0;
+       packet->ipfragok = 0;
+       packet->auth = NULL;
+}
 
 /* Config a packet.
  * This appears to be a followup set of initializations.
@@ -75,13 +92,8 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
        SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __func__,
                          packet, vtag);
 
+       sctp_packet_reset(packet);
        packet->vtag = vtag;
-       packet->has_cookie_echo = 0;
-       packet->has_sack = 0;
-       packet->has_auth = 0;
-       packet->has_data = 0;
-       packet->ipfragok = 0;
-       packet->auth = NULL;
 
        if (ecn_capable && sctp_packet_empty(packet)) {
                chunk = sctp_get_ecne_prepend(packet->transport->asoc);
@@ -119,15 +131,9 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
        }
        overhead += sizeof(struct sctphdr);
        packet->overhead = overhead;
-       packet->size = overhead;
+       sctp_packet_reset(packet);
        packet->vtag = 0;
-       packet->has_cookie_echo = 0;
-       packet->has_sack = 0;
-       packet->has_auth = 0;
-       packet->has_data = 0;
-       packet->ipfragok = 0;
        packet->malloced = 0;
-       packet->auth = NULL;
        return packet;
 }
 
@@ -204,7 +210,7 @@ static sctp_xmit_t sctp_packet_bundle_auth(struct sctp_packet *pkt,
        /* See if this is an auth chunk we are bundling or if
         * auth is already bundled.
         */
-       if (chunk->chunk_hdr->type == SCTP_CID_AUTH || pkt->auth)
+       if (chunk->chunk_hdr->type == SCTP_CID_AUTH || pkt->has_auth)
                return retval;
 
        /* if the peer did not request this chunk to be authenticated,
@@ -234,18 +240,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
        if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
            !pkt->has_cookie_echo) {
                struct sctp_association *asoc;
+               struct timer_list *timer;
                asoc = pkt->transport->asoc;
+               timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
 
-               if (asoc->a_rwnd > asoc->rwnd) {
+               /* If the SACK timer is running, we have a pending SACK */
+               if (timer_pending(timer)) {
                        struct sctp_chunk *sack;
                        asoc->a_rwnd = asoc->rwnd;
                        sack = sctp_make_sack(asoc);
                        if (sack) {
-                               struct timer_list *timer;
                                retval = sctp_packet_append_chunk(pkt, sack);
                                asoc->peer.sack_needed = 0;
-                               timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
-                               if (timer_pending(timer) && del_timer(timer))
+                               if (del_timer(timer))
                                        sctp_association_put(asoc);
                        }
                }
@@ -261,13 +268,20 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
 {
        sctp_xmit_t retval = SCTP_XMIT_OK;
        __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length));
-       size_t psize;
-       size_t pmtu;
-       int too_big;
 
        SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet,
                          chunk);
 
+       /* Data chunks are special.  Before seeing what else we can
+        * bundle into this packet, check to see if we are allowed to
+        * send this DATA.
+        */
+       if (sctp_chunk_is_data(chunk)) {
+               retval = sctp_packet_can_append_data(packet, chunk);
+               if (retval != SCTP_XMIT_OK)
+                       goto finish;
+       }
+
        /* Try to bundle AUTH chunk */
        retval = sctp_packet_bundle_auth(packet, chunk);
        if (retval != SCTP_XMIT_OK)
@@ -278,51 +292,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
        if (retval != SCTP_XMIT_OK)
                goto finish;
 
-       psize = packet->size;
-       pmtu  = ((packet->transport->asoc) ?
-                (packet->transport->asoc->pathmtu) :
-                (packet->transport->pathmtu));
-
-       too_big = (psize + chunk_len > pmtu);
-
-       /* Decide if we need to fragment or resubmit later. */
-       if (too_big) {
-               /* It's OK to fragmet at IP level if any one of the following
-                * is true:
-                *      1. The packet is empty (meaning this chunk is greater
-                *         the MTU)
-                *      2. The chunk we are adding is a control chunk
-                *      3. The packet doesn't have any data in it yet and data
-                *      requires authentication.
-                */
-               if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) ||
-                   (!packet->has_data && chunk->auth)) {
-                       /* We no longer do re-fragmentation.
-                        * Just fragment at the IP layer, if we
-                        * actually hit this condition
-                        */
-                       packet->ipfragok = 1;
-                       goto append;
-
-               } else {
-                       retval = SCTP_XMIT_PMTU_FULL;
-                       goto finish;
-               }
-       }
-
-append:
-       /* We believe that this chunk is OK to add to the packet (as
-        * long as we have the cwnd for it).
-        */
+       /* Check to see if this chunk will fit into the packet */
+       retval = sctp_packet_will_fit(packet, chunk, chunk_len);
+       if (retval != SCTP_XMIT_OK)
+               goto finish;
 
-       /* DATA is a special case since we must examine both rwnd and cwnd
-        * before we send DATA.
-        */
+       /* We believe that this chunk is OK to add to the packet */
        switch (chunk->chunk_hdr->type) {
            case SCTP_CID_DATA:
-               retval = sctp_packet_append_data(packet, chunk);
-               if (SCTP_XMIT_OK != retval)
-                       goto finish;
+               /* Account for the data being in the packet */
+               sctp_packet_append_data(packet, chunk);
                /* Disallow SACK bundling after DATA. */
                packet->has_sack = 1;
                /* Disallow AUTH bundling after DATA */
@@ -405,13 +384,14 @@ int sctp_packet_transmit(struct sctp_packet *packet)
                        sctp_assoc_sync_pmtu(asoc);
                }
        }
-       nskb->dst = dst_clone(tp->dst);
-       if (!nskb->dst)
+       dst = dst_clone(tp->dst);
+       skb_dst_set(nskb, dst);
+       if (!dst)
                goto no_route;
-       dst = nskb->dst;
 
        /* Build the SCTP header.  */
        sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr));
+       skb_reset_transport_header(nskb);
        sh->source = htons(packet->source_port);
        sh->dest   = htons(packet->destination_port);
 
@@ -449,11 +429,6 @@ int sctp_packet_transmit(struct sctp_packet *packet)
        list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
                list_del_init(&chunk->list);
                if (sctp_chunk_is_data(chunk)) {
-
-                       if (!chunk->has_tsn) {
-                               sctp_chunk_assign_ssn(chunk);
-                               sctp_chunk_assign_tsn(chunk);
-
                        /* 6.3.1 C4) When data is in flight and when allowed
                         * by rule C5, a new RTT measurement MUST be made each
                         * round trip.  Furthermore, new RTT measurements
@@ -461,13 +436,10 @@ int sctp_packet_transmit(struct sctp_packet *packet)
                         * for a given destination transport address.
                         */
 
-                               if (!tp->rto_pending) {
-                                       chunk->rtt_in_progress = 1;
-                                       tp->rto_pending = 1;
-                               }
-                       } else
-                               chunk->resent = 1;
-
+                       if (!tp->rto_pending) {
+                               chunk->rtt_in_progress = 1;
+                               tp->rto_pending = 1;
+                       }
                        has_data = 1;
                }
 
@@ -527,15 +499,25 @@ int sctp_packet_transmit(struct sctp_packet *packet)
         * Note: Adler-32 is no longer applicable, as has been replaced
         * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
         */
-       if (!sctp_checksum_disable && !(dst->dev->features & NETIF_F_NO_CSUM)) {
+       if (!sctp_checksum_disable &&
+           !(dst->dev->features & (NETIF_F_NO_CSUM | NETIF_F_SCTP_CSUM))) {
                __u32 crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len);
 
                /* 3) Put the resultant value into the checksum field in the
                 *    common header, and leave the rest of the bits unchanged.
                 */
                sh->checksum = sctp_end_cksum(crc32);
-       } else
-               nskb->ip_summed = CHECKSUM_UNNECESSARY;
+       } else {
+               if (dst->dev->features & NETIF_F_SCTP_CSUM) {
+                       /* no need to seed psuedo checksum for SCTP */
+                       nskb->ip_summed = CHECKSUM_PARTIAL;
+                       nskb->csum_start = (skb_transport_header(nskb) -
+                                           nskb->head);
+                       nskb->csum_offset = offsetof(struct sctphdr, checksum);
+               } else {
+                       nskb->ip_summed = CHECKSUM_UNNECESSARY;
+               }
+       }
 
        /* IP layer ECN support
         * From RFC 2481
@@ -568,8 +550,6 @@ int sctp_packet_transmit(struct sctp_packet *packet)
                struct timer_list *timer;
                unsigned long timeout;
 
-               tp->last_time_used = jiffies;
-
                /* Restart the AUTOCLOSE timer when sending data. */
                if (sctp_state(asoc, ESTABLISHED) && asoc->autoclose) {
                        timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE];
@@ -587,7 +567,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
        (*tp->af_specific->sctp_xmit)(nskb, tp);
 
 out:
-       packet->size = packet->overhead;
+       sctp_packet_reset(packet);
        return err;
 no_route:
        kfree_skb(nskb);
@@ -621,16 +601,14 @@ nomem:
  * 2nd Level Abstractions
  ********************************************************************/
 
-/* This private function handles the specifics of appending DATA chunks.  */
-static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
+/* This private function check to see if a chunk can be added */
+static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
                                           struct sctp_chunk *chunk)
 {
        sctp_xmit_t retval = SCTP_XMIT_OK;
-       size_t datasize, rwnd, inflight;
+       size_t datasize, rwnd, inflight, flight_size;
        struct sctp_transport *transport = packet->transport;
-       __u32 max_burst_bytes;
        struct sctp_association *asoc = transport->asoc;
-       struct sctp_sock *sp = sctp_sk(asoc->base.sk);
        struct sctp_outq *q = &asoc->outqueue;
 
        /* RFC 2960 6.1  Transmission of DATA Chunks
@@ -647,7 +625,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
         */
 
        rwnd = asoc->peer.rwnd;
-       inflight = asoc->outqueue.outstanding_bytes;
+       inflight = q->outstanding_bytes;
+       flight_size = transport->flight_size;
 
        datasize = sctp_data_size(chunk);
 
@@ -661,28 +640,6 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
                }
        }
 
-       /* sctpimpguide-05 2.14.2
-        * D) When the time comes for the sender to
-        * transmit new DATA chunks, the protocol parameter Max.Burst MUST
-        * first be applied to limit how many new DATA chunks may be sent.
-        * The limit is applied by adjusting cwnd as follows:
-        *      if ((flightsize + Max.Burst * MTU) < cwnd)
-        *              cwnd = flightsize + Max.Burst * MTU
-        */
-       max_burst_bytes = asoc->max_burst * asoc->pathmtu;
-       if ((transport->flight_size + max_burst_bytes) < transport->cwnd) {
-               transport->cwnd = transport->flight_size + max_burst_bytes;
-               SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: "
-                                 "transport: %p, cwnd: %d, "
-                                 "ssthresh: %d, flight_size: %d, "
-                                 "pba: %d\n",
-                                 __func__, transport,
-                                 transport->cwnd,
-                                 transport->ssthresh,
-                                 transport->flight_size,
-                                 transport->partial_bytes_acked);
-       }
-
        /* RFC 2960 6.1  Transmission of DATA Chunks
         *
         * B) At any given time, the sender MUST NOT transmit new data
@@ -696,7 +653,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
         *    ignore the value of cwnd and SHOULD NOT delay retransmission.
         */
        if (chunk->fast_retransmit != SCTP_NEED_FRTX)
-               if (transport->flight_size >= transport->cwnd) {
+               if (flight_size >= transport->cwnd) {
                        retval = SCTP_XMIT_RWND_FULL;
                        goto finish;
                }
@@ -706,20 +663,36 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
         * if any previously transmitted data on the connection remains
         * unacknowledged.
         */
-       if (!sp->nodelay && sctp_packet_empty(packet) &&
-           q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) {
-               unsigned len = datasize + q->out_qlen;
+       if (!sctp_sk(asoc->base.sk)->nodelay && sctp_packet_empty(packet) &&
+           inflight && sctp_state(asoc, ESTABLISHED)) {
+               unsigned max = transport->pathmtu - packet->overhead;
+               unsigned len = chunk->skb->len + q->out_qlen;
 
                /* Check whether this chunk and all the rest of pending
                 * data will fit or delay in hopes of bundling a full
                 * sized packet.
+                * Don't delay large message writes that may have been
+                * fragmeneted into small peices.
                 */
-               if (len < asoc->frag_point) {
+               if ((len < max) && chunk->msg->can_delay) {
                        retval = SCTP_XMIT_NAGLE_DELAY;
                        goto finish;
                }
        }
 
+finish:
+       return retval;
+}
+
+/* This private function does management things when adding DATA chunk */
+static void sctp_packet_append_data(struct sctp_packet *packet,
+                               struct sctp_chunk *chunk)
+{
+       struct sctp_transport *transport = packet->transport;
+       size_t datasize = sctp_data_size(chunk);
+       struct sctp_association *asoc = transport->asoc;
+       u32 rwnd = asoc->peer.rwnd;
+
        /* Keep track of how many bytes are in flight over this transport. */
        transport->flight_size += datasize;
 
@@ -742,7 +715,47 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
        /* Has been accepted for transmission. */
        if (!asoc->peer.prsctp_capable)
                chunk->msg->can_abandon = 0;
+       sctp_chunk_assign_tsn(chunk);
+       sctp_chunk_assign_ssn(chunk);
+}
+
+static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet,
+                                       struct sctp_chunk *chunk,
+                                       u16 chunk_len)
+{
+       size_t psize;
+       size_t pmtu;
+       int too_big;
+       sctp_xmit_t retval = SCTP_XMIT_OK;
+
+       psize = packet->size;
+       pmtu  = ((packet->transport->asoc) ?
+               (packet->transport->asoc->pathmtu) :
+               (packet->transport->pathmtu));
+
+       too_big = (psize + chunk_len > pmtu);
+
+       /* Decide if we need to fragment or resubmit later. */
+       if (too_big) {
+               /* It's OK to fragmet at IP level if any one of the following
+                * is true:
+                *      1. The packet is empty (meaning this chunk is greater
+                *         the MTU)
+                *      2. The chunk we are adding is a control chunk
+                *      3. The packet doesn't have any data in it yet and data
+                *      requires authentication.
+                */
+               if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) ||
+                   (!packet->has_data && chunk->auth)) {
+                       /* We no longer do re-fragmentation.
+                        * Just fragment at the IP layer, if we
+                        * actually hit this condition
+                        */
+                       packet->ipfragok = 1;
+               } else {
+                       retval = SCTP_XMIT_PMTU_FULL;
+               }
+       }
 
-finish:
        return retval;
 }