381ddf7a5f3aeaee06ed1ee344173e1287bf3bce
[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         switch(ID)
98         {
99         // --- Standard IOCtls (0-3) ---
100         case DRV_IOCTL_TYPE:
101                 LEAVE('i', DRV_TYPE_MISC);
102                 return DRV_TYPE_MISC;
103         
104         case DRV_IOCTL_IDENT:
105                 tmp = ModUtil_SetIdent(Data, STR(IDENT));
106                 LEAVE('i', 1);
107                 return 1;
108         
109         case DRV_IOCTL_VERSION:
110                 LEAVE('x', VERSION);
111                 return VERSION;
112         
113         case DRV_IOCTL_LOOKUP:
114                 tmp = ModUtil_LookupString( (char**)casIOCtls_RouteDir, (char*)Data );
115                 LEAVE('i', tmp);
116                 return tmp;
117         
118         case 4: // Add Route
119                 if( !CheckString(Data) )        return -1;
120                 return IPStack_Route_Create(Data);
121         
122         case 5: // Locate Route
123                 {
124                         struct {
125                                  int    Type;
126                                 Uint8   Addr[];
127                         }       *data = Data;
128                         tRoute  *rt;
129                         
130                         if( !CheckMem(Data, sizeof(int)) )
131                                 return -1;
132                         if( !CheckMem(Data, sizeof(int) + IPStack_GetAddressSize(data->Type)) )
133                                 return -1;
134                         
135                         rt = IPStack_FindRoute(data->Type, NULL, data->Addr);
136                         
137                         if( !rt )
138                                 return 0;
139                         
140                         return rt->Node.Inode;
141                 }
142                 break;
143         }
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 int 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 )     return 0;
162                 iface = node->ImplPtr;
163         }
164         
165         // Get the size of the specified address type
166         size = IPStack_GetAddressSize(iface->Type);
167         if( size == 0 ) {
168                 return 0;
169         }
170         
171         // Allocate space
172         rt = calloc(1, sizeof(tRoute) + size*2 );
173         
174         // Set up node
175         rt->Node.ImplPtr = rt;
176         rt->Node.Inode = giIP_NextRouteId ++;
177         rt->Node.Size = 0;
178         rt->Node.NumACLs = 1,
179         rt->Node.ACLs = &gVFS_ACL_EveryoneRO;
180         rt->Node.IOCtl = IPStack_Route_IOCtl;
181         
182         // Set up state
183         rt->AddressType = iface->Type;
184         rt->Network = (void *)( (tVAddr)rt + sizeof(tRoute) );
185         rt->SubnetBits = 0;
186         rt->NextHop = (void *)( (tVAddr)rt + sizeof(tRoute) + size );
187         rt->Interface = iface;
188         
189         // Add to list
190         if( gIP_RoutesEnd ) {
191                 gIP_RoutesEnd->Next = rt;
192                 gIP_RoutesEnd = rt;
193         }
194         else {
195                 gIP_Routes = gIP_RoutesEnd = rt;
196         }
197         
198         return rt->Node.Inode;
199 }
200
201 /**
202  */
203 tRoute  *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address)
204 {
205         tRoute  *rt;
206         tRoute  *best = NULL;
207         
208         if( Interface && AddressType != Interface->Type )       return NULL;
209         
210         for( rt = gIP_Routes; rt; rt = rt->Next )
211         {
212                 // Check interface
213                 if( Interface && rt->Interface != Interface )   continue;
214                 // Check address type
215                 if( rt->AddressType != AddressType )    continue;
216                 
217                 // Check if the address matches
218                 if( !IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
219                         continue;
220                 
221                 if( best ) {
222                         // More direct routes are preferred
223                         if( best->SubnetBits > rt->SubnetBits ) continue;
224                         // If equally direct, choose the best metric
225                         if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric )   continue;
226                 }
227                 
228                 best = rt;
229         }
230         
231         return best;
232 }
233
234 /**
235  * \brief Names for route IOCtl Calls
236  */
237 static const char *casIOCtls_Route[] = {
238         DRV_IOCTLNAMES,
239         "get_network",  // Get network - (void *Data), returns boolean success
240         "set_network",  // Set network - (void *Data), returns boolean success
241         "get_nexthop",  // Get next hop - (void *Data), returns boolean success
242         "set_nexthop",  // Set next hop - (void *Data), returns boolean success
243         "getset_subnetbits",    // Get/Set subnet bits - (int *Bits), returns current value
244         "getset_metric",        // Get/Set metric - (int *Metric), returns current value
245         "get_interface",        // Get interface name - (char *Name), returns name length, NULL OK
246         NULL
247         };
248
249 /**
250  * \brief IOCtl for /Devices/ip/routes/#
251  */
252 int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data)
253 {
254          int    tmp;
255          int    *iData = Data;
256         tRoute  *rt = Node->ImplPtr;
257          int    addrSize = IPStack_GetAddressSize(rt->AddressType);
258         
259         switch(ID)
260         {
261         // --- Standard IOCtls (0-3) ---
262         case DRV_IOCTL_TYPE:
263                 LEAVE('i', DRV_TYPE_MISC);
264                 return DRV_TYPE_MISC;
265         
266         case DRV_IOCTL_IDENT:
267                 tmp = ModUtil_SetIdent(Data, STR(IDENT));
268                 LEAVE('i', 1);
269                 return 1;
270         
271         case DRV_IOCTL_VERSION:
272                 LEAVE('x', VERSION);
273                 return VERSION;
274         
275         case DRV_IOCTL_LOOKUP:
276                 tmp = ModUtil_LookupString( (char**)casIOCtls_Route, (char*)Data );
277                 LEAVE('i', tmp);
278                 return tmp;
279         
280         // Get Network
281         case 4:
282                 if( !CheckMem(Data, addrSize) ) return -1;
283                 memcpy(Data, rt->Network, addrSize);
284                 return 1;
285         // Set Network
286         case 5:
287                 if( !CheckMem(Data, addrSize) ) return -1;
288                 memcpy(rt->Network, Data, addrSize);
289                 return 1;
290         
291         // Get Next Hop
292         case 6:
293                 if( !CheckMem(Data, addrSize) ) return -1;
294                 memcpy(Data, rt->NextHop, addrSize);
295                 return 1;
296         // Set Next Hop
297         case 7:
298                 if( !CheckMem(Data, addrSize) ) return -1;
299                 memcpy(rt->NextHop, Data, addrSize);
300                 return 1;
301         
302         // Get/Set Subnet Bits
303         case 8:
304                 if( Data ) {
305                         if( !CheckMem(Data, sizeof(int)) )      return -1;
306                         if( *iData < 0 || *iData > addrSize*8 )
307                                 return -1;
308                         rt->SubnetBits = *iData;
309                 }
310                 return rt->SubnetBits;
311         
312         // Get/Set Metric
313         case 9:
314                 if( Data ) {
315                         if( !CheckMem(Data, sizeof(int)) )      return -1;
316                         if( *iData < 0 )        return -1;
317                         rt->Metric = *iData;
318                 }
319                 return rt->Metric;
320         
321         // Get interface name
322         case 10:
323                 if( Data ) {
324                         if( !CheckMem(Data, strlen(rt->Interface->Name) + 1) )
325                                 return -1;
326                         strcpy(Data, rt->Interface->Name);
327                 }
328                 return strlen(rt->Interface->Name);
329         
330         default:
331                 return 0;
332         }
333 }

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