int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp);
 void sctp_stream_free(struct sctp_stream *stream);
 void sctp_stream_clear(struct sctp_stream *stream);
+void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new);
 
 /* What is the current SSN number for this stream? */
 #define sctp_ssn_peek(stream, type, sid) \
        __u32 default_rcv_context;
 
        /* Stream arrays */
-       struct sctp_stream *stream;
+       struct sctp_stream stream;
 
        /* All outbound chunks go through this structure.  */
        struct sctp_outq outqueue;
 
        return asoc;
 
 stream_free:
-       sctp_stream_free(asoc->stream);
+       sctp_stream_free(&asoc->stream);
 fail_init:
        sock_put(asoc->base.sk);
        sctp_endpoint_put(asoc->ep);
        sctp_tsnmap_free(&asoc->peer.tsn_map);
 
        /* Free stream information. */
-       sctp_stream_free(asoc->stream);
+       sctp_stream_free(&asoc->stream);
 
        if (asoc->strreset_chunk)
                sctp_chunk_free(asoc->strreset_chunk);
                /* Reinitialize SSN for both local streams
                 * and peer's streams.
                 */
-               sctp_stream_clear(asoc->stream);
+               sctp_stream_clear(&asoc->stream);
 
                /* Flush the ULP reassembly and ordered queue.
                 * Any data there will now be stale and will
                asoc->ctsn_ack_point = asoc->next_tsn - 1;
                asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
 
-               if (sctp_state(asoc, COOKIE_WAIT)) {
-                       sctp_stream_free(asoc->stream);
-                       asoc->stream = new->stream;
-                       new->stream = NULL;
-               }
+               if (sctp_state(asoc, COOKIE_WAIT))
+                       sctp_stream_update(&asoc->stream, &new->stream);
 
                if (!asoc->assoc_id) {
                        /* get a new association id since we don't have one
 
        if (SCTP_PR_TTL_ENABLED(chunk->sinfo.sinfo_flags) &&
            time_after(jiffies, chunk->msg->expires_at)) {
                struct sctp_stream_out *streamout =
-                       &chunk->asoc->stream->out[chunk->sinfo.sinfo_stream];
+                       &chunk->asoc->stream.out[chunk->sinfo.sinfo_stream];
 
                if (chunk->sent_count) {
                        chunk->asoc->abandoned_sent[SCTP_PR_INDEX(TTL)]++;
        } else if (SCTP_PR_RTX_ENABLED(chunk->sinfo.sinfo_flags) &&
                   chunk->sent_count > chunk->sinfo.sinfo_timetolive) {
                struct sctp_stream_out *streamout =
-                       &chunk->asoc->stream->out[chunk->sinfo.sinfo_stream];
+                       &chunk->asoc->stream.out[chunk->sinfo.sinfo_stream];
 
                chunk->asoc->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
                streamout->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
 
                sctp_insert_list(&asoc->outqueue.abandoned,
                                 &chk->transmitted_list);
 
-               streamout = &asoc->stream->out[chk->sinfo.sinfo_stream];
+               streamout = &asoc->stream.out[chk->sinfo.sinfo_stream];
                asoc->sent_cnt_removable--;
                asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++;
                streamout->abandoned_sent[SCTP_PR_INDEX(PRIO)]++;
                q->out_qlen -= chk->skb->len;
                asoc->sent_cnt_removable--;
                asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
-               if (chk->sinfo.sinfo_stream < asoc->stream->outcnt) {
+               if (chk->sinfo.sinfo_stream < asoc->stream.outcnt) {
                        struct sctp_stream_out *streamout =
-                               &asoc->stream->out[chk->sinfo.sinfo_stream];
+                               &asoc->stream.out[chk->sinfo.sinfo_stream];
 
                        streamout->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
                }
                        /* RFC 2960 6.5 Every DATA chunk MUST carry a valid
                         * stream identifier.
                         */
