Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision c8916d15d0b9a3ebcb74f63bfddee2a2188663df)
+++ uspace/Makefile	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -71,7 +71,9 @@
 	srv/loc \
 	srv/devman \
+	srv/inet \
 	srv/loader \
 	srv/ns \
 	srv/taskmon \
+	srv/tcp \
 	srv/vfs \
 	srv/bd/ata_bd \
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision c8916d15d0b9a3ebcb74f63bfddee2a2188663df)
+++ uspace/lib/c/Makefile	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -87,4 +87,5 @@
 	generic/task.c \
 	generic/futex.c \
+	generic/inet.c \
 	generic/io/asprintf.c \
 	generic/io/io.c \
Index: uspace/lib/c/generic/inet.c
===================================================================
--- uspace/lib/c/generic/inet.c	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
+++ uspace/lib/c/generic/inet.c	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * 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.
+ */
+
+#include <async.h>
+#include <assert.h>
+#include <errno.h>
+#include <inet/inet.h>
+#include <ipc/inet.h>
+#include <ipc/services.h>
+#include <loc.h>
+
+static void inet_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg);
+
+static async_sess_t *inet_sess = NULL;
+static inet_ev_ops_t *inet_ev_ops = NULL;
+static uint8_t inet_protocol = 0;
+
+static int inet_callback_create(void)
+{
+	async_exch_t *exch = async_exchange_begin(inet_sess);
+
+	ipc_call_t answer;
+	aid_t req = async_send_0(exch, INET_CALLBACK_CREATE, &answer);
+	int rc = async_connect_to_me(exch, 0, 0, 0, inet_cb_conn, NULL);
+	async_exchange_end(exch);
+
+	if (rc != EOK)
+		return rc;
+
+	sysarg_t retval;
+	async_wait_for(req, &retval);
+	if (retval != EOK)
+		return retval;
+
+	return EOK;
+}
+
+static int inet_set_proto(uint8_t protocol)
+{
+	int rc;
+
+	async_exch_t *exch = async_exchange_begin(inet_sess);
+	rc = async_req_1_0(exch, INET_SET_PROTO, protocol);
+	async_exchange_end(exch);
+
+	return rc;
+}
+
+int inet_init(uint8_t protocol, inet_ev_ops_t *ev_ops)
+{
+	service_id_t inet_svc;
+
+	assert(inet_sess == NULL);
+	assert(inet_ev_ops == NULL);
+	assert(inet_protocol == 0);
+
+	inet_svc = loc_service_get_id(SERVICE_NAME_INET, &inet_svc,
+	    IPC_FLAG_BLOCKING);
+	inet_sess = loc_service_connect(EXCHANGE_SERIALIZE, inet_svc,
+	    IPC_FLAG_BLOCKING);
+	if (inet_sess == NULL)
+		return ENOENT;
+
+	if (inet_set_proto(protocol) != EOK) {
+		async_hangup(inet_sess);
+		inet_sess = NULL;
+		return EIO;
+	}
+
+	if (inet_callback_create() != EOK) {
+		async_hangup(inet_sess);
+		inet_sess = NULL;
+		return EIO;
+	}
+
+	inet_protocol = protocol;
+	inet_ev_ops = ev_ops;
+
+	return EOK;
+}
+
+int inet_send(inet_dgram_t *dgram, uint8_t ttl, inet_df_t df)
+{
+	return ENOTSUP;
+}
+
+int inet_get_srcaddr(inet_addr_t *remote, uint8_t tos, inet_addr_t *local)
+{
+	return ENOTSUP;
+}
+
+static void inet_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call)) {
+			/* TODO: Handle hangup */
+			return;
+		}
+		
+		switch (IPC_GET_IMETHOD(call)) {
+		case INET_EV_RECV:
+			async_answer_0(callid, EOK);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+		}
+	}
+}
+
+/** @}
+ */
Index: uspace/lib/c/include/inet/inet.h
===================================================================
--- uspace/lib/c/include/inet/inet.h	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
+++ uspace/lib/c/include/inet/inet.h	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_INET_INET_H_
+#define LIBC_INET_INET_H_
+
+#include <sys/types.h>
+
+#define INET_TTL_MAX 255
+
+typedef struct {
+	uint32_t ipv4;
+} inet_addr_t;
+
+typedef struct {
+	inet_addr_t src;
+	inet_addr_t dest;
+	uint8_t tos;
+	void *data;
+	size_t size;
+} inet_dgram_t;
+
+typedef struct {
+	int (*recv)(inet_dgram_t *);
+} inet_ev_ops_t;
+
+typedef enum {
+	INET_DF = 1
+} inet_df_t;
+
+extern int inet_init(uint8_t, inet_ev_ops_t *);
+extern int inet_send(inet_dgram_t *, uint8_t, inet_df_t);
+extern int inet_get_srcaddr(inet_addr_t *, uint8_t, inet_addr_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/inet.h
===================================================================
--- uspace/lib/c/include/ipc/inet.h	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
+++ uspace/lib/c/include/ipc/inet.h	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * 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 libcipc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_IPC_INET_H_
+#define LIBC_IPC_INET_H_
+
+#include <ipc/common.h>
+
+typedef enum {
+	INET_CALLBACK_CREATE = IPC_FIRST_USER_METHOD,
+	INET_SEND,
+	INET_SET_PROTO
+} inet_request_t;
+
+typedef enum {
+	INET_EV_RECV = IPC_FIRST_USER_METHOD
+} inet_event_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/c/include/ipc/services.h
===================================================================
--- uspace/lib/c/include/ipc/services.h	(revision c8916d15d0b9a3ebcb74f63bfddee2a2188663df)
+++ uspace/lib/c/include/ipc/services.h	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -52,4 +52,6 @@
 } services_t;
 
