/* DF-1347 amd_Reselect: cur_target = ffs(HostID_xor) - 1 → -1 when x==0 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define AMD_MAX_TARGETS 16
struct amd_softc {
    int tinfo_sync_period[AMD_MAX_TARGETS];
    int tinfo_sync_offset[AMD_MAX_TARGETS];
    void *untagged_srbs[AMD_MAX_TARGETS][8];
    int disc_count[AMD_MAX_TARGETS][8];
    int cur_target, cur_lun;
};

static int reselect_vuln(struct amd_softc *s, uint8_t fifo_id, uint8_t HostID_Bit){
    s->cur_target = fifo_id ^ HostID_Bit;
    s->cur_target = ffs(s->cur_target) - 1;   /* -1 when 0 */
    s->cur_lun = 0;
    int t = s->cur_target;
    int period = s->tinfo_sync_period[t];     /* OOB when t==-1 */
    int off = s->tinfo_sync_offset[t];
    int dc = s->disc_count[t][s->cur_lun];
    void *a = s->untagged_srbs[t][s->cur_lun];
    return period + off + dc + (a!=NULL);
}
static int reselect_fixed(struct amd_softc *s, uint8_t fifo_id, uint8_t HostID_Bit){
    s->cur_target = fifo_id ^ HostID_Bit;
    /* FIX: reject x==0 or non-power-of-2 before ffs */
    if (s->cur_target == 0 || (s->cur_target & (s->cur_target - 1)) != 0) {
        return -1;
    }
    s->cur_target = ffs(s->cur_target) - 1;
    s->cur_lun = 0;
    int t = s->cur_target;
    int period = s->tinfo_sync_period[t];
    int off = s->tinfo_sync_offset[t];
    int dc = s->disc_count[t][s->cur_lun];
    void *a = s->untagged_srbs[t][s->cur_lun];
    return period + off + dc + (a!=NULL);
}

int main(void){
    struct amd_softc sc; memset(&sc, 0, sizeof(sc));
    /* malicious target drives bogus reselect ID -> after XOR with HostID_Bit, result is 0 */
    printf("== BEFORE-FIX (vulnerable) ==\n");
    int rc = reselect_vuln(&sc, 0x01 /* HostID bit */, 0x01);
    printf("BUG: cur_target=%d (ffs(0)-1) -> indexed tinfo[-1], untagged_srbs[-1][0], disc_count[-1][0] OOB\n", sc.cur_target);
    printf("== AFTER-FIX ==\n");
    memset(&sc, 0, sizeof(sc));
    int rc2 = reselect_fixed(&sc, 0x01, 0x01);
    if (rc2 == -1) printf("FIX: invalid reselect id rejected, cur_target untouched\n");
    return 0;
}
