shill: connection: Use peer-to-peer if netmask is all-ones

Special case IP configurations where the netmask is set to
the "all-ones" address.  Since this netmask indicates that
no other addresses should be reachable via broadcast domain,
this should imply that there is only a point-to-point link
with the gateway.

BUG=chrome-os-partner:10676
TEST=New unit test

Change-Id: I51f6cb8a1e71376f75be5122426172a6929e09d1
Reviewed-on: https://gerrit.chromium.org/gerrit/25910
Reviewed-by: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
Commit-Ready: Paul Stewart <pstew@chromium.org>
diff --git a/connection.cc b/connection.cc
index 071ce8c..3f76578 100644
--- a/connection.cc
+++ b/connection.cc
@@ -274,16 +274,23 @@
                << " is unreachable from local address/prefix "
                << local->ToString() << "/" << local->prefix();
 
+  bool found_new_prefix = false;
   size_t original_prefix = local->prefix();
-  size_t prefix = original_prefix - 1;
-  for (; prefix >= local->GetMinPrefixLength(); --prefix) {
-    local->set_prefix(prefix);
-    if (local->CanReachAddress(gateway)) {
-      break;
+  // Only try to expand the netmask if the configured prefix is
+  // less than "all ones".  This special-cases the "all-ones"
+  // prefix as a forced conversion to point-to-point networking.
+  if (local->prefix() < IPAddress::GetMaxPrefixLength(local->family())) {
+    size_t prefix = original_prefix - 1;
+    for (; prefix >= local->GetMinPrefixLength(); --prefix) {
+      local->set_prefix(prefix);
+      if (local->CanReachAddress(gateway)) {
+        found_new_prefix = true;
+        break;
+      }
     }
   }
 
-  if (prefix < local->GetMinPrefixLength()) {
+  if (!found_new_prefix) {
     // Restore the original prefix since we cannot find a better one.
     local->set_prefix(original_prefix);
     DCHECK(!peer->IsValid());
@@ -292,7 +299,8 @@
     return true;
   }
 
-  LOG(WARNING) << "Mitigating this by setting local prefix to " << prefix;
+  LOG(WARNING) << "Mitigating this by setting local prefix to "
+               << local->prefix();
   return true;
 }