
#include "packet.h"
#include "links.h"
#include <errno.h>



int open_socket(int *fd)
{

    *fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

    if (*fd < 0) {
	printf("%s %s\n","Unable to open raw socket",strerror(errno));
	return -1;
    }
    
     return 0;
}

unsigned short getlinktype(unsigned short family, char *ifname)
{
    unsigned short result = 0;

    switch (family) {
    case ARPHRD_ETHER:
	if (strncmp(ifname, "eth", 3) == 0){
	    result = LINK_ETHERNET;
//	    printf("%s\n","eth");	    
	}
	else if (strncmp(ifname, "plip", 4) == 0){
	    result = LINK_PLIP;
//	    printf("%s\n","plip");
	}
	else if (strncmp(ifname, "fddi", 4) == 0){    /* For some Ethernet- */
	    result = LINK_ETHERNET;                  /* emulated FDDI ifaces */
//	    printf("%s\n","fddi");	    
	}
	else if (strncmp(ifname, "aba", 3) == 0){
	    result = LINK_ETHERNET;
//	    printf("%s\n","dvb");
	}
	else if (strncmp(ifname, "sbni", 4) == 0){
	    result = LINK_ETHERNET;
//	    printf("%s\n","sbni");
	}
	else if (strncmp(ifname, "ipsec", 5) == 0){
	    result = LINK_ETHERNET;
//	    printf("%s\n","ipsec");
	}
	else if ((strncmp(ifname, "wvlan", 5) == 0) || (strncmp(ifname, "wlan", 4) == 0)){
	    result = LINK_ETHERNET;
//	    printf("%s\n","wvlan");
	}
        else if ((strncmp(ifname, "sm2", 3) == 0) || (strncmp(ifname, "sm3", 3) == 0)){
            result = LINK_ETHERNET;
//	    printf("%s\n","sm2");
	}
        else if (strncmp(ifname, "pent", 4) == 0){
            result = LINK_ETHERNET;
//	    printf("%s\n","pent");
	}
	else if (strncmp(ifname, "lec", 3) == 0){
	    result = LINK_ETHERNET;
//	    printf("%s\n","lec");
	};
	break;
    case ARPHRD_LOOPBACK:
	result = LINK_LOOPBACK;
	break;
    case ARPHRD_SLIP:
    case ARPHRD_CSLIP:
    case ARPHRD_SLIP6:
    case ARPHRD_CSLIP6:
	result = LINK_SLIP;
	break;
    case ARPHRD_PPP:
	result = LINK_PPP;
	break;
    case ARPHRD_FDDI:
	result = LINK_FDDI;
	break;
    case ARPHRD_IEEE802:
    case ARPHRD_IEEE802_TR:
        result = LINK_TR;
        break;
    case ARPHRD_FRAD:
        result = LINK_FRAD;
        break;
    case ARPHRD_DLCI:
        result = LINK_DLCI;
        break; 
    default:
	result = LINK_INVALID;
	break;
    }
    return result;
}

void adjustpacket(char *tpacket, unsigned short family,
		  char **packet, char *aligned_buf, unsigned int *readlen)
{
    
    switch (family) {
    case LINK_ETHERNET:
    case LINK_LOOPBACK:
    case LINK_PLIP:
	*packet = tpacket + ETH_HLEN;
	*readlen -= ETH_HLEN;

	/*
	 * Move IP data into an aligned buffer.  96 bytes should be sufficient
	 * for IP and TCP headers with reasonable numbers of options and some
	 * data.
	 */

	memmove(aligned_buf, *packet, min(SNAPSHOT_LEN, *readlen));
	*packet = aligned_buf;
	break;
    case LINK_PPP:
    case LINK_SLIP:
    case LINK_ISDN_RAWIP:
	*packet = tpacket;
	break;
    case LINK_ISDN_CISCOHDLC:
    case LINK_FRAD:
    case LINK_DLCI:
	*packet = tpacket + 4;
	*readlen -= 4;
	break;
    case LINK_FDDI:
	*packet = tpacket + sizeof(struct fddihdr);
	*readlen -= sizeof(struct fddihdr);

	/*
	 * Move IP data into an aligned buffer.  96 bytes should be sufficient
	 * for IP and TCP headers with reasonable numbers of options and some
	 * data.
	 */

	memmove(aligned_buf, *packet, min(SNAPSHOT_LEN, *readlen));
	*packet = aligned_buf;
	break;
    default:
	*packet = (char *) NULL;	/* return a NULL packet to signal */
	break;			/* an unrecognized link protocol */
    }				/* to the caller.  Hopefully, this */
}				/* switch statement will grow. */

