source: mainline/uspace/srv/net/il/arp/arp.c@ e417b96

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e417b96 was 19f857a, checked in by Jiri Svoboda <jiri@…>, 15 years ago

Rename string.h to str.h to avoid header conflict with standard C string.h.

  • Property mode set to 100644
File size: 20.2 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup arp
30 * @{
31 */
32
33/** @file
34 * ARP module implementation.
35 * @see arp.h
36 */
37
38#include <async.h>
39#include <malloc.h>
40#include <mem.h>
41#include <fibril_synch.h>
42#include <stdio.h>
43#include <str.h>
44#include <task.h>
45
46#include <ipc/ipc.h>
47#include <ipc/services.h>
48
49#include "../../err.h"
50#include "../../messages.h"
51#include "../../modules.h"
52
53#include "../../include/byteorder.h"
54#include "../../include/device.h"
55#include "../../include/arp_interface.h"
56#include "../../include/nil_interface.h"
57#include "../../include/protocol_map.h"
58
59#include "../../structures/measured_strings.h"
60#include "../../structures/packet/packet.h"
61#include "../../structures/packet/packet_client.h"
62
63#include "../il_messages.h"
64
65#include "arp.h"
66#include "arp_header.h"
67#include "arp_oc.h"
68#include "arp_module.h"
69#include "arp_messages.h"
70
71/** ARP global data.
72 */
73arp_globals_t arp_globals;
74
75/** Clears the device specific data.
76 * @param[in] device The device specific data.
77 */
78void arp_clear_device(arp_device_ref device);
79
80/** Creates new protocol specific data.
81 * Allocates and returns the needed memory block as the proto parameter.
82 * @param[out] proto The allocated protocol specific data.
83 * @param[in] service The protocol module service.
84 * @param[in] address The actual protocol device address.
85 * @returns EOK on success.
86 * @returns ENOMEM if there is not enough memory left.
87 */
88int arp_proto_create(arp_proto_ref * proto, services_t service, measured_string_ref address);
89
90/** @name Message processing functions
91 */
92/*@{*/
93
94/** Registers the device.
95 * Creates new device entry in the cache or updates the protocol address if the device with the device identifier and the driver service exists.
96 * @param[in] device_id The device identifier.
97 * @param[in] service The device driver service.
98 * @param[in] protocol The protocol service.
99 * @param[in] address The actual device protocol address.
100 * @returns EOK on success.
101 * @returns EEXIST if another device with the same device identifier and different driver service exists.
102 * @returns ENOMEM if there is not enough memory left.
103 * @returns Other error codes as defined for the measured_strings_return() function.
104 */
105int arp_device_message(device_id_t device_id, services_t service, services_t protocol, measured_string_ref address);
106
107/** Updates the device content length according to the new MTU value.
108 * @param[in] device_id The device identifier.
109 * @param[in] mtu The new mtu value.
110 * @returns ENOENT if device is not found.
111 * @returns EOK on success.
112 */
113int arp_mtu_changed_message(device_id_t device_id, size_t mtu);
114
115/** Processes the received ARP packet.
116 * Updates the source hardware address if the source entry exists or the packet is targeted to my protocol address.
117 * Responses to the ARP request if the packet is the ARP request and is targeted to my address.
118 * @param[in] device_id The source device identifier.
119 * @param[in,out] packet The received packet.
120 * @returns EOK on success and the packet is no longer needed.
121 * @returns 1 on success and the packet has been reused.
122 * @returns EINVAL if the packet is too small to carry an ARP packet.
123 * @returns EINVAL if the received address lengths differs from the registered values.
124 * @returns ENOENT if the device is not found in the cache.
125 * @returns ENOENT if the protocol for the device is not found in the cache.
126 * @returns ENOMEM if there is not enough memory left.
127 */
128int arp_receive_message(device_id_t device_id, packet_t packet);
129
130/** Returns the hardware address for the given protocol address.
131 * Sends the ARP request packet if the hardware address is not found in the cache.
132 * @param[in] device_id The device identifier.
133 * @param[in] protocol The protocol service.
134 * @param[in] target The target protocol address.
135 * @returns The hardware address of the target.
136 * @returns NULL if the target parameter is NULL.
137 * @returns NULL if the device is not found.
138 * @returns NULL if the device packet is too small to send a&nbsp;request.
139 * @returns NULL if the hardware address is not found in the cache.
140 */
141measured_string_ref arp_translate_message(device_id_t device_id, services_t protocol, measured_string_ref target);
142
143/*@}*/
144
145DEVICE_MAP_IMPLEMENT(arp_cache, arp_device_t)
146
147INT_MAP_IMPLEMENT(arp_protos, arp_proto_t)
148
149GENERIC_CHAR_MAP_IMPLEMENT(arp_addr, measured_string_t)
150
151int arp_clean_cache_req(int arp_phone){
152 int count;
153 arp_device_ref device;
154
155 fibril_rwlock_write_lock(&arp_globals.lock);
156 for(count = arp_cache_count(&arp_globals.cache) - 1; count >= 0; -- count){
157 device = arp_cache_get_index(&arp_globals.cache, count);
158 if(device){
159 arp_clear_device(device);
160 if(device->addr_data){
161 free(device->addr_data);
162 }
163 if(device->broadcast_data){
164 free(device->broadcast_data);
165 }
166 }
167 }
168 arp_cache_clear(&arp_globals.cache);
169 fibril_rwlock_write_unlock(&arp_globals.lock);
170 printf("Cache cleaned\n");
171 return EOK;
172}
173
174int arp_clear_address_req(int arp_phone, device_id_t device_id, services_t protocol, measured_string_ref address){
175 arp_device_ref device;
176 arp_proto_ref proto;
177
178 fibril_rwlock_write_lock(&arp_globals.lock);
179 device = arp_cache_find(&arp_globals.cache, device_id);
180 if(! device){
181 fibril_rwlock_write_unlock(&arp_globals.lock);
182 return ENOENT;
183 }
184 proto = arp_protos_find(&device->protos, protocol);
185 if(! proto){
186 fibril_rwlock_write_unlock(&arp_globals.lock);
187 return ENOENT;
188 }
189 arp_addr_exclude(&proto->addresses, address->value, address->length);
190 fibril_rwlock_write_unlock(&arp_globals.lock);
191 return EOK;
192}
193
194void arp_clear_device(arp_device_ref device){
195 int count;
196 arp_proto_ref proto;
197
198 for(count = arp_protos_count(&device->protos) - 1; count >= 0; -- count){
199 proto = arp_protos_get_index(&device->protos, count);
200 if(proto){
201 if(proto->addr){
202 free(proto->addr);
203 }
204 if(proto->addr_data){
205 free(proto->addr_data);
206 }
207 arp_addr_destroy(&proto->addresses);
208 }
209 }
210 arp_protos_clear(&device->protos);
211}
212
213int arp_clear_device_req(int arp_phone, device_id_t device_id){
214 arp_device_ref device;
215
216 fibril_rwlock_write_lock(&arp_globals.lock);
217 device = arp_cache_find(&arp_globals.cache, device_id);
218 if(! device){
219 fibril_rwlock_write_unlock(&arp_globals.lock);
220 return ENOENT;
221 }
222 arp_clear_device(device);
223 printf("Device %d cleared\n", device_id);
224 fibril_rwlock_write_unlock(&arp_globals.lock);
225 return EOK;
226}
227
228int arp_connect_module(services_t service){
229 if(service != SERVICE_ARP){
230 return EINVAL;
231 }
232 return EOK;
233}
234
235int arp_device_message(device_id_t device_id, services_t service, services_t protocol, measured_string_ref address){
236 ERROR_DECLARE;
237
238 arp_device_ref device;
239 arp_proto_ref proto;
240 int index;
241 hw_type_t hardware;
242
243 fibril_rwlock_write_lock(&arp_globals.lock);
244 // an existing device?
245 device = arp_cache_find(&arp_globals.cache, device_id);
246 if(device){
247 if(device->service != service){
248 printf("Device %d already exists\n", device->device_id);
249 fibril_rwlock_write_unlock(&arp_globals.lock);
250 return EEXIST;
251 }
252 proto = arp_protos_find(&device->protos, protocol);
253 if(proto){
254 free(proto->addr);
255 free(proto->addr_data);
256 proto->addr = address;
257 proto->addr_data = address->value;
258 }else{
259 if(ERROR_OCCURRED(arp_proto_create(&proto, protocol, address))){
260 fibril_rwlock_write_unlock(&arp_globals.lock);
261 return ERROR_CODE;
262 }
263 index = arp_protos_add(&device->protos, proto->service, proto);
264 if(index < 0){
265 fibril_rwlock_write_unlock(&arp_globals.lock);
266 free(proto);
267 return index;
268 }
269 printf("New protocol added:\n\tdevice id\t= %d\n\tproto\t= %d", device_id, protocol);
270 }
271 }else{
272 hardware = hardware_map(service);
273 if(! hardware){
274 return ENOENT;
275 }
276 // create a new device
277 device = (arp_device_ref) malloc(sizeof(arp_device_t));
278 if(! device){
279 fibril_rwlock_write_unlock(&arp_globals.lock);
280 return ENOMEM;
281 }
282 device->hardware = hardware;
283 device->device_id = device_id;
284 if(ERROR_OCCURRED(arp_protos_initialize(&device->protos))
285 || ERROR_OCCURRED(arp_proto_create(&proto, protocol, address))){
286 fibril_rwlock_write_unlock(&arp_globals.lock);
287 free(device);
288 return ERROR_CODE;
289 }
290 index = arp_protos_add(&device->protos, proto->service, proto);
291 if(index < 0){
292 fibril_rwlock_write_unlock(&arp_globals.lock);
293 arp_protos_destroy(&device->protos);
294 free(device);
295 return index;
296 }
297 device->service = service;
298 // bind the new one
299 device->phone = nil_bind_service(device->service, (ipcarg_t) device->device_id, SERVICE_ARP, arp_globals.client_connection);
300 if(device->phone < 0){
301 fibril_rwlock_write_unlock(&arp_globals.lock);
302 arp_protos_destroy(&device->protos);
303 free(device);
304 return EREFUSED;
305 }
306 // get packet dimensions
307 if(ERROR_OCCURRED(nil_packet_size_req(device->phone, device_id, &device->packet_dimension))){
308 fibril_rwlock_write_unlock(&arp_globals.lock);
309 arp_protos_destroy(&device->protos);
310 free(device);
311 return ERROR_CODE;
312 }
313 // get hardware address
314 if(ERROR_OCCURRED(nil_get_addr_req(device->phone, device_id, &device->addr, &device->addr_data))){
315 fibril_rwlock_write_unlock(&arp_globals.lock);
316 arp_protos_destroy(&device->protos);
317 free(device);
318 return ERROR_CODE;
319 }
320 // get broadcast address
321 if(ERROR_OCCURRED(nil_get_broadcast_addr_req(device->phone, device_id, &device->broadcast_addr, &device->broadcast_data))){
322 fibril_rwlock_write_unlock(&arp_globals.lock);
323 free(device->addr);
324 free(device->addr_data);
325 arp_protos_destroy(&device->protos);
326 free(device);
327 return ERROR_CODE;
328 }
329 if(ERROR_OCCURRED(arp_cache_add(&arp_globals.cache, device->device_id, device))){
330 fibril_rwlock_write_unlock(&arp_globals.lock);
331 free(device->addr);
332 free(device->addr_data);
333 free(device->broadcast_addr);
334 free(device->broadcast_data);
335 arp_protos_destroy(&device->protos);
336 free(device);
337 return ERROR_CODE;
338 }
339 printf("New device registered:\n\tid\t= %d\n\ttype\t= 0x%x\n\tservice\t= %d\n\tproto\t= %d\n", device->device_id, device->hardware, device->service, protocol);
340 }
341 fibril_rwlock_write_unlock(&arp_globals.lock);
342 return EOK;
343}
344
345int arp_device_req(int arp_phone, device_id_t device_id, services_t protocol, services_t netif, measured_string_ref address){
346 ERROR_DECLARE;
347
348 measured_string_ref tmp;
349
350 // copy the given address for exclusive use
351 tmp = measured_string_copy(address);
352 if(ERROR_OCCURRED(arp_device_message(device_id, netif, protocol, tmp))){
353 free(tmp->value);
354 free(tmp);
355 }
356 return ERROR_CODE;
357}
358
359int arp_initialize(async_client_conn_t client_connection){
360 ERROR_DECLARE;
361
362 fibril_rwlock_initialize(&arp_globals.lock);
363 fibril_rwlock_write_lock(&arp_globals.lock);
364 arp_globals.client_connection = client_connection;
365 ERROR_PROPAGATE(arp_cache_initialize(&arp_globals.cache));
366 fibril_rwlock_write_unlock(&arp_globals.lock);
367 return EOK;
368}
369
370int arp_message(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
371 ERROR_DECLARE;
372
373 measured_string_ref address;
374 measured_string_ref translation;
375 char * data;
376 packet_t packet;
377 packet_t next;
378
379// printf("message %d - %d\n", IPC_GET_METHOD(*call), NET_ARP_FIRST);
380 *answer_count = 0;
381 switch(IPC_GET_METHOD(*call)){
382 case IPC_M_PHONE_HUNGUP:
383 return EOK;
384 case NET_ARP_DEVICE:
385 ERROR_PROPAGATE(measured_strings_receive(&address, &data, 1));
386 if(ERROR_OCCURRED(arp_device_message(IPC_GET_DEVICE(call), IPC_GET_SERVICE(call), ARP_GET_NETIF(call), address))){
387 free(address);
388 free(data);
389 }
390 return ERROR_CODE;
391 case NET_ARP_TRANSLATE:
392 ERROR_PROPAGATE(measured_strings_receive(&address, &data, 1));
393 fibril_rwlock_read_lock(&arp_globals.lock);
394 translation = arp_translate_message(IPC_GET_DEVICE(call), IPC_GET_SERVICE(call), address);
395 free(address);
396 free(data);
397 if(! translation){
398 fibril_rwlock_read_unlock(&arp_globals.lock);
399 return ENOENT;
400 }
401 ERROR_CODE = measured_strings_reply(translation, 1);
402 fibril_rwlock_read_unlock(&arp_globals.lock);
403 return ERROR_CODE;
404 case NET_ARP_CLEAR_DEVICE:
405 return arp_clear_device_req(0, IPC_GET_DEVICE(call));
406 case NET_ARP_CLEAR_ADDRESS:
407 ERROR_PROPAGATE(measured_strings_receive(&address, &data, 1));
408 arp_clear_address_req(0, IPC_GET_DEVICE(call), IPC_GET_SERVICE(call), address);
409 free(address);
410 free(data);
411 return EOK;
412 case NET_ARP_CLEAN_CACHE:
413 return arp_clean_cache_req(0);
414 case NET_IL_DEVICE_STATE:
415 // do nothing - keep the cache
416 return EOK;
417 case NET_IL_RECEIVED:
418 if(! ERROR_OCCURRED(packet_translate(arp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
419 fibril_rwlock_read_lock(&arp_globals.lock);
420 do{
421 next = pq_detach(packet);
422 ERROR_CODE = arp_receive_message(IPC_GET_DEVICE(call), packet);
423 if(ERROR_CODE != 1){
424 pq_release(arp_globals.net_phone, packet_get_id(packet));
425 }
426 packet = next;
427 }while(packet);
428 fibril_rwlock_read_unlock(&arp_globals.lock);
429 }
430 return ERROR_CODE;
431 case NET_IL_MTU_CHANGED:
432 return arp_mtu_changed_message(IPC_GET_DEVICE(call), IPC_GET_MTU(call));
433 }
434 return ENOTSUP;
435}
436
437int arp_mtu_changed_message(device_id_t device_id, size_t mtu){
438 arp_device_ref device;
439
440 fibril_rwlock_write_lock(&arp_globals.lock);
441 device = arp_cache_find(&arp_globals.cache, device_id);
442 if(! device){
443 fibril_rwlock_write_unlock(&arp_globals.lock);
444 return ENOENT;
445 }
446 device->packet_dimension.content = mtu;
447 printf("arp - device %d changed mtu to %d\n\n", device_id, mtu);
448 fibril_rwlock_write_unlock(&arp_globals.lock);
449 return EOK;
450}
451
452int arp_proto_create(arp_proto_ref * proto, services_t service, measured_string_ref address){
453 ERROR_DECLARE;
454
455 *proto = (arp_proto_ref) malloc(sizeof(arp_proto_t));
456 if(!(*proto)){
457 return ENOMEM;
458 }
459 (** proto).service = service;
460 (** proto).addr = address;
461 (** proto).addr_data = address->value;
462 if(ERROR_OCCURRED(arp_addr_initialize(&(** proto).addresses))){
463 free(*proto);
464 return ERROR_CODE;
465 }
466 return EOK;
467}
468
469int arp_receive_message(device_id_t device_id, packet_t packet){
470 ERROR_DECLARE;
471
472 size_t length;
473 arp_header_ref header;
474 arp_device_ref device;
475 arp_proto_ref proto;
476 measured_string_ref hw_source;
477 uint8_t * src_hw;
478 uint8_t * src_proto;
479 uint8_t * des_hw;
480 uint8_t * des_proto;
481
482 length = packet_get_data_length(packet);
483 if(length <= sizeof(arp_header_t)){
484 return EINVAL;
485 }
486 device = arp_cache_find(&arp_globals.cache, device_id);
487 if(! device){
488 return ENOENT;
489 }
490 header = (arp_header_ref) packet_get_data(packet);
491 if((ntohs(header->hardware) != device->hardware)
492 || (length < sizeof(arp_header_t) + header->hardware_length * 2u + header->protocol_length * 2u)){
493 return EINVAL;
494 }
495 proto = arp_protos_find(&device->protos, protocol_unmap(device->service, ntohs(header->protocol)));
496 if(! proto){
497 return ENOENT;
498 }
499 src_hw = ((uint8_t *) header) + sizeof(arp_header_t);
500 src_proto = src_hw + header->hardware_length;
501 des_hw = src_proto + header->protocol_length;
502 des_proto = des_hw + header->hardware_length;
503 hw_source = arp_addr_find(&proto->addresses, (char *) src_proto, CONVERT_SIZE(uint8_t, char, header->protocol_length));
504 // exists?
505 if(hw_source){
506 if(hw_source->length != CONVERT_SIZE(uint8_t, char, header->hardware_length)){
507 return EINVAL;
508 }
509 memcpy(hw_source->value, src_hw, hw_source->length);
510 }
511 // is my protocol address?
512 if(proto->addr->length != CONVERT_SIZE(uint8_t, char, header->protocol_length)){
513 return EINVAL;
514 }
515 if(! str_lcmp(proto->addr->value, (char *) des_proto, proto->addr->length)){
516 // not already upadted?
517 if(! hw_source){
518 hw_source = measured_string_create_bulk((char *) src_hw, CONVERT_SIZE(uint8_t, char, header->hardware_length));
519 if(! hw_source){
520 return ENOMEM;
521 }
522 ERROR_PROPAGATE(arp_addr_add(&proto->addresses, (char *) src_proto, CONVERT_SIZE(uint8_t, char, header->protocol_length), hw_source));
523 }
524 if(ntohs(header->operation) == ARPOP_REQUEST){
525 header->operation = htons(ARPOP_REPLY);
526 memcpy(des_proto, src_proto, header->protocol_length);
527 memcpy(src_proto, proto->addr->value, header->protocol_length);
528 memcpy(src_hw, device->addr->value, device->packet_dimension.addr_len);
529 memcpy(des_hw, hw_source->value, header->hardware_length);
530 ERROR_PROPAGATE(packet_set_addr(packet, src_hw, des_hw, header->hardware_length));
531 nil_send_msg(device->phone, device_id, packet, SERVICE_ARP);
532 return 1;
533 }
534 }
535 return EOK;
536}
537
538task_id_t arp_task_get_id(void){
539 return task_get_id();
540}
541
542measured_string_ref arp_translate_message(device_id_t device_id, services_t protocol, measured_string_ref target){
543 arp_device_ref device;
544 arp_proto_ref proto;
545 measured_string_ref addr;
546 size_t length;
547 packet_t packet;
548 arp_header_ref header;
549
550 if(! target){
551 return NULL;
552 }
553 device = arp_cache_find(&arp_globals.cache, device_id);
554 if(! device){
555 return NULL;
556 }
557 proto = arp_protos_find(&device->protos, protocol);
558 if((! proto) || (proto->addr->length != target->length)){
559 return NULL;
560 }
561 addr = arp_addr_find(&proto->addresses, target->value, target->length);
562 if(addr){
563 return addr;
564 }
565 // ARP packet content size = header + (address + translation) * 2
566 length = 8 + (CONVERT_SIZE(char, uint8_t, proto->addr->length) + CONVERT_SIZE(char, uint8_t, device->addr->length)) * 2;
567 if(length > device->packet_dimension.content){
568 return NULL;
569 }
570 packet = packet_get_4(arp_globals.net_phone, device->packet_dimension.addr_len, device->packet_dimension.prefix, length, device->packet_dimension.suffix);
571 if(! packet){
572 return NULL;
573 }
574 header = (arp_header_ref) packet_suffix(packet, length);
575 if(! header){
576 pq_release(arp_globals.net_phone, packet_get_id(packet));
577 return NULL;
578 }
579 header->hardware = htons(device->hardware);
580 header->hardware_length = (uint8_t) device->addr->length;
581 header->protocol = htons(protocol_map(device->service, protocol));
582 header->protocol_length = (uint8_t) proto->addr->length;
583 header->operation = htons(ARPOP_REQUEST);
584 length = sizeof(arp_header_t);
585 memcpy(((uint8_t *) header) + length, device->addr->value, device->addr->length);
586 length += device->addr->length;
587 memcpy(((uint8_t *) header) + length, proto->addr->value, proto->addr->length);
588 length += proto->addr->length;
589 bzero(((uint8_t *) header) + length, device->addr->length);
590 length += device->addr->length;
591 memcpy(((uint8_t *) header) + length, target->value, target->length);
592 if(packet_set_addr(packet, (uint8_t *) device->addr->value, (uint8_t *) device->broadcast_addr->value, CONVERT_SIZE(char, uint8_t, device->addr->length)) != EOK){
593 pq_release(arp_globals.net_phone, packet_get_id(packet));
594 return NULL;
595 }
596 nil_send_msg(device->phone, device_id, packet, SERVICE_ARP);
597 return NULL;
598}
599
600int arp_translate_req(int arp_phone, device_id_t device_id, services_t protocol, measured_string_ref address, measured_string_ref * translation, char ** data){
601 measured_string_ref tmp;
602
603 fibril_rwlock_read_lock(&arp_globals.lock);
604 tmp = arp_translate_message(device_id, protocol, address);
605 if(tmp){
606 *translation = measured_string_copy(tmp);
607 fibril_rwlock_read_unlock(&arp_globals.lock);
608 if(*translation){
609 *data = (** translation).value;
610 return EOK;
611 }else{
612 return ENOMEM;
613 }
614 }else{
615 fibril_rwlock_read_unlock(&arp_globals.lock);
616 return ENOENT;
617 }
618}
619
620/** @}
621 */
Note: See TracBrowser for help on using the repository browser.