← Back to team overview

rohc team mailing list archive

Ethernet Transport app for ROHC pkts

 

Hello,

I have built an app which is an Ethernet based transport application for
ROHC pkts very similar to rohctunnel app on the trunk. The major highlights
are:-

1) It directly uses Ethernet as transport.
2) Because of Ethernet it is pont-to-point and cannot traverse
routers/gateways.
3) Since Ethernet's minimum payload is 46 bytes and kernel adds padding for
any payload less than that size, thus I have added a length byte after
sequence bytes before sending it on Ethernet. Other end will read this byte
as the length of ROHC packet instead of length returned by Ethernet
interface.

I am attaching the patch for review and submission.

regards,
Raman
=== modified file 'app/Makefile.am'
--- app/Makefile.am	2012-11-17 09:43:22 +0000
+++ app/Makefile.am	2012-12-29 08:30:11 +0000
@@ -5,6 +5,7 @@
 ################################################################################
 
 SUBDIRS = \
+  ethTunnel \
 	performance \
 	tunnel \
 	sniffer

=== added directory 'app/ethTunnel'
=== added file 'app/ethTunnel/Makefile.am'
--- app/ethTunnel/Makefile.am	1970-01-01 00:00:00 +0000
+++ app/ethTunnel/Makefile.am	2012-12-19 10:26:33 +0000
@@ -0,0 +1,28 @@
+################################################################################
+# Name       : Makefile
+# Author     : Didier Barvaux <didier.barvaux@xxxxxxxxxxxxxxxxxxxx>
+#              Didier Barvaux <didier@xxxxxxxxxxx>
+# Description: create the Ethernt ROHC tunnel application
+################################################################################
+
+sbin_PROGRAMS = ethTunnel
+
+ethTunnel_CFLAGS = \
+	-g -Wall -Wstrict-prototypes \
+	-I$(top_srcdir)/src/common \
+	-I$(top_srcdir)/src/comp \
+	-I$(top_srcdir)/src/decomp
+
+ethTunnel_LDFLAGS = \
+	-L$(top_builddir)/src/common/.libs \
+	-L$(top_builddir)/src/comp/.libs \
+	-L$(top_builddir)/src/decomp/.libs
+
+ethTunnel_SOURCES = \
+	ethTunnel.c
+
+ethTunnel_LDADD = \
+	-lrohc_comp \
+	-lrohc_decomp\
+	-lrohc_common
+