+#define SERVICE_NAME_INET "net/inet"
+
 #endif
 
Index: uspace/srv/inet/Makefile
===================================================================
--- uspace/srv/inet/Makefile	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
+++ uspace/srv/inet/Makefile	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2012 Jiri Svoboda
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = inet
+
+SOURCES = \
+	inet.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/inet/inet.c
===================================================================
--- uspace/srv/inet/inet.c	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
+++ uspace/srv/inet/inet.c	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * 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 inet
+ * @{
+ */
+/**
+ * @file
+ * @brief Internet Protocol service
+ */
+
+#include <adt/list.h>
+#include <async.h>
+#include <errno.h>
+#include <fibril_synch.h>
+#include <io/log.h>
+#include <ipc/inet.h>
+#include <ipc/services.h>
+#include <loc.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#define NAME "inet"
+
+/** Inet Client */
+typedef struct {
+	async_sess_t *sess;
+	uint8_t protocol;
+	link_t client_list;
+} inet_client_t;
+
+static void inet_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg);
+
+static FIBRIL_MUTEX_INITIALIZE(client_list_lock);
+static LIST_INITIALIZE(client_list);
+
+static int inet_init(void)
+{
+	service_id_t sid;
+	int rc;
+
+	log_msg(LVL_DEBUG, "inet_init()");
+
+	async_set_client_connection(inet_client_conn);
+
+	rc = loc_server_register(NAME);
+	if (rc != EOK) {
+		log_msg(LVL_ERROR, "Failed registering server (%d).", rc);
+		return EEXIST;
+	}
+
+	rc = loc_service_register(SERVICE_NAME_INET, &sid);
+	if (rc != EOK) {
+		log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
+		return EEXIST;
+	}
+
+	return EOK;
+}
+
+static void inet_callback_create(inet_client_t *client, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	log_msg(LVL_DEBUG, "inet_callback_create()");
+
+	async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (sess == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	client->sess = sess;
+	async_answer_0(callid, EOK);
+}
+
+static void inet_send(inet_client_t *client, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	log_msg(LVL_DEBUG, "inet_send()");
+	async_answer_0(callid, ENOTSUP);
+}
+
+static void inet_set_proto(inet_client_t *client, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	sysarg_t proto;
+
+	proto = IPC_GET_ARG1(*call);
+	log_msg(LVL_DEBUG, "inet_set_proto(%lu)", (unsigned long) proto);
+
+	if (proto > UINT8_MAX) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	client->protocol = proto;
+	async_answer_0(callid, EOK);
+}
+
+static void inet_client_init(inet_client_t *client)
+{
+	client->sess = NULL;
+
+	fibril_mutex_lock(&client_list_lock);
+	list_append(&client->client_list, &client_list);
+	fibril_mutex_unlock(&client_list_lock);
+}
+
+static void inet_client_fini(inet_client_t *client)
+{
+	async_hangup(client->sess);
+	client->sess = NULL;
+
+	fibril_mutex_lock(&client_list_lock);
+	list_remove(&client->client_list);
+	fibril_mutex_unlock(&client_list_lock);
+}
+
+static void inet_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	inet_client_t client;
+
+	log_msg(LVL_DEBUG, "inet_client_conn()");
+
+	/* Accept the connection */
+	async_answer_0(iid, EOK);
+
+	inet_client_init(&client);
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		sysarg_t method = IPC_GET_IMETHOD(call);
+
+		if (!method) {
+			/* The other side has hung up */
+			async_answer_0(callid, EOK);
+			return;
+		}
+
+		switch (method) {
+		case INET_CALLBACK_CREATE:
+			inet_callback_create(&client, callid, &call);
+			break;
+		case INET_SEND:
+			inet_send(&client, callid, &call);
+			break;
+		case INET_SET_PROTO:
+			inet_set_proto(&client, callid, &call);
+			break;
+		default:
+			async_answer_0(callid, EINVAL);
+		}
+	}
+
+	inet_client_fini(&client);
+}
+
+int main(int argc, char *argv[])
+{
+	int rc;
+
+	printf(NAME ": HelenOS Internet Protocol service");
+
+	if (log_init(NAME, LVL_DEBUG) != EOK) {
+		printf(NAME ": Failed to initialize logging.");
+		return 1;
+	}
+
+	rc = inet_init();
+	if (rc != EOK)
+		return 1;
+
+	task_retval(0);
+	async_manager();
+
+	/* Not reached */
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/srv/tcp/Makefile
===================================================================
--- uspace/srv/tcp/Makefile	(revision c8916d15d0b9a3ebcb74f63bfddee2a2188663df)
+++ uspace/srv/tcp/Makefile	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -27,5 +27,5 @@
 #
 
-USPACE_PREFIX = ../../../..
+USPACE_PREFIX = ../..
 LIBS = $(LIBNET_PREFIX)/libnet.a
 EXTRA_CFLAGS = -I$(LIBNET_PREFIX)/include
Index: uspace/srv/tcp/sock.c
===================================================================
--- uspace/srv/tcp/sock.c	(revision c8916d15d0b9a3ebcb74f63bfddee2a2188663df)
+++ uspace/srv/tcp/sock.c	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -38,9 +38,11 @@
 #include <async.h>
 #include <errno.h>
+#include <inet/inet.h>
 #include <io/log.h>
-#include <ip_client.h>
+#include <ipc/services.h>
 #include <ipc/socket.h>
 #include <net/modules.h>
 #include <net/socket.h>
+#include <ns.h>
 
 #include "sock.h"
@@ -63,9 +65,20 @@
 static socket_ports_t gsock;
 
+static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
 static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg);
 
