xref: /mOS-networking-stack/core/src/tcp_util.c (revision 76404edc)
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