sctp_supported_ext_param_t ext_param;
        int num_ext = 0;
        __u8 extensions[3];
+       sctp_paramhdr_t *auth_chunks = NULL,
+                       *auth_hmacs = NULL;
 
        /* RFC 2960 3.3.2 Initiation (INIT) (1)
         *
         *  An implementation supporting this extension [ADDIP] MUST list
         *  the ASCONF,the ASCONF-ACK, and the AUTH  chunks in its INIT and
         *  INIT-ACK parameters.
-        *  XXX: We don't support AUTH just yet, so don't list it.  AUTH
-        *  support should add it.
         */
        if (sctp_addip_enable) {
                extensions[num_ext] = SCTP_CID_ASCONF;
        chunksize += sizeof(aiparam);
        chunksize += vparam_len;
 
+       /* Account for AUTH related parameters */
+       if (sctp_auth_enable) {
+               /* Add random parameter length*/
+               chunksize += sizeof(asoc->c.auth_random);
+
+               /* Add HMACS parameter length if any were defined */
+               auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs;
+               if (auth_hmacs->length)
+                       chunksize += ntohs(auth_hmacs->length);
+               else
+                       auth_hmacs = NULL;
+
+               /* Add CHUNKS parameter length */
+               auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks;
+               if (auth_chunks->length)
+                       chunksize += ntohs(auth_chunks->length);
+               else
+                       auth_hmacs = NULL;
+
+               extensions[num_ext] = SCTP_CID_AUTH;
+               num_ext += 1;
+       }
+
        /* If we have any extensions to report, account for that */
        if (num_ext)
                chunksize += sizeof(sctp_supported_ext_param_t) + num_ext;
        aiparam.adaptation_ind = htonl(sp->adaptation_ind);
        sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
 
+       /* Add SCTP-AUTH chunks to the parameter list */
+       if (sctp_auth_enable) {
+               sctp_addto_chunk(retval, sizeof(asoc->c.auth_random),
+                                asoc->c.auth_random);
+               if (auth_hmacs)
+                       sctp_addto_chunk(retval, ntohs(auth_hmacs->length),
+                                       auth_hmacs);
+               if (auth_chunks)
+                       sctp_addto_chunk(retval, ntohs(auth_chunks->length),
+                                       auth_chunks);
+       }
 nodata:
        kfree(addrs.v);
        return retval;
        sctp_supported_ext_param_t ext_param;
        int num_ext = 0;
        __u8 extensions[3];
+       sctp_paramhdr_t *auth_chunks = NULL,
+                       *auth_hmacs = NULL,
+                       *auth_random = NULL;
 
        retval = NULL;
 
        chunksize += sizeof(ext_param) + num_ext;
        chunksize += sizeof(aiparam);
 
+       if (asoc->peer.auth_capable) {
+               auth_random = (sctp_paramhdr_t *)asoc->c.auth_random;
+               chunksize += ntohs(auth_random->length);
+
+               auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs;
+               if (auth_hmacs->length)
+                       chunksize += ntohs(auth_hmacs->length);
+               else
+                       auth_hmacs = NULL;
+
+               auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks;
+               if (auth_chunks->length)
+                       chunksize += ntohs(auth_chunks->length);
+               else
+                       auth_chunks = NULL;
+
+               extensions[num_ext] = SCTP_CID_AUTH;
+               num_ext += 1;
+       }
+
        /* Now allocate and fill out the chunk.  */
        retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize);
        if (!retval)
        aiparam.adaptation_ind = htonl(sctp_sk(asoc->base.sk)->adaptation_ind);
        sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
 
+       if (asoc->peer.auth_capable) {
+               sctp_addto_chunk(retval, ntohs(auth_random->length),
+                                auth_random);
+               if (auth_hmacs)
+                       sctp_addto_chunk(retval, ntohs(auth_hmacs->length),
+                                       auth_hmacs);
+               if (auth_chunks)
+                       sctp_addto_chunk(retval, ntohs(auth_chunks->length),
+                                       auth_chunks);
+       }
+
        /* We need to remove the const qualifier at this point.  */
        retval->asoc = (struct sctp_association *) asoc;
 
                                !asoc->peer.prsctp_capable)
                                    asoc->peer.prsctp_capable = 1;
                            break;
+                   case SCTP_CID_AUTH:
+                           /* if the peer reports AUTH, assume that he
+                            * supports AUTH.
+                            */
+                           asoc->peer.auth_capable = 1;
+                           break;
                    case SCTP_CID_ASCONF:
                    case SCTP_CID_ASCONF_ACK:
                            /* don't need to do anything for ASCONF */
        case SCTP_PARAM_FWD_TSN_SUPPORT:
                if (sctp_prsctp_enable)
                        break;
