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
ParseTCPOptions(tcp_stream * cur_stream,uint32_t cur_ts,uint8_t * tcpopt,int len)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
ParseTCPTimestamp(tcp_stream * cur_stream,struct tcp_timestamp * ts,uint8_t * tcpopt,int len)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
ParseSACKOption(tcp_stream * cur_stream,uint32_t ack_seq,uint8_t * tcpopt,int len)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
TCPCalcChecksum(uint16_t * buf,uint16_t len,uint32_t saddr,uint32_t daddr)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
PrintTCPOptions(uint8_t * tcpopt,int len)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