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

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

initial modifications for supporting declarative IPC interfaces

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