NetSim Source Code Help v14.4
All 13 Components
 
Loading...
Searching...
No Matches
ICMP.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 * Author: Shashi Kant Suman *
12 * *
13 * ---------------------------------------------------------------------------------*/
14
15/***********************************************************************
16
17Network Working Group J. Postel
18Request for Comments: 792 ISI
19 September 1981
20Updates: RFCs 777, 760
21Updates: IENs 109, 128
22
23 INTERNET CONTROL MESSAGE PROTOCOL
24
25 DARPA INTERNET PROGRAM
26 PROTOCOL SPECIFICATION
27
28*************************************************************************/
29#include "main.h"
30#include "List.h"
31#include "IP.h"
32#include "ICMP.h"
33
34typedef struct stru_ICMP_Data
35{
36 void(*callBack)(NetSim_PACKET*);
37 void* payload;
38}ICMPDATA, *ptrICMPDATA;
39_declspec(dllexport) NetSim_PACKET* fn_NetSim_IP_ICMP_GenerateEchoRequest(NETSIM_ID source,
40 NETSIM_ID dest,
41 NETSIM_IPAddress srcIP,
42 NETSIM_IPAddress destIP,
43 double time,
44 void* data,
45 unsigned int size,
46 unsigned int ttl,
47 void(*callback)(NetSim_PACKET*));
48/** This function is to initialize the ICMP parameters */
49_declspec(dllexport) int fn_NetSim_IP_ICMP_Init()
50{
51 NETSIM_ID i;
52 for(i=0;i<NETWORK->nDeviceCount;i++)
53 {
54 if(NETWORK->ppstruDeviceList[i]->pstruNetworkLayer)
55 {
56 IP_DEVVAR* devVar=NETWORK->ppstruDeviceList[i]->pstruNetworkLayer->ipVar;
57
58 if (!devVar->isICMP)
59 continue; //ICMP is not configured
60
61 if(devVar && devVar->nICMPPollingTime)
62 {
63 //Create timer event for poll
64 memset(pstruEventDetails,0,sizeof* pstruEventDetails);
65 pstruEventDetails->dEventTime = devVar->nICMPPollingTime*SECOND;
66 pstruEventDetails->nDeviceId = NETWORK->ppstruDeviceList[i]->nDeviceId;
67 pstruEventDetails->nDeviceType = NETWORK->ppstruDeviceList[i]->nDeviceType;
68 pstruEventDetails->nEventType = TIMER_EVENT;
69 pstruEventDetails->nProtocolId = NW_PROTOCOL_IPV4;
70 pstruEventDetails->nSubEventType = EVENT_ICMP_POLL;
71 fnpAddEvent(pstruEventDetails);
72 }
73 if(devVar && devVar->nRouterAdvertisementFlag)
74 {
75 //Create timer event for router advertisement
76 memset(pstruEventDetails,0,sizeof* pstruEventDetails);
77 pstruEventDetails->dEventTime = 0;
78 pstruEventDetails->nDeviceId = NETWORK->ppstruDeviceList[i]->nDeviceId;
79 pstruEventDetails->nDeviceType = NETWORK->ppstruDeviceList[i]->nDeviceType;
80 pstruEventDetails->nEventType = TIMER_EVENT;
81 pstruEventDetails->nProtocolId = NW_PROTOCOL_IPV4;
82 pstruEventDetails->nSubEventType = EVENT_ADVERTISE_ROUTER;
83 fnpAddEvent(pstruEventDetails);
84 }
85 }
86 }
87 return 1;
88}
89/**
90 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
91 Operations Manager uses a high-performance, asynchronous ICMP poller.
92 The ICMP poller performs at a consistent rate that is independent of poll response times.
93 Operations Manager achieves this using two asynchronous threads:
94 one that sends polls and one that receives polls. Because the send and receive threads
95 operate asynchronously, slow response times or excessive timeouts do not affect the polling rate.
96 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
97*/
98_declspec(dllexport) int fn_NetSim_IP_ICMP_POLL()
99{
100 unsigned int i;
101 double time=pstruEventDetails->dEventTime;
102 IP_DEVVAR* devVar=NETWORK->ppstruDeviceList[pstruEventDetails->nDeviceId-1]->pstruNetworkLayer->ipVar;
103 //Add the next ICMP poll event
104 pstruEventDetails->dEventTime += devVar->nICMPPollingTime*SECOND;
105 fnpAddEvent(pstruEventDetails);
106 for(i=0;i<devVar->nGatewayCount;i++)
107 {
108 NetSim_PACKET* packet;
109 if(devVar->nGatewayState[i] == GATEWAYSTATE_NOTIFICATION_PENDING)
110 devVar->nGatewayState[i] = GATEWAYSTATE_DOWN;
111 else if(devVar->nGatewayState[i] == GATEWAYSTATE_UP)
112 devVar->nGatewayState[i] = GATEWAYSTATE_NOTIFICATION_PENDING;
113 //Send ICMP echo request to gateway
114 packet = fn_NetSim_IP_ICMP_GenerateEchoRequest(pstruEventDetails->nDeviceId,
115 devVar->nGatewayId[i],
116 NETWORK->ppstruDeviceList[pstruEventDetails->nDeviceId - 1]->ppstruInterfaceList[devVar->nInterfaceId[i] - 1]->szAddress,
117 devVar->GatewayIPAddress[i],
118 pstruEventDetails->dEventTime,
119 NULL,
120 0,
121 1,
122 NULL);
123 //Generate Network out event to transmit
124 pstruEventDetails->dEventTime=time;
125 pstruEventDetails->dPacketSize = fnGetPacketSize(packet);
126 pstruEventDetails->nEventType = NETWORK_OUT_EVENT;
127 pstruEventDetails->nSubEventType = 0;
128 pstruEventDetails->pPacket = packet;
129 fnpAddEvent(pstruEventDetails);
130 }
131
132 return 1;
133}
134/** This function is used to generate echo request */
135_declspec(dllexport) NetSim_PACKET* fn_NetSim_IP_ICMP_GenerateEchoRequest(NETSIM_ID source,
136 NETSIM_ID dest,
137 NETSIM_IPAddress srcIP,
138 NETSIM_IPAddress destIP,
139 double time,
140 void* data,
141 unsigned int size,
142 unsigned int ttl,
143 void(*callback)(NetSim_PACKET*))
144{
145 static UINT64 seqNumber = 1;
146 ICMP_ECHO* echo = calloc(1, sizeof* echo);
147 NetSim_PACKET* packet = fn_NetSim_Packet_CreatePacket(NETWORK_LAYER);
148 add_dest_to_packet(packet, dest);
149 packet->nControlDataType = PACKET_ICMP_ECHORequest;
150 strcpy(packet->szPacketType, "ICMP_EchoRequest");
151 packet->nPacketId = 0;
152 packet->nPacketPriority = Priority_Low;
153 packet->nPacketType = PacketType_Control;
154 packet->nSourceId = source;
155 packet->pstruNetworkData->dArrivalTime = time;
156 packet->pstruNetworkData->dStartTime = time;
157 packet->pstruNetworkData->dEndTime = time;
158 packet->pstruNetworkData->dOverhead = 8;
159 packet->pstruNetworkData->dPayload = size;
160 packet->pstruNetworkData->dPacketSize = 8 + (double)size;
161 packet->pstruNetworkData->nNetworkProtocol = NW_PROTOCOL_IPV4;
162 packet->pstruNetworkData->nTTL = ttl + 1;
163 packet->pstruNetworkData->szDestIP = IP_COPY(destIP);
164 packet->pstruNetworkData->szSourceIP = IP_COPY(srcIP);
165 packet->pstruNetworkData->Packet_NetworkProtocol = echo;
166 packet->pstruNetworkData->IPProtocol = IPPROTOCOL_ICMP;
167 echo->Type = 8;
168 echo->SequenceNumber = (UINT16)(seqNumber);
169 seqNumber++;
170 if (data)
171 {
172 ptrICMPDATA ic = calloc(1, sizeof* ic);
173 ic->callBack = callback;
174 ic->payload = data;
175 echo->Data = ic;
176 }
177 return packet;
178}
179
180/// This function is to process the echo request.
181_declspec(dllexport) int fn_NetSim_IP_ICMP_EchoRequest()
182{
183 //generate echo reply packet
184 NetSim_PACKET* request = pstruEventDetails->pPacket;
185 NetSim_PACKET* reply = fn_NetSim_Packet_CreatePacket(NETWORK_LAYER);
186 ICMP_ECHO* echo = calloc(1,sizeof* echo);
187 reply->nControlDataType = PACKET_ICMP_ECHOReply;
188 strcpy(reply->szPacketType, "ICMP_EchoReply");
189 add_dest_to_packet(reply, request->nSourceId);
190 reply->nPacketType = PacketType_Control;
191 reply->nSourceId = pstruEventDetails->nDeviceId;
192 reply->pstruNetworkData->dArrivalTime = pstruEventDetails->dEventTime;
193 reply->pstruNetworkData->dEndTime = pstruEventDetails->dEventTime;
194 reply->pstruNetworkData->dOverhead = 8;
195 reply->pstruNetworkData->dPayload = request->pstruNetworkData->dPayload;
196 reply->pstruNetworkData->dPacketSize = 8+request->pstruNetworkData->dPayload;
197 reply->pstruNetworkData->dStartTime = pstruEventDetails->dEventTime;
198 reply->pstruNetworkData->nNetworkProtocol = NW_PROTOCOL_IPV4;
199 reply->pstruNetworkData->nTTL = 255;
200 reply->pstruNetworkData->Packet_NetworkProtocol = echo;
201 reply->pstruNetworkData->szDestIP=IP_COPY(request->pstruNetworkData->szSourceIP);
202 reply->pstruNetworkData->szSourceIP=IP_COPY(request->pstruNetworkData->szDestIP);
203 reply->pstruNetworkData->IPProtocol = IPPROTOCOL_ICMP;
204 echo->Type=0;
205 echo->Data = ((ICMP_ECHO*)request->pstruNetworkData->Packet_NetworkProtocol)->Data;
206 echo->SequenceNumber = ((ICMP_ECHO*)request->pstruNetworkData->Packet_NetworkProtocol)->SequenceNumber;
207 pstruEventDetails->pPacket=reply;
208 pstruEventDetails->nEventType = NETWORK_OUT_EVENT;
209 fnpAddEvent(pstruEventDetails);
210 //Free the request packet
211 fn_NetSim_Packet_FreePacket(request);
212 return 1;
213}
214
215/// The data received in the echo message must be returned in the echo reply message.
216_declspec(dllexport) int fn_NetSim_IP_ICMP_EchoReply()
217{
218 IP_DEVVAR* devVar = DEVICE_NWLAYER(pstruEventDetails->nDeviceId)->ipVar;
219 unsigned int i;
220 for(i=0;i<devVar->nGatewayCount;i++)
221 {
222 if(!IP_COMPARE(devVar->GatewayIPAddress[i],pstruEventDetails->pPacket->pstruNetworkData->szSourceIP))
223 {
224 devVar->nGatewayState[i] = GATEWAYSTATE_UP;
225 break;
226 }
227 }
228 ICMP_ECHO* echo = pstruEventDetails->pPacket->pstruNetworkData->Packet_NetworkProtocol;
229 if (echo->Data)
230 {
231 ptrICMPDATA ic = echo->Data;
232 if (ic->callBack)
233 ic->callBack(pstruEventDetails->pPacket);
234 }
235 //free the reply packet
236 fn_NetSim_Packet_FreePacket(pstruEventDetails->pPacket);
237 pstruEventDetails->pPacket = NULL;
238 return 1;
239}
240/** This function is to check the gateway state */
241_declspec(dllexport) int ICMP_CHECKSTATE(NETSIM_IPAddress ip)
242{
243 IP_DEVVAR* devVar = DEVICE_NWLAYER(pstruEventDetails->nDeviceId)->ipVar;
244 unsigned int i;
245 for(i=0;ip && i<devVar->nGatewayCount;i++)
246 if(!IP_COMPARE(devVar->GatewayIPAddress[i],ip))
247 {
248 if(devVar->nGatewayState[i] == GATEWAYSTATE_DOWN)
249 return 0;
250 break;
251 }
252 return 1;
253}
254unsigned long advertiseseed1=12345678;
255unsigned long advertiseseed2=23456789;
256/**
257 The ICMP router discovery messages are called "Router Advertisements"
258 and "Router Solicitations". Each router periodically multicasts a
259 Router Advertisement from each of its multicast interfaces,
260 announcing the IP address(es) of that interface. Hosts discover the
261 addresses of their neighboring routers simply by listening for
262 advertisements. When a host attached to a multicast link starts up,
263 it may multicast a Router Solicitation to ask for immediate
264 advertisements, rather than waiting for the next periodic ones to
265 arrive; if (and only if) no advertisements are forthcoming, the host
266 may retransmit the solicitation a small number of times, but then
267 must desist from sending any more solicitations. Any routers that
268 subsequently start up, or that were not discovered because of packet
269 loss or temporary link partitioning, are eventually discovered by
270 reception of their periodic (unsolicited) advertisements. (Links
271 that suffer high packet loss rates or frequent partitioning are
272 accommodated by increasing the rate of advertisements, rather than
273 increasing the number of solicitations that hosts are permitted to
274 send.)
275 */
276_declspec(dllexport) int fn_NetSim_IP_ICMP_AdvertiseRouter()
277{
278 ICMP_RouterAdvertisement* adver=calloc(1,sizeof* adver);
279 double time=pstruEventDetails->dEventTime;
280 NetSim_PACKET* packet;
281 NETSIM_ID nDeviceId=pstruEventDetails->nDeviceId;
282 NETSIM_ID i;
283 IP_DEVVAR* devVar = DEVICE_NWLAYER(nDeviceId)->ipVar;
284 //Add next event for router advertisement
285 pstruEventDetails->dEventTime += (fn_NetSim_Utilities_GenerateRandomNo(&advertiseseed1,&advertiseseed2)/NETSIM_RAND_MAX*(devVar->nRouterAdverMaxInterval-devVar->nRouterAdverMinInterval)+devVar->nRouterAdverMinInterval)*SECOND;
286 fnpAddEvent(pstruEventDetails);
287 //Generate router advertisement
288 packet = fn_NetSim_Packet_CreatePacket(NETWORK_LAYER);
289 packet->dEventTime = time;
290 packet->nControlDataType = PACKET_ROUTER_ADVERTISEMENT;
291 strcpy(packet->szPacketType, "ICMP_RouterAdvertisement");
292 add_dest_to_packet(packet, 0);
293 packet->nPacketType = PacketType_Control;
294 packet->nReceiverId=0;
295 packet->nSourceId=pstruEventDetails->nDeviceId;
296 packet->nTransmitterId=pstruEventDetails->nDeviceId;
297 packet->pstruNetworkData->dArrivalTime =time;
298 packet->pstruNetworkData->dEndTime=time;
299 packet->pstruNetworkData->dStartTime=time;
300 packet->pstruNetworkData->dOverhead=16;
301 packet->pstruNetworkData->dPacketSize=16;
302 packet->pstruNetworkData->dPayload=0;
303 packet->pstruNetworkData->nNetworkProtocol=NW_PROTOCOL_IPV4;
304 packet->pstruNetworkData->nTTL=2;
305 packet->pstruNetworkData->szDestIP=STR_TO_IP4("255.255.255.255");
306 packet->pstruNetworkData->Packet_NetworkProtocol=adver;
307 packet->pstruNetworkData->IPProtocol = IPPROTOCOL_ICMP;
308 adver->Type=9;
309 adver->AddrEntrySize=2;
310 adver->Lifetime = devVar->nRouterAdverLifeTime;
311 //count the num of address
312 for(i=0;i<NETWORK->ppstruDeviceList[nDeviceId-1]->nNumOfInterface;i++)
313 {
314 if(NETWORK->ppstruDeviceList[nDeviceId-1]->ppstruInterfaceList[i])
315 {
316 if(NETWORK->ppstruDeviceList[nDeviceId-1]->ppstruInterfaceList[i]->nInterfaceType && (NETWORK->ppstruDeviceList[nDeviceId-1]->ppstruInterfaceList[i]->nInterfaceType != INTERFACE_WAN_ROUTER && NETWORK->ppstruDeviceList[nDeviceId-1]->ppstruInterfaceList[i]->nInterfaceType != INTERFACE_VIRTUAL))
317 {
318 adver->NumAddrs++;
319 adver->RouterAddress = realloc(adver->RouterAddress,(sizeof* adver->RouterAddress)*adver->NumAddrs);
320 adver->RouterAddress[adver->NumAddrs-1] = IP_COPY(DEVICE_NWADDRESS(nDeviceId,i+1));
321 }
322 }
323 }
324 for(i=0;i<NETWORK->ppstruDeviceList[nDeviceId-1]->nNumOfInterface;i++)
325 {
326 if(NETWORK->ppstruDeviceList[nDeviceId-1]->ppstruInterfaceList[i])
327 {
328 if(NETWORK->ppstruDeviceList[nDeviceId-1]->ppstruInterfaceList[i]->nInterfaceType && (NETWORK->ppstruDeviceList[nDeviceId-1]->ppstruInterfaceList[i]->nInterfaceType != INTERFACE_WAN_ROUTER && NETWORK->ppstruDeviceList[nDeviceId-1]->ppstruInterfaceList[i]->nInterfaceType != INTERFACE_VIRTUAL))
329 {
330 NetSim_PACKET* temp=fn_NetSim_Packet_CopyPacket(packet);
331 //Create network out event to transmit
332 temp->pstruNetworkData->szGatewayIP = IP_COPY(DEVICE_NWADDRESS(nDeviceId,i+1));
333 temp->pstruNetworkData->szSourceIP = IP_COPY(DEVICE_NWADDRESS(nDeviceId,i+1));
334 temp->pstruNetworkData->szNextHopIp = temp->pstruNetworkData->szDestIP;
335 pstruEventDetails->dEventTime=time;
336 pstruEventDetails->nInterfaceId=i+1;
337 pstruEventDetails->dPacketSize=16;
338 pstruEventDetails->nEventType=NETWORK_OUT_EVENT;
339 pstruEventDetails->nSubEventType=0;
340 pstruEventDetails->pPacket=temp;
341 fnpAddEvent(pstruEventDetails);
342 }
343 }
344 }
345 return 1;
346}
347/**
348 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
349 The router discovery messages do not constitute a routing protocol:
350 they enable hosts to discover the existence of neighboring routers,
351 but not which router is best to reach a particular destination. If a
352 host chooses a poor first-hop router for a particular destination, it
353 should receive an ICMP Redirect from that router, identifying a
354 better one.
355 A Router Advertisement includes a "preference level" for each
356 advertised router address. When a host must choose a default router
357 address (i.e., when, for a particular destination, the host has not
358 been redirected or configured to use a specific router address), it
359 is expected to choose from those router addresses that have the
360 highest preference level.
361 A Router Advertisement also includes a "lifetime" field, specifying
362 the maximum length of time that the advertised addresses are to be
363 considered as valid router addresses by hosts, in the absence of
364 further advertisements. This is used to ensure that hosts eventually
365 forget about routers that fail, become unreachable, or stop acting as
366 routers.
367 The default advertising rate is once every 7 to 10 minutes, and the
368 default lifetime is 30 minutes.
369 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
370*/
371_declspec(dllexport) int fn_NetSim_IP_ICMP_ProcessRouterAdvertisement()
372{
373 int flag=0;
374 NETSIM_ID nDeviceId=pstruEventDetails->nDeviceId;
375 ptrIP_ROUTINGTABLE table = IP_TABLE_GET(nDeviceId);
376 NetSim_PACKET* packet = pstruEventDetails->pPacket;
377 ICMP_RouterAdvertisement* adver=PACKET_NWPROTOCOLDATA(packet);
378 //Get the source IP
379 NETSIM_IPAddress src=PACKET_NWDATA(packet)->szSourceIP;
380 NETSIM_IPAddress ip=STR_TO_IP4("0.0.0.0");
381 while(table)
382 {
383 if(table->gateway)
384 if(!IP_COMPARE(src,table->gateway) && !IP_COMPARE(table->networkDestination,ip) && !IP_COMPARE(table->netMask,ip))
385 {
386 //entry found
387 flag=1;
388 break;
389 }
390 table=LIST_NEXT(table);
391 }
392 if(!table)
393 {
394 //Create new entry
395 iptable_add(IP_WRAPPER_GET(nDeviceId),
396 ip, ip, 0, src, 1, &DEVICE_NWADDRESS(nDeviceId, pstruEventDetails->nInterfaceId),
397 &pstruEventDetails->nInterfaceId, DEFAULT_METRIC, "ICMP");
398
399 }
400 fn_NetSim_Packet_FreePacket(packet);
401 pstruEventDetails->pPacket = NULL;
402 return 1;
403}
404/**
405 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
406 If, according to the information in the gateway's routing tables,
407 the network specified in the internet destination field of a
408 datagram is unreachable, e.g., the distance to the network is
409 infinity, the gateway sends a destination unreachable message to
410 the internet source host of the datagram. In addition, in some
411 networks, the gateway may be able to determine if the internet
412 destination host is unreachable. Gateways in these networks may
413 send destination unreachable messages to the source host when the
414 destination host is unreachable.
415
416 If, in the destination host, the IP module cannot deliver the
417 datagram because the indicated protocol module or process port is
418 not active, the destination host may send a destination
419 unreachable message to the source host.
420
421 Another case is when a datagram must be fragmented to be forwarded
422 by a gateway yet the Don't Fragment flag is on. In this case the
423 gateway must discard the datagram and return a destination
424 unreachable message.
425 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
426*/
427_declspec(dllexport) int fn_NetSim_IP_ICMP_GenerateDstUnreachableMsg()
428{
429 NetSim_PACKET* orgPacket=pstruEventDetails->pPacket;
430 if (isMulticastPacket(orgPacket))
431 return -1;
432
433 NetSim_PACKET* packet = fn_NetSim_Packet_CreatePacket(NETWORK_LAYER);
434 ICMP_DestinationUnreachableMessage* message=calloc(1,sizeof* message);
435 message->Type=3;
436 message->code=1;//host unreachable
437 message->InternetHeader=orgPacket;
438 packet->pstruNetworkData->szDestIP = IP_COPY(orgPacket->pstruNetworkData->szSourceIP);
439 packet->nControlDataType = PACKET_ICMP_DstUnreachableMsg;
440 strcpy(packet->szPacketType, "ICMP_DstUnreachableMsg");
441 add_dest_to_packet(packet, orgPacket->nSourceId);
442 packet->nPacketType=PacketType_Control;
443 packet->nSourceId=pstruEventDetails->nDeviceId;
444 packet->nTransmitterId=pstruEventDetails->nDeviceId;
445 packet->pstruNetworkData->dArrivalTime=pstruEventDetails->dEventTime;
446 packet->pstruNetworkData->dEndTime=pstruEventDetails->dEventTime;
447 packet->pstruNetworkData->dStartTime=pstruEventDetails->dEventTime;
448 packet->pstruNetworkData->dOverhead=24+IPV4_HEADER_SIZE;
449 packet->pstruNetworkData->dPacketSize=24+IPV4_HEADER_SIZE;
450 packet->pstruNetworkData->dPayload=0;
451 packet->pstruNetworkData->nNetworkProtocol=NW_PROTOCOL_IPV4;
452 packet->pstruNetworkData->nTTL=255;
453 packet->pstruNetworkData->Packet_NetworkProtocol=message;
454 packet->pstruNetworkData->szSourceIP=fn_NetSim_Stack_GetFirstIPAddressAsId(pstruEventDetails->nDeviceId,0);
455 // Added by PV on 11-11-20 to resolve ICMP related issue 3495
456 packet->pstruNetworkData->szGatewayIP = IP_COPY(DEVICE_NWADDRESS(pstruEventDetails->nDeviceId,
457 pstruEventDetails->nInterfaceId));
458 // End
459 packet->pstruNetworkData->IPProtocol = IPPROTOCOL_ICMP;
460
461 //Add the network in event
462 pstruEventDetails->dPacketSize=24+IPV4_HEADER_SIZE;
463 pstruEventDetails->nApplicationId=0;
464 pstruEventDetails->nEventType=NETWORK_IN_EVENT;
465 pstruEventDetails->nInterfaceId=1;
466 pstruEventDetails->nPacketId=0;
467 pstruEventDetails->nProtocolId=NW_PROTOCOL_IPV4;
468 pstruEventDetails->nSegmentId=0;
469 pstruEventDetails->nSubEventType=0;
470 pstruEventDetails->pPacket=packet;
471 fnpAddEvent(pstruEventDetails);
472 return 1;
473}
474/**
475 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
476 If, according to the information in the gateway's routing tables,
477 the network specified in the internet destination field of a
478 datagram is unreachable, e.g., the distance to the network is
479 infinity, the gateway sends a destination unreachable message to
480 the internet source host of the datagram. In addition, in some
481 networks, the gateway may be able to determine if the internet
482 destination host is unreachable. Gateways in these networks may
483 send destination unreachable messages to the source host when the
484 destination host is unreachable.
485
486 If, in the destination host, the IP module cannot deliver the
487 datagram because the indicated protocol module or process port is
488 not active, the destination host may send a destination
489 unreachable message to the source host.
490
491 Another case is when a datagram must be fragmented to be forwarded
492 by a gateway yet the Don't Fragment flag is on. In this case the
493 gateway must discard the datagram and return a destination
494 unreachable message.
495 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
496*/
497_declspec(dllexport) int fn_NetSim_IP_ICMP_ProcessDestUnreachableMsg()
498{
499 NetSim_PACKET* packet = pstruEventDetails->pPacket;
500 ICMP_DestinationUnreachableMessage* message=packet->pstruNetworkData->Packet_NetworkProtocol;
501
502 NetSim_PACKET* p = message->InternetHeader;
503 iptable_delete(IP_WRAPPER_GET(pstruEventDetails->nDeviceId),
504 p->pstruNetworkData->szDestIP, p->pstruNetworkData->szSourceIP,NULL);
505
506 fn_NetSim_Stack_CallICMPErrorFun(message->InternetHeader,pstruEventDetails->nDeviceId,3);
507 if(get_first_dest_from_packet(pstruEventDetails->pPacket) == pstruEventDetails->nDeviceId)
508 {
509 NetSim_PACKET* p=message->InternetHeader;
510 pstruEventDetails->pPacket=NULL;
511 fn_NetSim_Packet_FreePacket(p);
512 free(message);
513 fn_NetSim_Packet_FreePacket(packet);
514 }
515 return 0;
516}
517
518void ICMP_copyPacket(NetSim_PACKET* d, NetSim_PACKET* s)
519{
520 switch(s->nControlDataType)
521 {
522 case PACKET_ICMP_DstUnreachableMsg:
523 {
524 ICMP_DestinationUnreachableMessage* sm=(ICMP_DestinationUnreachableMessage*)s->pstruNetworkData->Packet_NetworkProtocol;
525 ICMP_DestinationUnreachableMessage* dm = (ICMP_DestinationUnreachableMessage*)calloc(1,sizeof* dm);
526 memcpy(dm,sm,sizeof* dm);
527 d->pstruNetworkData->Packet_NetworkProtocol=dm;
528 }
529 break;
530 }
531}
532
533void process_icmp_packet()
534{
535 NETSIM_ID d = pstruEventDetails->nDeviceId;
536 NetSim_PACKET* packet = pstruEventDetails->pPacket;
537 IP_DEVVAR* ipVar = GET_IP_DEVVAR(d);
538 if (ipVar && !ipVar->isICMP)
539 {
540 fnNetSimError("ICMP packet %d is arrives to device %d from device %d.\n ICMP is not configured in this device.\n",
541 packet->nControlDataType,
542 d,
543 packet->nSourceId);
544 return;
545 }
546
547 switch (packet->nControlDataType)
548 {
549 case PACKET_ICMP_ECHORequest:
550 fn_NetSim_IP_ICMP_EchoRequest();
551 break;
552 case PACKET_ICMP_ECHOReply:
553 fn_NetSim_IP_ICMP_EchoReply();
554 break;
555 case PACKET_ROUTER_ADVERTISEMENT:
556 fn_NetSim_IP_ICMP_ProcessRouterAdvertisement();
557 break;
558 case PACKET_ICMP_DstUnreachableMsg:
559 fn_NetSim_IP_ICMP_ProcessDestUnreachableMsg();
560 break;
561 default:
562 fnNetSimError("Unknown ICMP packet %d in %s\n",
563 packet->nControlDataType,
564 __FUNCTION__);
565 break;
566 }
567}
568
569typedef struct stru_pingHandle
570{
571 NETSIM_ID src;
572 NETSIM_ID dest;
573 NETSIM_IPAddress srcIP;
574 NETSIM_IPAddress destIP;
575 UINT count;
576 bool(*ResponseHandler)(void* arg, char* msg, bool isMore);
577 double echoSendTime;
578 UINT currentCount;
579 UINT replyRecvCount;
580 UINT retryCount;
581 UINT16 seqNumber;
582 void* arg;
583}PINGHANDLER, *ptrPINGHANDLER;
584
585void IP_find_best_IP(NETSIM_ID s, NETSIM_ID d,
586 NETSIM_IPAddress* sIP,
587 NETSIM_IPAddress* dIP)
588{
589 int prev = 0;
590 NETSIM_ID si;
591 NETSIM_ID di;
592
593 *sIP = DEVICE_NWADDRESS(s, 1);
594 *dIP = DEVICE_NWADDRESS(d, 1);
595
596 for (si = 1; si <= DEVICE(s)->nNumOfInterface; si++)
597 {
598 NETSIM_IPAddress sip = DEVICE_NWADDRESS(s, si);
599 if (DEVICE_INTERFACE(s, si)->nInterfaceType == INTERFACE_WAN_ROUTER)
600 *sIP = sip;
601 for (di = 1; di <= DEVICE(d)->nNumOfInterface; di++)
602 {
603 NETSIM_IPAddress dip = DEVICE_NWADDRESS(d, di);
604 if (DEVICE_INTERFACE(d, di)->nInterfaceType == INTERFACE_WAN_ROUTER)
605 *dIP = dip;
606 NETSIM_IPAddress dnw = IP_NETWORK_ADDRESS_IPV4(dip, DEVICE_SUBNETMASK(d, di));
607 NETSIM_IPAddress snw = IP_NETWORK_ADDRESS_IPV4(sip, DEVICE_SUBNETMASK(s, si));
608 if (!IP_COMPARE4(dnw, snw))
609 {
610 *sIP = sip;
611 *dIP = dip;
612 return;
613 }
614 }
615 }
616}
617
618void replyRecevied(NetSim_PACKET* packet)
619{
620 ICMP_ECHO* echo = packet->pstruNetworkData->Packet_NetworkProtocol;
621 ptrICMPDATA data = echo->Data;
622 ptrPINGHANDLER ping = data->payload;
623 if (echo->SequenceNumber == ping->seqNumber)
624 {
625 ping->replyRecvCount++;
626 ping->retryCount = 0;
627 char msg[BUFSIZ];
628 sprintf(msg, "Reply from %s: bytes %d time=%dus TTL=%d\n",
629 packet->pstruNetworkData->szSourceIP->str_ip,
630 (int)packet->pstruNetworkData->dPayload,
631 (int)(pstruEventDetails->dEventTime - ping->echoSendTime),
632 MAX_TTL);
633 ping->ResponseHandler(ping->arg, msg, ping->count != ping->currentCount);
634 }
635}
636
637_declspec(dllexport) void* ICMP_StartPingRequest(NETSIM_ID src,
638 NETSIM_ID dest,
639 UINT count,
640 bool(*resp)(void*, char*, bool),
641 void* arg)
642{
643 ptrPINGHANDLER handle = calloc(1, sizeof* handle);
644 handle->count = count;
645 handle->dest = dest;
646 handle->ResponseHandler = resp;
647 handle->src = src;
648 handle->arg = arg;
649 IP_find_best_IP(src,
650 dest,
651 &handle->srcIP,
652 &handle->destIP);
653
654 //Start timer event to send ping
655 NetSim_EVENTDETAILS pevent;
656 memset(&pevent, 0, sizeof pevent);
657 pevent.dEventTime = ldEventTime + 1000;
658 pevent.nDeviceId = src;
659 pevent.nDeviceType = DEVICE_TYPE(src);
660 pevent.nEventType = TIMER_EVENT;
661 pevent.nProtocolId = NW_PROTOCOL_IPV4;
662 pevent.nSubEventType = EVENT_ICMP_SEND_ECHO;
663 pevent.szOtherDetails = handle;
664 fnpAddEvent(&pevent);
665 return handle;
666}
667
668void icmp_send_echo_request()
669{
670 ptrPINGHANDLER handle = pstruEventDetails->szOtherDetails;
671 if (handle->currentCount == handle->replyRecvCount)
672 goto SEND_ECHO_REQUEST;
673 else
674 {
675 if (handle->retryCount == ICMP_MAX_RETRY)
676 {
677 handle->seqNumber = 0;
678 handle->replyRecvCount++;
679 handle->ResponseHandler(handle->arg, "Request timed out!\n", handle->count != handle->currentCount);
680 if (handle->currentCount != handle->count)
681 goto SEND_ECHO_REQUEST;
682 else
683 return;
684 }
685 else
686 {
687 handle->retryCount++;
688 goto ADD_NEXT_SEND_REQUEST;
689 }
690 }
691
692SEND_ECHO_REQUEST:
693 if (handle->currentCount != handle->count)
694 {
695 handle->retryCount = 0;
696 handle->currentCount++;
697 handle->echoSendTime = pstruEventDetails->dEventTime;
698 NetSim_PACKET* packet = fn_NetSim_IP_ICMP_GenerateEchoRequest(handle->src,
699 handle->dest,
700 handle->srcIP,
701 handle->destIP,
702 pstruEventDetails->dEventTime,
703 handle,
704 32,
705 MAX_TTL - 1,
706 replyRecevied);
707 handle->seqNumber = ((ICMP_ECHO*)(packet->pstruNetworkData->Packet_NetworkProtocol))->SequenceNumber;
708
709 NetSim_EVENTDETAILS pevent;
710 memset(&pevent, 0, sizeof pevent);
711 pevent.dEventTime = pstruEventDetails->dEventTime;
712 pevent.dPacketSize = fnGetPacketSize(packet);
713 pevent.nDeviceId = pstruEventDetails->nDeviceId;
714 pevent.nDeviceType = pstruEventDetails->nDeviceType;
715 pevent.nEventType = NETWORK_OUT_EVENT;
716 pevent.nProtocolId = NW_PROTOCOL_IPV4;
717 pevent.pPacket = packet;
718 fnpAddEvent(&pevent);
719 }
720
721ADD_NEXT_SEND_REQUEST:
722 //Add next send event
723 if (handle->currentCount != handle->count + 2)
724 {
725 pstruEventDetails->dEventTime += ICMP_SEND_TIME;
726 fnpAddEvent(pstruEventDetails);
727 }
728}
unsigned short int SequenceNumber
If code = 0, a sequence number to aid in matching echos and replies, may be zero.
Definition ICMP.h:123