#!/bin/sh
# Le travail du crochet joyeuse-wifi-reveil, detache pour ne pas retarder le
# reveil. Voir l'en-tete de joyeuse-wifi-reveil pour la mesure qui le justifie.
#
# ⚠️ IL JOURNALISE MEME QUAND IL NE FAIT RIEN, et c'est delibere : un crochet
#    silencieux ne se distingue pas d'un crochet qui ne tourne pas. C'est le
#    piege paye ici avec les .post-install, qui ne s'executent jamais sans que
#    rien ne le dise. Une ligne par reveil est le prix de la preuve.

DIRE() { logger -t joyeuse-wifi-reveil "$*"; }

PILOTE=/sys/bus/platform/drivers/ath10k_snoc
CARTE=18800000.wifi

# ☠️☠️ r3 — « LOWER_UP » N'EST PAS UNE PREUVE QUE LE RESEAU EST REVENU.
#    Jusqu'ici ce script concluait « RETABLI » sur le seul drapeau du lien. C'est
#    le motif que ce depot traque partout : un etat vert qui ne dit rien de
#    l'effet. Une interface peut porter LOWER_UP en etant associee a rien, ou
#    associee sans bail. La seule preuve est qu'un paquet fait l'aller-retour.
# ⚠️ Et on laisse du temps AVANT de crier : apres un reveil, l'association puis
#    le bail DHCP prennent quelques secondes. Une alarme prematuree serait pire
#    que pas d'alarme — c'est ainsi qu'on apprend a ignorer un journal.
reseau_repond() {
	essai=0
	while [ "$essai" -lt 4 ]; do
		PASSERELLE=$(ip -4 route show default dev wlan0 2>/dev/null \
			| awk '{ for (i = 1; i <= NF; i++) if ($i == "via") { print $(i + 1); exit } }')
		if [ -n "$PASSERELLE" ] &&
			ping -c1 -W3 -I wlan0 "$PASSERELLE" >/dev/null 2>&1
		then
			return 0
		fi
		sleep 4
		essai=$((essai + 1))
	done
	return 1
}

# 🔑 L'etat de WoWLAN, a chaque reveil, dans la meme ligne. C'est le remede DE
#    FOND (voir 90-joyeuse-wowlan) et il est en cours d'evaluation A/B : sans
#    cette trace, on ne saurait pas, apres coup, si une nuit avait la puce armee
#    ou non. « enabled » n'est pas un reglage, c'est l'effet — cfg80211 ne le pose
#    qu'une fois la configuration wow reellement poussee au peripherique.
wowlan() {
	cat /sys/class/net/wlan0/device/power/wakeup 2>/dev/null || echo inconnu
}

# Le reveil met quelques secondes a se terminer : mac80211 emet son WARN pendant
# device_resume, et NetworkManager retente ensuite tout seul.
sleep 10

# ☠️ LE MARQUEUR EST LE WARN DU NOYAU, PAS L'ETAT DE wlan0. Une interface DOWN
#    peut l'etre parce que le proprietaire a coupe le Wi-Fi — agir la-dessus
#    serait le lui rallumer dans le dos. « Hardware became unavailable upon
#    resume » ne sort QUE sur ce defaut.
if ! journalctl -k --since "-3 min" --no-pager 2>/dev/null \
	| grep -q "Hardware became unavailable upon resume"
then
	if reseau_repond; then
		DIRE "reveil sain (WoWLAN : $(wowlan)) — la passerelle repond"
		exit 0
	fi
	# ⚖️ ON N'AGIT PAS ICI, ET C'EST DELIBERE. Le noyau n'a pas rale : ce n'est
	#    donc pas le 13-bis, et un unbind/bind aveugle couperait un Wi-Fi que le
	#    proprietaire est peut-etre en train d'utiliser — ou repondrait a une box
	#    qui redemarre. On le NOMME, on ne le repare pas.
	DIRE "reveil sans le WARN du 13-bis (WoWLAN : $(wowlan)), MAIS la passerelle ne repond pas"
	DIRE "  etat wlan0 : $(ip -br addr show wlan0 2>&1 | tr -s ' ')"
	exit 0
fi

DIRE "13-bis DETECTE (WoWLAN : $(wowlan)) : « Hardware became unavailable upon resume »"

# Si le proprietaire a coupe le Wi-Fi, on ne le rallume pas.
if rfkill list wifi 2>/dev/null | grep -q "Soft blocked: yes"; then
	DIRE "Wi-Fi coupe par l'utilisateur (rfkill) — on ne touche a rien"
	exit 0
fi

etat() { ip -br link show wlan0 2>/dev/null | grep -c "LOWER_UP"; }

