/* raceuid.c -- DF-3467 hammer: race in_pcbdetach() kfree(inp) against
 * ipfw3's check_uid (ip_fw3_match_guid) lookup+deref on the OUTPUT path.
 * Threads pinned to different CPUs; each does socket/connect/send/close
 * loops to 10.0.2.2:9 so packets traverse ether_output (ipfw3 runs in the
 * sender thread) while close frees the pcb (hash removal + deferred free).
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>

#define NTH 6
#define NITER 200000

static volatile int stop = 0;

/* DFly: no cpuset_setaffinity; rely on the LWKT scheduler spreading
 * the 6 busy threads across the 6 CPUs. */
static void pin(int cpu) { (void)cpu; }

static void *
worker(void *arg)
{
	long id = (long)arg;
	struct sockaddr_in dst;
	int i, fd;
	char buf[64];

	pin(id % 6);
	memset(&dst, 0, sizeof(dst));
	dst.sin_family = AF_INET;
	dst.sin_port = htons(9);
	dst.sin_addr.s_addr = inet_addr("10.0.2.2");

	for (i = 0; i < NITER && !stop; i++) {
		fd = socket(AF_INET, SOCK_DGRAM, 0);
		if (fd < 0) break;
		connect(fd, (struct sockaddr *)&dst, sizeof(dst));
		send(fd, buf, sizeof(buf), 0);
		close(fd);
	}
	return (NULL);
}

int main(int argc, char **argv)
{
	pthread_t th[NTH];
	int i;
	int secs = argc > 1 ? atoi(argv[1]) : 60;
	printf("racing %d threads x %d iters each (uid match rule must be loaded)\n",
	    NTH, NITER);
	for (i = 0; i < NTH; i++)
		pthread_create(&th[i], NULL, worker, (void *)(long)i);
	for (i = 0; i < NTH; i++)
		pthread_join(th[i], NULL);
	printf("RACEUID-DONE no panic\n");
	return (0);
}
