fda1b2f9f3f2c208743098657dd3f8d6a3ad22a8
[tpg/acess2.git] / Modules / IPStack / arp.c
1 /*
2  * Acess2 IP Stack
3  * - Address Resolution Protocol
4  */
5 #define DEBUG   0
6 #include "ipstack.h"
7 #include "arp.h"
8 #include "link.h"
9
10 #define ARPv6   1
11 #define ARP_CACHE_SIZE  64
12 #define ARP_MAX_AGE             (60*60*1000)    // 1Hr
13
14 // === IMPORTS ===
15 extern tInterface       *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast);
16 #if ARPv6
17 extern tInterface       *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast);
18 #endif
19
20 // === PROTOTYPES ===
21  int    ARP_Initialise();
22 tMacAddr        ARP_Resolve4(tInterface *Interface, tIPv4 Address);
23 void    ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer);
24
25 // === GLOBALS ===
26 struct sARP_Cache4 {
27         tIPv4   IP;
28         tMacAddr        MAC;
29         Sint64  LastUpdate;
30         Sint64  LastUsed;
31 }       *gaARP_Cache4;
32  int    giARP_Cache4Space;
33 tMutex  glARP_Cache4;
34 #if ARPv6
35 struct sARP_Cache6 {
36         tIPv6   IP;
37         tMacAddr        MAC;
38         Sint64  LastUpdate;
39         Sint64  LastUsed;
40 }       *gaARP_Cache6;
41  int    giARP_Cache6Space;
42 tMutex  glARP_Cache6;
43 #endif
44  int    giARP_LastUpdateID = 0;
45
46 // === CODE ===
47 /**
48  * \fn int ARP_Initialise()
49  * \brief Initalise the ARP section
50  */
51 int ARP_Initialise()
52 {
53         gaARP_Cache4 = malloc( ARP_CACHE_SIZE * sizeof(struct sARP_Cache4) );
54         memset( gaARP_Cache4, 0, ARP_CACHE_SIZE * sizeof(struct sARP_Cache4) );
55         giARP_Cache4Space = ARP_CACHE_SIZE;
56         
57         #if ARPv6
58         gaARP_Cache6 = malloc( ARP_CACHE_SIZE * sizeof(struct sARP_Cache6) );
59         memset( gaARP_Cache6, 0, ARP_CACHE_SIZE * sizeof(struct sARP_Cache6) );
60         giARP_Cache6Space = ARP_CACHE_SIZE;
61         #endif
62         
63         Link_RegisterType(0x0806, ARP_int_GetPacket);
64         return 1;
65 }
66
67 /**
68  * \brief Resolves a MAC address from an IPv4 address
69  */
70 tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address)
71 {
72          int    lastID;
73          int    i;
74         struct sArpRequest4     req;
75         
76         ENTER("pInterface xAddress", Interface, Address);
77         
78         // Check routing tables
79         // Replace address with gateway if needed
80         
81         Mutex_Acquire( &glARP_Cache4 );
82         for( i = 0; i < giARP_Cache4Space; i++ )
83         {
84                 if(gaARP_Cache4[i].IP.L != Address.L)   continue;
85                 
86                 // Check if the entry needs to be refreshed
87                 if( now() - gaARP_Cache4[i].LastUpdate > ARP_MAX_AGE )  break;
88                 
89                 Mutex_Release( &glARP_Cache4 );
90                 LOG("Return %x:%x:%x:%x:%x:%x",
91                         gaARP_Cache4[i].MAC.B[0], gaARP_Cache4[i].MAC.B[1],
92                         gaARP_Cache4[i].MAC.B[2], gaARP_Cache4[i].MAC.B[3],
93                         gaARP_Cache4[i].MAC.B[4], gaARP_Cache4[i].MAC.B[5]
94                         );
95                 LEAVE('-');
96                 return gaARP_Cache4[i].MAC;
97         }
98         Mutex_Release( &glARP_Cache4 );
99         
100         lastID = giARP_LastUpdateID;
101         
102         // Create request
103         Log_Log("ARP4", "Asking for address %i.%i.%i.%i",
104                 Address.B[0], Address.B[1], Address.B[2], Address.B[3]
105                 );
106         req.HWType = htons(0x0001);     // Ethernet
107         req.Type   = htons(0x0800);
108         req.HWSize = 6;
109         req.SWSize = 4;
110         req.Request = htons(1);
111         req.SourceMac = Interface->Adapter->MacAddr;
112         req.SourceIP = *(tIPv4*)Interface->Address;
113         req.DestMac = cMAC_BROADCAST;
114         req.DestIP = Address;
115         
116         // Send Request
117         Link_SendPacket(Interface->Adapter, 0x0806, req.DestMac, sizeof(struct sArpRequest4), &req);
118         
119         // Wait for a reply
120         for(;;)
121         {
122                 while(lastID == giARP_LastUpdateID)     Threads_Yield();
123                 lastID = giARP_LastUpdateID;
124                 
125                 Mutex_Acquire( &glARP_Cache4 );
126                 for( i = 0; i < giARP_Cache4Space; i++ )
127                 {
128                         if(gaARP_Cache4[i].IP.L != Address.L)   continue;
129                         
130                         Mutex_Release( &glARP_Cache4 );
131                         return gaARP_Cache4[i].MAC;
132                 }
133                 Mutex_Release( &glARP_Cache4 );
134         }
135 }
136
137 /**
138  * \brief Updates the ARP Cache entry for an IPv4 Address
139  */
140 void ARP_UpdateCache4(tIPv4 SWAddr, tMacAddr HWAddr)
141 {
142          int    i;
143          int    free = -1;
144          int    oldest = 0;
145         
146         // Find an entry for the IP address in the cache
147         Mutex_Acquire(&glARP_Cache4);
148         for( i = giARP_Cache4Space; i--; )
149         {
150                 if(gaARP_Cache4[oldest].LastUpdate > gaARP_Cache4[i].LastUpdate) {
151                         oldest = i;
152                 }
153                 if( gaARP_Cache4[i].IP.L == SWAddr.L )  break;
154                 if( gaARP_Cache4[i].LastUpdate == 0 && free == -1 )     free = i;
155         }
156         // If there was no match, we need to make one
157         if(i == -1) {
158                 if(free != -1)
159                         i = free;
160                 else
161                         i = oldest;
162                 gaARP_Cache4[i].IP = SWAddr;
163         }
164         
165         Log_Log("ARP4", "Caching %i.%i.%i.%i (%02x:%02x:%02x:%02x:%02x:%02x) in %i",
166                 SWAddr.B[0], SWAddr.B[1], SWAddr.B[2], SWAddr.B[3],
167                 HWAddr.B[0], HWAddr.B[1], HWAddr.B[2], HWAddr.B[3], HWAddr.B[4], HWAddr.B[5],
168                 i
169                 );
170                 
171         gaARP_Cache4[i].MAC = HWAddr;
172         gaARP_Cache4[i].LastUpdate = now();
173         giARP_LastUpdateID ++;
174         Mutex_Release(&glARP_Cache4);
175 }
176
177 #if ARPv6
178 /**
179  * \brief Updates the ARP Cache entry for an IPv6 Address
180  */
181 void ARP_UpdateCache6(tIPv6 SWAddr, tMacAddr HWAddr)
182 {
183          int    i;
184          int    free = -1;
185          int    oldest = 0;
186         
187         // Find an entry for the MAC address in the cache
188         Mutex_Acquire(&glARP_Cache6);
189         for( i = giARP_Cache6Space; i--; )
190         {
191                 if(gaARP_Cache6[oldest].LastUpdate > gaARP_Cache6[i].LastUpdate) {
192                         oldest = i;
193                 }
194                 if( MAC_EQU(gaARP_Cache6[i].MAC, HWAddr) )      break;
195                 if( gaARP_Cache6[i].LastUpdate == 0 && free == -1 )     free = i;
196         }
197         // If there was no match, we need to make one
198         if(i == -1) {
199                 if(free != -1)
200                         i = free;
201                 else
202                         i = oldest;
203                 gaARP_Cache6[i].MAC = HWAddr;
204         }
205         
206         gaARP_Cache6[i].IP = SWAddr;
207         gaARP_Cache6[i].LastUpdate = now();
208         giARP_LastUpdateID ++;
209         Mutex_Release(&glARP_Cache6);
210 }
211 #endif
212
213 /**
214  * \fn void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
215  * \brief Called when an ARP packet is recieved
216  */
217 void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
218 {
219         tArpRequest4    *req4 = Buffer;
220         #if ARPv6
221         tArpRequest6    *req6 = Buffer;
222         #endif
223         tInterface      *iface;
224         
225         // Sanity Check Packet
226         if( Length < (int)sizeof(tArpRequest4) ) {
227                 Log_Log("ARP", "Recieved undersized packet");
228                 return ;
229         }
230         if( ntohs(req4->Type) != 0x0800 ) {
231                 Log_Log("ARP", "Recieved a packet with a bad type (0x%x)", ntohs(req4->Type));
232                 return ;
233         }
234         if( req4->HWSize != 6 ) {
235                 Log_Log("ARP", "Recieved a packet with HWSize != 6 (%i)", req4->HWSize);
236                 return;
237         }
238         #if ARP_DETECT_SPOOFS
239         if( !MAC_EQU(req4->SourceMac, From) ) {
240                 Log_Log("ARP", "ARP spoofing detected "
241                         "(%02x%02x:%02x%02x:%02x%02x != %02x%02x:%02x%02x:%02x%02x)",
242                         req4->SourceMac.B[0], req4->SourceMac.B[1], req4->SourceMac.B[2],
243                         req4->SourceMac.B[3], req4->SourceMac.B[4], req4->SourceMac.B[5],
244                         From.B[0], From.B[1], From.B[2],
245                         From.B[3], From.B[4], From.B[5]
246                         );
247                 return;
248         }
249         #endif
250         
251         Log_Debug("ARP", "Request ID %i", ntohs(req4->Request));
252         
253         switch( ntohs(req4->Request) )
254         {
255         case 1: // You want my IP?
256                 Log_Debug("ARP", "ARP Request Address class %i", req4->SWSize);
257                 // Check what type of IP it is
258                 switch( req4->SWSize )
259                 {
260                 case 4:
261                         Log_Debug("ARP", "From MAC %02x:%02x:%02x:%02x:%02x:%02x",
262                                 req4->SourceMac.B[0], req4->SourceMac.B[1],
263                                 req4->SourceMac.B[2], req4->SourceMac.B[3],
264                                 req4->SourceMac.B[4], req4->SourceMac.B[5]);
265                         //Log_Debug("ARP", "to MAC %02x:%02x:%02x:%02x:%02x:%02x",
266                         //      req4->DestMac.B[0], req4->DestMac.B[1],
267                         //      req4->DestMac.B[2], req4->DestMac.B[3],
268                         //      req4->DestMac.B[4], req4->DestMac.B[5]);
269                         Log_Debug("ARP", "ARP Request IPv4 Address %i.%i.%i.%i from %i.%i.%i.%i",
270                                 req4->DestIP.B[0], req4->DestIP.B[1], req4->DestIP.B[2],
271                                 req4->DestIP.B[3],
272                                 req4->SourceIP.B[0], req4->SourceIP.B[1],
273                                 req4->SourceIP.B[2], req4->SourceIP.B[3]);
274                         iface = IPv4_GetInterface(Adapter, req4->DestIP, 0);
275                         if( iface )
276                         {
277                                 Log_Debug("ARP", "Caching sender's IP Address");
278                                 ARP_UpdateCache4(req4->SourceIP, req4->SourceMac);
279                                 
280                                 req4->DestIP = req4->SourceIP;
281                                 req4->DestMac = req4->SourceMac;
282                                 req4->SourceIP = *(tIPv4*)iface->Address;;
283                                 req4->SourceMac = Adapter->MacAddr;
284                                 req4->Request = htons(2);
285                                 Log_Debug("ARP", "Sending back us (%02x:%02x:%02x:%02x:%02x:%02x)",
286                                         req4->SourceMac.B[0], req4->SourceMac.B[1],
287                                         req4->SourceMac.B[2], req4->SourceMac.B[3],
288                                         req4->SourceMac.B[4], req4->SourceMac.B[5]);
289                                 Link_SendPacket(Adapter, 0x0806, req4->DestMac, sizeof(tArpRequest4), req4);
290                         }
291                         break;
292                 #if ARPv6
293                 case 6:
294                         if( Length < (int)sizeof(tArpRequest6) ) {
295                                 Log_Log("ARP", "Recieved undersized packet (IPv6)");
296                                 return ;
297                         }
298                         Log_Debug("ARP", "ARP Request IPv6 Address %08x:%08x:%08x:%08x",
299                                 ntohl(req6->DestIP.L[0]), ntohl(req6->DestIP.L[1]),
300                                 ntohl(req6->DestIP.L[2]), ntohl(req6->DestIP.L[3])
301                                 );
302                         iface = IPv6_GetInterface(Adapter, req6->DestIP, 0);
303                         if( iface )
304                         {
305                                 req6->DestIP = req6->SourceIP;
306                                 req6->DestMac = req6->SourceMac;
307                                 req6->SourceIP = *(tIPv6*)iface->Address;
308                                 req6->SourceMac = Adapter->MacAddr;
309                                 req6->Request = htons(2);
310                                 Log_Debug("ARP", "Sending back us (%02x:%02x:%02x:%02x:%02x:%02x)",
311                                         req4->SourceMac.B[0], req4->SourceMac.B[1],
312                                         req4->SourceMac.B[2], req4->SourceMac.B[3],
313                                         req4->SourceMac.B[4], req4->SourceMac.B[5]);
314                                 Link_SendPacket(Adapter, 0x0806, req6->DestMac, sizeof(tArpRequest6), req6);
315                         }
316                         break;
317                 #endif
318                 default:
319                         Log_Debug("ARP", "Unknown Protocol Address size (%i)", req4->SWSize);
320                         return ;
321                 }
322                 
323                 break;
324         
325         case 2: // Ooh! A response!             
326                 // Check what type of IP it is
327                 switch( req4->SWSize )
328                 {
329                 case 4:
330                         ARP_UpdateCache4( req4->SourceIP, From );
331                         break;
332                 #if ARPv6
333                 case 6:
334                         if( Length < (int)sizeof(tArpRequest6) ) {
335                                 Log_Debug("ARP", "Recieved undersized packet (IPv6)");
336                                 return ;
337                         }
338                         ARP_UpdateCache6( req6->SourceIP, From );
339                         break;
340                 #endif
341                 default:
342                         Log_Debug("ARP", "Unknown Protocol Address size (%i)", req4->SWSize);
343                         return ;
344                 }
345                 
346                 break;
347         
348         default:
349                 Log_Warning("ARP", "Unknown Request ID %i", ntohs(req4->Request));
350                 break;
351         }
352 }

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