Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision ffa89125d041d58392d67a3df0e52564a07cee35)
+++ uspace/Makefile	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -66,4 +66,5 @@
 	app/nettest2 \
 	app/nettest3 \
+	app/ping \
 	app/websrv \
 	app/sysinfo \
Index: uspace/app/ping/Makefile
===================================================================
--- uspace/app/ping/Makefile	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
+++ uspace/app/ping/Makefile	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2012 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+BINARY = ping
+
+SOURCES = \
+	ping.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/ping/ping.c
===================================================================
--- uspace/app/ping/ping.c	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
+++ uspace/app/ping/ping.c	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup ping
+ * @{
+ */
+/** @file ICMP echo utility.
+ */
+
+#include <errno.h>
+#include <fibril_synch.h>
+#include <inet/inetping.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#define NAME "ping"
+
+/** Ping request timeout in microseconds */
+#define PING_TIMEOUT (1000 * 1000)
+
+static int ping_ev_recv(inetping_sdu_t *);
+static FIBRIL_CONDVAR_INITIALIZE(done_cv);
+static FIBRIL_MUTEX_INITIALIZE(done_lock);
+
+static inetping_ev_ops_t ev_ops = {
+	.recv = ping_ev_recv
+};
+
+static void print_syntax(void)
+{
+	printf("syntax: " NAME " <addr>\n");
+}
+
+static int addr_parse(const char *text, inet_addr_t *addr)
+{
+	unsigned long a[4];
+	char *cp = (char *)text;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		a[i] = strtoul(cp, &cp, 10);
+		if (*cp != '.')
+			return EINVAL;
+		++cp;
+	}
+
+	a[3] = strtoul(cp, &cp, 10);
+	if (*cp != '\0')
+		return EINVAL;
+
+	addr->ipv4 = 0;
+	for (i = 0; i < 4; i++) {
+		if (a[i] > 255)
+			return EINVAL;
+		addr->ipv4 = (addr->ipv4 << 8) | a[i];
+	}
+
+	return EOK;
+}
+
+static int addr_format(inet_addr_t *addr, char **bufp)
+{
+	int rc;
+
+	rc = asprintf(bufp, "%d.%d.%d.%d", addr->ipv4 >> 24,
+	    (addr->ipv4 >> 16) & 0xff, (addr->ipv4 >> 8) & 0xff,
+	    addr->ipv4 & 0xff);
+
+	if (rc < 0)
+		return ENOMEM;
+
+	return EOK;
+}
+
+static int ping_ev_recv(inetping_sdu_t *sdu)
+{
+	char *asrc, *adest;
+	int rc;
+
+	rc = addr_format(&sdu->src, &asrc);
+	if (rc != EOK)
+		return ENOMEM;
+
+	rc = addr_format(&sdu->dest, &adest);
+	if (rc != EOK) {
+		free(asrc);
+		return ENOMEM;
+	}
+	printf("Received ICMP echo reply: from %s to %s, seq. no %u, "
+	    "payload size %zu\n", asrc, adest, sdu->seq_no, sdu->size);
+
+	fibril_condvar_broadcast(&done_cv);
+
+	free(asrc);
+	free(adest);
+	return EOK;
+}
+
+int main(int argc, char *argv[])
+{
+	int rc;
+	inetping_sdu_t sdu;
+
+	rc = inetping_init(&ev_ops);
+	if (rc != EOK) {
+		printf(NAME ": Failed connecting to internet ping service "
+		    "(%d).\n", rc);
+		return 1;
+	}
+
+	if (argc != 2) {
+		print_syntax();
+		return 1;
+	}
+
+	/* Parse destination address */
+	rc = addr_parse(argv[1], &sdu.dest);
+	if (rc != EOK) {
+		printf(NAME ": Invalid address format.\n");
+		print_syntax();
+		return 1;
+	}
+
+	sdu.seq_no = 1;
+	sdu.data = (void *) "foo";
+	sdu.size = 3;
+
+	/* Determine source address */
+	rc = inetping_get_srcaddr(&sdu.dest, &sdu.src);
+	if (rc != EOK) {
+		printf(NAME ": Failed determining source address.\n");
+		return 1;
+	}
+
+	rc = inetping_send(&sdu);
+	if (rc != EOK) {
+		printf(NAME ": Failed sending echo request (%d).\n", rc);
+		return 1;
+	}
+
+	fibril_mutex_lock(&done_lock);
+	rc = fibril_condvar_wait_timeout(&done_cv, &done_lock, PING_TIMEOUT);
+	fibril_mutex_unlock(&done_lock);
+
+	if (rc == ETIMEOUT) {
+		printf(NAME ": Echo request timed out.\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision ffa89125d041d58392d67a3df0e52564a07cee35)
+++ uspace/lib/c/Makefile	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -89,4 +89,5 @@
 	generic/inet.c \
 	generic/inetcfg.c \
+	generic/inetping.c \
 	generic/io/asprintf.c \
 	generic/io/io.c \
Index: uspace/lib/c/generic/inetping.c
===================================================================
--- uspace/lib/c/generic/inetping.c	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
+++ uspace/lib/c/generic/inetping.c	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <async.h>
+#include <assert.h>
+#include <errno.h>
+#include <inet/inetping.h>
+#include <ipc/inet.h>
+#include <ipc/services.h>
+#include <loc.h>
+#include <stdlib.h>
+#include <str.h>
+
+static void inetping_cb_conn(ipc_callid_t, ipc_call_t *, void *);
+static void inetping_ev_recv(ipc_callid_t, ipc_call_t *);
+
+static async_sess_t *inetping_sess = NULL;
+static inetping_ev_ops_t *inetping_ev_ops;
+
+int inetping_init(inetping_ev_ops_t *ev_ops)
+{
+	service_id_t inetping_svc;
+	int rc;
+
+	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);
+		inetping_sess = NULL;
+		return rc;
+	}
+
+	return EOK;
+}
+
+int inetping_send(inetping_sdu_t *sdu)
+{
+	async_exch_t *exch = async_exchange_begin(inetping_sess);
+
+	ipc_call_t answer;
+	aid_t req = async_send_3(exch, INETPING_SEND, sdu->src.ipv4,
+	    sdu->dest.ipv4, sdu->seq_no, &answer);
+	sysarg_t retval = async_data_write_start(exch, sdu->data, sdu->size);
+
+	async_exchange_end(exch);
+
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		return retval;
+	}
+
+	async_wait_for(req, &retval);
+	return retval;
+}
+
+int inetping_get_srcaddr(inet_addr_t *remote, inet_addr_t *local)
+{
+	sysarg_t local_addr;
+	async_exch_t *exch = async_exchange_begin(inetping_sess);
+
+	int rc = async_req_1_1(exch, INETPING_GET_SRCADDR, remote->ipv4,
+	    &local_addr);
+	async_exchange_end(exch);
+
+	if (rc != EOK)
+		return rc;
+
+	local->ipv4 = local_addr;
+	return EOK;
+}
+
+static void inetping_ev_recv(ipc_callid_t callid, ipc_call_t *call)
+{
+	int rc;
+	inetping_sdu_t sdu;
+
+	sdu.src.ipv4 = IPC_GET_ARG1(*call);
+	sdu.dest.ipv4 = IPC_GET_ARG2(*call);
+	sdu.seq_no = IPC_GET_ARG3(*call);
+
+	rc = async_data_write_accept(&sdu.data, false, 0, 0, 0, &sdu.size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	rc = inetping_ev_ops->recv(&sdu);
+	free(sdu.data);
+	async_answer_0(callid, rc);
+}
+
+static void inetping_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 INETPING_EV_RECV:
+			inetping_ev_recv(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+		}
+	}
+}
+
+/** @}
+ */
Index: uspace/lib/c/include/inet/inetping.h
===================================================================
--- uspace/lib/c/include/inet/inetping.h	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
+++ uspace/lib/c/include/inet/inetping.h	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_INET_INETPING_H_
+#define LIBC_INET_INETPING_H_
+
+#include <inet/inet.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;
+
+typedef struct inetping_ev_ops {
+	int (*recv)(inetping_sdu_t *);
+} inetping_ev_ops_t;
+
+extern int inetping_init(inetping_ev_ops_t *);
+extern int inetping_send(inetping_sdu_t *);
+extern int inetping_get_srcaddr(inet_addr_t *, inet_addr_t *);
+
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/inet.h
===================================================================
--- uspace/lib/c/include/ipc/inet.h	(revision ffa89125d041d58392d67a3df0e52564a07cee35)
+++ uspace/lib/c/include/ipc/inet.h	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -43,5 +43,7 @@
 	INET_PORT_DEFAULT = 1,
 	/** Configuration port */
