While interface going down and output stopped, packets could rest in
`if_snd' queue. So the (!ifq_empty(&sc->sc_if.if_snd)) condition will
always be true and wg_peer_destroy() will sleep until interface became
up and stuck packets transmitted.
Check IFF_RUNNING flag within (!ifq_empty(&sc->sc_if.if_snd)) loop in
wg_peer_destroy(). If the flag is not set that means interface is down,
so drain the `if_snd' queue manually to prevent wg_peer_destroy() stuck.
Problem reported and fix tested by Kirill Miazine.
ok bluhm@
-/* $OpenBSD: if_wg.c,v 1.31 2023/09/26 15:16:44 sthen Exp $ */
+/* $OpenBSD: if_wg.c,v 1.32 2023/10/23 10:22:05 mvs Exp $ */
/*
* Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
NET_LOCK();
while (!ifq_empty(&sc->sc_if.if_snd)) {
+ /*
+ * XXX: `if_snd' of stopped interface could still
+ * contain packets
+ */
+ if (!ISSET(sc->sc_if.if_flags, IFF_RUNNING)) {
+ ifq_purge(&sc->sc_if.if_snd);
+ continue;
+ }
NET_UNLOCK();
tsleep_nsec(sc, PWAIT, "wg_ifq", 1000);
NET_LOCK();