-void tcp_sock_init(void)
-{
+int tcp_sock_init(void)
+{
+	int rc;
+
 	socket_ports_initialize(&gsock);
+
+	async_set_client_connection(tcp_sock_connection);
+
+	rc = service_register(SERVICE_TCP);
+	if (rc != EOK)
+		return EEXIST;
+
+	return EOK;
 }
 
@@ -273,7 +286,4 @@
 	tcp_sock_t lsocket;
 	tcp_sock_t fsocket;
-	nic_device_id_t dev_id;
-	tcp_phdr_t *phdr;
-	size_t phdr_len;
 
 	log_msg(LVL_DEBUG, "tcp_sock_connect()");
@@ -309,18 +319,19 @@
 
 	if (socket->laddr.ipv4 == TCP_IPV4_ANY) {
-		/* Find route to determine local IP address. */
-		rc = ip_get_route_req(ip_sess, IPPROTO_TCP,
-		    (struct sockaddr *)addr, sizeof(*addr), &dev_id,
-		    (void **)&phdr, &phdr_len);
+		/* Determine local IP address */
+		inet_addr_t loc_addr, rem_addr;
+
+		rem_addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
+		rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
 		if (rc != EOK) {
 			fibril_mutex_unlock(&socket->lock);
 			async_answer_0(callid, rc);
-			log_msg(LVL_DEBUG, "tcp_transmit_connect: Failed to find route.");
-			return;
-		}
-
-		socket->laddr.ipv4 = uint32_t_be2host(phdr->src_addr);
+			log_msg(LVL_DEBUG, "tcp_sock_connect: Failed to "
+			    "determine local address.");
+			return;
+		}
+
+		socket->laddr.ipv4 = loc_addr.ipv4;
 		log_msg(LVL_DEBUG, "Local IP address is %x", socket->laddr.ipv4);
-		free(phdr);
 	}
 
