Index: uspace/srv/ethip/Makefile
===================================================================
--- uspace/srv/ethip/Makefile	(revision 081971b66ef5a553c4097cd202fc6ede83f82391)
+++ uspace/srv/ethip/Makefile	(revision 87e5658cd0c068690174e8476d75fbb9ba81f2ee)
@@ -31,4 +31,5 @@
 
 SOURCES = \
+	arp.c \
 	ethip.c \
 	ethip_nic.c \
Index: uspace/srv/ethip/arp.c
===================================================================
--- uspace/srv/ethip/arp.c	(revision 87e5658cd0c068690174e8476d75fbb9ba81f2ee)
+++ uspace/srv/ethip/arp.c	(revision 87e5658cd0c068690174e8476d75fbb9ba81f2ee)
@@ -0,0 +1,118 @@
+/*
+ * 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 <errno.h>
+#include <io/log.h>
+#include <inet/iplink_srv.h>
+#include <stdlib.h>
+
+#include "arp.h"
+#include "ethip.h"
+#include "ethip_nic.h"
+#include "pdu.h"
+#include "std.h"
+
+#define MY_IPV4_ADDR ( (192 << 24) | (168 << 16) | (0 << 8) | 4U )
+#define MY_ETH_ADDR 0xaafeedfaceee
+
+static int arp_send_packet(ethip_nic_t *nic, arp_eth_packet_t *packet);
+
+void arp_received(ethip_nic_t *nic, eth_frame_t *frame)
+{
+	int rc;
+	arp_eth_packet_t packet;
+	arp_eth_packet_t reply;
+
+	log_msg(LVL_DEBUG, "arp_received()");
+
+	rc = arp_pdu_decode(frame->data, frame->size, &packet);
+	if (rc != EOK)
+		return;
+
+	log_msg(LVL_DEBUG, "ARP PDU decoded, opcode=%d, tpa=%x",
+	    packet.opcode, packet.target_proto_addr.ipv4);
+	if (packet.opcode == aop_request &&
+	    packet.target_proto_addr.ipv4 == MY_IPV4_ADDR) {
+		log_msg(LVL_DEBUG, "Request on my address");
+
+		reply.opcode = aop_reply;
+		reply.sender_hw_addr.addr = MY_ETH_ADDR;
+		reply.sender_proto_addr.ipv4 = MY_IPV4_ADDR;
+		reply.target_hw_addr = packet.sender_hw_addr;
+		reply.target_proto_addr = packet.sender_proto_addr;
+
+		arp_send_packet(nic, &reply);
+	}
+}
+
+static int arp_send_packet(ethip_nic_t *nic, arp_eth_packet_t *packet)
+{
+	int rc;
+	void *pdata;
+	size_t psize;
+
+	eth_frame_t frame;
+	void *fdata;
+	size_t fsize;
+
+	log_msg(LVL_DEBUG, "arp_send_packet()");
+
+	rc = arp_pdu_encode(packet, &pdata, &psize);
+	if (rc != EOK)
+		return rc;
+
+	frame.dest.addr = packet->target_hw_addr.addr;
+	frame.src.addr =  packet->sender_hw_addr.addr;
+	frame.etype_len = ETYPE_ARP;
+	frame.data = pdata;
+	frame.size = psize;
+
+	rc = eth_pdu_encode(&frame, &fdata, &fsize);
+	if (rc != EOK) {
+		free(pdata);
+		return rc;
+	}
+
+	rc = ethip_nic_send(nic, fdata, fsize);
+	free(fdata);
+	free(pdata);
+
+	return rc;
+
+}
+
+/** @}
+ */
Index: uspace/srv/ethip/arp.h
===================================================================
--- uspace/srv/ethip/arp.h	(revision 87e5658cd0c068690174e8476d75fbb9ba81f2ee)
+++ uspace/srv/ethip/arp.h	(revision 87e5658cd0c068690174e8476d75fbb9ba81f2ee)
@@ -0,0 +1,48 @@
+/*
+ * 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 ARP_H_
+#define ARP_H_
+
+#include <inet/iplink_srv.h>
+#include "ethip.h"
+
+extern void arp_received(ethip_nic_t *, eth_frame_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/ethip/ethip.c
===================================================================
--- uspace/srv/ethip/ethip.c	(revision 081971b66ef5a553c4097cd202fc6ede83f82391)
+++ uspace/srv/ethip/ethip.c	(revision 87e5658cd0c068690174e8476d75fbb9ba81f2ee)
@@ -45,4 +45,5 @@
 #include <stdlib.h>
 
+#include "arp.h"
 #include "ethip.h"
 #include "ethip_nic.h"
@@ -204,11 +205,21 @@
 	}
 
-	log_msg(LVL_DEBUG, " - construct SDU");
-	sdu.lsrc.ipv4 = (192 << 24) | (168 << 16) | (0 << 8) | 1;
-	sdu.ldest.ipv4 = (192 << 24) | (168 << 16) | (0 << 8) | 4;
-	sdu.data = frame.data;
-	sdu.size = frame.size;
-	log_msg(LVL_DEBUG, " - call iplink_ev_recv");
-	rc = iplink_ev_recv(&nic->iplink, &sdu);
+	switch (frame.etype_len) {
+	case ETYPE_ARP:
+		arp_received(nic, &frame);
+		break;
+	case ETYPE_IP:
+		log_msg(LVL_DEBUG, " - construct SDU");
+		sdu.lsrc.ipv4 = (192 << 24) | (168 << 16) | (0 << 8) | 1;
+		sdu.ldest.ipv4 = (192 << 24) | (168 << 16) | (0 << 8) | 4;
+		sdu.data = frame.data;
+		sdu.size = frame.size;
+		log_msg(LVL_DEBUG, " - call iplink_ev_recv");
+		rc = iplink_ev_recv(&nic->iplink, &sdu);
+		break;
+	default:
+		log_msg(LVL_DEBUG, "Unknown ethertype %" PRIu16,
+		    frame.etype_len);
+	}
 
 	free(frame.data);
Index: uspace/srv/ethip/ethip.h
===================================================================
--- uspace/srv/ethip/ethip.h	(revision 081971b66ef5a553c4097cd202fc6ede83f82391)
+++ uspace/srv/ethip/ethip.h	(revision 87e5658cd0c068690174e8476d75fbb9ba81f2ee)
@@ -74,7 +74,31 @@
 } eth_frame_t;
 
+/** ARP opcode */
+typedef enum {
+	/** Request */
+	aop_request,
+	/** Reply */
+	aop_reply
+} arp_opcode_t;
+
+/** ARP packet (for 48-bit MAC addresses and IPv4)
+ *
+ * Internal representation
+ */
+typedef struct {
+	/** Opcode */
+	arp_opcode_t opcode;
+	/** Sender hardware address */
+	mac48_addr_t sender_hw_addr;
+	/** Sender protocol address */
+	iplink_srv_addr_t sender_proto_addr;
+	/** Target hardware address */
+	mac48_addr_t target_hw_addr;
+	/** Target protocol address */
+	iplink_srv_addr_t target_proto_addr;
+} arp_eth_packet_t;
+
 extern int ethip_iplink_init(ethip_nic_t *);
 extern int ethip_received(iplink_srv_t *, void *, size_t);
