51eb6db5a6c0aceb4701066a570921801ddac252
[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, 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, 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, void *Address)
204 {
205         tRoute  *rt;
206         tRoute  *best = NULL;
207         
208         for( rt = gIP_Routes; rt; rt = rt->Next )
209         {
210                 if( rt->AddressType != AddressType )    continue;
211                 
212                 if( !IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
213                         continue;
214                 
215                 if( best ) {
216                         // More direct routes are preferred
217                         if( best->SubnetBits > rt->SubnetBits ) continue;
218                         // If equally direct, choose the best metric
219                         if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric )   continue;
220                 }
221                 
222                 best = rt;
223         }
224         
225         return best;
226 }
227
228 /**
229  * \brief Names for route IOCtl Calls
230  */
231 static const char *casIOCtls_Route[] = {
232         DRV_IOCTLNAMES,
233         "get_network",  // Get network - (void *Data), returns boolean success
234         "set_network",  // Set network - (void *Data), returns boolean success
235         "get_nexthop",  // Get next hop - (void *Data), returns boolean success
236         "set_nexthop",  // Set next hop - (void *Data), returns boolean success
237         "getset_subnetbits",    // Get/Set subnet bits - (int *Bits), returns current value
238         "getset_metric",        // Get/Set metric - (int *Metric), returns current value
239         "get_interface",        // Get interface name - (char *Name), returns name length, NULL OK
240         NULL
241         };
242
243 /**
244  * \brief IOCtl for /Devices/ip/routes/#
245  */
246 int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data)
247 {
248          int    tmp;
249          int    *iData = Data;
250         tRoute  *rt = Node->ImplPtr;
251          int    addrSize = IPStack_GetAddressSize(rt->AddressType);
252         
253         switch(ID)
254         {
255         // --- Standard IOCtls (0-3) ---
256         case DRV_IOCTL_TYPE:
257                 LEAVE('i', DRV_TYPE_MISC);
258                 return DRV_TYPE_MISC;
259         
260         case DRV_IOCTL_IDENT:
261                 tmp = ModUtil_SetIdent(Data, STR(IDENT));
262                 LEAVE('i', 1);
263                 return 1;
264         
265         case DRV_IOCTL_VERSION:
266                 LEAVE('x', VERSION);
267                 return VERSION;
268         
269         case DRV_IOCTL_LOOKUP:
270                 tmp = ModUtil_LookupString( (char**)casIOCtls_Route, (char*)Data );
271                 LEAVE('i', tmp);
272                 return tmp;
273         
274         // Get Network
275         case 4:
276                 if( !CheckMem(Data, addrSize) ) return -1;
277                 memcpy(Data, rt->Network, addrSize);
278                 return 1;
279         // Set Network
280         case 5:
281                 if( !CheckMem(Data, addrSize) ) return -1;
282                 memcpy(rt->Network, Data, addrSize);
283                 return 1;
284         
285         // Get Next Hop
286         case 6:
287                 if( !CheckMem(Data, addrSize) ) return -1;
288                 memcpy(Data, rt->NextHop, addrSize);
289                 return 1;
290         // Set Next Hop
291         case 7:
292                 if( !CheckMem(Data, addrSize) ) return -1;
293                 memcpy(rt->NextHop, Data, addrSize);
294                 return 1;
295         
296         // Get/Set Subnet Bits
297         case 8:
298                 if( Data ) {
299                         if( !CheckMem(Data, sizeof(int)) )      return -1;
300                         if( *iData < 0 || *iData > addrSize*8 )
301                                 return -1;
302                         rt->SubnetBits = *iData;
303                 }
304                 return rt->SubnetBits;
305         
306         // Get/Set Metric
307         case 9:
308                 if( Data ) {
309                         if( !CheckMem(Data, sizeof(int)) )      return -1;
310                         if( *iData < 0 )        return -1;
311                         rt->Metric = *iData;
312                 }
313                 return rt->Metric;
314         
315         // Get interface name
316         case 10:
317                 if( Data ) {
318                         if( !CheckMem(Data, strlen(rt->Interface->Name) + 1) )
319                                 return -1;
320                         strcpy(Data, rt->Interface->Name);
321                 }
322                 return strlen(rt->Interface->Name);
323         
324         default:
325                 return 0;
326         }
327 }

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