Index: uspace/srv/net/inetsrv/ndp.c
===================================================================
--- uspace/srv/net/inetsrv/ndp.c	(revision 671b5465f603d36fcb7a767de9a968fd32b0076b)
+++ uspace/srv/net/inetsrv/ndp.c	(revision 671b5465f603d36fcb7a767de9a968fd32b0076b)
@@ -0,0 +1,169 @@
+/*
+ * 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 ethip
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#include <errno.h>
+#include <mem.h>
+#include <malloc.h>
+#include <net/socket_codes.h>
+#include "ntrans.h"
+#include "addrobj.h"
+#include "pdu.h"
+#include "inet_link.h"
+#include "ndp.h"
+
+/** Time to wait for NDP reply in microseconds */
+#define NDP_REQUEST_TIMEOUT  (3 * 1000 * 1000)
+
+static addr48_t solicited_node_mac =
+    {0x33, 0x33, 0xff, 0, 0, 0};
+
+static addr128_t solicited_node_ip =
+    {0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0xff, 0, 0, 0};
+
+static void ndp_solicited_node_mac(addr128_t ip_addr, addr48_t mac_addr)
+{
+	memcpy(mac_addr, solicited_node_mac, 3);
+	memcpy(mac_addr + 3, ip_addr + 13, 3);
+}
+
+static void ndp_solicited_node_ip(addr128_t ip_addr,
+    addr128_t ip_solicited)
+{
+	memcpy(ip_solicited, solicited_node_ip, 13);
+	memcpy(ip_solicited + 13, ip_addr + 13, 3);
+}
+
+static int ndp_send_packet(inet_link_t *link, ndp_packet_t *packet)
+{
+	inet_dgram_t dgram;
+	ndp_pdu_encode(packet, &dgram);
+	
+	inet_link_send_dgram6(link, packet->target_hw_addr, &dgram,
+	    IP_PROTO_ICMPV6, INET6_HOP_LIMIT_MAX, 0);
+	
+	free(dgram.data);
+	
+	return EOK;
+}
+
+static int ndp_router_advertisement(inet_dgram_t *dgram, inet_addr_t *router)
+{
+	// FIXME TODO
+	return ENOTSUP;
+}
+
+int ndp_received(inet_dgram_t *dgram)
+{
+	ndp_packet_t packet;
+	int rc = ndp_pdu_decode(dgram, &packet);
+	if (rc != EOK)
+		return rc;
+	
+	inet_addr_t sender;
+	inet_addr_set6(packet.sender_proto_addr, &sender);
+	
+	inet_addr_t target;
+	inet_addr_set6(packet.target_proto_addr, &target);
+	
+	inet_addrobj_t *laddr;
+	
+	switch (packet.opcode) {
+	case ICMPV6_NEIGHBOUR_SOLICITATION:
+		laddr = inet_addrobj_find(&target, iaf_addr);
+		if (laddr != NULL) {
+			rc = ntrans_add(packet.sender_proto_addr,
+			    packet.sender_hw_addr);
+			if (rc != EOK)
+				return rc;
+			
+			ndp_packet_t reply;
+			
+			reply.opcode = ICMPV6_NEIGHBOUR_ADVERTISEMENT;
+			addr48(laddr->ilink->mac, reply.sender_hw_addr);
+			addr128(packet.target_proto_addr, reply.sender_proto_addr);
+			addr48(packet.sender_hw_addr, reply.target_hw_addr);
+			addr128(packet.sender_proto_addr, reply.target_proto_addr);
+			
+			ndp_send_packet(laddr->ilink, &reply);
+		}
+		
+		break;
+	case ICMPV6_NEIGHBOUR_ADVERTISEMENT:
+		laddr = inet_addrobj_find(&dgram->dest, iaf_addr);
+		if (laddr != NULL)
+			return ntrans_add(packet.sender_proto_addr,
+			    packet.sender_hw_addr);
+		
+		break;
+	case ICMPV6_ROUTER_ADVERTISEMENT:
+		return ndp_router_advertisement(dgram, &sender);
+	default:
+		return ENOTSUP;
+	}
+	
+	return EOK;
+}
+
+int ndp_translate(addr128_t src_addr, addr128_t ip_addr, addr48_t mac_addr,
+    inet_link_t *ilink)
+{
+	if (!ilink->mac_valid) {
+		/* The link does not support NDP */
+		memset(mac_addr, 0, 6);
+		return EOK;
+	}
+	
+	int rc = ntrans_lookup(ip_addr, mac_addr);
+	if (rc == EOK)
+		return EOK;
+	
+	ndp_packet_t packet;
+	
+	packet.opcode = ICMPV6_NEIGHBOUR_SOLICITATION;
+	addr48(ilink->mac, packet.sender_hw_addr);
+	addr128(src_addr, packet.sender_proto_addr);
+	addr128(ip_addr, packet.solicited_ip);
+	ndp_solicited_node_mac(ip_addr, packet.target_hw_addr);
+	ndp_solicited_node_ip(ip_addr, packet.target_proto_addr);
+	
+	rc = ndp_send_packet(ilink, &packet);
+	if (rc != EOK)
+		return rc;
+	
+	(void) ntrans_wait_timeout(NDP_REQUEST_TIMEOUT);
+	
+	return ntrans_lookup(ip_addr, mac_addr);
+}
Index: uspace/srv/net/inetsrv/ndp.h
===================================================================
--- uspace/srv/net/inetsrv/ndp.h	(revision 671b5465f603d36fcb7a767de9a968fd32b0076b)
+++ uspace/srv/net/inetsrv/ndp.h	(revision 671b5465f603d36fcb7a767de9a968fd32b0076b)
@@ -0,0 +1,69 @@
+/*
+ * 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 ethip
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#ifndef ETH_NDP_H_
+#define ETH_NDP_H_
+
+#include <sys/types.h>
+#include <inet/addr.h>
+#include "inetsrv.h"
+#include "icmpv6_std.h"
+
+typedef enum icmpv6_type ndp_opcode_t;
+
+/** NDP packet (for 48-bit MAC addresses)
+ *
+ * Internal representation
+ */
+typedef struct {
+	/** Opcode */
+	ndp_opcode_t opcode;
+	/** Sender hardware address */
+	addr48_t sender_hw_addr;
+	/** Sender protocol address */
+	addr128_t sender_proto_addr;
+	/** Target hardware address */
+	addr48_t target_hw_addr;
+	/** Target protocol address */
+	addr128_t target_proto_addr;
+	/** Solicited IPv6 address */
+	addr128_t solicited_ip;
+} ndp_packet_t;
+
+extern int ndp_received(inet_dgram_t *);
+extern int ndp_translate(addr128_t, addr128_t, addr48_t, inet_link_t *);
+
+#endif
Index: uspace/srv/net/inetsrv/ntrans.c
===================================================================
--- uspace/srv/net/inetsrv/ntrans.c	(revision 671b5465f603d36fcb7a767de9a968fd32b0076b)
+++ uspace/srv/net/inetsrv/ntrans.c	(revision 671b5465f603d36fcb7a767de9a968fd32b0076b)
@@ -0,0 +1,131 @@
+/*
+ * 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 inet
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#include <adt/list.h>
+#include <errno.h>
+#include <fibril_synch.h>
+#include <inet/iplink_srv.h>
+#include <stdlib.h>
+#include "ntrans.h"
+
+/** Address translation list (of inet_ntrans_t) */
+static FIBRIL_MUTEX_INITIALIZE(ntrans_list_lock);
+static LIST_INITIALIZE(ntrans_list);
+static FIBRIL_CONDVAR_INITIALIZE(ntrans_cv);
+
+static inet_ntrans_t *ntrans_find(addr128_t ip_addr)
+{
+	list_foreach(ntrans_list, link) {
+		inet_ntrans_t *ntrans = list_get_instance(link,
+		    inet_ntrans_t, ntrans_list);
+
+		if (addr128_compare(ntrans->ip_addr, ip_addr))
+			return ntrans;
+	}
+
+	return NULL;
+}
+
+int ntrans_add(addr128_t ip_addr, addr48_t mac_addr)
+{
+	inet_ntrans_t *ntrans;
+	inet_ntrans_t *prev;
+
+	ntrans = calloc(1, sizeof(inet_ntrans_t));
+	if (ntrans == NULL)
+		return ENOMEM;
+
+	addr128(ip_addr, ntrans->ip_addr);
+	addr48(mac_addr, ntrans->mac_addr);
+
+	fibril_mutex_lock(&ntrans_list_lock);
+	prev = ntrans_find(ip_addr);
+	if (prev != NULL) {
+		list_remove(&prev->ntrans_list);
+		free(prev);
+	}
+
+	list_append(&ntrans->ntrans_list, &ntrans_list);
+	fibril_mutex_unlock(&ntrans_list_lock);
+	fibril_condvar_broadcast(&ntrans_cv);
+
+	return EOK;
+}
+
+int ntrans_remove(addr128_t ip_addr)
+{
+	inet_ntrans_t *ntrans;
+
+	fibril_mutex_lock(&ntrans_list_lock);
+	ntrans = ntrans_find(ip_addr);
+	if (ntrans == NULL) {
+		fibril_mutex_unlock(&ntrans_list_lock);
+		return ENOENT;
+	}
+
+	list_remove(&ntrans->ntrans_list);
+	fibril_mutex_unlock(&ntrans_list_lock);
+	free(ntrans);
+
+	return EOK;
+}
+
+int ntrans_lookup(addr128_t ip_addr, addr48_t mac_addr)
+{
+	fibril_mutex_lock(&ntrans_list_lock);
+	inet_ntrans_t *ntrans = ntrans_find(ip_addr);
+	if (ntrans == NULL) {
+		fibril_mutex_unlock(&ntrans_list_lock);
+		return ENOENT;
+	}
+	
+	fibril_mutex_unlock(&ntrans_list_lock);
+	addr48(ntrans->mac_addr, mac_addr);
+	return EOK;
+}
+
+int ntrans_wait_timeout(suseconds_t timeout)
+{
+	fibril_mutex_lock(&ntrans_list_lock);
+	int rc = fibril_condvar_wait_timeout(&ntrans_cv, &ntrans_list_lock,
+	    timeout);
+	fibril_mutex_unlock(&ntrans_list_lock);
+	
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/srv/net/inetsrv/ntrans.h
===================================================================
--- uspace/srv/net/inetsrv/ntrans.h	(revision 671b5465f603d36fcb7a767de9a968fd32b0076b)
+++ uspace/srv/net/inetsrv/ntrans.h	(revision 671b5465f603d36fcb7a767de9a968fd32b0076b)
@@ -0,0 +1,58 @@
+/*
+ * 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 inet
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#ifndef NTRANS_H_
+#define NTRANS_H_
+
+#include <inet/iplink_srv.h>
+#include <inet/addr.h>
+
+/** Address translation table element */
+typedef struct {
+	link_t ntrans_list;
+	addr128_t ip_addr;
+	addr48_t mac_addr;
+} inet_ntrans_t;
+
+extern int ntrans_add(addr128_t, addr48_t);
+extern int ntrans_remove(addr128_t);
+extern int ntrans_lookup(addr128_t, addr48_t);
+extern int ntrans_wait_timeout(suseconds_t);
+
+#endif
+
+/** @}
+ */
