/* DF-3391: ip_fw3_ctl discards ip_fw3_ctl_x() error in its IP_FW_X case
 * (ip_fw3.c:1058-1059).  Reach it with a NESTED opcode: payload opcode 49
 * (IP_FW_X) makes ip_fw3_ctl re-enter ip_fw3_ctl_x, whose inner failure
 * (invalid innermost opcode -> EINVAL, console "ip_fw3_ctl invalid option")
 * is dropped and setsockopt returns 0.  A flat invalid opcode via the glue
 * path propagates correctly (control case). */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#define IP_FW_X_DF 49

int main(void) {
    int s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    if (s < 0) { perror("socket"); return 1; }

    /* control: flat invalid opcode through the glue - error propagates */
    struct { unsigned short opcode; unsigned short pad; char payload[4]; } a;
    a.opcode = 0xbeef; a.pad = 0; memset(a.payload, 0, 4);
    errno = 0;
    int rc1 = setsockopt(s, IPPROTO_IP, IP_FW_X_DF, &a, sizeof(a));
    printf("[control] flat invalid opcode: rc=%d errno=%d (%s)\n",
           rc1, errno, rc1 ? strerror(errno) : "SUCCESS?!");

    /* bug case: nested IP_FW_X opcode -> ip_fw3_ctl case IP_FW_X drops it */
    struct { unsigned short opcode; unsigned short pad;
             unsigned short inner; unsigned short innerpad; } b;
    b.opcode = IP_FW_X_DF; b.pad = 0;
    b.inner = 0xbeef; b.innerpad = 0;
    errno = 0;
    int rc2 = setsockopt(s, IPPROTO_IP, IP_FW_X_DF, &b, sizeof(b));
    printf("[bugcase] nested IP_FW_X opcode: rc=%d errno=%d (%s)\n",
           rc2, errno, rc2 ? strerror(errno) : "SUCCESS despite inner EINVAL");
    close(s);
    return (rc2 == 0) ? 2 : 0;   /* rc2==0 == bug reproduced */
}
