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

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