From df95b1003c8e7564da73de92403013763eb028fe Mon Sep 17 00:00:00 2001
From: Harald Hoyer <harald@redhat.com>
Date: Mon, 14 Dec 2015 13:10:05 +0100
Subject: [PATCH] network: fix carrier detection

rename iface_has_link() to iface_has_carrier() to clarify usage

Only assign static "wildcard interface" settings, if the interface has a
carrier.

If the interface name was specified with a name, do not do carrier
checking for static configurations.
---
 modules.d/40network/ifup.sh    | 42 ++++++++++++++++++++-----------------
 modules.d/40network/net-lib.sh | 47 ++++++++++++++++++++++++++----------------
 2 files changed, 52 insertions(+), 37 deletions(-)

diff --git a/modules.d/40network/ifup.sh b/modules.d/40network/ifup.sh
index 109fb4b7..eca74788 100755
--- a/modules.d/40network/ifup.sh
+++ b/modules.d/40network/ifup.sh
@@ -100,7 +100,7 @@ do_dhcp() {
 
     [ -e /tmp/dhclient.$netif.pid ] && return 0
 
-    if ! iface_has_link $netif; then
+    if ! iface_has_carrier $netif; then
         warn "No carrier detected on interface $netif"
         return 1
     fi
@@ -150,7 +150,10 @@ do_ipv6auto() {
 do_static() {
     strglobin $ip '*:*:*' && load_ipv6
 
-    if ! linkup $netif; then
+    if [ -z "$dev" ] && ! iface_has_carrier "$netif"; then
+        warn "No carrier detected on interface $netif"
+        return 1
+    elif ! linkup "$netif"; then
         warn "Could not bring interface $netif up!"
         return 1
     fi
@@ -375,27 +378,28 @@ for p in $(getargs ip=); do
     done
     ret=$?
 
-    > /tmp/net.${netif}.up
+    if [ $ret -eq 0 ]; then
+        > /tmp/net.${netif}.up
 
-    if [ -e /sys/class/net/${netif}/address ]; then
-        > /tmp/net.$(cat /sys/class/net/${netif}/address).up
-    fi
+        if [ -e /sys/class/net/${netif}/address ]; then
+            > /tmp/net.$(cat /sys/class/net/${netif}/address).up
+        fi
 
-    case $autoconf in
-        dhcp|on|any|dhcp6)
+        case $autoconf in
+            dhcp|on|any|dhcp6)
             ;;
-        *)
-            if [ $ret -eq 0 ]; then
-                setup_net $netif
-                source_hook initqueue/online $netif
-                if [ -z "$manualup" ]; then
-                    /sbin/netroot $netif
+            *)
+                if [ $ret -eq 0 ]; then
+                    setup_net $netif
+                    source_hook initqueue/online $netif
+                    if [ -z "$manualup" ]; then
+                        /sbin/netroot $netif
+                    fi
                 fi
-            fi
-            ;;
-    esac
-
-    exit 0
+                ;;
+        esac
+        exit $ret
+    fi
 done
 
 # netif isn't the top stack? Then we should exit here.
diff --git a/modules.d/40network/net-lib.sh b/modules.d/40network/net-lib.sh
index 135c3787..256826e6 100755
--- a/modules.d/40network/net-lib.sh
+++ b/modules.d/40network/net-lib.sh
@@ -537,22 +537,20 @@ wait_for_if_up() {
 
     while [ $cnt -lt $timeout ]; do
         li=$(ip -o link show up dev $1)
-        if ! strstr "$li" "NO-CARRIER"; then
-            if [ -n "$li" ]; then
-                case "$li" in
-                    *\<UP*)
-                        return 0;;
-                    *\<*,UP\>*)
-                        return 0;;
-                    *\<*,UP,*\>*)
-                        return 0;;
-                esac
-            fi
-            if strstr "$li" "LOWER_UP" \
-                    && strstr "$li" "state UNKNOWN" \
-                    && ! strstr "$li" "DORMANT"; then
-                return 0
-            fi
+        if [ -n "$li" ]; then
+            case "$li" in
+                *\<UP*)
+                    return 0;;
+                *\<*,UP\>*)
+                    return 0;;
+                *\<*,UP,*\>*)
+                    return 0;;
+            esac
+        fi
+        if strstr "$li" "LOWER_UP" \
+                && strstr "$li" "state UNKNOWN" \
+                && ! strstr "$li" "DORMANT"; then
+            return 0
         fi
         sleep 0.1
         cnt=$(($cnt+1))
@@ -620,7 +618,7 @@ type hostname >/dev/null 2>&1 || \
     cat /proc/sys/kernel/hostname
 }
 
-iface_has_link() {
+iface_has_carrier() {
     local cnt=0
     local interface="$1" flags=""
     [ -n "$interface" ] || return 2
@@ -631,14 +629,27 @@ iface_has_link() {
     timeout=$(($timeout*10))
 
     linkup "$1"
+
+    li=$(ip -o link show up dev $1)
+    strstr "$li" "NO-CARRIER" && _no_carrier_flag=1
+
     while [ $cnt -lt $timeout ]; do
-        [ "$(cat $interface/carrier)" = 1 ] && return 0
+        if [ -n "$_no_carrier_flag" ]; then
+            # NO-CARRIER flag was cleared
+            strstr "$li" "NO-CARRIER" || return 0
+        fi
+        # double check the syscfs carrier flag
+        [ -e "$interface/carrier" ] && [ "$(cat $interface/carrier)" = 1 ] && return 0
         sleep 0.1
         cnt=$(($cnt+1))
     done
     return 1
 }
 
+iface_has_link() {
+    iface_has_carrier "$@"
+}
+
 find_iface_with_link() {
     local iface_path="" iface=""
     for iface_path in /sys/class/net/*; do
