Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -45,4 +45,5 @@
 	app/edit \
 	app/getterm \
+	app/hdisk \
 	app/init \
 	app/inet \
@@ -68,4 +69,5 @@
 	app/trace \
 	app/top \
+	app/untar \
 	app/usbinfo \
 	app/vuhid \
@@ -76,9 +78,9 @@
 	app/nettest3 \
 	app/ping \
-	app/ping6 \
 	app/sysinfo \
 	app/mkbd \
 	app/date \
 	app/vdemo \
+	app/viewer \
 	app/vlaunch \
 	app/vterm \
@@ -97,4 +99,5 @@
 	srv/net/inetsrv \
 	srv/net/loopip \
+	srv/net/nconfsrv \
 	srv/net/slip \
 	srv/net/tcp \
@@ -237,4 +240,5 @@
 	lib/softrend \
 	lib/draw \
+	lib/math \
 	lib/net \
 	lib/nic \
@@ -248,5 +252,7 @@
 	lib/pcm \
 	lib/bithenge \
-	lib/posix
+	lib/posix \
+	lib/mbr \
+	lib/gpt
 
 LIBC_BUILD = $(addsuffix .build,$(LIBC))
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/Makefile.common	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -45,4 +45,5 @@
 #
 #   POSIX_COMPAT       set to 'y' to use POSIX compatibility layer
+#   NEEDS_MATH         set to 'y' to add implementation of mathematical functions
 #
 # Optionally, for a binary:
@@ -109,4 +110,5 @@
 LIBSOFTFLOAT_PREFIX = $(LIB_PREFIX)/softfloat
 LIBSOFTINT_PREFIX = $(LIB_PREFIX)/softint
+LIBMATH_PREFIX = $(LIB_PREFIX)/math
 
 LIBPOSIX_PREFIX = $(LIB_PREFIX)/posix
@@ -143,4 +145,7 @@
 LIBHTTP_PREFIX = $(LIB_PREFIX)/http
 LIBURI_PREFIX = $(LIB_PREFIX)/uri
+
+LIBMBR_PREFIX = $(LIB_PREFIX)/mbr
+LIBGPT_PREFIX = $(LIB_PREFIX)/gpt
 
 ifeq ($(STATIC_NEEDED),y)
@@ -233,4 +238,9 @@
 endif
 
+# Do we need math?
+ifeq ($(NEEDS_MATH),y)
+	BASE_LIBS += $(LIBMATH_PREFIX)/libmath.a
+endif
+
 ## Setup platform configuration
 #
@@ -244,4 +254,9 @@
 
 ifeq ($(COMPILER),gcc_cross)
+	CFLAGS += $(GCC_CFLAGS) $(EXTRA_CFLAGS)
+	DEPEND_DEFS = $(DEFS) $(CONFIG_DEFS)
+endif
+
+ifeq ($(COMPILER),gcc_helenos)
 	CFLAGS += $(GCC_CFLAGS) $(EXTRA_CFLAGS)
 	DEPEND_DEFS = $(DEFS) $(CONFIG_DEFS)
Index: uspace/app/dnsres/dnsres.c
===================================================================
--- uspace/app/dnsres/dnsres.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/dnsres/dnsres.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -36,5 +36,4 @@
 #include <inet/addr.h>
 #include <inet/dnsr.h>
-#include <net/socket_codes.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -54,5 +53,5 @@
 	}
 	
-	uint16_t af;
+	uint16_t ver;
 	char *hname;
 	
@@ -63,5 +62,5 @@
 		}
 		
-		af = AF_INET;
+		ver = ip_v4;
 		hname = argv[2];
 	} else if (str_cmp(argv[1], "-6") == 0) {
@@ -71,13 +70,13 @@
 		}
 		
-		af = AF_INET6;
+		ver = ip_v6;
 		hname = argv[2];
 	} else {
-		af = 0;
+		ver = ip_any;
 		hname = argv[1];
 	}
 	
 	dnsr_hostinfo_t *hinfo;
-	int rc = dnsr_name2host(hname, &hinfo, af);
+	int rc = dnsr_name2host(hname, &hinfo, ver);
 	if (rc != EOK) {
 		printf("%s: Error resolving '%s'.\n", NAME, hname);
Index: uspace/app/download/Makefile
===================================================================
--- uspace/app/download/Makefile	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/download/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -29,5 +29,5 @@
 USPACE_PREFIX = ../..
 LIBS = $(LIBHTTP_PREFIX)/libhttp.a $(LIBURI_PREFIX)/liburi.a
-EXTRA_CFLAGS = -I$(LIBHTTP_PREFIX) -I$(LIBURI_PREFIX)
+EXTRA_CFLAGS = -I$(LIBHTTP_PREFIX)/include -I$(LIBURI_PREFIX)
 DEFS = -DRELEASE=$(RELEASE)
 BINARY = download
Index: uspace/app/download/main.c
===================================================================
--- uspace/app/download/main.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/download/main.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -47,5 +47,5 @@
 #include <net/socket.h>
 
-#include <http.h>
+#include <http/http.h>
 #include <uri.h>
 
@@ -132,39 +132,32 @@
 		fprintf(stderr, "Failed creating request\n");
 		uri_destroy(uri);
-		free(server_path);
 		return 3;
 	}
 	
-	http_header_t *header_host = http_header_create("Host", uri->host);
-	if (header_host == NULL) {
-		fprintf(stderr, "Failed creating Host header\n");
-		uri_destroy(uri);
-		free(server_path);
-		return 3;
-	}
-	list_append(&header_host->link, &req->headers);
-	
-	http_header_t *header_ua = http_header_create("User-Agent", USER_AGENT);
-	if (header_ua == NULL) {
-		fprintf(stderr, "Failed creating User-Agent header\n");
-		uri_destroy(uri);
-		free(server_path);
-		return 3;
-	}
-	list_append(&header_ua->link, &req->headers);
+	int rc = http_headers_append(&req->headers, "Host", uri->host);
+	if (rc != EOK) {
+		fprintf(stderr, "Failed setting Host header: %s\n", str_error(rc));
+		uri_destroy(uri);
+		return rc;
+	}
+	
+	rc = http_headers_append(&req->headers, "User-Agent", USER_AGENT);
+	if (rc != EOK) {
+		fprintf(stderr, "Failed creating User-Agent header: %s\n", str_error(rc));
+		uri_destroy(uri);
+		return rc;
+	}
 	
 	http_t *http = http_create(uri->host, port);
 	if (http == NULL) {
 		uri_destroy(uri);
-		free(server_path);
 		fprintf(stderr, "Failed creating HTTP object\n");
 		return 3;
 	}
 	
-	int rc = http_connect(http);
+	rc = http_connect(http);
 	if (rc != EOK) {
 		fprintf(stderr, "Failed connecting: %s\n", str_error(rc));
 		uri_destroy(uri);
-		free(server_path);
 		return rc;
 	}
@@ -174,14 +167,13 @@
 		fprintf(stderr, "Failed sending request: %s\n", str_error(rc));
 		uri_destroy(uri);
-		free(server_path);
 		return rc;
 	}
 	
 	http_response_t *response = NULL;
-	rc = http_receive_response(http, &response);
+	rc = http_receive_response(&http->recv_buffer, &response, 16 * 1024,
+	    100);
 	if (rc != EOK) {
 		fprintf(stderr, "Failed receiving response: %s\n", str_error(rc));
 		uri_destroy(uri);
-		free(server_path);
 		return rc;
 	}
@@ -197,10 +189,9 @@
 			fprintf(stderr, "Failed allocating buffer\n)");
 			uri_destroy(uri);
-			free(server_path);
 			return ENOMEM;
 		}
 		
 		int body_size;
-		while ((body_size = http_receive_body(http, buf, buf_size)) > 0) {
+		while ((body_size = recv_buffer(&http->recv_buffer, buf, buf_size)) > 0) {
 			fwrite(buf, 1, body_size, stdout);
 		}
@@ -212,5 +203,4 @@
 	
 	uri_destroy(uri);
-	free(server_path);
 	return EOK;
 }
Index: uspace/app/getterm/getterm.c
===================================================================
--- uspace/app/getterm/getterm.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/getterm/getterm.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -112,10 +112,4 @@
 	reopen(&stderr, 2, term, O_WRONLY, "w");
 	
-	/*
-	 * FIXME: fdopen() should actually detect that we are opening a console
-	 * and it should set line-buffering mode automatically.
-	 */
-	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
-	
 	if (stdin == NULL)
 		return -2;
@@ -126,4 +120,10 @@
 	if (stderr == NULL)
 		return -4;
+	
+	/*
+	 * FIXME: fdopen() should actually detect that we are opening a console
+	 * and it should set line-buffering mode automatically.
+	 */
+	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
 	
 	version_print(term);
Index: uspace/app/hdisk/Makefile
===================================================================
--- uspace/app/hdisk/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/hdisk/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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 = ../..
+LIBS = $(LIBMBR_PREFIX)/libmbr.a $(LIBGPT_PREFIX)/libgpt.a \
+	$(LIBBLOCK_PREFIX)/libblock.a $(LIBCLUI_PREFIX)/libclui.a \
+	$(LIBC_PREFIX)/libc.a
+EXTRA_CFLAGS = -I$(LIBMBR_PREFIX) -I$(LIBGPT_PREFIX) -I$(LIBBLOCK_PREFIX) -I$(LIBCLUI_PREFIX)
+BINARY = hdisk
+
+SOURCES = \
+	hdisk.c \
+	input.c \
+	func_none.c \
+	func_mbr.c \
+	func_gpt.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/hdisk/common.h
===================================================================
--- uspace/app/hdisk/common.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/hdisk/common.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012-2013 Dominik Taborsky
+ * 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 hdisk
+ * @{
+ */
+/** @file
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <libmbr.h>
+#include <libgpt.h>
+
+typedef enum {
+	LYT_NONE,
+	LYT_MBR,
+	LYT_GPT,
+} layouts_t;
+
+typedef union {
+	mbr_label_t *mbr;
+	gpt_label_t *gpt;
+} label_data_t;
+
+typedef struct label {
+	layouts_t layout;
+	aoff64_t blocks;
+	service_id_t device;
+	label_data_t data;
+	unsigned int alignment;
+	int (* destroy_label)(struct label *);
+	int (* add_part)(struct label *, tinput_t *);
+	int (* delete_part)(struct label *, tinput_t *);
+	int (* new_label)(struct label *);
+	int (* print_parts)(struct label *);
+	int (* read_parts)(struct label *);
+	int (* write_parts)(struct label *);
+	int (* extra_funcs)(struct label *, tinput_t *);
+} label_t;
+
+#endif
Index: uspace/app/hdisk/func_gpt.c
===================================================================
--- uspace/app/hdisk/func_gpt.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/hdisk/func_gpt.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2012-2013 Dominik Taborsky
+ * 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 hdisk
+ * @{
+ */
+/** @file
+ */
+
+#include <stdio.h>
+#include <str.h>
+#include <errno.h>
+#include <str_error.h>
+#include <sys/types.h>
+#include <sys/typefmt.h>
+#include "func_gpt.h"
+#include "input.h"
+
+static void print_part_types(void);
+static int set_gpt_partition(tinput_t *, gpt_part_t *, label_t *);
+
+int construct_gpt_label(label_t *this)
+{
+	this->layout = LYT_GPT;
+	this->alignment = 1;
+	
+	this->add_part = add_gpt_part;
+	this->delete_part = delete_gpt_part;
+	this->destroy_label = destroy_gpt_label;
+	this->new_label = new_gpt_label;
+	this->print_parts = print_gpt_parts;
+	this->read_parts = read_gpt_parts;
+	this->write_parts = write_gpt_parts;
+	this->extra_funcs = extra_gpt_funcs;
+	
+	return this->new_label(this);
+}
+
+int add_gpt_part(label_t *this, tinput_t *in)
+{
+	gpt_part_t *partition = gpt_get_partition(this->data.gpt);
+	if (partition == NULL)
+		return ENOMEM;
+	
+	return set_gpt_partition(in, partition, this);
+}
+
+int delete_gpt_part(label_t *this, tinput_t *in)
+{
+	printf("Index of the partition to delete (counted from 0): ");
+	size_t idx = get_input_size_t(in);
+	
+	int rc = gpt_remove_partition(this->data.gpt, idx);
+	if (rc == ENOMEM) {
+		printf("Warning: Running out on memory, not resizing.\n");
+		return rc;
+	} else if (rc == EINVAL) {
+		printf("Invalid index.\n");
+		return rc;
+	}
+	
+	return EOK;
+}
+
+int destroy_gpt_label(label_t *this)
+{
+	gpt_free_label(this->data.gpt);
+	return EOK;
+}
+
+int new_gpt_label(label_t *this)
+{
+	this->data.gpt = gpt_alloc_label();
+	return EOK;
+}
+
+int print_gpt_parts(label_t *this)
+{
+	printf("Current partition scheme: GPT\n");
+	printf("Number of blocks: %" PRIu64 "\n", this->blocks);
+	
+	size_t i = 0;
+	gpt_part_foreach (this->data.gpt, iter) {
+		if (gpt_get_part_type(iter) == GPT_PTE_UNUSED)
+			continue;
+		
+		if (i % 20 == 0)
+			printf("%15s %10s %10s Type: Name:\n",
+			    "Start:", "End:", "Length:");
+		
+		printf("%3zu  %10" PRIu64 " %10" PRIu64 " %10" PRIu64 "    %3zu %s\n",
+		   i, gpt_get_start_lba(iter), gpt_get_end_lba(iter),
+		   gpt_get_end_lba(iter) - gpt_get_start_lba(iter), 
+		   gpt_get_part_type(iter), gpt_get_part_name(iter));
+		
+		i++;
+	}
+	
+	return EOK;
+}
+
+int read_gpt_parts(label_t *this)
+{
+	int rc = gpt_read_header(this->data.gpt, this->device);
+	if (rc != EOK) {
+		printf("Error: Reading header failed: %d (%s)\n", rc,
+		    str_error(rc));
+		return rc;
+	}
+	
+	rc = gpt_read_partitions(this->data.gpt);
+	if (rc != EOK) {
+		printf("Error: Reading partitions failed: %d (%s)\n", rc,
+		    str_error(rc));
+		return rc;
+	}
+	
+	return EOK;
+}
+
+int write_gpt_parts(label_t *this)
+{
+	int rc = gpt_write_partitions(this->data.gpt, this->device);
+	if (rc != EOK) {
+		printf("Error: Writing partitions failed: %d (%s)\n", rc,
+		    str_error(rc));
+		return rc;
+	}
+	
+	return EOK;
+}
+
+int extra_gpt_funcs(label_t *this, tinput_t *in)
+{
+	printf("Not implemented.\n");
+	return EOK;
+}
+
+static int set_gpt_partition(tinput_t *in, gpt_part_t *partition, label_t *this)
+{
+	printf("Set starting address: ");
+	uint64_t sa = get_input_uint64(in);
+	if ((this->alignment != 0) && (this->alignment != 1) &&
+	    (sa % this->alignment != 0))
+		sa = gpt_get_next_aligned(sa, this->alignment);
+	
+	printf("Set end address (max: %" PRIu64 "): ", this->blocks);
+	uint64_t ea = get_input_uint64(in);
+	
+	if (ea <= sa) {
+		printf("Invalid value.\n");
+		return EINVAL;
+	}
+	
+	gpt_set_start_lba(partition, sa);
+	gpt_set_end_lba(partition, ea);
+	
+	printf("Choose type: ");
+	print_part_types();
+	printf("Set type (1 for HelenOS System): ");
+	size_t idx = get_input_size_t(in);
+	gpt_set_part_type(partition, idx);
+	
+	gpt_set_random_uuid(partition->part_id);
+	
+	printf("Name the partition: ");
+	char *name;
+	int rc = get_input_line(in, &name);
+	if (rc != EOK) {
+		printf("Error reading name: %d (%s)\n", rc, str_error(rc));
+		return rc;
+	}
+	
+	gpt_set_part_name(partition, name, str_size(name));
+	
+	return EOK;
+}
+
+static void print_part_types(void)
+{
+	unsigned int count = 0;
+	const partition_type_t *ptype = gpt_ptypes;
+	
+	do {
+		printf("%u: %s\n", count, ptype->desc);
+		count++;
+		ptype++;
+		
+		if (count % 10 == 0) {
+			printf("Print (more) partition types? (y/n)\n");
+			int c = getchar();
+			if (c == 'n')
+				return;
+		}
+	} while (ptype->guid != NULL);
+}
Index: uspace/app/hdisk/func_gpt.h
===================================================================
--- uspace/app/hdisk/func_gpt.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/hdisk/func_gpt.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012-2013 Dominik Taborsky
+ * 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 hdisk
+ * @{
+ */
+/** @file
+ */
+
+#ifndef __FUNC_GPT_H__
+#define __FUNC_GPT_H__
+
+#include <loc.h>
+#include <tinput.h>
+#include <libgpt.h>
+#include "common.h"
+
+extern int construct_gpt_label(label_t *);
+extern int add_gpt_part(label_t *, tinput_t *);
+extern int delete_gpt_part(label_t *, tinput_t *);
+extern int destroy_gpt_label(label_t *);
+extern int new_gpt_label(label_t *);
+extern int print_gpt_parts(label_t *);
+extern int read_gpt_parts(label_t *);
+extern int write_gpt_parts(label_t *);
+extern int extra_gpt_funcs(label_t *, tinput_t *);
+
+#endif
Index: uspace/app/hdisk/func_mbr.c
===================================================================
--- uspace/app/hdisk/func_mbr.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/hdisk/func_mbr.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2012-2013 Dominik Taborsky
+ * 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 hdisk
+ * @{
+ */
+/** @file
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <sys/types.h>
+#include "func_mbr.h"
+#include "input.h"
+
+static int set_mbr_partition(tinput_t *, mbr_part_t *, label_t *);
+
+int construct_mbr_label(label_t *this)
+{
+	this->layout = LYT_MBR;
+	this->alignment = 1;
+	
+	this->add_part      = add_mbr_part;
+	this->delete_part   = delete_mbr_part;
+	this->destroy_label = destroy_mbr_label;
+	this->new_label     = new_mbr_label;
+	this->print_parts   = print_mbr_parts;
+	this->read_parts    = read_mbr_parts;
+	this->write_parts   = write_mbr_parts;
+	this->extra_funcs   = extra_mbr_funcs;
+	
+	return this->new_label(this);
+}
+
+int add_mbr_part(label_t *this, tinput_t *in)
+{
+	mbr_part_t *partition = mbr_alloc_partition();
+	if (partition == NULL)
+		return ENOMEM;
+	
+	int rc = set_mbr_partition(in, partition, this);
+	if (rc != EOK)
+		return rc;
+	
+	rc = mbr_add_partition(this->data.mbr, partition);
+	if (rc != ERR_OK)
+		printf("Error adding partition: %d\n", rc);
+	
+	return EOK;
+}
+
+int delete_mbr_part(label_t *this, tinput_t *in)
+{
+	printf("Index of the partition to delete (counted from 0): ");
+	size_t idx = get_input_size_t(in);
+	
+	if ((idx == 0) && (errno != EOK))
+		return errno;
+	
+	int rc = mbr_remove_partition(this->data.mbr, idx);
+	if (rc != EOK)
+		printf("Error: partition does not exist?\n");
+	
+	return EOK;
+}
+
+int destroy_mbr_label(label_t *this)
+{
+	mbr_free_label(this->data.mbr);
+	return EOK;
+}
+
+int new_mbr_label(label_t *this)
+{
+	this->data.mbr = mbr_alloc_label();
+	if (this->data.mbr == NULL)
+		return ENOMEM;
+	
+	mbr_set_device(this->data.mbr, this->device);
+	return EOK;
+}
+
+int print_mbr_parts(label_t *this)
+{
+	printf("Current partition scheme: MBR\n");
+	printf("Number of blocks: %" PRIu64 "\n", this->blocks);
+	printf("\t\t%10s  %10s %10s %10s %7s\n",
+	    "Bootable:", "Start:", "End:", "Length:", "Type:");
+	
+	unsigned int num = 0;
+	mbr_part_t *it;
+	for (it = mbr_get_first_partition(this->data.mbr); it != NULL;
+	     it = mbr_get_next_partition(this->data.mbr, it)) {
+		if (it->type == PT_UNUSED)
+			continue;
+		
+		printf("\tP%u:\t", num);
+		if (mbr_get_flag(it, ST_BOOT))
+			printf("*");
+		else
+			printf(" ");
+		
+		printf("\t%10u %10u %10u %7u\n", it->start_addr,
+		    it->start_addr + it->length, it->length, it->type);
+		
+		num++;
+	}
+	
+	printf("%u partitions found.\n", num);
+	
+	return EOK;
+}
+
+int read_mbr_parts(label_t *this)
+{
+	int rc = mbr_read_mbr(this->data.mbr, this->device);
+	if (rc != EOK)
+		return rc;
+	
+	if (!mbr_is_mbr(this->data.mbr))
+		return EINVAL;
+	
+	rc = mbr_read_partitions(this->data.mbr);
+	if (rc != EOK)
+		return rc;
+	
+	return EOK;
+}
+
+int write_mbr_parts(label_t *this)
+{
+	int rc = mbr_write_partitions(this->data.mbr, this->device);
+	if (rc != EOK)
+		printf("Error occured during writing: ERR: %d: %s\n", rc,
+		    str_error(rc));
+	
+	return rc;
+}
+
+int extra_mbr_funcs(label_t *this, tinput_t *in)
+{
+	printf("Not implemented.\n");
+	return EOK;
+}
+
+static int set_mbr_partition(tinput_t *in, mbr_part_t *partition, label_t *this)
+{
+	printf("Primary (p) or logical (l): ");
+	int c = getchar();
+	printf("%c\n", c);
+
+	switch (c) {
+	case 'p':
+		mbr_set_flag(partition, ST_LOGIC, false);
+		break;
+	case 'l':
+		mbr_set_flag(partition, ST_LOGIC, true);
+		break;
+	default:
+		printf("Invalid type. Cancelled.\n");
+		return EINVAL;
+	}
+	
+	printf("Set type (0 - 255): ");
+	uint8_t type = get_input_uint8(in);
+	if ((type == 0) && (errno != EOK))
+		return errno;
+	
+	// FIXME: Make sure there is at most one bootable partition
+	printf("Bootable? (y/n): ");
+	c = getchar();
+	if ((c != 'y') && (c != 'Y') && (c != 'n') && (c != 'N')) {
+		printf("Invalid value. Cancelled.");
+		return EINVAL;
+	}
+	
+	printf("%c\n", c);
+	mbr_set_flag(partition, ST_BOOT, (c == 'y' || c == 'Y') ? true : false);
+	
+	printf("Set starting address: ");
+	uint32_t sa = get_input_uint32(in);
+	if ((sa == 0) && (errno != EOK))
+		return errno;
+	
+	if ((this->alignment != 0) && (this->alignment != 1) &&
+	    (sa % this->alignment != 0)) {
+		sa = mbr_get_next_aligned(sa, this->alignment);
+		printf("Starting address was aligned to %" PRIu32 ".\n", sa);
+	}
+	
+	printf("Set end addres (max: %" PRIu64 "): ", this->blocks);
+	uint32_t ea = get_input_uint32(in);
+	if ((ea == 0) && (errno != EOK))
+		return errno;
+	
+	if (ea < sa) {
+		printf("Invalid value. Canceled.\n");
+		return EINVAL;
+	}
+	
+	partition->type = type;
+	partition->start_addr = sa;
+	partition->length = ea - sa;
+	
+	return EOK;
+}
Index: uspace/app/hdisk/func_mbr.h
===================================================================
--- uspace/app/hdisk/func_mbr.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/hdisk/func_mbr.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012-2013 Dominik Taborsky
+ * 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 hdisk
+ * @{
+ */
+/** @file
+ */
+
+#ifndef __FUNC_MBR_H__
+#define __FUNC_MBR_H__
+
+#include <loc.h>
+#include <tinput.h>
+#include <libmbr.h>
+#include "common.h"
+
+extern int construct_mbr_label(label_t *);
+extern int add_mbr_part(label_t *, tinput_t *);
+extern int delete_mbr_part(label_t *, tinput_t *);
+extern int destroy_mbr_label(label_t *);
+extern int new_mbr_label(label_t *);
+extern int print_mbr_parts(label_t *);
+extern int read_mbr_parts(label_t *);
+extern int write_mbr_parts(label_t *);
+extern int extra_mbr_funcs(label_t *, tinput_t *);
+
+#endif
Index: uspace/app/hdisk/func_none.c
===================================================================
--- uspace/app/hdisk/func_none.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/hdisk/func_none.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2012-2013 Dominik Taborsky
+ * 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 hdisk
+ * @{
+ */
+/** @file
+ */
+
+#include <errno.h>
+#include "func_none.h"
+
+static void not_implemented(void);
+
+int construct_none_label(label_t *this)
+{
+	this->layout = LYT_NONE;
+	
+	this->add_part = add_none_part;
+	this->delete_part = delete_none_part;
+	this->destroy_label = destroy_none_label;
+	this->new_label = new_none_label;
+	this->print_parts = print_none_parts;
+	this->read_parts = read_none_parts;
+	this->write_parts = write_none_parts;
+	this->extra_funcs = extra_none_funcs;
+	
+	return EOK;
+}
+
+int add_none_part(label_t *this, tinput_t *in)
+{
+	not_implemented();
+	return EOK;
+}
+
+int delete_none_part(label_t *this, tinput_t *in)
+{
+	not_implemented();
+	return EOK;
+}
+
+int destroy_none_label(label_t *this)
+{
+	return EOK;
+}
+
+int new_none_label(label_t *this)
+{
+	not_implemented();
+	return EOK;
+}
+
+int print_none_parts(label_t *this)
+{
+	not_implemented();
+	return EOK;
+}
+
+int read_none_parts(label_t *this)
+{
+	not_implemented();
+	return EOK;
+}
+
+int write_none_parts(label_t *this)
+{
+	not_implemented();
+	return EOK;
+}
+
+int extra_none_funcs(label_t *this, tinput_t * in)
+{
+	not_implemented();
+	return EOK;
+}
+
+static void not_implemented(void)
+{
+	printf("No format selected.\n");
+}
Index: uspace/app/hdisk/func_none.h
===================================================================
--- uspace/app/hdisk/func_none.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/hdisk/func_none.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012-2013 Dominik Taborsky
+ * 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 hdisk
+ * @{
+ */
+/** @file
+ */
+
+#ifndef __FUNC_NONE_H__
+#define __FUNC_NONE_H__
+
+#include <loc.h>
+#include <tinput.h>
+#include "common.h"
+
+extern int construct_none_label(label_t *);
+extern int add_none_part(label_t *, tinput_t *);
+extern int delete_none_part(label_t *, tinput_t *);
+extern int destroy_none_label(label_t *);
+extern int new_none_label(label_t *);
+extern int print_none_parts(label_t *);
+extern int read_none_parts(label_t *);
+extern int write_none_parts(label_t *);
+extern int extra_none_funcs(label_t *, tinput_t *);
+
+#endif
Index: uspace/app/hdisk/hdisk.c
===================================================================
--- uspace/app/hdisk/hdisk.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/hdisk/hdisk.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2012-2013 Dominik Taborsky
+ * 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 hdisk
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/bd.h>
+#include <loc.h>
+#include <async.h>
+#include <stdio.h>
+#include <ipc/services.h>
+#include <block.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <str.h>
+#include <libmbr.h>
+#include <libgpt.h>
+#include <tinput.h>
+#include <str_error.h>
+#include "hdisk.h"
+#include "input.h"
+#include "func_gpt.h"
+#include "func_mbr.h"
+#include "func_none.h"
+
+static int interact(void);
+static void print_help(void);
+static void select_label_format(tinput_t *);
+static void construct_label(layouts_t);
+static void free_label(void);
+static int try_read(void);
+static int try_read_mbr(void);
+static int try_read_gpt(void);
+static void set_alignment(tinput_t *);
+
+static label_t label;
+
+int main(int argc, char *argv[])
+{
+	if (argc == 1) {
+		printf("Missing argument. Please specify a device to operate on.\n");
+		return 1;
+	}
+	
+	service_id_t dev_handle;
+	int rc = loc_service_get_id(argv[1], &dev_handle, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		printf("Unknown device. Exiting.\n");
+		return 2;
+	}
+	
+	init_label();
+	label.device = dev_handle;
+	
+	rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
+	if (rc != EOK) {
+		printf("Error during libblock init: %d - %s.\n", rc, str_error(rc));
+		return 3;
+	}
+	
+	aoff64_t blocks;
+	rc = block_get_nblocks(dev_handle, &blocks);
+	block_fini(dev_handle);
+	if (rc != EOK) {
+		printf("Error while getting number of blocks: %d - %s.\n",
+		    rc, str_error(rc));
+		return 4;
+	}
+	
+	label.blocks = blocks;
+	
+	rc = try_read_mbr();
+	if (rc == EOK)
+		goto interact;
+	
+	free_label();
+	
+	rc = try_read_gpt();
+	if (rc == EOK)
+		goto interact;
+	
+	printf("No label recognized. Create a new one.\n");
+	construct_label(LYT_NONE);
+	
+interact:
+	return interact();
+}
+
+/** Interact with user */
+int interact(void)
+{
+	tinput_t *in = tinput_new();
+	if (in == NULL) {
+		printf("Failed initing input. Free some memory.\n");
+		return ENOMEM;
+	}
+	tinput_set_prompt(in, "");
+	
+	printf("Welcome to hdisk.\nType 'h' for help.\n");
+	
+	while (true) {
+		printf("# ");
+		int input = getchar();
+		printf("%c\n", input);
+		
+		switch (input) {
+		case 'a':
+			label.add_part(&label, in);
+			break;
+		case 'd':
+			label.delete_part(&label, in);
+			break;
+		case 'e':
+			label.extra_funcs(&label, in);
+			break;
+		case 'f':
+			free_label();
+			select_label_format(in);
+			break;
+		case 'h':
+			print_help();
+			break;
+		case 'l':
+			set_alignment(in);
+			break;
+		case 'n':
+			printf("Discarding label...\n");
+			free_label();
+			label.new_label(&label);
+			break;
+		case 'p':
+			label.print_parts(&label);
+			break;
+		case 'q':
+			putchar('\n');
+			free_label();
+			goto end;
+		case 'r':
+			label.read_parts(&label);
+		case 'w':
+			label.write_parts(&label);
+			break;
+		default:
+			printf("Unknown command. Try 'h' for help.\n");
+			break;
+		}
+	}
+	
+end:
+	tinput_destroy(in);
+	return EOK;
+}
+
+void print_help(void)
+{
+	printf(
+	    "\t 'a' \t\t Add partition.\n"
+	    "\t 'd' \t\t Delete partition.\n"
+	    "\t 'e' \t\t Extra functions (per label format).\n"
+	    "\t 'f' \t\t Switch the format of the partition label.\n"
+	    "\t 'h' \t\t Prints help. See help for more.\n"
+	    "\t 'l' \t\t Set alignment.\n"
+	    "\t 'n' \t\t Create new label (discarding the old one).\n"
+	    "\t 'p' \t\t Prints label contents.\n"
+	    "\t 'q' \t\t Quit.\n"
+	    "\t 'r' \t\t Read label from disk.\n"
+	    "\t 'w' \t\t Write label to disk.\n");
+}
+
+void select_label_format(tinput_t *in)
+{
+	printf("Available formats are: \n"
+	    "1) MBR\n"
+	    "2) GPT\n");
+	
+	uint8_t val = get_input_uint8(in);
+	switch (val) {
+	case 1:
+		construct_label(LYT_MBR);
+		break;
+	case 2:
+		construct_label(LYT_GPT);
+		break;
+	default:
+		construct_label(LYT_NONE);
+		break;
+	}
+}
+
+void construct_label(layouts_t layout)
+{
+	switch (layout) {
+	case LYT_MBR:
+		label.layout = LYT_MBR;
+		construct_mbr_label(&label);
+		break;
+	case LYT_GPT:
+		label.layout = LYT_GPT;
+		construct_gpt_label(&label);
+		break;
+	default:
+		label.layout = LYT_NONE;
+		construct_none_label(&label);
+		break;
+	}
+}
+
+void free_label(void)
+{
+	label.destroy_label(&label);
+}
+
+int try_read(void)
+{
+	return label.read_parts(&label);
+}
+
+int try_read_mbr(void)
+{
+	construct_label(LYT_MBR);
+	return try_read();
+}
+
+int try_read_gpt(void)
+{
+	construct_label(LYT_GPT);
+	return try_read();
+}
+
+void set_alignment(tinput_t *in)
+{
+	printf("Set alignment to sectors: ");
+	label.alignment = get_input_uint32(in);
+	printf("Alignment set to %u sectors.\n", label.alignment);
+}
Index: uspace/app/hdisk/hdisk.h
===================================================================
--- uspace/app/hdisk/hdisk.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/hdisk/hdisk.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012-2013 Dominik Taborsky
+ * 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 hdisk
+ * @{
+ */
+/** @file
+ */
+
+#ifndef __HDISK_H__
+#define __HDISK_H__
+
+#include "common.h"
+
+#define init_label() \
+	label.layout = LYT_NONE
+
+#endif
Index: uspace/app/hdisk/input.c
===================================================================
--- uspace/app/hdisk/input.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/hdisk/input.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2012-2013 Dominik Taborsky
+ * 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 hdisk
+ * @{
+ */
+/** @file
+ */
+
+#include <str.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "input.h"
+
+typedef int (*conv_f)(const char *, char **, unsigned int, bool, void *);
+
+static int convert(tinput_t *, conv_f, void *);
+
+int get_input_line(tinput_t *in, char **str)
+{
+	int rc = tinput_read(in, str);
+	if (rc == ENOENT)
+		return EINTR;
+	
+	if (rc != EOK)
+		return rc;
+	
+	/* Check for empty input. */
+	if (str_cmp(*str, "") == 0) {
+		free(*str);
+		*str = NULL;
+		return EINVAL;
+	}
+	
+	return EOK;
+}
+
+uint8_t get_input_uint8(tinput_t *in)
+{
+	uint32_t val;
+	int rc = convert(in, (conv_f) str_uint8_t, &val);
+	if (rc != EOK) {
+		errno = rc;
+		return 0;
+	}
+	
+	errno = EOK;
+	return val;
+}
+
+uint32_t get_input_uint32(tinput_t *in)
+{
+	uint32_t val;
+	int rc = convert(in, (conv_f) str_uint32_t, &val);
+	if (rc != EOK) {
+		errno = rc;
+		return 0;
+	}
+	
+	errno = EOK;
+	return val;
+}
+
+uint64_t get_input_uint64(tinput_t *in)
+{
+	uint64_t val;
+	int rc = convert(in, (conv_f) str_uint64_t, &val);
+	if (rc != EOK) {
+		errno = rc;
+		return 0;
+	}
+	
+	errno = EOK;
+	return val;
+}
+
+size_t get_input_size_t(tinput_t *in)
+{
+	size_t val;
+	int rc = convert(in, (conv_f) str_size_t, &val);
+	if (rc != EOK) {
+		errno = rc;
+		return 0;
+	}
+	
+	errno = EOK;
+	return val;
+}
+
+static int convert(tinput_t *in, conv_f str_f, void *val)
+{
+	char *str;
+	int rc = get_input_line(in, &str);
+	if (rc != EOK) {
+		printf("Error reading input.\n");
+		return rc;
+	}
+	
+	rc = str_f(str, NULL, 10, true, val);
+	if (rc != EOK)
+		printf("Invalid value.\n");
+	
+	free(str);
+	return rc;
+}
Index: uspace/app/hdisk/input.h
===================================================================
--- uspace/app/hdisk/input.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/hdisk/input.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012-2013 Dominik Taborsky
+ * 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 hdisk
+ * @{
+ */
+/** @file
+ */
+
+#ifndef __INPUT_H__
+#define __INPUT_H__
+
+#include <tinput.h>
+
+extern int get_input_line(tinput_t *, char **);
+extern uint8_t get_input_uint8(tinput_t *);
+extern uint32_t get_input_uint32(tinput_t *);
+extern uint64_t get_input_uint64(tinput_t *);
+extern size_t get_input_size_t(tinput_t *);
+
+#endif
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/init/init.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -360,4 +360,6 @@
 	srv_start("/srv/udp");
 	srv_start("/srv/dnsrsrv");
+	srv_start("/srv/dhcp");
+	srv_start("/srv/nconfsrv");
 	
 	srv_start("/srv/clipboard");
Index: uspace/app/netspeed/netspeed.c
===================================================================
--- uspace/app/netspeed/netspeed.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/netspeed/netspeed.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -36,4 +36,9 @@
  */
 
+#include <assert.h>
+#include <inet/dnsr.h>
+#include <net/in.h>
+#include <net/inet.h>
+#include <net/socket.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -41,8 +46,4 @@
 #include <str_error.h>
 #include <task.h>
-
-#include <net/in.h>
-#include <net/inet.h>
-#include <net/socket.h>
 
 #define NAME "netspeed"
@@ -114,19 +115,31 @@
 }
 
-static int client(sock_type_t sock_type, const char *address, unsigned port,
+static int client(sock_type_t sock_type, const char *host, unsigned port,
     unsigned long count, char *buf, size_t bufsize)
 {
-	struct sockaddr_in addr;
-	
-	addr.sin_family = AF_INET;
-	addr.sin_port = htons(port);
-	
-	int rc = inet_pton(AF_INET, address, (void *) &addr.sin_addr.s_addr);
-	if (rc != EOK) {
-		fprintf(stderr, "inet_pton failed: %s\n", str_error(rc));
-		return rc;
-	}
-	
-	int conn_sd = socket(PF_INET, sock_type, 0);
+	inet_addr_t iaddr;
+	struct sockaddr *saddr;
+	socklen_t saddrlen;
+	
+	int rc = inet_addr_parse(host, &iaddr);
+	if (rc != EOK) {
+		dnsr_hostinfo_t *hinfo = NULL;
+		rc = dnsr_name2host(host, &hinfo, ip_any);
+		if (rc != EOK) {
+			fprintf(stderr, "Error resolving host '%s'.\n", host);
+			return ENOENT;
+		}
+		
+		iaddr = hinfo->addr;
+	}
+	
+	rc = inet_addr_sockaddr(&iaddr, port, &saddr, &saddrlen);
+	if (rc != EOK) {
+		assert(rc == ENOMEM);
+		fprintf(stderr, "Out of memory.\n");
+		return ENOMEM;
+	}
+	
+	int conn_sd = socket(saddr->sa_family, sock_type, 0);
 	if (conn_sd < 0) {
 		fprintf(stderr, "socket failed: %s\n", str_error(rc));
@@ -135,5 +148,5 @@
 	
 	if (sock_type == SOCK_STREAM) {
-		rc = connect(conn_sd, (struct sockaddr *) &addr, sizeof(addr));
+		rc = connect(conn_sd, saddr, saddrlen);
 		if (rc != EOK) {
 			fprintf(stderr, "connect failed: %s\n", str_error(rc));
@@ -151,6 +164,5 @@
 			rc = send(conn_sd, buf, bufsize, 0);
 		} else {
-			rc = sendto(conn_sd, buf, bufsize, 0,
-			    (struct sockaddr *) &addr, sizeof(addr));
+			rc = sendto(conn_sd, buf, bufsize, 0, saddr, saddrlen);
 		}
 		if (rc != EOK) {
@@ -161,4 +173,5 @@
 	
 	closesocket(conn_sd);
+	free(saddr);
 	return rc;
 }
@@ -167,5 +180,5 @@
 {
 	fprintf(stderr, "Usage: netspeed <tcp|udp> server [port] <buffer size>\n");
-	fprintf(stderr, "       netspeed <tcp|udp> client <ip> <port> <count> <buffer size>\n");
+	fprintf(stderr, "       netspeed <tcp|udp> client <host> <port> <count> <buffer size>\n");
 }
 
Index: uspace/app/nettest1/nettest1.c
===================================================================
--- uspace/app/nettest1/nettest1.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/nettest1/nettest1.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -38,4 +38,5 @@
 #include "print_error.h"
 
+#include <assert.h>
 #include <malloc.h>
 #include <stdio.h>
@@ -59,5 +60,5 @@
 #define NETTEST1_TEXT  "Networking test 1 - sockets"
 
-static uint16_t family = AF_INET;
+static uint16_t family = AF_NONE;
 static sock_type_t type = SOCK_DGRAM;
 static size_t size = 27;
@@ -326,48 +327,36 @@
 	}
 	
-	char *addr_s = argv[argc - 1];
+	char *host = argv[argc - 1];
 	
 	/* Interpret as address */
-	inet_addr_t addr_addr;
-	rc = inet_addr_parse(addr_s, &addr_addr);
+	inet_addr_t iaddr;
+	rc = inet_addr_parse(host, &iaddr);
 	
 	if (rc != EOK) {
 		/* Interpret as a host name */
 		dnsr_hostinfo_t *hinfo = NULL;
-		rc = dnsr_name2host(addr_s, &hinfo, family);
+		rc = dnsr_name2host(host, &hinfo, ipver_from_af(family));
 		
 		if (rc != EOK) {
-			printf("Error resolving host '%s'.\n", addr_s);
+			printf("Error resolving host '%s'.\n", host);
 			return EINVAL;
 		}
 		
-		addr_addr = hinfo->addr;
-	}
-	
-	struct sockaddr_in addr;
-	struct sockaddr_in6 addr6;
-	uint16_t af = inet_addr_sockaddr_in(&addr_addr, &addr, &addr6);
-	
-	if (af != family) {
+		iaddr = hinfo->addr;
+	}
+	
+	rc = inet_addr_sockaddr(&iaddr, port, &address, &addrlen);
+	if (rc != EOK) {
+		assert(rc == ENOMEM);
+		printf("Out of memory.\n");
+		return ENOMEM;
+	}
+	
+	if (family == AF_NONE)
+		family = address->sa_family;
+	
+	if (address->sa_family != family) {
 		printf("Address family does not match explicitly set family.\n");
 		return EINVAL;
-	}
-	
-	/* Prepare the address buffer */
-	
-	switch (af) {
-	case AF_INET:
-		addr.sin_port = htons(port);
-		address = (struct sockaddr *) &addr;
-		addrlen = sizeof(addr);
-		break;
-	case AF_INET6:
-		addr6.sin6_port = htons(port);
-		address = (struct sockaddr *) &addr6;
-		addrlen = sizeof(addr6);
-		break;
-	default:
-		fprintf(stderr, "Address family is not supported\n");
-		return EAFNOSUPPORT;
 	}
 	
@@ -434,4 +423,6 @@
 	    &time_before));
 	
+	free(address);
+	
 	if (verbose)
 		printf("Exiting\n");
Index: uspace/app/nettest2/nettest2.c
===================================================================
--- uspace/app/nettest2/nettest2.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/nettest2/nettest2.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -38,4 +38,5 @@
 #include "print_error.h"
 
+#include <assert.h>
 #include <malloc.h>
 #include <stdio.h>
@@ -60,5 +61,5 @@
 #define NETTEST2_TEXT  "Networking test 2 - transfer"
 
-static uint16_t family = PF_INET;
+static uint16_t family = AF_NONE;
 static size_t size = 28;
 static bool verbose = false;
@@ -271,5 +272,5 @@
 		/* Interpret as a host name */
 		dnsr_hostinfo_t *hinfo = NULL;
-		rc = dnsr_name2host(addr_s, &hinfo, family);
+		rc = dnsr_name2host(addr_s, &hinfo, ipver_from_af(family));
 		
 		if (rc != EOK) {
@@ -281,32 +282,19 @@
 	}
 	
-	struct sockaddr_in addr;
-	struct sockaddr_in6 addr6;
-	uint16_t af = inet_addr_sockaddr_in(&addr_addr, &addr, &addr6);
-	
-	if (af != family) {
+	struct sockaddr *address;
+	socklen_t addrlen;
+	rc = inet_addr_sockaddr(&addr_addr, port, &address, &addrlen);
+	if (rc != EOK) {
+		assert(rc == ENOMEM);
+		printf("Out of memory.\n");
+		return ENOMEM;
+	}
+	
+	if (family == AF_NONE)
+		family = address->sa_family;
+	
+	if (address->sa_family != family) {
 		printf("Address family does not match explicitly set family.\n");
 		return EINVAL;
-	}
-	
-	/* Prepare the address buffer */
-	
-	struct sockaddr *address;
-	socklen_t addrlen;
-	
-	switch (af) {
-	case AF_INET:
-		addr.sin_port = htons(port);
-		address = (struct sockaddr *) &addr;
-		addrlen = sizeof(addr);
-		break;
-	case AF_INET6:
-		addr6.sin6_port = htons(port);
-		address = (struct sockaddr *) &addr6;
-		addrlen = sizeof(addr6);
-		break;
-	default:
-		fprintf(stderr, "Address family is not supported\n");
-		return EAFNOSUPPORT;
 	}
 	
@@ -424,4 +412,6 @@
 		return rc;
 	
+	free(address);
+	
 	if (verbose)
 		printf("\nExiting\n");
Index: uspace/app/nettest3/nettest3.c
===================================================================
--- uspace/app/nettest3/nettest3.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/nettest3/nettest3.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -37,4 +37,5 @@
 #include <async.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <str.h>
 
@@ -52,5 +53,6 @@
 static char buf[BUF_SIZE];
 
-static struct sockaddr_in addr;
+static struct sockaddr *address;
+static socklen_t addrlen;
 
 static uint16_t port;
@@ -62,4 +64,6 @@
 	char *endptr;
 	dnsr_hostinfo_t *hinfo;
+	inet_addr_t addr;
+	char *addr_s;
 
 	port = 7;
@@ -69,32 +73,33 @@
 
 	/* Connect to local IP address by default */
-	addr.sin_family = AF_INET;
-	addr.sin_port = htons(port);
-	addr.sin_addr.s_addr = htonl(0x7f000001);
+	inet_addr(&addr, 127, 0, 0, 1);
 
 	if (argc >= 2) {
 		printf("parsing address '%s'\n", argv[1]);
-		rc = inet_pton(AF_INET, argv[1], (uint8_t *)&addr.sin_addr.s_addr);
+		rc = inet_addr_parse(argv[1], &addr);
 		if (rc != EOK) {
 			/* Try interpreting as a host name */
-			rc = dnsr_name2host(argv[1], &hinfo, AF_INET);
+			rc = dnsr_name2host(argv[1], &hinfo, ip_v4);
 			if (rc != EOK) {
 				printf("Error resolving host '%s'.\n", argv[1]);
 				return rc;
 			}
-			
-			uint16_t af = inet_addr_sockaddr_in(&hinfo->addr, &addr, NULL);
-			if (af != AF_INET) {
-				printf("Host '%s' not resolved as IPv4 address.\n", argv[1]);
-				return rc;
-			}
+
+			addr = hinfo->addr;
 		}
-		printf("result: rc=%d, family=%d, addr=%x\n", rc,
-		    addr.sin_family, addr.sin_addr.s_addr);
+		rc = inet_addr_format(&addr, &addr_s);
+		if (rc != EOK) {
+			assert(rc == ENOMEM);
+			printf("Out of memory.\n");
+			return rc;
+		}
+		printf("result: rc=%d, ver=%d, addr=%s\n", rc,
+		    addr.version, addr_s);
+		free(addr_s);
 	}
 
 	if (argc >= 3) {
 		printf("parsing port '%s'\n", argv[2]);
-		addr.sin_port = htons(strtoul(argv[2], &endptr, 10));
+		port = htons(strtoul(argv[2], &endptr, 10));
 		if (*endptr != '\0') {
 			fprintf(stderr, "Error parsing port\n");
@@ -103,6 +108,12 @@
 	}
 
+	rc = inet_addr_sockaddr(&hinfo->addr, port, &address, &addrlen);
+	if (rc != EOK) {
+		printf("Out of memory.\n");
+		return rc;
+	}
+
 	printf("socket()\n");
-	fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+	fd = socket(address->sa_family, SOCK_STREAM, IPPROTO_TCP);
 	printf(" -> %d\n", fd);
 	if (fd < 0)
@@ -110,5 +121,5 @@
 
 	printf("connect()\n");
-	rc = connect(fd, (struct sockaddr *) &addr, sizeof(addr));
+	rc = connect(fd, address, addrlen);
 	printf(" -> %d\n", rc);
 	if (rc != 0)
@@ -133,4 +144,6 @@
 	printf(" -> %d\n", rc);
 
+	free(address);
+
 	return 0;
 }
Index: uspace/app/nterm/conn.c
===================================================================
--- uspace/app/nterm/conn.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/nterm/conn.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -38,6 +38,8 @@
 #include <fibril.h>
 #include <inet/dnsr.h>
+#include <net/inet.h>
 #include <net/socket.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <str_error.h>
 #include <sys/types.h>
@@ -73,28 +75,26 @@
 }
 
-int conn_open(const char *addr_s, const char *port_s)
+int conn_open(const char *host, const char *port_s)
 {
 	int conn_fd = -1;
+	struct sockaddr *saddr = NULL;
+	socklen_t saddrlen;
 	
 	/* Interpret as address */
-	inet_addr_t addr_addr;
-	int rc = inet_addr_parse(addr_s, &addr_addr);
+	inet_addr_t iaddr;
+	int rc = inet_addr_parse(host, &iaddr);
 	
 	if (rc != EOK) {
 		/* Interpret as a host name */
 		dnsr_hostinfo_t *hinfo = NULL;
-		rc = dnsr_name2host(addr_s, &hinfo, 0);
+		rc = dnsr_name2host(host, &hinfo, ip_any);
 		
 		if (rc != EOK) {
-			printf("Error resolving host '%s'.\n", addr_s);
+			printf("Error resolving host '%s'.\n", host);
 			goto error;
 		}
 		
-		addr_addr = hinfo->addr;
+		iaddr = hinfo->addr;
 	}
-	
-	struct sockaddr_in addr;
-	struct sockaddr_in6 addr6;
-	uint16_t af = inet_addr_sockaddr_in(&addr_addr, &addr, &addr6);
 	
 	char *endptr;
@@ -105,24 +105,18 @@
 	}
 	
-	printf("Connecting to host %s port %u\n", addr_s, port);
+	rc = inet_addr_sockaddr(&iaddr, port, &saddr, &saddrlen);
+	if (rc != EOK) {
+		assert(rc == ENOMEM);
+		printf("Out of memory.\n");
+		return ENOMEM;
+	}
 	
-	conn_fd = socket(PF_INET, SOCK_STREAM, 0);
+	printf("Connecting to host %s port %u\n", host, port);
+	
+	conn_fd = socket(saddr->sa_family, SOCK_STREAM, 0);
 	if (conn_fd < 0)
 		goto error;
 	
-	switch (af) {
-	case AF_INET:
-		addr.sin_port = htons(port);
-		rc = connect(conn_fd, (struct sockaddr *) &addr, sizeof(addr));
-		break;
-	case AF_INET6:
-		addr6.sin6_port = htons(port);
-		rc = connect(conn_fd, (struct sockaddr *) &addr6, sizeof(addr6));
-		break;
-	default:
-		printf("Unknown address family.\n");
-		goto error;
-	}
-	
+	rc = connect(conn_fd, saddr, saddrlen);
 	if (rc != EOK)
 		goto error;
@@ -134,6 +128,6 @@
 	fibril_add_ready(rcv_fid);
 	
+	free(saddr);
 	return EOK;
-	
 error:
 	if (conn_fd >= 0) {
@@ -141,4 +135,5 @@
 		conn_fd = -1;
 	}
+	free(saddr);
 	
 	return EIO;
Index: uspace/app/ping/ping.c
===================================================================
--- uspace/app/ping/ping.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/ping/ping.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -37,5 +37,4 @@
 #include <errno.h>
 #include <fibril_synch.h>
-#include <net/socket_codes.h>
 #include <inet/dnsr.h>
 #include <inet/addr.h>
@@ -77,15 +76,18 @@
 };
 
-static addr32_t src;
-static addr32_t dest;
+static inet_addr_t src_addr;
+static inet_addr_t dest_addr;
 
 static bool repeat_forever = false;
 static size_t repeat_count = 1;
 
-static const char *short_options = "rn:";
+static const char *short_options = "46rn:";
 
 static void print_syntax(void)
 {
-	printf("Syntax: %s [-n <count>|-r] <host>\n", NAME);
+	printf("Syntax: %s [<options>] <host>\n", NAME);
+	printf("\t-n <count> Repeat the specified number of times\n");
+	printf("\t-r         Repeat forever\n");
+	printf("\t-4|-6      Use IPv4 or IPv6 destination host address\n");
 }
 
@@ -108,10 +110,4 @@
 static int ping_ev_recv(inetping_sdu_t *sdu)
 {
-	inet_addr_t src_addr;
-	inet_addr_set(sdu->src, &src_addr);
-	
-	inet_addr_t dest_addr;
-	inet_addr_set(sdu->dest, &dest_addr);
-	
 	char *asrc;
 	int rc = inet_addr_format(&src_addr, &asrc);
@@ -140,6 +136,6 @@
 	inetping_sdu_t sdu;
 	
-	sdu.src = src;
-	sdu.dest = dest;
+	sdu.src = src_addr;
+	sdu.dest = dest_addr;
 	sdu.seq_no = seq_no;
 	sdu.data = (void *) "foo";
@@ -222,4 +218,5 @@
 	char *adest = NULL;
 	char *sdest = NULL;
+	ip_ver_t ip_ver = ip_any;
 	
 	int rc = inetping_init(&ev_ops);
@@ -244,4 +241,10 @@
 			}
 			break;
+		case '4':
+			ip_ver = ip_v4;
+			break;
+		case '6':
+			ip_ver = ip_v6;
+			break;
 		default:
 			printf("Unknown option passed.\n");
@@ -258,9 +261,8 @@
 	
 	/* Parse destination address */
-	inet_addr_t dest_addr;
 	rc = inet_addr_parse(argv[optind], &dest_addr);
 	if (rc != EOK) {
 		/* Try interpreting as a host name */
-		rc = dnsr_name2host(argv[optind], &hinfo, AF_INET);
+		rc = dnsr_name2host(argv[optind], &hinfo, ip_ver);
 		if (rc != EOK) {
 			printf("Error resolving host '%s'.\n", argv[optind]);
@@ -271,20 +273,10 @@
 	}
 	
-	uint16_t af = inet_addr_get(&dest_addr, &dest, NULL);
-	if (af != AF_INET) {
-		printf("Destination '%s' is not an IPv4 address.\n",
-		    argv[optind]);
-		goto error;
-	}
-	
 	/* Determine source address */
-	rc = inetping_get_srcaddr(dest, &src);
+	rc = inetping_get_srcaddr(&dest_addr, &src_addr);
 	if (rc != EOK) {
 		printf("Failed determining source address.\n");
 		goto error;
 	}
-	
-	inet_addr_t src_addr;
-	inet_addr_set(src, &src_addr);
 	
 	rc = inet_addr_format(&src_addr, &asrc);
Index: uspace/app/ping6/Makefile
===================================================================
--- uspace/app/ping6/Makefile	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,35 +1,0 @@
-#
-# Copyright (c) 2013 Antonin Steinhauser
-# 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 = ping6
-
-SOURCES = \
-	ping6.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/ping6/ping6.c
===================================================================
--- uspace/app/ping6/ping6.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,352 +1,0 @@
-/*
- * Copyright (c) 2013 Antonin Steinhauser
- * 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 ping6
- * @{
- */
-/** @file ICMPv6 echo utility.
- */
-
-#include <async.h>
-#include <stdbool.h>
-#include <errno.h>
-#include <fibril_synch.h>
-#include <net/socket_codes.h>
-#include <inet/dnsr.h>
-#include <inet/addr.h>
-#include <inet/inetping6.h>
-#include <io/console.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <str.h>
-#include <str_error.h>
-#include <sys/types.h>
-
-#define NAME "ping6"
-
-/** Delay between subsequent ping requests in microseconds */
-#define PING_DELAY (1000 * 1000)
-
-/** Ping request timeout in microseconds */
-#define PING_TIMEOUT (1000 * 1000)
-
-typedef enum {
-	RECEIVED_NONE,
-	RECEIVED_SUCCESS,
-	RECEIVED_INTERRUPT
-} received_t;
-
-static received_t received;
-static FIBRIL_CONDVAR_INITIALIZE(received_cv);
-static FIBRIL_MUTEX_INITIALIZE(received_lock);
-
-static bool quit = false;
-static FIBRIL_CONDVAR_INITIALIZE(quit_cv);
-static FIBRIL_MUTEX_INITIALIZE(quit_lock);
-
-static int ping_ev_recv(inetping6_sdu_t *);
-
-static inetping6_ev_ops_t ev_ops = {
-	.recv = ping_ev_recv
-};
-
-static addr128_t src;
-static addr128_t dest;
-
-static bool repeat_forever = false;
-static size_t repeat_count = 1;
-
-static const char *short_options = "rn:";
-
-static void print_syntax(void)
-{
-	printf("Syntax: %s [-n <count>|-r] <host>\n", NAME);
-}
-
-static void ping_signal_received(received_t value)
-{
-	fibril_mutex_lock(&received_lock);
-	received = value;
-	fibril_mutex_unlock(&received_lock);
-	fibril_condvar_broadcast(&received_cv);
-}
-
-static void ping_signal_quit(void)
-{
-	fibril_mutex_lock(&quit_lock);
-	quit = true;
-	fibril_mutex_unlock(&quit_lock);
-	fibril_condvar_broadcast(&quit_cv);
-}
-
-static int ping_ev_recv(inetping6_sdu_t *sdu)
-{
-	inet_addr_t src_addr;
-	inet_addr_set6(sdu->src, &src_addr);
-	
-	inet_addr_t dest_addr;
-	inet_addr_set6(sdu->dest, &dest_addr);
-	
-	char *asrc;
-	int rc = inet_addr_format(&src_addr, &asrc);
-	if (rc != EOK)
-		return ENOMEM;
-	
-	char *adest;
-	rc = inet_addr_format(&dest_addr, &adest);
-	if (rc != EOK) {
-		free(asrc);
-		return ENOMEM;
-	}
-	
-	printf("Received ICMPv6 echo reply: from %s to %s, seq. no %u, "
-	    "payload size %zu\n", asrc, adest, sdu->seq_no, sdu->size);
-	
-	ping_signal_received(RECEIVED_SUCCESS);
-	
-	free(asrc);
-	free(adest);
-	return EOK;
-}
-
-static int ping_send(uint16_t seq_no)
-{
-	inetping6_sdu_t sdu;
-	
-	addr128(src, sdu.src);
-	addr128(dest, sdu.dest);
-	sdu.seq_no = seq_no;
-	sdu.data = (void *) "foo";
-	sdu.size = 3;
-	
-	int rc = inetping6_send(&sdu);
-	if (rc != EOK)
-		printf("Failed sending echo request: %s (%d).\n",
-		    str_error(rc), rc);
-	
-	return rc;
-}
-
-static int transmit_fibril(void *arg)
-{
-	uint16_t seq_no = 0;
-	
-	while ((repeat_count--) || (repeat_forever)) {
-		fibril_mutex_lock(&received_lock);
-		received = RECEIVED_NONE;
-		fibril_mutex_unlock(&received_lock);
-		
-		(void) ping_send(++seq_no);
-		
-		fibril_mutex_lock(&received_lock);
-		int rc = fibril_condvar_wait_timeout(&received_cv, &received_lock,
-		    PING_TIMEOUT);
-		received_t recv = received;
-		fibril_mutex_unlock(&received_lock);
-		
-		if ((rc == ETIMEOUT) || (recv == RECEIVED_NONE))
-			printf("Echo request timed out (seq. no %u)\n", seq_no);
-		
-		if (recv == RECEIVED_INTERRUPT)
-			break;
-		
-		if ((repeat_count > 0) || (repeat_forever)) {
-			fibril_mutex_lock(&received_lock);
-			rc = fibril_condvar_wait_timeout(&received_cv, &received_lock,
-			    PING_DELAY);
-			recv = received;
-			fibril_mutex_unlock(&received_lock);
-			
-			if (recv == RECEIVED_INTERRUPT)
-				break;
-		}
-	}
-	
-	ping_signal_quit();
-	return 0;
-}
-
-static int input_fibril(void *arg)
-{
-	console_ctrl_t *con = console_init(stdin, stdout);
-	
-	while (true) {
-		cons_event_t ev;
-		if (!console_get_event(con, &ev))
-			break;
-		
-		if ((ev.type == CEV_KEY) && (ev.ev.key.type == KEY_PRESS) &&
-		    ((ev.ev.key.mods & (KM_ALT | KM_SHIFT)) == 0) &&
-		    ((ev.ev.key.mods & KM_CTRL) != 0)) {
-			/* Ctrl+key */
-			if (ev.ev.key.key == KC_Q) {
-				ping_signal_received(RECEIVED_INTERRUPT);
-				break;
-			}
-		}
-	}
-	
-	return 0;
-}
-
-int main(int argc, char *argv[])
-{
-	dnsr_hostinfo_t *hinfo = NULL;
-	char *asrc = NULL;
-	char *adest = NULL;
-	char *sdest = NULL;
-	
-	int rc = inetping6_init(&ev_ops);
-	if (rc != EOK) {
-		printf("Failed connecting to internet ping service: "
-		    "%s (%d).\n", str_error(rc), rc);
-		goto error;
-	}
-	
-	int c;
-	while ((c = getopt(argc, argv, short_options)) != -1) {
-		switch (c) {
-		case 'r':
-			repeat_forever = true;
-			break;
-		case 'n':
-			rc = str_size_t(optarg, NULL, 10, true, &repeat_count);
-			if (rc != EOK) {
-				printf("Invalid repeat count.\n");
-				print_syntax();
-				goto error;
-			}
-			break;
-		default:
-			printf("Unknown option passed.\n");
-			print_syntax();
-			goto error;
-		}
-	}
-	
-	if (optind >= argc) {
-		printf("IP address or host name not supplied.\n");
-		print_syntax();
-		goto error;
-	}
-	
-	/* Parse destination address */
-	inet_addr_t dest_addr;
-	rc = inet_addr_parse(argv[optind], &dest_addr);
-	if (rc != EOK) {
-		/* Try interpreting as a host name */
-		rc = dnsr_name2host(argv[optind], &hinfo, AF_INET);
-		if (rc != EOK) {
-			printf("Error resolving host '%s'.\n", argv[optind]);
-			goto error;
-		}
-		
-		dest_addr = hinfo->addr;
-	}
-	
-	uint16_t af = inet_addr_get(&dest_addr, NULL, &dest);
-	if (af != AF_INET6) {
-		printf("Destination '%s' is not an IPv6 address.\n",
-		    argv[optind]);
-		goto error;
-	}
-	
-	/* Determine source address */
-	rc = inetping6_get_srcaddr(dest, src);
-	if (rc != EOK) {
-		printf("Failed determining source address.\n");
-		goto error;
-	}
-	
-	inet_addr_t src_addr;
-	inet_addr_set6(src, &src_addr);
-	
-	rc = inet_addr_format(&src_addr, &asrc);
-	if (rc != EOK) {
-		printf("Out of memory.\n");
-		goto error;
-	}
-	
-	rc = inet_addr_format(&dest_addr, &adest);
-	if (rc != EOK) {
-		printf("Out of memory.\n");
-		goto error;
-	}
-	
-	if (hinfo != NULL) {
-		rc = asprintf(&sdest, "%s (%s)", hinfo->cname, adest);
-		if (rc < 0) {
-			printf("Out of memory.\n");
-			goto error;
-		}
-	} else {
-		sdest = adest;
-		adest = NULL;
-	}
-	
-	printf("Sending ICMP echo request from %s to %s (Ctrl+Q to quit)\n",
-	    asrc, sdest);
-	
-	fid_t fid = fibril_create(transmit_fibril, NULL);
-	if (fid == 0) {
-		printf("Failed creating transmit fibril.\n");
-		goto error;
-	}
-	
-	fibril_add_ready(fid);
-	
-	fid = fibril_create(input_fibril, NULL);
-	if (fid == 0) {
-		printf("Failed creating input fibril.\n");
-		goto error;
-	}
-	
-	fibril_add_ready(fid);
-	
-	fibril_mutex_lock(&quit_lock);
-	while (!quit)
-		fibril_condvar_wait(&quit_cv, &quit_lock);
-	fibril_mutex_unlock(&quit_lock);
-	
-	free(asrc);
-	free(adest);
-	free(sdest);
-	dnsr_hostinfo_destroy(hinfo);
-	return 0;
-	
-error:
-	free(asrc);
-	free(adest);
-	free(sdest);
-	dnsr_hostinfo_destroy(hinfo);
-	return 1;
-}
-
-/** @}
- */
Index: uspace/app/tester/Makefile
===================================================================
--- uspace/app/tester/Makefile	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/tester/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -37,4 +37,5 @@
 	util.c \
 	thread/thread1.c \
+	thread/setjmp1.c \
 	print/print1.c \
 	print/print2.c \
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/tester/tester.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -48,4 +48,5 @@
 test_t tests[] = {
 #include "thread/thread1.def"
+#include "thread/setjmp1.def"
 #include "print/print1.def"
 #include "print/print2.def"
Index: uspace/app/tester/tester.h
===================================================================
--- uspace/app/tester/tester.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/app/tester/tester.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -39,4 +39,5 @@
 #include <stdbool.h>
 #include <stacktrace.h>
+#include <stdio.h>
 
 #define IPC_TEST_SERVICE  10240
@@ -80,4 +81,5 @@
 
 extern const char *test_thread1(void);
+extern const char *test_setjmp1(void);
 extern const char *test_print1(void);
 extern const char *test_print2(void);
Index: uspace/app/tester/thread/setjmp1.c
===================================================================
--- uspace/app/tester/thread/setjmp1.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/tester/thread/setjmp1.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 <setjmp.h>
+#include <stdlib.h>
+#include "../tester.h"
+
+static jmp_buf jmp_env;
+static int counter;
+
+static void do_the_long_jump(void) {
+	TPRINTF("Will do a long jump back to test_it().\n");
+	longjmp(jmp_env, 1);
+}
+
+static const char *test_it(void) {
+	int second_round = setjmp(jmp_env);
+	counter++;
+	TPRINTF("Just after setjmp(), counter is %d.\n", counter);
+	if (second_round) {
+		if (counter != 2) {
+			return "setjmp() have not returned twice";
+		} else {
+			return NULL;
+		}
+	}
+
+	if (counter != 1) {
+		return "Shall not reach here more than once";
+	}
+
+	do_the_long_jump();
+
+	return "Survived a long jump";
+}
+
+const char *test_setjmp1(void)
+{
+	counter = 0;
+	
+	const char *err_msg = test_it();
+	
+	return err_msg;
+}
Index: uspace/app/tester/thread/setjmp1.def
===================================================================
--- uspace/app/tester/thread/setjmp1.def	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/tester/thread/setjmp1.def	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,6 @@
+{
+	"setjmp1",
+	"Long jump test",
+	&test_setjmp1,
+	true
+},
Index: uspace/app/untar/Makefile
===================================================================
--- uspace/app/untar/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/untar/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2013 Vojtech Horky
+# 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 = untar
+
+SOURCES = \
+	main.c \
+	tar.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/untar/main.c
===================================================================
--- uspace/app/untar/main.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/untar/main.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 untar
+ * @{
+ */
+/** @file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <str_error.h>
+#include "tar.h"
+
+static size_t get_block_count(size_t bytes) {
+	return (bytes + TAR_BLOCK_SIZE - 1) / TAR_BLOCK_SIZE;
+}
+
+static int skip_blocks(FILE *tarfile, size_t valid_data_size)
+{
+	size_t blocks_to_read = get_block_count(valid_data_size);
+	while (blocks_to_read > 0) {
+		uint8_t block[TAR_BLOCK_SIZE];
+		size_t actually_read = fread(block, TAR_BLOCK_SIZE, 1, tarfile);
+		if (actually_read != 1) {
+			return errno;
+		}
+		blocks_to_read--;
+	}
+	return EOK;
+}
+
+static int handle_normal_file(const tar_header_t *header, FILE *tarfile)
+{
+	// FIXME: create the directory first
+
+	FILE *file = fopen(header->filename, "wb");
+	if (file == NULL) {
+		fprintf(stderr, "Failed to create %s: %s.\n", header->filename,
+		    str_error(errno));
+		return errno;
+	}
+
+	int rc = EOK;
+	size_t bytes_remaining = header->size;
+	size_t blocks = get_block_count(bytes_remaining);
+	while (blocks > 0) {
+		uint8_t block[TAR_BLOCK_SIZE];
+		size_t actually_read = fread(block, 1, TAR_BLOCK_SIZE, tarfile);
+		if (actually_read != TAR_BLOCK_SIZE) {
+			rc = errno;
+			fprintf(stderr, "Failed to read block for %s: %s.\n",
+			    header->filename, str_error(rc));
+			break;
+		}
+		size_t to_write = TAR_BLOCK_SIZE;
+		if (bytes_remaining < TAR_BLOCK_SIZE) {
+			to_write = bytes_remaining;
+		}
+		size_t actually_written = fwrite(block, 1, to_write, file);
+		if (actually_written != to_write) {
+			rc = errno;
+			fprintf(stderr, "Failed to write to %s: %s.\n",
+			    header->filename, str_error(rc));
+			break;
+		}
+		blocks--;
+		bytes_remaining -= TAR_BLOCK_SIZE;
+	}
+
+	fclose(file);
+
+	return rc;
+}
+
+static int handle_directory(const tar_header_t *header, FILE *tarfile)
+{
+	int rc = mkdir(header->filename, 0755);
+	if ((rc == EEXIST) || (rc == EEXISTS)) {
+		// printf("Note: directory %s already exists.\n", header->filename);
+		rc = EOK;
+	}
+	if (rc != EOK) {
+		fprintf(stderr, "Failed to create directory %s: %s.\n",
+		    header->filename, str_error(rc));
+		return rc;
+	}
+
+	return skip_blocks(tarfile, header->size);
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc != 2) {
+		fprintf(stderr, "Usage: %s tar-file\n", argv[0]);
+		return 1;
+	}
+
+	const char *filename = argv[1];
+
+	FILE *tarfile = fopen(filename, "rb");
+	if (tarfile == NULL) {
+		fprintf(stderr, "Failed to open `%s': %s.\n", filename, str_error(errno));
+		return 2;
+	}
+
+	while (true) {
+		size_t header_ok;
+		tar_header_raw_t header_raw;
+		tar_header_t header;
+		header_ok = fread(&header_raw, sizeof(header_raw), 1, tarfile);
+		if (header_ok != 1) {
+			break;
+		}
+		int rc = tar_header_parse(&header, &header_raw);
+		if (rc == EEMPTY) {
+			continue;
+		}
+		if (rc != EOK) {
+			fprintf(stderr, "Failed parsing TAR header: %s.\n", str_error(rc));
+			break;
+		}
+
+		//printf(" ==> %s (%zuB, type %s)\n", header.filename,
+		//    header.size, tar_type_str(header.type));
+
+		switch (header.type) {
+		case TAR_TYPE_DIRECTORY:
+			rc = handle_directory(&header, tarfile);
+			break;
+		case TAR_TYPE_NORMAL:
+			rc = handle_normal_file(&header, tarfile);
+			break;
+		default:
+			rc = skip_blocks(tarfile, header.size);
+			break;
+		}
+		if (rc != EOK) {
+			break;
+		}
+
+	}
+
+	fclose(tarfile);
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/untar/tar.c
===================================================================
--- uspace/app/untar/tar.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/untar/tar.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 untar
+ * @{
+ */
+/** @file
+ */
+
+#include <str.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "tar.h"
+
+tar_type_t tar_type_parse(const char type) {
+	switch (type) {
+	case '0':
+	case 0:
+		return TAR_TYPE_NORMAL;
+	case '5':
+		return TAR_TYPE_DIRECTORY;
+	default:
+		return TAR_TYPE_UNKNOWN;
+	}
+}
+
+const char *tar_type_str(tar_type_t type) {
+	switch (type) {
+	case TAR_TYPE_UNKNOWN:
+		return "unknown";
+	case TAR_TYPE_NORMAL:
+		return "normal";
+	case TAR_TYPE_DIRECTORY:
+		return "directory";
+	default:
+		assert(false && "unexpected tar_type_t enum value");
+		return "?";
+	}
+}
+
+int tar_header_parse(tar_header_t *parsed, const tar_header_raw_t *raw)
+{
+	int rc;
+
+	if (str_length(raw->filename) == 0) {
+		return EEMPTY;
+	}
+
+	size_t size;
+	rc = str_size_t(raw->size, NULL, 8, true, &size);
+	if (rc != EOK) {
+		return rc;
+	}
+	parsed->size = size;
+
+	str_cpy(parsed->filename, 100, raw->filename);
+
+	parsed->type = tar_type_parse(raw->type);
+
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/app/untar/tar.h
===================================================================
--- uspace/app/untar/tar.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/untar/tar.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 untar
+ * @{
+ */
+/** @file
+ */
+#ifndef TAR_H_GUARD
+#define TAR_H_GUARD
+
+#define TAR_BLOCK_SIZE 512
+
+typedef struct tar_header_raw {
+	char filename[100];
+	char permissions[8];
+	char owner[8];
+	char group[8];
+	char size[12];
+	char modification_time[12];
+	char checksum[8];
+	char type;
+	char name[100];
+	char ustar_magic[6];
+	char ustar_version[2];
+	char ustar_owner_name[32];
+	char ustar_group_name[32];
+	char ustar_device_major[8];
+	char ustar_device_minor[8];
+	char ustar_prefix[155];
+	char ignored[12];
+} tar_header_raw_t;
+
+typedef enum tar_type {
+	TAR_TYPE_UNKNOWN,
+	TAR_TYPE_NORMAL,
+	TAR_TYPE_DIRECTORY
+} tar_type_t;
+
+typedef struct tar_header {
+	char filename[100];
+	size_t size;
+	tar_type_t type;
+} tar_header_t;
+
+
+extern int tar_header_parse(tar_header_t *, const tar_header_raw_t *);
+extern tar_type_t tar_type_parse(const char);
+extern const char *tar_type_str(tar_type_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/viewer/Makefile
===================================================================
--- uspace/app/viewer/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/viewer/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2013 Martin Decky
+# 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 = ../..
+LIBS = $(LIBGUI_PREFIX)/libgui.a $(LIBDRAW_PREFIX)/libdraw.a \
+	$(LIBSOFTREND_PREFIX)/libsoftrend.a $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
+EXTRA_CFLAGS += -I$(LIBGUI_PREFIX) -I$(LIBDRAW_PREFIX) \
+	-I$(LIBSOFTREND_PREFIX)
+BINARY = viewer
+
+SOURCES = \
+	viewer.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/viewer/viewer.c
===================================================================
--- uspace/app/viewer/viewer.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/app/viewer/viewer.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2013 Martin Decky
+ * 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 viewer
+ * @{
+ */
+/** @file
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stdbool.h>
+#include <window.h>
+#include <canvas.h>
+#include <surface.h>
+#include <codec/tga.h>
+
+#define NAME  "viewer"
+
+#define WINDOW_WIDTH   1024
+#define WINDOW_HEIGHT  768
+
+static size_t imgs_count;
+static size_t imgs_current = 0;
+static char **imgs;
+
+static window_t *main_window;
+static surface_t *surface = NULL;
+static canvas_t *canvas = NULL;
+
+static bool img_load(const char *);
+
+static void on_keyboard_event(widget_t *widget, void *data)
+{
+	kbd_event_t *event = (kbd_event_t *) data;
+	bool update = false;
+	
+	if ((event->type == KEY_PRESS) && (event->c == 'q'))
+		exit(0);
+	
+	if ((event->type == KEY_PRESS) && (event->key == KC_PAGE_DOWN)) {
+		if (imgs_current == imgs_count - 1)
+			imgs_current = 0;
+		else
+			imgs_current++;
+		
+		update = true;
+	}
+	
+	if ((event->type == KEY_PRESS) && (event->key == KC_PAGE_UP)) {
+		if (imgs_current == 0)
+			imgs_current = imgs_count - 1;
+		else
+			imgs_current--;
+		
+		update = true;
+	}
+	
+	if (update) {
+		if (!img_load(imgs[imgs_current])) {
+			printf("Cannot load image \"%s\".\n", imgs[imgs_current]);
+			exit(2);
+		}
+	}
+}
+
+static bool img_load(const char *fname)
+{
+	int fd = open(fname, O_RDONLY);
+	if (fd < 0)
+		return false;
+	
+	struct stat stat;
+	int rc = fstat(fd, &stat);
+	if (rc != EOK) {
+		close(fd);
+		return false;
+	}
+	
+	void *tga = malloc(stat.size);
+	if (tga == NULL) {
+		close(fd);
+		return false;
+	}
+	
+	ssize_t rd = read_all(fd, tga, stat.size);
+	if ((rd < 0) || (rd != (ssize_t) stat.size)) {
+		free(tga);
+		close(fd);
+		return false;
+	}
+	
+	close(fd);
+	
+	surface_t *local_surface = decode_tga(tga, stat.size, 0);
+	if (local_surface == NULL) {
+		free(tga);
+		return false;
+	}
+	
+	free(tga);
+	
+	if (canvas != NULL) {
+		if (!update_canvas(canvas, local_surface)) {
+			surface_destroy(local_surface);
+			return false;
+		}
+	} else {
+		canvas = create_canvas(window_root(main_window),
+		    WINDOW_WIDTH, WINDOW_HEIGHT, local_surface);
+		if (canvas == NULL) {
+			surface_destroy(local_surface);
+			return false;
+		}
+		
+		sig_connect(&canvas->keyboard_event, NULL, on_keyboard_event);
+	}
+	
+	if (surface != NULL)
+		surface_destroy(surface);
+	
+	surface = local_surface;
+	
+	return true;
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc < 2) {
+		printf("Compositor server not specified.\n");
+		return 1;
+	}
+	
+	if (argc < 3) {
+		printf("No image files specified.\n");
+		return 1;
+	}
+	
+	main_window = window_open(argv[1], true, false, "viewer", 0, 0);
+	if (!main_window) {
+		printf("Cannot open main window.\n");
+		return 2;
+	}
+	
+	imgs_count = argc - 2;
+	imgs = calloc(imgs_count, sizeof(char *));
+	if (imgs == NULL) {
+		printf("Out of memory.\n");
+		return 3;
+	}
+	
+	for (int i = 0; i < argc - 2; i++) {
+		imgs[i] = str_dup(argv[i + 2]);
+		if (imgs[i] == NULL) {
+			printf("Out of memory.\n");
+			return 4;
+		}
+	}
+	
+	if (!img_load(imgs[imgs_current])) {
+		printf("Cannot load image \"%s\".\n", imgs[imgs_current]);
+		return 2;
+	}
+	
+	window_resize(main_window, WINDOW_WIDTH, WINDOW_HEIGHT);
+	window_exec(main_window);
+	
+	task_retval(0);
+	async_manager();
+	
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/dist/src/c/demos/hello/build.gcc
===================================================================
--- uspace/dist/src/c/demos/hello/build.gcc	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/dist/src/c/demos/hello/build.gcc	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,2 @@
+gcc -nostdlib -nostdinc -I/inc/c -Wl,-T/inc/_link.ld -L/lib -lc -lsoftint -o hello hello.c
+
Index: uspace/dist/src/c/demos/tetris/build.gcc
===================================================================
--- uspace/dist/src/c/demos/tetris/build.gcc	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/dist/src/c/demos/tetris/build.gcc	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,6 @@
+gcc -nostdinc -I/inc/c -c -Drestrict= scores.c
+gcc -nostdinc -I/inc/c -c -Drestrict= screen.c
+gcc -nostdinc -I/inc/c -c -Drestrict= shapes.c
+gcc -nostdinc -I/inc/c -c -Drestrict= tetris.c
+gcc -nostdlib -Wl,-T/inc/_link.ld -L/lib -o tetris_ scores.o screen.o shapes.o tetris.o -lc -lsoftint
+
Index: uspace/dist/src/c/demos/tetris/screen.c
===================================================================
--- uspace/dist/src/c/demos/tetris/screen.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/dist/src/c/demos/tetris/screen.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -344,7 +344,7 @@
 	
 	while (timeout > 0) {
-		kbd_event_t event;
-		
-		if (!console_get_kbd_event_timeout(console, &event, &timeout))
+		cons_event_t event;
+		
+		if (!console_get_event_timeout(console, &event, &timeout))
 			break;
 	}
@@ -376,13 +376,13 @@
 	
 	while (c == 0) {
-		kbd_event_t event;
-		
-		if (!console_get_kbd_event_timeout(console, &event, &timeleft)) {
+		cons_event_t event;
+		
+		if (!console_get_event_timeout(console, &event, &timeleft)) {
 			timeleft = 0;
 			return -1;
 		}
 		
-		if (event.type == KEY_PRESS)
-			c = event.c;
+		if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
+			c = event.ev.key.c;
 	}
 	
@@ -398,11 +398,11 @@
 	
 	while (c == 0) {
-		kbd_event_t event;
-		
-		if (!console_get_kbd_event(console, &event))
+		cons_event_t event;
+		
+		if (!console_get_event(console, &event))
 			return -1;
 		
-		if (event.type == KEY_PRESS)
-			c = event.c;
+		if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS)
+			c = event.ev.key.c;
 	}
 	
Index: uspace/dist/src/python/demo/hello.py
===================================================================
--- uspace/dist/src/python/demo/hello.py	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/dist/src/python/demo/hello.py	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,4 @@
+#!/usr/bin/python
+
+print("Hello, World!")
+
Index: uspace/dist/src/python/demo/sintab.py
===================================================================
--- uspace/dist/src/python/demo/sintab.py	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/dist/src/python/demo/sintab.py	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+
+# Probably not very Pythonic, but it runs well with both Python2 and Python3
+
+import math
+import sys
+
+sys.stdout.write("    ")
+for frac_part in range(0,10):
+	sys.stdout.write(" %5d" % frac_part)
+print("")
+
+for angle_deg in range(0,90):
+	sys.stdout.write("%3d " % angle_deg)
+	for angle_deg_frac in range(0,10):
+		angle = math.radians(angle_deg + angle_deg_frac/10.)
+		value = math.sin(angle) * 10000 + 0.5
+		if value > 10000:
+			sys.stdout.write(" %05d" % (value))
+		else:
+			sys.stdout.write("  %04d" % (value))
+	print("")
+
Index: uspace/dist/src/python/modules.py
===================================================================
--- uspace/dist/src/python/modules.py	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/dist/src/python/modules.py	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,15 @@
+#!/usr/bin/python
+
+import sys
+
+for m in sys.builtin_module_names:
+	print("Built-in module '%s'." % m)
+
+try:
+	import pkgutil
+	for (loader, name, ispkg) in pkgutil.iter_modules():
+		print("Loadable module '%s'." % name)
+except ImportError:
+	print("Cannot determine list of loadable modules (pkgutil not found)!")
+
+
Index: uspace/drv/block/ata_bd/ata_bd.c
===================================================================
--- uspace/drv/block/ata_bd/ata_bd.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/drv/block/ata_bd/ata_bd.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -1132,5 +1132,4 @@
 	cnt = 100;
 	while ((status & ~n_reset) != 0 || (status & set) != set) {
-		async_usleep(1);
 		--cnt;
 		if (cnt <= 0) break;
Index: uspace/drv/bus/amba/Makefile
===================================================================
--- uspace/drv/bus/amba/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/drv/bus/amba/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Lenka Trochtova
+# 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 = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = amba
+
+SOURCES = \
+	amba.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/bus/amba/amba.c
===================================================================
--- uspace/drv/bus/amba/amba.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/drv/bus/amba/amba.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2013 Jakub Klama
+ * 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.
+ */
+
+/**
+ * @defgroup amba AMBA bus driver.
+ * @brief HelenOS AMBA bus driver.
+ * @{
+ */
+/** @file
+ */
+
+#include <assert.h>
+#include <byteorder.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <fibril_synch.h>
+#include <str.h>
+#include <ctype.h>
+#include <macros.h>
+#include <str_error.h>
+#include <ddf/driver.h>
+#include <ddf/log.h>
+#include <ipc/dev_iface.h>
+#include <ipc/irc.h>
+#include <ns.h>
+#include <ipc/services.h>
+#include <sysinfo.h>
+#include <ops/hw_res.h>
+#include <device/hw_res.h>
+#include <ddi.h>
+#include "ambapp.h"
+
+#define NAME  "amba"
+#define ID_MAX_STR_LEN  32
+
+#define LVL_DEBUG  LVL_ERROR
+
+typedef struct leon_amba_bus {
+	/** DDF device node */
+	ddf_dev_t *dnode;
+	uintptr_t master_area_addr;
+	uintptr_t slave_area_addr;
+	size_t master_area_size;
+	size_t slave_area_size;
+	void *master_area;
+	void *slave_area;
+	fibril_mutex_t area_mutex;
+} amba_bus_t;
+
+typedef struct amba_fun_data {
+	amba_bus_t *busptr;
+	ddf_fun_t *fnode;
+	int bus;
+	int index;
+	uint8_t vendor_id;
+	uint32_t device_id;
+	int version;
+	hw_resource_list_t hw_resources;
+	hw_resource_t resources[AMBA_MAX_HW_RES];
+} amba_fun_t;
+
+static amba_fun_t *amba_fun_new(amba_bus_t *);
+static void amba_fun_set_name(amba_fun_t *);
+static void amba_fun_create_match_ids(amba_fun_t *);
+static int amba_fun_online(ddf_fun_t *);
+static int amba_fun_offline(ddf_fun_t *);
+static hw_resource_list_t *amba_get_resources(ddf_fun_t *);
+static bool amba_enable_interrupt(ddf_fun_t *);
+static void amba_add_bar(amba_fun_t *, uintptr_t, size_t);
+static void amba_add_interrupt(amba_fun_t *, int);
+static int amba_bus_scan(amba_bus_t *, void *, unsigned int);
+static void amba_fake_scan(amba_bus_t *);
+static int amba_dev_add(ddf_dev_t *);
+
+static hw_res_ops_t amba_fun_hw_res_ops = {
+	.get_resource_list = &amba_get_resources,
+	.enable_interrupt = &amba_enable_interrupt
+};
+
+static ddf_dev_ops_t amba_fun_ops = {
+	.interfaces[HW_RES_DEV_IFACE] = &amba_fun_hw_res_ops
+};
+
+static driver_ops_t amba_ops = {
+	.dev_add = &amba_dev_add,
+	.fun_online = &amba_fun_online,
+	.fun_offline = &amba_fun_offline
+};
+
+static driver_t amba_driver = {
+	.name = NAME,
+	.driver_ops = &amba_ops
+};
+
+static amba_fun_t *amba_fun_new(amba_bus_t *bus)
+{
+	ddf_msg(LVL_DEBUG, "amba_fun_new(): bus=%p, bus->dnode=%p", bus,
+	    bus->dnode);
+	
+	ddf_fun_t *fnode = ddf_fun_create(bus->dnode, fun_inner, NULL);
+	if (fnode == NULL)
+		return NULL;
+	
+	ddf_msg(LVL_DEBUG, "amba_fun_new(): created");
+	
+	amba_fun_t *fun = ddf_fun_data_alloc(fnode, sizeof(amba_fun_t));
+	if (fun == NULL)
+		return NULL;
+	
+	ddf_msg(LVL_DEBUG, "amba_fun_new(): allocated data");
+	
+	fun->busptr = bus;
+	fun->fnode = fnode;
+	return fun;
+}
+
+static void amba_fun_set_name(amba_fun_t *fun)
+{
+	char *name = NULL;
+	
+	asprintf(&name, "%02x:%02x", fun->bus, fun->index);
+	ddf_fun_set_name(fun->fnode, name);
+}
+
+static void amba_fun_create_match_ids(amba_fun_t *fun)
+{
+	/* Vendor ID & Device ID */
+	char match_id_str[ID_MAX_STR_LEN];
+	int rc = snprintf(match_id_str, ID_MAX_STR_LEN, "amba/ven=%02x&dev=%08x",
+	    fun->vendor_id, fun->device_id);
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
+		    str_error(rc));
+	}
+	
+	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 90);
+}
+
+static int amba_fun_online(ddf_fun_t *fun)
+{
+	ddf_msg(LVL_DEBUG, "amba_fun_online()");
+	return ddf_fun_online(fun);
+
+}
+
+static int amba_fun_offline(ddf_fun_t *fun)
+{
+	ddf_msg(LVL_DEBUG, "amba_fun_offline()");
+	return ddf_fun_offline(fun);
+}
+
+static hw_resource_list_t *amba_get_resources(ddf_fun_t *fnode)
+{
+	amba_fun_t *fun = ddf_fun_data_get(fnode);
+	
+	if (fun == NULL)
+		return NULL;
+	
+	return &fun->hw_resources;
+}
+
+static bool amba_enable_interrupt(ddf_fun_t *fnode)
+{
+	return true;
+}
+
+static void amba_alloc_resource_list(amba_fun_t *fun)
+{
+	fun->hw_resources.resources = fun->resources;
+}
+
+static void amba_add_bar(amba_fun_t *fun, uintptr_t addr, size_t size)
+{
+	hw_resource_list_t *hw_res_list = &fun->hw_resources;
+	hw_resource_t *hw_resources =  hw_res_list->resources;
+	size_t count = hw_res_list->count;
+	
+	assert(hw_resources != NULL);
+	assert(count < AMBA_MAX_HW_RES);
+	
+	hw_resources[count].type = MEM_RANGE;
+	hw_resources[count].res.mem_range.address = addr;
+	hw_resources[count].res.mem_range.size = size;
+	hw_resources[count].res.mem_range.endianness = BIG_ENDIAN;
+	
+	hw_res_list->count++;
+}
+
+static void amba_add_interrupt(amba_fun_t *fun, int irq)
+{
+	hw_resource_list_t *hw_res_list = &fun->hw_resources;
+	hw_resource_t *hw_resources = hw_res_list->resources;
+	size_t count = hw_res_list->count;
+	
+	assert(NULL != hw_resources);
+	assert(count < AMBA_MAX_HW_RES);
+	
+	hw_resources[count].type = INTERRUPT;
+	hw_resources[count].res.interrupt.irq = irq;
+	
+	hw_res_list->count++;
+	
+	ddf_msg(LVL_NOTE, "Function %s uses irq %x.", ddf_fun_get_name(fun->fnode), irq);
+}
+
+static int amba_bus_scan(amba_bus_t *bus, void *area, unsigned int max_entries)
+{
+	ddf_msg(LVL_DEBUG, "amba_bus_scan(): area=%p, max_entries=%u", area, max_entries);
+	
+	ambapp_entry_t *devices = (ambapp_entry_t *) area;
+	int found = 0;
+	
+	for (unsigned int i = 0; i < max_entries; i++) {
+		ambapp_entry_t *entry = &devices[i];
+		if (entry->vendor_id == 0xff)
+			continue;
+		
+		amba_fun_t *fun = amba_fun_new(bus);
+		fun->bus = 0;
+		fun->index = i;
+		fun->vendor_id = entry->vendor_id;
+		fun->device_id = entry->device_id;
+		fun->version = entry->version;
+		
+		for (unsigned int bnum = 0; bnum < 4; bnum++) {
+			ambapp_bar_t *bar = &entry->bar[bnum];
+			amba_add_bar(fun, bar->addr << 20, bar->mask);
+		}
+		
+		if (entry->irq != -1)
+			amba_add_interrupt(fun, entry->irq);
+		
+		ddf_fun_set_ops(fun->fnode, &amba_fun_ops);
+		ddf_fun_bind(fun->fnode);
+	}
+	
+	return found;
+}
+
+static void amba_fake_scan(amba_bus_t *bus)
+{
+	ddf_msg(LVL_DEBUG, "amba_fake_scan()");
+	
+	/* UART */
+	amba_fun_t *fun = amba_fun_new(bus);
+	fun->bus = 0;
+	fun->index = 0;
+	fun->vendor_id = GAISLER;
+	fun->device_id = GAISLER_APBUART;
+	fun->version = 1;
+	amba_alloc_resource_list(fun);
+	amba_add_bar(fun, 0x80000100, 0x100);
+	amba_add_interrupt(fun, 3);
+	amba_fun_set_name(fun);
+	amba_fun_create_match_ids(fun);
+	ddf_fun_set_ops(fun->fnode, &amba_fun_ops);
+	ddf_fun_bind(fun->fnode);
+	
+	ddf_msg(LVL_DEBUG, "added uart");
+	
+	/* IRQMP */
+	fun = amba_fun_new(bus);
+	fun->bus = 0;
+	fun->index = 1;
+	fun->vendor_id = GAISLER;
+	fun->device_id = GAISLER_IRQMP;
+	fun->version = 1;
+	amba_alloc_resource_list(fun);
+	amba_add_bar(fun, 0x80000200, 0x100);
+	amba_fun_set_name(fun);
+	amba_fun_create_match_ids(fun);
+	ddf_fun_set_ops(fun->fnode, &amba_fun_ops);
+	ddf_fun_bind(fun->fnode);
+	
+	ddf_msg(LVL_DEBUG, "added irqmp");
+	
+	/* GPTIMER */
+	fun = amba_fun_new(bus);
+	fun->bus = 0;
+	fun->index = 2;
+	fun->vendor_id = GAISLER;
+	fun->device_id = GAISLER_GPTIMER;
+	fun->version = 1;
+	amba_alloc_resource_list(fun);
+	amba_add_bar(fun, 0x80000300, 0x100);
+	amba_add_interrupt(fun, 8);
+	amba_fun_set_name(fun);
+	amba_fun_create_match_ids(fun);
+	ddf_fun_set_ops(fun->fnode, &amba_fun_ops);
+	ddf_fun_bind(fun->fnode);
+	
+	ddf_msg(LVL_DEBUG, "added timer");
+}
+
+static int amba_dev_add(ddf_dev_t *dnode)
+{
+	int rc = 0;
+	int found = 0;
+	bool got_res = false;
+	
+	amba_bus_t *bus = ddf_dev_data_alloc(dnode, sizeof(amba_bus_t));
+	if (bus == NULL) {
+		ddf_msg(LVL_ERROR, "amba_dev_add: allocation failed.");
+		rc = ENOMEM;
+		goto fail;
+	}
+	
+	bus->dnode = dnode;
+	async_sess_t *sess = ddf_dev_parent_sess_create(dnode, EXCHANGE_SERIALIZE);
+	if (sess == NULL) {
+		ddf_msg(LVL_ERROR, "amba_dev_add failed to connect to the "
+		    "parent driver.");
+		rc = ENOENT;
+		goto fail;
+	}
+	
+	hw_resource_list_t hw_resources;
+	rc = hw_res_get_resource_list(sess, &hw_resources);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "amba_dev_add failed to get hw resources "
+		    "for the device.");
+		goto fail;
+	}
+	
+	got_res = true;
+	assert(hw_resources.count > 1);
+	
+	bus->master_area_addr = hw_resources.resources[0].res.mem_range.address;
+	bus->master_area_size = hw_resources.resources[0].res.mem_range.size;
+	bus->slave_area_addr = hw_resources.resources[1].res.mem_range.address;
+	bus->slave_area_size = hw_resources.resources[1].res.mem_range.size;
+	
+	ddf_msg(LVL_DEBUG, "AMBA master area: 0x%08x", bus->master_area_addr);
+	ddf_msg(LVL_DEBUG, "AMBA slave area: 0x%08x", bus->slave_area_addr);
+	
+	if (pio_enable((void *)bus->master_area_addr, bus->master_area_size, &bus->master_area)) {
+		ddf_msg(LVL_ERROR, "Failed to enable master area.");
+		rc = EADDRNOTAVAIL;
+		goto fail;
+	}
+	
+	if (pio_enable((void *)bus->slave_area_addr, bus->slave_area_size, &bus->slave_area)) {
+		ddf_msg(LVL_ERROR, "Failed to enable slave area.");
+		rc = EADDRNOTAVAIL;
+		goto fail;
+	}
+	
+	/*
+	 * If nothing is found, we are probably running inside QEMU
+	 * and need to fake AMBA P&P entries.
+	 */
+	if (found == 0)
+		amba_fake_scan(bus);
+	
+	ddf_msg(LVL_DEBUG, "done");
+	
+	return EOK;
+	
+fail:
+	if (got_res)
+		hw_res_clean_resource_list(&hw_resources);
+	
+	return rc;
+}
+
+int main(int argc, char *argv[])
+{
+	printf("%s: HelenOS LEON3 AMBA bus driver\n", NAME);
+	ddf_log_init(NAME);
+	return ddf_driver_main(&amba_driver);
+}
Index: uspace/drv/bus/amba/amba.ma
===================================================================
--- uspace/drv/bus/amba/amba.ma	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/drv/bus/amba/amba.ma	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,1 @@
+10 amba
Index: uspace/drv/bus/amba/ambapp.h
===================================================================
--- uspace/drv/bus/amba/ambapp.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/drv/bus/amba/ambapp.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2011 Jiri Svoboda
+ * Copyright (c) 2013 Jakub Klama
+ * 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 amba
+ * @{
+ */
+/** @file
+ */
+
+#ifndef AMBAPP_H_
+#define AMBAPP_H_
+
+#include <ddf/driver.h>
+
+#define AMBAPP_MAX_DEVICES     64
+#define AMBAPP_AHBMASTER_AREA  0xfffff000
+#define AMBAPP_AHBSLAVE_AREA   0xfffff800
+#define AMBAPP_CONF_AREA       0xff000
+
+#define AMBA_MAX_HW_RES  (4 + 1)
+
+typedef enum {
+	GAISLER = 1,
+	ESA = 4
+} amba_vendor_id_t;
+
+typedef enum {
+	GAISLER_LEON3    = 0x003,
+	GAISLER_LEON3DSU = 0x004,
+	GAISLER_ETHAHB   = 0x005,
+	GAISLER_APBMST   = 0x006,
+	GAISLER_AHBUART  = 0x007,
+	GAISLER_SRCTRL   = 0x008,
+	GAISLER_SDCTRL   = 0x009,
+	GAISLER_APBUART  = 0x00c,
+	GAISLER_IRQMP    = 0x00d,
+	GAISLER_AHBRAM   = 0x00e,
+	GAISLER_GPTIMER  = 0x011,
+	GAISLER_PCITRG   = 0x012,
+	GAISLER_PCISBRG  = 0x013,
+	GAISLER_PCIFBRG  = 0x014,
+	GAISLER_PCITRACE = 0x015,
+	GAISLER_PCIDMA   = 0x016,
+	GAISLER_AHBTRACE = 0x017,
+	GAISLER_ETHDSU   = 0x018,
+	GAISLER_PIOPORT  = 0x01a,
+	GAISLER_AHBJTAG  = 0x01c,
+	GAISLER_SPW      = 0x01f,
+	GAISLER_ATACTRL  = 0x024,
+	GAISLER_VGA      = 0x061,
+	GAISLER_KBD      = 0x060,
+	GAISLER_ETHMAC   = 0x01d,
+	GAISLER_DDRSPA   = 0x025,
+	GAISLER_EHCI     = 0x026,
+	GAISLER_UHCI     = 0x027,
+	GAISLER_SPW2     = 0x029,
+	GAISLER_DDR2SPA  = 0x02e,
+	GAISLER_AHBSTAT  = 0x052,
+	GAISLER_FTMCTRL  = 0x054,
+	ESA_MCTRL        = 0x00f
+} amba_device_id_t;
+
+typedef struct {
+	unsigned int addr : 12;
+	unsigned int reserved : 2;
+	unsigned int prefetchable : 1;
+	unsigned int cacheable : 1;
+	unsigned int mask : 12;
+	unsigned int type : 4;
+} __attribute__((packed)) ambapp_bar_t;
+
+typedef struct {
+	unsigned int vendor_id : 8;
+	unsigned int device_id : 24;
+	unsigned int reserved : 2;
+	unsigned int version : 5;
+	unsigned int irq : 5;
+	uint32_t user_defined[3];
+	ambapp_bar_t bar[4];
+} __attribute__((packed)) ambapp_entry_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/char/grlib_uart/Makefile
===================================================================
--- uspace/drv/char/grlib_uart/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/drv/char/grlib_uart/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2013 Jakub Klama
+# 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 = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = grlib_uart
+
+SOURCES = \
+	grlib_uart.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/char/grlib_uart/cyclic_buffer.h
===================================================================
--- uspace/drv/char/grlib_uart/cyclic_buffer.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/drv/char/grlib_uart/cyclic_buffer.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2010 Lenka Trochtova
+ * 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 ns8250
+ * @{
+ */
+/** @file
+ */
+
+#ifndef CYCLIC_BUFFER_H_
+#define CYCLIC_BUFFER_H_
+
+#define BUF_LEN 4096
+
+typedef struct cyclic_buffer {
+	uint8_t buf[BUF_LEN];
+	int start;
+	int cnt;
+}  cyclic_buffer_t;
+
+/*
+ * @return		False if the buffer is full.
+ */
+static inline bool buf_push_back(cyclic_buffer_t *buf, uint8_t item)
+{
+	if (buf->cnt >= BUF_LEN)
+		return false;
+	
+	int pos = (buf->start + buf->cnt) % BUF_LEN;
+	buf->buf[pos] = item;
+	buf->cnt++;
+	return true;
+}
+
+static inline bool buf_is_empty(cyclic_buffer_t *buf)
+{
+	return buf->cnt == 0;
+}
+
+static inline uint8_t buf_pop_front(cyclic_buffer_t *buf)
+{
+	assert(!buf_is_empty(buf));
+	
+	uint8_t res = buf->buf[buf->start];
+	buf->start = (buf->start + 1) % BUF_LEN;
+	buf->cnt--;
+	return res;
+}
+
+static inline void buf_clear(cyclic_buffer_t *buf)
+{
+	buf->cnt = 0;
+}
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/char/grlib_uart/grlib_uart.c
===================================================================
--- uspace/drv/char/grlib_uart/grlib_uart.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/drv/char/grlib_uart/grlib_uart.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,872 @@
+/*
+ * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2011 Jiri Svoboda
+ * Copyright (c) 2013 Jakub Klama
+ * 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.
+ */
+
+/**
+ * @defgroup grlib_uart Serial port driver.
+ * @brief HelenOS serial port driver.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <fibril_synch.h>
+#include <stdlib.h>
+#include <str.h>
+#include <ctype.h>
+#include <macros.h>
+#include <malloc.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <ddi.h>
+
+#include <ddf/driver.h>
+#include <ddf/interrupt.h>
+#include <ddf/log.h>
+#include <ops/char_dev.h>
+
+#include <ns.h>
+#include <ipc/services.h>
+#include <ipc/irc.h>
+#include <device/hw_res.h>
+#include <ipc/serial_ctl.h>
+
+#include "cyclic_buffer.h"
+
+#define NAME "grlib_uart"
+
+#define REG_COUNT 5
+#define MAX_BAUD_RATE 115200
+
+#define LVL_DEBUG LVL_ERROR
+
+#define GRLIB_UART_STATUS_DR  (1 << 0)
+#define GRLIB_UART_STATUS_TS  (1 << 1)
+#define GRLIB_UART_STATUS_TE  (1 << 2)
+#define GRLIB_UART_STATUS_BR  (1 << 3)
+#define GRLIB_UART_STATUS_OV  (1 << 4)
+#define GRLIB_UART_STATUS_PE  (1 << 5)
+#define GRLIB_UART_STATUS_FE  (1 << 6)
+#define GRLIB_UART_STATUS_TH  (1 << 7)
+#define GRLIB_UART_STATUS_RH  (1 << 8)
+#define GRLIB_UART_STATUS_TF  (1 << 9)
+#define GRLIB_UART_STATUS_RF  (1 << 10)
+
+#define GRLIB_UART_CONTROL_RE  (1 << 0)
+#define GRLIB_UART_CONTROL_TE  (1 << 1)
+#define GRLIB_UART_CONTROL_RI  (1 << 2)
+#define GRLIB_UART_CONTROL_TI  (1 << 3)
+#define GRLIB_UART_CONTROL_PS  (1 << 4)
+#define GRLIB_UART_CONTROL_PE  (1 << 5)
+#define GRLIB_UART_CONTROL_FL  (1 << 6)
+#define GRLIB_UART_CONTROL_LB  (1 << 7)
+#define GRLIB_UART_CONTROL_EC  (1 << 8)
+#define GRLIB_UART_CONTROL_TF  (1 << 9)
+#define GRLIB_UART_CONTROL_RF  (1 << 10)
+#define GRLIB_UART_CONTROL_DB  (1 << 11)
+#define GRLIB_UART_CONTROL_BI  (1 << 12)
+#define GRLIB_UART_CONTROL_DI  (1 << 13)
+#define GRLIB_UART_CONTROL_SI  (1 << 14)
+#define GRLIB_UART_CONTROL_FA  (1 << 31)
+
+typedef struct {
+	unsigned int fa : 1;
+	unsigned int : 16;
+	unsigned int si : 1;
+	unsigned int di : 1;
+	unsigned int bi : 1;
+	unsigned int db : 1;
+	unsigned int rf : 1;
+	unsigned int tf : 1;
+	unsigned int ec : 1;
+	unsigned int lb : 1;
+	unsigned int fl : 1;
+	unsigned int pe : 1;
+	unsigned int ps : 1;
+	unsigned int ti : 1;
+	unsigned int ri : 1;
+	unsigned int te : 1;
+	unsigned int re : 1;
+} grlib_uart_control_t;
+
+/** GRLIB UART registers */
+typedef struct {
+	ioport32_t data;
+	ioport32_t status;
+	ioport32_t control;
+	ioport32_t scaler;
+	ioport32_t debug;
+} grlib_uart_regs_t;
+
+/** The number of bits of one data unit send by the serial port. */
+typedef enum {
+	WORD_LENGTH_5,
+	WORD_LENGTH_6,
+	WORD_LENGTH_7,
+	WORD_LENGTH_8
+} word_length_t;
+
+/** The number of stop bits used by the serial port. */
+typedef enum {
+	/** Use one stop bit. */
+	ONE_STOP_BIT,
+	/** 1.5 stop bits for word length 5, 2 stop bits otherwise. */
+	TWO_STOP_BITS
+} stop_bit_t;
+
+/** The driver data for the serial port devices. */
+typedef struct grlib_uart {
+	/** DDF device node */
+	ddf_dev_t *dev;
+	/** DDF function node */
+	ddf_fun_t *fun;
+	/** I/O registers **/
+	grlib_uart_regs_t *regs;
+	/** Are there any clients connected to the device? */
+	unsigned client_connections;
+	/** The irq assigned to this device. */
+	int irq;
+	/** The base i/o address of the devices registers. */
+	uintptr_t regs_addr;
+	/** The buffer for incoming data. */
+	cyclic_buffer_t input_buffer;
+	/** The fibril mutex for synchronizing the access to the device. */
+	fibril_mutex_t mutex;
+	/** Indicates that some data has become available */
+	fibril_condvar_t input_buffer_available;
+	/** True if device is removed. */
+	bool removed;
+} grlib_uart_t;
+
+/** Obtain soft-state structure from device node */
+static grlib_uart_t *dev_grlib_uart(ddf_dev_t *dev)
+{
+	return ddf_dev_data_get(dev);
+}
+
+/** Obtain soft-state structure from function node */
+static grlib_uart_t *fun_grlib_uart(ddf_fun_t *fun)
+{
+	return dev_grlib_uart(ddf_fun_get_dev(fun));
+}
+
+/** Find out if there is some incoming data available on the serial port.
+ *
+ * @param port The base address of the serial port device's ports.
+ *
+ * @return True if there are data waiting to be read.
+ * @return False otherwise.
+ *
+ */
+static bool grlib_uart_received(grlib_uart_regs_t *regs)
+{
+	return ((pio_read_32(&regs->status) & GRLIB_UART_STATUS_DR) != 0);
+}
+
+/** Read one byte from the serial port.
+ *
+ * @param port The base address of the serial port device's ports.
+ *
+ * @return The data read.
+ *
+ */
+static uint8_t grlib_uart_read_8(grlib_uart_regs_t *regs)
+{
+	return (uint8_t) pio_read_32(&regs->data);
+}
+
+/** Find out wheter it is possible to send data.
+ *
+ * @param port The base address of the serial port device's ports.
+ *
+ */
+static bool is_transmit_empty(grlib_uart_regs_t *regs)
+{
+	return ((pio_read_32(&regs->status) & GRLIB_UART_STATUS_TS) != 0);
+}
+
+/** Write one character on the serial port.
+ *
+ * @param port The base address of the serial port device's ports.
+ * @param c    The character to be written to the serial port device.
+ *
+ */
+static void grlib_uart_write_8(grlib_uart_regs_t *regs, uint8_t c)
+{
+	while (!is_transmit_empty(regs));
+	
+	pio_write_32(&regs->data, (uint32_t) c);
+}
+
+/** Read data from the serial port device.
+ *
+ * @param fun   The serial port function
+ * @param buf   The output buffer for read data.
+ * @param count The number of bytes to be read.
+ *
+ * @return The number of bytes actually read on success,
+ * @return Negative error number otherwise.
+ *
+ */
+static int grlib_uart_read(ddf_fun_t *fun, char *buf, size_t count)
+{
+	if (count == 0)
+		return 0;
+	
+	grlib_uart_t *ns = fun_grlib_uart(fun);
+	
+	fibril_mutex_lock(&ns->mutex);
+	
+	while (buf_is_empty(&ns->input_buffer))
+		fibril_condvar_wait(&ns->input_buffer_available, &ns->mutex);
+	
+	int ret = 0;
+	while ((!buf_is_empty(&ns->input_buffer)) && ((size_t) ret < count)) {
+		buf[ret] = (char) buf_pop_front(&ns->input_buffer);
+		ret++;
+	}
+	
+	fibril_mutex_unlock(&ns->mutex);
+	
+	return ret;
+}
+
+/** Write a character to the serial port.
+ *
+ * @param ns Serial port device
+ * @param c  The character to be written
+ *
+ */
+static inline void grlib_uart_putchar(grlib_uart_t *ns, uint8_t c)
+{
+	fibril_mutex_lock(&ns->mutex);
+	grlib_uart_write_8(ns->regs, c);
+	fibril_mutex_unlock(&ns->mutex);
+}
+
+/** Write data to the serial port.
+ *
+ * @param fun   The serial port function
+ * @param buf   The data to be written
+ * @param count The number of bytes to be written
+ *
+ * @return Zero on success
+ *
+ */
+static int grlib_uart_write(ddf_fun_t *fun, char *buf, size_t count)
+{
+	grlib_uart_t *ns = fun_grlib_uart(fun);
+	
+	for (size_t idx = 0; idx < count; idx++)
+		grlib_uart_putchar(ns, (uint8_t) buf[idx]);
+	
+	return count;
+}
+
+static ddf_dev_ops_t grlib_uart_dev_ops;
+
+/** The character interface's callbacks. */
+static char_dev_ops_t grlib_uart_char_dev_ops = {
+	.read = &grlib_uart_read,
+	.write = &grlib_uart_write
+};
+
+static int grlib_uart_dev_add(ddf_dev_t *);
+static int grlib_uart_dev_remove(ddf_dev_t *);
+
+/** The serial port device driver's standard operations. */
+static driver_ops_t grlib_uart_ops = {
+	.dev_add = &grlib_uart_dev_add,
+	.dev_remove = &grlib_uart_dev_remove
+};
+
+/** The serial port device driver structure. */
+static driver_t grlib_uart_driver = {
+	.name = NAME,
+	.driver_ops = &grlib_uart_ops
+};
+
+/** Clean up the serial port soft-state
+ *
+ * @param ns Serial port device
+ *
+ */
+static void grlib_uart_dev_cleanup(grlib_uart_t *ns)
+{
+}
+
+/** Enable the i/o ports of the device.
+ *
+ * @param ns Serial port device
+ *
+ * @return True on success, false otherwise
+ *
+ */
+static bool grlib_uart_pio_enable(grlib_uart_t *ns)
+{
+	ddf_msg(LVL_DEBUG, "grlib_uart_pio_enable %s", ddf_dev_get_name(ns->dev));
+	
+	/* Gain control over port's registers. */
+	if (pio_enable((void *) ns->regs_addr, REG_COUNT,
+	    (void **) &ns->regs)) {
+		ddf_msg(LVL_ERROR, "Cannot map the port %#" PRIx32
+		    " for device %s.", ns->regs_addr, ddf_dev_get_name(ns->dev));
+		return false;
+	}
+	
+	return true;
+}
+
+/** Probe the serial port device for its presence.
+ *
+ * @param ns Serial port device
+ *
+ * @return True if the device is present, false otherwise
+ *
+ */
+static bool grlib_uart_dev_probe(grlib_uart_t *ns)
+{
+	ddf_msg(LVL_DEBUG, "grlib_uart_dev_probe %s", ddf_dev_get_name(ns->dev));
+	
+	return true;
+}
+
+/** Initialize serial port device.
+ *
+ * @param ns Serial port device
+ *
+ * @return Zero on success, negative error number otherwise
+ *
+ */
+static int grlib_uart_dev_initialize(grlib_uart_t *ns)
+{
+	ddf_msg(LVL_DEBUG, "grlib_uart_dev_initialize %s", ddf_dev_get_name(ns->dev));
+	
+	hw_resource_list_t hw_resources;
+	memset(&hw_resources, 0, sizeof(hw_resource_list_t));
+	
+	int ret = EOK;
+	
+	/* Connect to the parent's driver. */
+	async_sess_t *parent_sess = ddf_dev_parent_sess_create(ns->dev,
+	    EXCHANGE_SERIALIZE);
+	if (parent_sess == NULL) {
+		ddf_msg(LVL_ERROR, "Failed to connect to parent driver of "
+		    "device %s.", ddf_dev_get_name(ns->dev));
+		ret = ENOENT;
+		goto failed;
+	}
+	
+	/* Get hw resources. */
+	ret = hw_res_get_resource_list(parent_sess, &hw_resources);
+	if (ret != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to get HW resources for device "
+		    "%s.", ddf_dev_get_name(ns->dev));
+		goto failed;
+	}
+	
+	bool irq = false;
+	bool ioport = false;
+	
+	for (size_t i = 0; i < hw_resources.count; i++) {
+		hw_resource_t *res = &hw_resources.resources[i];
+		switch (res->type) {
+		case INTERRUPT:
+			ns->irq = res->res.interrupt.irq;
+			irq = true;
+			ddf_msg(LVL_NOTE, "Device %s was assigned irq = 0x%x.",
+			    ddf_dev_get_name(ns->dev), ns->irq);
+			break;
+			
+		case MEM_RANGE:
+			ns->regs_addr = res->res.mem_range.address;
+			if (res->res.mem_range.size < REG_COUNT) {
+				ddf_msg(LVL_ERROR, "I/O range assigned to "
+				    "device %s is too small.", ddf_dev_get_name(ns->dev));
+				ret = ELIMIT;
+				goto failed;
+			}
+			ioport = true;
+			ddf_msg(LVL_NOTE, "Device %s was assigned I/O address = "
+			    "0x%x.", ddf_dev_get_name(ns->dev), ns->regs_addr);
+    			break;
+			
+		default:
+			break;
+		}
+	}
+	
+	if ((!irq) || (!ioport)) {
+		ddf_msg(LVL_ERROR, "Missing HW resource(s) for device %s.",
+		    ddf_dev_get_name(ns->dev));
+		ret = ENOENT;
+		goto failed;
+	}
+	
+	hw_res_clean_resource_list(&hw_resources);
+	return ret;
+	
+failed:
+	grlib_uart_dev_cleanup(ns);
+	hw_res_clean_resource_list(&hw_resources);
+	return ret;
+}
+
+/** Enable interrupts on the serial port device.
+ *
+ * Interrupt when data is received
+ *
+ * @param port The base address of the serial port device's ports.
+ *
+ */
+static inline void grlib_uart_port_interrupts_enable(grlib_uart_regs_t *regs)
+{
+	/* Interrupt when data received. */
+	uint32_t control = pio_read_32(&regs->control);
+	pio_write_32(&regs->control, control | GRLIB_UART_CONTROL_RE);
+}
+
+/** Disable interrupts on the serial port device.
+ *
+ * @param port The base address of the serial port device's ports.
+ *
+ */
+static inline void grlib_uart_port_interrupts_disable(grlib_uart_regs_t *regs)
+{
+	uint32_t control = pio_read_32(&regs->control);
+	pio_write_32(&regs->control, control & (~GRLIB_UART_CONTROL_RE));
+}
+
+/** Enable interrupts for the serial port device.
+ *
+ * @param ns Serial port device
+ *
+ * @return Zero on success, negative error number otherwise
+ *
+ */
+static int grlib_uart_interrupt_enable(grlib_uart_t *ns)
+{
+	/* Enable interrupt on the serial port. */
+	grlib_uart_port_interrupts_enable(ns->regs);
+	
+	return EOK;
+}
+
+static int grlib_uart_port_set_baud_rate(grlib_uart_regs_t *regs,
+    unsigned int baud_rate)
+{
+	if ((baud_rate < 50) || (MAX_BAUD_RATE % baud_rate != 0)) {
+		ddf_msg(LVL_ERROR, "Invalid baud rate %d requested.",
+		    baud_rate);
+		return EINVAL;
+	}
+	
+	/* XXX: Set baud rate */
+	
+	return EOK;
+}
+
+/** Set the parameters of the serial communication on the serial port device.
+ *
+ * @param parity      The parity to be used.
+ * @param word_length The length of one data unit in bits.
+ * @param stop_bits   The number of stop bits used (one or two).
+ *
+ * @return Zero on success.
+ * @return EINVAL if some of the specified values is invalid.
+ *
+ */
+static int grlib_uart_port_set_com_props(grlib_uart_regs_t *regs,
+    unsigned int parity, unsigned int word_length, unsigned int stop_bits)
+{
+	uint32_t val = pio_read_32(&regs->control);
+	
+	switch (parity) {
+	case SERIAL_NO_PARITY:
+	case SERIAL_ODD_PARITY:
+	case SERIAL_EVEN_PARITY:
+	case SERIAL_MARK_PARITY:
+	case SERIAL_SPACE_PARITY:
+		val |= GRLIB_UART_CONTROL_PE;
+		break;
+	default:
+		return EINVAL;
+	}
+	
+	pio_write_32(&regs->control, val);
+	
+	return EOK;
+}
+
+/** Initialize the serial port device.
+ *
+ * Set the default parameters of the serial communication.
+ *
+ * @param ns Serial port device
+ *
+ */
+static void grlib_uart_initialize_port(grlib_uart_t *ns)
+{
+	/* Disable interrupts. */
+	grlib_uart_port_interrupts_disable(ns->regs);
+	
+	/* Set baud rate. */
+	grlib_uart_port_set_baud_rate(ns->regs, 38400);
+	
+	/* 8 bits, no parity, two stop bits. */
+	grlib_uart_port_set_com_props(ns->regs, SERIAL_NO_PARITY, 8, 2);
+	
+	/*
+	 * Enable FIFO, clear them, with 4-byte threshold for greater
+	 * reliability.
+	 */
+	pio_write_32(&ns->regs->control, GRLIB_UART_CONTROL_RE |
+	    GRLIB_UART_CONTROL_TE | GRLIB_UART_CONTROL_RF |
+	    GRLIB_UART_CONTROL_TF | GRLIB_UART_CONTROL_RI |
+	    GRLIB_UART_CONTROL_FA);
+}
+
+/** Deinitialize the serial port device.
+ *
+ * @param ns Serial port device
+ *
+ */
+static void grlib_uart_port_cleanup(grlib_uart_t *ns)
+{
+	grlib_uart_port_interrupts_disable(ns->regs);
+}
+
+/** Read the data from the serial port device and store them to the input
+ * buffer.
+ *
+ * @param ns Serial port device
+ *
+ */
+static void grlib_uart_read_from_device(grlib_uart_t *ns)
+{
+	grlib_uart_regs_t *regs = ns->regs;
+	bool cont = true;
+	
+	fibril_mutex_lock(&ns->mutex);
+	
+	while (cont) {
+		cont = grlib_uart_received(regs);
+		if (cont) {
+			uint8_t val = grlib_uart_read_8(regs);
+			
+			if (ns->client_connections > 0) {
+				bool buf_was_empty = buf_is_empty(&ns->input_buffer);
+				if (!buf_push_back(&ns->input_buffer, val)) {
+					ddf_msg(LVL_WARN, "Buffer overflow on "
+					    "%s.", ddf_dev_get_name(ns->dev));
+					break;
+				} else {
+					ddf_msg(LVL_DEBUG2, "Character %c saved "
+					    "to the buffer of %s.",
+					    val, ddf_dev_get_name(ns->dev));
+					if (buf_was_empty)
+						fibril_condvar_broadcast(&ns->input_buffer_available);
+				}
+			}
+		}
+	}
+	
+	fibril_mutex_unlock(&ns->mutex);
+	fibril_yield();
+}
+
+/** The interrupt handler.
+ *
+ * The serial port is initialized to interrupt when some data come or line
+ * status register changes, so the interrupt is handled by reading the incoming
+ * data and reading the line status register.
+ *
+ * @param dev The serial port device.
+ *
+ */
+static inline void grlib_uart_interrupt_handler(ddf_dev_t *dev,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	grlib_uart_t *ns = dev_grlib_uart(dev);
+	
+	uint32_t status = pio_read_32(&ns->regs->status);
+	
+	if (status & GRLIB_UART_STATUS_RF) {
+		if (status & GRLIB_UART_STATUS_OV)
+			ddf_msg(LVL_WARN, "Overrun error on %s", ddf_dev_get_name(ns->dev));
+	}
+	
+	grlib_uart_read_from_device(ns);
+}
+
+/** Register the interrupt handler for the device.
+ *
+ * @param ns Serial port device
+ *
+ */
+static inline int grlib_uart_register_interrupt_handler(grlib_uart_t *ns)
+{
+	return register_interrupt_handler(ns->dev, ns->irq,
+	    grlib_uart_interrupt_handler, NULL);
+}
+
+/** Unregister the interrupt handler for the device.
+ *
+ * @param ns Serial port device
+ *
+ */
+static inline int grlib_uart_unregister_interrupt_handler(grlib_uart_t *ns)
+{
+	return unregister_interrupt_handler(ns->dev, ns->irq);
+}
+
+/** The dev_add callback method of the serial port driver.
+ *
+ * Probe and initialize the newly added device.
+ *
+ * @param dev The serial port device.
+ *
+ */
+static int grlib_uart_dev_add(ddf_dev_t *dev)
+{
+	grlib_uart_t *ns = NULL;
+	ddf_fun_t *fun = NULL;
+	bool need_cleanup = false;
+	bool need_unreg_intr_handler = false;
+	int rc;
+	
+	ddf_msg(LVL_DEBUG, "grlib_uart_dev_add %s (handle = %d)",
+	    ddf_dev_get_name(dev), (int) ddf_dev_get_handle(dev));
+	
+	/* Allocate soft-state for the device */
+	ns = ddf_dev_data_alloc(dev, sizeof(grlib_uart_t));
+	if (ns == NULL) {
+		rc = ENOMEM;
+		goto fail;
+	}
+	
+	fibril_mutex_initialize(&ns->mutex);
+	fibril_condvar_initialize(&ns->input_buffer_available);
+	ns->dev = dev;
+	
+	rc = grlib_uart_dev_initialize(ns);
+	if (rc != EOK)
+		goto fail;
+	
+	need_cleanup = true;
+	
+	if (!grlib_uart_pio_enable(ns)) {
+		rc = EADDRNOTAVAIL;
+		goto fail;
+	}
+	
+	/* Find out whether the device is present. */
+	if (!grlib_uart_dev_probe(ns)) {
+		rc = ENOENT;
+		goto fail;
+	}
+	
+	/* Serial port initialization (baud rate etc.). */
+	grlib_uart_initialize_port(ns);
+	
+	/* Register interrupt handler. */
+	if (grlib_uart_register_interrupt_handler(ns) != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to register interrupt handler.");
+		rc = EADDRNOTAVAIL;
+		goto fail;
+	}
+	need_unreg_intr_handler = true;
+	
+	/* Enable interrupt. */
+	rc = grlib_uart_interrupt_enable(ns);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to enable the interrupt. Error code = "
+		    "%d.", rc);
+		goto fail;
+	}
+	
+	fun = ddf_fun_create(dev, fun_exposed, "a");
+	if (fun == NULL) {
+		ddf_msg(LVL_ERROR, "Failed creating function.");
+		goto fail;
+	}
+	
+	/* Set device operations. */
+	ddf_fun_set_ops(fun, &grlib_uart_dev_ops);
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding function.");
+		goto fail;
+	}
+	
+	ns->fun = fun;
+	
+	ddf_fun_add_to_category(fun, "serial");
+	
+	ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
+	    ddf_dev_get_name(dev));
+	
+	return EOK;
+	
+fail:
+	if (fun != NULL)
+		ddf_fun_destroy(fun);
+	
+	if (need_unreg_intr_handler)
+		grlib_uart_unregister_interrupt_handler(ns);
+	
+	if (need_cleanup)
+		grlib_uart_dev_cleanup(ns);
+	
+	return rc;
+}
+
+static int grlib_uart_dev_remove(ddf_dev_t *dev)
+{
+	grlib_uart_t *ns = dev_grlib_uart(dev);
+	
+	fibril_mutex_lock(&ns->mutex);
+	if (ns->client_connections > 0) {
+		fibril_mutex_unlock(&ns->mutex);
+		return EBUSY;
+	}
+	ns->removed = true;
+	fibril_mutex_unlock(&ns->mutex);
+	
+	int rc = ddf_fun_unbind(ns->fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to unbind function.");
+		return rc;
+	}
+	
+	ddf_fun_destroy(ns->fun);
+	
+	grlib_uart_port_cleanup(ns);
+	grlib_uart_unregister_interrupt_handler(ns);
+	grlib_uart_dev_cleanup(ns);
+	return EOK;
+}
+
+/** Open the device.
+ *
+ * This is a callback function called when a client tries to connect to the
+ * device.
+ *
+ * @param dev The device.
+ *
+ */
+static int grlib_uart_open(ddf_fun_t *fun)
+{
+	grlib_uart_t *ns = fun_grlib_uart(fun);
+	int res;
+	
+	fibril_mutex_lock(&ns->mutex);
+	if (ns->removed) {
+		res = ENXIO;
+	} else {
+		res = EOK;
+		ns->client_connections++;
+	}
+	fibril_mutex_unlock(&ns->mutex);
+	
+	return res;
+}
+
+/** Close the device.
+ *
+ * This is a callback function called when a client tries to disconnect from
+ * the device.
+ *
+ * @param dev The device.
+ *
+ */
+static void grlib_uart_close(ddf_fun_t *fun)
+{
+	grlib_uart_t *data = fun_grlib_uart(fun);
+	
+	fibril_mutex_lock(&data->mutex);
+	
+	assert(data->client_connections > 0);
+	
+	if (!(--data->client_connections))
+		buf_clear(&data->input_buffer);
+	
+	fibril_mutex_unlock(&data->mutex);
+}
+
+/** Default handler for client requests which are not handled by the standard
+ * interfaces.
+ *
+ * Configure the parameters of the serial communication.
+ *
+ */
+static void grlib_uart_default_handler(ddf_fun_t *fun, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	sysarg_t method = IPC_GET_IMETHOD(*call);
+	
+	switch (method) {
+	default:
+		async_answer_0(callid, ENOTSUP);
+	}
+}
+
+/** Initialize the serial port driver.
+ *
+ * Initialize device operations structures with callback methods for handling
+ * client requests to the serial port devices.
+ *
+ */
+static void grlib_uart_init(void)
+{
+	ddf_log_init(NAME);
+	
+	grlib_uart_dev_ops.open = &grlib_uart_open;
+	grlib_uart_dev_ops.close = &grlib_uart_close;
+	
+	grlib_uart_dev_ops.interfaces[CHAR_DEV_IFACE] = &grlib_uart_char_dev_ops;
+	grlib_uart_dev_ops.default_handler = &grlib_uart_default_handler;
+}
+
+int main(int argc, char *argv[])
+{
+	printf("%s: HelenOS serial port driver\n", NAME);
+	grlib_uart_init();
+	return ddf_driver_main(&grlib_uart_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/char/grlib_uart/grlib_uart.ma
===================================================================
--- uspace/drv/char/grlib_uart/grlib_uart.ma	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/drv/char/grlib_uart/grlib_uart.ma	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,1 @@
+10 amba/ven=01&dev=0000000c
Index: uspace/drv/infrastructure/rootleon3/Makefile
===================================================================
--- uspace/drv/infrastructure/rootleon3/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/drv/infrastructure/rootleon3/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2012 Jan Vesely
+# 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 = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = rootleon3
+
+SOURCES = \
+	rootleon3.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/infrastructure/rootleon3/rootleon3.c
===================================================================
--- uspace/drv/infrastructure/rootleon3/rootleon3.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/drv/infrastructure/rootleon3/rootleon3.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2012 Jan Vesely
+ * Copyright (c) 2013 Jakub Klama
+ * 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.
+ */
+
+/**
+ * @defgroup root_leon3 SPARC LEON3 platform driver.
+ * @brief HelenOS SPARC LEON3 platform driver.
+ * @{
+ */
+/** @file
+ */
+
+#include <ddf/log.h>
+#include <errno.h>
+#include <ops/hw_res.h>
+#include <stdio.h>
+#include "rootleon3.h"
+
+#define NAME  "rootleon3"
+
+typedef struct {
+	const char *name;
+	match_id_t match_id;
+	hw_resource_list_t hw_resources;
+} rootleon3_fun_t;
+
+static hw_resource_t amba_res[] = {
+	{
+		.type = MEM_RANGE,
+		.res.mem_range = {
+			.address = AMBAPP_MASTER_AREA,
+			.size = AMBAPP_MASTER_SIZE,
+			.endianness = BIG_ENDIAN
+		}
+	},
+	{
+		.type = MEM_RANGE,
+		.res.mem_range = {
+			.address = AMBAPP_SLAVE_AREA,
+			.size = AMBAPP_SLAVE_SIZE,
+			.endianness = BIG_ENDIAN,
+		}
+	}
+};
+
+static const rootleon3_fun_t leon3_func = {
+	.name = "leon_amba",
+	.match_id = {
+		.id =  "leon_amba",
+		.score = 90 
+	},
+	.hw_resources = {
+		.count = 2,
+		.resources = amba_res
+	}
+};
+
+static hw_resource_list_t *rootleon3_get_resources(ddf_fun_t *);
+static bool rootleon3_enable_interrupt(ddf_fun_t *);
+
+static hw_res_ops_t fun_hw_res_ops = {
+	.get_resource_list = &rootleon3_get_resources,
+	.enable_interrupt = &rootleon3_enable_interrupt
+};
+
+static ddf_dev_ops_t rootleon3_fun_ops = {
+	.interfaces[HW_RES_DEV_IFACE] = &fun_hw_res_ops
+};
+
+static int rootleon3_add_fun(ddf_dev_t *dev, const rootleon3_fun_t *fun)
+{
+	assert(dev);
+	assert(fun);
+	
+	ddf_msg(LVL_DEBUG, "Adding new function '%s'.", fun->name);
+	
+	/* Create new device function. */
+	ddf_fun_t *fnode = ddf_fun_create(dev, fun_inner, fun->name);
+	if (fnode == NULL)
+		return ENOMEM;
+	
+	/* Add match id */
+	int ret = ddf_fun_add_match_id(fnode, fun->match_id.id,
+	    fun->match_id.score);
+	if (ret != EOK) {
+		ddf_fun_destroy(fnode);
+		return ret;
+	}
+	
+	/* Allocate needed data */
+	rootleon3_fun_t *rf =
+	    ddf_fun_data_alloc(fnode, sizeof(rootleon3_fun_t));
+	if (!rf) {
+		ddf_fun_destroy(fnode);
+		return ENOMEM;
+	}
+	*rf = *fun;
+	
+	/* Set provided operations to the device. */
+	ddf_fun_set_ops(fnode, &rootleon3_fun_ops);
+	
+	/* Register function. */
+	ret = ddf_fun_bind(fnode);
+	if (ret != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding function %s.", fun->name);
+		ddf_fun_destroy(fnode);
+		return ret;
+	}
+	
+	return EOK;
+}
+
+/** Add the root device.
+ *
+ * @param dev Device which is root of the whole device tree
+ *            (both of HW and pseudo devices).
+ *
+ * @return Zero on success, negative error number otherwise.
+ *
+ */
+static int rootleon3_dev_add(ddf_dev_t *dev)
+{
+	assert(dev);
+	
+	/* Register functions */
+	if (rootleon3_add_fun(dev, &leon3_func) != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to add %s function for "
+		    "LEON3 platform.", leon3_func.name);
+	}
+	
+	return EOK;
+}
+
+/** The root device driver's standard operations. */
+static driver_ops_t rootleon3_ops = {
+	.dev_add = &rootleon3_dev_add
+};
+
+/** The root device driver structure. */
+static driver_t rootleon3_driver = {
+	.name = NAME,
+	.driver_ops = &rootleon3_ops
+};
+
+static hw_resource_list_t *rootleon3_get_resources(ddf_fun_t *fnode)
+{
+	rootleon3_fun_t *fun = ddf_fun_data_get(fnode);
+	assert(fun != NULL);
+	
+	printf("rootleon3_get_resources() called\n");
+	
+	return &fun->hw_resources;
+}
+
+static bool rootleon3_enable_interrupt(ddf_fun_t *fun)
+{
+	// FIXME TODO
+	return false;
+}
+
+int main(int argc, char *argv[])
+{
+	printf("%s: HelenOS SPARC LEON3 platform driver\n", NAME);
+	ddf_log_init(NAME);
+	return ddf_driver_main(&rootleon3_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/infrastructure/rootleon3/rootleon3.h
===================================================================
--- uspace/drv/infrastructure/rootleon3/rootleon3.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/drv/infrastructure/rootleon3/rootleon3.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013 Jakub Klama
+ * 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 leon3drv
+ * @{
+ */
+/** @file
+ * @brief LEON3 root device.
+ */
+
+#ifndef ROOTLEON3_H
+#define ROOTLEON3_H
+
+#define AMBAPP_MASTER_AREA  0xfffff000
+#define AMBAPP_SLAVE_AREA   0xfffff800
+#define AMBAPP_MASTER_SIZE  0x800
+#define AMBAPP_SLAVE_SIZE   0x800
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/infrastructure/rootleon3/rootleon3.ma
===================================================================
--- uspace/drv/infrastructure/rootleon3/rootleon3.ma	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/drv/infrastructure/rootleon3/rootleon3.ma	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,1 @@
+100 platform/leon3
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -61,5 +61,4 @@
 	generic/bd.c \
 	generic/bd_srv.c \
-	generic/bitops.c \
 	generic/cap.c \
 	generic/cfg.c \
@@ -77,4 +76,5 @@
 	generic/device/pci.c \
 	generic/device/ahci.c \
+	generic/dhcp.c \
 	generic/dnsr.c \
 	generic/dlfcn.c \
@@ -99,5 +99,4 @@
 	generic/inetcfg.c \
 	generic/inetping.c \
-	generic/inetping6.c \
 	generic/io/asprintf.c \
 	generic/io/input.c \
@@ -129,4 +128,5 @@
 	generic/loader.c \
 	generic/getopt.c \
+	generic/adt/checksum.c \
 	generic/adt/list.c \
 	generic/adt/hash_table.c \
@@ -143,4 +143,5 @@
 	generic/net/socket_client.c \
 	generic/net/socket_parse.c \
+	generic/setjmp.c \
 	generic/stack.c \
 	generic/stacktrace.c \
Index: uspace/lib/c/arch/abs32le/include/libarch/atomic.h
===================================================================
--- uspace/lib/c/arch/abs32le/include/libarch/atomic.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/arch/abs32le/include/libarch/atomic.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -53,5 +53,6 @@
 }
 
-static inline void atomic_inc(atomic_t *val) {
+static inline void atomic_inc(atomic_t *val)
+{
 	/* On real hardware the increment has to be done
 	   as an atomic action. */
@@ -60,5 +61,6 @@
 }
 
-static inline void atomic_dec(atomic_t *val) {
+static inline void atomic_dec(atomic_t *val)
+{
 	/* On real hardware the decrement has to be done
 	   as an atomic action. */
Index: uspace/lib/c/arch/amd64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/amd64/_link.ld.in	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/arch/amd64/_link.ld.in	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -39,4 +39,5 @@
 	.data : {
 		*(.data);
+		*(.data.rel*);
 	} :data
 	
Index: uspace/lib/c/arch/ia32/Makefile.inc
===================================================================
--- uspace/lib/c/arch/ia32/Makefile.inc	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/arch/ia32/Makefile.inc	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -34,5 +34,4 @@
 	arch/$(UARCH)/src/fibril.S \
 	arch/$(UARCH)/src/tls.c \
-	arch/$(UARCH)/src/setjmp.S \
 	arch/$(UARCH)/src/stacktrace.c \
 	arch/$(UARCH)/src/stacktrace_asm.S \
Index: uspace/lib/c/arch/ia32/src/setjmp.S
===================================================================
--- uspace/lib/c/arch/ia32/src/setjmp.S	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,55 +1,0 @@
-#
-# Copyright (c) 2008 Josef Cejka
-# 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 <libarch/context_offset.h>
-
-.text
-.global setjmp
-.global longjmp
-
-.type setjmp,@function
-setjmp:
-	movl 0(%esp), %eax  # save pc value into eax
-	movl 4(%esp), %edx  # address of the jmp_buf structure to save context to
-	
-	# save registers to the jmp_buf structure
-	CONTEXT_SAVE_ARCH_CORE %edx %eax
-	
-	xorl %eax, %eax     # set_jmp returns 0
-	ret
-
-.type longjmp,@function
-longjmp:
-	movl 4(%esp), %ecx  # put address of jmp_buf into ecx
-	movl 8(%esp), %eax  # put return value into eax
-	
-	# restore registers from the jmp_buf structure
-	CONTEXT_RESTORE_ARCH_CORE %ecx %edx
-	
-	movl %edx, 0(%esp)  # put saved pc on stack
-	ret
Index: uspace/lib/c/arch/sparc32/Makefile.common
===================================================================
--- uspace/lib/c/arch/sparc32/Makefile.common	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/Makefile.common	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2006 Martin Decky
+# 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.
+#
+
+LFLAGS = -no-check-sections
+
+ENDIANESS = BE
+
+BFD_NAME = elf32-sparc
+BFD_ARCH = sparc
Index: uspace/lib/c/arch/sparc32/Makefile.inc
===================================================================
--- uspace/lib/c/arch/sparc32/Makefile.inc	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/Makefile.inc	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2006 Martin Decky
+# 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.
+#
+
+ARCH_SOURCES = \
+	arch/$(UARCH)/src/entry.s \
+	arch/$(UARCH)/src/entryjmp.s \
+	arch/$(UARCH)/src/thread_entry.s \
+	arch/$(UARCH)/src/fibril.S \
+	arch/$(UARCH)/src/tls.c \
+	arch/$(UARCH)/src/stacktrace.c \
+	arch/$(UARCH)/src/stacktrace_asm.S
+
+.PRECIOUS: arch/$(UARCH)/src/entry.o
Index: uspace/lib/c/arch/sparc32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/sparc32/_link.ld.in	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/_link.ld.in	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,68 @@
+STARTUP(LIBC_PATH/arch/UARCH/src/entry.o)
+ENTRY(__entry)
+
+PHDRS {
+#ifdef LOADER
+	interp PT_INTERP;
+	text PT_LOAD FILEHDR PHDRS FLAGS(5);
+#else
+	text PT_LOAD FLAGS(5);
+#endif
+	data PT_LOAD FLAGS(6);
+}
+
+SECTIONS {
+#ifdef LOADER
+	. = 0x70004000 + SIZEOF_HEADERS;
+#else
+	. = 0x4000 + SIZEOF_HEADERS;
+#endif
+	
+	.init : {
+		*(.init);
+	} :text
+	
+	.text : {
+		*(.text .text.*);
+		*(.rodata .rodata.*);
+	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
+	
+	. = . + 0x4000;
+	
+	.got : {
+		 _gp = .;
+		 *(.got*);
+	} :data
+	
+	.data : {
+		*(.data);
+		*(.sdata);
+	} :data
+	
+	.tdata : {
+		_tdata_start = .;
+		*(.tdata);
+		_tdata_end = .;
+		_tbss_start = .;
+		*(.tbss);
+		_tbss_end = .;
+	} :data
+	
+	_tls_alignment = ALIGNOF(.tdata);
+	
+	.bss : {
+		*(.sbss);
+		*(COMMON);
+		*(.bss);
+	} :data
+	
+	/DISCARD/ : {
+		*(*);
+	}
+}
Index: uspace/lib/c/arch/sparc32/include/libarch/atomic.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/atomic.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/atomic.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2005 Jakub Jermar
+ * 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 libcsparc32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_sparc32_ATOMIC_H_
+#define LIBC_sparc32_ATOMIC_H_
+
+#define LIBC_ARCH_ATOMIC_H_
+
+#define CAS
+
+#include <atomicdflt.h>
+#include <sys/types.h>
+
+static inline bool cas(atomic_t *val, atomic_count_t ov, atomic_count_t nv)
+{
+	if (val->count == ov) {
+		val->count = nv;
+		return true;
+	}
+	
+	return false;
+}
+
+static inline void atomic_inc(atomic_t *val)
+{
+	// FIXME TODO
+	val->count++;
+}
+
+static inline void atomic_dec(atomic_t *val)
+{
+	// FIXME TODO
+	val->count++;
+}
+
+static inline atomic_count_t atomic_postinc(atomic_t *val)
+{
+	// FIXME TODO
+	
+	atomic_count_t prev = val->count;
+	
+	val->count++;
+	return prev;
+}
+
+static inline atomic_count_t atomic_postdec(atomic_t *val)
+{
+	// FIXME TODO
+	
+	atomic_count_t prev = val->count;
+	
+	val->count--;
+	return prev;
+}
+
+#define atomic_preinc(val) (atomic_postinc(val) + 1)
+#define atomic_predec(val) (atomic_postdec(val) - 1)
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/include/libarch/barrier.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/barrier.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/barrier.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,1 @@
+../../../../../../../kernel/arch/sparc32/include/arch/barrier.h
Index: uspace/lib/c/arch/sparc32/include/libarch/config.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/config.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/config.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2006 Jakub Jermar
+ * 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 libcsparc32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_sparc32_CONFIG_H_
+#define LIBC_sparc32_CONFIG_H_
+
+#define PAGE_WIDTH  12
+#define PAGE_SIZE   (1 << PAGE_WIDTH)
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/include/libarch/context_offset.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/context_offset.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/context_offset.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,1 @@
+../../../../../../../kernel/arch/sparc32/include/arch/context_offset.h
Index: uspace/lib/c/arch/sparc32/include/libarch/ddi.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/ddi.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/ddi.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2009 Jakub Jermar
+ * 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.
+ */
+
+/** @file
+ * @ingroup libsparc32
+ */
+
+#ifndef LIBC_sparc32_DDI_H_
+#define LIBC_sparc32_DDI_H_
+
+#include <sys/types.h>
+#include <libarch/types.h>
+
+static inline void memory_barrier(void)
+{
+	asm volatile (
+		"stbar\n"
+		::: "memory"
+	);
+}
+
+static inline void arch_pio_write_8(ioport8_t *port, uint8_t v)
+{
+	*port = v;
+	memory_barrier();
+}
+
+static inline void arch_pio_write_16(ioport16_t *port, uint16_t v)
+{
+	*port = v;
+	memory_barrier();
+}
+
+static inline void arch_pio_write_32(ioport32_t *port, uint32_t v)
+{
+	*port = v;
+	memory_barrier();
+}
+
+static inline uint8_t arch_pio_read_8(const ioport8_t *port)
+{
+	uint8_t rv = *port;
+	memory_barrier();
+	
+	return rv;
+}
+
+static inline uint16_t arch_pio_read_16(const ioport16_t *port)
+{
+	uint16_t rv = *port;
+	memory_barrier();
+	
+	return rv;
+}
+
+static inline uint32_t arch_pio_read_32(const ioport32_t *port)
+{
+	uint32_t rv = *port;
+	memory_barrier();
+	
+	return rv;
+}
+
+#endif
Index: uspace/lib/c/arch/sparc32/include/libarch/elf.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/elf.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/elf.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,1 @@
+../../../../../../../kernel/arch/sparc32/include/arch/elf.h
Index: uspace/lib/c/arch/sparc32/include/libarch/elf_linux.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/elf_linux.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/elf_linux.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011 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 libcsparc32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_sparc32_ELF_LINUX_H_
+#define LBIC_sparc32_ELF_LINUX_H_
+
+#include <libarch/istate.h>
+#include <sys/types.h>
+
+typedef struct {
+	/* TODO */
+	uint64_t pad[16];
+} elf_regs_t;
+
+static inline void istate_to_elf_regs(istate_t *istate, elf_regs_t *elf_regs)
+{
+	/* TODO */
+	(void) istate;
+	(void) elf_regs;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/include/libarch/faddr.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/faddr.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/faddr.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2005 Ondrej Palkovsky
+ * 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 libcsparc32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_sparc32_FADDR_H_
+#define LIBC_sparc32_FADDR_H_
+
+#include <libarch/types.h>
+
+#define FADDR(fptr)  ((uintptr_t) (fptr))
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/include/libarch/fibril.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/fibril.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/fibril.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2005 Jakub Jermar
+ * 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 libcsparc32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_sparc32_FIBRIL_H_
+#define LIBC_sparc32_FIBRIL_H_
+
+#include <libarch/stack.h>
+#include <sys/types.h>
+#include <align.h>
+
+#define SP_DELTA  (STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE)
+
+#define context_set(c, _pc, stack, size, ptls) \
+	do { \
+		(c)->pc = ((uintptr_t) _pc) - 8; \
+		(c)->sp = ((uintptr_t) stack) + ALIGN_UP((size), \
+		    STACK_ALIGNMENT) - (SP_DELTA); \
+		(c)->fp = 0; \
+		(c)->tp = (uint32_t) ptls; \
+	} while (0)
+
+/*
+ * Save only registers that must be preserved across
+ * function calls.
+ */
+typedef struct {
+	uintptr_t sp;  /* %o6 */
+	uintptr_t pc;  /* %o7 */
+	uint32_t i0;
+	uint32_t i1;
+	uint32_t i2;
+	uint32_t i3;
+	uint32_t i4;
+	uint32_t i5;
+	uintptr_t fp;  /* %i6 */
+	uintptr_t i7;
+	uint32_t l0;
+	uint32_t l1;
+	uint32_t l2;
+	uint32_t l3;
+	uint32_t l4;
+	uint32_t l5;
+	uint32_t l6;
+	uint32_t l7;
+	uint32_t tp;  /* %g7 */
+} context_t;
+
+static inline uintptr_t context_get_fp(context_t *ctx)
+{
+	return ctx->sp;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/include/libarch/inttypes.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/inttypes.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/inttypes.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010 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 libcsparc32
+ * @{
+ */
+
+#ifndef LIBC_sparc32_INTTYPES_H_
+#define LIBC_sparc32_INTTYPES_H_
+
+#define PRIdn  PRId32  /**< Format for native_t. */
+#define PRIun  PRIu32  /**< Format for sysarg_t. */
+#define PRIxn  PRIx32  /**< Format for hexadecimal sysarg_t. */
+#define PRIua  PRIu32  /**< Format for atomic_count_t. */
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/include/libarch/istate.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/istate.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/istate.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,1 @@
+../../../../../../../kernel/arch/sparc32/include/arch/istate.h
Index: uspace/lib/c/arch/sparc32/include/libarch/stack.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/stack.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/stack.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2005 Jakub Jermar
+ * 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 libcsparc32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_sparc32_STACK_H_
+#define LIBC_sparc32_STACK_H_
+
+#define STACK_ITEM_SIZE  4
+
+#define STACK_ALIGNMENT  8
+
+/** 16-extended-word save area for %i[0-7] and %l[0-7] registers. */
+#define STACK_WINDOW_SAVE_AREA_SIZE  (16 * STACK_ITEM_SIZE)
+
+/* Six extended words for first six arguments. */
+#define STACK_ARG_SAVE_AREA_SIZE  (6 * STACK_ITEM_SIZE)
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/include/libarch/stackarg.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/stackarg.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/stackarg.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2006 Josef Cejka
+ * 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 libcsparc32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_sparc32_STACKARG_H_
+#define LIBC_sparc32_STACKARG_H_
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/include/libarch/syscall.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/syscall.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/syscall.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2005 Martin Decky
+ * 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 libcsparc32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_sparc32_SYSCALL_H_
+#define LIBC_sparc32_SYSCALL_H_
+
+#include <sys/types.h>
+#include <abi/syscall.h>
+
+#define __syscall0  __syscall
+#define __syscall1  __syscall
+#define __syscall2  __syscall
+#define __syscall3  __syscall
+#define __syscall4  __syscall
+#define __syscall5  __syscall
+#define __syscall6  __syscall
+
+static inline sysarg_t __syscall(const sysarg_t p1, const sysarg_t p2,
+    const sysarg_t p3, const sysarg_t p4, const sysarg_t p5, const sysarg_t p6,
+    const syscall_t id)
+{
+	register uint32_t a1 asm("o0") = p1;
+	register uint32_t a2 asm("o1") = p2;
+	register uint32_t a3 asm("o2") = p3;
+	register uint32_t a4 asm("o3") = p4;
+	register uint32_t a5 asm("o4") = p5;
+	register uint32_t a6 asm("o5") = p6;
+	
+	asm volatile (
+		"ta %7\n"
+		: "=r" (a1)
+		: "r" (a1),
+		  "r" (a2),
+		  "r" (a3),
+		  "r" (a4),
+		  "r" (a5),
+		  "r" (a6),
+		  "i" (id)
+		: "memory"
+	);
+	
+	return a1;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/include/libarch/thread.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/thread.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/thread.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2006 Jakub Jermar
+ * 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 libcsparc32
+ * @{
+ */
+
+#ifndef LIBC_sparc32_THREAD_H_
+#define LIBC_sparc32_THREAD_H_
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/include/libarch/tls.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/tls.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/tls.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2006 Jakub Jermar
+ * 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 libcsparc32
+ * @{
+ */
+/** @file
+ * @brief sparc32 TLS functions.
+ */
+
+#ifndef LIBC_sparc32_TLS_H_
+#define LIBC_sparc32_TLS_H_
+
+#define CONFIG_TLS_VARIANT_2
+
+typedef struct {
+	void *self;
+	void *fibril_data;
+} tcb_t;
+
+static inline void __tcb_set(tcb_t *tcb)
+{
+	asm volatile (
+		"mov %0, %%g7\n"
+		:: "r" (tcb)
+		: "g7"
+	);
+}
+
+static inline tcb_t *__tcb_get(void)
+{
+	void *retval;
+	
+	asm volatile (
+		"mov %%g7, %0\n"
+		: "=r" (retval)
+	);
+	
+	return retval;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/include/libarch/types.h
===================================================================
--- uspace/lib/c/arch/sparc32/include/libarch/types.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/include/libarch/types.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2005 Martin Decky
+ * 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 libcsparc32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_sparc32_TYPES_H_
+#define LIBC_sparc32_TYPES_H_
+
+#define __32_BITS__
+
+#include <libarch/common.h>
+
+#define SIZE_MIN  UINT32_MIN
+#define SIZE_MAX  UINT32_MAX
+
+#define SSIZE_MIN  INT32_MIN
+#define SSIZE_MAX  INT32_MAX
+
+typedef uint32_t sysarg_t;
+typedef int32_t native_t;
+
+typedef int32_t ssize_t;
+typedef uint32_t size_t;
+
+typedef uint32_t uintptr_t;
+typedef int32_t intptr_t;
+typedef uint32_t atomic_count_t;
+typedef int32_t atomic_signed_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/src/entry.s
===================================================================
--- uspace/lib/c/arch/sparc32/src/entry.s	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/src/entry.s	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,67 @@
+#
+# Copyright (c) 2006 Martin Decky
+# 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.
+#
+
+.section .init, "ax"
+
+.org 0
+
+.globl __entry
+
+## User-space task entry point
+#
+# %o0 contains uarg
+# %o1 contains pcb_ptr
+#
+__entry:
+	#
+	# Create the first stack frame.
+	#
+	
+	save %sp, -176, %sp
+	## XXX	flushw
+	mov 7, %g1
+	1:
+		subcc %g1, 1, %g1
+		bg 1b
+		save %sp, -64, %sp
+	
+	mov 7, %g1
+	1:
+		subcc %g1, 1, %g1
+		bg 1b
+		restore
+	
+	## XXX end flush
+	## add %g0, -0x7ff, %fp
+	set 0x80000000, %fp
+	
+	# Pass pcb_ptr as the first argument to __main()
+	mov %i1, %o0
+	sethi %hi(_gp), %l7
+	call __main
+	or %l7, %lo(_gp), %l7
Index: uspace/lib/c/arch/sparc32/src/entryjmp.s
===================================================================
--- uspace/lib/c/arch/sparc32/src/entryjmp.s	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/src/entryjmp.s	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2008 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.
+#
+
+.globl entry_point_jmp
+
+## void entry_point_jmp(void *entry_point, void *pcb);
+#
+# %o0	contains entry_point
+# %o1	contains pcb
+#
+# Jump to program entry point
+entry_point_jmp:
+	# Pass pcb pointer to entry point in %o1. As it is already
+	# there, no action is needed.
+	call %o0
+	nop
+	# FIXME: use branch instead of call
Index: uspace/lib/c/arch/sparc32/src/fibril.S
===================================================================
--- uspace/lib/c/arch/sparc32/src/fibril.S	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/src/fibril.S	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,85 @@
+#
+# Copyright (c) 2005 Jakub Jermar
+# 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 <libarch/context_offset.h>
+
+.text
+
+.global flush_windows
+.global context_save
+.global context_restore
+
+context_save:
+	#
+	# We rely on the kernel to flush our active register windows to memory
+	# should a thread switch occur.
+	#
+	
+	mov 7, %g1
+	1:
+		subcc %g1, 1, %g1
+		bg 1b
+		save %sp, -64, %sp
+	
+	mov 7, %g1
+	1:
+		subcc %g1, 1, %g1
+		bg 1b
+		restore
+	
+	CONTEXT_SAVE_ARCH_CORE %o0
+	retl
+	mov 1, %o0              ! context_save_arch returns 1
+
+context_restore:
+	#
+	# Flush all active windows.
+	# This is essential, because CONTEXT_RESTORE_ARCH_CORE overwrites %sp of
+	# CWP - 1 with the value written to %fp of CWP.  Flushing all active
+	# windows mitigates this problem as CWP - 1 becomes the overlap window.
+	#
+	
+	## XXX
+	## flushw
+	## ta 0x4f
+	## nop
+	mov 7, %g1
+	1:
+		subcc %g1, 1, %g1
+		bg 1b
+		save %sp, -64, %sp
+	
+	mov 7, %g1
+	1:
+		subcc %g1, 1, %g1
+		bg 1b
+		restore
+	
+	CONTEXT_RESTORE_ARCH_CORE %o0
+	retl
+	xor %o0, %o0, %o0       ! context_restore_arch returns 0
Index: uspace/lib/c/arch/sparc32/src/stacktrace.c
===================================================================
--- uspace/lib/c/arch/sparc32/src/stacktrace.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/src/stacktrace.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010 Jakub Jermar
+ * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2013 Jakub Klama
+ * 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 sparc32
+ * @{
+ */
+/** @file
+ */
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <libarch/stack.h>
+#include <errno.h>
+#include <stacktrace.h>
+
+#define FRAME_OFFSET_FP_PREV  (14 * 4)
+#define FRAME_OFFSET_RA       (15 * 4)
+
+bool stacktrace_fp_valid(stacktrace_t *st, uintptr_t fp)
+{
+	(void) st;
+	return fp != 0;
+}
+
+int stacktrace_fp_prev(stacktrace_t *st, uintptr_t fp, uintptr_t *prev)
+{
+	uintptr_t bprev;
+	int rc = (*st->read_uintptr)(st->op_arg, fp + FRAME_OFFSET_FP_PREV,
+	    &bprev);
+	if (rc == EOK)
+		*prev = bprev;
+	
+	return rc;
+}
+
+int stacktrace_ra_get(stacktrace_t *st, uintptr_t fp, uintptr_t *ra)
+{
+	return (*st->read_uintptr)(st->op_arg, fp + FRAME_OFFSET_RA, ra);
+}
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc32/src/stacktrace_asm.S
===================================================================
--- uspace/lib/c/arch/sparc32/src/stacktrace_asm.S	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/src/stacktrace_asm.S	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,63 @@
+#
+# Copyright (c) 2009 Jakub Jermar
+# 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 <libarch/stack.h>
+
+.text
+
+.global stacktrace_prepare
+.global stacktrace_fp_get
+.global stacktrace_pc_get
+
+stacktrace_prepare:
+	save %sp, -(STACK_WINDOW_SAVE_AREA_SIZE+STACK_ARG_SAVE_AREA_SIZE), %sp
+	
+	# Flush all other windows to memory so that we can read their contents.
+	
+	mov 7, %g1
+	1:
+		subcc %g1, 1, %g1
+		bg 1b
+		save %sp, -64, %sp
+	
+	mov 7, %g1
+	1:
+		subcc %g1, 1, %g1
+		bg 1b
+	
+	ret
+	restore
+
+stacktrace_fp_get:
+	# Add the stack bias to %sp to get the actual address.
+	retl
+	mov %sp,  %o0
+
+stacktrace_pc_get:
+	retl
+	mov %o7, %o0
Index: uspace/lib/c/arch/sparc32/src/thread_entry.s
===================================================================
--- uspace/lib/c/arch/sparc32/src/thread_entry.s	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/src/thread_entry.s	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,69 @@
+#
+# Copyright (c) 2006 Jakub Jermar
+# 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.
+#
+
+.text
+
+.globl __thread_entry
+
+## User-space thread entry point for all but the first threads.
+#
+#
+__thread_entry:
+	#
+	# Create the first stack frame.
+	#
+	
+	save %sp, -176, %sp
+	## XXX flushw
+	mov 7, %g1
+	1:
+		subcc %g1, 1, %g1
+		bg 1b
+		save %sp, -64, %sp
+	
+	mov 7, %g1
+	1:
+		subcc %g1, 1, %g1
+		bg 1b
+	
+	## XXX end flushw
+	set 0x80000000, %fp
+	
+	#
+	# Propagate the input arguments to the new window.
+	#
+	
+	mov %i0, %o0
+	
+	sethi %hi(_gp), %l7
+	call __thread_main      ! %o0 contains address of uarg
+	or %l7, %lo(_gp), %l7
+	
+	! not reached
+	
+.end __thread_entry
Index: uspace/lib/c/arch/sparc32/src/tls.c
===================================================================
--- uspace/lib/c/arch/sparc32/src/tls.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/arch/sparc32/src/tls.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * 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 libcsparc32 sparc32
+ * @ingroup lc
+ * @{
+ */
+/** @file
+ *
+ */
+
+#include <tls.h>
+#include <sys/types.h>
+
+tcb_t *tls_alloc_arch(void **data, size_t size)
+{
+	return tls_alloc_variant_2(data, size);
+}
+
+void tls_free_arch(tcb_t *tcb, size_t size)
+{
+	tls_free_variant_2(tcb, size);
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/adt/checksum.c
===================================================================
--- uspace/lib/c/generic/adt/checksum.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/generic/adt/checksum.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2012 Dominik Taborsky
+ * 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 <adt/checksum.h>
+
+/**
+ * 256-value table of precomputed polynomials for CRC32. Note
+ * the values depend on the selected divisor polynomial (currently
+ * 0xedb88320) and whether the CRC computation is reflected or not.
+ * See http://www.repairfaq.org/filipg/LINK/F_crc_v3.html for a perfect
+ * source of info about this.
+ */
+uint32_t poly_table[256] = {
+	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+	0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+	0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+	0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+	0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+	0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+	0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+	0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+	0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+	0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+	0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+	0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+	0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+	0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+	0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+	0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+	0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+	0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+	0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+	0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+	0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+	0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+	0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+	0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+	0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+	0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+	0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+	0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+	0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+	0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+	0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+	0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+/** Compute CRC32 value.
+ *
+ * See wiki.osdev.org/CRC32 for reference.
+ *
+ * @param[in] data   Data to process.
+ * @param[in] length Length of the data in bytes.
+ *
+ * @return Computed CRC32 of the data.
+ *
+ */
+uint32_t compute_crc32(uint8_t *data, size_t length)
+{
+	return compute_crc32_seed(data, length, 0);
+}
+
+/** Compute CRC32 value with initial seed.
+ *
+ * Use this when checksumming non-continous data (linked lists, trees,
+ * etc.). On the first data block call compute_crc32() and use the result
+ * as the seed for the following call of compute_crc32_seed() on the next
+ * block. Then use the result of that call as the seed of the following
+ * call, etc.
+ *
+ * @param[in] data   Fata to process.
+ * @param[in] length Length of the data in bytes.
+ * @param[in] seed   The starting value of the CRC.
+ *
+ * @return Computed CRC32 of the data of all the previous blocks.
+ *
+ */
+uint32_t compute_crc32_seed(uint8_t *data, size_t length, uint32_t seed)
+{
+	uint32_t crc;
+	
+	for (crc = ~seed; length > 0; length--)
+		crc = poly_table[((uint8_t) crc ^ *(data++))] ^ (crc >> 8);
+	
+	return (~crc);
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/bitops.c
===================================================================
--- uspace/lib/c/generic/bitops.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,42 +1,0 @@
-/*
- * Copyright (c) 2013 Vojtech Horky
- * 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
- * @{
- */
-
-#include <bitops.h>
-
-extern int __popcountsi2(int a)
-{
-	return __builtin_popcount(a);
-}
-
-
-/** @}
- */
Index: uspace/lib/c/generic/dhcp.c
===================================================================
--- uspace/lib/c/generic/dhcp.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/generic/dhcp.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013 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
+ */
+
+#include <async.h>
+#include <assert.h>
+#include <errno.h>
+#include <inet/dhcp.h>
+#include <ipc/dhcp.h>
+#include <ipc/services.h>
+#include <loc.h>
+#include <stdlib.h>
+
+static async_sess_t *dhcp_sess = NULL;
+
+int dhcp_init(void)
+{
+	service_id_t dhcp_svc;
+	int rc;
+
+	assert(dhcp_sess == NULL);
+
+	rc = loc_service_get_id(SERVICE_NAME_DHCP, &dhcp_svc,
+	    IPC_FLAG_BLOCKING);
+	if (rc != EOK)
+		return ENOENT;
+
+	dhcp_sess = loc_service_connect(EXCHANGE_SERIALIZE, dhcp_svc,
+	    IPC_FLAG_BLOCKING);
+	if (dhcp_sess == NULL)
+		return ENOENT;
+
+	return EOK;
+}
+
+int dhcp_link_add(sysarg_t link_id)
+{
+	async_exch_t *exch = async_exchange_begin(dhcp_sess);
+
+	int rc = async_req_1_0(exch, DHCP_LINK_ADD, link_id);
+	async_exchange_end(exch);
+
+	return rc;
+}
+
+int dhcp_link_remove(sysarg_t link_id)
+{
+	async_exch_t *exch = async_exchange_begin(dhcp_sess);
+
+	int rc = async_req_1_0(exch, DHCP_LINK_REMOVE, link_id);
+	async_exchange_end(exch);
+
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/dnsr.c
===================================================================
--- uspace/lib/c/generic/dnsr.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/generic/dnsr.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -67,5 +67,5 @@
 }
 
-int dnsr_name2host(const char *name, dnsr_hostinfo_t **rinfo, uint16_t af)
+int dnsr_name2host(const char *name, dnsr_hostinfo_t **rinfo, ip_ver_t ver)
 {
 	dnsr_hostinfo_t *info = calloc(1, sizeof(dnsr_hostinfo_t));
@@ -76,5 +76,5 @@
 	
 	ipc_call_t answer;
-	aid_t req = async_send_1(exch, DNSR_NAME2HOST, (sysarg_t) af,
+	aid_t req = async_send_1(exch, DNSR_NAME2HOST, (sysarg_t) ver,
 	    &answer);
 	
Index: uspace/lib/c/generic/inet.c
===================================================================
--- uspace/lib/c/generic/inet.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/generic/inet.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -30,5 +30,4 @@
 #include <assert.h>
 #include <errno.h>
-#include <net/socket_codes.h>
 #include <inet/inet.h>
 #include <ipc/inet.h>
Index: uspace/lib/c/generic/inet/addr.c
===================================================================
--- uspace/lib/c/generic/inet/addr.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/generic/inet/addr.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -33,4 +33,5 @@
  */
 
+#include <assert.h>
 #include <errno.h>
 #include <unistd.h>
@@ -59,10 +60,10 @@
 
 static const inet_addr_t inet_addr_any_addr = {
-	.family = AF_INET,
+	.version = ip_v4,
 	.addr = 0
 };
 
 static const inet_addr_t inet_addr_any_addr6 = {
-	.family = AF_INET6,
+	.version = ip_v6,
 	.addr6 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
 };
@@ -78,12 +79,20 @@
 }
 
+/** Compare addr48.
+  *
+  * @return Non-zero if equal, zero if not equal.
+  */
 int addr48_compare(const addr48_t a, const addr48_t b)
 {
-	return memcmp(a, b, 6);
-}
-
+	return memcmp(a, b, 6) == 0;
+}
+
+/** Compare addr128.
+  *
+  * @return Non-zero if equal, zero if not equal.
+  */
 int addr128_compare(const addr128_t a, const addr128_t b)
 {
-	return memcmp(a, b, 16);
+	return memcmp(a, b, 16) == 0;
 }
 
@@ -102,53 +111,15 @@
 void host2addr128_t_be(const addr128_t host, addr128_t be)
 {
-#ifdef __BE__
 	memcpy(be, host, 16);
-#else
-	be[0] = host[15];
-	be[1] = host[14];
-	be[2] = host[13];
-	be[3] = host[12];
-	be[4] = host[11];
-	be[5] = host[10];
-	be[6] = host[9];
-	be[7] = host[8];
-	be[8] = host[7];
-	be[9] = host[6];
-	be[10] = host[5];
-	be[11] = host[4];
-	be[12] = host[3];
-	be[13] = host[2];
-	be[14] = host[1];
-	be[15] = host[0];
-#endif
 }
 
 void addr128_t_be2host(const addr128_t be, addr128_t host)
 {
-#ifdef __BE__
 	memcpy(host, be, 16);
-#else
-	host[0] = be[15];
-	host[1] = be[14];
-	host[2] = be[13];
-	host[3] = be[12];
-	host[4] = be[11];
-	host[5] = be[10];
-	host[6] = be[9];
-	host[7] = be[8];
-	host[8] = be[7];
-	host[9] = be[6];
-	host[10] = be[5];
-	host[11] = be[4];
-	host[12] = be[3];
-	host[13] = be[2];
-	host[14] = be[1];
-	host[15] = be[0];
-#endif
 }
 
 void inet_addr(inet_addr_t *addr, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
 {
-	addr->family = AF_INET;
+	addr->version = ip_v4;
 	addr->addr = ((addr32_t) a << 24) | ((addr32_t) b << 16) |
 	    ((addr32_t) c << 8) | ((addr32_t) d);
@@ -158,5 +129,5 @@
     uint8_t prefix)
 {
-	naddr->family = AF_INET;
+	naddr->version = ip_v4;
 	naddr->addr = ((addr32_t) a << 24) | ((addr32_t) b << 16) |
 	    ((addr32_t) c << 8) | ((addr32_t) d);
@@ -167,5 +138,5 @@
     uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h)
 {
-	addr->family = AF_INET6;
+	addr->version = ip_v6;
 	addr->addr6[0] = (a >> 8) & 0xff;
 	addr->addr6[1] = a & 0xff;
@@ -189,5 +160,5 @@
     uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h, uint8_t prefix)
 {
-	naddr->family = AF_INET6;
+	naddr->version = ip_v6;
 	naddr->addr6[0] = (a >> 8) & 0xff;
 	naddr->addr6[1] = a & 0xff;
@@ -209,32 +180,62 @@
 }
 
-/** Parse network address family.
- *
- * @param text Network address in common notation.
- * @param af   Place to store network address family.
+/** Determine address version.
+ *
+ * @param text Address in common notation.
+ * @param af   Place to store address version.
  *
  * @return EOK on success, EINVAL if input is not in valid format.
  *
  */
-int inet_addr_family(const char *text, uint16_t *af)
+static int inet_addr_version(const char *text, ip_ver_t *ver)
 {
 	char *dot = str_chr(text, '.');
 	if (dot != NULL) {
-		*af = AF_INET;
+		*ver = ip_v4;
 		return EOK;
 	}
-	
+
 	char *collon = str_chr(text, ':');
 	if (collon != NULL) {
-		*af = AF_INET6;
+		*ver = ip_v6;
 		return EOK;
 	}
-	
+
 	return EINVAL;
 }
 
+static int ipver_af(ip_ver_t ver)
+{
+	switch (ver) {
+	case ip_any:
+		return AF_NONE;
+	case ip_v4:
+		return AF_INET;
+	case ip_v6:
+		return AF_INET6;
+	default:
+		assert(false);
+		return EINVAL;
+	}
+}
+
+ip_ver_t ipver_from_af(int af)
+{
+	switch (af) {
+	case AF_NONE:
+		return ip_any;
+	case AF_INET:
+		return ip_v4;
+	case AF_INET6:
+		return ip_v6;
+	default:
+		assert(false);
+		return EINVAL;
+	}
+}
+
 void inet_naddr_addr(const inet_naddr_t *naddr, inet_addr_t *addr)
 {
-	addr->family = naddr->family;
+	addr->version = naddr->version;
 	memcpy(addr->addr6, naddr->addr6, 16);
 }
@@ -243,5 +244,5 @@
     inet_naddr_t *naddr)
 {
-	naddr->family = addr->family;
+	naddr->version = addr->version;
 	memcpy(naddr->addr6, addr->addr6, 16);
 	naddr->prefix = prefix;
@@ -250,5 +251,5 @@
 void inet_addr_any(inet_addr_t *addr)
 {
-	addr->family = AF_NONE;
+	addr->version = ip_any;
 	memset(addr->addr6, 0, 16);
 }
@@ -256,5 +257,5 @@
 void inet_naddr_any(inet_naddr_t *naddr)
 {
-	naddr->family = AF_NONE;
+	naddr->version = ip_any;
 	memset(naddr->addr6, 0, 16);
 	naddr->prefix = 0;
@@ -263,11 +264,11 @@
 int inet_addr_compare(const inet_addr_t *a, const inet_addr_t *b)
 {
-	if (a->family != b->family)
+	if (a->version != b->version)
 		return 0;
-	
-	switch (a->family) {
-	case AF_INET:
+
+	switch (a->version) {
+	case ip_v4:
 		return (a->addr == b->addr);
-	case AF_INET6:
+	case ip_v6:
 		return addr128_compare(a->addr6, b->addr6);
 	default:
@@ -278,5 +279,5 @@
 int inet_addr_is_any(const inet_addr_t *addr)
 {
-	return ((addr->family == 0) ||
+	return ((addr->version == ip_any) ||
 	    (inet_addr_compare(addr, &inet_addr_any_addr)) ||
 	    (inet_addr_compare(addr, &inet_addr_any_addr6)));
@@ -285,11 +286,11 @@
 int inet_naddr_compare(const inet_naddr_t *naddr, const inet_addr_t *addr)
 {
-	if (naddr->family != addr->family)
+	if (naddr->version != addr->version)
 		return 0;
 	
-	switch (naddr->family) {
-	case AF_INET:
+	switch (naddr->version) {
+	case ip_v4:
 		return (naddr->addr == addr->addr);
-	case AF_INET6:
+	case ip_v6:
 		return addr128_compare(naddr->addr6, addr->addr6);
 	default:
@@ -300,16 +301,16 @@
 int inet_naddr_compare_mask(const inet_naddr_t *naddr, const inet_addr_t *addr)
 {
-	if (naddr->family != addr->family)
+	if (naddr->version != addr->version)
 		return 0;
-	
-	switch (naddr->family) {
-	case AF_INET:
+
+	switch (naddr->version) {
+	case ip_v4:
 		if (naddr->prefix > 32)
 			return 0;
-		
+
 		addr32_t mask =
 		    BIT_RANGE(addr32_t, 31, 31 - (naddr->prefix - 1));
 		return ((naddr->addr & mask) == (addr->addr & mask));
-	case AF_INET6:
+	case ip_v6:
 		if (naddr->prefix > 128)
 			return 0;
@@ -352,19 +353,19 @@
 int inet_addr_parse(const char *text, inet_addr_t *addr)
 {
-	int rc = inet_addr_family(text, &addr->family);
+	int rc = inet_addr_version(text, &addr->version);
 	if (rc != EOK)
 		return rc;
 	
 	uint8_t buf[16];
-	rc = inet_pton(addr->family, text, buf);
+	rc = inet_pton(ipver_af(addr->version), text, buf);
 	if (rc != EOK)
 		return rc;
 	
-	switch (addr->family) {
-	case AF_INET:
+	switch (addr->version) {
+	case ip_v4:
 		addr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) |
 		    buf[3];
 		break;
-	case AF_INET6:
+	case ip_v6:
 		memcpy(addr->addr6, buf, 16);
 		break;
@@ -392,10 +393,10 @@
 	*slash = 0;
 	
-	int rc = inet_addr_family(text, &naddr->family);
+	int rc = inet_addr_version(text, &naddr->version);
 	if (rc != EOK)
 		return rc;
 	
 	uint8_t buf[16];
-	rc = inet_pton(naddr->family, text, buf);
+	rc = inet_pton(ipver_af(naddr->version), text, buf);
 	*slash = '/';
 	
@@ -406,6 +407,6 @@
 	uint8_t prefix;
 	
-	switch (naddr->family) {
-	case AF_INET:
+	switch (naddr->version) {
+	case ip_v4:
 		prefix = strtoul(slash, &slash, 10);
 		if (prefix > 32)
@@ -417,5 +418,5 @@
 		
 		break;
-	case AF_INET6:
+	case ip_v6:
 		prefix = strtoul(slash, &slash, 10);
 		if (prefix > 128)
@@ -447,14 +448,14 @@
 	int rc = 0;
 	
-	switch (addr->family) {
-	case AF_NONE:
+	switch (addr->version) {
+	case ip_any:
 		rc = asprintf(bufp, "none");
 		break;
-	case AF_INET:
+	case ip_v4:
 		rc = asprintf(bufp, "%u.%u.%u.%u", (addr->addr >> 24) & 0xff,
 		    (addr->addr >> 16) & 0xff, (addr->addr >> 8) & 0xff,
 		    addr->addr & 0xff);
 		break;
-	case AF_INET6:
+	case ip_v6:
 		*bufp = (char *) malloc(INET6_ADDRSTRLEN);
 		if (*bufp == NULL)
@@ -487,9 +488,9 @@
 	char prefix[INET_PREFIXSTRSIZE];
 	
-	switch (naddr->family) {
-	case AF_NONE:
+	switch (naddr->version) {
+	case ip_any:
 		rc = asprintf(bufp, "none");
 		break;
-	case AF_INET:
+	case ip_v4:
 		rc = asprintf(bufp, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8
 		    "/%" PRIu8, (naddr->addr >> 24) & 0xff,
@@ -497,5 +498,5 @@
 		    naddr->addr & 0xff, naddr->prefix);
 		break;
-	case AF_INET6:
+	case ip_v6:
 		*bufp = (char *) malloc(INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE);
 		if (*bufp == NULL)
@@ -529,50 +530,50 @@
 }
 
-uint16_t inet_addr_get(const inet_addr_t *addr, addr32_t *v4, addr128_t *v6)
-{
-	switch (addr->family) {
-	case AF_INET:
+ip_ver_t inet_addr_get(const inet_addr_t *addr, addr32_t *v4, addr128_t *v6)
+{
+	switch (addr->version) {
+	case ip_v4:
 		if (v4 != NULL)
 			*v4 = addr->addr;
-		
-		break;
-	case AF_INET6:
+		break;
+	case ip_v6:
 		if (v6 != NULL)
 			memcpy(*v6, addr->addr6, 16);
-		
-		break;
-	}
-	
-	return addr->family;
-}
-
-uint16_t inet_naddr_get(const inet_naddr_t *naddr, addr32_t *v4, addr128_t *v6,
+		break;
+	default:
+		assert(false);
+		break;
+	}
+
+	return addr->version;
+}
+
+ip_ver_t inet_naddr_get(const inet_naddr_t *naddr, addr32_t *v4, addr128_t *v6,
     uint8_t *prefix)
 {
-	switch (naddr->family) {
-	case AF_INET:
+	switch (naddr->version) {
+	case ip_v4:
 		if (v4 != NULL)
 			*v4 = naddr->addr;
-		
 		if (prefix != NULL)
 			*prefix = naddr->prefix;
-		
-		break;
-	case AF_INET6:
+		break;
+	case ip_v6:
 		if (v6 != NULL)
 			memcpy(*v6, naddr->addr6, 16);
-		
 		if (prefix != NULL)
 			*prefix = naddr->prefix;
-		
-		break;
-	}
-	
-	return naddr->family;
+		break;
+	default:
+		assert(false);
+		break;
+	}
+
+	return naddr->version;
 }
 
 void inet_addr_set(addr32_t v4, inet_addr_t *addr)
 {
-	addr->family = AF_INET;
+	addr->version = ip_v4;
 	addr->addr = v4;
 }
@@ -580,5 +581,5 @@
 void inet_naddr_set(addr32_t v4, uint8_t prefix, inet_naddr_t *naddr)
 {
-	naddr->family = AF_INET;
+	naddr->version = ip_v4;
 	naddr->addr = v4;
 	naddr->prefix = prefix;
@@ -587,5 +588,5 @@
 void inet_sockaddr_in_addr(const sockaddr_in_t *sockaddr_in, inet_addr_t *addr)
 {
-	addr->family = AF_INET;
+	addr->version = ip_v4;
 	addr->addr = uint32_t_be2host(sockaddr_in->sin_addr.s_addr);
 }
@@ -593,5 +594,5 @@
 void inet_addr_set6(addr128_t v6, inet_addr_t *addr)
 {
-	addr->family = AF_INET6;
+	addr->version = ip_v6;
 	memcpy(addr->addr6, v6, 16);
 }
@@ -599,5 +600,5 @@
 void inet_naddr_set6(addr128_t v6, uint8_t prefix, inet_naddr_t *naddr)
 {
-	naddr->family = AF_INET6;
+	naddr->version = ip_v6;
 	memcpy(naddr->addr6, v6, 16);
 	naddr->prefix = prefix;
@@ -607,5 +608,5 @@
     inet_addr_t *addr)
 {
-	addr->family = AF_INET6;
+	addr->version = ip_v6;
 	addr128_t_be2host(sockaddr_in6->sin6_addr.s6_addr, addr->addr6);
 }
@@ -614,22 +615,64 @@
     sockaddr_in_t *sockaddr_in, sockaddr_in6_t *sockaddr_in6)
 {
-	switch (addr->family) {
-	case AF_INET:
+	switch (addr->version) {
+	case ip_v4:
 		if (sockaddr_in != NULL) {
 			sockaddr_in->sin_family = AF_INET;
 			sockaddr_in->sin_addr.s_addr = host2uint32_t_be(addr->addr);
 		}
-		
-		break;
-	case AF_INET6:
+		break;
+	case ip_v6:
 		if (sockaddr_in6 != NULL) {
 			sockaddr_in6->sin6_family = AF_INET6;
 			host2addr128_t_be(addr->addr6, sockaddr_in6->sin6_addr.s6_addr);
 		}
-		
-		break;
-	}
-	
-	return addr->family;
+		break;
+	default:
+		assert(false);
+		break;
+	}
+
+	return ipver_af(addr->version);
+}
+
+int inet_addr_sockaddr(const inet_addr_t *addr, uint16_t port,
+    sockaddr_t **nsockaddr, socklen_t *naddrlen)
+{
+	sockaddr_in_t *sa4;
+	sockaddr_in6_t *sa6;
+
+	switch (addr->version) {
+	case ip_v4:
+		sa4 = calloc(1, sizeof(sockaddr_in_t));
+		if (sa4 == NULL)
+			return ENOMEM;
+
+		sa4->sin_family = AF_INET;
+		sa4->sin_port = host2uint16_t_be(port);
+		sa4->sin_addr.s_addr = host2uint32_t_be(addr->addr);
+		if (nsockaddr != NULL)
+			*nsockaddr = (sockaddr_t *)sa4;
+		if (naddrlen != NULL)
+			*naddrlen = sizeof(*sa4);
+		break;
+	case ip_v6:
+		sa6 = calloc(1, sizeof(sockaddr_in6_t));
+		if (sa6 == NULL)
+			return ENOMEM;
+
+		sa6->sin6_family = AF_INET6;
+		sa6->sin6_port = host2uint16_t_be(port);
+		host2addr128_t_be(addr->addr6, sa6->sin6_addr.s6_addr);
+		if (nsockaddr != NULL)
+			*nsockaddr = (sockaddr_t *)sa6;
+		if (naddrlen != NULL)
+			*naddrlen = sizeof(*sa6);
+		break;
+	default:
+		assert(false);
+		break;
+	}
+
+	return EOK;
 }
 
Index: uspace/lib/c/generic/inetcfg.c
===================================================================
--- uspace/lib/c/generic/inetcfg.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/generic/inetcfg.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -267,4 +267,14 @@
 }
 
+int inetcfg_link_add(sysarg_t link_id)
+{
+	async_exch_t *exch = async_exchange_begin(inetcfg_sess);
+
+	int rc = async_req_1_0(exch, INETCFG_LINK_ADD, link_id);
+	async_exchange_end(exch);
+
+	return rc;
+}
+
 int inetcfg_link_get(sysarg_t link_id, inet_link_info_t *linfo)
 {
@@ -305,4 +315,14 @@
 }
 
+int inetcfg_link_remove(sysarg_t link_id)
+{
+	async_exch_t *exch = async_exchange_begin(inetcfg_sess);
+
+	int rc = async_req_1_0(exch, INETCFG_LINK_REMOVE, link_id);
+	async_exchange_end(exch);
+
+	return rc;
+}
+
 int inetcfg_sroute_create(const char *name, inet_naddr_t *dest,
     inet_addr_t *router, sysarg_t *sroute_id)
Index: uspace/lib/c/generic/inetping.c
===================================================================
--- uspace/lib/c/generic/inetping.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/generic/inetping.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -1,4 +1,5 @@
 /*
- * Copyright (c) 2012 Jiri Svoboda
+ * Copyright (c) 2013 Jiri Svoboda
+ * Copyright (c) 2013 Martin Decky
  * All rights reserved.
  *
@@ -49,22 +50,22 @@
 
 	assert(inetping_sess == NULL);
-	
+
 	inetping_ev_ops = ev_ops;
-	
+
 	rc = loc_service_get_id(SERVICE_NAME_INETPING, &inetping_svc,
 	    IPC_FLAG_BLOCKING);
 	if (rc != EOK)
 		return ENOENT;
-	
+
 	inetping_sess = loc_service_connect(EXCHANGE_SERIALIZE, inetping_svc,
 	    IPC_FLAG_BLOCKING);
 	if (inetping_sess == NULL)
 		return ENOENT;
-	
+
 	async_exch_t *exch = async_exchange_begin(inetping_sess);
 
 	rc = async_connect_to_me(exch, 0, 0, 0, inetping_cb_conn, NULL);
 	async_exchange_end(exch);
-	
+
 	if (rc != EOK) {
 		async_hangup(inetping_sess);
@@ -72,5 +73,5 @@
 		return rc;
 	}
-	
+
 	return EOK;
 }
@@ -79,55 +80,126 @@
 {
 	async_exch_t *exch = async_exchange_begin(inetping_sess);
-	
+
 	ipc_call_t answer;
-	aid_t req = async_send_3(exch, INETPING_SEND, (sysarg_t) sdu->src,
-	    (sysarg_t) sdu->dest, sdu->seq_no, &answer);
-	sysarg_t retval = async_data_write_start(exch, sdu->data, sdu->size);
-	
+	aid_t req = async_send_1(exch, INETPING_SEND, sdu->seq_no, &answer);
+
+	int rc = async_data_write_start(exch, &sdu->src, sizeof(sdu->src));
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		async_forget(req);
+		return rc;
+	}
+
+	rc = async_data_write_start(exch, &sdu->dest, sizeof(sdu->dest));
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		async_forget(req);
+		return rc;
+	}
+
+	rc = async_data_write_start(exch, sdu->data, sdu->size);
+
 	async_exchange_end(exch);
-	
-	if (retval != EOK) {
-		async_forget(req);
-		return retval;
-	}
-	
+
+	if (rc != EOK) {
+		async_forget(req);
+		return rc;
+	}
+
+	sysarg_t retval;
 	async_wait_for(req, &retval);
-	return retval;
-}
-
-int inetping_get_srcaddr(uint32_t remote, uint32_t *local)
+
+	return (int) retval;
+}
+
+int inetping_get_srcaddr(const inet_addr_t *remote, inet_addr_t *local)
 {
 	async_exch_t *exch = async_exchange_begin(inetping_sess);
-	
-	sysarg_t local_addr;
-	int rc = async_req_1_1(exch, INETPING_GET_SRCADDR, (sysarg_t) remote,
-	    &local_addr);
-	
+
+	ipc_call_t answer;
+	aid_t req = async_send_0(exch, INETPING_GET_SRCADDR, &answer);
+
+	int rc = async_data_write_start(exch, remote, sizeof(*remote));
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		async_forget(req);
+		return rc;
+	}
+
+	ipc_call_t answer_local;
+	aid_t req_local = async_data_read(exch, local, sizeof(*local),
+	    &answer_local);
+
 	async_exchange_end(exch);
-	
-	if (rc != EOK)
-		return rc;
-	
-	*local = (uint32_t) local_addr;
-	return EOK;
-}
-
-static void inetping_ev_recv(ipc_callid_t callid, ipc_call_t *call)
+
+	sysarg_t retval_local;
+	async_wait_for(req_local, &retval_local);
+
+	if (retval_local != EOK) {
+		async_forget(req);
+		return (int) retval_local;
+	}
+
+	sysarg_t retval;
+	async_wait_for(req, &retval);
+
+	return (int) retval;
+}
+
+static void inetping_ev_recv(ipc_callid_t iid, ipc_call_t *icall)
 {
 	inetping_sdu_t sdu;
-	
-	sdu.src = IPC_GET_ARG1(*call);
-	sdu.dest = IPC_GET_ARG2(*call);
-	sdu.seq_no = IPC_GET_ARG3(*call);
-	
-	int rc = async_data_write_accept(&sdu.data, false, 0, 0, 0, &sdu.size);
+
+	sdu.seq_no = IPC_GET_ARG1(*icall);
+
+	ipc_callid_t callid;
+	size_t size;
+	if (!async_data_write_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+
+	if (size != sizeof(sdu.src)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	int rc = async_data_write_finalize(callid, &sdu.src, size);
 	if (rc != EOK) {
 		async_answer_0(callid, rc);
-		return;
-	}
-	
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	if (!async_data_write_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+
+	if (size != sizeof(sdu.dest)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	rc = async_data_write_finalize(callid, &sdu.dest, size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	rc = async_data_write_accept(&sdu.data, false, 0, 0, 0, &sdu.size);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
 	rc = inetping_ev_ops->recv(&sdu);
 	free(sdu.data);
-	async_answer_0(callid, rc);
+	async_answer_0(iid, rc);
 }
 
Index: uspace/lib/c/generic/inetping6.c
===================================================================
--- uspace/lib/c/generic/inetping6.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,225 +1,0 @@
-/*
- * Copyright (c) 2013 Martin Decky
- * 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/inetping6.h>
-#include <ipc/inet.h>
-#include <ipc/services.h>
-#include <loc.h>
-#include <stdlib.h>
-#include <str.h>
-
-static void inetping6_cb_conn(ipc_callid_t, ipc_call_t *, void *);
-static void inetping6_ev_recv(ipc_callid_t, ipc_call_t *);
-
-static async_sess_t *inetping6_sess = NULL;
-static inetping6_ev_ops_t *inetping6_ev_ops;
-
-int inetping6_init(inetping6_ev_ops_t *ev_ops)
-{
-	assert(inetping6_sess == NULL);
-	
-	inetping6_ev_ops = ev_ops;
-	
-	service_id_t inetping6_svc;
-	int rc = loc_service_get_id(SERVICE_NAME_INETPING6, &inetping6_svc,
-	    IPC_FLAG_BLOCKING);
-	if (rc != EOK)
-		return ENOENT;
-	
-	inetping6_sess = loc_service_connect(EXCHANGE_SERIALIZE, inetping6_svc,
-	    IPC_FLAG_BLOCKING);
-	if (inetping6_sess == NULL)
-		return ENOENT;
-	
-	async_exch_t *exch = async_exchange_begin(inetping6_sess);
-	
-	rc = async_connect_to_me(exch, 0, 0, 0, inetping6_cb_conn, NULL);
-	async_exchange_end(exch);
-	
-	if (rc != EOK) {
-		async_hangup(inetping6_sess);
-		inetping6_sess = NULL;
-		return rc;
-	}
-	
-	return EOK;
-}
-
-int inetping6_send(inetping6_sdu_t *sdu)
-{
-	async_exch_t *exch = async_exchange_begin(inetping6_sess);
-	
-	ipc_call_t answer;
-	aid_t req = async_send_1(exch, INETPING6_SEND, sdu->seq_no, &answer);
-	
-	int rc = async_data_write_start(exch, &sdu->src, sizeof(addr128_t));
-	if (rc != EOK) {
-		async_exchange_end(exch);
-		async_forget(req);
-		return rc;
-	}
-	
-	rc = async_data_write_start(exch, &sdu->dest, sizeof(addr128_t));
-	if (rc != EOK) {
-		async_exchange_end(exch);
-		async_forget(req);
-		return rc;
-	}
-	
-	rc = async_data_write_start(exch, sdu->data, sdu->size);
-	
-	async_exchange_end(exch);
-	
-	if (rc != EOK) {
-		async_forget(req);
-		return rc;
-	}
-	
-	sysarg_t retval;
-	async_wait_for(req, &retval);
-	
-	return (int) retval;
-}
-
-int inetping6_get_srcaddr(addr128_t remote, addr128_t local)
-{
-	async_exch_t *exch = async_exchange_begin(inetping6_sess);
-	
-	ipc_call_t answer;
-	aid_t req = async_send_0(exch, INETPING6_GET_SRCADDR, &answer);
-	
-	int rc = async_data_write_start(exch, remote, sizeof(addr128_t));
-	if (rc != EOK) {
-		async_exchange_end(exch);
-		async_forget(req);
-		return rc;
-	}
-	
-	ipc_call_t answer_local;
-	aid_t req_local = async_data_read(exch, local, sizeof(addr128_t),
-	    &answer_local);
-	
-	async_exchange_end(exch);
-	
-	sysarg_t retval_local;
-	async_wait_for(req_local, &retval_local);
-	
-	if (retval_local != EOK) {
-		async_forget(req);
-		return (int) retval_local;
-	}
-	
-	sysarg_t retval;
-	async_wait_for(req, &retval);
-	
-	return (int) retval;
-}
-
-static void inetping6_ev_recv(ipc_callid_t iid, ipc_call_t *icall)
-{
-	inetping6_sdu_t sdu;
-	
-	sdu.seq_no = IPC_GET_ARG1(*icall);
-	
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_write_receive(&callid, &size)) {
-		async_answer_0(callid, EREFUSED);
-		async_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	if (size != sizeof(addr128_t)) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	int rc = async_data_write_finalize(callid, &sdu.src, size);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	if (!async_data_write_receive(&callid, &size)) {
-		async_answer_0(callid, EREFUSED);
-		async_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	if (size != sizeof(addr128_t)) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	rc = async_data_write_finalize(callid, &sdu.dest, size);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	rc = async_data_write_accept(&sdu.data, false, 0, 0, 0, &sdu.size);
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	rc = inetping6_ev_ops->recv(&sdu);
-	free(sdu.data);
-	async_answer_0(iid, rc);
-}
-
-static void inetping6_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 INETPING6_EV_RECV:
-			inetping6_ev_recv(callid, &call);
-			break;
-		default:
-			async_answer_0(callid, ENOTSUP);
-		}
-	}
-}
-
-/** @}
- */
Index: uspace/lib/c/generic/iplink.c
===================================================================
--- uspace/lib/c/generic/iplink.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/generic/iplink.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -218,5 +218,5 @@
 	iplink_recv_sdu_t sdu;
 	
-	uint16_t af = IPC_GET_ARG1(*icall);
+	ip_ver_t ver = IPC_GET_ARG1(*icall);
 	
 	int rc = async_data_write_accept(&sdu.data, false, 0, 0, 0,
@@ -227,5 +227,5 @@
 	}
 	
-	rc = iplink->ev_ops->recv(iplink, &sdu, af);
+	rc = iplink->ev_ops->recv(iplink, &sdu, ver);
 	free(sdu.data);
 	async_answer_0(iid, rc);
Index: uspace/lib/c/generic/iplink_srv.c
===================================================================
--- uspace/lib/c/generic/iplink_srv.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/generic/iplink_srv.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -272,5 +272,6 @@
 }
 
-int iplink_ev_recv(iplink_srv_t *srv, iplink_recv_sdu_t *sdu, uint16_t af)
+/* XXX Version should be part of @a sdu */
+int iplink_ev_recv(iplink_srv_t *srv, iplink_recv_sdu_t *sdu, ip_ver_t ver)
 {
 	if (srv->client_sess == NULL)
@@ -280,5 +281,5 @@
 	
 	ipc_call_t answer;
-	aid_t req = async_send_1(exch, IPLINK_EV_RECV, (sysarg_t) af,
+	aid_t req = async_send_1(exch, IPLINK_EV_RECV, (sysarg_t)ver,
 	    &answer);
 	
Index: uspace/lib/c/generic/rtld/module.c
===================================================================
--- uspace/lib/c/generic/rtld/module.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/generic/rtld/module.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -93,5 +93,4 @@
 module_t *module_find(const char *name)
 {
-	module_t *m;
 	const char *p, *soname;
 
@@ -107,7 +106,6 @@
 
 	/* Traverse list of all modules. Not extremely fast, but simple */
-	list_foreach(runtime_env->modules, cur) {
-		DPRINTF("cur = %p\n", cur);
-		m = list_get_instance(cur, module_t, modules_link);
+	list_foreach(runtime_env->modules, modules_link, module_t, m) {
+		DPRINTF("m = %p\n", m);
 		if (str_cmp(m->dyn.soname, soname) == 0) {
 			return m; /* Found */
@@ -245,9 +243,5 @@
 void modules_process_relocs(module_t *start)
 {
-	module_t *m;
-
-	list_foreach(runtime_env->modules, cur) {
-		m = list_get_instance(cur, module_t, modules_link);
-
+	list_foreach(runtime_env->modules, modules_link, module_t, m) {
 		/* Skip rtld, since it has already been processed */
 		if (m != &runtime_env->rtld) {
@@ -261,8 +255,5 @@
 void modules_untag(void)
 {
-	module_t *m;
-
-	list_foreach(runtime_env->modules, cur) {
-		m = list_get_instance(cur, module_t, modules_link);
+	list_foreach(runtime_env->modules, modules_link, module_t, m) {
 		m->bfs_tag = false;
 	}
Index: uspace/lib/c/generic/setjmp.c
===================================================================
--- uspace/lib/c/generic/setjmp.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/generic/setjmp.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 Long jump implementation.
+ *
+ * Implementation inspired by Jiri Zarevucky's code from
+ * http://bazaar.launchpad.net/~zarevucky-jiri/helenos/stdc/revision/1544/uspace/lib/posix/setjmp.h
+ */
+
+#include <setjmp.h>
+#include <libarch/fibril.h>
+#include <fibril.h>
+
+/**
+ * Restore environment previously stored by setjmp.
+ *
+ * This function never returns.
+ *
+ * @param env Variable with the environment previously stored by call
+ * to setjmp.
+ * @param val Value to fake when returning from setjmp (0 is transformed to 1).
+ */
+void longjmp(jmp_buf env, int val) {
+	env[0].return_value = (val == 0) ? 1 : val;
+	context_restore(&env[0].context);
+	__builtin_unreachable();
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -342,5 +342,5 @@
 }
 
-ssize_t read(int fildes, void *buf, size_t nbyte) 
+ssize_t read(int fildes, void *buf, size_t nbyte)
 {
 	sysarg_t rc;
@@ -348,8 +348,11 @@
 	aid_t req;
 	
+	if (nbyte > DATA_XFER_LIMIT)
+		nbyte = DATA_XFER_LIMIT;
+	
 	async_exch_t *exch = vfs_exchange_begin();
 	
 	req = async_send_1(exch, VFS_IN_READ, fildes, &answer);
-	rc = async_data_read_start(exch, (void *)buf, nbyte);
+	rc = async_data_read_start(exch, (void *) buf, nbyte);
 	if (rc != EOK) {
 		vfs_exchange_end(exch);
@@ -377,8 +380,11 @@
 	aid_t req;
 	
+	if (nbyte > DATA_XFER_LIMIT)
+		nbyte = DATA_XFER_LIMIT;
+	
 	async_exch_t *exch = vfs_exchange_begin();
 	
 	req = async_send_1(exch, VFS_IN_WRITE, fildes, &answer);
-	rc = async_data_write_start(exch, (void *)buf, nbyte);
+	rc = async_data_write_start(exch, (void *) buf, nbyte);
 	if (rc != EOK) {
 		vfs_exchange_end(exch);
@@ -736,4 +742,9 @@
 }
 
+int remove(const char *path)
+{
+	return unlink(path);
+}
+
 int chdir(const char *path)
 {
Index: uspace/lib/c/include/adt/checksum.h
===================================================================
--- uspace/lib/c/include/adt/checksum.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/include/adt/checksum.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012 Dominik Taborsky
+ * 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_CHECKSUM_H_
+#define LIBC_CHECKSUM_H_
+
+#include <sys/types.h>
+
+extern uint32_t compute_crc32(uint8_t *, size_t);
+extern uint32_t compute_crc32_seed(uint8_t *, size_t, uint32_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/adt/list.h
===================================================================
--- uspace/lib/c/include/adt/list.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/include/adt/list.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -38,4 +38,5 @@
 
 #include <assert.h>
+#include <stdbool.h>
 #include <unistd.h>
 
@@ -72,4 +73,10 @@
 	    iterator = list_get_instance(_link, itype, member), \
 	    _link != &(list).head; _link = _link->next)
+
+#define list_foreach_rev(list, member, itype, iterator) \
+	for (itype *iterator = NULL; iterator == NULL; iterator = (itype *) 1) \
+	    for (link_t *_link = (list).head.prev; \
+	    iterator = list_get_instance(_link, itype, member), \
+	    _link != &(list).head; _link = _link->prev)
 
 /** Unlike list_foreach(), allows removing items while traversing a list.
@@ -105,5 +112,5 @@
 
 #define assert_link_not_used(link) \
-	assert(((link)->prev == NULL) && ((link)->next == NULL))
+	assert(!link_used(link))
 
 /** Returns true if the link is definitely part of a list. False if not sure. */
@@ -357,4 +364,18 @@
 }
 
+/** Determine if link is used.
+ *
+ * @param link Link
+ * @return @c true if link is used, @c false if not.
+ */
+static inline bool link_used(link_t *link)
+{
+	if (link->prev == NULL && link->next == NULL)
+		return false;
+
+	assert(link->prev != NULL && link->next != NULL);
+	return true;
+}
+
 extern int list_member(const link_t *, const list_t *);
 extern void list_concat(list_t *, list_t *);
Index: uspace/lib/c/include/bitops.h
===================================================================
--- uspace/lib/c/include/bitops.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/include/bitops.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -107,6 +107,4 @@
 }
 
-extern int __popcountsi2(int);
-
 #endif
 
Index: uspace/lib/c/include/inet/addr.h
===================================================================
--- uspace/lib/c/include/inet/addr.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/include/inet/addr.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -39,4 +39,5 @@
 #include <net/in.h>
 #include <net/in6.h>
+#include <net/socket.h>
 
 typedef uint32_t addr32_t;
@@ -44,7 +45,17 @@
 typedef uint8_t addr128_t[16];
 
+typedef enum {
+	/** Any IP protocol version */
+	ip_any,
+	/** IPv4 */
+	ip_v4,
+	/** IPv6 */
+	ip_v6
+} ip_ver_t;
+
 /** Node address */
 typedef struct {
-	uint16_t family;
+	/** IP version */
+	ip_ver_t version;
 	union {
 		addr32_t addr;
@@ -55,6 +66,6 @@
 /** Network address */
 typedef struct {
-	/** Address family */
-	uint16_t family;
+	/** IP version */
+	ip_ver_t version;
 	
 	/** Address */
@@ -91,5 +102,4 @@
     uint16_t, uint16_t, uint16_t, uint16_t, uint8_t);
 
-extern int inet_addr_family(const char *, uint16_t *);
 extern void inet_naddr_addr(const inet_naddr_t *, inet_addr_t *);
 extern void inet_addr_naddr(const inet_addr_t *, uint8_t, inet_naddr_t *);
@@ -110,6 +120,6 @@
 extern int inet_naddr_format(const inet_naddr_t *, char **);
 
-extern uint16_t inet_addr_get(const inet_addr_t *, addr32_t *, addr128_t *);
-extern uint16_t inet_naddr_get(const inet_naddr_t *, addr32_t *, addr128_t *,
+extern ip_ver_t inet_addr_get(const inet_addr_t *, addr32_t *, addr128_t *);
+extern ip_ver_t inet_naddr_get(const inet_naddr_t *, addr32_t *, addr128_t *,
     uint8_t *);
 
@@ -125,4 +135,8 @@
     sockaddr_in6_t *);
 
+extern ip_ver_t ipver_from_af(int af);
+extern int inet_addr_sockaddr(const inet_addr_t *, uint16_t, sockaddr_t **,
+    socklen_t *);
+
 #endif
 
Index: uspace/lib/c/include/inet/dhcp.h
===================================================================
--- uspace/lib/c/include/inet/dhcp.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/include/inet/dhcp.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 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_DHCP_H_
+#define LIBC_INET_DHCP_H_
+
+#include <sys/types.h>
+
+extern int dhcp_init(void);
+extern int dhcp_link_add(sysarg_t);
+extern int dhcp_link_remove(sysarg_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/inet/dnsr.h
===================================================================
--- uspace/lib/c/include/inet/dnsr.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/include/inet/dnsr.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -51,5 +51,5 @@
 
 extern int dnsr_init(void);
-extern int dnsr_name2host(const char *, dnsr_hostinfo_t **, uint16_t);
+extern int dnsr_name2host(const char *, dnsr_hostinfo_t **, ip_ver_t);
 extern void dnsr_hostinfo_destroy(dnsr_hostinfo_t *);
 extern int dnsr_get_srvaddr(inet_addr_t *);
Index: uspace/lib/c/include/inet/inetcfg.h
===================================================================
--- uspace/lib/c/include/inet/inetcfg.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/include/inet/inetcfg.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -48,5 +48,7 @@
 extern int inetcfg_get_link_list(sysarg_t **, size_t *);
 extern int inetcfg_get_sroute_list(sysarg_t **, size_t *);
+extern int inetcfg_link_add(sysarg_t);
 extern int inetcfg_link_get(sysarg_t, inet_link_info_t *);
+extern int inetcfg_link_remove(sysarg_t);
 extern int inetcfg_sroute_get(sysarg_t, inet_sroute_info_t *);
 extern int inetcfg_sroute_get_id(const char *, sysarg_t *);
Index: uspace/lib/c/include/inet/inetping.h
===================================================================
--- uspace/lib/c/include/inet/inetping.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/include/inet/inetping.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2012 Jiri Svoboda
+ * Copyright (c) 2013 Jiri Svoboda
  * All rights reserved.
  *
@@ -38,12 +38,5 @@
 #include <inet/inet.h>
 #include <sys/types.h>
-
-typedef struct {
-	uint32_t src;
-	uint32_t dest;
-	uint16_t seq_no;
-	void *data;
-	size_t size;
-} inetping_sdu_t;
+#include <types/inetping.h>
 
 typedef struct inetping_ev_ops {
@@ -53,5 +46,5 @@
 extern int inetping_init(inetping_ev_ops_t *);
 extern int inetping_send(inetping_sdu_t *);
-extern int inetping_get_srcaddr(uint32_t, uint32_t *);
+extern int inetping_get_srcaddr(const inet_addr_t *, inet_addr_t *);
 
 #endif
Index: uspace/lib/c/include/inet/inetping6.h
===================================================================
--- uspace/lib/c/include/inet/inetping6.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,60 +1,0 @@
-/*
- * Copyright (c) 2013 Martin Decky
- * 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_INETPING6_H_
-#define LIBC_INET_INETPING6_H_
-
-#include <inet/inet.h>
-#include <sys/types.h>
-
-typedef struct {
-	addr128_t src;
-	addr128_t dest;
-	uint16_t seq_no;
-	void *data;
-	size_t size;
-} inetping6_sdu_t;
-
-typedef struct inetping6_ev_ops {
-	int (*recv)(inetping6_sdu_t *);
-} inetping6_ev_ops_t;
-
-extern int inetping6_init(inetping6_ev_ops_t *);
-extern int inetping6_send(inetping6_sdu_t *);
-extern int inetping6_get_srcaddr(addr128_t, addr128_t);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/include/inet/iplink.h
===================================================================
--- uspace/lib/c/include/inet/iplink.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/include/inet/iplink.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -37,5 +37,4 @@
 
 #include <async.h>
-#include <sys/types.h>
 #include <inet/addr.h>
 
@@ -78,5 +77,5 @@
 
 typedef struct iplink_ev_ops {
-	int (*recv)(iplink_t *, iplink_recv_sdu_t *, uint16_t);
+	int (*recv)(iplink_t *, iplink_recv_sdu_t *, ip_ver_t);
 } iplink_ev_ops_t;
 
Index: uspace/lib/c/include/inet/iplink_srv.h
===================================================================
--- uspace/lib/c/include/inet/iplink_srv.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/include/inet/iplink_srv.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -39,5 +39,4 @@
 #include <fibril_synch.h>
 #include <stdbool.h>
-#include <sys/types.h>
 #include <inet/addr.h>
 #include <inet/iplink.h>
@@ -67,5 +66,5 @@
 
 extern int iplink_conn(ipc_callid_t, ipc_call_t *, void *);
-extern int iplink_ev_recv(iplink_srv_t *, iplink_recv_sdu_t *, uint16_t);
+extern int iplink_ev_recv(iplink_srv_t *, iplink_recv_sdu_t *, ip_ver_t);
 
 #endif
Index: uspace/lib/c/include/ipc/dhcp.h
===================================================================
--- uspace/lib/c/include/ipc/dhcp.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/include/ipc/dhcp.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013 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_DHCP_H_
+#define LIBC_IPC_DHCP_H_
+
+#include <ipc/common.h>
+
+/** DHCP service requests */
+typedef enum {
+	DHCP_LINK_ADD = IPC_FIRST_USER_METHOD,
+	DHCP_LINK_REMOVE
+} dhcp_request_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/c/include/ipc/inet.h
===================================================================
--- uspace/lib/c/include/ipc/inet.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/include/ipc/inet.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -72,5 +72,7 @@
 	INETCFG_GET_LINK_LIST,
 	INETCFG_GET_SROUTE_LIST,
+	INETCFG_LINK_ADD,
 	INETCFG_LINK_GET,
+	INETCFG_LINK_REMOVE,
 	INETCFG_SROUTE_CREATE,
 	INETCFG_SROUTE_DELETE,
@@ -90,15 +92,4 @@
 } inetping_request_t;
 
-/** Events on Inet ping6 port */
-typedef enum {
-	INETPING6_EV_RECV = IPC_FIRST_USER_METHOD
-} inetping6_event_t;
-
-/** Requests on Inet ping6 port */
-typedef enum {
-	INETPING6_SEND = IPC_FIRST_USER_METHOD,
-	INETPING6_GET_SRCADDR
-} inetping6_request_t;
-
 #endif
 
Index: uspace/lib/c/include/ipc/services.h
===================================================================
--- uspace/lib/c/include/ipc/services.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/include/ipc/services.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -54,4 +54,5 @@
 
 #define SERVICE_NAME_CORECFG	"corecfg"
+#define SERVICE_NAME_DHCP       "net/dhcp"
 #define SERVICE_NAME_DNSR       "net/dnsr"
 #define SERVICE_NAME_INET       "net/inet"
@@ -59,4 +60,5 @@
 #define SERVICE_NAME_INETPING   "net/inetping"
 #define SERVICE_NAME_INETPING6  "net/inetping6"
+#define SERVICE_NAME_NETCONF    "net/netconf"
 
 #endif
Index: uspace/lib/c/include/math.h
===================================================================
--- uspace/lib/c/include/math.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/include/math.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011 Petr Koupy
+ * 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 libposix
+ * @{
+ */
+/** @file Mathematical operations.
+ *
+ * The implementation is provided by a separate library to allow
+ * switching of the implementations.
+ */
+
+#ifndef LIBC_MATH_H_
+#define LIBC_MATH_H_
+
+#ifdef __GNUC__
+	#define HUGE_VAL (__builtin_huge_val())
+#endif
+
+extern double ldexp(double, int);
+extern double frexp(double, int *);
+
+extern double fabs(double);
+extern double floor(double);
+extern double ceil(double);
+extern double modf(double, double *);
+extern double fmod(double, double);
+extern double pow(double, double);
+extern double exp(double);
+extern double expm1(double);
+extern double sqrt(double);
+extern double log(double);
+extern double log10(double);
+extern double sin(double);
+extern double sinh(double);
+extern double asin(double);
+extern double asinh(double);
+extern double cos(double);
+extern double cosh(double);
+extern double acos(double);
+extern double acosh(double);
+extern double tan(double);
+extern double tanh(double);
+extern double atan(double);
+extern double atanh(double);
+extern double atan2(double, double);
+
+double copysign(double, double);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/net/device.h
===================================================================
--- uspace/lib/c/include/net/device.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,58 +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 libc
- * @{
- */
-
-/** @file
- * Network device.
- */
-
-#ifndef LIBC_NET_DEVICE_H_
-#define LIBC_NET_DEVICE_H_
-
-#include <adt/int_map.h>
-#include <nic/nic.h>
-
-/** Device identifier to generic type map declaration. */
-#define DEVICE_MAP_DECLARE  INT_MAP_DECLARE
-
-/** Device identifier to generic type map implementation. */
-#define DEVICE_MAP_IMPLEMENT  INT_MAP_IMPLEMENT
-
-/** Device identifier type. */
-typedef int nic_device_id_t;
-
-/** Invalid device identifier. */
-#define NIC_DEVICE_INVALID_ID  (-1)
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/include/net/ip_codes.h
===================================================================
--- uspace/lib/c/include/net/ip_codes.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,118 +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 libc
- *  @{
- */
-
-/** @file
- * IP codes and definitions.
- */
-
-#ifndef LIBC_IP_CODES_H_
-#define LIBC_IP_CODES_H_
-
-#include <sys/types.h>
-
-/** IP time to live counter type definition. */
-typedef uint8_t ip_ttl_t;
-
-/** IP type of service type definition. */
-typedef uint8_t ip_tos_t;
-
-/** IP transport protocol type definition. */
-typedef uint8_t ip_protocol_t;
-
-/** Default IPVERSION. */
-#define IPVERSION	4
-
-/** Default time to live counter. */
-#define IPDEFTTL	64
-
-/** @name IP options definitions */
-/*@{*/
-
-/** Copy shift. */
-#define IPOPT_COPY_SHIFT	7
-
-/** Class shift. */
-#define IPOPT_CLASS_SHIFT	5
-
-/** Number shift. */
-#define IPOPT_NUMBER_SHIFT	0
-
-/** Class mask. */
-#define IPOPT_CLASS_MASK	0x60
-
-/** Number mask. */
-#define IPOPT_NUMBER_MASK	0x1f
-
-/** Copy flag. */
-#define IPOPT_COPY		(1 << IPOPT_COPY_SHIFT)
-
-/** Returns IP option type.
- *
- * @param[in] copy	The value indication whether the IP option should be
- *			copied.
- * @param[in] class	The IP option class.
- * @param[in] number	The IP option number.
- */
-#define IPOPT_TYPE(copy, class, number) \
-	(((copy) & IPOPT_COPY) | ((class) & IPOPT_CLASS_MASK) | \
-	(((number) << IPOPT_NUMBER_SHIFT) & IPOPT_NUMBER_MASK))
-
-/** Returns a value indicating whether the IP option should be copied.
- * @param[in] o The IP option.
- */
-#define IPOPT_COPIED(o)		((o) & IPOPT_COPY)
-
-/*@}*/
-
-/** @name IP option class definitions */
-/*@{*/
-
-/** Control class. */
-#define IPOPT_CONTROL		(0 << IPOPT_CLASS_SHIFT)
-
-/*@}*/
-
-/** @name IP option type definitions */
-/*@{*/
-
-/** End of list. */
-#define IPOPT_END		IPOPT_TYPE(0, IPOPT_CONTROL, 0)
-
-/** No operation. */
-#define IPOPT_NOOP		IPOPT_TYPE(0, IPOPT_CONTROL, 1)
-
-/*@}*/
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/include/setjmp.h
===================================================================
--- uspace/lib/c/include/setjmp.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/include/setjmp.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2008 Josef Cejka
+ * Copyright (c) 2013 Vojtech Horky
  * All rights reserved.
  *
@@ -30,5 +31,8 @@
  * @{
  */
-/** @file
+/** @file Long jump implementation.
+ *
+ * Implementation inspired by Jiri Zarevucky's code from
+ * http://bazaar.launchpad.net/~zarevucky-jiri/helenos/stdc/revision/1544/uspace/lib/posix/setjmp.h
  */
 
@@ -38,7 +42,31 @@
 #include <libarch/fibril.h>
 
-typedef context_t jmp_buf[1];
+struct jmp_buf_interal {
+	context_t context;
+	int return_value;
+};
+typedef struct jmp_buf_interal jmp_buf[1];
 
-extern int setjmp(jmp_buf env);
+/*
+ * Specified as extern to minimize number of included headers
+ * because this file is used as is in libposix too.
+ */
+extern int context_save(context_t *ctx) __attribute__((returns_twice));
+
+/**
+ * Save current environment (registers).
+ *
+ * This function may return twice.
+ *
+ * @param env Variable where to save the environment (of type jmp_buf).
+ * @return Whether the call returned after longjmp.
+ * @retval 0 Environment was saved, normal execution.
+ * @retval other longjmp was executed and returned here.
+ */
+#define setjmp(env) \
+	((env)[0].return_value = 0, \
+	context_save(&(env)[0].context), \
+	(env)[0].return_value)
+
 extern void longjmp(jmp_buf env, int val) __attribute__((noreturn));
 
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/c/include/stdio.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -151,4 +151,5 @@
 /* Misc file functions */
 extern int rename(const char *, const char *);
+extern int remove(const char *);
 
 #endif
Index: uspace/lib/c/include/types/inetping.h
===================================================================
--- uspace/lib/c/include/types/inetping.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/c/include/types/inetping.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013 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
+ * @brief
+ */
+
+#ifndef LIBC_TYPES_INETPING_H_
+#define LIBC_TYPES_INETPING_H_
+
+#include <inet/addr.h>
+#include <sys/types.h>
+
+typedef struct {
+	inet_addr_t src;
+	inet_addr_t dest;
+	uint16_t seq_no;
+	void *data;
+	size_t size;
+} inetping_sdu_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/gpt/Makefile
===================================================================
--- uspace/lib/gpt/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/gpt/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2011 Dominik Taborsky
+# 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 = ../..
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBMBR_PREFIX)
+LIBRARY = libgpt
+
+SOURCES = \
+	libgpt.c \
+	global.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/gpt/global.c
===================================================================
--- uspace/lib/gpt/global.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/gpt/global.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2011-2013 Dominik Taborsky
+ * 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 libgpt
+ * @{
+ */
+/** @file
+ */
+
+#include "libgpt.h"
+
+/** GPT header signature ("EFI PART" in ASCII) */
+const uint8_t efi_signature[8] = {
+	0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54
+};
+
+const uint8_t revision[4] = {
+	00, 00, 01, 00
+};
+
+const partition_type_t gpt_ptypes[] = {
+	{ "unused entry",                 "00000000" "0000" "0000" "0000000000000000" }, /* 0 */
+	{ "HelenOS System",               "3dc61fa0" "cf7a" "3ad8" "ac57615029d81a6b" }, /* "HelenOS System" encoded as RFC 4122 UUID, version 3 (MD5 name-based) */
+	{ "MBR partition scheme",         "024dee41" "33e7" "11d3" "9d690008c781f39f" },
+	{ "EFI System",                   "c12a7328" "f81f" "11d2" "ba4b00a0c93ec93b" },
+	{ "BIOS Boot",                    "21686148" "6449" "6e6f" "744e656564454649" },
+	{ "Windows Reserved",             "e3c9e316" "0b5c" "4db8" "817df92df00215ae" },
+	{ "Windows Basic data",           "ebd0a0a2" "b9e5" "4433" "87c068b6b72699c7" },
+	{ "Windows LDM metadata",         "5808c8aa" "7e8f" "42e0" "85d2e1e90434cfb3" },
+	{ "Windows LDM data",             "af9b60a0" "1431" "4f62" "bc683311714a69ad" },
+	{ "Windows Recovery Environment", "de94bba4" "06d1" "4d40" "a16abfd50179d6ac" },
+	{ "Windows IBM GPFS",             "37affc90" "ef7d" "4e96" "91c32d7ae055b174" }, /* 10 */
+	{ "Windows Cluster metadata",     "db97dba9" "0840" "4bae" "97f0ffb9a327c7e1" },
+	{ "HP-UX Data",                   "75894c1e" "3aeb" "11d3" "b7c17b03a0000000" },
+	{ "HP-UX Service",                "e2a1e728" "32e3" "11d6" "a6827b03a0000000" },
+	{ "Linux filesystem data",        "0fc63daf" "8483" "4772" "8e793d69d8477de4" },
+	{ "Linux RAID",                   "a19d880f" "05fc" "4d3b" "a006743f0f84911e" },
+	{ "Linux Swap",                   "0657fd6d" "a4ab" "43c4" "84e50933c84b4f4f" },
+	{ "Linux LVM",                    "e6d6d379" "f507" "44c2" "a23c238f2a3df928" },
+	{ "Linux filesystem data",        "933ac7e1" "2eb4" "4f13" "b8440e14e2aef915" },
+	{ "Linux Reserved",               "8da63339" "0007" "60c0" "c436083ac8230908" },
+	{ "FreeBSD Boot",                 "83bd6b9d" "7f41" "11dc" "be0b001560b84f0f" }, /* 20 */
+	{ "FreeBSD Data",                 "516e7cb4" "6ecf" "11d6" "8ff800022d09712b" },
+	{ "FreeBSD Swap",                 "516e7cb5" "6ecf" "11d6" "8ff800022d09712b" },
+	{ "FreeBSD UFS",                  "516e7cb6" "6ecf" "11d6" "8ff800022d09712b" },
+	{ "FreeBSD Vinum VM",             "516e7cb8" "6ecf" "11d6" "8ff800022d09712b" },
+	{ "FreeBSD ZFS",                  "516e7cba" "6ecf" "11d6" "8ff800022d09712b" },
+	{ "Mac OS X HFS+",                "48465300" "0000" "11aa" "aa1100306543ecac" },
+	{ "Mac OS X UFS",                 "55465300" "0000" "11aa" "aa1100306543ecac" },
+	{ "Mac OS X ZFS",                 "6a898cc3" "1dd2" "11b2" "99a6080020736631" },
+	{ "Mac OS X RAID",                "52414944" "0000" "11aa" "aa1100306543ecac" },
+	{ "Mac OS X RAID, offline",       "52414944" "5f4f" "11aa" "aa1100306543ecac" }, /* 30 */
+	{ "Mac OS X Boot",                "426f6f74" "0000" "11aa" "aa1100306543ecac" },
+	{ "Mac OS X Label",               "4c616265" "6c00" "11aa" "aa1100306543ecac" },
+	{ "Mac OS X TV Recovery",         "5265636f" "7665" "11aa" "aa1100306543ecac" },
+	{ "Mac OS X Core Storage",        "53746f72" "6167" "11aa" "aa1100306543ecac" },
+	{ "Solaris Boot",                 "6a82cb45" "1dd2" "11b2" "99a6080020736631" },
+	{ "Solaris Root",                 "6a85cf4d" "1dd2" "11b2" "99a6080020736631" },
+	{ "Solaris Swap",                 "6a87c46f" "1dd2" "11b2" "99a6080020736631" },
+	{ "Solaris Backup",               "6a8b642b" "1dd2" "11b2" "99a6080020736631" },
+	{ "Solaris /usr",                 "6a898cc3" "1dd2" "11b2" "99a6080020736631" },
+	{ "Solaris /var",                 "6a8ef2e9" "1dd2" "11b2" "99a6080020736631" }, /* 40 */
+	{ "Solaris /home",                "6a90ba39" "1dd2" "11b2" "99a6080020736631" },
+	{ "Solaris Alternate sector",     "6a9283a5" "1dd2" "11b2" "99a6080020736631" },
+	{ "Solaris Reserved",             "6a945a3b" "1dd2" "11b2" "99a6080020736631" },
+	{ "Solaris Reserved",             "6a9630d1" "1dd2" "11b2" "99a6080020736631" },
+	{ "Solaris Reserved",             "6a980767" "1dd2" "11b2" "99a6080020736631" },
+	{ "Solaris Reserved",             "6a96237f" "1dd2" "11b2" "99a6080020736631" },
+	{ "Solaris Reserved",             "6a8d2ac7" "1dd2" "11b2" "99a6080020736631" },
+	{ "NetBSD Swap",                  "49f48d32" "b10e" "11dc" "b99b0019d1879648" },
+	{ "NetBSD FFS",                   "49f48d5a" "b10e" "11dc" "b99b0019d1879648" },
+	{ "NetBSD LFS",                   "49f48d82" "b10e" "11dc" "b99b0019d1879648" }, /* 50 */
+	{ "NetBSD RAID",                  "49f48daa" "b10e" "11dc" "b99b0019d1879648" },
+	{ "NetBSD Concatenated",          "2db519c4" "b10f" "11dc" "b99b0019d1879648" },
+	{ "NetBSD Encrypted",             "2db519ec" "b10f" "11dc" "b99b0019d1879648" },
+	{ "ChromeOS ChromeOS kernel",     "fe3a2a5d" "4f32" "41a7" "b725accc3285a309" },
+	{ "ChromeOS rootfs",              "3cb8e202" "3b7e" "47dd" "8a3c7ff2a13cfcec" },
+	{ "ChromeOS future use",          "2e0a753d" "9e48" "43b0" "8337b15192cb1b5e" },
+	{ "MidnightBSD Boot",             "85d5e45e" "237c" "11e1" "b4b3e89a8f7fc3a7" },
+	{ "MidnightBSD Data",             "85d5e45a" "237c" "11e1" "b4b3e89a8f7fc3a7" },
+	{ "MidnightBSD Swap",             "85d5e45b" "237c" "11e1" "b4b3e89a8f7fc3a7" },
+	{ "MidnightBSD UFS",              "0394ef8b" "237e" "11e1" "b4b3e89a8f7fc3a7" }, /* 60 */
+	{ "MidnightBSD Vinum VM",         "85d5e45c" "237c" "11e1" "b4b3e89a8f7fc3a7" },
+	{ "MidnightBSD ZFS",              "85d5e45d" "237c" "11e1" "b4b3e89a8f7fc3a7" },
+	{ "unknown entry",                NULL } /* Keep this as the last entry */
+};
Index: uspace/lib/gpt/gpt.h
===================================================================
--- uspace/lib/gpt/gpt.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/gpt/gpt.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011-2013 Dominik Taborsky
+ * 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 libgpt
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBGPT_GPT_H_
+#define LIBGPT_GPT_H_
+
+typedef enum {
+	AT_REQ_PART = 0,
+	AT_NO_BLOCK_IO,
+	AT_LEGACY_BOOT,
+	AT_UNDEFINED,
+	AT_SPECIFIC = 48
+} gpt_attr_t;
+
+/** GPT header */
+typedef struct {
+	uint8_t efi_signature[8];
+	uint8_t revision[4];
+	uint32_t header_size;
+	uint32_t header_crc32;
+	uint32_t reserved;
+	uint64_t current_lba;
+	uint64_t alternate_lba;
+	uint64_t first_usable_lba;
+	uint64_t last_usable_lba;
+	uint8_t disk_guid[16];
+	uint64_t entry_lba;
+	uint32_t fillries;
+	uint32_t entry_size;
+	uint32_t pe_array_crc32;
+} __attribute__((packed)) gpt_header_t;
+
+/** GPT partition entry */
+typedef struct {
+	uint8_t part_type[16];
+	uint8_t part_id[16];
+	uint64_t start_lba;
+	uint64_t end_lba;
+	uint64_t attributes;
+	uint8_t part_name[72];
+} __attribute__((packed)) gpt_entry_t;
+
+#endif
Index: uspace/lib/gpt/libgpt.c
===================================================================
--- uspace/lib/gpt/libgpt.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/gpt/libgpt.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,853 @@
+/*
+ * Copyright (c) 2011-2013 Dominik Taborsky
+ * 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 libgpt
+ * @{
+ */
+/** @file
+ */
+
+/* TODO:
+ * The implementation currently supports fixed size partition entries only.
+ * The specification requires otherwise, though.
+ */
+
+#include <ipc/bd.h>
+#include <async.h>
+#include <stdio.h>
+#include <block.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <byteorder.h>
+#include <adt/checksum.h>
+#include <mem.h>
+#include <sys/typefmt.h>
+#include <mbr.h>
+#include <align.h>
+#include "libgpt.h"
+
+static int load_and_check_header(service_id_t, aoff64_t, size_t, gpt_header_t *);
+static gpt_partitions_t *alloc_part_array(uint32_t);
+static int extend_part_array(gpt_partitions_t *);
+static int reduce_part_array(gpt_partitions_t *);
+static uint8_t get_byte(const char *);
+static bool check_overlap(gpt_part_t *, gpt_part_t *);
+static bool check_encaps(gpt_part_t *, uint64_t, uint64_t);
+
+/** Allocate a GPT label */
+gpt_label_t *gpt_alloc_label(void)
+{
+	gpt_label_t *label = malloc(sizeof(gpt_label_t));
+	if (label == NULL)
+		return NULL;
+	
+	label->parts = gpt_alloc_partitions();
+	if (label->parts == NULL) {
+		free(label);
+		return NULL;
+	}
+	
+	label->gpt = NULL;
+	label->device = 0;
+	
+	return label;
+}
+
+/** Free a GPT label */
+void gpt_free_label(gpt_label_t *label)
+{
+	if (label->gpt != NULL)
+		gpt_free_gpt(label->gpt);
+	
+	if (label->parts != NULL)
+		gpt_free_partitions(label->parts);
+	
+	free(label);
+}
+
+/** Allocate a GPT header */
+gpt_t *gpt_alloc_header(size_t size)
+{
+	gpt_t *gpt = malloc(sizeof(gpt_t));
+	if (gpt == NULL)
+		return NULL;
+	
+	/*
+	 * We might need only sizeof(gpt_header_t), but we should follow
+	 * specs and have zeroes through all the rest of the block
+	 */
+	size_t final_size = max(size, sizeof(gpt_header_t));
+	gpt->header = malloc(final_size);
+	if (gpt->header == NULL) {
+		free(gpt);
+		return NULL;
+	}
+	
+	memset(gpt->header, 0, final_size);
+	memcpy(gpt->header->efi_signature, efi_signature, 8);
+	memcpy(gpt->header->revision, revision, 4);
+	gpt->header->header_size = host2uint32_t_le(final_size);
+	gpt->header->entry_lba = host2uint64_t_le((uint64_t) 2);
+	gpt->header->entry_size = host2uint32_t_le(sizeof(gpt_entry_t));
+	
+	return gpt;
+}
+
+/** Free a GPT header */
+void gpt_free_gpt(gpt_t *gpt)
+{
+	free(gpt->header);
+	free(gpt);
+}
+
+/** Read GPT from a device
+ *
+ * @param label      Label to read.
+ * @param dev_handle Device to read GPT from.
+ *
+ * @return EOK on success, error code on error.
+ *
+ */
+int gpt_read_header(gpt_label_t *label, service_id_t dev_handle)
+{
+	int rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
+	if (rc != EOK)
+		return rc;
+	
+	size_t block_size;
+	rc = block_get_bsize(dev_handle, &block_size);
+	if (rc != EOK)
+		goto end;
+	
+	if (label->gpt == NULL) {
+		label->gpt = gpt_alloc_header(block_size);
+		if (label->gpt == NULL) {
+			rc = ENOMEM;
+			goto end;
+		}
+	}
+	
+	rc = load_and_check_header(dev_handle, GPT_HDR_BA, block_size,
+	    label->gpt->header);
+	if ((rc == EBADCHECKSUM) || (rc == EINVAL)) {
+		aoff64_t blocks;
+		rc = block_get_nblocks(dev_handle, &blocks);
+		if (rc != EOK) {
+			gpt_free_gpt(label->gpt);
+			goto end;
+		}
+		
+		rc = load_and_check_header(dev_handle, blocks - 1, block_size,
+		    label->gpt->header);
+		if ((rc == EBADCHECKSUM) || (rc == EINVAL)) {
+			gpt_free_gpt(label->gpt);
+			goto end;
+		}
+	}
+	
+	label->device = dev_handle;
+	rc = EOK;
+	
+end:
+	block_fini(dev_handle);
+	return rc;
+}
+
+/** Write GPT header to device
+ *
+ * @param label        Label to be written.
+ * @param dev_handle   Device to write the GPT to.
+ *
+ * @return EOK on success, libblock error code otherwise.
+ *
+ */
+int gpt_write_header(gpt_label_t *label, service_id_t dev_handle)
+{
+	/* The comm_size argument (the last one) is ignored */
+	int rc = block_init(EXCHANGE_ATOMIC, dev_handle, 4096);
+	if ((rc != EOK) && (rc != EEXIST))
+		return rc;
+	
+	size_t block_size;
+	rc = block_get_bsize(dev_handle, &block_size);
+	if (rc != EOK)
+		goto end;
+	
+	aoff64_t blocks;
+	rc = block_get_nblocks(dev_handle, &blocks);
+	if (rc != EOK)
+		goto end;
+	
+	gpt_set_random_uuid(label->gpt->header->disk_guid);
+	
+	/* Prepare the backup header */
+	label->gpt->header->alternate_lba = label->gpt->header->current_lba;
+	label->gpt->header->current_lba = host2uint64_t_le(blocks - 1);
+	
+	uint64_t lba = label->gpt->header->entry_lba;
+	label->gpt->header->entry_lba = host2uint64_t_le(blocks -
+	    (uint32_t_le2host(label->gpt->header->fillries) *
+	    sizeof(gpt_entry_t)) / block_size - 1);
+	
+	label->gpt->header->header_crc32 = 0;
+	label->gpt->header->header_crc32 =
+	    host2uint32_t_le(compute_crc32((uint8_t *) label->gpt->header,
+	    uint32_t_le2host(label->gpt->header->header_size)));
+	
+	/* Write to backup GPT header location */
+	rc = block_write_direct(dev_handle, blocks - 1, GPT_HDR_BS,
+	    label->gpt->header);
+	if (rc != EOK)
+		goto end;
+	
+	/* Prepare the main header */
+	label->gpt->header->entry_lba = lba;
+	
+	lba = label->gpt->header->alternate_lba;
+	label->gpt->header->alternate_lba = label->gpt->header->current_lba;
+	label->gpt->header->current_lba = lba;
+	
+	label->gpt->header->header_crc32 = 0;
+	label->gpt->header->header_crc32 =
+	    host2uint32_t_le(compute_crc32((uint8_t *) label->gpt->header,
+	    uint32_t_le2host(label->gpt->header->header_size)));
+	
+	/* Write to main GPT header location */
+	rc = block_write_direct(dev_handle, GPT_HDR_BA, GPT_HDR_BS,
+	    label->gpt->header);
+	if (rc != EOK)
+		goto end;
+	
+	/* Write Protective MBR */
+	br_block_t mbr;
+	memset(&mbr, 0, 512);
+	
+	memset(mbr.pte[0].first_chs, 1, 3);
+	mbr.pte[0].ptype = 0xEE;
+	memset(mbr.pte[0].last_chs, 0xff, 3);
+	mbr.pte[0].first_lba = host2uint32_t_le(1);
+	mbr.pte[0].length = 0xffffffff;
+	mbr.signature = host2uint16_t_le(BR_SIGNATURE);
+	
+	rc = block_write_direct(dev_handle, 0, 1, &mbr);
+	
+end:
+	block_fini(dev_handle);
+	return rc;
+}
+
+/** Alloc partition array */
+gpt_partitions_t *gpt_alloc_partitions(void)
+{
+	return alloc_part_array(GPT_MIN_PART_NUM);
+}
+
+/** Parse partitions from GPT
+ *
+ * @param label GPT label to be parsed.
+ *
+ * @return EOK on success, error code otherwise.
+ *
+ */
+int gpt_read_partitions(gpt_label_t *label)
+{
+	uint32_t fillries = uint32_t_le2host(label->gpt->header->fillries);
+	uint32_t ent_size = uint32_t_le2host(label->gpt->header->entry_size);
+	uint64_t ent_lba = uint64_t_le2host(label->gpt->header->entry_lba);
+	
+	if (label->parts == NULL) {
+		label->parts = alloc_part_array(fillries);
+		if (label->parts == NULL)
+			return ENOMEM;
+	}
+	
+	int rc = block_init(EXCHANGE_SERIALIZE, label->device,
+	    sizeof(gpt_entry_t));
+	if (rc != EOK) {
+		gpt_free_partitions(label->parts);
+		label->parts = NULL;
+		goto end;
+	}
+	
+	size_t block_size;
+	rc = block_get_bsize(label->device, &block_size);
+	if (rc != EOK) {
+		gpt_free_partitions(label->parts);
+		label->parts = NULL;
+		goto end;
+	}
+	
+	aoff64_t pos = ent_lba * block_size;
+	
+	for (uint32_t i = 0; i < fillries; i++) {
+		rc = block_read_bytes_direct(label->device, pos, sizeof(gpt_entry_t),
+		    label->parts->part_array + i);
+		pos += ent_size;
+		
+		if (rc != EOK) {
+			gpt_free_partitions(label->parts);
+			label->parts = NULL;
+			goto end;
+		}
+	}
+	
+	uint32_t crc = compute_crc32((uint8_t *) label->parts->part_array,
+	    fillries * ent_size);
+	
+	if (uint32_t_le2host(label->gpt->header->pe_array_crc32) != crc) {
+		rc = EBADCHECKSUM;
+		gpt_free_partitions(label->parts);
+		label->parts = NULL;
+		goto end;
+	}
+	
+	rc = EOK;
+	
+end:
+	block_fini(label->device);
+	return rc;
+}
+
+/** Write GPT and partitions to device
+ *
+ * Note: Also writes the header.
+ *
+ * @param label      Label to write.
+ * @param dev_handle Device to write the data to.
+ *
+ * @return EOK on succes, error code otherwise
+ *
+ */
+int gpt_write_partitions(gpt_label_t *label, service_id_t dev_handle)
+{
+	/* comm_size of 4096 is ignored */
+	int rc = block_init(EXCHANGE_ATOMIC, dev_handle, 4096);
+	if ((rc != EOK) && (rc != EEXIST))
+		return rc;
+	
+	size_t block_size;
+	rc = block_get_bsize(dev_handle, &block_size);
+	if (rc != EOK)
+		goto fail;
+	
+	aoff64_t blocks;
+	rc = block_get_nblocks(dev_handle, &blocks);
+	if (rc != EOK)
+		goto fail;
+	
+	if (label->gpt == NULL)
+		label->gpt = gpt_alloc_header(block_size);
+	
+	uint32_t entry_size =
+	    uint32_t_le2host(label->gpt->header->entry_size);
+	size_t fillries = (label->parts->fill > GPT_MIN_PART_NUM) ?
+	    label->parts->fill : GPT_MIN_PART_NUM;
+	
+	if (entry_size != sizeof(gpt_entry_t))
+		return ENOTSUP;
+	
+	label->gpt->header->fillries = host2uint32_t_le(fillries);
+	
+	uint64_t arr_blocks = (fillries * sizeof(gpt_entry_t)) / block_size;
+	
+	/* Include Protective MBR */
+	uint64_t gpt_space = arr_blocks + GPT_HDR_BS + 1;
+	
+	label->gpt->header->first_usable_lba = host2uint64_t_le(gpt_space);
+	label->gpt->header->last_usable_lba =
+	    host2uint64_t_le(blocks - gpt_space - 1);
+	
+	/* Perform checks */
+	gpt_part_foreach (label, p) {
+		if (gpt_get_part_type(p) == GPT_PTE_UNUSED)
+			continue;
+		
+		if (!check_encaps(p, blocks, gpt_space)) {
+			rc = ERANGE;
+			goto fail;
+		}
+		
+		gpt_part_foreach (label, q) {
+			if (p == q)
+				continue;
+			
+			if (gpt_get_part_type(p) != GPT_PTE_UNUSED) {
+				if (check_overlap(p, q)) {
+					rc = ERANGE;
+					goto fail;
+				}
+			}
+		}
+	}
+	
+	label->gpt->header->pe_array_crc32 =
+	    host2uint32_t_le(compute_crc32((uint8_t *) label->parts->part_array,
+	    fillries * entry_size));
+	
+	/* Write to backup GPT partition array location */
+	rc = block_write_direct(dev_handle, blocks - arr_blocks - 1,
+	    arr_blocks, label->parts->part_array);
+	if (rc != EOK)
+		goto fail;
+	
+	/* Write to main GPT partition array location */
+	rc = block_write_direct(dev_handle,
+	    uint64_t_le2host(label->gpt->header->entry_lba),
+	    arr_blocks, label->parts->part_array);
+	if (rc != EOK)
+		goto fail;
+	
+	return gpt_write_header(label, dev_handle);
+	
+fail:
+	block_fini(dev_handle);
+	return rc;
+}
+
+/** Allocate a new partition
+ *
+ * Note: Use either gpt_alloc_partition() or gpt_get_partition().
+ * This returns a memory block (zero-filled) and needs gpt_add_partition()
+ * to be called to insert it into a partition array.
+ * Requires you to call gpt_free_partition afterwards.
+ *
+ * @return Pointer to the new partition or NULL.
+ *
+ */
+gpt_part_t *gpt_alloc_partition(void)
+{
+	gpt_part_t *partition = malloc(sizeof(gpt_part_t));
+	if (partition == NULL)
+		return NULL;
+	
+	memset(partition, 0, sizeof(gpt_part_t));
+	
+	return partition;
+}
+
+/** Allocate a new partition already inside the label
+ *
+ * Note: Use either gpt_alloc_partition() or gpt_get_partition().
+ * This one returns a pointer to the first empty structure already
+ * inside the array, so don't call gpt_add_partition() afterwards.
+ * This is the one you will usually want.
+ *
+ * @param label Label to carry new partition.
+ *
+ * @return Pointer to the new partition or NULL.
+ *
+ */
+gpt_part_t *gpt_get_partition(gpt_label_t *label)
+{
+	gpt_part_t *partition;
+	
+	/* Find the first empty entry */
+	do {
+		if (label->parts->fill == label->parts->arr_size) {
+			if (extend_part_array(label->parts) == -1)
+				return NULL;
+		}
+		
+		partition = label->parts->part_array + label->parts->fill++;
+	} while (gpt_get_part_type(partition) != GPT_PTE_UNUSED);
+	
+	return partition;
+}
+
+/** Get partition already inside the label
+ *
+ * Note: For new partitions use either gpt_alloc_partition() or
+ * gpt_get_partition() unless you want a partition at a specific place.
+ * This returns a pointer to a structure already inside the array,
+ * so don't call gpt_add_partition() afterwards.
+ * This function is handy when you want to change already existing
+ * partition or to simply write somewhere in the middle. This works only
+ * for indexes smaller than either 128 or the actual number of filled
+ * entries.
+ *
+ * @param label Label to carrying the partition.
+ * @param idx   Index of the partition.
+ *
+ * @return Pointer to the partition or NULL when out of range.
+ *
+ */
+gpt_part_t *gpt_get_partition_at(gpt_label_t *label, size_t idx)
+{
+	if ((idx >= GPT_MIN_PART_NUM) && (idx >= label->parts->fill))
+		return NULL;
+	
+	return label->parts->part_array + idx;
+}
+
+/** Copy partition into partition array
+ *
+ * Note: For use with gpt_alloc_partition() only. You will get
+ * duplicates with gpt_get_partition().
+ * Note: Does not call gpt_free_partition()!
+ *
+ * @param parts     Target label
+ * @param partition Source partition to copy
+ *
+ * @return EOK on succes, error code otherwise
+ *
+ */
+int gpt_add_partition(gpt_label_t *label, gpt_part_t *partition)
+{
+	/* Find the first empty entry */
+	
+	gpt_part_t *part;
+	
+	do {
+		if (label->parts->fill == label->parts->arr_size) {
+			if (extend_part_array(label->parts) == -1)
+				return ENOMEM;
+		}
+		
+		part = label->parts->part_array + label->parts->fill++;
+	} while (gpt_get_part_type(part) != GPT_PTE_UNUSED);
+	
+	memcpy(part, partition, sizeof(gpt_entry_t));
+	return EOK;
+}
+
+/** Remove partition from array
+ *
+ * Note: Even if it fails, the partition still gets removed. Only
+ * reducing the array failed.
+ *
+ * @param label Label to remove from
+ * @param idx   Index of the partition to remove
+ *
+ * @return EOK on success, ENOMEM on array reduction failure
+ *
+ */
+int gpt_remove_partition(gpt_label_t *label, size_t idx)
+{
+	if (idx >= label->parts->arr_size)
+		return EINVAL;
+	
+	/*
+	 * FIXME:
+	 * If we allow blank spots, we break the array. If we have more than
+	 * 128 partitions in the array and then remove something from
+	 * the first 128 partitions, we would forget to write the last one.
+	 */
+	
+	memset(label->parts->part_array + idx, 0, sizeof(gpt_entry_t));
+	
+	if (label->parts->fill > idx)
+		label->parts->fill = idx;
+	
+	gpt_part_t *partition;
+	
+	if ((label->parts->fill > GPT_MIN_PART_NUM) &&
+	    (label->parts->fill < (label->parts->arr_size / 2) -
+	    GPT_IGNORE_FILL_NUM)) {
+		for (partition = gpt_get_partition_at(label, label->parts->arr_size / 2);
+		     partition < label->parts->part_array + label->parts->arr_size;
+		     partition++) {
+			if (gpt_get_part_type(partition) != GPT_PTE_UNUSED)
+				return EOK;
+		}
+		
+		if (reduce_part_array(label->parts) == ENOMEM)
+			return ENOMEM;
+	}
+	
+	return EOK;
+}
+
+/** Free partition list
+ *
+ * @param parts Partition list to be freed
+ *
+ */
+void gpt_free_partitions(gpt_partitions_t *parts)
+{
+	free(parts->part_array);
+	free(parts);
+}
+
+/** Get partition type */
+size_t gpt_get_part_type(gpt_part_t *partition)
+{
+	size_t i;
+	
+	for (i = 0; gpt_ptypes[i].guid != NULL; i++) {
+		if ((partition->part_type[3] == get_byte(gpt_ptypes[i].guid + 0)) &&
+		    (partition->part_type[2] == get_byte(gpt_ptypes[i].guid + 2)) &&
+		    (partition->part_type[1] == get_byte(gpt_ptypes[i].guid + 4)) &&
+		    (partition->part_type[0] == get_byte(gpt_ptypes[i].guid + 6)) &&
+		    (partition->part_type[5] == get_byte(gpt_ptypes[i].guid + 8)) &&
+		    (partition->part_type[4] == get_byte(gpt_ptypes[i].guid + 10)) &&
+		    (partition->part_type[7] == get_byte(gpt_ptypes[i].guid + 12)) &&
+		    (partition->part_type[6] == get_byte(gpt_ptypes[i].guid + 14)) &&
+		    (partition->part_type[8] == get_byte(gpt_ptypes[i].guid + 16)) &&
+		    (partition->part_type[9] == get_byte(gpt_ptypes[i].guid + 18)) &&
+		    (partition->part_type[10] == get_byte(gpt_ptypes[i].guid + 20)) &&
+		    (partition->part_type[11] == get_byte(gpt_ptypes[i].guid + 22)) &&
+		    (partition->part_type[12] == get_byte(gpt_ptypes[i].guid + 24)) &&
+		    (partition->part_type[13] == get_byte(gpt_ptypes[i].guid + 26)) &&
+		    (partition->part_type[14] == get_byte(gpt_ptypes[i].guid + 28)) &&
+		    (partition->part_type[15] == get_byte(gpt_ptypes[i].guid + 30)))
+			return i;
+	}
+	
+	return i;
+}
+
+/** Set partition type */
+void gpt_set_part_type(gpt_part_t *partition, size_t type)
+{
+	/* Beware: first 3 blocks are byteswapped! */
+	partition->part_type[3] = get_byte(gpt_ptypes[type].guid + 0);
+	partition->part_type[2] = get_byte(gpt_ptypes[type].guid + 2);
+	partition->part_type[1] = get_byte(gpt_ptypes[type].guid + 4);
+	partition->part_type[0] = get_byte(gpt_ptypes[type].guid + 6);
+	
+	partition->part_type[5] = get_byte(gpt_ptypes[type].guid + 8);
+	partition->part_type[4] = get_byte(gpt_ptypes[type].guid + 10);
+	
+	partition->part_type[7] = get_byte(gpt_ptypes[type].guid + 12);
+	partition->part_type[6] = get_byte(gpt_ptypes[type].guid + 14);
+	
+	partition->part_type[8] = get_byte(gpt_ptypes[type].guid + 16);
+	partition->part_type[9] = get_byte(gpt_ptypes[type].guid + 18);
+	partition->part_type[10] = get_byte(gpt_ptypes[type].guid + 20);
+	partition->part_type[11] = get_byte(gpt_ptypes[type].guid + 22);
+	partition->part_type[12] = get_byte(gpt_ptypes[type].guid + 24);
+	partition->part_type[13] = get_byte(gpt_ptypes[type].guid + 26);
+	partition->part_type[14] = get_byte(gpt_ptypes[type].guid + 28);
+	partition->part_type[15] = get_byte(gpt_ptypes[type].guid + 30);
+}
+
+/** Get partition starting LBA */
+uint64_t gpt_get_start_lba(gpt_part_t *partition)
+{
+	return uint64_t_le2host(partition->start_lba);
+}
+
+/** Set partition starting LBA */
+void gpt_set_start_lba(gpt_part_t *partition, uint64_t start)
+{
+	partition->start_lba = host2uint64_t_le(start);
+}
+
+/** Get partition ending LBA */
+uint64_t gpt_get_end_lba(gpt_part_t *partition)
+{
+	return uint64_t_le2host(partition->end_lba);
+}
+
+/** Set partition ending LBA */
+void gpt_set_end_lba(gpt_part_t *partition, uint64_t end)
+{
+	partition->end_lba = host2uint64_t_le(end);
+}
+
+/** Get partition name */
+unsigned char * gpt_get_part_name(gpt_part_t *partition)
+{
+	return partition->part_name;
+}
+
+/** Copy partition name */
+void gpt_set_part_name(gpt_part_t *partition, char *name, size_t length)
+{
+	if (length >= 72)
+		length = 71;
+	
+	memcpy(partition->part_name, name, length);
+	partition->part_name[length] = '\0';
+}
+
+/** Get partition attribute */
+bool gpt_get_flag(gpt_part_t *partition, gpt_attr_t flag)
+{
+	return (partition->attributes & (((uint64_t) 1) << flag)) ? 1 : 0;
+}
+
+/** Set partition attribute */
+void gpt_set_flag(gpt_part_t *partition, gpt_attr_t flag, bool value)
+{
+	uint64_t attr = partition->attributes;
+	
+	if (value)
+		attr = attr | (((uint64_t) 1) << flag);
+	else
+		attr = attr ^ (attr & (((uint64_t) 1) << flag));
+	
+	partition->attributes = attr;
+}
+
+/** Generate a new pseudo-random UUID
+ *
+ * FIXME: This UUID generator is not compliant with RFC 4122.
+ *
+ */
+void gpt_set_random_uuid(uint8_t *uuid)
+{
+	srandom((unsigned int) (size_t) uuid);
+	
+	for (size_t i = 0; i < 16; i++)
+		uuid[i] = random();
+}
+
+/** Get next aligned address */
+uint64_t gpt_get_next_aligned(uint64_t addr, unsigned int alignment)
+{
+	return ALIGN_UP(addr + 1, alignment);
+}
+
+static int load_and_check_header(service_id_t dev_handle, aoff64_t addr,
+    size_t block_size, gpt_header_t *header)
+{
+	int rc = block_read_direct(dev_handle, addr, GPT_HDR_BS, header);
+	if (rc != EOK)
+		return rc;
+	
+	/* Check the EFI signature */
+	for (unsigned int i = 0; i < 8; i++) {
+		if (header->efi_signature[i] != efi_signature[i])
+			return EINVAL;
+	}
+	
+	/* Check the CRC32 of the header */
+	uint32_t crc = header->header_crc32;
+	header->header_crc32 = 0;
+	
+	if (crc != compute_crc32((uint8_t *) header, header->header_size))
+		return EBADCHECKSUM;
+	else
+		header->header_crc32 = crc;
+	
+	/* Check for zeroes in the rest of the block */
+	for (size_t i = sizeof(gpt_header_t); i < block_size; i++) {
+		if (((uint8_t *) header)[i] != 0)
+			return EINVAL;
+	}
+	
+	return EOK;
+}
+
+static gpt_partitions_t *alloc_part_array(uint32_t num)
+{
+	gpt_partitions_t *res = malloc(sizeof(gpt_partitions_t));
+	if (res == NULL)
+		return NULL;
+	
+	uint32_t size = num > GPT_BASE_PART_NUM ? num : GPT_BASE_PART_NUM;
+	res->part_array = malloc(size * sizeof(gpt_entry_t));
+	if (res->part_array == NULL) {
+		free(res);
+		return NULL;
+	}
+	
+	memset(res->part_array, 0, size * sizeof(gpt_entry_t));
+	
+	res->fill = 0;
+	res->arr_size = num;
+	
+	return res;
+}
+
+static int extend_part_array(gpt_partitions_t *partition)
+{
+	size_t nsize = partition->arr_size * 2;
+	gpt_entry_t *entry = malloc(nsize * sizeof(gpt_entry_t));
+	if (entry == NULL)
+		return ENOMEM;
+	
+	memcpy(entry, partition->part_array, partition->fill *
+	    sizeof(gpt_entry_t));
+	free(partition->part_array);
+	
+	partition->part_array = entry;
+	partition->arr_size = nsize;
+	
+	return EOK;
+}
+
+static int reduce_part_array(gpt_partitions_t *partition)
+{
+	if (partition->arr_size > GPT_MIN_PART_NUM) {
+		unsigned int nsize = partition->arr_size / 2;
+		nsize = nsize > GPT_MIN_PART_NUM ? nsize : GPT_MIN_PART_NUM;
+		
+		gpt_entry_t *entry = malloc(nsize * sizeof(gpt_entry_t));
+		if (entry == NULL)
+			return ENOMEM;
+		
+		memcpy(entry, partition->part_array,
+		    partition->fill < nsize ? partition->fill : nsize);
+		free(partition->part_array);
+		
+		partition->part_array = entry;
+		partition->arr_size = nsize;
+	}
+	
+	return EOK;
+}
+
+/* Parse a byte from a string in hexadecimal */
+static uint8_t get_byte(const char *c)
+{
+	uint8_t val = 0;
+	char hex[3] = {*c, *(c + 1), 0};
+	
+	str_uint8_t(hex, NULL, 16, false, &val);
+	return val;
+}
+
+static bool check_overlap(gpt_part_t *part1, gpt_part_t *part2)
+{
+	if ((gpt_get_start_lba(part1) < gpt_get_start_lba(part2)) &&
+	    (gpt_get_end_lba(part1) < gpt_get_start_lba(part2)))
+		return false;
+	
+	if ((gpt_get_start_lba(part1) > gpt_get_start_lba(part2)) &&
+	    (gpt_get_end_lba(part2) < gpt_get_start_lba(part1)))
+		return false;
+	
+	return true;
+}
+
+static bool check_encaps(gpt_part_t *part, uint64_t blocks,
+    uint64_t first_lba)
+{
+	/*
+	 * We allow "<=" in the second expression because it lacks
+	 * MBR so it is smaller by 1 block.
+	 */
+	if ((gpt_get_start_lba(part) >= first_lba) &&
+	    (gpt_get_end_lba(part) <= blocks - first_lba))
+		return true;
+	
+	return false;
+}
Index: uspace/lib/gpt/libgpt.h
===================================================================
--- uspace/lib/gpt/libgpt.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/gpt/libgpt.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011-2013 Dominik Taborsky
+ * 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 libgpt
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBGPT_LIBGPT_H_
+#define LIBGPT_LIBGPT_H_
+
+#include <loc.h>
+#include <sys/types.h>
+#include "gpt.h"
+
+/** Block address of GPT header. */
+#define GPT_HDR_BA  1
+
+/** Block size of GPT header. */
+#define GPT_HDR_BS  1
+
+/** Minimum number of GPT partition entries */
+#define GPT_MIN_PART_NUM  128
+
+/** Basic number of GPT partition entries */
+#define GPT_BASE_PART_NUM  (GPT_MIN_PART_NUM)
+
+/** How much fill we ignore before resizing partition array */
+#define GPT_IGNORE_FILL_NUM  10
+
+/** Unused partition entry */
+#define GPT_PTE_UNUSED  0
+
+/** Raw GPT header.
+ *
+ * Uses more bytes than sizeof(gpt_header_t).
+ */
+typedef struct {
+	gpt_header_t *header;
+} gpt_t;
+
+typedef gpt_entry_t gpt_part_t;
+
+typedef struct {
+	/** Number of entries */
+	size_t fill;
+	
+	/** Size of the array */
+	size_t arr_size;
+	
+	/** Resizable partition array */
+	gpt_part_t *part_array;
+} gpt_partitions_t;
+
+typedef struct {
+	gpt_t *gpt;
+	gpt_partitions_t *parts;
+	service_id_t device;
+} gpt_label_t;
+
+typedef struct {
+	const char *desc;
+	const char *guid;
+} partition_type_t;
+
+/** GPT header signature ("EFI PART" in ASCII) */
+extern const uint8_t efi_signature[8];
+extern const uint8_t revision[4];
+
+extern const partition_type_t gpt_ptypes[];
+
+extern gpt_label_t *gpt_alloc_label(void);
+extern void gpt_free_label(gpt_label_t *);
+
+extern gpt_t *gpt_alloc_header(size_t);
+extern int gpt_read_header(gpt_label_t *, service_id_t);
+extern int gpt_write_header(gpt_label_t *, service_id_t);
+
+extern gpt_partitions_t *gpt_alloc_partitions(void);
+extern int gpt_read_partitions(gpt_label_t *);
+extern int gpt_write_partitions(gpt_label_t *, service_id_t);
+extern gpt_part_t *gpt_alloc_partition(void);
+extern gpt_part_t *gpt_get_partition(gpt_label_t *);
+extern gpt_part_t *gpt_get_partition_at(gpt_label_t *, size_t);
+extern int gpt_add_partition(gpt_label_t *, gpt_part_t *);
+extern int gpt_remove_partition(gpt_label_t *, size_t);
+
+extern size_t gpt_get_part_type(gpt_part_t *);
+extern void gpt_set_part_type(gpt_part_t *, size_t);
+extern void gpt_set_start_lba(gpt_part_t *, uint64_t);
+extern uint64_t gpt_get_start_lba(gpt_part_t *);
+extern void gpt_set_end_lba(gpt_part_t *, uint64_t);
+extern uint64_t gpt_get_end_lba(gpt_part_t *);
+extern unsigned char *gpt_get_part_name(gpt_part_t *);
+extern void gpt_set_part_name(gpt_part_t *, char *, size_t);
+extern bool gpt_get_flag(gpt_part_t *, gpt_attr_t);
+extern void gpt_set_flag(gpt_part_t *, gpt_attr_t, bool);
+
+extern void gpt_set_random_uuid(uint8_t *);
+extern uint64_t gpt_get_next_aligned(uint64_t, unsigned int);
+
+
+#define gpt_part_foreach(label, iterator) \
+	for (gpt_part_t *iterator = (label)->parts->part_array; \
+	    iterator < (label)->parts->part_array + (label)->parts->arr_size; \
+	    iterator++)
+
+extern void gpt_free_gpt(gpt_t *);
+extern void gpt_free_partitions(gpt_partitions_t *);
+
+#endif
Index: uspace/lib/gui/canvas.c
===================================================================
--- uspace/lib/gui/canvas.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/gui/canvas.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -105,10 +105,19 @@
 static void canvas_handle_keyboard_event(widget_t *widget, kbd_event_t event)
 {
-	/* No-op */
+	canvas_t *canvas = (canvas_t *) widget;
+	
+	sig_send(&canvas->keyboard_event, &event);
 }
 
 static void canvas_handle_position_event(widget_t *widget, pos_event_t event)
 {
-	/* No-op */
+	canvas_t *canvas = (canvas_t *) widget;
+	pos_event_t tevent;
+	
+	tevent = event;
+	tevent.hpos -= widget->hpos;
+	tevent.vpos -= widget->vpos;
+	
+	sig_send(&canvas->position_event, &tevent);
 }
 
@@ -142,4 +151,13 @@
 }
 
+bool update_canvas(canvas_t *canvas, surface_t *surface)
+{
+	if (surface != NULL)
+		canvas->surface = surface;
+	
+	canvas_repaint(&canvas->widget);
+	return true;
+}
+
 canvas_t *create_canvas(widget_t *parent, sysarg_t width, sysarg_t height,
     surface_t *surface)
Index: uspace/lib/gui/canvas.h
===================================================================
--- uspace/lib/gui/canvas.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/gui/canvas.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -42,4 +42,5 @@
 #include <surface.h>
 #include "widget.h"
+#include "connection.h"
 
 typedef struct {
@@ -48,4 +49,6 @@
 	sysarg_t height;
 	surface_t *surface;
+	signal_t keyboard_event;
+	signal_t position_event;
 } canvas_t;
 
@@ -53,4 +56,5 @@
     surface_t *);
 extern canvas_t *create_canvas(widget_t *, sysarg_t, sysarg_t, surface_t *);
+extern bool update_canvas(canvas_t *, surface_t *);
 extern void deinit_canvas(canvas_t *);
 
Index: uspace/lib/gui/window.c
===================================================================
--- uspace/lib/gui/window.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/gui/window.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -529,5 +529,5 @@
 }
 
-window_t *window_open(char *winreg, bool is_main, bool is_decorated, 
+window_t *window_open(const char *winreg, bool is_main, bool is_decorated,
     const char *caption, sysarg_t x_offset, sysarg_t y_offset)
 {
Index: uspace/lib/gui/window.h
===================================================================
--- uspace/lib/gui/window.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/gui/window.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -66,5 +66,6 @@
  * If the window is declared as main, its closure causes termination of the
  * whole application. Note that opened window does not have any surface yet. */
-extern window_t *window_open(char *, bool, bool, const char *, sysarg_t, sysarg_t);
+extern window_t *window_open(const char *, bool, bool, const char *, sysarg_t,
+    sysarg_t);
 
 /**
Index: uspace/lib/http/Makefile
===================================================================
--- uspace/lib/http/Makefile	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/http/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -31,8 +31,12 @@
 SLIBRARY = libhttp.so.0.0
 LSONAME = libhttp.so0
-#EXTRA_CFLAGS += 
+EXTRA_CFLAGS += -Iinclude
 
 SOURCES = \
-	http.c
+	src/http.c \
+	src/headers.c \
+	src/request.c \
+	src/response.c \
+	src/receive-buffer.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/http/http.c
===================================================================
--- uspace/lib/http/http.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,530 +1,0 @@
-/*
- * Copyright (c) 2013 Martin Sucha
- * 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 http
- * @{
- */
-/**
- * @file
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <str.h>
-#include <macros.h>
-
-#include <net/socket.h>
-#include <inet/dnsr.h>
-
-#include "http.h"
-
-#define HTTP_METHOD_LINE "%s %s HTTP/1.1\r\n"
-#define HTTP_HEADER_LINE "%s: %s\r\n"
-#define HTTP_REQUEST_LINE "\r\n"
-
-static char *cut_str(const char *start, const char *end)
-{
-	size_t size = end - start;
-	return str_ndup(start, size);
-}
-
-static void recv_reset(http_t *http)
-{
-	http->recv_buffer_in = 0;
-	http->recv_buffer_out = 0;
-}
-
-/** Receive one character (with buffering) */
-static int recv_char(http_t *http, char *c, bool consume)
-{
-	if (http->recv_buffer_out == http->recv_buffer_in) {
-		recv_reset(http);
-		
-		ssize_t rc = recv(http->conn_sd, http->recv_buffer, http->buffer_size, 0);
-		if (rc <= 0)
-			return rc;
-		
-		http->recv_buffer_in = rc;
-	}
-	
-	*c = http->recv_buffer[http->recv_buffer_out];
-	if (consume)
-		http->recv_buffer_out++;
-	return EOK;
-}
-
-static ssize_t recv_buffer(http_t *http, char *buf, size_t buf_size)
-{
-	/* Flush any buffered data*/
-	if (http->recv_buffer_out != http->recv_buffer_in) {
-		size_t size = min(http->recv_buffer_in - http->recv_buffer_out, buf_size);
-		memcpy(buf, http->recv_buffer + http->recv_buffer_out, size);
-		http->recv_buffer_out += size;
-		return size;
-	}
-	
-	return recv(http->conn_sd, buf, buf_size, 0);
-}
-
-/** Receive a character and if it is c, discard it from input buffer */
-static int recv_discard(http_t *http, char discard)
-{
-	char c = 0;
-	int rc = recv_char(http, &c, false);
-	if (rc != EOK)
-		return rc;
-	if (c != discard)
-		return EOK;
-	return recv_char(http, &c, true);
-}
-
-/* Receive a single line */
-static ssize_t recv_line(http_t *http, char *line, size_t size)
-{
-	size_t written = 0;
-	
-	while (written < size) {
-		char c = 0;
-		int rc = recv_char(http, &c, true);
-		if (rc != EOK)
-			return rc;
-		if (c == '\n') {
-			recv_discard(http, '\r');
-			line[written++] = 0;
-			return written;
-		}
-		else if (c == '\r') {
-			recv_discard(http, '\n');
-			line[written++] = 0;
-			return written;
-		}
-		line[written++] = c;
-	}
-	
-	return ELIMIT;
-}
-
-http_t *http_create(const char *host, uint16_t port)
-{
-	http_t *http = malloc(sizeof(http_t));
-	if (http == NULL)
-		return NULL;
-	
-	http->host = str_dup(host);
-	if (http->host == NULL) {
-		free(http);
-		return NULL;
-	}
-	http->port = port;
-	
-	http->buffer_size = 4096;
-	http->recv_buffer = malloc(http->buffer_size);
-	if (http->recv_buffer == NULL) {
-		free(http->host);
-		free(http);
-		return NULL;
-	}
-	
-	return http;
-}
-
-int http_connect(http_t *http)
-{
-	if (http->connected)
-		return EBUSY;
-	
-	/* Interpret as address */
-	int rc = inet_addr_parse(http->host, &http->addr);
-	
-	if (rc != EOK) {
-		/* Interpret as a host name */
-		dnsr_hostinfo_t *hinfo = NULL;
-		rc = dnsr_name2host(http->host, &hinfo, AF_NONE);
-		
-		if (rc != EOK)
-			return rc;
-		
-		http->addr = hinfo->addr;
-		dnsr_hostinfo_destroy(hinfo);
-	}
-	
-	struct sockaddr_in addr;
-	struct sockaddr_in6 addr6;
-	uint16_t af = inet_addr_sockaddr_in(&http->addr, &addr, &addr6);
-	
-	http->conn_sd = socket(PF_INET, SOCK_STREAM, 0);
-	if (http->conn_sd < 0)
-		return http->conn_sd;
-	
-	switch (af) {
-	case AF_INET:
-		addr.sin_port = htons(http->port);
-		rc = connect(http->conn_sd, (struct sockaddr *) &addr, sizeof(addr));
-		break;
-	case AF_INET6:
-		addr6.sin6_port = htons(http->port);
-		rc = connect(http->conn_sd, (struct sockaddr *) &addr6, sizeof(addr6));
-		break;
-	default:
-		return ENOTSUP;
-	}
-	
-	return rc;
-}
-
-http_header_t *http_header_create(const char *name, const char *value)
-{
-	char *dname = str_dup(name);
-	if (dname == NULL)
-		return NULL;
-	
-	char *dvalue = str_dup(value);
-	if (dvalue == NULL) {
-		free(dname);
-		return NULL;
-	}
-
-	return http_header_create_no_copy(dname, dvalue);
-}
-
-http_header_t *http_header_create_no_copy(char *name, char *value)
-{
-	http_header_t *header = malloc(sizeof(http_header_t));
-	if (header == NULL)
-		return NULL;
-	
-	link_initialize(&header->link);
-	header->name = name;
-	header->value = value;
-	
-	return header;
-}
-
-void http_header_destroy(http_header_t *header)
-{
-	free(header->name);
-	free(header->value);
-	free(header);
-}
-
-http_request_t *http_request_create(const char *method, const char *path)
-{
-	http_request_t *req = malloc(sizeof(http_request_t));
-	if (req == NULL)
-		return NULL;
-	
-	req->method = str_dup(method);
-	if (req->method == NULL) {
-		free(req);
-		return NULL;
-	}
-	
-	req->path = str_dup(path);
-	if (req->path == NULL) {
-		free(req->method);
-		free(req);
-		return NULL;
-	}
-	
-	list_initialize(&req->headers);
-	
-	return req;
-}
-
-void http_request_destroy(http_request_t *req)
-{
-	free(req->method);
-	free(req->path);
-	link_t *link = req->headers.head.next;
-	while (link != &req->headers.head) {
-		link_t *next = link->next;
-		http_header_t *header = list_get_instance(link, http_header_t, link);
-		http_header_destroy(header);
-		link = next;
-	}
-	free(req);
-}
-
-static ssize_t http_encode_method(char *buf, size_t buf_size,
-    const char *method, const char *path)
-{
-	if (buf == NULL) {
-		return printf_size(HTTP_METHOD_LINE, method, path);
-	}
-	else {
-		return snprintf(buf, buf_size, HTTP_METHOD_LINE, method, path);
-	}
-}
-
-static ssize_t http_encode_header(char *buf, size_t buf_size,
-    http_header_t *header)
-{
-	/* TODO properly split long header values */
-	if (buf == NULL) {
-		return printf_size(HTTP_HEADER_LINE, header->name, header->value);
-	}
-	else {
-		return snprintf(buf, buf_size,
-		    HTTP_HEADER_LINE, header->name, header->value);
-	}
-}
-
-int http_request_format(http_request_t *req, char **out_buf,
-    size_t *out_buf_size)
-{
-	/* Compute the size of the request */
-	ssize_t meth_size = http_encode_method(NULL, 0, req->method, req->path);
-	if (meth_size < 0)
-		return meth_size;
-	size_t size = meth_size;
-	
-	list_foreach(req->headers, link, http_header_t, header) {
-		ssize_t header_size = http_encode_header(NULL, 0, header);
-		if (header_size < 0)
-			return header_size;
-		size += header_size;
-	}
-	size += str_length(HTTP_REQUEST_LINE);
-	
-	char *buf = malloc(size);
-	if (buf == NULL)
-		return ENOMEM;
-	
-	char *pos = buf;
-	size_t pos_size = size;
-	ssize_t written = http_encode_method(pos, pos_size, req->method, req->path);
-	if (written < 0) {
-		free(buf);
-		return written;
-	}
-	pos += written;
-	pos_size -= written;
-	
-	list_foreach(req->headers, link, http_header_t, header) {
-		written = http_encode_header(pos, pos_size, header);
-		if (written < 0) {
-			free(buf);
-			return written;
-		}
-		pos += written;
-		pos_size -= written;
-	}
-	
-	size_t rlsize = str_size(HTTP_REQUEST_LINE);
-	memcpy(pos, HTTP_REQUEST_LINE, rlsize);
-	pos_size -= rlsize;
-	assert(pos_size == 0);
-	
-	*out_buf = buf;
-	*out_buf_size = size;
-	return EOK;
-}
-
-int http_send_request(http_t *http, http_request_t *req)
-{
-	char *buf;
-	size_t buf_size;
-	
-	int rc = http_request_format(req, &buf, &buf_size);
-	if (rc != EOK)
-		return rc;
-	
-	rc = send(http->conn_sd, buf, buf_size, 0);
-	free(buf);
-	
-	return rc;
-}
-
-int http_parse_status(const char *line, http_version_t *out_version,
-    uint16_t *out_status, char **out_message)
-{
-	http_version_t version;
-	uint16_t status;
-	char *message = NULL;
-	
-	if (!str_test_prefix(line, "HTTP/"))
-		return EINVAL;
-	
-	const char *pos_version = line + 5;
-	const char *pos = pos_version;
-	
-	int rc = str_uint8_t(pos_version, &pos, 10, false, &version.major);
-	if (rc != EOK)
-		return rc;
-	if (*pos != '.')
-		return EINVAL;
-	pos++;
-	
-	pos_version = pos;
-	rc = str_uint8_t(pos_version, &pos, 10, false, &version.minor);
-	if (rc != EOK)
-		return rc;
-	if (*pos != ' ')
-		return EINVAL;
-	pos++;
-	
-	const char *pos_status = pos;
-	rc = str_uint16_t(pos_status, &pos, 10, false, &status);
-	if (rc != EOK)
-		return rc;
-	if (*pos != ' ')
-		return EINVAL;
-	pos++;
-	
-	if (out_message) {
-		message = str_dup(pos);
-		if (message == NULL)
-			return ENOMEM;
-	}
-	
-	if (out_version)
-		*out_version = version;
-	if (out_status)
-		*out_status = status;
-	if (out_message)
-		*out_message = message;
-	return EOK;
-}
-
-int http_parse_header(const char *line, char **out_name, char **out_value)
-{
-	const char *pos = line;
-	while (*pos != 0 && *pos != ':') pos++;
-	if (*pos != ':')
-		return EINVAL;
-	
-	char *name = cut_str(line, pos);
-	if (name == NULL)
-		return ENOMEM;
-	
-	pos++;
-	
-	while (*pos == ' ') pos++;
-	
-	char *value = str_dup(pos);
-	if (value == NULL) {
-		free(name);
-		return ENOMEM;
-	}
-	
-	*out_name = name;
-	*out_value = value;
-	
-	return EOK;
-}
-
-int http_receive_response(http_t *http, http_response_t **out_response)
-{
-	http_response_t *resp = malloc(sizeof(http_response_t));
-	if (resp == NULL)
-		return ENOMEM;
-	memset(resp, 0, sizeof(http_response_t));
-	list_initialize(&resp->headers);
-	
-	char *line = malloc(http->buffer_size);
-	if (line == NULL) {
-		free(resp);
-		return ENOMEM;
-	}
-	
-	int rc = recv_line(http, line, http->buffer_size);
-	if (rc < 0)
-		goto error;
-	
-	rc = http_parse_status(line, &resp->version, &resp->status,
-	    &resp->message);
-	if (rc != EOK)
-		goto error;
-	
-	while (true) {
-		rc = recv_line(http, line, http->buffer_size);
-		if (rc < 0)
-			goto error;
-		if (*line == 0)
-			break;
-		
-		char *name = NULL;
-		char *value = NULL;
-		rc = http_parse_header(line, &name, &value);
-		if (rc != EOK)
-			goto error;
-		
-		http_header_t *header = http_header_create_no_copy(name, value);
-		if (header == NULL) {
-			free(name);
-			free(value);
-			rc = ENOMEM;
-			goto error;
-		}
-		
-		list_append(&header->link, &resp->headers);
-	}
-	
-	*out_response = resp;
-	
-	return EOK;
-error:
-	free(line);
-	http_response_destroy(resp);
-	return rc;
-}
-
-int http_receive_body(http_t *http, void *buf, size_t buf_size)
-{
-	return recv_buffer(http, buf, buf_size);
-}
-
-void http_response_destroy(http_response_t *resp)
-{
-	free(resp->message);
-	link_t *link = resp->headers.head.next;
-	while (link != &resp->headers.head) {
-		link_t *next = link->next;
-		http_header_t *header = list_get_instance(link, http_header_t, link);
-		http_header_destroy(header);
-		link = next;
-	}
-	free(resp);
-}
-
-int http_close(http_t *http)
-{
-	if (!http->connected)
-		return EINVAL;
-	
-	return closesocket(http->conn_sd);
-}
-
-void http_destroy(http_t *http)
-{
-	free(http->recv_buffer);
-	free(http);
-}
-
-/** @}
- */
Index: uspace/lib/http/http.h
===================================================================
--- uspace/lib/http/http.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,102 +1,0 @@
-/*
- * Copyright (c) 2013 Martin Sucha
- * 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 http
- * @{
- */
-/**
- * @file
- */
-
-#ifndef HTTP_HTTP_H_
-#define HTTP_HTTP_H_
-
-#include <net/socket.h>
-#include <adt/list.h>
-#include <inet/addr.h>
-
-typedef struct {
-	char *host;
-	uint16_t port;
-	inet_addr_t addr;
-
-	bool connected;
-	int conn_sd;
-	
-	size_t buffer_size;
-	char *recv_buffer;
-	size_t recv_buffer_in;
-	size_t recv_buffer_out;
-} http_t;
-
-typedef struct {
-	uint8_t minor;
-	uint8_t major;
-} http_version_t;
-
-typedef struct {
-	link_t link;
-	char *name;
-	char *value;
-} http_header_t;
-
-typedef struct {
-	char *method;
-	char *path;
-	list_t headers;
-} http_request_t;
-
-typedef struct {
-	http_version_t version;
-	uint16_t status;
-	char *message;
-	list_t headers;
-} http_response_t;
-
-extern http_t *http_create(const char *, uint16_t);
-extern int http_connect(http_t *);
-extern http_header_t *http_header_create(const char *, const char *);
-extern http_header_t *http_header_create_no_copy(char *, char *);
-extern void http_header_destroy(http_header_t *);
-extern http_request_t *http_request_create(const char *, const char *);
-extern void http_request_destroy(http_request_t *);
-extern int http_request_format(http_request_t *, char **, size_t *);
-extern int http_send_request(http_t *, http_request_t *);
-extern int http_parse_status(const char *, http_version_t *, uint16_t *,
-    char **);
-extern int http_parse_header(const char *, char **, char **);
-extern int http_receive_response(http_t *, http_response_t **);
-extern int http_receive_body(http_t *, void *, size_t);
-extern void http_response_destroy(http_response_t *);
-extern int http_close(http_t *);
-extern void http_destroy(http_t *);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/http/include/http/ctype.h
===================================================================
--- uspace/lib/http/include/http/ctype.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/http/include/http/ctype.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * 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 http
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef HTTP_CTYPE_H_
+#define HTTP_CTYPE_H_
+
+static inline bool is_separator(char c)
+{
+	switch (c) {
+	case '(':
+	case ')':
+	case '<':
+	case '>':
+	case '@':
+	case ',':
+	case ';':
+	case ':':
+	case '\\':
+	case '"':
+	case '/':
+	case '[':
+	case ']':
+	case '?':
+	case '=':
+	case '{':
+	case '}':
+	case ' ':
+	case '\t':
+		return true;
+	default:
+		return false;
+	}
+}
+
+static inline bool is_lws(char c)
+{
+	switch (c) {
+	case '\r':
+	case '\n':
+	case ' ':
+	case '\t':
+		return true;
+	default:
+		return false;
+	}
+}
+
+static inline bool is_ctl(char c)
+{
+	return c < 32 || c == 127;
+}
+
+static inline bool is_token(char c)
+{
+	return !is_separator(c) && !is_ctl(c);
+}
+
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/http/include/http/errno.h
===================================================================
--- uspace/lib/http/include/http/errno.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/http/include/http/errno.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * 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 http
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef HTTP_ERRNO_H_
+#define HTTP_ERRNO_H_
+
+#include <errno.h>
+
+#define HTTP_EMULTIPLE_HEADERS -20001
+#define HTTP_EMISSING_HEADER -20002
+#define HTTP_EPARSE -20003
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/http/include/http/http.h
===================================================================
--- uspace/lib/http/include/http/http.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/http/include/http/http.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * 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 http
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef HTTP_HTTP_H_
+#define HTTP_HTTP_H_
+
+#include <net/socket.h>
+#include <adt/list.h>
+#include <inet/addr.h>
+
+#include "receive-buffer.h"
+
+typedef struct {
+	char *host;
+	uint16_t port;
+	inet_addr_t addr;
+
+	bool connected;
+	int conn_sd;
+	
+	size_t buffer_size;
+	receive_buffer_t recv_buffer;
+} http_t;
+
+typedef struct {
+	uint8_t minor;
+	uint8_t major;
+} http_version_t;
+
+typedef struct {
+	link_t link;
+	char *name;
+	char *value;
+} http_header_t;
+
+typedef struct {
+	list_t list;
+} http_headers_t;
+
+typedef struct {
+	char *method;
+	char *path;
+	http_headers_t headers;
+} http_request_t;
+
+typedef struct {
+	http_version_t version;
+	uint16_t status;
+	char *message;
+	http_headers_t headers;
+} http_response_t;
+
+extern http_t *http_create(const char *, uint16_t);
+extern int http_connect(http_t *);
+
+extern void http_header_init(http_header_t *);
+extern http_header_t *http_header_create(const char *, const char *);
+extern int http_header_receive_name(receive_buffer_t *, receive_buffer_mark_t *);
+extern int http_header_receive_value(receive_buffer_t *, receive_buffer_mark_t *,
+    receive_buffer_mark_t *);
+extern int http_header_receive(receive_buffer_t *, http_header_t *, size_t,
+    size_t *);
+extern void http_header_normalize_value(char *);
+extern bool http_header_name_match(const char *, const char *);
+ssize_t http_header_encode(http_header_t *, char *, size_t);
+extern void http_header_destroy(http_header_t *);
+
+extern void http_headers_init(http_headers_t *);
+extern int http_headers_find_single(http_headers_t *, const char *,
+    http_header_t **);
+extern int http_headers_append(http_headers_t *, const char *, const char *);
+extern int http_headers_set(http_headers_t *, const char *, const char *);
+extern int http_headers_get(http_headers_t *, const char *, char **);
+extern int http_headers_receive(receive_buffer_t *, http_headers_t *, size_t,
+    unsigned);
+extern void http_headers_clear(http_headers_t *);
+
+#define http_headers_foreach(headers, iter) \
+    list_foreach((headers).list, link, http_header_t, (iter))
+
+static inline void http_headers_remove(http_headers_t *headers,
+    http_header_t *header)
+{
+	list_remove(&header->link);
+}
+
+static inline void http_headers_append_header(http_headers_t *headers,
+    http_header_t *header)
+{
+	list_append(&header->link, &headers->list);
+}
+
+extern http_request_t *http_request_create(const char *, const char *);
+extern void http_request_destroy(http_request_t *);
+extern int http_request_format(http_request_t *, char **, size_t *);
+extern int http_send_request(http_t *, http_request_t *);
+extern int http_receive_status(receive_buffer_t *, http_version_t *, uint16_t *,
+    char **);
+extern int http_receive_response(receive_buffer_t *, http_response_t **,
+    size_t, unsigned);
+extern void http_response_destroy(http_response_t *);
+extern int http_close(http_t *);
+extern void http_destroy(http_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/http/include/http/receive-buffer.h
===================================================================
--- uspace/lib/http/include/http/receive-buffer.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/http/include/http/receive-buffer.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * 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 http
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef HTTP_RECEIVE_BUFFER_H_
+#define HTTP_RECEIVE_BUFFER_H_
+
+#include <adt/list.h>
+
+/** Receive data.
+ *
+ * @param client_data client data
+ * @param buf buffer to store the data
+ * @param buf_size buffer size
+ * @return number of bytes received or negative error code
+ */
+typedef ssize_t (*receive_func_t)(void *, void *, size_t);
+
+typedef struct {
+	size_t size;
+	char *buffer;
+	size_t in;
+	size_t out;
+	
+	void *client_data;
+	receive_func_t receive;
+	
+	list_t marks;
+} receive_buffer_t;
+
+typedef struct {
+	link_t link;
+	size_t offset;
+} receive_buffer_mark_t;
+
+typedef bool (*char_class_func_t)(char);
+
+extern int recv_buffer_init(receive_buffer_t *, size_t, receive_func_t, void *);
+extern int recv_buffer_init_const(receive_buffer_t *, void *, size_t);
+extern void recv_buffer_fini(receive_buffer_t *);
+extern void recv_reset(receive_buffer_t *);
+extern void recv_mark(receive_buffer_t *, receive_buffer_mark_t *);
+extern void recv_unmark(receive_buffer_t *, receive_buffer_mark_t *);
+extern void recv_mark_update(receive_buffer_t *, receive_buffer_mark_t *);
+extern int recv_cut(receive_buffer_t *, receive_buffer_mark_t *,
+    receive_buffer_mark_t *, void **, size_t *);
+extern int recv_cut_str(receive_buffer_t *, receive_buffer_mark_t *,
+    receive_buffer_mark_t *, char **);
+extern int recv_char(receive_buffer_t *, char *, bool);
+extern ssize_t recv_buffer(receive_buffer_t *, char *, size_t);
+extern ssize_t recv_discard(receive_buffer_t *, char);
+extern ssize_t recv_discard_str(receive_buffer_t *, const char *);
+extern ssize_t recv_while(receive_buffer_t *, char_class_func_t);
+extern ssize_t recv_eol(receive_buffer_t *);
+extern ssize_t recv_line(receive_buffer_t *, char *, size_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/http/src/headers.c
===================================================================
--- uspace/lib/http/src/headers.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/http/src/headers.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * 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 http
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <macros.h>
+
+#include <http/http.h>
+#include <http/ctype.h>
+#include <http/errno.h>
+
+#define HTTP_HEADER_LINE "%s: %s\r\n"
+
+void http_header_init(http_header_t *header)
+{
+	link_initialize(&header->link);
+	header->name = NULL;
+	header->value = NULL;
+}
+
+http_header_t *http_header_create(const char *name, const char *value)
+{
+	http_header_t *header = malloc(sizeof(http_header_t));
+	if (header == NULL)
+		return NULL;
+	http_header_init(header);
+
+	header->name = str_dup(name);
+	if (header->name == NULL) {
+		free(header);
+		return NULL;
+	}
+	
+	header->value = str_dup(value);
+	if (header->value == NULL) {
+		free(header->name);
+		free(header);
+		return NULL;
+	}
+
+	return header;
+}
+
+void http_header_destroy(http_header_t *header)
+{
+	free(header->name);
+	free(header->value);
+	free(header);
+}
+
+ssize_t http_header_encode(http_header_t *header, char *buf, size_t buf_size)
+{
+	/* TODO properly split long header values */
+	if (buf == NULL) {
+		return printf_size(HTTP_HEADER_LINE, header->name, header->value);
+	}
+	else {
+		return snprintf(buf, buf_size,
+		    HTTP_HEADER_LINE, header->name, header->value);
+	}
+}
+
+int http_header_receive_name(receive_buffer_t *rb,
+    receive_buffer_mark_t *name_end)
+{
+	char c = 0;
+	do {
+		if (name_end)
+			recv_mark_update(rb, name_end);
+		
+		int rc = recv_char(rb, &c, true);
+		if (rc != EOK)
+			return rc;
+	} while (is_token(c));
+	
+	if (c != ':')
+		return EINVAL;
+	
+	return EOK;
+}
+
+int http_header_receive_value(receive_buffer_t *rb,
+    receive_buffer_mark_t *value_start, receive_buffer_mark_t *value_end)
+{
+	int rc = EOK;
+	char c = 0;
+	
+	/* Ignore any inline LWS */
+	while (true) {
+		if (value_start)
+			recv_mark_update(rb, value_start);
+		
+		rc = recv_char(rb, &c, false);
+		if (rc != EOK)
+			return rc;
+		
+		if (c != ' ' && c != '\t')
+			break;
+		
+		rc = recv_char(rb, &c, true);
+		if (rc != EOK)
+			return rc;
+	}
+	
+	while (true) {
+		recv_mark_update(rb, value_end);
+		
+		rc = recv_char(rb, &c, true);
+		if (rc != EOK)
+			return rc;
+		
+		if (c != '\r' && c != '\n')
+			continue;
+		
+		rc = recv_discard(rb, (c == '\r' ? '\n' : '\r'));
+		if (rc < 0)
+			return rc;
+		
+		rc = recv_char(rb, &c, false);
+		if (rc != EOK)
+			return rc;
+		
+		if (c != ' ' && c != '\t')
+			break;
+		
+		/* Ignore the char */
+		rc = recv_char(rb, &c, true);
+		if (rc != EOK)
+			return rc;
+	}
+	
+	return EOK;
+}
+
+int http_header_receive(receive_buffer_t *rb, http_header_t *header,
+    size_t size_limit, size_t *out_bytes_used)
+{
+	receive_buffer_mark_t mark_start;
+	receive_buffer_mark_t mark_end;
+	
+	recv_mark(rb, &mark_start);
+	recv_mark(rb, &mark_end);
+	
+	int rc = http_header_receive_name(rb, &mark_end);
+	if (rc != EOK)
+		goto end;
+	
+	size_t name_size = mark_end.offset - mark_start.offset;
+	if (size_limit > 0 && name_size > size_limit) {
+		rc = ELIMIT;
+		goto end;
+	}
+	
+	char *name = NULL;
+	rc = recv_cut_str(rb, &mark_start, &mark_end, &name);
+	if (rc != EOK)
+		goto end;
+	
+	rc = http_header_receive_value(rb, &mark_start, &mark_end);
+	if (rc != EOK)
+		goto end_with_name;
+	
+	size_t value_size = mark_end.offset - mark_start.offset;
+	if (size_limit > 0 && (name_size + value_size) > size_limit) {
+		rc = ELIMIT;
+		goto end_with_name;
+	}
+	
+	char *value = NULL;
+	rc = recv_cut_str(rb, &mark_start, &mark_end, &value);
+	if (rc != EOK)
+		goto end_with_name;
+	
+	if (out_bytes_used)
+		*out_bytes_used = name_size + value_size;
+	
+	header->name = name;
+	header->value = value;
+	goto end;
+end_with_name:
+	free(name);
+end:
+	recv_unmark(rb, &mark_start);
+	recv_unmark(rb, &mark_end);
+	return rc;
+}
+
+/** Normalize HTTP header value
+ *
+ * @see RFC2616 section 4.2
+ */
+void http_header_normalize_value(char *value)
+{
+	size_t read_index = 0;
+	size_t write_index = 0;
+	
+	while (is_lws(value[read_index])) read_index++;
+	
+	while (value[read_index] != 0) {
+		if (is_lws(value[read_index])) {
+			while (is_lws(value[read_index])) read_index++;
+			
+			if (value[read_index] != 0)
+				value[write_index++] = ' ';
+			
+			continue;
+		}
+		
+		value[write_index++] = value[read_index++];
+	}
+	
+	value[write_index] = 0;
+}
+
+/** Test if two header names are equivalent
+ *
+ */
+bool http_header_name_match(const char *name_a, const char *name_b)
+{
+	return stricmp(name_a, name_b) == 0;
+}
+
+void http_headers_init(http_headers_t *headers) {
+	list_initialize(&headers->list);
+}
+
+int http_headers_find_single(http_headers_t *headers, const char *name,
+    http_header_t **out_header)
+{
+	http_header_t *found = NULL;
+	http_headers_foreach(*headers, header) {
+		if (!http_header_name_match(header->name, name))
+			continue;
+		
+		if (found == NULL) {
+			found = header;
+		}
+		else {
+			return HTTP_EMULTIPLE_HEADERS;
+		}
+	}
+	
+	if (found == NULL)
+		return HTTP_EMISSING_HEADER;
+	
+	*out_header = found;
+	return EOK;
+}
+
+int http_headers_append(http_headers_t *headers, const char *name,
+    const char *value)
+{
+	http_header_t *header = http_header_create(name, value);
+	if (header == NULL)
+		return ENOMEM;
+	
+	http_headers_append_header(headers, header);
+	return EOK;
+}
+
+int http_headers_set(http_headers_t *headers, const char *name,
+    const char *value)
+{
+	http_header_t *header = NULL;
+	int rc = http_headers_find_single(headers, name, &header);
+	if (rc != EOK && rc != HTTP_EMISSING_HEADER)
+		return rc;
+	
+	if (rc == HTTP_EMISSING_HEADER)
+		return http_headers_append(headers, name, value);
+	
+	char *new_value = str_dup(value);
+	if (new_value == NULL)
+		return ENOMEM;
+	
+	free(header->value);
+	header->value = new_value;
+	return EOK;
+}
+
+int http_headers_get(http_headers_t *headers, const char *name, char **value)
+{
+	http_header_t *header = NULL;
+	int rc = http_headers_find_single(headers, name, &header);
+	if (rc != EOK)
+		return rc;
+	
+	*value = header->value;
+	return EOK;
+}
+
+int http_headers_receive(receive_buffer_t *rb, http_headers_t *headers,
+    size_t limit_alloc, unsigned limit_count)
+{
+	int rc = EOK;
+	unsigned added = 0;
+	
+	while (true) {
+		char c = 0;
+		rc = recv_char(rb, &c, false);
+		if (rc != EOK)
+			goto error;
+		
+		if (c == '\n' || c == '\r')
+			break;
+		
+		if (limit_count > 0 && added >= limit_count) {
+			rc = ELIMIT;
+			goto error;
+		}
+		
+		http_header_t *header = malloc(sizeof(http_header_t));
+		if (header == NULL) {
+			rc = ENOMEM;
+			goto error;
+		}
+		http_header_init(header);
+		
+		size_t header_size;
+		rc = http_header_receive(rb, header, limit_alloc, &header_size);
+		if (rc != EOK) {
+			free(header);
+			goto error;
+		}
+		limit_alloc -= header_size;
+		
+		http_headers_append_header(headers, header);
+		added++;
+	}
+	
+	return EOK;
+error:
+	while (added-- > 0) {
+		link_t *link = list_last(&headers->list);
+		http_header_t *header = list_get_instance(link, http_header_t, link);
+		http_headers_remove(headers, header);
+		http_header_destroy(header);
+	}
+	return rc;
+}
+
+void http_headers_clear(http_headers_t *headers)
+{
+	link_t *link = list_first(&headers->list);
+	while (link != NULL) {
+		link_t *next = list_next(link, &headers->list);
+		http_header_t *header = list_get_instance(link, http_header_t, link);
+		list_remove(link);
+		http_header_destroy(header);
+		link = next;
+	}
+}
+
+/** @}
+ */
Index: uspace/lib/http/src/http.c
===================================================================
--- uspace/lib/http/src/http.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/http/src/http.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * 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 http
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <macros.h>
+
+#include <net/socket.h>
+#include <inet/dnsr.h>
+
+#include <http/http.h>
+#include <http/receive-buffer.h>
+
+static ssize_t http_receive(void *client_data, void *buf, size_t buf_size)
+{
+	http_t *http = client_data;
+	return recv(http->conn_sd, buf, buf_size, 0);
+}
+
+http_t *http_create(const char *host, uint16_t port)
+{
+	http_t *http = malloc(sizeof(http_t));
+	if (http == NULL)
+		return NULL;
+	
+	http->host = str_dup(host);
+	if (http->host == NULL) {
+		free(http);
+		return NULL;
+	}
+	http->port = port;
+	
+	http->buffer_size = 4096;
+	int rc = recv_buffer_init(&http->recv_buffer, http->buffer_size,
+	    http_receive, http);
+	if (rc != EOK) {
+		free(http);
+		return NULL;
+	}
+	
+	return http;
+}
+
+int http_connect(http_t *http)
+{
+	if (http->connected)
+		return EBUSY;
+	
+	/* Interpret as address */
+	int rc = inet_addr_parse(http->host, &http->addr);
+	
+	if (rc != EOK) {
+		/* Interpret as a host name */
+		dnsr_hostinfo_t *hinfo = NULL;
+		rc = dnsr_name2host(http->host, &hinfo, ip_any);
+		
+		if (rc != EOK)
+			return rc;
+		
+		http->addr = hinfo->addr;
+		dnsr_hostinfo_destroy(hinfo);
+	}
+	
+	struct sockaddr *saddr;
+	socklen_t saddrlen;
+	
+	rc = inet_addr_sockaddr(&http->addr, http->port, &saddr, &saddrlen);
+	if (rc != EOK) {
+		assert(rc == ENOMEM);
+		return ENOMEM;
+	}
+	
+	http->conn_sd = socket(saddr->sa_family, SOCK_STREAM, 0);
+	if (http->conn_sd < 0)
+		return http->conn_sd;
+	
+	rc = connect(http->conn_sd, saddr, saddrlen);
+	free(saddr);
+	
+	return rc;
+}
+
+int http_close(http_t *http)
+{
+	if (!http->connected)
+		return EINVAL;
+	
+	return closesocket(http->conn_sd);
+}
+
+void http_destroy(http_t *http)
+{
+	recv_buffer_fini(&http->recv_buffer);
+	free(http);
+}
+
+/** @}
+ */
Index: uspace/lib/http/src/receive-buffer.c
===================================================================
--- uspace/lib/http/src/receive-buffer.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/http/src/receive-buffer.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * Copyright (c) 2013 Martin Sucha
+ * 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 http
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdlib.h>
+#include <str.h>
+#include <errno.h>
+#include <macros.h>
+#include <adt/list.h>
+
+#include <http/receive-buffer.h>
+
+int recv_buffer_init(receive_buffer_t *rb, size_t buffer_size,
+    receive_func_t receive, void *client_data)
+{
+	rb->receive = receive;
+	rb->client_data = client_data;
+	
+	rb->in = 0;
+	rb->out = 0;
+	rb->size = buffer_size;
+	
+	list_initialize(&rb->marks);
+	
+	rb->buffer = malloc(buffer_size);
+	if (rb->buffer == NULL)
+		return ENOMEM;
+	return EOK;
+}
+
+static ssize_t dummy_receive(void *unused, void *buf, size_t buf_size)
+{
+	return 0;
+}
+
+int recv_buffer_init_const(receive_buffer_t *rb, void *buf, size_t size)
+{
+	int rc = recv_buffer_init(rb, size, dummy_receive, NULL);
+	if (rc != EOK)
+		return rc;
+	
+	memcpy(rb->buffer, buf, size);
+	rb->in = size;
+	return EOK;
+}
+
+void recv_buffer_fini(receive_buffer_t *rb)
+{
+	free(rb->buffer);
+}
+
+void recv_reset(receive_buffer_t *rb)
+{
+	rb->in = 0;
+	rb->out = 0;
+}
+
+void recv_mark(receive_buffer_t *rb, receive_buffer_mark_t *mark)
+{
+	link_initialize(&mark->link);
+	list_append(&mark->link, &rb->marks);
+	recv_mark_update(rb, mark);
+}
+
+void recv_unmark(receive_buffer_t *rb, receive_buffer_mark_t *mark)
+{
+	list_remove(&mark->link);
+}
+
+void recv_mark_update(receive_buffer_t *rb, receive_buffer_mark_t *mark)
+{
+	mark->offset = rb->out;
+}
+
+int recv_cut(receive_buffer_t *rb, receive_buffer_mark_t *a, receive_buffer_mark_t *b, void **out_buf, size_t *out_size)
+{
+	if (a->offset > b->offset)
+		return EINVAL;
+	
+	size_t size = b->offset - a->offset;
+	void *buf = malloc(size);
+	if (buf == NULL)
+		return ENOMEM;
+	
+	memcpy(buf, rb->buffer + a->offset, size);
+	*out_buf = buf;
+	*out_size = size;
+	return EOK;
+}
+
+int recv_cut_str(receive_buffer_t *rb, receive_buffer_mark_t *a, receive_buffer_mark_t *b, char **out_buf)
+{
+	if (a->offset > b->offset)
+		return EINVAL;
+	
+	size_t size = b->offset - a->offset;
+	char *buf = malloc(size + 1);
+	if (buf == NULL)
+		return ENOMEM;
+	
+	memcpy(buf, rb->buffer + a->offset, size);
+	buf[size] = 0;
+	for (size_t i = 0; i < size; i++) {
+		if (buf[i] == 0) {
+			free(buf);
+			return EIO;
+		}
+	}
+	*out_buf = buf;
+	return EOK;
+}
+
+
+/** Receive one character (with buffering) */
+int recv_char(receive_buffer_t *rb, char *c, bool consume)
+{
+	if (rb->out == rb->in) {
+		size_t free = rb->size - rb->in;
+		if (free == 0) {
+			size_t min_mark = rb->size;
+			list_foreach(rb->marks, link, receive_buffer_mark_t, mark) {
+				min_mark = min(min_mark, mark->offset);
+			}
+			
+			if (min_mark == 0)
+				return ELIMIT;
+			
+			size_t new_in = rb->in - min_mark;
+			memmove(rb->buffer, rb->buffer + min_mark, new_in);
+			rb->out = rb->in = new_in;
+			free = rb->size - rb->in;
+			list_foreach(rb->marks, link, receive_buffer_mark_t, mark) {
+				mark->offset -= min_mark;
+			}
+		}
+		
+		ssize_t rc = rb->receive(rb->client_data, rb->buffer + rb->in, free);
+		if (rc <= 0)
+			return rc;
+		
+		rb->in = rc;
+	}
+	
+	*c = rb->buffer[rb->out];
+	if (consume)
+		rb->out++;
+	return EOK;
+}
+
+ssize_t recv_buffer(receive_buffer_t *rb, char *buf, size_t buf_size)
+{
+	/* Flush any buffered data*/
+	if (rb->out != rb->in) {
+		size_t size = min(rb->in - rb->out, buf_size);
+		memcpy(buf, rb->buffer + rb->out, size);
+		rb->out += size;
+		return size;
+	}
+	
+	return rb->receive(rb->client_data, buf, buf_size);
+}
+
+/** Receive a character and if it is c, discard it from input buffer
+ * @return number of characters discarded (0 or 1) or negative error code
+ */
+ssize_t recv_discard(receive_buffer_t *rb, char discard)
+{
+	char c = 0;
+	int rc = recv_char(rb, &c, false);
+	if (rc != EOK)
+		return rc;
+	if (c != discard)
+		return 0;
+	rc = recv_char(rb, &c, true);
+	if (rc != EOK)
+		return rc;
+	return 1;
+}
+
+/** Receive a prefix of constant string discard and return number of bytes read
+ * @return number of characters discarded or negative error code
+ */
+ssize_t recv_discard_str(receive_buffer_t *rb, const char *discard)
+{
+	size_t discarded = 0;
+	while (*discard) {
+		ssize_t rc = recv_discard(rb, *discard);
+		if (rc < 0)
+			return rc;
+		if (rc == 0)
+			break;
+		discarded++;
+		discard++;
+	}
+	return discarded;
+}
+
+ssize_t recv_while(receive_buffer_t *rb, char_class_func_t class)
+{
+	size_t received = 0;
+	
+	while (true) {
+		char c = 0;
+		int rc = recv_char(rb, &c, false);
+		if (rc != EOK)
+			return rc;
+		
+		if (!class(c))
+			break;
+		
+		rc = recv_char(rb, &c, true);
+		if (rc != EOK)
+			return rc;
+		
+		received++;
+	}
+	
+	return received;
+}
+
+/** Receive an end of line, either CR, LF, CRLF or LFCR
+ *
+ * @return number of bytes read (0 if no newline is present in the stream)
+ *         or negative error code
+ */
+ssize_t recv_eol(receive_buffer_t *rb)
+{
+	char c = 0;
+	int rc = recv_char(rb, &c, false);
+	if (rc != EOK)
+		return rc;
+	
+	if (c != '\r' && c != '\n')
+		return 0;
+	
+	rc = recv_char(rb, &c, true);
+	if (rc != EOK)
+		return rc;
+	
+	ssize_t rc2 = recv_discard(rb, (c == '\r' ? '\n' : '\r'));
+	if (rc2 < 0)
+		return rc2;
+	
+	return 1 + rc2;
+}
+
+/* Receive a single line */
+ssize_t recv_line(receive_buffer_t *rb, char *line, size_t size)
+{
+	size_t written = 0;
+	
+	while (written < size) {
+		char c = 0;
+		int rc = recv_char(rb, &c, true);
+		if (rc != EOK)
+			return rc;
+		if (c == '\n') {
+			recv_discard(rb, '\r');
+			line[written++] = 0;
+			return written;
+		}
+		else if (c == '\r') {
+			recv_discard(rb, '\n');
+			line[written++] = 0;
+			return written;
+		}
+		line[written++] = c;
+	}
+	
+	return ELIMIT;
+}
+
+/** @}
+ */
Index: uspace/lib/http/src/request.c
===================================================================
--- uspace/lib/http/src/request.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/http/src/request.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * 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 http
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <macros.h>
+
+#include <net/socket.h>
+
+#include <http/http.h>
+
+#define HTTP_METHOD_LINE "%s %s HTTP/1.1\r\n"
+#define HTTP_REQUEST_LINE "\r\n"
+
+http_request_t *http_request_create(const char *method, const char *path)
+{
+	http_request_t *req = malloc(sizeof(http_request_t));
+	if (req == NULL)
+		return NULL;
+	
+	req->method = str_dup(method);
+	if (req->method == NULL) {
+		free(req);
+		return NULL;
+	}
+	
+	req->path = str_dup(path);
+	if (req->path == NULL) {
+		free(req->method);
+		free(req);
+		return NULL;
+	}
+	
+	http_headers_init(&req->headers);
+	
+	return req;
+}
+
+void http_request_destroy(http_request_t *req)
+{
+	free(req->method);
+	free(req->path);
+	http_headers_clear(&req->headers);
+	free(req);
+}
+
+static ssize_t http_encode_method(char *buf, size_t buf_size,
+    const char *method, const char *path)
+{
+	if (buf == NULL) {
+		return printf_size(HTTP_METHOD_LINE, method, path);
+	}
+	else {
+		return snprintf(buf, buf_size, HTTP_METHOD_LINE, method, path);
+	}
+}
+
+int http_request_format(http_request_t *req, char **out_buf,
+    size_t *out_buf_size)
+{
+	/* Compute the size of the request */
+	ssize_t meth_size = http_encode_method(NULL, 0, req->method, req->path);
+	if (meth_size < 0)
+		return meth_size;
+	size_t size = meth_size;
+	
+	http_headers_foreach(req->headers, header) {
+		ssize_t header_size = http_header_encode(header, NULL, 0);
+		if (header_size < 0)
+			return header_size;
+		size += header_size;
+	}
+	size += str_length(HTTP_REQUEST_LINE);
+	
+	char *buf = malloc(size);
+	if (buf == NULL)
+		return ENOMEM;
+	
+	char *pos = buf;
+	size_t pos_size = size;
+	ssize_t written = http_encode_method(pos, pos_size, req->method, req->path);
+	if (written < 0) {
+		free(buf);
+		return written;
+	}
+	pos += written;
+	pos_size -= written;
+	
+	http_headers_foreach(req->headers, header) {
+		written = http_header_encode(header, pos, pos_size);
+		if (written < 0) {
+			free(buf);
+			return written;
+		}
+		pos += written;
+		pos_size -= written;
+	}
+	
+	size_t rlsize = str_size(HTTP_REQUEST_LINE);
+	memcpy(pos, HTTP_REQUEST_LINE, rlsize);
+	pos_size -= rlsize;
+	assert(pos_size == 0);
+	
+	*out_buf = buf;
+	*out_buf_size = size;
+	return EOK;
+}
+
+int http_send_request(http_t *http, http_request_t *req)
+{
+	char *buf;
+	size_t buf_size;
+	
+	int rc = http_request_format(req, &buf, &buf_size);
+	if (rc != EOK)
+		return rc;
+	
+	rc = send(http->conn_sd, buf, buf_size, 0);
+	free(buf);
+	
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/http/src/response.c
===================================================================
--- uspace/lib/http/src/response.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/http/src/response.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * 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 http
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <macros.h>
+
+#include <http/http.h>
+#include <http/errno.h>
+
+static bool is_digit(char c)
+{
+	return (c >= '0' && c <= '9');
+}
+
+static int receive_number(receive_buffer_t *rb, char **str)
+{
+	receive_buffer_mark_t start;
+	receive_buffer_mark_t end;
+	
+	recv_mark(rb, &start);
+	int rc = recv_while(rb, is_digit);
+	if (rc < 0) {
+		recv_unmark(rb, &start);
+		return rc;
+	}
+	recv_mark(rb, &end);
+	
+	rc = recv_cut_str(rb, &start, &end, str);
+	recv_unmark(rb, &start);
+	recv_unmark(rb, &end);
+	return rc;
+}
+
+static int receive_uint8_t(receive_buffer_t *rb, uint8_t *out_value)
+{
+	char *str = NULL;
+	int rc = receive_number(rb, &str);
+	
+	if (rc != EOK)
+		return rc;
+	
+	rc = str_uint8_t(str, NULL, 10, true, out_value);
+	free(str);
+	
+	return rc;
+}
+
+static int receive_uint16_t(receive_buffer_t *rb, uint16_t *out_value)
+{
+	char *str = NULL;
+	int rc = receive_number(rb, &str);
+	
+	if (rc != EOK)
+		return rc;
+	
+	rc = str_uint16_t(str, NULL, 10, true, out_value);
+	free(str);
+	
+	return rc;
+}
+
+static int expect(receive_buffer_t *rb, const char *expect)
+{
+	int rc = recv_discard_str(rb, expect);
+	if (rc < 0)
+		return rc;
+	if ((size_t) rc < str_length(expect))
+		return HTTP_EPARSE;
+	return EOK;
+}
+
+static bool is_not_newline(char c)
+{
+	return (c != '\n' && c != '\r');
+}
+
+int http_receive_status(receive_buffer_t *rb, http_version_t *out_version,
+    uint16_t *out_status, char **out_message)
+{
+	http_version_t version;
+	uint16_t status;
+	char *message = NULL;
+	
+	int rc = expect(rb, "HTTP/");
+	if (rc != EOK)
+		return rc;
+	
+	rc = receive_uint8_t(rb, &version.major);
+	if (rc != EOK)
+		return rc;
+	
+	rc = expect(rb, ".");
+	if (rc != EOK)
+		return rc;
+	
+	rc = receive_uint8_t(rb, &version.minor);
+	if (rc != EOK)
+		return rc;
+	
+	rc = expect(rb, " ");
+	if (rc != EOK)
+		return rc;
+	
+	rc = receive_uint16_t(rb, &status);
+	if (rc != EOK)
+		return rc;
+	
+	rc = expect(rb, " ");
+	if (rc != EOK)
+		return rc;
+	
+	receive_buffer_mark_t msg_start;
+	recv_mark(rb, &msg_start);
+	
+	rc = recv_while(rb, is_not_newline);
+	if (rc < 0) {
+		recv_unmark(rb, &msg_start);
+		return rc;
+	}
+	
+	receive_buffer_mark_t msg_end;
+	recv_mark(rb, &msg_end);
+	
+	if (out_message) {
+		rc = recv_cut_str(rb, &msg_start, &msg_end, &message);
+		if (rc != EOK) {
+			recv_unmark(rb, &msg_start);
+			recv_unmark(rb, &msg_end);
+			return rc;
+		}
+	}
+	
+	recv_unmark(rb, &msg_start);
+	recv_unmark(rb, &msg_end);
+	
+	rc = recv_eol(rb);
+	if (rc == 0)
+		rc = HTTP_EPARSE;
+	if (rc < 0) {
+		free(message);
+		return rc;
+	}
+	
+	if (out_version)
+		*out_version = version;
+	if (out_status)
+		*out_status = status;
+	if (out_message)
+		*out_message = message;
+	return EOK;
+}
+
+int http_receive_response(receive_buffer_t *rb, http_response_t **out_response,
+    size_t max_headers_size, unsigned max_headers_count)
+{
+	http_response_t *resp = malloc(sizeof(http_response_t));
+	if (resp == NULL)
+		return ENOMEM;
+	memset(resp, 0, sizeof(http_response_t));
+	http_headers_init(&resp->headers);
+	
+	int rc = http_receive_status(rb, &resp->version, &resp->status,
+	    &resp->message);
+	if (rc != EOK)
+		goto error;
+	
+	rc = http_headers_receive(rb, &resp->headers, max_headers_size,
+	    max_headers_count);
+	if (rc != EOK)
+		goto error;
+	
+	rc = recv_eol(rb);
+	if (rc == 0)
+		rc = HTTP_EPARSE;
+	if (rc < 0)
+		goto error;
+	
+	*out_response = resp;
+	
+	return EOK;
+error:
+	http_response_destroy(resp);
+	return rc;
+}
+
+void http_response_destroy(http_response_t *resp)
+{
+	free(resp->message);
+	http_headers_clear(&resp->headers);
+	free(resp);
+}
+
+/** @}
+ */
Index: uspace/lib/math/Makefile
===================================================================
--- uspace/lib/math/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/math/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2013 Vojtech Horky
+# 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 = ../..
+LIBRARY = libmath
+
+SOURCES = \
+	src/dummy.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/math/src/dummy.c
===================================================================
--- uspace/lib/math/src/dummy.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/math/src/dummy.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 libmath
+ * @{
+ */
+/** @file Mathematical operations (dummy implementation).
+ */
+#include <math.h>
+#include <stdio.h>
+
+#define WARN_NOT_IMPLEMENTED() \
+	do { \
+		static int __not_implemented_counter = 0; \
+		if (__not_implemented_counter == 0) { \
+			fprintf(stderr, "Warning: using dummy implementation of %s().\n", \
+				__func__); \
+		} \
+		__not_implemented_counter++; \
+	} while (0)
+
+double ldexp(double x, int exp)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double frexp(double num, int *exp)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double cos(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double cosh(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double acos(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double acosh(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double pow(double x, double y)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double floor(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double ceil(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double fabs(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double modf(double x, double *iptr)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double fmod(double x, double y)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double log(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double log10(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+
+double atan2(double y, double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double sin(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double sinh(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double asin(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double asinh(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double tan(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double tanh(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double atan(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double atanh(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+
+double exp(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double expm1(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double sqrt(double x)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+double copysign(double x, double y)
+{
+	WARN_NOT_IMPLEMENTED();
+	return 0.0;
+}
+
+
+/** @}
+ */
Index: uspace/lib/mbr/Makefile
===================================================================
--- uspace/lib/mbr/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/mbr/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2011 Dominik Taborsky
+# 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 = ../..
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX)
+LIBRARY = libmbr
+
+SOURCES = \
+	libmbr.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/mbr/libmbr.c
===================================================================
--- uspace/lib/mbr/libmbr.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/mbr/libmbr.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,852 @@
+/*
+ * Copyright (c) 2011-2013 Dominik Taborsky
+ * 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 LIBMBR_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 libmbr
+ * @{
+ */
+/** @file MBR extraxtion library
+ */
+
+#include <async.h>
+#include <assert.h>
+#include <block.h>
+#include <byteorder.h>
+#include <errno.h>
+#include <ipc/bd.h>
+#include <mem.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <str_error.h>
+#include <align.h>
+#include "libmbr.h"
+
+static br_block_t *alloc_br(void);
+static int decode_part(pt_entry_t *, mbr_part_t *, uint32_t);
+static int decode_logical(mbr_label_t *, mbr_part_t *);
+static void encode_part(mbr_part_t *, pt_entry_t *, uint32_t, bool);
+static bool check_overlap(mbr_part_t *, mbr_part_t *);
+static bool check_encaps(mbr_part_t *, mbr_part_t *);
+static bool check_preceeds(mbr_part_t *, mbr_part_t *);
+static mbr_err_val mbr_add_primary(mbr_label_t *, mbr_part_t *);
+static mbr_err_val mbr_add_logical(mbr_label_t *, mbr_part_t *);
+
+/** Allocate and initialize mbr_label_t structure */
+mbr_label_t *mbr_alloc_label(void)
+{
+	mbr_label_t *label = malloc(sizeof(mbr_label_t));
+	if (label == NULL)
+		return NULL;
+	
+	label->mbr = NULL;
+	label->parts = NULL;
+	label->device = 0;
+	
+	return label;
+}
+
+void mbr_set_device(mbr_label_t *label, service_id_t dev_handle)
+{
+	label->device = dev_handle;
+}
+
+/** Free mbr_label_t structure */
+void mbr_free_label(mbr_label_t *label)
+{
+	if (label->mbr != NULL)
+		mbr_free_mbr(label->mbr);
+	
+	if (label->parts != NULL)
+		mbr_free_partitions(label->parts);
+	
+	free(label);
+}
+
+/** Allocate memory for mbr_t */
+mbr_t *mbr_alloc_mbr(void)
+{
+	return malloc(sizeof(mbr_t));
+}
+
+/** Read MBR from specific device
+ *
+ * @param label      Label to be read.
+ * @param dev_handle Device to read MBR from.
+ *
+ * @return EOK on success, error code on error.
+ *
+ */
+int mbr_read_mbr(mbr_label_t *label, service_id_t dev_handle)
+{	
+	if (label->mbr == NULL) {
+		label->mbr = mbr_alloc_mbr();
+		if (label->mbr == NULL)
+			return ENOMEM;
+	}
+	
+	int rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
+	if (rc != EOK)
+		return rc;
+	
+	rc = block_read_direct(dev_handle, 0, 1, &label->mbr->raw_data);
+	block_fini(dev_handle);
+	if (rc != EOK)
+		return rc;
+	
+	label->device = dev_handle;
+	
+	return EOK;
+}
+
+/** Write MBR to specific device
+ *
+ * @param label      Label to be written.
+ * @param dev_handle Device to write MBR to.
+ *
+ * @return EOK on success, error code on error.
+ *
+ */
+int mbr_write_mbr(mbr_label_t *label, service_id_t dev_handle)
+{
+	int rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
+	if (rc != EOK)
+		return rc;
+	
+	rc = block_write_direct(dev_handle, 0, 1, &label->mbr->raw_data);
+	block_fini(dev_handle);
+	
+	return rc;
+}
+
+/** Decide whether this is an actual MBR or a Protective MBR for GPT
+ *
+ * @param label Label to decide upon.
+ *
+ * @return True if MBR.
+ * @return False if Protective MBR for GPT.
+ *
+ */
+int mbr_is_mbr(mbr_label_t *label)
+{
+	return (label->mbr->raw_data.pte[0].ptype != PT_GPT);
+}
+
+/** Parse partitions from MBR (freeing previous partitions if any)
+ *
+ * It is assumed that mbr_read_mbr() was called before.
+ *
+ * @param label Label to be parsed.
+ *
+ * @return EOK on success, error code on error.
+ *
+ */
+int mbr_read_partitions(mbr_label_t *label)
+{
+	if ((label == NULL) || (label->mbr == NULL))
+		return EINVAL;
+	
+	if (label->parts != NULL)
+		mbr_free_partitions(label->parts);
+	
+	label->parts = mbr_alloc_partitions();
+	if (label->parts == NULL)
+		return ENOMEM;
+	
+	mbr_part_t *extended = NULL;
+	
+	/* Generate the primary partitions */
+	for (unsigned int i = 0; i < N_PRIMARY; i++) {
+		if (label->mbr->raw_data.pte[i].ptype == PT_UNUSED)
+			continue;
+		
+		mbr_part_t *partition = mbr_alloc_partition();
+		if (partition == NULL) {
+			mbr_free_partitions(label->parts);
+			return ENOMEM;
+		}
+		
+		int is_extended =
+		    decode_part(&label->mbr->raw_data.pte[i], partition, 0);
+		
+		mbr_set_flag(partition, ST_LOGIC, false);
+		
+		int rc = mbr_add_partition(label, partition);
+		if (rc != ERR_OK) {
+			mbr_free_partitions(label->parts);
+			return EINVAL;
+		}
+		
+		if (is_extended) {
+			extended = partition;
+			label->parts->l_extended = &partition->link;
+		}
+	}
+	
+	/* Fill in the primary partitions and generate logical ones (if any) */
+	return decode_logical(label, extended);
+}
+
+/** Write MBR and partitions to device
+ *
+ * @param label      Label to write.
+ * @param dev_handle Device to write the data to.
+ *
+ * @return EOK on success, specific error code otherwise.
+ *
+ */
+int mbr_write_partitions(mbr_label_t *label, service_id_t dev_handle)
+{
+	if (label->parts == NULL)
+		return EOK;
+	
+	if (label->mbr == NULL)
+		label->mbr = mbr_alloc_mbr();
+	
+	int rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
+	if (rc != EOK)
+		return rc;
+	
+	mbr_part_t *partition = NULL;
+	mbr_part_t *extended = NULL;
+	
+	if (label->parts->l_extended != NULL)
+		extended = list_get_instance(label->parts->l_extended,
+		    mbr_part_t, link);
+	
+	link_t *link = label->parts->list.head.next;
+	
+	/* Encode primary partitions */
+	for (unsigned int i = 0; i < N_PRIMARY; i++) {
+		partition = list_get_instance(link, mbr_part_t, link);
+		
+		encode_part(partition, &label->mbr->raw_data.pte[i], 0, false);
+		link = link->next;
+	}
+	
+	/* Write MBR */
+	rc = block_write_direct(dev_handle, 0, 1, &label->mbr->raw_data);
+	if ((rc != EOK) || (extended == NULL))
+		goto end;
+	
+	uint32_t base = extended->start_addr;
+	mbr_part_t *prev_partition;
+	
+	/* Encode and write first logical partition */
+	if (link != &label->parts->list.head) {
+		partition = list_get_instance(link, mbr_part_t, link);
+		
+		partition->ebr_addr = base;
+		encode_part(partition, &partition->ebr->pte[0], base, false);
+		link = link->next;
+	} else {
+		/*
+		 * If there was an extended partition but no logical partitions,
+		 * we should overwrite the space where the first logical
+		 * partitions's EBR would have been. There might be some
+		 * garbage from the past.
+		 */
+		
+		br_block_t *br = alloc_br();
+		rc = block_write_direct(dev_handle, base, 1, br);
+		if (rc != EOK)
+			goto end;
+		
+		free(br);
+		goto end;
+	}
+	
+	prev_partition = partition;
+	
+	/*
+	 * Check EBR addresses: The code saves previous EBR
+	 * placements from other software. But if our user
+	 * modifies the logical partition chain, we have to
+	 * fix those placements if needed.
+	 */
+	
+	link_t *link_ebr = link;
+	link_t *link_iter;
+	
+	mbr_part_t tmp_partition;
+	tmp_partition.length = 1;
+	
+	while (link_ebr != &label->parts->list.head) {
+		partition = list_get_instance(link_ebr, mbr_part_t, link);
+		
+		tmp_partition.start_addr = partition->ebr_addr;
+		
+		link_iter = link;
+		while (link_iter != &label->parts->list.head) {
+			/*
+			 * Check whether EBR address makes sense. If not, we take
+			 * a guess.  So far this is simple, we just take the first
+			 * preceeding sector. FDisk always reserves at least 2048
+			 * sectors (1 MiB), so it can have the EBR aligned as well
+			 * as the partition itself. Parted reserves minimum one
+			 * sector, like we do.
+			 *
+			 * Note that we know there is at least one sector free from
+			 * previous checks. Also note that the user can set ebr_addr
+			 * to their liking (if it is valid).
+			 */
+			
+			if ((partition->ebr_addr < base) ||
+			    (partition->ebr_addr >= base + extended->length) ||
+			    (check_overlap(&tmp_partition,
+			    list_get_instance(link_iter, mbr_part_t, link)))) {
+				partition->ebr_addr = partition->start_addr - 1;
+				break;
+			}
+			
+			link_iter = link_iter->next;
+		}
+		
+		link_ebr = link_ebr->next;
+	}
+	
+	/* Encode and write logical partitions */
+	while (link != &label->parts->list.head) {
+		partition = list_get_instance(link, mbr_part_t, link);
+		
+		encode_part(partition, &partition->ebr->pte[0],
+		    partition->ebr_addr, false);
+		encode_part(partition, &prev_partition->ebr->pte[1],
+		    base, true);
+		
+		rc = block_write_direct(dev_handle, prev_partition->ebr_addr, 1,
+		    prev_partition->ebr);
+		if (rc != EOK)
+			goto end;
+		
+		prev_partition = partition;
+		link = link->next;
+	}
+	
+	/* Write the last EBR */
+	encode_part(NULL, &prev_partition->ebr->pte[1], 0, false);
+	rc = block_write_direct(dev_handle, prev_partition->ebr_addr,
+	    1, prev_partition->ebr);
+	
+end:
+	block_fini(dev_handle);
+	return rc;
+}
+
+/** Partition constructor */
+mbr_part_t *mbr_alloc_partition(void)
+{
+	mbr_part_t *partition = malloc(sizeof(mbr_part_t));
+	if (partition == NULL)
+		return NULL;
+	
+	link_initialize(&partition->link);
+	partition->ebr = NULL;
+	partition->type = PT_UNUSED;
+	partition->status = 0;
+	partition->start_addr = 0;
+	partition->length = 0;
+	partition->ebr_addr = 0;
+	
+	return partition;
+}
+
+/** Partitions constructor */
+mbr_partitions_t *mbr_alloc_partitions(void)
+{
+	mbr_partitions_t *parts = malloc(sizeof(mbr_partitions_t));
+	if (parts == NULL)
+		return NULL;
+	
+	list_initialize(&parts->list);
+	parts->n_primary = 0;
+	parts->n_logical = 0;
+	parts->l_extended = NULL;
+	
+	/* Add blank primary partitions */
+	for (unsigned int i = 0; i < N_PRIMARY; ++i) {
+		mbr_part_t *part = mbr_alloc_partition();
+		if (part == NULL) {
+			mbr_free_partitions(parts);
+			return NULL;
+		}
+		
+		list_append(&part->link, &parts->list);
+	}
+	
+	return parts;
+}
+
+/** Add partition
+ *
+ * Perform checks, sort the list.
+ *
+ * @param label Label to add to.
+ * @param part  Partition to add.
+ *
+ * @return ERR_OK on success, other MBR_ERR_VAL otherwise
+ *
+ */
+mbr_err_val mbr_add_partition(mbr_label_t *label, mbr_part_t *part)
+{
+	int rc = block_init(EXCHANGE_ATOMIC, label->device, 512);
+	if ((rc != EOK) && (rc != EEXIST))
+		return ERR_LIBBLOCK;
+	
+	aoff64_t nblocks;
+	int ret = block_get_nblocks(label->device, &nblocks);
+	
+	if (rc != EEXIST)
+		block_fini(label->device);
+	
+	if (ret != EOK)
+		return ERR_LIBBLOCK;
+	
+	if ((aoff64_t) part->start_addr + part->length > nblocks)
+		return ERR_OUT_BOUNDS;
+	
+	if (label->parts == NULL) {
+		label->parts = mbr_alloc_partitions();
+		if (label->parts == NULL)
+			// FIXME! merge mbr_err_val into errno.h
+			return ENOMEM;
+	}
+	
+	if (mbr_get_flag(part, ST_LOGIC))
+		return mbr_add_logical(label, part);
+	else
+		return mbr_add_primary(label, part);
+}
+
+/** Remove partition
+ *
+ * Remove partition (indexed from zero). When removing the extended
+ * partition, all logical partitions get removed as well.
+ *
+ * @param label Label to remove from.
+ * @param idx   Index of the partition to remove.
+ *
+ * @return EOK on success.
+ * @return EINVAL if the index is invalid.
+ *
+ */
+int mbr_remove_partition(mbr_label_t *label, size_t idx)
+{
+	link_t *link = list_nth(&label->parts->list, idx);
+	if (link == NULL)
+		return EINVAL;
+	
+	/*
+	 * If removing the extended partition, remove all
+	 * logical partitions as well.
+	 */
+	if (link == label->parts->l_extended) {
+		label->parts->l_extended = NULL;
+		
+		link_t *iterator = link->next;
+		link_t *next;
+		
+		while (iterator != &label->parts->list.head) {
+			next = iterator->next;
+			mbr_part_t *partition =
+			    list_get_instance(iterator, mbr_part_t, link);
+			
+			if (mbr_get_flag(partition, ST_LOGIC)) {
+				list_remove(iterator);
+				label->parts->n_logical--;
+				mbr_free_partition(partition);
+			}
+			
+			iterator = next;
+		}
+	}
+	
+	/* Remove the partition itself */
+	mbr_part_t *partition =
+	    list_get_instance(link, mbr_part_t, link);
+	
+	if (mbr_get_flag(partition, ST_LOGIC)) {
+		label->parts->n_logical--;
+		list_remove(link);
+		mbr_free_partition(partition);
+	} else {
+		/*
+		 * Cannot remove a primary partition without
+		 * breaking the ordering. Just zero it.
+		 */
+		label->parts->n_primary--;
+		partition->type = 0;
+		partition->status = 0;
+		partition->start_addr = 0;
+		partition->length = 0;
+		partition->ebr_addr = 0;
+	}
+	
+	return EOK;
+}
+
+/** Partition destructor */
+void mbr_free_partition(mbr_part_t *partition)
+{
+	if (partition->ebr != NULL)
+		free(partition->ebr);
+	
+	free(partition);
+}
+
+/** Check for flag */
+int mbr_get_flag(mbr_part_t *partition, mbr_flags_t flag)
+{
+	return (partition->status & (1 << flag));
+}
+
+/** Set a specific status flag */
+void mbr_set_flag(mbr_part_t *partition, mbr_flags_t flag, bool set)
+{
+	if (set)
+		partition->status |= 1 << flag;
+	else
+		partition->status &= ~((uint16_t) (1 << flag));
+}
+
+/** Get next aligned address */
+uint32_t mbr_get_next_aligned(uint32_t addr, unsigned int alignment)
+{
+	return ALIGN_UP(addr + 1, alignment);
+}
+
+list_t *mbr_get_list(mbr_label_t *label)
+{
+	if (label->parts != NULL)
+		return &label->parts->list;
+	else
+		return NULL;
+}
+
+mbr_part_t *mbr_get_first_partition(mbr_label_t *label)
+{
+	list_t *list = mbr_get_list(label);
+	if ((list != NULL) && (!list_empty(list)))
+		return list_get_instance(list->head.next, mbr_part_t, link);
+	else
+		return NULL;
+}
+
+mbr_part_t *mbr_get_next_partition(mbr_label_t *label, mbr_part_t *partition)
+{
+	list_t *list = mbr_get_list(label);
+	if ((list != NULL) && (&partition->link != list_last(list)))
+		return list_get_instance(partition->link.next, mbr_part_t, link);
+	else
+		return NULL;
+}
+
+void mbr_free_mbr(mbr_t *mbr)
+{
+	free(mbr);
+}
+
+/** Free partition list
+ *
+ * @param parts Partition list to be freed
+ *
+ */
+void mbr_free_partitions(mbr_partitions_t *parts)
+{
+	list_foreach_safe(parts->list, cur_link, next) {
+		mbr_part_t *partition = list_get_instance(cur_link, mbr_part_t, link);
+		list_remove(cur_link);
+		mbr_free_partition(partition);
+	}
+	
+	free(parts);
+}
+
+static br_block_t *alloc_br(void)
+{
+	br_block_t *br = malloc(sizeof(br_block_t));
+	if (br == NULL)
+		return NULL;
+	
+	memset(br, 0, 512);
+	br->signature = host2uint16_t_le(BR_SIGNATURE);
+	
+	return br;
+}
+
+/** Decode partition entry */
+static int decode_part(pt_entry_t *src, mbr_part_t *partition, uint32_t base)
+{
+	partition->type = src->ptype;
+	partition->status = (partition->status & 0xff00) | (uint16_t) src->status;
+	partition->start_addr = uint32_t_le2host(src->first_lba) + base;
+	partition->length = uint32_t_le2host(src->length);
+	
+	return (src->ptype == PT_EXTENDED);
+}
+
+/** Parse logical partitions */
+static int decode_logical(mbr_label_t *label, mbr_part_t *extended)
+{
+	if (extended == NULL)
+		return EOK;
+	
+	br_block_t *ebr = alloc_br();
+	if (ebr == NULL)
+		return ENOMEM;
+	
+	uint32_t base = extended->start_addr;
+	uint32_t addr = base;
+	
+	int rc = block_init(EXCHANGE_ATOMIC, label->device, 512);
+	if (rc != EOK)
+		goto end;
+	
+	rc = block_read_direct(label->device, addr, 1, ebr);
+	if (rc != EOK)
+		goto end;
+	
+	if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
+		rc = EINVAL;
+		goto end;
+	}
+	
+	if (ebr->pte[0].ptype == PT_UNUSED) {
+		rc = EOK;
+		goto end;
+	}
+	
+	mbr_part_t *partition = mbr_alloc_partition();
+	if (partition == NULL) {
+		rc = ENOMEM;
+		goto end;
+	}
+	
+	decode_part(&ebr->pte[0], partition, base);
+	mbr_set_flag(partition, ST_LOGIC, true);
+	partition->ebr = ebr;
+	partition->ebr_addr = addr;
+	
+	rc = mbr_add_partition(label, partition);
+	if (rc != ERR_OK)
+		goto end;
+	
+	addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
+	
+	while (ebr->pte[1].ptype != PT_UNUSED) {
+		rc = block_read_direct(label->device, addr, 1, ebr);
+		if (rc != EOK)
+			goto end;
+		
+		if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
+			rc = EINVAL;
+			goto end;
+		}
+		
+		mbr_part_t *partition = mbr_alloc_partition();
+		if (partition == NULL) {
+			rc = ENOMEM;
+			goto end;
+		}
+		
+		decode_part(&ebr->pte[0], partition, addr);
+		mbr_set_flag(partition, ST_LOGIC, true);
+		partition->ebr = ebr;
+		partition->ebr_addr = addr;
+		
+		rc = mbr_add_partition(label, partition);
+		if (rc != ERR_OK)
+			goto end;
+		
+		addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
+	}
+	
+	rc = EOK;
+	
+end:
+	// FIXME possible memory leaks
+	block_fini(label->device);
+	
+	return rc;
+}
+
+/** Encode partition entry */
+static void encode_part(mbr_part_t *src, pt_entry_t *entry, uint32_t base,
+    bool ebr)
+{
+	if (src != NULL) {
+		entry->status = (uint8_t) src->status & 0xff;
+		
+		/* Ignore CHS */
+		entry->first_chs[0] = 0xfe;
+		entry->first_chs[1] = 0xff;
+		entry->first_chs[2] = 0xff;
+		entry->last_chs[0] = 0xfe;
+		entry->last_chs[1] = 0xff;
+		entry->last_chs[2] = 0xff;
+		
+		if (ebr) {
+			/* Encode reference to EBR */
+			entry->ptype = PT_EXTENDED_LBA;
+			entry->first_lba = host2uint32_t_le(src->ebr_addr - base);
+			entry->length = host2uint32_t_le(src->length + src->start_addr -
+			    src->ebr_addr);
+		} else {
+			/* Encode reference to partition */
+			entry->ptype = src->type;
+			entry->first_lba = host2uint32_t_le(src->start_addr - base);
+			entry->length = host2uint32_t_le(src->length);
+		}
+		
+		if (entry->ptype == PT_UNUSED)
+			memset(entry, 0, sizeof(pt_entry_t));
+	} else
+		memset(entry, 0, sizeof(pt_entry_t));
+}
+
+/** Check whether two partitions overlap */
+static bool check_overlap(mbr_part_t *part1, mbr_part_t *part2)
+{
+	if ((part1->start_addr < part2->start_addr) &&
+	    (part1->start_addr + part1->length <= part2->start_addr))
+		return false;
+	
+	if ((part1->start_addr > part2->start_addr) &&
+	    (part2->start_addr + part2->length <= part1->start_addr))
+		return false;
+	
+	return true;
+}
+
+/** Check whether one partition encapsulates the other */
+static bool check_encaps(mbr_part_t *inner, mbr_part_t *outer)
+{
+	if ((inner->start_addr <= outer->start_addr) ||
+	    (outer->start_addr + outer->length <= inner->start_addr))
+		return false;
+	
+	if (outer->start_addr + outer->length < inner->start_addr + inner->length)
+		return false;
+	
+	return true;
+}
+
+/** Check whether one partition preceeds the other */
+static bool check_preceeds(mbr_part_t *preceeder, mbr_part_t *precedee)
+{
+	return preceeder->start_addr < precedee->start_addr;
+}
+
+mbr_err_val mbr_add_primary(mbr_label_t *label, mbr_part_t *part)
+{
+	if (label->parts->n_primary == 4)
+		return ERR_PRIMARY_FULL;
+	
+	/* Check if partition makes space for MBR itself */
+	if (part->start_addr == 0)
+		return ERR_OUT_BOUNDS;
+	
+	/* If it is an extended partition, is there any other one? */
+	if (((part->type == PT_EXTENDED) || (part->type == PT_EXTENDED_LBA)) &&
+	    (label->parts->l_extended != NULL))
+		return ERR_EXTENDED_PRESENT;
+	
+	/* Find a place and add it */
+	mbr_part_t *iter;
+	mbr_part_t *empty = NULL;
+	mbr_part_foreach(label, iter) {
+		if (iter->type == PT_UNUSED) {
+			if (empty == NULL)
+				empty = iter;
+		} else if (check_overlap(part, iter))
+			return ERR_OVERLAP;
+	}
+	
+	list_insert_after(&part->link, &empty->link);
+	list_remove(&empty->link);
+	free(empty);
+	
+	label->parts->n_primary++;
+	
+	if ((part->type == PT_EXTENDED) || (part->type == PT_EXTENDED_LBA))
+		label->parts->l_extended = &part->link;
+	
+	return EOK;
+}
+
+mbr_err_val mbr_add_logical(mbr_label_t *label, mbr_part_t *part)
+{
+	/* Is there any extended partition? */
+	if (label->parts->l_extended == NULL)
+		return ERR_NO_EXTENDED;
+	
+	/* Is the logical partition inside the extended partition? */
+	mbr_part_t *extended = list_get_instance(label->parts->l_extended, mbr_part_t, link);
+	if (!check_encaps(part, extended))
+		return ERR_OUT_BOUNDS;
+	
+	/* Find a place for the new partition in a sorted linked list */
+	bool first_logical = true;
+	mbr_part_t *iter;
+	mbr_part_foreach (label, iter) {
+		if (mbr_get_flag(iter, ST_LOGIC)) {
+			if (check_overlap(part, iter))
+				return ERR_OVERLAP;
+			
+			if (check_preceeds(iter, part)) {
+				/* Check if there is at least one sector of space preceeding */
+				if ((iter->start_addr + iter->length) >= part->start_addr - 1)
+					return ERR_NO_EBR;
+			} else if (first_logical) {
+				/*
+				 * First logical partition's EBR is before every other
+				 * logical partition. Thus we do not check if this partition
+				 * leaves enough space for it.
+				 */
+				first_logical = false;
+			} else {
+				/*
+				 * Check if there is at least one sector of space following
+				 * (for following partitions's EBR).
+				 */
+				if ((part->start_addr + part->length) >= iter->start_addr - 1)
+					return ERR_NO_EBR;
+			}
+		}
+	}
+	
+	/* Allocate EBR if it is not already there */
+	if (part->ebr == NULL) {
+		part->ebr = alloc_br();
+		if (part->ebr == NULL)
+			return ERR_NOMEM;
+	}
+	
+	list_append(&part->link, &label->parts->list);
+	label->parts->n_logical++;
+	
+	return EOK;
+}
Index: uspace/lib/mbr/libmbr.h
===================================================================
--- uspace/lib/mbr/libmbr.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/mbr/libmbr.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011-2013 Dominik Taborsky
+ * 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 libmbr
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBMBR_LIBMBR_H_
+#define LIBMBR_LIBMBR_H_
+
+#include <sys/types.h>
+#include "mbr.h"
+
+/*
+ * WARNING: When changing both header and partitions, write first header,
+ * then partitions. The MBR headers' raw_data is not updated to follow
+ * partition changes.
+ *
+ * NOTE: Writing partitions writes the complete header as well.
+ */
+
+typedef enum {
+	/** Other flags unknown - saving previous state */
+	/** Bootability */
+	ST_BOOT = 7,
+	/** Logical partition, 0 = primary, 1 = logical*/
+	ST_LOGIC = 8
+} mbr_flags_t;
+
+typedef enum {
+	/** No error */
+	ERR_OK = 0,
+	/** All primary partitions already present */
+	ERR_PRIMARY_FULL,
+	/** Extended partition already present */
+	ERR_EXTENDED_PRESENT,
+	/** No extended partition present */
+	ERR_NO_EXTENDED,
+	/** Partition overlapping */
+	ERR_OVERLAP,
+	/** Partition out of bounds */
+	ERR_OUT_BOUNDS,
+	/** No space left for EBR */
+	ERR_NO_EBR,
+	/** Out of memory */
+	ERR_NOMEM,
+	/** Libblock error */
+	ERR_LIBBLOCK,
+} mbr_err_val;
+
+/** MBR header */
+typedef struct {
+	/** Raw access to data */
+	br_block_t raw_data;
+} mbr_t;
+
+/** Partition */
+typedef struct mbr_part {
+	/** The link in the doubly-linked list */
+	link_t link;
+	/** Partition type */
+	uint8_t type;
+	/** Flags */
+	uint16_t status;
+	/** Address of first block */
+	uint32_t start_addr;
+	/** Number of blocks */
+	uint32_t length;
+	/** Points to Extended Boot Record of logical partition */
+	br_block_t *ebr;
+	/** EBR address */
+	uint32_t ebr_addr;
+} mbr_part_t;
+
+/** Partition list structure */
+typedef struct mbr_parts {
+	/** Number of primary partitions */
+	unsigned char n_primary;
+	/** Index to the extended partition in the array */
+	link_t *l_extended;
+	/** Number of logical partitions */
+	unsigned int n_logical;
+	/** Logical partition linked list */
+	list_t list;
+} mbr_partitions_t;
+
+/** Both header and partition list */
+typedef struct mbr_label {
+	/** MBR header */
+	mbr_t *mbr;
+	/** Partition list */
+	mbr_partitions_t * parts;
+	/** Device where the data are from (or for) */
+	service_id_t device;
+} mbr_label_t;
+
+#define mbr_part_foreach(label, iterator) \
+	for (iterator = list_get_instance((label)->parts->list.head.next, mbr_part_t, link); \
+	    iterator != list_get_instance(&((label)->parts->list.head), mbr_part_t, link); \
+	    iterator = list_get_instance(iterator->link.next, mbr_part_t, link))
+
+extern mbr_label_t *mbr_alloc_label(void);
+
+extern void mbr_set_device(mbr_label_t *, service_id_t);
+extern mbr_t *mbr_alloc_mbr(void);
+extern int mbr_read_mbr(mbr_label_t *, service_id_t);
+extern int mbr_write_mbr(mbr_label_t *, service_id_t);
+extern int mbr_is_mbr(mbr_label_t *);
+
+extern int mbr_read_partitions(mbr_label_t *);
+extern int mbr_write_partitions(mbr_label_t *, service_id_t);
+extern mbr_part_t *mbr_alloc_partition(void);
+extern mbr_partitions_t *mbr_alloc_partitions(void);
+extern mbr_err_val mbr_add_partition(mbr_label_t *, mbr_part_t *);
+extern int mbr_remove_partition(mbr_label_t *, size_t);
+extern int mbr_get_flag(mbr_part_t *, mbr_flags_t);
+extern void mbr_set_flag(mbr_part_t *, mbr_flags_t, bool);
+extern uint32_t mbr_get_next_aligned(uint32_t, unsigned int);
+extern list_t *mbr_get_list(mbr_label_t *);
+extern mbr_part_t *mbr_get_first_partition(mbr_label_t *);
+extern mbr_part_t *mbr_get_next_partition(mbr_label_t *, mbr_part_t *);
+
+extern void mbr_free_label(mbr_label_t *);
+extern void mbr_free_mbr(mbr_t *);
+extern void mbr_free_partition(mbr_part_t *);
+extern void mbr_free_partitions(mbr_partitions_t *);
+
+#endif
Index: uspace/lib/mbr/mbr.h
===================================================================
--- uspace/lib/mbr/mbr.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/mbr/mbr.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011-2013 Dominik Taborsky
+ * 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 libmbr
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBMBR_MBR_H_
+#define LIBMBR_MBR_H_
+
+#include <sys/types.h>
+
+enum {
+	/** Number of primary partition records */
+	N_PRIMARY = 4,
+	
+	/** Boot record signature */
+	BR_SIGNATURE = 0xAA55
+};
+
+enum {
+	/** Non-bootable */
+	B_INACTIVE = 0x00,
+	/** Bootable */
+	B_ACTIVE = 0x80,
+	/** Anything else means invalid */
+};
+
+enum {
+	/** Unused partition entry */
+	PT_UNUSED = 0x00,
+	/** Extended partition */
+	PT_EXTENDED = 0x05,
+	/** Extended partition with LBA */
+	PT_EXTENDED_LBA = 0x0F,
+	/** GPT Protective partition */
+	PT_GPT = 0xEE,
+};
+
+/** Structure of a partition table entry */
+typedef struct {
+	uint8_t status;
+	/** CHS of fist block in partition */
+	uint8_t first_chs[3];
+	/** Partition type */
+	uint8_t ptype;
+	/** CHS of last block in partition */
+	uint8_t last_chs[3];
+	/** LBA of first block in partition */
+	uint32_t first_lba;
+	/** Number of blocks in partition */
+	uint32_t length;
+} __attribute__((packed)) pt_entry_t;
+
+/** Structure of a boot-record block */
+typedef struct {
+	/** Area for boot code */
+	uint8_t code_area[440];
+	/** Optional media ID */
+	uint32_t media_id;
+	/** Padding */
+	uint16_t pad0;
+	/** Partition table entries */
+	pt_entry_t pte[N_PRIMARY];
+	/** Boot record block signature (@c BR_SIGNATURE) */
+	uint16_t signature;
+} __attribute__((packed)) br_block_t;
+
+#endif
+
Index: uspace/lib/net/include/socket_core.h
===================================================================
--- uspace/lib/net/include/socket_core.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/net/include/socket_core.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -43,5 +43,4 @@
 #include <adt/int_map.h>
 #include <net/in.h>
-#include <net/device.h>
 #include <async.h>
 
Index: uspace/lib/posix/Makefile
===================================================================
--- uspace/lib/posix/Makefile	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/posix/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -42,6 +42,6 @@
 FIXED_C_LIBRARY = libc4posix.a
 
-REDEFS_HIDE_LIBC = redefs-hide-libc.xargs
-REDEFS_SHOW_LIBPOSIX = redefs-show-posix.xargs
+REDEFS_HIDE_LIBC = redefs-hide-libc-symbols.list
+REDEFS_SHOW_LIBPOSIX = redefs-show-posix-symbols.list
 COLLISIONS_LIST = collisions.list
 
@@ -60,5 +60,8 @@
 	source/getopt.c \
 	source/locale.c \
-	source/math.c \
+	source/pthread/condvar.c \
+	source/pthread/keys.c \
+	source/pthread/mutex.c \
+	source/pthread/threads.c \
 	source/pwd.c \
 	source/signal.c \
@@ -81,21 +84,20 @@
 
 $(FIXED_C_LIBRARY): $(REDEFS_HIDE_LIBC) $(REDEFS_SHOW_LIBPOSIX)
-	./tools/transform-symbols.sh \
-		$(OBJCOPY) $(AR) echo \
-		$(LIBC_FILE) $@ \
-		$(REDEFS_HIDE_LIBC) $(REDEFS_SHOW_LIBPOSIX)
+	$(OBJCOPY) --redefine-syms=$(REDEFS_HIDE_LIBC) $(LIBC_FILE) $@
+	$(OBJCOPY) --redefine-syms=$(REDEFS_SHOW_LIBPOSIX) $@ $@
 
 $(FIXED_POSIX_LIBRARY): $(LIBRARY).a $(REDEFS_HIDE_LIBC) $(REDEFS_SHOW_LIBPOSIX)
-	./tools/transform-symbols.sh \
-		$(OBJCOPY) $(AR) echo \
-		$(LIBRARY).a $@ \
-		$(REDEFS_HIDE_LIBC) $(REDEFS_SHOW_LIBPOSIX)
+	$(OBJCOPY) --redefine-syms=$(REDEFS_HIDE_LIBC) $(LIBRARY).a $@
+	$(OBJCOPY) --redefine-syms=$(REDEFS_SHOW_LIBPOSIX) $@ $@
 
 $(REDEFS_HIDE_LIBC): $(COLLISIONS_LIST)
-	./tools/create-redefines.sh "" "__helenos_libc_" <$(COLLISIONS_LIST) >$@
-	
+	sed 's/.*/& __helenos_libc_&/' <$(COLLISIONS_LIST) >$@
+
 $(REDEFS_SHOW_LIBPOSIX): $(COLLISIONS_LIST)
-	./tools/create-redefines.sh "posix_" "" <$(COLLISIONS_LIST) >$@
+	sed 's/.*/posix_& &/' <$(COLLISIONS_LIST) >$@
 
 $(COLLISIONS_LIST):
-	./tools/get-collision-list.sh ./include/posix >$@
+	find ./include/posix -name '*.h' -exec \
+		sed -n -e '/^#/d' -e 's/__POSIX_DEF__/\n&/gp' {} \; | \
+		sed -n -e 's/__POSIX_DEF__(\([^)]*\)).*/\1/p' | \
+		sort -u >$@
Index: uspace/lib/posix/include/posix/float.h
===================================================================
--- uspace/lib/posix/include/posix/float.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/posix/include/posix/float.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -59,6 +59,22 @@
 	#undef DBL_EPSILON
 	#define DBL_EPSILON __DBL_EPSILON__
+	#undef LDBL_EPSILON
+	#define LDBL_EPSILON __LDBL_EPSILON__
 	#undef FLT_RADIX
 	#define FLT_RADIX __FLT_RADIX__
+	#undef FLT_MIN
+	#define FLT_MIN __FLT_MIN__
+	#undef FLT_MAX
+	#define FLT_MAX __FLT_MAX__
+	#undef FLT_EPSILON
+	#define FLT_EPSILON __FLT_EPSILON__
+	#undef FLT_MANT_DIG
+	#define FLT_MANT_DIG __FLT_MANT_DIG__
+	#undef LDBL_MIN
+	#define LDBL_MIN __LDBL_MIN__
+	#undef LDBL_MAX
+	#define LDBL_MAX __LDBL_MAX__
+	#undef LDBL_MANT_DIG 
+	#define LDBL_MANT_DIG __LDBL_MANT_DIG__
 #else
 /* For something else than GCC, following definitions are provided.
Index: uspace/lib/posix/include/posix/math.h
===================================================================
--- uspace/lib/posix/include/posix/math.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/posix/include/posix/math.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -36,27 +36,5 @@
 #define POSIX_MATH_H_
 
-#ifndef __POSIX_DEF__
-#define __POSIX_DEF__(x) x
-#endif
-
-#ifdef __GNUC__
-	#define HUGE_VAL (__builtin_huge_val())
-#endif
-
-/* Normalization Functions */
-extern double __POSIX_DEF__(ldexp)(double x, int exp);
-extern double __POSIX_DEF__(frexp)(double num, int *exp);
-
-double __POSIX_DEF__(fabs)(double x);
-double __POSIX_DEF__(floor)(double x);
-double __POSIX_DEF__(modf)(double x, double *iptr);
-double __POSIX_DEF__(fmod)(double x, double y);
-double __POSIX_DEF__(pow)(double x, double y);
-double __POSIX_DEF__(exp)(double x);
-double __POSIX_DEF__(sqrt)(double x);
-double __POSIX_DEF__(log)(double x);
-double __POSIX_DEF__(sin)(double x);
-double __POSIX_DEF__(cos)(double x);
-double __POSIX_DEF__(atan2)(double y, double x);
+#include "libc/math.h"
 
 #endif /* POSIX_MATH_H_ */
Index: uspace/lib/posix/include/posix/pthread.h
===================================================================
--- uspace/lib/posix/include/posix/pthread.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/posix/include/posix/pthread.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 libposix
+ * @{
+ */
+#ifndef POSIX_PTHREAD_H_
+#define POSIX_PTHREAD_H_
+
+#ifndef __POSIX_DEF__
+#define __POSIX_DEF__(x) x
+#endif
+
+#include "libc/thread.h"
+#include "time.h"
+
+typedef thread_id_t pthread_t;
+
+typedef struct {
+	int dummy;
+} pthread_attr_t;
+
+typedef int pthread_key_t;
+
+#define PTHREAD_MUTEX_RECURSIVE 1
+
+typedef struct pthread_mutex {
+	int dummy;
+} pthread_mutex_t;
+
+#define PTHREAD_MUTEX_INITIALIZER { 0 }
+
+typedef struct {
+	int dummy;
+} pthread_mutexattr_t;
+
+typedef struct {
+	int dummy;
+} pthread_condattr_t;
+
+typedef struct {
+	int dummy;
+} pthread_cond_t;
+
+#define PTHREAD_COND_INITIALIZER { 0 }
+
+extern pthread_t pthread_self(void);
+extern int pthread_equal(pthread_t, pthread_t);
+extern int pthread_create(pthread_t *, const pthread_attr_t *,
+    void *(*)(void *), void *);
+extern int pthread_join(pthread_t, void **);
+extern int pthread_detach(pthread_t);
+
+extern int pthread_attr_init(pthread_attr_t *);
+extern int pthread_attr_destroy(pthread_attr_t *);
+
+extern int pthread_mutex_init(pthread_mutex_t *restrict,
+    const pthread_mutexattr_t *restrict);
+extern int pthread_mutex_destroy(pthread_mutex_t *);
+extern int pthread_mutex_lock(pthread_mutex_t *);
+extern int pthread_mutex_trylock(pthread_mutex_t *);
+extern int pthread_mutex_unlock(pthread_mutex_t *);
+
+extern int pthread_mutexattr_init(pthread_mutexattr_t *);
+extern int pthread_mutexattr_destroy(pthread_mutexattr_t *);
+extern int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict,
+    int *restrict);
+extern int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
+
+extern int pthread_cond_init(pthread_cond_t *restrict,
+    const pthread_condattr_t *restrict);
+extern int pthread_cond_destroy(pthread_cond_t *);
+extern int pthread_cond_broadcast(pthread_cond_t *);
+extern int pthread_cond_signal(pthread_cond_t *);
+extern int pthread_cond_timedwait(pthread_cond_t *restrict,
+    pthread_mutex_t *restrict, const struct __POSIX_DEF__(timespec) *restrict);
+extern int pthread_cond_wait(pthread_cond_t *restrict,
+    pthread_mutex_t *restrict);
+
+extern int pthread_condattr_destroy(pthread_condattr_t *);
+extern int pthread_condattr_init(pthread_condattr_t *);
+
+extern void *pthread_getspecific(pthread_key_t);
+extern int pthread_setspecific(pthread_key_t, const void *);
+extern int pthread_key_delete(pthread_key_t);
+extern int pthread_key_create(pthread_key_t *, void (*)(void*));
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/setjmp.h
===================================================================
--- uspace/lib/posix/include/posix/setjmp.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/posix/include/posix/setjmp.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 libposix
+ * @{
+ */
+
+/*
+ * Just a pass-through to libc setjmp.
+ */
+#include "libc/setjmp.h"
+
+/** @}
+ */
Index: uspace/lib/posix/include/posix/stdint.h
===================================================================
--- uspace/lib/posix/include/posix/stdint.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/posix/include/posix/stdint.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -108,4 +108,29 @@
 
 
+/*
+ * Fast* and least* integer types.
+ *
+ * The definitions below are definitely safe if not the best.
+ */
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+
 #endif /* POSIX_STDINT_H_ */
 
Index: uspace/lib/posix/include/posix/stdio.h
===================================================================
--- uspace/lib/posix/include/posix/stdio.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/posix/include/posix/stdio.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -123,5 +123,5 @@
 
 extern void setvbuf(FILE *, void *, int, size_t);
-
+extern void setbuf(FILE *, void *);
 
 /* POSIX specific stuff. */
Index: uspace/lib/posix/include/posix/stdlib.h
===================================================================
--- uspace/lib/posix/include/posix/stdlib.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/posix/include/posix/stdlib.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -56,5 +56,5 @@
 #define _Exit exit
 extern int __POSIX_DEF__(atexit)(void (*func)(void));
-extern void exit(int status);
+extern void exit(int status) __attribute__((noreturn));
 extern void abort(void) __attribute__((noreturn));
 
Index: uspace/lib/posix/include/posix/time.h
===================================================================
--- uspace/lib/posix/include/posix/time.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/posix/include/posix/time.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -104,4 +104,5 @@
 extern char *__POSIX_DEF__(ctime_r)(const time_t *timer, char *buf);
 extern char *__POSIX_DEF__(ctime)(const time_t *timer);
+extern time_t time(time_t *t);
 
 /* Clocks */
Index: uspace/lib/posix/source/internal/common.h
===================================================================
--- uspace/lib/posix/source/internal/common.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/posix/source/internal/common.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -39,7 +39,12 @@
 #include <stdlib.h>
 
-#define not_implemented() (fprintf(stderr, \
-    "Function %s() in file %s at line %d is not implemented\n", \
-    __func__, __FILE__, __LINE__), abort())
+#define not_implemented() do { \
+		static int __not_implemented_counter = 0; \
+		if (__not_implemented_counter == 0) { \
+			fprintf(stderr, "%s() not implemented in %s:%d, something will NOT work.\n", \
+				__func__, __FILE__, __LINE__); \
+		} \
+		__not_implemented_counter++; \
+	} while (0)
 
 /* A little helper macro to avoid typing this over and over. */
Index: uspace/lib/posix/source/math.c
===================================================================
--- uspace/lib/posix/source/math.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,191 +1,0 @@
-/*
- * Copyright (c) 2011 Petr Koupy
- * 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 libposix
- * @{
- */
-/** @file Mathematical operations.
- */
-
-#define LIBPOSIX_INTERNAL
-#define __POSIX_DEF__(x) posix_##x
-
-#include "internal/common.h"
-#include "posix/math.h"
-
-/**
- * 
- * @param x
- * @param exp
- * @return
- */
-double posix_ldexp(double x, int exp)
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
-/**
- * 
- * @param num
- * @param exp
- * @return
- */
-double posix_frexp(double num, int *exp)
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
-/**
- * 
- * @param x
- * @return
- */
-double posix_cos(double x)
-{
-	// TODO: Python dependency
-	not_implemented();
-}
-
-/**
- * 
- * @param x
- * @param y
- * @return
- */
-double posix_pow(double x, double y)
-{
-	// TODO: Python dependency
-	not_implemented();
-}
-
-/**
- * 
- * @param x
- * @return
- */
-double posix_floor(double x)
-{
-	// TODO: Python dependency
-	not_implemented();
-}
-
-/**
- * 
- * @param x
- * @return
- */
-double posix_fabs(double x)
-{
-	// TODO: Python dependency
-	not_implemented();
-}
-
-/**
- * 
- * @param x
- * @param iptr
- * @return
- */
-double posix_modf(double x, double *iptr)
-{
-	// TODO: Python dependency
-	not_implemented();
-}
-
-/**
- * 
- * @param x
- * @param y
- * @return
- */
-double posix_fmod(double x, double y)
-{
-	// TODO: Python dependency
-	not_implemented();
-}
-
-/**
- * 
- * @param x
- * @return
- */
-double posix_log(double x)
-{
-	// TODO: Python dependency
-	not_implemented();
-}
-
-/**
- * 
- * @param x
- * @param y
- * @return
- */
-double posix_atan2(double y, double x)
-{
-	// TODO: Python dependency
-	not_implemented();
-}
-
-/**
- * 
- * @param x
- * @return
- */
-double posix_sin(double x)
-{
-	// TODO: Python dependency
-	not_implemented();
-}
-
-/**
- * 
- * @param x
- * @return
- */
-double posix_exp(double x)
-{
-	// TODO: Python dependency
-	not_implemented();
-}
-
-/**
- * 
- * @param x
- * @return
- */
-double posix_sqrt(double x)
-{
-	// TODO: Python dependency
-	not_implemented();
-}
-
-/** @}
- */
Index: uspace/lib/posix/source/pthread/condvar.c
===================================================================
--- uspace/lib/posix/source/pthread/condvar.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/posix/source/pthread/condvar.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 libposix
+ * @{
+ */
+/** @file Pthread: condition variables.
+ */
+
+#define LIBPOSIX_INTERNAL
+#define __POSIX_DEF__(x) posix_##x
+
+#include "posix/pthread.h"
+#include "errno.h"
+#include "../internal/common.h"
+
+int pthread_cond_init(pthread_cond_t *restrict condvar,
+    const pthread_condattr_t *restrict attr)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_cond_destroy(pthread_cond_t *condvar)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_cond_broadcast(pthread_cond_t *condvar)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_cond_signal(pthread_cond_t *condvar)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_cond_timedwait(pthread_cond_t *restrict condvar,
+    pthread_mutex_t *restrict mutex, const struct __POSIX_DEF__(timespec) *restrict timeout)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_cond_wait(pthread_cond_t *restrict condvar,
+    pthread_mutex_t *restrict mutex)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+
+int pthread_condattr_init(pthread_condattr_t *attr)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+
+/** @}
+ */
Index: uspace/lib/posix/source/pthread/keys.c
===================================================================
--- uspace/lib/posix/source/pthread/keys.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/posix/source/pthread/keys.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 libposix
+ * @{
+ */
+/** @file Pthread: keys and thread-specific storage.
+ */
+
+#define LIBPOSIX_INTERNAL
+#define __POSIX_DEF__(x) posix_##x
+
+#include "posix/stdlib.h"
+#include "posix/pthread.h"
+#include "errno.h"
+#include "../internal/common.h"
+
+
+void *pthread_getspecific(pthread_key_t key)
+{
+	not_implemented();
+	return NULL;
+}
+
+int pthread_setspecific(pthread_key_t key, const void *data)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_key_delete(pthread_key_t key)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/pthread/mutex.c
===================================================================
--- uspace/lib/posix/source/pthread/mutex.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/posix/source/pthread/mutex.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 libposix
+ * @{
+ */
+/** @file Pthread: mutexes.
+ */
+
+#define LIBPOSIX_INTERNAL
+#define __POSIX_DEF__(x) posix_##x
+
+#include "posix/pthread.h"
+#include "errno.h"
+#include "../internal/common.h"
+
+
+int pthread_mutex_init(pthread_mutex_t *restrict mutex,
+    const pthread_mutexattr_t *restrict attr)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,
+    int *restrict type)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+
+
+/** @}
+ */
Index: uspace/lib/posix/source/pthread/threads.c
===================================================================
--- uspace/lib/posix/source/pthread/threads.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/posix/source/pthread/threads.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 libposix
+ * @{
+ */
+/** @file Pthread: thread management.
+ */
+
+#define LIBPOSIX_INTERNAL
+#define __POSIX_DEF__(x) posix_##x
+
+#include "posix/pthread.h"
+#include "errno.h"
+#include "posix/stdlib.h"
+#include "libc/thread.h"
+#include "../internal/common.h"
+
+pthread_t pthread_self(void)
+{
+	return thread_get_id();
+}
+
+int pthread_equal(pthread_t thread1, pthread_t thread2)
+{
+	return thread1 == thread2;
+}
+
+int pthread_create(pthread_t *thread_id, const pthread_attr_t *attributes,
+    void *(*start_routine)(void *), void *arg)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_join(pthread_t thread, void **ret_val)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_detach(pthread_t thread)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_attr_init(pthread_attr_t *attr)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+int pthread_attr_destroy(pthread_attr_t *attr)
+{
+	not_implemented();
+	return ENOTSUP;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/source/stdlib.c
===================================================================
--- uspace/lib/posix/source/stdlib.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/posix/source/stdlib.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -63,5 +63,5 @@
 	// TODO: low priority, just a compile-time dependency of binutils
 	not_implemented();
-	return 1;
+	return 0;
 }
 
Index: uspace/lib/posix/source/unistd.c
===================================================================
--- uspace/lib/posix/source/unistd.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/posix/source/unistd.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -389,4 +389,5 @@
 	// TODO: low priority, just a compile-time dependency of binutils
 	not_implemented();
+	return -1;
 }
 
@@ -399,4 +400,5 @@
 	// TODO: low priority, just a compile-time dependency of binutils
 	not_implemented();
+	return -1;
 }
 
@@ -411,4 +413,5 @@
 	// TODO: low priority, just a compile-time dependency of binutils
 	not_implemented();
+	return -1;
 }
 
@@ -423,4 +426,5 @@
 	// TODO: low priority, just a compile-time dependency of binutils
 	not_implemented();
+	return -1;
 }
 
@@ -434,4 +438,5 @@
 	// TODO: low priority, just a compile-time dependency of binutils
 	not_implemented();
+	return -1;
 }
 
Index: uspace/lib/posix/tools/create-redefines.sh
===================================================================
--- uspace/lib/posix/tools/create-redefines.sh	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,7 +1,0 @@
-#!/bin/sh
-
-set -e
-
-while read symbolname; do
-	echo "--redefine-sym=$1$symbolname=$2$symbolname"
-done
Index: uspace/lib/posix/tools/get-collision-list.sh
===================================================================
--- uspace/lib/posix/tools/get-collision-list.sh	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,8 +1,0 @@
-#!/bin/sh
-
-set -e
-
-find "$1" -name '*.h' -exec \
-	sed -n -e '/^#/d' -e 's/__POSIX_DEF__/\n&/gp' {} \; | \
-	sed -n -e 's/__POSIX_DEF__(\([^)]*\)).*/\1/p' | \
-	sort -u
Index: uspace/lib/posix/tools/transform-symbols.sh
===================================================================
--- uspace/lib/posix/tools/transform-symbols.sh	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,31 +1,0 @@
-#!/bin/sh
-
-OBJCOPY="$1"
-AR="$2"
-ECHO="$3"
-LIB_SOURCE="$4"
-LIB_RESULT="$5"
-REDEFS_FIRST="$6"
-REDEFS_SECOND="$7"
-
-set -e
-
-rm -f "$LIB_RESULT"
-
-$ECHO -n "$LIB_RESULT:"
-
-$AR t "$LIB_SOURCE" | sort | uniq -c | while read count filename; do
-	rm -f "$filename"
-	$ECHO -n " $filename"
-	for idx in `seq 1 $count`; do
-		$AR xN $idx "$LIB_SOURCE" "$filename"
-		xargs "$OBJCOPY" "$filename" "$filename" <"$REDEFS_FIRST"
-		xargs "$OBJCOPY" "$filename" "$filename" <"$REDEFS_SECOND"
-		$AR qc "$LIB_RESULT" "$filename"
-		rm -f "$filename"
-	done
-done
-
-$AR s "$LIB_RESULT"
-
-$ECHO ""
Index: uspace/lib/softfloat/softfloat.c
===================================================================
--- uspace/lib/softfloat/softfloat.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/softfloat/softfloat.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -1265,4 +1265,15 @@
 }
 
+float __aeabi_d2f(double a)
+{
+	return __truncdfsf2(a);
+}
+
+double __aeabi_f2d(float a)
+{
+	return __extendsfdf2(a);
+}
+
+
 float __aeabi_i2f(int i)
 {
@@ -1285,4 +1296,19 @@
 }
 
+double __aeabi_l2d(long long i)
+{
+	return __floattidf(i);
+}
+
+float __aeabi_l2f(long long i)
+{
+	return __floattisf(i);
+}
+
+float __aeabi_ul2f(unsigned long long u)
+{
+	return __floatuntisf(u);
+}
+
 int __aeabi_f2iz(float a)
 {
@@ -1305,4 +1331,9 @@
 }
 
+long long __aeabi_d2lz(double a)
+{
+	return __fixdfti(a);
+}
+
 int __aeabi_fcmpge(float a, float b)
 {
@@ -1339,4 +1370,10 @@
 	return __ltdf2(a, b);
 }
+
+int __aeabi_dcmple(double a, double b)
+{
+	return __ledf2(a, b);
+}
+
 
 int __aeabi_dcmpeq(double a, double b)
Index: uspace/lib/softfloat/softfloat.h
===================================================================
--- uspace/lib/softfloat/softfloat.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/softfloat/softfloat.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -204,9 +204,15 @@
 
 /* ARM EABI */
+extern float __aeabi_d2f(double);
+extern double __aeabi_f2d(float);
 extern float __aeabi_i2f(int);
 extern float __aeabi_ui2f(int);
 extern double __aeabi_i2d(int);
 extern double __aeabi_ui2d(unsigned int);
+extern double __aeabi_l2d(long long);
+extern float __aeabi_l2f(long long);
+extern float __aeabi_ul2f(unsigned long long);
 extern unsigned int __aeabi_d2uiz(double);
+extern long long __aeabi_d2lz(double);
 
 extern int __aeabi_f2iz(float);
@@ -222,4 +228,5 @@
 extern int __aeabi_dcmpgt(double, double);
 extern int __aeabi_dcmplt(double, double);
+extern int __aeabi_dcmple(double, double);
 extern int __aeabi_dcmpeq(double, double);
 
Index: uspace/lib/softint/Makefile
===================================================================
--- uspace/lib/softint/Makefile	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/softint/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -35,4 +35,5 @@
 
 SOURCES = \
+	generic/bits.c \
 	generic/comparison.c \
 	generic/division.c \
Index: uspace/lib/softint/generic/bits.c
===================================================================
--- uspace/lib/softint/generic/bits.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/softint/generic/bits.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 softint
+ * @{
+ */
+
+#include <bits.h>
+
+/** Compute number of trailing 0-bits in a number. */
+int __ctzdi2(long a)
+{
+	unsigned int bits = 0;
+	while (((a >> bits) & 1) == 0) {
+		bits++;
+		if (bits >= sizeof(a) * 8) {
+			break;
+		}
+	}
+
+	return bits;
+}
+
+/** Compute number of trailing 0-bits in a number. */
+int __ctzsi2(int a)
+{
+	unsigned int bits = 0;
+	while (((a >> bits) & 1) == 0) {
+		bits++;
+		if (bits >= sizeof(a) * 8) {
+			break;
+		}
+	}
+
+	return bits;
+}
+
+/** Compute number of leading 0-bits in a number. */
+int __clzdi2(long a)
+{
+	int index = sizeof(a) * 8 - 1;
+	int bits = 0;
+	while (index >= 0) {
+		if (((a >> index) & 1) == 0) {
+			bits++;
+		} else {
+			break;
+		}
+		index--;
+	}
+
+	return bits;
+}
+
+/** Compute index of the first 1-bit in a number increased by one.
+ *
+ * If the number is zero, zero is returned.
+ */
+int __ffsdi2(long a) {
+	if (a == 0) {
+		return 0;
+	}
+
+	return 1 + __ctzdi2(a);
+}
+
+/** Compute number of set bits in a number. */
+int __popcountsi2(int a)
+{
+	int bits = 0;
+	for (unsigned int i = 0; i < sizeof(a) * 8; i++)	 {
+		if (((a >> i) & 1) != 0) {
+			bits++;
+		}
+	}
+	return bits;									
+}
+
+/** Compute number of set bits in a number. */
+int __popcountdi2(long a)
+{
+	int bits = 0;
+	for (unsigned int i = 0; i < sizeof(a) * 8; i++)	 {
+		if (((a >> i) & 1) != 0) {
+			bits++;
+		}
+	}
+	return bits;									
+}
+
+/** @}
+ */
Index: uspace/lib/softint/generic/shift.c
===================================================================
--- uspace/lib/softint/generic/shift.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/softint/generic/shift.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -123,4 +123,9 @@
 }
 
+long long __aeabi_llsl(long long val, int shift)
+{
+	return __ashldi3(val, shift);
+}
+
 /** @}
  */
Index: uspace/lib/softint/include/bits.h
===================================================================
--- uspace/lib/softint/include/bits.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/lib/softint/include/bits.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 softint
+ * @{
+ */
+/** @file
+ */
+
+#ifndef __SOFTINT_BITS_H_
+#define __SOFTINT_BITS_H_
+
+extern int __ctzdi2(long);
+extern int __ctzsi2(int);
+extern int __clzdi2(long);
+extern int __ffsdi2(long);
+extern int __popcountsi2(int);
+extern int __popcountdi2(long);
+
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/softint/include/shift.h
===================================================================
--- uspace/lib/softint/include/shift.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/lib/softint/include/shift.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -46,4 +46,8 @@
 extern long long __lshrdi3(long long, int);
 
+
+/* ARM EABI */
+extern long long __aeabi_llsl(long long, int);
+
 #endif
 
Index: uspace/srv/fs/ext4fs/Makefile
===================================================================
--- uspace/srv/fs/ext4fs/Makefile	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/fs/ext4fs/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -31,4 +31,5 @@
 EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX) -I$(LIBEXT4_PREFIX)
 BINARY = ext4fs
+STATIC_NEEDED = y
 
 SOURCES = \
Index: uspace/srv/fs/locfs/Makefile
===================================================================
--- uspace/srv/fs/locfs/Makefile	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/fs/locfs/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -32,5 +32,4 @@
 EXTRA_CFLAGS += -I$(LIBFS_PREFIX)
 BINARY = locfs
-STATIC_NEEDED = y
 
 SOURCES = \
Index: uspace/srv/net/dhcp/Makefile
===================================================================
--- uspace/srv/net/dhcp/Makefile	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/dhcp/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -31,5 +31,7 @@
 
 SOURCES = \
-	dhcp.c 
+	dhcp.c \
+	main.c \
+	transport.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/net/dhcp/dhcp.c
===================================================================
--- uspace/srv/net/dhcp/dhcp.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/dhcp/dhcp.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -35,24 +35,48 @@
  */
 
+#include <adt/list.h>
 #include <bitops.h>
+#include <errno.h>
+#include <fibril_synch.h>
 #include <inet/addr.h>
 #include <inet/dnsr.h>
 #include <inet/inetcfg.h>
+#include <io/log.h>
 #include <loc.h>
-#include <net/in.h>
-#include <net/inet.h>
-#include <net/socket.h>
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "dhcp.h"
 #include "dhcp_std.h"
-
-#define NAME "dhcp"
+#include "transport.h"
+
+enum {
+	/** In microseconds */
+	dhcp_discover_timeout_val = 5 * 1000 * 1000,
+	/** In microseconds */
+	dhcp_request_timeout_val = 1 * 1000 * 1000,
+	dhcp_discover_retries = 5,
+	dhcp_request_retries = 3
+};
 
 #define MAX_MSG_SIZE 1024
-
-static int transport_fd = -1;
-static inet_link_info_t link_info;
 static uint8_t msgbuf[MAX_MSG_SIZE];
+
+/** List of registered links (of dhcp_link_t) */
+static list_t dhcp_links;
+
+static void dhcpsrv_discover_timeout(void *);
+static void dhcpsrv_request_timeout(void *);
+
+typedef enum {
+	ds_bound,
+	ds_fail,
+	ds_init,
+	ds_init_reboot,
+	ds_rebinding,
+	ds_renewing,
+	ds_requesting,
+	ds_selecting
+} dhcp_state_t;
 
 typedef struct {
@@ -69,4 +93,25 @@
 } dhcp_offer_t;
 
+typedef struct {
+	/** Link to dhcp_links list */
+	link_t links;
+	/** Link service ID */
+	service_id_t link_id;
+	/** Link info */
+	inet_link_info_t link_info;
+	/** Transport */
+	dhcp_transport_t dt;
+	/** Transport timeout */
+	fibril_timer_t *timeout;
+	/** Number of retries */
+	int retries_left;
+	/** Link state */
+	dhcp_state_t state;
+	/** Last received offer */
+	dhcp_offer_t offer;
+} dhcp_link_t;
+
+static void dhcpsrv_recv(void *, void *, size_t);
+
 /** Decode subnet mask into subnet prefix length. */
 static int subnet_mask_decode(uint32_t mask, int *bits)
@@ -101,24 +146,5 @@
 }
 
-static int dhcp_send(void *msg, size_t size)
-{
-	struct sockaddr_in addr;
-	int rc;
-
-	addr.sin_family = AF_INET;
-	addr.sin_port = htons(dhcp_server_port);
-	addr.sin_addr.s_addr = htonl(addr32_broadcast_all_hosts);
-
-	rc = sendto(transport_fd, msg, size, 0,
-	    (struct sockaddr *)&addr, sizeof(addr));
-	if (rc != EOK) {
-		printf("Sending failed\n");
-		return rc;
-	}
-
-	return EOK;
-}
-
-static int dhcp_send_discover(void)
+static int dhcp_send_discover(dhcp_link_t *dlink)
 {
 	dhcp_hdr_t *hdr = (dhcp_hdr_t *)msgbuf;
@@ -132,5 +158,5 @@
 	hdr->flags = flag_broadcast;
 
-	addr48(link_info.mac_addr, hdr->chaddr);
+	addr48(dlink->link_info.mac_addr, hdr->chaddr);
 	hdr->opt_magic = host2uint32_t_be(dhcp_opt_magic);
 
@@ -140,30 +166,8 @@
 	opt[3] = opt_end;
 
-	return dhcp_send(msgbuf, sizeof(dhcp_hdr_t) + 4);
-}
-
-static int dhcp_recv_msg(void **rmsg, size_t *rsize)
-{
-	struct sockaddr_in src_addr;
-	socklen_t src_addr_size;
-	size_t recv_size;
-	int rc;
-
-	src_addr_size = sizeof(src_addr);
-	rc = recvfrom(transport_fd, msgbuf, MAX_MSG_SIZE, 0,
-	    (struct sockaddr *)&src_addr, &src_addr_size);
-	if (rc < 0) {
-		printf("recvfrom failed (%d)\n", rc);
-		return rc;
-	}
-
-	recv_size = (size_t)rc;
-	*rmsg = msgbuf;
-	*rsize = recv_size;
-
-	return EOK;
-}
-
-static int dhcp_send_request(dhcp_offer_t *offer)
+	return dhcp_send(&dlink->dt, msgbuf, sizeof(dhcp_hdr_t) + 4);
+}
+
+static int dhcp_send_request(dhcp_link_t *dlink, dhcp_offer_t *offer)
 {
 	dhcp_hdr_t *hdr = (dhcp_hdr_t *)msgbuf;
@@ -178,5 +182,5 @@
 	hdr->flags = flag_broadcast;
 	hdr->ciaddr = host2uint32_t_be(offer->oaddr.addr);
-	addr48(link_info.mac_addr, hdr->chaddr);
+	addr48(dlink->link_info.mac_addr, hdr->chaddr);
 	hdr->opt_magic = host2uint32_t_be(dhcp_opt_magic);
 
@@ -203,8 +207,8 @@
 	opt[i++] = opt_end;
 
-	return dhcp_send(msgbuf, sizeof(dhcp_hdr_t) + i);
-}
-
-static int dhcp_recv_reply(void *msg, size_t size, dhcp_offer_t *offer)
+	return dhcp_send(&dlink->dt, msgbuf, sizeof(dhcp_hdr_t) + i);
+}
+
+static int dhcp_parse_reply(void *msg, size_t size, dhcp_offer_t *offer)
 {
 	dhcp_hdr_t *hdr = (dhcp_hdr_t *)msg;
@@ -222,36 +226,32 @@
 	size_t i;
 
-	printf("Receive reply\n");
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Receive reply");
 	memset(offer, 0, sizeof(*offer));
 
-	yiaddr.family = AF_INET;
-	yiaddr.addr = uint32_t_be2host(hdr->yiaddr);
+	inet_addr_set(uint32_t_be2host(hdr->yiaddr), &yiaddr);
 	rc = inet_addr_format(&yiaddr, &saddr);
 	if (rc != EOK)
 		return rc;
 
-	printf("Your IP address: %s\n", saddr);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Your IP address: %s", saddr);
 	free(saddr);
 
-	siaddr.family = AF_INET;
-	siaddr.addr = uint32_t_be2host(hdr->siaddr);
+	inet_addr_set(uint32_t_be2host(hdr->siaddr), &siaddr);
 	rc = inet_addr_format(&siaddr, &saddr);
 	if (rc != EOK)
 		return rc;
 
-	printf("Next server IP address: %s\n", saddr);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Next server IP address: %s", saddr);
 	free(saddr);
 
-	giaddr.family = AF_INET;
-	giaddr.addr = uint32_t_be2host(hdr->giaddr);
+	inet_addr_set(uint32_t_be2host(hdr->giaddr), &giaddr);
 	rc = inet_addr_format(&giaddr, &saddr);
 	if (rc != EOK)
 		return rc;
 
-	printf("Relay agent IP address: %s\n", saddr);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Relay agent IP address: %s", saddr);
 	free(saddr);
 
-	offer->oaddr.family = AF_INET;
-	offer->oaddr.addr = yiaddr.addr;
+	inet_naddr_set(yiaddr.addr, 0, &offer->oaddr);
 
 	msgb = (uint8_t *)msg;
@@ -293,6 +293,6 @@
 			if (opt_len != 4)
 				return EINVAL;
-			offer->srv_addr.family = AF_INET;
-			offer->srv_addr.addr = dhcp_uint32_decode(&msgb[i]);
+			inet_addr_set(dhcp_uint32_decode(&msgb[i]),
+			    &offer->srv_addr);
 			have_server_id = true;
 			break;
@@ -300,12 +300,12 @@
 			if (opt_len != 4)
 				return EINVAL;
-			offer->router.family = AF_INET;
-			offer->router.addr = dhcp_uint32_decode(&msgb[i]);
+			inet_addr_set(dhcp_uint32_decode(&msgb[i]),
+			    &offer->router);
 			break;
 		case opt_dns_server:
 			if (opt_len != 4)
 				return EINVAL;
-			offer->dns_server.family = AF_INET;
-			offer->dns_server.addr = dhcp_uint32_decode(&msgb[i]);
+			inet_addr_set(dhcp_uint32_decode(&msgb[i]),
+			    &offer->dns_server);
 			break;
 		case opt_end:
@@ -320,10 +320,10 @@
 
 	if (!have_server_id) {
-		printf("Missing server ID option.\n");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Missing server ID option.");
 		return rc;
 	}
 
 	if (!have_subnet_mask) {
-		printf("Missing subnet mask option.\n");
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Missing subnet mask option.");
 		return rc;
 	}
@@ -333,5 +333,5 @@
 		return rc;
 
-	printf("Offered network address: %s\n", saddr);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Offered network address: %s", saddr);
 	free(saddr);
 
@@ -341,5 +341,5 @@
 			return rc;
 
-		printf("Router address: %s\n", saddr);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Router address: %s", saddr);
 		free(saddr);
 	}
@@ -350,5 +350,5 @@
 			return rc;
 
-		printf("DNS server: %s\n", saddr);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "DNS server: %s", saddr);
 		free(saddr);
 	}
@@ -367,17 +367,16 @@
 	    &addr_id);
 	if (rc != EOK) {
-		printf("Error creating IP address %s (%d)\n", "dhcp4a", rc);
+		log_msg(LOG_DEFAULT, LVL_ERROR,
+		    "Error creating IP address %s (%d)", "dhcp4a", rc);
 		return rc;
 	}
 
 	if (offer->router.addr != 0) {
-		defr.family = AF_INET;
-		defr.addr = 0;
-		defr.prefix = 0;
+		inet_naddr_set(0, 0, &defr);
 
 		rc = inetcfg_sroute_create("dhcpdef", &defr, &offer->router, &sroute_id);
 		if (rc != EOK) {
-			printf("Error creating default route %s (%d).\n", "dhcpdef",
-			    rc);
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Error creating "
+			    "default route %s (%d).", "dhcpdef", rc);
 			return rc;
 		}
@@ -387,6 +386,6 @@
 		rc = dnsr_set_srvaddr(&offer->dns_server);
 		if (rc != EOK) {
-			printf("%s: Error setting nameserver address (%d))\n",
-			    NAME, rc);
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Error setting "
+			    "nameserver address (%d))", rc);
 			return rc;
 		}
@@ -396,93 +395,230 @@
 }
 
-int main(int argc, char *argv[])
-{
-	int fd;
-	struct sockaddr_in laddr;
-	void *msg;
-	service_id_t iplink;
-	size_t msg_size;
+void dhcpsrv_links_init(void)
+{
+	list_initialize(&dhcp_links);
+}
+
+static dhcp_link_t *dhcpsrv_link_find(service_id_t link_id)
+{
+	list_foreach(dhcp_links, links, dhcp_link_t, dlink) {
+		if (dlink->link_id == link_id)
+			return dlink;
+	}
+
+	return NULL;
+}
+
+static void dhcp_link_set_failed(dhcp_link_t *dlink)
+{
+	log_msg(LOG_DEFAULT, LVL_NOTE, "Giving up on link %s",
+	    dlink->link_info.name);
+	dlink->state = ds_fail;
+}
+
+int dhcpsrv_link_add(service_id_t link_id)
+{
+	dhcp_link_t *dlink;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcpsrv_link_add(%zu)", link_id);
+
+	if (dhcpsrv_link_find(link_id) != NULL) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Link %zu already added",
+		    link_id);
+		return EEXIST;
+	}
+
+	dlink = calloc(1, sizeof(dhcp_link_t));
+	if (dlink == NULL)
+		return ENOMEM;
+
+	dlink->link_id = link_id;
+	dlink->timeout = fibril_timer_create();
+	if (dlink->timeout == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	/* Get link hardware address */
+	rc = inetcfg_link_get(link_id, &dlink->link_info);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting properties "
+		    "for link %zu.", link_id);
+		rc = EIO;
+		goto error;
+	}
+
+	rc = dhcp_transport_init(&dlink->dt, link_id, dhcpsrv_recv, dlink);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error initializing DHCP "
+		    "transport for link %s.", dlink->link_info.name);
+		rc = EIO;
+		goto error;
+	}
+
+	dlink->state = ds_selecting;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPDISCOVER");
+	rc = dhcp_send_discover(dlink);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error sending DHCPDISCOVER.");
+		dhcp_link_set_failed(dlink);
+		rc = EIO;
+		goto error;
+	}
+
+	dlink->retries_left = dhcp_discover_retries;
+	fibril_timer_set(dlink->timeout, dhcp_discover_timeout_val,
+	    dhcpsrv_discover_timeout, dlink);
+
+	list_append(&dlink->links, &dhcp_links);
+
+	return EOK;
+error:
+	if (dlink != NULL && dlink->timeout != NULL)
+		fibril_timer_destroy(dlink->timeout);
+	free(dlink);
+	return rc;
+}
+
+int dhcpsrv_link_remove(service_id_t link_id)
+{
+	return ENOTSUP;
+}
+
+static void dhcpsrv_recv_offer(dhcp_link_t *dlink, dhcp_offer_t *offer)
+{
+	int rc;
+
+	if (dlink->state != ds_selecting) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Received offer in state "
+		    " %d, ignoring.", (int)dlink->state);
+		return;
+	}
+
+	fibril_timer_clear(dlink->timeout);
+	dlink->offer = *offer;
+	dlink->state = ds_requesting;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPREQUEST");
+	rc = dhcp_send_request(dlink, offer);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending request.");
+		return;
+	}
+
+	dlink->retries_left = dhcp_request_retries;
+	fibril_timer_set(dlink->timeout, dhcp_request_timeout_val,
+	    dhcpsrv_request_timeout, dlink);
+}
+
+static void dhcpsrv_recv_ack(dhcp_link_t *dlink, dhcp_offer_t *offer)
+{
+	int rc;
+
+	if (dlink->state != ds_requesting) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Received ack in state "
+		    " %d, ignoring.", (int)dlink->state);
+		return;
+	}
+
+	fibril_timer_clear(dlink->timeout);
+	dlink->offer = *offer;
+	dlink->state = ds_bound;
+
+	rc = dhcp_cfg_create(dlink->link_id, offer);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Error creating configuration.");
+		return;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "%s: Successfully configured.",
+	    dlink->link_info.name);
+}
+
+static void dhcpsrv_recv(void *arg, void *msg, size_t size)
+{
+	dhcp_link_t *dlink = (dhcp_link_t *)arg;
 	dhcp_offer_t offer;
 	int rc;
 
-	if (argc < 2) {
-		printf("syntax: %s <ip-link>\n", NAME);
-		return 1;
-	}
-
-	rc = inetcfg_init();
-	if (rc != EOK) {
-		printf("Error contacting inet configuration service.\n");
-		return 1;
-	}
-
-	rc = loc_service_get_id(argv[1], &iplink, 0);
-	if (rc != EOK) {
-		printf("Error resolving service '%s'.\n", argv[1]);
-		return 1;
-	}
-
-	/* Get link hardware address */
-	rc = inetcfg_link_get(iplink, &link_info);
-	if (rc != EOK) {
-		printf("Error getting properties for link '%s'.\n", argv[1]);
-		return 1;
-	}
-
-	laddr.sin_family = AF_INET;
-	laddr.sin_port = htons(dhcp_client_port);
-	laddr.sin_addr.s_addr = INADDR_ANY;
-
-	fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
-	if (fd < 0)
-		return 1;
-
-	printf("Bind socket.\n");
-	rc = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr));
-	if (rc != EOK)
-		return 1;
-
-	printf("Set socket options\n");
-	rc = setsockopt(fd, SOL_SOCKET, SO_IPLINK, &iplink, sizeof(iplink));
-	if (rc != EOK)
-		return 1;
-
-	transport_fd = fd;
-
-	printf("Send DHCPDISCOVER\n");
-	rc = dhcp_send_discover();
-	if (rc != EOK)
-		return 1;
-
-	rc = dhcp_recv_msg(&msg, &msg_size);
-	if (rc != EOK)
-		return 1;
-
-	printf("Received %zu bytes\n", msg_size);
-
-	rc = dhcp_recv_reply(msg, msg_size, &offer);
-	if (rc != EOK)
-		return 1;
-
-	rc = dhcp_send_request(&offer);
-	if (rc != EOK)
-		return 1;
-
-	rc = dhcp_recv_msg(&msg, &msg_size);
-	if (rc != EOK)
-		return 1;
-
-	printf("Received %zu bytes\n", msg_size);
-
-	rc = dhcp_recv_reply(msg, msg_size, &offer);
-	if (rc != EOK)
-		return 1;
-
-	rc = dhcp_cfg_create(iplink, &offer);
-	if (rc != EOK)
-		return 1;
-
-	closesocket(fd);
-	return 0;
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: dhcpsrv_recv() %zu bytes",
+	    dlink->link_info.name, size);
+
+	rc = dhcp_parse_reply(msg, size, &offer);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Error parsing reply");
+		return;
+	}
+
+	switch (offer.msg_type) {
+	case msg_dhcpoffer:
+		dhcpsrv_recv_offer(dlink, &offer);
+		break;
+	case msg_dhcpack:
+		dhcpsrv_recv_ack(dlink, &offer);
+		break;
+	default:
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Received unexpected "
+		    "message type. %d", (int)offer.msg_type);
+		break;
+	}
+}
+
+static void dhcpsrv_discover_timeout(void *arg)
+{
+	dhcp_link_t *dlink = (dhcp_link_t *)arg;
+	int rc;
+
+	assert(dlink->state == ds_selecting);
+	log_msg(LOG_DEFAULT, LVL_NOTE, "%s: dcpsrv_discover_timeout",
+	    dlink->link_info.name);
+
+	if (dlink->retries_left == 0) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Retries exhausted");
+		dhcp_link_set_failed(dlink);
+		return;
+	}
+	--dlink->retries_left;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPDISCOVER");
+	rc = dhcp_send_discover(dlink);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error sending DHCPDISCOVER");
+		dhcp_link_set_failed(dlink);
+		return;
+	}
+
+	fibril_timer_set(dlink->timeout, dhcp_discover_timeout_val,
+	    dhcpsrv_discover_timeout, dlink);
+}
+
+static void dhcpsrv_request_timeout(void *arg)
+{
+	dhcp_link_t *dlink = (dhcp_link_t *)arg;
+	int rc;
+
+	assert(dlink->state == ds_requesting);
+	log_msg(LOG_DEFAULT, LVL_NOTE, "%s: dcpsrv_request_timeout",
+	    dlink->link_info.name);
+
+	if (dlink->retries_left == 0) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Retries exhausted");
+		dhcp_link_set_failed(dlink);
+		return;
+	}
+	--dlink->retries_left;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPREQUEST");
+	rc = dhcp_send_request(dlink, &dlink->offer);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending request.");
+		dhcp_link_set_failed(dlink);
+		return;
+	}
+
+	fibril_timer_set(dlink->timeout, dhcp_request_timeout_val,
+	    dhcpsrv_request_timeout, dlink);
 }
 
Index: uspace/srv/net/dhcp/dhcp.h
===================================================================
--- uspace/srv/net/dhcp/dhcp.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/srv/net/dhcp/dhcp.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013 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 dhcp
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#ifndef DHCP_H
+#define DHCP_H
+
+#include <ipc/loc.h>
+
+extern void dhcpsrv_links_init(void);
+extern int dhcpsrv_link_add(service_id_t);
+extern int dhcpsrv_link_remove(service_id_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/dhcp/main.c
===================================================================
--- uspace/srv/net/dhcp/main.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/srv/net/dhcp/main.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2013 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 dhcp
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <io/log.h>
+#include <inet/inetcfg.h>
+#include <ipc/dhcp.h>
+#include <ipc/services.h>
+#include <loc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <task.h>
+
+#include "dhcp.h"
+
+#define NAME  "dhcp"
+
+static void dhcp_client_conn(ipc_callid_t, ipc_call_t *, void *);
+
+static int dhcp_init(void)
+{
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcp_init()");
+
+	dhcpsrv_links_init();
+
+	rc = inetcfg_init();
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error contacting inet configuration service.\n");
+		return EIO;
+	}
+
+	async_set_client_connection(dhcp_client_conn);
+
+	rc = loc_server_register(NAME);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server (%d).", rc);
+		return EEXIST;
+	}
+
+	service_id_t sid;
+	rc = loc_service_register(SERVICE_NAME_DHCP, &sid);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
+		return EEXIST;
+	}
+
+	return EOK;
+}
+
+static void dhcp_link_add_srv(ipc_callid_t callid, ipc_call_t *call)
+{
+	sysarg_t link_id;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcp_link_add_srv()");
+
+	link_id = IPC_GET_ARG1(*call);
+
+	rc = dhcpsrv_link_add(link_id);
+	async_answer_0(callid, rc);
+}
+
+static void dhcp_link_remove_srv(ipc_callid_t callid, ipc_call_t *call)
+{
+	sysarg_t link_id;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcp_link_remove_srv()");
+
+	link_id = IPC_GET_ARG1(*call);
+
+	rc = dhcpsrv_link_remove(link_id);
+	async_answer_0(callid, rc);
+}
+
+static void dhcp_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcp_client_conn()");
+
+	/* Accept the connection */
+	async_answer_0(iid, EOK);
+
+	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 DHCP_LINK_ADD:
+			dhcp_link_add_srv(callid, &call);
+			break;
+		case DHCP_LINK_REMOVE:
+			dhcp_link_remove_srv(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, EINVAL);
+		}
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	int rc;
+
+	printf("%s: DHCP Service\n", NAME);
+
+	if (log_init(NAME) != EOK) {
+		printf(NAME ": Failed to initialize logging.\n");
+		return 1;
+	}
+
+	rc = dhcp_init();
+	if (rc != EOK)
+		return 1;
+
+	printf(NAME ": Accepting connections.\n");
+	task_retval(0);
+	async_manager();
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/srv/net/dhcp/transport.c
===================================================================
--- uspace/srv/net/dhcp/transport.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/srv/net/dhcp/transport.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2013 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 dhcp
+ * @{
+ */
+/**
+ * @file
+ * @brief DHCP client
+ */
+
+#include <bitops.h>
+#include <inet/addr.h>
+#include <inet/dnsr.h>
+#include <inet/inetcfg.h>
+#include <io/log.h>
+#include <loc.h>
+#include <net/in.h>
+#include <net/inet.h>
+#include <net/socket.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dhcp.h"
+#include "dhcp_std.h"
+#include "transport.h"
+
+#define MAX_MSG_SIZE 1024
+static uint8_t msgbuf[MAX_MSG_SIZE];
+
+typedef struct {
+	/** Message type */
+	enum dhcp_msg_type msg_type;
+	/** Offered address */
+	inet_naddr_t oaddr;
+	/** Server address */
+	inet_addr_t srv_addr;
+	/** Router address */
+	inet_addr_t router;
+	/** DNS server */
+	inet_addr_t dns_server;
+} dhcp_offer_t;
+
+static int dhcp_recv_fibril(void *);
+
+int dhcp_send(dhcp_transport_t *dt, void *msg, size_t size)
+{
+	struct sockaddr_in addr;
+	int rc;
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(dhcp_server_port);
+	addr.sin_addr.s_addr = htonl(addr32_broadcast_all_hosts);
+
+	rc = sendto(dt->fd, msg, size, 0,
+	    (struct sockaddr *)&addr, sizeof(addr));
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Sending failed");
+		return rc;
+	}
+
+	return EOK;
+}
+
+static int dhcp_recv_msg(dhcp_transport_t *dt, void **rmsg, size_t *rsize)
+{
+	struct sockaddr_in src_addr;
+	socklen_t src_addr_size;
+	size_t recv_size;
+	int rc;
+
+	src_addr_size = sizeof(src_addr);
+	rc = recvfrom(dt->fd, msgbuf, MAX_MSG_SIZE, 0,
+	    (struct sockaddr *)&src_addr, &src_addr_size);
+	if (rc < 0) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "recvfrom failed (%d)", rc);
+		return rc;
+	}
+
+	recv_size = (size_t)rc;
+	*rmsg = msgbuf;
+	*rsize = recv_size;
+
+	return EOK;
+}
+
+int dhcp_transport_init(dhcp_transport_t *dt, service_id_t link_id,
+    dhcp_recv_cb_t recv_cb, void *arg)
+{
+	int fd;
+	struct sockaddr_in laddr;
+	int fid;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcptransport_init()");
+
+	laddr.sin_family = AF_INET;
+	laddr.sin_port = htons(dhcp_client_port);
+	laddr.sin_addr.s_addr = INADDR_ANY;
+
+	fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (fd < 0) {
+		rc = EIO;
+		goto error;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Bind socket.");
+	rc = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr));
+	if (rc != EOK) {
+		rc = EIO;
+		goto error;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Set socket options");
+	rc = setsockopt(fd, SOL_SOCKET, SO_IPLINK, &link_id, sizeof(link_id));
+	if (rc != EOK) {
+		rc = EIO;
+		goto error;
+	}
+
+	dt->fd = fd;
+	dt->recv_cb = recv_cb;
+	dt->cb_arg = arg;
+
+	fid = fibril_create(dhcp_recv_fibril, dt);
+	if (fid == 0) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	dt->recv_fid = fid;
+	fibril_add_ready(fid);
+
+	return EOK;
+error:
+	closesocket(fd);
+	return rc;
+}
+
+void dhcp_transport_fini(dhcp_transport_t *dt)
+{
+	closesocket(dt->fd);
+}
+
+static int dhcp_recv_fibril(void *arg)
+{
+	dhcp_transport_t *dt = (dhcp_transport_t *)arg;
+	void *msg;
+	size_t size;
+	int rc;
+
+	while (true) {
+		rc = dhcp_recv_msg(dt, &msg, &size);
+		if (rc != EOK)
+			break;
+
+		dt->recv_cb(dt->cb_arg, msg, size);
+	}
+
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/srv/net/dhcp/transport.h
===================================================================
--- uspace/srv/net/dhcp/transport.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/srv/net/dhcp/transport.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013 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 dhcp
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#ifndef TRANSPORT_H
+#define TRANSPORT_H
+
+#include <ipc/loc.h>
+#include <sys/types.h>
+
+struct dhcp_transport;
+typedef struct dhcp_transport dhcp_transport_t;
+
+typedef void (*dhcp_recv_cb_t)(void *, void *, size_t);
+
+struct dhcp_transport {
+	/** Transport socket */
+	int fd;
+	/** Receive callback */
+	dhcp_recv_cb_t recv_cb;
+	/** Callback argument */
+	void *cb_arg;
+	/** Receive fibril ID */
+	int recv_fid;
+};
+
+extern int dhcp_transport_init(dhcp_transport_t *, service_id_t,
+    dhcp_recv_cb_t, void *);
+extern void dhcp_transport_fini(dhcp_transport_t *);
+extern int dhcp_send(dhcp_transport_t *dt, void *msg, size_t size);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/dnsrsrv/dnsrsrv.c
===================================================================
--- uspace/srv/net/dnsrsrv/dnsrsrv.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/dnsrsrv/dnsrsrv.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -89,5 +89,5 @@
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_get_srvaddr_srv()");
 	
-	uint16_t af = IPC_GET_ARG1(*icall);
+	ip_ver_t ver = IPC_GET_ARG1(*icall);
 	
 	char *name;
@@ -100,5 +100,5 @@
 	
 	dns_host_info_t *hinfo;
-	rc = dns_name2host(name, &hinfo, af);
+	rc = dns_name2host(name, &hinfo, ver);
 	if (rc != EOK) {
 		async_answer_0(iid, rc);
Index: uspace/srv/net/dnsrsrv/query.c
===================================================================
--- uspace/srv/net/dnsrsrv/query.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/dnsrsrv/query.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -39,5 +39,4 @@
 #include <stdlib.h>
 #include <str.h>
-#include <net/socket_codes.h>
 #include "dns_msg.h"
 #include "dns_std.h"
@@ -190,5 +189,5 @@
 }
 
-int dns_name2host(const char *name, dns_host_info_t **rinfo, uint16_t af)
+int dns_name2host(const char *name, dns_host_info_t **rinfo, ip_ver_t ver)
 {
 	dns_host_info_t *info = calloc(1, sizeof(dns_host_info_t));
@@ -198,6 +197,6 @@
 	int rc;
 	
-	switch (af) {
-	case AF_NONE:
+	switch (ver) {
+	case ip_any:
 		rc = dns_name_query(name, DTYPE_AAAA, info);
 		
@@ -206,8 +205,8 @@
 		
 		break;
-	case AF_INET:
+	case ip_v4:
 		rc = dns_name_query(name, DTYPE_A, info);
 		break;
-	case AF_INET6:
+	case ip_v6:
 		rc = dns_name_query(name, DTYPE_AAAA, info);
 		break;
Index: uspace/srv/net/dnsrsrv/query.h
===================================================================
--- uspace/srv/net/dnsrsrv/query.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/dnsrsrv/query.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -37,7 +37,8 @@
 #define QUERY_H
 
+#include <inet/addr.h>
 #include "dns_type.h"
 
-extern int dns_name2host(const char *, dns_host_info_t **, uint16_t);
+extern int dns_name2host(const char *, dns_host_info_t **, ip_ver_t);
 extern void dns_hostinfo_destroy(dns_host_info_t *);
 
Index: uspace/srv/net/dnsrsrv/transport.c
===================================================================
--- uspace/srv/net/dnsrsrv/transport.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/dnsrsrv/transport.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -182,4 +182,6 @@
 {
 	trans_req_t *treq = NULL;
+	struct sockaddr *saddr = NULL;
+	socklen_t saddrlen;
 	
 	void *req_data;
@@ -189,25 +191,8 @@
 		goto error;
 	
-	struct sockaddr_in addr;
-	struct sockaddr_in6 addr6;
-	uint16_t af =
-	    inet_addr_sockaddr_in(&dns_server_addr, &addr, &addr6);
-	
-	struct sockaddr *address;
-	socklen_t addrlen;
-	
-	switch (af) {
-	case AF_INET:
-		addr.sin_port = htons(DNS_SERVER_PORT);
-		address = (struct sockaddr *) &addr;
-		addrlen = sizeof(addr);
-		break;
-	case AF_INET6:
-		addr6.sin6_port = htons(DNS_SERVER_PORT);
-		address = (struct sockaddr *) &addr6;
-		addrlen = sizeof(addr6);
-		break;
-	default:
-		rc = EAFNOSUPPORT;
+	rc = inet_addr_sockaddr(&dns_server_addr, DNS_SERVER_PORT,
+	    &saddr, &saddrlen);
+	if (rc != EOK) {
+		assert(rc == ENOMEM);
 		goto error;
 	}
@@ -217,5 +202,5 @@
 	while (ntry < REQ_RETRY_MAX) {
 		rc = sendto(transport_fd, req_data, req_size, 0,
-		    (struct sockaddr *) address, addrlen);
+		    saddr, saddrlen);
 		if (rc != EOK)
 			goto error;
@@ -256,4 +241,5 @@
 	treq_destroy(treq);
 	free(req_data);
+	free(saddr);
 	return EOK;
 	
@@ -263,4 +249,5 @@
 	
 	free(req_data);
+	free(saddr);
 	return rc;
 }
Index: uspace/srv/net/ethip/arp.c
===================================================================
--- uspace/srv/net/ethip/arp.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/ethip/arp.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -40,5 +40,4 @@
 #include <inet/addr.h>
 #include <stdlib.h>
-#include <net/socket_codes.h>
 #include "arp.h"
 #include "atrans.h"
@@ -73,6 +72,6 @@
 	
 	addr32_t laddr_v4;
-	uint16_t laddr_af = inet_addr_get(&laddr->addr, &laddr_v4, NULL);
-	if (laddr_af != AF_INET)
+	ip_ver_t laddr_ver = inet_addr_get(&laddr->addr, &laddr_v4, NULL);
+	if (laddr_ver != ip_v4)
 		return;
 	
Index: uspace/srv/net/ethip/ethip.c
===================================================================
--- uspace/srv/net/ethip/ethip.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/ethip/ethip.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -44,5 +44,4 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <net/socket_codes.h>
 #include "arp.h"
 #include "ethip.h"
@@ -249,5 +248,5 @@
 		sdu.size = frame.size;
 		log_msg(LOG_DEFAULT, LVL_DEBUG, " - call iplink_ev_recv");
-		rc = iplink_ev_recv(&nic->iplink, &sdu, AF_INET);
+		rc = iplink_ev_recv(&nic->iplink, &sdu, ip_v4);
 		break;
 	case ETYPE_IPV6:
@@ -256,5 +255,5 @@
 		sdu.size = frame.size;
 		log_msg(LOG_DEFAULT, LVL_DEBUG, " - call iplink_ev_recv");
-		rc = iplink_ev_recv(&nic->iplink, &sdu, AF_INET6);
+		rc = iplink_ev_recv(&nic->iplink, &sdu, ip_v6);
 		break;
 	default:
Index: uspace/srv/net/ethip/ethip_nic.c
===================================================================
--- uspace/srv/net/ethip/ethip_nic.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/ethip/ethip_nic.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -45,5 +45,4 @@
 #include <device/nic.h>
 #include <stdlib.h>
-#include <net/socket_codes.h>
 #include <mem.h>
 #include "ethip.h"
@@ -354,6 +353,6 @@
 	
 	list_foreach(nic->addr_list, link, ethip_link_addr_t, laddr) {
-		uint16_t af = inet_addr_get(&laddr->addr, NULL, NULL);
-		if (af == AF_INET6)
+		ip_ver_t ver = inet_addr_get(&laddr->addr, NULL, NULL);
+		if (ver == ip_v6)
 			count++;
 	}
@@ -373,6 +372,6 @@
 	list_foreach(nic->addr_list, link, ethip_link_addr_t, laddr) {
 		addr128_t v6;
-		uint16_t af = inet_addr_get(&laddr->addr, NULL, &v6);
-		if (af != AF_INET6)
+		ip_ver_t ver = inet_addr_get(&laddr->addr, NULL, &v6);
+		if (ver != ip_v6)
 			continue;
 		
Index: uspace/srv/net/inetsrv/Makefile
===================================================================
--- uspace/srv/net/inetsrv/Makefile	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -38,5 +38,4 @@
 	inetcfg.c \
 	inetping.c \
-	inetping6.c \
 	ndp.c \
 	ntrans.c \
Index: uspace/srv/net/inetsrv/addrobj.c
===================================================================
--- uspace/srv/net/inetsrv/addrobj.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/addrobj.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -42,5 +42,4 @@
 #include <stdlib.h>
 #include <str.h>
-#include <net/socket_codes.h>
 #include "addrobj.h"
 #include "inetsrv.h"
@@ -218,24 +217,24 @@
 	inet_addr_t lsrc_addr;
 	inet_naddr_addr(&addr->naddr, &lsrc_addr);
-	
+
 	addr32_t lsrc_v4;
 	addr128_t lsrc_v6;
-	uint16_t lsrc_af = inet_addr_get(&lsrc_addr, &lsrc_v4, &lsrc_v6);
-	
+	ip_ver_t lsrc_ver = inet_addr_get(&lsrc_addr, &lsrc_v4, &lsrc_v6);
+
 	addr32_t ldest_v4;
 	addr128_t ldest_v6;
-	uint16_t ldest_af = inet_addr_get(ldest, &ldest_v4, &ldest_v6);
-	
-	if (lsrc_af != ldest_af)
+	ip_ver_t ldest_ver = inet_addr_get(ldest, &ldest_v4, &ldest_v6);
+
+	if (lsrc_ver != ldest_ver)
 		return EINVAL;
-	
+
 	int rc;
 	addr48_t ldest_mac;
-	
-	switch (ldest_af) {
-	case AF_INET:
+
+	switch (ldest_ver) {
+	case ip_v4:
 		return inet_link_send_dgram(addr->ilink, lsrc_v4, ldest_v4,
 		    dgram, proto, ttl, df);
-	case AF_INET6:
+	case ip_v6:
 		/*
 		 * Translate local destination IPv6 address.
@@ -244,9 +243,12 @@
 		if (rc != EOK)
 			return rc;
-		
+
 		return inet_link_send_dgram6(addr->ilink, ldest_mac, dgram,
 		    proto, ttl, df);
-	}
-	
+	default:
+		assert(false);
+		break;
+	}
+
 	return ENOTSUP;
 }
Index: uspace/srv/net/inetsrv/icmp.c
===================================================================
--- uspace/srv/net/inetsrv/icmp.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/icmp.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -40,5 +40,5 @@
 #include <mem.h>
 #include <stdlib.h>
-#include <net/socket_codes.h>
+#include <types/inetping.h>
 #include "icmp.h"
 #include "icmp_std.h"
@@ -122,24 +122,18 @@
 {
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "icmp_recv_echo_reply()");
-	
+
 	if (dgram->size < sizeof(icmp_echo_t))
 		return EINVAL;
-	
+
 	icmp_echo_t *reply = (icmp_echo_t *) dgram->data;
-	
+
 	inetping_sdu_t sdu;
-	
-	uint16_t family = inet_addr_get(&dgram->src, &sdu.src, NULL);
-	if (family != AF_INET)
-		return EINVAL;
-	
-	family = inet_addr_get(&dgram->dest, &sdu.dest, NULL);
-	if (family != AF_INET)
-		return EINVAL;
-	
+
+	sdu.src = dgram->src;
+	sdu.dest = dgram->dest;
 	sdu.seq_no = uint16_t_be2host(reply->seq_no);
 	sdu.data = reply + sizeof(icmp_echo_t);
 	sdu.size = dgram->size - sizeof(icmp_echo_t);
-	
+
 	uint16_t ident = uint16_t_be2host(reply->ident);
 
@@ -153,7 +147,7 @@
 	if (rdata == NULL)
 		return ENOMEM;
-	
+
 	icmp_echo_t *request = (icmp_echo_t *) rdata;
-	
+
 	request->type = ICMP_ECHO_REQUEST;
 	request->code = 0;
@@ -161,22 +155,21 @@
 	request->ident = host2uint16_t_be(ident);
 	request->seq_no = host2uint16_t_be(sdu->seq_no);
-	
+
 	memcpy(rdata + sizeof(icmp_echo_t), sdu->data, sdu->size);
-	
+
 	uint16_t checksum = inet_checksum_calc(INET_CHECKSUM_INIT, rdata, rsize);
 	request->checksum = host2uint16_t_be(checksum);
-	
+
 	inet_dgram_t dgram;
-	
-	inet_addr_set(sdu->src, &dgram.src);
-	inet_addr_set(sdu->dest, &dgram.dest);
-	
+
+	dgram.src = sdu->src;
+	dgram.dest = sdu->dest;
 	dgram.iplink = 0;
 	dgram.tos = ICMP_TOS;
 	dgram.data = rdata;
 	dgram.size = rsize;
-	
+
 	int rc = inet_route_packet(&dgram, IP_PROTO_ICMP, INET_TTL_MAX, 0);
-	
+
 	free(rdata);
 	return rc;
Index: uspace/srv/net/inetsrv/icmp.h
===================================================================
--- uspace/srv/net/inetsrv/icmp.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/icmp.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -38,4 +38,5 @@
 #define ICMP_H_
 
+#include <types/inetping.h>
 #include "inetsrv.h"
 
Index: uspace/srv/net/inetsrv/icmpv6.c
===================================================================
--- uspace/srv/net/inetsrv/icmpv6.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/icmpv6.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -40,9 +40,9 @@
 #include <mem.h>
 #include <stdlib.h>
-#include <net/socket_codes.h>
+#include <types/inetping.h>
 #include "icmpv6.h"
 #include "icmpv6_std.h"
 #include "inetsrv.h"
-#include "inetping6.h"
+#include "inetping.h"
 #include "pdu.h"
 
@@ -58,10 +58,10 @@
 	
 	addr128_t src_v6;
-	uint16_t src_af = inet_addr_get(&dgram->src, NULL, &src_v6);
+	ip_ver_t src_ver = inet_addr_get(&dgram->src, NULL, &src_v6);
 	
 	addr128_t dest_v6;
-	uint16_t dest_af = inet_addr_get(&dgram->dest, NULL, &dest_v6);
-	
-	if ((src_af != dest_af) || (src_af != AF_INET6))
+	ip_ver_t dest_ver = inet_addr_get(&dgram->dest, NULL, &dest_v6);
+	
+	if ((src_ver != dest_ver) || (src_ver != ip_v6))
 		return EINVAL;
 	
@@ -80,4 +80,5 @@
 	inet_get_srcaddr(&dgram->src, 0, &rdgram.src);
 	rdgram.dest = dgram->src;
+	rdgram.iplink = 0;
 	rdgram.tos = 0;
 	rdgram.data = reply;
@@ -115,11 +116,8 @@
 		return EINVAL;
 	
-	inetping6_sdu_t sdu;
-	
-	uint16_t src_af = inet_addr_get(&dgram->src, NULL, &sdu.src);
-	uint16_t dest_af = inet_addr_get(&dgram->dest, NULL, &sdu.dest);
-	
-	if ((src_af != dest_af) || (src_af != AF_INET6))
-		return EINVAL;
+	inetping_sdu_t sdu;
+	
+	sdu.src = dgram->src;
+	sdu.dest = dgram->dest;
 	
 	icmpv6_message_t *reply = (icmpv6_message_t *) dgram->data;
@@ -131,5 +129,5 @@
 	uint16_t ident = uint16_t_be2host(reply->un.echo.ident);
 	
-	return inetping6_recv(ident, &sdu);
+	return inetping_recv(ident, &sdu);
 }
 
@@ -159,5 +157,5 @@
 }
 
-int icmpv6_ping_send(uint16_t ident, inetping6_sdu_t *sdu)
+int icmpv6_ping_send(uint16_t ident, inetping_sdu_t *sdu)
 {
 	size_t rsize = sizeof(icmpv6_message_t) + sdu->size;
@@ -178,6 +176,7 @@
 	inet_dgram_t dgram;
 	
-	inet_addr_set6(sdu->src, &dgram.src);
-	inet_addr_set6(sdu->dest, &dgram.dest);
+	dgram.src = sdu->src;
+	dgram.dest = sdu->dest;
+	dgram.iplink = 0;
 	dgram.tos = 0;
 	dgram.data = rdata;
@@ -186,6 +185,9 @@
 	icmpv6_phdr_t phdr;
 	
-	host2addr128_t_be(sdu->src, phdr.src_addr);
-	host2addr128_t_be(sdu->dest, phdr.dest_addr);
+	assert(sdu->src.version == ip_v6);
+	assert(sdu->dest.version == ip_v6);
+	
+	host2addr128_t_be(sdu->src.addr6, phdr.src_addr);
+	host2addr128_t_be(sdu->dest.addr6, phdr.dest_addr);
 	phdr.length = host2uint32_t_be(dgram.size);
 	memset(phdr.zeroes, 0, 3);
Index: uspace/srv/net/inetsrv/icmpv6.h
===================================================================
--- uspace/srv/net/inetsrv/icmpv6.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/icmpv6.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -38,8 +38,9 @@
 #define ICMPV6_H_
 
+#include <types/inetping.h>
 #include "inetsrv.h"
 
 extern int icmpv6_recv(inet_dgram_t *);
-extern int icmpv6_ping_send(uint16_t, inetping6_sdu_t *);
+extern int icmpv6_ping_send(uint16_t, inetping_sdu_t *);
 
 #endif
Index: uspace/srv/net/inetsrv/inet_link.c
===================================================================
--- uspace/srv/net/inetsrv/inet_link.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/inet_link.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -43,5 +43,4 @@
 #include <stdlib.h>
 #include <str.h>
-#include <net/socket_codes.h>
 #include "addrobj.h"
 #include "inetsrv.h"
@@ -55,6 +54,6 @@
 static uint16_t ip_ident = 0;
 
-static int inet_link_open(service_id_t);
-static int inet_iplink_recv(iplink_t *, iplink_recv_sdu_t *, uint16_t);
+static int inet_iplink_recv(iplink_t *, iplink_recv_sdu_t *, ip_ver_t);
+static inet_link_t *inet_link_get_by_id_locked(sysarg_t);
 
 static iplink_ev_ops_t inet_iplink_ev_ops = {
@@ -62,6 +61,6 @@
 };
 
-static LIST_INITIALIZE(inet_link_list);
-static FIBRIL_MUTEX_INITIALIZE(inet_discovery_lock);
+static LIST_INITIALIZE(inet_links);
+static FIBRIL_MUTEX_INITIALIZE(inet_links_lock);
 
 static addr128_t link_local_node_ip =
@@ -81,5 +80,5 @@
 }
 
-static int inet_iplink_recv(iplink_t *iplink, iplink_recv_sdu_t *sdu, uint16_t af)
+static int inet_iplink_recv(iplink_t *iplink, iplink_recv_sdu_t *sdu, ip_ver_t ver)
 {
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv()");
@@ -88,13 +87,13 @@
 	inet_packet_t packet;
 	
-	switch (af) {
-	case AF_INET:
+	switch (ver) {
+	case ip_v4:
 		rc = inet_pdu_decode(sdu->data, sdu->size, &packet);
 		break;
-	case AF_INET6:
+	case ip_v6:
 		rc = inet_pdu_decode6(sdu->data, sdu->size, &packet);
 		break;
 	default:
-		log_msg(LOG_DEFAULT, LVL_DEBUG, "invalid address family");
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "invalid IP version");
 		return EINVAL;
 	}
@@ -113,51 +112,4 @@
 }
 
-static int inet_link_check_new(void)
-{
-	bool already_known;
-	category_id_t iplink_cat;
-	service_id_t *svcs;
-	size_t count, i;
-	int rc;
-
-	fibril_mutex_lock(&inet_discovery_lock);
-
-	rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'iplink'.");
-		fibril_mutex_unlock(&inet_discovery_lock);
-		return ENOENT;
-	}
-
-	rc = loc_category_get_svcs(iplink_cat, &svcs, &count);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of IP links.");
-		fibril_mutex_unlock(&inet_discovery_lock);
-		return EIO;
-	}
-
-	for (i = 0; i < count; i++) {
-		already_known = false;
-
-		list_foreach(inet_link_list, link_list, inet_link_t, ilink) {
-			if (ilink->svc_id == svcs[i]) {
-				already_known = true;
-				break;
-			}
-		}
-
-		if (!already_known) {
-			log_msg(LOG_DEFAULT, LVL_DEBUG, "Found IP link '%lu'",
-			    (unsigned long) svcs[i]);
-			rc = inet_link_open(svcs[i]);
-			if (rc != EOK)
-				log_msg(LOG_DEFAULT, LVL_ERROR, "Could not open IP link.");
-		}
-	}
-
-	fibril_mutex_unlock(&inet_discovery_lock);
-	return EOK;
-}
-
 static inet_link_t *inet_link_new(void)
 {
@@ -183,5 +135,5 @@
 }
 
-static int inet_link_open(service_id_t sid)
+int inet_link_open(service_id_t sid)
 {
 	inet_link_t *ilink;
@@ -231,5 +183,17 @@
 
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "Opened IP link '%s'", ilink->svc_name);
-	list_append(&ilink->link_list, &inet_link_list);
+
+	fibril_mutex_lock(&inet_links_lock);
+
+	if (inet_link_get_by_id_locked(sid) != NULL) {
+		fibril_mutex_unlock(&inet_links_lock);
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "Link %zu already open",
+		    sid);
+		rc = EEXIST;
+		goto error;
+	}
+
+	list_append(&ilink->link_list, &inet_links);
+	fibril_mutex_unlock(&inet_links_lock);
 
 	inet_addrobj_t *addr = NULL;
@@ -299,4 +263,5 @@
 	}
 	
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Configured link '%s'.", ilink->svc_name);
 	return EOK;
 	
@@ -307,23 +272,4 @@
 	inet_link_delete(ilink);
 	return rc;
-}
-
-static void inet_link_cat_change_cb(void)
-{
-	(void) inet_link_check_new();
-}
-
-int inet_link_discovery_start(void)
-{
-	int rc;
-
-	rc = loc_register_cat_change_cb(inet_link_cat_change_cb);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback for IP link "
-		    "discovery (%d).", rc);
-		return rc;
-	}
-
-	return inet_link_check_new();
 }
 
@@ -347,11 +293,11 @@
 {
 	addr32_t src_v4;
-	uint16_t src_af = inet_addr_get(&dgram->src, &src_v4, NULL);
-	if (src_af != AF_INET)
+	ip_ver_t src_ver = inet_addr_get(&dgram->src, &src_v4, NULL);
+	if (src_ver != ip_v4)
 		return EINVAL;
 	
 	addr32_t dest_v4;
-	uint16_t dest_af = inet_addr_get(&dgram->dest, &dest_v4, NULL);
-	if (dest_af != AF_INET)
+	ip_ver_t dest_ver = inet_addr_get(&dgram->dest, &dest_v4, NULL);
+	if (dest_ver != ip_v4)
 		return EINVAL;
 	
@@ -422,11 +368,11 @@
 {
 	addr128_t src_v6;
-	uint16_t src_af = inet_addr_get(&dgram->src, NULL, &src_v6);
-	if (src_af != AF_INET6)
+	ip_ver_t src_ver = inet_addr_get(&dgram->src, NULL, &src_v6);
+	if (src_ver != ip_v6)
 		return EINVAL;
 	
 	addr128_t dest_v6;
-	uint16_t dest_af = inet_addr_get(&dgram->dest, NULL, &dest_v6);
-	if (dest_af != AF_INET6)
+	ip_ver_t dest_ver = inet_addr_get(&dgram->dest, NULL, &dest_v6);
+	if (dest_ver != ip_v6)
 		return EINVAL;
 	
@@ -478,17 +424,25 @@
 }
 
+static inet_link_t *inet_link_get_by_id_locked(sysarg_t link_id)
+{
+	assert(fibril_mutex_is_locked(&inet_links_lock));
+
+	list_foreach(inet_links, link_list, inet_link_t, ilink) {
+		if (ilink->svc_id == link_id)
+			return ilink;
+	}
+
+	return NULL;
+}
+
 inet_link_t *inet_link_get_by_id(sysarg_t link_id)
 {
-	fibril_mutex_lock(&inet_discovery_lock);
-
-	list_foreach(inet_link_list, link_list, inet_link_t, ilink) {
-		if (ilink->svc_id == link_id) {
-			fibril_mutex_unlock(&inet_discovery_lock);
-			return ilink;
-		}
-	}
-
-	fibril_mutex_unlock(&inet_discovery_lock);
-	return NULL;
+	inet_link_t *ilink;
+
+	fibril_mutex_lock(&inet_links_lock);
+	ilink = inet_link_get_by_id_locked(link_id);
+	fibril_mutex_unlock(&inet_links_lock);
+
+	return ilink;
 }
 
@@ -499,20 +453,20 @@
 	size_t count, i;
 
-	fibril_mutex_lock(&inet_discovery_lock);
-	count = list_count(&inet_link_list);
+	fibril_mutex_lock(&inet_links_lock);
+	count = list_count(&inet_links);
 
 	id_list = calloc(count, sizeof(sysarg_t));
 	if (id_list == NULL) {
-		fibril_mutex_unlock(&inet_discovery_lock);
+		fibril_mutex_unlock(&inet_links_lock);
 		return ENOMEM;
 	}
 
 	i = 0;
-	list_foreach(inet_link_list, link_list, inet_link_t, ilink) {
+	list_foreach(inet_links, link_list, inet_link_t, ilink) {
 		id_list[i++] = ilink->svc_id;
 		log_msg(LOG_DEFAULT, LVL_NOTE, "add link to list");
 	}
 
-	fibril_mutex_unlock(&inet_discovery_lock);
+	fibril_mutex_unlock(&inet_links_lock);
 
 	log_msg(LOG_DEFAULT, LVL_NOTE, "return %zu links", count);
Index: uspace/srv/net/inetsrv/inet_link.h
===================================================================
--- uspace/srv/net/inetsrv/inet_link.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/inet_link.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -41,5 +41,5 @@
 #include "inetsrv.h"
 
-extern int inet_link_discovery_start(void);
+extern int inet_link_open(service_id_t);
 extern int inet_link_send_dgram(inet_link_t *, addr32_t,
     addr32_t, inet_dgram_t *, uint8_t, uint8_t, int);
Index: uspace/srv/net/inetsrv/inetcfg.c
===================================================================
--- uspace/srv/net/inetsrv/inetcfg.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/inetcfg.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2012 Jiri Svoboda
+ * Copyright (c) 2013 Jiri Svoboda
  * All rights reserved.
  *
@@ -160,4 +160,9 @@
 }
 
+static int inetcfg_link_add(sysarg_t link_id)
+{
+	return inet_link_open(link_id);
+}
+
 static int inetcfg_link_get(sysarg_t link_id, inet_link_info_t *linfo)
 {
@@ -180,4 +185,9 @@
 }
 
+static int inetcfg_link_remove(sysarg_t link_id)
+{
+	return ENOTSUP;
+}
+
 static int inetcfg_sroute_create(char *name, inet_naddr_t *dest,
     inet_addr_t *router, sysarg_t *sroute_id)
@@ -483,4 +493,17 @@
 }
 
+static void inetcfg_link_add_srv(ipc_callid_t callid, ipc_call_t *call)
+{
+	sysarg_t link_id;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_link_add_srv()");
+
+	link_id = IPC_GET_ARG1(*call);
+
+	rc = inetcfg_link_add(link_id);
+	async_answer_0(callid, rc);
+}
+
 static void inetcfg_link_get_srv(ipc_callid_t callid, ipc_call_t *call)
 {
@@ -536,4 +559,17 @@
 }
 
+static void inetcfg_link_remove_srv(ipc_callid_t callid, ipc_call_t *call)
+{
+	sysarg_t link_id;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetcfg_link_remove_srv()");
+
+	link_id = IPC_GET_ARG1(*call);
+
+	rc = inetcfg_link_remove(link_id);
+	async_answer_0(callid, rc);
+}
+
 static void inetcfg_sroute_create_srv(ipc_callid_t iid,
     ipc_call_t *icall)
@@ -714,4 +750,5 @@
 		sysarg_t method = IPC_GET_IMETHOD(call);
 
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "method %d", (int)method);
 		if (!method) {
 			/* The other side has hung up */
@@ -742,6 +779,12 @@
 			inetcfg_get_sroute_list_srv(callid, &call);
 			break;
+		case INETCFG_LINK_ADD:
+			inetcfg_link_add_srv(callid, &call);
+			break;
 		case INETCFG_LINK_GET:
 			inetcfg_link_get_srv(callid, &call);
+			break;
+		case INETCFG_LINK_REMOVE:
+			inetcfg_link_remove_srv(callid, &call);
 			break;
 		case INETCFG_SROUTE_CREATE:
Index: uspace/srv/net/inetsrv/inetping.c
===================================================================
--- uspace/srv/net/inetsrv/inetping.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/inetping.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -1,4 +1,5 @@
 /*
- * Copyright (c) 2012 Jiri Svoboda
+ * Copyright (c) 2013 Jiri Svoboda
+ * Copyright (c) 2013 Martin Decky
  * All rights reserved.
  *
@@ -43,6 +44,7 @@
 #include <stdlib.h>
 #include <sys/types.h>
-#include <net/socket_codes.h>
+#include <types/inetping.h>
 #include "icmp.h"
+#include "icmpv6.h"
 #include "icmp_std.h"
 #include "inetsrv.h"
@@ -57,23 +59,21 @@
 static int inetping_send(inetping_client_t *client, inetping_sdu_t *sdu)
 {
-	return icmp_ping_send(client->ident, sdu);
-}
-
-static int inetping_get_srcaddr(inetping_client_t *client, addr32_t remote,
-    addr32_t *local)
-{
-	inet_addr_t remote_addr;
-	inet_addr_set(remote, &remote_addr);
-	
-	inet_addr_t local_addr;
-	int rc = inet_get_srcaddr(&remote_addr, ICMP_TOS, &local_addr);
-	if (rc != EOK)
-		return rc;
-	
-	uint16_t family = inet_addr_get(&local_addr, local, NULL);
-	if (family != AF_INET)
+	if (sdu->src.version != sdu->dest.version)
 		return EINVAL;
-	
-	return EOK;
+
+	switch (sdu->src.version) {
+	case ip_v4:
+		return icmp_ping_send(client->ident, sdu);
+	case ip_v6:
+		return icmpv6_ping_send(client->ident, sdu);
+	default:
+		return EINVAL;
+	}
+}
+
+static int inetping_get_srcaddr(inetping_client_t *client,
+    inet_addr_t *remote, inet_addr_t *local)
+{
+	return inet_get_srcaddr(remote, ICMP_TOS, local);
 }
 
@@ -81,5 +81,5 @@
 {
 	fibril_mutex_lock(&client_list_lock);
-	
+
 	list_foreach(client_list, client_list, inetping_client_t, client) {
 		if (client->ident == ident) {
@@ -88,5 +88,5 @@
 		}
 	}
-	
+
 	fibril_mutex_unlock(&client_list_lock);
 	return NULL;
@@ -100,60 +100,155 @@
 		return ENOENT;
 	}
-	
+
 	async_exch_t *exch = async_exchange_begin(client->sess);
-	
+
 	ipc_call_t answer;
-	aid_t req = async_send_3(exch, INETPING_EV_RECV, (sysarg_t) sdu->src,
-	    (sysarg_t) sdu->dest, sdu->seq_no, &answer);
-	int rc = async_data_write_start(exch, sdu->data, sdu->size);
-	
-	async_exchange_end(exch);
-	
-	if (rc != EOK) {
+	aid_t req = async_send_1(exch, INETPING_EV_RECV, sdu->seq_no, &answer);
+
+	int rc = async_data_write_start(exch, &sdu->src, sizeof(sdu->src));
+	if (rc != EOK) {
+		async_exchange_end(exch);
 		async_forget(req);
 		return rc;
 	}
-	
+
+	rc = async_data_write_start(exch, &sdu->dest, sizeof(sdu->dest));
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		async_forget(req);
+		return rc;
+	}
+
+	rc = async_data_write_start(exch, sdu->data, sdu->size);
+
+	async_exchange_end(exch);
+
+	if (rc != EOK) {
+		async_forget(req);
+		return rc;
+	}
+
 	sysarg_t retval;
 	async_wait_for(req, &retval);
-	
+
 	return (int) retval;
 }
 
-static void inetping_send_srv(inetping_client_t *client, ipc_callid_t callid,
-    ipc_call_t *call)
-{
+static void inetping_send_srv(inetping_client_t *client, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_send_srv()");
+
 	inetping_sdu_t sdu;
 	int rc;
 
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_send_srv()");
+	sdu.seq_no = IPC_GET_ARG1(*icall);
+
+	ipc_callid_t callid;
+	size_t size;
+	if (!async_data_write_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+
+	if (size != sizeof(sdu.src)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	rc = async_data_write_finalize(callid, &sdu.src, size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	if (!async_data_write_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+
+	if (size != sizeof(sdu.dest)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	rc = async_data_write_finalize(callid, &sdu.dest, size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(iid, rc);
+		return;
+	}
 
 	rc = async_data_write_accept((void **) &sdu.data, false, 0, 0, 0,
 	    &sdu.size);
 	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		return;
-	}
-
-	sdu.src = IPC_GET_ARG1(*call);
-	sdu.dest = IPC_GET_ARG2(*call);
-	sdu.seq_no = IPC_GET_ARG3(*call);
+		async_answer_0(iid, rc);
+		return;
+	}
 
 	rc = inetping_send(client, &sdu);
 	free(sdu.data);
 
-	async_answer_0(callid, rc);
+	async_answer_0(iid, rc);
 }
 
 static void inetping_get_srcaddr_srv(inetping_client_t *client,
-    ipc_callid_t callid, ipc_call_t *call)
+    ipc_callid_t iid, ipc_call_t *icall)
 {
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_get_srcaddr_srv()");
-	
-	uint32_t remote = IPC_GET_ARG1(*call);
-	uint32_t local = 0;
-	
-	int rc = inetping_get_srcaddr(client, remote, &local);
-	async_answer_1(callid, rc, (sysarg_t) local);
+
+	ipc_callid_t callid;
+	size_t size;
+
+	inet_addr_t local;
+	inet_addr_t remote;
+
+	if (!async_data_write_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+
+	if (size != sizeof(remote)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	int rc = async_data_write_finalize(callid, &remote, size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	rc = inetping_get_srcaddr(client, &remote, &local);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+
+	if (size != sizeof(local)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	rc = async_data_read_finalize(callid, &local, size);
+	if (rc != EOK)
+		async_answer_0(callid, rc);
+
+	async_answer_0(iid, rc);
 }
 
@@ -163,13 +258,13 @@
 	if (sess == NULL)
 		return ENOMEM;
-	
+
 	client->sess = sess;
 	link_initialize(&client->client_list);
-	
+
 	fibril_mutex_lock(&client_list_lock);
 	client->ident = ++inetping_ident;
 	list_append(&client->client_list, &client_list);
 	fibril_mutex_unlock(&client_list_lock);
-	
+
 	return EOK;
 }
@@ -179,5 +274,5 @@
 	async_hangup(client->sess);
 	client->sess = NULL;
-	
+
 	fibril_mutex_lock(&client_list_lock);
 	list_remove(&client->client_list);
@@ -188,18 +283,18 @@
 {
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_conn()");
-	
+
 	/* Accept the connection */
 	async_answer_0(iid, EOK);
-	
+
 	inetping_client_t client;
 	int rc = inetping_client_init(&client);
 	if (rc != EOK)
 		return;
-	
+
 	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 */
@@ -207,5 +302,5 @@
 			break;
 		}
-		
+
 		switch (method) {
 		case INETPING_SEND:
@@ -219,5 +314,5 @@
 		}
 	}
-	
+
 	inetping_client_fini(&client);
 }
Index: uspace/srv/net/inetsrv/inetping.h
===================================================================
--- uspace/srv/net/inetsrv/inetping.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/inetping.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -38,4 +38,5 @@
 #define INETPING_H_
 
+#include <types/inetping.h>
 #include "inetsrv.h"
 
Index: uspace/srv/net/inetsrv/inetping6.c
===================================================================
--- uspace/srv/net/inetsrv/inetping6.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,318 +1,0 @@
-/*
- * Copyright (c) 2013 Martin Decky
- * 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
- */
-
-#include <async.h>
-#include <errno.h>
-#include <fibril_synch.h>
-#include <io/log.h>
-#include <ipc/inet.h>
-#include <loc.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <net/socket_codes.h>
-#include "icmpv6.h"
-#include "icmpv6_std.h"
-#include "inetsrv.h"
-#include "inetping6.h"
-
-static FIBRIL_MUTEX_INITIALIZE(client_list_lock);
-static LIST_INITIALIZE(client_list);
-
-/** Last used session identifier. Protected by @c client_list_lock */
-static uint16_t inetping6_ident = 0;
-
-static int inetping6_send(inetping6_client_t *client, inetping6_sdu_t *sdu)
-{
-	return icmpv6_ping_send(client->ident, sdu);
-}
-
-static int inetping6_get_srcaddr(inetping6_client_t *client, addr128_t remote,
-    addr128_t *local)
-{
-	inet_addr_t remote_addr;
-	inet_addr_set6(remote, &remote_addr);
-	
-	inet_addr_t local_addr;
-	int rc = inet_get_srcaddr(&remote_addr, ICMPV6_TOS, &local_addr);
-	if (rc != EOK)
-		return rc;
-	
-	uint16_t family = inet_addr_get(&local_addr, NULL, local);
-	if (family != AF_INET6)
-		return EINVAL;
-	
-	return EOK;
-}
-
-static inetping6_client_t *inetping6_client_find(uint16_t ident)
-{
-	fibril_mutex_lock(&client_list_lock);
-	
-	list_foreach(client_list, client_list, inetping6_client_t, client) {
-		if (client->ident == ident) {
-			fibril_mutex_unlock(&client_list_lock);
-			return client;
-		}
-	}
-	
-	fibril_mutex_unlock(&client_list_lock);
-	return NULL;
-}
-
-int inetping6_recv(uint16_t ident, inetping6_sdu_t *sdu)
-{
-	inetping6_client_t *client = inetping6_client_find(ident);
-	if (client == NULL) {
-		log_msg(LOG_DEFAULT, LVL_DEBUG, "Unknown ICMP ident. Dropping.");
-		return ENOENT;
-	}
-	
-	async_exch_t *exch = async_exchange_begin(client->sess);
-	
-	ipc_call_t answer;
-	aid_t req = async_send_1(exch, INETPING6_EV_RECV, sdu->seq_no, &answer);
-	
-	int rc = async_data_write_start(exch, sdu->src, sizeof(addr128_t));
-	if (rc != EOK) {
-		async_exchange_end(exch);
-		async_forget(req);
-		return rc;
-	}
-	
-	rc = async_data_write_start(exch, sdu->dest, sizeof(addr128_t));
-	if (rc != EOK) {
-		async_exchange_end(exch);
-		async_forget(req);
-		return rc;
-	}
-	
-	rc = async_data_write_start(exch, sdu->data, sdu->size);
-	
-	async_exchange_end(exch);
-	
-	if (rc != EOK) {
-		async_forget(req);
-		return rc;
-	}
-	
-	sysarg_t retval;
-	async_wait_for(req, &retval);
-	
-	return (int) retval;
-}
-
-static void inetping6_send_srv(inetping6_client_t *client, ipc_callid_t iid,
-    ipc_call_t *icall)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping6_send_srv()");
-	
-	inetping6_sdu_t sdu;
-	
-	sdu.seq_no = IPC_GET_ARG1(*icall);
-	
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_write_receive(&callid, &size)) {
-		async_answer_0(callid, EREFUSED);
-		async_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	if (size != sizeof(addr128_t)) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	int rc = async_data_write_finalize(callid, &sdu.src, size);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	if (!async_data_write_receive(&callid, &size)) {
-		async_answer_0(callid, EREFUSED);
-		async_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	if (size != sizeof(addr128_t)) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	rc = async_data_write_finalize(callid, &sdu.dest, size);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	rc = async_data_write_accept((void **) &sdu.data, false, 0, 0, 0,
-	    &sdu.size);
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	rc = inetping6_send(client, &sdu);
-	free(sdu.data);
-	
-	async_answer_0(iid, rc);
-}
-
-static void inetping6_get_srcaddr_srv(inetping6_client_t *client,
-    ipc_callid_t iid, ipc_call_t *icall)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping6_get_srcaddr_srv()");
-	
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_write_receive(&callid, &size)) {
-		async_answer_0(callid, EREFUSED);
-		async_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	if (size != sizeof(addr128_t)) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	addr128_t remote;
-	int rc = async_data_write_finalize(callid, &remote, size);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	addr128_t local;
-	rc = inetping6_get_srcaddr(client, remote, &local);
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	if (!async_data_read_receive(&callid, &size)) {
-		async_answer_0(callid, EREFUSED);
-		async_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	if (size != sizeof(addr128_t)) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	rc = async_data_read_finalize(callid, &local, size);
-	if (rc != EOK)
-		async_answer_0(callid, rc);
-	
-	async_answer_0(iid, rc);
-}
-
-static int inetping6_client_init(inetping6_client_t *client)
-{
-	async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
-	if (sess == NULL)
-		return ENOMEM;
-	
-	client->sess = sess;
-	link_initialize(&client->client_list);
-	
-	fibril_mutex_lock(&client_list_lock);
-	client->ident = ++inetping6_ident;
-	list_append(&client->client_list, &client_list);
-	fibril_mutex_unlock(&client_list_lock);
-	
-	return EOK;
-}
-
-static void inetping6_client_fini(inetping6_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);
-}
-
-void inetping6_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping6_conn()");
-	
-	/* Accept the connection */
-	async_answer_0(iid, EOK);
-	
-	inetping6_client_t client;
-	int rc = inetping6_client_init(&client);
-	if (rc != EOK)
-		return;
-	
-	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);
-			break;
-		}
-		
-		switch (method) {
-		case INETPING6_SEND:
-			inetping6_send_srv(&client, callid, &call);
-			break;
-		case INETPING6_GET_SRCADDR:
-			inetping6_get_srcaddr_srv(&client, callid, &call);
-			break;
-		default:
-			async_answer_0(callid, EINVAL);
-		}
-	}
-	
-	inetping6_client_fini(&client);
-}
-
-/** @}
- */
Index: uspace/srv/net/inetsrv/inetping6.h
===================================================================
--- uspace/srv/net/inetsrv/inetping6.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ 	(revision )
@@ -1,48 +1,0 @@
-/*
- * Copyright (c) 2013 Martin Decky
- * 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
- */
-
-#ifndef INETPING6_H_
-#define INETPING6_H_
-
-#include "inetsrv.h"
-
-extern void inetping6_conn(ipc_callid_t, ipc_call_t *, void *);
-extern int inetping6_recv(uint16_t, inetping6_sdu_t *);
-
-#endif
-
-/** @}
- */
Index: uspace/srv/net/inetsrv/inetsrv.c
===================================================================
--- uspace/srv/net/inetsrv/inetsrv.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/inetsrv.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -46,5 +46,4 @@
 #include <stdlib.h>
 #include <sys/types.h>
-#include <net/socket_codes.h>
 #include "addrobj.h"
 #include "icmp.h"
@@ -55,5 +54,4 @@
 #include "inetcfg.h"
 #include "inetping.h"
-#include "inetping6.h"
 #include "inet_link.h"
 #include "reass.h"
@@ -63,5 +61,5 @@
 
 static inet_naddr_t solicited_node_mask = {
-	.family = AF_INET6,
+	.version = ip_v6,
 	.addr6 = {0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0xff, 0, 0, 0},
 	.prefix = 104
@@ -69,10 +67,10 @@
 
 static inet_addr_t broadcast4_all_hosts = {
-	.family = AF_INET,
+	.version = ip_v4,
 	.addr = 0xffffffff
 };
 
 static inet_addr_t multicast_all_nodes = {
-	.family = AF_INET6,
+	.version = ip_v6,
 	.addr6 = {0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
 };
@@ -116,15 +114,4 @@
 		return EEXIST;
 	}
-	
-	rc = loc_service_register_with_iface(SERVICE_NAME_INETPING6, &sid,
-	    INET_PORT_PING6);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
-		return EEXIST;
-	}
-	
-	rc = inet_link_discovery_start();
-	if (rc != EOK)
-		return EEXIST;
 	
 	return EOK;
@@ -184,4 +171,5 @@
 
 	if (dgram->iplink != 0) {
+		/* XXX TODO - IPv6 */
 		log_msg(LOG_DEFAULT, LVL_DEBUG, "dgram directly to iplink %zu",
 		    dgram->iplink);
@@ -191,6 +179,6 @@
 			return ENOENT;
 
-		if (dgram->src.family != AF_INET ||
-			dgram->dest.family != AF_INET)
+		if (dgram->src.version != ip_v4 ||
+			dgram->dest.version != ip_v4)
 			return EINVAL;
 
@@ -229,9 +217,11 @@
 
 	/* Take source address from the address object */
-	if (remote->family == AF_INET && remote->addr == 0xffffffff) {
-		local->family = AF_INET;
+	if (remote->version == ip_v4 && remote->addr == 0xffffffff) {
+		/* XXX TODO - IPv6 */
+		local->version = ip_v4;
 		local->addr = 0;
 		return EOK;
 	}
+
 	inet_naddr_addr(&dir.aobj->naddr, local);
 	return EOK;
@@ -454,7 +444,4 @@
 		inetping_conn(iid, icall, arg);
 		break;
-	case INET_PORT_PING6:
-		inetping6_conn(iid, icall, arg);
-		break;
 	default:
 		async_answer_0(iid, ENOTSUP);
Index: uspace/srv/net/inetsrv/inetsrv.h
===================================================================
--- uspace/srv/net/inetsrv/inetsrv.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/inetsrv.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -148,20 +148,4 @@
 } inet_dir_t;
 
-typedef struct {
-	uint32_t src;
-	uint32_t dest;
-	uint16_t seq_no;
-	void *data;
-	size_t size;
-} inetping_sdu_t;
-
-typedef struct {
-	addr128_t src;
-	addr128_t dest;
-	uint16_t seq_no;
-	void *data;
-	size_t size;
-} inetping6_sdu_t;
-
 extern int inet_ev_recv(inet_client_t *, inet_dgram_t *);
 extern int inet_recv_packet(inet_packet_t *);
Index: uspace/srv/net/inetsrv/ndp.c
===================================================================
--- uspace/srv/net/inetsrv/ndp.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/ndp.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -39,5 +39,4 @@
 #include <malloc.h>
 #include <io/log.h>
-#include <net/socket_codes.h>
 #include "ntrans.h"
 #include "addrobj.h"
Index: uspace/srv/net/inetsrv/pdu.c
===================================================================
--- uspace/srv/net/inetsrv/pdu.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/pdu.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -44,5 +44,4 @@
 #include <mem.h>
 #include <stdlib.h>
-#include <net/socket_codes.h>
 #include "inetsrv.h"
 #include "inet_std.h"
@@ -533,7 +532,7 @@
 int ndp_pdu_decode(inet_dgram_t *dgram, ndp_packet_t *ndp)
 {
-	uint16_t src_af = inet_addr_get(&dgram->src, NULL,
+	ip_ver_t src_ver = inet_addr_get(&dgram->src, NULL,
 	    &ndp->sender_proto_addr);
-	if (src_af != AF_INET6)
+	if (src_ver != ip_v6)
 		return EINVAL;
 	
Index: uspace/srv/net/inetsrv/sroute.c
===================================================================
--- uspace/srv/net/inetsrv/sroute.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/inetsrv/sroute.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -95,5 +95,5 @@
 inet_sroute_t *inet_sroute_find(inet_addr_t *addr)
 {
-	uint16_t addr_af = inet_addr_get(addr, NULL, NULL);
+	ip_ver_t addr_ver = inet_addr_get(addr, NULL, NULL);
 	
 	inet_sroute_t *best = NULL;
@@ -104,9 +104,9 @@
 	list_foreach(sroute_list, sroute_list, inet_sroute_t, sroute) {
 		uint8_t dest_bits;
-		uint16_t dest_af = inet_naddr_get(&sroute->dest, NULL, NULL,
+		ip_ver_t dest_ver = inet_naddr_get(&sroute->dest, NULL, NULL,
 		    &dest_bits);
 		
 		/* Skip comparison with different address family */
-		if (addr_af != dest_af)
+		if (addr_ver != dest_ver)
 			continue;
 		
Index: uspace/srv/net/loopip/loopip.c
===================================================================
--- uspace/srv/net/loopip/loopip.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/loopip/loopip.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -40,5 +40,4 @@
 #include <inet/iplink_srv.h>
 #include <inet/addr.h>
-#include <net/socket_codes.h>
 #include <io/log.h>
 #include <loc.h>
@@ -76,5 +75,6 @@
 	link_t link;
 	
-	uint16_t af;
+	/* XXX Version should be part of SDU */
+	ip_ver_t ver;
 	iplink_recv_sdu_t sdu;
 } rqueue_entry_t;
@@ -88,5 +88,5 @@
 		    list_get_instance(link, rqueue_entry_t, link);
 		
-		(void) iplink_ev_recv(&loopip_iplink, &rqe->sdu, rqe->af);
+		(void) iplink_ev_recv(&loopip_iplink, &rqe->sdu, rqe->ver);
 		
 		free(rqe->sdu.data);
@@ -174,5 +174,5 @@
 	 * Clone SDU
 	 */
-	rqe->af = AF_INET;
+	rqe->ver = ip_v4;
 	rqe->sdu.data = malloc(sdu->size);
 	if (rqe->sdu.data == NULL) {
@@ -203,5 +203,5 @@
 	 * Clone SDU
 	 */
-	rqe->af = AF_INET6;
+	rqe->ver = ip_v6;
 	rqe->sdu.data = malloc(sdu->size);
 	if (rqe->sdu.data == NULL) {
Index: uspace/srv/net/nconfsrv/Makefile
===================================================================
--- uspace/srv/net/nconfsrv/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/srv/net/nconfsrv/Makefile	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2013 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 = nconfsrv
+
+SOURCES = \
+	iplink.c \
+	nconfsrv.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/net/nconfsrv/iplink.c
===================================================================
--- uspace/srv/net/nconfsrv/iplink.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/srv/net/nconfsrv/iplink.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2013 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 nconfsrv
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#include <stdbool.h>
+#include <errno.h>
+#include <fibril_synch.h>
+#include <inet/dhcp.h>
+#include <inet/inetcfg.h>
+#include <io/log.h>
+#include <loc.h>
+#include <stdlib.h>
+#include <str.h>
+
+#include "iplink.h"
+#include "nconfsrv.h"
+
+static int ncs_link_add(service_id_t);
+
+static LIST_INITIALIZE(ncs_links);
+static FIBRIL_MUTEX_INITIALIZE(ncs_links_lock);
+
+static int ncs_link_check_new(void)
+{
+	bool already_known;
+	category_id_t iplink_cat;
+	service_id_t *svcs;
+	size_t count, i;
+	int rc;
+
+	fibril_mutex_lock(&ncs_links_lock);
+
+	rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'iplink'.");
+		fibril_mutex_unlock(&ncs_links_lock);
+		return ENOENT;
+	}
+
+	rc = loc_category_get_svcs(iplink_cat, &svcs, &count);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of IP links.");
+		fibril_mutex_unlock(&ncs_links_lock);
+		return EIO;
+	}
+
+	for (i = 0; i < count; i++) {
+		already_known = false;
+
+		list_foreach(ncs_links, link_list, ncs_link_t, ilink) {
+			if (ilink->svc_id == svcs[i]) {
+				already_known = true;
+				break;
+			}
+		}
+
+		if (!already_known) {
+			log_msg(LOG_DEFAULT, LVL_NOTE, "Found IP link '%lu'",
+			    (unsigned long) svcs[i]);
+			rc = ncs_link_add(svcs[i]);
+			if (rc != EOK)
+				log_msg(LOG_DEFAULT, LVL_ERROR, "Could not add IP link.");
+		}
+	}
+
+	fibril_mutex_unlock(&ncs_links_lock);
+	return EOK;
+}
+
+static ncs_link_t *ncs_link_new(void)
+{
+	ncs_link_t *nlink = calloc(1, sizeof(ncs_link_t));
+
+	if (nlink == NULL) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating link structure. "
+		    "Out of memory.");
+		return NULL;
+	}
+
+	link_initialize(&nlink->link_list);
+
+	return nlink;
+}
+
+static void ncs_link_delete(ncs_link_t *nlink)
+{
+	if (nlink->svc_name != NULL)
+		free(nlink->svc_name);
+
+	free(nlink);
+}
+
+static int ncs_link_add(service_id_t sid)
+{
+	ncs_link_t *nlink;
+	int rc;
+
+	assert(fibril_mutex_is_locked(&ncs_links_lock));
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ncs_link_add()");
+	nlink = ncs_link_new();
+	if (nlink == NULL)
+		return ENOMEM;
+
+	nlink->svc_id = sid;
+
+	rc = loc_service_get_name(sid, &nlink->svc_name);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting service name.");
+		goto error;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "Configure link %s", nlink->svc_name);
+	rc = inetcfg_link_add(sid);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed configuring link "
+		    "'%s'.\n", nlink->svc_name);
+		goto error;
+	}
+
+	if (str_lcmp(nlink->svc_name, "net/eth", str_length("net/eth")) == 0) {
+		rc = dhcp_link_add(sid);
+		if (rc != EOK) {
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Failed configuring DHCP on "
+			    " link '%s'.\n", nlink->svc_name);
+			goto error;
+		}
+	}
+
+	list_append(&nlink->link_list, &ncs_links);
+
+	return EOK;
+
+error:
+	ncs_link_delete(nlink);
+	return rc;
+}
+
+static void ncs_link_cat_change_cb(void)
+{
+	(void) ncs_link_check_new();
+}
+
+int ncs_link_discovery_start(void)
+{
+	int rc;
+
+	rc = loc_register_cat_change_cb(ncs_link_cat_change_cb);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback for IP link "
+		    "discovery (%d).", rc);
+		return rc;
+	}
+
+	return ncs_link_check_new();
+}
+
+ncs_link_t *ncs_link_get_by_id(sysarg_t link_id)
+{
+	fibril_mutex_lock(&ncs_links_lock);
+
+	list_foreach(ncs_links, link_list, ncs_link_t, nlink) {
+		if (nlink->svc_id == link_id) {
+			fibril_mutex_unlock(&ncs_links_lock);
+			return nlink;
+		}
+	}
+
+	fibril_mutex_unlock(&ncs_links_lock);
+	return NULL;
+}
+
+/** Get IDs of all links. */
+int ncs_link_get_id_list(sysarg_t **rid_list, size_t *rcount)
+{
+	sysarg_t *id_list;
+	size_t count, i;
+
+	fibril_mutex_lock(&ncs_links_lock);
+	count = list_count(&ncs_links);
+
+	id_list = calloc(count, sizeof(sysarg_t));
+	if (id_list == NULL) {
+		fibril_mutex_unlock(&ncs_links_lock);
+		return ENOMEM;
+	}
+
+	i = 0;
+	list_foreach(ncs_links, link_list, ncs_link_t, nlink) {
+		id_list[i++] = nlink->svc_id;
+		log_msg(LOG_DEFAULT, LVL_NOTE, "add link to list");
+	}
+
+	fibril_mutex_unlock(&ncs_links_lock);
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "return %zu links", count);
+	*rid_list = id_list;
+	*rcount = count;
+
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/srv/net/nconfsrv/iplink.h
===================================================================
--- uspace/srv/net/nconfsrv/iplink.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/srv/net/nconfsrv/iplink.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013 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 nconfsrv
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#ifndef NCONFSRV_IPLINK_H_
+#define NCONFSRV_IPLINK_H_
+
+#include <sys/types.h>
+#include "nconfsrv.h"
+
+extern int ncs_link_discovery_start(void);
+extern ncs_link_t *ncs_link_get_by_id(sysarg_t);
+extern int ncs_link_get_id_list(sysarg_t **, size_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/nconfsrv/nconfsrv.c
===================================================================
--- uspace/srv/net/nconfsrv/nconfsrv.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/srv/net/nconfsrv/nconfsrv.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2013 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 nconfsrv
+ * @{
+ */
+/**
+ * @file
+ * @brief Network configuration Service
+ */
+
+#include <adt/list.h>
+#include <async.h>
+#include <errno.h>
+#include <fibril_synch.h>
+#include <inet/dhcp.h>
+#include <inet/inetcfg.h>
+#include <io/log.h>
+#include <ipc/inet.h>
+#include <ipc/services.h>
+#include <loc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "iplink.h"
+#include "nconfsrv.h"
+
+#define NAME "nconfsrv"
+
+static void ncs_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg);
+
+static int ncs_init(void)
+{
+	service_id_t sid;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ncs_init()");
+
+	rc = inetcfg_init();
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error contacting inet "
+		    "configuration service.");
+		return EIO;
+	}
+
+	rc = dhcp_init();
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error contacting dhcp "
+		    "configuration service.");
+		return EIO;
+	}
+
+	async_set_client_connection(ncs_client_conn);
+
+	rc = loc_server_register(NAME);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server (%d).", rc);
+		return EEXIST;
+	}
+
+	rc = loc_service_register(SERVICE_NAME_NETCONF, &sid);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
+		return EEXIST;
+	}
+
+	rc = ncs_link_discovery_start();
+	if (rc != EOK)
+		return EEXIST;
+
+	return EOK;
+}
+
+static void ncs_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	async_answer_0(iid, ENOTSUP);
+}
+
+int main(int argc, char *argv[])
+{
+	int rc;
+
+	printf(NAME ": HelenOS Network configuration service\n");
+
+	if (log_init(NAME) != EOK) {
+		printf(NAME ": Failed to initialize logging.\n");
+		return 1;
+	}
+
+	rc = ncs_init();
+	if (rc != EOK)
+		return 1;
+
+	printf(NAME ": Accepting connections.\n");
+	task_retval(0);
+	async_manager();
+
+	/* Not reached */
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/srv/net/nconfsrv/nconfsrv.h
===================================================================
--- uspace/srv/net/nconfsrv/nconfsrv.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
+++ uspace/srv/net/nconfsrv/nconfsrv.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 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 inetsrv
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#ifndef INETSRV_H_
+#define INETSRV_H_
+
+#include <adt/list.h>
+#include <ipc/loc.h>
+
+typedef struct {
+	link_t link_list;
+	service_id_t svc_id;
+	char *svc_name;
+} ncs_link_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/slip/slip.c
===================================================================
--- uspace/srv/net/slip/slip.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/slip/slip.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -38,5 +38,4 @@
 #include <stdint.h>
 #include <loc.h>
-#include <net/socket_codes.h>
 #include <inet/addr.h>
 #include <inet/iplink_srv.h>
@@ -277,5 +276,5 @@
 
 pass:
-		rc = iplink_ev_recv(&slip_iplink, &sdu, AF_INET);
+		rc = iplink_ev_recv(&slip_iplink, &sdu, ip_v4);
 		if (rc != EOK) {
 			log_msg(LOG_DEFAULT, LVL_ERROR,
Index: uspace/srv/net/tcp/conn.c
===================================================================
--- uspace/srv/net/tcp/conn.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/tcp/conn.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -381,5 +381,5 @@
  * @param conn	Connection
  */
-static void tcp_conn_reset(tcp_conn_t *conn)
+void tcp_conn_reset(tcp_conn_t *conn)
 {
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_reset()", conn->name);
Index: uspace/srv/net/tcp/conn.h
===================================================================
--- uspace/srv/net/tcp/conn.h	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/tcp/conn.h	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -43,4 +43,5 @@
 extern void tcp_conn_add(tcp_conn_t *);
 extern void tcp_conn_remove(tcp_conn_t *);
+extern void tcp_conn_reset(tcp_conn_t *conn);
 extern void tcp_conn_sync(tcp_conn_t *);
 extern void tcp_conn_fin_sent(tcp_conn_t *);
Index: uspace/srv/net/tcp/pdu.c
===================================================================
--- uspace/srv/net/tcp/pdu.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/tcp/pdu.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -40,5 +40,4 @@
 #include <mem.h>
 #include <stdlib.h>
-#include <net/socket_codes.h>
 #include "pdu.h"
 #include "segment.h"
@@ -145,19 +144,19 @@
 }
 
-static uint16_t tcp_phdr_setup(tcp_pdu_t *pdu, tcp_phdr_t *phdr,
+static ip_ver_t tcp_phdr_setup(tcp_pdu_t *pdu, tcp_phdr_t *phdr,
     tcp_phdr6_t *phdr6)
 {
 	addr32_t src_v4;
 	addr128_t src_v6;
-	uint16_t src_af = inet_addr_get(&pdu->src, &src_v4, &src_v6);
-	
+	uint16_t src_ver = inet_addr_get(&pdu->src, &src_v4, &src_v6);
+
 	addr32_t dest_v4;
 	addr128_t dest_v6;
-	uint16_t dest_af = inet_addr_get(&pdu->dest, &dest_v4, &dest_v6);
-	
-	assert(src_af == dest_af);
-	
-	switch (src_af) {
-	case AF_INET:
+	uint16_t dest_ver = inet_addr_get(&pdu->dest, &dest_v4, &dest_v6);
+
+	assert(src_ver == dest_ver);
+
+	switch (src_ver) {
+	case ip_v4:
 		phdr->src = host2uint32_t_be(src_v4);
 		phdr->dest = host2uint32_t_be(dest_v4);
@@ -167,5 +166,5 @@
 		    host2uint16_t_be(pdu->header_size + pdu->text_size);
 		break;
-	case AF_INET6:
+	case ip_v6:
 		host2addr128_t_be(src_v6, phdr6->src);
 		host2addr128_t_be(dest_v6, phdr6->dest);
@@ -178,6 +177,6 @@
 		assert(false);
 	}
-	
-	return src_af;
+
+	return src_ver;
 }
 
@@ -266,12 +265,12 @@
 	tcp_phdr_t phdr;
 	tcp_phdr6_t phdr6;
-	
-	uint16_t af = tcp_phdr_setup(pdu, &phdr, &phdr6);
-	switch (af) {
-	case AF_INET:
+
+	ip_ver_t ver = tcp_phdr_setup(pdu, &phdr, &phdr6);
+	switch (ver) {
+	case ip_v4:
 		cs_phdr = tcp_checksum_calc(TCP_CHECKSUM_INIT, (void *) &phdr,
 		    sizeof(tcp_phdr_t));
 		break;
-	case AF_INET6:
+	case ip_v6:
 		cs_phdr = tcp_checksum_calc(TCP_CHECKSUM_INIT, (void *) &phdr6,
 		    sizeof(tcp_phdr6_t));
@@ -280,5 +279,5 @@
 		assert(false);
 	}
-	
+
 	cs_headers = tcp_checksum_calc(cs_phdr, pdu->header, pdu->header_size);
 	return tcp_checksum_calc(cs_headers, pdu->text, pdu->text_size);
Index: uspace/srv/net/tcp/sock.c
===================================================================
--- uspace/srv/net/tcp/sock.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/tcp/sock.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -882,4 +882,5 @@
 	tcp_sockdata_t *socket;
 	tcp_error_t trc;
+	int i;
 	int rc;
 
@@ -897,4 +898,5 @@
 
 	if (socket->conn != NULL) {
+		/* Close connection */
 		trc = tcp_uc_close(socket->conn);
 		if (trc != TCP_EOK && trc != TCP_ENOTEXIST) {
@@ -905,4 +907,20 @@
 	}
 
+	if (socket->lconn != NULL) {
+		/* Close listening connections */
+		for (i = 0; i < socket->backlog; i++) {
+			tcp_uc_set_cstate_cb(socket->lconn[i]->conn, NULL, NULL);
+			trc = tcp_uc_close(socket->lconn[i]->conn);
+			if (trc != TCP_EOK && trc != TCP_ENOTEXIST) {
+				fibril_mutex_unlock(&socket->lock);
+				async_answer_0(callid, EBADF);
+				return;
+			}
+
+			free(socket->lconn[i]);
+			socket->lconn[i] = NULL;
+		}
+	}
+
 	/* Grab recv_buffer_lock because of CV wait in tcp_sock_recv_fibril() */
 	fibril_mutex_lock(&socket->recv_buffer_lock);
Index: uspace/srv/net/tcp/ucall.c
===================================================================
--- uspace/srv/net/tcp/ucall.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/tcp/ucall.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -83,4 +83,5 @@
 
 	if (oflags == tcp_open_nonblock) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open -> %p", nconn);
 		*conn = nconn;
 		return TCP_EOK;
@@ -234,18 +235,29 @@
 tcp_error_t tcp_uc_close(tcp_conn_t *conn)
 {
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_uc_close()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_uc_close(%p)", conn->name,
+	    conn);
 
 	fibril_mutex_lock(&conn->lock);
 
 	if (conn->cstate == st_closed) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_close - ENOTEXIST");
 		fibril_mutex_unlock(&conn->lock);
 		return TCP_ENOTEXIST;
 	}
 
+	if (conn->cstate == st_listen || conn->cstate == st_syn_sent) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_close - listen/syn_sent");
+		tcp_conn_reset(conn);
+		tcp_conn_remove(conn);
+		return TCP_EOK;
+	}
+
 	if (conn->snd_buf_fin) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_close - ECLOSING");
 		fibril_mutex_unlock(&conn->lock);
 		return TCP_ECLOSING;
 	}
 
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_close - set snd_buf_fin");
 	conn->snd_buf_fin = true;
 	tcp_tqueue_new_data(conn);
Index: uspace/srv/net/udp/pdu.c
===================================================================
--- uspace/srv/net/udp/pdu.c	(revision 6297465f7d3b817f92dba0162f342c50ff988a8a)
+++ uspace/srv/net/udp/pdu.c	(revision 4c14b88bea8dc57378db2c26f17fe9babd996fa9)
@@ -85,19 +85,19 @@
 }
 
-static uint16_t udp_phdr_setup(udp_pdu_t *pdu, udp_phdr_t *phdr,
+static ip_ver_t udp_phdr_setup(udp_pdu_t *pdu, udp_phdr_t *phdr,
     udp_phdr6_t *phdr6)
 {
 	addr32_t src_v4;
 	addr128_t src_v6;
-	uint16_t src_af = inet_addr_get(&pdu->src, &src_v4, &src_v6);
-	
+	ip_ver_t src_ver = inet_addr_get(&pdu->src, &src_v4, &src_v6);
+
 	addr32_t dest_v4;
 	addr128_t dest_v6;
-	uint16_t dest_af = inet_addr_get(&pdu->dest, &dest_v4, &dest_v6);
-	
-	assert(src_af == dest_af);
-	
-	switch (src_af) {
-	case AF_INET:
+	ip_ver_t dest_ver = inet_addr_get(&pdu->dest, &dest_v4, &dest_v6);
+
+	assert(src_ver == dest_ver);
+
+	switch (src_ver) {
+	case ip_v4:
 		phdr->src_addr = host2uint32_t_be(src_v4);
 		phdr->dest_addr = host2uint32_t_be(dest_v4);
@@ -106,5 +106,5 @@
 		phdr->udp_length = host2uint16_t_be(pdu->data_size);
 		break;
-	case AF_INET6:
+	case ip_v6:
 		host2addr128_t_be(src_v6, phdr6->src_addr);
 		host2addr128_t_be(dest_v6, phdr6->dest_addr);
@@ -116,6 +116,6 @@
 		assert(false);
 	}
-	
-	return src_af;
+
+	return src_ver;
 }
 
@@ -136,12 +136,12 @@
 	udp_phdr_t phdr;
 	udp_phdr6_t phdr6;
-	
-	uint16_t af = udp_phdr_setup(pdu, &phdr, &phdr6);
-	switch (af) {
-	case AF_INET:
+
+	ip_ver_t ver = udp_phdr_setup(pdu, &phdr, &phdr6);
+	switch (ver) {
+	case ip_v4:
 		cs_phdr = udp_checksum_calc(UDP_CHECKSUM_INIT, (void *) &phdr,
 		    sizeof(udp_phdr_t));
 		break;
-	case AF_INET6:
+	case ip_v6:
 		cs_phdr = udp_checksum_calc(UDP_CHECKSUM_INIT, (void *) &phdr6,
 		    sizeof(udp_phdr6_t));
@@ -150,5 +150,5 @@
 		assert(false);
 	}
-	
+
 	return udp_checksum_calc(cs_phdr, pdu->data, pdu->data_size);
 }
