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

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