srtp_unprotect_rtcp_aead (srtp_t ctx, srtp_stream_ctx_t *stream, 
                          void *srtcp_hdr, unsigned int *pkt_octet_len)
{
    srtcp_hdr_t *hdr = (srtcp_hdr_t*)srtcp_hdr;
    uint32_t *enc_start;        /* pointer to start of encrypted portion  */
    uint32_t *trailer;          /* pointer to start of trailer            */
    unsigned int enc_octet_len = 0; /* number of octets in encrypted portion */
    uint8_t *auth_tag = NULL;   /* location of auth_tag within packet     */
    err_status_t status;
    int tag_len;
    unsigned int tmp_len;
    uint32_t seq_num;
    v128_t iv;
    uint32_t tseq;

    /* get tag length from stream context */
    tag_len = auth_get_tag_length(stream->rtcp_auth);

    /*
     * set encryption start, encryption length, and trailer
     */
    /* index & E (encryption) bit follow normal data.  hdr->len
           is the number of words (32-bit) in the normal packet minus 1 */
    /* This should point trailer to the word past the end of the
           normal data. */
    /* This would need to be modified for optional mikey data */
    /*
     * NOTE: trailer is 32-bit aligned because RTCP 'packets' are always
     *	 multiples of 32-bits (RFC 3550 6.1)
     */
    trailer = (uint32_t*)((char*)hdr + *pkt_octet_len - sizeof(srtcp_trailer_t));
    /*
     * We pass the tag down to the cipher when doing GCM mode 
     */
    enc_octet_len = *pkt_octet_len - (octets_in_rtcp_header + 
                                      sizeof(srtcp_trailer_t));
    auth_tag = (uint8_t*)hdr + *pkt_octet_len - tag_len - sizeof(srtcp_trailer_t);

    if (*((unsigned char*)trailer) & SRTCP_E_BYTE_BIT) {
        enc_start = (uint32_t*)hdr + uint32s_in_rtcp_header;
    } else {
        enc_octet_len = 0;
        enc_start = NULL; /* this indicates that there's no encryption */
    }

    /*
     * check the sequence number for replays
     */
    /* this is easier than dealing with bitfield access */
    seq_num = ntohl(*trailer) & SRTCP_INDEX_MASK;
    debug_print(mod_srtp, "srtcp index: %x", seq_num);
    status = rdb_check(&stream->rtcp_rdb, seq_num);
    if (status) {
        return status;
    }

    /*
     * Calculate and set the IV
     */
    srtp_calc_aead_iv_srtcp(stream, &iv, seq_num, hdr);
    status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_decrypt);
    if (status) {
        return err_status_cipher_fail;
    }

    /*
     * Set the AAD for GCM mode
     */
    if (enc_start) {
	/*
	 * If payload encryption is enabled, then the AAD consist of
	 * the RTCP header and the seq# at the end of the packet
	 */
	status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)hdr, 
                                octets_in_rtcp_header);
	if (status) {
	    return ( err_status_cipher_fail);
	}
    } else {
	/*
	 * Since payload encryption is not enabled, we must authenticate
	 * the entire packet as described in section 10.3 in revision 07
	 * of the draft.
	 */
	status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)hdr, 
			       (*pkt_octet_len - tag_len - sizeof(srtcp_trailer_t)));
	if (status) {
	    return ( err_status_cipher_fail);
	}
    }

    /* 
     * put the idx# into network byte order, and process it as AAD 
     */
    tseq = htonl(*trailer);
    status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)&tseq, 
                            sizeof(srtcp_trailer_t));
    if (status) {
	return ( err_status_cipher_fail);
    }

    /* if we're decrypting, exor keystream into the message */
    if (enc_start) {
        status = cipher_decrypt(stream->rtcp_cipher,
                                (uint8_t*)enc_start, &enc_octet_len);
        if (status) {
            return status;
        }
    } else {
	/*
	 * Still need to run the cipher to check the tag
	 */
	tmp_len = tag_len;
        status = cipher_decrypt(stream->rtcp_cipher, (uint8_t*)auth_tag, 
                                &tmp_len);
        if (status) {
            return status;
        }
    }

    /* decrease the packet length by the length of the auth tag and seq_num*/
    *pkt_octet_len -= (tag_len + sizeof(srtcp_trailer_t));

    /*
     * verify that stream is for received traffic - this check will
     * detect SSRC collisions, since a stream that appears in both
     * srtp_protect() and srtp_unprotect() will fail this test in one of
     * those functions.
     *
     * we do this check *after* the authentication check, so that the
     * latter check will catch any attempts to fool us into thinking
     * that we've got a collision
     */
    if (stream->direction != dir_srtp_receiver) {
        if (stream->direction == dir_unknown) {
            stream->direction = dir_srtp_receiver;
        } else {
            srtp_handle_event(ctx, stream, event_ssrc_collision);
        }
    }

    /*
     * if the stream is a 'provisional' one, in which the template context
     * is used, then we need to allocate a new stream at this point, since
     * the authentication passed
     */
    if (stream == ctx->stream_template) {
        srtp_stream_ctx_t *new_stream;

        /*
         * allocate and initialize a new stream
         *
         * note that we indicate failure if we can't allocate the new
         * stream, and some implementations will want to not return
         * failure here
         */
        status = srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream);
        if (status) {
            return status;
        }

        /* add new stream to the head of the stream_list */
        new_stream->next = ctx->stream_list;
        ctx->stream_list = new_stream;

        /* set stream (the pointer used in this function) */
        stream = new_stream;
    }

    /* we've passed the authentication check, so add seq_num to the rdb */
    rdb_add_index(&stream->rtcp_rdb, seq_num);

    return err_status_ok;
}