/*
 * Copyright (c) 2008 Paul de Weerd <weerd@weirdnet.nl>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <net/if.h>
#include <net/bpf.h>

#define MACLENGTH 6
#define MAXMTU 2 * MACLENGTH + 2 + 1500
#define MINMTU 2 * MACLENGTH + 2 + 46

__dead void usage(void);
int bpf_open(void);

__dead void
usage(void) {
	extern char *__progname;

	fprintf(stderr, "usage: %s [some options]\n", __progname);
	exit(1);
}

int
bpf_open(void) {
	/* straight from /usr/src/usr.sbin/rarpd/rarpd.c */

	int fd, n = 0;
	char device[sizeof "/dev/bpf0000000000"];

	do {
		(void) snprintf(device, sizeof device, "/dev/bpf%d", n++);
		fd = open(bpfdev, O_RDWR, 0);
	} while (fd < 0 && errno == EBUSY);

	if (fd == -1)
		err(1, "%s", device);

	return fd;
}

int
main(int argc, char *argv[]) {
	int verbose = 0;
	int bpf, ret, i, c;
	char interface[IFNAMSIZ];
	char srcmac[MACLENGTH];
	char dstmac[MACLENGTH];
	struct ifreq bound_if;
	char frame[100];

	while ((c = getopt(argc, argv, "D:R:S:c:d:fi:p:r:s:vw:")) != -1) {
		switch (c) {
		case 'D': /* destination IP */
			fprintf(stderr, "-%c not implemented yet\n", c);
			exit(1);
			break;
		case 'R': /* random delay median */
			fprintf(stderr, "-%c not implemented yet\n", c);
			exit(1);
			break;
		case 'S': /* source IP */
			fprintf(stderr, "-%c not implemented yet\n", c);
			exit(1);
			break;
		case 'c': /* packet count */
			fprintf(stderr, "-%c not implemented yet\n", c);
			exit(1);
			break;
		case 'd': /* destination MAC */
			fprintf(stderr, "-%c not implemented yet\n", c);
			exit(1);
			break;
		case 'f': /* flooding */
			fprintf(stderr, "-%c not implemented yet\n", c);
			exit(1);
			break;
		case 'i': /* interface */
			strlcpy(bound_if.ifr_name, optarg, IFNAMSIZ);
			break;
		case 'p': /* payload */
			fprintf(stderr, "-%c not implemented yet\n", c);
			exit(1);
			break;
		case 'r': /* random delay range */
			fprintf(stderr, "-%c not implemented yet\n", c);
			exit(1);
			break;
		case 's': /* source MAC address */
			fprintf(stderr, "-%c not implemented yet\n", c);
			exit(1);
			break;
		case 'v': /* verbosity increment */
			verbose++;
			break;
		case 'w': /* fixed delay */
			fprintf(stderr, "-%c not implemented yet\n", c);
			exit(1);
			break;
		default:
			usage();
		}
	}

	bpf = bpf_open;

	if (verbose == 1)
		printf("%s: Opened %s (fd %d)\n", argv[0], bpfdev, bpf);

	if (ioctl(bpf, BIOCSETIF, &bound_if) == -1)
		err(1, "%s", bound_if.ifr_name);

	if (verbose == 1)
		printf("%s: Bound fd %d to %s\n", argv[0], bpf, argv[1]);

	ret = 1;
	if (ioctl(bpf, BIOCSHDRCMPLT, &ret) == -1)
		err(1, "%s", bound_if.ifr_name);

	if (verbose == 1)
		printf("%s: configured fd %d to disable header completion\n",
		    argv[0], bpf, argv[1]);

	/* Arp reply from 10.0.0.1 02:02:02:02:02:02 to */
	/* 10.0.0.1 ff:ff:ff:ff:ff:ff                   */

	/* DST MAC ff:ff:ff:ff:ff:ff */
	frame[0]  = 0xff; frame[1]  = 0xff; frame[2]  = 0xff;
	frame[3]  = 0xff; frame[4]  = 0xff; frame[5]  = 0xff;
	/* SRC MAC 02:02:02:02:02:02 */
	frame[6]  = 0x02; frame[7]  = 0x02; frame[8]  = 0x02;
	frame[9]  = 0x02; frame[10] = 0x02; frame[11] = 0x02;
	/* Ethernet type ARP 0x0806 */
	frame[12] = 0x08; frame[13] = 0x06;
	/* Hardware type Ethernet 0x0001 */
	frame[14] = 0x00; frame[15] = 0x01;
	/* Protocol type IP 0x0800 */
	frame[16] = 0x08; frame[17] = 0x00;
	/* Ethernet address length 0x06 */
	frame[18] = 0x06;
	/* IP address length 0x04 */
	frame[19] = 0x04;
	/* ARP type reply 0x0001 */
	frame[20] = 0x00; frame[21] = 0x01;
	/* Requester SRC MAC 02:02:02:02:02:02 */
	frame[22] = 0x02; frame[23] = 0x02; frame[24] = 0x02;
	frame[25] = 0x02; frame[26] = 0x02; frame[27] = 0x02;
	/* Requester IP address 10.0.0.1 */
	frame[28] = 0x0a; frame[29] = 0x00;
	frame[30] = 0x00; frame[31] = 0x01;
	/* Destination MAC address ff:ff:ff:ff:ff:ff */
	frame[32] = 0xff; frame[33] = 0xff; frame[34] = 0xff;
	frame[35] = 0xff; frame[36] = 0xff; frame[37] = 0xff;
	/* Destination IP address 10.0.0.1 */
	frame[38] = 0x0a; frame[39] = 0x00;
	frame[40] = 0x00; frame[41] = 0x01;

	while ((ret = write(bpf, frame, 60 /*sizeof(frame)*/)) == 0)
		printf(".");

	if (verbose == 1)
		printf("%s: wrote %d bytes to fd %d\n", argv[0], ret, bpf);

	close(bpf);

	return 0;
}
