tools headers UAPI: Sync linux/prctl.h with the kernel sources
[linux-2.6-microblaze.git] / net / sctp / sm_statefuns.c
index 7632714..fd1e319 100644 (file)
@@ -1773,6 +1773,30 @@ enum sctp_disposition sctp_sf_do_5_2_3_initack(
                return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
 }
 
+static int sctp_sf_do_assoc_update(struct sctp_association *asoc,
+                                  struct sctp_association *new,
+                                  struct sctp_cmd_seq *cmds)
+{
+       struct net *net = asoc->base.net;
+       struct sctp_chunk *abort;
+
+       if (!sctp_assoc_update(asoc, new))
+               return 0;
+
+       abort = sctp_make_abort(asoc, NULL, sizeof(struct sctp_errhdr));
+       if (abort) {
+               sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, 0);
+               sctp_add_cmd_sf(cmds, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+       }
+       sctp_add_cmd_sf(cmds, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNABORTED));
+       sctp_add_cmd_sf(cmds, SCTP_CMD_ASSOC_FAILED,
+                       SCTP_PERR(SCTP_ERROR_RSRC_LOW));
+       SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+       SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
+
+       return -ENOMEM;
+}
+
 /* Unexpected COOKIE-ECHO handler for peer restart (Table 2, action 'A')
  *
  * Section 5.2.4
@@ -1852,20 +1876,22 @@ static enum sctp_disposition sctp_sf_do_dupcook_a(
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
        sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_ASCONF_QUEUE, SCTP_NULL());
 
-       repl = sctp_make_cookie_ack(new_asoc, chunk);
+       /* Update the content of current association. */
+       if (sctp_sf_do_assoc_update((struct sctp_association *)asoc, new_asoc, commands))
+               goto nomem;
+
+       repl = sctp_make_cookie_ack(asoc, chunk);
        if (!repl)
                goto nomem;
 
        /* Report association restart to upper layer. */
        ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0,
-                                            new_asoc->c.sinit_num_ostreams,
-                                            new_asoc->c.sinit_max_instreams,
+                                            asoc->c.sinit_num_ostreams,
+                                            asoc->c.sinit_max_instreams,
                                             NULL, GFP_ATOMIC);
        if (!ev)
                goto nomem_ev;
 
-       /* Update the content of current association. */
-       sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
        sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
        if ((sctp_state(asoc, SHUTDOWN_PENDING) ||
             sctp_state(asoc, SHUTDOWN_SENT)) &&
@@ -1925,14 +1951,17 @@ static enum sctp_disposition sctp_sf_do_dupcook_b(
        if (!sctp_auth_chunk_verify(net, chunk, new_asoc))
                return SCTP_DISPOSITION_DISCARD;
 
-       /* Update the content of current association.  */
-       sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_ESTABLISHED));
-       SCTP_INC_STATS(net, SCTP_MIB_CURRESTAB);
+       if (asoc->state < SCTP_STATE_ESTABLISHED)
+               SCTP_INC_STATS(net, SCTP_MIB_CURRESTAB);
        sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
 
-       repl = sctp_make_cookie_ack(new_asoc, chunk);
+       /* Update the content of current association.  */
+       if (sctp_sf_do_assoc_update((struct sctp_association *)asoc, new_asoc, commands))
+               goto nomem;
+
+       repl = sctp_make_cookie_ack(asoc, chunk);
        if (!repl)
                goto nomem;