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

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