-
 
 #endif
Index: uspace/srv/ethip/pdu.c
===================================================================
--- uspace/srv/ethip/pdu.c	(revision 081971b66ef5a553c4097cd202fc6ede83f82391)
+++ uspace/srv/ethip/pdu.c	(revision 87e5658cd0c068690174e8476d75fbb9ba81f2ee)
@@ -140,4 +140,106 @@
 }
 
+/** Encode ARP PDU. */
+int arp_pdu_encode(arp_eth_packet_t *packet, void **rdata, size_t *rsize)
+{
+	void *data;
+	size_t size;
+	arp_eth_packet_fmt_t *pfmt;
+	uint16_t fopcode;
+
+	log_msg(LVL_DEBUG, "arp_pdu_encode()");
+
+	size = sizeof(arp_eth_packet_fmt_t);
+
+	data = calloc(size, 1);
+	if (data == NULL)
+		return ENOMEM;
+
+	pfmt = (arp_eth_packet_fmt_t *)data;
+
+	switch (packet->opcode) {
+	case aop_request: fopcode = AOP_REQUEST; break;
+	case aop_reply: fopcode = AOP_REPLY; break;
+	default:
+		assert(false);
+		fopcode = 0;
+	}
+
+	pfmt->hw_addr_space = host2uint16_t_be(AHRD_ETHERNET);
+	pfmt->proto_addr_space = host2uint16_t_be(ETYPE_IP);
+	pfmt->hw_addr_size = ETH_ADDR_SIZE;
+	pfmt->proto_addr_size = IPV4_ADDR_SIZE;
+	pfmt->opcode = host2uint16_t_be(fopcode);
+	mac48_encode(&packet->sender_hw_addr, pfmt->sender_hw_addr);
+	pfmt->sender_proto_addr =
+	    host2uint32_t_be(packet->sender_proto_addr.ipv4);
+	mac48_encode(&packet->target_hw_addr, pfmt->target_hw_addr);
+	pfmt->target_proto_addr =
+	    host2uint32_t_be(packet->target_proto_addr.ipv4);
+
+	*rdata = data;
+	*rsize = size;
+	return EOK;
+}
+
+/** Decode ARP PDU. */
+int arp_pdu_decode(void *data, size_t size, arp_eth_packet_t *packet)
+{
+	arp_eth_packet_fmt_t *pfmt;
+
+	log_msg(LVL_DEBUG, "arp_pdu_decode()");
+
+	if (size < sizeof(arp_eth_packet_fmt_t)) {
+		log_msg(LVL_DEBUG, "ARP PDU too short (%zu)", size);
+		return EINVAL;
+	}
+
+	pfmt = (arp_eth_packet_fmt_t *)data;
+
+	if (uint16_t_be2host(pfmt->hw_addr_space) != AHRD_ETHERNET) {
+		log_msg(LVL_DEBUG, "HW address space != %u (%" PRIu16 ")",
+		    AHRD_ETHERNET, uint16_t_be2host(pfmt->hw_addr_space));
+		return EINVAL;
+	}
+
+	if (uint16_t_be2host(pfmt->proto_addr_space) != ETYPE_IP) {
+		log_msg(LVL_DEBUG, "Proto address space != %u (%" PRIu16 ")",
+		    ETYPE_IP, uint16_t_be2host(pfmt->proto_addr_space));
+		return EINVAL;
+	}
+
+	if (pfmt->hw_addr_size != ETH_ADDR_SIZE) {
+		log_msg(LVL_DEBUG, "HW address size != %zu (%zu)",
+		    (size_t)ETH_ADDR_SIZE, (size_t)pfmt->hw_addr_size);
+		return EINVAL;
+	}
+
+	if (pfmt->proto_addr_size != IPV4_ADDR_SIZE) {
+		log_msg(LVL_DEBUG, "Proto address size != %zu (%zu)",
+		    (size_t)IPV4_ADDR_SIZE, (size_t)pfmt->proto_addr_size);
+		return EINVAL;
+	}
+
+	switch (uint16_t_be2host(pfmt->opcode)) {
+	case AOP_REQUEST: packet->opcode = aop_request; break;
+	case AOP_REPLY: packet->opcode = aop_reply; break;
+	default:
+		log_msg(LVL_DEBUG, "Invalid ARP opcode (%" PRIu16 ")",
+		    uint16_t_be2host(pfmt->opcode));
+		return EINVAL;
+	}
+
+	mac48_decode(pfmt->sender_hw_addr, &packet->sender_hw_addr);
+	packet->sender_proto_addr.ipv4 =
+	    uint32_t_be2host(pfmt->sender_proto_addr);
+	mac48_decode(pfmt->target_hw_addr, &packet->target_hw_addr);
+	packet->target_proto_addr.ipv4 =
+	    uint32_t_be2host(pfmt->target_proto_addr);
+	log_msg(LVL_DEBUG, "packet->tpa = %x\n", pfmt->target_proto_addr);
+
+	return EOK;
+}
+
+
 /** @}
  */
