diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h
index e8e3a64eb322..148cdb4b9606 100644
--- a/include/net/sctp/sm.h
+++ b/include/net/sctp/sm.h
@@ -256,6 +256,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
 struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
 				    __u32 new_cum_tsn, size_t nstreams,
 				    struct sctp_fwdtsn_skip *skiplist);
+struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc);
 
 void sctp_chunk_assign_tsn(struct sctp_chunk *);
 void sctp_chunk_assign_ssn(struct sctp_chunk *);
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 18b06afacea0..31841c3a7fe8 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -798,6 +798,9 @@ struct sctp_packet {
 	/* This packet contains an AUTH chunk */
 	__u8 has_auth;
 
+	/* This packet contains at least 1 DATA chunk */
+	__u8 has_data;
+
 	/* SCTP cannot fragment this packet. So let ip fragment it. */
 	__u8 ipfragok;
 
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 77fb7b06a9c4..619d0f2dee51 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -194,6 +194,18 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
 
 	max = asoc->frag_point;
 
+	/* If the the peer requested that we authenticate DATA chunks
+	 * we need to accound for bundling of the AUTH chunks along with
+	 * DATA.
+	 */
+	if (sctp_auth_send_cid(SCTP_CID_DATA, asoc)) {
+		struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc);
+
+		if (hmac_desc)
+			max -= WORD_ROUND(sizeof(sctp_auth_chunk_t) +
+					    hmac_desc->hmac_len);
+	}
+
 	whole = 0;
 	first_len = max;
 
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 49b9f5f031a4..847639d542c0 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -80,6 +80,7 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
 	packet->has_cookie_echo = 0;
 	packet->has_sack = 0;
 	packet->has_auth = 0;
+	packet->has_data = 0;
 	packet->ipfragok = 0;
 	packet->auth = NULL;
 
@@ -124,6 +125,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
 	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;
@@ -185,6 +187,39 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
 	return retval;
 }
 
+/* Try to bundle an auth chunk into the packet. */
+static sctp_xmit_t sctp_packet_bundle_auth(struct sctp_packet *pkt,
+					   struct sctp_chunk *chunk)
+{
+	struct sctp_association *asoc = pkt->transport->asoc;
+	struct sctp_chunk *auth;
+	sctp_xmit_t retval = SCTP_XMIT_OK;
+
+	/* if we don't have an association, we can't do authentication */
+	if (!asoc)
+		return retval;
+
+	/* 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)
+		return retval;
+
+	/* if the peer did not request this chunk to be authenticated,
+	 * don't do it
+	 */
+	if (!chunk->auth)
+		return retval;
+
+	auth = sctp_make_auth(asoc);
+	if (!auth)
+		return retval;
+
+	retval = sctp_packet_append_chunk(pkt, auth);
+
+	return retval;
+}
+
 /* Try to bundle a SACK with the packet. */
 static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
 					   struct sctp_chunk *chunk)
@@ -231,12 +266,17 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
 	SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, packet,
 			  chunk);
 
-	retval = sctp_packet_bundle_sack(packet, chunk);
-	psize = packet->size;
-
+	/* 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;
+
+	psize = packet->size;
 	pmtu  = ((packet->transport->asoc) ?
 		 (packet->transport->asoc->pathmtu) :
 		 (packet->transport->pathmtu));
@@ -245,10 +285,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
 
 	/* Decide if we need to fragment or resubmit later. */
 	if (too_big) {
-		/* Both control chunks and data chunks with TSNs are
-		 * non-fragmentable.
+		/* 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)) {
+		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
@@ -270,16 +316,31 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
 	/* DATA is a special case since we must examine both rwnd and cwnd
 	 * before we send DATA.
 	 */
-	if (sctp_chunk_is_data(chunk)) {
+	switch (chunk->chunk_hdr->type) {
+	    case SCTP_CID_DATA:
 		retval = sctp_packet_append_data(packet, chunk);
 		/* Disallow SACK bundling after DATA. */
 		packet->has_sack = 1;
+		/* Disallow AUTH bundling after DATA */
+		packet->has_auth = 1;
+		/* Let it be knows that packet has DATA in it */
+		packet->has_data = 1;
 		if (SCTP_XMIT_OK != retval)
 			goto finish;
-	} else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type)
+		break;
+	    case SCTP_CID_COOKIE_ECHO:
 		packet->has_cookie_echo = 1;
-	else if (SCTP_CID_SACK == chunk->chunk_hdr->type)
+		break;
+
+	    case SCTP_CID_SACK:
 		packet->has_sack = 1;
+		break;
+
+	    case SCTP_CID_AUTH:
+		packet->has_auth = 1;
+		packet->auth = chunk;
+		break;
+	}
 
 	/* It is OK to send this chunk.  */
 	list_add_tail(&chunk->list, &packet->chunk_list);
@@ -307,6 +368,8 @@ int sctp_packet_transmit(struct sctp_packet *packet)
 	int padding;		/* How much padding do we need?  */
 	__u8 has_data = 0;
 	struct dst_entry *dst = tp->dst;
+	unsigned char *auth = NULL;	/* pointer to auth in skb data */
+	__u32 cksum_buf_len = sizeof(struct sctphdr);
 
 	SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
 