-	INET_PORT_CFG
+	INET_PORT_CFG,
+	/** Ping service port */
+	INET_PORT_PING
 } inet_port_t;
 
@@ -70,4 +72,15 @@
 } inetcfg_request_t;
 
+/** Events on Inet ping port */
+typedef enum {
+	INETPING_EV_RECV = IPC_FIRST_USER_METHOD
+} inetping_event_t;
+
+/** Requests on Inet ping port */
+typedef enum {
+	INETPING_SEND = IPC_FIRST_USER_METHOD,
+	INETPING_GET_SRCADDR
+} inetping_request_t;
+
 #endif
 
Index: uspace/lib/c/include/ipc/services.h
===================================================================
--- uspace/lib/c/include/ipc/services.h	(revision ffa89125d041d58392d67a3df0e52564a07cee35)
+++ uspace/lib/c/include/ipc/services.h	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -52,6 +52,7 @@
 } services_t;
 
-#define SERVICE_NAME_INET    "net/inet"
-#define SERVICE_NAME_INETCFG "net/inetcfg"
+#define SERVICE_NAME_INET     "net/inet"
+#define SERVICE_NAME_INETCFG  "net/inetcfg"
+#define SERVICE_NAME_INETPING "net/inetping"
 
 #endif
Index: uspace/srv/inet/Makefile
===================================================================
--- uspace/srv/inet/Makefile	(revision ffa89125d041d58392d67a3df0e52564a07cee35)
+++ uspace/srv/inet/Makefile	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -36,4 +36,5 @@
 	inet_link.c \
 	inetcfg.c \