Index: uspace/srv/ethip/pdu.h
===================================================================
--- uspace/srv/ethip/pdu.h	(revision 081971b66ef5a553c4097cd202fc6ede83f82391)
+++ uspace/srv/ethip/pdu.h	(revision 87e5658cd0c068690174e8476d75fbb9ba81f2ee)
@@ -40,6 +40,8 @@
 #include "ethip.h"
 
-int eth_pdu_encode(eth_frame_t *frame, void **rdata, size_t *rsize);
-int eth_pdu_decode(void *data, size_t size, eth_frame_t *frame);
+extern int eth_pdu_encode(eth_frame_t *, void **, size_t *);
+extern int eth_pdu_decode(void *, size_t, eth_frame_t *);
+extern int arp_pdu_encode(arp_eth_packet_t *, void **, size_t *);
+extern int arp_pdu_decode(void *, size_t, arp_eth_packet_t *);
 
 #endif
Index: uspace/srv/ethip/std.h
===================================================================
--- uspace/srv/ethip/std.h	(revision 081971b66ef5a553c4097cd202fc6ede83f82391)
+++ uspace/srv/ethip/std.h	(revision 87e5658cd0c068690174e8476d75fbb9ba81f2ee)
@@ -40,18 +40,55 @@
 #include <sys/types.h>
 
