Fixed and improved Ping support
[tpg/acess2.git] / Modules / IPStack / icmp.c
1 /*
2  * Acess2 IP Stack
3  * - ICMP Handling
4  */
5 #include "ipstack.h"
6 #include "ipv4.h"
7 #include "icmp.h"
8
9 // === CONSTANTS ===
10 #define PING_SLOTS      64
11
12 // === PROTOTYPES ===
13 void    ICMP_Initialise();
14 void    ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
15
16 // === GLOBALS ===
17 struct {
18         tInterface      *Interface;
19          int    bArrived;
20 }       gICMP_PingSlots[PING_SLOTS];
21
22 // === CODE ===
23 /**
24  * \fn void ICMP_Initialise()
25  * \brief Initialise the ICMP Layer
26  */
27 void ICMP_Initialise()
28 {
29         IPv4_RegisterCallback(IP4PROT_ICMP, ICMP_GetPacket);
30 }
31
32 /**
33  * \fn void ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
34  * \brief Handles a packet from the IP Layer
35  */
36 void ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
37 {
38         tICMPHeader     *hdr = Buffer;
39         
40         Log("[ICMP ] Length = %i", Length);
41         Log("[ICMP ] hdr->Type = %i", hdr->Type);
42         Log("[ICMP ] hdr->Code = %i", hdr->Code);
43         Log("[ICMP ] hdr->Checksum = 0x%x", ntohs(hdr->Checksum));
44         Log("[ICMP ] hdr->ID = 0x%x", ntohs(hdr->ID));
45         Log("[ICMP ] hdr->Sequence = 0x%x", ntohs(hdr->Sequence));
46         
47         switch(hdr->Type)
48         {
49         // -- 0: Echo Reply
50         case ICMP_ECHOREPLY:
51                 if(hdr->Code != 0) {
52                         Warning("[ICMP ] Code == %i for ICMP Echo Reply, should be 0", hdr->Code);
53                         return ;
54                 }
55                 if(hdr->ID != (Uint16)~hdr->Sequence) {
56                         Warning("[ICMP ] ID and Sequence values do not match");
57                         return ;
58                 }
59                 gICMP_PingSlots[hdr->ID].bArrived = 1;
60                 break;
61         
62         // -- 8: Echo Request
63         case ICMP_ECHOREQ:
64                 if(hdr->Code != 0) {
65                         Warning("[ICMP ] Code == %i for ICMP Echo Request, should be 0", hdr->Code);
66                         return ;
67                 }
68                 Log("[ICMP ] Replying");
69                 hdr->Type = ICMP_ECHOREPLY;
70                 hdr->Checksum = 0;
71                 hdr->Checksum = htons( IPv4_Checksum(hdr, Length) );
72                 Log("[ICMP ] Checksum = 0x%04x", hdr->Checksum);
73                 IPv4_SendPacket(Interface, *(tIPv4*)Address, 1, ntohs(hdr->Sequence), Length, hdr);
74                 break;
75         }
76         
77 }
78
79 /**
80  * \brief Sends ICMP Echo and waits for the reply
81  * \note Times out after \a Interface->TimeoutDelay has elapsed
82  */
83 int ICMP_Ping(tInterface *Interface, tIPv4 Addr)
84 {
85         Sint64  ts;
86         Sint64  end;
87         char    buf[32] = "\x8\0\0\0\0\0\0\0Acess2 I"
88                       "P/TCP Stack 1.0\0";
89         tICMPHeader     *hdr = (void*)buf;
90          int    i;
91         
92         for(;;)
93         {
94                 for(i=0;i<PING_SLOTS;i++)
95                 {
96                         if(gICMP_PingSlots[i].Interface == NULL)        break;
97                 }
98                 if(gICMP_PingSlots[i].Interface == NULL)        break;
99                 Threads_Yield();
100         }
101         gICMP_PingSlots[i].Interface = Interface;
102         gICMP_PingSlots[i].bArrived = 0;
103         hdr->ID = i;
104         hdr->Sequence = ~i;
105         hdr->Checksum = htons( IPv4_Checksum(hdr, sizeof(buf)) );
106         IPv4_SendPacket(Interface, Addr, 1, i, sizeof(buf), buf);
107         
108         ts = now();
109         end = ts + Interface->TimeoutDelay;
110         while( !gICMP_PingSlots[i].bArrived && now() < end)     Threads_Yield();
111         
112         ts = now() - ts;
113         if(ts > Interface->TimeoutDelay)
114                 return -1;
115         
116         return (int)ts;
117 }

UCC git Repository :: git.ucc.asn.au