+	inetping.c \
 	pdu.c
 
Index: uspace/srv/inet/icmp.c
===================================================================
--- uspace/srv/inet/icmp.c	(revision ffa89125d041d58392d67a3df0e52564a07cee35)
+++ uspace/srv/inet/icmp.c	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -44,4 +44,5 @@
 #include "icmp_std.h"
 #include "inet.h"
+#include "inetping.h"
 #include "pdu.h"
 
@@ -49,5 +50,6 @@
 #define INET_TTL_MAX 255
 
-static int icmp_echo_request(inet_dgram_t *);
+static int icmp_recv_echo_request(inet_dgram_t *);
+static int icmp_recv_echo_reply(inet_dgram_t *);
 
 int icmp_recv(inet_dgram_t *dgram)
@@ -64,5 +66,7 @@
 	switch (type) {
 	case ICMP_ECHO_REQUEST:
-		return icmp_echo_request(dgram);
+		return icmp_recv_echo_request(dgram);
+	case ICMP_ECHO_REPLY:
+		return icmp_recv_echo_reply(dgram);
 	default:
 		break;
@@ -72,5 +76,5 @@
 }
 
-static int icmp_echo_request(inet_dgram_t *dgram)
+static int icmp_recv_echo_request(inet_dgram_t *dgram)
 {
 	icmp_echo_t *request, *reply;
@@ -80,5 +84,5 @@
 	int rc;
 
-	log_msg(LVL_DEBUG, "icmp_echo_request()");
+	log_msg(LVL_DEBUG, "icmp_recv_echo_request()");
 
 	if (dgram->size < sizeof(icmp_echo_t))
@@ -103,5 +107,5 @@
 	rdgram.src = dgram->dest;
 	rdgram.dest = dgram->src;
-	rdgram.tos = 0;
+	rdgram.tos = ICMP_TOS;
 	rdgram.data = reply;
 	rdgram.size = size;
@@ -114,4 +118,66 @@
 }
 
+static int icmp_recv_echo_reply(inet_dgram_t *dgram)
+{
+	icmp_echo_t *reply;
+	inetping_sdu_t sdu;
+	uint16_t ident;
+
+	log_msg(LVL_DEBUG, "icmp_recv_echo_reply()");
+
+	if (dgram->size < sizeof(icmp_echo_t))
+		return EINVAL;
+
+	reply = (icmp_echo_t *)dgram->data;
+
+	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);
+	ident = uint16_t_be2host(reply->ident);
+
+	return inetping_recv(ident, &sdu);
+}
+
+int icmp_ping_send(uint16_t ident, inetping_sdu_t *sdu)
+{
+	inet_dgram_t dgram;
+	icmp_echo_t *request;
+	void *rdata;
+	size_t rsize;
+	uint16_t checksum;
+	int rc;
+
+	rsize = sizeof(icmp_echo_t) + sdu->size;
+	rdata = calloc(rsize, 1);
+	if (rdata == NULL)
+		return ENOMEM;
+
+	request = (icmp_echo_t *)rdata;
+
+	request->type = ICMP_ECHO_REQUEST;
+	request->code = 0;
+	request->checksum = 0;
+	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);
+
+	checksum = inet_checksum_calc(INET_CHECKSUM_INIT, rdata, rsize);
+	request->checksum = host2uint16_t_be(checksum);
+
+	dgram.src = sdu->src;
+	dgram.dest = sdu->dest;
+	dgram.tos = ICMP_TOS;
+	dgram.data = rdata;
+	dgram.size = rsize;
+
+	rc = inet_route_packet(&dgram, IP_PROTO_ICMP, INET_TTL_MAX, 0);
+
+	free(rdata);
+	return rc;
+}
+
 /** @}
  */
