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

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