[openbeosnetteam] Re: routes

  • From: "Axel Dörfler" <axeld@xxxxxxxxxxxxxxxx>
  • To: openbeosnetteam@xxxxxxxxxxxxx
  • Date: Mon, 31 Jul 2006 16:32:18 +0200 CEST

Oliver Tappe <openbeos@xxxxxxxxxxxxxxx> wrote:
> I'm glad you mention it, since I just wanted to start a new submodule 
> of 
> net_domain (address_arithmetic_module_info or anything like that) and 
> move 
> all the functions that deal with address-comparing/-masking and the 
> like from 
> route.cpp and interfaces.cpp into the new module. I suppose we could 
> even get 
> rid of address_offset and address_length.

If we do that, we can for sure get rid of address_offset and 
address_length; they are only used for comparison and (not yet) 
masking. It probably depends a bit on the needs of other address 
domains if this is really necessary (in terms of required), anyway, but 
I must admit I haven't had a closer look at IPv6 yet (I just went the 
BONE route :-)).

> Anyway, I'll just wait for BerliOS to move...

WAITING? :-))
I've attached a routes.diff that has all the changes in it, it's not 
that much, anyway :-)
If you want an updated route command as well, please tell.

Bye,
   Axel.

Index: routes.cpp
===================================================================
--- routes.cpp  (revision 18318)
+++ routes.cpp  (working copy)
@@ -49,22 +49,90 @@
 }
 
 
+//     #pragma mark -
+
+
+static int32
+first_bit(net_domain_private *domain, sockaddr *address)
+{
+       uint8 *bits = (uint8 *)address + domain->address_offset;
+       size_t length = domain->address_length;
+
+       // TODO: this can be optimized, there are also some nice assembler 
mnemonics for this
+       for (uint32 i = 0; i < length; i++) {
+               if (bits[i]) {
+                       for (int32 bitMask = 128, bit = 0; bitMask > 0; bitMask 
>>= 1, bit++) {
+                               if (bits[i] & bitMask)
+                                       return bit;
+                       }
+               }
+       }
+
+       return length;
+}
+
+
+static bool
+check_mask(net_domain_private *domain, const sockaddr *mask)
+{
+       if (mask == NULL)
+               return true;
+
+       uint8 *bits = (uint8 *)mask + domain->address_offset;
+       size_t length = domain->address_length;
+       bool zero = true;
+
+       // A mask starts with zeros, after the first one, only ones are allowed.
+
+       for (uint32 i = 0; i < length; i++) {
+               if (zero) {
+                       if (bits[i]) {
+                               for (int32 bitMask = 128, bit = 0; bitMask > 0; 
bitMask >>= 1, bit++) {
+                                       if (bits[i] & bitMask) {
+                                               if (((int32)bits[i] + 1) & ((1 
<< (bit + 1)) - 1))
+                                                       return false;
+
+                                               break;
+                                       }
+                               }
+                       }
+               } else if (bits[i] != 0xff)
+                       return false;
+       }
+
+       return true;
+}
+
+
 static status_t
