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

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