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


Ignore:
Timestamp:
2010-11-22T15:39:53Z (13 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
0eddb76, aae339e9
Parents:
9a1d8ab (diff), 8cd1aa5e (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 development/ changes

File:
1 edited

Legend:

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

    r9a1d8ab r0b749a3  
    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>
     
    4447#include <ipc/ipc.h>
    4548#include <ipc/services.h>
     49#include <ipc/net.h>
     50#include <ipc/tl.h>
     51#include <ipc/icmp.h>
    4652#include <sys/time.h>
    4753#include <sys/types.h>
    48 
    49 #include <net_err.h>
    50 #include <net_messages.h>
    51 #include <net_modules.h>
    52 #include <packet/packet_client.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>
    5366#include <packet_remote.h>
    54 #include <net_byteorder.h>
    5567#include <net_checksum.h>
    56 #include <icmp_api.h>
    5768#include <icmp_client.h>
    58 #include <icmp_codes.h>
    59 #include <icmp_common.h>
    6069#include <icmp_interface.h>
    6170#include <il_interface.h>
    62 #include <inet.h>
    6371#include <ip_client.h>
    6472#include <ip_interface.h>
    65 #include <ip_protocols.h>
    6673#include <net_interface.h>
    67 #include <socket_codes.h>
    68 #include <socket_errno.h>
    69 #include <tl_messages.h>
    7074#include <tl_interface.h>
    7175#include <tl_local.h>
    72 #include <icmp_messages.h>
    7376#include <icmp_header.h>
    7477
    75 #include "icmp.h"
    76 #include "icmp_module.h"
    77 
    78 /** ICMP module name.
    79  */
     78/** ICMP module name. */
    8079#define NAME    "ICMP protocol"
    8180
    82 /** Default ICMP error reporting.
    83  */
     81/** Default ICMP error reporting. */
    8482#define NET_DEFAULT_ICMP_ERROR_REPORTING        true
    8583
    86 /** Default ICMP echo replying.
    87  */
     84/** Default ICMP echo replying. */
    8885#define NET_DEFAULT_ICMP_ECHO_REPLYING          true
    8986
    90 /** Original datagram length in bytes transfered to the error notification message.
     87/** Original datagram length in bytes transfered to the error notification
     88 * message.
    9189 */
    9290#define ICMP_KEEP_LENGTH        8
    9391
    94 /** Free identifier numbers pool start.
    95  */
     92/** Free identifier numbers pool start. */
    9693#define ICMP_FREE_IDS_START     1
    9794
    98 /** Free identifier numbers pool end.
    99  */
     95/** Free identifier numbers pool end. */
    10096#define ICMP_FREE_IDS_END       UINT16_MAX
    10197
    10298/** Computes the ICMP datagram checksum.
    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."
     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."
    112109
    113110/** Computes an ICMP reply data key.
    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  */
    130 int 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  */
    145 int 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  */
    156 int 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  */
    169 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 * @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. */
     121icmp_globals_t  icmp_globals;
     122
     123INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t);
     124INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t);
    170125
    171126/** 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  */
    176 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 * @return              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 * @return              EOK on success.
     155 * @return              EPERM if the error message is not allowed.
     156 */
     157static 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)
     165                return icmp_release_and_return(packet, EPERM);
     166
     167        header->type = type;
     168        header->code = code;
     169        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 */
     191static 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}
    177219
    178220/** 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  */
    197 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);
    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  */
    206 icmp_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  */
    223 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);
    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  */
    235 int 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  */
    244 int icmp_bind_free_id(icmp_echo_ref echo_data);
    245 
    246 /** ICMP global data.
    247  */
    248 icmp_globals_t  icmp_globals;
    249 
    250 INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t);
    251 
    252 INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t);
    253 
    254 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){
    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 
    275 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){
    276         ERROR_DECLARE;
    277 
    278         icmp_header_ref header;
    279         packet_t packet;
     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 */
     245static 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;
    280251        size_t length;
    281         uint8_t * data;
    282         icmp_reply_ref reply;
     252        uint8_t *data;
     253        icmp_reply_t *reply;
    283254        int reply_key;
    284         int result;
    285255        int index;
    286 
    287         if(addrlen <= 0){
     256        int rc;
     257
     258        if (addrlen <= 0)
    288259                return EINVAL;
    289         }
     260
    290261        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){
     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)
    295273                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
     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 */
    304281        data = (uint8_t *) packet_suffix(packet, size);
    305         if(! data){
     282        if (!data)
    306283                return icmp_release_and_return(packet, ENOMEM);
    307         }
    308         // fill the data
     284
     285        /* Fill the data */
    309286        length = 0;
    310         while(size > length + sizeof(ICMP_ECHO_TEXT)){
     287        while (size > length + sizeof(ICMP_ECHO_TEXT)) {
    311288                memcpy(data + length, ICMP_ECHO_TEXT, sizeof(ICMP_ECHO_TEXT));
    312289                length += sizeof(ICMP_ECHO_TEXT);
    313290        }
    314291        memcpy(data + length, ICMP_ECHO_TEXT, size - length);
    315         // prefix the header
     292
     293        /* Prefix the header */
    316294        header = PACKET_PREFIX(packet, icmp_header_t);
    317         if(! header){
     295        if (!header)
    318296                return icmp_release_and_return(packet, ENOMEM);
    319         }
     297
    320298        bzero(header, sizeof(*header));
    321299        header->un.echo.identifier = id;
    322300        header->un.echo.sequence_number = sequence;
    323301
    324         // prepare the reply structure
     302        /* Prepare the reply structure */
    325303        reply = malloc(sizeof(*reply));
    326         if(! reply){
     304        if (!reply)
    327305                return icmp_release_and_return(packet, ENOMEM);
    328         }
     306
    329307        fibril_mutex_initialize(&reply->mutex);
    330308        fibril_mutex_lock(&reply->mutex);
    331309        fibril_condvar_initialize(&reply->condvar);
    332         reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier, header->un.echo.sequence_number);
     310        reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier,
     311            header->un.echo.sequence_number);
    333312        index = icmp_replies_add(&icmp_globals.replies, reply_key, reply);
    334         if(index < 0){
     313        if (index < 0) {
    335314                free(reply);
    336315                return icmp_release_and_return(packet, index);
    337316        }
    338317
    339         // unlock the globals so that we can wait for the reply
     318        /* Unlock the globals so that we can wait for the reply */
    340319        fibril_rwlock_write_unlock(&icmp_globals.lock);
    341320
    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
     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 */
    355332        fibril_mutex_unlock(&reply->mutex);
    356333        fibril_rwlock_write_lock(&icmp_globals.lock);
    357334
    358         // destroy the reply structure
     335        /* Destroy the reply structure */
    359336        icmp_replies_exclude_index(&icmp_globals.replies, index);
    360         return result;
    361 }
    362 
    363 int icmp_destination_unreachable_msg(int icmp_phone, icmp_code_t code, icmp_param_t mtu, packet_t packet){
    364         icmp_header_ref header;
     337
     338        return rc;
     339}
     340
     341static 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;
    365345
    366346        header = icmp_prepare_packet(packet);
    367         if(! header){
     347        if (!header)
    368348                return icmp_release_and_return(packet, ENOMEM);
    369         }
    370         if(mtu){
     349
     350        if (mtu)
    371351                header->un.frag.mtu = mtu;
    372         }
    373         return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header, SERVICE_ICMP, 0, 0, 0);
    374 }
    375 
    376 int icmp_source_quench_msg(int icmp_phone, packet_t packet){
    377         icmp_header_ref header;
     352
     353        return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header,
     354            SERVICE_ICMP, 0, 0, 0);
     355}
     356
     357static int icmp_source_quench_msg_local(int icmp_phone, packet_t *packet)
     358{
     359        icmp_header_t *header;
    378360
    379361        header = icmp_prepare_packet(packet);
    380         if(! header){
     362        if (!header)
    381363                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 
    386 int icmp_time_exceeded_msg(int icmp_phone, icmp_code_t code, packet_t packet){
    387         icmp_header_ref header;
     364
     365        return icmp_send_packet(ICMP_SOURCE_QUENCH, 0, packet, header,
     366            SERVICE_ICMP, 0, 0, 0);
     367}
     368
     369static int icmp_time_exceeded_msg_local(int icmp_phone, icmp_code_t code,
     370    packet_t *packet)
     371{
     372        icmp_header_t *header;
    388373
    389374        header = icmp_prepare_packet(packet);
    390         if(! header){
     375        if (!header)
    391376                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 
    396 int icmp_parameter_problem_msg(int icmp_phone, icmp_code_t code, icmp_param_t pointer, packet_t packet){
    397         icmp_header_ref header;
     377
     378        return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header,
     379            SERVICE_ICMP, 0, 0, 0);
     380}
     381
     382static 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;
    398386
    399387        header = icmp_prepare_packet(packet);
    400         if(! header){
     388        if (!header)
    401389                return icmp_release_and_return(packet, ENOMEM);
    402         }
     390
    403391        header->un.param.pointer = pointer;
    404         return icmp_send_packet(ICMP_PARAMETERPROB, code, packet, header, SERVICE_ICMP, 0, 0, 0);
    405 }
    406 
    407 icmp_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 
    433 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){
    434         ERROR_DECLARE;
    435 
    436         // do not send an error if disabled
    437         if(error && (! icmp_globals.error_reporting)){
    438                 return icmp_release_and_return(packet, EPERM);
    439         }
    440         header->type = type;
    441         header->code = code;
    442         header->checksum = 0;
    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 
    450 int icmp_connect_module(services_t service, suseconds_t timeout){
    451         icmp_echo_ref echo_data;
    452         icmp_param_t id;
    453         int index;
    454 
    455         echo_data = (icmp_echo_ref) malloc(sizeof(*echo_data));
    456         if(! echo_data){
    457                 return ENOMEM;
    458         }
    459         // assign a new identifier
    460         fibril_rwlock_write_lock(&icmp_globals.lock);
    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 
    474 int 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;
     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 */
     403int 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;
    479416        size_t count = sizeof(names) / sizeof(measured_string_t);
    480         char * data;
     417        char *data;
     418        int rc;
    481419
    482420        fibril_rwlock_initialize(&icmp_globals.lock);
     
    484422        icmp_replies_initialize(&icmp_globals.replies);
    485423        icmp_echo_data_initialize(&icmp_globals.echo_data);
    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){
     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);
    488429                return icmp_globals.ip_phone;
    489430        }
    490         ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1, &icmp_globals.packet_dimension));
     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
    491439        icmp_globals.packet_dimension.prefix += ICMP_HEADER_SIZE;
    492440        icmp_globals.packet_dimension.content -= ICMP_HEADER_SIZE;
    493         // get configuration
     441
    494442        icmp_globals.error_reporting = NET_DEFAULT_ICMP_ERROR_REPORTING;
    495443        icmp_globals.echo_replying = NET_DEFAULT_ICMP_ECHO_REPLYING;
     444
     445        /* Get configuration */
    496446        configuration = &names[0];
    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');
     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');
    501458                }
    502                 if(configuration[1].value){
    503                         icmp_globals.echo_replying = (configuration[1].value[0] == 'y');
     459                if (configuration[1].value) {
     460                        icmp_globals.echo_replying =
     461                            (configuration[1].value[0] == 'y');
    504462                }
    505463                net_free_settings(configuration, data);
    506464        }
     465
    507466        fibril_rwlock_write_unlock(&icmp_globals.lock);
    508467        return EOK;
    509468}
    510469
    511 int 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 
    521 int icmp_process_packet(packet_t packet, services_t error){
    522         ERROR_DECLARE;
    523 
     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 */
     481static 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 */
     520static int icmp_process_packet(packet_t *packet, services_t error)
     521{
    524522        size_t length;
    525         uint8_t * src;
     523        uint8_t *src;
    526524        int addrlen;
    527525        int result;
    528         void * data;
    529         icmp_header_ref header;
     526        void *data;
     527        icmp_header_t *header;
    530528        icmp_type_t type;
    531529        icmp_code_t code;
    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
     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 */
    550552        length = ip_client_header_length(packet);
    551         ERROR_PROPAGATE(packet_trim(packet, length, 0));
     553        rc = packet_trim(packet, length, 0);
     554        if (rc != EOK)
     555                return rc;
    552556
    553557        length = packet_get_data_length(packet);
    554         if(length <= 0){
     558        if (length <= 0)
    555559                return EINVAL;
    556         }
    557         if(length < ICMP_HEADER_SIZE){
     560
     561        if (length < ICMP_HEADER_SIZE)
    558562                return EINVAL;
    559         }
     563
    560564        data = packet_get_data(packet);
    561         if(! data){
     565        if (!data)
    562566                return EINVAL;
    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;
     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;
    576582                                }
    577583                        }
     
    579585                }
    580586        }
    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        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);
     600                        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;
    587618                        }
    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;
     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 */
     660static 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 */
     690static 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 */
     737static 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;
    602758                                }
    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);
    619                         return EOK;
    620                 default:
    621                         return ENOTSUP;
    622         }
    623 }
    624 
    625 int 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 
    646 int 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));
    656                         }
    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 
    666 int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call){
    667         ERROR_DECLARE;
    668 
     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 */
     785static int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
     786{
    669787        bool keep_on_going = true;
    670 //      fibril_rwlock_t                 lock;
    671788        ipc_call_t answer;
    672789        int answer_count;
    673790        size_t length;
    674         struct sockaddr * addr;
     791        struct sockaddr *addr;
    675792        ipc_callid_t data_callid;
    676         icmp_echo_ref echo_data;
    677         int res;
     793        icmp_echo_t *echo_data;
     794        int rc = EOK;
    678795
    679796        /*
     
    681798         *  - Answer the first NET_ICMP_INIT call.
    682799         */
    683         res = EOK;
    684800        answer_count = 0;
    685801
    686 //      fibril_rwlock_initialize(&lock);
    687 
    688         echo_data = (icmp_echo_ref) malloc(sizeof(*echo_data));
    689         if(! echo_data){
     802        echo_data = (icmp_echo_t *) malloc(sizeof(*echo_data));
     803        if (!echo_data)
    690804                return ENOMEM;
    691         }
    692 
    693         // assign a new identifier
     805
     806        /* Assign a new identifier */
    694807        fibril_rwlock_write_lock(&icmp_globals.lock);
    695         res = icmp_bind_free_id(echo_data);
     808        rc = icmp_bind_free_id(echo_data);
    696809        fibril_rwlock_write_unlock(&icmp_globals.lock);
    697         if(res < 0){
     810        if (rc < 0) {
    698811                free(echo_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
     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 */
    708820                refresh_answer(&answer, &answer_count);
    709821
    710                 // get the next call
     822                /* Get the next call */
    711823                callid = async_get_call(&call);
    712824
    713                 // process the call
    714                 switch(IPC_GET_METHOD(call)){
    715                         case IPC_M_PHONE_HUNGUP:
    716                                 keep_on_going = false;
    717                                 res = EHANGUP;
     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;
    718835                                break;
    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);
     836                        }
     837                       
     838                        addr = malloc(length);
     839                        if (!addr) {
     840                                rc = ENOMEM;
    744841                                break;
    745                         default:
    746                                 res = icmp_process_message(&call);
     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);
    747870                }
    748         }
    749 
    750         // release the identifier
     871
     872        }
     873
     874        /* Release the identifier */
    751875        fibril_rwlock_write_lock(&icmp_globals.lock);
    752876        icmp_echo_data_exclude(&icmp_globals.echo_data, echo_data->identifier);
    753877        fibril_rwlock_write_unlock(&icmp_globals.lock);
    754         return res;
    755 }
    756 
    757 int 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 
    788 int 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 
    793 int 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 }
     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 */
     895int 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
    823921
    824922/** Default thread for new connections.
    825923 *
    826  *  @param[in] iid The initial message identifier.
    827  *  @param[in] icall The initial message call structure.
    828  *
    829  */
    830 static void tl_client_connection(ipc_callid_t iid, ipc_call_t * icall)
     924 * @param[in] iid The initial message identifier.
     925 * @param[in] icall The initial message call structure.
     926 *
     927 */
     928static void tl_client_connection(ipc_callid_t iid, ipc_call_t *icall)
    831929{
    832930        /*
     
    836934        ipc_answer_0(iid, EOK);
    837935       
    838         while(true) {
     936        while (true) {
    839937                ipc_call_t answer;
    840938                int answer_count;
     
    851949                    &answer_count);
    852950               
    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))
     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))
    855957                        return;
    856958               
     
    862964/** Starts the module.
    863965 *
    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  *
     966 * @return              EOK on success.
     967 * @return              Other error codes as defined for each specific module
     968 *                      start function.
    870969 */
    871970int main(int argc, char *argv[])
    872971{
    873         ERROR_DECLARE;
     972        int rc;
    874973       
    875974        /* Start the module */
    876         if (ERROR_OCCURRED(tl_module_start_standalone(tl_client_connection)))
    877                 return ERROR_CODE;
    878        
    879         return EOK;
     975        rc = tl_module_start_standalone(tl_client_connection);
     976        return rc;
    880977}
    881978
    882979/** @}
    883980 */
     981
Note: See TracChangeset for help on using the changeset viewer.