Stop using netmask in the framework

This pushes prefixLength down as far as we can.

bug:2542681
Change-Id: I94b7cde9d10e97ee2c071d92f25555cff5934f0b
diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c
index ff00432..5039e26 100644
--- a/libnetutils/dhcpclient.c
+++ b/libnetutils/dhcpclient.c
@@ -93,6 +93,8 @@
     return inet_ntoa(in_addr);
 }
 
+extern int ipv4NetmaskToPrefixLength(in_addr_t mask);
+
 typedef struct dhcp_info dhcp_info;
 
 struct dhcp_info {
@@ -100,7 +102,7 @@
 
     uint32_t ipaddr;
     uint32_t gateway;
-    uint32_t netmask;
+    uint32_t prefixLength;
 
     uint32_t dns1;
     uint32_t dns2;
@@ -111,13 +113,13 @@
 
 dhcp_info last_good_info;
 
-void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *mask,
+void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *prefixLength,
                    uint32_t *dns1, uint32_t *dns2, uint32_t *server,
                    uint32_t *lease)
 {
     *ipaddr = last_good_info.ipaddr;
     *gateway = last_good_info.gateway;
-    *mask = last_good_info.netmask;
+    *prefixLength = last_good_info.prefixLength;
     *dns1 = last_good_info.dns1;
     *dns2 = last_good_info.dns2;
     *server = last_good_info.serveraddr;
@@ -127,7 +129,7 @@
 static int dhcp_configure(const char *ifname, dhcp_info *info)
 {
     last_good_info = *info;
-    return ifc_configure(ifname, info->ipaddr, info->netmask, info->gateway,
+    return ifc_configure(ifname, info->ipaddr, info->prefixLength, info->gateway,
                          info->dns1, info->dns2);
 }
 
@@ -153,8 +155,7 @@
             dhcp_type_to_name(info->type), info->type);
     strcpy(addr, ipaddr(info->ipaddr));
     strcpy(gway, ipaddr(info->gateway));
-    strcpy(mask, ipaddr(info->netmask));
-    LOGD("ip %s gw %s mask %s", addr, gway, mask);
+    LOGD("ip %s gw %s prefixLength %d", addr, gway, info->prefixLength);
     if (info->dns1) LOGD("dns1: %s", ipaddr(info->dns1));
     if (info->dns2) LOGD("dns2: %s", ipaddr(info->dns2));
     LOGD("server %s, lease %d seconds",
@@ -196,7 +197,7 @@
         }
         switch(opt) {
         case OPT_SUBNET_MASK:
-            if (optlen >= 4) memcpy(&info->netmask, x, 4);
+            if (optlen >= 4) info->prefixLength = ipv4NetmaskToPrefixLength((int)x);
             break;
         case OPT_GATEWAY:
             if (optlen >= 4) memcpy(&info->gateway, x, 4);
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 6788391..e5c58b9 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -51,6 +51,33 @@
 static int ifc_ctl_sock6 = -1;
 void printerr(char *fmt, ...);
 
+in_addr_t prefixLengthToIpv4Netmask(int prefix_length)
+{
+    in_addr_t mask = 0;
+
+    // C99 (6.5.7): shifts of 32 bits have undefined results
+    if (prefix_length <= 0 || prefix_length > 32) {
+        return 0;
+    }
+
+    mask = ~mask << (32 - prefix_length);
+    mask = htonl(mask);
+
+    return mask;
+}
+
+int ipv4NetmaskToPrefixLength(in_addr_t mask)
+{
+    mask = ntohl(mask);
+    int prefixLength = 0;
+    uint32_t m = (uint32_t)mask;
+    while (m & 0x80000000) {
+        prefixLength++;
+        m = m << 1;
+    }
+    return prefixLength;
+}
+
 static const char *ipaddr_to_string(in_addr_t addr)
 {
     struct in_addr in_addr;
@@ -179,10 +206,13 @@
     return ioctl(ifc_ctl_sock, SIOCSIFHWADDR, &ifr);
 }
 
-int ifc_set_mask(const char *name, in_addr_t mask)
+int ifc_set_prefixLength(const char *name, int prefixLength)
 {
     struct ifreq ifr;
+    // TODO - support ipv6
+    if (prefixLength > 32 || prefixLength < 0) return -1;
 
+    in_addr_t mask = prefixLengthToIpv4Netmask(prefixLength);
     ifc_init_ifr(name, &ifr);
     init_sockaddr_in(&ifr.ifr_addr, mask);
 
@@ -206,7 +236,7 @@
     return ret;
 }
 
-int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags)
+int ifc_get_info(const char *name, in_addr_t *addr, int *prefixLength, unsigned *flags)
 {
     struct ifreq ifr;
     ifc_init_ifr(name, &ifr);
@@ -219,11 +249,12 @@
         }
     }
 
-    if (mask != NULL) {
+    if (prefixLength != NULL) {
         if(ioctl(ifc_ctl_sock, SIOCGIFNETMASK, &ifr) < 0) {
-            *mask = 0;
+            *prefixLength = 0;
         } else {
-            *mask = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
+            *prefixLength = ipv4NetmaskToPrefixLength((int)
+                    ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr);
         }
     }
 
@@ -238,21 +269,6 @@
     return 0;
 }
 
-in_addr_t get_ipv4_netmask(int prefix_length)
-{
-    in_addr_t mask = 0;
-
-    // C99 (6.5.7): shifts of 32 bits have undefined results
-    if (prefix_length == 0) {
-        return 0;
-    }
-
-    mask = ~mask << (32 - prefix_length);
-    mask = htonl(mask);
-
-    return mask;
-}
-
 int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length,
       struct in_addr gw)
 {
@@ -265,7 +281,7 @@
     rt.rt_dst.sa_family = AF_INET;
     rt.rt_dev = (void*) ifname;
 
-    netmask = get_ipv4_netmask(prefix_length);
+    netmask = prefixLengthToIpv4Netmask(prefix_length);
     init_sockaddr_in(&rt.rt_genmask, netmask);
     init_sockaddr_in(&rt.rt_dst, dst.s_addr);
     rt.rt_flags = RTF_UP;
@@ -499,7 +515,7 @@
 int
 ifc_configure(const char *ifname,
         in_addr_t address,
-        in_addr_t netmask,
+        uint32_t prefixLength,
         in_addr_t gateway,
         in_addr_t dns1,
         in_addr_t dns2) {
@@ -518,8 +534,8 @@
         ifc_close();
         return -1;
     }
-    if (ifc_set_mask(ifname, netmask)) {
-        printerr("failed to set netmask %s: %s\n", ipaddr_to_string(netmask), strerror(errno));
+    if (ifc_set_prefixLength(ifname, prefixLength)) {
+        printerr("failed to set prefixLength %d: %s\n", prefixLength, strerror(errno));
         ifc_close();
         return -1;
     }