Author: tuexen
Date: Fri Nov 12 20:45:21 2010
New Revision: 215198
URL: http://svn.freebsd.org/changeset/base/215198

Log:
  Fix more issues with the SACK/NR-SACK generation code.
  
  MFC after: 3 days.

Modified:
  head/sys/netinet/sctp_output.c

Modified: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c      Fri Nov 12 20:26:34 2010        
(r215197)
+++ head/sys/netinet/sctp_output.c      Fri Nov 12 20:45:21 2010        
(r215198)
@@ -9927,13 +9927,14 @@ sctp_send_sack(struct sctp_tcb *stcb)
        caddr_t limit;
        uint32_t *dup;
        int limit_reached = 0;
-       unsigned int i, sel_start, siz, j;
+       unsigned int i, siz, j;
        unsigned int num_gap_blocks = 0, num_nr_gap_blocks = 0, space;
        int num_dups = 0;
        int space_req;
        uint32_t highest_tsn;
        uint8_t flags;
        uint8_t type;
+       uint8_t tsn_map;
 
        if ((stcb->asoc.sctp_nr_sack_on_off == 1) &&
            (stcb->asoc.peer_supports_nr_sack == 1)) {
@@ -10123,24 +10124,24 @@ sctp_send_sack(struct sctp_tcb *stcb)
        } else {
                offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn;
        }
-       if ((offset == 1) ||
-           ((type == SCTP_NR_SELECTIVE_ACK) &&
-           ((asoc->mapping_array[0] & (1 << (1 - offset))) == 0))) {
-               sel_start = 0;
-       } else {
-               sel_start = 1;
-       }
        if (((type == SCTP_SELECTIVE_ACK) &&
            compare_with_wrap(highest_tsn, asoc->cumulative_tsn, MAX_TSN)) ||
            ((type == SCTP_NR_SELECTIVE_ACK) &&
            compare_with_wrap(asoc->highest_tsn_inside_map, 
asoc->cumulative_tsn, MAX_TSN))) {
                /* we have a gap .. maybe */
                for (i = 0; i < siz; i++) {
+                       tsn_map = asoc->mapping_array[i];
                        if (type == SCTP_SELECTIVE_ACK) {
-                               selector = &sack_array[asoc->mapping_array[i] | 
asoc->nr_mapping_array[i]];
-                       } else {
-                               selector = &sack_array[asoc->mapping_array[i]];
+                               tsn_map |= asoc->nr_mapping_array[i];
+                       }
+                       if (i == 0) {
+                               /*
+                                * Clear all bits corresponding to TSNs
+                                * smaller or equal to the cumulative TSN.
+                                */
+                               tsn_map &= (~0 << (1 - offset));
                        }
+                       selector = &sack_array[tsn_map];
                        if (mergeable && selector->right_edge) {
                                /*
                                 * Backup, left and right edges were ok to
@@ -10152,7 +10153,7 @@ sctp_send_sack(struct sctp_tcb *stcb)
                        if (selector->num_entries == 0)
                                mergeable = 0;
                        else {
-                               for (j = sel_start; j < selector->num_entries; 
j++) {
+                               for (j = 0; j < selector->num_entries; j++) {
                                        if (mergeable && selector->right_edge) {
                                                /*
                                                 * do a merge by NOT setting
@@ -10184,7 +10185,6 @@ sctp_send_sack(struct sctp_tcb *stcb)
                                /* Reached the limit stop */
                                break;
                        }
-                       sel_start = 0;
                        offset += 8;
                }
        }
@@ -10199,11 +10199,6 @@ sctp_send_sack(struct sctp_tcb *stcb)
                        siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + 
asoc->highest_tsn_inside_nr_map + 7) / 8;
                }
 
-               if ((asoc->nr_mapping_array[0] & (1 << (1 - offset))) == 0) {
-                       sel_start = 0;
-               } else {
-                       sel_start = 1;
-               }
                if (compare_with_wrap(asoc->mapping_array_base_tsn, 
asoc->cumulative_tsn, MAX_TSN)) {
                        offset = 1;
                } else {
@@ -10212,7 +10207,16 @@ sctp_send_sack(struct sctp_tcb *stcb)
                if (compare_with_wrap(asoc->highest_tsn_inside_nr_map, 
asoc->cumulative_tsn, MAX_TSN)) {
                        /* we have a gap .. maybe */
                        for (i = 0; i < siz; i++) {
-                               selector = 
&sack_array[asoc->nr_mapping_array[i]];
+                               tsn_map = asoc->nr_mapping_array[i];
+                               if (i == 0) {
+                                       /*
+                                        * Clear all bits corresponding to
+                                        * TSNs smaller or equal to the
+                                        * cumulative TSN.
+                                        */
+                                       tsn_map &= (~0 << (1 - offset));
+                               }
+                               selector = &sack_array[tsn_map];
                                if (mergeable && selector->right_edge) {
                                        /*
                                         * Backup, left and right edges were
@@ -10224,7 +10228,7 @@ sctp_send_sack(struct sctp_tcb *stcb)
                                if (selector->num_entries == 0)
                                        mergeable = 0;
                                else {
-                                       for (j = sel_start; j < 
selector->num_entries; j++) {
+                                       for (j = 0; j < selector->num_entries; 
j++) {
                                                if (mergeable && 
selector->right_edge) {
                                                        /*
                                                         * do a merge by NOT
@@ -10257,7 +10261,6 @@ sctp_send_sack(struct sctp_tcb *stcb)
                                        /* Reached the limit stop */
                                        break;
                                }
-                               sel_start = 0;
                                offset += 8;
                        }
                }
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to