/*
 * IPTraf input function; reads both keystrokes and network packets.
 */
 
void getpacket(int fd, char *buf, struct sockaddr_ll *fromaddr,
	       int *ch, int *br, char *ifname)
{
    int fromlen;
    fd_set set;
    struct timeval tv;
    int ss;
    int ir;
    struct ifreq ifr;

    FD_ZERO(&set);
    FD_SET(0, &set);
    FD_SET(fd, &set);

    tv.tv_sec = 0;
    tv.tv_usec = DEFAULT_UPDATE_DELAY;

    do {
	ss = select(fd + 1, &set, 0, 0, &tv);
    } while ((ss < 0) && (errno == EINTR));

    *br = 0;
    *ch = ERR;

    if (FD_ISSET(fd, &set)) {
	fromlen = sizeof(struct sockaddr_pkt);
	*br = recvfrom(fd, buf, MAX_PACKET_SIZE, 0,(struct sockaddr *) fromaddr, &fromlen);
	ifr.ifr_ifindex = fromaddr->sll_ifindex;
	ir = ioctl(fd, SIOCGIFNAME, &ifr);
	strcpy(ifname, ifr.ifr_name);
//	printf("----- %s\n",ifname);
    }
/*
    if (!daemonized) {
	if (FD_ISSET(0, &set))
	    *ch = wgetch(win);
    } else
	*ch = ERR;
*/	
}

int processpacket(char *tpacket, char **packet, unsigned int *br,
                   unsigned int *total_br, unsigned int *sport,
                   unsigned int *dport, struct sockaddr_ll *fromaddr,
                   unsigned short *linktype,char *ifname, char *ifptr)
{
    static char aligned_buf[ALIGNED_BUF_LEN];

    /*
     * Does returned interface (ifname) match the specified interface name
     * (ifptr)?
     */    
    if (ifptr != NULL) {
        if (strcmp(ifptr, ifname) != 0) {
            return INVALID_PACKET;
        }
    }
    
    *linktype = getlinktype(fromaddr->sll_hatype, ifname);
    fromaddr->sll_protocol = ntohs(fromaddr->sll_protocol);
    adjustpacket(tpacket, *linktype, packet, aligned_buf, br);
    
    if (*packet == NULL)
        return INVALID_PACKET;
        
     return PACKET_OK;
}

char *c2b(char c){
    char *buf=malloc(10);
    int i;
    
    buf[8]=0x0;
    if(!buf) exit(1);

    for(i=0;i<8;i++){
	buf[i]= (short)((c & 128)>>7)+(short)'0';    
	c <<= 1;	
    };
    return buf;
}

char *prn32bit(char *c){
    char *ret=malloc(1024);
    if(!ret) return 0x0;
    sprintf(ret,"%p %s %s  %s %s %x%x %x%x  %x%x %x%x ",c,c2b((char)*c),c2b((char)*(c+1)),c2b((char)*(c+2)),c2b((char)*(c+3)),
	    ((char)*c & 0xf0)>>4,(char)*c & 0xf,((char)*(c+1) & 0xf0)>>4,(char)*(c+1) & 0xf,
	    ((char)*(c+2)&0xf0)>>4,(char)*(c+2)&0xf,((char)*(c+3) & 0xf0)>>4,(char)*(c+3) & 0xf);
    return ret;
}

char *prn8bitP(char *c){
    char *ret=malloc(1024);
    if(!ret) return 0x0;
    sprintf(ret,"%p",c);
    return ret;
}

char *prn8bitB(char *c){
    char *ret=malloc(1024);
    if(!ret) return 0x0;
    sprintf(ret,"%s",c2b((char)*c));
    return ret;
}

char *prn32bitH(char *c){
    char *ret=malloc(1024);
    if(!ret) return 0x0;
    sprintf(ret,"%x%x",((char)*c & 0xf0)>>4,(char)*c & 0xf);
    return ret;
}

char *prnaddr(char *c){
    char *ret=malloc(1024);
    if(!ret) return 0x0;
    sprintf(ret,"  %u.%u.%u.%u  ",(short)*c & 0xff,(short)*(c+1) & 0xff,(short)*(c+2) & 0xff,(short)*(c+3) & 0xff);
    return ret;    
}


