#include "common.h"

int frag_open_tunnel_send() {
int         on = 1, s;

	if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 
		ERROR("socket output");

	if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0)
		ERROR("setsockopt");

return s;
}

int frag_open_tunnel_recv(int sock_send) {
int         s;

  if((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP))) < 0)
		ERROR("socket input");

return(s);
}

void frag_send_tunnel(int fd, unsigned char *buffer, int length, struct sockaddr_in saddr, struct sockaddr_in daddr, struct struct_conf conf) {
struct iphdr         *iphdr;
unsigned char        packet[MAX_PACKET];

  /* IP packet */
  iphdr = (struct iphdr *)packet;
  memset((char *)iphdr, 0, sizeof(struct iphdr));
  
  iphdr->ihl =                   5;
  iphdr->version =               4;
  iphdr->frag_off =              htons(IP_FO|IP_DF);  /* Fragmentation */
  iphdr->id =                    htons(conf.id);
  iphdr->ttl =                   IPDEFTTL;
  iphdr->protocol =              conf.protocol;
  iphdr->daddr =                 daddr.sin_addr.s_addr;

	/* Layer 4 */
	memcpy(packet+sizeof(struct iphdr), buffer, length);
	length += sizeof(struct iphdr);
  
  if(sendto(fd, packet, length, 0x0, (struct sockaddr *)&daddr, sizeof(struct sockaddr)) != length)
  	  ERROR("sendto");
}

int frag_recv_tunnel(int fd, unsigned char *buffer, struct sockaddr_in *saddr, struct sockaddr_in *daddr, struct struct_conf conf) {
unsigned char packet[MAX_PACKET];
struct sockaddr_ll from;
struct iphdr *iphdr;
int fromlen, length;

  fromlen = sizeof(from);
  if((length = recvfrom(fd, packet, MAX_PACKET, 0x0, (struct sockaddr *)&from, &fromlen)) <= 0) 
    ERROR("recvfrom");

	iphdr = (struct iphdr *)(packet+conf.ethhdrlen);
	if(iphdr->protocol == conf.protocol && htons(iphdr->id) == conf.id && iphdr->frag_off == htons(IP_FO|IP_DF)) {
			length = htons(iphdr->tot_len)-sizeof(struct iphdr);
			memcpy(buffer, packet+conf.ethhdrlen+sizeof(struct iphdr), length); 
         saddr->sin_addr.s_addr = iphdr->saddr;
         daddr->sin_addr.s_addr = iphdr->daddr;

	return(length);
	}

return(0);
}
