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


Ignore:
Timestamp:
2011-05-12T16:49:44Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f36787d7
Parents:
e80329d6 (diff), 750636a (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

    re80329d6 rb5e68c8  
    2828
    2929/** @addtogroup icmp
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  ICMP module implementation.
    35  *  @see icmp.h
     34 * ICMP module implementation.
    3635 */
    3736
     
    4241#include <stdint.h>
    4342#include <str.h>
    44 #include <ipc/ipc.h>
    4543#include <ipc/services.h>
    4644#include <ipc/net.h>
     
    5149#include <byteorder.h>
    5250#include <errno.h>
    53 #include <err.h>
     51#include <adt/hash_table.h>
    5452
    5553#include <net/socket_codes.h>
    5654#include <net/ip_protocols.h>
    5755#include <net/inet.h>
    58 
    5956#include <net/modules.h>
     57#include <net/icmp_api.h>
     58#include <net/icmp_codes.h>
     59#include <net/icmp_common.h>
     60
    6061#include <packet_client.h>
    6162#include <packet_remote.h>
    6263#include <net_checksum.h>
    63 #include <net/icmp_api.h>
    6464#include <icmp_client.h>
    65 #include <net/icmp_codes.h>
    66 #include <net/icmp_common.h>
    67 #include <icmp_interface.h>
    68 #include <il_interface.h>
     65#include <icmp_remote.h>
     66#include <il_remote.h>
    6967#include <ip_client.h>
    7068#include <ip_interface.h>
    7169#include <net_interface.h>
    72 #include <tl_interface.h>
    73 #include <tl_local.h>
     70#include <tl_remote.h>
     71#include <tl_skel.h>
    7472#include <icmp_header.h>
    7573
    76 #include "icmp.h"
    77 #include "icmp_module.h"
    78 
    79 /** ICMP module name.
    80  */
    81 #define NAME    "ICMP protocol"
    82 
    83 /** Default ICMP error reporting.
    84  */
    85 #define NET_DEFAULT_ICMP_ERROR_REPORTING        true
    86 
    87 /** Default ICMP echo replying.
    88  */
    89 #define NET_DEFAULT_ICMP_ECHO_REPLYING          true
    90 
    91 /** Original datagram length in bytes transfered to the error notification message.
    92  */
    93 #define ICMP_KEEP_LENGTH        8
    94 
    95 /** Free identifier numbers pool start.
    96  */
    97 #define ICMP_FREE_IDS_START     1
    98 
    99 /** Free identifier numbers pool end.
    100  */
    101 #define ICMP_FREE_IDS_END       UINT16_MAX
    102 
    103 /** 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."
    113 
    114 /** 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);
    171 
    172 /** Releases the packet and returns the result.
    173  *  @param[in] packet The packet queue to be released.
    174  *  @param[in] result The result to be returned.
    175  *  @returns The result parameter.
    176  */
    177 int icmp_release_and_return(packet_t packet, int result);
    178 
    179 /** Requests an echo message.
    180  *  Sends a packet with specified parameters to the target host and waits for the reply upto the given timeout.
    181  *  Blocks the caller until the reply or the timeout occurs.
    182  *  @param[in] id The message identifier.
    183  *  @param[in] sequence The message sequence parameter.
    184  *  @param[in] size The message data length in bytes.
    185  *  @param[in] timeout The timeout in miliseconds.
    186  *  @param[in] ttl The time to live.
    187  *  @param[in] tos The type of service.
    188  *  @param[in] dont_fragment The value indicating whether the datagram must not be fragmented. Is used as a MTU discovery.
    189  *  @param[in] addr The target host address.
    190  *  @param[in] addrlen The torget host address length.
    191  *  @returns ICMP_ECHO on success.
    192  *  @returns ETIMEOUT if the reply has not arrived before the timeout.
    193  *  @returns ICMP type of the received error notification.
    194  *  @returns EINVAL if the addrlen parameter is less or equal to zero (<=0).
    195  *  @returns ENOMEM if there is not enough memory left.
    196  *  @returns EPARTY if there was an internal error.
    197  */
    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 
    279         icmp_header_ref header;
    280         packet_t packet;
    281         size_t length;
    282         uint8_t * data;
    283         icmp_reply_ref reply;
    284         int reply_key;
     74/** ICMP module name */
     75#define NAME  "icmp"
     76
     77/** Number of replies hash table keys */
     78#define REPLY_KEYS  2
     79
     80/** Number of replies hash table buckets */
     81#define REPLY_BUCKETS  1024
     82
     83/**
     84 * Original datagram length in bytes transfered to the error
     85 * notification message.
     86 */
     87#define ICMP_KEEP_LENGTH  8
     88
     89/** Compute the ICMP datagram checksum.
     90 *
     91 * @param[in,out] header ICMP datagram header.
     92 * @param[in]     length Total datagram length.
     93 *
     94 * @return Computed checksum.
     95 *
     96 */
     97#define ICMP_CHECKSUM(header, length) \
     98        htons(ip_checksum((uint8_t *) (header), (length)))
     99
     100/** An echo request datagrams pattern. */
     101#define ICMP_ECHO_TEXT  "ICMP hello from HelenOS."
     102
     103/** ICMP reply data. */
     104typedef struct {
     105        /** Hash table link */
     106        link_t link;
     107       
     108        /** Reply identification and sequence */
     109        icmp_param_t id;
     110        icmp_param_t sequence;
     111       
     112        /** Reply signaling */
     113        fibril_condvar_t condvar;
     114       
     115        /** Reply result */
    285116        int result;
    286         int index;
    287 
    288         if(addrlen <= 0){
     117} icmp_reply_t;
     118
     119/** Global data */
     120static int phone_net = -1;
     121static int phone_ip = -1;
     122static bool error_reporting = true;
     123static bool echo_replying = true;
     124static packet_dimension_t icmp_dimension;
     125
     126/** ICMP client identification counter */
     127static atomic_t icmp_client;
     128
     129/** ICMP identifier and sequence number (client-specific) */
     130static fibril_local icmp_param_t icmp_id;
     131static fibril_local icmp_param_t icmp_seq;
     132
     133/** Reply hash table */
     134static fibril_mutex_t reply_lock;
     135static hash_table_t replies;
     136
     137static hash_index_t replies_hash(unsigned long key[])
     138{
     139        /*
     140         * ICMP identifier and sequence numbers
     141         * are 16-bit values.
     142         */
     143        hash_index_t index = ((key[0] & 0xffff) << 16) | (key[1] & 0xffff);
     144        return (index % REPLY_BUCKETS);
     145}
     146
     147static int replies_compare(unsigned long key[], hash_count_t keys, link_t *item)
     148{
     149        icmp_reply_t *reply =
     150            hash_table_get_instance(item, icmp_reply_t, link);
     151       
     152        if (keys == 1)
     153                return (reply->id == key[0]);
     154        else
     155                return ((reply->id == key[0]) && (reply->sequence == key[1]));
     156}
     157
     158static void replies_remove_callback(link_t *item)
     159{
     160}
     161
     162static hash_table_operations_t reply_ops = {
     163        .hash = replies_hash,
     164        .compare = replies_compare,
     165        .remove_callback = replies_remove_callback
     166};
     167
     168/** Release the packet and return the result.
     169 *
     170 * @param[in] packet Packet queue to be released.
     171 *
     172 */
     173static void icmp_release(packet_t *packet)
     174{
     175        pq_release_remote(phone_net, packet_get_id(packet));
     176}
     177
     178/** Send the ICMP message.
     179 *
     180 * Set the message type and code and compute the checksum.
     181 * Error messages are sent only if allowed in the configuration.
     182 * Release the packet on errors.
     183 *
     184 * @param[in] type          Message type.
     185 * @param[in] code          Message code.
     186 * @param[in] packet        Message packet to be sent.
     187 * @param[in] header        ICMP header.
     188 * @param[in] error         Error service to be announced. Should be
     189 *                          SERVICE_ICMP or zero.
     190 * @param[in] ttl           Time to live.
     191 * @param[in] tos           Type of service.
     192 * @param[in] dont_fragment Disable fragmentation.
     193 *
     194 * @return EOK on success.
     195 * @return EPERM if the error message is not allowed.
     196 *
     197 */
     198static int icmp_send_packet(icmp_type_t type, icmp_code_t code,
     199    packet_t *packet, icmp_header_t *header, services_t error, ip_ttl_t ttl,
     200    ip_tos_t tos, bool dont_fragment)
     201{
     202        /* Do not send an error if disabled */
     203        if ((error) && (!error_reporting)) {
     204                icmp_release(packet);
     205                return EPERM;
     206        }
     207       
     208        header->type = type;
     209        header->code = code;
     210       
     211        /*
     212         * The checksum needs to be calculated
     213         * with a virtual checksum field set to
     214         * zero.
     215         */
     216        header->checksum = 0;
     217        header->checksum = ICMP_CHECKSUM(header,
     218            packet_get_data_length(packet));
     219       
     220        int rc = ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl, tos,
     221            dont_fragment, 0);
     222        if (rc != EOK) {
     223                icmp_release(packet);
     224                return rc;
     225        }
     226       
     227        return ip_send_msg(phone_ip, -1, packet, SERVICE_ICMP, error);
     228}
     229
     230/** Prepare the ICMP error packet.
     231 *
     232 * Truncate the original packet if longer than ICMP_KEEP_LENGTH bytes.
     233 * Prefix and return the ICMP header.
     234 *
     235 * @param[in,out] packet Original packet.
     236 *
     237 * @return The prefixed ICMP header.
     238 * @return NULL on errors.
     239 *
     240 */
     241static icmp_header_t *icmp_prepare_packet(packet_t *packet)
     242{
     243        size_t total_length = packet_get_data_length(packet);
     244        if (total_length <= 0)
     245                return NULL;
     246       
     247        size_t header_length = ip_client_header_length(packet);
     248        if (header_length <= 0)
     249                return NULL;
     250       
     251        /* Truncate if longer than 64 bits (without the IP header) */
     252        if ((total_length > header_length + ICMP_KEEP_LENGTH) &&
     253            (packet_trim(packet, 0,
     254            total_length - header_length - ICMP_KEEP_LENGTH) != EOK))
     255                return NULL;
     256       
     257        icmp_header_t *header = PACKET_PREFIX(packet, icmp_header_t);
     258        if (!header)
     259                return NULL;
     260       
     261        bzero(header, sizeof(*header));
     262        return header;
     263}
     264
     265/** Request an echo message.
     266 *
     267 * Send a packet with specified parameters to the target host
     268 * and wait for the reply upto the given timeout.
     269 * Block the caller until the reply or the timeout occurs.
     270 *
     271 * @param[in] id            Message identifier.
     272 * @param[in] sequence      Message sequence parameter.
     273 * @param[in] size          Message data length in bytes.
     274 * @param[in] timeout       Timeout in miliseconds.
     275 * @param[in] ttl           Time to live.
     276 * @param[in] tos           Type of service.
     277 * @param[in] dont_fragment Disable fragmentation.
     278 * @param[in] addr          Target host address.
     279 * @param[in] addrlen       Torget host address length.
     280 *
     281 * @return ICMP_ECHO on success.
     282 * @return ETIMEOUT if the reply has not arrived before the
     283 *         timeout.
     284 * @return ICMP type of the received error notification.
     285 * @return EINVAL if the addrlen parameter is less or equal to
     286 *         zero.
     287 * @return ENOMEM if there is not enough memory left.
     288 *
     289 */
     290static int icmp_echo(icmp_param_t id, icmp_param_t sequence, size_t size,
     291    mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, bool dont_fragment,
     292    const struct sockaddr *addr, socklen_t addrlen)
     293{
     294        if (addrlen <= 0)
    289295                return EINVAL;
    290         }
    291         length = (size_t) addrlen;
    292         // TODO do not ask all the time
    293         ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1, &icmp_globals.packet_dimension));
    294         packet = packet_get_4_remote(icmp_globals.net_phone, size, icmp_globals.packet_dimension.addr_len, ICMP_HEADER_SIZE + icmp_globals.packet_dimension.prefix, icmp_globals.packet_dimension.suffix);
    295         if(! packet){
     296       
     297        size_t length = (size_t) addrlen;
     298       
     299        packet_t *packet = packet_get_4_remote(phone_net, size,
     300            icmp_dimension.addr_len, ICMP_HEADER_SIZE + icmp_dimension.prefix,
     301            icmp_dimension.suffix);
     302        if (!packet)
    296303                return ENOMEM;
    297         }
    298 
    299         // prepare the requesting packet
    300         // set the destination address
    301         if(ERROR_OCCURRED(packet_set_addr(packet, NULL, (const uint8_t *) addr, length))){
    302                 return icmp_release_and_return(packet, ERROR_CODE);
    303         }
    304         // allocate space in the packet
    305         data = (uint8_t *) packet_suffix(packet, size);
    306         if(! data){
    307                 return icmp_release_and_return(packet, ENOMEM);
    308         }
    309         // fill the data
     304       
     305        /* Prepare the requesting packet, set the destination address. */
     306        int rc = packet_set_addr(packet, NULL, (const uint8_t *) addr, length);
     307        if (rc != EOK) {
     308                icmp_release(packet);
     309                return rc;
     310        }
     311       
     312        /* Allocate space in the packet */
     313        uint8_t *data = (uint8_t *) packet_suffix(packet, size);
     314        if (!data) {
     315                icmp_release(packet);
     316                return ENOMEM;
     317        }
     318       
     319        /* Fill the data */
    310320        length = 0;
    311         while(size > length + sizeof(ICMP_ECHO_TEXT)){
     321        while (size > length + sizeof(ICMP_ECHO_TEXT)) {
    312322                memcpy(data + length, ICMP_ECHO_TEXT, sizeof(ICMP_ECHO_TEXT));
    313323                length += sizeof(ICMP_ECHO_TEXT);
    314324        }
    315325        memcpy(data + length, ICMP_ECHO_TEXT, size - length);
    316         // prefix the header
    317         header = PACKET_PREFIX(packet, icmp_header_t);
    318         if(! header){
    319                 return icmp_release_and_return(packet, ENOMEM);
    320         }
    321         bzero(header, sizeof(*header));
     326       
     327        /* Prefix the header */
     328        icmp_header_t *header = PACKET_PREFIX(packet, icmp_header_t);
     329        if (!header) {
     330                icmp_release(packet);
     331                return ENOMEM;
     332        }
     333       
     334        bzero(header, sizeof(icmp_header_t));
    322335        header->un.echo.identifier = id;
    323336        header->un.echo.sequence_number = sequence;
    324 
    325         // prepare the reply structure
    326         reply = malloc(sizeof(*reply));
    327         if(! reply){
    328                 return icmp_release_and_return(packet, ENOMEM);
    329         }
    330         fibril_mutex_initialize(&reply->mutex);
    331         fibril_mutex_lock(&reply->mutex);
     337       
     338        /* Prepare the reply structure */
     339        icmp_reply_t *reply = malloc(sizeof(icmp_reply_t));
     340        if (!reply) {
     341                icmp_release(packet);
     342                return ENOMEM;
     343        }
     344       
     345        reply->id = id;
     346        reply->sequence = sequence;
    332347        fibril_condvar_initialize(&reply->condvar);
    333         reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier, header->un.echo.sequence_number);
    334         index = icmp_replies_add(&icmp_globals.replies, reply_key, reply);
    335         if(index < 0){
    336                 free(reply);
    337                 return icmp_release_and_return(packet, index);
    338         }
    339 
    340         // unlock the globals so that we can wait for the reply
    341         fibril_rwlock_write_unlock(&icmp_globals.lock);
    342 
    343         // send the request
    344         icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos, dont_fragment);
    345 
    346         // wait for the reply
    347         // timeout in microseconds
    348         if(ERROR_OCCURRED(fibril_condvar_wait_timeout(&reply->condvar, &reply->mutex, timeout * 1000))){
    349                 result = ERROR_CODE;
    350         }else{
    351                 // read the result
    352                 result = reply->result;
    353         }
    354 
    355         // drop the reply mutex before locking the globals again
    356         fibril_mutex_unlock(&reply->mutex);
    357         fibril_rwlock_write_lock(&icmp_globals.lock);
    358 
    359         // destroy the reply structure
    360         icmp_replies_exclude_index(&icmp_globals.replies, index);
    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){
    365         icmp_header_ref header;
    366 
    367         header = icmp_prepare_packet(packet);
    368         if(! header){
    369                 return icmp_release_and_return(packet, ENOMEM);
    370         }
    371         if(mtu){
     348       
     349        /* Add the reply to the replies hash table */
     350        fibril_mutex_lock(&reply_lock);
     351       
     352        unsigned long key[REPLY_KEYS] = {id, sequence};
     353        hash_table_insert(&replies, key, &reply->link);
     354       
     355        /* Send the request */
     356        icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos,
     357            dont_fragment);
     358       
     359        /* Wait for the reply. Timeout in microseconds. */
     360        rc = fibril_condvar_wait_timeout(&reply->condvar, &reply_lock,
     361            timeout * 1000);
     362        if (rc == EOK)
     363                rc = reply->result;
     364       
     365        /* Remove the reply from the replies hash table */
     366        hash_table_remove(&replies, key, REPLY_KEYS);
     367       
     368        fibril_mutex_unlock(&reply_lock);
     369       
     370        free(reply);
     371       
     372        return rc;
     373}
     374
     375static int icmp_destination_unreachable(icmp_code_t code, icmp_param_t mtu,
     376    packet_t *packet)
     377{
     378        icmp_header_t *header = icmp_prepare_packet(packet);
     379        if (!header) {
     380                icmp_release(packet);
     381                return ENOMEM;
     382        }
     383       
     384        if (mtu)
    372385                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){
    378         icmp_header_ref header;
    379 
    380         header = icmp_prepare_packet(packet);
    381         if(! header){
    382                 return icmp_release_and_return(packet, ENOMEM);
    383         }
    384         return icmp_send_packet(ICMP_SOURCE_QUENCH, 0, packet, header, SERVICE_ICMP, 0, 0, 0);
    385 }
    386 
    387 int icmp_time_exceeded_msg(int icmp_phone, icmp_code_t code, packet_t packet){
    388         icmp_header_ref header;
    389 
    390         header = icmp_prepare_packet(packet);
    391         if(! header){
    392                 return icmp_release_and_return(packet, ENOMEM);
    393         }
    394         return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header, SERVICE_ICMP, 0, 0, 0);
    395 }
    396 
    397 int icmp_parameter_problem_msg(int icmp_phone, icmp_code_t code, icmp_param_t pointer, packet_t packet){
    398         icmp_header_ref header;
    399 
    400         header = icmp_prepare_packet(packet);
    401         if(! header){
    402                 return icmp_release_and_return(packet, ENOMEM);
    403         }
     386       
     387        return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header,
     388            SERVICE_ICMP, 0, 0, false);
     389}
     390
     391static int icmp_source_quench(packet_t *packet)
     392{
     393        icmp_header_t *header = icmp_prepare_packet(packet);
     394        if (!header) {
     395                icmp_release(packet);
     396                return ENOMEM;
     397        }
     398       
     399        return icmp_send_packet(ICMP_SOURCE_QUENCH, 0, packet, header,
     400            SERVICE_ICMP, 0, 0, false);
     401}
     402
     403static int icmp_time_exceeded(icmp_code_t code, packet_t *packet)
     404{
     405        icmp_header_t *header = icmp_prepare_packet(packet);
     406        if (!header) {
     407                icmp_release(packet);
     408                return ENOMEM;
     409        }
     410       
     411        return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header,
     412            SERVICE_ICMP, 0, 0, false);
     413}
     414
     415static int icmp_parameter_problem(icmp_code_t code, icmp_param_t pointer,
     416    packet_t *packet)
     417{
     418        icmp_header_t *header = icmp_prepare_packet(packet);
     419        if (!header) {
     420                icmp_release(packet);
     421                return ENOMEM;
     422        }
     423       
    404424        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}};
    455         measured_string_ref configuration;
    456         size_t count = sizeof(names) / sizeof(measured_string_t);
    457         char * data;
    458 
    459         fibril_rwlock_initialize(&icmp_globals.lock);
    460         fibril_rwlock_write_lock(&icmp_globals.lock);
    461         icmp_replies_initialize(&icmp_globals.replies);
    462         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){
    465                 return icmp_globals.ip_phone;
    466         }
    467         ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1, &icmp_globals.packet_dimension));
    468         icmp_globals.packet_dimension.prefix += ICMP_HEADER_SIZE;
    469         icmp_globals.packet_dimension.content -= ICMP_HEADER_SIZE;
    470         // get configuration
    471         icmp_globals.error_reporting = NET_DEFAULT_ICMP_ERROR_REPORTING;
    472         icmp_globals.echo_replying = NET_DEFAULT_ICMP_ECHO_REPLYING;
    473         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');
    478                 }
    479                 if(configuration[1].value){
    480                         icmp_globals.echo_replying = (configuration[1].value[0] == 'y');
    481                 }
    482                 net_free_settings(configuration, data);
    483         }
    484         fibril_rwlock_write_unlock(&icmp_globals.lock);
    485         return EOK;
    486 }
    487 
    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 
    501         size_t length;
    502         uint8_t * src;
    503         int addrlen;
    504         int result;
    505         void * data;
    506         icmp_header_ref header;
     425        return icmp_send_packet(ICMP_PARAMETERPROB, code, packet, header,
     426            SERVICE_ICMP, 0, 0, false);
     427}
     428
     429/** Try to set the pending reply result as the received message type.
     430 *
     431 * If the reply data is not present, the reply timed out and the other fibril
     432 * is already awake. The packet is released.
     433 *
     434 * @param[in] packet The received reply message.
     435 * @param[in] header The ICMP message header.
     436 * @param[in] type   The received reply message type.
     437 * @param[in] code   The received reply message code.
     438 *
     439 */
     440static void icmp_process_echo_reply(packet_t *packet, icmp_header_t *header,
     441    icmp_type_t type, icmp_code_t code)
     442{
     443        unsigned long key[REPLY_KEYS] =
     444            {header->un.echo.identifier, header->un.echo.sequence_number};
     445       
     446        /* The packet is no longer needed */
     447        icmp_release(packet);
     448       
     449        /* Find the pending reply */
     450        fibril_mutex_lock(&reply_lock);
     451       
     452        link_t *link = hash_table_find(&replies, key);
     453        if (link != NULL) {
     454                icmp_reply_t *reply =
     455                   hash_table_get_instance(link, icmp_reply_t, link);
     456               
     457                reply->result = type;
     458                fibril_condvar_signal(&reply->condvar);
     459        }
     460       
     461        fibril_mutex_unlock(&reply_lock);
     462}
     463
     464/** Process the received ICMP packet.
     465 *
     466 * Notify the destination socket application.
     467 *
     468 * @param[in,out] packet Received packet.
     469 * @param[in]     error  Packet error reporting service to prefix
     470 *                       the received packet.
     471 *
     472 * @return EOK on success.
     473 * @return EINVAL if the packet is not valid.
     474 * @return EINVAL if the stored packet address is not the an_addr_t.
     475 * @return EINVAL if the packet does not contain any data.
     476 * @return NO_DATA if the packet content is shorter than the user
     477 *         datagram header.
     478 * @return ENOMEM if there is not enough memory left.
     479 * @return EADDRNOTAVAIL if the destination socket does not exist.
     480 * @return Other error codes as defined for the
     481 *         ip_client_process_packet() function.
     482 *
     483 */
     484static int icmp_process_packet(packet_t *packet, services_t error)
     485{
    507486        icmp_type_t type;
    508487        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         }
    526         // get rid of the ip header
    527         length = ip_client_header_length(packet);
    528         ERROR_PROPAGATE(packet_trim(packet, length, 0));
    529 
     488        int rc;
     489       
     490        switch (error) {
     491        case SERVICE_NONE:
     492                break;
     493        case SERVICE_ICMP:
     494                /* Process error */
     495                rc = icmp_client_process_packet(packet, &type, &code, NULL, NULL);
     496                if (rc < 0)
     497                        return rc;
     498               
     499                /* Remove the error header */
     500                rc = packet_trim(packet, (size_t) rc, 0);
     501                if (rc != EOK)
     502                        return rc;
     503               
     504                break;
     505        default:
     506                return ENOTSUP;
     507        }
     508       
     509        /* Get rid of the IP header */
     510        size_t length = ip_client_header_length(packet);
     511        rc = packet_trim(packet, length, 0);
     512        if (rc != EOK)
     513                return rc;
     514       
    530515        length = packet_get_data_length(packet);
    531         if(length <= 0){
     516        if (length <= 0)
    532517                return EINVAL;
    533         }
    534         if(length < ICMP_HEADER_SIZE){
     518       
     519        if (length < ICMP_HEADER_SIZE)
    535520                return EINVAL;
    536         }
    537         data = packet_get_data(packet);
    538         if(! data){
     521       
     522        void *data = packet_get_data(packet);
     523        if (!data)
    539524                return EINVAL;
    540         }
    541         // get icmp header
    542         header = (icmp_header_ref) data;
    543         // checksum
    544         if(header->checksum){
    545                 while(ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO){
    546                         // set the original message type on error notification
    547                         // type swap observed in Qemu
    548                         if(error){
    549                                 switch(header->type){
    550                                         case ICMP_ECHOREPLY:
    551                                                 header->type = ICMP_ECHO;
    552                                                 continue;
     525       
     526        /* Get ICMP header */
     527        icmp_header_t *header = (icmp_header_t *) data;
     528       
     529        if (header->checksum) {
     530                while (ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO) {
     531                        /*
     532                         * Set the original message type on error notification.
     533                         * Type swap observed in Qemu.
     534                         */
     535                        if (error) {
     536                                switch (header->type) {
     537                                case ICMP_ECHOREPLY:
     538                                        header->type = ICMP_ECHO;
     539                                        continue;
    553540                                }
    554541                        }
     542                       
    555543                        return EINVAL;
    556544                }
    557545        }
    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);
     546       
     547        switch (header->type) {
     548        case ICMP_ECHOREPLY:
     549                if (error)
     550                        icmp_process_echo_reply(packet, header, type, code);
     551                else
     552                        icmp_process_echo_reply(packet, header, ICMP_ECHO, 0);
     553               
     554                return EOK;
     555       
     556        case ICMP_ECHO:
     557                if (error) {
     558                        icmp_process_echo_reply(packet, header, type, code);
     559                        return EOK;
     560                }
     561               
     562                /* Do not send a reply if disabled */
     563                if (echo_replying) {
     564                        uint8_t *src;
     565                        int addrlen = packet_get_addr(packet, &src, NULL);
     566                       
     567                        /*
     568                         * Set both addresses to the source one (avoid the
     569                         * source address deletion before setting the
     570                         * destination one).
     571                         */
     572                        if ((addrlen > 0) && (packet_set_addr(packet, src, src,
     573                            (size_t) addrlen) == EOK)) {
     574                                /* Send the reply */
     575                                icmp_send_packet(ICMP_ECHOREPLY, 0, packet,
     576                                    header, 0, 0, 0, 0);
     577                                return EOK;
    564578                        }
    565                 case ICMP_ECHO:
    566                         if(error){
    567                                 return icmp_process_echo_reply(packet, header, type, code);
    568                         // do not send a reply if disabled
    569                         }else if(icmp_globals.echo_replying){
    570                                 addrlen = packet_get_addr(packet, &src, NULL);
    571                                 if((addrlen > 0)
    572                                 // set both addresses to the source one (avoids the source address deletion before setting the destination one)
    573                                         && (packet_set_addr(packet, src, src, (size_t) addrlen) == EOK)){
    574                                         // send the reply
    575                                         icmp_send_packet(ICMP_ECHOREPLY, 0, packet, header, 0, 0, 0, 0);
    576                                         return EOK;
    577                                 }else{
    578                                         return EINVAL;
    579                                 }
    580                         }else{
    581                                 return EPERM;
     579                       
     580                        return EINVAL;
     581                }
     582               
     583                return EPERM;
     584       
     585        case ICMP_DEST_UNREACH:
     586        case ICMP_SOURCE_QUENCH:
     587        case ICMP_REDIRECT:
     588        case ICMP_ALTERNATE_ADDR:
     589        case ICMP_ROUTER_ADV:
     590        case ICMP_ROUTER_SOL:
     591        case ICMP_TIME_EXCEEDED:
     592        case ICMP_PARAMETERPROB:
     593        case ICMP_CONVERSION_ERROR:
     594        case ICMP_REDIRECT_MOBILE:
     595        case ICMP_SKIP:
     596        case ICMP_PHOTURIS:
     597                ip_received_error_msg(phone_ip, -1, packet,
     598                    SERVICE_IP, SERVICE_ICMP);
     599                return EOK;
     600       
     601        default:
     602                return ENOTSUP;
     603        }
     604}
     605
     606/** Process IPC messages from the IP module
     607 *
     608 * @param[in]     iid   Message identifier.
     609 * @param[in,out] icall Message parameters.
     610 *
     611 */
     612static void icmp_receiver(ipc_callid_t iid, ipc_call_t *icall)
     613{
     614        bool loop = true;
     615        packet_t *packet;
     616        int rc;
     617       
     618        while (loop) {
     619                switch (IPC_GET_IMETHOD(*icall)) {
     620                case NET_TL_RECEIVED:
     621                        rc = packet_translate_remote(phone_net, &packet,
     622                            IPC_GET_PACKET(*icall));
     623                        if (rc == EOK) {
     624                                rc = icmp_process_packet(packet, IPC_GET_ERROR(*icall));
     625                                if (rc != EOK)
     626                                        icmp_release(packet);
    582627                        }
    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;
     628                       
     629                        async_answer_0(iid, (sysarg_t) rc);
     630                        break;
     631                case IPC_M_PHONE_HUNGUP:
     632                        loop = false;
     633                        continue;
    597634                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);
     635                        async_answer_0(iid, (sysarg_t) ENOTSUP);
     636                }
     637               
     638                iid = async_get_call(icall);
     639        }
     640}
     641
     642/** Initialize the ICMP module.
     643 *
     644 * @param[in] net_phone Network module phone.
     645 *
     646 * @return EOK on success.
     647 * @return ENOMEM if there is not enough memory left.
     648 *
     649 */
     650int tl_initialize(int net_phone)
     651{
     652        measured_string_t names[] = {
     653                {
     654                        (uint8_t *) "ICMP_ERROR_REPORTING",
     655                        20
     656                },
     657                {
     658                        (uint8_t *) "ICMP_ECHO_REPLYING",
     659                        18
     660                }
     661        };
     662        measured_string_t *configuration;
     663        size_t count = sizeof(names) / sizeof(measured_string_t);
     664        uint8_t *data;
     665       
     666        if (!hash_table_create(&replies, REPLY_BUCKETS, REPLY_KEYS, &reply_ops))
     667                return ENOMEM;
     668       
     669        fibril_mutex_initialize(&reply_lock);
     670        atomic_set(&icmp_client, 0);
     671       
     672        phone_net = net_phone;
     673        phone_ip = ip_bind_service(SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP,
     674            icmp_receiver);
     675        if (phone_ip < 0)
     676                return phone_ip;
     677       
     678        int rc = ip_packet_size_req(phone_ip, -1, &icmp_dimension);
     679        if (rc != EOK)
     680                return rc;
     681       
     682        icmp_dimension.prefix += ICMP_HEADER_SIZE;
     683        icmp_dimension.content -= ICMP_HEADER_SIZE;
     684       
     685        /* Get configuration */
     686        configuration = &names[0];
     687        rc = net_get_conf_req(phone_net, &configuration, count, &data);
     688        if (rc != EOK)
     689                return rc;
     690       
     691        if (configuration) {
     692                if (configuration[0].value)
     693                        error_reporting = (configuration[0].value[0] == 'y');
     694               
     695                if (configuration[1].value)
     696                        echo_replying = (configuration[1].value[0] == 'y');
     697               
     698                net_free_settings(configuration, data);
     699        }
     700       
    620701        return EOK;
    621702}
    622703
    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         }
     704/** Per-connection initialization
     705 *
     706 * Initialize client-specific global variables.
     707 *
     708 */
     709void tl_connection(void)
     710{
     711        icmp_id = (icmp_param_t) atomic_postinc(&icmp_client);
     712        icmp_seq = 1;
     713}
     714
     715/** Process the ICMP message.
     716 *
     717 * @param[in]  callid Message identifier.
     718 * @param[in]  call   Message parameters.
     719 * @param[out] answer Answer.
     720 * @param[out] count  Number of arguments of the answer.
     721 *
     722 * @return EOK on success.
     723 * @return ENOTSUP if the message is not known.
     724 * @return Other error codes as defined for the packet_translate()
     725 *         function.
     726 * @return Other error codes as defined for the
     727 *         icmp_destination_unreachable() function.
     728 * @return Other error codes as defined for the
     729 *         icmp_source_quench() function.
     730 * @return Other error codes as defined for the
     731 *         icmp_time_exceeded() function.
     732 * @return Other error codes as defined for the
     733 *         icmp_parameter_problem() function.
     734 *
     735 * @see icmp_remote.h
     736 * @see IS_NET_ICMP_MESSAGE()
     737 *
     738 */
     739int tl_message(ipc_callid_t callid, ipc_call_t *call,
     740    ipc_call_t *answer, size_t *count)
     741{
     742        struct sockaddr *addr;
     743        size_t size;
     744        packet_t *packet;
     745        int rc;
     746       
     747        *count = 0;
     748       
     749        switch (IPC_GET_IMETHOD(*call)) {
     750        case NET_ICMP_ECHO:
     751                rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &size);
     752                if (rc != EOK)
     753                        return rc;
     754               
     755                rc = icmp_echo(icmp_id, icmp_seq, ICMP_GET_SIZE(*call),
     756                    ICMP_GET_TIMEOUT(*call), ICMP_GET_TTL(*call),
     757                    ICMP_GET_TOS(*call), ICMP_GET_DONT_FRAGMENT(*call),
     758                    addr, (socklen_t) size);
     759               
     760                free(addr);
     761                icmp_seq++;
     762                return rc;
     763       
     764        case NET_ICMP_DEST_UNREACH:
     765                rc = packet_translate_remote(phone_net, &packet,
     766                    IPC_GET_PACKET(*call));
     767                if (rc != EOK)
     768                        return rc;
     769               
     770                return icmp_destination_unreachable(ICMP_GET_CODE(*call),
     771                    ICMP_GET_MTU(*call), packet);
     772       
     773        case NET_ICMP_SOURCE_QUENCH:
     774                rc = packet_translate_remote(phone_net, &packet,
     775                    IPC_GET_PACKET(*call));
     776                if (rc != EOK)
     777                        return rc;
     778               
     779                return icmp_source_quench(packet);
     780       
     781        case NET_ICMP_TIME_EXCEEDED:
     782                rc = packet_translate_remote(phone_net, &packet,
     783                    IPC_GET_PACKET(*call));
     784                if (rc != EOK)
     785                        return rc;
     786               
     787                return icmp_time_exceeded(ICMP_GET_CODE(*call), packet);
     788       
     789        case NET_ICMP_PARAMETERPROB:
     790                rc = packet_translate_remote(phone_net, &packet,
     791                    IPC_GET_PACKET(*call));
     792                if (rc != EOK)
     793                        return rc;
     794               
     795                return icmp_parameter_problem(ICMP_GET_CODE(*call),
     796                    ICMP_GET_POINTER(*call), packet);
     797        }
     798       
    640799        return ENOTSUP;
    641800}
    642801
    643 int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call){
    644         ERROR_DECLARE;
    645 
    646         bool keep_on_going = true;
    647 //      fibril_rwlock_t                 lock;
    648         ipc_call_t answer;
    649         int answer_count;
    650         size_t length;
    651         struct sockaddr * addr;
    652         ipc_callid_t data_callid;
    653         icmp_echo_ref echo_data;
    654         int res;
    655 
    656         /*
    657          * Accept the connection
    658          *  - Answer the first NET_ICMP_INIT call.
    659          */
    660         res = EOK;
    661         answer_count = 0;
    662 
    663 //      fibril_rwlock_initialize(&lock);
    664 
    665         echo_data = (icmp_echo_ref) malloc(sizeof(*echo_data));
    666         if(! echo_data){
    667                 return ENOMEM;
    668         }
    669 
    670         // assign a new identifier
    671         fibril_rwlock_write_lock(&icmp_globals.lock);
    672         res = icmp_bind_free_id(echo_data);
    673         fibril_rwlock_write_unlock(&icmp_globals.lock);
    674         if(res < 0){
    675                 free(echo_data);
    676                 return res;
    677         }
    678 
    679         while(keep_on_going){
    680 
    681                 // answer the call
    682                 answer_call(callid, res, &answer, answer_count);
    683 
    684                 // refresh data
    685                 refresh_answer(&answer, &answer_count);
    686 
    687                 // get the next call
    688                 callid = async_get_call(&call);
    689 
    690                 // process the call
    691                 switch(IPC_GET_METHOD(call)){
    692                         case IPC_M_PHONE_HUNGUP:
    693                                 keep_on_going = false;
    694                                 res = EHANGUP;
    695                                 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);
    721                                 break;
    722                         default:
    723                                 res = icmp_process_message(&call);
    724                 }
    725         }
    726 
    727         // release the identifier
    728         fibril_rwlock_write_lock(&icmp_globals.lock);
    729         icmp_echo_data_exclude(&icmp_globals.echo_data, echo_data->identifier);
    730         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 
    737         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 }
    800 
    801 /** Default thread for new connections.
    802  *
    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)
    808 {
    809         /*
    810          * Accept the connection
    811          *  - Answer the first IPC_M_CONNECT_ME_TO call.
    812          */
    813         ipc_answer_0(iid, EOK);
    814        
    815         while(true) {
    816                 ipc_call_t answer;
    817                 int answer_count;
    818                
    819                 /* Clear the answer structure */
    820                 refresh_answer(&answer, &answer_count);
    821                
    822                 /* Fetch the next message */
    823                 ipc_call_t call;
    824                 ipc_callid_t callid = async_get_call(&call);
    825                
    826                 /* Process the message */
    827                 int res = tl_module_message_standalone(callid, &call, &answer,
    828                     &answer_count);
    829                
    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))
    832                         return;
    833                
    834                 /* Answer the message */
    835                 answer_call(callid, res, &answer, answer_count);
    836         }
    837 }
    838 
    839 /** Starts the module.
    840  *
    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  *
    847  */
    848802int main(int argc, char *argv[])
    849803{
    850         ERROR_DECLARE;
    851        
    852804        /* Start the module */
    853         if (ERROR_OCCURRED(tl_module_start_standalone(tl_client_connection)))
    854                 return ERROR_CODE;
    855        
    856         return EOK;
     805        return tl_module_start(SERVICE_ICMP);
    857806}
    858807
Note: See TracChangeset for help on using the changeset viewer.