sctp: implement event notification SCTP_SENDER_DRY_EVENT
[cascardo/linux.git] / net / sctp / sm_statefuns.c
index 4b4eb7c..7f4a4f8 100644 (file)
@@ -393,8 +393,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
                goto nomem_init;
 
        /* The call, sctp_process_init(), can fail on memory allocation.  */
-       if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
-                              sctp_source(chunk),
+       if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk),
                               (sctp_init_chunk_t *)chunk->chunk_hdr,
                               GFP_ATOMIC))
                goto nomem_init;
@@ -551,7 +550,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
                 *
                 * This means that if we only want to abort associations
                 * in an authenticated way (i.e AUTH+ABORT), then we
-                * can't destroy this association just becuase the packet
+                * can't destroy this association just because the packet
                 * was malformed.
                 */
                if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
@@ -725,7 +724,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
         */
        peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
 
-       if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
+       if (!sctp_process_init(new_asoc, chunk,
                               &chunk->subh.cookie_hdr->c.peer_addr,
                               peer_init, GFP_ATOMIC))
                goto nomem_init;
@@ -942,18 +941,9 @@ static sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
 {
        struct sctp_transport *transport = (struct sctp_transport *) arg;
        struct sctp_chunk *reply;
-       sctp_sender_hb_info_t hbinfo;
-       size_t paylen = 0;
-
-       hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO;
-       hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t));
-       hbinfo.daddr = transport->ipaddr;
-       hbinfo.sent_at = jiffies;
-       hbinfo.hb_nonce = transport->hb_nonce;
 
        /* Send a heartbeat to our peer.  */
-       paylen = sizeof(sctp_sender_hb_info_t);
-       reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen);
+       reply = sctp_make_heartbeat(asoc, transport);
        if (!reply)
                return SCTP_DISPOSITION_NOMEM;
 
@@ -1464,8 +1454,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
         * Verification Tag and Peers Verification tag into a reserved
         * place (local tie-tag and per tie-tag) within the state cookie.
         */
-       if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
-                              sctp_source(chunk),
+       if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk),
                               (sctp_init_chunk_t *)chunk->chunk_hdr,
                               GFP_ATOMIC))
                goto nomem;
@@ -1546,7 +1535,7 @@ cleanup:
 }
 
 /*
- * Handle simultanous INIT.
+ * Handle simultaneous INIT.
  * This means we started an INIT and then we got an INIT request from
  * our peer.
  *
@@ -1694,8 +1683,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep,
         */
        peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
 
-       if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
-                              sctp_source(chunk), peer_init,
+       if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), peer_init,
                               GFP_ATOMIC))
                goto nomem;
 
@@ -1780,8 +1768,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
         * side effects--it is safe to run them here.
         */
        peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
-       if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
-                              sctp_source(chunk), peer_init,
+       if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), peer_init,
                               GFP_ATOMIC))
                goto nomem;
 
@@ -2079,7 +2066,7 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(
         * RFC 2960, Section 3.3.7
         *    If an endpoint receives an ABORT with a format error or for an
         *    association that doesn't exist, it MUST silently discard it.
-        * Becasue the length is "invalid", we can't really discard just
+        * Because the length is "invalid", we can't really discard just
         * as we do not know its true length.  So, to be safe, discard the
         * packet.
         */
@@ -2120,7 +2107,7 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
         * RFC 2960, Section 3.3.7
         *    If an endpoint receives an ABORT with a format error or for an
         *    association that doesn't exist, it MUST silently discard it.
-        * Becasue the length is "invalid", we can't really discard just
+        * Because the length is "invalid", we can't really discard just
         * as we do not know its true length.  So, to be safe, discard the
         * packet.
         */
@@ -2381,7 +2368,7 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
         * RFC 2960, Section 3.3.7
         *    If an endpoint receives an ABORT with a format error or for an
         *    association that doesn't exist, it MUST silently discard it.
-        * Becasue the length is "invalid", we can't really discard just
+        * Because the length is "invalid", we can't really discard just
         * as we do not know its true length.  So, to be safe, discard the
         * packet.
         */
@@ -2412,8 +2399,15 @@ static sctp_disposition_t __sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
 
        /* See if we have an error cause code in the chunk.  */
        len = ntohs(chunk->chunk_hdr->length);
-       if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
+       if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) {
+
+               sctp_errhdr_t *err;
+               sctp_walk_errors(err, chunk->chunk_hdr);
+               if ((void *)err != (void *)chunk->chunk_end)
+                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
                error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
+       }
 
        sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNRESET));
        /* ASSOC_FAILED will DELETE_TCB. */
@@ -2448,7 +2442,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
         * RFC 2960, Section 3.3.7
         *    If an endpoint receives an ABORT with a format error or for an
         *    association that doesn't exist, it MUST silently discard it.
-        * Becasue the length is "invalid", we can't really discard just
+        * Because the length is "invalid", we can't really discard just
         * as we do not know its true length.  So, to be safe, discard the
         * packet.
         */
