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

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