#!/bin/bash
# NetworkManager dispatcher script: 10-link-local-mgmt
#
# Temporarily suppresses IPv4 link-local when a DHCP address is available,
# using nmcli device modify (active session only, NOT saved to the profile).
# The persistent profile always keeps ipv4.link-local=enabled so that
# direct-connect (no DHCP) plug-ins always activate and trigger events.
# Avahi is reloaded on each event — no /etc/avahi/hosts file, avahi uses
# natural per-interface advertisement so each segment gets the right IP.
#
# Triggers: up, down, dhcp4-change on ethernet interfaces
# Install to: /etc/NetworkManager/dispatcher.d/10-link-local-mgmt
# Permissions: root:root 0755

INTERFACE="$1"
ACTION="$2"
# Only handle ethernet interfaces
if [[ ! "$INTERFACE" =~ ^eth ]]; then
    exit 0
fi

reload_avahi() {
    systemctl reload avahi-daemon 2>/dev/null || systemctl restart avahi-daemon 2>/dev/null
    logger -t nm-link-local "[$INTERFACE] $ACTION — avahi reloaded"
}

case "$ACTION" in
    up)
        # On 'up' the interface may still carry a stale DHCP address from the previous
        # session (NM hasn't cleaned it up yet). Reading ip-addr here is unreliable.
        # Always re-enable link-local as a clean slate; let dhcp4-change suppress it
        # later if a real DHCP lease is obtained.
        logger -t nm-link-local "[$INTERFACE] Up — ensuring link-local active (clean slate)"
        (sleep 2 && nmcli device modify "$INTERFACE" ipv4.link-local enabled 2>/dev/null \
            && logger -t nm-link-local "[$INTERFACE] Link-local explicitly enabled on up") &
        reload_avahi
        ;;

    dhcp4-change)
        # dhcp4-change fires only when DHCP actually succeeds (new/renewed lease).
        # At this point the DHCP IP is reliably present — safe to read and suppress link-local.
        DHCP_IP=$(ip -4 addr show "$INTERFACE" 2>/dev/null \
            | grep -oP '(?<=inet\s)\d+(\.\d+){3}' \
            | grep -v '^127\.' \
            | grep -v '^169\.254\.' \
            | head -n1)

        if [ -n "$DHCP_IP" ]; then
            logger -t nm-link-local "[$INTERFACE] DHCP $DHCP_IP confirmed — suppressing link-local (session only)"
            # Run in background after a delay — nmcli blocks on NM, which is waiting for
            # this dispatcher to return, causing a deadlock if called synchronously.
            (sleep 2 && nmcli device modify "$INTERFACE" ipv4.link-local disabled 2>/dev/null \
                && logger -t nm-link-local "[$INTERFACE] Link-local suppressed for current session") &
        fi
        reload_avahi
        ;;

    down)
        # NOTE: a carrier-change does NOT fully reset session-level 'device modify' state.
        # The re-enable is therefore handled in the 'up' handler when no DHCP is detected.
        logger -t nm-link-local "[$INTERFACE] Down — link-local will be re-enabled on next up without DHCP"
        reload_avahi
        ;;
esac
