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

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

partial networking stack overhaul

  • a lot of coding style changes (comments, indentation, etc.)
  • convert several ints to unsigned ints or size_t values
  • streamline many of the IPC-related macros (they no longer dereference the call structure by themselves)
  • get rid of netif_interface.h (containing only aliases for remote functions and not serving any purpose)
  • rename netif_local.{c|h} to netif_skel.{c|h} (it is really just a skeleton)
  • drop the "_remote" and "_standalone" suffixes from most of the netif_ functions (they do not serve any purpose anymore)
  • implement netif_client_connection() as a common framework function for all netif modules
    • update the lo module accordingly
  • ip module now reports the default gateway to the user whenever it is being set
  • 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 "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, src_proto,
485 header->protocol_length);
486 /* Exists? */
487 if (trans && trans->hw_addr) {
488 if (trans->hw_addr->length != header->hardware_length)
489 return EINVAL;
490 memcpy(trans->hw_addr->value, src_hw, trans->hw_addr->length);
491 }
492 /* Is my protocol address? */
493 if (proto->addr->length != header->protocol_length)
494 return EINVAL;
495
496 if (!bcmp(proto->addr->value, des_proto, proto->addr->length)) {
497 /* Not already updated? */
498 if (!trans) {
499 trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
500 if (!trans)
501 return ENOMEM;
502 trans->hw_addr = NULL;
503 fibril_condvar_initialize(&trans->cv);
504 rc = arp_addr_add(&proto->addresses, src_proto,
505 header->protocol_length, trans);
506 if (rc != EOK) {
507 /* The generic char map has already freed trans! */
508 return rc;
509 }
510 }
511 if (!trans->hw_addr) {
512 trans->hw_addr = measured_string_create_bulk(src_hw,
513 header->hardware_length);
514 if (!trans->hw_addr)
515 return ENOMEM;
516
517 /* Notify the fibrils that wait for the translation. */
518 fibril_condvar_broadcast(&trans->cv);
519 }
520 if (ntohs(header->operation) == ARPOP_REQUEST) {
521 header->operation = htons(ARPOP_REPLY);
522 memcpy(des_proto, src_proto, header->protocol_length);
523 memcpy(src_proto, proto->addr->value,
524 header->protocol_length);
525 memcpy(src_hw, device->addr->value,
526 device->packet_dimension.addr_len);
527 memcpy(des_hw, trans->hw_addr->value,
528 header->hardware_length);
529
530 rc = packet_set_addr(packet, src_hw, des_hw,
531 header->hardware_length);
532 if (rc != EOK)
533 return rc;
534
535 nil_send_msg(device->phone, device_id, packet,
536 SERVICE_ARP);
537 return 1;
538 }
539 }
540
541 return EOK;
542}
543
544
545/** Returns the hardware address for the given protocol address.
546 *
547 * Sends the ARP request packet if the hardware address is not found in the
548 * cache.
549 *
550 * @param[in] device_id The device identifier.
551 * @param[in] protocol The protocol service.
552 * @param[in] target The target protocol address.
553 * @param[out] translation Where the hardware address of the target is stored.
554 * @return EOK on success.
555 * @return EAGAIN if the caller should try again.
556 * @return Other error codes in case of error.
557 */
558static int
559arp_translate_message(device_id_t device_id, services_t protocol,
560 measured_string_t *target, measured_string_t **translation)
561{
562 arp_device_t *device;
563 arp_proto_t *proto;
564 arp_trans_t *trans;
565 size_t length;
566 packet_t *packet;
567 arp_header_t *header;
568 bool retry = false;
569 int rc;
570
571restart:
572 if (!target || !translation)
573 return EBADMEM;
574
575 device = arp_cache_find(&arp_globals.cache, device_id);
576 if (!device)
577 return ENOENT;
578
579 proto = arp_protos_find(&device->protos, protocol);
580 if (!proto || (proto->addr->length != target->length))
581 return ENOENT;
582
583 trans = arp_addr_find(&proto->addresses, target->value, target->length);
584 if (trans) {
585 if (trans->hw_addr) {
586 *translation = trans->hw_addr;
587 return EOK;
588 }
589 if (retry)
590 return EAGAIN;
591 rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
592 ARP_TRANS_WAIT);
593 if (rc == ETIMEOUT)
594 return ENOENT;
595 retry = true;
596 goto restart;
597 }
598 if (retry)
599 return EAGAIN;
600
601 /* ARP packet content size = header + (address + translation) * 2 */
602 length = 8 + 2 * (proto->addr->length + device->addr->length);
603 if (length > device->packet_dimension.content)
604 return ELIMIT;
605
606 packet = packet_get_4_remote(arp_globals.net_phone,
607 device->packet_dimension.addr_len, device->packet_dimension.prefix,
608 length, device->packet_dimension.suffix);
609 if (!packet)
610 return ENOMEM;
611
612 header = (arp_header_t *) packet_suffix(packet, length);
613 if (!header) {
614 pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
615 return ENOMEM;
616 }
617
618 header->hardware = htons(device->hardware);
619 header->hardware_length = (uint8_t) device->addr->length;
620 header->protocol = htons(protocol_map(device->service, protocol));
621 header->protocol_length = (uint8_t) proto->addr->length;
622 header->operation = htons(ARPOP_REQUEST);
623 length = sizeof(arp_header_t);
624 memcpy(((uint8_t *) header) + length, device->addr->value,
625 device->addr->length);
626 length += device->addr->length;
627 memcpy(((uint8_t *) header) + length, proto->addr->value,
628 proto->addr->length);
629 length += proto->addr->length;
630 bzero(((uint8_t *) header) + length, device->addr->length);
631 length += device->addr->length;
632 memcpy(((uint8_t *) header) + length, target->value, target->length);
633
634 rc = packet_set_addr(packet, (uint8_t *) device->addr->value,
635 (uint8_t *) device->broadcast_addr->value, device->addr->length);
636 if (rc != EOK) {
637 pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
638 return rc;
639 }
640
641 nil_send_msg(device->phone, device_id, packet, SERVICE_ARP);
642
643 trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
644 if (!trans)
645 return ENOMEM;
646 trans->hw_addr = NULL;
647 fibril_condvar_initialize(&trans->cv);
648 rc = arp_addr_add(&proto->addresses, target->value, target->length,
649 trans);
650 if (rc != EOK) {
651 /* The generic char map has already freed trans! */
652 return rc;
653 }
654
655 rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
656 ARP_TRANS_WAIT);
657 if (rc == ETIMEOUT)
658 return ENOENT;
659 retry = true;
660 goto restart;
661}
662
663
664/** Processes the ARP message.
665 *
666 * @param[in] callid The message identifier.
667 * @param[in] call The message parameters.
668 * @param[out] answer The message answer parameters.
669 * @param[out] answer_count The last parameter for the actual answer in the
670 * answer parameter.
671 * @return EOK on success.
672 * @return ENOTSUP if the message is not known.
673 *
674 * @see arp_interface.h
675 * @see IS_NET_ARP_MESSAGE()
676 */
677int
678arp_message_standalone(ipc_callid_t callid, ipc_call_t *call,
679 ipc_call_t *answer, size_t *answer_count)
680{
681 measured_string_t *address;
682 measured_string_t *translation;
683 uint8_t *data;
684 packet_t *packet;
685 packet_t *next;
686 int rc;
687
688 *answer_count = 0;
689 switch (IPC_GET_IMETHOD(*call)) {
690 case IPC_M_PHONE_HUNGUP:
691 return EOK;
692
693 case NET_ARP_DEVICE:
694 rc = measured_strings_receive(&address, &data, 1);
695 if (rc != EOK)
696 return rc;
697
698 rc = arp_device_message(IPC_GET_DEVICE(*call),
699 IPC_GET_SERVICE(*call), ARP_GET_NETIF(*call), address);
700 if (rc != EOK) {
701 free(address);
702 free(data);
703 }
704 return rc;
705
706 case NET_ARP_TRANSLATE:
707 rc = measured_strings_receive(&address, &data, 1);
708 if (rc != EOK)
709 return rc;
710
711 fibril_mutex_lock(&arp_globals.lock);
712 rc = arp_translate_message(IPC_GET_DEVICE(*call),
713 IPC_GET_SERVICE(*call), address, &translation);
714 free(address);
715 free(data);
716 if (rc != EOK) {
717 fibril_mutex_unlock(&arp_globals.lock);
718 return rc;
719 }
720 if (!translation) {
721 fibril_mutex_unlock(&arp_globals.lock);
722 return ENOENT;
723 }
724 rc = measured_strings_reply(translation, 1);
725 fibril_mutex_unlock(&arp_globals.lock);
726 return rc;
727
728 case NET_ARP_CLEAR_DEVICE:
729 return arp_clear_device_req(0, IPC_GET_DEVICE(*call));
730
731 case NET_ARP_CLEAR_ADDRESS:
732 rc = measured_strings_receive(&address, &data, 1);
733 if (rc != EOK)
734 return rc;
735
736 arp_clear_address_req(0, IPC_GET_DEVICE(*call),
737 IPC_GET_SERVICE(*call), address);
738 free(address);
739 free(data);
740 return EOK;
741
742 case NET_ARP_CLEAN_CACHE:
743 return arp_clean_cache_req(0);
744
745 case NET_IL_DEVICE_STATE:
746 /* Do nothing - keep the cache */
747 return EOK;
748
749 case NET_IL_RECEIVED:
750
751 rc = packet_translate_remote(arp_globals.net_phone, &packet,
752 IPC_GET_PACKET(*call));
753 if (rc != EOK)
754 return rc;
755
756 fibril_mutex_lock(&arp_globals.lock);
757 do {
758 next = pq_detach(packet);
759 rc = arp_receive_message(IPC_GET_DEVICE(*call), packet);
760 if (rc != 1) {
761 pq_release_remote(arp_globals.net_phone,
762 packet_get_id(packet));
763 }
764 packet = next;
765 } while (packet);
766 fibril_mutex_unlock(&arp_globals.lock);
767
768 return EOK;
769
770 case NET_IL_MTU_CHANGED:
771 return arp_mtu_changed_message(IPC_GET_DEVICE(*call),
772 IPC_GET_MTU(*call));
773 }
774
775 return ENOTSUP;
776}
777
778/** Default thread for new connections.
779 *
780 * @param[in] iid The initial message identifier.
781 * @param[in] icall The initial message call structure.
782 */
783static void il_client_connection(ipc_callid_t iid, ipc_call_t *icall)
784{
785 /*
786 * Accept the connection
787 * - Answer the first IPC_M_CONNECT_ME_TO call.
788 */
789 ipc_answer_0(iid, EOK);
790
791 while (true) {
792 ipc_call_t answer;
793 size_t count;
794
795 /* Clear the answer structure */
796 refresh_answer(&answer, &count);
797
798 /* Fetch the next message */
799 ipc_call_t call;
800 ipc_callid_t callid = async_get_call(&call);
801
802 /* Process the message */
803 int res = il_module_message_standalone(callid, &call, &answer,
804 &count);
805
806 /*
807 * End if told to either by the message or the processing
808 * result.
809 */
810 if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||
811 (res == EHANGUP))
812 return;
813
814 /* Answer the message */
815 answer_call(callid, res, &answer, count);
816 }
817}
818
819/** Starts the module.
820 *
821 * @return EOK on success.
822 * @return Other error codes as defined for each specific module
823 * start function.
824 */
825int main(int argc, char *argv[])
826{
827 int rc;
828
829 /* Start the module */
830 rc = il_module_start_standalone(il_client_connection);
831 return rc;
832}
833
834/** @}
835 */
836
Note: See TracBrowser for help on using the repository browser.