char *prnaddrX(char *c){
    char *ret=malloc(1024);
    if(!ret) return 0x0;
    sprintf(ret,"%u.%u.%u.%u",(short)*c & 0xff,(short)*(c+1) & 0xff,(short)*(c+2) & 0xff,(short)*(c+3) & 0xff);
    return ret;    
}


char *pr_iph(struct ip *ip,char *packet)
{
	int hlen;
	u_char *cp;
	char *tmp,*tmp1;
	unsigned int plen,i,j,i1,i2,flg;

	char *ret=malloc(65535);
	if(!ret) return 0x0;

	hlen = ip->ip_hl << 2;
	cp = (u_char *)ip + 20;		/* point to options */
	plen=htons(ip->ip_len);


	tmp=prn32bit((char *)(packet+0));
	sprintf(ret,"\n  1 %s   Vr[4] :%02u       HL[4] :%02u    ToS[8]:%03u   Len[16]:%05u \n",tmp,ip->ip_v, ip->ip_hl, ip->ip_tos, htons(ip->ip_len));    
	free(tmp);

	tmp=prn32bit((char *)(packet+4));
	sprintf((char *)(ret+strlen(ret)),"  2 %s   ID[16]:%05u    Flg[3]:%01u    off[13]:%05u \n",tmp, htons(ip->ip_id),(htons(ip->ip_off) & 0xe000) >> 13,(htons(ip->ip_off) & 0x1fff));
	free(tmp);
	
	tmp=prn32bit((char *)(packet+8));	
	sprintf((char *)(ret+strlen(ret)),"  3 %s   TTL[8]:%03u     Prot[8]:%03u  cks[16]:%05u \n",tmp,ip->ip_ttl, ip->ip_p, htons(ip->ip_sum));
	free(tmp);
	
	tmp=prn32bit((char *)(packet+12));tmp1=prnaddr((char *)(packet+12));
	sprintf((char *)(ret+strlen(ret)),"  4 %s   Src[32] :%s \n",tmp,tmp1);						     
	free(tmp);free(tmp1);
	
	tmp=prn32bit((char *)(packet+16));tmp1=prnaddr((char *)(packet+16));		
	sprintf((char *)(ret+strlen(ret)),"  5 %s   Dest[32]:%s \n",tmp,tmp1);						     
	free(tmp);free(tmp1);
						     
	for(i=(ip->ip_hl)*4,j=6;i<(plen-1);j++){

	    tmp=prn8bitP((char *)(packet+i));
	    sprintf((char *)(ret+strlen(ret)),"%3d %s ",j,tmp);
	    free(tmp);

	    tmp=prn8bitB((char *)(packet+i));
	    sprintf((char *)(ret+strlen(ret)),"%s ",tmp);
	    free(tmp);
	    flg=0;i1=i;
	    i++;if(i>(plen-1)) flg=1;

	    if(!flg){
		tmp=prn8bitB((char *)(packet+i));
		sprintf((char *)(ret+strlen(ret)),"%s  ",tmp);
		free(tmp);
		i++;if(i>(plen-1)) flg=1;
	    } else sprintf((char *)(ret+strlen(ret)),"          ",tmp);

	    if(!flg){
    		tmp=prn8bitB((char *)(packet+i));
		sprintf((char *)(ret+strlen(ret)),"%s",tmp);
		free(tmp);
		i++;if(i>(plen-1)) flg=1;
	    } else sprintf((char *)(ret+strlen(ret)),"        ",tmp);	    

	    if(!flg){
		tmp=prn8bitB((char *)(packet+i));
		sprintf((char *)(ret+strlen(ret))," %s ",tmp);
		free(tmp);
		i++;if(i>(plen-1)) flg=1;
	    } else sprintf((char *)(ret+strlen(ret)),"          ",tmp);

	    i2=0;
	    do {
		if(i2==2) sprintf((char *)(ret+strlen(ret)),"%s"," ");
		tmp=prn32bitH((char *)(packet+i1));
		sprintf((char *)(ret+strlen(ret)),"%s ",tmp);
		free(tmp);
		i1++;i2++;
	    } while(i1<i);	    

	    sprintf((char *)(ret+strlen(ret)),"%s"," \n");
	    
	};

	sprintf((char *)(ret+strlen(ret)),"%s"," \n");

	/* dump and option bytes */
	/*
	
	while (hlen-- > 20) {
		(void)printf("%02x", *cp++);
	}
	*/
	return ret;
}
