Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / net / sctp / sm_statefuns.c
index 28c070e187c2ed84fc531622a8090888207844ba..c9ae3404b1bb11572e34255cb3eae86ca1dd8131 100644 (file)
@@ -153,10 +153,7 @@ static enum sctp_disposition sctp_sf_violation_chunk(
                                        struct sctp_cmd_seq *commands);
 
 static enum sctp_ierror sctp_sf_authenticate(
-                                       struct net *net,
-                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
-                                       const union sctp_subtype type,
                                        struct sctp_chunk *chunk);
 
 static enum sctp_disposition __sctp_sf_do_9_1_abort(
@@ -626,6 +623,38 @@ enum sctp_disposition sctp_sf_do_5_1C_ack(struct net *net,
        return SCTP_DISPOSITION_CONSUME;
 }
 
+static bool sctp_auth_chunk_verify(struct net *net, struct sctp_chunk *chunk,
+                                  const struct sctp_association *asoc)
+{
+       struct sctp_chunk auth;
+
+       if (!chunk->auth_chunk)
+               return true;
+
+       /* SCTP-AUTH:  auth_chunk pointer is only set when the cookie-echo
+        * is supposed to be authenticated and we have to do delayed
+        * authentication.  We've just recreated the association using
+        * the information in the cookie and now it's much easier to
+        * do the authentication.
+        */
+
+       /* Make sure that we and the peer are AUTH capable */
+       if (!net->sctp.auth_enable || !asoc->peer.auth_capable)
+               return false;
+
+       /* set-up our fake chunk so that we can process it */
+       auth.skb = chunk->auth_chunk;
+       auth.asoc = chunk->asoc;
+       auth.sctp_hdr = chunk->sctp_hdr;
+       auth.chunk_hdr = (struct sctp_chunkhdr *)
+                               skb_push(chunk->auth_chunk,
+                                        sizeof(struct sctp_chunkhdr));
+       skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr));
+       auth.transport = chunk->transport;
+
+       return sctp_sf_authenticate(asoc, &auth) == SCTP_IERROR_NO_ERROR;
+}
+
 /*
  * Respond to a normal COOKIE ECHO chunk.
  * We are the side that is being asked for an association.
@@ -763,37 +792,9 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
        if (error)
                goto nomem_init;
 
-       /* SCTP-AUTH:  auth_chunk pointer is only set when the cookie-echo
-        * is supposed to be authenticated and we have to do delayed
-        * authentication.  We've just recreated the association using
-        * the information in the cookie and now it's much easier to
-        * do the authentication.
-        */
-       if (chunk->auth_chunk) {
-               struct sctp_chunk auth;
-               enum sctp_ierror ret;
-
-               /* Make sure that we and the peer are AUTH capable */
-               if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) {
-                       sctp_association_free(new_asoc);
-                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
-               }
-
-               /* set-up our fake chunk so that we can process it */
-               auth.skb = chunk->auth_chunk;
-               auth.asoc = chunk->asoc;
-               auth.sctp_hdr = chunk->sctp_hdr;
-               auth.chunk_hdr = (struct sctp_chunkhdr *)
-                                       skb_push(chunk->auth_chunk,
-                                                sizeof(struct sctp_chunkhdr));
-               skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr));
-               auth.transport = chunk->transport;
-
-               ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth);
-               if (ret != SCTP_IERROR_NO_ERROR) {
-                       sctp_association_free(new_asoc);
-                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
-               }
+       if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) {
+               sctp_association_free(new_asoc);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
        }
 
        repl = sctp_make_cookie_ack(new_asoc, chunk);
@@ -1797,13 +1798,15 @@ static enum sctp_disposition sctp_sf_do_dupcook_a(
        if (sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC))
                goto nomem;
 
+       if (!sctp_auth_chunk_verify(net, chunk, new_asoc))
+               return SCTP_DISPOSITION_DISCARD;
+
        /* Make sure no new addresses are being added during the
         * restart.  Though this is a pretty complicated attack
         * since you'd have to get inside the cookie.
         */
-       if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) {
+       if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands))
                return SCTP_DISPOSITION_CONSUME;
-       }
 
        /* If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
         * the peer has restarted (Action A), it MUST NOT setup a new
@@ -1912,6 +1915,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_b(
        if (sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC))
                goto nomem;
 
+       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,
@@ -2009,6 +2015,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_d(
         * a COOKIE ACK.
         */
 
+       if (!sctp_auth_chunk_verify(net, chunk, asoc))
+               return SCTP_DISPOSITION_DISCARD;
+
        /* Don't accidentally move back into established state. */
        if (asoc->state < SCTP_STATE_ESTABLISHED) {
                sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
@@ -4171,10 +4180,7 @@ gen_shutdown:
  * The return value is the disposition of the chunk.
  */
 static enum sctp_ierror sctp_sf_authenticate(
-                                       struct net *net,
-                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
-                                       const union sctp_subtype type,
                                        struct sctp_chunk *chunk)
 {
        struct sctp_shared_key *sh_key = NULL;
@@ -4275,7 +4281,7 @@ enum sctp_disposition sctp_sf_eat_auth(struct net *net,
                                                  commands);
 
        auth_hdr = (struct sctp_authhdr *)chunk->skb->data;
-       error = sctp_sf_authenticate(net, ep, asoc, type, chunk);
+       error = sctp_sf_authenticate(asoc, chunk);
        switch (error) {
        case SCTP_IERROR_AUTH_BAD_HMAC:
                /* Generate the ERROR chunk and discard the rest