/* 
 *  dsrgen
 *
 *  tool for creating DSR/IP packets with payload.
 */

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <libnet.h>
#include <stdlib.h>
#include "dsr_header.h"

#define DSR_PACKET_MAXLEN 1500

char header_file[FILENAME_MAX] = "";
char payload_file[FILENAME_MAX] = "";

int payload_filesize = 0;
int payload_size = 0;

u_char eth_saddr[6];	/* NULL Ethernet saddr */
u_char eth_daddr[6]; 	/* NULL Ethernet daddr */
u_char eth_proto[60];       /* Ethernet protocol */

u_short i_id;		/* IP id */
u_short i_frag;		/* IP frag */
u_long i_des_addr;		/* IP dest addr */
u_long i_src_addr;		/* IP source addr */
u_char i_ttos[90];		/* IP TOS string */
u_char i_ttos_val = 0;	/* final or'd value for ip tos */
u_char i_ttl;		/* IP TTL */

u_char ip_proto[40];

u_char *buf;

char errbuf[256];
char interface[256] = "eth0";

u_short e_proto_val = 0;    /* final resulting value for eth_proto */
u_short ip_proto_val = 0;   /* final resulting value for ip_proto */
struct link_int *l;	

u_char *dsr_packet = NULL;  /* DSR packet */
int dsr_hdr_size = sizeof(struct dsr_hdr) + sizeof(struct dsr_opt_hdr);

int pktcount = 1;        /* How many packets to send */
int sleep_time = 0;            /* How long to sleep */


void load_header(char* filename) {
    FILE *infile;
    char line[256] = "";
    char addr[256];
    struct dsr_hdr dsr_hdr_s;
    struct dsr_opt_hdr dsr_opt_hdr_s;
    int i;
    unsigned int uint[6];
    
    
    infile = fopen(filename, "r");


    /* eth header */
    fgets(line, 256, infile);    sscanf(line, "eth_saddr%x:%x:%x:%x:%x:%x", &(uint[0]), &(uint[1]), &(uint[2]), &(uint[3]), &(uint[4]), &(uint[5]));
    for(i=0; i<6; i++) eth_saddr[i] = uint[i];
    fgets(line, 256, infile);    sscanf(line, "eth_daddr%x:%x:%x:%x:%x:%x", &(uint[0]), &(uint[1]), &(uint[2]), &(uint[3]), &(uint[4]), &(uint[5]));
    for(i=0; i<6; i++) eth_daddr[i] = uint[i];
    fgets(line, 256, infile);    sscanf(line, "eth_proto%s", &(eth_proto[0]));

    if(strstr(eth_proto, "arp")) e_proto_val = e_proto_val | ETHERTYPE_ARP;
    if(strstr(eth_proto, "ip"))  e_proto_val = e_proto_val | ETHERTYPE_IP;


    /* ip header */    
    fgets(line, 256, infile);    sscanf(line, "ip_id%hd", &i_id);
    fgets(line, 256, infile);    sscanf(line, "ip_frag%hd", &i_frag);
    fgets(line, 256, infile);    sscanf(line, "ip_ttl%d", &i); i_ttl = i;
    fgets(line, 256, infile);    sscanf(line, "ip_saddr%s", addr);
    i_src_addr = libnet_name_resolve(addr, 1);
    fgets(line, 256, infile);    sscanf(line, "ip_daddr%s", addr);
    i_des_addr = libnet_name_resolve(addr, 1); 
    fgets(line, 256, infile);    sscanf(line, "ip_proto%s", ip_proto);
    fgets(line, 256, infile);    sscanf(line, "ip_tos%[^!]", i_ttos);


    if(strstr(ip_proto, "dsr")) ip_proto_val = ip_proto_val | DSR_PROTOCOL;

    if(strstr(i_ttos, "lowdelay"))    i_ttos_val = i_ttos_val | IPTOS_LOWDELAY;
    if(strstr(i_ttos, "throughput"))  i_ttos_val = i_ttos_val | IPTOS_THROUGHPUT;
    if(strstr(i_ttos, "reliability")) i_ttos_val = i_ttos_val | IPTOS_RELIABILITY;
    if(strstr(i_ttos, "mincost"))     i_ttos_val = i_ttos_val | IPTOS_MINCOST;


    /* dsr header */
    fgets(line, 256, infile);    sscanf(line, "dsr_nexthdr%d", &i); dsr_hdr_s.nexthdr = i;
    fgets(line, 256, infile);    sscanf(line, "dsr_reserved%d", &i); dsr_hdr_s.reserved = i;
    fgets(line, 256, infile);    sscanf(line, "dsr_length%d", &i); dsr_hdr_s.length = i;
    fgets(line, 256, infile);    sscanf(line, "dsr_opt_type%d", &i); dsr_opt_hdr_s.type = i;
    fgets(line, 256, infile);    sscanf(line, "dsr_opt_len%d", &i); dsr_opt_hdr_s.len = i;

    memcpy(dsr_packet, &dsr_hdr_s, sizeof(struct dsr_hdr));
    memcpy(dsr_packet + sizeof(struct dsr_hdr), &dsr_opt_hdr_s, sizeof(struct dsr_opt_hdr));


    fclose(infile);
}