=== added file 'app/ethTunnel/ethTunnel.c'
--- app/ethTunnel/ethTunnel.c	1970-01-01 00:00:00 +0000
+++ app/ethTunnel/ethTunnel.c	2013-01-07 13:47:39 +0000
@@ -0,0 +1,1701 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * @file ethTunnel.c
+ * @brief ROHC Ethernet tunnel
+ *
+ * Description
+ * -----------
+ *
+ * The program creates a ROHC tunnel over Ethernet between two systems.
+ * Both the systems need to be on same Ethernet network connected via
+ * L2 hub/switch. This is needed so that packets can be forwarded using
+ * MAC Address without the need of network layer routing.
+ *
+ * A ROHC tunnel compresses the IP packets it receives from a virtual
+ * network interface and decompresses the ROHC packets it receives over Ethernet.
+ *
+ *               +-----------+                          +----------+
+ * IP packets    |  Virtual  |     +--------------+     |          |
+ * sent by   --> | interface | --> |  Compressor  | --> |   ROHC   |
+ * the host      |   (TUN)   |     +--------------+     |  packets |
+ *               |           |                          |   over   |
+ * IP packets    |           |     +--------------+     | Ethernet |
+ * received  <-- |           | <-- | Decompressor | <-- |          |
+ * from the      |           |     +--------------+     |          |
+ * tunnel        +-----------+                          +----------+
+ *
+ * The program outputs messages from the tunnel application on stderr and
+ * messages from the ROHC library on stdout. It outputs compression statistics
+ * on file descriptor 3 and decompression statistics on file descriptor 4.
+ *
+ * The tunnel can emulate a lossy medium with a given error rate. Unidirectional
+ * mode can be forced (no feedback channel).
+ *
+ * Usage
+ * -----
+ *
+ * Run the ethTunnel without any argument to see what arguments the application
+ * accepts.
+ *
+ * Basic example
+ * -------------
+ *
+ * Type as root on machine A:
+ *
+ * # ethTunnel rohc0 remote 08:00:27:E1:1E:E6 local-interface eth0 tun-ip-address 10.0.0.1
+ *
+ * Type as root on machine B:
+ *
+ * # ethTunnel rohc0 remote 08:00:27:0F:D9:8D local-interface eth0 tun-ip-address 10.0.0.2
+ *
+ * Notes:-
+ * 1) The 'tun-ip-address' currently only supports IPv4 address.
+ * 2) The 'tun-ip-address' defaults to /24 netmask.
+ * 3) The 'tun-ip-address' should not clash with IP routes on any of the machines. 
+ *    Use command 'route -n' to check routes defined on the system.
+ * 4) To know the MAC address of remote machines use command 'arp' OR get it
+ *    directly from remote machine
+ * 5) Use command 'route -n' in a different shell to check new route defined on the 
+ *    system after executing above 'ethTunnel' binary. An entry similar to:
+ *			Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
+ *			10.0.0.0        0.0.0.0         255.255.255.0   U     0      0        0 rohc0
+ *    should be observed.
+ *
+ * Then, on machine B:
+ *  $ ping 10.0.0.1
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <signal.h>
+#include <errno.h>
+#include <math.h> /* for HUGE_VAL */
+#include <time.h> /* for time(2) */
+#include <sys/time.h> /* for gettimeofday(2) */
+#include <assert.h>
+
+/* TUN includes */
+#include <net/if.h> /* for IFNAMSIZ */
+#include <linux/if_tun.h>
+#include <net/ethernet.h> //ETHER_ADDR_LEN=6, ETH_P_* 
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+/* struct sockaddr_ll */
+#include <netpacket/packet.h> 
+
+/* UDP includes */
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+/* ROHC includes */
+#include "rohc.h"
+#include "rohc_comp.h"
+#include "rohc_decomp.h"
+
+
+
+/*
+ * Macros & definitions:
+ */
+
+/// Return the greater value from the two
+#define max(x, y)  (((x) > (y)) ? (x) : (y))
+
+/// The maximal size of data that can be received on the virtual interface
+#define TUNTAP_BUFSIZE 1518
+
+/// The maximal size of a ROHC packet
+#define MAX_ROHC_SIZE	(5 * 1024)
+
+/// Enable debug ?
+#define DEBUG 0
+
+/// Stop on compression/decompression failure
+#define STOP_ON_FAILURE 0
+
+#define MACFMT "%02X:%02X:%02X:%02X:%02X:%02X"
+#define MACBYTES(p)  	(uint8_t)p[0],(uint8_t)p[1], \
+										 	(uint8_t)p[2],(uint8_t)p[3], \
+										 	(uint8_t)p[4],(uint8_t)p[5]
+
+
+/*
+ * Function prototypes:
+ */
+
+int tun_create(char *name, const char* tun_ip_address);
+int read_from_tun(int fd, unsigned char *packet, unsigned int *length);
+int write_to_tun(int fd, unsigned char *packet, unsigned int length);
+
+int ethernet_create(const char* laddr, int* localInterfaceIndex);
+int read_from_ethernet(int sock, unsigned char *buffer, unsigned int *length);
+int write_to_ethernet(int sock, unsigned char destMacOctets[ETHER_ADDR_LEN],
+											int localInterfaceIndex,
+                 			unsigned char *packet, unsigned int length);
+
+int tun2ethernet(struct rohc_comp *comp,
+            int from, int to,
+						unsigned char destMacOctets[ETHER_ADDR_LEN],
+						int localInterfaceIndex,
+            int error, double ber, double pe2, double p2);
+int ethernet2tun(struct rohc_decomp *decomp, int from,
+								 int to, int localInterfaceIndex);
+int flush_feedback(struct rohc_comp *comp,
+  								 unsigned char destMacOctets[ETHER_ADDR_LEN],
+									int localInterfaceIndex, int to);
+
+void dump_packet(char *descr, unsigned char *packet, unsigned int length);
+double get_probability(char *arg, int *error);
+int is_timeout(struct timeval first,
+               struct timeval second,
+               unsigned int max);
+int convertMacStringToArray(const char* macStr,
+														unsigned char macOctets[ETHER_ADDR_LEN]);
+static int gen_random_num(const struct rohc_comp *const comp,
+                          void *const user_context)
+	__attribute__((nonnull(1)));
+
+/*
+ * Main functions:
+ */
+
+
+/// Whether the application should continue to live or not
+int alive;
+
+
+/**
+ * @brief Catch the INT, TERM and KILL signals to properly shutdown the tunnel
+ *
+ * @param sig  The signal catched: SIGINT, SIGTERM or SIGKILL
+ */
+void sighandler(int sig)
+{
+	fprintf(stderr, "signal %d received, terminate the process\n", sig);
+	alive = 0;
+}
+
+
+/**
+ * @brief Display the application usage
+ */
+void usage(void)
+{
+	printf("Ethernet ROHC tunnel: make a ROHC over Ethernet\n\
+\n\
+usage:\n\
+  ethTunnel [ version | help ]\n\
+  ethTunnel TUNNEL [ ERROR ] [ DIR ]\n\
+\n\
+Tunnel parameters:\n\
+  TUNNEL    := NAME remote MAC_ADDR local-interface LOCAL tun-ip-address IPv4_ADDR\n\
+  NAME      := STRING           The name of the tunnel\n\
+  RADDR     := MAC-ADDR         The MAC address of remote host in standard notation\n\
+  LOCAL     := Local Interface  The local ethernet interface string of the host\n\
+  IPv4_ADDR := IP Address       The local ROHC Tunnel IPv4 Address to create\n\
+\n\
+Error model (none if not specified):\n\
+  ERROR  := error { none | uniform RATE | burst PE2 P2 }\n\
+  RATE   := FLOAT             The BER (binary error rate) to emulate\n\
+  PE2    := FLOAT             The probability to be in error state\n\
+  P2     := FLOAT             The probability to stay in error state\n\
+\n\
+Direction (bidirectional if not specified):\n\
+  DIR    := dir { bidirectional | unidirectional }\n\
+\n\
+Examples:\n\
+  # ethTunnel rohc0 remote 08:00:27:E1:1E:E6 local-interface eth0 tun-ip-address 10.0.0.1\n\
+  # ethTunnel rohc0 remote 08:00:27:E1:1E:E6 local-interface eth0 tun-ip-address 10.0.0.1\\\n\
+    dir unidirectional\n\
+  # ethTunnel rohc0 remote 08:00:27:E1:1E:E6 local-interface eth0 tun-ip-address 10.0.0.1\\\n\
+    error uniform 1e-5 dir bidirectional\n\
+  # ethTunnel rohc0 remote 08:00:27:E1:1E:E6 local-interface eth0 tun-ip-address 10.0.0.1\\\n\
+    error burst 1e-5 2e-5\n\
+");
+}
+
+
+/**
+ * @brief Display the application version
+ */
+void version(void)
+{
+	printf("ROHC Ethernet tunnel version %s\n", rohc_version());
+}
+
+
+/// The file descriptor where to write the compression statistics
+FILE *stats_comp;
+/// The file descriptor where to write the decompression statistics
+FILE *stats_decomp;
+/// The sequence number for the Ethernet tunnel (used to discover lost packets)
+unsigned int seq;
+
+
+/**
+ * @brief Setup a ROHC over Ethernet tunnel
+ *
+ * @param argc  The number of arguments given on the command line
+ * @param argv  The arguments given on the command line
+ * @return      0 in case of success, > 0 otherwise
+ */
+int main(int argc, char *argv[])
+{
+	int failure = 0;
+
+	char *tun_name;
+	unsigned char raddr[ETHER_ADDR_LEN]; 	//Remote MAC Address
+	char* laddr; 							//Local inerface e.g eth0
+	int localInterfaceIndex;	//Local Interface Index
+	static const char* tun_ip_address; // Local tun IP Address e.g "10.0.0.1";
+	int error_model;
+	int conv_error;
+	double ber = 0;
+	double pe2 = 0;
+	double p2 = 0;
+	int arg_count;
+	int is_umode;
+
+	unsigned long seed;
+	int ret;
+
+	int tun, ethernet;
+
+	fd_set readfds;
+	struct timespec timeout;
+	sigset_t sigmask;
+
+	struct timeval last;
+	struct timeval now;
+
+	struct rohc_comp *comp;
+	struct rohc_decomp *decomp;
+
+	
+	/*
+	 * Parse arguments:
+	 */
+
+	/* check the number of arguments:
+	 *   ethTunnel version          -> 2 arguments
+	 *   ethTunnel help             -> 2 arguments
+	 *   ethTunnel TUNNEL           -> 6 arguments
+	 *   ethTunnel TUNNEL ERROR     -> 8-10 arguments
+	 *   ethTunnel TUNNEL DIR       -> 8 arguments
+	 *   ethTunnel TUNNEL ERROR DIR -> 10-12 arguments
+	 */
+	if(argc != 2 && argc != 8 && (argc < 10 || argc > 14))
+	{
+		usage();
+		goto quit;
+	}
+
+	/* is the first argument 'version' or 'help' ? */
+	if(strcmp(argv[1], "version") == 0)
+	{
+		version();
+		goto quit;
+	}
+	else if(strcmp(argv[1], "help") == 0)
+	{
+		usage();
+		goto quit;
+	}
+
+	/* first argument is not 'version' or 'help', so we have a tunnel request */
+	if(argc < 6)
+	{
+		usage();
+		goto quit;
+	}
+
+	/* get the tunnel name */
+	tun_name = argv[1];
+
+	/* get the remote MAC address */
+	if(strcmp(argv[2], "remote") != 0)
+	{
+		usage();
+		goto quit;
+	}
+	if(convertMacStringToArray(argv[3], raddr) != ETHER_ADDR_LEN)
+	{
+		fprintf(stderr, "bad remote MAC Address:- %s\n", argv[3]);
+		goto quit;
+	}
+	printf("Remote MAC Address: " MACFMT "\n", MACBYTES(raddr));
+
+	/* get the local Interface address */
+	if(strcmp(argv[4], "local-interface") != 0)
+	{
+		usage();
+		goto quit;
+	}
+	laddr = argv[5];
+
+	/* get the local Interface address */
+	if(strcmp(argv[6], "tun-ip-address") != 0)
+	{
+		usage();
+		goto quit;
+	}
+	tun_ip_address = argv[7];
+
+	/* get the error model and its parameters if present */
+	if(argc >= 9 && strcmp(argv[8], "error") == 0)
+	{
+		arg_count = 9;
+
+		if(argc < arg_count + 1)
+		{
+			fprintf(stderr, "the error keyword requires an argument: "
+			        "none, uniform or burst\n");
+			goto quit;
+		}
+
+		if(strcmp(argv[arg_count], "none") == 0)
+		{
+			/* no error model */
+			fprintf(stderr, "do not emulate lossy medium\n");
+			error_model = 0;
+			arg_count++;
+		}
+		else if(strcmp(argv[arg_count], "uniform") == 0)
+		{
+			/* uniform error model */
+			error_model = 1;
+			arg_count++;
+
+			/* check if parameters are present */
+			if(argc < arg_count + 1)
+			{
+				usage();
+				goto quit;
+			}
+
+			/* get the RATE value */
+			ber = get_probability(argv[arg_count], &conv_error);
+			if(conv_error != 0)
+			{
+				fprintf(stderr, "cannot read the RATE parameter\n");
+				goto quit;
+			}
+			arg_count++;
+	
+			fprintf(stderr, "emulate lossy medium with %e errors/bit "
+			                "= 1 error every %lu bytes\n",
+			        ber, (unsigned long) (1 / (ber * 8)));
+		}
+		else if(strcmp(argv[arg_count], "burst") == 0)
+		{
+			/* non-uniform/burst error model */
+			error_model = 2;
+			arg_count++;
+
+			/* check if parameters are present */
+			if(argc < arg_count + 2)
+			{
+				usage();
+				goto quit;
+			}
+
+			/* get the PE2 probability */
+			pe2 = get_probability(argv[arg_count], &conv_error);
+			if(conv_error != 0)
+			{
+				fprintf(stderr, "cannot read the PE2 parameter\n");
+				goto quit;
+			}
+			arg_count++;
+
+			/* get the P2 probability */
+			p2 = get_probability(argv[arg_count], &conv_error);
+			if(conv_error != 0)
+			{
+				fprintf(stderr, "cannot read the P2 parameter\n");
+				goto quit;
+			}
+			arg_count++;
+
+			fprintf(stderr, "emulate lossy medium with PE2 = %e and P2 = %e\n",
+			        pe2, p2);
+		}
+		else
+		{
+			fprintf(stderr, "bad error model: %s\n", argv[arg_count]);
+			goto quit;
+		}
+	}
+	else
+	{
+		/* no error model */
+		fprintf(stderr, "do not emulate lossy medium (default)\n");
+		error_model = 0;
+		arg_count = 8;
+	}
+
+	/* get the direction mode if present */
+	if(argc >= arg_count + 1 && strcmp(argv[arg_count], "dir") == 0)
+	{
+		arg_count++;
+
+		if(argc < arg_count + 1)
+		{
+			fprintf(stderr, "the dir keyword requires an argument: "
+			        "unidirectional or bidirectional\n");
+			goto quit;
+		}
+
+		if(strcmp(argv[arg_count], "unidirectional") == 0)
+		{
+			fprintf(stderr, "force unidirectional mode\n");
+			is_umode = 1;
+		}
+		else if(strcmp(argv[arg_count], "bidirectional") == 0)
+		{
+			fprintf(stderr, "force bidirectional mode\n");
+			is_umode = 0;
+		}
+		else
+		{
+			fprintf(stderr, "bad direction mode: %s\n", argv[arg_count]);
+			goto quit;
+		}
+	}
+	else
+	{
+		fprintf(stderr, "force bidirectional mode (default)\n");
+		is_umode = 0;
+	}
+
+
+	/*
+	 * Network interface part:
+	 */
+
+	/* create virtual network interface */
+	tun = tun_create(tun_name, tun_ip_address);
+	if(tun < 0)
+	{
+		fprintf(stderr, "%s creation failed, be sure to start ethTunnel "
+		        "as root\n", tun_name);
+		failure = 1;
+		goto quit;
+	}
+	fprintf(stderr, "%s created with IP Address %s, fd %d\n", tun_name,
+					tun_ip_address, tun);
+
+	/* create an Ethernet socket */
+	ethernet = ethernet_create(laddr, &localInterfaceIndex);
+	if(ethernet < 0)
+	{
+		fprintf(stderr, "Ethernet socket creation failed\n");
+		failure = 1;
+		goto close_tun;
+	}
+	fprintf(stderr, "Ethenet socket created, fd %d\n", ethernet);
+
+
+	/*
+	 * ROHC part:
+	 */
+
+	/* create the compressor and activate profiles */
+	comp = rohc_alloc_compressor(15, 0, 0, 0);
+	if(comp == NULL)
+	{
+		fprintf(stderr, "cannot create the ROHC compressor\n");
+		goto close_ethernet;
+	}
+	rohc_activate_profile(comp, ROHC_PROFILE_UNCOMPRESSED);
+	rohc_activate_profile(comp, ROHC_PROFILE_UDP);
+	rohc_activate_profile(comp, ROHC_PROFILE_IP);
+	rohc_activate_profile(comp, ROHC_PROFILE_UDPLITE);
+	rohc_activate_profile(comp, ROHC_PROFILE_RTP);
+	rohc_activate_profile(comp, ROHC_PROFILE_ESP);
+
+	/* initialize the random generator */
+	seed = time(NULL);
+	srand(seed);
+
+	/* set the callback for random numbers */
+	if(!rohc_comp_set_random_cb(comp, gen_random_num, NULL))
+	{
+		fprintf(stderr, "failed to set the callback for random numbers\n");
+		goto destroy_comp;
+	}
+
+	/* create the decompressor (associate it with the compressor) */
+	decomp = rohc_alloc_decompressor(is_umode ? NULL : comp);
+	if(decomp == NULL)
+	{
+		fprintf(stderr, "cannot create the ROHC decompressor\n");
+		goto destroy_comp;
+	}
+
+
+	/* 
+	 * Main program:
+	 */
+
+	/* write the compression stats to fd 3 */
+	stats_comp = fdopen(3, "a");
+	if(stats_comp == NULL)
+	{
+		fprintf(stderr, "cannot open fd 3 for compression stats: %s (%d)\n",
+		        strerror(errno), errno);
+		goto destroy_decomp;
+	}
+
+	/* write the decompression stats to fd 4 */
+	stats_decomp = fdopen(4, "a");
+	if(stats_decomp == NULL)
+	{
+		fprintf(stderr, "cannot open fd 4 for decompresion stats: %s (%d)\n",
+		        strerror(errno), errno);
+		goto close_stats_comp;
+	}
+
+	/* init the tunnel sequence number */
+	seq = 0;
+
+	/* catch signals to properly shutdown the bridge */
+	alive = 1;
+	signal(SIGKILL, sighandler);
+	signal(SIGTERM, sighandler);
+	signal(SIGINT, sighandler);
+
+	/* poll network interfaces each second */
+	timeout.tv_sec = 1;
+	timeout.tv_nsec = 0;
+
+	/* mask signals during interface polling */
+	sigemptyset(&sigmask);
+	sigaddset(&sigmask, SIGKILL);
+	sigaddset(&sigmask, SIGTERM);
+	sigaddset(&sigmask, SIGINT);
+
+	/* initialize the last time we sent a packet */
+	gettimeofday(&last, NULL);
+
+	/* tunnel each packet from the Ethernet socket to the virtual interface
+	 * and from the virtual interface to the Ethernet socket */
+	do
+	{
+		/* poll the read sockets/file descriptors */
+		FD_ZERO(&readfds);
+		FD_SET(tun, &readfds);
+		FD_SET(ethernet, &readfds);
+
+		ret = pselect(max(tun, ethernet) + 1, &readfds, NULL, NULL, 
+										&timeout, &sigmask);
+		if(ret < 0)
+		{
+			fprintf(stderr, "pselect failed: %s (%d)\n", strerror(errno), errno);
+			failure = 1;
+			alive = 0;
+		}
+		else if(ret > 0)
+		{
+			/* bridge from TUN to Ethernet */
+			if(FD_ISSET(tun, &readfds))
+			{
+				failure = tun2ethernet(comp, tun, ethernet, raddr, localInterfaceIndex,
+																error_model, ber, pe2, p2);
+				gettimeofday(&last, NULL);
+#if STOP_ON_FAILURE
+				if(failure)
+					alive = 0;
+#endif
+			}
+
+			/* bridge from Ethernet to TUN */
+			if(
+#if STOP_ON_FAILURE
+			   !failure &&
+#endif
+			   FD_ISSET(ethernet, &readfds))
+			{
+				failure = ethernet2tun(decomp, ethernet, tun, localInterfaceIndex);
+#if STOP_ON_FAILURE
+				if(failure)
+					alive = 0;
+#endif
+			}
+		}
+
+		/* flush feedback data if nothing is sent in the tunnel for a moment */
+		gettimeofday(&now, NULL);
+		if(now.tv_sec > last.tv_sec + 1)
+		{
+			failure = flush_feedback(comp, raddr, localInterfaceIndex, ethernet);
+			last = now;
+#if STOP_ON_FAILURE
+			if(failure)
+				alive = 0;
+#endif
+		}
+	}
+	while(alive);
+
+
+	/*
+	 * Cleaning:
+	 */
+
+	fclose(stats_decomp);
+close_stats_comp:
+	fclose(stats_comp);
+destroy_decomp:
+	rohc_free_decompressor(decomp);
+destroy_comp:
+	rohc_free_compressor(comp);
+close_ethernet:
+	close(ethernet);
+close_tun:
+	close(tun);
+quit:
+	return failure;
+}
+
+
+
+/*
+ * TUN interface:
+ */
+
+
+/**
+ * @brief Create a virtual network interface of type TUN and assign IP config
+ *
+ * @param name  The name of the TUN interface to create
+ * @return      An opened file descriptor on the TUN interface in case of
+ *              success, a negative value otherwise
+ */
+int tun_create(char *name, const char* tun_ip_address)
+{
+	struct ifreq ifr;
+	int fd, fd1, err;
+
+	if((fd = open("/dev/net/tun", O_RDWR)) < 0)
+	{
+		fprintf(stderr, "failed to open /dev/net/tun: %s (%d)\n",
+		        strerror(errno), errno);
+		return fd;
+	}
+
+	/* flags: IFF_TUN   - TUN device (no Ethernet headers)
+	 *        IFF_TAP   - TAP device
+	 *        IFF_NO_PI - Do not provide packet information */
+	bzero(&ifr, sizeof(ifr));
+	strncpy(ifr.ifr_name, name, IFNAMSIZ);
+	ifr.ifr_name[IFNAMSIZ - 1] = '\0';
+	ifr.ifr_flags = IFF_TUN;
+
+	/* create the TUN interface */
+	if((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0)
+	{
+		fprintf(stderr, "failed to ioctl(TUNSETIFF) on /dev/net/tun: %s (%d)\n",
+		        strerror(errno), errno);
+		close(fd);
+		return err;
+	}
+
+  /*Create socket to assign IPv4 configuration to tun device*/
+	if((fd1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0)
+	{
+		fprintf(stderr, "failed to open /dev/net/tun: %s (%d)\n",
+		        strerror(errno), errno);
+		close(fd);
+		return fd1;
+	}
+
+  /*Assign IPv4 Address to tun device*/
+	ifr.ifr_flags = 0;
+	struct sockaddr_in* addr = (struct sockaddr_in*)&ifr.ifr_addr;
+  addr->sin_family = AF_INET;
+	inet_aton(tun_ip_address, &addr->sin_addr);
+  if((err = ioctl(fd1, SIOCSIFADDR, &ifr)) < 0)
+	{
+		fprintf(stderr, "failed to SET IP ADDRESS tun: %s (%d)\n",
+		        strerror(errno), errno);
+		close(fd1);
+		close(fd);
+		return err;
+	}
+
+  /*Assign Net mask to tun device*/
+	inet_aton("255.255.255.0", &addr->sin_addr);
+  if((err = ioctl(fd1, SIOCSIFNETMASK, &ifr)) < 0)
+	{
+		fprintf(stderr, "failed to SET NetMask 255.255.255.0: %s (%d)\n",
+		        strerror(errno), errno);
+		close(fd1);
+		close(fd);
+		return err;
+	}
+
+  /*Assign Flags for tun device*/
+	ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
+  if((err = ioctl(fd1, SIOCSIFFLAGS, &ifr)) < 0)
+	{
+		fprintf(stderr, "failed to SET Flags IFF_UP | IFF_RUNNING: %s (%d)\n",
+		        strerror(errno), errno);
+		close(fd1);
+		close(fd);
+		return err;
+	}
+
+	close(fd1);
+	return fd;
+}
+
+
+/**
+ * @brief Read data from the TUN interface
+ *
+ * Data read by this function contains a 4-byte header that gives the protocol
+ * of the data.
+ *
+ *   +-----+-----+-----+-----+
+ *   |  0  |  0  |  Protocol |
+ *   +-----+-----+-----+-----+
+ *
+ * Protocol = 0x0800 for IPv4
+ *            0x86dd for IPv6
+ *
+ * @param fd      The TUN file descriptor to read data from
+ * @param packet  The buffer where to store the data
+ * @param length  OUT: the length of the data
+ * @return        0 in case of success, a non-null value otherwise
+ */
+int read_from_tun(int fd, unsigned char *packet, unsigned int *length)
+{
+	int ret;
+
+	ret = read(fd, packet, *length);
+
+	if(ret < 0 || ret > *length)
+	{
+		fprintf(stderr, "read failed: %s (%d)\n", strerror(errno), errno);
+		goto error;
+	}
+
+	*length = ret;
+
+#if DEBUG
+	fprintf(stderr, "read %u bytes on fd %d\n", ret, fd);
+#endif
+
+	return 0;
+
+error:
+	*length = 0;
+	return 1;
+}
+
+
+/**
+ * @brief Write data to the TUN interface
+ *
+ * Data written to the TUN interface must contain a 4-byte header that gives
+ * the protocol of the data. See the read_from_tun function for details.
+ *
+ * @param fd      The TUN file descriptor to write data to
+ * @param packet  The packet to write to the TUN interface (header included)
+ * @param length  The length of the packet (header included)
+ * @return        0 in case of success, a non-null value otherwise
+ */
+int write_to_tun(int fd, unsigned char *packet, unsigned int length)
+{
+	int ret;
+
+	ret = write(fd, packet, length);
+	if(ret < 0)
+	{
+		fprintf(stderr, "write failed: %s (%d)\n", strerror(errno), errno);
+		goto error;
+	}
+
+#if DEBUG
+	fprintf(stderr, "%u bytes written on fd %d\n", length, fd);
+#endif
+
+	return 0;
+
+error:
+	return 1;
+}
+
+
+
+/*
+ * Raw socket:
+ */
+
+
+/**
+ * @brief Create an Ethernet socket
+ *
+ * @param laddr  The local interface name to bind the socket to
+ * @return       An opened socket descriptor on the TUN interface in case of
+ *               success, a negative value otherwise
+ */
+int ethernet_create(const char* laddr, int* localInterfaceIndex)
+{
+	int sock;
+	int ret;
+	struct sockaddr_ll addr = {0};
+
+	/* create an Ethernet ROHC socket */
+  sock = socket(AF_PACKET, SOCK_DGRAM, htons(ROHC_ETHERTYPE));
+
+	if(sock < 0)
+	{
+		fprintf(stderr, "cannot create Ethernet socket:%s\n", strerror(errno));
+		goto quit;
+	}
+
+	/* Use ifreq structure to get interface information */
+  struct ifreq ifr;
+	memset(&ifr, 0, sizeof(struct ifreq));
+  size_t if_name_len = strlen(laddr);
+  if (if_name_len < sizeof(ifr.ifr_name)) 
+	{
+  	memcpy(ifr.ifr_name,laddr,if_name_len);
+    ifr.ifr_name[if_name_len] = 0;
+  }
+	else
+	{
+		fprintf(stderr, "Interface name is too long\n");
+		goto quit;
+  }
+
+	// Get interface index
+	if(ioctl(sock, SIOCGIFINDEX, &ifr) == -1) 
+	{
+    fprintf(stderr, "Failed to get interface. Error:%s", strerror(errno));
+		goto close;
+	}
+
+	*localInterfaceIndex = ifr.ifr_ifindex;
+	printf("Interface %s index %d ", laddr, *localInterfaceIndex);
+
+	/* Bind the socket on given interface for ROHC */
+	bzero(&addr, sizeof(addr));
+	addr.sll_family = AF_PACKET;
+	addr.sll_protocol = htons(ROHC_ETHERTYPE); //ROHC
+	addr.sll_ifindex = *localInterfaceIndex;
+
+	ret = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+	if(ret < 0)
+	{
+		fprintf(stderr, "cannot bind to Ethernrt socket: %s (%d)\n",
+		        strerror(errno), errno);
+		goto close;
+	}
+	
+	return sock;
+
+close:
+	close(sock);
+quit:
+	return -1;
+}
+
+
+/**
+ * @brief Read data from the Ethernet socket
+ *
+ * @param sock    The Ethernet socket descriptor to read data from
+ * @param buffer  The buffer where to store the data
+ * @param length  OUT: the length of the data
+ * @return        0 in case of success, a non-null value otherwise
+ */
+int read_from_ethernet(int sock, unsigned char *buffer, unsigned int *length)
+{
+	struct sockaddr_ll fromAddr;
+	socklen_t fromAddrLen = sizeof(struct sockaddr_ll);
+	int ret;
+
+	bzero(&fromAddr, fromAddrLen);
+	
+	/* read data from the Etherent socket */
+	ret = recvfrom(sock, buffer, *length, 0, (struct sockaddr *) &fromAddr,
+	               &fromAddrLen);
+
+	if(ret < 0 || ret > *length)
+	{
+		fprintf(stderr, "recvfrom failed: %s (%d)\n", strerror(errno), errno);
+		goto error;
+	}
+
+	if(ret == 0)
+		goto quit;
+
+	*length = ret;
+
+#if DEBUG
+	fprintf(stderr, "read one %u-byte ROHC packet from Ethernet \n", *length - 3);
+#endif
+
+quit:
+	return 0;
+
+error:
+	*length = 0;
+	return 1;
+}
+
+
+/**
+ * @brief Write data to Ethernet socket
+ *
+ * All UDP packets contain a sequence number that identify the UDP packet. It
+ * helps discovering lost packets (for statistical purposes). The buffer that
+ * contains the ROHC packet must have 2 bytes of free space at the beginning.
+ * This allows the write_to_ethernet function to add the 2-bytes sequence number in
+ * the UDP packet without allocating new memory.
+ *
+ * @param sock    The UDP socket descriptor to write data to
+ * @param destMacOctetes The remote MAC address
+ * @param localInterfaceIndex The local interface index
+ * @param buffer  The packet to write to the UDP socket
+ * @param length  The length of the packet
+ * @return        0 in case of success, a non-null value otherwise
+ */
+int write_to_ethernet(int sock, unsigned char destMacOctets[ETHER_ADDR_LEN],
+											int localInterfaceIndex,
+		                  unsigned char *packet, unsigned int length)
+{
+	struct sockaddr_ll addr;
+	int ret;
+
+	bzero(&addr, sizeof(addr));
+	addr.sll_family = AF_PACKET;
+	addr.sll_protocol = htons(ROHC_ETHERTYPE);
+	addr.sll_ifindex = localInterfaceIndex;
+	addr.sll_halen = ETHER_ADDR_LEN;
+
+	// Destination MAC Address
+	memcpy(addr.sll_addr,destMacOctets,ETHER_ADDR_LEN);
+
+	/* write the tunnel sequence number at the beginning of packet */
+	packet[0] = (htons(seq) >> 8) & 0xff;
+	packet[1] = htons(seq) & 0xff;
+
+	/* Actual ROHC Packet Length. Since for Ethernet min payload is 46
+     and any excess bytes after payload are  padded. It is very much 
+     possible that actual ROHC packet length is less than 46 bytes
+     So the actual ROHC packet length is conveyed in third byte */
+  packet[2] = length - 3;
+
+	/* send the data on Ethernet socket */
+	ret = sendto(sock, packet, length, 0, (struct sockaddr *) &addr,
+	             sizeof(struct sockaddr_ll));
+	if(ret < 0)
+	{
+		fprintf(stderr, "sendto failed: %s (%d)\n", strerror(errno), errno);
+		goto error;
+	}
+
+#if DEBUG
+	fprintf(stderr, "%u bytes written on Ethernet \n", length);
+#endif
+
+	return 0;
+
+error:
+	return 1;
+}
+
+
+
+/*
+ * Forwarding between the TUN interface and the UDP socket
+ */
+
+
+/**
+ * @brief Forward IP packets received on the TUN interface to Ethernet socket
+ *
+ * The function compresses the IP packets thanks to the ROHC library before
+ * sending them on the Ethernet socket.
+ *
+ * @param comp   The ROHC compressor
+ * @param from   The TUN file descriptor to read from
+ * @param to     The Ethernet socket descriptor to write to
+ * @param destMacOctetes The remote MAC address
+ * @param localInterfaceIndex The local interface index
+ * @param error  Type of error emulation (0 = none, 1 = uniform,
+ *               2 = non-uniform/burst)
+ * @param ber    The BER (Binary Error Rate) to emulate (value used on first
+ *               call only if error model is uniform)
+ * @param pe2    The probability to be in error state (value used on first
+ *               call only if error model is non-uniform)
+ * @param p2     The probability to stay in error state (value used on first
+ *               call only if error model is non-uniform)
+ * @return       0 in case of success, a non-null value otherwise
+ */
+int tun2ethernet(struct rohc_comp *comp,
+            int from, int to,
+						unsigned char destMacOctets[ETHER_ADDR_LEN],
+						int localInterfaceIndex,
+            int error, double ber, double pe2, double p2)
+{
+	static unsigned char buffer[TUNTAP_BUFSIZE];
+	static unsigned char rohc_packet[3 + MAX_ROHC_SIZE];
+	unsigned int buffer_len = TUNTAP_BUFSIZE;
+	unsigned char *packet;
+	unsigned int packet_len;
+	bool is_segment = false;
+	size_t rohc_size;
+	int ret;
+
+	/* error emulation */
+	static unsigned int dropped = 0;
+	int to_drop = 0;
+
+	/* uniform model */
+	static unsigned long nb_bytes = 0;
+	static unsigned long bytes_without_error = 0;
+
+	/* non-uniform error model */
+	static int is_state_drop = 0;
+	static float p1 = 0;
+	static struct timeval last;
+	struct timeval now;
+
+	/* statistics output */
+	rohc_comp_last_packet_info2_t last_packet_info;
+	const char *modes[] = { "error", "U-mode", "O-mode", "R-mode" };
+	const char *states[] = { "error", "IR", "FO", "SO" };
+
+	/* init the error model variables */
+	if(error > 0)
+	{
+		/* init uniform error model variables */
+		if(error == 1 && bytes_without_error == 0)
+		{
+			// find out the number of bytes without an error
+			bytes_without_error = (unsigned long) (1 / (ber * 8));
+		}
+
+		/* init non-uniform error model variables */
+		if(error == 2 && p1 == 0)
+		{
+			/* init of the random generator */
+			gettimeofday(&last, NULL);
+			srand(last.tv_sec);
+			
+			/* init the probability to stay in non-error state */
+			p1 = (p2 - 1) / (1 - pe2) + 2 - p2;
+		}
+	}
+
+#if DEBUG
+	fprintf(stderr, "\n");
+#endif
+
+	/* read the IP packet from the virtual interface */
+	ret = read_from_tun(from, buffer, &buffer_len);
+	if(ret != 0)
+	{
+		fprintf(stderr, "read_from_tun failed\n");
+		goto error;
+	}
+
+	if(buffer_len == 0)
+		goto quit;
+
+	packet = &buffer[4];
+	packet_len = buffer_len - 4;
+
+	/* increment the tunnel sequence number */
+	seq++;
+
+	/* compress the IP packet */
+#if DEBUG
+	fprintf(stderr, "compress packet #%u (%u bytes)\n", seq, packet_len);
+#endif
+	ret = rohc_compress2(comp, packet, packet_len,
+	                          rohc_packet + 3, MAX_ROHC_SIZE,
+														&rohc_size);
+	if(ret == ROHC_NEED_SEGMENT)
+	{
+		is_segment = true;
+	}
+	else if(ret != ROHC_OK)
+	{
+		fprintf(stderr, "compression of packet #%u failed\n", seq);
+		dump_packet("IP packet", packet, packet_len);
+		goto error;
+	}
+
+	/* emulate lossy medium if asked to do so */
+	if(error == 1) /* uniform error model */
+	{
+		if(nb_bytes + rohc_size >= bytes_without_error)
+		{
+			to_drop = 1;
+			dropped++;
+			fprintf(stderr, "error inserted, ROHC packet #%u dropped\n", seq);
+			nb_bytes = rohc_size - (bytes_without_error - nb_bytes);
+		}
+		
+		nb_bytes += rohc_size;
+	}
+	else if(error == 2) /* non-uniform/burst error model */
+	{
+		/* reset to normal state if too much time between two packets */
+		gettimeofday(&now, NULL);
+		if(is_state_drop && is_timeout(last, now, 2))
+		{
+			fprintf(stderr, "go back to normal state (too much time between "
+			        "packets #%u and #%u)\n", seq - 1, seq);
+			is_state_drop = 0;
+		}
+		last = now;
+
+		/* do we change state ? */
+		int r = rand() % 1000;
+		if(!is_state_drop)
+			is_state_drop = (r > (int) (p1 * 1000));
+		else
+			is_state_drop = (r <= (int) (p2 * 1000));
+
+		if(is_state_drop)
+		{
+			to_drop = 1;
+			dropped++;
+			fprintf(stderr, "error inserted, ROHC packet #%u dropped\n", seq);
+		}
+	}
+
+	/* write the ROHC packet to Ethernet if not dropped */
+	if(!to_drop)
+	{
+		if(is_segment)
+		{
+			/* retrieve and transmit all remaining ROHC segments */
+			while((ret = rohc_comp_get_segment(comp, rohc_packet + 3, MAX_ROHC_SIZE,
+			                                   &rohc_size)) != ROHC_NEED_SEGMENT)
+			{
+				/* write the ROHC segment in the UDP tunnel */
+				ret = write_to_ethernet(to, destMacOctets, localInterfaceIndex,
+																rohc_packet, 3 + rohc_size);
+				if(ret != 0)
+				{
+					fprintf(stderr, "write_to_ethernet(segment) failed\n");
+					goto error;
+				}
+			}
+		}
+		else
+		{
+			/* write the ROHC packet in the UDP tunnel */
+			ret = write_to_ethernet(to, destMacOctets, localInterfaceIndex,
+																rohc_packet, 3 + rohc_size);
+			if(ret != 0)
+			{
+				fprintf(stderr, "write_to_ethernet(packet) failed\n");
+				goto error;
+			}
+		}
+	}
+
+	/* print packet statistics */
+  last_packet_info.version_major = 0;
+	last_packet_info.version_minor = 0;
+	ret = rohc_comp_get_last_packet_info2(comp, &last_packet_info);
+	if(ret != ROHC_OK)
+	{
+		fprintf(stderr, "cannot display stats about the last compressed packet\n");
+		goto error;
+	}
+	fprintf(stats_comp, "%d\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%u\n",
+	        seq,
+	        modes[last_packet_info.context_mode],
+	        states[last_packet_info.context_state],
+	        last_packet_info.total_last_uncomp_size,
+	        last_packet_info.header_last_uncomp_size,
+	        last_packet_info.total_last_comp_size,
+	        last_packet_info.header_last_comp_size,
+	        dropped);
+	fflush(stats_comp);
+
+quit:
+	return 0;
+
+error:
+	return 1;
+}
+
+
+/*
+ * @brief Print packet statistics for decompressor
+ *
+ * @param decomp        The ROHC decompressor
+ * @param seq           The tunnel sequence number
+ * @param lost_packets  The number of lost packets
+ * @return              0 in case of success, 1 otherwise
+ */
+int print_decomp_stats(struct rohc_decomp *decomp,
+                       unsigned int seq,
+                       unsigned int lost_packets)
+{
+	if(decomp->last_context == NULL)
+	{
+		fprintf(stderr, "cannot display stats (last context == NULL)\n");
+		goto error;
+	}
+
+	fprintf(stats_decomp, "%u\t%d\t%u\t%d\n", seq,
+	        lost_packets + decomp->last_context->num_decomp_failures,
+	        lost_packets, decomp->last_context->num_decomp_failures);
+	fflush(stats_decomp);
+
+	return 0;
+
+error:
+	return 1;
+}
+
+
+/**
+ * @brief Forward ROHC packets received on the Ethernet to the TUN interface
+ *
+ * The function decompresses the ROHC packets thanks to the ROHC library before
+ * sending them on the TUN interface.
+ *
+ * @param decomp  The ROHC decompressor
+ * @param from    The Ethernet socket descriptor to read from
+ * @param to      The TUN file descriptor to write to
+ * @param localInterfaceIndex The local interface index
+ * @return        0 in case of success, a non-null value otherwise
+ */
+int ethernet2tun(struct rohc_decomp *decomp, int from,
+								int to, int localInterfaceIndex)
+{
+	static unsigned char packet[3 + MAX_ROHC_SIZE];
+	static unsigned char decomp_packet[MAX_ROHC_SIZE + 4];
+	unsigned int packet_len = TUNTAP_BUFSIZE;
+	int decomp_size;
+	int ret;
+	static unsigned int max_seq = 0;
+	unsigned int new_seq;
+	static unsigned long lost_packets = 0;
+  unsigned int rohc_pkt_len = 0;
+
+#if DEBUG
+	fprintf(stderr, "\n");
+#endif
+
+	/* read the sequence number + ROHC packet from the UDP tunnel */
+	ret = read_from_ethernet(from, packet, &packet_len);
+	if(ret != 0)
+	{
+		fprintf(stderr, "read_from_ethernet failed\n");
+		goto error;
+	}
+
+	if(packet_len <= 2)
+		goto quit;
+
+	/* find out if some ROHC packets were lost between compressor and
+	 * decompressor (use the tunnel sequence number) */
+	new_seq = ntohs((packet[0] << 8) + packet[1]);
+
+	/* Actual ROHC Packet Length. Since for Ethernet min payload is 46
+     bytes and it is possible that actual ROHC packet length is not
+     that much. So the actual length is extracted from third byte */
+	rohc_pkt_len = packet[2];
+
+	if(new_seq < max_seq)
+	{
+		/* some packets were reordered, the packet was wrongly
+		 * considered as lost */
+		fprintf(stderr, "ROHC packet with seq = %u received after seq = %u\n",
+		        new_seq, max_seq);
+		lost_packets--;
+	}
+	else if(new_seq > max_seq + 1)
+	{
+		/* there is a gap between sequence numbers, some packets were lost */
+		fprintf(stderr, "ROHC packet(s) probably lost between "
+		        "seq = %u and seq = %u\n", max_seq, new_seq);
+		lost_packets += new_seq - (max_seq + 1);
+	}
+	else if(new_seq == max_seq)
+	{
+		/* should not happen */
+		fprintf(stderr, "ROHC packet #%u duplicated\n", new_seq);
+	}
+	
+	if(new_seq > max_seq)
+	{
+		/* update max sequence numbers */
+		max_seq = new_seq;
+	}
+
+	/* decompress the ROHC packet */
+#if DEBUG
+	fprintf(stderr, "decompress ROHC packet #%u (%u bytes)\n",
+	        new_seq, rohc_pkt_len);
+#endif
+	decomp_size = rohc_decompress(decomp, packet + 3, rohc_pkt_len,
+	                              &decomp_packet[4], MAX_ROHC_SIZE);
+	if(decomp_size <= 0)
+	{
+		if(decomp_size == ROHC_FEEDBACK_ONLY)
+		{
+			/* no stats for feedback-only packets */
+			goto quit;
+		}
+		else
+		{
+			fprintf(stderr, "decompression of packet #%u failed\n", new_seq);
+			dump_packet("ROHC packet", packet + 3, packet_len - 3);
+			goto drop;
+		}
+	}
+
+	/* build the TUN header */
+	decomp_packet[0] = 0;
+	decomp_packet[1] = 0;
+	switch((decomp_packet[4] >> 4) & 0x0f)
+	{
+		case 4: /* IPv4 */
+			decomp_packet[2] = 0x08;
+			decomp_packet[3] = 0x00;
+			break;
+		case 6: /* IPv6 */
+			decomp_packet[2] = 0x86;
+			decomp_packet[3] = 0xdd;
+			break;
+		default:
+			fprintf(stderr, "bad IP version (%d)\n",
+			        (decomp_packet[4] >> 4) & 0x0f);
+			dump_packet("ROHC packet", packet, packet_len);
+			dump_packet("Decompressed packet", &decomp_packet[4], decomp_size);
+			goto drop;
+	}
+	
+	/* write the IP packet on the virtual interface */
+	ret = write_to_tun(to, decomp_packet, decomp_size + 4);
+	if(ret != 0)
+	{
+		fprintf(stderr, "write_to_tun failed\n");
+		goto drop;
+	}
+
+	/* print packet statistics */
+	ret = print_decomp_stats(decomp, new_seq, lost_packets);
+	if(ret != 0)
+	{
+		fprintf(stderr, "cannot display stats (print_decomp_stats failed)\n");
+		goto drop;
+	}
+
+quit:
+	return 0;
+
+drop:
+	/* print packet statistics */
+	ret = print_decomp_stats(decomp, new_seq, lost_packets);
+	if(ret != 0)
+		fprintf(stderr, "cannot display stats (print_decomp_stats failed)\n");
+
+error:
+	return 1;
+}
+
+
+
+/*
+ * Feedback flushing to the UDP socket
+ */
+
+
+/**
+ * @brief Flush feedback packets stored at the compressor to the UDP socket
+ *
+ * @param comp   The ROHC compressor
+ * @param to     The UDP socket descriptor to write to
+ * @param raddr  The remote address of the tunnel
+ * @param port   The remote port of the tunnel
+ * @return       0 in case of success, a non-null value otherwise
+ */
+int flush_feedback(struct rohc_comp *comp,
+  								 unsigned char destMacOctets[ETHER_ADDR_LEN],
+									 int localInterfaceIndex, int to)
+{
+	static unsigned char rohc_packet[3 + MAX_ROHC_SIZE];
+	int rohc_size;
+	int ret;
+	
+#if DEBUG
+	fprintf(stderr, "\n");
+#endif
+
+	/* flush feedback data as many times as necessary */
+	do
+	{
+		/* flush feedback data */
+		rohc_size = rohc_feedback_flush(comp, rohc_packet + 3, MAX_ROHC_SIZE);
+
+#if DEBUG
+		fprintf(stderr, "flush %d bytes of feedback data\n", rohc_size);
+#endif
+
+		if(rohc_size > 0)
+		{
+			/* increment the tunnel sequence number */
+			seq++;
+
+			/* write the ROHC packet in the Ethernet tunnel */
+			ret = write_to_ethernet(to, destMacOctets, localInterfaceIndex,
+													rohc_packet, 3 + rohc_size);
+			if(ret != 0)
+			{
+				fprintf(stderr, "write_to_ethernet failed\n");
+				goto error;
+			}
+		}
+	}
+	while(rohc_size > 0);
+
+	return 0;
+
+error:
+	return 1;
+}
+
+
+
+/*
+ * Miscellaneous functions:
+ */
+
+
+/**
+ * @brief Display the content of a IP or ROHC packet
+ *
+ * This function is used for debugging purposes.
+ *
+ * @param descr   A string that describes the packet
+ * @param packet  The packet to display
+ * @param length  The length of the packet to display
+ */
+void dump_packet(char *descr, unsigned char *packet, unsigned int length)
+{
+	unsigned int i;
+
+	fprintf(stderr, "-------------------------------\n");
+	fprintf(stderr, "%s (%u bytes):\n", descr, length);
+	for(i = 0; i < length; i++)
+	{
+		if(i > 0 && (i % 16) == 0)
+			fprintf(stderr, "\n");
+		else if(i > 0 && (i % 8) == 0)
+			fprintf(stderr, "\t");
+
+		fprintf(stderr, "%.2x ", packet[i]);
+	}
+	fprintf(stderr, "\n");
+	fprintf(stderr, "-------------------------------\n");
+}
+
+
+/**
+ * @brief Get a probability number from the command line
+ *
+ * If error = 1, the return value is undetermined.
+ *
+ * @param arg    The argument from the command line
+ * @param error  OUT: whether the conversion failed or not
+ * @return       The probability
+ */
+double get_probability(char *arg, int *error)
+{
+	double proba;
+	char *endptr;
+	
+	/* set error by default */
+	*error = 1;
+
+	/* convert from string to double */
+	proba = strtod(arg, &endptr);
+
+	/* check for conversion error */
+	if(proba == 0 && endptr == arg)
+	{
+		if(errno == ERANGE)
+			fprintf(stderr, "probability out of range (underflow): %s (%d)\n",
+			        strerror(errno), errno);
+		else
+			fprintf(stderr, "bad probability value\n");
+		goto quit;
+	}
+
+	/* check for overflow */
+	if(proba == HUGE_VAL)
+	{
+		fprintf(stderr, "probability out of range (overflow): %s (%d)\n",
+		        strerror(errno), errno);
+		goto quit;
+	}
+
+	/* check probability value */
+	if(proba < 0 || proba > 1)
+	{
+		fprintf(stderr, "probability must not be negative nor greater than 1\n");
+		goto quit;
+	}
+
+	/* everything is fine */
+	*error = 0;
+
+quit:
+	return proba;
+}
+
+/**
+ * @brief Whether timeout is reached or not ?
+ *
+ * Timeout is reached if the differences between the two dates
+ * is greater than the amount of time given as third parameter.
+ *
+ * @param first   The first date
+ * @param second  The second date
+ * @param max     The maximal amount of time between the two dates
+ *                in seconds
+ * @return        Whether timeout is reached or not ?
+ */
+int is_timeout(struct timeval first,
+               struct timeval second,
+               unsigned int max)
+{
+	unsigned int delta_sec;
+	int is_timeout;
+
+	delta_sec = second.tv_sec - first.tv_sec;
+
+	if(delta_sec > max)
+		is_timeout = 1;
+	else if(delta_sec == max)
+	{
+		if(second.tv_usec > first.tv_usec)
+			is_timeout = 1;
+		else
+			is_timeout = 0;
+	}
+	else
+		is_timeout = 0;
+
+	return is_timeout;
+}
+
+int convertMacStringToArray(const char * macStr,
+														unsigned char macOctets[ETHER_ADDR_LEN])
+{
+	const char* ch = macStr;
+  char first = 0;
+	char second = 0;
+  char p = 0;
+	int i = 0;
+  int sep_count = 0;
+	int mac_byte_count = 0;
+
+	while(*ch)
+	{
+		if(*ch == ':')
+		{
+			macOctets[i] = (first << 4) | second;
+			++i;
+			++sep_count;
+		}
+		else
+		{
+			p = toupper(*ch);
+			if(isalpha(p) && (p >= 'A' && p <= 'F'))
+			{
+				first = p - 'A' + 10;
+			}
+			else if(isdigit(p) && (p >= '0' || p <= '9'))
+			{
+				first = p - '0';
+			}
+			else
+			{
+				fprintf(stderr, "Wrong char %c at octet number %d\n", p, i+1);
+				return 0;
+			}
+			
+			++ch;
+			p = toupper(*ch);
+			if(isalpha(p) && (p >= 'A' && p <= 'F'))
+			{
+				second = p - 'A' + 10;
+			}
+			else if(isdigit(p) && (p >= '0' || p <= '9'))
+			{
+				second = p - '0';
+			}
+			else
+			{
+				fprintf(stderr, "Wrong char %c at octet number %d\n", p, i+1);
+				return 0;
+			}
+			++mac_byte_count;
+		}
+		++ch;
+	}
+	macOctets[i] = (first << 4) | second;
+
+	if(sep_count != 5 || mac_byte_count != 6)
+	{
+		return 0;
+	}
+
+	return i + 1;
+}
+
+/**
+ * @brief Generate a random number
+ *
+ * @param comp          The ROHC compressor
+ * @param user_context  Should always be NULL
+ * @return              A random number
+ */
+static int gen_random_num(const struct rohc_comp *const comp,
+                          void *const user_context)
+{
+	assert(comp != NULL);
+	assert(user_context == NULL);
+	return rand();
+}
+

=== modified file 'configure.ac'
--- configure.ac	2013-01-06 13:30:27 +0000
+++ configure.ac	2013-01-07 10:35:12 +0000
@@ -629,6 +629,7 @@
 	statistics/Makefile \
 	examples/Makefile \
 	app/Makefile \
+  app/ethTunnel/Makefile \
 	app/performance/Makefile \
 	app/tunnel/Makefile \
 	app/sniffer/Makefile \


Follow ups