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

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