Index: uspace/srv/net/il/ip/ip.c
===================================================================
--- uspace/srv/net/il/ip/ip.c	(revision e9caf4779c4818e0894f8ea2cb6815ec2e723d8f)
+++ uspace/srv/net/il/ip/ip.c	(revision e8199d776ec319b694087134f35a2caed4576004)
@@ -28,11 +28,14 @@
 
 /** @addtogroup ip
- *  @{
+ * @{
  */
 
 /** @file
- *  IP module implementation.
- *  @see arp.h
- */
+ * IP module implementation.
+ * @see arp.h
+ */
+
+#include "ip.h"
+#include "ip_module.h"
 
 #include <async.h>
@@ -51,4 +54,8 @@
 #include <byteorder.h>
 
+#include <adt/measured_strings.h>
+#include <adt/module_map.h>
+
+#include <packet_client.h>
 #include <net/socket_codes.h>
 #include <net/in.h>
@@ -71,341 +78,180 @@
 #include <nil_interface.h>
 #include <tl_interface.h>
-#include <adt/measured_strings.h>
-#include <adt/module_map.h>
-#include <packet_client.h>
 #include <packet_remote.h>
 #include <il_local.h>
 
-#include "ip.h"
-#include "ip_module.h"
-#include "ip_local.h"
-
-/** IP module name.
- */
-#define NAME  "ip"
-
-/** IP version 4.
- */
-#define IPV4				4
-
-/** Default network interface IP version.
- */
+/** IP module name. */
+#define NAME			"ip"
+
+/** IP version 4. */
+#define IPV4			4
+
+/** Default network interface IP version. */
 #define NET_DEFAULT_IPV		IPV4
 
-/** Default network interface IP routing.
- */
+/** Default network interface IP routing. */
 #define NET_DEFAULT_IP_ROUTING	false
 
-/** Minimum IP packet content.
- */
-#define IP_MIN_CONTENT	576
-
-/** ARP module name.
- */
-#define ARP_NAME				"arp"
-
-/** ARP module filename.
- */
-#define ARP_FILENAME			"/srv/arp"
-
-/** IP packet address length.
- */
-#define IP_ADDR							sizeof(struct sockaddr_in6)
-
-/** IP packet prefix length.
- */
-#define IP_PREFIX						sizeof(ip_header_t)
-
-/** IP packet suffix length.
- */
-#define IP_SUFFIX						0
-
-/** IP packet maximum content length.
- */
-#define IP_MAX_CONTENT					65535
-
-/** The IP localhost address.
- */
+/** Minimum IP packet content. */
+#define IP_MIN_CONTENT		576
+
+/** ARP module name. */
+#define ARP_NAME		"arp"
+
+/** ARP module filename. */
+#define ARP_FILENAME		"/srv/arp"
+
+/** IP packet address length. */
+#define IP_ADDR			sizeof(struct sockaddr_in6)
+
+/** IP packet prefix length. */
+#define IP_PREFIX		sizeof(ip_header_t)
+
+/** IP packet suffix length. */
+#define IP_SUFFIX		0
+
+/** IP packet maximum content length. */
+#define IP_MAX_CONTENT		65535
+
+/** The IP localhost address. */
 #define IPV4_LOCALHOST_ADDRESS	htonl((127 << 24) + 1)
 