Index: uspace/srv/inet/icmp.h
===================================================================
--- uspace/srv/inet/icmp.h	(revision ffa89125d041d58392d67a3df0e52564a07cee35)
+++ uspace/srv/inet/icmp.h	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -41,4 +41,5 @@
 
 extern int icmp_recv(inet_dgram_t *);
+extern int icmp_ping_send(uint16_t, inetping_sdu_t *);
 
 #endif
Index: uspace/srv/inet/icmp_std.h
===================================================================
--- uspace/srv/inet/icmp_std.h	(revision ffa89125d041d58392d67a3df0e52564a07cee35)
+++ uspace/srv/inet/icmp_std.h	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -42,4 +42,7 @@
 #define IP_PROTO_ICMP 1
 
+/** Type of service used for ICMP */
+#define ICMP_TOS	0
+
 /** ICMP message type */
 enum icmp_type {
Index: uspace/srv/inet/inet.c
===================================================================
--- uspace/srv/inet/inet.c	(revision ffa89125d041d58392d67a3df0e52564a07cee35)
+++ uspace/srv/inet/inet.c	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -52,4 +52,5 @@
 #include "inet.h"
 #include "inetcfg.h"
+#include "inetping.h"
 #include "inet_link.h"
 
@@ -85,4 +86,11 @@
 	rc = loc_service_register_with_iface(SERVICE_NAME_INETCFG, &sid,
 	    INET_PORT_CFG);
+	if (rc != EOK) {
+		log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
+		return EEXIST;
+	}
+
+	rc = loc_service_register_with_iface(SERVICE_NAME_INETPING, &sid,
+	    INET_PORT_PING);
 	if (rc != EOK) {
 		log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
@@ -134,6 +142,5 @@
 }
 
-static int inet_get_srcaddr(inet_client_t *client, inet_addr_t *remote,
-    uint8_t tos, inet_addr_t *local)
+int inet_get_srcaddr(inet_addr_t *remote, uint8_t tos, inet_addr_t *local)
 {
 	inet_addrobj_t *addr;
@@ -163,5 +170,5 @@
 	local.ipv4 = 0;
 
-	rc = inet_get_srcaddr(client, &remote, tos, &local);
+	rc = inet_get_srcaddr(&remote, tos, &local);
 	async_answer_1(callid, rc, local.ipv4);
 }
@@ -287,4 +294,7 @@
 		inet_cfg_conn(iid, icall, arg);
 		break;
+	case INET_PORT_PING:
+		inetping_conn(iid, icall, arg);
+		break;
 	default:
 		async_answer_0(iid, ENOTSUP);
Index: uspace/srv/inet/inet.h
===================================================================
--- uspace/srv/inet/inet.h	(revision ffa89125d041d58392d67a3df0e52564a07cee35)
+++ uspace/srv/inet/inet.h	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -50,4 +50,14 @@
 	link_t client_list;
 } inet_client_t;
+
+/** Inetping Client */
+typedef struct {
+	/** Callback session */
+	async_sess_t *sess;
+	/** Session identifier */
+	uint16_t ident;
+	/** Link to client list */
+	link_t client_list;
+} inetping_client_t;
 
 /** Host address */
@@ -115,7 +125,17 @@
 } inet_addrobj_t;
 
+typedef struct {
+	inet_addr_t src;
+	inet_addr_t dest;
+	uint16_t seq_no;
+	void *data;
+	size_t size;
+} inetping_sdu_t;
+
 extern int inet_ev_recv(inet_client_t *, inet_dgram_t *);
 extern int inet_recv_packet(inet_packet_t *);
 extern int inet_route_packet(inet_dgram_t *, uint8_t, uint8_t, int);
+extern int inet_get_srcaddr(inet_addr_t *, uint8_t, inet_addr_t *);
+
 
 #endif
