X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FIPStack%2Frouting.c;h=637930271178d8fce8c8a6f3a04ee6ad1deb30fd;hb=7c5a60c8be053f65ecceb47be773ea21a050b186;hp=690352ce23629d96c47227a9370cffd9a4ab2263;hpb=fd2f0a88bc702cccc6e15fdf39caaa084c3dd2fe;p=tpg%2Facess2.git diff --git a/Modules/IPStack/routing.c b/Modules/IPStack/routing.c index 690352ce..63793027 100644 --- a/Modules/IPStack/routing.c +++ b/Modules/IPStack/routing.c @@ -9,29 +9,21 @@ #include "ipstack.h" #include "link.h" -// === IMPORTS === -tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Filename); +#define DEFAUTL_METRIC 30 -// === TYPES === -typedef struct sRoute { - struct sRoute *Next; - - tVFS_Node Node; - - tInterface *Interface; // Interface for this route - int AddressType; // 0: Invalid, 4: IPv4, 6: IPv4 - void *Network; // Network - Pointer to tIPv4/tIPv6/... at end of structure - int SubnetBits; // Number of bits in \a Network that are valid - void *NextHop; // Next Hop address - Pointer to tIPv4/tIPv6/... at end of structure - int Metric; // Route priority -} tRoute; +// === IMPORTS === +extern tInterface *gIP_Interfaces; +extern tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Filename); // === PROTOTYPES === // - Routes directory char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos); tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name); int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data); - int IPStack_Route_Create(const char *InterfaceName); +// - Route Management +tRoute *IPStack_Route_Create(const char *InterfaceName); +tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric); +tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address); // - Individual Routes int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data); @@ -40,13 +32,13 @@ tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name); tRoute *gIP_Routes; tRoute *gIP_RoutesEnd; tVFS_Node gIP_RouteNode = { - Flags: VFS_FFLAG_DIRECTORY, - Size: -1, - NumACLs: 1, - ACLs: &gVFS_ACL_EveryoneRX, - ReadDir: IPStack_RouteDir_ReadDir, - FindDir: IPStack_RouteDir_FindDir, - IOCtl: IPStack_RouteDir_IOCtl + .Flags = VFS_FFLAG_DIRECTORY, + .Size = -1, + .NumACLs = 1, + .ACLs = &gVFS_ACL_EveryoneRX, + .ReadDir = IPStack_RouteDir_ReadDir, + .FindDir = IPStack_RouteDir_FindDir, + .IOCtl = IPStack_RouteDir_IOCtl }; // === CODE === @@ -82,10 +74,39 @@ tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name) // Zero is invalid, sorry :) if( !num ) return NULL; + // Interpret the name as :, returning the interface for + // needed to access that address. + // E.g. '4:0A02000A' - 10.2.0.10 + // Hm... It could do with a way to have a better address type representation + if( Name[1] == ':' ) // TODO: Allow variable length type codes + { + int addrSize = IPStack_GetAddressSize(num); + Uint8 addrData[addrSize]; + + // Errof if the size is invalid + if( strlen(Name) != 2 + addrSize*2 ) + return NULL; + + // Parse the address + // - Error if the address data is not fully hex + if( UnHex(addrData, addrSize, Name + 2) != addrSize ) + return NULL; + + // Find the route + rt = IPStack_FindRoute(num, NULL, addrData); + if(!rt) return NULL; + + // Return the interface node + // - Sure it's hijacking it from inteface.c's area, but it's + // simpler this way + return &rt->Interface->Node; + } + // The list is inherently sorted, so we can do a quick search for(rt = gIP_Routes; rt && rt->Node.Inode < num; rt = rt->Next); - // Fast fail on larger number - if( rt->Node.Inode > num ) + + // Fast fail end of list / larger number + if( !rt || rt->Node.Inode > num ) return NULL; return &rt->Node; @@ -97,6 +118,7 @@ tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name) static const char *casIOCtls_RouteDir[] = { DRV_IOCTLNAMES, "add_route", // Add a route - char *InterfaceName + "locate_route", // Find the best route for an address - struct {int Type, char Address[]} * NULL }; @@ -106,31 +128,48 @@ static const char *casIOCtls_RouteDir[] = { int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data) { int tmp; + tRoute *rt; + ENTER("pNode iID pData", Node, ID, Data); switch(ID) { // --- Standard IOCtls (0-3) --- - case DRV_IOCTL_TYPE: - LEAVE('i', DRV_TYPE_MISC); - return DRV_TYPE_MISC; - - case DRV_IOCTL_IDENT: - tmp = ModUtil_SetIdent(Data, STR(IDENT)); - LEAVE('i', 1); - return 1; + BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_RouteDir) - case DRV_IOCTL_VERSION: - LEAVE('x', VERSION); - return VERSION; - - case DRV_IOCTL_LOOKUP: - tmp = ModUtil_LookupString( (char**)casIOCtls_RouteDir, (char*)Data ); + case 4: // Add Route + if( !CheckString(Data) ) LEAVE_RET('i', -1); + rt = IPStack_Route_Create(Data); + if( !rt ) + tmp = -1; + else + tmp = rt->Node.Inode; LEAVE('i', tmp); return tmp; - case 4: // Add Route - if( !CheckString(Data) ) return -1; - return IPStack_Route_Create(Data); + case 5: // Locate Route + { + struct { + int Type; + Uint8 Addr[]; + } *data = Data; + + if( !CheckMem(Data, sizeof(int)) ) + LEAVE_RET('i', -1); + if( !CheckMem(Data, sizeof(int) + IPStack_GetAddressSize(data->Type)) ) + LEAVE_RET('i', -1); + + Log_Debug("IPStack", "Route_RouteDir_IOCtl - FindRoute %i, %s", + data->Type, IPStack_PrintAddress(data->Type, data->Addr) ); + rt = IPStack_FindRoute(data->Type, NULL, data->Addr); + + if( !rt ) + LEAVE_RET('i', 0); + + LEAVE('i', rt->Node.Inode); + return rt->Node.Inode; + } + break; } + LEAVE('i', 0); return 0; } @@ -138,7 +177,7 @@ int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data) * \brief Create a new route entry * \param InterfaceName Name of the interface using this route */ -int IPStack_Route_Create(const char *InterfaceName) +tRoute *IPStack_Route_Create(const char *InterfaceName) { tRoute *rt; tInterface *iface; @@ -148,14 +187,18 @@ int IPStack_Route_Create(const char *InterfaceName) // Note: Oh man! This is such a hack { tVFS_Node *node = IPStack_Root_FindDir(NULL, InterfaceName); - if( !node ) return 0; + if( !node ) { + Log_Debug("IPStack", "IPStack_Route_Create - Unknown interface '%s'\n", InterfaceName); + return NULL; + } iface = node->ImplPtr; + if(node->Close) node->Close(node); } // Get the size of the specified address type size = IPStack_GetAddressSize(iface->Type); if( size == 0 ) { - return 0; + return NULL; } // Allocate space @@ -175,6 +218,9 @@ int IPStack_Route_Create(const char *InterfaceName) rt->SubnetBits = 0; rt->NextHop = (void *)( (tVAddr)rt + sizeof(tRoute) + size ); rt->Interface = iface; + rt->Metric = DEFAUTL_METRIC; + memset(rt->Network, 0, size); + memset(rt->NextHop, 0, size); // Add to list if( gIP_RoutesEnd ) { @@ -185,7 +231,136 @@ int IPStack_Route_Create(const char *InterfaceName) gIP_Routes = gIP_RoutesEnd = rt; } - return rt->Node.Inode; + Log_Log("IPStack", "Route entry for '%s' created", InterfaceName); + + return rt; +} + +/** + * \brief Add and fill a route + */ +tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric) +{ + tRoute *rt = IPStack_Route_Create(Interface); + int addrSize; + + if( !rt ) return NULL; + + addrSize = IPStack_GetAddressSize(rt->Interface->Type); + + memcpy(rt->Network, Network, addrSize); + if( NextHop ) + memcpy(rt->NextHop, NextHop, addrSize); + rt->SubnetBits = SubnetBits; + if( Metric ) + rt->Metric = Metric; + + return rt; +} + +/** + */ +tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address) +{ + tRoute *rt; + tRoute *best = NULL; + tInterface *iface; + int addrSize; + + ENTER("iAddressType pInterface sAddress", + AddressType, Interface, IPStack_PrintAddress(AddressType, Address)); + + if( Interface && AddressType != Interface->Type ) { + LOG("Interface->Type (%i) != AddressType", Interface->Type); + LEAVE('n'); + return NULL; + } + + // Get address size + addrSize = IPStack_GetAddressSize(AddressType); + + // Check against explicit routes + for( rt = gIP_Routes; rt; rt = rt->Next ) + { + // Check interface + if( Interface && rt->Interface != Interface ) continue; + // Check address type + if( rt->AddressType != AddressType ) continue; + + LOG("Checking network %s/%i", IPStack_PrintAddress(AddressType, rt->Network), rt->SubnetBits); + + // Check if the address matches + if( !IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) ) + continue; + + if( best ) { + // More direct routes are preferred + if( best->SubnetBits > rt->SubnetBits ) { + LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits); + continue; + } + // If equally direct, choose the best metric + if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) { + LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric); + continue; + } + } + + best = rt; + } + + // Check against implicit routes + if( !best && !Interface ) + { + for( iface = gIP_Interfaces; iface; iface = iface->Next ) + { + if( Interface && iface != Interface ) continue; + if( iface->Type != AddressType ) continue; + + + // Check if the address matches + if( !IPStack_CompareAddress(AddressType, iface->Address, Address, iface->SubnetBits) ) + continue; + + if( best ) { + // More direct routes are preferred + if( best->SubnetBits > rt->SubnetBits ) { + LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits); + continue; + } + // If equally direct, choose the best metric + if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) { + LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric); + continue; + } + } + + rt = &iface->Route; + memcpy(rt->Network, iface->Address, addrSize); + memset(rt->NextHop, 0, addrSize); + rt->Metric = DEFAUTL_METRIC; + rt->SubnetBits = iface->SubnetBits; + + best = rt; + } + } + if( !best && Interface ) + { + rt = &Interface->Route; + // Make sure route is up to date + memcpy(rt->Network, Interface->Address, addrSize); + memset(rt->NextHop, 0, addrSize); + rt->Metric = DEFAUTL_METRIC; + rt->SubnetBits = Interface->SubnetBits; + + if( IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) ) + { + best = rt; + } + } + + LEAVE('p', best); + return best; } /** @@ -193,12 +368,14 @@ int IPStack_Route_Create(const char *InterfaceName) */ static const char *casIOCtls_Route[] = { DRV_IOCTLNAMES, - "get_network", // Get network - (void *Data) - "set_network", // Set network - (void *Data) - "get_nexthop", // Get next hop - (void *Data) - "set_nexthop", // Set next hop - (void *Data) - "getset_subnetbits", // Get/Set subnet bits - (int *Bits) - "getset_metric", // Get/Set metric - (int *Metric) + "get_type", // Get address type - (void), returns integer type + "get_network", // Get network - (void *Data), returns boolean success + "set_network", // Set network - (void *Data), returns boolean success + "get_nexthop", // Get next hop - (void *Data), returns boolean success + "set_nexthop", // Set next hop - (void *Data), returns boolean success + "getset_subnetbits", // Get/Set subnet bits - (int *Bits), returns current value + "getset_metric", // Get/Set metric - (int *Metric), returns current value + "get_interface", // Get interface name - (char *Name), returns name length, NULL OK NULL }; @@ -207,7 +384,6 @@ static const char *casIOCtls_Route[] = { */ int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data) { - int tmp; int *iData = Data; tRoute *rt = Node->ImplPtr; int addrSize = IPStack_GetAddressSize(rt->AddressType); @@ -215,48 +391,36 @@ int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data) switch(ID) { // --- Standard IOCtls (0-3) --- - case DRV_IOCTL_TYPE: - LEAVE('i', DRV_TYPE_MISC); - return DRV_TYPE_MISC; + BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_Route) - case DRV_IOCTL_IDENT: - tmp = ModUtil_SetIdent(Data, STR(IDENT)); - LEAVE('i', 1); - return 1; - - case DRV_IOCTL_VERSION: - LEAVE('x', VERSION); - return VERSION; - - case DRV_IOCTL_LOOKUP: - tmp = ModUtil_LookupString( (char**)casIOCtls_Route, (char*)Data ); - LEAVE('i', tmp); - return tmp; + // Get address type + case 4: + return rt->AddressType; // Get Network - case 4: + case 5: if( !CheckMem(Data, addrSize) ) return -1; memcpy(Data, rt->Network, addrSize); return 1; // Set Network - case 5: + case 6: if( !CheckMem(Data, addrSize) ) return -1; memcpy(rt->Network, Data, addrSize); return 1; // Get Next Hop - case 6: + case 7: if( !CheckMem(Data, addrSize) ) return -1; memcpy(Data, rt->NextHop, addrSize); return 1; // Set Next Hop - case 7: + case 8: if( !CheckMem(Data, addrSize) ) return -1; memcpy(rt->NextHop, Data, addrSize); return 1; // Get/Set Subnet Bits - case 8: + case 9: if( Data ) { if( !CheckMem(Data, sizeof(int)) ) return -1; if( *iData < 0 || *iData > addrSize*8 ) @@ -266,7 +430,7 @@ int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data) return rt->SubnetBits; // Get/Set Metric - case 9: + case 10: if( Data ) { if( !CheckMem(Data, sizeof(int)) ) return -1; if( *iData < 0 ) return -1; @@ -274,7 +438,16 @@ int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data) } return rt->Metric; + // Get interface name + case 11: + if( Data ) { + if( !CheckMem(Data, strlen(rt->Interface->Name) + 1) ) + return -1; + strcpy(Data, rt->Interface->Name); + } + return strlen(rt->Interface->Name); + default: - return 0; + return -1; } }