@@ -713,5 +724,5 @@
 	}
 
-	rc = socket_destroy(net_sess, socket_id, &client->sockets, &gsock,
+	rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
 	    tcp_free_sock_data);
 	if (rc != EOK) {
@@ -764,5 +775,5 @@
 }
 
-int tcp_sock_connection(async_sess_t *sess, ipc_callid_t iid, ipc_call_t icall)
+static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
 	ipc_callid_t callid;
@@ -773,5 +784,5 @@
 	async_answer_0(iid, EOK);
 
-	client.sess = sess;
+	client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
 	socket_cores_initialize(&client.sockets);
 
@@ -824,6 +835,4 @@
 		}
 	}
-
-	return EOK;
 }
 
Index: uspace/srv/tcp/sock.h
===================================================================
--- uspace/srv/tcp/sock.h	(revision c8916d15d0b9a3ebcb74f63bfddee2a2188663df)
+++ uspace/srv/tcp/sock.h	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -38,6 +38,5 @@
 #include <async.h>
 
-extern void tcp_sock_init(void);
-extern int tcp_sock_connection(async_sess_t *, ipc_callid_t, ipc_call_t);
+extern int tcp_sock_init(void);
 
 #endif
Index: uspace/srv/tcp/tcp.c
===================================================================
--- uspace/srv/tcp/tcp.c	(revision c8916d15d0b9a3ebcb74f63bfddee2a2188663df)
+++ uspace/srv/tcp/tcp.c	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2011 Jiri Svoboda
+ * Copyright (c) 2012 Jiri Svoboda
  * All rights reserved.
  *
@@ -39,17 +39,8 @@
 #include <byteorder.h>
 #include <errno.h>
+#include <inet/inet.h>
 #include <io/log.h>
 #include <stdio.h>
 #include <task.h>
-
-#include <icmp_remote.h>
-#include <ip_client.h>
-#include <ip_interface.h>
-#include <ipc/services.h>
-#include <ipc/tl.h>
-#include <tl_common.h>
-#include <tl_skel.h>
-#include <packet_client.h>
-#include <packet_remote.h>
 
 #include "ncsim.h"
@@ -63,130 +54,25 @@
 #define NAME       "tcp"
 
-async_sess_t *net_sess;
-static async_sess_t *icmp_sess;
-async_sess_t *ip_sess;
-packet_dimensions_t pkt_dims;
-
+static int tcp_inet_ev_recv(inet_dgram_t *dgram);
 static void tcp_received_pdu(tcp_pdu_t *pdu);
 
