static int dump_domains(int argc, char** argv) { DomainList::Iterator iterator = sDomains.GetIterator(); while (net_domain_private* domain = iterator.Next()) { kprintf("domain: %p, %s, %d\n", domain, domain->name, domain->family); kprintf(" module: %p\n", domain->module); kprintf(" address_module: %p\n", domain->address_module); if (!domain->routes.IsEmpty()) kprintf(" routes:\n"); RouteList::Iterator routeIterator = domain->routes.GetIterator(); while (net_route_private* route = routeIterator.Next()) { kprintf(" %p: dest %s, mask %s, gw %s, flags %" B_PRIx32 ", " "address %p\n", route, AddressString(domain, route->destination ? route->destination : NULL).Data(), AddressString(domain, route->mask ? route->mask : NULL).Data(), AddressString(domain, route->gateway ? route->gateway : NULL).Data(), route->flags, route->interface_address); } if (!domain->route_infos.IsEmpty()) kprintf(" route infos:\n"); RouteInfoList::Iterator infoIterator = domain->route_infos.GetIterator(); while (net_route_info* info = infoIterator.Next()) { kprintf(" %p\n", info); } } return 0; }
static struct net_route* get_route_internal(struct net_domain_private* domain, const struct sockaddr* address) { ASSERT_LOCKED_RECURSIVE(&domain->lock); net_route_private* route = NULL; if (address->sa_family == AF_LINK) { // special address to find an interface directly RouteList::Iterator iterator = domain->routes.GetIterator(); const sockaddr_dl* link = (const sockaddr_dl*)address; while (iterator.HasNext()) { route = iterator.Next(); net_device* device = route->interface_address->interface->device; if ((link->sdl_nlen > 0 && !strncmp(device->name, (const char*)link->sdl_data, IF_NAMESIZE)) || (link->sdl_nlen == 0 && link->sdl_alen > 0 && !memcmp(LLADDR(link), device->address.data, device->address.length))) break; } } else route = find_route(domain, address); if (route != NULL && atomic_add(&route->ref_count, 1) == 0) { // route has been deleted already route = NULL; } return route; }
static net_route_private* find_route(struct net_domain* _domain, const net_route* description) { struct net_domain_private* domain = (net_domain_private*)_domain; RouteList::Iterator iterator = domain->routes.GetIterator(); while (iterator.HasNext()) { net_route_private* route = iterator.Next(); if ((route->flags & RTF_DEFAULT) != 0 && (description->flags & RTF_DEFAULT) != 0) { // there can only be one default route per interface address family // TODO: check this better if (route->interface_address == description->interface_address) return route; continue; } if ((route->flags & (RTF_GATEWAY | RTF_HOST | RTF_LOCAL | RTF_DEFAULT)) == (description->flags & (RTF_GATEWAY | RTF_HOST | RTF_LOCAL | RTF_DEFAULT)) && domain->address_module->equal_masked_addresses( route->destination, description->destination, description->mask) && domain->address_module->equal_addresses(route->mask, description->mask) && domain->address_module->equal_addresses(route->gateway, description->gateway) && (description->interface_address == NULL || description->interface_address == route->interface_address)) return route; } return NULL; }
static net_route_private* find_route(net_domain* _domain, const sockaddr* address) { net_domain_private* domain = (net_domain_private*)_domain; // find last matching route RouteList::Iterator iterator = domain->routes.GetIterator(); net_route_private* candidate = NULL; TRACE("test address %s for routes...\n", AddressString(domain, address).Data()); // TODO: alternate equal default routes while (iterator.HasNext()) { net_route_private* route = iterator.Next(); if (route->mask) { sockaddr maskedAddress; domain->address_module->mask_address(address, route->mask, &maskedAddress); if (!domain->address_module->equal_addresses(&maskedAddress, route->destination)) continue; } else if (!domain->address_module->equal_addresses(address, route->destination)) continue; // neglect routes that point to devices that have no link if ((route->interface_address->interface->device->flags & IFF_LINK) == 0) { if (candidate == NULL) { TRACE(" found candidate: %s, flags %lx\n", AddressString( domain, route->destination).Data(), route->flags); candidate = route; } continue; } TRACE(" found route: %s, flags %lx\n", AddressString(domain, route->destination).Data(), route->flags); return route; } return candidate; }
void invalidate_routes(net_domain* _domain, net_interface* interface) { net_domain_private* domain = (net_domain_private*)_domain; RecursiveLocker locker(domain->lock); TRACE("invalidate_routes(%i, %s)\n", domain->family, interface->name); RouteList::Iterator iterator = domain->routes.GetIterator(); while (iterator.HasNext()) { net_route* route = iterator.Next(); if (route->interface_address->interface == interface) remove_route(domain, route); } }
void invalidate_routes(InterfaceAddress* address) { net_domain_private* domain = (net_domain_private*)address->domain; TRACE("invalidate_routes(%s)\n", AddressString(domain, address->local).Data()); RecursiveLocker locker(domain->lock); RouteList::Iterator iterator = domain->routes.GetIterator(); while (iterator.HasNext()) { net_route* route = iterator.Next(); if (route->interface_address == address) remove_route(domain, route); } }
static int dump_domains(int argc, char** argv) { DomainList::Iterator iterator = sDomains.GetIterator(); while (net_domain_private* domain = iterator.Next()) { kprintf("domain: %p, %s, %d\n", domain, domain->name, domain->family); kprintf(" module: %p\n", domain->module); kprintf(" address_module: %p\n", domain->address_module); if (!list_is_empty(&domain->interfaces)) kprintf(" interfaces:\n"); net_interface* interface = NULL; while (true) { interface = (net_interface*)list_get_next_item(&domain->interfaces, interface); if (interface == NULL) break; kprintf(" %p\n", interface); } if (!domain->routes.IsEmpty()) kprintf(" routes:\n"); RouteList::Iterator routeIterator = domain->routes.GetIterator(); while (net_route* route = routeIterator.Next()) { kprintf(" %p\n", route); } if (!domain->route_infos.IsEmpty()) kprintf(" route infos:\n"); RouteInfoList::Iterator infoIterator = domain->route_infos.GetIterator(); while (net_route_info* info = infoIterator.Next()) { kprintf(" %p\n", info); } } return 0; }
/*! Determines the size of a buffer large enough to contain the whole routing table. */ uint32 route_table_size(net_domain_private* domain) { RecursiveLocker locker(domain->lock); uint32 size = 0; RouteList::Iterator iterator = domain->routes.GetIterator(); while (iterator.HasNext()) { net_route_private* route = iterator.Next(); size += IF_NAMESIZE + sizeof(route_entry); if (route->destination) size += route->destination->sa_len; if (route->mask) size += route->mask->sa_len; if (route->gateway) size += route->gateway->sa_len; } return size; }
status_t add_route(struct net_domain* _domain, const struct net_route* newRoute) { struct net_domain_private* domain = (net_domain_private*)_domain; TRACE("add route to domain %s: dest %s, mask %s, gw %s, flags %lx\n", domain->name, AddressString(domain, newRoute->destination ? newRoute->destination : NULL).Data(), AddressString(domain, newRoute->mask ? newRoute->mask : NULL).Data(), AddressString(domain, newRoute->gateway ? newRoute->gateway : NULL).Data(), newRoute->flags); if (domain == NULL || newRoute == NULL || newRoute->interface_address == NULL || ((newRoute->flags & RTF_HOST) != 0 && newRoute->mask != NULL) || ((newRoute->flags & RTF_DEFAULT) == 0 && newRoute->destination == NULL) || ((newRoute->flags & RTF_GATEWAY) != 0 && newRoute->gateway == NULL) || !domain->address_module->check_mask(newRoute->mask)) return B_BAD_VALUE; RecursiveLocker _(domain->lock); net_route_private* route = find_route(domain, newRoute); if (route != NULL) return B_FILE_EXISTS; route = new (std::nothrow) net_route_private; if (route == NULL) return B_NO_MEMORY; if (domain->address_module->copy_address(newRoute->destination, &route->destination, (newRoute->flags & RTF_DEFAULT) != 0, newRoute->mask) != B_OK || domain->address_module->copy_address(newRoute->mask, &route->mask, (newRoute->flags & RTF_DEFAULT) != 0, NULL) != B_OK || domain->address_module->copy_address(newRoute->gateway, &route->gateway, false, NULL) != B_OK) { delete route; return B_NO_MEMORY; } route->flags = newRoute->flags; route->interface_address = newRoute->interface_address; ((InterfaceAddress*)route->interface_address)->AcquireReference(); route->mtu = 0; route->ref_count = 1; // Insert the route sorted by completeness of its mask RouteList::Iterator iterator = domain->routes.GetIterator(); net_route_private* before = NULL; while ((before = iterator.Next()) != NULL) { // if the before mask is less specific than the one of the route, // we can insert it before that route. if (domain->address_module->first_mask_bit(before->mask) > domain->address_module->first_mask_bit(route->mask)) break; if ((route->flags & RTF_DEFAULT) != 0 && (before->flags & RTF_DEFAULT) != 0) { // both routes are equal - let the link speed decide the // order if (before->interface_address->interface->device->link_speed < route->interface_address->interface->device->link_speed) break; } } domain->routes.Insert(before, route); update_route_infos(domain); return B_OK; }
/*! Dumps a list of all routes into the supplied userland buffer. If the routes don't fit into the buffer, an error (\c ENOBUFS) is returned. */ status_t list_routes(net_domain_private* domain, void* buffer, size_t size) { RecursiveLocker _(domain->lock); RouteList::Iterator iterator = domain->routes.GetIterator(); size_t spaceLeft = size; sockaddr zeros; memset(&zeros, 0, sizeof(sockaddr)); zeros.sa_family = domain->family; zeros.sa_len = sizeof(sockaddr); while (iterator.HasNext()) { net_route* route = iterator.Next(); size = IF_NAMESIZE + sizeof(route_entry); sockaddr* destination = NULL; sockaddr* mask = NULL; sockaddr* gateway = NULL; uint8* next = (uint8*)buffer + size; if (route->destination != NULL) { destination = (sockaddr*)next; next += route->destination->sa_len; size += route->destination->sa_len; } if (route->mask != NULL) { mask = (sockaddr*)next; next += route->mask->sa_len; size += route->mask->sa_len; } if (route->gateway != NULL) { gateway = (sockaddr*)next; next += route->gateway->sa_len; size += route->gateway->sa_len; } if (spaceLeft < size) return ENOBUFS; ifreq request; strlcpy(request.ifr_name, route->interface_address->interface->name, IF_NAMESIZE); request.ifr_route.destination = destination; request.ifr_route.mask = mask; request.ifr_route.gateway = gateway; request.ifr_route.mtu = route->mtu; request.ifr_route.flags = route->flags; // copy data into userland buffer if (user_memcpy(buffer, &request, size) < B_OK || (route->destination != NULL && user_memcpy(request.ifr_route.destination, route->destination, route->destination->sa_len) < B_OK) || (route->mask != NULL && user_memcpy(request.ifr_route.mask, route->mask, route->mask->sa_len) < B_OK) || (route->gateway != NULL && user_memcpy(request.ifr_route.gateway, route->gateway, route->gateway->sa_len) < B_OK)) return B_BAD_ADDRESS; buffer = (void*)next; spaceLeft -= size; } return B_OK; }