Added some very pedantic warning flags
[tpg/acess2.git] / Modules / IPStack / routing.c
1 /*
2  * Acess2 IP Stack
3  * - Routing Tables
4  */
5 #define DEBUG   1
6 #define VERSION VER2(0,10)
7 #include <acess.h>
8 #include <tpl_drv_common.h>
9 #include "ipstack.h"
10 #include "link.h"
11
12 #define DEFAUTL_METRIC  30
13
14 // === IMPORTS ===
15 extern tInterface       *gIP_Interfaces;
16 extern tVFS_Node        *IPStack_Root_FindDir(tVFS_Node *Node, const char *Filename);
17
18 // === PROTOTYPES ===
19 // - Routes directory
20 char    *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos);
21 tVFS_Node       *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name);
22  int    IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data);
23 // - Route Management
24 tRoute  *IPStack_Route_Create(const char *InterfaceName);
25 tRoute  *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric);
26 tRoute  *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address);
27 // - Individual Routes
28  int    IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data);
29
30 // === GLOBALS ===
31  int    giIP_NextRouteId = 1;
32 tRoute  *gIP_Routes;
33 tRoute  *gIP_RoutesEnd;
34 tVFS_Node       gIP_RouteNode = {
35         Flags: VFS_FFLAG_DIRECTORY,
36         Size: -1,
37         NumACLs: 1,
38         ACLs: &gVFS_ACL_EveryoneRX,
39         ReadDir: IPStack_RouteDir_ReadDir,
40         FindDir: IPStack_RouteDir_FindDir,
41         IOCtl: IPStack_RouteDir_IOCtl
42 };
43
44 // === CODE ===
45 /**
46  * \brief ReadDir for the /Devices/ip/routes/ directory
47  */
48 char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos)
49 {
50         tRoute  *rt;
51         
52         for(rt = gIP_Routes; rt && Pos --; rt = rt->Next);
53         
54         if( !rt ) {
55                 return NULL;
56         }
57         
58         {
59                  int    len = sprintf(NULL, "%i", rt->Node.Inode);
60                 char    buf[len+1];
61                 sprintf(buf, "%i", rt->Node.Inode);
62                 return strdup(buf);
63         }
64 }
65
66 /**
67  * \brief FindDir for the /Devices/ip/routes/ directory
68  */
69 tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name)
70 {
71          int    num = atoi(Name);
72         tRoute  *rt;
73         
74         // Zero is invalid, sorry :)
75         if( !num )      return NULL;
76         
77         // The list is inherently sorted, so we can do a quick search
78         for(rt = gIP_Routes; rt && rt->Node.Inode < num; rt = rt->Next);
79         // Fast fail on larger number
80         if( rt->Node.Inode > num )
81                 return NULL;
82         
83         return &rt->Node;
84 }
85
86 /**
87  * \brief Names for the route list IOCtl Calls
88  */
89 static const char *casIOCtls_RouteDir[] = {
90         DRV_IOCTLNAMES,
91         "add_route",    // Add a route - char *InterfaceName
92         "locate_route", // Find the best route for an address - struct {int Type, char Address[]} *
93         NULL
94         };
95
96 /**
97  * \brief IOCtl for /Devices/ip/routes/
98  */
99 int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data)
100 {
101          int    tmp;
102         tRoute  *rt;
103         ENTER("pNode iID pData", Node, ID, Data);
104         switch(ID)
105         {
106         // --- Standard IOCtls (0-3) ---
107         BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_RouteDir)
108         
109         case 4: // Add Route
110                 if( !CheckString(Data) )        LEAVE_RET('i', -1);
111                 rt = IPStack_Route_Create(Data);
112                 if( !rt )
113                         tmp = -1;
114                 else
115                         tmp = rt->Node.Inode;
116                 LEAVE('i', tmp);
117                 return tmp;
118         
119         case 5: // Locate Route
120                 {
121                         struct {
122                                  int    Type;
123                                 Uint8   Addr[];
124                         }       *data = Data;
125                         
126                         if( !CheckMem(Data, sizeof(int)) )
127                                 LEAVE_RET('i', -1);
128                         if( !CheckMem(Data, sizeof(int) + IPStack_GetAddressSize(data->Type)) )
129                                 LEAVE_RET('i', -1);
130                         
131                         Log_Debug("IPStack", "Route_RouteDir_IOCtl - FindRoute %i, %s",
132                                 data->Type, IPStack_PrintAddress(data->Type, data->Addr) );
133                         rt = IPStack_FindRoute(data->Type, NULL, data->Addr);
134                         
135                         if( !rt )
136                                 LEAVE_RET('i', 0);
137                         
138                         LEAVE('i', rt->Node.Inode);
139                         return rt->Node.Inode;
140                 }
141                 break;
142         }
143         LEAVE('i', 0);
144         return 0;
145 }
146
147 /**
148  * \brief Create a new route entry
149  * \param InterfaceName Name of the interface using this route
150  */
151 tRoute *IPStack_Route_Create(const char *InterfaceName)
152 {
153         tRoute  *rt;
154         tInterface      *iface;
155          int    size;
156         
157         // Get interface
158         // Note: Oh man! This is such a hack
159         {
160                 tVFS_Node       *node = IPStack_Root_FindDir(NULL, InterfaceName);
161                 if( !node ) {
162                         Log_Debug("IPStack", "IPStack_Route_Create - Unknown interface '%s'\n", InterfaceName);
163                         return NULL;
164                 }
165                 iface = node->ImplPtr;
166                 if(node->Close) node->Close(node);
167         }
168         
169         // Get the size of the specified address type
170         size = IPStack_GetAddressSize(iface->Type);
171         if( size == 0 ) {
172                 return NULL;
173         }
174         
175         // Allocate space
176         rt = calloc(1, sizeof(tRoute) + size*2 );
177         
178         // Set up node
179         rt->Node.ImplPtr = rt;
180         rt->Node.Inode = giIP_NextRouteId ++;
181         rt->Node.Size = 0;
182         rt->Node.NumACLs = 1,
183         rt->Node.ACLs = &gVFS_ACL_EveryoneRO;
184         rt->Node.IOCtl = IPStack_Route_IOCtl;
185         
186         // Set up state
187         rt->AddressType = iface->Type;
188         rt->Network = (void *)( (tVAddr)rt + sizeof(tRoute) );
189         rt->SubnetBits = 0;
190         rt->NextHop = (void *)( (tVAddr)rt + sizeof(tRoute) + size );
191         rt->Interface = iface;
192         rt->Metric = DEFAUTL_METRIC;
193         memset(rt->Network, 0, size);
194         memset(rt->NextHop, 0, size);
195         
196         // Add to list
197         if( gIP_RoutesEnd ) {
198                 gIP_RoutesEnd->Next = rt;
199                 gIP_RoutesEnd = rt;
200         }
201         else {
202                 gIP_Routes = gIP_RoutesEnd = rt;
203         }
204         
205         Log_Log("IPStack", "Route entry for '%s' created", InterfaceName);
206         
207         return rt;
208 }
209
210 /**
211  * \brief Add and fill a route
212  */
213 tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric)
214 {
215         tRoute  *rt = IPStack_Route_Create(Interface);
216          int    addrSize;
217         
218         if( !rt )       return NULL;
219         
220         addrSize = IPStack_GetAddressSize(rt->Interface->Type);
221         
222         memcpy(rt->Network, Network, addrSize);
223         if( NextHop )
224                 memcpy(rt->NextHop, NextHop, addrSize);
225         rt->SubnetBits = SubnetBits;
226         if( Metric )
227                 rt->Metric = Metric;
228         
229         return rt;
230 }
231
232 /**
233  */
234 tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address)
235 {
236         tRoute  *rt;
237         tRoute  *best = NULL;
238         tInterface      *iface;
239          int    addrSize;
240         
241         ENTER("iAddressType pInterface sAddress",
242                 AddressType, Interface, IPStack_PrintAddress(AddressType, Address));
243         
244         if( Interface && AddressType != Interface->Type ) {
245                 LOG("Interface->Type (%i) != AddressType", Interface->Type);
246                 LEAVE('n');
247                 return NULL;
248         }
249         
250         // Get address size
251         addrSize = IPStack_GetAddressSize(AddressType);
252         
253         // Check against explicit routes
254         for( rt = gIP_Routes; rt; rt = rt->Next )
255         {
256                 // Check interface
257                 if( Interface && rt->Interface != Interface )   continue;
258                 // Check address type
259                 if( rt->AddressType != AddressType )    continue;
260                 
261                 LOG("Checking network %s/%i", IPStack_PrintAddress(AddressType, rt->Network), rt->SubnetBits);
262                 
263                 // Check if the address matches
264                 if( !IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
265                         continue;
266                 
267                 if( best ) {
268                         // More direct routes are preferred
269                         if( best->SubnetBits > rt->SubnetBits ) {
270                                 LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits);
271                                 continue;
272                         }
273                         // If equally direct, choose the best metric
274                         if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) {
275                                 LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric);
276                                 continue;
277                         }
278                 }
279                 
280                 best = rt;
281         }
282         
283         // Check against implicit routes
284         if( !best && !Interface )
285         {
286                 for( iface = gIP_Interfaces; iface; iface = iface->Next )
287                 {
288                         if( Interface && iface != Interface )   continue;
289                         if( iface->Type != AddressType )        continue;
290                         
291                         
292                         // Check if the address matches
293                         if( !IPStack_CompareAddress(AddressType, iface->Address, Address, iface->SubnetBits) )
294                                 continue;
295                         
296                         if( best ) {
297                                 // More direct routes are preferred
298                                 if( best->SubnetBits > rt->SubnetBits ) {
299                                         LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits);
300                                         continue;
301                                 }
302                                 // If equally direct, choose the best metric
303                                 if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) {
304                                         LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric);
305                                         continue;
306                                 }
307                         }
308                         
309                         rt = &iface->Route;
310                         memcpy(rt->Network, iface->Address, addrSize);
311                         memset(rt->NextHop, 0, addrSize);
312                         rt->Metric = DEFAUTL_METRIC;
313                         rt->SubnetBits = iface->SubnetBits;
314                         
315                         best = rt;
316                 }
317         }
318         if( !best && Interface )
319         {
320                 rt = &Interface->Route;
321                 // Make sure route is up to date
322                 memcpy(rt->Network, iface->Address, addrSize);
323                 memset(rt->NextHop, 0, addrSize);
324                 rt->Metric = DEFAUTL_METRIC;
325                 rt->SubnetBits = iface->SubnetBits;
326                 
327                 if( IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
328                 {
329                         best = rt;
330                 }
331         }
332         
333         LEAVE('p', best);
334         return best;
335 }
336
337 /**
338  * \brief Names for route IOCtl Calls
339  */
340 static const char *casIOCtls_Route[] = {
341         DRV_IOCTLNAMES,
342         "get_type",     // Get address type - (void), returns integer type
343         "get_network",  // Get network - (void *Data), returns boolean success
344         "set_network",  // Set network - (void *Data), returns boolean success
345         "get_nexthop",  // Get next hop - (void *Data), returns boolean success
346         "set_nexthop",  // Set next hop - (void *Data), returns boolean success
347         "getset_subnetbits",    // Get/Set subnet bits - (int *Bits), returns current value
348         "getset_metric",        // Get/Set metric - (int *Metric), returns current value
349         "get_interface",        // Get interface name - (char *Name), returns name length, NULL OK
350         NULL
351         };
352
353 /**
354  * \brief IOCtl for /Devices/ip/routes/#
355  */
356 int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data)
357 {
358          int    *iData = Data;
359         tRoute  *rt = Node->ImplPtr;
360          int    addrSize = IPStack_GetAddressSize(rt->AddressType);
361         
362         switch(ID)
363         {
364         // --- Standard IOCtls (0-3) ---
365         BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_Route)
366         
367         // Get address type
368         case 4:
369                 return rt->AddressType;
370         
371         // Get Network
372         case 5:
373                 if( !CheckMem(Data, addrSize) ) return -1;
374                 memcpy(Data, rt->Network, addrSize);
375                 return 1;
376         // Set Network
377         case 6:
378                 if( !CheckMem(Data, addrSize) ) return -1;
379                 memcpy(rt->Network, Data, addrSize);
380                 return 1;
381         
382         // Get Next Hop
383         case 7:
384                 if( !CheckMem(Data, addrSize) ) return -1;
385                 memcpy(Data, rt->NextHop, addrSize);
386                 return 1;
387         // Set Next Hop
388         case 8:
389                 if( !CheckMem(Data, addrSize) ) return -1;
390                 memcpy(rt->NextHop, Data, addrSize);
391                 return 1;
392         
393         // Get/Set Subnet Bits
394         case 9:
395                 if( Data ) {
396                         if( !CheckMem(Data, sizeof(int)) )      return -1;
397                         if( *iData < 0 || *iData > addrSize*8 )
398                                 return -1;
399                         rt->SubnetBits = *iData;
400                 }
401                 return rt->SubnetBits;
402         
403         // Get/Set Metric
404         case 10:
405                 if( Data ) {
406                         if( !CheckMem(Data, sizeof(int)) )      return -1;
407                         if( *iData < 0 )        return -1;
408                         rt->Metric = *iData;
409                 }
410                 return rt->Metric;
411         
412         // Get interface name
413         case 11:
414                 if( Data ) {
415                         if( !CheckMem(Data, strlen(rt->Interface->Name) + 1) )
416                                 return -1;
417                         strcpy(Data, rt->Interface->Name);
418                 }
419                 return strlen(rt->Interface->Name);
420         
421         default:
422                 return -1;
423         }
424 }

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