Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/tl/icmp/icmp.c

    rd8f95529 r8e3a65c  
    2828
    2929/** @addtogroup icmp
    30  * @{
     30 *  @{
    3131 */
    3232
    3333/** @file
    34  * ICMP module implementation.
    35  * @see icmp.h
    36  */
    37 
    38 #include "icmp.h"
    39 #include "icmp_module.h"
     34 *  ICMP module implementation.
     35 *  @see icmp.h
     36 */
    4037
    4138#include <async.h>
     
    5451#include <byteorder.h>
    5552#include <errno.h>
     53#include <err.h>
    5654
    5755#include <net/socket_codes.h>
    5856#include <net/ip_protocols.h>
    5957#include <net/inet.h>
     58
    6059#include <net/modules.h>
    61 #include <net/icmp_api.h>
    62 #include <net/icmp_codes.h>
    63 #include <net/icmp_common.h>
    64 
    6560#include <packet_client.h>
    6661#include <packet_remote.h>
    6762#include <net_checksum.h>
     63#include <net/icmp_api.h>
    6864#include <icmp_client.h>
     65#include <net/icmp_codes.h>
     66#include <net/icmp_common.h>
    6967#include <icmp_interface.h>
    7068#include <il_interface.h>
     
    7674#include <icmp_header.h>
    7775
    78 /** ICMP module name. */
     76#include "icmp.h"
     77#include "icmp_module.h"
     78
     79/** ICMP module name.
     80 */
    7981#define NAME    "ICMP protocol"
    8082
    81 /** Default ICMP error reporting. */
     83/** Default ICMP error reporting.
     84 */
    8285#define NET_DEFAULT_ICMP_ERROR_REPORTING        true
    8386
    84 /** Default ICMP echo replying. */
     87/** Default ICMP echo replying.
     88 */
    8589#define NET_DEFAULT_ICMP_ECHO_REPLYING          true
    8690
    87 /** Original datagram length in bytes transfered to the error notification
    88  * message.
     91/** Original datagram length in bytes transfered to the error notification message.
    8992 */
    9093#define ICMP_KEEP_LENGTH        8
    9194
    92 /** Free identifier numbers pool start. */
     95/** Free identifier numbers pool start.
     96 */
    9397#define ICMP_FREE_IDS_START     1
    9498
    95 /** Free identifier numbers pool end. */
     99/** Free identifier numbers pool end.
     100 */
    96101#define ICMP_FREE_IDS_END       UINT16_MAX
    97102
    98103/** Computes the ICMP datagram checksum.
    99  *
    100  * @param[in,out] header The ICMP datagram header.
    101  * @param[in] length    The total datagram length.
    102  * @returns             The computed checksum.
    103  */
    104 #define ICMP_CHECKSUM(header, length) \
    105         htons(ip_checksum((uint8_t *) (header), (length)))
    106 
    107 /** An echo request datagrams pattern. */
    108 #define ICMP_ECHO_TEXT          "Hello from HelenOS."
     104 *  @param[in,out] header The ICMP datagram header.
     105 *  @param[in] length The total datagram length.
     106 *  @returns The computed checksum.
     107 */
     108#define ICMP_CHECKSUM(header, length)           htons(ip_checksum((uint8_t *) (header), (length)))
     109
     110/** An echo request datagrams pattern.
     111 */
     112#define ICMP_ECHO_TEXT                                  "Hello from HelenOS."
    109113
    110114/** Computes an ICMP reply data key.
    111  *
    112  * @param[in] id        The message identifier.
    113  * @param[in] sequence  The message sequence number.
    114  * @returns             The computed ICMP reply data key.
    115  */
    116 #define ICMP_GET_REPLY_KEY(id, sequence) \
    117         (((id) << 16) | (sequence & 0xFFFF))
    118 
    119 
    120 /** ICMP global data. */
     115 *  @param[in] id The message identifier.
     116 *  @param[in] sequence The message sequence number.
     117 *  @returns The computed ICMP reply data key.
     118 */
     119#define ICMP_GET_REPLY_KEY(id, sequence)        (((id) << 16) | (sequence &0xFFFF))
     120
     121/** Processes the received ICMP packet.
     122 *  Is used as an entry point from the underlying IP module.
     123 *  Releases the packet on error.
     124 *  @param device_id The device identifier. Ignored parameter.
     125 *  @param[in,out] packet The received packet.
     126 *  @param receiver The target service. Ignored parameter.
     127 *  @param[in] error The packet error reporting service. Prefixes the received packet.
     128 *  @returns EOK on success.
     129 *  @returns Other error codes as defined for the icmp_process_packet() function.
     130 */
     131int icmp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error);
     132
     133/** Processes the received ICMP packet.
     134 *  Notifies the destination socket application.
     135 *  @param[in,out] packet The received packet.
     136 *  @param[in] error The packet error reporting service. Prefixes the received packet.
     137 *  @returns EOK on success.
     138 *  @returns EINVAL if the packet is not valid.
     139 *  @returns EINVAL if the stored packet address is not the an_addr_t.
     140 *  @returns EINVAL if the packet does not contain any data.
     141 *  @returns NO_DATA if the packet content is shorter than the user datagram header.
     142 *  @returns ENOMEM if there is not enough memory left.
     143 *  @returns EADDRNOTAVAIL if the destination socket does not exist.
     144 *  @returns Other error codes as defined for the ip_client_process_packet() function.
     145 */
     146int icmp_process_packet(packet_t packet, services_t error);
     147
     148/** Processes the client messages.
     149 *  Remembers the assigned identifier and sequence numbers.
     150 *  Runs until the client module disconnects.
     151 *  @param[in] callid The message identifier.
     152 *  @param[in] call The message parameters.
     153 *  @returns EOK.
     154 *  @see icmp_interface.h
     155 *  @see icmp_api.h
     156 */
     157int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call);
     158
     159/** Processes the generic client messages.
     160 *  @param[in] call The message parameters.
     161 *  @returns EOK on success.
     162 *  @returns ENOTSUP if the message is not known.
     163 *  @returns Other error codes as defined for the packet_translate() function.
     164 *  @returns Other error codes as defined for the icmp_destination_unreachable_msg() function.
     165 *  @returns Other error codes as defined for the icmp_source_quench_msg() function.
     166 *  @returns Other error codes as defined for the icmp_time_exceeded_msg() function.
     167 *  @returns Other error codes as defined for the icmp_parameter_problem_msg() function.
     168 *  @see icmp_interface.h
     169 */
     170int icmp_process_message(ipc_call_t * call);
     171
     172/** Releases the packet and returns the result.
     173 *  @param[in] packet The packet queue to be released.
     174 *  @param[in] result The result to be returned.
     175 *  @returns The result parameter.
     176 */
     177int icmp_release_and_return(packet_t packet, int result);
     178
     179/** Requests an echo message.
     180 *  Sends a packet with specified parameters to the target host and waits for the reply upto the given timeout.
     181 *  Blocks the caller until the reply or the timeout occurs.
     182 *  @param[in] id The message identifier.
     183 *  @param[in] sequence The message sequence parameter.
     184 *  @param[in] size The message data length in bytes.
     185 *  @param[in] timeout The timeout in miliseconds.
     186 *  @param[in] ttl The time to live.
     187 *  @param[in] tos The type of service.
     188 *  @param[in] dont_fragment The value indicating whether the datagram must not be fragmented. Is used as a MTU discovery.
     189 *  @param[in] addr The target host address.
     190 *  @param[in] addrlen The torget host address length.
     191 *  @returns ICMP_ECHO on success.
     192 *  @returns ETIMEOUT if the reply has not arrived before the timeout.
     193 *  @returns ICMP type of the received error notification.
     194 *  @returns EINVAL if the addrlen parameter is less or equal to zero (<=0).
     195 *  @returns ENOMEM if there is not enough memory left.
     196 *  @returns EPARTY if there was an internal error.
     197 */
     198int icmp_echo(icmp_param_t id, icmp_param_t sequence, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen);
     199
     200/** Prepares the ICMP error packet.
     201 *  Truncates the original packet if longer than ICMP_KEEP_LENGTH bytes.
     202 *  Prefixes and returns the ICMP header.
     203 *  @param[in,out] packet The original packet.
     204 *  @returns The prefixed ICMP header.
     205 *  @returns NULL on errors.
     206 */
     207icmp_header_ref icmp_prepare_packet(packet_t packet);
     208
     209/** Sends the ICMP message.
     210 *  Sets the message type and code and computes the checksum.
     211 *  Error messages are sent only if allowed in the configuration.
     212 *  Releases the packet on errors.
     213 *  @param[in] type The message type.
     214 *  @param[in] code The message code.
     215 *  @param[in] packet The message packet to be sent.
     216 *  @param[in] header The ICMP header.
     217 *  @param[in] error The error service to be announced. Should be SERVICE_ICMP or zero (0).
     218 *  @param[in] ttl The time to live.
     219 *  @param[in] tos The type of service.
     220 *  @param[in] dont_fragment The value indicating whether the datagram must not be fragmented. Is used as a MTU discovery.
     221 *  @returns EOK on success.
     222 *  @returns EPERM if the error message is not allowed.
     223 */
     224int icmp_send_packet(icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header, services_t error, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment);
     225
     226/** Tries to set the pending reply result as the received message type.
     227 *  If the reply data is not present, the reply timed out and the other fibril
     228 *  is already awake.
     229 *  Releases the packet.
     230 *  @param[in] packet The received reply message.
     231 *  @param[in] header The ICMP message header.
     232 *  @param[in] type The received reply message type.
     233 *  @param[in] code The received reply message code.
     234 *  @returns EOK.
     235 */
     236int icmp_process_echo_reply(packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code);
     237
     238/** Assigns a new identifier for the connection.
     239 *  Fills the echo data parameter with the assigned values.
     240 *  @param[in,out] echo_data The echo data to be bound.
     241 *  @returns Index of the inserted echo data.
     242 *  @returns EBADMEM if the echo_data parameter is NULL.
     243 *  @returns ENOTCONN if no free identifier have been found.
     244 */
     245int icmp_bind_free_id(icmp_echo_ref echo_data);
     246
     247/** ICMP global data.
     248 */
    121249icmp_globals_t  icmp_globals;
    122250
    123251INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t);
     252
    124253INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t);
    125254
    126 /** Releases the packet and returns the result.
    127  *
    128  * @param[in] packet    The packet queue to be released.
    129  * @param[in] result    The result to be returned.
    130  * @returns             The result parameter.
    131  */
    132 static int icmp_release_and_return(packet_t packet, int result)
    133 {
    134         pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
     255int icmp_echo_msg(int icmp_phone, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen){
     256        icmp_echo_ref echo_data;
     257        int res;
     258
     259        fibril_rwlock_write_lock(&icmp_globals.lock);
     260        // use the phone as the echo data index
     261        echo_data = icmp_echo_data_find(&icmp_globals.echo_data, icmp_phone);
     262        if(! echo_data){
     263                res = ENOENT;
     264        }else{
     265                res = icmp_echo(echo_data->identifier, echo_data->sequence_number, size, timeout, ttl, tos, dont_fragment, addr, addrlen);
     266                if(echo_data->sequence_number < UINT16_MAX){
     267                        ++ echo_data->sequence_number;
     268                }else{
     269                        echo_data->sequence_number = 0;
     270                }
     271        }
     272        fibril_rwlock_write_unlock(&icmp_globals.lock);
     273        return res;
     274}
     275
     276int icmp_echo(icmp_param_t id, icmp_param_t sequence, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen){
     277        ERROR_DECLARE;
     278
     279        icmp_header_ref header;
     280        packet_t packet;
     281        size_t length;
     282        uint8_t * data;
     283        icmp_reply_ref reply;
     284        int reply_key;
     285        int result;
     286        int index;
     287
     288        if(addrlen <= 0){
     289                return EINVAL;
     290        }
     291        length = (size_t) addrlen;
     292        // TODO do not ask all the time
     293        ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1, &icmp_globals.packet_dimension));
     294        packet = packet_get_4_remote(icmp_globals.net_phone, size, icmp_globals.packet_dimension.addr_len, ICMP_HEADER_SIZE + icmp_globals.packet_dimension.prefix, icmp_globals.packet_dimension.suffix);
     295        if(! packet){
     296                return ENOMEM;
     297        }
     298
     299        // prepare the requesting packet
     300        // set the destination address
     301        if(ERROR_OCCURRED(packet_set_addr(packet, NULL, (const uint8_t *) addr, length))){
     302                return icmp_release_and_return(packet, ERROR_CODE);
     303        }
     304        // allocate space in the packet
     305        data = (uint8_t *) packet_suffix(packet, size);
     306        if(! data){
     307                return icmp_release_and_return(packet, ENOMEM);
     308        }
     309        // fill the data
     310        length = 0;
     311        while(size > length + sizeof(ICMP_ECHO_TEXT)){
     312                memcpy(data + length, ICMP_ECHO_TEXT, sizeof(ICMP_ECHO_TEXT));
     313                length += sizeof(ICMP_ECHO_TEXT);
     314        }
     315        memcpy(data + length, ICMP_ECHO_TEXT, size - length);
     316        // prefix the header
     317        header = PACKET_PREFIX(packet, icmp_header_t);
     318        if(! header){
     319                return icmp_release_and_return(packet, ENOMEM);
     320        }
     321        bzero(header, sizeof(*header));
     322        header->un.echo.identifier = id;
     323        header->un.echo.sequence_number = sequence;
     324
     325        // prepare the reply structure
     326        reply = malloc(sizeof(*reply));
     327        if(! reply){
     328                return icmp_release_and_return(packet, ENOMEM);
     329        }
     330        fibril_mutex_initialize(&reply->mutex);
     331        fibril_mutex_lock(&reply->mutex);
     332        fibril_condvar_initialize(&reply->condvar);
     333        reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier, header->un.echo.sequence_number);
     334        index = icmp_replies_add(&icmp_globals.replies, reply_key, reply);
     335        if(index < 0){
     336                free(reply);
     337                return icmp_release_and_return(packet, index);
     338        }
     339
     340        // unlock the globals so that we can wait for the reply
     341        fibril_rwlock_write_unlock(&icmp_globals.lock);
     342
     343        // send the request
     344        icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos, dont_fragment);
     345
     346        // wait for the reply
     347        // timeout in microseconds
     348        if(ERROR_OCCURRED(fibril_condvar_wait_timeout(&reply->condvar, &reply->mutex, timeout * 1000))){
     349                result = ERROR_CODE;
     350        }else{
     351                // read the result
     352                result = reply->result;
     353        }
     354
     355        // drop the reply mutex before locking the globals again
     356        fibril_mutex_unlock(&reply->mutex);
     357        fibril_rwlock_write_lock(&icmp_globals.lock);
     358
     359        // destroy the reply structure
     360        icmp_replies_exclude_index(&icmp_globals.replies, index);
    135361        return result;
    136362}
    137363
    138 /** Sends the ICMP message.
    139  *
    140  * Sets the message type and code and computes the checksum.
    141  * Error messages are sent only if allowed in the configuration.
    142  * Releases the packet on errors.
    143  *
    144  * @param[in] type      The message type.
    145  * @param[in] code      The message code.
    146  * @param[in] packet    The message packet to be sent.
    147  * @param[in] header    The ICMP header.
    148  * @param[in] error     The error service to be announced. Should be
    149  *                      SERVICE_ICMP or zero.
    150  * @param[in] ttl       The time to live.
    151  * @param[in] tos       The type of service.
    152  * @param[in] dont_fragment The value indicating whether the datagram must not
    153  *                      be fragmented. Is used as a MTU discovery.
    154  * @returns             EOK on success.
    155  * @returns             EPERM if the error message is not allowed.
    156  */
    157 static int
    158 icmp_send_packet(icmp_type_t type, icmp_code_t code, packet_t packet,
    159     icmp_header_ref header, services_t error, ip_ttl_t ttl, ip_tos_t tos,
    160     int dont_fragment)
    161 {
    162         int rc;
     364int icmp_destination_unreachable_msg(int icmp_phone, icmp_code_t code, icmp_param_t mtu, packet_t packet){
     365        icmp_header_ref header;
     366
     367        header = icmp_prepare_packet(packet);
     368        if(! header){
     369                return icmp_release_and_return(packet, ENOMEM);
     370        }
     371        if(mtu){
     372                header->un.frag.mtu = mtu;
     373        }
     374        return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header, SERVICE_ICMP, 0, 0, 0);
     375}
     376
     377int icmp_source_quench_msg(int icmp_phone, packet_t packet){
     378        icmp_header_ref header;
     379
     380        header = icmp_prepare_packet(packet);
     381        if(! header){
     382                return icmp_release_and_return(packet, ENOMEM);
     383        }
     384        return icmp_send_packet(ICMP_SOURCE_QUENCH, 0, packet, header, SERVICE_ICMP, 0, 0, 0);
     385}
     386
     387int icmp_time_exceeded_msg(int icmp_phone, icmp_code_t code, packet_t packet){
     388        icmp_header_ref header;
     389
     390        header = icmp_prepare_packet(packet);
     391        if(! header){
     392                return icmp_release_and_return(packet, ENOMEM);
     393        }
     394        return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header, SERVICE_ICMP, 0, 0, 0);
     395}
     396
     397int icmp_parameter_problem_msg(int icmp_phone, icmp_code_t code, icmp_param_t pointer, packet_t packet){
     398        icmp_header_ref header;
     399
     400        header = icmp_prepare_packet(packet);
     401        if(! header){
     402                return icmp_release_and_return(packet, ENOMEM);
     403        }
     404        header->un.param.pointer = pointer;
     405        return icmp_send_packet(ICMP_PARAMETERPROB, code, packet, header, SERVICE_ICMP, 0, 0, 0);
     406}
     407
     408icmp_header_ref icmp_prepare_packet(packet_t packet){
     409        icmp_header_ref header;
     410        size_t header_length;
     411        size_t total_length;
     412
     413        total_length = packet_get_data_length(packet);
     414        if(total_length <= 0){
     415                return NULL;
     416        }
     417        header_length = ip_client_header_length(packet);
     418        if(header_length <= 0){
     419                return NULL;
     420        }
     421        // truncate if longer than 64 bits (without the IP header)
     422        if((total_length > header_length + ICMP_KEEP_LENGTH)
     423                && (packet_trim(packet, 0, total_length - header_length - ICMP_KEEP_LENGTH) != EOK)){
     424                return NULL;
     425        }
     426        header = PACKET_PREFIX(packet, icmp_header_t);
     427        if(! header){
     428                return NULL;
     429        }
     430        bzero(header, sizeof(*header));
     431        return header;
     432}
     433
     434int icmp_send_packet(icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header, services_t error, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment){
     435        ERROR_DECLARE;
    163436
    164437        // do not send an error if disabled
    165         if (error && !icmp_globals.error_reporting)
     438        if(error && (! icmp_globals.error_reporting)){
    166439                return icmp_release_and_return(packet, EPERM);
    167 
     440        }
    168441        header->type = type;
    169442        header->code = code;
    170443        header->checksum = 0;
    171         header->checksum = ICMP_CHECKSUM(header,
    172             packet_get_data_length(packet));
    173        
    174         rc = ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl, tos,
    175             dont_fragment, 0);
    176         if (rc != EOK)
    177                 return icmp_release_and_return(packet, rc);
    178 
    179         return ip_send_msg(icmp_globals.ip_phone, -1, packet, SERVICE_ICMP,
    180             error);
    181 }
    182 
    183 /** Prepares the ICMP error packet.
    184  *
    185  * Truncates the original packet if longer than ICMP_KEEP_LENGTH bytes.
    186  * Prefixes and returns the ICMP header.
    187  *
    188  * @param[in,out] packet The original packet.
    189  * @returns The prefixed ICMP header.
    190  * @returns NULL on errors.
    191  */
    192 static icmp_header_ref icmp_prepare_packet(packet_t packet)
    193 {
    194         icmp_header_ref header;
    195         size_t header_length;
    196         size_t total_length;
    197 
    198         total_length = packet_get_data_length(packet);
    199         if (total_length <= 0)
    200                 return NULL;
    201 
    202         header_length = ip_client_header_length(packet);
    203         if (header_length <= 0)
    204                 return NULL;
    205 
    206         // truncate if longer than 64 bits (without the IP header)
    207         if ((total_length > header_length + ICMP_KEEP_LENGTH) &&
    208             (packet_trim(packet, 0,
    209             total_length - header_length - ICMP_KEEP_LENGTH) != EOK)) {
    210                 return NULL;
    211         }
    212 
    213         header = PACKET_PREFIX(packet, icmp_header_t);
    214         if (!header)
    215                 return NULL;
    216 
    217         bzero(header, sizeof(*header));
    218         return header;
    219 }
    220 
    221 /** Requests an echo message.
    222  *
    223  * Sends a packet with specified parameters to the target host and waits for
    224  * the reply upto the given timeout.
    225  * Blocks the caller until the reply or the timeout occurs.
    226  *
    227  * @param[in] id        The message identifier.
    228  * @param[in] sequence  The message sequence parameter.
    229  * @param[in] size      The message data length in bytes.
    230  * @param[in] timeout   The timeout in miliseconds.
    231  * @param[in] ttl       The time to live.
    232  * @param[in] tos       The type of service.
    233  * @param[in] dont_fragment The value indicating whether the datagram must not
    234  *                      be fragmented. Is used as a MTU discovery.
    235  * @param[in] addr      The target host address.
    236  * @param[in] addrlen   The torget host address length.
    237  * @returns             ICMP_ECHO on success.
    238  * @returns             ETIMEOUT if the reply has not arrived before the
    239  *                      timeout.
    240  * @returns             ICMP type of the received error notification.
    241  * @returns             EINVAL if the addrlen parameter is less or equal to
    242  *                      zero.
    243  * @returns             ENOMEM if there is not enough memory left.
    244  * @returns             EPARTY if there was an internal error.
    245  */
    246 static int
    247 icmp_echo(icmp_param_t id, icmp_param_t sequence, size_t size,
    248     mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment,
    249     const struct sockaddr * addr, socklen_t addrlen)
    250 {
    251         icmp_header_ref header;
    252         packet_t packet;
    253         size_t length;
    254         uint8_t *data;
    255         icmp_reply_ref reply;
    256         int reply_key;
    257         int index;
    258         int rc;
    259 
    260         if (addrlen <= 0)
    261                 return EINVAL;
    262 
    263         length = (size_t) addrlen;
    264         // TODO do not ask all the time
    265         rc = ip_packet_size_req(icmp_globals.ip_phone, -1,
    266             &icmp_globals.packet_dimension);
    267         if (rc != EOK)
    268                 return rc;
    269 
    270         packet = packet_get_4_remote(icmp_globals.net_phone, size,
    271             icmp_globals.packet_dimension.addr_len,
    272             ICMP_HEADER_SIZE + icmp_globals.packet_dimension.prefix,
    273             icmp_globals.packet_dimension.suffix);
    274         if (!packet)
    275                 return ENOMEM;
    276 
    277         // prepare the requesting packet
    278         // set the destination address
    279         rc = packet_set_addr(packet, NULL, (const uint8_t *) addr, length);
    280         if (rc != EOK)
    281                 return icmp_release_and_return(packet, rc);
    282 
    283         // allocate space in the packet
    284         data = (uint8_t *) packet_suffix(packet, size);
    285         if (!data)
    286                 return icmp_release_and_return(packet, ENOMEM);
    287 
    288         // fill the data
    289         length = 0;
    290         while (size > length + sizeof(ICMP_ECHO_TEXT)) {
    291                 memcpy(data + length, ICMP_ECHO_TEXT, sizeof(ICMP_ECHO_TEXT));
    292                 length += sizeof(ICMP_ECHO_TEXT);
    293         }
    294         memcpy(data + length, ICMP_ECHO_TEXT, size - length);
    295 
    296         // prefix the header
    297         header = PACKET_PREFIX(packet, icmp_header_t);
    298         if (!header)
    299                 return icmp_release_and_return(packet, ENOMEM);
    300 
    301         bzero(header, sizeof(*header));
    302         header->un.echo.identifier = id;
    303         header->un.echo.sequence_number = sequence;
    304 
    305         // prepare the reply structure
    306         reply = malloc(sizeof(*reply));
    307         if (!reply)
    308                 return icmp_release_and_return(packet, ENOMEM);
    309 
    310         fibril_mutex_initialize(&reply->mutex);
    311         fibril_mutex_lock(&reply->mutex);
    312         fibril_condvar_initialize(&reply->condvar);
    313         reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier,
    314             header->un.echo.sequence_number);
    315         index = icmp_replies_add(&icmp_globals.replies, reply_key, reply);
    316         if (index < 0) {
    317                 free(reply);
    318                 return icmp_release_and_return(packet, index);
    319         }
    320 
    321         // unlock the globals so that we can wait for the reply
    322         fibril_rwlock_write_unlock(&icmp_globals.lock);
    323 
    324         // send the request
    325         icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos,
    326             dont_fragment);
    327 
    328         // wait for the reply
    329         // timeout in microseconds
    330         rc = fibril_condvar_wait_timeout(&reply->condvar, &reply->mutex,
    331             timeout * 1000);
    332         if (rc == EOK)
    333                 rc = reply->result;
    334 
    335         // drop the reply mutex before locking the globals again
    336         fibril_mutex_unlock(&reply->mutex);
    337         fibril_rwlock_write_lock(&icmp_globals.lock);
    338 
    339         // destroy the reply structure
    340         icmp_replies_exclude_index(&icmp_globals.replies, index);
    341 
    342         return rc;
    343 }
    344 
    345 static int
    346 icmp_destination_unreachable_msg_local(int icmp_phone, icmp_code_t code,
    347     icmp_param_t mtu, packet_t packet)
    348 {
    349         icmp_header_ref header;
    350 
    351         header = icmp_prepare_packet(packet);
    352         if (!header)
    353                 return icmp_release_and_return(packet, ENOMEM);
    354 
    355         if (mtu)
    356                 header->un.frag.mtu = mtu;
    357 
    358         return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header,
    359             SERVICE_ICMP, 0, 0, 0);
    360 }
    361 
    362 static int icmp_source_quench_msg_local(int icmp_phone, packet_t packet)
    363 {
    364         icmp_header_ref header;
    365 
    366         header = icmp_prepare_packet(packet);
    367         if (!header)
    368                 return icmp_release_and_return(packet, ENOMEM);
    369 
    370         return icmp_send_packet(ICMP_SOURCE_QUENCH, 0, packet, header,
    371             SERVICE_ICMP, 0, 0, 0);
    372 }
    373 
    374 static int
    375 icmp_time_exceeded_msg_local(int icmp_phone, icmp_code_t code, packet_t packet)
    376 {
    377         icmp_header_ref header;
    378 
    379         header = icmp_prepare_packet(packet);
    380         if (!header)
    381                 return icmp_release_and_return(packet, ENOMEM);
    382 
    383         return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header,
    384             SERVICE_ICMP, 0, 0, 0);
    385 }
    386 
    387 static int
    388 icmp_parameter_problem_msg_local(int icmp_phone, icmp_code_t code,
    389     icmp_param_t pointer, packet_t packet)
    390 {
    391         icmp_header_ref header;
    392 
    393         header = icmp_prepare_packet(packet);
    394         if (!header)
    395                 return icmp_release_and_return(packet, ENOMEM);
    396 
    397         header->un.param.pointer = pointer;
    398         return icmp_send_packet(ICMP_PARAMETERPROB, code, packet, header,
    399             SERVICE_ICMP, 0, 0, 0);
    400 }
    401 
    402 /** Initializes the ICMP module.
    403  *
    404  * @param[in] client_connection The client connection processing function. The
    405  *                      module skeleton propagates its own one.
    406  * @returns             EOK on success.
    407  * @returns             ENOMEM if there is not enough memory left.
    408  */
    409 int icmp_initialize(async_client_conn_t client_connection)
    410 {
    411         measured_string_t names[] = {
    412                 {
    413                         (char *) "ICMP_ERROR_REPORTING",
    414                         20
    415                 },
    416                 {
    417                         (char *) "ICMP_ECHO_REPLYING",
    418                         18
    419                 }
    420         };
     444        header->checksum = ICMP_CHECKSUM(header, packet_get_data_length(packet));
     445        if(ERROR_OCCURRED(ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl, tos, dont_fragment, 0))){
     446                return icmp_release_and_return(packet, ERROR_CODE);
     447        }
     448        return ip_send_msg(icmp_globals.ip_phone, -1, packet, SERVICE_ICMP, error);
     449}
     450
     451int icmp_initialize(async_client_conn_t client_connection){
     452        ERROR_DECLARE;
     453
     454        measured_string_t names[] = {{str_dup("ICMP_ERROR_REPORTING"), 20}, {str_dup("ICMP_ECHO_REPLYING"), 18}};
    421455        measured_string_ref configuration;
    422456        size_t count = sizeof(names) / sizeof(measured_string_t);
    423         char *data;
    424         int rc;
     457        char * data;
    425458
    426459        fibril_rwlock_initialize(&icmp_globals.lock);
     
    428461        icmp_replies_initialize(&icmp_globals.replies);
    429462        icmp_echo_data_initialize(&icmp_globals.echo_data);
    430        
    431         icmp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_ICMP,
    432             SERVICE_ICMP, client_connection);
    433         if (icmp_globals.ip_phone < 0) {
    434                 fibril_rwlock_write_unlock(&icmp_globals.lock);
     463        icmp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP, client_connection);
     464        if(icmp_globals.ip_phone < 0){
    435465                return icmp_globals.ip_phone;
    436466        }
    437        
    438         rc = ip_packet_size_req(icmp_globals.ip_phone, -1,
    439             &icmp_globals.packet_dimension);
    440         if (rc != EOK) {
    441                 fibril_rwlock_write_unlock(&icmp_globals.lock);
    442                 return rc;
    443         }
    444 
     467        ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1, &icmp_globals.packet_dimension));
    445468        icmp_globals.packet_dimension.prefix += ICMP_HEADER_SIZE;
    446469        icmp_globals.packet_dimension.content -= ICMP_HEADER_SIZE;
    447 
     470        // get configuration
    448471        icmp_globals.error_reporting = NET_DEFAULT_ICMP_ERROR_REPORTING;
    449472        icmp_globals.echo_replying = NET_DEFAULT_ICMP_ECHO_REPLYING;
    450 
    451         // get configuration
    452473        configuration = &names[0];
    453         rc = net_get_conf_req(icmp_globals.net_phone, &configuration, count,
    454             &data);
    455         if (rc != EOK) {
    456                 fibril_rwlock_write_unlock(&icmp_globals.lock);
    457                 return rc;
    458         }
    459        
    460         if (configuration) {
    461                 if (configuration[0].value) {
    462                         icmp_globals.error_reporting =
    463                             (configuration[0].value[0] == 'y');
     474        ERROR_PROPAGATE(net_get_conf_req(icmp_globals.net_phone, &configuration, count, &data));
     475        if(configuration){
     476                if(configuration[0].value){
     477                        icmp_globals.error_reporting = (configuration[0].value[0] == 'y');
    464478                }
    465                 if (configuration[1].value) {
    466                         icmp_globals.echo_replying =
    467                             (configuration[1].value[0] == 'y');
     479                if(configuration[1].value){
     480                        icmp_globals.echo_replying = (configuration[1].value[0] == 'y');
    468481                }
    469482                net_free_settings(configuration, data);
    470483        }
    471 
    472484        fibril_rwlock_write_unlock(&icmp_globals.lock);
    473485        return EOK;
    474486}
    475487
    476 /** Tries to set the pending reply result as the received message type.
    477  *
    478  * If the reply data is not present, the reply timed out and the other fibril
    479  * is already awake.
    480  * Releases the packet.
    481  *
    482  * @param[in] packet    The received reply message.
    483  * @param[in] header    The ICMP message header.
    484  * @param[in] type      The received reply message type.
    485  * @param[in] code      The received reply message code.
    486  */
    487 static void
    488 icmp_process_echo_reply(packet_t packet, icmp_header_ref header,
    489     icmp_type_t type, icmp_code_t code)
    490 {
    491         int reply_key;
    492         icmp_reply_ref reply;
    493 
    494         // compute the reply key
    495         reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier,
    496             header->un.echo.sequence_number);
    497         pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
    498 
    499         fibril_rwlock_write_lock(&icmp_globals.lock);
    500         // find the pending reply
    501         reply = icmp_replies_find(&icmp_globals.replies, reply_key);
    502         if (reply) {
    503                 reply->result = type;
    504                 fibril_condvar_signal(&reply->condvar);
    505         }
    506         fibril_rwlock_write_unlock(&icmp_globals.lock);
    507 }
    508 
    509 /** Processes the received ICMP packet.
    510  *
    511  * Notifies the destination socket application.
    512  *
    513  * @param[in,out] packet The received packet.
    514  * @param[in] error     The packet error reporting service. Prefixes the
    515  *                      received packet.
    516  * @returns             EOK on success.
    517  * @returns             EINVAL if the packet is not valid.
    518  * @returns             EINVAL if the stored packet address is not the an_addr_t.
    519  * @returns             EINVAL if the packet does not contain any data.
    520  * @returns             NO_DATA if the packet content is shorter than the user
    521  *                      datagram header.
    522  * @returns             ENOMEM if there is not enough memory left.
    523  * @returns             EADDRNOTAVAIL if the destination socket does not exist.
    524  * @returns             Other error codes as defined for the
    525  *                      ip_client_process_packet() function.
    526  */
    527 static int icmp_process_packet(packet_t packet, services_t error)
    528 {
     488int icmp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error){
     489        ERROR_DECLARE;
     490
     491        if(ERROR_OCCURRED(icmp_process_packet(packet, error))){
     492                return icmp_release_and_return(packet, ERROR_CODE);
     493        }
     494
     495        return EOK;
     496}
     497
     498int icmp_process_packet(packet_t packet, services_t error){
     499        ERROR_DECLARE;
     500
    529501        size_t length;
    530         uint8_t *src;
     502        uint8_t * src;
    531503        int addrlen;
    532504        int result;
    533         void *data;
     505        void * data;
    534506        icmp_header_ref header;
    535507        icmp_type_t type;
    536508        icmp_code_t code;
    537         int rc;
    538 
    539         switch (error) {
    540         case SERVICE_NONE:
    541                 break;
    542         case SERVICE_ICMP:
    543                 // process error
    544                 result = icmp_client_process_packet(packet, &type, &code, NULL,
    545                     NULL);
    546                 if (result < 0)
    547                         return result;
    548                 length = (size_t) result;
    549                 // remove the error header
    550                 rc = packet_trim(packet, length, 0);
    551                 if (rc != EOK)
    552                         return rc;
    553                 break;
    554         default:
    555                 return ENOTSUP;
    556         }
    557 
     509
     510        if(error){
     511                switch(error){
     512                        case SERVICE_ICMP:
     513                                // process error
     514                                result = icmp_client_process_packet(packet, &type, &code, NULL, NULL);
     515                                if(result < 0){
     516                                        return result;
     517                                }
     518                                length = (size_t) result;
     519                                // remove the error header
     520                                ERROR_PROPAGATE(packet_trim(packet, length, 0));
     521                                break;
     522                        default:
     523                                return ENOTSUP;
     524                }
     525        }
    558526        // get rid of the ip header
    559527        length = ip_client_header_length(packet);
    560         rc = packet_trim(packet, length, 0);
    561         if (rc != EOK)
    562                 return rc;
     528        ERROR_PROPAGATE(packet_trim(packet, length, 0));
    563529
    564530        length = packet_get_data_length(packet);
    565         if (length <= 0)
     531        if(length <= 0){
    566532                return EINVAL;
    567 
    568         if (length < ICMP_HEADER_SIZE)
     533        }
     534        if(length < ICMP_HEADER_SIZE){
    569535                return EINVAL;
    570 
     536        }
    571537        data = packet_get_data(packet);
    572         if (!data)
     538        if(! data){
    573539                return EINVAL;
    574 
     540        }
    575541        // get icmp header
    576542        header = (icmp_header_ref) data;
    577 
    578         if (header->checksum) {
    579                 while (ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO) {
     543        // checksum
     544        if(header->checksum){
     545                while(ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO){
    580546                        // set the original message type on error notification
    581547                        // type swap observed in Qemu
    582                         if (error) {
    583                                 switch (header->type) {
    584                                 case ICMP_ECHOREPLY:
    585                                         header->type = ICMP_ECHO;
    586                                         continue;
     548                        if(error){
     549                                switch(header->type){
     550                                        case ICMP_ECHOREPLY:
     551                                                header->type = ICMP_ECHO;
     552                                                continue;
    587553                                }
    588554                        }
     
    590556                }
    591557        }
    592 
    593         switch (header->type) {
    594         case ICMP_ECHOREPLY:
    595                 if (error)
    596                         icmp_process_echo_reply(packet, header, type, code);
    597                 else
    598                         icmp_process_echo_reply(packet, header, ICMP_ECHO, 0);
    599 
    600                 return EOK;
    601 
    602         case ICMP_ECHO:
    603                 if (error) {
    604                         icmp_process_echo_reply(packet, header, type, code);
     558        switch(header->type){
     559                case ICMP_ECHOREPLY:
     560                        if(error){
     561                                return icmp_process_echo_reply(packet, header, type, code);
     562                        }else{
     563                                return icmp_process_echo_reply(packet, header, ICMP_ECHO, 0);
     564                        }
     565                case ICMP_ECHO:
     566                        if(error){
     567                                return icmp_process_echo_reply(packet, header, type, code);
     568                        // do not send a reply if disabled
     569                        }else if(icmp_globals.echo_replying){
     570                                addrlen = packet_get_addr(packet, &src, NULL);
     571                                if((addrlen > 0)
     572                                // set both addresses to the source one (avoids the source address deletion before setting the destination one)
     573                                        && (packet_set_addr(packet, src, src, (size_t) addrlen) == EOK)){
     574                                        // send the reply
     575                                        icmp_send_packet(ICMP_ECHOREPLY, 0, packet, header, 0, 0, 0, 0);
     576                                        return EOK;
     577                                }else{
     578                                        return EINVAL;
     579                                }
     580                        }else{
     581                                return EPERM;
     582                        }
     583                case ICMP_DEST_UNREACH:
     584                case ICMP_SOURCE_QUENCH:
     585                case ICMP_REDIRECT:
     586                case ICMP_ALTERNATE_ADDR:
     587                case ICMP_ROUTER_ADV:
     588                case ICMP_ROUTER_SOL:
     589                case ICMP_TIME_EXCEEDED:
     590                case ICMP_PARAMETERPROB:
     591                case ICMP_CONVERSION_ERROR:
     592                case ICMP_REDIRECT_MOBILE:
     593                case ICMP_SKIP:
     594                case ICMP_PHOTURIS:
     595                        ip_received_error_msg(icmp_globals.ip_phone, -1, packet, SERVICE_IP, SERVICE_ICMP);
    605596                        return EOK;
    606                 }
    607                
    608                 // do not send a reply if disabled
    609                 if (icmp_globals.echo_replying) {
    610                         addrlen = packet_get_addr(packet, &src, NULL);
    611 
    612                         // set both addresses to the source one (avoids the
    613                         // source address deletion before setting the
    614                         // destination one)
    615                         if ((addrlen > 0) && (packet_set_addr(packet, src, src,
    616                             (size_t) addrlen) == EOK)) {
    617                                 // send the reply
    618                                 icmp_send_packet(ICMP_ECHOREPLY, 0, packet,
    619                                     header, 0, 0, 0, 0);
    620                                 return EOK;
     597                default:
     598                        return ENOTSUP;
     599        }
     600}
     601
     602int icmp_process_echo_reply(packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code){
     603        int reply_key;
     604        icmp_reply_ref reply;
     605
     606        // compute the reply key
     607        reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier, header->un.echo.sequence_number);
     608        pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
     609        // lock the globals
     610        fibril_rwlock_write_lock(&icmp_globals.lock);
     611        // find the pending reply
     612        reply = icmp_replies_find(&icmp_globals.replies, reply_key);
     613        if(reply){
     614                // set the result
     615                reply->result = type;
     616                // notify the waiting fibril
     617                fibril_condvar_signal(&reply->condvar);
     618        }
     619        fibril_rwlock_write_unlock(&icmp_globals.lock);
     620        return EOK;
     621}
     622
     623int icmp_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
     624        ERROR_DECLARE;
     625
     626        packet_t packet;
     627
     628        *answer_count = 0;
     629        switch(IPC_GET_METHOD(*call)){
     630                case NET_TL_RECEIVED:
     631                        if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
     632                                ERROR_CODE = icmp_received_msg(IPC_GET_DEVICE(call), packet, SERVICE_ICMP, IPC_GET_ERROR(call));
    621633                        }
    622 
    623                         return EINVAL;
    624                 }
    625 
    626                 return EPERM;
    627 
    628         case ICMP_DEST_UNREACH:
    629         case ICMP_SOURCE_QUENCH:
    630         case ICMP_REDIRECT:
    631         case ICMP_ALTERNATE_ADDR:
    632         case ICMP_ROUTER_ADV:
    633         case ICMP_ROUTER_SOL:
    634         case ICMP_TIME_EXCEEDED:
    635         case ICMP_PARAMETERPROB:
    636         case ICMP_CONVERSION_ERROR:
    637         case ICMP_REDIRECT_MOBILE:
    638         case ICMP_SKIP:
    639         case ICMP_PHOTURIS:
    640                 ip_received_error_msg(icmp_globals.ip_phone, -1, packet,
    641                     SERVICE_IP, SERVICE_ICMP);
    642                 return EOK;
    643 
    644         default:
    645                 return ENOTSUP;
    646         }
    647 }
    648 
    649 /** Processes the received ICMP packet.
    650  *
    651  * Is used as an entry point from the underlying IP module.
    652  * Releases the packet on error.
    653  *
    654  * @param device_id     The device identifier. Ignored parameter.
    655  * @param[in,out] packet The received packet.
    656  * @param receiver      The target service. Ignored parameter.
    657  * @param[in] error     The packet error reporting service. Prefixes the
    658  *                      received packet.
    659  * @returns             EOK on success.
    660  * @returns             Other error codes as defined for the
    661  *                      icmp_process_packet() function.
    662  */
    663 static int
    664 icmp_received_msg_local(device_id_t device_id, packet_t packet,
    665     services_t receiver, services_t error)
    666 {
    667         int rc;
    668 
    669         rc = icmp_process_packet(packet, error);
    670         if (rc != EOK)
    671                 return icmp_release_and_return(packet, rc);
    672 
    673         return EOK;
    674 }
    675 
    676 /** Processes the generic client messages.
    677  *
    678  * @param[in] call      The message parameters.
    679  * @returns             EOK on success.
    680  * @returns             ENOTSUP if the message is not known.
    681  * @returns             Other error codes as defined for the packet_translate()
    682  *                      function.
    683  * @returns             Other error codes as defined for the
    684  *                      icmp_destination_unreachable_msg_local() function.
    685  * @returns             Other error codes as defined for the
    686  *                      icmp_source_quench_msg_local() function.
    687  * @returns             Other error codes as defined for the
    688  *                      icmp_time_exceeded_msg_local() function.
    689  * @returns             Other error codes as defined for the
    690  *                      icmp_parameter_problem_msg_local() function.
    691  *
    692  * @see icmp_interface.h
    693  */
    694 static int icmp_process_message(ipc_call_t *call)
    695 {
    696         packet_t packet;
    697         int rc;
    698 
    699         switch (IPC_GET_METHOD(*call)) {
    700         case NET_ICMP_DEST_UNREACH:
    701                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    702                     IPC_GET_PACKET(call));
    703                 if (rc != EOK)
    704                         return rc;
    705                 return icmp_destination_unreachable_msg_local(0,
    706                     ICMP_GET_CODE(call), ICMP_GET_MTU(call), packet);
    707         case NET_ICMP_SOURCE_QUENCH:
    708                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    709                     IPC_GET_PACKET(call));
    710                 if (rc != EOK)
    711                         return rc;
    712                 return icmp_source_quench_msg_local(0, packet);
    713         case NET_ICMP_TIME_EXCEEDED:
    714                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    715                     IPC_GET_PACKET(call));
    716                 if (rc != EOK)
    717                         return rc;
    718                 return icmp_time_exceeded_msg_local(0, ICMP_GET_CODE(call),
    719                     packet);
    720         case NET_ICMP_PARAMETERPROB:
    721                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    722                     IPC_GET_PACKET(call));
    723                 if (rc != EOK)
    724                         return rc;
    725                 return icmp_parameter_problem_msg_local(0, ICMP_GET_CODE(call),
    726                     ICMP_GET_POINTER(call), packet);
    727         default:
    728                 return ENOTSUP;
    729         }
    730 }
    731 
    732 /** Assigns a new identifier for the connection.
    733  *
    734  * Fills the echo data parameter with the assigned values.
    735  *
    736  * @param[in,out] echo_data The echo data to be bound.
    737  * @returns             Index of the inserted echo data.
    738  * @returns             EBADMEM if the echo_data parameter is NULL.
    739  * @returns             ENOTCONN if no free identifier have been found.
    740  */
    741 static int icmp_bind_free_id(icmp_echo_ref echo_data)
    742 {
    743         icmp_param_t index;
    744 
    745         if (!echo_data)
    746                 return EBADMEM;
    747 
    748         // from the last used one
    749         index = icmp_globals.last_used_id;
    750         do {
    751                 index++;
    752                 // til the range end
    753                 if (index >= ICMP_FREE_IDS_END) {
    754                         // start from the range beginning
    755                         index = ICMP_FREE_IDS_START - 1;
    756                         do {
    757                                 index++;
    758                                 // til the last used one
    759                                 if (index >= icmp_globals.last_used_id) {
    760                                         // none found
    761                                         return ENOTCONN;
    762                                 }
    763                         } while(icmp_echo_data_find(&icmp_globals.echo_data,
    764                             index) != NULL);
    765 
    766                         // found, break immediately
    767                         break;
    768                 }
    769         } while (icmp_echo_data_find(&icmp_globals.echo_data, index) != NULL);
    770 
    771         echo_data->identifier = index;
    772         echo_data->sequence_number = 0;
    773 
    774         return icmp_echo_data_add(&icmp_globals.echo_data, index, echo_data);
    775 }
    776 
    777 /** Processes the client messages.
    778  *
    779  * Remembers the assigned identifier and sequence numbers.
    780  * Runs until the client module disconnects.
    781  *
    782  * @param[in] callid    The message identifier.
    783  * @param[in] call      The message parameters.
    784  * @returns EOK.
    785  *
    786  * @see icmp_interface.h
    787  * @see icmp_api.h
    788  */
    789 static int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
    790 {
     634                        return ERROR_CODE;
     635                case NET_ICMP_INIT:
     636                        return icmp_process_client_messages(callid, * call);
     637                default:
     638                        return icmp_process_message(call);
     639        }
     640        return ENOTSUP;
     641}
     642
     643int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call){
     644        ERROR_DECLARE;
     645
    791646        bool keep_on_going = true;
     647//      fibril_rwlock_t                 lock;
    792648        ipc_call_t answer;
    793649        int answer_count;
    794650        size_t length;
    795         struct sockaddr *addr;
     651        struct sockaddr * addr;
    796652        ipc_callid_t data_callid;
    797653        icmp_echo_ref echo_data;
    798         int rc = EOK;
     654        int res;
    799655
    800656        /*
     
    802658         *  - Answer the first NET_ICMP_INIT call.
    803659         */
     660        res = EOK;
    804661        answer_count = 0;
    805662
     663//      fibril_rwlock_initialize(&lock);
     664
    806665        echo_data = (icmp_echo_ref) malloc(sizeof(*echo_data));
    807         if (!echo_data)
     666        if(! echo_data){
    808667                return ENOMEM;
     668        }
    809669
    810670        // assign a new identifier
    811671        fibril_rwlock_write_lock(&icmp_globals.lock);
    812         rc = icmp_bind_free_id(echo_data);
     672        res = icmp_bind_free_id(echo_data);
    813673        fibril_rwlock_write_unlock(&icmp_globals.lock);
    814         if (rc < 0) {
     674        if(res < 0){
    815675                free(echo_data);
    816                 return rc;
    817         }
    818 
    819         while (keep_on_going) {
     676                return res;
     677        }
     678
     679        while(keep_on_going){
     680
    820681                // answer the call
    821                 answer_call(callid, rc, &answer, answer_count);
     682                answer_call(callid, res, &answer, answer_count);
    822683
    823684                // refresh data
     
    828689
    829690                // process the call
    830                 switch (IPC_GET_METHOD(call)) {
    831                 case IPC_M_PHONE_HUNGUP:
    832                         keep_on_going = false;
    833                         rc = EHANGUP;
    834                         break;
    835                
    836                 case NET_ICMP_ECHO:
    837                         if (!async_data_write_receive(&data_callid, &length)) {
    838                                 rc = EINVAL;
     691                switch(IPC_GET_METHOD(call)){
     692                        case IPC_M_PHONE_HUNGUP:
     693                                keep_on_going = false;
     694                                res = EHANGUP;
    839695                                break;
    840                         }
    841                        
    842                         addr = malloc(length);
    843                         if (!addr) {
    844                                 rc = ENOMEM;
     696                        case NET_ICMP_ECHO:
     697//                              fibril_rwlock_write_lock(&lock);
     698                                if(! async_data_write_receive(&data_callid, &length)){
     699                                        res = EINVAL;
     700                                }else{
     701                                        addr = malloc(length);
     702                                        if(! addr){
     703                                                res = ENOMEM;
     704                                        }else{
     705                                                if(! ERROR_OCCURRED(async_data_write_finalize(data_callid, addr, length))){
     706                                                        fibril_rwlock_write_lock(&icmp_globals.lock);
     707                                                        res = icmp_echo(echo_data->identifier, echo_data->sequence_number, ICMP_GET_SIZE(call), ICMP_GET_TIMEOUT(call), ICMP_GET_TTL(call), ICMP_GET_TOS(call), ICMP_GET_DONT_FRAGMENT(call), addr, (socklen_t) length);
     708                                                        fibril_rwlock_write_unlock(&icmp_globals.lock);
     709                                                        free(addr);
     710                                                        if(echo_data->sequence_number < UINT16_MAX){
     711                                                                ++ echo_data->sequence_number;
     712                                                        }else{
     713                                                                echo_data->sequence_number = 0;
     714                                                        }
     715                                                }else{
     716                                                        res = ERROR_CODE;
     717                                                }
     718                                        }
     719                                }
     720//                              fibril_rwlock_write_unlock(&lock);
    845721                                break;
    846                         }
    847                        
    848                         rc = async_data_write_finalize(data_callid, addr,
    849                             length);
    850                         if (rc != EOK) {
    851                                 free(addr);
    852                                 break;
    853                         }
    854 
    855                         fibril_rwlock_write_lock(&icmp_globals.lock);
    856                         rc = icmp_echo(echo_data->identifier,
    857                             echo_data->sequence_number, ICMP_GET_SIZE(call),
    858                             ICMP_GET_TIMEOUT(call), ICMP_GET_TTL(call),
    859                             ICMP_GET_TOS(call), ICMP_GET_DONT_FRAGMENT(call),
    860                             addr, (socklen_t) length);
    861                         fibril_rwlock_write_unlock(&icmp_globals.lock);
    862 
    863                         free(addr);
    864 
    865                         if (echo_data->sequence_number < UINT16_MAX)
    866                                 echo_data->sequence_number++;
    867                         else
    868                                 echo_data->sequence_number = 0;
    869 
    870                         break;
    871 
    872                 default:
    873                         rc = icmp_process_message(&call);
     722                        default:
     723                                res = icmp_process_message(&call);
    874724                }
    875 
    876725        }
    877726
     
    880729        icmp_echo_data_exclude(&icmp_globals.echo_data, echo_data->identifier);
    881730        fibril_rwlock_write_unlock(&icmp_globals.lock);
    882 
    883         return rc;
    884 }
    885 
    886 /** Processes the ICMP message.
    887  *
    888  * @param[in] callid    The message identifier.
    889  * @param[in] call      The message parameters.
    890  * @param[out] answer   The message answer parameters.
    891  * @param[out] answer_count The last parameter for the actual answer in the
    892  *                      answer parameter.
    893  * @returns             EOK on success.
    894  * @returns             ENOTSUP if the message is not known.
    895  *
    896  * @see icmp_interface.h
    897  * @see IS_NET_ICMP_MESSAGE()
    898  */
    899 int
    900 icmp_message_standalone(ipc_callid_t callid, ipc_call_t *call,
    901     ipc_call_t *answer, int *answer_count)
    902 {
     731        return res;
     732}
     733
     734int icmp_process_message(ipc_call_t * call){
     735        ERROR_DECLARE;
     736
    903737        packet_t packet;
    904         int rc;
    905 
    906         *answer_count = 0;
    907         switch (IPC_GET_METHOD(*call)) {
    908         case NET_TL_RECEIVED:
    909                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    910                     IPC_GET_PACKET(call));
    911                 if (rc != EOK)
    912                         return rc;
    913                 return icmp_received_msg_local(IPC_GET_DEVICE(call), packet,
    914                     SERVICE_ICMP, IPC_GET_ERROR(call));
    915        
    916         case NET_ICMP_INIT:
    917                 return icmp_process_client_messages(callid, * call);
    918        
    919         default:
    920                 return icmp_process_message(call);
    921         }
    922 
    923         return ENOTSUP;
    924 }
    925 
     738
     739        switch(IPC_GET_METHOD(*call)){
     740                case NET_ICMP_DEST_UNREACH:
     741                        if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
     742                                ERROR_CODE = icmp_destination_unreachable_msg(0, ICMP_GET_CODE(call), ICMP_GET_MTU(call), packet);
     743                        }
     744                        return ERROR_CODE;
     745                case NET_ICMP_SOURCE_QUENCH:
     746                        if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
     747                                ERROR_CODE = icmp_source_quench_msg(0, packet);
     748                        }
     749                        return ERROR_CODE;
     750                case NET_ICMP_TIME_EXCEEDED:
     751                        if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
     752                                ERROR_CODE = icmp_time_exceeded_msg(0, ICMP_GET_CODE(call), packet);
     753                        }
     754                        return ERROR_CODE;
     755                case NET_ICMP_PARAMETERPROB:
     756                        if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
     757                                ERROR_CODE = icmp_parameter_problem_msg(0, ICMP_GET_CODE(call), ICMP_GET_POINTER(call), packet);
     758                        }
     759                        return ERROR_CODE;
     760                default:
     761                        return ENOTSUP;
     762        }
     763}
     764
     765int icmp_release_and_return(packet_t packet, int result){
     766        pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
     767        return result;
     768}
     769
     770int icmp_bind_free_id(icmp_echo_ref echo_data){
     771        icmp_param_t index;
     772
     773        if(! echo_data){
     774                return EBADMEM;
     775        }
     776        // from the last used one
     777        index = icmp_globals.last_used_id;
     778        do{
     779                ++ index;
     780                // til the range end
     781                if(index >= ICMP_FREE_IDS_END){
     782                        // start from the range beginning
     783                        index = ICMP_FREE_IDS_START - 1;
     784                        do{
     785                                ++ index;
     786                                // til the last used one
     787                                if(index >= icmp_globals.last_used_id){
     788                                        // none found
     789                                        return ENOTCONN;
     790                                }
     791                        }while(icmp_echo_data_find(&icmp_globals.echo_data, index) != NULL);
     792                        // found, break immediately
     793                        break;
     794                }
     795        }while(icmp_echo_data_find(&icmp_globals.echo_data, index) != NULL);
     796        echo_data->identifier = index;
     797        echo_data->sequence_number = 0;
     798        return icmp_echo_data_add(&icmp_globals.echo_data, index, echo_data);
     799}
    926800
    927801/** Default thread for new connections.
    928802 *
    929  * @param[in] iid The initial message identifier.
    930  * @param[in] icall The initial message call structure.
     803 *  @param[in] iid The initial message identifier.
     804 *  @param[in] icall The initial message call structure.
    931805 *
    932806 */
    933 static void tl_client_connection(ipc_callid_t iid, ipc_call_t *icall)
     807static void tl_client_connection(ipc_callid_t iid, ipc_call_t * icall)
    934808{
    935809        /*
     
    939813        ipc_answer_0(iid, EOK);
    940814       
    941         while (true) {
     815        while(true) {
    942816                ipc_call_t answer;
    943817                int answer_count;
     
    954828                    &answer_count);
    955829               
    956                 /*
    957                  * End if told to either by the message or the processing
    958                  * result.
    959                  */
    960                 if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) ||
    961                     (res == EHANGUP))
     830                /* End if said to either by the message or the processing result */
     831                if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) || (res == EHANGUP))
    962832                        return;
    963833               
     
    969839/** Starts the module.
    970840 *
    971  * @returns             EOK on success.
    972  * @returns             Other error codes as defined for each specific module
    973  *                      start function.
     841 *  @param argc The count of the command line arguments. Ignored parameter.
     842 *  @param argv The command line parameters. Ignored parameter.
     843 *
     844 *  @returns EOK on success.
     845 *  @returns Other error codes as defined for each specific module start function.
     846 *
    974847 */
    975848int main(int argc, char *argv[])
    976849{
    977         int rc;
     850        ERROR_DECLARE;
    978851       
    979852        /* Start the module */
    980         rc = tl_module_start_standalone(tl_client_connection);
    981         return rc;
     853        if (ERROR_OCCURRED(tl_module_start_standalone(tl_client_connection)))
     854                return ERROR_CODE;
     855       
     856        return EOK;
    982857}
    983858
    984859/** @}
    985860 */
    986 
Note: See TracChangeset for help on using the changeset viewer.