+               goto fallthrough;
+
+       case SCTP_PARAM_RANDOM:
+               if (!sctp_auth_enable)
+                       goto fallthrough;
+
+               /* SCTP-AUTH: Secion 6.1
+                * If the random number is not 32 byte long the association
+                * MUST be aborted.  The ABORT chunk SHOULD contain the error
+                * cause 'Protocol Violation'.
+                */
+               if (SCTP_AUTH_RANDOM_LENGTH !=
+                       ntohs(param.p->length) - sizeof(sctp_paramhdr_t))
+                       return sctp_process_inv_paramlength(asoc, param.p,
+                                                       chunk, err_chunk);
+               break;
+
+       case SCTP_PARAM_CHUNKS:
+               if (!sctp_auth_enable)
+                       goto fallthrough;
+
+               /* SCTP-AUTH: Section 3.2
+                * The CHUNKS parameter MUST be included once in the INIT or
+                *  INIT-ACK chunk if the sender wants to receive authenticated
+                *  chunks.  Its maximum length is 260 bytes.
+                */
+               if (260 < ntohs(param.p->length))
+                       return sctp_process_inv_paramlength(asoc, param.p,
+                                                       chunk, err_chunk);
+               break;
+
+       case SCTP_PARAM_HMAC_ALGO:
+               if (!sctp_auth_enable)
+                       break;
                /* Fall Through */
+fallthrough:
        default:
                SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n",
                                ntohs(param.p->type), cid);
        }
 
        /* Process the initialization parameters.  */
-
        sctp_walk_params(param, peer_init, init_hdr.params) {
 
                if (!sctp_process_param(asoc, param, peer_addr, gfp))
                        goto clean_up;
        }
 
+       /* AUTH: After processing the parameters, make sure that we
+        * have all the required info to potentially do authentications.
+        */
+       if (asoc->peer.auth_capable && (!asoc->peer.peer_random ||
+                                       !asoc->peer.peer_hmacs))
+               asoc->peer.auth_capable = 0;
+
        /* Walk list of transports, removing transports in the UNKNOWN state. */
        list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
                transport = list_entry(pos, struct sctp_transport, transports);
                        break;
                }
                /* Fall Through */
+               goto fall_through;
+
+       case SCTP_PARAM_RANDOM:
+               if (!sctp_auth_enable)
+                       goto fall_through;
+
+               /* Save peer's random parameter */
+               asoc->peer.peer_random = kmemdup(param.p,
+                                           ntohs(param.p->length), gfp);
+               if (!asoc->peer.peer_random) {
+                       retval = 0;
+                       break;
+               }
+               break;
+
+       case SCTP_PARAM_HMAC_ALGO:
+               if (!sctp_auth_enable)
+                       goto fall_through;
+
+               /* Save peer's HMAC list */
+               asoc->peer.peer_hmacs = kmemdup(param.p,
+                                           ntohs(param.p->length), gfp);
+               if (!asoc->peer.peer_hmacs) {
+                       retval = 0;
+                       break;
+               }
+
+               /* Set the default HMAC the peer requested*/
+               sctp_auth_asoc_set_default_hmac(asoc, param.hmac_algo);
+               break;
+
+       case SCTP_PARAM_CHUNKS:
+               if (!sctp_auth_enable)
+                       goto fall_through;
+
+               asoc->peer.peer_chunks = kmemdup(param.p,
+                                           ntohs(param.p->length), gfp);
+               if (!asoc->peer.peer_chunks)
+                       retval = 0;
+               break;
+fall_through:
        default:
                /* Any unrecognized parameters should have been caught
                 * and handled by sctp_verify_param() which should be
 
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_COOKIE_ECHOED));
 
+       /* SCTP-AUTH: genereate the assocition shared keys so that
+        * we can potentially signe the COOKIE-ECHO.
+        */
+       sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_SHKEY, SCTP_NULL());
+
        /* 5.1 C) "A" shall then send the State Cookie received in the
         * INIT ACK chunk in a COOKIE ECHO chunk, ...
         */
                               peer_init, GFP_ATOMIC))
                goto nomem_init;
 
+       /* SCTP-AUTH:  Now that we've populate required fields in
+        * sctp_process_init, set up the assocaition shared keys as
+        * necessary so that we can potentially authenticate the ACK
+        */
+       error = sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC);
+       if (error)
+               goto nomem_init;
+
        repl = sctp_make_cookie_ack(new_asoc, chunk);
        if (!repl)
                goto nomem_init;
        new_asoc->c.initial_tsn         = asoc->c.initial_tsn;
 }
 
+static void sctp_auth_params_populate(struct sctp_association *new_asoc,
+                                   const struct sctp_association *asoc)
+{
+       /* Only perform this if AUTH extension is enabled */
+       if (!sctp_auth_enable)
+               return;
+
+       /* We need to provide the same parameter information as
+        * was in the original INIT.  This means that we need to copy
+        * the HMACS, CHUNKS, and RANDOM parameter from the original
+        * assocaition.
+        */
+       memcpy(new_asoc->c.auth_random, asoc->c.auth_random,
+               sizeof(asoc->c.auth_random));
+       memcpy(new_asoc->c.auth_hmacs, asoc->c.auth_hmacs,
+               sizeof(asoc->c.auth_hmacs));
+       memcpy(new_asoc->c.auth_chunks, asoc->c.auth_chunks,
+               sizeof(asoc->c.auth_chunks));
+}
+
 /*
  * Compare vtag/tietag values to determine unexpected COOKIE-ECHO
  * handling action.
 
        sctp_tietags_populate(new_asoc, asoc);
 
+       sctp_auth_params_populate(new_asoc, asoc);
+
        /* B) "Z" shall respond immediately with an INIT ACK chunk.  */
 
        /* If there are errors need to be reported for unknown parameters,