# ☠️ ET « LOWER_UP » NE SUFFIT PAS A CLASSER LE CAS SANS RISQUE. Le WARN du
#    noyau vient de sortir : le drapeau du lien peut etre remonte alors que le
#    firmware est muet — c'est precisement ce qu'a montre la MAC aleatoire du
#    19/08. On ne renonce donc au unbind/bind que si la passerelle REPOND.
if [ "$(etat)" = "1" ]; then
	if reseau_repond; then
		DIRE "wlan0 porte LOWER_UP et la passerelle repond — le noyau a rale, la radio est revenue"
		exit 0
	fi
	DIRE "wlan0 porte LOWER_UP mais la passerelle ne repond pas — on ne s'y fie pas"
fi

DIRE "avant : $(ip -br link show wlan0 2>&1 | tr -s ' ')"

# ☠️☠️ ON VA DIRECTEMENT AU unbind/bind, ET LES DEUX ETAGES DOUX SONT SUPPRIMES.
#    Ils ont ete MESURES sur un vrai 13-bis, le 19/08 a 19:50, et ils ne
#    reparent rien — ils ne font que geler l'appareil :
#
#      19:50:40  etage 1 : ip link set wlan0 up
#      19:51:12    RTNETLINK answers: Operation timed out      <- 32 s perdues
#      19:51:44  etage 2 : nmcli radio wifi off puis on
#      19:52:09    Erreur : NetworkManager n'est pas lance.
#      19:52:49  ECHEC des deux etages
#
#    ⚠️ ET CE « NetworkManager n'est pas lance » EST UN FAUX MESSAGE : mesure
#       ensuite, NM n'etait PAS tombe — « NRestarts=0 », actif sans interruption
#       depuis la veille. nmcli parle a NM par D-Bus ; le bus etait bloque, nmcli
#       a expire, et il a accuse NM. Un message d'erreur qui nomme le mauvais
#       coupable, exactement ce que ce depot traque partout.
#
# 🔑 CE QUI MARCHE, ET C'EST MESURE LE 19/08 A 20:08 : unbind puis bind. Le
#    pilote repasse par probe() au lieu de start(), le QMI repond
#    (« qmi wlan mode req completed: 0 »), et l'association se refait en 6 s.
#    SANS REDEMARRAGE — uptime 21 h 58 apres coup.
#
# ☠️ ET LA PREUVE QUE LE FIRMWARE ETAIT MUET TIENT DANS UNE ADRESSE MAC. Pendant
#    la panne wlan0 portait « 5a:00:32:65:d4:15 » au lieu de
#    « 12:1d:e9:7e:15:91 » : une MAC ALEATOIRE, que mac.c ne tire QUE si
#    device_get_mac_address() ET le firmware echouent tous les deux. Apres le
#    bind, la vraie MAC est revenue.
DIRE "unbind $CARTE"
if ! echo "$CARTE" > "$PILOTE"/unbind 2>/dev/null; then
	DIRE "  le unbind a ete REFUSE — le pilote n'est peut-etre plus la"
	DIRE "  ECHEC : l'appareil a besoin d'un redemarrage"
	exit 1
fi
sleep 3

DIRE "bind $CARTE"
if ! echo "$CARTE" > "$PILOTE"/bind 2>/dev/null; then
	DIRE "  le bind a ete REFUSE — la carte reste sans pilote"
	DIRE "  ECHEC : l'appareil a besoin d'un redemarrage"
	exit 1
fi
sleep 15

# ⚠️ On laisse une seconde chance au lien : l'association peut prendre plus
#    longtemps quand le point d'acces est loin.
if [ "$(etat)" != "1" ]; then
	sleep 20
fi

if [ "$(etat)" = "1" ]; then
	# ☠️ ET ON NE S'ARRETE PAS LA. Le lien remonte ne prouve pas que le reseau est
	#    revenu — c'est justement ce que le 13-bis casse : pendant la panne, wlan0
	#    portait une MAC ALEATOIRE (5a:00:32:65:d4:15 au lieu de 12:1d:e9:7e:15:91),
	#    signe que le firmware etait muet. Un lien qui remonte sans firmware ne
	#    fait rien passer.
	if reseau_repond; then
		DIRE "RETABLI par unbind/bind — la passerelle repond, $(ip -br addr show wlan0 2>&1 | tr -s ' ')"
		exit 0
	fi
	DIRE "unbind/bind : le lien est remonte MAIS la passerelle ne repond pas"
	DIRE "  etat wlan0 : $(ip -br addr show wlan0 2>&1 | tr -s ' ')"
	exit 1
fi

DIRE "ECHEC du unbind/bind — l'appareil a besoin d'un redemarrage"
DIRE "  etat wlan0 : $(ip -br link show wlan0 2>&1 | tr -s ' ')"
exit 1
