IPStack / ifconfig - Routing changes
[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         case DRV_IOCTL_TYPE:
108                 LEAVE('i', DRV_TYPE_MISC);
109                 return DRV_TYPE_MISC;
110         
111         case DRV_IOCTL_IDENT:
112                 tmp = ModUtil_SetIdent(Data, STR(IDENT));
113                 LEAVE('i', 1);
114                 return 1;
115         
116         case DRV_IOCTL_VERSION:
117                 LEAVE('x', VERSION);
118                 return VERSION;
119         
120         case DRV_IOCTL_LOOKUP:
121                 tmp = ModUtil_LookupString( (char**)casIOCtls_RouteDir, (char*)Data );
122                 LEAVE('i', tmp);
123                 return tmp;
124         
125         case 4: // Add Route
126                 if( !CheckString(Data) )        LEAVE_RET('i', -1);
127                 rt = IPStack_Route_Create(Data);
128                 if( !rt )
129                         tmp = -1;
130                 else
131                         tmp = rt->Node.Inode;
132                 LEAVE('i', tmp);
133                 return tmp;
134         
135         case 5: // Locate Route
136                 {
137                         struct {
138                                  int    Type;
139                                 Uint8   Addr[];
140                         }       *data = Data;
141                         
142                         if( !CheckMem(Data, sizeof(int)) )
143                                 LEAVE_RET('i', -1);
144                         if( !CheckMem(Data, sizeof(int) + IPStack_GetAddressSize(data->Type)) )
145                                 LEAVE_RET('i', -1);
146                         
147                         Log_Debug("IPStack", "Route_RouteDir_IOCtl - FindRoute %i, %s",
148                                 data->Type, IPStack_PrintAddress(data->Type, data->Addr) );
149                         rt = IPStack_FindRoute(data->Type, NULL, data->Addr);
150                         
151                         if( !rt )
152                                 LEAVE_RET('i', 0);
153                         
154                         LEAVE('i', rt->Node.Inode);
155                         return rt->Node.Inode;
156                 }
157                 break;
158         }
159         LEAVE('i', 0);
160         return 0;
161 }
162
163 /**
164  * \brief Create a new route entry
165  * \param InterfaceName Name of the interface using this route
166  */
167 tRoute *IPStack_Route_Create(const char *InterfaceName)
168 {
169         tRoute  *rt;
170         tInterface      *iface;
171          int    size;
172         
173         // Get interface
174         // Note: Oh man! This is such a hack
175         {
176                 tVFS_Node       *node = IPStack_Root_FindDir(NULL, InterfaceName);
177                 if( !node ) {
178                         Log_Debug("IPStack", "IPStack_Route_Create - Unknown interface '%s'\n", InterfaceName);
179                         return NULL;
180                 }
181                 iface = node->ImplPtr;
182                 if(node->Close) node->Close(node);
183         }
184         
185         // Get the size of the specified address type
186         size = IPStack_GetAddressSize(iface->Type);
187         if( size == 0 ) {
188                 return NULL;
189         }
190         
191         // Allocate space
192         rt = calloc(1, sizeof(tRoute) + size*2 );
193         
194         // Set up node
195         rt->Node.ImplPtr = rt;
196         rt->Node.Inode = giIP_NextRouteId ++;
197         rt->Node.Size = 0;
198         rt->Node.NumACLs = 1,
199         rt->Node.ACLs = &gVFS_ACL_EveryoneRO;
200         rt->Node.IOCtl = IPStack_Route_IOCtl;
201         
202         // Set up state
203         rt->AddressType = iface->Type;
204         rt->Network = (void *)( (tVAddr)rt + sizeof(tRoute) );
205         rt->SubnetBits = 0;
206         rt->NextHop = (void *)( (tVAddr)rt + sizeof(tRoute) + size );
207         rt->Interface = iface;
208         rt->Metric = DEFAUTL_METRIC;
209         memset(rt->Network, 0, size);
210         memset(rt->NextHop, 0, size);
211         
212         // Add to list
213         if( gIP_RoutesEnd ) {
214                 gIP_RoutesEnd->Next = rt;
215                 gIP_RoutesEnd = rt;
216         }
217         else {
218                 gIP_Routes = gIP_RoutesEnd = rt;
219         }
220         
221         Log_Log("IPStack", "Route entry for '%s' created", InterfaceName);
222         
223         return rt;
224 }
225
226 /**
227  * \brief Add and fill a route
228  */
229 tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric)
230 {
231         tRoute  *rt = IPStack_Route_Create(Interface);
232          int    addrSize;
233         
234         if( !rt )       return NULL;
235         
236         addrSize = IPStack_GetAddressSize(rt->Interface->Type);
237         
238         memcpy(rt->Network, Network, addrSize);
239         if( NextHop )
240                 memcpy(rt->NextHop, NextHop, addrSize);
241         rt->SubnetBits = SubnetBits;
242         if( Metric )
243                 rt->Metric = Metric;
244         
245         return rt;
246 }
247
248 /**
249  */
250 tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address)
251 {
252         tRoute  *rt;
253         tRoute  *best = NULL;
254         tInterface      *iface;
255          int    addrSize;
256         
257         ENTER("iAddressType pInterface sAddress",
258                 AddressType, Interface, IPStack_PrintAddress(AddressType, Address));
259         
260         if( Interface && AddressType != Interface->Type ) {
261                 LOG("Interface->Type (%i) != AddressType", Interface->Type);
262                 LEAVE('n');
263                 return NULL;
264         }
265         
266         // Get address size
267         addrSize = IPStack_GetAddressSize(AddressType);
268         
269         // Check against explicit routes
270         for( rt = gIP_Routes; rt; rt = rt->Next )
271         {
272                 // Check interface
273                 if( Interface && rt->Interface != Interface )   continue;
274                 // Check address type
275                 if( rt->AddressType != AddressType )    continue;
276                 
277                 LOG("Checking network %s/%i", IPStack_PrintAddress(AddressType, rt->Network), rt->SubnetBits);
278                 
279                 // Check if the address matches
280                 if( !IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
281                         continue;
282                 
283                 if( best ) {
284                         // More direct routes are preferred
285                         if( best->SubnetBits > rt->SubnetBits ) {
286                                 LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits);
287                                 continue;
288                         }
289                         // If equally direct, choose the best metric
290                         if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) {
291                                 LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric);
292                                 continue;
293                         }
294                 }
295                 
296                 best = rt;
297         }
298         
299         // Check against implicit routes
300         if( !best && !Interface )
301         {
302                 for( iface = gIP_Interfaces; iface; iface = iface->Next )
303                 {
304                         if( Interface && iface != Interface )   continue;
305                         if( iface->Type != AddressType )        continue;
306                         
307                         
308                         // Check if the address matches
309                         if( !IPStack_CompareAddress(AddressType, iface->Address, Address, iface->SubnetBits) )
310                                 continue;
311                         
312                         if( best ) {
313                                 // More direct routes are preferred
314                                 if( best->SubnetBits > rt->SubnetBits ) {
315                                         LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits);
316                                         continue;
317                                 }
318                                 // If equally direct, choose the best metric
319                                 if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) {
320                                         LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric);
321                                         continue;
322                                 }
323                         }
324                         
325                         rt = &iface->Route;
326                         memcpy(rt->Network, iface->Address, addrSize);
327                         memset(rt->NextHop, 0, addrSize);
328                         rt->Metric = DEFAUTL_METRIC;
329                         rt->SubnetBits = iface->SubnetBits;
330                         
331                         best = rt;
332                 }
333         }
334         if( !best && Interface )
335         {
336                 rt = &Interface->Route;
337                 // Make sure route is up to date
338                 memcpy(rt->Network, iface->Address, addrSize);
339                 memset(rt->NextHop, 0, addrSize);
340                 rt->Metric = DEFAUTL_METRIC;
341                 rt->SubnetBits = iface->SubnetBits;
342                 
343                 if( IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
344                 {
345                         best = rt;
346                 }
347         }
348         
349         LEAVE('p', best);
350         return best;
351 }
352
353 /**
354  * \brief Names for route IOCtl Calls
355  */
356 static const char *casIOCtls_Route[] = {
357         DRV_IOCTLNAMES,
358         "get_type",     // Get address type - (void), returns integer type
359         "get_network",  // Get network - (void *Data), returns boolean success
360         "set_network",  // Set network - (void *Data), returns boolean success
361         "get_nexthop",  // Get next hop - (void *Data), returns boolean success
362         "set_nexthop",  // Set next hop - (void *Data), returns boolean success
363         "getset_subnetbits",    // Get/Set subnet bits - (int *Bits), returns current value
364         "getset_metric",        // Get/Set metric - (int *Metric), returns current value
365         "get_interface",        // Get interface name - (char *Name), returns name length, NULL OK
366         NULL
367         };
368
369 /**
370  * \brief IOCtl for /Devices/ip/routes/#
371  */
372 int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data)
373 {
374          int    tmp;
375          int    *iData = Data;
376         tRoute  *rt = Node->ImplPtr;
377          int    addrSize = IPStack_GetAddressSize(rt->AddressType);
378         
379         switch(ID)
380         {
381         // --- Standard IOCtls (0-3) ---
382         case DRV_IOCTL_TYPE:
383                 LEAVE('i', DRV_TYPE_MISC);
384                 return DRV_TYPE_MISC;
385         
386         case DRV_IOCTL_IDENT:
387                 tmp = ModUtil_SetIdent(Data, STR(IDENT));
388                 LEAVE('i', 1);
389                 return 1;
390         
391         case DRV_IOCTL_VERSION:
392                 LEAVE('x', VERSION);
393                 return VERSION;
394         
395         case DRV_IOCTL_LOOKUP:
396                 tmp = ModUtil_LookupString( (char**)casIOCtls_Route, (char*)Data );
397                 LEAVE('i', tmp);
398                 return tmp;
399         
400         // Get address type
401         case 4:
402                 return rt->AddressType;
403         
404         // Get Network
405         case 5:
406                 if( !CheckMem(Data, addrSize) ) return -1;
407                 memcpy(Data, rt->Network, addrSize);
408                 return 1;
409         // Set Network
410         case 6:
411                 if( !CheckMem(Data, addrSize) ) return -1;
412                 memcpy(rt->Network, Data, addrSize);
413                 return 1;
414         
415         // Get Next Hop
416         case 7:
417                 if( !CheckMem(Data, addrSize) ) return -1;
418                 memcpy(Data, rt->NextHop, addrSize);
419                 return 1;
420         // Set Next Hop
421         case 8:
422                 if( !CheckMem(Data, addrSize) ) return -1;
423                 memcpy(rt->NextHop, Data, addrSize);
424                 return 1;
425         
426         // Get/Set Subnet Bits
427         case 9:
428                 if( Data ) {
429                         if( !CheckMem(Data, sizeof(int)) )      return -1;
430                         if( *iData < 0 || *iData > addrSize*8 )
431                                 return -1;
432                         rt->SubnetBits = *iData;
433                 }
434                 return rt->SubnetBits;
435         
436         // Get/Set Metric
437         case 10:
438                 if( Data ) {
439                         if( !CheckMem(Data, sizeof(int)) )      return -1;
440                         if( *iData < 0 )        return -1;
441                         rt->Metric = *iData;
442                 }
443                 return rt->Metric;
444         
445         // Get interface name
446         case 11:
447                 if( Data ) {
448                         if( !CheckMem(Data, strlen(rt->Interface->Name) + 1) )
449                                 return -1;
450                         strcpy(Data, rt->Interface->Name);
451                 }
452                 return strlen(rt->Interface->Name);
453         
454         default:
455                 return -1;
456         }
457 }

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