/*
 * DF-5248 - run_drain_fifo() unbounded loop on device-controlled/dataless
 *           TX_STAT_FIFO reads                          if_run.c:2503-2563
 * =====================================================================
 * static void
 * run_drain_fifo(void *arg)
 * {
 *     for (;;) {
 *         run_read(sc, RT2860_TX_STAT_FIFO, &stat);      <-- 2515 RETURN
 *         if (!(stat & RT2860_TXQ_VLD))                  <-- VALUE IGNORED
 *             break;
 *         ...
 *     }
 * }
 *
 * RT2860_TXQ_VLD == (1 << 0)                     if_runreg.h:664
 * run_read() on USB failure sets *val = 0xffffffff  if_run.c:1254
 *
 * => every failed control read yields 0xffffffff which HAS bit0 set
 *    (and wcid 0xff > RT2870_WCID_MAX so the `continue' path is taken),
 *    so a device that stops responding (unplug, hostile stall) or a
 *    hostile device that always returns VLD makes the loop unbounded.
 *    Each iteration burns up to 10 x 250 ms of control-request retries
 *    (run_do_request, if_run.c:1232-1240), wedging the ieee80211 task
 *    forever; run_detach()'s ieee80211_draintask() (if_run.c:879-880)
 *    then blocks device_detach() indefinitely.
 *
 * This harness proves the loop condition never terminates under either
 * condition, using the exact kernel expressions.
 */
#include <stdio.h>

#define RT2860_TXQ_VLD      (1 << 0)
#define RT2860_TXQ_ACKREQ   (1 << 7)
#define RT2860_TXQ_WCID_SHIFT 8
#define RT2870_WCID_MAX     64

/* mock run_read(): error => *val = 0xffffffff, returns nonzero (ignored) */
static int usb_error;                 /* set by the scenario             */
static unsigned hostile_stat;         /* what a lying device returns     */

static int run_read(unsigned *val)
{
    if (usb_error) { *val = 0xffffffffu; return (-1); }
    *val = hostile_stat; return (0);
}

int main(void)
{
    unsigned stat;
    unsigned char wcid;
    unsigned long iters;
    const unsigned long CAP = 1000000;   /* kernel has NO cap; we cap to
                                            prove non-termination */

    /* scenario 1: device unplugged / control transfer fails forever */
    usb_error = 1;
    for (iters = 0; iters < CAP; iters++) {
        run_read(&stat);
        if (!(stat & RT2860_TXQ_VLD))
            break;
        wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
        if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX || wcid == 0)
            continue;                 /* loop again */
    }
    printf("scenario 1 (persistent read error, *val=0xffffffff): "
        "%s after %lu iterations (cap %lu)\n",
        iters == CAP ? "NEVER TERMINATES" : "terminated", iters, CAP);

    /* scenario 2: hostile device always returns VLD */
    usb_error = 0;
    hostile_stat = RT2860_TXQ_VLD | RT2860_TXQ_ACKREQ | (0x42u << RT2860_TXQ_WCID_SHIFT);
    for (iters = 0; iters < CAP; iters++) {
        run_read(&stat);
        if (!(stat & RT2860_TXQ_VLD))
            break;
        wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
        if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX || wcid == 0)
            continue;
    }
    printf("scenario 2 (hostile device, VLD always set):         "
        "%s after %lu iterations (cap %lu)\n",
        iters == CAP ? "NEVER TERMINATES" : "terminated", iters, CAP);
    return 0;
}
