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

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

Replace @returns with @return.

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