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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ffa2c8ef was ffa2c8ef, checked in by Martin Decky <martin@…>, 14 years ago

do not intermix low-level IPC methods with async framework methods

  • Property mode set to 100644
File size: 23.7 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 <assert.h>
43#include <stdio.h>
44#include <str.h>
45#include <task.h>
46#include <adt/measured_strings.h>
47#include <ipc/services.h>
48#include <ipc/net.h>
49#include <ipc/arp.h>
50#include <ipc/il.h>
51#include <ipc/nil.h>
52#include <byteorder.h>
53#include <errno.h>
54#include <net/modules.h>
55#include <net/device.h>
56#include <net/packet.h>
57#include <nil_remote.h>
58#include <protocol_map.h>
59#include <packet_client.h>
60#include <packet_remote.h>
61#include <il_remote.h>
62#include <il_skel.h>
63#include "arp.h"
64
65/** ARP module name. */
66#define NAME "arp"
67
68/** Number of microseconds to wait for an ARP reply. */
69#define ARP_TRANS_WAIT 1000000
70
71/** @name ARP operation codes definitions */
72/*@{*/
73
74/** REQUEST operation code. */
75#define ARPOP_REQUEST 1
76
77/** REPLY operation code. */
78#define ARPOP_REPLY 2
79
80/*@}*/
81
82/** Type definition of an ARP protocol header.
83 * @see arp_header
84 */
85typedef struct arp_header arp_header_t;
86
87/** ARP protocol header. */
88struct arp_header {
89 /**
90 * Hardware type identifier.
91 * @see hardware.h
92 */
93 uint16_t hardware;
94
95 /** Protocol identifier. */
96 uint16_t protocol;
97 /** Hardware address length in bytes. */
98 uint8_t hardware_length;
99 /** Protocol address length in bytes. */
100 uint8_t protocol_length;
101
102 /**
103 * ARP packet type.
104 * @see arp_oc.h
105 */
106 uint16_t operation;
107} __attribute__ ((packed));
108
109/** ARP global data. */
110arp_globals_t arp_globals;
111
112DEVICE_MAP_IMPLEMENT(arp_cache, arp_device_t);
113INT_MAP_IMPLEMENT(arp_protos, arp_proto_t);
114GENERIC_CHAR_MAP_IMPLEMENT(arp_addr, arp_trans_t);
115
116static void arp_clear_trans(arp_trans_t *trans)
117{
118 if (trans->hw_addr) {
119 free(trans->hw_addr);
120 trans->hw_addr = NULL;
121 }
122
123 fibril_condvar_broadcast(&trans->cv);
124}
125
126static void arp_clear_addr(arp_addr_t *addresses)
127{
128 int count;
129
130 for (count = arp_addr_count(addresses) - 1; count >= 0; count--) {
131 arp_trans_t *trans = arp_addr_items_get_index(&addresses->values,
132 count);
133 if (trans)
134 arp_clear_trans(trans);
135 }
136}
137
138/** Clear the device specific data.
139 *
140 * @param[in] device Device specific data.
141 */
142static void arp_clear_device(arp_device_t *device)
143{
144 int count;
145
146 for (count = arp_protos_count(&device->protos) - 1; count >= 0;
147 count--) {
148 arp_proto_t *proto = arp_protos_get_index(&device->protos,
149 count);
150
151 if (proto) {
152 if (proto->addr)
153 free(proto->addr);
154
155 if (proto->addr_data)
156 free(proto->addr_data);
157
158 arp_clear_addr(&proto->addresses);
159 arp_addr_destroy(&proto->addresses);
160 }
161 }
162
163 arp_protos_clear(&device->protos);
164}
165
166static int arp_clean_cache_req(int arp_phone)
167{
168 int count;
169
170 fibril_mutex_lock(&arp_globals.lock);
171 for (count = arp_cache_count(&arp_globals.cache) - 1; count >= 0;
172 count--) {
173 arp_device_t *device = arp_cache_get_index(&arp_globals.cache,
174 count);
175
176 if (device) {
177 arp_clear_device(device);
178 if (device->addr_data)
179 free(device->addr_data);
180
181 if (device->broadcast_data)
182 free(device->broadcast_data);
183 }
184 }
185
186 arp_cache_clear(&arp_globals.cache);
187 fibril_mutex_unlock(&arp_globals.lock);
188
189 return EOK;
190}
191
192static int arp_clear_address_req(int arp_phone, device_id_t device_id,
193 services_t protocol, measured_string_t *address)
194{
195 fibril_mutex_lock(&arp_globals.lock);
196
197 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
198 if (!device) {
199 fibril_mutex_unlock(&arp_globals.lock);
200 return ENOENT;
201 }
202
203 arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
204 if (!proto) {
205 fibril_mutex_unlock(&arp_globals.lock);
206 return ENOENT;
207 }
208
209 arp_trans_t *trans = arp_addr_find(&proto->addresses, address->value,
210 address->length);
211 if (trans)
212 arp_clear_trans(trans);
213
214 arp_addr_exclude(&proto->addresses, address->value, address->length);
215
216 fibril_mutex_unlock(&arp_globals.lock);
217 return EOK;
218}
219
220static int arp_clear_device_req(int arp_phone, device_id_t device_id)
221{
222 fibril_mutex_lock(&arp_globals.lock);
223
224 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
225 if (!device) {
226 fibril_mutex_unlock(&arp_globals.lock);
227 return ENOENT;
228 }
229
230 arp_clear_device(device);
231
232 fibril_mutex_unlock(&arp_globals.lock);
233 return EOK;
234}
235
236/** Create new protocol specific data.
237 *
238 * Allocate and return the needed memory block as the proto parameter.
239 *
240 * @param[out] proto Allocated protocol specific data.
241 * @param[in] service Protocol module service.
242 * @param[in] address Actual protocol device address.
243 *
244 * @return EOK on success.
245 * @return ENOMEM if there is not enough memory left.
246 *
247 */
248static int arp_proto_create(arp_proto_t **proto, services_t service,
249 measured_string_t *address)
250{
251 *proto = (arp_proto_t *) malloc(sizeof(arp_proto_t));
252 if (!*proto)
253 return ENOMEM;
254
255 (*proto)->service = service;
256 (*proto)->addr = address;
257 (*proto)->addr_data = address->value;
258
259 int rc = arp_addr_initialize(&(*proto)->addresses);
260 if (rc != EOK) {
261 free(*proto);
262 return rc;
263 }
264
265 return EOK;
266}
267
268/** Process the received ARP packet.
269 *
270 * Update the source hardware address if the source entry exists or the packet
271 * is targeted to my protocol address.
272 *
273 * Respond to the ARP request if the packet is the ARP request and is
274 * targeted to my address.
275 *
276 * @param[in] device_id Source device identifier.
277 * @param[in,out] packet Received packet.
278 *
279 * @return EOK on success and the packet is no longer needed.
280 * @return One on success and the packet has been reused.
281 * @return EINVAL if the packet is too small to carry an ARP
282 * packet.
283 * @return EINVAL if the received address lengths differs from
284 * the registered values.
285 * @return ENOENT if the device is not found in the cache.
286 * @return ENOENT if the protocol for the device is not found in
287 * the cache.
288 * @return ENOMEM if there is not enough memory left.
289 *
290 */
291static int arp_receive_message(device_id_t device_id, packet_t *packet)
292{
293 int rc;
294
295 size_t length = packet_get_data_length(packet);
296 if (length <= sizeof(arp_header_t))
297 return EINVAL;
298
299 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
300 if (!device)
301 return ENOENT;
302
303 arp_header_t *header = (arp_header_t *) packet_get_data(packet);
304 if ((ntohs(header->hardware) != device->hardware) ||
305 (length < sizeof(arp_header_t) + header->hardware_length * 2U +
306 header->protocol_length * 2U)) {
307 return EINVAL;
308 }
309
310 arp_proto_t *proto = arp_protos_find(&device->protos,
311 protocol_unmap(device->service, ntohs(header->protocol)));
312 if (!proto)
313 return ENOENT;
314
315 uint8_t *src_hw = ((uint8_t *) header) + sizeof(arp_header_t);
316 uint8_t *src_proto = src_hw + header->hardware_length;
317 uint8_t *des_hw = src_proto + header->protocol_length;
318 uint8_t *des_proto = des_hw + header->hardware_length;
319
320 arp_trans_t *trans = arp_addr_find(&proto->addresses, src_proto,
321 header->protocol_length);
322
323 if ((trans) && (trans->hw_addr)) {
324 /* Translation exists */
325 if (trans->hw_addr->length != header->hardware_length)
326 return EINVAL;
327
328 memcpy(trans->hw_addr->value, src_hw, trans->hw_addr->length);
329 }
330
331 /* Is my protocol address? */
332 if (proto->addr->length != header->protocol_length)
333 return EINVAL;
334
335 if (!bcmp(proto->addr->value, des_proto, proto->addr->length)) {
336 if (!trans) {
337 /* Update the translation */
338 trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
339 if (!trans)
340 return ENOMEM;
341
342 trans->hw_addr = NULL;
343 fibril_condvar_initialize(&trans->cv);
344 rc = arp_addr_add(&proto->addresses, src_proto,
345 header->protocol_length, trans);
346 if (rc != EOK) {
347 /* The generic char map has already freed trans! */
348 return rc;
349 }
350 }
351
352 if (!trans->hw_addr) {
353 trans->hw_addr = measured_string_create_bulk(src_hw,
354 header->hardware_length);
355 if (!trans->hw_addr)
356 return ENOMEM;
357
358 /* Notify the fibrils that wait for the translation. */
359 fibril_condvar_broadcast(&trans->cv);
360 }
361
362 if (ntohs(header->operation) == ARPOP_REQUEST) {
363 header->operation = htons(ARPOP_REPLY);
364 memcpy(des_proto, src_proto, header->protocol_length);
365 memcpy(src_proto, proto->addr->value,
366 header->protocol_length);
367 memcpy(src_hw, device->addr->value,
368 device->packet_dimension.addr_len);
369 memcpy(des_hw, trans->hw_addr->value,
370 header->hardware_length);
371
372 rc = packet_set_addr(packet, src_hw, des_hw,
373 header->hardware_length);
374 if (rc != EOK)
375 return rc;
376
377 nil_send_msg(device->phone, device_id, packet,
378 SERVICE_ARP);
379 return 1;
380 }
381 }
382
383 return EOK;
384}
385
386/** Update the device content length according to the new MTU value.
387 *
388 * @param[in] device_id Device identifier.
389 * @param[in] mtu New MTU value.
390 *
391 * @return ENOENT if device is not found.
392 * @return EOK on success.
393 *
394 */
395static int arp_mtu_changed_message(device_id_t device_id, size_t mtu)
396{
397 fibril_mutex_lock(&arp_globals.lock);
398
399 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
400 if (!device) {
401 fibril_mutex_unlock(&arp_globals.lock);
402 return ENOENT;
403 }
404
405 device->packet_dimension.content = mtu;
406
407 fibril_mutex_unlock(&arp_globals.lock);
408
409 printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
410
411 return EOK;
412}
413
414/** Process IPC messages from the registered device driver modules
415 *
416 * @param[in] iid Message identifier.
417 * @param[in,out] icall Message parameters.
418 *
419 */
420static void arp_receiver(ipc_callid_t iid, ipc_call_t *icall)
421{
422 packet_t *packet;
423 int rc;
424
425 while (true) {
426 switch (IPC_GET_IMETHOD(*icall)) {
427 case NET_IL_DEVICE_STATE:
428 /* Do nothing - keep the cache */
429 async_answer_0(iid, (sysarg_t) EOK);
430 break;
431
432 case NET_IL_RECEIVED:
433 rc = packet_translate_remote(arp_globals.net_phone, &packet,
434 IPC_GET_PACKET(*icall));
435 if (rc == EOK) {
436 fibril_mutex_lock(&arp_globals.lock);
437 do {
438 packet_t *next = pq_detach(packet);
439 rc = arp_receive_message(IPC_GET_DEVICE(*icall), packet);
440 if (rc != 1) {
441 pq_release_remote(arp_globals.net_phone,
442 packet_get_id(packet));
443 }
444
445 packet = next;
446 } while (packet);
447 fibril_mutex_unlock(&arp_globals.lock);
448 }
449 async_answer_0(iid, (sysarg_t) rc);
450 break;
451
452 case NET_IL_MTU_CHANGED:
453 rc = arp_mtu_changed_message(IPC_GET_DEVICE(*icall),
454 IPC_GET_MTU(*icall));
455 async_answer_0(iid, (sysarg_t) rc);
456 break;
457
458 default:
459 async_answer_0(iid, (sysarg_t) ENOTSUP);
460 }
461
462 iid = async_get_call(icall);
463 }
464}
465
466/** Register the device.
467 *
468 * Create new device entry in the cache or update the protocol address if the
469 * device with the device identifier and the driver service exists.
470 *
471 * @param[in] device_id Device identifier.
472 * @param[in] service Device driver service.
473 * @param[in] protocol Protocol service.
474 * @param[in] address Actual device protocol address.
475 *
476 * @return EOK on success.
477 * @return EEXIST if another device with the same device identifier
478 * and different driver service exists.
479 * @return ENOMEM if there is not enough memory left.
480 * @return Other error codes as defined for the
481 * measured_strings_return() function.
482 *
483 */
484static int arp_device_message(device_id_t device_id, services_t service,
485 services_t protocol, measured_string_t *address)
486{
487 int index;
488 int rc;
489
490 fibril_mutex_lock(&arp_globals.lock);
491
492 /* An existing device? */
493 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
494 if (device) {
495 if (device->service != service) {
496 printf("%s: Device %d already exists\n", NAME,
497 device->device_id);
498 fibril_mutex_unlock(&arp_globals.lock);
499 return EEXIST;
500 }
501
502 arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
503 if (proto) {
504 free(proto->addr);
505 free(proto->addr_data);
506 proto->addr = address;
507 proto->addr_data = address->value;
508 } else {
509 rc = arp_proto_create(&proto, protocol, address);
510 if (rc != EOK) {
511 fibril_mutex_unlock(&arp_globals.lock);
512 return rc;
513 }
514
515 index = arp_protos_add(&device->protos, proto->service,
516 proto);
517 if (index < 0) {
518 fibril_mutex_unlock(&arp_globals.lock);
519 free(proto);
520 return index;
521 }
522
523 printf("%s: New protocol added (id: %d, proto: %d)\n", NAME,
524 device_id, protocol);
525 }
526 } else {
527 hw_type_t hardware = hardware_map(service);
528 if (!hardware)
529 return ENOENT;
530
531 /* Create new device */
532 device = (arp_device_t *) malloc(sizeof(arp_device_t));
533 if (!device) {
534 fibril_mutex_unlock(&arp_globals.lock);
535 return ENOMEM;
536 }
537
538 device->hardware = hardware;
539 device->device_id = device_id;
540 rc = arp_protos_initialize(&device->protos);
541 if (rc != EOK) {
542 fibril_mutex_unlock(&arp_globals.lock);
543 free(device);
544 return rc;
545 }
546
547 arp_proto_t *proto;
548 rc = arp_proto_create(&proto, protocol, address);
549 if (rc != EOK) {
550 fibril_mutex_unlock(&arp_globals.lock);
551 free(device);
552 return rc;
553 }
554
555 index = arp_protos_add(&device->protos, proto->service, proto);
556 if (index < 0) {
557 fibril_mutex_unlock(&arp_globals.lock);
558 arp_protos_destroy(&device->protos);
559 free(device);
560 return index;
561 }
562
563 device->service = service;
564
565 /* Bind */
566 device->phone = nil_bind_service(device->service,
567 (sysarg_t) device->device_id, SERVICE_ARP,
568 arp_receiver);
569 if (device->phone < 0) {
570 fibril_mutex_unlock(&arp_globals.lock);
571 arp_protos_destroy(&device->protos);
572 free(device);
573 return EREFUSED;
574 }
575
576 /* Get packet dimensions */
577 rc = nil_packet_size_req(device->phone, device_id,
578 &device->packet_dimension);
579 if (rc != EOK) {
580 fibril_mutex_unlock(&arp_globals.lock);
581 arp_protos_destroy(&device->protos);
582 free(device);
583 return rc;
584 }
585
586 /* Get hardware address */
587 rc = nil_get_addr_req(device->phone, device_id, &device->addr,
588 &device->addr_data);
589 if (rc != EOK) {
590 fibril_mutex_unlock(&arp_globals.lock);
591 arp_protos_destroy(&device->protos);
592 free(device);
593 return rc;
594 }
595
596 /* Get broadcast address */
597 rc = nil_get_broadcast_addr_req(device->phone, device_id,
598 &device->broadcast_addr, &device->broadcast_data);
599 if (rc != EOK) {
600 fibril_mutex_unlock(&arp_globals.lock);
601 free(device->addr);
602 free(device->addr_data);
603 arp_protos_destroy(&device->protos);
604 free(device);
605 return rc;
606 }
607
608 rc = arp_cache_add(&arp_globals.cache, device->device_id,
609 device);
610 if (rc != EOK) {
611 fibril_mutex_unlock(&arp_globals.lock);
612 free(device->addr);
613 free(device->addr_data);
614 free(device->broadcast_addr);
615 free(device->broadcast_data);
616 arp_protos_destroy(&device->protos);
617 free(device);
618 return rc;
619 }
620 printf("%s: Device registered (id: %d, type: 0x%x, service: %d,"
621 " proto: %d)\n", NAME, device->device_id, device->hardware,
622 device->service, protocol);
623 }
624
625 fibril_mutex_unlock(&arp_globals.lock);
626 return EOK;
627}
628
629int il_initialize(int net_phone)
630{
631 fibril_mutex_initialize(&arp_globals.lock);
632
633 fibril_mutex_lock(&arp_globals.lock);
634 arp_globals.net_phone = net_phone;
635 int rc = arp_cache_initialize(&arp_globals.cache);
636 fibril_mutex_unlock(&arp_globals.lock);
637
638 return rc;
639}
640
641static int arp_send_request(device_id_t device_id, services_t protocol,
642 measured_string_t *target, arp_device_t *device, arp_proto_t *proto)
643{
644 /* ARP packet content size = header + (address + translation) * 2 */
645 size_t length = 8 + 2 * (proto->addr->length + device->addr->length);
646 if (length > device->packet_dimension.content)
647 return ELIMIT;
648
649 packet_t *packet = packet_get_4_remote(arp_globals.net_phone,
650 device->packet_dimension.addr_len, device->packet_dimension.prefix,
651 length, device->packet_dimension.suffix);
652 if (!packet)
653 return ENOMEM;
654
655 arp_header_t *header = (arp_header_t *) packet_suffix(packet, length);
656 if (!header) {
657 pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
658 return ENOMEM;
659 }
660
661 header->hardware = htons(device->hardware);
662 header->hardware_length = (uint8_t) device->addr->length;
663 header->protocol = htons(protocol_map(device->service, protocol));
664 header->protocol_length = (uint8_t) proto->addr->length;
665 header->operation = htons(ARPOP_REQUEST);
666
667 length = sizeof(arp_header_t);
668
669 memcpy(((uint8_t *) header) + length, device->addr->value,
670 device->addr->length);
671 length += device->addr->length;
672 memcpy(((uint8_t *) header) + length, proto->addr->value,
673 proto->addr->length);
674 length += proto->addr->length;
675 bzero(((uint8_t *) header) + length, device->addr->length);
676 length += device->addr->length;
677 memcpy(((uint8_t *) header) + length, target->value, target->length);
678
679 int rc = packet_set_addr(packet, (uint8_t *) device->addr->value,
680 (uint8_t *) device->broadcast_addr->value, device->addr->length);
681 if (rc != EOK) {
682 pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
683 return rc;
684 }
685
686 nil_send_msg(device->phone, device_id, packet, SERVICE_ARP);
687 return EOK;
688}
689
690/** Return the hardware address for the given protocol address.
691 *
692 * Send the ARP request packet if the hardware address is not found in the
693 * cache.
694 *
695 * @param[in] device_id Device identifier.
696 * @param[in] protocol Protocol service.
697 * @param[in] target Target protocol address.
698 * @param[out] translation Where the hardware address of the target is stored.
699 *
700 * @return EOK on success.
701 * @return EAGAIN if the caller should try again.
702 * @return Other error codes in case of error.
703 *
704 */
705static int arp_translate_message(device_id_t device_id, services_t protocol,
706 measured_string_t *target, measured_string_t **translation)
707{
708 bool retry = false;
709 int rc;
710
711 assert(fibril_mutex_is_locked(&arp_globals.lock));
712
713restart:
714 if ((!target) || (!translation))
715 return EBADMEM;
716
717 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
718 if (!device)
719 return ENOENT;
720
721 arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
722 if ((!proto) || (proto->addr->length != target->length))
723 return ENOENT;
724
725 arp_trans_t *trans = arp_addr_find(&proto->addresses, target->value,
726 target->length);
727 if (trans) {
728 if (trans->hw_addr) {
729 /* The translation is in place. */
730 *translation = trans->hw_addr;
731 return EOK;
732 }
733
734 if (retry) {
735 /*
736 * We may get here as a result of being signalled for
737 * some reason while waiting for the translation (e.g.
738 * translation becoming available, record being removed
739 * from the table) and then losing the race for
740 * the arp_globals.lock with someone else who modified
741 * the table.
742 *
743 * Remove the incomplete record so that it is possible
744 * to make new ARP requests.
745 */
746 arp_clear_trans(trans);
747 arp_addr_exclude(&proto->addresses, target->value,
748 target->length);
749 return EAGAIN;
750 }
751
752 /*
753 * We are a random passer-by who merely joins an already waiting
754 * fibril in waiting for the translation.
755 */
756 rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
757 ARP_TRANS_WAIT);
758 if (rc == ETIMEOUT)
759 return ENOENT;
760
761 /*
762 * Need to recheck because we did not hold the lock while
763 * sleeping on the condition variable.
764 */
765 retry = true;
766 goto restart;
767 }
768
769 if (retry)
770 return EAGAIN;
771
772 /*
773 * We are under the protection of arp_globals.lock, so we can afford to
774 * first send the ARP request and then insert an incomplete ARP record.
775 * The incomplete record is used to tell any other potential waiter
776 * that this fibril has already sent the request and that it is waiting
777 * for the answer. Lastly, any fibril which sees the incomplete request
778 * can perform a timed wait on its condition variable to wait for the
779 * ARP reply to arrive.
780 */
781
782 rc = arp_send_request(device_id, protocol, target, device, proto);
783 if (rc != EOK)
784 return rc;
785
786 trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
787 if (!trans)
788 return ENOMEM;
789
790 trans->hw_addr = NULL;
791 fibril_condvar_initialize(&trans->cv);
792
793 rc = arp_addr_add(&proto->addresses, target->value, target->length,
794 trans);
795 if (rc != EOK) {
796 /* The generic char map has already freed trans! */
797 return rc;
798 }
799
800 rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
801 ARP_TRANS_WAIT);
802 if (rc == ETIMEOUT) {
803 /*
804 * Remove the incomplete record so that it is possible to make
805 * new ARP requests.
806 */
807 arp_clear_trans(trans);
808 arp_addr_exclude(&proto->addresses, target->value,
809 target->length);
810 return ENOENT;
811 }
812
813 /*
814 * We need to recheck that the translation has indeed become available,
815 * because we dropped the arp_globals.lock while sleeping on the
816 * condition variable and someone else might have e.g. removed the
817 * translation before we managed to lock arp_globals.lock again.
818 */
819
820 retry = true;
821 goto restart;
822}
823
824/** Process the ARP message.
825 *
826 * @param[in] callid Message identifier.
827 * @param[in] call Message parameters.
828 * @param[out] answer Answer.
829 * @param[out] count Number of arguments of the answer.
830 *
831 * @return EOK on success.
832 * @return ENOTSUP if the message is not known.
833 *
834 * @see arp_interface.h
835 * @see IS_NET_ARP_MESSAGE()
836 *
837 */
838int il_module_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
839 size_t *count)
840{
841 measured_string_t *address;
842 measured_string_t *translation;
843 uint8_t *data;
844 int rc;
845
846 *count = 0;
847 switch (IPC_GET_IMETHOD(*call)) {
848 case IPC_M_PHONE_HUNGUP:
849 return EOK;
850
851 case NET_ARP_DEVICE:
852 rc = measured_strings_receive(&address, &data, 1);
853 if (rc != EOK)
854 return rc;
855
856 rc = arp_device_message(IPC_GET_DEVICE(*call),
857 IPC_GET_SERVICE(*call), ARP_GET_NETIF(*call), address);
858 if (rc != EOK) {
859 free(address);
860 free(data);
861 }
862
863 return rc;
864
865 case NET_ARP_TRANSLATE:
866 rc = measured_strings_receive(&address, &data, 1);
867 if (rc != EOK)
868 return rc;
869
870 fibril_mutex_lock(&arp_globals.lock);
871 rc = arp_translate_message(IPC_GET_DEVICE(*call),
872 IPC_GET_SERVICE(*call), address, &translation);
873 free(address);
874 free(data);
875
876 if (rc != EOK) {
877 fibril_mutex_unlock(&arp_globals.lock);
878 return rc;
879 }
880
881 if (!translation) {
882 fibril_mutex_unlock(&arp_globals.lock);
883 return ENOENT;
884 }
885
886 rc = measured_strings_reply(translation, 1);
887 fibril_mutex_unlock(&arp_globals.lock);
888 return rc;
889
890 case NET_ARP_CLEAR_DEVICE:
891 return arp_clear_device_req(0, IPC_GET_DEVICE(*call));
892
893 case NET_ARP_CLEAR_ADDRESS:
894 rc = measured_strings_receive(&address, &data, 1);
895 if (rc != EOK)
896 return rc;
897
898 arp_clear_address_req(0, IPC_GET_DEVICE(*call),
899 IPC_GET_SERVICE(*call), address);
900 free(address);
901 free(data);
902 return EOK;
903
904 case NET_ARP_CLEAN_CACHE:
905 return arp_clean_cache_req(0);
906 }
907
908 return ENOTSUP;
909}
910
911int main(int argc, char *argv[])
912{
913 /* Start the module */
914 return il_module_start(SERVICE_ARP);
915}
916
917/** @}
918 */
Note: See TracBrowser for help on using the repository browser.