-/* Pull up packets into a single memory block. */
-static int pq_pullup(packet_t *packet, void **data, size_t *dsize)
-{
-	packet_t *npacket;
-	size_t tot_len;
-	int length;
-
-	npacket = packet;
-	tot_len = 0;
-	do {
-		length = packet_get_data_length(packet);
-		if (length <= 0)
-			return EINVAL;
-
-		tot_len += length;
-	} while ((npacket = pq_next(npacket)) != NULL);
-
-	uint8_t *buf;
-	uint8_t *dp;
-
-	buf = calloc(tot_len, 1);
-	if (buf == NULL) {
-		free(buf);
-		return ENOMEM;
-	}
-
-	npacket = packet;
-	dp = buf;
-	do {
-		length = packet_get_data_length(packet);
-		if (length <= 0) {
-			free(buf);
-			return EINVAL;
-		}
-
-		memcpy(dp, packet_get_data(packet), length);
-		dp += length;
-	} while ((npacket = pq_next(npacket)) != NULL);
-
-	*data = buf;
-	*dsize = tot_len;
-	return EOK;
-}
-
-/** Process packet received from network layer. */
-static int tcp_received_msg(nic_device_id_t device_id, packet_t *packet,
-    services_t error)
-{
-	int rc;
-	size_t offset;
-	int length;
-	struct sockaddr_in *src_addr;
-	struct sockaddr_in *dest_addr;
-	size_t addr_len;
-
-	log_msg(LVL_DEBUG, "tcp_received_msg()");
-
-	switch (error) {
-	case SERVICE_NONE:
-		break;
-	case SERVICE_ICMP:
-	default:
-		log_msg(LVL_WARN, "Unsupported service number %u",
-		    (unsigned)error);
-		pq_release_remote(net_sess, packet_get_id(packet));
-		return ENOTSUP;
-	}
-
-	/* Process and trim off IP header */
-	log_msg(LVL_DEBUG, "tcp_received_msg() - IP header");
-
-	rc = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
-	if (rc < 0) {
-		log_msg(LVL_WARN, "ip_client_process_packet() failed");
-		pq_release_remote(net_sess, packet_get_id(packet));
-		return rc;
-	}
-
-	offset = (size_t)rc;
-	length = packet_get_data_length(packet);
-
-	if (length < 0 || (size_t)length < offset) {
-		log_msg(LVL_WARN, "length=%d, dropping.", length);
-		pq_release_remote(net_sess, packet_get_id(packet));
-		return EINVAL;
-	}
-
-	addr_len = packet_get_addr(packet, (uint8_t **)&src_addr,
-	    (uint8_t **)&dest_addr);
-	if (addr_len <= 0) {
-		log_msg(LVL_WARN, "Failed to get packet address.");
-		pq_release_remote(net_sess, packet_get_id(packet));
-		return EINVAL;
-	}
-
-	if (addr_len != sizeof(struct sockaddr_in)) {
-		log_msg(LVL_WARN, "Unsupported address size %zu (!= %zu)",
-		    addr_len, sizeof(struct sockaddr_in));
-		pq_release_remote(net_sess, packet_get_id(packet));
-		return EINVAL;
-	}
-
-	rc = packet_trim(packet, offset, 0);
-	if (rc != EOK) {
-		log_msg(LVL_WARN, "Failed to trim packet.");
-		pq_release_remote(net_sess, packet_get_id(packet));
-		return rc;
-	}
-
-	/* Pull up packets into a single memory block, pdu_raw. */
-	log_msg(LVL_DEBUG, "tcp_received_msg() - pull up");
+static inet_ev_ops_t tcp_inet_ev_ops = {
+	.recv = tcp_inet_ev_recv
+};
+
+/** Received datagram callback */
+static int tcp_inet_ev_recv(inet_dgram_t *dgram)
+{
 	uint8_t *pdu_raw;
-	size_t pdu_raw_size = 0;
-
-	pq_pullup(packet, (void **)&pdu_raw, &pdu_raw_size);
+	size_t pdu_raw_size;
+
+	log_msg(LVL_DEBUG, "tcp_inet_ev_recv()");
+
+	pdu_raw = dgram->data;
+	pdu_raw_size = dgram->size;
 
 	/* Split into header and payload. */
 
-	log_msg(LVL_DEBUG, "tcp_received_msg() - split header/payload");
+	log_msg(LVL_DEBUG, "tcp_inet_ev_recv() - split header/payload");
 
 	tcp_pdu_t *pdu;
@@ -198,5 +84,4 @@
 		log_msg(LVL_WARN, "pdu_raw_size = %zu < sizeof(tcp_header_t) = %zu",
 		    pdu_raw_size, sizeof(tcp_header_t));
-		pq_release_remote(net_sess, packet_get_id(packet));
 		return EINVAL;
 	}
@@ -211,5 +96,4 @@
 		log_msg(LVL_WARN, "pdu_raw_size = %zu < hdr_size = %zu",
 		    pdu_raw_size, hdr_size);
-		pq_release_remote(net_sess, packet_get_id(packet));
 		return EINVAL;
 	}
@@ -217,7 +101,5 @@
 	if (hdr_size < sizeof(tcp_header_t)) {
 		log_msg(LVL_WARN, "hdr_size = %zu < sizeof(tcp_header_t) = %zu",
-		    hdr_size, sizeof(tcp_header_t));
-		pq_release_remote(net_sess, packet_get_id(packet));
-		return EINVAL;
+		    hdr_size, sizeof(tcp_header_t));		return EINVAL;
 	}
 
