/*
 * Copyright (c) 1999 - 2002
 *  Politecnico di Torino.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that: (1) source code distributions
 * retain the above copyright notice and this paragraph in its entirety, (2)
 * distributions including binary code include the above copyright notice and
 * this paragraph in its entirety in the documentation or other materials
 * provided with the distribution, and (3) all advertising materials mentioning
 * features or use of this software display the following acknowledgement:
 * ``This product includes software developed by the Politecnico
 * di Torino, and its contributors.'' Neither the name of
 * the University nor the names of its contributors may be used to endorse
 * or promote products derived from this software without specific prior
 * written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "pcap.h"

/* 4 bytes IP address */
typedef struct ip_address{
    u_char byte1;
    u_char byte2;
    u_char byte3;
    u_char byte4;
}ip_address;

typedef struct mac_address{
	u_char byte1;
    u_char byte2;
    u_char byte3;
	u_char byte4;
    u_char byte5;
    u_char byte6;
}mac_address;

/* IPv4 header */
typedef struct ip_header{
    u_char  ver_ihl;        // Version (4 bits) + Internet header length (4 bits)
    u_char  tos;            // Type of service 
    u_short tlen;           // Total length 
    u_short identification; // Identification
    u_short flags_fo;       // Flags (3 bits) + Fragment offset (13 bits)
    u_char  ttl;            // Time to live
    u_char  proto;          // Protocol
    u_short crc;            // Header checksum
    ip_address  saddr;      // Source address
    ip_address  daddr;      // Destination address
    u_int   op_pad;         // Option + Padding
}ip_header;

/* UDP header*/
typedef struct udp_header{
    u_short sport;          // Source port
    u_short dport;          // Destination port
    u_short len;            // Datagram length
    u_short crc;            // Checksum
}udp_header;

//WLAN header with WEP
typedef struct wlan_header_wep{
	u_short fcontrol;
	u_short nav;
	mac_address transmitt;
	mac_address source;
	mac_address recieve;
	u_short scontrol;
	mac_address destination;
	u_int wep;
}wlan_header_wep;

//WLAN header without WEP
typedef struct wlan_header{
	u_short fcontrol;
	u_short nav;
	mac_address transmitt;
	mac_address source;
	mac_address recieve;
	u_short scontrol;
	mac_address destination;
}wlan_header;

//WLAN trailer with WEP
typedef struct wlan_trailer_wep{
	u_int wep;
	u_int fcs;
}wlan_trailer_wep;

//WLAN trailer without wep
typedef struct wlan_trailer{
	u_int fcs;
}wlan_trailer;

u_int pcount=0;

/* prototype of the packet handler */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
void printMac(mac_address *mac);