-                       if (chunk->sinfo.sinfo_stream >= asoc->stream->outcnt) {
+                       if (chunk->sinfo.sinfo_stream >= asoc->stream.outcnt) {
 
                                /* Mark as failed send. */
                                sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM);
                                continue;
                        }
 
-                       if (asoc->stream->out[sid].state == SCTP_STREAM_CLOSED) {
+                       if (asoc->stream.out[sid].state == SCTP_STREAM_CLOSED) {
                                sctp_outq_head_data(q, chunk);
                                goto sctp_flush_out;
                        }
 
        sctp_seq_dump_remote_addrs(seq, assoc);
        seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d "
                   "%8d %8d %8d %8d",
-               assoc->hbinterval, assoc->stream->incnt,
-               assoc->stream->outcnt, assoc->max_retrans,
+               assoc->hbinterval, assoc->stream.incnt,
+               assoc->stream.outcnt, assoc->max_retrans,
                assoc->init_retries, assoc->shutdown_retries,
                assoc->rtx_data_chunks,
                atomic_read(&sk->sk_wmem_alloc),
 
 
        /* All fragments will be on the same stream */
        sid = ntohs(chunk->subh.data_hdr->stream);
-       stream = chunk->asoc->stream;
+       stream = &chunk->asoc->stream;
 
        /* Now assign the sequence number to the entire message.
         * All fragments must have the same stream sequence number.
 
 
        /* Silently discard the chunk if stream-id is not valid */
        sctp_walk_fwdtsn(skip, chunk) {
-               if (ntohs(skip->stream) >= asoc->stream->incnt)
+               if (ntohs(skip->stream) >= asoc->stream.incnt)
                        goto discard_noforce;
        }
 
 
        /* Silently discard the chunk if stream-id is not valid */
        sctp_walk_fwdtsn(skip, chunk) {
-               if (ntohs(skip->stream) >= asoc->stream->incnt)
+               if (ntohs(skip->stream) >= asoc->stream.incnt)
                        goto gen_shutdown;
        }
 
         * and discard the DATA chunk.
         */
        sid = ntohs(data_hdr->stream);
-       if (sid >= asoc->stream->incnt) {
+       if (sid >= asoc->stream.incnt) {
                /* Mark tsn as received even though we drop it */
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
 
         * and is invalid.
         */
        ssn = ntohs(data_hdr->ssn);
-       if (ordered && SSN_lt(ssn, sctp_ssn_peek(asoc->stream, in, sid)))
+       if (ordered && SSN_lt(ssn, sctp_ssn_peek(&asoc->stream, in, sid)))
                return SCTP_IERROR_PROTO_VIOLATION;
 
        /* Send the data up to the user.  Note:  Schedule  the
 
        }
 
        /* Check for invalid stream. */
-       if (sinfo->sinfo_stream >= asoc->stream->outcnt) {
+       if (sinfo->sinfo_stream >= asoc->stream.outcnt) {
                err = -EINVAL;
                goto out_free;
        }
        info->sctpi_rwnd = asoc->a_rwnd;
        info->sctpi_unackdata = asoc->unack_data;
        info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
-       info->sctpi_instrms = asoc->stream->incnt;
-       info->sctpi_outstrms = asoc->stream->outcnt;
+       info->sctpi_instrms = asoc->stream.incnt;
+       info->sctpi_outstrms = asoc->stream.outcnt;
        list_for_each(pos, &asoc->base.inqueue.in_chunk_list)
                info->sctpi_inqueue++;
        list_for_each(pos, &asoc->outqueue.out_chunk_list)
        status.sstat_unackdata = asoc->unack_data;
 
        status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
-       status.sstat_instrms = asoc->stream->incnt;
-       status.sstat_outstrms = asoc->stream->outcnt;
+       status.sstat_instrms = asoc->stream.incnt;
+       status.sstat_outstrms = asoc->stream.outcnt;
        status.sstat_fragmentation_point = asoc->frag_point;
        status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
        memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr,
                goto out;
 
        asoc = sctp_id2assoc(sk, params.sprstat_assoc_id);
-       if (!asoc || params.sprstat_sid >= asoc->stream->outcnt)
+       if (!asoc || params.sprstat_sid >= asoc->stream.outcnt)
                goto out;
 
-       streamout = &asoc->stream->out[params.sprstat_sid];
+       streamout = &asoc->stream.out[params.sprstat_sid];
        if (policy == SCTP_PR_SCTP_NONE) {
                params.sprstat_abandoned_unsent = 0;
                params.sprstat_abandoned_sent = 0;
 
 
 int sctp_stream_new(struct sctp_association *asoc, gfp_t gfp)
 {
-       struct sctp_stream *stream;
+       struct sctp_stream *stream = &asoc->stream;
        int i;
 
-       stream = kzalloc(sizeof(*stream), gfp);
-       if (!stream)
-               return -ENOMEM;
-
        stream->outcnt = asoc->c.sinit_num_ostreams;
        stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp);
-       if (!stream->out) {
-               kfree(stream);
+       if (!stream->out)
                return -ENOMEM;
-       }
+
        for (i = 0; i < stream->outcnt; i++)
                stream->out[i].state = SCTP_STREAM_OPEN;
 
-       asoc->stream = stream;
-
        return 0;
 }
 
 int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp)
 {
-       struct sctp_stream *stream = asoc->stream;
+       struct sctp_stream *stream = &asoc->stream;
        int i;
 
        /* Initial stream->out size may be very big, so free it and alloc
        stream->outcnt = asoc->c.sinit_num_ostreams;
        stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp);
        if (!stream->out)
-               goto nomem;
+               return -ENOMEM;
 
        for (i = 0; i < stream->outcnt; i++)
                stream->out[i].state = SCTP_STREAM_OPEN;
        stream->in = kcalloc(stream->incnt, sizeof(*stream->in), gfp);
        if (!stream->in) {
                kfree(stream->out);
-               goto nomem;
+               stream->out = NULL;
+               return -ENOMEM;
        }
 
        return 0;
-
-nomem:
-       asoc->stream = NULL;
-       kfree(stream);
-
-       return -ENOMEM;
 }
 
 void sctp_stream_free(struct sctp_stream *stream)
 {
-       if (unlikely(!stream))
-               return;
-
        kfree(stream->out);
        kfree(stream->in);
-       kfree(stream);
 }
 
 void sctp_stream_clear(struct sctp_stream *stream)
                stream->in[i].ssn = 0;
 }
 
+void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
+{
+       sctp_stream_free(stream);
+
+       stream->out = new->out;
+       stream->in  = new->in;
+       stream->outcnt = new->outcnt;
+       stream->incnt  = new->incnt;
+
+       new->out = NULL;
+       new->in  = NULL;
+}
+
 static int sctp_send_reconf(struct sctp_association *asoc,
                            struct sctp_chunk *chunk)
 {
 int sctp_send_reset_streams(struct sctp_association *asoc,
                            struct sctp_reset_streams *params)
 {
-       struct sctp_stream *stream = asoc->stream;
+       struct sctp_stream *stream = &asoc->stream;
        __u16 i, str_nums, *str_list;
        struct sctp_chunk *chunk;
        int retval = -EINVAL;
 
 int sctp_send_reset_assoc(struct sctp_association *asoc)
 {
+       struct sctp_stream *stream = &asoc->stream;
        struct sctp_chunk *chunk = NULL;
        int retval;
        __u16 i;
                return -ENOMEM;
 
        /* Block further xmit of data until this request is completed */
-       for (i = 0; i < asoc->stream->outcnt; i++)
-               asoc->stream->out[i].state = SCTP_STREAM_CLOSED;
+       for (i = 0; i < stream->outcnt; i++)
+               stream->out[i].state = SCTP_STREAM_CLOSED;
 
        asoc->strreset_chunk = chunk;
        sctp_chunk_hold(asoc->strreset_chunk);
                sctp_chunk_put(asoc->strreset_chunk);
                asoc->strreset_chunk = NULL;
 
-               for (i = 0; i < asoc->stream->outcnt; i++)
-                       asoc->stream->out[i].state = SCTP_STREAM_OPEN;
+               for (i = 0; i < stream->outcnt; i++)
+                       stream->out[i].state = SCTP_STREAM_OPEN;
 
                return retval;
        }
 int sctp_send_add_streams(struct sctp_association *asoc,
                          struct sctp_add_streams *params)
 {
-       struct sctp_stream *stream = asoc->stream;
+       struct sctp_stream *stream = &asoc->stream;
        struct sctp_chunk *chunk = NULL;
        int retval = -ENOMEM;
        __u32 outcnt, incnt;
                                struct sctp_ulpevent **evp)
 {
        struct sctp_strreset_outreq *outreq = param.v;
-       struct sctp_stream *stream = asoc->stream;
+       struct sctp_stream *stream = &asoc->stream;
        __u16 i, nums, flags = 0, *str_p = NULL;
        __u32 result = SCTP_STRRESET_DENIED;
        __u32 request_seq;
                                struct sctp_ulpevent **evp)
 {
        struct sctp_strreset_inreq *inreq = param.v;
-       struct sctp_stream *stream = asoc->stream;
+       struct sctp_stream *stream = &asoc->stream;
        __u32 result = SCTP_STRRESET_DENIED;
        struct sctp_chunk *chunk = NULL;
        __u16 i, nums, *str_p;
 {
        __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
        struct sctp_strreset_tsnreq *tsnreq = param.v;
-       struct sctp_stream *stream = asoc->stream;
+       struct sctp_stream *stream = &asoc->stream;
        __u32 result = SCTP_STRRESET_DENIED;
        __u32 request_seq;
        __u16 i;
                                struct sctp_ulpevent **evp)
 {
        struct sctp_strreset_addstrm *addstrm = param.v;
-       struct sctp_stream *stream = asoc->stream;
+       struct sctp_stream *stream = &asoc->stream;
        __u32 result = SCTP_STRRESET_DENIED;
        struct sctp_stream_in *streamin;
        __u32 request_seq, incnt;
                                struct sctp_ulpevent **evp)
 {
        struct sctp_strreset_addstrm *addstrm = param.v;
-       struct sctp_stream *stream = asoc->stream;
+       struct sctp_stream *stream = &asoc->stream;
        __u32 result = SCTP_STRRESET_DENIED;
        struct sctp_stream_out *streamout;
        struct sctp_chunk *chunk = NULL;
                                union sctp_params param,
                                struct sctp_ulpevent **evp)
 {
+       struct sctp_stream *stream = &asoc->stream;
        struct sctp_strreset_resp *resp = param.v;
-       struct sctp_stream *stream = asoc->stream;
        struct sctp_transport *t;
        __u16 i, nums, flags = 0;
        sctp_paramhdr_t *req;
 
        __u16 sid, csid, cssn;
 
        sid = event->stream;
-       stream  = ulpq->asoc->stream;
+       stream  = &ulpq->asoc->stream;
 
        event_list = (struct sk_buff_head *) sctp_event2skb(event)->prev;
 
        /* Note: The stream ID must be verified before this routine.  */
        sid = event->stream;
        ssn = event->ssn;
-       stream  = ulpq->asoc->stream;
+       stream  = &ulpq->asoc->stream;
 
        /* Is this the expected SSN for this stream ID?  */
        if (ssn != sctp_ssn_peek(stream, in, sid)) {
        struct sk_buff_head *lobby = &ulpq->lobby;
        __u16 csid, cssn;
 
-       stream = ulpq->asoc->stream;
+       stream = &ulpq->asoc->stream;
 
        /* We are holding the chunks by stream, by SSN.  */
        skb_queue_head_init(&temp);
        struct sctp_stream *stream;
 
        /* Note: The stream ID must be verified before this routine.  */
-       stream  = ulpq->asoc->stream;
+       stream  = &ulpq->asoc->stream;
 
        /* Is this an old SSN?  If so ignore. */
        if (SSN_lt(ssn, sctp_ssn_peek(stream, in, sid)))