-/** IP global data.
- */
-ip_globals_t	ip_globals;
-
-DEVICE_MAP_IMPLEMENT(ip_netifs, ip_netif_t)
-
-INT_MAP_IMPLEMENT(ip_protos, ip_proto_t)
-
-GENERIC_FIELD_IMPLEMENT(ip_routes, ip_route_t)
-
-/** Updates the device content length according to the new MTU value.
- *  @param[in] device_id The device identifier.
- *  @param[in] mtu The new mtu value.
- *  @returns EOK on success.
- *  @returns ENOENT if device is not found.
- */
-int ip_mtu_changed_message(device_id_t device_id, size_t mtu);
-
-/** Updates the device state.
- *  @param[in] device_id The device identifier.
- *  @param[in] state The new state value.
- *  @returns EOK on success.
- *  @returns ENOENT if device is not found.
- */
-int ip_device_state_message(device_id_t device_id, device_state_t state);
-
-/** Returns the device packet dimensions for sending.
- *  @param[in] phone The service module phone.
- *  @param[in] message The service specific message.
- *  @param[in] device_id The device identifier.
- *  @param[out] addr_len The minimum reserved address length.
- *  @param[out] prefix The minimum reserved prefix size.
- *  @param[out] content The maximum content size.
- *  @param[out] suffix The minimum reserved suffix size.
- *  @returns EOK on success.
- */
-int ip_packet_size_message(device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix);
-
-/** Registers the transport layer protocol.
- *  The traffic of this protocol will be supplied using either the receive function or IPC message.
- *  @param[in] protocol The transport layer module protocol.
- *  @param[in] service The transport layer module service.
- *  @param[in] phone The transport layer module phone.
- *  @param[in] tl_received_msg The receiving function.
- *  @returns EOK on success.
- *  @returns EINVAL if the protocol parameter and/or the service parameter is zero (0).
- *  @returns EINVAL if the phone parameter is not a positive number and the tl_receive_msg is NULL.
- *  @returns ENOMEM if there is not enough memory left.
- */
-int ip_register(int protocol, services_t service, int phone, tl_received_msg_t tl_received_msg);
-
-/** Initializes a new network interface specific data.
- *  Connects to the network interface layer module, reads the netif configuration, starts an ARP module if needed and sets the netif routing table.
- *  The device identifier and the nil service has to be set.
- *  @param[in,out] ip_netif Network interface specific data.
- *  @returns EOK on success.
- *  @returns ENOTSUP if DHCP is configured.
- *  @returns ENOTSUP if IPv6 is configured.
- *  @returns EINVAL if any of the addresses is invalid.
- *  @returns EINVAL if the used ARP module is not known.
- *  @returns ENOMEM if there is not enough memory left.
- *  @returns Other error codes as defined for the net_get_device_conf_req() function.
- *  @returns Other error codes as defined for the bind_service() function.
- *  @returns Other error codes as defined for the specific arp_device_req() function.
- *  @returns Other error codes as defined for the nil_packet_size_req() function.
- */
-int ip_netif_initialize(ip_netif_ref ip_netif);
-
-/** Sends the packet or the packet queue via the specified route.
- *  The ICMP_HOST_UNREACH error notification may be sent if route hardware destination address is found.
- *  @param[in,out] packet The packet to be sent.
- *  @param[in] netif The target network interface.
- *  @param[in] route The target route.
- *  @param[in] src The source address.
- *  @param[in] dest The destination address.
- *  @param[in] error The error module service.
- *  @returns EOK on success.
- *  @returns Other error codes as defined for the arp_translate_req() function.
- *  @returns Other error codes as defined for the ip_prepare_packet() function.
- */
-int ip_send_route(packet_t packet, ip_netif_ref netif, ip_route_ref route, in_addr_t * src, in_addr_t dest, services_t error);
-
-/** Prepares the outgoing packet or the packet queue.
- *  The packet queue is a fragmented packet
- *  Updates the first packet's IP header.
- *  Prefixes the additional packets with fragment headers.
- *  @param[in] source The source address.
- *  @param[in] dest The destination address.
- *  @param[in,out] packet The packet to be sent.
- *  @param[in] destination The destination hardware address.
- *  @returns EOK on success.
- *  @returns EINVAL if the packet is too small to contain the IP header.
- *  @returns EINVAL if the packet is too long than the IP allows.
- *  @returns ENOMEM if there is not enough memory left.
- *  @returns Other error codes as defined for the packet_set_addr() function.
- */
-int ip_prepare_packet(in_addr_t * source, in_addr_t dest, packet_t packet, measured_string_ref destination);
-
-/** Checks the packet queue lengths and fragments the packets if needed.
- *  The ICMP_FRAG_NEEDED error notification may be sent if the packet needs to be fragmented and the fragmentation is not allowed.
- *  @param[in,out] packet The packet or the packet queue to be checked.
- *  @param[in] prefix The minimum prefix size.
- *  @param[in] content The maximum content size.
- *  @param[in] suffix The minimum suffix size.
- *  @param[in] addr_len The minimum address length.
- *  @param[in] error The error module service.
- *  @returns The packet or the packet queue of the allowed length.
- *  @returns NULL if there are no packets left.
- */
-packet_t ip_split_packet(packet_t packet, size_t prefix, size_t content, size_t suffix, socklen_t addr_len, services_t error);
-
-/** Checks the packet length and fragments it if needed.
- *  The new fragments are queued before the original packet.
- *  @param[in,out] packet The packet to be checked.
- *  @param[in] length The maximum packet length.
- *  @param[in] prefix The minimum prefix size.
- *  @param[in] suffix The minimum suffix size.
- *  @param[in] addr_len The minimum address length.
- *  @returns EOK on success.
- *  @returns EINVAL if the packet_get_addr() function fails.
- *  @returns EINVAL if the packet does not contain the IP header.
- *  @returns EPERM if the packet needs to be fragmented and the fragmentation is not allowed.
- *  @returns ENOMEM if there is not enough memory left.
- *  @returns ENOMEM if there is no packet available.
- *  @returns ENOMEM if the packet is too small to contain the IP header.
- *  @returns Other error codes as defined for the packet_trim() function.
- *  @returns Other error codes as defined for the ip_create_middle_header() function.
- *  @returns Other error codes as defined for the ip_fragment_packet_data() function.
- */
-int ip_fragment_packet(packet_t packet, size_t length, size_t prefix, size_t suffix, socklen_t addr_len);
-
-/** Fragments the packet from the end.
- *  @param[in] packet The packet to be fragmented.
- *  @param[in,out] new_packet The new packet fragment.
- *  @param[in,out] header The original packet header.
- *  @param[in,out] new_header The new packet fragment header.
- *  @param[in] length The new fragment length.
- *  @param[in] src The source address.
- *  @param[in] dest The destiantion address.
- *  @param[in] addrlen The address length.
- *  @returns EOK on success.
- *  @returns ENOMEM if the target packet is too small.
- *  @returns Other error codes as defined for the packet_set_addr() function.
- *  @returns Other error codes as defined for the pq_insert_after() function.
- */
-int ip_fragment_packet_data(packet_t packet, packet_t new_packet, ip_header_ref header, ip_header_ref new_header, size_t length, const struct sockaddr * src, const struct sockaddr * dest, socklen_t addrlen);
-
-/** Prefixes a middle fragment header based on the last fragment header to the packet.
- *  @param[in] packet The packet to be prefixed.
- *  @param[in] last The last header to be copied.
- *  @returns The prefixed middle header.
- *  @returns NULL on error.
- */
-ip_header_ref ip_create_middle_header(packet_t packet, ip_header_ref last);
-
-/** Copies the fragment header.
- *  Copies only the header itself and relevant IP options.
- *  @param[out] last The created header.
- *  @param[in] first The original header to be copied.
- */
-void ip_create_last_header(ip_header_ref last, ip_header_ref first);
-
-/** Returns the network interface's IP address.
- *  @param[in] netif The network interface.
- *  @returns The IP address.
- *  @returns NULL if no IP address was found.
- */
-in_addr_t * ip_netif_address(ip_netif_ref netif);
-
-/** Searches all network interfaces if there is a suitable route.
- *  @param[in] destination The destination address.
- *  @returns The found route.
- *  @returns NULL if no route was found.
- */
-ip_route_ref ip_find_route(in_addr_t destination);
-
-/** Searches the network interfaces if there is a suitable route.
- *  @param[in] netif The network interface to be searched for routes. May be NULL.
- *  @param[in] destination The destination address.
- *  @returns The found route.
- *  @returns NULL if no route was found.
- */
-ip_route_ref ip_netif_find_route(ip_netif_ref netif, in_addr_t destination);
-
-/** Processes the received IP packet or the packet queue one by one.
- *  The packet is either passed to another module or released on error.
- *  @param[in] device_id The source device identifier.
- *  @param[in,out] packet The received packet.
- *  @returns EOK on success and the packet is no longer needed.
- *  @returns EINVAL if the packet is too small to carry the IP packet.
- *  @returns EINVAL if the received address lengths differs from the registered values.
- *  @returns ENOENT if the device is not found in the cache.
- *  @returns ENOENT if the protocol for the device is not found in the cache.
- *  @returns ENOMEM if there is not enough memory left.
- */
-int ip_receive_message(device_id_t device_id, packet_t packet);
-
-/** Processes the received packet.
- *  The packet is either passed to another module or released on error.
- *  The ICMP_PARAM_POINTER error notification may be sent if the checksum is invalid.
- *  The ICMP_EXC_TTL error notification may be sent if the TTL is less than two (2).
- *  The ICMP_HOST_UNREACH error notification may be sent if no route was found.
- *  The ICMP_HOST_UNREACH error notification may be sent if the packet is for another host and the routing is disabled.
- *  @param[in] device_id The source device identifier.
- *  @param[in] packet The received packet to be processed.
- *  @returns EOK on success.
- *  @returns EINVAL if the TTL is less than two (2).
- *  @returns EINVAL if the checksum is invalid.
- *  @returns EAFNOSUPPORT if the address family is not supported.
- *  @returns ENOENT if no route was found.
- *  @returns ENOENT if the packet is for another host and the routing is disabled.
- */
-int ip_process_packet(device_id_t device_id, packet_t packet);
-
-/** Returns the packet destination address from the IP header.
- *  @param[in] header The packet IP header to be read.
- *  @returns The packet destination address.
- */
-in_addr_t ip_get_destination(ip_header_ref header);
-
-/** Delivers the packet to the local host.
- *  The packet is either passed to another module or released on error.
- *  The ICMP_PROT_UNREACH error notification may be sent if the protocol is not found.
- *  @param[in] device_id The source device identifier.
- *  @param[in] packet The packet to be delivered.
- *  @param[in] header The first packet IP header. May be NULL.
- *  @param[in] error The packet error service.
- *  @returns EOK on success.
- *  @returns ENOTSUP if the packet is a fragment.
- *  @returns EAFNOSUPPORT if the address family is not supported.
- *  @returns ENOENT if the target protocol is not found.
- *  @returns Other error codes as defined for the packet_set_addr() function.
- *  @returns Other error codes as defined for the packet_trim() function.
- *  @returns Other error codes as defined for the protocol specific tl_received_msg function.
- */
-int ip_deliver_local(device_id_t device_id, packet_t packet, ip_header_ref header, services_t error);
+/** IP global data. */
+ip_globals_t ip_globals;
+
+DEVICE_MAP_IMPLEMENT(ip_netifs, ip_netif_t);
+INT_MAP_IMPLEMENT(ip_protos, ip_proto_t);
+GENERIC_FIELD_IMPLEMENT(ip_routes, ip_route_t);
+
+/** Releases the packet and returns the result.
+ *
+ * @param[in] packet	The packet queue to be released.
+ * @param[in] result	The result to be returned.
+ * @return		The result parameter.
+ */
+static int ip_release_and_return(packet_t packet, int result)
+{
+	pq_release_remote(ip_globals.net_phone, packet_get_id(packet));
+	return result;
+}
+
+/** Returns the ICMP phone.
+ *
+ * Searches the registered protocols.
+ *
+ * @returns		The found ICMP phone.
+ * @returns		ENOENT if the ICMP is not registered.
+ */
+static int ip_get_icmp_phone(void)
+{
+	ip_proto_ref proto;
+	int phone;
+
+	fibril_rwlock_read_lock(&ip_globals.protos_lock);
+	proto = ip_protos_find(&ip_globals.protos, IPPROTO_ICMP);
+	phone = proto ? proto->phone : ENOENT;
+	fibril_rwlock_read_unlock(&ip_globals.protos_lock);
+	return phone;
+}
 
 /** Prepares the ICMP notification packet.
- *  Releases additional packets and keeps only the first one.
- *  All packets is released on error.
- *  @param[in] error The packet error service.
- *  @param[in] packet The packet or the packet queue to be reported as faulty.
- *  @param[in] header The first packet IP header. May be NULL.
- *  @returns The found ICMP phone.
- *  @returns EINVAL if the error parameter is set.
- *  @returns EINVAL if the ICMP phone is not found.
- *  @returns EINVAL if the ip_prepare_icmp() fails.
- */
-int ip_prepare_icmp_and_get_phone(services_t error, packet_t packet, ip_header_ref header);
-
-/** Returns the ICMP phone.
- *  Searches the registered protocols.
- *  @returns The found ICMP phone.
- *  @returns ENOENT if the ICMP is not registered.
- */
-int ip_get_icmp_phone(void);
+ *
+ * Releases additional packets and keeps only the first one.
+ *
+ * @param[in] packet	The packet or the packet queue to be reported as faulty.
+ * @param[in] header	The first packet IP header. May be NULL.
+ * @returns		EOK on success.
+ * @returns		EINVAL if there are no data in the packet.
+ * @returns		EINVAL if the packet is a fragment.
+ * @returns		ENOMEM if the packet is too short to contain the IP
+ *			header.
+ * @returns		EAFNOSUPPORT if the address family is not supported.
+ * @returns		EPERM if the protocol is not allowed to send ICMP
+ *			notifications. The ICMP protocol itself.
+ * @returns		Other error codes as defined for the packet_set_addr().
+ */
+static int ip_prepare_icmp(packet_t packet, ip_header_ref header)
+{
+	packet_t next;
+	struct sockaddr *dest;
+	struct sockaddr_in dest_in;
+	socklen_t addrlen;
+
+	// detach the first packet and release the others
+	next = pq_detach(packet);
+	if (next)
+		pq_release_remote(ip_globals.net_phone, packet_get_id(next));
+
+	if (!header) {
+		if (packet_get_data_length(packet) <= sizeof(ip_header_t))
+			return ENOMEM;
+
+		// get header
+		header = (ip_header_ref) packet_get_data(packet);
+		if (!header)
+			return EINVAL;
+
+	}
+
+	// only for the first fragment
+	if (IP_FRAGMENT_OFFSET(header))
+		return EINVAL;
+
+	// not for the ICMP protocol
+	if (header->protocol == IPPROTO_ICMP)
+		return EPERM;
+
+	// set the destination address
+	switch (header->version) {
+	case IPVERSION:
+		addrlen = sizeof(dest_in);
+		bzero(&dest_in, addrlen);
+		dest_in.sin_family = AF_INET;
+		memcpy(&dest_in.sin_addr.s_addr, &header->source_address,
+		    sizeof(header->source_address));
+		dest = (struct sockaddr *) &dest_in;
+		break;
+
+	default:
+		return EAFNOSUPPORT;
+	}
+
+	return packet_set_addr(packet, NULL, (uint8_t *) dest, addrlen);
+}
 
 /** Prepares the ICMP notification packet.
- *  Releases additional packets and keeps only the first one.
- *  @param[in] packet The packet or the packet queue to be reported as faulty.
- *  @param[in] header The first packet IP header. May be NULL.
- *  @returns EOK on success.
- *  @returns EINVAL if there are no data in the packet.
- *  @returns EINVAL if the packet is a fragment.
- *  @returns ENOMEM if the packet is too short to contain the IP header.
- *  @returns EAFNOSUPPORT if the address family is not supported.
- *  @returns EPERM if the protocol is not allowed to send ICMP notifications. The ICMP protocol itself.
- *  @returns Other error codes as defined for the packet_set_addr().
- */
-int ip_prepare_icmp(packet_t packet, ip_header_ref header);
-
-/** Releases the packet and returns the result.
- *  @param[in] packet The packet queue to be released.
- *  @param[in] result The result to be returned.
- *  @return The result parameter.
- */
-int ip_release_and_return(packet_t packet, int result);
-
-int ip_initialize(async_client_conn_t client_connection){
+ *
+ * Releases additional packets and keeps only the first one.
+ * All packets are released on error.
+ *
+ * @param[in] error	The packet error service.
+ * @param[in] packet	The packet or the packet queue to be reported as faulty.
+ * @param[in] header	The first packet IP header. May be NULL.
+ * @returns		The found ICMP phone.
+ * @returns		EINVAL if the error parameter is set.
+ * @returns		EINVAL if the ICMP phone is not found.
+ * @returns		EINVAL if the ip_prepare_icmp() fails.
+ */
+static int
+ip_prepare_icmp_and_get_phone(services_t error, packet_t packet,
+    ip_header_ref header)
+{
+	int phone;
+
+	phone = ip_get_icmp_phone();
+	if (error || (phone < 0) || ip_prepare_icmp(packet, header))
+		return ip_release_and_return(packet, EINVAL);
+	return phone;
+}
+
+/** Initializes the IP module.
+ *
+ * @param[in] client_connection The client connection processing function. The
+ *			module skeleton propagates its own one.
+ * @returns		EOK on success.
+ * @returns		ENOMEM if there is not enough memory left.
+ */
+int ip_initialize(async_client_conn_t client_connection)
+{
 	ERROR_DECLARE;
 
@@ -423,73 +269,76 @@
 	ip_globals.client_connection = client_connection;
 	ERROR_PROPAGATE(modules_initialize(&ip_globals.modules));
-	ERROR_PROPAGATE(add_module(NULL, &ip_globals.modules, ARP_NAME, ARP_FILENAME, SERVICE_ARP, 0, arp_connect_module));
+	ERROR_PROPAGATE(add_module(NULL, &ip_globals.modules, ARP_NAME,
+	    ARP_FILENAME, SERVICE_ARP, 0, arp_connect_module));
 	fibril_rwlock_write_unlock(&ip_globals.lock);
+
 	return EOK;
 }
 
-int ip_device_req_local(int il_phone, device_id_t device_id, services_t netif){
+/** Initializes a new network interface specific data.
+ *
+ * Connects to the network interface layer module, reads the netif
+ * configuration, starts an ARP module if needed and sets the netif routing
+ * table.
+ * 
+ * The device identifier and the nil service has to be set.
+ *
+ * @param[in,out] ip_netif Network interface specific data.
+ * @returns		EOK on success.
+ * @returns		ENOTSUP if DHCP is configured.
+ * @returns		ENOTSUP if IPv6 is configured.
+ * @returns		EINVAL if any of the addresses is invalid.
+ * @returns		EINVAL if the used ARP module is not known.
+ * @returns		ENOMEM if there is not enough memory left.
+ * @returns		Other error codes as defined for the
+ *			net_get_device_conf_req() function.
+ * @returns		Other error codes as defined for the bind_service()
+ *			function.
+ * @returns		Other error codes as defined for the specific
+ *			arp_device_req() function.
+ * @returns		Other error codes as defined for the
+ *			nil_packet_size_req() function.
+ */
+static int ip_netif_initialize(ip_netif_ref ip_netif)
+{
 	ERROR_DECLARE;
 
-	ip_netif_ref ip_netif;
-	ip_route_ref route;
-	int index;
-
-	ip_netif = (ip_netif_ref) malloc(sizeof(ip_netif_t));
-	if(! ip_netif){
-		return ENOMEM;
-	}
-	if(ERROR_OCCURRED(ip_routes_initialize(&ip_netif->routes))){
-		free(ip_netif);
-		return ERROR_CODE;
-	}
-	ip_netif->device_id = device_id;
-	ip_netif->service = netif;
-	ip_netif->state = NETIF_STOPPED;
-	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
-	if(ERROR_OCCURRED(ip_netif_initialize(ip_netif))){
-		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-		ip_routes_destroy(&ip_netif->routes);
-		free(ip_netif);
-		return ERROR_CODE;
-	}
-	if(ip_netif->arp){
-		++ ip_netif->arp->usage;
-	}
-	// print the settings
-	printf("%s: Device registered (id: %d, phone: %d, ipv: %d, conf: %s)\n",
-	    NAME, ip_netif->device_id, ip_netif->phone, ip_netif->ipv,
-	    ip_netif->dhcp ? "dhcp" : "static");
-	
-	// TODO ipv6 addresses
-	
-	char address[INET_ADDRSTRLEN];
-	char netmask[INET_ADDRSTRLEN];
-	char gateway[INET_ADDRSTRLEN];
-	
-	for (index = 0; index < ip_routes_count(&ip_netif->routes); ++ index){
-		route = ip_routes_get_index(&ip_netif->routes, index);
-		if (route) {
-			inet_ntop(AF_INET, (uint8_t *) &route->address.s_addr, address, INET_ADDRSTRLEN);
-			inet_ntop(AF_INET, (uint8_t *) &route->netmask.s_addr, netmask, INET_ADDRSTRLEN);
-			inet_ntop(AF_INET, (uint8_t *) &route->gateway.s_addr, gateway, INET_ADDRSTRLEN);
-			printf("%s: Route %d (address: %s, netmask: %s, gateway: %s)\n",
-			    NAME, index, address, netmask, gateway);
-		}
-	}
-	
-	inet_ntop(AF_INET, (uint8_t *) &ip_netif->broadcast.s_addr, address, INET_ADDRSTRLEN);
-	printf("%s: Broadcast (%s)\n", NAME, address);
-	
-	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-	return EOK;
-}
-
-int ip_netif_initialize(ip_netif_ref ip_netif){
-	ERROR_DECLARE;
-
-	measured_string_t names[] = {{str_dup("IPV"), 3}, {str_dup("IP_CONFIG"), 9}, {str_dup("IP_ADDR"), 7}, {str_dup("IP_NETMASK"), 10}, {str_dup("IP_GATEWAY"), 10}, {str_dup("IP_BROADCAST"), 12}, {str_dup("ARP"), 3}, {str_dup("IP_ROUTING"), 10}};
+	measured_string_t names[] = {
+		{
+			str_dup("IPV"),
+			3
+		},
+		{
+			str_dup("IP_CONFIG"),
+			9
+		},
+		{
+			str_dup("IP_ADDR"),
+			7
+		},
+		{
+			str_dup("IP_NETMASK"),
+			10
+		},
+		{
+			str_dup("IP_GATEWAY"),
+			10
+		},
+		{
+			str_dup("IP_BROADCAST"),
+			12
+		},
+		{
+			str_dup("ARP"),
+			3
+		},
+		{
+			str_dup("IP_ROUTING"),
+			10
+		}
+	};
 	measured_string_ref configuration;
 	size_t count = sizeof(names) / sizeof(measured_string_t);
-	char * data;
+	char *data;
 	measured_string_t address;
 	int index;
@@ -503,18 +352,22 @@
 	ip_netif->routing = NET_DEFAULT_IP_ROUTING;
 	configuration = &names[0];
+
 	// get configuration
-	ERROR_PROPAGATE(net_get_device_conf_req(ip_globals.net_phone, ip_netif->device_id, &configuration, count, &data));
-	if(configuration){
-		if(configuration[0].value){
+	ERROR_PROPAGATE(net_get_device_conf_req(ip_globals.net_phone,
+	    ip_netif->device_id, &configuration, count, &data));
+	if (configuration) {
+		if (configuration[0].value)
 			ip_netif->ipv = strtol(configuration[0].value, NULL, 0);
-		}
-		ip_netif->dhcp = ! str_lcmp(configuration[1].value, "dhcp", configuration[1].length);
-		if(ip_netif->dhcp){
+
+		ip_netif->dhcp = !str_lcmp(configuration[1].value, "dhcp",
+		    configuration[1].length);
+		
+		if (ip_netif->dhcp) {
 			// TODO dhcp
 			net_free_settings(configuration, data);
 			return ENOTSUP;
-		}else if(ip_netif->ipv == IPV4){
+		} else if (ip_netif->ipv == IPV4) {
 			route = (ip_route_ref) malloc(sizeof(ip_route_t));
-			if(! route){
+			if (!route) {
 				net_free_settings(configuration, data);
 				return ENOMEM;
@@ -525,61 +378,83 @@
 			route->netif = ip_netif;
 			index = ip_routes_add(&ip_netif->routes, route);
-			if(index < 0){
+			if (index < 0) {
 				net_free_settings(configuration, data);
 				free(route);
 				return index;
 			}
-			if(ERROR_OCCURRED(inet_pton(AF_INET, configuration[2].value, (uint8_t *) &route->address.s_addr))
-				|| ERROR_OCCURRED(inet_pton(AF_INET, configuration[3].value, (uint8_t *) &route->netmask.s_addr))
-				|| (inet_pton(AF_INET, configuration[4].value, (uint8_t *) &gateway.s_addr) == EINVAL)
-				|| (inet_pton(AF_INET, configuration[5].value, (uint8_t *) &ip_netif->broadcast.s_addr) == EINVAL)){
+			if (ERROR_OCCURRED(inet_pton(AF_INET,
+			    configuration[2].value,
+			    (uint8_t *) &route->address.s_addr)) ||
+			    ERROR_OCCURRED(inet_pton(AF_INET,
+			    configuration[3].value,
+			    (uint8_t *) &route->netmask.s_addr)) ||
+			    (inet_pton(AF_INET, configuration[4].value,
+			    (uint8_t *) &gateway.s_addr) == EINVAL) ||
+			    (inet_pton(AF_INET, configuration[5].value,
+			    (uint8_t *) &ip_netif->broadcast.s_addr) == EINVAL))
+			    {
 				net_free_settings(configuration, data);
 				return EINVAL;
 			}
-		}else{
+		} else {
 			// TODO ipv6 in separate module
 			net_free_settings(configuration, data);
 			return ENOTSUP;
 		}
-		if(configuration[6].value){
-			ip_netif->arp = get_running_module(&ip_globals.modules, configuration[6].value);
-			if(! ip_netif->arp){
-				printf("Failed to start the arp %s\n", configuration[6].value);
+
+		if (configuration[6].value) {
+			ip_netif->arp = get_running_module(&ip_globals.modules,
+			    configuration[6].value);
+			if (!ip_netif->arp) {
+				printf("Failed to start the arp %s\n",
+				    configuration[6].value);
 				net_free_settings(configuration, data);
 				return EINVAL;
 			}
 		}
-		if(configuration[7].value){
+		if (configuration[7].value)
 			ip_netif->routing = (configuration[7].value[0] == 'y');
-		}
+
 		net_free_settings(configuration, data);
 	}
+
 	// binds the netif service which also initializes the device
-	ip_netif->phone = nil_bind_service(ip_netif->service, (ipcarg_t) ip_netif->device_id, SERVICE_IP, ip_globals.client_connection);
-	if(ip_netif->phone < 0){
-		printf("Failed to contact the nil service %d\n", ip_netif->service);
+	ip_netif->phone = nil_bind_service(ip_netif->service,
+	    (ipcarg_t) ip_netif->device_id, SERVICE_IP,
+	    ip_globals.client_connection);
+	if (ip_netif->phone < 0) {
+		printf("Failed to contact the nil service %d\n",
+		    ip_netif->service);
 		return ip_netif->phone;
 	}
+
 	// has to be after the device netif module initialization
-	if(ip_netif->arp){
-		if(route){
+	if (ip_netif->arp) {
+		if (route) {
 			address.value = (char *) &route->address.s_addr;
 			address.length = CONVERT_SIZE(in_addr_t, char, 1);
-			ERROR_PROPAGATE(arp_device_req(ip_netif->arp->phone, ip_netif->device_id, SERVICE_IP, ip_netif->service, &address));
-		}else{
+			ERROR_PROPAGATE(arp_device_req(ip_netif->arp->phone,
+			    ip_netif->device_id, SERVICE_IP, ip_netif->service,
+			    &address));
+		} else {
 			ip_netif->arp = 0;
 		}
 	}
+
 	// get packet dimensions
-	ERROR_PROPAGATE(nil_packet_size_req(ip_netif->phone, ip_netif->device_id, &ip_netif->packet_dimension));
-	if(ip_netif->packet_dimension.content < IP_MIN_CONTENT){
-		printf("Maximum transmission unit %d bytes is too small, at least %d bytes are needed\n", ip_netif->packet_dimension.content, IP_MIN_CONTENT);
+	ERROR_PROPAGATE(nil_packet_size_req(ip_netif->phone,
+	    ip_netif->device_id, &ip_netif->packet_dimension));
+	if (ip_netif->packet_dimension.content < IP_MIN_CONTENT) {
+		printf("Maximum transmission unit %d bytes is too small, at "
+		    "least %d bytes are needed\n",
+		    ip_netif->packet_dimension.content, IP_MIN_CONTENT);
 		ip_netif->packet_dimension.content = IP_MIN_CONTENT;
 	}
+
 	index = ip_netifs_add(&ip_globals.netifs, ip_netif->device_id, ip_netif);
-	if(index < 0){
+	if (index < 0)
 		return index;
-	}
-	if(gateway.s_addr){
+	
+	if (gateway.s_addr) {
 		// the default gateway
 		ip_globals.gateway.address.s_addr = 0;
@@ -588,23 +463,42 @@
 		ip_globals.gateway.netif = ip_netif;
 	}
+
 	return EOK;
 }
 
-int ip_mtu_changed_message(device_id_t device_id, size_t mtu){
+/** Updates the device content length according to the new MTU value.
+ *
+ * @param[in] device_id	The device identifier.
+ * @param[in] mtu	The new mtu value.
+ * @returns		EOK on success.
+ * @returns		ENOENT if device is not found.
+ */
+static int ip_mtu_changed_message(device_id_t device_id, size_t mtu)
+{
 	ip_netif_ref netif;
 
 	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
 	netif = ip_netifs_find(&ip_globals.netifs, device_id);
-	if(! netif){
+	if (!netif) {
 		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
 		return ENOENT;
 	}
 	netif->packet_dimension.content = mtu;
+	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+
 	printf("%s: Device %d changed MTU to %d\n", NAME, device_id, mtu);
-	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+
 	return EOK;
 }
 
-int ip_device_state_message(device_id_t device_id, device_state_t state){
+/** Updates the device state.
+ *
+ * @param[in] device_id	The device identifier.
+ * @param[in] state	The new state value.
+ * @returns		EOK on success.
+ * @returns		ENOENT if device is not found.
+ */
+static int ip_device_state_message(device_id_t device_id, device_state_t state)
+{
 	ip_netif_ref netif;
 
@@ -612,202 +506,108 @@
 	// find the device
 	netif = ip_netifs_find(&ip_globals.netifs, device_id);
-	if(! netif){
+	if (!netif) {
 		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
 		return ENOENT;
 	}
 	netif->state = state;
+	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+
 	printf("%s: Device %d changed state to %d\n", NAME, device_id, state);
-	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+
 	return EOK;
 }
 
-int ip_register(int protocol, services_t service, int phone, tl_received_msg_t received_msg){
-	ip_proto_ref proto;
-	int index;
-
-	if(!(protocol && service && ((phone > 0) || (received_msg)))){
-		return EINVAL;
-	}
-	proto = (ip_proto_ref) malloc(sizeof(ip_protos_t));
-	if(! proto){
-		return ENOMEM;
-	}
-	proto->protocol = protocol;
-	proto->service = service;
-	proto->phone = phone;
-	proto->received_msg = received_msg;
-	fibril_rwlock_write_lock(&ip_globals.protos_lock);
-	index = ip_protos_add(&ip_globals.protos, proto->protocol, proto);
-	if(index < 0){
-		fibril_rwlock_write_unlock(&ip_globals.protos_lock);
-		free(proto);
-		return index;
-	}
-	
-	printf("%s: Protocol registered (protocol: %d, phone: %d)\n",
-	    NAME, proto->protocol, proto->phone);
-	
-	fibril_rwlock_write_unlock(&ip_globals.protos_lock);
-	return EOK;
-}
-
-int ip_send_msg_local(int il_phone, device_id_t device_id, packet_t packet, services_t sender, services_t error){
-	ERROR_DECLARE;
-
-	int addrlen;
-	ip_netif_ref netif;
-	ip_route_ref route;
-	struct sockaddr * addr;
-	struct sockaddr_in * address_in;
-//	struct sockaddr_in6 *	address_in6;
-	in_addr_t * dest;
-	in_addr_t * src;
-	int phone;
-
-	// addresses in the host byte order
-	// should be the next hop address or the target destination address
-	addrlen = packet_get_addr(packet, NULL, (uint8_t **) &addr);
-	if(addrlen < 0){
-		return ip_release_and_return(packet, addrlen);
-	}
-	if((size_t) addrlen < sizeof(struct sockaddr)){
-		return ip_release_and_return(packet, EINVAL);
-	}
-	switch(addr->sa_family){
-		case AF_INET:
-			if(addrlen != sizeof(struct sockaddr_in)){
-				return ip_release_and_return(packet, EINVAL);
+
+/** Prefixes a middle fragment header based on the last fragment header to the
+ * packet.
+ *
+ * @param[in] packet	The packet to be prefixed.
+ * @param[in] last	The last header to be copied.
+ * @returns		The prefixed middle header.
+ * @returns		NULL on error.
+ */
+static ip_header_ref
+ip_create_middle_header(packet_t packet, ip_header_ref last)
+{
+	ip_header_ref middle;
+
+	middle = (ip_header_ref) packet_suffix(packet, IP_HEADER_LENGTH(last));
+	if (!middle)
+		return NULL;
+	memcpy(middle, last, IP_HEADER_LENGTH(last));
+	middle->flags |= IPFLAG_MORE_FRAGMENTS;
+	return middle;
+}
+
+/** Copies the fragment header.
+ *
+ * Copies only the header itself and relevant IP options.
+ *
+ * @param[out] last	The created header.
+ * @param[in] first	The original header to be copied.
+ */
+static void ip_create_last_header(ip_header_ref last, ip_header_ref first)
+{
+	ip_option_ref option;
+	size_t next;
+	size_t length;
+
+	// copy first itself
+	memcpy(last, first, sizeof(ip_header_t));
+	length = sizeof(ip_header_t);
+	next = sizeof(ip_header_t);
+
+	// process all ip options
+	while (next < first->header_length) {
+		option = (ip_option_ref) (((uint8_t *) first) + next);
+		// skip end or noop
+		if ((option->type == IPOPT_END) ||
+		    (option->type == IPOPT_NOOP)) {
+			next++;
+		} else {
+			// copy if told so or skip
+			if (IPOPT_COPIED(option->type)) {
+				memcpy(((uint8_t *) last) + length,
+				    ((uint8_t *) first) + next, option->length);
+				length += option->length;
 			}
-			address_in = (struct sockaddr_in *) addr;
-			dest = &address_in->sin_addr;
-			if(! dest->s_addr){
-				dest->s_addr = IPV4_LOCALHOST_ADDRESS;
-			}
-			break;
-		// TODO IPv6
-/*		case AF_INET6:
-			if(addrlen != sizeof(struct sockaddr_in6)){
-				return EINVAL;
-			}
-			address_in6 = (struct sockaddr_in6 *) dest;
-			address_in6.sin6_addr.s6_addr;
-			IPV6_LOCALHOST_ADDRESS;
-*/		default:
-			return ip_release_and_return(packet, EAFNOSUPPORT);
-	}
-	netif = NULL;
-	route = NULL;
-	fibril_rwlock_read_lock(&ip_globals.netifs_lock);
-	// device specified?
-	if(device_id > 0){
-		netif = ip_netifs_find(&ip_globals.netifs, device_id);
-		route = ip_netif_find_route(netif, * dest);
-		if(netif && (! route) && (ip_globals.gateway.netif == netif)){
-			route = &ip_globals.gateway;
-		}
-	}
-	if(! route){
-		route = ip_find_route(*dest);
-		netif = route ? route->netif : NULL;
-	}
-	if(!(netif && route)){
-		fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
-		phone = ip_prepare_icmp_and_get_phone(error, packet, NULL);
-		if(phone >= 0){
-			// unreachable ICMP if no routing
-			icmp_destination_unreachable_msg(phone, ICMP_NET_UNREACH, 0, packet);
-		}
-		return ENOENT;
-	}
-	if(error){
-		// do not send for broadcast, anycast packets or network broadcast
-		if((! dest->s_addr)
-			|| (!(~ dest->s_addr))
-			|| (!(~((dest->s_addr &(~ route->netmask.s_addr)) | route->netmask.s_addr)))
-			|| (!(dest->s_addr &(~ route->netmask.s_addr)))){
-			return ip_release_and_return(packet, EINVAL);
-		}
-	}
-	// if the local host is the destination
-	if((route->address.s_addr == dest->s_addr)
-		&& (dest->s_addr != IPV4_LOCALHOST_ADDRESS)){
-		// find the loopback device to deliver
-		dest->s_addr = IPV4_LOCALHOST_ADDRESS;
-		route = ip_find_route(*dest);
-		netif = route ? route->netif : NULL;
-		if(!(netif && route)){
-			fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
-			phone = ip_prepare_icmp_and_get_phone(error, packet, NULL);
-			if(phone >= 0){
-				// unreachable ICMP if no routing
-				icmp_destination_unreachable_msg(phone, ICMP_HOST_UNREACH, 0, packet);
-			}
-			return ENOENT;
-		}
-	}
-	src = ip_netif_address(netif);
-	if(! src){
-		fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
-		return ip_release_and_return(packet, ENOENT);
-	}
-	ERROR_CODE = ip_send_route(packet, netif, route, src, * dest, error);
-	fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
-	return ERROR_CODE;
-}
-
-in_addr_t * ip_netif_address(ip_netif_ref netif){
-	ip_route_ref route;
-
-	route = ip_routes_get_index(&netif->routes, 0);
-	return route ? &route->address : NULL;
-}
-
-int ip_send_route(packet_t packet, ip_netif_ref netif, ip_route_ref route, in_addr_t * src, in_addr_t dest, services_t error){
-	ERROR_DECLARE;
-
-	measured_string_t destination;
-	measured_string_ref translation;
-	char * data;
-	int phone;
-
-	// get destination hardware address
-	if(netif->arp && (route->address.s_addr != dest.s_addr)){
-		destination.value = route->gateway.s_addr ? (char *) &route->gateway.s_addr : (char *) &dest.s_addr;
-		destination.length = CONVERT_SIZE(dest.s_addr, char, 1);
-		if(ERROR_OCCURRED(arp_translate_req(netif->arp->phone, netif->device_id, SERVICE_IP, &destination, &translation, &data))){
-//			sleep(1);
-//			ERROR_PROPAGATE(arp_translate_req(netif->arp->phone, netif->device_id, SERVICE_IP, &destination, &translation, &data));
-			pq_release_remote(ip_globals.net_phone, packet_get_id(packet));
-			return ERROR_CODE;
-		}
-		if(!(translation && translation->value)){
-			if(translation){
-				free(translation);
-				free(data);
-			}
-			phone = ip_prepare_icmp_and_get_phone(error, packet, NULL);
-			if(phone >= 0){
-				// unreachable ICMP if no routing
-				icmp_destination_unreachable_msg(phone, ICMP_HOST_UNREACH, 0, packet);
-			}
-			return EINVAL;
-		}
-	}else translation = NULL;
-	if(ERROR_OCCURRED(ip_prepare_packet(src, dest, packet, translation))){
-		pq_release_remote(ip_globals.net_phone, packet_get_id(packet));
-	}else{
-		packet = ip_split_packet(packet, netif->packet_dimension.prefix, netif->packet_dimension.content, netif->packet_dimension.suffix, netif->packet_dimension.addr_len, error);
-		if(packet){
-			nil_send_msg(netif->phone, netif->device_id, packet, SERVICE_IP);
-		}
-	}
-	if(translation){
-		free(translation);
-		free(data);
-	}
-	return ERROR_CODE;
-}
-
-int ip_prepare_packet(in_addr_t * source, in_addr_t dest, packet_t packet, measured_string_ref destination){
+			// next option
+			next += option->length;
+		}
+	}
+
+	// align 4 byte boundary
+	if (length % 4) {
+		bzero(((uint8_t *) last) + length, 4 - (length % 4));
+		last->header_length = length / 4 + 1;
+	} else {
+		last->header_length = length / 4;
+	}
+
+	last->header_checksum = 0;
+}
+
+/** Prepares the outgoing packet or the packet queue.
+ *
+ * The packet queue is a fragmented packet
+ * Updates the first packet's IP header.
+ * Prefixes the additional packets with fragment headers.
+ *
+ * @param[in] source	The source address.
+ * @param[in] dest	The destination address.
+ * @param[in,out] packet The packet to be sent.
+ * @param[in] destination The destination hardware address.
+ * @returns		EOK on success.
+ * @returns		EINVAL if the packet is too small to contain the IP
+ *			header.
+ * @returns		EINVAL if the packet is too long than the IP allows.
+ * @returns		ENOMEM if there is not enough memory left.
+ * @returns		Other error codes as defined for the packet_set_addr()
+ *			function.
+ */
+static int
+ip_prepare_packet(in_addr_t *source, in_addr_t dest, packet_t packet,
+    measured_string_ref destination)
+{
 	ERROR_DECLARE;
 
@@ -819,11 +619,13 @@
 
 	length = packet_get_data_length(packet);
-	if((length < sizeof(ip_header_t)) || (length > IP_MAX_CONTENT)){
+	if ((length < sizeof(ip_header_t)) || (length > IP_MAX_CONTENT))
 		return EINVAL;
-	}
+
 	header = (ip_header_ref) packet_get_data(packet);
-	if(destination){
-		ERROR_PROPAGATE(packet_set_addr(packet, NULL, (uint8_t *) destination->value, CONVERT_SIZE(char, uint8_t, destination->length)));
-	}else{
+	if (destination) {
+		ERROR_PROPAGATE(packet_set_addr(packet, NULL,
+		    (uint8_t *) destination->value,
+		    CONVERT_SIZE(char, uint8_t, destination->length)));
+	} else {
 		ERROR_PROPAGATE(packet_set_addr(packet, NULL, NULL, 0));
 	}
@@ -832,48 +634,65 @@
 	header->fragment_offset_low = 0;
 	header->header_checksum = 0;
-	if(source){
+	if (source)
 		header->source_address = source->s_addr;
-	}
 	header->destination_address = dest.s_addr;
+
 	fibril_rwlock_write_lock(&ip_globals.lock);
-	++ ip_globals.packet_counter;
+	ip_globals.packet_counter++;
 	header->identification = htons(ip_globals.packet_counter);
 	fibril_rwlock_write_unlock(&ip_globals.lock);
-//	length = packet_get_data_length(packet);
-	if(pq_next(packet)){
+
+	if (pq_next(packet)) {
 		last_header = (ip_header_ref) malloc(IP_HEADER_LENGTH(header));
-		if(! last_header){
+		if (!last_header)
 			return ENOMEM;
-		}
 		ip_create_last_header(last_header, header);
 		next = pq_next(packet);
-		while(pq_next(next)){
-			middle_header = (ip_header_ref) packet_prefix(next, IP_HEADER_LENGTH(last_header));
-			if(! middle_header){
+		while (pq_next(next)) {
+			middle_header = (ip_header_ref) packet_prefix(next,
+			    IP_HEADER_LENGTH(last_header));
+			if (!middle_header)
 				return ENOMEM;
-			}
-			memcpy(middle_header, last_header, IP_HEADER_LENGTH(last_header));
+
+			memcpy(middle_header, last_header,
+			    IP_HEADER_LENGTH(last_header));
 			header->flags |= IPFLAG_MORE_FRAGMENTS;
-			middle_header->total_length = htons(packet_get_data_length(next));
-			middle_header->fragment_offset_high = IP_COMPUTE_FRAGMENT_OFFSET_HIGH(length);
-			middle_header->fragment_offset_low = IP_COMPUTE_FRAGMENT_OFFSET_LOW(length);
-			middle_header->header_checksum = IP_HEADER_CHECKSUM(middle_header);
-			if(destination){
-				ERROR_PROPAGATE(packet_set_addr(next, NULL, (uint8_t *) destination->value, CONVERT_SIZE(char, uint8_t, destination->length)));
+			middle_header->total_length =
+			    htons(packet_get_data_length(next));
+			middle_header->fragment_offset_high =
+			    IP_COMPUTE_FRAGMENT_OFFSET_HIGH(length);
+			middle_header->fragment_offset_low =
+			    IP_COMPUTE_FRAGMENT_OFFSET_LOW(length);
+			middle_header->header_checksum =
+			    IP_HEADER_CHECKSUM(middle_header);
+			if (destination) {
+				ERROR_PROPAGATE(packet_set_addr(next, NULL,
+				    (uint8_t *) destination->value,
+				    CONVERT_SIZE(char, uint8_t,
+				    destination->length)));
 			}
 			length += packet_get_data_length(next);
 			next = pq_next(next);
 		}
-		middle_header = (ip_header_ref) packet_prefix(next, IP_HEADER_LENGTH(last_header));
-		if(! middle_header){
+
+		middle_header = (ip_header_ref) packet_prefix(next,
+		    IP_HEADER_LENGTH(last_header));
+		if (!middle_header)
 			return ENOMEM;
-		}
-		memcpy(middle_header, last_header, IP_HEADER_LENGTH(last_header));
-		middle_header->total_length = htons(packet_get_data_length(next));
-		middle_header->fragment_offset_high = IP_COMPUTE_FRAGMENT_OFFSET_HIGH(length);
-		middle_header->fragment_offset_low = IP_COMPUTE_FRAGMENT_OFFSET_LOW(length);
-		middle_header->header_checksum = IP_HEADER_CHECKSUM(middle_header);
-		if(destination){
-			ERROR_PROPAGATE(packet_set_addr(next, NULL, (uint8_t *) destination->value, CONVERT_SIZE(char, uint8_t, destination->length)));
+
+		memcpy(middle_header, last_header,
+		    IP_HEADER_LENGTH(last_header));
+		middle_header->total_length =
+		    htons(packet_get_data_length(next));
+		middle_header->fragment_offset_high =
+		    IP_COMPUTE_FRAGMENT_OFFSET_HIGH(length);
+		middle_header->fragment_offset_low =
+		    IP_COMPUTE_FRAGMENT_OFFSET_LOW(length);
+		middle_header->header_checksum =
+		    IP_HEADER_CHECKSUM(middle_header);
+		if (destination) {
+			ERROR_PROPAGATE(packet_set_addr(next, NULL,
+			    (uint8_t *) destination->value,
+			    CONVERT_SIZE(char, uint8_t, destination->length)));
 		}
 		length += packet_get_data_length(next);
@@ -881,12 +700,1159 @@
 		header->flags |= IPFLAG_MORE_FRAGMENTS;
 	}
+
 	header->total_length = htons(length);
 	// unnecessary for all protocols
 	header->header_checksum = IP_HEADER_CHECKSUM(header);
+
 	return EOK;
 }
 
-int ip_message_standalone(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, int * answer_count)
+/** Fragments the packet from the end.
+ *
+ * @param[in] packet	The packet to be fragmented.
+ * @param[in,out] new_packet The new packet fragment.
+ * @param[in,out] header The original packet header.
+ * @param[in,out] new_header The new packet fragment header.
+ * @param[in] length	The new fragment length.
+ * @param[in] src	The source address.
+ * @param[in] dest	The destiantion address.
+ * @param[in] addrlen	The address length.
+ * @returns		EOK on success.
+ * @returns		ENOMEM if the target packet is too small.
+ * @returns		Other error codes as defined for the packet_set_addr()
+ *			function.
+ * @returns		Other error codes as defined for the pq_insert_after()
+ *			function.
+ */
+static int
+ip_fragment_packet_data(packet_t packet, packet_t new_packet,
+    ip_header_ref header, ip_header_ref new_header, size_t length,
+    const struct sockaddr *src, const struct sockaddr *dest, socklen_t addrlen)
+{
+	ERROR_DECLARE;
+
+	void *data;
+	size_t offset;
+
+	data = packet_suffix(new_packet, length);
+	if (!data)
+		return ENOMEM;
+
+	memcpy(data, ((void *) header) + IP_TOTAL_LENGTH(header) - length,
+	    length);
+	ERROR_PROPAGATE(packet_trim(packet, 0, length));
+	header->total_length = htons(IP_TOTAL_LENGTH(header) - length);
+	new_header->total_length = htons(IP_HEADER_LENGTH(new_header) + length);
+	offset = IP_FRAGMENT_OFFSET(header) + IP_HEADER_DATA_LENGTH(header);
+	new_header->fragment_offset_high =
+	    IP_COMPUTE_FRAGMENT_OFFSET_HIGH(offset);
+	new_header->fragment_offset_low =
+	    IP_COMPUTE_FRAGMENT_OFFSET_LOW(offset);
+	new_header->header_checksum = IP_HEADER_CHECKSUM(new_header);
+	ERROR_PROPAGATE(packet_set_addr(new_packet, (const uint8_t *) src,
+	    (const uint8_t *) dest, addrlen));
+
+	return pq_insert_after(packet, new_packet);
+}
+
+/** Checks the packet length and fragments it if needed.
+ *
+ * The new fragments are queued before the original packet.
+ *
+ * @param[in,out] packet The packet to be checked.
+ * @param[in] length	The maximum packet length.
+ * @param[in] prefix	The minimum prefix size.
+ * @param[in] suffix	The minimum suffix size.
+ * @param[in] addr_len	The minimum address length.
+ * @returns		EOK on success.
+ * @returns		EINVAL if the packet_get_addr() function fails.
+ * @returns		EINVAL if the packet does not contain the IP header.
+ * @returns		EPERM if the packet needs to be fragmented and the
+ *			fragmentation is not allowed.
+ * @returns		ENOMEM if there is not enough memory left.
+ * @returns		ENOMEM if there is no packet available.
+ * @returns		ENOMEM if the packet is too small to contain the IP
+ *			header.
+ * @returns		Other error codes as defined for the packet_trim()
+ *			function.
+ * @returns		Other error codes as defined for the
+ *			ip_create_middle_header() function.
+ * @returns		Other error codes as defined for the
+ *			ip_fragment_packet_data() function.
+ */
+static int
+ip_fragment_packet(packet_t packet, size_t length, size_t prefix, size_t suffix,
+    socklen_t addr_len)
+{
+	ERROR_DECLARE;
+
+	packet_t new_packet;
+	ip_header_ref header;
+	ip_header_ref middle_header;
+	ip_header_ref last_header;
+	struct sockaddr *src;
+	struct sockaddr *dest;
+	socklen_t addrlen;
+	int result;
+
+	result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest);
+	if (result <= 0)
+		return EINVAL;
+
+	addrlen = (socklen_t) result;
+	if (packet_get_data_length(packet) <= sizeof(ip_header_t))
+		return ENOMEM;
+
+	// get header
+	header = (ip_header_ref) packet_get_data(packet);
+	if (!header)
+		return EINVAL;
+
+	// fragmentation forbidden?
+	if(header->flags & IPFLAG_DONT_FRAGMENT)
+		return EPERM;
+
+	// create the last fragment
+	new_packet = packet_get_4_remote(ip_globals.net_phone, prefix, length,
+	    suffix, ((addrlen > addr_len) ? addrlen : addr_len));
+	if (!new_packet)
+		return ENOMEM;
+
+	// allocate as much as originally
+	last_header = (ip_header_ref) packet_suffix(new_packet,
+	    IP_HEADER_LENGTH(header));
+	if (!last_header)
+		return ip_release_and_return(packet, ENOMEM);
+
+	ip_create_last_header(last_header, header);
+
+	// trim the unused space
+	if (ERROR_OCCURRED(packet_trim(new_packet, 0,
+	    IP_HEADER_LENGTH(header) - IP_HEADER_LENGTH(last_header)))) {
+		return ip_release_and_return(packet, ERROR_CODE);
+	}
+
+	// biggest multiple of 8 lower than content
+	// TODO even fragmentation?
+	length = length & ~0x7;
+	if (ERROR_OCCURRED(ip_fragment_packet_data(packet, new_packet, header,
+	    last_header,
+	    ((IP_HEADER_DATA_LENGTH(header) -
+	    ((length - IP_HEADER_LENGTH(header)) & ~0x7)) %
+	    ((length - IP_HEADER_LENGTH(last_header)) & ~0x7)), src, dest,
+	    addrlen))) {
+		return ip_release_and_return(packet, ERROR_CODE);
+	}
+
+	// mark the first as fragmented
+	header->flags |= IPFLAG_MORE_FRAGMENTS;
+
+	// create middle framgents
+	while (IP_TOTAL_LENGTH(header) > length) {
+		new_packet = packet_get_4_remote(ip_globals.net_phone, prefix,
+		    length, suffix,
+		    ((addrlen >= addr_len) ? addrlen : addr_len));
+		if (!new_packet)
+			return ENOMEM;
+
+		middle_header = ip_create_middle_header(new_packet,
+		    last_header);
+		if (!middle_header)
+			return ip_release_and_return(packet, ENOMEM);
+
+		if (ERROR_OCCURRED(ip_fragment_packet_data(packet, new_packet,
+		    header, middle_header,
+		    (length - IP_HEADER_LENGTH(middle_header)) & ~0x7, src,
+		    dest, addrlen))) {
+			return ip_release_and_return(packet, ERROR_CODE);
+		}
+	}
+
+	// finish the first fragment
+	header->header_checksum = IP_HEADER_CHECKSUM(header);
+
+	return EOK;
+}
+
+/** Checks the packet queue lengths and fragments the packets if needed.
+ *
+ * The ICMP_FRAG_NEEDED error notification may be sent if the packet needs to
+ * be fragmented and the fragmentation is not allowed.
+ *
+ * @param[in,out] packet The packet or the packet queue to be checked.
+ * @param[in] prefix	The minimum prefix size.
+ * @param[in] content	The maximum content size.
+ * @param[in] suffix	The minimum suffix size.
+ * @param[in] addr_len	The minimum address length.
+ * @param[in] error	The error module service.
+ * @returns		The packet or the packet queue of the allowed length.
+ * @returns		NULL if there are no packets left.
+ */
+static packet_t
+ip_split_packet(packet_t packet, size_t prefix, size_t content, size_t suffix,
+    socklen_t addr_len, services_t error)
+{
+	size_t length;
+	packet_t next;
+	packet_t new_packet;
+	int result;
+	int phone;
+
+	next = packet;
+	// check all packets
+	while (next) {
+		length = packet_get_data_length(next);
+		
+		if (length <= content) {
+			next = pq_next(next);
+			continue;
+		}
+
+		// too long
+		result = ip_fragment_packet(next, content, prefix,
+		    suffix, addr_len);
+		if (result != EOK) {
+			new_packet = pq_detach(next);
+			if (next == packet) {
+				// the new first packet of the queue
+				packet = new_packet;
+			}
+			// fragmentation needed?
+			if (result == EPERM) {
+				phone = ip_prepare_icmp_and_get_phone(
+				    error, next, NULL);
+				if (phone >= 0) {
+					// fragmentation necessary ICMP
+					icmp_destination_unreachable_msg(phone,
+					    ICMP_FRAG_NEEDED, content, next);
+				}
+			} else {
+				pq_release_remote(ip_globals.net_phone,
+				    packet_get_id(next));
+			}
+
+			next = new_packet;
+			continue;
+		}
+
+		next = pq_next(next);
+	}
+
+	return packet;
+}
+
+/** Sends the packet or the packet queue via the specified route.
+ *
+ * The ICMP_HOST_UNREACH error notification may be sent if route hardware
+ * destination address is found.
+ *
+ * @param[in,out] packet The packet to be sent.
+ * @param[in] netif	The target network interface.
+ * @param[in] route	The target route.
+ * @param[in] src	The source address.
+ * @param[in] dest	The destination address.
+ * @param[in] error	The error module service.
+ * @returns		EOK on success.
+ * @returns		Other error codes as defined for the arp_translate_req()
+ *			function.
+ * @returns		Other error codes as defined for the ip_prepare_packet()
+ *			function.
+ */
+static int
+ip_send_route(packet_t packet, ip_netif_ref netif, ip_route_ref route,
+    in_addr_t *src, in_addr_t dest, services_t error)
+{
+	ERROR_DECLARE;
+
+	measured_string_t destination;
+	measured_string_ref translation;
+	char *data;
+	int phone;
+
+	// get destination hardware address
+	if (netif->arp && (route->address.s_addr != dest.s_addr)) {
+		destination.value = route->gateway.s_addr ?
+		    (char *) &route->gateway.s_addr : (char *) &dest.s_addr;
+		destination.length = CONVERT_SIZE(dest.s_addr, char, 1);
+
+		if (ERROR_OCCURRED(arp_translate_req(netif->arp->phone,
+		    netif->device_id, SERVICE_IP, &destination, &translation,
+		    &data))) {
+			pq_release_remote(ip_globals.net_phone,
+			    packet_get_id(packet));
+			return ERROR_CODE;
+		}
+
+		if (!translation || !translation->value) {
+			if (translation) {
+				free(translation);
+				free(data);
+			}
+			phone = ip_prepare_icmp_and_get_phone(error, packet,
+			    NULL);
+			if (phone >= 0) {
+				// unreachable ICMP if no routing
+				icmp_destination_unreachable_msg(phone,
+				    ICMP_HOST_UNREACH, 0, packet);
+			}
+			return EINVAL;
+		}
+
+	} else {
+		translation = NULL;
+	}
+
+	if (ERROR_OCCURRED(ip_prepare_packet(src, dest, packet, translation))) {
+		pq_release_remote(ip_globals.net_phone, packet_get_id(packet));
+	} else {
+		packet = ip_split_packet(packet, netif->packet_dimension.prefix,
+		    netif->packet_dimension.content,
+		    netif->packet_dimension.suffix,
+		    netif->packet_dimension.addr_len, error);
+		if (packet) {
+			nil_send_msg(netif->phone, netif->device_id, packet,
+			    SERVICE_IP);
+		}
+	}
+
+	if (translation) {
+		free(translation);
+		free(data);
+	}
+
+	return ERROR_CODE;
+}
+
+/** Searches the network interfaces if there is a suitable route.
+ *
+ * @param[in] netif	The network interface to be searched for routes. May be
+ *			NULL.
+ * @param[in] destination The destination address.
+ * @returns		The found route.
+ * @returns		NULL if no route was found.
+ */
+static ip_route_ref
+ip_netif_find_route(ip_netif_ref netif, in_addr_t destination)
+{
+	int index;
+	ip_route_ref route;
+
+	if (!netif)
+		return NULL;
+
+	// start with the first one - the direct route
+	for (index = 0; index < ip_routes_count(&netif->routes); index++) {
+		route = ip_routes_get_index(&netif->routes, index);
+		if (route &&
+		    ((route->address.s_addr & route->netmask.s_addr) ==
+		    (destination.s_addr & route->netmask.s_addr))) {
+			return route;
+		}
+	}
+
+	return NULL;
+}
+
+/** Searches all network interfaces if there is a suitable route.
+ *
+ * @param[in] destination The destination address.
+ * @returns		The found route.
+ * @returns		NULL if no route was found.
+ */
+static ip_route_ref ip_find_route(in_addr_t destination) {
+	int index;
+	ip_route_ref route;
+	ip_netif_ref netif;
+
+	// start with the last netif - the newest one
+	index = ip_netifs_count(&ip_globals.netifs) - 1;
+	while (index >= 0) {
+		netif = ip_netifs_get_index(&ip_globals.netifs, index);
+		if (netif && (netif->state == NETIF_ACTIVE)) {
+			route = ip_netif_find_route(netif, destination);
+			if (route)
+				return route;
+		}
+		index--;
+	}
+
+	return &ip_globals.gateway;
+}
+
+/** Returns the network interface's IP address.
+ *
+ * @param[in] netif	The network interface.
+ * @returns		The IP address.
+ * @returns		NULL if no IP address was found.
+ */
+static in_addr_t *ip_netif_address(ip_netif_ref netif)
+{
+	ip_route_ref route;
+
+	route = ip_routes_get_index(&netif->routes, 0);
+	return route ? &route->address : NULL;
+}
+
+/** Registers the transport layer protocol.
+ *
+ * The traffic of this protocol will be supplied using either the receive
+ * function or IPC message.
+ *
+ * @param[in] protocol	The transport layer module protocol.
+ * @param[in] service	The transport layer module service.
+ * @param[in] phone	The transport layer module phone.
+ * @param[in] received_msg The receiving function.
+ * @returns		EOK on success.
+ * @returns		EINVAL if the protocol parameter and/or the service
+ *			parameter is zero.
+ * @returns		EINVAL if the phone parameter is not a positive number
+ *			and the tl_receive_msg is NULL.
+ * @returns		ENOMEM if there is not enough memory left.
+ */
+static int
+ip_register(int protocol, services_t service, int phone,
+    tl_received_msg_t received_msg)
+{
+	ip_proto_ref proto;
+	int index;
+
+	if (!protocol || !service || ((phone < 0) && !received_msg))
+		return EINVAL;
+
+	proto = (ip_proto_ref) malloc(sizeof(ip_protos_t));
+	if (!proto)
+		return ENOMEM;
+
+	proto->protocol = protocol;
+	proto->service = service;
+	proto->phone = phone;
+	proto->received_msg = received_msg;
+
+	fibril_rwlock_write_lock(&ip_globals.protos_lock);
+	index = ip_protos_add(&ip_globals.protos, proto->protocol, proto);
+	if (index < 0) {
+		fibril_rwlock_write_unlock(&ip_globals.protos_lock);
+		free(proto);
+		return index;
+	}
+	fibril_rwlock_write_unlock(&ip_globals.protos_lock);
+
+	printf("%s: Protocol registered (protocol: %d, phone: %d)\n",
+	    NAME, proto->protocol, proto->phone);
+
+	return EOK;
+}
+
+static int
+ip_device_req_local(int il_phone, device_id_t device_id, services_t netif)
+{
+	ERROR_DECLARE;
+
+	ip_netif_ref ip_netif;
+	ip_route_ref route;
+	int index;
+
+	ip_netif = (ip_netif_ref) malloc(sizeof(ip_netif_t));
+	if (!ip_netif)
+		return ENOMEM;
+
+	if (ERROR_OCCURRED(ip_routes_initialize(&ip_netif->routes))) {
+		free(ip_netif);
+		return ERROR_CODE;
+	}
+
+	ip_netif->device_id = device_id;
+	ip_netif->service = netif;
+	ip_netif->state = NETIF_STOPPED;
+
+	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
+	if (ERROR_OCCURRED(ip_netif_initialize(ip_netif))) {
+		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+		ip_routes_destroy(&ip_netif->routes);
+		free(ip_netif);
+		return ERROR_CODE;
+	}
+	if (ip_netif->arp)
+		ip_netif->arp->usage++;
+
+	// print the settings
+	printf("%s: Device registered (id: %d, phone: %d, ipv: %d, conf: %s)\n",
+	    NAME, ip_netif->device_id, ip_netif->phone, ip_netif->ipv,
+	    ip_netif->dhcp ? "dhcp" : "static");
+	
+	// TODO ipv6 addresses
+	
+	char address[INET_ADDRSTRLEN];
+	char netmask[INET_ADDRSTRLEN];
+	char gateway[INET_ADDRSTRLEN];
+	
+	for (index = 0; index < ip_routes_count(&ip_netif->routes); index++) {
+		route = ip_routes_get_index(&ip_netif->routes, index);
+		if (route) {
+			inet_ntop(AF_INET, (uint8_t *) &route->address.s_addr,
+			    address, INET_ADDRSTRLEN);
+			inet_ntop(AF_INET, (uint8_t *) &route->netmask.s_addr,
+			    netmask, INET_ADDRSTRLEN);
+			inet_ntop(AF_INET, (uint8_t *) &route->gateway.s_addr,
+			    gateway, INET_ADDRSTRLEN);
+			printf("%s: Route %d (address: %s, netmask: %s, "
+			    "gateway: %s)\n", NAME, index, address, netmask,
+			    gateway);
+		}
+	}
+	
+	inet_ntop(AF_INET, (uint8_t *) &ip_netif->broadcast.s_addr, address,
+	    INET_ADDRSTRLEN);
+	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+
+	printf("%s: Broadcast (%s)\n", NAME, address);
+
+	return EOK;
+}
+
+static int
+ip_send_msg_local(int il_phone, device_id_t device_id, packet_t packet,
+    services_t sender, services_t error)
+{
+	ERROR_DECLARE;
+
+	int addrlen;
+	ip_netif_ref netif;
+	ip_route_ref route;
+	struct sockaddr *addr;
+	struct sockaddr_in *address_in;
+	in_addr_t *dest;
+	in_addr_t *src;
+	int phone;
+
+	// addresses in the host byte order
+	// should be the next hop address or the target destination address
+	addrlen = packet_get_addr(packet, NULL, (uint8_t **) &addr);
+	if (addrlen < 0)
+		return ip_release_and_return(packet, addrlen);
+	if ((size_t) addrlen < sizeof(struct sockaddr))
+		return ip_release_and_return(packet, EINVAL);
+
+	switch (addr->sa_family) {
+	case AF_INET:
+		if (addrlen != sizeof(struct sockaddr_in))
+			return ip_release_and_return(packet, EINVAL);
+		address_in = (struct sockaddr_in *) addr;
+		dest = &address_in->sin_addr;
+		if (!dest->s_addr)
+			dest->s_addr = IPV4_LOCALHOST_ADDRESS;
+		break;
+	case AF_INET6:
+	default:
+		return ip_release_and_return(packet, EAFNOSUPPORT);
+	}
+
+	netif = NULL;
+	route = NULL;
+	fibril_rwlock_read_lock(&ip_globals.netifs_lock);
+
+	// device specified?
+	if (device_id > 0) {
+		netif = ip_netifs_find(&ip_globals.netifs, device_id);
+		route = ip_netif_find_route(netif, * dest);
+		if (netif && !route && (ip_globals.gateway.netif == netif))
+			route = &ip_globals.gateway;
+	}
+
+	if (!route) {
+		route = ip_find_route(*dest);
+		netif = route ? route->netif : NULL;
+	}
+	if (!netif || !route) {
+		fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
+		phone = ip_prepare_icmp_and_get_phone(error, packet, NULL);
+		if (phone >= 0) {
+			// unreachable ICMP if no routing
+			icmp_destination_unreachable_msg(phone,
+			    ICMP_NET_UNREACH, 0, packet);
+		}
+		return ENOENT;
+	}
+
+	if (error) {
+		// do not send for broadcast, anycast packets or network
+		// broadcast
+		if (!dest->s_addr || !(~dest->s_addr) ||
+		    !(~((dest->s_addr & ~route->netmask.s_addr) |
+		    route->netmask.s_addr)) ||
+		    (!(dest->s_addr & ~route->netmask.s_addr))) {
+			return ip_release_and_return(packet, EINVAL);
+		}
+	}
+
+	// if the local host is the destination
+	if ((route->address.s_addr == dest->s_addr) &&
+	    (dest->s_addr != IPV4_LOCALHOST_ADDRESS)) {
+		// find the loopback device to deliver
+		dest->s_addr = IPV4_LOCALHOST_ADDRESS;
+		route = ip_find_route(*dest);
+		netif = route ? route->netif : NULL;
+		if (!netif || !route) {
+			fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
+			phone = ip_prepare_icmp_and_get_phone(error, packet,
+			    NULL);
+			if (phone >= 0) {
+				// unreachable ICMP if no routing
+				icmp_destination_unreachable_msg(phone,
+				    ICMP_HOST_UNREACH, 0, packet);
+			}
+			return ENOENT;
+		}
+	}
+	
+	src = ip_netif_address(netif);
+	if (!src) {
+		fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
+		return ip_release_and_return(packet, ENOENT);
+	}
+
+	ERROR_CODE = ip_send_route(packet, netif, route, src, *dest, error);
+	fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
+
+	return ERROR_CODE;
+}
+
+/** Returns the device packet dimensions for sending.
+ *
+ * @param[in] phone	The service module phone.
+ * @param[in] message	The service specific message.
+ * @param[in] device_id	The device identifier.
+ * @param[out] addr_len	The minimum reserved address length.
+ * @param[out] prefix	The minimum reserved prefix size.
+ * @param[out] content	The maximum content size.
+ * @param[out] suffix	The minimum reserved suffix size.
+ * @returns		EOK on success.
+ */
+static int
+ip_packet_size_message(device_id_t device_id, size_t *addr_len, size_t *prefix,
+    size_t *content, size_t *suffix)
+{
+	ip_netif_ref netif;
+	int index;
+
+	if (!addr_len || !prefix || !content || !suffix)
+		return EBADMEM;
+
+	*content = IP_MAX_CONTENT - IP_PREFIX;
+	fibril_rwlock_read_lock(&ip_globals.netifs_lock);
+	if (device_id < 0) {
+		*addr_len = IP_ADDR;
+		*prefix = 0;
+		*suffix = 0;
+
+		for (index = ip_netifs_count(&ip_globals.netifs) - 1;
+		    index >= 0; index--) {
+			netif = ip_netifs_get_index(&ip_globals.netifs, index);
+			if (!netif)
+				continue;
+			
+			if (netif->packet_dimension.addr_len > *addr_len)
+				*addr_len = netif->packet_dimension.addr_len;
+			
+			if (netif->packet_dimension.prefix > *prefix)
+				*prefix = netif->packet_dimension.prefix;
+				
+			if (netif->packet_dimension.suffix > *suffix)
+				*suffix = netif->packet_dimension.suffix;
+		}
+
+		*prefix = *prefix + IP_PREFIX;
+		*suffix = *suffix + IP_SUFFIX;
+	} else {
+		netif = ip_netifs_find(&ip_globals.netifs, device_id);
+		if (!netif) {
+			fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
+			return ENOENT;
+		}
+
+		*addr_len = (netif->packet_dimension.addr_len > IP_ADDR) ?
+		    netif->packet_dimension.addr_len : IP_ADDR;
+		*prefix = netif->packet_dimension.prefix + IP_PREFIX;
+		*suffix = netif->packet_dimension.suffix + IP_SUFFIX;
+	}
+	fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
+
+	return EOK;
+}
+
+/** Returns the packet destination address from the IP header.
+ *
+ * @param[in] header	The packet IP header to be read.
+ * @returns		The packet destination address.
+ */
+static in_addr_t ip_get_destination(ip_header_ref header)
+{
+	in_addr_t destination;
+
+	// TODO search set ipopt route?
+	destination.s_addr = header->destination_address;
+	return destination;
+}
+
+/** Delivers the packet to the local host.
+ *
+ * The packet is either passed to another module or released on error.
+ * The ICMP_PROT_UNREACH error notification may be sent if the protocol is not
+ * found.
+ *
+ * @param[in] device_id	The source device identifier.
+ * @param[in] packet	The packet to be delivered.
+ * @param[in] header	The first packet IP header. May be NULL.
+ * @param[in] error	The packet error service.
+ * @returns		EOK on success.
+ * @returns		ENOTSUP if the packet is a fragment.
+ * @returns		EAFNOSUPPORT if the address family is not supported.
+ * @returns		ENOENT if the target protocol is not found.
+ * @returns		Other error codes as defined for the packet_set_addr()
+ *			function.
+ * @returns		Other error codes as defined for the packet_trim()
+ *			function.
+ * @returns		Other error codes as defined for the protocol specific
+ *			tl_received_msg() function.
+ */
+static int
+ip_deliver_local(device_id_t device_id, packet_t packet, ip_header_ref header,
+    services_t error)
+{
+	ERROR_DECLARE;
+
+	ip_proto_ref proto;
+	int phone;
+	services_t service;
+	tl_received_msg_t received_msg;
+	struct sockaddr *src;
+	struct sockaddr *dest;
+	struct sockaddr_in src_in;
+	struct sockaddr_in dest_in;
+	socklen_t addrlen;
+
+	if ((header->flags & IPFLAG_MORE_FRAGMENTS) ||
+	    IP_FRAGMENT_OFFSET(header)) {
+		// TODO fragmented
+		return ENOTSUP;
+	}
+	
+	switch (header->version) {
+	case IPVERSION:
+		addrlen = sizeof(src_in);
+		bzero(&src_in, addrlen);
+		src_in.sin_family = AF_INET;
+		memcpy(&dest_in, &src_in, addrlen);
+		memcpy(&src_in.sin_addr.s_addr, &header->source_address,
+		    sizeof(header->source_address));
+		memcpy(&dest_in.sin_addr.s_addr, &header->destination_address,
+		    sizeof(header->destination_address));
+		src = (struct sockaddr *) &src_in;
+		dest = (struct sockaddr *) &dest_in;
+		break;
+
+	default:
+		return ip_release_and_return(packet, EAFNOSUPPORT);
+	}
+
+	if (ERROR_OCCURRED(packet_set_addr(packet, (uint8_t *) src,
+	    (uint8_t *) dest, addrlen))) {
+		return ip_release_and_return(packet, ERROR_CODE);
+	}
+
+	// trim padding if present
+	if (!error &&
+	    (IP_TOTAL_LENGTH(header) < packet_get_data_length(packet))) {
+		if (ERROR_OCCURRED(packet_trim(packet, 0,
+		    packet_get_data_length(packet) - IP_TOTAL_LENGTH(header))))
+			return ip_release_and_return(packet, ERROR_CODE);
+	}
+
+	fibril_rwlock_read_lock(&ip_globals.protos_lock);
+
+	proto = ip_protos_find(&ip_globals.protos, header->protocol);
+	if (!proto) {
+		fibril_rwlock_read_unlock(&ip_globals.protos_lock);
+		phone = ip_prepare_icmp_and_get_phone(error, packet, header);
+		if (phone >= 0) {
+			// unreachable ICMP
+			icmp_destination_unreachable_msg(phone,
+			    ICMP_PROT_UNREACH, 0, packet);
+		}
+		return ENOENT;
+	}
+
+	if (proto->received_msg) {
+		service = proto->service;
+		received_msg = proto->received_msg;
+		fibril_rwlock_read_unlock(&ip_globals.protos_lock);
+		ERROR_CODE = received_msg(device_id, packet, service, error);
+	} else {
+		ERROR_CODE = tl_received_msg(proto->phone, device_id, packet,
+		    proto->service, error);
+		fibril_rwlock_read_unlock(&ip_globals.protos_lock);
+	}
+
+	return ERROR_CODE;
+}
+
+/** Processes the received packet.
+ *
+ * The packet is either passed to another module or released on error.
+ *
+ * The ICMP_PARAM_POINTER error notification may be sent if the checksum is
+ * invalid.
+ * The ICMP_EXC_TTL error notification may be sent if the TTL is less than two.
+ * The ICMP_HOST_UNREACH error notification may be sent if no route was found.
+ * The ICMP_HOST_UNREACH error notification may be sent if the packet is for
+ * another host and the routing is disabled.
+ *
+ * @param[in] device_id	The source device identifier.
+ * @param[in] packet	The received packet to be processed.
+ * @returns		EOK on success.
+ * @returns		EINVAL if the TTL is less than two.
+ * @returns		EINVAL if the checksum is invalid.
+ * @returns		EAFNOSUPPORT if the address family is not supported.
+ * @returns		ENOENT if no route was found.
+ * @returns		ENOENT if the packet is for another host and the routing
+ *			is disabled.
+ */
+static int
+ip_process_packet(device_id_t device_id, packet_t packet)
+{
+	ERROR_DECLARE;
+
+	ip_header_ref header;
+	in_addr_t dest;
+	ip_route_ref route;
+	int phone;
+	struct sockaddr *addr;
+	struct sockaddr_in addr_in;
+	socklen_t addrlen;
+
+	header = (ip_header_ref) packet_get_data(packet);
+	if (!header)
+		return ip_release_and_return(packet, ENOMEM);
+
+	// checksum
+	if ((header->header_checksum) &&
+	    (IP_HEADER_CHECKSUM(header) != IP_CHECKSUM_ZERO)) {
+		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
+		if (phone >= 0) {
+			// checksum error ICMP
+			icmp_parameter_problem_msg(phone, ICMP_PARAM_POINTER,
+			    ((size_t) ((void *) &header->header_checksum)) -
+			    ((size_t) ((void *) header)), packet);
+		}
+		return EINVAL;
+	}
+
+	if (header->ttl <= 1) {
+		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
+		if (phone >= 0) {
+			// ttl exceeded ICMP
+			icmp_time_exceeded_msg(phone, ICMP_EXC_TTL, packet);
+		}
+		return EINVAL;
+	}
+
+	// process ipopt and get destination
+	dest = ip_get_destination(header);
+
+	// set the addrination address
+	switch (header->version) {
+	case IPVERSION:
+		addrlen = sizeof(addr_in);
+		bzero(&addr_in, addrlen);
+		addr_in.sin_family = AF_INET;
+		memcpy(&addr_in.sin_addr.s_addr, &dest, sizeof(dest));
+		addr = (struct sockaddr *) &addr_in;
+		break;
+
+	default:
+		return ip_release_and_return(packet, EAFNOSUPPORT);
+	}
+
+	ERROR_PROPAGATE(packet_set_addr(packet, NULL, (uint8_t *) &addr,
+	    addrlen));
+
+	route = ip_find_route(dest);
+	if (!route) {
+		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
+		if (phone >= 0) {
+			// unreachable ICMP
+			icmp_destination_unreachable_msg(phone,
+			    ICMP_HOST_UNREACH, 0, packet);
+		}
+		return ENOENT;
+	}
+
+	if (route->address.s_addr == dest.s_addr) {
+		// local delivery
+		return ip_deliver_local(device_id, packet, header, 0);
+	}
+
+	if (route->netif->routing) {
+		header->ttl--;
+		return ip_send_route(packet, route->netif, route, NULL, dest,
+		    0);
+	}
+
+	phone = ip_prepare_icmp_and_get_phone(0, packet, header);
+	if (phone >= 0) {
+		// unreachable ICMP if no routing
+		icmp_destination_unreachable_msg(phone, ICMP_HOST_UNREACH, 0,
+		    packet);
+	}
+	
+	return ENOENT;
+}
+
+static int
+ip_add_route_req_local(int ip_phone, device_id_t device_id, in_addr_t address,
+    in_addr_t netmask, in_addr_t gateway)
+{
+	ip_route_ref route;
+	ip_netif_ref netif;
+	int index;
+
+	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
+
+	netif = ip_netifs_find(&ip_globals.netifs, device_id);
+	if (!netif) {
+		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+		return ENOENT;
+	}
+
+	route = (ip_route_ref) malloc(sizeof(ip_route_t));
+	if (!route) {
+		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+		return ENOMEM;
+	}
+
+	route->address.s_addr = address.s_addr;
+	route->netmask.s_addr = netmask.s_addr;
+	route->gateway.s_addr = gateway.s_addr;
+	route->netif = netif;
+	index = ip_routes_add(&netif->routes, route);
+	if (index < 0)
+		free(route);
+
+	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+	
+	return index;
+}
+
+static int
+ip_set_gateway_req_local(int ip_phone, device_id_t device_id, in_addr_t gateway)
+{
+	ip_netif_ref netif;
+
+	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
+
+	netif = ip_netifs_find(&ip_globals.netifs, device_id);
+	if (!netif) {
+		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+		return ENOENT;
+	}
+
+	ip_globals.gateway.address.s_addr = 0;
+	ip_globals.gateway.netmask.s_addr = 0;
+	ip_globals.gateway.gateway.s_addr = gateway.s_addr;
+	ip_globals.gateway.netif = netif;
+	
+	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+	
+	return EOK;
+}
+
+/** Notify the IP module about the received error notification packet.
+ *
+ * @param[in] ip_phone	The IP module phone used for (semi)remote calls.
+ * @param[in] device_id	The device identifier.
+ * @param[in] packet	The received packet or the received packet queue.
+ * @param[in] target	The target internetwork module service to be
+ *			delivered to.
+ * @param[in] error	The packet error reporting service. Prefixes the
+ *			received packet.
+ * @return		EOK on success.
+ *
+ */
+static int
+ip_received_error_msg_local(int ip_phone, device_id_t device_id,
+    packet_t packet, services_t target, services_t error)
+{
+	uint8_t *data;
+	int offset;
+	icmp_type_t type;
+	icmp_code_t code;
+	ip_netif_ref netif;
+	measured_string_t address;
+	ip_route_ref route;
+	ip_header_ref header;
+
+	switch (error) {
+	case SERVICE_ICMP:
+		offset = icmp_client_process_packet(packet, &type, &code, NULL,
+		    NULL);
+		if (offset < 0)
+			return ip_release_and_return(packet, ENOMEM);
+
+		data = packet_get_data(packet);
+		header = (ip_header_ref)(data + offset);
+
+		// destination host unreachable?
+		if ((type != ICMP_DEST_UNREACH) ||
+		    (code != ICMP_HOST_UNREACH)) {
+		    	// no, something else
+			break;
+		}
+
+		fibril_rwlock_read_lock(&ip_globals.netifs_lock);
+
+		netif = ip_netifs_find(&ip_globals.netifs, device_id);
+		if (!netif || !netif->arp) {
+			fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
+			break;
+		}
+
+		route = ip_routes_get_index(&netif->routes, 0);
+
+		// from the same network?
+		if (route && ((route->address.s_addr & route->netmask.s_addr) ==
+		    (header->destination_address & route->netmask.s_addr))) {
+			// clear the ARP mapping if any
+			address.value = (char *) &header->destination_address;
+			address.length = CONVERT_SIZE(uint8_t, char,
+			    sizeof(header->destination_address));
+			arp_clear_address_req(netif->arp->phone,
+			    netif->device_id, SERVICE_IP, &address);
+		}
+
+		fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
+		break;
+
+	default:
+		return ip_release_and_return(packet, ENOTSUP);
+	}
+
+	return ip_deliver_local(device_id, packet, header, error);
+}
+
+static int
+ip_get_route_req_local(int ip_phone, ip_protocol_t protocol,
+    const struct sockaddr *destination, socklen_t addrlen,
+    device_id_t *device_id, void **header, size_t *headerlen)
+{
+	struct sockaddr_in *address_in;
+	in_addr_t *dest;
+	in_addr_t *src;
+	ip_route_ref route;
+	ipv4_pseudo_header_ref header_in;
+
+	if (!destination || (addrlen <= 0))
+		return EINVAL;
+
+	if (!device_id || !header || !headerlen)
+		return EBADMEM;
+
+	if ((size_t) addrlen < sizeof(struct sockaddr))
+		return EINVAL;
+
+	switch (destination->sa_family) {
+	case AF_INET:
+		if (addrlen != sizeof(struct sockaddr_in))
+			return EINVAL;
+		address_in = (struct sockaddr_in *) destination;
+		dest = &address_in->sin_addr;
+		if (!dest->s_addr)
+			dest->s_addr = IPV4_LOCALHOST_ADDRESS;
+		break;
+
+	case AF_INET6:
+	default:
+		return EAFNOSUPPORT;
+	}
+
+	fibril_rwlock_read_lock(&ip_globals.lock);
+	route = ip_find_route(*dest);
+	// if the local host is the destination
+	if (route && (route->address.s_addr == dest->s_addr) &&
+	    (dest->s_addr != IPV4_LOCALHOST_ADDRESS)) {
+		// find the loopback device to deliver
+		dest->s_addr = IPV4_LOCALHOST_ADDRESS;
+		route = ip_find_route(*dest);
+	}
+
+	if (!route || !route->netif) {
+		fibril_rwlock_read_unlock(&ip_globals.lock);
+		return ENOENT;
+	}
+
+	*device_id = route->netif->device_id;
+	src = ip_netif_address(route->netif);
+	fibril_rwlock_read_unlock(&ip_globals.lock);
+
+	*headerlen = sizeof(*header_in);
+	header_in = (ipv4_pseudo_header_ref) malloc(*headerlen);
+	if (!header_in)
+		return ENOMEM;
+
+	bzero(header_in, *headerlen);
+	header_in->destination_address = dest->s_addr;
+	header_in->source_address = src->s_addr;
+	header_in->protocol = protocol;
+	header_in->data_length = 0;
+	*header = header_in;
+
+	return EOK;
+}
+
+/** Processes the received IP packet or the packet queue one by one.
+ *
+ * The packet is either passed to another module or released on error.
+ *
+ * @param[in] device_id	The source device identifier.
+ * @param[in,out] packet The received packet.
+ * @returns		EOK on success and the packet is no longer needed.
+ * @returns		EINVAL if the packet is too small to carry the IP
+ *			packet.
+ * @returns		EINVAL if the received address lengths differs from the
+ *			registered values.
+ * @returns		ENOENT if the device is not found in the cache.
+ * @returns		ENOENT if the protocol for the device is not found in
+ *			the cache.
+ * @returns		ENOMEM if there is not enough memory left.
+ */
+static int ip_receive_message(device_id_t device_id, packet_t packet)
+{
+	packet_t next;
+
+	do {
+		next = pq_detach(packet);
+		ip_process_packet(device_id, packet);
+		packet = next;
+	} while (packet);
+
+	return EOK;
+}
+
+/** Processes the IP message.
+ *
+ * @param[in] callid	The message identifier.
+ * @param[in] call	The message parameters.
+ * @param[out] answer	The message answer parameters.
+ * @param[out] answer_count The last parameter for the actual answer in the
+ *			answer parameter.
+ * @returns		EOK on success.
+ * @returns		ENOTSUP if the message is not known.
+ *
+ * @see ip_interface.h
+ * @see il_interface.h
+ * @see IS_NET_IP_MESSAGE()
+ */
+int
+ip_message_standalone(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
+    int *answer_count)
 {
 	ERROR_DECLARE;
@@ -904,61 +1870,74 @@
 	*answer_count = 0;
 	switch (IPC_GET_METHOD(*call)) {
-		case IPC_M_PHONE_HUNGUP:
-			return EOK;
-		case NET_IL_DEVICE:
-			return ip_device_req_local(0, IPC_GET_DEVICE(call),
-			    IPC_GET_SERVICE(call));
-		case IPC_M_CONNECT_TO_ME:
-			return ip_register(IL_GET_PROTO(call), IL_GET_SERVICE(call),
-			    IPC_GET_PHONE(call), NULL);
-		case NET_IL_SEND:
-			ERROR_PROPAGATE(packet_translate_remote(ip_globals.net_phone, &packet,
-			    IPC_GET_PACKET(call)));
-			return ip_send_msg_local(0, IPC_GET_DEVICE(call), packet, 0,
-			    IPC_GET_ERROR(call));
-		case NET_IL_DEVICE_STATE:
-			return ip_device_state_message(IPC_GET_DEVICE(call),
-			    IPC_GET_STATE(call));
-		case NET_IL_RECEIVED:
-			ERROR_PROPAGATE(packet_translate_remote(ip_globals.net_phone, &packet,
-			    IPC_GET_PACKET(call)));
-			return ip_receive_message(IPC_GET_DEVICE(call), packet);
-		case NET_IP_RECEIVED_ERROR:
-			ERROR_PROPAGATE(packet_translate_remote(ip_globals.net_phone, &packet,
-			    IPC_GET_PACKET(call)));
-			return ip_received_error_msg_local(0, IPC_GET_DEVICE(call), packet,
-			    IPC_GET_TARGET(call), IPC_GET_ERROR(call));
-		case NET_IP_ADD_ROUTE:
-			return ip_add_route_req_local(0, IPC_GET_DEVICE(call),
-			    IP_GET_ADDRESS(call), IP_GET_NETMASK(call), IP_GET_GATEWAY(call));
-		case NET_IP_SET_GATEWAY:
-			return ip_set_gateway_req_local(0, IPC_GET_DEVICE(call),
-			    IP_GET_GATEWAY(call));
-		case NET_IP_GET_ROUTE:
-			ERROR_PROPAGATE(data_receive((void **) &addr, &addrlen));
-			ERROR_PROPAGATE(ip_get_route_req_local(0, IP_GET_PROTOCOL(call),
-			    addr, (socklen_t) addrlen, &device_id, &header, &headerlen));
-			IPC_SET_DEVICE(answer, device_id);
-			IP_SET_HEADERLEN(answer, headerlen);
+	case IPC_M_PHONE_HUNGUP:
+		return EOK;
+	
+	case IPC_M_CONNECT_TO_ME:
+		return ip_register(IL_GET_PROTO(call), IL_GET_SERVICE(call),
+		    IPC_GET_PHONE(call), NULL);
+	
+	case NET_IL_DEVICE:
+		return ip_device_req_local(0, IPC_GET_DEVICE(call),
+		    IPC_GET_SERVICE(call));
+	
+	case NET_IL_SEND:
+		ERROR_PROPAGATE(packet_translate_remote(ip_globals.net_phone,
+		    &packet, IPC_GET_PACKET(call)));
+		return ip_send_msg_local(0, IPC_GET_DEVICE(call), packet, 0,
+		    IPC_GET_ERROR(call));
+	
+	case NET_IL_DEVICE_STATE:
+		return ip_device_state_message(IPC_GET_DEVICE(call),
+		    IPC_GET_STATE(call));
+	
+	case NET_IL_RECEIVED:
+		ERROR_PROPAGATE(packet_translate_remote(ip_globals.net_phone,
+		    &packet, IPC_GET_PACKET(call)));
+		return ip_receive_message(IPC_GET_DEVICE(call), packet);
+	
+	case NET_IP_RECEIVED_ERROR:
+		ERROR_PROPAGATE(packet_translate_remote(ip_globals.net_phone,
+		    &packet, IPC_GET_PACKET(call)));
+		return ip_received_error_msg_local(0, IPC_GET_DEVICE(call),
+		    packet, IPC_GET_TARGET(call), IPC_GET_ERROR(call));
+	
+	case NET_IP_ADD_ROUTE:
+		return ip_add_route_req_local(0, IPC_GET_DEVICE(call),
+		    IP_GET_ADDRESS(call), IP_GET_NETMASK(call),
+		    IP_GET_GATEWAY(call));
+
+	case NET_IP_SET_GATEWAY:
+		return ip_set_gateway_req_local(0, IPC_GET_DEVICE(call),
+		    IP_GET_GATEWAY(call));
+
+	case NET_IP_GET_ROUTE:
+		ERROR_PROPAGATE(data_receive((void **) &addr, &addrlen));
+		ERROR_PROPAGATE(ip_get_route_req_local(0, IP_GET_PROTOCOL(call),
+		    addr, (socklen_t) addrlen, &device_id, &header,
+		    &headerlen));
+		IPC_SET_DEVICE(answer, device_id);
+		IP_SET_HEADERLEN(answer, headerlen);
+		
+		*answer_count = 2;
 			
-			*answer_count = 2;
+		if (ERROR_NONE(data_reply(&headerlen, sizeof(headerlen))))
+			ERROR_CODE = data_reply(header, headerlen);
 			
-			if (!ERROR_OCCURRED(data_reply(&headerlen, sizeof(headerlen))))
-				ERROR_CODE = data_reply(header, headerlen);
-			
-			free(header);
-			return ERROR_CODE;
-		case NET_IL_PACKET_SPACE:
-			ERROR_PROPAGATE(ip_packet_size_message(IPC_GET_DEVICE(call),
-			    &addrlen, &prefix, &content, &suffix));
-			IPC_SET_ADDR(answer, addrlen);
-			IPC_SET_PREFIX(answer, prefix);
-			IPC_SET_CONTENT(answer, content);
-			IPC_SET_SUFFIX(answer, suffix);
-			*answer_count = 4;
-			return EOK;
-		case NET_IL_MTU_CHANGED:
-			return ip_mtu_changed_message(IPC_GET_DEVICE(call),
-			    IPC_GET_MTU(call));
+		free(header);
+		return ERROR_CODE;
+	
+	case NET_IL_PACKET_SPACE:
+		ERROR_PROPAGATE(ip_packet_size_message(IPC_GET_DEVICE(call),
+		    &addrlen, &prefix, &content, &suffix));
+		IPC_SET_ADDR(answer, addrlen);
+		IPC_SET_PREFIX(answer, prefix);
+		IPC_SET_CONTENT(answer, content);
+		IPC_SET_SUFFIX(answer, suffix);
+		*answer_count = 4;
+		return EOK;
+	
+	case NET_IL_MTU_CHANGED:
+		return ip_mtu_changed_message(IPC_GET_DEVICE(call),
+		    IPC_GET_MTU(call));
 	}
 	
@@ -966,704 +1945,10 @@
 }
 
-int ip_packet_size_req_local(int ip_phone, device_id_t device_id,
-    packet_dimension_ref packet_dimension)
-{
-	if (!packet_dimension)
-		return EBADMEM;
-	
-	return ip_packet_size_message(device_id, &packet_dimension->addr_len,
-	    &packet_dimension->prefix, &packet_dimension->content,
-	    &packet_dimension->suffix);
-}
-
-int ip_packet_size_message(device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix){
-	ip_netif_ref netif;
-	int index;
-
-	if(!(addr_len && prefix && content && suffix)){
-		return EBADMEM;
-	}
-	*content = IP_MAX_CONTENT - IP_PREFIX;
-	fibril_rwlock_read_lock(&ip_globals.netifs_lock);
-	if(device_id < 0){
-		*addr_len = IP_ADDR;
-		*prefix = 0;
-		*suffix = 0;
-		for(index = ip_netifs_count(&ip_globals.netifs) - 1; index >= 0; -- index){
-			netif = ip_netifs_get_index(&ip_globals.netifs, index);
-			if(netif){
-				if(netif->packet_dimension.addr_len > * addr_len){
-					*addr_len = netif->packet_dimension.addr_len;
-				}
-				if(netif->packet_dimension.prefix > * prefix){
-					*prefix = netif->packet_dimension.prefix;
-				}
-				if(netif->packet_dimension.suffix > * suffix){
-					*suffix = netif->packet_dimension.suffix;
-				}
-			}
-		}
-		*prefix = * prefix + IP_PREFIX;
-		*suffix = * suffix + IP_SUFFIX;
-	}else{
-		netif = ip_netifs_find(&ip_globals.netifs, device_id);
-		if(! netif){
-			fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
-			return ENOENT;
-		}
-		*addr_len = (netif->packet_dimension.addr_len > IP_ADDR) ? netif->packet_dimension.addr_len : IP_ADDR;
-		*prefix = netif->packet_dimension.prefix + IP_PREFIX;
-		*suffix = netif->packet_dimension.suffix + IP_SUFFIX;
-	}
-	fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
-	return EOK;
-}
-
-int ip_add_route_req_local(int ip_phone, device_id_t device_id, in_addr_t address, in_addr_t netmask, in_addr_t gateway){
-	ip_route_ref route;
-	ip_netif_ref netif;
-	int index;
-
-	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
-	netif = ip_netifs_find(&ip_globals.netifs, device_id);
-	if(! netif){
-		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-		return ENOENT;
-	}
-	route = (ip_route_ref) malloc(sizeof(ip_route_t));
-	if(! route){
-		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-		return ENOMEM;
-	}
-	route->address.s_addr = address.s_addr;
-	route->netmask.s_addr = netmask.s_addr;
-	route->gateway.s_addr = gateway.s_addr;
-	route->netif = netif;
-	index = ip_routes_add(&netif->routes, route);
-	if(index < 0){
-		free(route);
-	}
-	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-	return index;
-}
-
-ip_route_ref ip_find_route(in_addr_t destination){
-	int index;
-	ip_route_ref route;
-	ip_netif_ref netif;
-
-	// start with the last netif - the newest one
-	index = ip_netifs_count(&ip_globals.netifs) - 1;
-	while(index >= 0){
-		netif = ip_netifs_get_index(&ip_globals.netifs, index);
-		if(netif && (netif->state == NETIF_ACTIVE)){
-			route = ip_netif_find_route(netif, destination);
-			if(route){
-				return route;
-			}
-		}
-		-- index;
-	}
-	return &ip_globals.gateway;
-}
-
-ip_route_ref ip_netif_find_route(ip_netif_ref netif, in_addr_t destination){
-	int index;
-	ip_route_ref route;
-
-	if(netif){
-		// start with the first one - the direct route
-		for(index = 0; index < ip_routes_count(&netif->routes); ++ index){
-			route = ip_routes_get_index(&netif->routes, index);
-			if(route && ((route->address.s_addr &route->netmask.s_addr) == (destination.s_addr &route->netmask.s_addr))){
-				return route;
-			}
-		}
-	}
-	return NULL;
-}
-
-int ip_set_gateway_req_local(int ip_phone, device_id_t device_id, in_addr_t gateway)
-{
-	ip_netif_ref netif;
-
-	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
-	netif = ip_netifs_find(&ip_globals.netifs, device_id);
-	if(! netif){
-		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-		return ENOENT;
-	}
-	ip_globals.gateway.address.s_addr = 0;
-	ip_globals.gateway.netmask.s_addr = 0;
-	ip_globals.gateway.gateway.s_addr = gateway.s_addr;
-	ip_globals.gateway.netif = netif;
-	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-	return EOK;
-}
-
-packet_t ip_split_packet(packet_t packet, size_t prefix, size_t content, size_t suffix, socklen_t addr_len, services_t error){
-	size_t length;
-	packet_t next;
-	packet_t new_packet;
-	int result;
-	int phone;
-
-	next = packet;
-	// check all packets
-	while(next){
-		length = packet_get_data_length(next);
-		// too long?
-		if(length > content){
-			result = ip_fragment_packet(next, content, prefix, suffix, addr_len);
-			if(result != EOK){
-				new_packet = pq_detach(next);
-				if(next == packet){
-					// the new first packet of the queue
-					packet = new_packet;
-				}
-				// fragmentation needed?
-				if(result == EPERM){
-					phone = ip_prepare_icmp_and_get_phone(error, next, NULL);
-					if(phone >= 0){
-						// fragmentation necessary ICMP
-						icmp_destination_unreachable_msg(phone, ICMP_FRAG_NEEDED, content, next);
-					}
-				}else{
-					pq_release_remote(ip_globals.net_phone, packet_get_id(next));
-				}
-				next = new_packet;
-				continue;
-			}
-		}
-		next = pq_next(next);
-	}
-	return packet;
-}
-
-int ip_fragment_packet(packet_t packet, size_t length, size_t prefix, size_t suffix, socklen_t addr_len){
-	ERROR_DECLARE;
-
-	packet_t new_packet;
-	ip_header_ref header;
-	ip_header_ref middle_header;
-	ip_header_ref last_header;
-	struct sockaddr * src;
-	struct sockaddr * dest;
-	socklen_t addrlen;
-	int result;
-
-	result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest);
-	if(result <= 0){
-		return EINVAL;
-	}
-	addrlen = (socklen_t) result;
-	if(packet_get_data_length(packet) <= sizeof(ip_header_t)){
-		return ENOMEM;
-	}
-	// get header
-	header = (ip_header_ref) packet_get_data(packet);
-	if(! header){
-		return EINVAL;
-	}
-	// fragmentation forbidden?
-	if(header->flags &IPFLAG_DONT_FRAGMENT){
-		return EPERM;
-	}
-	// create the last fragment
-	new_packet = packet_get_4_remote(ip_globals.net_phone, prefix, length, suffix, ((addrlen > addr_len) ? addrlen : addr_len));
-	if(! new_packet){
-		return ENOMEM;
-	}
-	// allocate as much as originally
-	last_header = (ip_header_ref) packet_suffix(new_packet, IP_HEADER_LENGTH(header));
-	if(! last_header){
-		return ip_release_and_return(packet, ENOMEM);
-	}
-	ip_create_last_header(last_header, header);
-	// trim the unused space
-	if(ERROR_OCCURRED(packet_trim(new_packet, 0, IP_HEADER_LENGTH(header) - IP_HEADER_LENGTH(last_header)))){
-		return ip_release_and_return(packet, ERROR_CODE);
-	}
-	// biggest multiple of 8 lower than content
-	// TODO even fragmentation?
-	length = length &(~ 0x7);// (content / 8) * 8
-	if(ERROR_OCCURRED(ip_fragment_packet_data(packet, new_packet, header, last_header, ((IP_HEADER_DATA_LENGTH(header) - ((length - IP_HEADER_LENGTH(header)) &(~ 0x7))) % ((length - IP_HEADER_LENGTH(last_header)) &(~ 0x7))), src, dest, addrlen))){
-		return ip_release_and_return(packet, ERROR_CODE);
-	}
-	// mark the first as fragmented
-	header->flags |= IPFLAG_MORE_FRAGMENTS;
-	// create middle framgents
-	while(IP_TOTAL_LENGTH(header) > length){
-		new_packet = packet_get_4_remote(ip_globals.net_phone, prefix, length, suffix, ((addrlen >= addr_len) ? addrlen : addr_len));
-		if(! new_packet){
-			return ENOMEM;
-		}
-		middle_header = ip_create_middle_header(new_packet, last_header);
-		if(! middle_header){
-			return ip_release_and_return(packet, ENOMEM);
-		}
-		if(ERROR_OCCURRED(ip_fragment_packet_data(packet, new_packet, header, middle_header, (length - IP_HEADER_LENGTH(middle_header)) &(~ 0x7), src, dest, addrlen))){
-			return ip_release_and_return(packet, ERROR_CODE);
-		}
-	}
-	// finish the first fragment
-	header->header_checksum = IP_HEADER_CHECKSUM(header);
-	return EOK;
-}
-
-int ip_fragment_packet_data(packet_t packet, packet_t new_packet, ip_header_ref header, ip_header_ref new_header, size_t length, const struct sockaddr * src, const struct sockaddr * dest, socklen_t addrlen){
-	ERROR_DECLARE;
-
-	void * data;
-	size_t offset;
-
-	data = packet_suffix(new_packet, length);
-	if(! data){
-		return ENOMEM;
-	}
-	memcpy(data, ((void *) header) + IP_TOTAL_LENGTH(header) - length, length);
-	ERROR_PROPAGATE(packet_trim(packet, 0, length));
-	header->total_length = htons(IP_TOTAL_LENGTH(header) - length);
-	new_header->total_length = htons(IP_HEADER_LENGTH(new_header) + length);
-	offset = IP_FRAGMENT_OFFSET(header) + IP_HEADER_DATA_LENGTH(header);
-	new_header->fragment_offset_high = IP_COMPUTE_FRAGMENT_OFFSET_HIGH(offset);
-	new_header->fragment_offset_low = IP_COMPUTE_FRAGMENT_OFFSET_LOW(offset);
-	new_header->header_checksum = IP_HEADER_CHECKSUM(new_header);
-	ERROR_PROPAGATE(packet_set_addr(new_packet, (const uint8_t *) src, (const uint8_t *) dest, addrlen));
-	return pq_insert_after(packet, new_packet);
-}
-
-ip_header_ref ip_create_middle_header(packet_t packet, ip_header_ref last){
-	ip_header_ref middle;
-
-	middle = (ip_header_ref) packet_suffix(packet, IP_HEADER_LENGTH(last));
-	if(! middle){
-		return NULL;
-	}
-	memcpy(middle, last, IP_HEADER_LENGTH(last));
-	middle->flags |= IPFLAG_MORE_FRAGMENTS;
-	return middle;
-}
-
-void ip_create_last_header(ip_header_ref last, ip_header_ref first){
-	ip_option_ref option;
-	size_t next;
-	size_t length;
-
-	// copy first itself
-	memcpy(last, first, sizeof(ip_header_t));
-	length = sizeof(ip_header_t);
-	next = sizeof(ip_header_t);
-	// process all ip options
-	while(next < first->header_length){
-		option = (ip_option_ref) (((uint8_t *) first) + next);
-		// skip end or noop
-		if((option->type == IPOPT_END) || (option->type == IPOPT_NOOP)){
-			++ next;
-		}else{
-			// copy if said so or skip
-			if(IPOPT_COPIED(option->type)){
-				memcpy(((uint8_t *) last) + length, ((uint8_t *) first) + next, option->length);
-				length += option->length;
-			}
-			// next option
-			next += option->length;
-		}
-	}
-	// align 4 byte boundary
-	if(length % 4){
-		bzero(((uint8_t *) last) + length, 4 - (length % 4));
-		last->header_length = length / 4 + 1;
-	}else{
-		last->header_length = length / 4;
-	}
-	last->header_checksum = 0;
-}
-
-int ip_receive_message(device_id_t device_id, packet_t packet){
-	packet_t next;
-
-	do{
-		next = pq_detach(packet);
-		ip_process_packet(device_id, packet);
-		packet = next;
-	}while(packet);
-	return EOK;
-}
-
-int ip_process_packet(device_id_t device_id, packet_t packet){
-	ERROR_DECLARE;
-
-	ip_header_ref header;
-	in_addr_t dest;
-	ip_route_ref route;
-	int phone;
-	struct sockaddr * addr;
-	struct sockaddr_in addr_in;
-//	struct sockaddr_in	addr_in6;
-	socklen_t addrlen;
-
-	header = (ip_header_ref) packet_get_data(packet);
-	if(! header){
-		return ip_release_and_return(packet, ENOMEM);
-	}
-	// checksum
-	if((header->header_checksum) && (IP_HEADER_CHECKSUM(header) != IP_CHECKSUM_ZERO)){
-		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
-		if(phone >= 0){
-			// checksum error ICMP
-			icmp_parameter_problem_msg(phone, ICMP_PARAM_POINTER, ((size_t) ((void *) &header->header_checksum)) - ((size_t) ((void *) header)), packet);
-		}
-		return EINVAL;
-	}
-	if(header->ttl <= 1){
-		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
-		if(phone >= 0){
-			// ttl oxceeded ICMP
-			icmp_time_exceeded_msg(phone, ICMP_EXC_TTL, packet);
-		}
-		return EINVAL;
-	}
-	// process ipopt and get destination
-	dest = ip_get_destination(header);
-	// set the addrination address
-	switch(header->version){
-		case IPVERSION:
-			addrlen = sizeof(addr_in);
-			bzero(&addr_in, addrlen);
-			addr_in.sin_family = AF_INET;
-			memcpy(&addr_in.sin_addr.s_addr, &dest, sizeof(dest));
-			addr = (struct sockaddr *) &addr_in;
-			break;
-/*		case IPv6VERSION:
-			addrlen = sizeof(dest_in6);
-			bzero(&dest_in6, addrlen);
-			dest_in6.sin6_family = AF_INET6;
-			memcpy(&dest_in6.sin6_addr.s6_addr,);
-			dest = (struct sockaddr *) &dest_in;
-			break;
-*/		default:
-			return ip_release_and_return(packet, EAFNOSUPPORT);
-	}
-	ERROR_PROPAGATE(packet_set_addr(packet, NULL, (uint8_t *) &addr, addrlen));
-	route = ip_find_route(dest);
-	if(! route){
-		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
-		if(phone >= 0){
-			// unreachable ICMP
-			icmp_destination_unreachable_msg(phone, ICMP_HOST_UNREACH, 0, packet);
-		}
-		return ENOENT;
-	}
-	if(route->address.s_addr == dest.s_addr){
-		// local delivery
-		return ip_deliver_local(device_id, packet, header, 0);
-	}else{
-		// only if routing enabled
-		if(route->netif->routing){
-			-- header->ttl;
-			return ip_send_route(packet, route->netif, route, NULL, dest, 0);
-		}else{
-			phone = ip_prepare_icmp_and_get_phone(0, packet, header);
-			if(phone >= 0){
-				// unreachable ICMP if no routing
-				icmp_destination_unreachable_msg(phone, ICMP_HOST_UNREACH, 0, packet);
-			}
-			return ENOENT;
-		}
-	}
-}
-
-/** Notify the IP module about the received error notification packet.
- *
- * @param[in] ip_phone  The IP module phone used for (semi)remote calls.
- * @param[in] device_id The device identifier.
- * @param[in] packet    The received packet or the received packet queue.
- * @param[in] target    The target internetwork module service to be
- *                      delivered to.
- * @param[in] error     The packet error reporting service. Prefixes the
- *                      received packet.
- *
- * @return EOK on success.
- *
- */
-int ip_received_error_msg_local(int ip_phone, device_id_t device_id, packet_t packet, services_t target, services_t error){
-	uint8_t * data;
-	int offset;
-	icmp_type_t type;
-	icmp_code_t code;
-	ip_netif_ref netif;
-	measured_string_t address;
-	ip_route_ref route;
-	ip_header_ref header;
-
-	switch(error){
-		case SERVICE_ICMP:
-			offset = icmp_client_process_packet(packet, &type, &code, NULL, NULL);
-			if(offset < 0){
-				return ip_release_and_return(packet, ENOMEM);
-			}
-			data = packet_get_data(packet);
-			header = (ip_header_ref)(data + offset);
-			// destination host unreachable?
-			if((type == ICMP_DEST_UNREACH) && (code == ICMP_HOST_UNREACH)){
-				fibril_rwlock_read_lock(&ip_globals.netifs_lock);
-				netif = ip_netifs_find(&ip_globals.netifs, device_id);
-				if(netif && netif->arp){
-					route = ip_routes_get_index(&netif->routes, 0);
-					// from the same network?
-					if(route && ((route->address.s_addr &route->netmask.s_addr) == (header->destination_address &route->netmask.s_addr))){
-						// clear the ARP mapping if any
-						address.value = (char *) &header->destination_address;
-						address.length = CONVERT_SIZE(uint8_t, char, sizeof(header->destination_address));
-						arp_clear_address_req(netif->arp->phone, netif->device_id, SERVICE_IP, &address);
-					}
-				}
-				fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
-			}
-			break;
-		default:
-			return ip_release_and_return(packet, ENOTSUP);
-	}
-	return ip_deliver_local(device_id, packet, header, error);
-}
-
-int ip_deliver_local(device_id_t device_id, packet_t packet, ip_header_ref header, services_t error){
-	ERROR_DECLARE;
-
-	ip_proto_ref proto;
-	int phone;
-	services_t service;
-	tl_received_msg_t received_msg;
-	struct sockaddr * src;
-	struct sockaddr * dest;
-	struct sockaddr_in src_in;
-	struct sockaddr_in dest_in;
-//	struct sockaddr_in	src_in6;
-//	struct sockaddr_in	dest_in6;
-	socklen_t addrlen;
-
-	if((header->flags &IPFLAG_MORE_FRAGMENTS) || IP_FRAGMENT_OFFSET(header)){
-		// TODO fragmented
-		return ENOTSUP;
-	}else{
-		switch(header->version){
-			case IPVERSION:
-				addrlen = sizeof(src_in);
-				bzero(&src_in, addrlen);
-				src_in.sin_family = AF_INET;
-				memcpy(&dest_in, &src_in, addrlen);
-				memcpy(&src_in.sin_addr.s_addr, &header->source_address, sizeof(header->source_address));
-				memcpy(&dest_in.sin_addr.s_addr, &header->destination_address, sizeof(header->destination_address));
-				src = (struct sockaddr *) &src_in;
-				dest = (struct sockaddr *) &dest_in;
-				break;
-/*			case IPv6VERSION:
-				addrlen = sizeof(src_in6);
-				bzero(&src_in6, addrlen);
-				src_in6.sin6_family = AF_INET6;
-				memcpy(&dest_in6, &src_in6, addrlen);
-				memcpy(&src_in6.sin6_addr.s6_addr,);
-				memcpy(&dest_in6.sin6_addr.s6_addr,);
-				src = (struct sockaddr *) &src_in;
-				dest = (struct sockaddr *) &dest_in;
-				break;
-*/			default:
-				return ip_release_and_return(packet, EAFNOSUPPORT);
-		}
-		if(ERROR_OCCURRED(packet_set_addr(packet, (uint8_t *) src, (uint8_t *) dest, addrlen))){
-			return ip_release_and_return(packet, ERROR_CODE);
-		}
-		// trim padding if present
-		if((! error) && (IP_TOTAL_LENGTH(header) < packet_get_data_length(packet))){
-			if(ERROR_OCCURRED(packet_trim(packet, 0, packet_get_data_length(packet) - IP_TOTAL_LENGTH(header)))){
-				return ip_release_and_return(packet, ERROR_CODE);
-			}
-		}
-		fibril_rwlock_read_lock(&ip_globals.protos_lock);
-		proto = ip_protos_find(&ip_globals.protos, header->protocol);
-		if(! proto){
-			fibril_rwlock_read_unlock(&ip_globals.protos_lock);
-			phone = ip_prepare_icmp_and_get_phone(error, packet, header);
-			if(phone >= 0){
-				// unreachable ICMP
-				icmp_destination_unreachable_msg(phone, ICMP_PROT_UNREACH, 0, packet);
-			}
-			return ENOENT;
-		}
-		if(proto->received_msg){
-			service = proto->service;
-			received_msg = proto->received_msg;
-			fibril_rwlock_read_unlock(&ip_globals.protos_lock);
-			ERROR_CODE = received_msg(device_id, packet, service, error);
-		}else{
-			ERROR_CODE = tl_received_msg(proto->phone, device_id, packet, proto->service, error);
-			fibril_rwlock_read_unlock(&ip_globals.protos_lock);
-		}
-		return ERROR_CODE;
-	}
-}
-
-in_addr_t ip_get_destination(ip_header_ref header){
-	in_addr_t destination;
-
-	// TODO search set ipopt route?
-	destination.s_addr = header->destination_address;
-	return destination;
-}
-
-int ip_prepare_icmp(packet_t packet, ip_header_ref header){
-	packet_t next;
-	struct sockaddr * dest;
-	struct sockaddr_in dest_in;
-//	struct sockaddr_in	dest_in6;
-	socklen_t addrlen;
-
-	// detach the first packet and release the others
-	next = pq_detach(packet);
-	if(next){
-		pq_release_remote(ip_globals.net_phone, packet_get_id(next));
-	}
-	if(! header){
-		if(packet_get_data_length(packet) <= sizeof(ip_header_t)){
-			return ENOMEM;
-		}
-		// get header
-		header = (ip_header_ref) packet_get_data(packet);
-		if(! header){
-			return EINVAL;
-		}
-	}
-	// only for the first fragment
-	if(IP_FRAGMENT_OFFSET(header)){
-		return EINVAL;
-	}
-	// not for the ICMP protocol
-	if(header->protocol == IPPROTO_ICMP){
-		return EPERM;
-	}
-	// set the destination address
-	switch(header->version){
-		case IPVERSION:
-			addrlen = sizeof(dest_in);
-			bzero(&dest_in, addrlen);
-			dest_in.sin_family = AF_INET;
-			memcpy(&dest_in.sin_addr.s_addr, &header->source_address, sizeof(header->source_address));
-			dest = (struct sockaddr *) &dest_in;
-			break;
-/*		case IPv6VERSION:
-			addrlen = sizeof(dest_in6);
-			bzero(&dest_in6, addrlen);
-			dest_in6.sin6_family = AF_INET6;
-			memcpy(&dest_in6.sin6_addr.s6_addr,);
-			dest = (struct sockaddr *) &dest_in;
-			break;
-*/		default:
-			return EAFNOSUPPORT;
-	}
-	return packet_set_addr(packet, NULL, (uint8_t *) dest, addrlen);
-}
-
-int ip_get_icmp_phone(void){
-	ip_proto_ref proto;
-	int phone;
-
-	fibril_rwlock_read_lock(&ip_globals.protos_lock);
-	proto = ip_protos_find(&ip_globals.protos, IPPROTO_ICMP);
-	phone = proto ? proto->phone : ENOENT;
-	fibril_rwlock_read_unlock(&ip_globals.protos_lock);
-	return phone;
-}
-
-int ip_prepare_icmp_and_get_phone(services_t error, packet_t packet, ip_header_ref header){
-	int phone;
-
-	phone = ip_get_icmp_phone();
-	if(error || (phone < 0) || ip_prepare_icmp(packet, header)){
-		return ip_release_and_return(packet, EINVAL);
-	}
-	return phone;
-}
-
-int ip_release_and_return(packet_t packet, int result){
-	pq_release_remote(ip_globals.net_phone, packet_get_id(packet));
-	return result;
-}
-
-int ip_get_route_req_local(int ip_phone, ip_protocol_t protocol, const struct sockaddr * destination, socklen_t addrlen, device_id_t * device_id, void **header, size_t * headerlen){
-	struct sockaddr_in * address_in;
-//	struct sockaddr_in6 *	address_in6;
-	in_addr_t * dest;
-	in_addr_t * src;
-	ip_route_ref route;
-	ipv4_pseudo_header_ref header_in;
-
-	if(!(destination && (addrlen > 0))){
-		return EINVAL;
-	}
-	if(!(device_id && header && headerlen)){
-		return EBADMEM;
-	}
-	if((size_t) addrlen < sizeof(struct sockaddr)){
-		return EINVAL;
-	}
-	switch(destination->sa_family){
-		case AF_INET:
-			if(addrlen != sizeof(struct sockaddr_in)){
-				return EINVAL;
-			}
-			address_in = (struct sockaddr_in *) destination;
-			dest = &address_in->sin_addr;
-			if(! dest->s_addr){
-				dest->s_addr = IPV4_LOCALHOST_ADDRESS;
-			}
-			break;
-		// TODO IPv6
-/*		case AF_INET6:
-			if(addrlen != sizeof(struct sockaddr_in6)){
-				return EINVAL;
-			}
-			address_in6 = (struct sockaddr_in6 *) dest;
-			address_in6.sin6_addr.s6_addr;
-*/		default:
-			return EAFNOSUPPORT;
-	}
-	fibril_rwlock_read_lock(&ip_globals.lock);
-	route = ip_find_route(*dest);
-	// if the local host is the destination
-	if(route && (route->address.s_addr == dest->s_addr)
-		&& (dest->s_addr != IPV4_LOCALHOST_ADDRESS)){
-		// find the loopback device to deliver
-		dest->s_addr = IPV4_LOCALHOST_ADDRESS;
-		route = ip_find_route(*dest);
-	}
-	if(!(route && route->netif)){
-		fibril_rwlock_read_unlock(&ip_globals.lock);
-		return ENOENT;
-	}
-	*device_id = route->netif->device_id;
-	src = ip_netif_address(route->netif);
-	fibril_rwlock_read_unlock(&ip_globals.lock);
-	*headerlen = sizeof(*header_in);
-	header_in = (ipv4_pseudo_header_ref) malloc(*headerlen);
-	if(! header_in){
-		return ENOMEM;
-	}
-	bzero(header_in, * headerlen);
-	header_in->destination_address = dest->s_addr;
-	header_in->source_address = src->s_addr;
-	header_in->protocol = protocol;
-	header_in->data_length = 0;
-	*header = header_in;
-	return EOK;
-}
-
 /** Default thread for new connections.
  *
- *  @param[in] iid The initial message identifier.
- *  @param[in] icall The initial message call structure.
- *
- */
-static void il_client_connection(ipc_callid_t iid, ipc_call_t * icall)
+ * @param[in] iid	The initial message identifier.
+ * @param[in] icall	The initial message call structure.
+ */
+static void il_client_connection(ipc_callid_t iid, ipc_call_t *icall)
 {
 	/*
@@ -1673,5 +1958,5 @@
 	ipc_answer_0(iid, EOK);
 	
-	while(true) {
+	while (true) {
 		ipc_call_t answer;
 		int answer_count;
@@ -1688,7 +1973,12 @@
 		    &answer_count);
 		
-		/* End if said to either by the message or the processing result */
-		if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) || (res == EHANGUP))
+		/*
+		 * End if told to either by the message or the processing
+		 * result.
+		 */
+		if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) ||
+		    (res == EHANGUP)) {
 			return;
+		}
 		
 		/* Answer the message */
@@ -1699,10 +1989,6 @@
 /** Starts the module.
  *
- *  @param argc The count of the command line arguments. Ignored parameter.
- *  @param argv The command line parameters. Ignored parameter.
- *
- *  @returns EOK on success.
- *  @returns Other error codes as defined for each specific module start function.
- *
+ * @returns EOK on success.
+ * @returns Other error codes as defined for each specific module start function.
  */
 int main(int argc, char *argv[])
@@ -1711,7 +1997,5 @@
 	
 	/* Start the module */
-	if (ERROR_OCCURRED(il_module_start_standalone(il_client_connection)))
-		return ERROR_CODE;
-	
+	ERROR_PROPAGATE(il_module_start_standalone(il_client_connection));
 	return EOK;
 }
Index: uspace/srv/net/il/ip/ip.h
===================================================================
--- uspace/srv/net/il/ip/ip.h	(revision e9caf4779c4818e0894f8ea2cb6815ec2e723d8f)
+++ uspace/srv/net/il/ip/ip.h	(revision e8199d776ec319b694087134f35a2caed4576004)
@@ -28,13 +28,13 @@
 
 /** @addtogroup ip
- *  @{
+ * @{
  */
 
 /** @file
- *  IP module.
+ * IP module.
  */
 
-#ifndef __NET_IP_H__
-#define __NET_IP_H__
+#ifndef NET_IP_H_
+#define NET_IP_H_
 
 #include <fibril_synch.h>
@@ -50,27 +50,27 @@
 
 /** Type definition of the IP global data.
- *  @see ip_globals
+ * @see ip_globals
  */
-typedef struct ip_globals	ip_globals_t;
+typedef struct ip_globals ip_globals_t;
 
 /** Type definition of the IP network interface specific data.
- *  @see ip_netif
+ * @see ip_netif
  */
-typedef struct ip_netif	ip_netif_t;
+typedef struct ip_netif ip_netif_t;
 
 /** Type definition of the IP network interface specific data pointer.
- *  @see ip_netif
+ * @see ip_netif
  */
-typedef ip_netif_t *	ip_netif_ref;
+typedef ip_netif_t *ip_netif_ref;
 
 /** Type definition of the IP protocol specific data.
- *  @see ip_proto
+ * @see ip_proto
  */
-typedef struct ip_proto	ip_proto_t;
+typedef struct ip_proto ip_proto_t;
 
 /** Type definition of the IP protocol specific data pointer.
- *  @see ip_proto
+ * @see ip_proto
  */
-typedef ip_proto_t *	ip_proto_ref;
+typedef ip_proto_t *ip_proto_ref;
 
 /** Type definition of the IP route specific data.
@@ -82,128 +82,94 @@
  *  @see ip_route
  */
-typedef ip_route_t *	ip_route_ref;
+typedef ip_route_t *ip_route_ref;
 
 /** IP network interfaces.
- *  Maps devices to the IP network interface specific data.
- *  @see device.h
+ * Maps devices to the IP network interface specific data.
+ * @see device.h
  */
-DEVICE_MAP_DECLARE(ip_netifs, ip_netif_t)
+DEVICE_MAP_DECLARE(ip_netifs, ip_netif_t);
 
 /** IP registered protocols.
- *  Maps protocols to the IP protocol specific data.
- *  @see int_map.h
+ * Maps protocols to the IP protocol specific data.
+ * @see int_map.h
  */
-INT_MAP_DECLARE(ip_protos, ip_proto_t)
+INT_MAP_DECLARE(ip_protos, ip_proto_t);
 
 /** IP routing table.
- *  @see generic_field.h
+ * @see generic_field.h
  */
-GENERIC_FIELD_DECLARE(ip_routes, ip_route_t)
+GENERIC_FIELD_DECLARE(ip_routes, ip_route_t);
 
-/** IP network interface specific data.
- */
-struct	ip_netif{
-	/** ARP module.
-	 *  Assigned if using ARP.
-	 */
+/** IP network interface specific data. */
+struct ip_netif {
+	/** ARP module. Assigned if using ARP. */
 	module_ref arp;
-	/** Broadcast address.
-	 */
+	/** Broadcast address. */
 	in_addr_t broadcast;
-	/** Device identifier.
-	 */
+	/** Device identifier. */
 	device_id_t device_id;
-	/** Indicates whether using DHCP.
-	 */
+	/** Indicates whether using DHCP. */
 	int dhcp;
-	/** IP version.
-	 */
+	/** IP version. */
 	int ipv;
-	/** Packet dimension.
-	 */
+	/** Packet dimension. */
 	packet_dimension_t packet_dimension;
-	/** Netif module phone.
-	 */
+	/** Netif module phone. */
 	int phone;
-	/** Routing table.
-	 */
+	/** Routing table. */
 	ip_routes_t routes;
-	/** Indicates whether IP routing is enabled.
-	 */
+	/** Indicates whether IP routing is enabled. */
 	int routing;
-	/** Netif module service.
-	 */
+	/** Netif module service. */
 	services_t service;
-	/** Device state.
-	 */
+	/** Device state. */
 	device_state_t state;
 };
 
-/** IP protocol specific data.
- */
-struct ip_proto{
-	/** Protocol module phone.
-	 */
+/** IP protocol specific data. */
+struct ip_proto {
+	/** Protocol module phone. */
 	int phone;
-	/** Protocol number.
-	 */
+	/** Protocol number. */
 	int protocol;
-	/** Protocol packet receiving function.
-	 */
+	/** Protocol packet receiving function. */
 	tl_received_msg_t received_msg;
-	/** Protocol module service.
-	 */
+	/** Protocol module service. */
 	services_t service;
 };
 
-/** IP route specific data.
- */
-struct ip_route{
-	/** Target address.
-	 */
+/** IP route specific data. */
+struct ip_route {
+	/** Target address. */
 	in_addr_t address;
-	/** Gateway.
-	 */
+	/** Gateway. */
 	in_addr_t gateway;
-	/** Parent netif.
-	 */
+	/** Parent netif. */
 	ip_netif_ref netif;
-	/** Target network mask.
-	 */
+	/** Target network mask. */
 	in_addr_t netmask;
 };
 
-/** IP global data.
- */
-struct	ip_globals{
-	/** Default client connection function for support modules.
-	 */
+/** IP global data. */
+struct ip_globals {
+	/** Default client connection function for support modules. */
 	async_client_conn_t client_connection;
-	/** Default gateway.
-	 */
+	/** Default gateway. */
 	ip_route_t gateway;
-	/** Safety lock.
-	 */
+	/** Safety lock. */
 	fibril_rwlock_t lock;
-	/** Known support modules.
-	 */
+	/** Known support modules. */
 	modules_t modules;
-	/** Networking module phone.
-	 */
+	/** Networking module phone. */
 	int net_phone;
-	/** Registered network interfaces.
-	 */
+	/** Registered network interfaces. */
 	ip_netifs_t netifs;
-	/** Netifs safeyt lock.
-	 */
+	/** Netifs safeyt lock. */
 	fibril_rwlock_t netifs_lock;
-	/** Packet counter.
-	 */
+	/** Packet counter. */
 	uint16_t packet_counter;
-	/** Registered protocols.
-	 */
+	/** Registered protocols. */
 	ip_protos_t protos;
-	/** Protocols safety lock.
-	 */
+	/** Protocols safety lock. */
 	fibril_rwlock_t protos_lock;
 };
Index: uspace/srv/net/il/ip/ip_local.h
===================================================================
--- uspace/srv/net/il/ip/ip_local.h	(revision e9caf4779c4818e0894f8ea2cb6815ec2e723d8f)
+++ 	(revision )
@@ -1,60 +1,0 @@
-/*
- * Copyright (c) 2009 Lukas Mejdrech
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup ip
- * @{
- */
-
-#ifndef NET_IP_LOCAL_H_
-#define NET_IP_LOCAL_H_
-
-#include <async.h>
-#include <ipc/services.h>
-
-#include <net/ip_codes.h>
-#include <net/inet.h>
-#include <net/in.h>
-
-extern int ip_received_error_msg_local(int, device_id_t, packet_t, services_t,
-    services_t);
-extern int ip_set_gateway_req_local(int, device_id_t, in_addr_t);
-extern int ip_packet_size_req_local(int, device_id_t, packet_dimension_ref);
-extern int ip_received_error_msg_local(int, device_id_t, packet_t, services_t,
-    services_t);
-extern int ip_device_req_local(int, device_id_t, services_t);
-extern int ip_add_route_req_local(int, device_id_t, in_addr_t, in_addr_t,
-    in_addr_t);
-extern int ip_send_msg_local(int, device_id_t, packet_t, services_t,
-    services_t);
-extern int ip_get_route_req_local(int, ip_protocol_t, const struct sockaddr *,
-    socklen_t, device_id_t *, void **, size_t *);
-
-#endif
-
-/** @}
- */
Index: uspace/srv/net/il/ip/ip_module.c
===================================================================
--- uspace/srv/net/il/ip/ip_module.c	(revision e9caf4779c4818e0894f8ea2cb6815ec2e723d8f)
+++ uspace/srv/net/il/ip/ip_module.c	(revision e8199d776ec319b694087134f35a2caed4576004)
@@ -32,8 +32,10 @@
 
 /** @file
- *  IP standalone module implementation.
- *  Contains skeleton module functions mapping.
- *  The functions are used by the module skeleton as module specific entry points.
- *  @see module.c
+ * IP standalone module implementation.
+ * Contains skeleton module functions mapping.
+ * The functions are used by the module skeleton as module specific entry
+ * points.
+ *
+ * @see module.c
  */
 
@@ -52,13 +54,16 @@
 #include "ip_module.h"
 
-/** IP module global data.
- */
+/** IP module global data. */
 extern ip_globals_t ip_globals;
 
-int il_module_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
+int
+il_module_message_standalone(ipc_callid_t callid, ipc_call_t *call,
+    ipc_call_t *answer, int *answer_count)
+{
 	return ip_message_standalone(callid, call, answer, answer_count);
 }
 
-int il_module_start_standalone(async_client_conn_t client_connection){
+int il_module_start_standalone(async_client_conn_t client_connection)
+{
 	ERROR_DECLARE;
 	
@@ -68,6 +73,6 @@
 	
 	ipcarg_t phonehash;
-	if (ERROR_OCCURRED(ip_initialize(client_connection))
-	    || ERROR_OCCURRED(REGISTER_ME(SERVICE_IP, &phonehash))) {
+	if (ERROR_OCCURRED(ip_initialize(client_connection)) ||
+	    ERROR_OCCURRED(REGISTER_ME(SERVICE_IP, &phonehash))) {
 		pm_destroy();
 		return ERROR_CODE;
Index: uspace/srv/net/il/ip/ip_module.h
===================================================================
--- uspace/srv/net/il/ip/ip_module.h	(revision e9caf4779c4818e0894f8ea2cb6815ec2e723d8f)
+++ uspace/srv/net/il/ip/ip_module.h	(revision e8199d776ec319b694087134f35a2caed4576004)
@@ -28,36 +28,20 @@
 
 /** @addtogroup ip
- *  @{
+ * @{
  */
 
 /** @file
- *  IP module functions.
- *  The functions are used as IP module entry points.
+ * IP module functions.
+ * The functions are used as IP module entry points.
  */
 
-#ifndef __NET_IP_MODULE_H__
-#define __NET_IP_MODULE_H__
+#ifndef NET_IP_MODULE_H_
+#define NET_IP_MODULE_H_
 
 #include <ipc/ipc.h>
 
-/** Initializes the IP module.
- *  @param[in] client_connection The client connection processing function. The module skeleton propagates its own one.
- *  @returns EOK on success.
- *  @returns ENOMEM if there is not enough memory left.
- */
-int ip_initialize(async_client_conn_t client_connection);
-
-/** Processes the IP message.
- *  @param[in] callid The message identifier.
- *  @param[in] call The message parameters.
- *  @param[out] answer The message answer parameters.
- *  @param[out] answer_count The last parameter for the actual answer in the answer parameter.
- *  @returns EOK on success.
- *  @returns ENOTSUP if the message is not known.
- *  @see ip_interface.h
- *  @see il_interface.h
- *  @see IS_NET_IP_MESSAGE()
- */
-int ip_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count);
+extern int ip_initialize(async_client_conn_t);
+extern int ip_message_standalone(ipc_callid_t, ipc_call_t *, ipc_call_t *,
+    int *);
 
 #endif
