1 #include <assert.h> 2 3 #include "tcp_util.h" 4 #include "tcp_ring_buffer.h" 5 #include "eventpoll.h" 6 #include "debug.h" 7 #include "timer.h" 8 #include "ip_in.h" 9 10 #define MAX(a, b) ((a)>(b)?(a):(b)) 11 #define MIN(a, b) ((a)<(b)?(a):(b)) 12 13 /*---------------------------------------------------------------------------*/ 14 void 15 ParseTCPOptions(tcp_stream *cur_stream, 16 uint32_t cur_ts, uint8_t *tcpopt, int len) 17 { 18 int i; 19 unsigned int opt, optlen; 20 21 for (i = 0; i < len; ) { 22 opt = *(tcpopt + i++); 23 24 if (opt == TCP_OPT_END) { // end of option field 25 break; 26 } else if (opt == TCP_OPT_NOP) { // no option 27 continue; 28 } else { 29 30 optlen = *(tcpopt + i++); 31 if (i + optlen - 2 > len) { 32 break; 33 } 34 35 if (opt == TCP_OPT_MSS) { 36 cur_stream->sndvar->mss = *(tcpopt + i++) << 8; 37 cur_stream->sndvar->mss += *(tcpopt + i++); 38 cur_stream->sndvar->eff_mss = cur_stream->sndvar->mss; 39 #if TCP_OPT_TIMESTAMP_ENABLED 40 cur_stream->sndvar->eff_mss -= (TCP_OPT_TIMESTAMP_LEN + 2); 41 #endif 42 } else if (opt == TCP_OPT_WSCALE) { 43 cur_stream->sndvar->wscale_peer = *(tcpopt + i++); 44 } else if (opt == TCP_OPT_SACK_PERMIT) { 45 cur_stream->sack_permit = TRUE; 46 TRACE_SACK("Remote SACK permited.\n"); 47 } else if (opt == TCP_OPT_TIMESTAMP) { 48 TRACE_TSTAMP("Saw peer timestamp!\n"); 49 cur_stream->saw_timestamp = TRUE; 50 cur_stream->rcvvar->ts_recent = ntohl(*(uint32_t *)(tcpopt + i)); 51 cur_stream->rcvvar->ts_last_ts_upd = cur_ts; 52 i += 8; 53 } else { 54 // not handle 55 i += optlen - 2; 56 } 57 } 58 } 59 } 60 /*---------------------------------------------------------------------------*/ 61 inline int 62 ParseTCPTimestamp(tcp_stream *cur_stream, 63 struct tcp_timestamp *ts, uint8_t *tcpopt, int len) 64 { 65 int i; 66 unsigned int opt, optlen; 67 68 for (i = 0; i < len; ) { 69 opt = *(tcpopt + i++); 70 71 if (opt == TCP_OPT_END) { // end of option field 72 break; 73 } else if (opt == TCP_OPT_NOP) { // no option 74 continue; 75 } else { 76 optlen = *(tcpopt + i++); 77 if (i + optlen - 2 > len) { 78 break; 79 } 80 81 if (opt == TCP_OPT_TIMESTAMP) { 82 ts->ts_val = ntohl(*(uint32_t *)(tcpopt + i)); 83 ts->ts_ref = ntohl(*(uint32_t *)(tcpopt + i + 4)); 84 return TRUE; 85 } else { 86 // not handle 87 i += optlen - 2; 88 } 89 } 90 } 91 return FALSE; 92 } 93 #if TCP_OPT_SACK_ENABLED 94 /*----------------------------------------------------------------------------*/ 95 void 96 ParseSACKOption(tcp_stream *cur_stream, 97 uint32_t ack_seq, uint8_t *tcpopt, int len) 98 { 99 int i, j; 100 unsigned int opt, optlen; 101 uint32_t left_edge, right_edge; 102 103 for (i = 0; i < len; ) { 104 opt = *(tcpopt + i++); 105 106 if (opt == TCP_OPT_END) { // end of option field 107 break; 108 } else if (opt == TCP_OPT_NOP) { // no option 109 continue; 110 } else { 111 optlen = *(tcpopt + i++); 112 if (i + optlen - 2 > len) { 113 break; 114 } 115 116 if (opt == TCP_OPT_SACK) { 117 j = 0; 118 while (j < optlen - 2) { 119 left_edge = ntohl(*(uint32_t *)(tcpopt + i + j)); 120 right_edge = ntohl(*(uint32_t *)(tcpopt + i + j + 4)); 121 122 cur_stream->rcvvar->sack_table 123 [cur_stream->rcvvar->sacks].left_edge = left_edge; 124 cur_stream->rcvvar->sack_table 125 [cur_stream->rcvvar->sacks].right_edge = right_edge; 126 cur_stream->rcvvar->sacks++; 127 j += 8; 128 #if RTM_STAT 129 cur_stream->rstat->sack_cnt++; 130 cur_stream->rstat->sack_bytes += (right_edge - left_edge); 131 #endif 132 if (cur_stream->rcvvar->dup_acks == 3) { 133 #if RTM_STAT 134 cur_stream->rstat->tdp_sack_cnt++; 135 cur_stream-> 136 rstat->tdp_sack_bytes += (right_edge - left_edge); 137 #endif 138 TRACE_LOSS("SACK entry. " 139 "left_edge: %u, right_edge: %u (ack_seq: %u)\n", 140 left_edge, right_edge, ack_seq); 141 142 } 143 TRACE_SACK("Found SACK entry. " 144 "left_edge: %u, right_edge: %u\n", 145 left_edge, right_edge); 146 } 147 i += j; 148 } else { 149 // not handle 150 i += optlen - 2; 151 } 152 } 153 } 154 } 155 #endif /* TCP_OPT_SACK_ENABLED */ 156 /*---------------------------------------------------------------------------*/ 157 uint16_t 158 TCPCalcChecksum(uint16_t *buf, uint16_t len, uint32_t saddr, uint32_t daddr) 159 { 160 uint32_t sum; 161 uint16_t *w; 162 int nleft; 163 164 sum = 0; 165 nleft = len; 166 w = buf; 167 168 while (nleft > 1) 169 { 170 sum += *w++; 171 nleft -= 2; 172 } 173 174 // add padding for odd length 175 if (nleft) 176 sum += *w & ntohs(0xFF00); 177 178 // add pseudo header 179 sum += (saddr & 0x0000FFFF) + (saddr >> 16); 180 sum += (daddr & 0x0000FFFF) + (daddr >> 16); 181 sum += htons(len); 182 sum += htons(IPPROTO_TCP); 183 184 sum = (sum >> 16) + (sum & 0xFFFF); 185 sum += (sum >> 16); 186 187 sum = ~sum; 188 189 return (uint16_t)sum; 190 } 191 /*---------------------------------------------------------------------------*/ 192 void 193 PrintTCPOptions(uint8_t *tcpopt, int len) 194 { 195 int i; 196 unsigned int opt, optlen; 197 198 for (i = 0; i < len; i++) { 199 printf("%u ", tcpopt[i]); 200 } 201 printf("\n"); 202 203 for (i = 0; i < len; ) { 204 opt = *(tcpopt + i++); 205 206 if (opt == TCP_OPT_END) { // end of option field 207 break; 208 } else if (opt == TCP_OPT_NOP) { // no option 209 continue; 210 } else { 211 212 optlen = *(tcpopt + i++); 213 214 printf("Option: %d", opt); 215 printf(", length: %d", optlen); 216 217 if (opt == TCP_OPT_MSS) { 218 uint16_t mss; 219 mss = *(tcpopt + i++) << 8; 220 mss += *(tcpopt + i++); 221 printf(", MSS: %u", mss); 222 } else if (opt == TCP_OPT_SACK_PERMIT) { 223 printf(", SACK permit"); 224 } else if (opt == TCP_OPT_TIMESTAMP) { 225 uint32_t ts_val, ts_ref; 226 ts_val = *(uint32_t *)(tcpopt + i); 227 i += 4; 228 ts_ref = *(uint32_t *)(tcpopt + i); 229 i += 4; 230 printf(", TSval: %u, TSref: %u", ts_val, ts_ref); 231 } else if (opt == TCP_OPT_WSCALE) { 232 uint8_t wscale; 233 wscale = *(tcpopt + i++); 234 printf(", Wscale: %u", wscale); 235 } else { 236 // not handle 237 i += optlen - 2; 238 } 239 printf("\n"); 240 } 241 } 242 } 243