/*
 * DF-0414 sanity check: a WELL-FORMED PPPoE PADI with ph->length matching
 * the actual payload should NOT be rejected by the fix. This proves the
 * fix is precise and doesn't break legitimate PPPoE traffic.
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <netgraph.h>
#include <netgraph/ng_message.h>
#include <arpa/inet.h>

#define ETHERTYPE_PPPOE_DISC 0x8863
#define PADI_CODE            0x09

int main(void) {
    int cs = -1, ds = -1, rc;
    NgSetErrLog((void(*)(const char*, ...))printf,
                (void(*)(const char*, ...))printf);
    if (NgMkSockNode(NULL, &cs, &ds) < 0) return 2;

    struct ngm_mkpeer mp;
    memset(&mp, 0, sizeof(mp));
    strlcpy(mp.type, "pppoe", sizeof(mp.type));
    strlcpy(mp.ourhook, "mydata", sizeof(mp.ourhook));
    strlcpy(mp.peerhook, "ethernet", sizeof(mp.peerhook));
    if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
        fprintf(stderr, "MKPEER: %s\n", strerror(errno)); return 3;
    }

    /* Well-formed PADI: eth(14) + pppoe(6) + one SRV_NAME tag (4 bytes empty)
     * ph->length MUST equal the actual payload = 4 bytes (the tag size).
     * Total frame = 24 bytes. */
    unsigned char frame[24];
    memset(frame, 0, sizeof(frame));
    memset(frame + 0, 0xff, 6);
    frame[6]=0x00; frame[7]=0x11; frame[8]=0x22;
    frame[9]=0x33; frame[10]=0x44; frame[11]=0x55;
    frame[12] = 0x88; frame[13] = 0x63;
    frame[14] = 0x11; frame[15] = PADI_CODE;
    frame[16] = 0x00; frame[17] = 0x00;
    frame[18] = 0x00; frame[19] = 0x04;       /* ph->length = 4 (matches actual) */
    frame[20] = 0x01; frame[21] = 0x01;       /* tag_type = PTT_SRV_NAME */
    frame[22] = 0x00; frame[23] = 0x00;       /* tag_len = 0 */

    fprintf(stderr, "[*] sending well-formed PADI (ph->length=4, matches payload)\n");
    rc = NgSendData(ds, "mydata", frame, sizeof(frame));
    if (rc < 0) {
        fprintf(stderr, "[!] NgSendData failed: %s\n", strerror(errno));
        fprintf(stderr, "[!] If this is EMSGSIZE, the fix is INCORRECTLY rejecting valid packets!\n");
        return 4;
    }
    /* rc==0 means ng_pppoe accepted the frame. ENETUNREACH (no matching service)
     * would still be propagated, but EMSGSIZE means the fix rejected it. */
    fprintf(stderr, "[+] NgSendData returned %d (frame accepted by ng_pppoe)\n", rc);
    fprintf(stderr, "[+] Fix correctly distinguishes valid ph->length from malicious.\n");
    return 0;
}
