Merge tag 'trace-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux...
[firefly-linux-kernel-4.4.55.git] / net / sctp / sm_statefuns.c
index d3f1ea460c500caf6e39c1a9b2f31f2de28f37a4..d7eaa7354cf76148d1a2c9ee3af4fff9a24990fb 100644 (file)
@@ -170,6 +170,9 @@ sctp_chunk_length_valid(struct sctp_chunk *chunk,
 {
        __u16 chunk_length = ntohs(chunk->chunk_hdr->length);
 
+       /* Previously already marked? */
+       if (unlikely(chunk->pdiscard))
+               return 0;
        if (unlikely(chunk_length < required_length))
                return 0;
 
@@ -850,7 +853,7 @@ nomem:
 
 /*
  * Respond to a normal COOKIE ACK chunk.
- * We are the side that is being asked for an association.
+ * We are the side that is asking for an association.
  *
  * RFC 2960 5.1 Normal Establishment of an Association
  *
@@ -1775,9 +1778,22 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(struct net *net,
        /* 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));
-       sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
-                       SCTP_STATE(SCTP_STATE_ESTABLISHED));
-       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
+       if (sctp_state(asoc, SHUTDOWN_PENDING) &&
+           (sctp_sstate(asoc->base.sk, CLOSING) ||
+            sock_flag(asoc->base.sk, SOCK_DEAD))) {
+               /* if were currently in SHUTDOWN_PENDING, but the socket
+                * has been closed by user, don't transition to ESTABLISHED.
+                * Instead trigger SHUTDOWN bundled with COOKIE_ACK.
+                */
+               sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
+               return sctp_sf_do_9_2_start_shutdown(net, ep, asoc,
+                                                    SCTP_ST_CHUNK(0), NULL,
+                                                    commands);
+       } else {
+               sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
+                               SCTP_STATE(SCTP_STATE_ESTABLISHED));
+               sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
+       }
        return SCTP_DISPOSITION_CONSUME;
 
 nomem_ev:
@@ -3578,9 +3594,7 @@ sctp_disposition_t sctp_sf_do_asconf(struct net *net,
        struct sctp_chunk       *asconf_ack = NULL;
        struct sctp_paramhdr    *err_param = NULL;
        sctp_addiphdr_t         *hdr;
-       union sctp_addr_param   *addr_param;
        __u32                   serial;
-       int                     length;
 
        if (!sctp_vtag_verify(chunk, asoc)) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
@@ -3605,17 +3619,8 @@ sctp_disposition_t sctp_sf_do_asconf(struct net *net,
        hdr = (sctp_addiphdr_t *)chunk->skb->data;
        serial = ntohl(hdr->serial);
 
-       addr_param = (union sctp_addr_param *)hdr->params;
-       length = ntohs(addr_param->p.length);
-       if (length < sizeof(sctp_paramhdr_t))
-               return sctp_sf_violation_paramlen(net, ep, asoc, type, arg,
-                          (void *)addr_param, commands);
-
        /* Verify the ASCONF chunk before processing it. */
-       if (!sctp_verify_asconf(asoc,
-                           (sctp_paramhdr_t *)((void *)addr_param + length),
-                           (void *)chunk->chunk_end,
-                           &err_param))
+       if (!sctp_verify_asconf(asoc, chunk, true, &err_param))
                return sctp_sf_violation_paramlen(net, ep, asoc, type, arg,
                                                  (void *)err_param, commands);
 
@@ -3732,10 +3737,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(struct net *net,
        rcvd_serial = ntohl(addip_hdr->serial);
 
        /* Verify the ASCONF-ACK chunk before processing it. */
-       if (!sctp_verify_asconf(asoc,
-           (sctp_paramhdr_t *)addip_hdr->params,
-           (void *)asconf_ack->chunk_end,
-           &err_param))
+       if (!sctp_verify_asconf(asoc, asconf_ack, false, &err_param))
                return sctp_sf_violation_paramlen(net, ep, asoc, type, arg,
                           (void *)err_param, commands);