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