Index: uspace/app/netecho/print_error.c
===================================================================
--- uspace/app/netecho/print_error.c	(revision e3c3172de8f6c4741dd8c769b65f646f797b7da8)
+++ uspace/app/netecho/print_error.c	(revision bea023b9b8202ba19f790a340e59e36be213fadf)
@@ -164,5 +164,5 @@
 	case EDESTADDRREQ:
 		fprintf(output, "Destination address required (%d) error", error_code);
-	case TRY_AGAIN:
+	case EAGAIN:
 		fprintf(output, "Try again (%d) error", error_code);
 	default:
Index: uspace/lib/c/generic/adt/char_map.c
===================================================================
--- uspace/lib/c/generic/adt/char_map.c	(revision e3c3172de8f6c4741dd8c769b65f646f797b7da8)
+++ uspace/lib/c/generic/adt/char_map.c	(revision bea023b9b8202ba19f790a340e59e36be213fadf)
@@ -90,8 +90,8 @@
 	}
 
-	map->items[map->next]->c = * identifier;
-	++ identifier;
-	++ map->next;
-	if ((length > 1) || ((length == 0) && (*identifier))) {
+	map->items[map->next]->c = *identifier;
+	identifier++;
+	map->next++;
+	if ((length > 1) || ((length == 0) && *identifier)) {
 		map->items[map->next - 1]->value = CHAR_MAP_NULL;
 		return char_map_add_item(map->items[map->next - 1], identifier,
@@ -142,14 +142,13 @@
     const int value)
 {
-	if (char_map_is_valid(map) && (identifier) &&
-	    ((length) || (*identifier))) {
+	if (char_map_is_valid(map) && identifier && (length || *identifier)) {
 		int index;
 
-		for (index = 0; index < map->next; ++ index) {
+		for (index = 0; index < map->next; index++) {
 			if (map->items[index]->c != *identifier)
 				continue;
 				
-			++ identifier;
-			if((length > 1) || ((length == 0) && (*identifier))) {
+			identifier++;
+			if((length > 1) || ((length == 0) && *identifier)) {
 				return char_map_add(map->items[index],
 				    identifier, length ? length - 1 : 0, value);
@@ -178,5 +177,5 @@
 
 		map->magic = 0;
-		for (index = 0; index < map->next; ++index)
+		for (index = 0; index < map->next; index++)
 			char_map_destroy(map->items[index]);
 
@@ -207,10 +206,10 @@
 		return NULL;
 
-	if (length || (*identifier)) {
+	if (length || *identifier) {
 		int index;
 
-		for (index = 0; index < map->next; ++index) {
+		for (index = 0; index < map->next; index++) {
 			if (map->items[index]->c == *identifier) {
-				++identifier;
+				identifier++;
 				if (length == 1)
 					return map->items[index];
Index: uspace/lib/c/include/adt/generic_field.h
===================================================================
--- uspace/lib/c/include/adt/generic_field.h	(revision e3c3172de8f6c4741dd8c769b65f646f797b7da8)
+++ uspace/lib/c/include/adt/generic_field.h	(revision bea023b9b8202ba19f790a340e59e36be213fadf)
@@ -91,5 +91,5 @@
 			} \
 			field->items[field->next] = value; \
-			++field->next; \
+			field->next++; \
 			field->items[field->next] = NULL; \
 			return field->next - 1; \
@@ -108,5 +108,5 @@
 			int index; \
 			field->magic = 0; \
-			for (index = 0; index < field->next; ++ index) { \
+			for (index = 0; index < field->next; index++) { \
 				if (field->items[index]) \
 					free(field->items[index]); \
Index: uspace/lib/c/include/errno.h
===================================================================
--- uspace/lib/c/include/errno.h	(revision e3c3172de8f6c4741dd8c769b65f646f797b7da8)
+++ uspace/lib/c/include/errno.h	(revision bea023b9b8202ba19f790a340e59e36be213fadf)
@@ -83,8 +83,6 @@
 #define ENOTCONN	(-10057)
 
-/** The requested operation was not performed.
- *  Try again later.
- */
-#define TRY_AGAIN	(-11002)
+/** The requested operation was not performed. Try again later. */
+#define EAGAIN		(-11002)
 
 /** No data.
Index: uspace/srv/net/il/arp/arp.c
===================================================================
--- uspace/srv/net/il/arp/arp.c	(revision e3c3172de8f6c4741dd8c769b65f646f797b7da8)
+++ uspace/srv/net/il/arp/arp.c	(revision bea023b9b8202ba19f790a340e59e36be213fadf)
@@ -72,4 +72,7 @@
 #define NAME  "arp"
 
+/** Number of microseconds to wait for an ARP reply. */
+#define ARP_TRANS_WAIT	1000000
+
 /** ARP global data. */
 arp_globals_t arp_globals;
@@ -77,5 +80,27 @@
 DEVICE_MAP_IMPLEMENT(arp_cache, arp_device_t);
 INT_MAP_IMPLEMENT(arp_protos, arp_proto_t);
-GENERIC_CHAR_MAP_IMPLEMENT(arp_addr, measured_string_t);
+GENERIC_CHAR_MAP_IMPLEMENT(arp_addr, arp_trans_t);
+
+static void arp_clear_trans(arp_trans_t *trans)
+{
+	if (trans->hw_addr) {
+		free(trans->hw_addr);
+		trans->hw_addr = NULL;
+	}
+	fibril_condvar_broadcast(&trans->cv);
+}
+
+static void arp_clear_addr(arp_addr_t *addresses)
+{
+	int count;
+	arp_trans_t *trans;
+
+	for (count = arp_addr_count(addresses) - 1; count >= 0; count--) {
+		trans = arp_addr_items_get_index(&addresses->values, count);
+		if (trans)
+			arp_clear_trans(trans);
+	}
+}
+
 
 /** Clears the device specific data.
@@ -96,4 +121,5 @@
 			if (proto->addr_data)
 				free(proto->addr_data);
+			arp_clear_addr(&proto->addresses);
 			arp_addr_destroy(&proto->addresses);
 		}
@@ -107,5 +133,5 @@
 	arp_device_t *device;
 
-	fibril_rwlock_write_lock(&arp_globals.lock);
+	fibril_mutex_lock(&arp_globals.lock);
 	for (count = arp_cache_count(&arp_globals.cache) - 1; count >= 0;
 	    count--) {
@@ -120,5 +146,5 @@
 	}
 	arp_cache_clear(&arp_globals.cache);
-	fibril_rwlock_write_unlock(&arp_globals.lock);
+	fibril_mutex_unlock(&arp_globals.lock);
 	printf("Cache cleaned\n");
 	return EOK;
@@ -130,18 +156,22 @@
 	arp_device_t *device;
 	arp_proto_t *proto;
-
-	fibril_rwlock_write_lock(&arp_globals.lock);
+	arp_trans_t *trans;
+
+	fibril_mutex_lock(&arp_globals.lock);
 	device = arp_cache_find(&arp_globals.cache, device_id);
 	if (!device) {
-		fibril_rwlock_write_unlock(&arp_globals.lock);
+		fibril_mutex_unlock(&arp_globals.lock);
 		return ENOENT;
 	}
 	proto = arp_protos_find(&device->protos, protocol);
 	if (!proto) {
-		fibril_rwlock_write_unlock(&arp_globals.lock);
+		fibril_mutex_unlock(&arp_globals.lock);
 		return ENOENT;
 	}
+	trans = arp_addr_find(&proto->addresses, address->value, address->length);
+	if (trans)
+		arp_clear_trans(trans);
 	arp_addr_exclude(&proto->addresses, address->value, address->length);
-	fibril_rwlock_write_unlock(&arp_globals.lock);
+	fibril_mutex_unlock(&arp_globals.lock);
 	return EOK;
 }
@@ -152,13 +182,13 @@
 	arp_device_t *device;
 
-	fibril_rwlock_write_lock(&arp_globals.lock);
+	fibril_mutex_lock(&arp_globals.lock);
 	device = arp_cache_find(&arp_globals.cache, device_id);
 	if (!device) {
-		fibril_rwlock_write_unlock(&arp_globals.lock);
+		fibril_mutex_unlock(&arp_globals.lock);
 		return ENOENT;
 	}
 	arp_clear_device(device);
 	printf("Device %d cleared\n", device_id);
-	fibril_rwlock_write_unlock(&arp_globals.lock);
+	fibril_mutex_unlock(&arp_globals.lock);
 	return EOK;
 }
@@ -221,5 +251,5 @@
 	int rc;
 
-	fibril_rwlock_write_lock(&arp_globals.lock);
+	fibril_mutex_lock(&arp_globals.lock);
 
 	/* An existing device? */
@@ -229,5 +259,5 @@
 		if (device->service != service) {
 			printf("Device %d already exists\n", device->device_id);
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			return EEXIST;
 		}
@@ -241,5 +271,5 @@
 			rc = arp_proto_create(&proto, protocol, address);
 			if (rc != EOK) {
-				fibril_rwlock_write_unlock(&arp_globals.lock);
+				fibril_mutex_unlock(&arp_globals.lock);
 				return rc;
 			}
@@ -247,5 +277,5 @@
 			    proto);
 			if (index < 0) {
-				fibril_rwlock_write_unlock(&arp_globals.lock);
+				fibril_mutex_unlock(&arp_globals.lock);
 				free(proto);
 				return index;
@@ -262,5 +292,5 @@
 		device = (arp_device_t *) malloc(sizeof(arp_device_t));
 		if (!device) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			return ENOMEM;
 		}
@@ -269,5 +299,5 @@
 		rc = arp_protos_initialize(&device->protos);
 		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			free(device);
 			return rc;
@@ -275,5 +305,5 @@
 		rc = arp_proto_create(&proto, protocol, address);
 		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			free(device);
 			return rc;
@@ -281,5 +311,5 @@
 		index = arp_protos_add(&device->protos, proto->service, proto);
 		if (index < 0) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			arp_protos_destroy(&device->protos);
 			free(device);
@@ -293,5 +323,5 @@
 		    arp_globals.client_connection);
 		if (device->phone < 0) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			arp_protos_destroy(&device->protos);
 			free(device);
@@ -303,5 +333,5 @@
 		    &device->packet_dimension);
 		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			arp_protos_destroy(&device->protos);
 			free(device);
@@ -313,5 +343,5 @@
 		    &device->addr_data);
 		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			arp_protos_destroy(&device->protos);
 			free(device);
@@ -323,5 +353,5 @@
 		    &device->broadcast_addr, &device->broadcast_data);
 		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			free(device->addr);
 			free(device->addr_data);
@@ -334,5 +364,5 @@
 		    device);
 		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			free(device->addr);
 			free(device->addr_data);
@@ -347,5 +377,5 @@
 		    device->service, protocol);
 	}
-	fibril_rwlock_write_unlock(&arp_globals.lock);
+	fibril_mutex_unlock(&arp_globals.lock);
 	
 	return EOK;
@@ -363,9 +393,9 @@
 	int rc;
 
-	fibril_rwlock_initialize(&arp_globals.lock);
-	fibril_rwlock_write_lock(&arp_globals.lock);
+	fibril_mutex_initialize(&arp_globals.lock);
+	fibril_mutex_lock(&arp_globals.lock);
 	arp_globals.client_connection = client_connection;
 	rc = arp_cache_initialize(&arp_globals.cache);
-	fibril_rwlock_write_unlock(&arp_globals.lock);
+	fibril_mutex_unlock(&arp_globals.lock);
 	
 	return rc;
@@ -383,12 +413,12 @@
 	arp_device_t *device;
 
-	fibril_rwlock_write_lock(&arp_globals.lock);
+	fibril_mutex_lock(&arp_globals.lock);
 	device = arp_cache_find(&arp_globals.cache, device_id);
 	if (!device) {
-		fibril_rwlock_write_unlock(&arp_globals.lock);
+		fibril_mutex_unlock(&arp_globals.lock);
 		return ENOENT;
 	}
 	device->packet_dimension.content = mtu;
-	fibril_rwlock_write_unlock(&arp_globals.lock);
+	fibril_mutex_unlock(&arp_globals.lock);
 	printf("arp - device %d changed mtu to %zu\n\n", device_id, mtu);
 	return EOK;
@@ -421,5 +451,5 @@
 	arp_device_t *device;
 	arp_proto_t *proto;
-	measured_string_t *hw_source;
+	arp_trans_t *trans;
 	uint8_t *src_hw;
 	uint8_t *src_proto;
@@ -452,13 +482,13 @@
 	des_hw = src_proto + header->protocol_length;
 	des_proto = des_hw + header->hardware_length;
-	hw_source = arp_addr_find(&proto->addresses, (char *) src_proto,
+	trans = arp_addr_find(&proto->addresses, (char *) src_proto,
 	    CONVERT_SIZE(uint8_t, char, header->protocol_length));
 	/* Exists? */
-	if (hw_source) {
-		if (hw_source->length != CONVERT_SIZE(uint8_t, char,
+	if (trans && trans->hw_addr) {
+		if (trans->hw_addr->length != CONVERT_SIZE(uint8_t, char,
 		    header->hardware_length)) {
 			return EINVAL;
 		}
-		memcpy(hw_source->value, src_hw, hw_source->length);
+		memcpy(trans->hw_addr->value, src_hw, trans->hw_addr->length);
 	}
 	/* Is my protocol address? */
@@ -470,16 +500,27 @@
 	    proto->addr->length)) {
 		/* Not already updated? */
-		if (!hw_source) {
-			hw_source = measured_string_create_bulk((char *) src_hw,
-			    CONVERT_SIZE(uint8_t, char,
+		if (!trans) {
+			trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
+			if (!trans)
+				return ENOMEM;
+			trans->hw_addr = NULL;
+			fibril_condvar_initialize(&trans->cv);
+			rc = arp_addr_add(&proto->addresses, (char *) src_proto,
+			    CONVERT_SIZE(uint8_t, char, header->protocol_length),
+			    trans);
+			if (rc != EOK) {
+				/* The generic char map has already freed trans! */
+				return rc;
+			}
+		}
+		if (!trans->hw_addr) {
+			trans->hw_addr = measured_string_create_bulk(
+			    (char *) src_hw, CONVERT_SIZE(uint8_t, char,
 			    header->hardware_length));
-			if (!hw_source)
+			if (!trans->hw_addr)
 				return ENOMEM;
 
-			rc = arp_addr_add(&proto->addresses, (char *) src_proto,
-			    CONVERT_SIZE(uint8_t, char,
-			    header->protocol_length), hw_source);
-			if (rc != EOK)
-				return rc;
+			/* Notify the fibrils that wait for the translation. */
+			fibril_condvar_broadcast(&trans->cv);
 		}
 		if (ntohs(header->operation) == ARPOP_REQUEST) {
@@ -490,5 +531,5 @@
 			memcpy(src_hw, device->addr->value,
 			    device->packet_dimension.addr_len);
-			memcpy(des_hw, hw_source->value,
+			memcpy(des_hw, trans->hw_addr->value,
 			    header->hardware_length);
 			
@@ -516,36 +557,51 @@
  * @param[in] protocol	The protocol service.
  * @param[in] target	The target protocol address.
- * @return		The hardware address of the target.
- * @return		NULL if the target parameter is NULL.
- * @return		NULL if the device is not found.
- * @return		NULL if the device packet is too small to send a
- *			request.
- * @return		NULL if the hardware address is not found in the cache.
- */
-static measured_string_t *
+ * @param[out] translation Where the hardware address of the target is stored.
+ * @return		EOK on success.
+ * @return		EAGAIN if the caller should try again.
+ * @return		Other error codes in case of error.
+ */
+static int
 arp_translate_message(device_id_t device_id, services_t protocol,
-    measured_string_t *target)
+    measured_string_t *target, measured_string_t **translation)
 {
 	arp_device_t *device;
 	arp_proto_t *proto;
-	measured_string_t *addr;
+	arp_trans_t *trans;
 	size_t length;
 	packet_t *packet;
 	arp_header_t *header;
-
-	if (!target)
-		return NULL;
+	bool retry = false;
+	int rc;
+
+restart:
+	if (!target || !translation)
+		return EBADMEM;
 
 	device = arp_cache_find(&arp_globals.cache, device_id);
 	if (!device)
-		return NULL;
+		return ENOENT;
 
 	proto = arp_protos_find(&device->protos, protocol);
 	if (!proto || (proto->addr->length != target->length))
-		return NULL;
-
-	addr = arp_addr_find(&proto->addresses, target->value, target->length);
-	if (addr)
-		return addr;
+		return ENOENT;
+
+	trans = arp_addr_find(&proto->addresses, target->value, target->length);
+	if (trans) {
+		if (trans->hw_addr) {
+			*translation = trans->hw_addr;
+			return EOK;
+		}
+		if (retry)
+			return EAGAIN;
+		rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
+		    ARP_TRANS_WAIT);
+		if (rc == ETIMEOUT)
+			return ENOENT;
+		retry = true;
+		goto restart;
+	}
+	if (retry)
+		return EAGAIN;
 
 	/* ARP packet content size = header + (address + translation) * 2 */
@@ -553,5 +609,5 @@
 	    CONVERT_SIZE(char, uint8_t, device->addr->length));
 	if (length > device->packet_dimension.content)
-		return NULL;
+		return ELIMIT;
 
 	packet = packet_get_4_remote(arp_globals.net_phone,
@@ -559,10 +615,10 @@
 	    length, device->packet_dimension.suffix);
 	if (!packet)
-		return NULL;
+		return ENOMEM;
 
 	header = (arp_header_t *) packet_suffix(packet, length);
 	if (!header) {
 		pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
-		return NULL;
+		return ENOMEM;
 	}
 
@@ -583,13 +639,32 @@
 	memcpy(((uint8_t *) header) + length, target->value, target->length);
 
-	if (packet_set_addr(packet, (uint8_t *) device->addr->value,
+	rc = packet_set_addr(packet, (uint8_t *) device->addr->value,
 	    (uint8_t *) device->broadcast_addr->value,
-	    CONVERT_SIZE(char, uint8_t, device->addr->length)) != EOK) {
+	    CONVERT_SIZE(char, uint8_t, device->addr->length));
+	if (rc != EOK) {
 		pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
-		return NULL;
+		return rc;
 	}
 
 	nil_send_msg(device->phone, device_id, packet, SERVICE_ARP);
-	return NULL;
+
+	trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
+	if (!trans)
+		return ENOMEM;
+	trans->hw_addr = NULL;
+	fibril_condvar_initialize(&trans->cv);
+	rc = arp_addr_add(&proto->addresses, target->value, target->length,
+	    trans);
+	if (rc != EOK) {
+		/* The generic char map has already freed trans! */
+		return rc;
+	}
+	
+	rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
+	    ARP_TRANS_WAIT);
+	if (rc == ETIMEOUT)
+		return ENOENT;
+	retry = true;
+	goto restart;
 }
 
@@ -642,15 +717,19 @@
 			return rc;
 		
-		fibril_rwlock_read_lock(&arp_globals.lock);
-		translation = arp_translate_message(IPC_GET_DEVICE(call),
-		    IPC_GET_SERVICE(call), address);
+		fibril_mutex_lock(&arp_globals.lock);
+		rc = arp_translate_message(IPC_GET_DEVICE(call),
+		    IPC_GET_SERVICE(call), address, &translation);
 		free(address);
 		free(data);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&arp_globals.lock);
+			return rc;
+		}
 		if (!translation) {
-			fibril_rwlock_read_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			return ENOENT;
 		}
 		rc = measured_strings_reply(translation, 1);
-		fibril_rwlock_read_unlock(&arp_globals.lock);
+		fibril_mutex_unlock(&arp_globals.lock);
 		return rc;
 
@@ -682,5 +761,5 @@
 			return rc;
 		
-		fibril_rwlock_read_lock(&arp_globals.lock);
+		fibril_mutex_lock(&arp_globals.lock);
 		do {
 			next = pq_detach(packet);
@@ -692,5 +771,5 @@
 			packet = next;
 		} while (packet);
-		fibril_rwlock_read_unlock(&arp_globals.lock);
+		fibril_mutex_unlock(&arp_globals.lock);
 		
 		return EOK;
Index: uspace/srv/net/il/arp/arp.h
===================================================================
--- uspace/srv/net/il/arp/arp.h	(revision e3c3172de8f6c4741dd8c769b65f646f797b7da8)
+++ uspace/srv/net/il/arp/arp.h	(revision bea023b9b8202ba19f790a340e59e36be213fadf)
@@ -65,4 +65,9 @@
 typedef struct arp_proto arp_proto_t;
 
+/** Type definition of the ARP address translation record.
+ * @see arp_trans
+ */
+typedef struct arp_trans arp_trans_t;
+
 /** ARP address map.
  *
@@ -70,5 +75,5 @@
  * @see generic_char_map.h
  */
-GENERIC_CHAR_MAP_DECLARE(arp_addr, measured_string_t);
+GENERIC_CHAR_MAP_DECLARE(arp_addr, arp_trans_t);
 
 /** ARP address cache.
@@ -89,9 +94,9 @@
 struct arp_device {
 	/** Actual device hardware address. */
-	measured_string_t * addr;
+	measured_string_t *addr;
 	/** Actual device hardware address data. */
 	char *addr_data;
 	/** Broadcast device hardware address. */
-	measured_string_t * broadcast_addr;
+	measured_string_t *broadcast_addr;
 	/** Broadcast device hardware address data. */
 	char *broadcast_data;
@@ -129,5 +134,5 @@
 	int net_phone;
 	/** Safety lock. */
-	fibril_rwlock_t lock;
+	fibril_mutex_t lock;
 };
 
@@ -144,6 +149,18 @@
 };
 
+/** ARP address translation record. */
+struct arp_trans {
+	/**
+	 * Hardware address for the translation. NULL denotes an incomplete
+	 * record with possible waiters.
+	 */ 
+	measured_string_t *hw_addr;
+	/** Condition variable used for waiting for completion of the record. */
+	fibril_condvar_t cv;
+};
+
 #endif
 
 /** @}
  */
+