main()
{
    pcap_if_t *alldevs;
    pcap_if_t *d;
    int inum;
    int i=0;
    pcap_t *adhandle;
    char errbuf[PCAP_ERRBUF_SIZE];
//    u_int netmask;
//    char packet_filter[] = "ip and udp";
//    struct bpf_program fcode;
  
    /* Retrieve the device list */
    if (pcap_findalldevs(&alldevs, errbuf) == -1)
    {
        fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }
    
    /* Print the list */
    for(d=alldevs; d; d=d->next)
    {        
        if (d->description)
            printf("%d (%s)\n",++i, d->description);
        else
            printf("%d. %s", ++i, d->name);
    }

    if(i==0)
    {
        printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
        return -1;
    }
    
    printf("Enter the interface number (1-%d):",i);
    scanf("%d", &inum);
    
    if(inum < 1 || inum > i)
    {
        printf("\nInterface number out of range.\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return -1;
    }

    /* Jump to the selected adapter */
    for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
    
    /* Open the adapter */
    if ( (adhandle= pcap_open_live(d->name, // name of the device
                             65536,     // portion of the packet to capture. 
                                        // 65536 grants that the whole packet will be captured on all the MACs.
                             1,         // promiscuous mode
                             1000,      // read timeout
                             errbuf     // error buffer
                             ) ) == NULL)
    {
        fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return -1;
    }
    
    /* Check the link layer. We support only Ethernet for simplicity. */
    if(pcap_datalink(adhandle) != DLT_EN10MB)
    {
        fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return -1;
    }

   
    printf("\nlistening on %s...\n", d->description);
    
    /* At this point, we don't need any more the device list. Free it */
    pcap_freealldevs(alldevs);
    
    /* start the capture */
    pcap_loop(adhandle, 0, packet_handler, NULL);
    
    return 0;
}

/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{	
	int brutto;
	int netto;
	double anteil;
	int wep=0;
	wlan_header *wh;
	wlan_header_wep *whw;
	ip_header *ih;
    udp_header *uh;
	wlan_trailer *wt;
	wlan_trailer_wep *wtw;
    u_int ip_len;
	u_int wlan_len = sizeof(wlan_header);
	u_int end = sizeof(wlan_trailer);

	brutto = header->len;	//length of the packet
	end=brutto-end;

	netto=brutto-(sizeof(wlan_header)+20+8+sizeof(wlan_trailer));
	anteil = ((double)netto/brutto)*100;
	

	// retrieve the position of the wlan header
	wh = (wlan_header *) (pkt_data);
	// test if wep bit is set
	if (((wh->fcontrol)&0x0002)==0x0002){
		wep=1;
		wlan_len = sizeof(wlan_header_wep);
		whw = (wlan_header_wep *) (pkt_data);
		end = brutto-sizeof(wlan_trailer_wep);
	}	

    // retireve the position of the ip header 
	if (wep ==0){
		ih = (ip_header *) (pkt_data +
        sizeof(wlan_header)); //length of wlan header
	}else
		ih = (ip_header *) (pkt_data +
        sizeof(wlan_header_wep)); //length of wlan header

    // retireve the position of the udp header
	
	ip_len = (ih->ver_ihl & 0xf) * 4;
	if (wep==0)
		uh = (udp_header *) ((u_char*)ih + ip_len+sizeof(wlan_header));
	else
		uh = (udp_header *) ((u_char*)ih + ip_len+sizeof(wlan_header_wep));

	// retrieve the position of the wlan trailer
	if (wep==0)
		wt = (wlan_trailer *)(pkt_data+sizeof(wlan_header)+20+8);
	else
		wtw = (wlan_trailer_wep *)(pkt_data+sizeof(wlan_header_wep)+20+8);

	//Print out data
	if (wep==0){
		printf("WLAN HEADER:\n");
		printf("\tControl Frame:\n");
		printf("\t\tVersion: %d\n",ntohs(wh->fcontrol&0xC000));
		printf("\t\tFrame Type: %d\n",ntohs(wh->fcontrol&0x3000));
		printf("\t\tFrame Subtype: %d\n",ntohs(wh->fcontrol&0x0F00));
		if (((wh->fcontrol)&0x0080)==0x0080)
			printf("\t\tPacket sent to Distribute System\n");
		else
			printf("\t\tPacket not sent to Distribute System\n");
		if (((wh->fcontrol)&0x0040)==0x0040)
			printf("\t\tPacket sent from Distribute System\n");
		else
			printf("\t\tPacket not sent from Distribute System\n");
		if (((wh->fcontrol)&0x0020)==0x0020)
			printf("\t\tThere are more fragments\n");
		else
			printf("\t\tThere are no more fragments\n");
		if (((wh->fcontrol)&0x0010)==0x0010)
			printf("\t\tRetry flag set\n");
		else
			printf("\t\tRetry flag not set\n");
		if (((wh->fcontrol)&0x0008)==0x0008)
			printf("\t\tStation is in power save mode\n");
		else
			printf("\t\tStation is active\n");
		if (((wh->fcontrol)&0x0004)==0x0004)
			printf("\t\tThere are data bufferd in the retransmitt station\n");
		else
			printf("\t\tThere are data bufferd in the retransmitt station\n");
		if (((wh->fcontrol)&0x0002)==0x0002)
			printf("\t\tData is encripted with WEP\n");
		else
			printf("\t\tData is not encripted with WEP\n");
		if (((wh->fcontrol)&0x0001)==0x0001)
			printf("\t\tThe packets are ordered\n");
		else
			printf("\t\tThe packets are not ordered\n");
		printf("\tNetwork allocation vector (ms): %d\n",ntohs(wh->nav));
		printf("\tTransmitter address: 0x%x\n", wh->transmitt);
		printf("\tSource address: 0x%x\n", wh->source);
		printf("\tReciever address: 0x%x\n", wh->recieve);
		printf("\tSequence control:\n");
		printf("\t\tFragment number: %d\n",ntohs(wh->scontrol&0x8000));
		printf("\t\tSequence number: %d\n",ntohs(wh->scontrol&0x0FFF));
		printf("\tDestination address: 0x%x\n", wh->destination);
	} else {
		printf("WLAN HEADER:\n");
		printf("\tControl Frame:\n");
		printf("\t\tVersion: %d\n",ntohs(whw->fcontrol&0xC000));
		printf("\t\tFrame Type: %d\n",ntohs(whw->fcontrol&0x3000));
		printf("\t\tFrame Subtype: %d\n",ntohs(whw->fcontrol&0x0F00));
		if (((whw->fcontrol)&0x0080)==0x0080)
			printf("\t\tPacket sent to Distribute System\n");
		else
			printf("\t\tPacket not sent to Distribute System\n");
		if (((whw->fcontrol)&0x0040)==0x0040)
			printf("\t\tPacket sent from Distribute System\n");
		else
			printf("\t\tPacket not sent from Distribute System\n");
		if (((whw->fcontrol)&0x0020)==0x0020)
			printf("\t\tThere are more fragments\n");
		else
			printf("\t\tThere are no more fragments\n");
		if (((whw->fcontrol)&0x0010)==0x0010)
			printf("\t\tRetry flag set\n");
		else
			printf("\t\tRetry flag not set\n");
		if (((whw->fcontrol)&0x0008)==0x0008)
			printf("\t\tStation is in power save mode\n");
		else
			printf("\t\tStation is active\n");
		if (((whw->fcontrol)&0x0004)==0x0004)
			printf("\t\tThere are data bufferd in the retransmitt station\n");
		else
			printf("\t\tThere are data bufferd in the retransmitt station\n");
		if (((whw->fcontrol)&0x0002)==0x0002)
			printf("\t\tData is encripted with WEP\n");
		else
			printf("\t\tData is not encripted with WEP\n");
		if (((whw->fcontrol)&0x0001)==0x0001)
			printf("\t\tThe packets are ordered\n");
		else
			printf("\t\tThe packets are not ordered\n");
		printf("\tNetwork allocation vector (ms): %d\n",ntohs(whw->nav));
		printf("\tTransmitter address: 0x%x\n", whw->transmitt);
		printf("\tSource address: 0x%x\n", whw->source);
		printf("\tReciever address: 0x%x\n", whw->recieve);
		printf("\tSequence control:\n");
		printf("\t\tFragment number: %d\n",ntohs(whw->scontrol&0x8000));
		printf("\t\tSequence number: %d\n",ntohs(whw->scontrol&0x0FFF));
		printf("\tDestination address: 0x%x\n", whw->destination);
		printf("\tWEP IV header:\n");
		printf("\t\tInitialisation vector: 0x%x\n",ntohs(whw->wep&0xFFF0));
		printf("\t\tWEP Key: 0x%x\n",ntohs(whw->wep&0x0003));
	}
	printf("IP HEADER:\n");
	printf("\tIP version: %d\n",ih->ver_ihl&0xF0);
	printf("\tIP header length (4 byte): %d\n",ih->ver_ihl&0x0F);
	printf("\tType of Service: %d\n",ih->tos);
	printf("\tSize of datagram (byte): %d\n",ntohs(ih->tlen));
	printf("\tIdentification: %d\n",ntohs(ih->identification));
	if (((ih->flags_fo)&0x4000)==0x4000)	
		printf("\tDon't fragment\n");
	else 
		printf("\tFragmentation allowd\n");
	if (((ih->flags_fo)&0x0200)==0x0200){	
		printf("\tThere are more fragments\n");
		printf("\tFragment offset: 0x%d\n",ntohs(ih->flags_fo&0x1FFF));
	} else 
		printf("\tThere are no more fragments\n");
	printf("\tTime to live: %d\n",ih->ttl);
	if(ih->proto==(u_char)1)
		printf("\tContains an ICMP packet\n");
	if(ih->proto==(u_char)2)
		printf("\tContains an IGMP packet\n");
	if(ih->proto==(u_char)6)
		printf("\tContains an TCP packet\n");
	if(ih->proto==(u_char)17)
		printf("\tContains an UDP packet\n");
	printf("\tCRC Checksum: 0x%x\n",ih->crc);
	printf("\tSource IP address: %d.%d.%d.%d\n",
        ih->saddr.byte1,
        ih->saddr.byte2,
        ih->saddr.byte3,
        ih->saddr.byte4);
	printf("\tDestination IP address: %d.%d.%d.%d\n",
        ih->daddr.byte1,
        ih->daddr.byte2,
        ih->daddr.byte3,
        ih->daddr.byte4);
	if (ih->tlen>5)
		printf("\tAdditional options: 0x%x\n",ih->op_pad);
	printf("UDP HEADER:\n");
	printf("\tSource port: %d\n",ntohs( uh->sport ));
	printf("\tDestination port: %d\n",ntohs( uh->dport ));
	printf("\tLength Payload: %d\n",ntohs(uh->len));
	printf("\tCRC Checksum: 0x%x\n",ntohs(uh->crc));
/*	printf("Payload:\n\t");
	for(i=wlan_len+ip_len+sizeof(udp_header);i<end;i++)
		printf("%s",pkt_data[i]);
*/
	printf("WLAN TRAILER:\n");
	if (wep==0){
		printf("\tFrame check sequence: 0x%x\n", wt->fcs);
	} else {
		printf("\tWEP trailer CRC: 0x%x\n",wtw->wep);
		printf("\tFrame check sequence: 0x%x\n", wtw->fcs);
	}
	pcount++;
}

void printMac(mac_address *mac){
	printf("%s:%s:%s:%s:%s:%s",mac->byte1,mac->byte2,mac->byte3,mac->byte4,mac->byte5,mac->byte6);
}