Multi-user testing and bugfixing
[tpg/acess2.git] / Modules / IPStack / arp.c
1 /*
2  * Acess2 IP Stack
3  * - Address Resolution Protocol
4  */
5 #include "ipstack.h"
6 #include "arp.h"
7 #include "link.h"
8
9 #define ARP_CACHE_SIZE  64
10 #define ARP_MAX_AGE             (60*60*1000)    // 1Hr
11
12 // === IMPORTS ===
13 extern tInterface       *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast);
14 extern tInterface       *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast);
15
16 // === PROTOTYPES ===
17  int    ARP_Initialise();
18  int    ARP_int_Resolve4(tInterface *Interface, tIPv4 Address);
19 void    ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer);
20
21 // === GLOBALS ===
22 struct sARP_Cache {
23         tMacAddr        MAC;
24         tIPv4   IP4;
25         tIPv6   IP6;
26         Sint64  LastUpdate;
27         Sint64  LastUsed;
28 }       *gaARP_Cache;
29  int    giARP_CacheSpace;
30  int    giARP_LastUpdateID = 0;
31 tSpinlock       glARP_Cache;
32
33 // === CODE ===
34 /**
35  * \fn int ARP_Initialise()
36  * \brief Initalise the ARP section
37  */
38 int ARP_Initialise()
39 {
40         gaARP_Cache = malloc( ARP_CACHE_SIZE * sizeof(*gaARP_Cache) );
41         memset( gaARP_Cache, 0, ARP_CACHE_SIZE * sizeof(*gaARP_Cache) );
42         giARP_CacheSpace = ARP_CACHE_SIZE;
43         
44         Link_RegisterType(0x0806, ARP_int_GetPacket);
45         return 1;
46 }
47
48 /**
49  * \brief Resolves a MAC address from an IPv4 address
50  */
51 tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address)
52 {
53          int    lastID;
54          int    i;
55         
56         LOCK( &glARP_Cache );
57         for( i = 0; i < giARP_CacheSpace; i++ )
58         {
59                 if(gaARP_Cache[i].IP4.L != Address.L)   continue;
60                 
61                 // Check if the entry needs to be refreshed
62                 if( now() - gaARP_Cache[i].LastUpdate > ARP_MAX_AGE )   break;
63                 
64                 RELEASE( &glARP_Cache );
65                 return gaARP_Cache[i].MAC;
66         }
67         RELEASE( &glARP_Cache );
68         
69         lastID = giARP_LastUpdateID;
70         ARP_int_Resolve4(Interface, Address);
71         for(;;)
72         {
73                 while(lastID == giARP_LastUpdateID)     Threads_Yield();
74                 
75                 LOCK( &glARP_Cache );
76                 for( i = 0; i < giARP_CacheSpace; i++ )
77                 {
78                         if(gaARP_Cache[i].IP4.L != Address.L)   continue;
79                         
80                         RELEASE( &glARP_Cache );
81                         return gaARP_Cache[i].MAC;
82                 }
83                 RELEASE( &glARP_Cache );
84         }
85 }
86
87 /**
88  * \fn int ARP_int_Resolve4(tInterface *Interface, tIPv4 Address)
89  * \brief Request the network to resolve an IPv4 Address
90  * \return Boolean Success
91  */
92 int ARP_int_Resolve4(tInterface *Interface, tIPv4 Address)
93 {
94         struct sArpRequest4     req;
95         
96         req.HWType = htons(0x100);      // Ethernet
97         req.Type   = htons(0x0800);
98         req.HWSize = 6;
99         req.SWSize = 4;
100         req.Request = htons(1);
101         req.SourceMac = Interface->Adapter->MacAddr;
102         req.SourceIP = Interface->IP4.Address;
103         req.DestMac = cMAC_BROADCAST;
104         req.DestIP = Address;
105         
106         Link_SendPacket(Interface->Adapter, 0x0806, req.DestMac, sizeof(struct sArpRequest4), &req);
107         
108         return 0;
109 }
110
111 /**
112  * \fn void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
113  * \brief Called when an ARP packet is recieved
114  */
115 void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
116 {
117          int    i, free = -1;
118          int    oldest = 0;
119         tArpRequest4    *req4 = Buffer;
120         tArpRequest6    *req6 = Buffer;
121         tInterface      *iface;
122         
123         // Sanity Check Packet
124         if( Length < sizeof(tArpRequest4) ) {
125                 Log("[ARP  ] Recieved undersized packet");
126                 return ;
127         }
128         if( ntohs(req4->Type) != 0x0800 ) {
129                 Log("[ARP  ] Recieved a packet with a bad type 0x%x", ntohs(req4->Type));
130                 return ;
131         }
132         if( req4->HWSize != 6 ) {
133                 Log("[ARP  ] Recieved a packet with HWSize != 6 (%i)", req4->HWSize);
134                 return;
135         }
136         if( !MAC_EQU(req4->SourceMac, From) ) {
137                 Log("[ARP  ] ARP spoofing detected", req4->HWSize);
138                 return;
139         }
140         
141         Log("[ARP  ] Request ID %i", ntohs(req4->Request));
142         
143         switch( ntohs(req4->Request) )
144         {
145         case 1: // You want my IP?
146                 Log("[ARP  ] ARP Request Address class %i", req4->SWSize);
147                 // Check what type of IP it is
148                 switch( req4->SWSize )
149                 {
150                 case 4:
151                         Log("[ARP  ] From MAC %02x:%02x:%02x:%02x:%02x:%02x",
152                                 req4->SourceMac.B[0], req4->SourceMac.B[1],
153                                 req4->SourceMac.B[2], req4->SourceMac.B[3],
154                                 req4->SourceMac.B[4], req4->SourceMac.B[5]);
155                         Log("[ARP  ] to MAC %02x:%02x:%02x:%02x:%02x:%02x",
156                                 req4->DestMac.B[0], req4->DestMac.B[1],
157                                 req4->DestMac.B[2], req4->DestMac.B[3],
158                                 req4->DestMac.B[4], req4->DestMac.B[5]);
159                         Log("[ARP  ] ARP Request IPv4 Address %i.%i.%i.%i",
160                                 req4->DestIP.B[0], req4->DestIP.B[1], req4->DestIP.B[2],
161                                 req4->DestIP.B[3]);
162                         Log("[ARP  ] from %i.%i.%i.%i",
163                                 req4->SourceIP.B[0], req4->SourceIP.B[1],
164                                 req4->SourceIP.B[2], req4->SourceIP.B[3]);
165                         iface = IPv4_GetInterface(Adapter, req4->DestIP, 0);
166                         if( iface )
167                         {
168                                 req4->DestIP = req4->SourceIP;
169                                 req4->DestMac = req4->SourceMac;
170                                 req4->SourceIP = iface->IP4.Address;
171                                 req4->SourceMac = Adapter->MacAddr;
172                                 req4->Request = htons(2);
173                                 Log("[ARP  ] Hey, That's us!");
174                                 Log("[ARP  ] Sending back %02x:%02x:%02x:%02x:%02x:%02x",
175                                         req4->SourceMac.B[0], req4->SourceMac.B[1],
176                                         req4->SourceMac.B[2], req4->SourceMac.B[3],
177                                         req4->SourceMac.B[4], req4->SourceMac.B[5]);
178                                 Link_SendPacket(Adapter, 0x0806, req4->DestMac, sizeof(tArpRequest4), req4);
179                         }
180                         break;
181                 case 6:
182                         if( Length < sizeof(tArpRequest6) ) {
183                                 Log("[ARP  ] Recieved undersized packet (IPv6)");
184                                 return ;
185                         }
186                         iface = IPv6_GetInterface(Adapter, req6->DestIP, 0);
187                         if( iface )
188                         {
189                                 req6->DestIP = req6->SourceIP;
190                                 req6->DestMac = req6->SourceMac;
191                                 req6->SourceIP = iface->IP6.Address;
192                                 req6->SourceMac = Adapter->MacAddr;
193                                 req6->Request = htons(2);
194                                 Link_SendPacket(Adapter, 0x0806, req6->DestMac, sizeof(tArpRequest6), req6);
195                         }
196                         break;
197                 default:
198                         Log("[ARP  ] Unknown Protocol Address size (%i)", req4->SWSize);
199                         return ;
200                 }
201                 
202                 break;
203         
204         case 2: // Ooh! A response!
205                 // Find an entry for the MAC address in the cache
206                 LOCK(&glARP_Cache);
207                 for( i = giARP_CacheSpace; i--; )
208                 {
209                         if(gaARP_Cache[oldest].LastUpdate > gaARP_Cache[i].LastUpdate) {
210                                 oldest = i;
211                         }
212                         if( MAC_EQU(gaARP_Cache[i].MAC, From) ) break;
213                         if( gaARP_Cache[i].LastUpdate == 0 && free==-1 )        free = i;
214                 }
215                 if(i + 1 == 0) {
216                         if(free != -1)
217                                 i = free;
218                         else
219                                 i = oldest;
220                 }
221                 
222                 // Check what type of IP it is
223                 switch( req4->SWSize )
224                 {
225                 case 4:
226                         gaARP_Cache[i].IP4 = req4->SourceIP;
227                         break;
228                 case 6:
229                         if( Length < sizeof(tArpRequest6) ) {
230                                 Log("[ARP  ] Recieved undersized packet (IPv6)");
231                                 return ;
232                         }
233                         gaARP_Cache[i].IP6 = req6->SourceIP;
234                         break;
235                 default:
236                         Log("[ARP  ] Unknown Protocol Address size (%i)", req4->SWSize);
237                         RELEASE(&glARP_Cache);
238                         return ;
239                 }
240                 
241                 gaARP_Cache[i].LastUpdate = now();
242                 RELEASE(&glARP_Cache);
243                 break;
244         }
245 }

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