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

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

streamline internetworking layer

  • IPC method renaming

NET_IL_DEVICE → NET_IP_DEVICE
NET_IL_PACKET_SPACE → NET_IP_PACKET_SPACE
NET_IL_SEND → NET_IP_SEND

The original methods were actually not generic methods of the IL layer (used by the lower layers), but specific methods of the IP module
and used by the higher layers. The original naming was rather confusing.

  • implelement common IL module skeleton
  • small improvements in the comments of the NETIF and NIL skeletons
  • IL modules now use a separate receiver function for the NET_IL_* calls
  • Property mode set to 100644
File size: 22.1 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#include <adt/measured_strings.h>
46#include <ipc/ipc.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 ipc_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 ipc_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 ipc_answer_0(iid, (sysarg_t) rc);
456 break;
457
458 default:
459 ipc_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
711restart:
712 if ((!target) || (!translation))
713 return EBADMEM;
714
715 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
716 if (!device)
717 return ENOENT;
718
719 arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
720 if ((!proto) || (proto->addr->length != target->length))
721 return ENOENT;
722
723 arp_trans_t *trans = arp_addr_find(&proto->addresses, target->value,
724 target->length);
725 if (trans) {
726 if (trans->hw_addr) {
727 *translation = trans->hw_addr;
728 return EOK;
729 }
730
731 if (retry) {
732 /* Remove the translation from the map */
733 arp_clear_trans(trans);
734 arp_addr_exclude(&proto->addresses, target->value,
735 target->length);
736 return EAGAIN;
737 }
738
739 rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
740 ARP_TRANS_WAIT);
741 if (rc == ETIMEOUT)
742 return ENOENT;
743
744 retry = true;
745 goto restart;
746 }
747
748 if (retry)
749 return EAGAIN;
750
751 trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
752 if (!trans)
753 return ENOMEM;
754
755 trans->hw_addr = NULL;
756 fibril_condvar_initialize(&trans->cv);
757
758 rc = arp_addr_add(&proto->addresses, target->value, target->length,
759 trans);
760 if (rc != EOK) {
761 /* The generic char map has already freed trans! */
762 return rc;
763 }
764
765 rc = arp_send_request(device_id, protocol, target, device, proto);
766 if (rc != EOK)
767 return rc;
768
769 rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
770 ARP_TRANS_WAIT);
771 if (rc == ETIMEOUT)
772 return ENOENT;
773
774 retry = true;
775 goto restart;
776}
777
778/** Process the ARP message.
779 *
780 * @param[in] callid Message identifier.
781 * @param[in] call Message parameters.
782 * @param[out] answer Answer.
783 * @param[out] count Number of arguments of the answer.
784 *
785 * @return EOK on success.
786 * @return ENOTSUP if the message is not known.
787 *
788 * @see arp_interface.h
789 * @see IS_NET_ARP_MESSAGE()
790 *
791 */
792int il_module_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
793 size_t *count)
794{
795 measured_string_t *address;
796 measured_string_t *translation;
797 uint8_t *data;
798 int rc;
799
800 *count = 0;
801 switch (IPC_GET_IMETHOD(*call)) {
802 case IPC_M_PHONE_HUNGUP:
803 return EOK;
804
805 case NET_ARP_DEVICE:
806 rc = measured_strings_receive(&address, &data, 1);
807 if (rc != EOK)
808 return rc;
809
810 rc = arp_device_message(IPC_GET_DEVICE(*call),
811 IPC_GET_SERVICE(*call), ARP_GET_NETIF(*call), address);
812 if (rc != EOK) {
813 free(address);
814 free(data);
815 }
816
817 return rc;
818
819 case NET_ARP_TRANSLATE:
820 rc = measured_strings_receive(&address, &data, 1);
821 if (rc != EOK)
822 return rc;
823
824 fibril_mutex_lock(&arp_globals.lock);
825 rc = arp_translate_message(IPC_GET_DEVICE(*call),
826 IPC_GET_SERVICE(*call), address, &translation);
827 free(address);
828 free(data);
829
830 if (rc != EOK) {
831 fibril_mutex_unlock(&arp_globals.lock);
832 return rc;
833 }
834
835 if (!translation) {
836 fibril_mutex_unlock(&arp_globals.lock);
837 return ENOENT;
838 }
839
840 rc = measured_strings_reply(translation, 1);
841 fibril_mutex_unlock(&arp_globals.lock);
842 return rc;
843
844 case NET_ARP_CLEAR_DEVICE:
845 return arp_clear_device_req(0, IPC_GET_DEVICE(*call));
846
847 case NET_ARP_CLEAR_ADDRESS:
848 rc = measured_strings_receive(&address, &data, 1);
849 if (rc != EOK)
850 return rc;
851
852 arp_clear_address_req(0, IPC_GET_DEVICE(*call),
853 IPC_GET_SERVICE(*call), address);
854 free(address);
855 free(data);
856 return EOK;
857
858 case NET_ARP_CLEAN_CACHE:
859 return arp_clean_cache_req(0);
860 }
861
862 return ENOTSUP;
863}
864
865int main(int argc, char *argv[])
866{
867 /* Start the module */
868 return il_module_start(SERVICE_ARP);
869}
870
871/** @}
872 */
Note: See TracBrowser for help on using the repository browser.