Index: uspace/srv/inet/inetping.c
===================================================================
--- uspace/srv/inet/inetping.c	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
+++ uspace/srv/inet/inetping.c	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup inet
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#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 "icmp.h"
+#include "icmp_std.h"
+#include "inet.h"
+#include "inetping.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 inetping_ident = 0;
+
+static inetping_client_t *inetping_client_find(uint16_t);
+
+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, inet_addr_t *remote,
+    inet_addr_t *local)
+{
+	return inet_get_srcaddr(remote, ICMP_TOS, local);
+}
+
+int inetping_recv(uint16_t ident, inetping_sdu_t *sdu)
+{
+	inetping_client_t *client;
+	async_exch_t *exch;
+	ipc_call_t answer;
+
+	client = inetping_client_find(ident);
+	if (client == NULL) {
+		log_msg(LVL_DEBUG, "Unknown ICMP ident. Dropping.");
+		return ENOENT;
+	}
+
+	exch = async_exchange_begin(client->sess);
+
+	aid_t req = async_send_3(exch, INETPING_EV_RECV, sdu->src.ipv4,
+	    sdu->dest.ipv4, sdu->seq_no, &answer);
+	int rc = async_data_write_start(exch, sdu->data, sdu->size);
+	async_exchange_end(exch);
+
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		return rc;
+	}
+
+	sysarg_t retval;
+	async_wait_for(req, &retval);
+	if (retval != EOK) {
+		return retval;
+	}
+
+	return EOK;
+}
+
+static void inetping_send_srv(inetping_client_t *client, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	inetping_sdu_t sdu;
+	int rc;
+
+	log_msg(LVL_DEBUG, "inetping_send_srv()");
+
+	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.ipv4 = IPC_GET_ARG1(*call);
+	sdu.dest.ipv4 = IPC_GET_ARG2(*call);
+	sdu.seq_no = IPC_GET_ARG3(*call);
+
+	rc = inetping_send(client, &sdu);
+	free(sdu.data);
+
+	async_answer_0(callid, rc);
+}
+
+static void inetping_get_srcaddr_srv(inetping_client_t *client,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	inet_addr_t remote;
+	inet_addr_t local;
+	int rc;
+
+	log_msg(LVL_DEBUG, "inetping_get_srcaddr_srv()");
+
+	remote.ipv4 = IPC_GET_ARG1(*call);
+	local.ipv4 = 0;
+
+	rc = inetping_get_srcaddr(client, &remote, &local);
+	async_answer_1(callid, rc, local.ipv4);
+}
+
+static int inetping_client_init(inetping_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 = ++inetping_ident;
+	list_append(&client->client_list, &client_list);
+	fibril_mutex_unlock(&client_list_lock);
+
+	return EOK;
+}
+
+static void inetping_client_fini(inetping_client_t *client)
+{
+	async_hangup(client->sess);
+	client->sess = NULL;
+
+	fibril_mutex_lock(&client_list_lock);
+	list_remove(&client->client_list);
+	fibril_mutex_unlock(&client_list_lock);
+}
+
+static inetping_client_t *inetping_client_find(uint16_t ident)
+{
+	fibril_mutex_lock(&client_list_lock);
+
+	list_foreach(client_list, link) {
+		inetping_client_t *client = list_get_instance(link,
+		    inetping_client_t, client_list);
+
+		if (client->ident == ident) {
+			fibril_mutex_unlock(&client_list_lock);
+			return client;
+		}
+	}
+
+	fibril_mutex_unlock(&client_list_lock);
+	return NULL;
+}
+
+void inetping_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	inetping_client_t client;
+	int rc;
+
+	log_msg(LVL_DEBUG, "inetping_conn()");
+
+	/* Accept the connection */
+	async_answer_0(iid, EOK);
+
+	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 */
+			async_answer_0(callid, EOK);
+			break;
+		}
+
+		switch (method) {
+		case INETPING_SEND:
+			inetping_send_srv(&client, callid, &call);
+			break;
+		case INETPING_GET_SRCADDR:
+			inetping_get_srcaddr_srv(&client, callid, &call);
+			break;
+		default:
+			async_answer_0(callid, EINVAL);
+		}
+	}
+
+	inetping_client_fini(&client);
+}
+
+/** @}
+ */
Index: uspace/srv/inet/inetping.h
===================================================================
--- uspace/srv/inet/inetping.h	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
+++ uspace/srv/inet/inetping.h	(revision 6428115342e73b6e994e17c494a77a400a7c1ba8)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup inet
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#ifndef INETPING_H_
+#define INETPING_H_
+
+extern void inetping_conn(ipc_callid_t, ipc_call_t *, void *);
+extern int inetping_recv(uint16_t, inetping_sdu_t *);
+
+#endif
+
+/** @}
+ */