+#define ETH_ADDR_SIZE 6
+#define IPV4_ADDR_SIZE 4
+#define ETH_FRAME_MIN_SIZE 60
+
 /** Ethernet frame header */
 typedef struct {
 	/** Destination Address */
-	uint8_t dest[6];
+	uint8_t dest[ETH_ADDR_SIZE];
 	/** Source Address */
-	uint8_t src[6];
+	uint8_t src[ETH_ADDR_SIZE];
 	/** Ethertype or Length */
 	uint16_t etype_len;
 } eth_header_t;
 
+/** ARP packet format (for 48-bit MAC addresses and IPv4) */
+typedef struct {
+	/** Hardware address space */
+	uint16_t hw_addr_space;
+	/** Protocol address space */
+	uint16_t proto_addr_space;
+	/** Hardware address size */
+	uint8_t hw_addr_size;
+	/** Protocol address size */
+	uint8_t proto_addr_size;
+	/** Opcode */
+	uint16_t opcode;
+	/** Sender hardware address */
+	uint8_t sender_hw_addr[ETH_ADDR_SIZE];
+	/** Sender protocol address */
+	uint32_t sender_proto_addr;
+	/** Target hardware address */
+	uint8_t target_hw_addr[ETH_ADDR_SIZE];
+	/** Target protocol address */
+	uint32_t target_proto_addr;
+} __attribute__((packed)) arp_eth_packet_fmt_t;
+
+enum arp_opcode_fmt {
+	AOP_REQUEST = 1,
+	AOP_REPLY   = 2
+};
+
+enum arp_hw_addr_space {
+	AHRD_ETHERNET = 1
+};
+
 /** IP Ethertype */
-#define ETYPE_IP	0x0800
+enum ether_type {
+	ETYPE_ARP = 0x0806,
+	ETYPE_IP  = 0x0800
+};
 
-#define ETH_FRAME_MIN_SIZE 60
 
 #endif