@@ -3204,6 +3198,7 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
                                        sctp_cmd_seq_t *commands)
 {
        struct sctp_chunk *chunk = arg;
+       sctp_errhdr_t *err;
 
        if (!sctp_vtag_verify(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
@@ -3212,6 +3207,10 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t)))
                return sctp_sf_violation_chunklen(ep, asoc, type, arg,
                                                  commands);
+       sctp_walk_errors(err, chunk->chunk_hdr);
+       if ((void *)err != (void *)chunk->chunk_end)
+               return sctp_sf_violation_paramlen(ep, asoc, type, arg,
+                                                 (void *)err, commands);
 
        sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR,
                        SCTP_CHUNK(chunk));
@@ -3320,8 +3319,10 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
        struct sctp_chunk *chunk = arg;
        struct sk_buff *skb = chunk->skb;
        sctp_chunkhdr_t *ch;
+       sctp_errhdr_t *err;
        __u8 *ch_end;
        int ootb_shut_ack = 0;
+       int ootb_cookie_ack = 0;
 
        SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES);
 
@@ -3346,6 +3347,23 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
                if (SCTP_CID_ABORT == ch->type)
                        return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+               /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR
+                * or a COOKIE ACK the SCTP Packet should be silently
+                * discarded.
+                */
+
+               if (SCTP_CID_COOKIE_ACK == ch->type)
+                       ootb_cookie_ack = 1;
+
+               if (SCTP_CID_ERROR == ch->type) {
+                       sctp_walk_errors(err, ch) {
+                               if (SCTP_ERROR_STALE_COOKIE == err->cause) {
+                                       ootb_cookie_ack = 1;
+                                       break;
+                               }
+                       }
+               }
+
                /* Report violation if chunk len overflows */
                ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
                if (ch_end > skb_tail_pointer(skb))
@@ -3357,6 +3375,8 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
 
        if (ootb_shut_ack)
                return sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands);
+       else if (ootb_cookie_ack)
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
        else
                return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 }
@@ -3855,7 +3875,7 @@ gen_shutdown:
 }
 
 /*
- * SCTP-AUTH Section 6.3 Receving authenticated chukns
+ * SCTP-AUTH Section 6.3 Receiving authenticated chukns
  *
  *    The receiver MUST use the HMAC algorithm indicated in the HMAC
  *    Identifier field.  If this algorithm was not specified by the
@@ -4231,7 +4251,7 @@ static sctp_disposition_t sctp_sf_abort_violation(
         *
         * This means that if we only want to abort associations
         * in an authenticated way (i.e AUTH+ABORT), then we
-        * can't destroy this association just becuase the packet
+        * can't destroy this association just because the packet
         * was malformed.
         */
        if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
@@ -4343,8 +4363,9 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
 
 /*
  * Handle a protocol violation when the parameter length is invalid.
- * "Invalid" length is identified as smaller than the minimal length a
- * given parameter can be.
+ * If the length is smaller than the minimum length of a given parameter,
+ * or accumulated length in multi parameters exceeds the end of the chunk,
+ * the length is considered as invalid.
  */
 static sctp_disposition_t sctp_sf_violation_paramlen(
                                     const struct sctp_endpoint *ep,
@@ -4402,9 +4423,9 @@ static sctp_disposition_t sctp_sf_violation_ctsn(
 }
 
 /* Handle protocol violation of an invalid chunk bundling.  For example,
- * when we have an association and we recieve bundled INIT-ACK, or
+ * when we have an association and we receive bundled INIT-ACK, or
  * SHUDOWN-COMPLETE, our peer is clearly violationg the "MUST NOT bundle"
- * statement from the specs.  Additinally, there might be an attacker
+ * statement from the specs.  Additionally, there might be an attacker
  * on the path and we may not want to continue this communication.
  */
 static sctp_disposition_t sctp_sf_violation_chunk(
@@ -5055,6 +5076,30 @@ sctp_disposition_t sctp_sf_ignore_primitive(
  * These are the state functions for the OTHER events.
  ***************************************************************************/
 
+/*
+ * When the SCTP stack has no more user data to send or retransmit, this
+ * notification is given to the user. Also, at the time when a user app
+ * subscribes to this event, if there is no data to be sent or
+ * retransmit, the stack will immediately send up this notification.
+ */
+sctp_disposition_t sctp_sf_do_no_pending_tsn(
+       const struct sctp_endpoint *ep,
+       const struct sctp_association *asoc,
+       const sctp_subtype_t type,
+       void *arg,
+       sctp_cmd_seq_t *commands)
+{
+       struct sctp_ulpevent *event;
+
+       event = sctp_ulpevent_make_sender_dry_event(asoc, GFP_ATOMIC);
+       if (!event)
+               return SCTP_DISPOSITION_NOMEM;
+
+       sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(event));
+
+       return SCTP_DISPOSITION_CONSUME;
+}
+
 /*
  * Start the shutdown negotiation.
  *