source: mainline/uspace/srv/net/tl/icmp/icmp.c@ ffaba00

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

improve cstyle and comments

  • Property mode set to 100644
File size: 20.1 KB
Line 
1/*
2 * Copyright (c) 2008 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 icmp
30 * @{
31 */
32
33/** @file
34 * ICMP module implementation.
35 */
36
37#include <async.h>
38#include <atomic.h>
39#include <fibril.h>
40#include <fibril_synch.h>
41#include <stdint.h>
42#include <str.h>
43#include <ipc/ipc.h>
44#include <ipc/services.h>
45#include <ipc/net.h>
46#include <ipc/tl.h>
47#include <ipc/icmp.h>
48#include <sys/time.h>
49#include <sys/types.h>
50#include <byteorder.h>
51#include <errno.h>
52#include <adt/hash_table.h>
53
54#include <net/socket_codes.h>
55#include <net/ip_protocols.h>
56#include <net/inet.h>
57#include <net/modules.h>
58#include <net/icmp_api.h>
59#include <net/icmp_codes.h>
60#include <net/icmp_common.h>
61
62#include <packet_client.h>
63#include <packet_remote.h>
64#include <net_checksum.h>
65#include <icmp_client.h>
66#include <icmp_remote.h>
67#include <il_remote.h>
68#include <ip_client.h>
69#include <ip_interface.h>
70#include <net_interface.h>
71#include <tl_remote.h>
72#include <tl_skel.h>
73#include <icmp_header.h>
74
75/** ICMP module name */
76#define NAME "icmp"
77
78/** Number of replies hash table keys */
79#define REPLY_KEYS 2
80
81/** Number of replies hash table buckets */
82#define REPLY_BUCKETS 1024
83
84/**
85 * Original datagram length in bytes transfered to the error
86 * notification message.
87 */
88#define ICMP_KEEP_LENGTH 8
89
90/** Compute the ICMP datagram checksum.
91 *
92 * @param[in,out] header ICMP datagram header.
93 * @param[in] length Total datagram length.
94 *
95 * @return Computed checksum.
96 *
97 */
98#define ICMP_CHECKSUM(header, length) \
99 htons(ip_checksum((uint8_t *) (header), (length)))
100
101/** An echo request datagrams pattern. */
102#define ICMP_ECHO_TEXT "ICMP hello from HelenOS."
103
104/** ICMP reply data. */
105typedef struct {
106 /** Hash table link */
107 link_t link;
108
109 /** Reply identification and sequence */
110 icmp_param_t id;
111 icmp_param_t sequence;
112
113 /** Reply signaling */
114 fibril_condvar_t condvar;
115
116 /** Reply result */
117 int result;
118} icmp_reply_t;
119
120/** Global data */
121static int phone_net = -1;
122static int phone_ip = -1;
123static bool error_reporting = true;
124static bool echo_replying = true;
125static packet_dimension_t icmp_dimension;
126
127/** ICMP client identification counter */
128static atomic_t icmp_client;
129
130/** ICMP identifier and sequence number (client-specific) */
131static fibril_local icmp_param_t icmp_id;
132static fibril_local icmp_param_t icmp_seq;
133
134/** Reply hash table */
135static fibril_mutex_t reply_lock;
136static hash_table_t replies;
137
138static hash_index_t replies_hash(unsigned long key[])
139{
140 /*
141 * ICMP identifier and sequence numbers
142 * are 16-bit values.
143 */
144 hash_index_t index = ((key[0] & 0xffff) << 16) | (key[1] & 0xffff);
145 return (index % REPLY_BUCKETS);
146}
147
148static int replies_compare(unsigned long key[], hash_count_t keys, link_t *item)
149{
150 icmp_reply_t *reply =
151 hash_table_get_instance(item, icmp_reply_t, link);
152
153 if (keys == 1)
154 return (reply->id == key[0]);
155 else
156 return ((reply->id == key[0]) && (reply->sequence == key[1]));
157}
158
159static void replies_remove_callback(link_t *item)
160{
161}
162
163static hash_table_operations_t reply_ops = {
164 .hash = replies_hash,
165 .compare = replies_compare,
166 .remove_callback = replies_remove_callback
167};
168
169/** Release the packet and return the result.
170 *
171 * @param[in] packet Packet queue to be released.
172 *
173 */
174static void icmp_release(packet_t *packet)
175{
176 pq_release_remote(phone_net, packet_get_id(packet));
177}
178
179/** Send the ICMP message.
180 *
181 * Set the message type and code and compute the checksum.
182 * Error messages are sent only if allowed in the configuration.
183 * Release the packet on errors.
184 *
185 * @param[in] type Message type.
186 * @param[in] code Message code.
187 * @param[in] packet Message packet to be sent.
188 * @param[in] header ICMP header.
189 * @param[in] error Error service to be announced. Should be
190 * SERVICE_ICMP or zero.
191 * @param[in] ttl Time to live.
192 * @param[in] tos Type of service.
193 * @param[in] dont_fragment Disable fragmentation.
194 *
195 * @return EOK on success.
196 * @return EPERM if the error message is not allowed.
197 *
198 */
199static int icmp_send_packet(icmp_type_t type, icmp_code_t code,
200 packet_t *packet, icmp_header_t *header, services_t error, ip_ttl_t ttl,
201 ip_tos_t tos, bool dont_fragment)
202{
203 /* Do not send an error if disabled */
204 if ((error) && (!error_reporting)) {
205 icmp_release(packet);
206 return EPERM;
207 }
208
209 header->type = type;
210 header->code = code;
211
212 /*
213 * The checksum needs to be calculated
214 * with a virtual checksum field set to
215 * zero.
216 */
217 header->checksum = 0;
218 header->checksum = ICMP_CHECKSUM(header,
219 packet_get_data_length(packet));
220
221 int rc = ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl, tos,
222 dont_fragment, 0);
223 if (rc != EOK) {
224 icmp_release(packet);
225 return rc;
226 }
227
228 return ip_send_msg(phone_ip, -1, packet, SERVICE_ICMP, error);
229}
230
231/** Prepare the ICMP error packet.
232 *
233 * Truncate the original packet if longer than ICMP_KEEP_LENGTH bytes.
234 * Prefix and return the ICMP header.
235 *
236 * @param[in,out] packet Original packet.
237 *
238 * @return The prefixed ICMP header.
239 * @return NULL on errors.
240 *
241 */
242static icmp_header_t *icmp_prepare_packet(packet_t *packet)
243{
244 size_t total_length = packet_get_data_length(packet);
245 if (total_length <= 0)
246 return NULL;
247
248 size_t header_length = ip_client_header_length(packet);
249 if (header_length <= 0)
250 return NULL;
251
252 /* Truncate if longer than 64 bits (without the IP header) */
253 if ((total_length > header_length + ICMP_KEEP_LENGTH) &&
254 (packet_trim(packet, 0,
255 total_length - header_length - ICMP_KEEP_LENGTH) != EOK))
256 return NULL;
257
258 icmp_header_t *header = PACKET_PREFIX(packet, icmp_header_t);
259 if (!header)
260 return NULL;
261
262 bzero(header, sizeof(*header));
263 return header;
264}
265
266/** Request an echo message.
267 *
268 * Send a packet with specified parameters to the target host
269 * and wait for the reply upto the given timeout.
270 * Block the caller until the reply or the timeout occurs.
271 *
272 * @param[in] id Message identifier.
273 * @param[in] sequence Message sequence parameter.
274 * @param[in] size Message data length in bytes.
275 * @param[in] timeout Timeout in miliseconds.
276 * @param[in] ttl Time to live.
277 * @param[in] tos Type of service.
278 * @param[in] dont_fragment Disable fragmentation.
279 * @param[in] addr Target host address.
280 * @param[in] addrlen Torget host address length.
281 *
282 * @return ICMP_ECHO on success.
283 * @return ETIMEOUT if the reply has not arrived before the
284 * timeout.
285 * @return ICMP type of the received error notification.
286 * @return EINVAL if the addrlen parameter is less or equal to
287 * zero.
288 * @return ENOMEM if there is not enough memory left.
289 *
290 */
291static int icmp_echo(icmp_param_t id, icmp_param_t sequence, size_t size,
292 mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, bool dont_fragment,
293 const struct sockaddr *addr, socklen_t addrlen)
294{
295 if (addrlen <= 0)
296 return EINVAL;
297
298 size_t length = (size_t) addrlen;
299
300 packet_t *packet = packet_get_4_remote(phone_net, size,
301 icmp_dimension.addr_len, ICMP_HEADER_SIZE + icmp_dimension.prefix,
302 icmp_dimension.suffix);
303 if (!packet)
304 return ENOMEM;
305
306 /* Prepare the requesting packet, set the destination address. */
307 int rc = packet_set_addr(packet, NULL, (const uint8_t *) addr, length);
308 if (rc != EOK) {
309 icmp_release(packet);
310 return rc;
311 }
312
313 /* Allocate space in the packet */
314 uint8_t *data = (uint8_t *) packet_suffix(packet, size);
315 if (!data) {
316 icmp_release(packet);
317 return ENOMEM;
318 }
319
320 /* Fill the data */
321 length = 0;
322 while (size > length + sizeof(ICMP_ECHO_TEXT)) {
323 memcpy(data + length, ICMP_ECHO_TEXT, sizeof(ICMP_ECHO_TEXT));
324 length += sizeof(ICMP_ECHO_TEXT);
325 }
326 memcpy(data + length, ICMP_ECHO_TEXT, size - length);
327
328 /* Prefix the header */
329 icmp_header_t *header = PACKET_PREFIX(packet, icmp_header_t);
330 if (!header) {
331 icmp_release(packet);
332 return ENOMEM;
333 }
334
335 bzero(header, sizeof(icmp_header_t));
336 header->un.echo.identifier = id;
337 header->un.echo.sequence_number = sequence;
338
339 /* Prepare the reply structure */
340 icmp_reply_t *reply = malloc(sizeof(icmp_reply_t));
341 if (!reply) {
342 icmp_release(packet);
343 return ENOMEM;
344 }
345
346 reply->id = id;
347 reply->sequence = sequence;
348 fibril_condvar_initialize(&reply->condvar);
349
350 /* Add the reply to the replies hash table */
351 fibril_mutex_lock(&reply_lock);
352
353 unsigned long key[REPLY_KEYS] = {id, sequence};
354 hash_table_insert(&replies, key, &reply->link);
355
356 /* Send the request */
357 icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos,
358 dont_fragment);
359
360 /* Wait for the reply. Timeout in microseconds. */
361 rc = fibril_condvar_wait_timeout(&reply->condvar, &reply_lock,
362 timeout * 1000);
363 if (rc == EOK)
364 rc = reply->result;
365
366 /* Remove the reply from the replies hash table */
367 hash_table_remove(&replies, key, REPLY_KEYS);
368
369 fibril_mutex_unlock(&reply_lock);
370
371 free(reply);
372
373 return rc;
374}
375
376static int icmp_destination_unreachable(icmp_code_t code, icmp_param_t mtu,
377 packet_t *packet)
378{
379 icmp_header_t *header = icmp_prepare_packet(packet);
380 if (!header) {
381 icmp_release(packet);
382 return ENOMEM;
383 }
384
385 if (mtu)
386 header->un.frag.mtu = mtu;
387
388 return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header,
389 SERVICE_ICMP, 0, 0, false);
390}
391
392static int icmp_source_quench(packet_t *packet)
393{
394 icmp_header_t *header = icmp_prepare_packet(packet);
395 if (!header) {
396 icmp_release(packet);
397 return ENOMEM;
398 }
399
400 return icmp_send_packet(ICMP_SOURCE_QUENCH, 0, packet, header,
401 SERVICE_ICMP, 0, 0, false);
402}
403
404static int icmp_time_exceeded(icmp_code_t code, packet_t *packet)
405{
406 icmp_header_t *header = icmp_prepare_packet(packet);
407 if (!header) {
408 icmp_release(packet);
409 return ENOMEM;
410 }
411
412 return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header,
413 SERVICE_ICMP, 0, 0, false);
414}
415
416static int icmp_parameter_problem(icmp_code_t code, icmp_param_t pointer,
417 packet_t *packet)
418{
419 icmp_header_t *header = icmp_prepare_packet(packet);
420 if (!header) {
421 icmp_release(packet);
422 return ENOMEM;
423 }
424
425 header->un.param.pointer = pointer;
426 return icmp_send_packet(ICMP_PARAMETERPROB, code, packet, header,
427 SERVICE_ICMP, 0, 0, false);
428}
429
430/** Try to set the pending reply result as the received message type.
431 *
432 * If the reply data is not present, the reply timed out and the other fibril
433 * is already awake. The packet is released.
434 *
435 * @param[in] packet The received reply message.
436 * @param[in] header The ICMP message header.
437 * @param[in] type The received reply message type.
438 * @param[in] code The received reply message code.
439 *
440 */
441static void icmp_process_echo_reply(packet_t *packet, icmp_header_t *header,
442 icmp_type_t type, icmp_code_t code)
443{
444 unsigned long key[REPLY_KEYS] =
445 {header->un.echo.identifier, header->un.echo.sequence_number};
446
447 /* The packet is no longer needed */
448 icmp_release(packet);
449
450 /* Find the pending reply */
451 fibril_mutex_lock(&reply_lock);
452
453 link_t *link = hash_table_find(&replies, key);
454 if (link != NULL) {
455 icmp_reply_t *reply =
456 hash_table_get_instance(link, icmp_reply_t, link);
457
458 reply->result = type;
459 fibril_condvar_signal(&reply->condvar);
460 }
461
462 fibril_mutex_unlock(&reply_lock);
463}
464
465/** Process the received ICMP packet.
466 *
467 * Notify the destination socket application.
468 *
469 * @param[in,out] packet Received packet.
470 * @param[in] error Packet error reporting service to prefix
471 * the received packet.
472 *
473 * @return EOK on success.
474 * @return EINVAL if the packet is not valid.
475 * @return EINVAL if the stored packet address is not the an_addr_t.
476 * @return EINVAL if the packet does not contain any data.
477 * @return NO_DATA if the packet content is shorter than the user
478 * datagram header.
479 * @return ENOMEM if there is not enough memory left.
480 * @return EADDRNOTAVAIL if the destination socket does not exist.
481 * @return Other error codes as defined for the
482 * ip_client_process_packet() function.
483 *
484 */
485static int icmp_process_packet(packet_t *packet, services_t error)
486{
487 icmp_type_t type;
488 icmp_code_t code;
489 int rc;
490
491 switch (error) {
492 case SERVICE_NONE:
493 break;
494 case SERVICE_ICMP:
495 /* Process error */
496 rc = icmp_client_process_packet(packet, &type, &code, NULL, NULL);
497 if (rc < 0)
498 return rc;
499
500 /* Remove the error header */
501 rc = packet_trim(packet, (size_t) rc, 0);
502 if (rc != EOK)
503 return rc;
504
505 break;
506 default:
507 return ENOTSUP;
508 }
509
510 /* Get rid of the IP header */
511 size_t length = ip_client_header_length(packet);
512 rc = packet_trim(packet, length, 0);
513 if (rc != EOK)
514 return rc;
515
516 length = packet_get_data_length(packet);
517 if (length <= 0)
518 return EINVAL;
519
520 if (length < ICMP_HEADER_SIZE)
521 return EINVAL;
522
523 void *data = packet_get_data(packet);
524 if (!data)
525 return EINVAL;
526
527 /* Get ICMP header */
528 icmp_header_t *header = (icmp_header_t *) data;
529
530 if (header->checksum) {
531 while (ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO) {
532 /*
533 * Set the original message type on error notification.
534 * Type swap observed in Qemu.
535 */
536 if (error) {
537 switch (header->type) {
538 case ICMP_ECHOREPLY:
539 header->type = ICMP_ECHO;
540 continue;
541 }
542 }
543
544 return EINVAL;
545 }
546 }
547
548 switch (header->type) {
549 case ICMP_ECHOREPLY:
550 if (error)
551 icmp_process_echo_reply(packet, header, type, code);
552 else
553 icmp_process_echo_reply(packet, header, ICMP_ECHO, 0);
554
555 return EOK;
556
557 case ICMP_ECHO:
558 if (error) {
559 icmp_process_echo_reply(packet, header, type, code);
560 return EOK;
561 }
562
563 /* Do not send a reply if disabled */
564 if (echo_replying) {
565 uint8_t *src;
566 int addrlen = packet_get_addr(packet, &src, NULL);
567
568 /*
569 * Set both addresses to the source one (avoid the
570 * source address deletion before setting the
571 * destination one).
572 */
573 if ((addrlen > 0) && (packet_set_addr(packet, src, src,
574 (size_t) addrlen) == EOK)) {
575 /* Send the reply */
576 icmp_send_packet(ICMP_ECHOREPLY, 0, packet,
577 header, 0, 0, 0, 0);
578 return EOK;
579 }
580
581 return EINVAL;
582 }
583
584 return EPERM;
585
586 case ICMP_DEST_UNREACH:
587 case ICMP_SOURCE_QUENCH:
588 case ICMP_REDIRECT:
589 case ICMP_ALTERNATE_ADDR:
590 case ICMP_ROUTER_ADV:
591 case ICMP_ROUTER_SOL:
592 case ICMP_TIME_EXCEEDED:
593 case ICMP_PARAMETERPROB:
594 case ICMP_CONVERSION_ERROR:
595 case ICMP_REDIRECT_MOBILE:
596 case ICMP_SKIP:
597 case ICMP_PHOTURIS:
598 ip_received_error_msg(phone_ip, -1, packet,
599 SERVICE_IP, SERVICE_ICMP);
600 return EOK;
601
602 default:
603 return ENOTSUP;
604 }
605}
606
607/** Process IPC messages from the IP module
608 *
609 * @param[in] iid Message identifier.
610 * @param[in,out] icall Message parameters.
611 *
612 */
613static void icmp_receiver(ipc_callid_t iid, ipc_call_t *icall)
614{
615 bool loop = true;
616 packet_t *packet;
617 int rc;
618
619 while (loop) {
620 switch (IPC_GET_IMETHOD(*icall)) {
621 case NET_TL_RECEIVED:
622 rc = packet_translate_remote(phone_net, &packet,
623 IPC_GET_PACKET(*icall));
624 if (rc == EOK) {
625 rc = icmp_process_packet(packet, IPC_GET_ERROR(*icall));
626 if (rc != EOK)
627 icmp_release(packet);
628 }
629
630 ipc_answer_0(iid, (sysarg_t) rc);
631 break;
632 case IPC_M_PHONE_HUNGUP:
633 loop = false;
634 continue;
635 default:
636 ipc_answer_0(iid, (sysarg_t) ENOTSUP);
637 }
638
639 iid = async_get_call(icall);
640 }
641}
642
643/** Initialize the ICMP module.
644 *
645 * @param[in] net_phone Network module phone.
646 *
647 * @return EOK on success.
648 * @return ENOMEM if there is not enough memory left.
649 *
650 */
651int tl_initialize(int net_phone)
652{
653 measured_string_t names[] = {
654 {
655 (uint8_t *) "ICMP_ERROR_REPORTING",
656 20
657 },
658 {
659 (uint8_t *) "ICMP_ECHO_REPLYING",
660 18
661 }
662 };
663 measured_string_t *configuration;
664 size_t count = sizeof(names) / sizeof(measured_string_t);
665 uint8_t *data;
666
667 if (!hash_table_create(&replies, REPLY_BUCKETS, REPLY_KEYS, &reply_ops))
668 return ENOMEM;
669
670 fibril_mutex_initialize(&reply_lock);
671 atomic_set(&icmp_client, 0);
672
673 phone_net = net_phone;
674 phone_ip = ip_bind_service(SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP,
675 icmp_receiver);
676 if (phone_ip < 0)
677 return phone_ip;
678
679 int rc = ip_packet_size_req(phone_ip, -1, &icmp_dimension);
680 if (rc != EOK)
681 return rc;
682
683 icmp_dimension.prefix += ICMP_HEADER_SIZE;
684 icmp_dimension.content -= ICMP_HEADER_SIZE;
685
686 /* Get configuration */
687 configuration = &names[0];
688 rc = net_get_conf_req(phone_net, &configuration, count, &data);
689 if (rc != EOK)
690 return rc;
691
692 if (configuration) {
693 if (configuration[0].value)
694 error_reporting = (configuration[0].value[0] == 'y');
695
696 if (configuration[1].value)
697 echo_replying = (configuration[1].value[0] == 'y');
698
699 net_free_settings(configuration, data);
700 }
701
702 return EOK;
703}
704
705/** Per-connection initialization
706 *
707 * Initialize client-specific global variables.
708 *
709 */
710void tl_connection(void)
711{
712 icmp_id = (icmp_param_t) atomic_postinc(&icmp_client);
713 icmp_seq = 1;
714}
715
716/** Process the ICMP message.
717 *
718 * @param[in] callid Message identifier.
719 * @param[in] call Message parameters.
720 * @param[out] answer Answer.
721 * @param[out] count Number of arguments of the answer.
722 *
723 * @return EOK on success.
724 * @return ENOTSUP if the message is not known.
725 * @return Other error codes as defined for the packet_translate()
726 * function.
727 * @return Other error codes as defined for the
728 * icmp_destination_unreachable() function.
729 * @return Other error codes as defined for the
730 * icmp_source_quench() function.
731 * @return Other error codes as defined for the
732 * icmp_time_exceeded() function.
733 * @return Other error codes as defined for the
734 * icmp_parameter_problem() function.
735 *
736 * @see icmp_remote.h
737 * @see IS_NET_ICMP_MESSAGE()
738 *
739 */
740int tl_message(ipc_callid_t callid, ipc_call_t *call,
741 ipc_call_t *answer, size_t *count)
742{
743 struct sockaddr *addr;
744 size_t size;
745 packet_t *packet;
746 int rc;
747
748 *count = 0;
749
750 switch (IPC_GET_IMETHOD(*call)) {
751 case NET_ICMP_ECHO:
752 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &size);
753 if (rc != EOK)
754 return rc;
755
756 rc = icmp_echo(icmp_id, icmp_seq, ICMP_GET_SIZE(*call),
757 ICMP_GET_TIMEOUT(*call), ICMP_GET_TTL(*call),
758 ICMP_GET_TOS(*call), ICMP_GET_DONT_FRAGMENT(*call),
759 addr, (socklen_t) size);
760
761 free(addr);
762 icmp_seq++;
763 return rc;
764
765 case NET_ICMP_DEST_UNREACH:
766 rc = packet_translate_remote(phone_net, &packet,
767 IPC_GET_PACKET(*call));
768 if (rc != EOK)
769 return rc;
770
771 return icmp_destination_unreachable(ICMP_GET_CODE(*call),
772 ICMP_GET_MTU(*call), packet);
773
774 case NET_ICMP_SOURCE_QUENCH:
775 rc = packet_translate_remote(phone_net, &packet,
776 IPC_GET_PACKET(*call));
777 if (rc != EOK)
778 return rc;
779
780 return icmp_source_quench(packet);
781
782 case NET_ICMP_TIME_EXCEEDED:
783 rc = packet_translate_remote(phone_net, &packet,
784 IPC_GET_PACKET(*call));
785 if (rc != EOK)
786 return rc;
787
788 return icmp_time_exceeded(ICMP_GET_CODE(*call), packet);
789
790 case NET_ICMP_PARAMETERPROB:
791 rc = packet_translate_remote(phone_net, &packet,
792 IPC_GET_PACKET(*call));
793 if (rc != EOK)
794 return rc;
795
796 return icmp_parameter_problem(ICMP_GET_CODE(*call),
797 ICMP_GET_POINTER(*call), packet);
798 }
799
800 return ENOTSUP;
801}
802
803int main(int argc, char *argv[])
804{
805 /* Start the module */
806 return tl_module_start(SERVICE_ICMP);
807}
808
809/** @}
810 */
Note: See TracBrowser for help on using the repository browser.