IPStack - Routing improvement
[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         
255         ENTER("iAddressType pInterface sAddress",
256                 AddressType, Interface, IPStack_PrintAddress(AddressType, Address));
257         
258         if( Interface && AddressType != Interface->Type ) {
259                 LOG("Interface->Type (%i) != AddressType", Interface->Type);
260                 LEAVE('n');
261                 return NULL;
262         }
263         
264         for( rt = gIP_Routes; rt; rt = rt->Next )
265         {
266                 // Check interface
267                 if( Interface && rt->Interface != Interface )   continue;
268                 // Check address type
269                 if( rt->AddressType != AddressType )    continue;
270                 
271                 LOG("Checking network %s/%i", IPStack_PrintAddress(AddressType, rt->Network), rt->SubnetBits);
272                 
273                 // Check if the address matches
274                 if( !IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
275                         continue;
276                 
277                 if( best ) {
278                         // More direct routes are preferred
279                         if( best->SubnetBits > rt->SubnetBits ) {
280                                 LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits);
281                                 continue;
282                         }
283                         // If equally direct, choose the best metric
284                         if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) {
285                                 LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric);
286                                 continue;
287                         }
288                 }
289                 
290                 best = rt;
291         }
292         
293         LEAVE('p', best);
294         return best;
295 }
296
297 /**
298  * \brief Names for route IOCtl Calls
299  */
300 static const char *casIOCtls_Route[] = {
301         DRV_IOCTLNAMES,
302         "get_type",     // Get address type - (void), returns integer type
303         "get_network",  // Get network - (void *Data), returns boolean success
304         "set_network",  // Set network - (void *Data), returns boolean success
305         "get_nexthop",  // Get next hop - (void *Data), returns boolean success
306         "set_nexthop",  // Set next hop - (void *Data), returns boolean success
307         "getset_subnetbits",    // Get/Set subnet bits - (int *Bits), returns current value
308         "getset_metric",        // Get/Set metric - (int *Metric), returns current value
309         "get_interface",        // Get interface name - (char *Name), returns name length, NULL OK
310         NULL
311         };
312
313 /**
314  * \brief IOCtl for /Devices/ip/routes/#
315  */
316 int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data)
317 {
318          int    tmp;
319          int    *iData = Data;
320         tRoute  *rt = Node->ImplPtr;
321          int    addrSize = IPStack_GetAddressSize(rt->AddressType);
322         
323         switch(ID)
324         {
325         // --- Standard IOCtls (0-3) ---
326         case DRV_IOCTL_TYPE:
327                 LEAVE('i', DRV_TYPE_MISC);
328                 return DRV_TYPE_MISC;
329         
330         case DRV_IOCTL_IDENT:
331                 tmp = ModUtil_SetIdent(Data, STR(IDENT));
332                 LEAVE('i', 1);
333                 return 1;
334         
335         case DRV_IOCTL_VERSION:
336                 LEAVE('x', VERSION);
337                 return VERSION;
338         
339         case DRV_IOCTL_LOOKUP:
340                 tmp = ModUtil_LookupString( (char**)casIOCtls_Route, (char*)Data );
341                 LEAVE('i', tmp);
342                 return tmp;
343         
344         // Get address type
345         case 4:
346                 return rt->AddressType;
347         
348         // Get Network
349         case 5:
350                 if( !CheckMem(Data, addrSize) ) return -1;
351                 memcpy(Data, rt->Network, addrSize);
352                 return 1;
353         // Set Network
354         case 6:
355                 if( !CheckMem(Data, addrSize) ) return -1;
356                 memcpy(rt->Network, Data, addrSize);
357                 return 1;
358         
359         // Get Next Hop
360         case 7:
361                 if( !CheckMem(Data, addrSize) ) return -1;
362                 memcpy(Data, rt->NextHop, addrSize);
363                 return 1;
364         // Set Next Hop
365         case 8:
366                 if( !CheckMem(Data, addrSize) ) return -1;
367                 memcpy(rt->NextHop, Data, addrSize);
368                 return 1;
369         
370         // Get/Set Subnet Bits
371         case 9:
372                 if( Data ) {
373                         if( !CheckMem(Data, sizeof(int)) )      return -1;
374                         if( *iData < 0 || *iData > addrSize*8 )
375                                 return -1;
376                         rt->SubnetBits = *iData;
377                 }
378                 return rt->SubnetBits;
379         
380         // Get/Set Metric
381         case 10:
382                 if( Data ) {
383                         if( !CheckMem(Data, sizeof(int)) )      return -1;
384                         if( *iData < 0 )        return -1;
385                         rt->Metric = *iData;
386                 }
387                 return rt->Metric;
388         
389         // Get interface name
390         case 11:
391                 if( Data ) {
392                         if( !CheckMem(Data, strlen(rt->Interface->Name) + 1) )
393                                 return -1;
394                         strcpy(Data, rt->Interface->Name);
395                 }
396                 return strlen(rt->Interface->Name);
397         
398         default:
399                 return -1;
400         }
401 }

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