Merge tag 'backport/v3.14.24-ltsi-rc1/phy-rcar-gen2-usb-to-v3.15' into backport/v3...
[platform/adaptation/renesas_rcar/renesas_kernel.git] / net / sctp / sm_statefuns.c
index ae65b6b..3e287a3 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;
 
@@ -357,7 +360,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net,
 
        /* Verify the INIT chunk before processing it. */
        err_chunk = NULL;
-       if (!sctp_verify_init(net, asoc, chunk->chunk_hdr->type,
+       if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
                              (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
                              &err_chunk)) {
                /* This chunk contains fatal error. It is to be discarded.
@@ -524,7 +527,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net,
 
        /* Verify the INIT chunk before processing it. */
        err_chunk = NULL;
-       if (!sctp_verify_init(net, asoc, chunk->chunk_hdr->type,
+       if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
                              (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
                              &err_chunk)) {
 
@@ -760,7 +763,6 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
 
                /* Make sure that we and the peer are AUTH capable */
                if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) {
-                       kfree_skb(chunk->auth_chunk);
                        sctp_association_free(new_asoc);
                        return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
                }
@@ -775,10 +777,6 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
                auth.transport = chunk->transport;
 
                ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth);
-
-               /* We can now safely free the auth_chunk clone */
-               kfree_skb(chunk->auth_chunk);
-
                if (ret != SCTP_IERROR_NO_ERROR) {
                        sctp_association_free(new_asoc);
                        return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
@@ -1435,7 +1433,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
 
        /* Verify the INIT chunk before processing it. */
        err_chunk = NULL;
-       if (!sctp_verify_init(net, asoc, chunk->chunk_hdr->type,
+       if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
                              (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
                              &err_chunk)) {
                /* This chunk contains fatal error. It is to be discarded.
@@ -1780,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:
@@ -3583,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,
@@ -3610,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);
 
@@ -3737,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);
 
@@ -6183,7 +6180,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
         * PMTU.  In cases, such as loopback, this might be a rather
         * large spill over.
         */
-       if ((!chunk->data_accepted) && (!asoc->rwnd ||
+       if ((!chunk->data_accepted) && (!asoc->rwnd || asoc->rwnd_over ||
            (datalen > asoc->rwnd + asoc->frag_point))) {
 
                /* If this is the next TSN, consider reneging to make