Changeset b40bfac in mainline for uspace/srv/net/tl/icmp/icmp.c


Ignore:
Timestamp:
2010-11-08T07:13:25Z (13 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
63a1e60
Parents:
d70a463 (diff), 3da12d74 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes

File:
1 edited

Legend:

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

    rd70a463 rb40bfac  
    2828
    2929/** @addtogroup icmp
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  ICMP module implementation.
    35  *  @see icmp.h
    36  */
     34 * ICMP module implementation.
     35 * @see icmp.h
     36 */
     37
     38#include "icmp.h"
     39#include "icmp_module.h"
    3740
    3841#include <async.h>
     
    5154#include <byteorder.h>
    5255#include <errno.h>
    53 #include <err.h>
    5456
    5557#include <net/socket_codes.h>
    5658#include <net/ip_protocols.h>
    5759#include <net/inet.h>
    58 
    5960#include <net/modules.h>
     61#include <net/icmp_api.h>
     62#include <net/icmp_codes.h>
     63#include <net/icmp_common.h>
     64
    6065#include <packet_client.h>
    6166#include <packet_remote.h>
    6267#include <net_checksum.h>
    63 #include <net/icmp_api.h>
    6468#include <icmp_client.h>
    65 #include <net/icmp_codes.h>
    66 #include <net/icmp_common.h>
    6769#include <icmp_interface.h>
    6870#include <il_interface.h>
     
    7476#include <icmp_header.h>
    7577
    76 #include "icmp.h"
    77 #include "icmp_module.h"
    78 
    79 /** ICMP module name.
    80  */
     78/** ICMP module name. */
    8179#define NAME    "ICMP protocol"
    8280
    83 /** Default ICMP error reporting.
    84  */
     81/** Default ICMP error reporting. */
    8582#define NET_DEFAULT_ICMP_ERROR_REPORTING        true
    8683
    87 /** Default ICMP echo replying.
    88  */
     84/** Default ICMP echo replying. */
    8985#define NET_DEFAULT_ICMP_ECHO_REPLYING          true
    9086
    91 /** Original datagram length in bytes transfered to the error notification message.
     87/** Original datagram length in bytes transfered to the error notification
     88 * message.
    9289 */
    9390#define ICMP_KEEP_LENGTH        8
    9491
    95 /** Free identifier numbers pool start.
    96  */
     92/** Free identifier numbers pool start. */
    9793#define ICMP_FREE_IDS_START     1
    9894
    99 /** Free identifier numbers pool end.
    100  */
     95/** Free identifier numbers pool end. */
    10196#define ICMP_FREE_IDS_END       UINT16_MAX
    10297
    10398/** Computes the ICMP datagram checksum.
    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."
     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."
    113109
    114110/** Computes an ICMP reply data key.
    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  */
    131 int 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  */
    146 int 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  */
    157 int 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  */
    170 int icmp_process_message(ipc_call_t * call);
     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. */
     121icmp_globals_t  icmp_globals;
     122
     123INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t);
     124INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t);
    171125
    172126/** 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  */
    177 int icmp_release_and_return(packet_t packet, int 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 */
     132static int icmp_release_and_return(packet_t packet, int result)
     133{
     134        pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
     135        return result;
     136}
     137
     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 */
     157static int
     158icmp_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;
     163
     164        // do not send an error if disabled
     165        if (error && !icmp_globals.error_reporting)
     166                return icmp_release_and_return(packet, EPERM);
     167
     168        header->type = type;
     169        header->code = code;
     170        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 */
     192static 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}
    178220
    179221/** 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  */
    198 int 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  */
    207 icmp_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  */
    224 int 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  */
    236 int 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  */
    245 int icmp_bind_free_id(icmp_echo_ref echo_data);
    246 
    247 /** ICMP global data.
    248  */
    249 icmp_globals_t  icmp_globals;
    250 
    251 INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t);
    252 
    253 INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t);
    254 
    255 int 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 
    276 int 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 
     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 */
     246static int
     247icmp_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{
    279251        icmp_header_ref header;
    280252        packet_t packet;
    281253        size_t length;
    282         uint8_t * data;
     254        uint8_t *data;
    283255        icmp_reply_ref reply;
    284256        int reply_key;
    285         int result;
    286257        int index;
    287 
    288         if(addrlen <= 0){
     258        int rc;
     259
     260        if (addrlen <= 0)
    289261                return EINVAL;
    290         }
     262
    291263        length = (size_t) addrlen;
    292264        // 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){
     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)
    296275                return ENOMEM;
    297         }
    298276
    299277        // prepare the requesting packet
    300278        // 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         }
     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
    304283        // allocate space in the packet
    305284        data = (uint8_t *) packet_suffix(packet, size);
    306         if(! data){
     285        if (!data)
    307286                return icmp_release_and_return(packet, ENOMEM);
    308         }
     287
    309288        // fill the data
    310289        length = 0;
    311         while(size > length + sizeof(ICMP_ECHO_TEXT)){
     290        while (size > length + sizeof(ICMP_ECHO_TEXT)) {
    312291                memcpy(data + length, ICMP_ECHO_TEXT, sizeof(ICMP_ECHO_TEXT));
    313292                length += sizeof(ICMP_ECHO_TEXT);
    314293        }
    315294        memcpy(data + length, ICMP_ECHO_TEXT, size - length);
     295
    316296        // prefix the header
    317297        header = PACKET_PREFIX(packet, icmp_header_t);
    318         if(! header){
     298        if (!header)
    319299                return icmp_release_and_return(packet, ENOMEM);
    320         }
     300
    321301        bzero(header, sizeof(*header));
    322302        header->un.echo.identifier = id;
     
    325305        // prepare the reply structure
    326306        reply = malloc(sizeof(*reply));
    327         if(! reply){
     307        if (!reply)
    328308                return icmp_release_and_return(packet, ENOMEM);
    329         }
     309
    330310        fibril_mutex_initialize(&reply->mutex);
    331311        fibril_mutex_lock(&reply->mutex);
    332312        fibril_condvar_initialize(&reply->condvar);
    333         reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier, header->un.echo.sequence_number);
     313        reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier,
     314            header->un.echo.sequence_number);
    334315        index = icmp_replies_add(&icmp_globals.replies, reply_key, reply);
    335         if(index < 0){
     316        if (index < 0) {
    336317                free(reply);
    337318                return icmp_release_and_return(packet, index);
     
    342323
    343324        // send the request
    344         icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos, dont_fragment);
     325        icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos,
     326            dont_fragment);
    345327
    346328        // wait for the reply
    347329        // 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         }
     330        rc = fibril_condvar_wait_timeout(&reply->condvar, &reply->mutex,
     331            timeout * 1000);
     332        if (rc == EOK)
     333                rc = reply->result;
    354334
    355335        // drop the reply mutex before locking the globals again
     
    359339        // destroy the reply structure
    360340        icmp_replies_exclude_index(&icmp_globals.replies, index);
    361         return result;
    362 }
    363 
    364 int icmp_destination_unreachable_msg(int icmp_phone, icmp_code_t code, icmp_param_t mtu, packet_t packet){
     341
     342        return rc;
     343}
     344
     345static int
     346icmp_destination_unreachable_msg_local(int icmp_phone, icmp_code_t code,
     347    icmp_param_t mtu, packet_t packet)
     348{
    365349        icmp_header_ref header;
    366350
    367351        header = icmp_prepare_packet(packet);
    368         if(! header){
     352        if (!header)
    369353                return icmp_release_and_return(packet, ENOMEM);
    370         }
    371         if(mtu){
     354
     355        if (mtu)
    372356                header->un.frag.mtu = mtu;
    373         }
    374         return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header, SERVICE_ICMP, 0, 0, 0);
    375 }
    376 
    377 int icmp_source_quench_msg(int icmp_phone, packet_t packet){
     357
     358        return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header,
     359            SERVICE_ICMP, 0, 0, 0);
     360}
     361
     362static int icmp_source_quench_msg_local(int icmp_phone, packet_t packet)
     363{
    378364        icmp_header_ref header;
    379365
    380366        header = icmp_prepare_packet(packet);
    381         if(! header){
     367        if (!header)
    382368                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 
    387 int icmp_time_exceeded_msg(int icmp_phone, icmp_code_t code, packet_t packet){
     369
     370        return icmp_send_packet(ICMP_SOURCE_QUENCH, 0, packet, header,
     371            SERVICE_ICMP, 0, 0, 0);
     372}
     373
     374static int
     375icmp_time_exceeded_msg_local(int icmp_phone, icmp_code_t code, packet_t packet)
     376{
    388377        icmp_header_ref header;
    389378
    390379        header = icmp_prepare_packet(packet);
    391         if(! header){
     380        if (!header)
    392381                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 
    397 int icmp_parameter_problem_msg(int icmp_phone, icmp_code_t code, icmp_param_t pointer, packet_t packet){
     382
     383        return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header,
     384            SERVICE_ICMP, 0, 0, 0);
     385}
     386
     387static int
     388icmp_parameter_problem_msg_local(int icmp_phone, icmp_code_t code,
     389    icmp_param_t pointer, packet_t packet)
     390{
    398391        icmp_header_ref header;
    399392
    400393        header = icmp_prepare_packet(packet);
    401         if(! header){
     394        if (!header)
    402395                return icmp_release_and_return(packet, ENOMEM);
    403         }
     396
    404397        header->un.param.pointer = pointer;
    405         return icmp_send_packet(ICMP_PARAMETERPROB, code, packet, header, SERVICE_ICMP, 0, 0, 0);
    406 }
    407 
    408 icmp_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 
    434 int 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;
    436 
    437         // do not send an error if disabled
    438         if(error && (! icmp_globals.error_reporting)){
    439                 return icmp_release_and_return(packet, EPERM);
    440         }
    441         header->type = type;
    442         header->code = code;
    443         header->checksum = 0;
    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 
    451 int 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}};
     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 */
     409int 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        };
    455421        measured_string_ref configuration;
    456422        size_t count = sizeof(names) / sizeof(measured_string_t);
    457         char * data;
     423        char *data;
     424        int rc;
    458425
    459426        fibril_rwlock_initialize(&icmp_globals.lock);
     
    461428        icmp_replies_initialize(&icmp_globals.replies);
    462429        icmp_echo_data_initialize(&icmp_globals.echo_data);
    463         icmp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP, client_connection);
    464         if(icmp_globals.ip_phone < 0){
     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);
    465435                return icmp_globals.ip_phone;
    466436        }
    467         ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1, &icmp_globals.packet_dimension));
     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
    468445        icmp_globals.packet_dimension.prefix += ICMP_HEADER_SIZE;
    469446        icmp_globals.packet_dimension.content -= ICMP_HEADER_SIZE;
    470         // get configuration
     447
    471448        icmp_globals.error_reporting = NET_DEFAULT_ICMP_ERROR_REPORTING;
    472449        icmp_globals.echo_replying = NET_DEFAULT_ICMP_ECHO_REPLYING;
     450
     451        // get configuration
    473452        configuration = &names[0];
    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');
     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');
    478464                }
    479                 if(configuration[1].value){
    480                         icmp_globals.echo_replying = (configuration[1].value[0] == 'y');
     465                if (configuration[1].value) {
     466                        icmp_globals.echo_replying =
     467                            (configuration[1].value[0] == 'y');
    481468                }
    482469                net_free_settings(configuration, data);
    483470        }
     471
    484472        fibril_rwlock_write_unlock(&icmp_globals.lock);
    485473        return EOK;
    486474}
    487475
    488 int 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 
    498 int icmp_process_packet(packet_t packet, services_t error){
    499         ERROR_DECLARE;
    500 
     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 */
     487static void
     488icmp_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 */
     527static int icmp_process_packet(packet_t packet, services_t error)
     528{
    501529        size_t length;
    502         uint8_t * src;
     530        uint8_t *src;
    503531        int addrlen;
    504532        int result;
    505         void * data;
     533        void *data;
    506534        icmp_header_ref header;
    507535        icmp_type_t type;
    508536        icmp_code_t code;
    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         }
     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
    526558        // get rid of the ip header
    527559        length = ip_client_header_length(packet);
    528         ERROR_PROPAGATE(packet_trim(packet, length, 0));
     560        rc = packet_trim(packet, length, 0);
     561        if (rc != EOK)
     562                return rc;
    529563
    530564        length = packet_get_data_length(packet);
    531         if(length <= 0){
     565        if (length <= 0)
    532566                return EINVAL;
    533         }
    534         if(length < ICMP_HEADER_SIZE){
     567
     568        if (length < ICMP_HEADER_SIZE)
    535569                return EINVAL;
    536         }
     570
    537571        data = packet_get_data(packet);
    538         if(! data){
     572        if (!data)
    539573                return EINVAL;
    540         }
     574
    541575        // get icmp header
    542576        header = (icmp_header_ref) data;
    543         // checksum
    544         if(header->checksum){
    545                 while(ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO){
     577
     578        if (header->checksum) {
     579                while (ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO) {
    546580                        // set the original message type on error notification
    547581                        // type swap observed in Qemu
    548                         if(error){
    549                                 switch(header->type){
    550                                         case ICMP_ECHOREPLY:
    551                                                 header->type = ICMP_ECHO;
    552                                                 continue;
     582                        if (error) {
     583                                switch (header->type) {
     584                                case ICMP_ECHOREPLY:
     585                                        header->type = ICMP_ECHO;
     586                                        continue;
    553587                                }
    554588                        }
     
    556590                }
    557591        }
    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);
     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);
     605                        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;
    564621                        }
    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;
     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 */
     663static int
     664icmp_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 */
     694static 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 */
     741static 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;
    579762                                }
    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);
    596                         return EOK;
    597                 default:
    598                         return ENOTSUP;
    599         }
    600 }
    601 
    602 int 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 
    623 int 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));
    633                         }
    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 
    643 int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call){
    644         ERROR_DECLARE;
    645 
     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 */
     789static int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
     790{
    646791        bool keep_on_going = true;
    647 //      fibril_rwlock_t                 lock;
    648792        ipc_call_t answer;
    649793        int answer_count;
    650794        size_t length;
    651         struct sockaddr * addr;
     795        struct sockaddr *addr;
    652796        ipc_callid_t data_callid;
    653797        icmp_echo_ref echo_data;
    654         int res;
     798        int rc = EOK;
    655799
    656800        /*
     
    658802         *  - Answer the first NET_ICMP_INIT call.
    659803         */
    660         res = EOK;
    661804        answer_count = 0;
    662805
    663 //      fibril_rwlock_initialize(&lock);
    664 
    665806        echo_data = (icmp_echo_ref) malloc(sizeof(*echo_data));
    666         if(! echo_data){
     807        if (!echo_data)
    667808                return ENOMEM;
    668         }
    669809
    670810        // assign a new identifier
    671811        fibril_rwlock_write_lock(&icmp_globals.lock);
    672         res = icmp_bind_free_id(echo_data);
     812        rc = icmp_bind_free_id(echo_data);
    673813        fibril_rwlock_write_unlock(&icmp_globals.lock);
    674         if(res < 0){
     814        if (rc < 0) {
    675815                free(echo_data);
    676                 return res;
    677         }
    678 
    679         while(keep_on_going){
    680 
     816                return rc;
     817        }
     818
     819        while (keep_on_going) {
    681820                // answer the call
    682                 answer_call(callid, res, &answer, answer_count);
     821                answer_call(callid, rc, &answer, answer_count);
    683822
    684823                // refresh data
     
    689828
    690829                // process the call
    691                 switch(IPC_GET_METHOD(call)){
    692                         case IPC_M_PHONE_HUNGUP:
    693                                 keep_on_going = false;
    694                                 res = EHANGUP;
     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;
    695839                                break;
    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);
     840                        }
     841                       
     842                        addr = malloc(length);
     843                        if (!addr) {
     844                                rc = ENOMEM;
    721845                                break;
    722                         default:
    723                                 res = icmp_process_message(&call);
     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);
    724874                }
     875
    725876        }
    726877
     
    729880        icmp_echo_data_exclude(&icmp_globals.echo_data, echo_data->identifier);
    730881        fibril_rwlock_write_unlock(&icmp_globals.lock);
    731         return res;
    732 }
    733 
    734 int icmp_process_message(ipc_call_t * call){
    735         ERROR_DECLARE;
    736 
     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 */
     899int
     900icmp_message_standalone(ipc_callid_t callid, ipc_call_t *call,
     901    ipc_call_t *answer, int *answer_count)
     902{
    737903        packet_t packet;
    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 
    765 int 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 
    770 int 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 }
     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
    800926
    801927/** Default thread for new connections.
    802928 *
    803  *  @param[in] iid The initial message identifier.
    804  *  @param[in] icall The initial message call structure.
    805  *
    806  */
    807 static void tl_client_connection(ipc_callid_t iid, ipc_call_t * icall)
     929 * @param[in] iid The initial message identifier.
     930 * @param[in] icall The initial message call structure.
     931 *
     932 */
     933static void tl_client_connection(ipc_callid_t iid, ipc_call_t *icall)
    808934{
    809935        /*
     
    813939        ipc_answer_0(iid, EOK);
    814940       
    815         while(true) {
     941        while (true) {
    816942                ipc_call_t answer;
    817943                int answer_count;
     
    828954                    &answer_count);
    829955               
    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))
     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))
    832962                        return;
    833963               
     
    839969/** Starts the module.
    840970 *
    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  *
     971 * @returns             EOK on success.
     972 * @returns             Other error codes as defined for each specific module
     973 *                      start function.
    847974 */
    848975int main(int argc, char *argv[])
    849976{
    850         ERROR_DECLARE;
     977        int rc;
    851978       
    852979        /* Start the module */
    853         if (ERROR_OCCURRED(tl_module_start_standalone(tl_client_connection)))
    854                 return ERROR_CODE;
    855        
    856         return EOK;
     980        rc = tl_module_start_standalone(tl_client_connection);
     981        return rc;
    857982}
    858983
    859984/** @}
    860985 */
     986
Note: See TracChangeset for help on using the changeset viewer.