-copy_address(const sockaddr *from, sockaddr **to, sockaddr *mask = NULL)
+copy_address(net_domain_private *domain, const sockaddr *from, sockaddr **to,
+       bool replaceWithZeros = false, sockaddr *mask = NULL)
 {
-       if (from == NULL)
-               return B_OK;
+       if (replaceWithZeros) {
+               size_t length = domain->address_offset + domain->address_length;
+               length = max_c(length, sizeof(sockaddr));
+               *to = (sockaddr *)malloc(length);
+               if (*to == NULL)
+                       return B_NO_MEMORY;
 
-       *to = (sockaddr *)malloc(from->sa_len);
-       if (*to == NULL)
-               return B_NO_MEMORY;
+               memset(*to, 0, length);
+               (*to)->sa_family = domain->family;
+               (*to)->sa_len = length;
+       } else {
+               if (from == NULL)
+                       return B_OK;
 
-       memcpy(*to, from, from->sa_len);
+               *to = (sockaddr *)malloc(from->sa_len);
+               if (*to == NULL)
+                       return B_NO_MEMORY;
 
-       if (mask != NULL) {
-               // TODO: this only works for IPv4!
-               // mask off unused bits from the address
-               ((sockaddr_in *)*to)->sin_addr.s_addr &= ((sockaddr_in 
*)mask)->sin_addr.s_addr;
+               memcpy(*to, from, from->sa_len);
+
+               if (mask != NULL) {
+                       // TODO: this only works for IPv4!
+                       // mask off unused bits from the address
+                       ((sockaddr_in *)*to)->sin_addr.s_addr &= ((sockaddr_in 
*)mask)->sin_addr.s_addr;
+               }
        }
        return B_OK;
 }
@@ -97,14 +165,15 @@
 
 
 static bool
-equal_addresses(sockaddr *a, sockaddr *b)
+equal_addresses(net_domain_private *domain, sockaddr *a, sockaddr *b)
 {
        if (a == NULL && b == NULL)
                return true;
-       if (a == NULL && b != NULL || a != NULL && b == NULL)
+       if (a != NULL && b == NULL || a == NULL || b != NULL)
                return false;
 
-       return !memcmp(a, b, a->sa_len);
+       return !memcmp((uint8 *)a + domain->address_offset,
+               (uint8 *)b + domain->address_offset, domain->address_length);
 }
 
 
@@ -117,9 +186,11 @@
        while (iterator.HasNext()) {
                net_route_private *route = iterator.Next();
 
-               if (equal_addresses(route->destination, 
description->destination)
-                       && equal_addresses(route->destination, 
description->destination)
-                       && equal_addresses(route->destination, 
description->destination))
+               if ((route->flags & (RTF_GATEWAY | RTF_HOST | RTF_LOCAL)) ==
+                               (description->flags & (RTF_GATEWAY | RTF_HOST | 
RTF_LOCAL))
+                       && equal_addresses(domain, route->destination, 
description->destination)
+                       && equal_addresses(domain, route->mask, 
description->mask)
+                       && equal_addresses(domain, route->gateway, 
description->gateway))
                        return route;
        }
 
@@ -242,6 +313,11 @@
        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();
 
@@ -303,11 +379,11 @@
                case SIOCDELRT:
                {
                        // add or remove a route
-                       if (length != sizeof(route_entry))
+                       if (length != sizeof(struct ifreq))
                                return B_BAD_VALUE;
 
                        route_entry entry;
-                       if (user_memcpy(&entry, argument, sizeof(route_entry)) 
!= B_OK)
+                       if (user_memcpy(&entry, &((ifreq 
*)argument)->ifr_route, sizeof(route_entry)) != B_OK)
                                return B_BAD_ADDRESS;
 
                        net_route_private route;
@@ -326,41 +402,6 @@
 
                        return remove_route(domain, &route);
                }
-
-               case SIOCGRTSIZE:
-               {
-dprintf("LENGTH = %ld, sizeof(ifconf) == %lu\n", length, sizeof(ifconf));
-//                     if (length != sizeof(ifconf))
-//                             return B_BAD_VALUE;
-
-                       struct ifconf config;
-                       config.ifc_value = 0;
-
-                       RouteList::Iterator iterator = 
domain->routes.GetIterator();
-                       while (iterator.HasNext()) {
-                               net_route_private *route = iterator.Next();
-                               config.ifc_value += IF_NAMESIZE + 
sizeof(route_entry);
-
-                               if (route->destination)
-                                       config.ifc_value += 
route->destination->sa_len;
-                               if (route->mask)
-                                       config.ifc_value += route->mask->sa_len;
-                               if (route->gateway)
-                                       config.ifc_value += 
route->gateway->sa_len;
-                       }
-
-                       return user_memcpy(argument, &config, sizeof(struct 
ifconf));
-               }
-
-               case SIOCGRTTABLE:
-                       if (length != sizeof(ifconf))
-                               return B_BAD_VALUE;
-
-                       struct ifconf config;
-                       if (user_memcpy(&config, argument, sizeof(struct 
ifconf)) < B_OK)
-                               return B_BAD_ADDRESS;
-
-                       return list_routes(domain, config.ifc_buf, 
config.ifc_len);
        }
        return B_BAD_VALUE;
 }
@@ -381,16 +422,19 @@
        if (domain == NULL || newRoute == NULL || newRoute->interface == 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))
+               || ((newRoute->flags & RTF_GATEWAY) != 0 && newRoute->gateway 
== NULL)
+               || !check_mask(domain, newRoute->mask))
                return B_BAD_VALUE;
 
        net_route_private *route = new (std::nothrow) net_route_private;
        if (route == NULL)
                return B_NO_MEMORY;
 
-       if (copy_address(newRoute->destination, &route->destination, 
newRoute->mask) != B_OK
-               || copy_address(newRoute->mask, &route->mask) != B_OK
-               || copy_address(newRoute->gateway, &route->gateway) != B_OK) {
+       if (copy_address(domain, newRoute->destination, &route->destination,
+                               (newRoute->flags & RTF_DEFAULT) != 0, 
newRoute->mask) != B_OK
+               || copy_address(domain, newRoute->mask, &route->mask,
+                               (newRoute->flags & RTF_DEFAULT) != 0) != B_OK
+               || copy_address(domain, newRoute->gateway, &route->gateway) != 
B_OK) {
                delete route;
                return B_NO_MEMORY;
        }
@@ -413,13 +457,12 @@
 
                // if the before mask is larger than the one of the route, we 
can insert it
                // before that route.
+
                if (before->mask == NULL && route->mask == NULL)
                        break;
-               if (before->mask != NULL && route->mask != NULL) {
-                       in_addr_t beforeMask = ((sockaddr_in 
*)before->mask)->sin_addr.s_addr;
-                       if ((beforeMask | ((sockaddr_in 
*)route->mask)->sin_addr.s_addr) == beforeMask)
-                               break;
-               }
+               if (before->mask != NULL && route->mask != NULL
+                       && first_bit(domain, before->mask) < first_bit(domain, 
route->mask))
+                       break;
        }
 
        domain->routes.Insert(before, route);

Other related posts: