Ignore:
File:
1 edited

Legend:

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

    r46d4d9f r9539be6  
    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>
     
    4744#include <ipc/ipc.h>
    4845#include <ipc/services.h>
    49 #include <ipc/net.h>
    50 #include <ipc/tl.h>
    51 #include <ipc/icmp.h>
    5246#include <sys/time.h>
    5347#include <sys/types.h>
    54 #include <byteorder.h>
    55 #include <errno.h>
    56 
    57 #include <net/socket_codes.h>
    58 #include <net/ip_protocols.h>
    59 #include <net/inet.h>
    60 #include <net/modules.h>
    61 #include <net/icmp_api.h>
    62 #include <net/icmp_codes.h>
    63 #include <net/icmp_common.h>
    64 
    65 #include <packet_client.h>
     48
     49#include <net_err.h>
     50#include <net_messages.h>
     51#include <net_modules.h>
     52#include <packet/packet_client.h>
    6653#include <packet_remote.h>
     54#include <net_byteorder.h>
    6755#include <net_checksum.h>
     56#include <icmp_api.h>
    6857#include <icmp_client.h>
     58#include <icmp_codes.h>
     59#include <icmp_common.h>
    6960#include <icmp_interface.h>
    7061#include <il_interface.h>
     62#include <inet.h>
    7163#include <ip_client.h>
    7264#include <ip_interface.h>
     65#include <ip_protocols.h>
    7366#include <net_interface.h>
     67#include <socket_codes.h>
     68#include <socket_errno.h>
     69#include <tl_messages.h>
    7470#include <tl_interface.h>
    7571#include <tl_local.h>
     72#include <icmp_messages.h>
    7673#include <icmp_header.h>
    7774
    78 /** ICMP module name. */
     75#include "icmp.h"
     76#include "icmp_module.h"
     77
     78/** ICMP module name.
     79 */
    7980#define NAME    "ICMP protocol"
    8081
    81 /** Default ICMP error reporting. */
     82/** Default ICMP error reporting.
     83 */
    8284#define NET_DEFAULT_ICMP_ERROR_REPORTING        true
    8385
    84 /** Default ICMP echo replying. */
     86/** Default ICMP echo replying.
     87 */
    8588#define NET_DEFAULT_ICMP_ECHO_REPLYING          true
    8689
    87 /** Original datagram length in bytes transfered to the error notification
    88  * message.
     90/** Original datagram length in bytes transfered to the error notification message.
    8991 */
    9092#define ICMP_KEEP_LENGTH        8
    9193
    92 /** Free identifier numbers pool start. */
     94/** Free identifier numbers pool start.
     95 */
    9396#define ICMP_FREE_IDS_START     1
    9497
    95 /** Free identifier numbers pool end. */
     98/** Free identifier numbers pool end.
     99 */
    96100#define ICMP_FREE_IDS_END       UINT16_MAX
    97101
    98102/** Computes the ICMP datagram checksum.
    99  *
    100  * @param[in,out] header The ICMP datagram header.
    101  * @param[in] length    The total datagram length.
    102  * @return              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."
     103 *  @param[in,out] header The ICMP datagram header.
     104 *  @param[in] length The total datagram length.
     105 *  @returns The computed checksum.
     106 */
     107#define ICMP_CHECKSUM(header, length)           htons(ip_checksum((uint8_t *) (header), (length)))
     108
     109/** An echo request datagrams pattern.
     110 */
     111#define ICMP_ECHO_TEXT                                  "Hello from HelenOS."
    109112
    110113/** Computes an ICMP reply data key.
    111  *
    112  * @param[in] id        The message identifier.
    113  * @param[in] sequence  The message sequence number.
    114  * @return              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. */
     114 *  @param[in] id The message identifier.
     115 *  @param[in] sequence The message sequence number.
     116 *  @returns The computed ICMP reply data key.
     117 */
     118#define ICMP_GET_REPLY_KEY(id, sequence)        (((id) << 16) | (sequence &0xFFFF))
     119
     120/** Processes the received ICMP packet.
     121 *  Is used as an entry point from the underlying IP module.
     122 *  Releases the packet on error.
     123 *  @param device_id The device identifier. Ignored parameter.
     124 *  @param[in,out] packet The received packet.
     125 *  @param receiver The target service. Ignored parameter.
     126 *  @param[in] error The packet error reporting service. Prefixes the received packet.
     127 *  @returns EOK on success.
     128 *  @returns Other error codes as defined for the icmp_process_packet() function.
     129 */
     130int icmp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error);
     131
     132/** Processes the received ICMP packet.
     133 *  Notifies the destination socket application.
     134 *  @param[in,out] packet The received packet.
     135 *  @param[in] error The packet error reporting service. Prefixes the received packet.
     136 *  @returns EOK on success.
     137 *  @returns EINVAL if the packet is not valid.
     138 *  @returns EINVAL if the stored packet address is not the an_addr_t.
     139 *  @returns EINVAL if the packet does not contain any data.
     140 *  @returns NO_DATA if the packet content is shorter than the user datagram header.
     141 *  @returns ENOMEM if there is not enough memory left.
     142 *  @returns EADDRNOTAVAIL if the destination socket does not exist.
     143 *  @returns Other error codes as defined for the ip_client_process_packet() function.
     144 */
     145int icmp_process_packet(packet_t packet, services_t error);
     146
     147/** Processes the client messages.
     148 *  Remembers the assigned identifier and sequence numbers.
     149 *  Runs until the client module disconnects.
     150 *  @param[in] callid The message identifier.
     151 *  @param[in] call The message parameters.
     152 *  @returns EOK.
     153 *  @see icmp_interface.h
     154 *  @see icmp_api.h
     155 */
     156int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call);
     157
     158/** Processes the generic client messages.
     159 *  @param[in] call The message parameters.
     160 *  @returns EOK on success.
     161 *  @returns ENOTSUP if the message is not known.
     162 *  @returns Other error codes as defined for the packet_translate() function.
     163 *  @returns Other error codes as defined for the icmp_destination_unreachable_msg() function.
     164 *  @returns Other error codes as defined for the icmp_source_quench_msg() function.
     165 *  @returns Other error codes as defined for the icmp_time_exceeded_msg() function.
     166 *  @returns Other error codes as defined for the icmp_parameter_problem_msg() function.
     167 *  @see icmp_interface.h
     168 */
     169int icmp_process_message(ipc_call_t * call);
     170
     171/** Releases the packet and returns the result.
     172 *  @param[in] packet The packet queue to be released.
     173 *  @param[in] result The result to be returned.
     174 *  @returns The result parameter.
     175 */
     176int icmp_release_and_return(packet_t packet, int result);
     177
     178/** Requests an echo message.
     179 *  Sends a packet with specified parameters to the target host and waits for the reply upto the given timeout.
     180 *  Blocks the caller until the reply or the timeout occurs.
     181 *  @param[in] id The message identifier.
     182 *  @param[in] sequence The message sequence parameter.
     183 *  @param[in] size The message data length in bytes.
     184 *  @param[in] timeout The timeout in miliseconds.
     185 *  @param[in] ttl The time to live.
     186 *  @param[in] tos The type of service.
     187 *  @param[in] dont_fragment The value indicating whether the datagram must not be fragmented. Is used as a MTU discovery.
     188 *  @param[in] addr The target host address.
     189 *  @param[in] addrlen The torget host address length.
     190 *  @returns ICMP_ECHO on success.
     191 *  @returns ETIMEOUT if the reply has not arrived before the timeout.
     192 *  @returns ICMP type of the received error notification.
     193 *  @returns EINVAL if the addrlen parameter is less or equal to zero (<=0).
     194 *  @returns ENOMEM if there is not enough memory left.
     195 *  @returns EPARTY if there was an internal error.
     196 */
     197int 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);
     198
     199/** Prepares the ICMP error packet.
     200 *  Truncates the original packet if longer than ICMP_KEEP_LENGTH bytes.
     201 *  Prefixes and returns the ICMP header.
     202 *  @param[in,out] packet The original packet.
     203 *  @returns The prefixed ICMP header.
     204 *  @returns NULL on errors.
     205 */
     206icmp_header_ref icmp_prepare_packet(packet_t packet);
     207
     208/** Sends the ICMP message.
     209 *  Sets the message type and code and computes the checksum.
     210 *  Error messages are sent only if allowed in the configuration.
     211 *  Releases the packet on errors.
     212 *  @param[in] type The message type.
     213 *  @param[in] code The message code.
     214 *  @param[in] packet The message packet to be sent.
     215 *  @param[in] header The ICMP header.
     216 *  @param[in] error The error service to be announced. Should be SERVICE_ICMP or zero (0).
     217 *  @param[in] ttl The time to live.
     218 *  @param[in] tos The type of service.
     219 *  @param[in] dont_fragment The value indicating whether the datagram must not be fragmented. Is used as a MTU discovery.
     220 *  @returns EOK on success.
     221 *  @returns EPERM if the error message is not allowed.
     222 */
     223int 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);
     224
     225/** Tries to set the pending reply result as the received message type.
     226 *  If the reply data is not present, the reply timed out and the other fibril
     227 *  is already awake.
     228 *  Releases the packet.
     229 *  @param[in] packet The received reply message.
     230 *  @param[in] header The ICMP message header.
     231 *  @param[in] type The received reply message type.
     232 *  @param[in] code The received reply message code.
     233 *  @returns EOK.
     234 */
     235int icmp_process_echo_reply(packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code);
     236
     237/** Assigns a new identifier for the connection.
     238 *  Fills the echo data parameter with the assigned values.
     239 *  @param[in,out] echo_data The echo data to be bound.
     240 *  @returns Index of the inserted echo data.
     241 *  @returns EBADMEM if the echo_data parameter is NULL.
     242 *  @returns ENOTCONN if no free identifier have been found.
     243 */
     244int icmp_bind_free_id(icmp_echo_ref echo_data);
     245
     246/** ICMP global data.
     247 */
    121248icmp_globals_t  icmp_globals;
    122249
    123250INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t);
     251
    124252INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t);
    125253
    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  * @return              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));
     254int 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){
     255        icmp_echo_ref echo_data;
     256        int res;
     257
     258        fibril_rwlock_write_lock(&icmp_globals.lock);
     259        // use the phone as the echo data index
     260        echo_data = icmp_echo_data_find(&icmp_globals.echo_data, icmp_phone);
     261        if(! echo_data){
     262                res = ENOENT;
     263        }else{
     264                res = icmp_echo(echo_data->identifier, echo_data->sequence_number, size, timeout, ttl, tos, dont_fragment, addr, addrlen);
     265                if(echo_data->sequence_number < UINT16_MAX){
     266                        ++ echo_data->sequence_number;
     267                }else{
     268                        echo_data->sequence_number = 0;
     269                }
     270        }
     271        fibril_rwlock_write_unlock(&icmp_globals.lock);
     272        return res;
     273}
     274
     275int 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){
     276        ERROR_DECLARE;
     277
     278        icmp_header_ref header;
     279        packet_t packet;
     280        size_t length;
     281        uint8_t * data;
     282        icmp_reply_ref reply;
     283        int reply_key;
     284        int result;
     285        int index;
     286
     287        if(addrlen <= 0){
     288                return EINVAL;
     289        }
     290        length = (size_t) addrlen;
     291        // TODO do not ask all the time
     292        ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1, &icmp_globals.packet_dimension));
     293        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);
     294        if(! packet){
     295                return ENOMEM;
     296        }
     297
     298        // prepare the requesting packet
     299        // set the destination address
     300        if(ERROR_OCCURRED(packet_set_addr(packet, NULL, (const uint8_t *) addr, length))){
     301                return icmp_release_and_return(packet, ERROR_CODE);
     302        }
     303        // allocate space in the packet
     304        data = (uint8_t *) packet_suffix(packet, size);
     305        if(! data){
     306                return icmp_release_and_return(packet, ENOMEM);
     307        }
     308        // fill the data
     309        length = 0;
     310        while(size > length + sizeof(ICMP_ECHO_TEXT)){
     311                memcpy(data + length, ICMP_ECHO_TEXT, sizeof(ICMP_ECHO_TEXT));
     312                length += sizeof(ICMP_ECHO_TEXT);
     313        }
     314        memcpy(data + length, ICMP_ECHO_TEXT, size - length);
     315        // prefix the header
     316        header = PACKET_PREFIX(packet, icmp_header_t);
     317        if(! header){
     318                return icmp_release_and_return(packet, ENOMEM);
     319        }
     320        bzero(header, sizeof(*header));
     321        header->un.echo.identifier = id;
     322        header->un.echo.sequence_number = sequence;
     323
     324        // prepare the reply structure
     325        reply = malloc(sizeof(*reply));
     326        if(! reply){
     327                return icmp_release_and_return(packet, ENOMEM);
     328        }
     329        fibril_mutex_initialize(&reply->mutex);
     330        fibril_mutex_lock(&reply->mutex);
     331        fibril_condvar_initialize(&reply->condvar);
     332        reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier, header->un.echo.sequence_number);
     333        index = icmp_replies_add(&icmp_globals.replies, reply_key, reply);
     334        if(index < 0){
     335                free(reply);
     336                return icmp_release_and_return(packet, index);
     337        }
     338
     339        // unlock the globals so that we can wait for the reply
     340        fibril_rwlock_write_unlock(&icmp_globals.lock);
     341
     342        // send the request
     343        icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos, dont_fragment);
     344
     345        // wait for the reply
     346        // timeout in microseconds
     347        if(ERROR_OCCURRED(fibril_condvar_wait_timeout(&reply->condvar, &reply->mutex, timeout * 1000))){
     348                result = ERROR_CODE;
     349        }else{
     350                // read the result
     351                result = reply->result;
     352        }
     353
     354        // drop the reply mutex before locking the globals again
     355        fibril_mutex_unlock(&reply->mutex);
     356        fibril_rwlock_write_lock(&icmp_globals.lock);
     357
     358        // destroy the reply structure
     359        icmp_replies_exclude_index(&icmp_globals.replies, index);
    135360        return result;
    136361}
    137362
    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  * @return              EOK on success.
    155  * @return              EPERM if the error message is not allowed.
    156  */
    157 static int icmp_send_packet(icmp_type_t type, icmp_code_t code, packet_t *packet,
    158     icmp_header_t *header, services_t error, ip_ttl_t ttl, ip_tos_t tos,
    159     int dont_fragment)
    160 {
    161         int rc;
    162 
    163         /* Do not send an error if disabled */
    164         if (error && !icmp_globals.error_reporting)
     363int icmp_destination_unreachable_msg(int icmp_phone, icmp_code_t code, icmp_param_t mtu, packet_t packet){
     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        if(mtu){
     371                header->un.frag.mtu = mtu;
     372        }
     373        return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header, SERVICE_ICMP, 0, 0, 0);
     374}
     375
     376int icmp_source_quench_msg(int icmp_phone, packet_t packet){
     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_SOURCE_QUENCH, 0, packet, header, SERVICE_ICMP, 0, 0, 0);
     384}
     385
     386int icmp_time_exceeded_msg(int icmp_phone, icmp_code_t code, packet_t packet){
     387        icmp_header_ref header;
     388
     389        header = icmp_prepare_packet(packet);
     390        if(! header){
     391                return icmp_release_and_return(packet, ENOMEM);
     392        }
     393        return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header, SERVICE_ICMP, 0, 0, 0);
     394}
     395
     396int icmp_parameter_problem_msg(int icmp_phone, icmp_code_t code, icmp_param_t pointer, packet_t packet){
     397        icmp_header_ref header;
     398
     399        header = icmp_prepare_packet(packet);
     400        if(! header){
     401                return icmp_release_and_return(packet, ENOMEM);
     402        }
     403        header->un.param.pointer = pointer;
     404        return icmp_send_packet(ICMP_PARAMETERPROB, code, packet, header, SERVICE_ICMP, 0, 0, 0);
     405}
     406
     407icmp_header_ref icmp_prepare_packet(packet_t packet){
     408        icmp_header_ref header;
     409        size_t header_length;
     410        size_t total_length;
     411
     412        total_length = packet_get_data_length(packet);
     413        if(total_length <= 0){
     414                return NULL;
     415        }
     416        header_length = ip_client_header_length(packet);
     417        if(header_length <= 0){
     418                return NULL;
     419        }
     420        // truncate if longer than 64 bits (without the IP header)
     421        if((total_length > header_length + ICMP_KEEP_LENGTH)
     422                && (packet_trim(packet, 0, total_length - header_length - ICMP_KEEP_LENGTH) != EOK)){
     423                return NULL;
     424        }
     425        header = PACKET_PREFIX(packet, icmp_header_t);
     426        if(! header){
     427                return NULL;
     428        }
     429        bzero(header, sizeof(*header));
     430        return header;
     431}
     432
     433int 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){
     434        ERROR_DECLARE;
     435
     436        // do not send an error if disabled
     437        if(error && (! icmp_globals.error_reporting)){
    165438                return icmp_release_and_return(packet, EPERM);
    166 
     439        }
    167440        header->type = type;
    168441        header->code = code;
    169442        header->checksum = 0;
    170         header->checksum = ICMP_CHECKSUM(header,
    171             packet_get_data_length(packet));
    172        
    173         rc = ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl, tos,
    174             dont_fragment, 0);
    175         if (rc != EOK)
    176                 return icmp_release_and_return(packet, rc);
    177 
    178         return ip_send_msg(icmp_globals.ip_phone, -1, packet, SERVICE_ICMP,
    179             error);
    180 }
    181 
    182 /** Prepares the ICMP error packet.
    183  *
    184  * Truncates the original packet if longer than ICMP_KEEP_LENGTH bytes.
    185  * Prefixes and returns the ICMP header.
    186  *
    187  * @param[in,out] packet The original packet.
    188  * @return The prefixed ICMP header.
    189  * @return NULL on errors.
    190  */
    191 static icmp_header_t *icmp_prepare_packet(packet_t *packet)
    192 {
    193         icmp_header_t *header;
    194         size_t header_length;
    195         size_t total_length;
    196 
    197         total_length = packet_get_data_length(packet);
    198         if (total_length <= 0)
    199                 return NULL;
    200 
    201         header_length = ip_client_header_length(packet);
    202         if (header_length <= 0)
    203                 return NULL;
    204 
    205         /* Truncate if longer than 64 bits (without the IP header) */
    206         if ((total_length > header_length + ICMP_KEEP_LENGTH) &&
    207             (packet_trim(packet, 0,
    208             total_length - header_length - ICMP_KEEP_LENGTH) != EOK)) {
    209                 return NULL;
    210         }
    211 
    212         header = PACKET_PREFIX(packet, icmp_header_t);
    213         if (!header)
    214                 return NULL;
    215 
    216         bzero(header, sizeof(*header));
    217         return header;
    218 }
    219 
    220 /** Requests an echo message.
    221  *
    222  * Sends a packet with specified parameters to the target host and waits for
    223  * the reply upto the given timeout.
    224  * Blocks the caller until the reply or the timeout occurs.
    225  *
    226  * @param[in] id        The message identifier.
    227  * @param[in] sequence  The message sequence parameter.
    228  * @param[in] size      The message data length in bytes.
    229  * @param[in] timeout   The timeout in miliseconds.
    230  * @param[in] ttl       The time to live.
    231  * @param[in] tos       The type of service.
    232  * @param[in] dont_fragment The value indicating whether the datagram must not
    233  *                      be fragmented. Is used as a MTU discovery.
    234  * @param[in] addr      The target host address.
    235  * @param[in] addrlen   The torget host address length.
    236  * @return              ICMP_ECHO on success.
    237  * @return              ETIMEOUT if the reply has not arrived before the
    238  *                      timeout.
    239  * @return              ICMP type of the received error notification.
    240  * @return              EINVAL if the addrlen parameter is less or equal to
    241  *                      zero.
    242  * @return              ENOMEM if there is not enough memory left.
    243  * @return              EPARTY if there was an internal error.
    244  */
    245 static int icmp_echo(icmp_param_t id, icmp_param_t sequence, size_t size,
    246     mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment,
    247     const struct sockaddr * addr, socklen_t addrlen)
    248 {
    249         icmp_header_t *header;
    250         packet_t *packet;
    251         size_t length;
    252         uint8_t *data;
    253         icmp_reply_t *reply;
    254         int reply_key;
     443        header->checksum = ICMP_CHECKSUM(header, packet_get_data_length(packet));
     444        if(ERROR_OCCURRED(ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl, tos, dont_fragment, 0))){
     445                return icmp_release_and_return(packet, ERROR_CODE);
     446        }
     447        return ip_send_msg(icmp_globals.ip_phone, -1, packet, SERVICE_ICMP, error);
     448}
     449
     450int icmp_connect_module(services_t service, suseconds_t timeout){
     451        icmp_echo_ref echo_data;
     452        icmp_param_t id;
    255453        int index;
    256         int rc;
    257 
    258         if (addrlen <= 0)
    259                 return EINVAL;
    260 
    261         length = (size_t) addrlen;
    262         /* TODO do not ask all the time */
    263         rc = ip_packet_size_req(icmp_globals.ip_phone, -1,
    264             &icmp_globals.packet_dimension);
    265         if (rc != EOK)
    266                 return rc;
    267 
    268         packet = packet_get_4_remote(icmp_globals.net_phone, size,
    269             icmp_globals.packet_dimension.addr_len,
    270             ICMP_HEADER_SIZE + icmp_globals.packet_dimension.prefix,
    271             icmp_globals.packet_dimension.suffix);
    272         if (!packet)
     454
     455        echo_data = (icmp_echo_ref) malloc(sizeof(*echo_data));
     456        if(! echo_data){
    273457                return ENOMEM;
    274 
    275         /* Prepare the requesting packet, set the destination address. */
    276         rc = packet_set_addr(packet, NULL, (const uint8_t *) addr, length);
    277         if (rc != EOK)
    278                 return icmp_release_and_return(packet, rc);
    279 
    280         /* Allocate space in the packet */
    281         data = (uint8_t *) packet_suffix(packet, size);
    282         if (!data)
    283                 return icmp_release_and_return(packet, ENOMEM);
    284 
    285         /* Fill the data */
    286         length = 0;
    287         while (size > length + sizeof(ICMP_ECHO_TEXT)) {
    288                 memcpy(data + length, ICMP_ECHO_TEXT, sizeof(ICMP_ECHO_TEXT));
    289                 length += sizeof(ICMP_ECHO_TEXT);
    290         }
    291         memcpy(data + length, ICMP_ECHO_TEXT, size - length);
    292 
    293         /* Prefix the header */
    294         header = PACKET_PREFIX(packet, icmp_header_t);
    295         if (!header)
    296                 return icmp_release_and_return(packet, ENOMEM);
    297 
    298         bzero(header, sizeof(*header));
    299         header->un.echo.identifier = id;
    300         header->un.echo.sequence_number = sequence;
    301 
    302         /* Prepare the reply structure */
    303         reply = malloc(sizeof(*reply));
    304         if (!reply)
    305                 return icmp_release_and_return(packet, ENOMEM);
    306 
    307         fibril_mutex_initialize(&reply->mutex);
    308         fibril_mutex_lock(&reply->mutex);
    309         fibril_condvar_initialize(&reply->condvar);
    310         reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier,
    311             header->un.echo.sequence_number);
    312         index = icmp_replies_add(&icmp_globals.replies, reply_key, reply);
    313         if (index < 0) {
    314                 free(reply);
    315                 return icmp_release_and_return(packet, index);
    316         }
    317 
    318         /* Unlock the globals so that we can wait for the reply */
    319         fibril_rwlock_write_unlock(&icmp_globals.lock);
    320 
    321         /* Send the request */
    322         icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos,
    323             dont_fragment);
    324 
    325         /* Wait for the reply. Timeout in microseconds. */
    326         rc = fibril_condvar_wait_timeout(&reply->condvar, &reply->mutex,
    327             timeout * 1000);
    328         if (rc == EOK)
    329                 rc = reply->result;
    330 
    331         /* Drop the reply mutex before locking the globals again */
    332         fibril_mutex_unlock(&reply->mutex);
     458        }
     459        // assign a new identifier
    333460        fibril_rwlock_write_lock(&icmp_globals.lock);
    334 
    335         /* Destroy the reply structure */
    336         icmp_replies_exclude_index(&icmp_globals.replies, index);
    337 
    338         return rc;
    339 }
    340 
    341 static int icmp_destination_unreachable_msg_local(int icmp_phone,
    342     icmp_code_t code, icmp_param_t mtu, packet_t *packet)
    343 {
    344         icmp_header_t *header;
    345 
    346         header = icmp_prepare_packet(packet);
    347         if (!header)
    348                 return icmp_release_and_return(packet, ENOMEM);
    349 
    350         if (mtu)
    351                 header->un.frag.mtu = mtu;
    352 
    353         return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header,
    354             SERVICE_ICMP, 0, 0, 0);
    355 }
    356 
    357 static int icmp_source_quench_msg_local(int icmp_phone, packet_t *packet)
    358 {
    359         icmp_header_t *header;
    360 
    361         header = icmp_prepare_packet(packet);
    362         if (!header)
    363                 return icmp_release_and_return(packet, ENOMEM);
    364 
    365         return icmp_send_packet(ICMP_SOURCE_QUENCH, 0, packet, header,
    366             SERVICE_ICMP, 0, 0, 0);
    367 }
    368 
    369 static int icmp_time_exceeded_msg_local(int icmp_phone, icmp_code_t code,
    370     packet_t *packet)
    371 {
    372         icmp_header_t *header;
    373 
    374         header = icmp_prepare_packet(packet);
    375         if (!header)
    376                 return icmp_release_and_return(packet, ENOMEM);
    377 
    378         return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header,
    379             SERVICE_ICMP, 0, 0, 0);
    380 }
    381 
    382 static int icmp_parameter_problem_msg_local(int icmp_phone, icmp_code_t code,
    383     icmp_param_t pointer, packet_t *packet)
    384 {
    385         icmp_header_t *header;
    386 
    387         header = icmp_prepare_packet(packet);
    388         if (!header)
    389                 return icmp_release_and_return(packet, ENOMEM);
    390 
    391         header->un.param.pointer = pointer;
    392         return icmp_send_packet(ICMP_PARAMETERPROB, code, packet, header,
    393             SERVICE_ICMP, 0, 0, 0);
    394 }
    395 
    396 /** Initializes the ICMP module.
    397  *
    398  * @param[in] client_connection The client connection processing function. The
    399  *                      module skeleton propagates its own one.
    400  * @return              EOK on success.
    401  * @return              ENOMEM if there is not enough memory left.
    402  */
    403 int icmp_initialize(async_client_conn_t client_connection)
    404 {
    405         measured_string_t names[] = {
    406                 {
    407                         (char *) "ICMP_ERROR_REPORTING",
    408                         20
    409                 },
    410                 {
    411                         (char *) "ICMP_ECHO_REPLYING",
    412                         18
    413                 }
    414         };
    415         measured_string_t *configuration;
     461        index = icmp_bind_free_id(echo_data);
     462        if(index < 0){
     463                free(echo_data);
     464                fibril_rwlock_write_unlock(&icmp_globals.lock);
     465                return index;
     466        }else{
     467                id = echo_data->identifier;
     468                fibril_rwlock_write_unlock(&icmp_globals.lock);
     469                // return the echo data identifier as the ICMP phone
     470                return id;
     471        }
     472}
     473
     474int icmp_initialize(async_client_conn_t client_connection){
     475        ERROR_DECLARE;
     476
     477        measured_string_t names[] = {{str_dup("ICMP_ERROR_REPORTING"), 20}, {str_dup("ICMP_ECHO_REPLYING"), 18}};
     478        measured_string_ref configuration;
    416479        size_t count = sizeof(names) / sizeof(measured_string_t);
    417         char *data;
    418         int rc;
     480        char * data;
    419481
    420482        fibril_rwlock_initialize(&icmp_globals.lock);
     
    422484        icmp_replies_initialize(&icmp_globals.replies);
    423485        icmp_echo_data_initialize(&icmp_globals.echo_data);
    424        
    425         icmp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_ICMP,
    426             SERVICE_ICMP, client_connection);
    427         if (icmp_globals.ip_phone < 0) {
    428                 fibril_rwlock_write_unlock(&icmp_globals.lock);
     486        icmp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP, client_connection, icmp_received_msg);
     487        if(icmp_globals.ip_phone < 0){
    429488                return icmp_globals.ip_phone;
    430489        }
    431        
    432         rc = ip_packet_size_req(icmp_globals.ip_phone, -1,
    433             &icmp_globals.packet_dimension);
    434         if (rc != EOK) {
    435                 fibril_rwlock_write_unlock(&icmp_globals.lock);
    436                 return rc;
    437         }
    438 
     490        ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1, &icmp_globals.packet_dimension));
    439491        icmp_globals.packet_dimension.prefix += ICMP_HEADER_SIZE;
    440492        icmp_globals.packet_dimension.content -= ICMP_HEADER_SIZE;
    441 
     493        // get configuration
    442494        icmp_globals.error_reporting = NET_DEFAULT_ICMP_ERROR_REPORTING;
    443495        icmp_globals.echo_replying = NET_DEFAULT_ICMP_ECHO_REPLYING;
    444 
    445         /* Get configuration */
    446496        configuration = &names[0];
    447         rc = net_get_conf_req(icmp_globals.net_phone, &configuration, count,
    448             &data);
    449         if (rc != EOK) {
    450                 fibril_rwlock_write_unlock(&icmp_globals.lock);
    451                 return rc;
    452         }
    453        
    454         if (configuration) {
    455                 if (configuration[0].value) {
    456                         icmp_globals.error_reporting =
    457                             (configuration[0].value[0] == 'y');
     497        ERROR_PROPAGATE(net_get_conf_req(icmp_globals.net_phone, &configuration, count, &data));
     498        if(configuration){
     499                if(configuration[0].value){
     500                        icmp_globals.error_reporting = (configuration[0].value[0] == 'y');
    458501                }
    459                 if (configuration[1].value) {
    460                         icmp_globals.echo_replying =
    461                             (configuration[1].value[0] == 'y');
     502                if(configuration[1].value){
     503                        icmp_globals.echo_replying = (configuration[1].value[0] == 'y');
    462504                }
    463505                net_free_settings(configuration, data);
    464506        }
    465 
    466507        fibril_rwlock_write_unlock(&icmp_globals.lock);
    467508        return EOK;
    468509}
    469510
    470 /** Tries to set the pending reply result as the received message type.
    471  *
    472  * If the reply data is not present, the reply timed out and the other fibril
    473  * is already awake.
    474  * Releases the packet.
    475  *
    476  * @param[in] packet    The received reply message.
    477  * @param[in] header    The ICMP message header.
    478  * @param[in] type      The received reply message type.
    479  * @param[in] code      The received reply message code.
    480  */
    481 static void  icmp_process_echo_reply(packet_t *packet, icmp_header_t *header,
    482     icmp_type_t type, icmp_code_t code)
    483 {
    484         int reply_key;
    485         icmp_reply_t *reply;
    486 
    487         /* Compute the reply key */
    488         reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier,
    489             header->un.echo.sequence_number);
    490         pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
    491 
    492         /* Find the pending reply */
    493         fibril_rwlock_write_lock(&icmp_globals.lock);
    494         reply = icmp_replies_find(&icmp_globals.replies, reply_key);
    495         if (reply) {
    496                 reply->result = type;
    497                 fibril_condvar_signal(&reply->condvar);
    498         }
    499         fibril_rwlock_write_unlock(&icmp_globals.lock);
    500 }
    501 
    502 /** Processes the received ICMP packet.
    503  *
    504  * Notifies the destination socket application.
    505  *
    506  * @param[in,out] packet The received packet.
    507  * @param[in] error     The packet error reporting service. Prefixes the
    508  *                      received packet.
    509  * @return              EOK on success.
    510  * @return              EINVAL if the packet is not valid.
    511  * @return              EINVAL if the stored packet address is not the an_addr_t.
    512  * @return              EINVAL if the packet does not contain any data.
    513  * @return              NO_DATA if the packet content is shorter than the user
    514  *                      datagram header.
    515  * @return              ENOMEM if there is not enough memory left.
    516  * @return              EADDRNOTAVAIL if the destination socket does not exist.
    517  * @return              Other error codes as defined for the
    518  *                      ip_client_process_packet() function.
    519  */
    520 static int icmp_process_packet(packet_t *packet, services_t error)
    521 {
     511int icmp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error){
     512        ERROR_DECLARE;
     513
     514        if(ERROR_OCCURRED(icmp_process_packet(packet, error))){
     515                return icmp_release_and_return(packet, ERROR_CODE);
     516        }
     517
     518        return EOK;
     519}
     520
     521int icmp_process_packet(packet_t packet, services_t error){
     522        ERROR_DECLARE;
     523
    522524        size_t length;
    523         uint8_t *src;
     525        uint8_t * src;
    524526        int addrlen;
    525527        int result;
    526         void *data;
    527         icmp_header_t *header;
     528        void * data;
     529        icmp_header_ref header;
    528530        icmp_type_t type;
    529531        icmp_code_t code;
    530         int rc;
    531 
    532         switch (error) {
    533         case SERVICE_NONE:
    534                 break;
    535         case SERVICE_ICMP:
    536                 /* Process error */
    537                 result = icmp_client_process_packet(packet, &type, &code, NULL,
    538                     NULL);
    539                 if (result < 0)
    540                         return result;
    541                 length = (size_t) result;
    542                 /* Remove the error header */
    543                 rc = packet_trim(packet, length, 0);
    544                 if (rc != EOK)
    545                         return rc;
    546                 break;
    547         default:
    548                 return ENOTSUP;
    549         }
    550 
    551         /* Get rid of the IP header */
     532
     533        if(error){
     534                switch(error){
     535                        case SERVICE_ICMP:
     536                                // process error
     537                                result = icmp_client_process_packet(packet, &type, &code, NULL, NULL);
     538                                if(result < 0){
     539                                        return result;
     540                                }
     541                                length = (size_t) result;
     542                                // remove the error header
     543                                ERROR_PROPAGATE(packet_trim(packet, length, 0));
     544                                break;
     545                        default:
     546                                return ENOTSUP;
     547                }
     548        }
     549        // get rid of the ip header
    552550        length = ip_client_header_length(packet);
    553         rc = packet_trim(packet, length, 0);
    554         if (rc != EOK)
    555                 return rc;
     551        ERROR_PROPAGATE(packet_trim(packet, length, 0));
    556552
    557553        length = packet_get_data_length(packet);
    558         if (length <= 0)
     554        if(length <= 0){
    559555                return EINVAL;
    560 
    561         if (length < ICMP_HEADER_SIZE)
     556        }
     557        if(length < ICMP_HEADER_SIZE){
    562558                return EINVAL;
    563 
     559        }
    564560        data = packet_get_data(packet);
    565         if (!data)
     561        if(! data){
    566562                return EINVAL;
    567 
    568         /* Get ICMP header */
    569         header = (icmp_header_t *) data;
    570 
    571         if (header->checksum) {
    572                 while (ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO) {
    573                         /*
    574                          * Set the original message type on error notification.
    575                          * Type swap observed in Qemu.
    576                          */
    577                         if (error) {
    578                                 switch (header->type) {
    579                                 case ICMP_ECHOREPLY:
    580                                         header->type = ICMP_ECHO;
    581                                         continue;
     563        }
     564        // get icmp header
     565        header = (icmp_header_ref) data;
     566        // checksum
     567        if(header->checksum){
     568                while(ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO){
     569                        // set the original message type on error notification
     570                        // type swap observed in Qemu
     571                        if(error){
     572                                switch(header->type){
     573                                        case ICMP_ECHOREPLY:
     574                                                header->type = ICMP_ECHO;
     575                                                continue;
    582576                                }
    583577                        }
     
    585579                }
    586580        }
    587 
    588         switch (header->type) {
    589         case ICMP_ECHOREPLY:
    590                 if (error)
    591                         icmp_process_echo_reply(packet, header, type, code);
    592                 else
    593                         icmp_process_echo_reply(packet, header, ICMP_ECHO, 0);
    594 
    595                 return EOK;
    596 
    597         case ICMP_ECHO:
    598                 if (error) {
    599                         icmp_process_echo_reply(packet, header, type, code);
     581        switch(header->type){
     582                case ICMP_ECHOREPLY:
     583                        if(error){
     584                                return icmp_process_echo_reply(packet, header, type, code);
     585                        }else{
     586                                return icmp_process_echo_reply(packet, header, ICMP_ECHO, 0);
     587                        }
     588                case ICMP_ECHO:
     589                        if(error){
     590                                return icmp_process_echo_reply(packet, header, type, code);
     591                        // do not send a reply if disabled
     592                        }else if(icmp_globals.echo_replying){
     593                                addrlen = packet_get_addr(packet, &src, NULL);
     594                                if((addrlen > 0)
     595                                // set both addresses to the source one (avoids the source address deletion before setting the destination one)
     596                                        && (packet_set_addr(packet, src, src, (size_t) addrlen) == EOK)){
     597                                        // send the reply
     598                                        icmp_send_packet(ICMP_ECHOREPLY, 0, packet, header, 0, 0, 0, 0);
     599                                        return EOK;
     600                                }else{
     601                                        return EINVAL;
     602                                }
     603                        }else{
     604                                return EPERM;
     605                        }
     606                case ICMP_DEST_UNREACH:
     607                case ICMP_SOURCE_QUENCH:
     608                case ICMP_REDIRECT:
     609                case ICMP_ALTERNATE_ADDR:
     610                case ICMP_ROUTER_ADV:
     611                case ICMP_ROUTER_SOL:
     612                case ICMP_TIME_EXCEEDED:
     613                case ICMP_PARAMETERPROB:
     614                case ICMP_CONVERSION_ERROR:
     615                case ICMP_REDIRECT_MOBILE:
     616                case ICMP_SKIP:
     617                case ICMP_PHOTURIS:
     618                        ip_received_error_msg(icmp_globals.ip_phone, -1, packet, SERVICE_IP, SERVICE_ICMP);
    600619                        return EOK;
    601                 }
    602                
    603                 /* Do not send a reply if disabled */
    604                 if (icmp_globals.echo_replying) {
    605                         addrlen = packet_get_addr(packet, &src, NULL);
    606 
    607                         /*
    608                          * Set both addresses to the source one (avoids the
    609                          * source address deletion before setting the
    610                          * destination one).
    611                          */
    612                         if ((addrlen > 0) && (packet_set_addr(packet, src, src,
    613                             (size_t) addrlen) == EOK)) {
    614                                 /* Send the reply */
    615                                 icmp_send_packet(ICMP_ECHOREPLY, 0, packet,
    616                                     header, 0, 0, 0, 0);
    617                                 return EOK;
     620                default:
     621                        return ENOTSUP;
     622        }
     623}
     624
     625int icmp_process_echo_reply(packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code){
     626        int reply_key;
     627        icmp_reply_ref reply;
     628
     629        // compute the reply key
     630        reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier, header->un.echo.sequence_number);
     631        pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
     632        // lock the globals
     633        fibril_rwlock_write_lock(&icmp_globals.lock);
     634        // find the pending reply
     635        reply = icmp_replies_find(&icmp_globals.replies, reply_key);
     636        if(reply){
     637                // set the result
     638                reply->result = type;
     639                // notify the waiting fibril
     640                fibril_condvar_signal(&reply->condvar);
     641        }
     642        fibril_rwlock_write_unlock(&icmp_globals.lock);
     643        return EOK;
     644}
     645
     646int icmp_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
     647        ERROR_DECLARE;
     648
     649        packet_t packet;
     650
     651        *answer_count = 0;
     652        switch(IPC_GET_METHOD(*call)){
     653                case NET_TL_RECEIVED:
     654                        if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
     655                                ERROR_CODE = icmp_received_msg(IPC_GET_DEVICE(call), packet, SERVICE_ICMP, IPC_GET_ERROR(call));
    618656                        }
    619 
    620                         return EINVAL;
    621                 }
    622 
    623                 return EPERM;
    624 
    625         case ICMP_DEST_UNREACH:
    626         case ICMP_SOURCE_QUENCH:
    627         case ICMP_REDIRECT:
    628         case ICMP_ALTERNATE_ADDR:
    629         case ICMP_ROUTER_ADV:
    630         case ICMP_ROUTER_SOL:
    631         case ICMP_TIME_EXCEEDED:
    632         case ICMP_PARAMETERPROB:
    633         case ICMP_CONVERSION_ERROR:
    634         case ICMP_REDIRECT_MOBILE:
    635         case ICMP_SKIP:
    636         case ICMP_PHOTURIS:
    637                 ip_received_error_msg(icmp_globals.ip_phone, -1, packet,
    638                     SERVICE_IP, SERVICE_ICMP);
    639                 return EOK;
    640 
    641         default:
    642                 return ENOTSUP;
    643         }
    644 }
    645 
    646 /** Processes the received ICMP packet.
    647  *
    648  * Is used as an entry point from the underlying IP module.
    649  * Releases the packet on error.
    650  *
    651  * @param device_id     The device identifier. Ignored parameter.
    652  * @param[in,out] packet The received packet.
    653  * @param receiver      The target service. Ignored parameter.
    654  * @param[in] error     The packet error reporting service. Prefixes the
    655  *                      received packet.
    656  * @return              EOK on success.
    657  * @return              Other error codes as defined for the
    658  *                      icmp_process_packet() function.
    659  */
    660 static int icmp_received_msg_local(device_id_t device_id, packet_t *packet,
    661     services_t receiver, services_t error)
    662 {
    663         int rc;
    664 
    665         rc = icmp_process_packet(packet, error);
    666         if (rc != EOK)
    667                 return icmp_release_and_return(packet, rc);
    668 
    669         return EOK;
    670 }
    671 
    672 /** Processes the generic client messages.
    673  *
    674  * @param[in] call      The message parameters.
    675  * @return              EOK on success.
    676  * @return              ENOTSUP if the message is not known.
    677  * @return              Other error codes as defined for the packet_translate()
    678  *                      function.
    679  * @return              Other error codes as defined for the
    680  *                      icmp_destination_unreachable_msg_local() function.
    681  * @return              Other error codes as defined for the
    682  *                      icmp_source_quench_msg_local() function.
    683  * @return              Other error codes as defined for the
    684  *                      icmp_time_exceeded_msg_local() function.
    685  * @return              Other error codes as defined for the
    686  *                      icmp_parameter_problem_msg_local() function.
    687  *
    688  * @see icmp_interface.h
    689  */
    690 static int icmp_process_message(ipc_call_t *call)
    691 {
    692         packet_t *packet;
    693         int rc;
    694 
    695         switch (IPC_GET_METHOD(*call)) {
    696         case NET_ICMP_DEST_UNREACH:
    697                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    698                     IPC_GET_PACKET(call));
    699                 if (rc != EOK)
    700                         return rc;
    701                 return icmp_destination_unreachable_msg_local(0,
    702                     ICMP_GET_CODE(call), ICMP_GET_MTU(call), packet);
    703         case NET_ICMP_SOURCE_QUENCH:
    704                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    705                     IPC_GET_PACKET(call));
    706                 if (rc != EOK)
    707                         return rc;
    708                 return icmp_source_quench_msg_local(0, packet);
    709         case NET_ICMP_TIME_EXCEEDED:
    710                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    711                     IPC_GET_PACKET(call));
    712                 if (rc != EOK)
    713                         return rc;
    714                 return icmp_time_exceeded_msg_local(0, ICMP_GET_CODE(call),
    715                     packet);
    716         case NET_ICMP_PARAMETERPROB:
    717                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    718                     IPC_GET_PACKET(call));
    719                 if (rc != EOK)
    720                         return rc;
    721                 return icmp_parameter_problem_msg_local(0, ICMP_GET_CODE(call),
    722                     ICMP_GET_POINTER(call), packet);
    723         default:
    724                 return ENOTSUP;
    725         }
    726 }
    727 
    728 /** Assigns a new identifier for the connection.
    729  *
    730  * Fills the echo data parameter with the assigned values.
    731  *
    732  * @param[in,out] echo_data The echo data to be bound.
    733  * @return              Index of the inserted echo data.
    734  * @return              EBADMEM if the echo_data parameter is NULL.
    735  * @return              ENOTCONN if no free identifier have been found.
    736  */
    737 static int icmp_bind_free_id(icmp_echo_t *echo_data)
    738 {
    739         icmp_param_t index;
    740 
    741         if (!echo_data)
    742                 return EBADMEM;
    743 
    744         /* From the last used one */
    745         index = icmp_globals.last_used_id;
    746         do {
    747                 index++;
    748                 /* til the range end */
    749                 if (index >= ICMP_FREE_IDS_END) {
    750                         /* start from the range beginning */
    751                         index = ICMP_FREE_IDS_START - 1;
    752                         do {
    753                                 index++;
    754                                 /* til the last used one */
    755                                 if (index >= icmp_globals.last_used_id) {
    756                                         /* none found */
    757                                         return ENOTCONN;
    758                                 }
    759                         } while(icmp_echo_data_find(&icmp_globals.echo_data,
    760                             index) != NULL);
    761 
    762                         /* Found, break immediately */
    763                         break;
    764                 }
    765         } while (icmp_echo_data_find(&icmp_globals.echo_data, index) != NULL);
    766 
    767         echo_data->identifier = index;
    768         echo_data->sequence_number = 0;
    769 
    770         return icmp_echo_data_add(&icmp_globals.echo_data, index, echo_data);
    771 }
    772 
    773 /** Processes the client messages.
    774  *
    775  * Remembers the assigned identifier and sequence numbers.
    776  * Runs until the client module disconnects.
    777  *
    778  * @param[in] callid    The message identifier.
    779  * @param[in] call      The message parameters.
    780  * @return EOK.
    781  *
    782  * @see icmp_interface.h
    783  * @see icmp_api.h
    784  */
    785 static int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
    786 {
     657                        return ERROR_CODE;
     658                case NET_ICMP_INIT:
     659                        return icmp_process_client_messages(callid, * call);
     660                default:
     661                        return icmp_process_message(call);
     662        }
     663        return ENOTSUP;
     664}
     665
     666int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call){
     667        ERROR_DECLARE;
     668
    787669        bool keep_on_going = true;
     670//      fibril_rwlock_t                 lock;
    788671        ipc_call_t answer;
    789672        int answer_count;
    790673        size_t length;
    791         struct sockaddr *addr;
     674        struct sockaddr * addr;
    792675        ipc_callid_t data_callid;
    793         icmp_echo_t *echo_data;
    794         int rc = EOK;
     676        icmp_echo_ref echo_data;
     677        int res;
    795678
    796679        /*
     
    798681         *  - Answer the first NET_ICMP_INIT call.
    799682         */
     683        res = EOK;
    800684        answer_count = 0;
    801685
    802         echo_data = (icmp_echo_t *) malloc(sizeof(*echo_data));
    803         if (!echo_data)
     686//      fibril_rwlock_initialize(&lock);
     687
     688        echo_data = (icmp_echo_ref) malloc(sizeof(*echo_data));
     689        if(! echo_data){
    804690                return ENOMEM;
    805 
    806         /* Assign a new identifier */
     691        }
     692
     693        // assign a new identifier
    807694        fibril_rwlock_write_lock(&icmp_globals.lock);
    808         rc = icmp_bind_free_id(echo_data);
     695        res = icmp_bind_free_id(echo_data);
    809696        fibril_rwlock_write_unlock(&icmp_globals.lock);
    810         if (rc < 0) {
     697        if(res < 0){
    811698                free(echo_data);
    812                 return rc;
    813         }
    814 
    815         while (keep_on_going) {
    816                 /* Answer the call */
    817                 answer_call(callid, rc, &answer, answer_count);
    818 
    819                 /* Refresh data */
     699                return res;
     700        }
     701
     702        while(keep_on_going){
     703
     704                // answer the call
     705                answer_call(callid, res, &answer, answer_count);
     706
     707                // refresh data
    820708                refresh_answer(&answer, &answer_count);
    821709
    822                 /* Get the next call */
     710                // get the next call
    823711                callid = async_get_call(&call);
    824712
    825                 /* Process the call */
    826                 switch (IPC_GET_METHOD(call)) {
    827                 case IPC_M_PHONE_HUNGUP:
    828                         keep_on_going = false;
    829                         rc = EHANGUP;
    830                         break;
    831                
    832                 case NET_ICMP_ECHO:
    833                         if (!async_data_write_receive(&data_callid, &length)) {
    834                                 rc = EINVAL;
     713                // process the call
     714                switch(IPC_GET_METHOD(call)){
     715                        case IPC_M_PHONE_HUNGUP:
     716                                keep_on_going = false;
     717                                res = EHANGUP;
    835718                                break;
    836                         }
    837                        
    838                         addr = malloc(length);
    839                         if (!addr) {
    840                                 rc = ENOMEM;
     719                        case NET_ICMP_ECHO:
     720//                              fibril_rwlock_write_lock(&lock);
     721                                if(! async_data_write_receive(&data_callid, &length)){
     722                                        res = EINVAL;
     723                                }else{
     724                                        addr = malloc(length);
     725                                        if(! addr){
     726                                                res = ENOMEM;
     727                                        }else{
     728                                                if(! ERROR_OCCURRED(async_data_write_finalize(data_callid, addr, length))){
     729                                                        fibril_rwlock_write_lock(&icmp_globals.lock);
     730                                                        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);
     731                                                        fibril_rwlock_write_unlock(&icmp_globals.lock);
     732                                                        free(addr);
     733                                                        if(echo_data->sequence_number < UINT16_MAX){
     734                                                                ++ echo_data->sequence_number;
     735                                                        }else{
     736                                                                echo_data->sequence_number = 0;
     737                                                        }
     738                                                }else{
     739                                                        res = ERROR_CODE;
     740                                                }
     741                                        }
     742                                }
     743//                              fibril_rwlock_write_unlock(&lock);
    841744                                break;
    842                         }
    843                        
    844                         rc = async_data_write_finalize(data_callid, addr,
    845                             length);
    846                         if (rc != EOK) {
    847                                 free(addr);
    848                                 break;
    849                         }
    850 
    851                         fibril_rwlock_write_lock(&icmp_globals.lock);
    852                         rc = icmp_echo(echo_data->identifier,
    853                             echo_data->sequence_number, ICMP_GET_SIZE(call),
    854                             ICMP_GET_TIMEOUT(call), ICMP_GET_TTL(call),
    855                             ICMP_GET_TOS(call), ICMP_GET_DONT_FRAGMENT(call),
    856                             addr, (socklen_t) length);
    857                         fibril_rwlock_write_unlock(&icmp_globals.lock);
    858 
    859                         free(addr);
    860 
    861                         if (echo_data->sequence_number < UINT16_MAX)
    862                                 echo_data->sequence_number++;
    863                         else
    864                                 echo_data->sequence_number = 0;
    865 
    866                         break;
    867 
    868                 default:
    869                         rc = icmp_process_message(&call);
     745                        default:
     746                                res = icmp_process_message(&call);
    870747                }
    871 
    872         }
    873 
    874         /* Release the identifier */
     748        }
     749
     750        // release the identifier
    875751        fibril_rwlock_write_lock(&icmp_globals.lock);
    876752        icmp_echo_data_exclude(&icmp_globals.echo_data, echo_data->identifier);
    877753        fibril_rwlock_write_unlock(&icmp_globals.lock);
    878 
    879         return rc;
    880 }
    881 
    882 /** Processes the ICMP message.
    883  *
    884  * @param[in] callid    The message identifier.
    885  * @param[in] call      The message parameters.
    886  * @param[out] answer   The message answer parameters.
    887  * @param[out] answer_count The last parameter for the actual answer in the
    888  *                      answer parameter.
    889  * @return              EOK on success.
    890  * @return              ENOTSUP if the message is not known.
    891  *
    892  * @see icmp_interface.h
    893  * @see IS_NET_ICMP_MESSAGE()
    894  */
    895 int icmp_message_standalone(ipc_callid_t callid, ipc_call_t *call,
    896     ipc_call_t *answer, int *answer_count)
    897 {
    898         packet_t *packet;
    899         int rc;
    900 
    901         *answer_count = 0;
    902         switch (IPC_GET_METHOD(*call)) {
    903         case NET_TL_RECEIVED:
    904                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    905                     IPC_GET_PACKET(call));
    906                 if (rc != EOK)
    907                         return rc;
    908                 return icmp_received_msg_local(IPC_GET_DEVICE(call), packet,
    909                     SERVICE_ICMP, IPC_GET_ERROR(call));
    910        
    911         case NET_ICMP_INIT:
    912                 return icmp_process_client_messages(callid, * call);
    913        
    914         default:
    915                 return icmp_process_message(call);
    916         }
    917 
    918         return ENOTSUP;
    919 }
    920 
     754        return res;
     755}
     756
     757int icmp_process_message(ipc_call_t * call){
     758        ERROR_DECLARE;
     759
     760        packet_t packet;
     761
     762        switch(IPC_GET_METHOD(*call)){
     763                case NET_ICMP_DEST_UNREACH:
     764                        if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
     765                                ERROR_CODE = icmp_destination_unreachable_msg(0, ICMP_GET_CODE(call), ICMP_GET_MTU(call), packet);
     766                        }
     767                        return ERROR_CODE;
     768                case NET_ICMP_SOURCE_QUENCH:
     769                        if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
     770                                ERROR_CODE = icmp_source_quench_msg(0, packet);
     771                        }
     772                        return ERROR_CODE;
     773                case NET_ICMP_TIME_EXCEEDED:
     774                        if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
     775                                ERROR_CODE = icmp_time_exceeded_msg(0, ICMP_GET_CODE(call), packet);
     776                        }
     777                        return ERROR_CODE;
     778                case NET_ICMP_PARAMETERPROB:
     779                        if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
     780                                ERROR_CODE = icmp_parameter_problem_msg(0, ICMP_GET_CODE(call), ICMP_GET_POINTER(call), packet);
     781                        }
     782                        return ERROR_CODE;
     783                default:
     784                        return ENOTSUP;
     785        }
     786}
     787
     788int icmp_release_and_return(packet_t packet, int result){
     789        pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
     790        return result;
     791}
     792
     793int icmp_bind_free_id(icmp_echo_ref echo_data){
     794        icmp_param_t index;
     795
     796        if(! echo_data){
     797                return EBADMEM;
     798        }
     799        // from the last used one
     800        index = icmp_globals.last_used_id;
     801        do{
     802                ++ index;
     803                // til the range end
     804                if(index >= ICMP_FREE_IDS_END){
     805                        // start from the range beginning
     806                        index = ICMP_FREE_IDS_START - 1;
     807                        do{
     808                                ++ index;
     809                                // til the last used one
     810                                if(index >= icmp_globals.last_used_id){
     811                                        // none found
     812                                        return ENOTCONN;
     813                                }
     814                        }while(icmp_echo_data_find(&icmp_globals.echo_data, index) != NULL);
     815                        // found, break immediately
     816                        break;
     817                }
     818        }while(icmp_echo_data_find(&icmp_globals.echo_data, index) != NULL);
     819        echo_data->identifier = index;
     820        echo_data->sequence_number = 0;
     821        return icmp_echo_data_add(&icmp_globals.echo_data, index, echo_data);
     822}
    921823
    922824/** Default thread for new connections.
    923825 *
    924  * @param[in] iid The initial message identifier.
    925  * @param[in] icall The initial message call structure.
     826 *  @param[in] iid The initial message identifier.
     827 *  @param[in] icall The initial message call structure.
    926828 *
    927829 */
    928 static void tl_client_connection(ipc_callid_t iid, ipc_call_t *icall)
     830static void tl_client_connection(ipc_callid_t iid, ipc_call_t * icall)
    929831{
    930832        /*
     
    934836        ipc_answer_0(iid, EOK);
    935837       
    936         while (true) {
     838        while(true) {
    937839                ipc_call_t answer;
    938840                int answer_count;
     
    949851                    &answer_count);
    950852               
    951                 /*
    952                  * End if told to either by the message or the processing
    953                  * result.
    954                  */
    955                 if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) ||
    956                     (res == EHANGUP))
     853                /* End if said to either by the message or the processing result */
     854                if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) || (res == EHANGUP))
    957855                        return;
    958856               
     
    964862/** Starts the module.
    965863 *
    966  * @return              EOK on success.
    967  * @return              Other error codes as defined for each specific module
    968  *                      start function.
     864 *  @param argc The count of the command line arguments. Ignored parameter.
     865 *  @param argv The command line parameters. Ignored parameter.
     866 *
     867 *  @returns EOK on success.
     868 *  @returns Other error codes as defined for each specific module start function.
     869 *
    969870 */
    970871int main(int argc, char *argv[])
    971872{
    972         int rc;
     873        ERROR_DECLARE;
    973874       
    974875        /* Start the module */
    975         rc = tl_module_start_standalone(tl_client_connection);
    976         return rc;
     876        if (ERROR_OCCURRED(tl_module_start_standalone(tl_client_connection)))
     877                return ERROR_CODE;
     878       
     879        return EOK;
    977880}
    978881
    979882/** @}
    980883 */
    981 
Note: See TracChangeset for help on using the changeset viewer.