NetSim Source Code Help v14.4
All 13 Components
 
Loading...
Searching...
No Matches
TCP_Incoming.c
1/************************************************************************************
2* Copyright (C) 2023 *
3* TETCOS, Bangalore. India *
4* *
5* Tetcos owns the intellectual property rights in the Product and its content. *
6* The copying, redistribution, reselling or publication of any or all of the *
7* Product or its content without express prior written consent of Tetcos is *
8* prohibited. Ownership and / or any other right relating to the software and all *
9* intellectual property rights therein shall remain at all times with Tetcos. *
10* *
11* This source code is licensed per the NetSim license agreement. *
12* *
13* No portion of this source code may be used as the basis for a derivative work, *
14* or used, for any purpose other than its intended use per the NetSim license *
15* agreement. *
16* *
17* This source code and the algorithms contained within it are confidential trade *
18* secrets of TETCOS and may not be used as the basis for any other software, *
19* hardware, product or service. *
20* *
21* Author: Shashi Kant Suman *
22* *
23* ----------------------------------------------------------------------------------*/
24#include "main.h"
25#include "TCP.h"
26#include "TCP_Header.h"
27
28//#define _LOG_INCOMING_
29
30#ifdef _LOG_INCOMING_
31static FILE* fp;
32#endif
33
34static bool Validate_segment(PNETSIM_SOCKET s)
35{
36 /*RFC 793 Sept 1981 Page 69
37 There are four cases for the acceptability test for an incoming
38 segment:
39
40 Segment Receive Test
41 Length Window
42 ------- ------- -------------------------------------------
43
44 0 0 SEG.SEQ = RCV.NXT
45
46 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
47
48 >0 0 not acceptable
49
50 >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
51 or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
52 */
53 PTCB t = s->tcb;
54 if (!t->SEG.LEN && !t->RCV.WND)
55 return t->SEG.SEQ == t->RCV.NXT;
56 else if (!t->SEG.LEN && t->RCV.WND > 0)
57 return (t->RCV.NXT <= t->SEG.SEQ) &&
58 (t->SEG.SEQ < t->RCV.NXT + t->RCV.WND);
59 else if (t->SEG.LEN > 0 && t->RCV.WND == 0)
60 return false;
61 else if (t->SEG.LEN > 0 && t->RCV.WND > 0)
62 return ((t->RCV.NXT <= t->SEG.SEQ) &&
63 (t->SEG.SEQ < t->RCV.NXT + t->RCV.WND)) ||
64 ((t->RCV.NXT <= t->SEG.SEQ + t->SEG.LEN - 1) &&
65 (t->SEG.SEQ + t->SEG.LEN - 1 < t->RCV.NXT + t->RCV.WND));
66
67 assert(false); // TCP is now mad. Enjoy debugging....:(
68 return false;
69}
70
71static void process_rst_packet(PNETSIM_SOCKET s, NetSim_PACKET* p)
72{
73 switch (s->tcb->tcp_state)
74 {
75 case TCPCONNECTION_SYN_RECEIVED:
76 {
77 delete_all_segment_from_queue(&s->tcb->retransmissionQueue);
78 if (s->tcb->tcp_prev_state == TCPCONNECTION_LISTEN)
79 {
80 //Passive open case
81 tcp_change_state(s, TCPCONNECTION_LISTEN);
82 }
83 else
84 {
85 //Active open case
86 print_tcp_log("Connection Refused for local addr %s:%d, remote addr %s:%d",
87 s->localAddr->ip->str_ip,
88 s->localAddr->port,
89 s->remoteAddr->ip->str_ip,
90 s->remoteAddr->port);
91 tcp_close_socket(s, s->localDeviceId);
92 }
93 }
94 break;
95 case TCPCONNECTION_ESTABLISHED:
96 case TCPCONNECTION_FIN_WAIT_1:
97 case TCPCONNECTION_FIN_WAIT_2:
98 case TCPCONNECTION_CLOSE_WAIT:
99 {
100 print_tcp_log("Connection Reset for local addr %s:%d, remote addr %s:%d",
101 s->localAddr->ip->str_ip,
102 s->localAddr->port,
103 s->remoteAddr->ip->str_ip,
104 s->remoteAddr->port);
105 }
106 case TCPCONNECTION_CLOSING:
107 case TCPCONNECTION_LAST_ACK:
108 case TCPCONNECTION_TIME_WAIT:
109 tcp_close_socket(s, s->localDeviceId);
110 break;
111 }
112 fn_NetSim_Packet_FreePacket(p);
113 pstruEventDetails->pPacket = NULL;
114}
115
116static void process_syn_packet(PNETSIM_SOCKET s, NetSim_PACKET* p)
117{
118 switch (s->tcb->tcp_state)
119 {
120 case TCPCONNECTION_SYN_RECEIVED:
121 //Correction made by RFC 1122 Page 94
122 tcp_change_state(s, TCPCONNECTION_LISTEN);
123 break;
124 case TCPCONNECTION_ESTABLISHED:
125 case TCPCONNECTION_FIN_WAIT_1:
126 case TCPCONNECTION_FIN_WAIT_2:
127 case TCPCONNECTION_CLOSE_WAIT:
128 case TCPCONNECTION_CLOSING:
129 case TCPCONNECTION_LAST_ACK:
130 case TCPCONNECTION_TIME_WAIT:
131 print_tcp_log("Connection Reset for local addr %s:%d, remote addr %s:%d",
132 s->localAddr->ip->str_ip,
133 s->localAddr->port,
134 s->remoteAddr->ip->str_ip,
135 s->remoteAddr->port);
136 tcp_close_socket(s, s->localDeviceId);
137 break;
138 }
139 fn_NetSim_Packet_FreePacket(p);
140 pstruEventDetails->pPacket = NULL;
141}
142
143static bool process_ack_in_establishedState(PNETSIM_SOCKET s, PTCP_SEGMENT_HDR hdr)
144{
145#ifdef _LOG_INCOMING_
146 fprintf(fp, "%lf,,,,,%d,\n",
147 pstruEventDetails->dEventTime,
148 s->tcb->SEG.ACK);
149 fflush(fp);
150#endif
151
152 PTCB t = s->tcb;
153
154 //Call Sack
155 receive_sack_option(s, hdr);
156
157 if (s->tcb->isTSopt)
158 {
159 //Store the timestamp option based on peer device
160 PTSopt tsopt = get_tcp_option(hdr,
161 TCP_OPTION_TIMESTAMP);
162 set_timestamp_value(s, hdr, tsopt);
163 }
164
165 //Call congestion algorithm
166 t->ack_received(s);
167
168
169 s->tcpMetrics->ackReceived++;
170
171 if (t->SND.UNA < t->SEG.ACK &&
172 t->SEG.ACK <= t->SND.NXT) //RFC 793
173 {
174
175 //Update the RTO
176 TCP_RTO(s->tcb) = calculate_RTO(get_RTT(s->tcb,t->SEG.ACK),
177 &TCP_SRTT(s->tcb),
178 &TCP_RTTVAR(s->tcb));
179
180
181 t->SND.UNA = t->SEG.ACK;
182 delete_segment_from_queue(&t->retransmissionQueue, t->SEG.ACK);
183 restart_rto_timer(s);
184 if (t->SND.WL1 < t->SEG.SEQ ||
185 (t->SND.WL1 == t->SEG.SEQ &&
186 t->SND.WL2 <= t->SEG.ACK))
187 {
188 t->SND.WND = t->SEG.WND;
189 t->SND.WL1 = t->SEG.SEQ;
190 t->SND.WL2 = t->SEG.ACK;
191 }
192 return true;
193 }
194 //else if (t->SEG.ACK < t->SND.UNA) //RFC 793
195 else if (t->SEG.ACK <= t->SND.UNA) //RFC 1122 Page 94
196 {
197 //Duplicate ack. Ignore
198 s->tcpMetrics->dupAckReceived++;
199 UINT dupackcount = s->tcb->get_dup_ack_count(s);
200 if (dupackcount == 1 || dupackcount == 2) return true;
201 else return false;
202 }
203 else if (t->SEG.ACK > t->SND.NXT)
204 {
205 send_ack(s, pstruEventDetails->dEventTime, t->SEG.SEQ, t->SEG.ACK);
206 return false;
207 }
208
209 return false;
210}
211
212static void process_ack_packet(PNETSIM_SOCKET s, NetSim_PACKET* p)
213{
214 PTCP_SEGMENT_HDR hdr = TCP_GET_SEGMENT_HDR(p);
215 bool isContinueProcessing=false;
216 switch (s->tcb->tcp_state)
217 {
218 case TCPCONNECTION_SYN_RECEIVED:
219 {
220 if (!(s->tcb->SND.UNA <= s->tcb->SEG.ACK &&
221 s->tcb->SEG.ACK <= s->tcb->SND.NXT))
222 {
223 send_rst(s, p, 1);
224 break;
225 }
226 else
227 {
228 //Correction made by RFC 1122 page 94
229 s->tcb->SND.WND = s->tcb->SEG.WND;
230 s->tcb->SND.WL1 = s->tcb->SEG.SEQ;
231 s->tcb->SND.WL2 = s->tcb->SEG.ACK;
232
233 tcp_change_state(s, TCPCONNECTION_ESTABLISHED);
234 }
235 }
236 case TCPCONNECTION_ESTABLISHED:
237 {
238 isContinueProcessing = process_ack_in_establishedState(s, hdr);
239 if (isContinueProcessing)
240 send_segment(s);
241 }
242 break;
243 case TCPCONNECTION_FIN_WAIT_1:
244 isContinueProcessing = process_ack_in_establishedState(s, hdr);
245 if (isContinueProcessing)
246 send_segment(s);
247 if(hdr->Fin)
248 tcp_change_state(s, TCPCONNECTION_FIN_WAIT_2);
249 break;
250 case TCPCONNECTION_FIN_WAIT_2:
251 case TCPCONNECTION_CLOSE_WAIT:
252 isContinueProcessing = process_ack_in_establishedState(s, hdr);
253 if (isContinueProcessing)
254 send_segment(s);
255 break;
256 case TCPCONNECTION_CLOSING:
257 isContinueProcessing = process_ack_in_establishedState(s, hdr);
258 if (isContinueProcessing)
259 send_segment(s);
260 if (hdr->Fin)
261 {
262 start_timewait_timer(s);
263 tcp_change_state(s, TCPCONNECTION_TIME_WAIT);
264 }
265 break;
266 case TCPCONNECTION_LAST_ACK:
267 s->tcpMetrics->ackReceived++;
268 tcp_change_state(s, TCPCONNECTION_CLOSED);
269 delete_tcb(s);
270 tcp_close_socket(s, pstruEventDetails->nDeviceId);
271 break;
272 case TCPCONNECTION_TIME_WAIT:
273 send_fin_ack(s, pstruEventDetails->dEventTime, s->tcb->SEG.SEQ, s->tcb->SEG.ACK);
274 start_timewait_timer(s);
275 s->tcb->istimewaittimerrestarted = true;
276 break;
277 default:
278 fnNetSimError("Unknown TCP connection state %d in %s",
279 s->tcb->tcp_state,
280 __FUNCTION__);
281 break;
282 }
283 fn_NetSim_Packet_FreePacket(p);
284 pstruEventDetails->pPacket = NULL;
285}
286
287static void process_fin_packet(PNETSIM_SOCKET s, NetSim_PACKET* p)
288{
289 switch (s->tcb->tcp_state)
290 {
291 case TCPCONNECTION_CLOSED:
292 case TCPCONNECTION_LISTEN:
293 case TCPCONNECTION_SYN_SENT:
294 goto DISCARD_SEGMENT;
295 }
296
297 switch (s->tcb->tcp_state)
298 {
299 case TCPCONNECTION_SYN_RECEIVED:
300 case TCPCONNECTION_ESTABLISHED:
301 send_fin_ack(s, pstruEventDetails->dEventTime, s->tcb->SND.NXT, s->tcb->RCV.NXT);
302 tcp_change_state(s, TCPCONNECTION_CLOSE_WAIT);
303 //User will call close
304 send_fin(s);
305 tcp_change_state(s, TCPCONNECTION_LAST_ACK);
306 print_tcp_log("Canceling all timer.");
307 s->tcb->isOtherTimerCancel = true;
308 break;
309 case TCPCONNECTION_FIN_WAIT_1:
310 tcp_change_state(s, TCPCONNECTION_CLOSING);
311 send_fin_ack(s, pstruEventDetails->dEventTime, s->tcb->SND.NXT, s->tcb->RCV.NXT);
312 break;
313 case TCPCONNECTION_FIN_WAIT_2:
314 tcp_change_state(s, TCPCONNECTION_TIME_WAIT);
315 start_timewait_timer(s);
316 send_ack(s, pstruEventDetails->dEventTime, s->tcb->SND.NXT+1, s->tcb->SEG.SEQ+1);
317 break;
318 case TCPCONNECTION_CLOSE_WAIT:
319 case TCPCONNECTION_CLOSING:
320 case TCPCONNECTION_LAST_ACK:
321 // No operation
322 break;
323 case TCPCONNECTION_TIME_WAIT:
324 s->tcb->istimewaittimerrestarted = true;
325 start_timewait_timer(s);
326 break;
327 default:
328 fnNetSimError("Unknown tcp state %d", s->tcb->tcp_state);
329 break;
330 }
331DISCARD_SEGMENT:
332 fn_NetSim_Packet_FreePacket(p);
333 pstruEventDetails->pPacket = NULL;
334}
335
336static bool check_segment(PNETSIM_SOCKET s, NetSim_PACKET* p)
337{
338 PTCP_SEGMENT_HDR hdr = TCP_GET_SEGMENT_HDR(p);
339 if (s->tcb->RCV.NXT == hdr->SeqNum)
340 {
341 s->tcb->RCV.NXT += s->tcb->SEG.LEN;
342 //Check from queue
343 check_segment_in_queue(s);
344 return true;
345 }
346 else if ((s->tcb->RCV.NXT > hdr->SeqNum))
347 {
348 //Duplicate segment
349 s->tcpMetrics->dupSegmentReceived++;
350 return false;
351 }
352 else
353 {
354 s->tcpMetrics->outOfOrderSegmentReceived++;
355 if (isSegmentInQueue(&s->tcb->outOfOrderSegment, p))
356 s->tcpMetrics->dupSegmentReceived++;
357 else
358 add_packet_to_queue(&s->tcb->outOfOrderSegment, p, pstruEventDetails->dEventTime);
359 return false;
360 }
361}
362
363static bool process_segment_text(PNETSIM_SOCKET s, NetSim_PACKET* p)
364{
365 PTCP_SEGMENT_HDR hdr = TCP_GET_SEGMENT_HDR(p);
366
367#ifdef _LOG_INCOMING_
368 fprintf(fp, "%lf,%d,,,,,\n",
369 pstruEventDetails->dEventTime,
370 s->tcb->SEG.SEQ);
371 fflush(fp);
372#endif
373
374 write_congestion_plot(s, p);
375 s->tcpMetrics->segmentReceived++;
376
377 if (s->tcb->isTSopt)
378 {
379 //Store the timestamp option based on peer device
380 PTSopt tsopt = get_tcp_option(hdr,
381 TCP_OPTION_TIMESTAMP);
382 set_timestamp_value(s, hdr, tsopt);
383 }
384
385 if (s->tcb->tcp_state == TCPCONNECTION_ESTABLISHED ||
386 s->tcb->tcp_state == TCPCONNECTION_FIN_WAIT_1 ||
387 s->tcb->tcp_state == TCPCONNECTION_FIN_WAIT_2)
388 {
389 bool isinorder = check_segment(s, p);
390
391 if((!isinorder || send_ack_or_not(s)) && !hdr->Fin)
392 send_ack(s, pstruEventDetails->dEventTime, s->tcb->SND.NXT, s->tcb->RCV.NXT);
393
394 if(isinorder)
395 send_to_application(s, p);
396
397 return true;
398 }
399 else if (hdr->Fin)
400 {
401 return true; //FIN Packet
402 }
403 else if (s->tcb->tcp_state == TCPCONNECTION_CLOSE_WAIT ||
404 s->tcb->tcp_state == TCPCONNECTION_CLOSING ||
405 s->tcb->tcp_state == TCPCONNECTION_LAST_ACK ||
406 s->tcb->tcp_state == TCPCONNECTION_TIME_WAIT)
407 {
408 fn_NetSim_Packet_FreePacket(p);
409 pstruEventDetails->pPacket = NULL;
410 return false;
411 }
412 else if (s->tcb->tcp_state == TCPCONNECTION_SYN_RECEIVED)
413 {
414 // May be ack got error. Ignore segment
415 fn_NetSim_Packet_FreePacket(p);
416 pstruEventDetails->pPacket = NULL;
417 return false;
418 }
419 else
420 {
421 fnNetSimError("Unknown TCP connection state %s in %s",
422 state_to_str(s->tcb->tcp_state),
423 __FUNCTION__);
424 fn_NetSim_Packet_FreePacket(p);
425 pstruEventDetails->pPacket = NULL;
426 return false;
427 }
428}
429
430void packet_arrives_at_incoming_tcp(PNETSIM_SOCKET s, NetSim_PACKET* p)
431{
432 bool isContinue;
433
434#ifdef _LOG_INCOMING_
435 if (!fp)
436 {
437 fp = fopen("IncomingTCP.csv", "w");
438 fprintf(fp, "Time,Seq,,,Ack\n");
439 fflush(fp);
440 }
441#endif
442
443 PTCP_SEGMENT_HDR hdr = TCP_GET_SEGMENT_HDR(p);
444
445 bool isValidSeg = Validate_segment(s);
446
447 if (isValidSeg)
448 {
449 if (hdr->Rst)
450 process_rst_packet(s, p);
451 else if (hdr->Syn)
452 process_syn_packet(s, p);
453 else if (hdr->Ack)
454 process_ack_packet(s, p);
455 else
456 {
457 isContinue = process_segment_text(s, p);
458
459 if (isContinue && hdr->Fin)
460 process_fin_packet(s, p);
461 }
462 }
463 else
464 {
465 print_tcp_log("unacceptable segment");
466
467 if (!hdr->Rst)
468 send_ack(s,
469 pstruEventDetails->dEventTime,
470 s->tcb->SND.NXT,
471 s->tcb->RCV.NXT);
472
473 fn_NetSim_Packet_FreePacket(p);
474 pstruEventDetails->pPacket = NULL;
475 }
476}