Index: .bzrignore
===================================================================
--- .bzrignore	(revision ae7bbfd0bcf872d80ac6f3f37faf7fa216782613)
+++ .bzrignore	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
@@ -55,4 +55,5 @@
 uspace/app/nettest3/nettest3
 uspace/app/nic/nic
+uspace/app/netecho/netecho
 uspace/app/nterm/nterm
 uspace/app/ping/ping
@@ -112,4 +113,5 @@
 uspace/dist/app/nettest3
 uspace/dist/app/nic
+uspace/dist/app/netecho
 uspace/dist/app/nterm
 uspace/dist/app/ping
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision ae7bbfd0bcf872d80ac6f3f37faf7fa216782613)
+++ boot/Makefile.common	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
@@ -205,4 +205,5 @@
 	$(USPACE_PATH)/app/tetris/tetris \
 	$(USPACE_PATH)/app/trace/trace \
+	$(USPACE_PATH)/app/netecho/netecho \
 	$(USPACE_PATH)/app/nterm/nterm \
 	$(USPACE_PATH)/app/ping/ping \
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision ae7bbfd0bcf872d80ac6f3f37faf7fa216782613)
+++ uspace/Makefile	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
@@ -60,4 +60,5 @@
 	app/mkmfs \
 	app/modplay \
+	app/netecho \
 	app/nterm \
 	app/redir \
