Merge remote-tracking branches 'regmap/topic/cache' and 'regmap/topic/irq' into regma...
[platform/adaptation/renesas_rcar/renesas_kernel.git] / net / sctp / output.c
index 6ae47ac..be50aa2 100644 (file)
@@ -64,6 +64,8 @@
 #include <net/sctp/checksum.h>
 
 /* Forward declarations for private helpers. */
+static sctp_xmit_t __sctp_packet_append_chunk(struct sctp_packet *packet,
+                                             struct sctp_chunk *chunk);
 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,
@@ -224,7 +226,10 @@ static sctp_xmit_t sctp_packet_bundle_auth(struct sctp_packet *pkt,
        if (!auth)
                return retval;
 
-       retval = sctp_packet_append_chunk(pkt, auth);
+       retval = __sctp_packet_append_chunk(pkt, auth);
+
+       if (retval != SCTP_XMIT_OK)
+               sctp_chunk_free(auth);
 
        return retval;
 }
@@ -256,48 +261,31 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
                        asoc->a_rwnd = asoc->rwnd;
                        sack = sctp_make_sack(asoc);
                        if (sack) {
-                               retval = sctp_packet_append_chunk(pkt, sack);
+                               retval = __sctp_packet_append_chunk(pkt, sack);
+                               if (retval != SCTP_XMIT_OK) {
+                                       sctp_chunk_free(sack);
+                                       goto out;
+                               }
                                asoc->peer.sack_needed = 0;
                                if (del_timer(timer))
                                        sctp_association_put(asoc);
                        }
                }
        }
+out:
        return retval;
 }
 
+
 /* Append a chunk to the offered packet reporting back any inability to do
  * so.
  */
-sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
-                                    struct sctp_chunk *chunk)
+static sctp_xmit_t __sctp_packet_append_chunk(struct sctp_packet *packet,
+                                             struct sctp_chunk *chunk)
 {
        sctp_xmit_t retval = SCTP_XMIT_OK;
        __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length));
 
-       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)
-               goto finish;
-
-       /* Try to bundle SACK chunk */
-       retval = sctp_packet_bundle_sack(packet, chunk);
-       if (retval != SCTP_XMIT_OK)
-               goto finish;
-
        /* 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)
@@ -339,6 +327,62 @@ finish:
        return retval;
 }
 
+/* Append a chunk to the offered packet reporting back any inability to do
+ * so.
+ */
+sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
+                                    struct sctp_chunk *chunk)
+{
+       sctp_xmit_t retval = SCTP_XMIT_OK;
+
+       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)
+               goto finish;
+
+       /* Try to bundle SACK chunk */
+       retval = sctp_packet_bundle_sack(packet, chunk);
+       if (retval != SCTP_XMIT_OK)
+               goto finish;
+
+       retval = __sctp_packet_append_chunk(packet, chunk);
+
+finish:
+       return retval;
+}
+
+static void sctp_packet_release_owner(struct sk_buff *skb)
+{
+       sk_free(skb->sk);
+}
+
+static void sctp_packet_set_owner_w(struct sk_buff *skb, struct sock *sk)
+{
+       skb_orphan(skb);
+       skb->sk = sk;
+       skb->destructor = sctp_packet_release_owner;
+
+       /*
+        * The data chunks have already been accounted for in sctp_sendmsg(),
+        * therefore only reserve a single byte to keep socket around until
+        * the packet has been transmitted.
+        */
+       atomic_inc(&sk->sk_wmem_alloc);
+}
+
 /* All packets are sent to the network through this function from
  * sctp_outq_tail().
  *
@@ -380,12 +424,12 @@ int sctp_packet_transmit(struct sctp_packet *packet)
        /* Set the owning socket so that we know where to get the
         * destination IP address.
         */
-       skb_set_owner_w(nskb, sk);
+       sctp_packet_set_owner_w(nskb, sk);
 
        if (!sctp_transport_dst_check(tp)) {
                sctp_transport_route(tp, NULL, sctp_sk(sk));
                if (asoc && (asoc->param_flags & SPP_PMTUD_ENABLE)) {
-                       sctp_assoc_sync_pmtu(asoc);
+                       sctp_assoc_sync_pmtu(sk, asoc);
                }
        }
        dst = dst_clone(tp->dst);