@@ -360,16 +423,6 @@ int sctp_packet_transmit(struct sctp_packet *packet)
 	sh->vtag     = htonl(packet->vtag);
 	sh->checksum = 0;
 
-	/* 2) Calculate the Adler-32 checksum of the whole packet,
-	 *    including the SCTP common header and all the
-	 *    chunks.
-	 *
-	 * Note: Adler-32 is no longer applicable, as has been replaced
-	 * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
-	 */
-	if (!(dst->dev->features & NETIF_F_NO_CSUM))
-		crc32 = sctp_start_cksum((__u8 *)sh, sizeof(struct sctphdr));
-
 	/**
 	 * 6.10 Bundling
 	 *
@@ -420,14 +473,16 @@ int sctp_packet_transmit(struct sctp_packet *packet)
 		if (padding)
 			memset(skb_put(chunk->skb, padding), 0, padding);
 
-		if (dst->dev->features & NETIF_F_NO_CSUM)
-			memcpy(skb_put(nskb, chunk->skb->len),
+		/* if this is the auth chunk that we are adding,
+		 * store pointer where it will be added and put
+		 * the auth into the packet.
+		 */
+		if (chunk == packet->auth)
+			auth = skb_tail_pointer(nskb);
+
+		cksum_buf_len += chunk->skb->len;
+		memcpy(skb_put(nskb, chunk->skb->len),
 			       chunk->skb->data, chunk->skb->len);
-		else
-			crc32 = sctp_update_copy_cksum(skb_put(nskb,
-							chunk->skb->len),
-						chunk->skb->data,
-						chunk->skb->len, crc32);
 
 		SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d\n",
 				  "*** Chunk", chunk,
@@ -449,9 +504,31 @@ int sctp_packet_transmit(struct sctp_packet *packet)
 			sctp_chunk_free(chunk);
 	}
 
-	/* Perform final transformation on checksum. */
-	if (!(dst->dev->features & NETIF_F_NO_CSUM))
+	/* SCTP-AUTH, Section 6.2
+	 *    The sender MUST calculate the MAC as described in RFC2104 [2]
+	 *    using the hash function H as described by the MAC Identifier and
+	 *    the shared association key K based on the endpoint pair shared key
+	 *    described by the shared key identifier.  The 'data' used for the
+	 *    computation of the AUTH-chunk is given by the AUTH chunk with its
+	 *    HMAC field set to zero (as shown in Figure 6) followed by all
+	 *    chunks that are placed after the AUTH chunk in the SCTP packet.
+	 */
+	if (auth)
+		sctp_auth_calculate_hmac(asoc, nskb,
+					(struct sctp_auth_chunk *)auth,
+					GFP_ATOMIC);
+
+	/* 2) Calculate the Adler-32 checksum of the whole packet,
+	 *    including the SCTP common header and all the
+	 *    chunks.
+	 *
+	 * Note: Adler-32 is no longer applicable, as has been replaced
+	 * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
+	 */
+	if (!(dst->dev->features & NETIF_F_NO_CSUM)) {
+		crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len);
 		crc32 = sctp_end_cksum(crc32);
+	}
 
 	/* 3) Put the resultant value into the checksum field in the
 	 *    common header, and leave the rest of the bits unchanged.
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 4c02875786ac..fa2ba543183d 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1111,6 +1111,41 @@ struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
 	return retval;
 }
 
+struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)
+{
+	struct sctp_chunk *retval;
+	struct sctp_hmac *hmac_desc;
+	struct sctp_authhdr auth_hdr;
+	__u8 *hmac;
+
+	/* Get the first hmac that the peer told us to use */
+	hmac_desc = sctp_auth_asoc_get_hmac(asoc);
+	if (unlikely(!hmac_desc))
+		return NULL;
+
+	retval = sctp_make_chunk(asoc, SCTP_CID_AUTH, 0,
+			hmac_desc->hmac_len + sizeof(sctp_authhdr_t));
+	if (!retval)
+		return NULL;
+
+	auth_hdr.hmac_id = htons(hmac_desc->hmac_id);
+	auth_hdr.shkey_id = htons(asoc->active_key_id);
+
+	retval->subh.auth_hdr = sctp_addto_chunk(retval, sizeof(sctp_authhdr_t),
+						&auth_hdr);
+
+	hmac = skb_put(retval->skb, hmac_desc->hmac_len);
+	memset(hmac, 0, hmac_desc->hmac_len);
+
+	/* Adjust the chunk header to include the empty MAC */
+	retval->chunk_hdr->length =
+		htons(ntohs(retval->chunk_hdr->length) + hmac_desc->hmac_len);
+	retval->chunk_end = skb_tail_pointer(retval->skb);
+
+	return retval;
+}
+
+
 /********************************************************************
  * 2nd Level Abstractions
  ********************************************************************/
@@ -1225,6 +1260,10 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
 	retval->chunk_hdr = chunk_hdr;
 	retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(struct sctp_chunkhdr);
 
+	/* Determine if the chunk needs to be authenticated */
+	if (sctp_auth_send_cid(type, asoc))
+		retval->auth = 1;
+
 	/* Set the skb to the belonging sock for accounting.  */
 	skb->sk = sk;