Index: uspace/app/netecho/Makefile
===================================================================
--- uspace/app/netecho/Makefile	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
+++ uspace/app/netecho/Makefile	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2016 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 = netecho
+
+SOURCES = \
+	comm.c \
+	netecho.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/netecho/comm.c
===================================================================
--- uspace/app/netecho/comm.c	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
+++ uspace/app/netecho/comm.c	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2016 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 netecho
+ * @{
+ */
+/** @file
+ */
+
+#include <byteorder.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <fibril.h>
+#include <inet/dnsr.h>
+#include <inet/endpoint.h>
+#include <inet/udp.h>
+#include <macros.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <str_error.h>
+#include <sys/types.h>
+
+#include "comm.h"
+#include "netecho.h"
+
+static udp_t *udp;
+static udp_assoc_t *assoc;
+static inet_ep_t remote;
+
+#define RECV_BUF_SIZE 1024
+static uint8_t recv_buf[RECV_BUF_SIZE];
+
+static void comm_udp_recv_msg(udp_assoc_t *, udp_rmsg_t *);
+static void comm_udp_recv_err(udp_assoc_t *, udp_rerr_t *);
+static void comm_udp_link_state(udp_assoc_t *, udp_link_state_t);
+
+static udp_cb_t comm_udp_cb = {
+	.recv_msg = comm_udp_recv_msg,
+	.recv_err = comm_udp_recv_err,
+	.link_state = comm_udp_link_state
+};
+
+static void comm_udp_recv_msg(udp_assoc_t *assoc, udp_rmsg_t *rmsg)
+{
+	size_t size;
+	size_t pos;
+	size_t now;
+	int rc;
+
+	size = udp_rmsg_size(rmsg);
+	pos = 0;
+	while (pos < size) {
+		now = min(size - pos, RECV_BUF_SIZE);
+		rc = udp_rmsg_read(rmsg, pos, recv_buf, now);
+		if (rc != EOK) {
+			printf("Error reading message.\n");
+			return;
+		}
+
+		netecho_received(recv_buf, now);
+		pos += now;
+	}
+}
+
+static void comm_udp_recv_err(udp_assoc_t *assoc, udp_rerr_t *rerr)
+{
+	printf("Got ICMP error message.\n");
+}
+
+static void comm_udp_link_state(udp_assoc_t *assoc, udp_link_state_t lstate)
+{
+	const char *sstate = NULL;
+
+	switch (lstate) {
+	case udp_ls_down:
+		sstate = "Down";
+		break;
+	case udp_ls_up:
+		sstate = "Up";
+		break;
+	}
+
+	printf("Link state change: %s.\n", sstate);
+}
+
+int comm_open(const char *host, const char *port_s)
+{
+	inet_ep2_t epp;
+	inet_addr_t iaddr;
+	int rc;
+
+	if (host != NULL) {
+		/* Interpret as address */
+		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(host, &hinfo, ip_any);
+
+			if (rc != EOK) {
+				printf("Error resolving host '%s'.\n", host);
+				goto error;
+			}
+
+			iaddr = hinfo->addr;
+		}
+	}
+
+	char *endptr;
+	uint16_t port = strtol(port_s, &endptr, 10);
+	if (*endptr != '\0') {
+		printf("Invalid port number %s\n", port_s);
+		goto error;
+	}
+
+	inet_ep2_init(&epp);
+	if (host != NULL) {
+		/* Talk to remote host */
+		remote.addr = iaddr;
+		remote.port = port;
+
+		printf("Talking to host %s port %u\n", host, port);
+	} else {
+		/* Listen on local port */
+		epp.local.port = port;
+
+		printf("Listening on port %u\n", port);
+	}
+
+	rc = udp_create(&udp);
+	if (rc != EOK)
+		goto error;
+
+	rc = udp_assoc_create(udp, &epp, &comm_udp_cb, NULL, &assoc);
+	if (rc != EOK)
+		goto error;
+
+	return EOK;
+error:
+	udp_assoc_destroy(assoc);
+	udp_destroy(udp);
+
+	return EIO;
+}
+
+void comm_close(void)
+{
+	if (assoc != NULL)
+		udp_assoc_destroy(assoc);
+	if (udp != NULL)
+		udp_destroy(udp);
+}
+
+int comm_send(void *data, size_t size)
+{
+	int rc = udp_assoc_send_msg(assoc, &remote, data, size);
+	if (rc != EOK)
+		return EIO;
+
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/app/netecho/comm.h
===================================================================
--- uspace/app/netecho/comm.h	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
+++ uspace/app/netecho/comm.h	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016 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 netecho
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef COMM_H
+#define COMM_H
+
+#include <sys/types.h>
+
+extern int comm_open(const char *, const char *);
+extern void comm_close(void);
+extern int comm_send(void *, size_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/netecho/netecho.c
===================================================================
--- uspace/app/netecho/netecho.c	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
+++ uspace/app/netecho/netecho.c	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2016 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 netecho
+ * @{
+ */
+/** @file Network UDP echo diagnostic utility.
+ */
+
+#include <stdbool.h>
+#include <errno.h>
+#include <io/console.h>
+#include <stdio.h>
+#include <str.h>
+
+#include "comm.h"
+#include "netecho.h"
+
+#define NAME "netecho"
+
+static console_ctrl_t *con;
+static bool done;
+
+void netecho_received(void *data, size_t size)
+{
+	char *p;
+	size_t i;
+
+	printf("Received message '");
+	p = data;
+
+	for (i = 0; i < size; i++)
+		putchar(p[i]);
+	printf("'.\n");
+}
+
+static void key_handle_ctrl(kbd_event_t *ev)
+{
+	switch (ev->key) {
+	case KC_Q:
+		done = true;
+		break;
+	default:
+		break;
+	}
+}
+
+static void send_char(wchar_t c)
+{
+	char cbuf[STR_BOUNDS(1)];
+	size_t offs;
+	int rc;
+
+	offs = 0;
+	chr_encode(c, cbuf, &offs, STR_BOUNDS(1));
+
+	rc = comm_send(cbuf, offs);
+	if (rc != EOK) {
+		printf("[Failed sending data]\n");
+	}
+}
+
+static void key_handle_unmod(kbd_event_t *ev)
+{
+	switch (ev->key) {
+	case KC_ENTER:
+		send_char('\n');
+		break;
+	default:
+		if (ev->c >= 32 || ev->c == '\t' || ev->c == '\b') {
+			send_char(ev->c);
+		}
+	}
+}
+
+static void key_handle(kbd_event_t *ev)
+{
+	if ((ev->mods & KM_ALT) == 0 &&
+	    (ev->mods & KM_SHIFT) == 0 &&
+	    (ev->mods & KM_CTRL) != 0) {
+		key_handle_ctrl(ev);
+	} else if ((ev->mods & (KM_CTRL | KM_ALT)) == 0) {
+		key_handle_unmod(ev);
+	}
+}
+
+
+static void print_syntax(void)
+{
+	printf("syntax:\n");
+	printf("\t%s -l <port>\n", NAME);
+	printf("\t%s -d <host> <port> [<message> [<message...>]]\n", NAME);
+}
+
+/* Interactive mode */
+static void netecho_interact(void)
+{
+	cons_event_t ev;
+
+	printf("Communication started. Press Ctrl-Q to quit.\n");
+
+	con = console_init(stdin, stdout);
+
+	done = false;
+	while (!done) {
+		console_get_event(con, &ev);
+		if (ev.type == CEV_KEY && ev.ev.key.type == KEY_PRESS)
+			key_handle(&ev.ev.key);
+	}
+}
+
+static void netecho_send_messages(char **msgs)
+{
+	int rc;
+
+	while (*msgs != NULL) {
+		rc = comm_send(*msgs, str_size(*msgs));
+		if (rc != EOK) {
+			printf("[Failed sending data]\n");
+		}
+
+		++msgs;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	char *host;
+	char *port;
+	char **msgs;
+	int rc;
+
+	if (argc < 2) {
+		print_syntax();
+		return 1;
+	}
+
+	if (str_cmp(argv[1], "-l") == 0) {
+		if (argc != 3) {
+			print_syntax();
+			return 1;
+		}
+
+		host = NULL;
+		port = argv[2];
+		msgs = NULL;
+	} else if (str_cmp(argv[1], "-d") == 0) {
+		if (argc < 4) {
+			print_syntax();
+			return 1;
+		}
+
+		host = argv[2];
+		port = argv[3];
+		msgs = argv + 4;
+	} else {
+		print_syntax();
+		return 1;
+	}
+
+	rc = comm_open(host, port);
+	if (rc != EOK) {
+		printf("Error setting up communication.\n");
+		return 1;
+	}
+
+	if (msgs != NULL && *msgs != NULL) {
+		/* Just send messages and quit */
+		netecho_send_messages(msgs);
+	} else {
+		/* Interactive mode */
+		netecho_interact();
+	}
+
+	comm_close();
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/netecho/netecho.h
===================================================================
--- uspace/app/netecho/netecho.h	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
+++ uspace/app/netecho/netecho.h	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 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 netecho
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef NETECHO_H
+#define NETECHO_H
+
+#include <sys/types.h>
+
+extern void netecho_received(void *, size_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nterm/conn.h
===================================================================
--- uspace/app/nterm/conn.h	(revision ae7bbfd0bcf872d80ac6f3f37faf7fa216782613)
+++ uspace/app/nterm/conn.h	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup edit
+/** @addtogroup nterm
  * @{
  */
Index: uspace/app/nterm/nterm.h
===================================================================
--- uspace/app/nterm/nterm.h	(revision ae7bbfd0bcf872d80ac6f3f37faf7fa216782613)
+++ uspace/app/nterm/nterm.h	(revision 5147ff124d29e1b9d3e60be5848187fd214f2924)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup edit
+/** @addtogroup nterm
  * @{
  */