/* usage: Print out usage */
void usage(char* name)
{
    printf("Usage:\n");
    printf("%s -h header_file -p payload_ file [-i interface] [-s interval] [-c count]\n", name);
}



/* load_payload: load the payload into memory */
void load_payload(char *filename) {
    FILE *infile;
    struct stat statbuf;

    /* get the file size */
    stat(filename, &statbuf);
    payload_size = statbuf.st_size;

    /* open and read file */
    infile = fopen(filename, "r");

    payload_size = fread(dsr_packet + dsr_hdr_size, 1, DSR_PACKET_MAXLEN - dsr_hdr_size, infile);

    printf("hdr_size=%i,payload_size=%i\n", dsr_hdr_size, payload_size);
    fclose(infile);
}




int main(int argc, char **argv) {
    int i;
    int c;
    struct libnet_link_int * link_int;

    while ((c = getopt (argc, argv, "h:p:i:s:c:")) != EOF) {
	switch (c) {
	case 'p':
	    strcpy(payload_file, optarg);
	    break;
	case 'h':
	    strcpy(header_file, optarg);
	    break;
	case 'i':
	    strcpy(interface, optarg);
	    break;
	case 's':
	    sleep_time = atoi(optarg);
	    break;
	case 'c':
	    pktcount = atoi(optarg);
	    break;
	default:
	    usage(argv[0]);
	    break;
	}
    }

    /* parse non-option arguments */
    for (i = optind; i < argc; i++) {
        printf(argv[i]);
    }


    if((payload_file[0] == '\0') || (header_file[0] == '\0')) {
	usage(argv[0]);
	exit(-1);
    }

    dsr_packet = malloc(DSR_PACKET_MAXLEN);
    if (!dsr_packet) {
	printf("malloc for dsr_header failed.\n");
	exit(0);
    }

    load_header(header_file);
    load_payload(payload_file);


    /* Open the link layer interface */
    
    link_int = libnet_open_link_interface(interface, errbuf);
    if (!link_int) {
	printf("link layer error on %s : %s\n", interface, errbuf);
	exit(0);
    }   

    buf = malloc(ETH_H + IP_H +  dsr_hdr_size + payload_size);
    if (!buf) {
	printf("malloc for packet failed.\n");
	exit(0);
    }

    /* build the packet */

    libnet_build_ethernet(eth_daddr, eth_saddr, e_proto_val, NULL, 0, buf);
    libnet_build_ip(dsr_hdr_size + payload_size, i_ttos_val, i_id, i_frag, i_ttl, ip_proto_val, i_src_addr, i_des_addr, dsr_packet, dsr_hdr_size + payload_size, buf + ETH_H);

    /* checksum the packet */
    libnet_do_checksum(buf + ETH_H, IPPROTO_IP, IP_H);

    /* inject the packet through device */
    printf("sending packets: ");
    for(i=0; i<pktcount; i++) {
	printf(".");
	libnet_write_link_layer(link_int, interface, buf, ETH_H + IP_H + dsr_hdr_size + payload_size);
	sleep(sleep_time);
    }
    printf("\n");

    printf("%i packets sent\n", pktcount);


    libnet_destroy_packet(&buf);
    free(buf);
    free(dsr_packet);

    return 0;
}

