Modules/IPStack - Made use of "sti" x86 only
[tpg/acess2.git] / KernelLand / 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 <api_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_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
23  int    IPStack_RouteDir_Unlink(tVFS_Node *Node, const char *OldName);
24 tRoute  *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric);
25  int    _Route_ParseRouteName(const char *Name, void *Addr, int *SubnetBits, int *Metric);
26  int    IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data);
27 // - Route Management
28 tRoute  *IPStack_Route_Create(int AddrType, void *Network, int SubnetBits, int Metric);
29 tRoute  *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric);
30 tRoute  *_Route_FindInterfaceRoute(int AddressType, void *Address);
31 tRoute  *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address);
32 // - Individual Routes
33  int    IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data);
34
35 // === GLOBALS ===
36  int    giIP_NextRouteId = 1;
37 tRoute  *gIP_Routes;
38 tRoute  *gIP_RoutesEnd;
39 tVFS_NodeType   gIP_RouteNodeType = {
40         .IOCtl = IPStack_Route_IOCtl
41 };
42 tVFS_NodeType   gIP_RouteDirNodeType = {
43         .ReadDir = IPStack_RouteDir_ReadDir,
44         .FindDir = IPStack_RouteDir_FindDir,
45         .MkNod = IPStack_RouteDir_MkNod,
46         .Unlink = IPStack_RouteDir_Unlink,
47         .IOCtl = IPStack_RouteDir_IOCtl
48 };
49 tVFS_Node       gIP_RouteNode = {
50         .Flags = VFS_FFLAG_DIRECTORY,
51         .Size = -1,
52         .NumACLs = 1,
53         .ACLs = &gVFS_ACL_EveryoneRX,
54         .Type = &gIP_RouteDirNodeType
55 };
56
57 // === CODE ===
58 /**
59  * \brief ReadDir for the /Devices/ip/routes/ directory
60  */
61 char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos)
62 {
63         tRoute  *rt;
64         
65         for(rt = gIP_Routes; rt && Pos --; rt = rt->Next);
66         if( !rt )       return NULL;
67         
68         {
69                  int    addrlen = IPStack_GetAddressSize(rt->AddressType);
70                  int    len = sprintf(NULL, "%i::%i:%i", rt->AddressType, rt->SubnetBits, rt->Metric) + addrlen*2;
71                 char    buf[len+1];
72                  int    ofs;
73                 ofs = sprintf(buf, "%i:", rt->AddressType);
74                 ofs += Hex(buf+ofs, addrlen, rt->Network);
75                 sprintf(buf+ofs, ":%i:%i", rt->SubnetBits, rt->Metric);
76                 return strdup(buf);
77         }
78 }
79
80 /**
81  * \brief FindDir for the /Devices/ip/routes/ directory
82  */
83 tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name)
84 {
85         // Interpret the name as <type>:<addr>, returning the interface for
86         // needed to access that address.
87         //   E.g. '@4:0A02000A' - 10.2.0.10
88         // Hm... It could do with a way to have a better address type representation
89         if( Name[0] == '@' )
90         {
91                 tRoute  *rt;
92                  int    ofs = 1;
93                  int    type;
94                 
95                 ofs += ParseInt(Name+ofs, &type);
96                  int    addrSize = IPStack_GetAddressSize(type);
97                 Uint8   addrData[addrSize];
98
99                 // Separator
100                 if( Name[ofs] != ':' )  return NULL;
101                 ofs ++;
102
103                 // Error if the size is invalid
104                 if( strlen(Name+ofs) != addrSize*2 )
105                         return NULL;
106                 
107                 // Parse the address
108                 // - Error if the address data is not fully hex
109                 if( UnHex(addrData, addrSize, Name + ofs) != addrSize )
110                         return NULL;
111                 
112                 // Find the route
113                 rt = IPStack_FindRoute(type, NULL, addrData);
114                 if(!rt) return NULL;
115         
116                 if( !rt->Interface )
117                 {       
118                         LOG("Why does this route not have a node? trying to find an iface for the next hop");
119
120                         rt = _Route_FindInterfaceRoute(type, rt->NextHop);
121                         if(!rt) {
122                                 Log_Notice("Cannot find route to next hop '%s'",
123                                         IPStack_PrintAddress(type, rt->NextHop));
124                                 return NULL;
125                         }
126                 }
127                 if( !rt->Interface ) {
128                         Log_Notice("Routes", "No interface for route %p, what the?", rt);
129                         return NULL;
130                 }
131                 // Return the interface node
132                 // - Sure it's hijacking it from inteface.c's area, but it's
133                 //   simpler this way
134                 return &rt->Interface->Node;
135         }
136         else if( Name[0] == '#' )
137         {
138                 int num, ofs = 1;
139                 
140                 ofs = ParseInt(Name+ofs, &num);
141                 if( ofs == 1 )  return NULL;
142                 if( Name[ofs] != '\0' ) return NULL;
143                 if( num < 0)    return NULL;            
144
145                 for( tRoute *rt = gIP_Routes; rt; rt = rt->Next )
146                 {
147                         if( rt->Node.Inode > num )      return NULL;
148                         if( rt->Node.Inode == num )     return &rt->Node;
149                 }
150                 return NULL;
151         }
152         else
153         {
154                  int    type = _Route_ParseRouteName(Name, NULL, NULL, NULL);
155                 if( type <= 0 ) return NULL;
156
157                  int    addrSize = IPStack_GetAddressSize(type);
158                 Uint8   addrData[addrSize];
159                  int    subnet_bits, metric;
160                 
161                 _Route_ParseRouteName(Name, addrData, &subnet_bits, &metric);
162
163                 tRoute *rt = _Route_FindExactRoute(type, addrData, subnet_bits, metric);
164                 if(rt)  return &rt->Node;
165                 return NULL;
166         }
167 }
168
169 /**
170  * \brief Create a new route node
171  */
172 int IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
173 {
174         if( Flags )     return -EINVAL; 
175         if( Threads_GetUID() != 0 )     return -EACCES;
176
177          int    type = _Route_ParseRouteName(Name, NULL, NULL, NULL);
178         if( type <= 0 ) return -EINVAL;
179
180          int    size = IPStack_GetAddressSize(type);
181         Uint8   addrdata[size]; 
182          int    subnet, metric;
183
184         _Route_ParseRouteName(Name, addrdata, &subnet, &metric);
185
186         // Check for duplicates
187         if( _Route_FindExactRoute(type, addrdata, subnet, metric) )
188                 return -EEXIST;
189
190         IPStack_Route_Create(type, addrdata, subnet, metric);
191
192         return 0;
193 }
194
195 /**
196  * \brief Rename / Delete a route
197  */
198 int IPStack_RouteDir_Unlink(tVFS_Node *Node, const char *OldName)
199 {
200         tRoute  *rt;
201         
202         if( Threads_GetUID() != 0 )     return -EACCES;
203
204         // Get the original route entry
205         {
206                  int    type = _Route_ParseRouteName(OldName, NULL, NULL, NULL);
207                 if(type <= 0)   return -EINVAL;
208                 Uint8   addr[IPStack_GetAddressSize(type)];
209                  int    subnet, metric;
210                 _Route_ParseRouteName(OldName, addr, &subnet, &metric);
211                 
212                 rt = _Route_FindExactRoute(type, addr, subnet, metric);
213         }       
214
215         // Delete the route
216         tRoute  *prev = NULL;
217         for(tRoute *r = gIP_Routes; r && r != rt; prev = r, r = r->Next);
218         
219         if(prev)
220                 prev->Next = rt->Next;
221         else
222                 gIP_Routes = rt->Next;
223         free(rt);
224         return 0;
225 }
226
227 tRoute *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric)
228 {
229         for(tRoute *rt = gIP_Routes; rt; rt = rt->Next)
230         {
231                 if( rt->AddressType != Type )   continue;
232                 if( rt->Metric != Metric )      continue;
233                 if( rt->SubnetBits != Subnet )  continue;
234                 if( IPStack_CompareAddress(Type, rt->Network, Network, -1) == 0 )
235                         continue ;
236                 return rt;
237         }
238         return NULL;
239 }
240
241 int _Route_ParseRouteName(const char *Name, void *Addr, int *SubnetBits, int *Metric)
242 {
243          int    type, addrlen;
244          int    ofs = 0, ilen;
245         
246         ENTER("sName pAddr pSubnetBits pMetric", Name, Addr, SubnetBits, Metric);
247
248         ilen = ParseInt(Name, &type);
249         if(ilen == 0) {
250                 LOG("Type failed to parse");
251                 LEAVE_RET('i', -1);
252         }
253         ofs += ilen;
254         
255         if(Name[ofs] != ':')    LEAVE_RET('i', -1);
256         ofs ++;
257
258         addrlen = IPStack_GetAddressSize(type);
259         if( Addr )
260         {
261                 if( UnHex(Addr, addrlen, Name + ofs) != addrlen )
262                         return -1;
263         }
264         ofs += addrlen*2;
265         
266         if(Name[ofs] != ':')    LEAVE_RET('i', -1);
267         ofs ++;
268
269         ilen = ParseInt(Name+ofs, SubnetBits);
270         if(ilen == 0) {
271                 LOG("Subnet failed to parse");
272                 LEAVE_RET('i', -1);
273         }
274         ofs += ilen;
275         
276         if(Name[ofs] != ':')    LEAVE_RET('i', -1);
277         ofs ++;
278
279         ilen = ParseInt(Name+ofs, Metric);
280         if(ilen == 0) {
281                 LOG("Metric failed to parse");
282                 LEAVE_RET('i', -1);
283         }
284         ofs += ilen;
285         
286         if(Name[ofs] != '\0')   LEAVE_RET('i', -1);
287
288         LEAVE('i', type);
289         return type;
290 }
291
292 /**
293  * \brief Names for the route list IOCtl Calls
294  */
295 static const char *casIOCtls_RouteDir[] = {
296         DRV_IOCTLNAMES,
297         "locate_route", // Find the best route for an address - struct {int Type, char Address[]} *
298         NULL
299         };
300
301 /**
302  * \brief IOCtl for /Devices/ip/routes/
303  */
304 int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data)
305 {
306         tRoute  *rt;
307         ENTER("pNode iID pData", Node, ID, Data);
308         switch(ID)
309         {
310         // --- Standard IOCtls (0-3) ---
311         BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_RouteDir)
312         
313         case 4: // Locate Route
314                 {
315                         struct {
316                                  int    Type;
317                                 Uint8   Addr[];
318                         }       *data = Data;
319                         
320                         if( !CheckMem(Data, sizeof(int)) )
321                                 LEAVE_RET('i', -1);
322                         if( !CheckMem(Data, sizeof(int) + IPStack_GetAddressSize(data->Type)) )
323                                 LEAVE_RET('i', -1);
324                         
325                         Log_Debug("IPStack", "Route_RouteDir_IOCtl - FindRoute %i, %s",
326                                 data->Type, IPStack_PrintAddress(data->Type, data->Addr) );
327                         rt = IPStack_FindRoute(data->Type, NULL, data->Addr);
328                         
329                         if( !rt )
330                                 LEAVE_RET('i', 0);
331                         
332                         LEAVE('i', rt->Node.Inode);
333                         return rt->Node.Inode;
334                 }
335                 break;
336         }
337         LEAVE('i', 0);
338         return 0;
339 }
340
341 /**
342  * \brief Create a new route entry
343  * \param InterfaceName Name of the interface using this route
344  */
345 tRoute *IPStack_Route_Create(int AddrType, void *Network, int SubnetBits, int Metric)
346 {
347         tRoute  *rt;
348          int    size;
349         
350         // Get the size of the specified address type
351         size = IPStack_GetAddressSize(AddrType);
352         if( size == 0 ) {
353                 return NULL;
354         }
355         
356         // Allocate space
357         rt = calloc(1, sizeof(tRoute) + size*2 );
358         
359         // Set up node
360         rt->Node.ImplPtr = rt;
361         rt->Node.Inode = giIP_NextRouteId ++;
362         rt->Node.Size = 0;
363         rt->Node.NumACLs = 1,
364         rt->Node.ACLs = &gVFS_ACL_EveryoneRO;
365         rt->Node.Type = &gIP_RouteNodeType;
366         
367         // Set up state
368         rt->AddressType = AddrType;
369         rt->Network = (void *)( (tVAddr)rt + sizeof(tRoute) );
370         rt->SubnetBits = SubnetBits;
371         rt->NextHop = (void *)( (tVAddr)rt + sizeof(tRoute) + size );
372         rt->Interface = NULL;
373         rt->Metric = Metric;
374         memcpy(rt->Network, Network, size);
375         memset(rt->NextHop, 0, size);
376         
377         // Clear non-fixed bits
378         {
379                 Uint8   *data = rt->Network;
380                  int    i;
381                 i = SubnetBits / 8;
382                 if( SubnetBits % 8 ) {
383                         data[i] &= ~((1 << (8 - SubnetBits % 8)) - 1);
384                         i ++;
385                 }
386                 memset(data + i, 0, size - i);
387         }       
388
389
390         // Add to list
391         if( gIP_RoutesEnd ) {
392                 gIP_RoutesEnd->Next = rt;
393                 gIP_RoutesEnd = rt;
394         }
395         else {
396                 gIP_Routes = gIP_RoutesEnd = rt;
397         }
398         
399 //      Log_Log("IPStack", "Route entry for '%s' created", InterfaceName);
400         
401         return rt;
402 }
403
404 /**
405  * \brief Add and fill a route
406  */
407 tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric)
408 {
409         tInterface      *iface;
410         tRoute  *rt;
411          int    addrSize;
412         
413         {
414                 tVFS_Node       *tmp;
415                 tmp = IPStack_Root_FindDir(NULL, Interface);
416                 if(!tmp)        return NULL;
417                 iface = tmp->ImplPtr;
418                 if(tmp->Type->Close)    tmp->Type->Close(tmp);
419         }
420
421         rt = IPStack_Route_Create(iface->Type, Network, SubnetBits, Metric);
422         if( !rt )       return NULL;
423         
424         addrSize = IPStack_GetAddressSize(iface->Type);
425         rt->Interface = iface;
426         
427         if( NextHop )
428                 memcpy(rt->NextHop, NextHop, addrSize);
429         
430         return rt;
431 }
432
433 /**
434  * \brief Locates what interface should be used to get directly to an address
435  */
436 tRoute *_Route_FindInterfaceRoute(int AddressType, void *Address)
437 {
438         tRoute  *best = NULL, *rt;
439          int addrSize = IPStack_GetAddressSize(AddressType);
440         for( tInterface *iface = gIP_Interfaces; iface; iface = iface->Next )
441         {
442                 if( iface->Type != AddressType )        continue;
443                 
444                 // Check if the address matches
445                 if( !IPStack_CompareAddress(AddressType, iface->Address, Address, iface->SubnetBits) )
446                         continue;
447                 
448                 rt = &iface->Route;
449                 if( !rt->Interface )
450                 {
451                         memcpy(rt->Network, iface->Address, addrSize);
452                         memset(rt->NextHop, 0, addrSize);
453                         rt->Metric = DEFAUTL_METRIC;
454                         rt->SubnetBits = iface->SubnetBits;
455                         rt->Interface = iface;
456                 }
457                 
458                 if( best ) {
459                         // More direct routes are preferred
460                         if( best->SubnetBits > rt->SubnetBits ) {
461                                 LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits);
462                                 continue;
463                         }
464                         // If equally direct, choose the best metric
465                         if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) {
466                                 LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric);
467                                 continue;
468                         }
469                 }
470                 
471                 best = rt;
472         }
473
474         return best;
475 }
476
477 /**
478  */
479 tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address)
480 {
481         tRoute  *rt;
482         tRoute  *best = NULL;
483          int    addrSize;
484         
485         ENTER("iAddressType pInterface sAddress",
486                 AddressType, Interface, IPStack_PrintAddress(AddressType, Address));
487         
488         if( Interface && AddressType != Interface->Type ) {
489                 LOG("Interface->Type (%i) != AddressType", Interface->Type);
490                 LEAVE('n');
491                 return NULL;
492         }
493         
494         // Get address size
495         addrSize = IPStack_GetAddressSize(AddressType);
496         
497         // Check against explicit routes
498         for( rt = gIP_Routes; rt; rt = rt->Next )
499         {
500                 // Check interface
501                 if( Interface && rt->Interface && rt->Interface != Interface )  continue;
502                 // Check address type
503                 if( rt->AddressType != AddressType )    continue;
504                 
505                 LOG("Checking network %s/%i", IPStack_PrintAddress(AddressType, rt->Network), rt->SubnetBits);
506                 
507                 // Check if the address matches
508                 if( !IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
509                         continue;
510                 
511                 if( best ) {
512                         // More direct routes are preferred
513                         if( best->SubnetBits > rt->SubnetBits ) {
514                                 LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits);
515                                 continue;
516                         }
517                         // If equally direct, choose the best metric
518                         if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) {
519                                 LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric);
520                                 continue;
521                         }
522                 }
523                 
524                 best = rt;
525         }
526         
527         // Check against implicit routes
528         if( !best && !Interface )
529         {
530                 best = _Route_FindInterfaceRoute(AddressType, Address);
531         }
532         if( !best && Interface )
533         {
534                 rt = &Interface->Route;
535                 // Make sure route is up to date
536                 memcpy(rt->Network, Interface->Address, addrSize);
537                 memset(rt->NextHop, 0, addrSize);
538                 rt->Metric = DEFAUTL_METRIC;
539                 rt->SubnetBits = Interface->SubnetBits;
540                 
541                 if( IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
542                 {
543                         best = rt;
544                 }
545         }
546         
547         LEAVE('p', best);
548         return best;
549 }
550
551 /**
552  * \brief Names for route IOCtl Calls
553  */
554 static const char *casIOCtls_Route[] = {
555         DRV_IOCTLNAMES,
556         "get_nexthop",  // Get next hop - (void *Data), returns boolean success
557         "set_nexthop",  // Set next hop - (void *Data), returns boolean success
558         "get_interface",        // Get interface name - (char *Name), returns name length, NULL OK
559         "set_interface",        // Set interface - (const char *Name)
560         NULL
561         };
562
563 /**
564  * \brief IOCtl for /Devices/ip/routes/#
565  */
566 int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data)
567 {
568         tRoute  *rt = Node->ImplPtr;
569          int    addrSize = IPStack_GetAddressSize(rt->AddressType);
570
571         ENTER("pNode iID pData", Node, ID, Data);
572         
573         switch(ID)
574         {
575         // --- Standard IOCtls (0-3) ---
576         BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_Route)
577         
578         // Get Next Hop
579         case 4:
580                 if( !CheckMem(Data, addrSize) ) LEAVE_RET('i', -1);
581                 memcpy(Data, rt->NextHop, addrSize);
582                 LEAVE_RET('i', 1);
583         // Set Next Hop
584         case 5:
585                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
586                 if( !CheckMem(Data, addrSize) ) LEAVE_RET('i', -1);
587                 memcpy(rt->NextHop, Data, addrSize);
588                 LEAVE_RET('i', 1);
589
590         // Get interface name
591         case 6:
592                 if( !rt->Interface ) {
593                         if(Data && !CheckMem(Data, 1) )
594                                 LEAVE_RET('i', -1);
595                         if(Data)
596                                 *(char*)Data = 0;
597                         LEAVE_RET('i', 0);
598                 }
599                 if( Data ) {
600                         if( !CheckMem(Data, strlen(rt->Interface->Name) + 1) )
601                                 LEAVE_RET('i', -1);
602                         strcpy(Data, rt->Interface->Name);
603                 }
604                 LEAVE_RET('i', strlen(rt->Interface->Name));
605         // Set interface name
606         case 7:
607                 if( Threads_GetUID() != 0 )
608                         LEAVE_RET('i', -1);
609                 if( !CheckString(Data) )
610                         LEAVE_RET('i', -1);
611                 else
612                 {
613                         tInterface      *iface;
614                         tVFS_Node       *tmp;
615                         tmp = IPStack_Root_FindDir(NULL, Data);
616                         if(!tmp)
617                                 LEAVE_RET('i', -1);
618                         iface = tmp->ImplPtr;
619                         if(tmp->Type->Close)    tmp->Type->Close(tmp);
620                         
621                         if( iface->Type != rt->AddressType )
622                                 LEAVE_RET('i', -1);
623
624                         // TODO: Other checks?          
625         
626                         rt->Interface = iface;
627                 }
628                 LEAVE_RET('i', 0);
629
630         default:
631                 LEAVE_RET('i', -1);
632         }
633 }

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