@@ -231,8 +113,6 @@
 	}
 
-	free(pdu_raw);
-
-	pdu->src_addr.ipv4 = uint32_t_be2host(src_addr->sin_addr.s_addr);
-	pdu->dest_addr.ipv4 = uint32_t_be2host(dest_addr->sin_addr.s_addr);
+	pdu->src_addr.ipv4 = dgram->src.ipv4;
+	pdu->dest_addr.ipv4 = dgram->dest.ipv4;
 	log_msg(LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
 	    pdu->src_addr.ipv4, pdu->dest_addr.ipv4);
@@ -244,106 +124,32 @@
 }
 
-/** Receive packets from network layer. */
-static void tcp_receiver(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	packet_t *packet;
-	int rc;
-
-	log_msg(LVL_DEBUG, "tcp_receiver()");
-
-	while (true) {
-		switch (IPC_GET_IMETHOD(*icall)) {
-		case NET_TL_RECEIVED:
-			log_msg(LVL_DEBUG, "method = NET_TL_RECEIVED");
-			rc = packet_translate_remote(net_sess, &packet,
-			    IPC_GET_PACKET(*icall));
-			if (rc != EOK) {
-				log_msg(LVL_DEBUG, "Error %d translating packet.", rc);
-				async_answer_0(iid, (sysarg_t)rc);
-				break;
-			}
-			rc = tcp_received_msg(IPC_GET_DEVICE(*icall), packet,
-			    IPC_GET_ERROR(*icall));
-			async_answer_0(iid, (sysarg_t)rc);
-			break;
-		default:
-			log_msg(LVL_DEBUG, "method = %u",
-			    (unsigned)IPC_GET_IMETHOD(*icall));
-			async_answer_0(iid, ENOTSUP);
-			break;
-		}
-
-		iid = async_get_call(icall);
-	}
-}
-
 /** Transmit PDU over network layer. */
 void tcp_transmit_pdu(tcp_pdu_t *pdu)
 {
-	struct sockaddr_in dest;
-	nic_device_id_t dev_id;
-	void *phdr;
-	size_t phdr_len;
-	packet_dimension_t *pkt_dim;
 	int rc;
-	packet_t *packet;
-	void *pkt_data;
-	size_t pdu_size;
-
-	dest.sin_family = AF_INET;
-	dest.sin_port = 0; /* not needed */
-	dest.sin_addr.s_addr = host2uint32_t_be(pdu->dest_addr.ipv4);
-
-	/* Find route. Obtained pseudo-header is not used. */
-	rc = ip_get_route_req(ip_sess, IPPROTO_TCP, (struct sockaddr *)&dest,
-	    sizeof(dest), &dev_id, &phdr, &phdr_len);
-	if (rc != EOK) {
-		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to find route.");
+	uint8_t *pdu_raw;
+	size_t pdu_raw_size;
+	inet_dgram_t dgram;
+
+	pdu_raw_size = pdu->header_size + pdu->text_size;
+	pdu_raw = malloc(pdu_raw_size);
+	if (pdu_raw == NULL) {
+		log_msg(LVL_ERROR, "Failed to transmit PDU. Out of memory.");
 		return;
 	}
 
-	rc = tl_get_ip_packet_dimension(ip_sess, &pkt_dims, dev_id, &pkt_dim);
-	if (rc != EOK) {
-		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get dimension.");
-		return;
-	}
-
-	pdu_size = pdu->header_size + pdu->text_size;
-
-	packet = packet_get_4_remote(net_sess, pdu_size, pkt_dim->addr_len,
-	    pkt_dim->prefix, pkt_dim->suffix);
-	if (!packet) {
-		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get packet.");
-		return;
-	}
-
-	pkt_data = packet_suffix(packet, pdu_size);
-	if (!pkt_data) {
-		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get pkt_data ptr.");
-		pq_release_remote(net_sess, packet_get_id(packet));
-		return;
-	}
-
-	rc = ip_client_prepare_packet(packet, IPPROTO_TCP, 0, 0, 0, 0);
-	if (rc != EOK) {
-		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to prepare IP packet part.");
-		pq_release_remote(net_sess, packet_get_id(packet));
-		return;
-	}
-
-	rc = packet_set_addr(packet, NULL, (uint8_t *)&dest, sizeof(dest));
-	if (rc != EOK) {
-		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to set packet address.");
-		pq_release_remote(net_sess, packet_get_id(packet));
-		return;
-	}
-
-	/* Copy PDU data to packet */
-	memcpy(pkt_data, pdu->header, pdu->header_size);
-	memcpy((uint8_t *)pkt_data + pdu->header_size, pdu->text,
+	memcpy(pdu_raw, pdu->header, pdu->header_size);
+	memcpy(pdu_raw + pdu->header_size, pdu->text,
 	    pdu->text_size);
 
-	/* Transmit packet. XXX Transfers packet ownership to IP? */
-	ip_send_msg(ip_sess, dev_id, packet, SERVICE_TCP, 0);
+	dgram.src.ipv4 = pdu->src_addr.ipv4;
+	dgram.dest.ipv4 = pdu->dest_addr.ipv4;
+	dgram.tos = 0;
+	dgram.data = pdu_raw;
+	dgram.size = pdu_raw_size;
+
+	rc = inet_send(&dgram, INET_TTL_MAX, 0);
+	if (rc != EOK)
+		log_msg(LVL_ERROR, "Failed to transmit PDU.");
 }
 
@@ -365,46 +171,25 @@
 }
 
-/* Called from libnet */
-void tl_connection(void)
-{
-	log_msg(LVL_DEBUG, "tl_connection()");
-}
-
-/* Called from libnet */
-int tl_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
-    size_t *answer_count)
-{
-	async_sess_t *callback;
-
-	log_msg(LVL_DEBUG, "tl_message()");
-
-	*answer_count = 0;
-	callback = async_callback_receive_start(EXCHANGE_SERIALIZE, call);
-	if (callback)
-		return tcp_sock_connection(callback, callid, *call);
-
-	return ENOTSUP;
-}
-
-/* Called from libnet */
-int tl_initialize(async_sess_t *sess)
+static int tcp_init(void)
 {
 	int rc;
 
-	net_sess = sess;
-	icmp_sess = icmp_connect_module();
-
-	log_msg(LVL_DEBUG, "tl_initialize()");
-
-	tcp_sock_init();
-
-	ip_sess = ip_bind_service(SERVICE_IP, IPPROTO_TCP, SERVICE_TCP,
-	    tcp_receiver);
-	if (ip_sess == NULL)
+	log_msg(LVL_DEBUG, "tcp_init()");
+
+	tcp_rqueue_init();
+	tcp_rqueue_thread_start();
+
+	tcp_ncsim_init();
+	tcp_ncsim_thread_start();
+
+	if (0) tcp_test();
+
+	rc = inet_init(42, &tcp_inet_ev_ops);
+	if (rc != EOK)
 		return ENOENT;
 
-	rc = packet_dimensions_initialize(&pkt_dims);
+	rc = tcp_sock_init();
 	if (rc != EOK)
-		return rc;
+		return ENOENT;
 
 	return EOK;
@@ -423,18 +208,7 @@
 	}
 
-//	printf(NAME ": Accepting connections\n");
-//	task_retval(0);
-
-	tcp_rqueue_init();
-	tcp_rqueue_thread_start();
-
-	tcp_ncsim_init();
-	tcp_ncsim_thread_start();
-
-	if (0) tcp_test();
-/*
+	tcp_init();
+	task_retval(0);
 	async_manager();
-*/
-	tl_module_start(SERVICE_TCP);
 
 	/* Not reached */
Index: uspace/srv/tcp/tcp.h
===================================================================
--- uspace/srv/tcp/tcp.h	(revision c8916d15d0b9a3ebcb74f63bfddee2a2188663df)
+++ uspace/srv/tcp/tcp.h	(revision c76e9267a192002d0dc6f41f5e2984b3599ac46c)
@@ -37,9 +37,6 @@
 
 #include <async.h>
-#include <packet_remote.h>
 #include "tcp_type.h"
 
-extern async_sess_t *net_sess;
-extern async_sess_t *ip_sess;
 extern void tcp_transmit_pdu(tcp_pdu_t *);
 
