Subversion Repositories HelenOS

Rev

Rev 4715 | Rev 4720 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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.  *  @see icmp.h
  36.  */
  37.  
  38. #include <async.h>
  39. #include <atomic.h>
  40. #include <fibril.h>
  41. #include <fibril_sync.h>
  42.  
  43. #include <ipc/ipc.h>
  44. #include <ipc/services.h>
  45.  
  46. #include <sys/types.h>
  47.  
  48. #include "../../err.h"
  49. #include "../../messages.h"
  50. #include "../../modules.h"
  51.  
  52. #include "../../structures/packet/packet_client.h"
  53.  
  54. #include "../../include/byteorder.h"
  55. #include "../../include/crc.h"
  56. #include "../../include/icmp_api.h"
  57. #include "../../include/icmp_client.h"
  58. #include "../../include/icmp_codes.h"
  59. #include "../../include/icmp_common.h"
  60. #include "../../include/icmp_interface.h"
  61. #include "../../include/il_interface.h"
  62. #include "../../include/inet.h"
  63. #include "../../include/ip_client.h"
  64. #include "../../include/ip_interface.h"
  65. #include "../../include/ip_protocols.h"
  66. #include "../../include/socket_codes.h"
  67. #include "../../include/socket_errno.h"
  68.  
  69. #include "../../tl/tl_messages.h"
  70.  
  71. #include "icmp.h"
  72. #include "icmp_header.h"
  73. #include "icmp_messages.h"
  74. #include "icmp_module.h"
  75.  
  76. #define ICMP_KEEP_LENGTH    8
  77.  
  78. #define ICMP_CHECKSUM( header, length )     htons( ip_checksum(( uint8_t * ) ( header ), ( length )))
  79.  
  80. #define ICMP_ECHO_TEXT                  "Hello from HelenOS."
  81.  
  82. #define ICMP_GET_LOCK_KEY( id, sequence )   ((( id ) << 16 ) | ( sequence & 0xFFFF ))
  83.  
  84. /** Processes the received ICMP packet.
  85.  *  Is used as an entry point from the underlying IP module.
  86.  *  Releases the packet on error.
  87.  *  @param device_id The device identifier. Ignored parameter.
  88.  *  @param packet The received packet. Input/output parameter.
  89.  *  @param receiver The target service. Ignored parameter.
  90.  *  @param error The packet error reporting service. Prefixes the received packet. Input parameter.
  91.  *  @returns EOK on success.
  92.  *  @returns Other error codes as defined for the icmp_process_packet() function.
  93.  */
  94. int icmp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error );
  95.  
  96. /** Processes the received ICMP packet.
  97.  *  Notifies the destination socket application.
  98.  *  @param packet The received packet. Input/output parameter.
  99.  *  @param error The packet error reporting service. Prefixes the received packet. Input parameter.
  100.  *  @returns EOK on success.
  101.  *  @returns EINVAL if the packet is not valid.
  102.  *  @returns EINVAL if the stored packet address is not the an_addr_t.
  103.  *  @returns EINVAL if the packet does not contain any data.
  104.  *  @returns NO_DATA if the packet content is shorter than the user datagram header.
  105.  *  @returns ENOMEM if there is not enough memory left.
  106.  *  @returns EADDRNOTAVAIL if the destination socket does not exist.
  107.  *  @returns Other error codes as defined for the ip_client_process_packet() function.
  108.  */
  109. int icmp_process_packet( packet_t packet, services_t error );
  110.  
  111. /** Processes the client messages.
  112.  *  Remenbers the assigned identifier and sequence numbers.
  113.  *  Runs until the client module disconnects.
  114.  *  @param callid The message identifier. Input parameter.
  115.  *  @param call The message parameters. Input parameter.
  116.  *  @returns EOK on success.
  117.  *  @see icmp_interface.h
  118.  */
  119. int icmp_process_client_messages( ipc_callid_t callid, ipc_call_t call );
  120.  
  121. /** Releases the packet and returns the result.
  122.  *  @param packet The packet queue to be released. Input parameter.
  123.  *  @param result The result to be returned. Input parameter.
  124.  *  @return The result parameter.
  125.  */
  126. int icmp_release_and_return( packet_t packet, int result );
  127.  
  128. int icmp_echo( icmp_param_t id, icmp_param_t sequence, size_t size, suseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen );
  129. icmp_header_ref icmp_prepare_packet( packet_t packet );
  130. int icmp_send_packet( icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header, services_t error );
  131. int process_echo_reply( packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code );
  132.  
  133. /** ICMP global data.
  134.  */
  135. icmp_globals_t  icmp_globals;
  136.  
  137. INT_MAP_IMPLEMENT( time_locks, atomic_t );
  138.  
  139. GENERIC_FIELD_IMPLEMENT( echo_data, icmp_echo_t );
  140.  
  141. int icmp_echo_msg( int icmp_phone, size_t size, suseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen ){
  142.     icmp_echo_ref   echo_data;
  143.     int             res;
  144.  
  145.     fibril_rwlock_write_lock( & icmp_globals.lock );
  146.     // use the phone as the echo data index
  147.     echo_data = echo_data_get_index( & icmp_globals.echo_data, icmp_phone );
  148.     if( ! echo_data ){
  149.         res = ENOENT;
  150.     }else{
  151.         res = icmp_echo( echo_data->id, echo_data->sequence, size, timeout, ttl, tos, dont_fragment, addr, addrlen );
  152.         ++ echo_data->sequence;
  153.     }
  154.     fibril_rwlock_write_unlock( & icmp_globals.lock );
  155.     return res;
  156. }
  157.  
  158. int icmp_echo( icmp_param_t id, icmp_param_t sequence, size_t size, suseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen ){
  159.     ERROR_DECLARE;
  160.  
  161.     icmp_header_ref header;
  162.     packet_t        packet;
  163.     size_t          offset;
  164.     uint8_t *       data;
  165.     atomic_t *      lock;
  166.     int             result;
  167.     int             index;
  168.     int             lock_key;
  169.     struct sockaddr_in *    address_in;
  170.     struct timeval  time_before;
  171.     struct timeval  time_after;
  172.  
  173.     // TODO do not ask all the time
  174.     ERROR_PROPAGATE( ip_packet_size_req( icmp_globals.ip_phone, -1, & icmp_globals.addr_len, & icmp_globals.prefix, & icmp_globals.content, & icmp_globals.suffix ));
  175.     packet = packet_get_4( icmp_globals.net_phone, size, icmp_globals.addr_len, sizeof( icmp_header_t ) + icmp_globals.prefix, icmp_globals.suffix );
  176.     if( ! packet ) return ENOMEM;
  177.     // set the destination address
  178.     if( addrlen < sizeof( struct sockaddr )){
  179.         return icmp_release_and_return( packet, EINVAL );
  180.     }
  181.     switch( addr->sa_family ){
  182.         case AF_INET:
  183.             if( addrlen != sizeof( struct sockaddr_in )){
  184.                 return icmp_release_and_return( packet, EINVAL );
  185.             }
  186.             address_in = ( struct sockaddr_in * ) addr;
  187.             if( ERROR_OCCURRED( packet_set_addr( packet, NULL, ( uint8_t * ) & address_in->sin_addr.s_addr, sizeof( address_in->sin_addr.s_addr )))){
  188.                 return icmp_release_and_return( packet, ERROR_CODE );
  189.             }
  190.             break;
  191.         default:
  192.             return icmp_release_and_return( packet, EAFNOSUPPORT );
  193.     }
  194.     // allocate space in the packet
  195.     data = ( uint8_t * ) packet_suffix( packet, size );
  196.     if( ! data ){
  197.         return icmp_release_and_return( packet, ENOMEM );
  198.     }
  199.     offset = 0;
  200.     while( size > offset + sizeof( ICMP_ECHO_TEXT )){
  201.         memcpy( data + offset, ICMP_ECHO_TEXT, sizeof( ICMP_ECHO_TEXT ));
  202.         offset += sizeof( ICMP_ECHO_TEXT );
  203.     }
  204.     memcpy( data + offset, ICMP_ECHO_TEXT, size - offset );
  205.     header = icmp_prepare_packet( packet );
  206.     if( ! header ){
  207.         return icmp_release_and_return( packet, ENOMEM );
  208.     }
  209.     header->un.echo.id = id;
  210.     header->un.echo.sequence = sequence;
  211.     lock_key = ICMP_GET_LOCK_KEY( header->un.echo.id, header->un.echo.sequence );
  212.     // create a locked fuxed
  213.     lock = malloc( sizeof( * lock ));
  214.     if( ! lock ){
  215.         return icmp_release_and_return( packet, ENOMEM );
  216.     }
  217.     atomic_set( lock, 0 );
  218.     index = time_locks_add( & icmp_globals.time_locks, lock_key, lock );
  219.     if( index < 0 ){
  220.         free( lock );
  221.         return icmp_release_and_return( packet, index );
  222.     }
  223.     if( ERROR_OCCURRED( icmp_send_packet( ICMP_ECHO, 0, packet, header, 0 ))){
  224.         free( lock );
  225.         return icmp_release_and_return( packet, ERROR_CODE );
  226.     }
  227.     // unlock the global to allow unlocking and other fibrils to work
  228.     // try to lock again - may be unlocked by the reply
  229.     ERROR_PROPAGATE( gettimeofday( & time_before, NULL ));
  230.     do{
  231.         result = atomic_get( lock );
  232.         if( result ){
  233.             break;
  234.         }else{
  235.             fibril_rwlock_write_unlock( & icmp_globals.lock );
  236.             // TODO does not yield?
  237.             //printf( "y %d\n", fibril_yield());
  238.             fibril_yield();
  239.             fibril_rwlock_write_lock( & icmp_globals.lock );
  240.             ERROR_PROPAGATE( gettimeofday( & time_after, NULL ));
  241.         }
  242.     }while( tv_sub( & time_after, & time_before ) <= timeout );
  243.     if( ! result ){
  244.         result = ELIMIT;
  245.     }
  246.     // destroy the lock
  247.     time_locks_exclude_index( & icmp_globals.time_locks, index );
  248.     return result;
  249. }
  250.  
  251. int icmp_destination_unreachable_msg( int icmp_phone, icmp_code_t code, icmp_param_t mtu, packet_t packet ){
  252.     icmp_header_ref header;
  253.  
  254.     header = icmp_prepare_packet( packet );
  255.     if( ! header ) return ENOMEM;
  256.     if( mtu ){
  257.         header->un.frag.mtu = mtu;
  258.     }
  259.     return icmp_send_packet( ICMP_DEST_UNREACH, code, packet, header, SERVICE_ICMP );
  260. }
  261.  
  262. int icmp_source_quench_msg( int icmp_phone, packet_t packet ){
  263.     icmp_header_ref header;
  264.  
  265.     header = icmp_prepare_packet( packet );
  266.     if( ! header ) return ENOMEM;
  267.     return icmp_send_packet( ICMP_SOURCE_QUENCH, 0, packet, header, SERVICE_ICMP );
  268. }
  269.  
  270. int icmp_time_exceeded_msg( int icmp_phone, icmp_code_t code, packet_t packet ){
  271.     icmp_header_ref header;
  272.  
  273.     header = icmp_prepare_packet( packet );
  274.     if( ! header ) return ENOMEM;
  275.     return icmp_send_packet( ICMP_TIME_EXCEEDED, code, packet, header, SERVICE_ICMP );
  276. }
  277.  
  278. int icmp_parameter_problem_msg( int icmp_phone, icmp_code_t code, icmp_param_t pointer, packet_t packet ){
  279.     icmp_header_ref header;
  280.  
  281.     header = icmp_prepare_packet( packet );
  282.     if( ! header ) return ENOMEM;
  283.     header->un.param.pointer = pointer;
  284.     return icmp_send_packet( ICMP_PARAMETERPROB, code, packet, header, SERVICE_ICMP );
  285. }
  286.  
  287. icmp_header_ref icmp_prepare_packet( packet_t packet ){
  288.     icmp_header_ref header;
  289.     int             header_length;
  290.     size_t          total_length;
  291.  
  292.     total_length = packet_get_data_length( packet );
  293.     if( total_length <= 0 ) return NULL;
  294.     header_length = ip_client_header_length( packet );
  295.     if( header_length <= 0 ) return NULL;
  296.     // truncate if longer than 64 bits (without the IP header)
  297.     if( total_length - header_length > ICMP_KEEP_LENGTH ){
  298.         if( packet_trim( packet, 0, total_length - header_length - ICMP_KEEP_LENGTH ) != EOK ) return NULL;
  299.     }
  300.     header = PACKET_PREFIX( packet, icmp_header_t );
  301.     if( ! header ){
  302.         pq_release( icmp_globals.net_phone, packet_get_id( packet ));
  303.         return NULL;
  304.     }
  305.     bzero( header, sizeof( * header ));
  306.     return header;
  307. }
  308.  
  309. int icmp_send_packet( icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header, services_t error ){
  310.     ERROR_DECLARE;
  311.  
  312.     header->type = type;
  313.     header->code = code;
  314.     header->checksum = 0;
  315.     header->checksum = ICMP_CHECKSUM( header, packet_get_data_length( packet ));
  316.     if( ERROR_OCCURRED( ip_client_prepare_packet( packet, IPPROTO_ICMP, 0, 0, 0, 0 ))){
  317.         pq_release( icmp_globals.net_phone, packet_get_id( packet ));
  318.         return ERROR_CODE;
  319.     }
  320.     return ip_send_msg( icmp_globals.ip_phone, -1, packet, SERVICE_ICMP, error );
  321. }
  322.  
  323. int icmp_connect_module( services_t service ){
  324.     icmp_echo_ref   echo_data;
  325.     int             index;
  326.  
  327.     echo_data = ( icmp_echo_ref ) malloc( sizeof( * echo_data ));
  328.     if( ! echo_data ) return ENOMEM;
  329.     // assign a new identifier
  330.     fibril_rwlock_write_lock( & icmp_globals.lock );
  331.     ++ icmp_globals.last_used_id;
  332.     echo_data->id = icmp_globals.last_used_id;
  333.     echo_data->sequence = 0;
  334.     // remember the assigned echo data
  335.     index = echo_data_add( & icmp_globals.echo_data, echo_data );
  336.     if( index < 0 ){
  337.         free( echo_data );
  338.     }
  339.     fibril_rwlock_write_unlock( & icmp_globals.lock );
  340.     // return the echo data index as the ICMP phone
  341.     return index;
  342. }
  343.  
  344. int icmp_initialize( async_client_conn_t client_connection ){
  345.     ERROR_DECLARE;
  346.  
  347.     fibril_rwlock_initialize( & icmp_globals.lock );
  348.     fibril_rwlock_write_lock( & icmp_globals.lock );
  349.     time_locks_initialize( & icmp_globals.time_locks );
  350.     echo_data_initialize( & icmp_globals.echo_data );
  351.     icmp_globals.ip_phone = ip_bind_service( SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP, client_connection, icmp_received_msg );
  352.     if( icmp_globals.ip_phone < 0 ){
  353.         return icmp_globals.ip_phone;
  354.     }
  355.     ERROR_PROPAGATE( ip_packet_size_req( icmp_globals.ip_phone, -1, & icmp_globals.addr_len, & icmp_globals.prefix, & icmp_globals.content, & icmp_globals.suffix ));
  356.     icmp_globals.prefix += sizeof( icmp_header_t );
  357.     icmp_globals.content -= sizeof( icmp_header_t );
  358.     fibril_rwlock_write_unlock( & icmp_globals.lock );
  359.     return EOK;
  360. }
  361.  
  362. int icmp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ){
  363.     ERROR_DECLARE;
  364.  
  365.     if( ERROR_OCCURRED( icmp_process_packet( packet, error ))){
  366.         pq_release( icmp_globals.net_phone, packet_get_id( packet ));
  367.         return ERROR_CODE;
  368.     }
  369.  
  370.     return EOK;
  371. }
  372.  
  373. int icmp_process_packet( packet_t packet, services_t error ){
  374.     ERROR_DECLARE;
  375.  
  376.     size_t          length;
  377.     uint8_t *       src;
  378.     int             addrlen;
  379.     int             result;
  380.     void *          data;
  381.     icmp_header_ref header;
  382.     icmp_type_t     type;
  383.     icmp_code_t     code;
  384.  
  385.     if( error ){
  386.         switch( error ){
  387.             case SERVICE_ICMP:
  388.                 // process error
  389.                 // TODO remove debug dump
  390.                 // length = icmp_client_header_length( packet );
  391.                 result = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
  392.                 if( result < 0 ) return result;
  393.                 length = ( size_t ) result;
  394.                 printf( "ICMP error %d (%d) in packet %d\n", type, code, packet_get_id( packet ) );
  395.                 ERROR_PROPAGATE( packet_trim( packet, length, 0 ));
  396.                 break;
  397.             default:
  398.                 return ENOTSUP;
  399.         }
  400.     }
  401.     // get rid of the ip header
  402.     result = ip_client_process_packet( packet, NULL, NULL, NULL, NULL, NULL );
  403.     if( result < 0 ) return result;
  404.     packet_trim( packet, ( size_t ) result, 0 );
  405.  
  406.     length = packet_get_data_length( packet );
  407.     if( length <= 0 ) return EINVAL;
  408.     if( length < sizeof( icmp_header_t )) return EINVAL;
  409.     data = packet_get_data( packet );
  410.     if( ! data ) return EINVAL;
  411.     // get icmp header
  412.     header = ( icmp_header_ref ) data;
  413.     // checksum
  414.     if(( header->checksum ) && ( ICMP_CHECKSUM( header, length ))){
  415.         return EINVAL;
  416.     }
  417.     switch( header->type ){
  418.         case ICMP_ECHOREPLY:
  419.             return process_echo_reply( packet, header, ICMP_ECHO, 0 );
  420.         case ICMP_ECHO:
  421.             if( error ){
  422.                 return process_echo_reply( packet, header, type, code );
  423.             }else{
  424.                 addrlen = packet_get_addr( packet, & src, NULL );
  425.                 if(( addrlen > 0 )
  426.                 // set both addresses to the source one (avoids the source address deletion before setting the destination one)
  427.                 && ( packet_set_addr( packet, src, src, ( size_t ) addrlen ) == EOK )){
  428.                     // send the reply
  429.                     return icmp_send_packet( ICMP_ECHOREPLY, 0, packet, header, 0 );
  430.                 }else{
  431.                     return icmp_release_and_return( packet, EINVAL );
  432.                 }
  433.             }
  434.         case ICMP_DEST_UNREACH:
  435.         case ICMP_SOURCE_QUENCH:
  436.         case ICMP_REDIRECT:
  437.         case ICMP_ALTERNATE_ADDR:
  438.         case ICMP_ROUTER_ADV:
  439.         case ICMP_ROUTER_SOL:
  440.         case ICMP_TIME_EXCEEDED:
  441.         case ICMP_PARAMETERPROB:
  442.         case ICMP_CONVERSION_ERROR:
  443.         case ICMP_REDIRECT_MOBILE:
  444.         case ICMP_SKIP:
  445.         case ICMP_PHOTURIS:
  446.             fibril_rwlock_read_lock( & icmp_globals.lock );
  447.             ip_received_error_msg( icmp_globals.ip_phone, -1, packet, SERVICE_IP, SERVICE_ICMP );
  448.             fibril_rwlock_read_unlock( & icmp_globals.lock );
  449.             return EOK;
  450.         default:
  451.             return icmp_release_and_return( packet, ENOTSUP );
  452.     }
  453. }
  454.  
  455. int process_echo_reply( packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code ){
  456.     int             lock_key;
  457.     atomic_t *      lock;
  458.  
  459.     lock_key = ICMP_GET_LOCK_KEY( header->un.echo.id, header->un.echo.sequence );
  460.     fibril_rwlock_write_lock( & icmp_globals.lock );
  461.     lock = time_locks_find( & icmp_globals.time_locks, lock_key );
  462.     if( lock ){
  463.         // unlock the lock for the waiting fibril
  464.         atomic_set( lock, type );
  465.     }
  466.     pq_release( icmp_globals.net_phone, packet_get_id( packet ));
  467.     fibril_rwlock_write_unlock( & icmp_globals.lock );
  468.     return EOK;
  469. }
  470.  
  471. int icmp_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
  472.     ERROR_DECLARE;
  473.  
  474.     packet_t            packet;
  475.  
  476.     * answer_count = 0;
  477.     switch( IPC_GET_METHOD( * call )){
  478.         case NET_TL_RECEIVED:
  479.             if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
  480.                 ERROR_CODE = icmp_received_msg( IPC_GET_DEVICE( call ), packet, SERVICE_ICMP, IPC_GET_ERROR( call ));
  481.             }
  482.             return ERROR_CODE;
  483.         case NET_ICMP_INIT:
  484.             return icmp_process_client_messages( callid, * call );
  485.     }
  486.     return ENOTSUP;
  487. }
  488.  
  489. int icmp_process_client_messages( ipc_callid_t callid, ipc_call_t call ){
  490.     ERROR_DECLARE;
  491.  
  492.     bool                    keep_on_going = true;
  493.     fibril_rwlock_t         lock;
  494.     ipc_call_t              answer;
  495.     int                     answer_count;
  496.     packet_t                packet;
  497.     size_t                  addrlen;
  498.     struct sockaddr *       addr;
  499.     icmp_param_t            id;
  500.     icmp_param_t            sequence = 0;
  501.     ipc_callid_t            data_callid;
  502.  
  503.     /*
  504.      * Accept the connection
  505.      *  - Answer the first NET_ICMP_INIT call.
  506.      */
  507.     ipc_answer_0( callid, EOK );
  508.  
  509.     fibril_rwlock_initialize( & lock );
  510.  
  511.     // assign a new identifier
  512.     fibril_rwlock_write_lock( & icmp_globals.lock );
  513.     ++ icmp_globals.last_used_id;
  514.     id = icmp_globals.last_used_id;
  515.     fibril_rwlock_write_unlock( & icmp_globals.lock );
  516.  
  517.     while( keep_on_going ){
  518.         refresh_answer( & answer, & answer_count );
  519.  
  520.         callid = async_get_call( & call );
  521.  
  522.         switch( IPC_GET_METHOD( call )){
  523.             case IPC_M_PHONE_HUNGUP:
  524.                 keep_on_going = false;
  525.                 ERROR_CODE = EOK;
  526.                 break;
  527.             case NET_ICMP_ECHO:
  528.                 fibril_rwlock_write_lock( & lock );
  529.                 if( ! ipc_data_write_receive( & data_callid, & addrlen )){
  530.                     ERROR_CODE = EINVAL;
  531.                 }else{
  532.                     addr = malloc( addrlen );
  533.                     if( ! addr ){
  534.                         ERROR_CODE = ENOMEM;
  535.                     }else{
  536.                         if( ! ERROR_OCCURRED( ipc_data_write_finalize( data_callid, addr, addrlen ))){
  537.                             fibril_rwlock_write_lock( & icmp_globals.lock );
  538.                             ERROR_CODE = icmp_echo( id, sequence, ICMP_GET_SIZE( call ), ICMP_GET_TIMEOUT( call ), ICMP_GET_TTL( call ), ICMP_GET_TOS( call ), ICMP_GET_DONT_FRAGMENT( call ), addr, addrlen );
  539.                             fibril_rwlock_write_unlock( & icmp_globals.lock );
  540.                             free( addr );
  541.                             ++ sequence;
  542.                         }
  543.                     }
  544.                 }
  545.                 fibril_rwlock_write_unlock( & lock );
  546.                 break;
  547.             case NET_ICMP_DEST_UNREACH:
  548.                 if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( & call )))){
  549.                     ERROR_CODE = icmp_destination_unreachable_msg( 0, ICMP_GET_CODE( call ), ICMP_GET_MTU( call ), packet );
  550.                 }
  551.                 break;
  552.             case NET_ICMP_SOURCE_QUENCH:
  553.                 if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( & call )))){
  554.                     ERROR_CODE = icmp_source_quench_msg( 0, packet );
  555.                 }
  556.             case NET_ICMP_TIME_EXCEEDED:
  557.                 if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( & call )))){
  558.                     ERROR_CODE = icmp_time_exceeded_msg( 0, ICMP_GET_CODE( call ), packet );
  559.                 }
  560.                 break;
  561.             case NET_ICMP_PARAMETERPROB:
  562.                 if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( & call )))){
  563.                     ERROR_CODE = icmp_parameter_problem_msg( 0, ICMP_GET_CODE( call ), ICMP_GET_POINTER( call ), packet );
  564.                 }
  565.             default:
  566.                 ERROR_CODE = ENOTSUP;
  567.         }
  568.  
  569.         answer_call( callid, ERROR_CODE, & answer, answer_count );
  570.     }
  571.  
  572.     return EOK;
  573. }
  574.  
  575. int icmp_release_and_return( packet_t packet, int result ){
  576.     pq_release( icmp_globals.net_phone, packet_get_id( packet ));
  577.     return result;
  578. }
  579.  
  580. /** @}
  581.  */
  582.