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


Ignore:
Timestamp:
2011-02-03T05:11:01Z (13 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
ba38f72c
Parents:
22027b6e (diff), 86d7bfa (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

    r22027b6e r8b5690f  
    3333/** @file
    3434 * ICMP module implementation.
    35  * @see icmp.h
    36  */
    37 
    38 #include "icmp.h"
    39 #include "icmp_module.h"
     35 */
    4036
    4137#include <async.h>
     
    4541#include <stdint.h>
    4642#include <str.h>
    47 #include <ipc/ipc.h>
    4843#include <ipc/services.h>
    4944#include <ipc/net.h>
     
    5449#include <byteorder.h>
    5550#include <errno.h>
     51#include <adt/hash_table.h>
    5652
    5753#include <net/socket_codes.h>
     
    6763#include <net_checksum.h>
    6864#include <icmp_client.h>
    69 #include <icmp_interface.h>
    70 #include <il_interface.h>
     65#include <icmp_remote.h>
     66#include <il_remote.h>
    7167#include <ip_client.h>
    7268#include <ip_interface.h>
    7369#include <net_interface.h>
    74 #include <tl_interface.h>
    75 #include <tl_local.h>
     70#include <tl_remote.h>
     71#include <tl_skel.h>
    7672#include <icmp_header.h>
    7773
    78 /** ICMP module name. */
    79 #define NAME    "ICMP protocol"
    80 
    81 /** Default ICMP error reporting. */
    82 #define NET_DEFAULT_ICMP_ERROR_REPORTING        true
    83 
    84 /** Default ICMP echo replying. */
    85 #define NET_DEFAULT_ICMP_ECHO_REPLYING          true
    86 
    87 /** Original datagram length in bytes transfered to the error notification
    88  * message.
    89  */
    90 #define ICMP_KEEP_LENGTH        8
    91 
    92 /** Free identifier numbers pool start. */
    93 #define ICMP_FREE_IDS_START     1
    94 
    95 /** Free identifier numbers pool end. */
    96 #define ICMP_FREE_IDS_END       UINT16_MAX
    97 
    98 /** Computes the ICMP datagram checksum.
    99  *
    100  * @param[in,out] header The ICMP datagram header.
    101  * @param[in] length    The total datagram length.
    102  * @return              The computed checksum.
     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 *
    10396 */
    10497#define ICMP_CHECKSUM(header, length) \
     
    10699
    107100/** An echo request datagrams pattern. */
    108 #define ICMP_ECHO_TEXT          "Hello from HelenOS."
    109 
    110 /** Computes an ICMP reply data key.
    111  *
    112  * @param[in] id        The message identifier.
    113  * @param[in] sequence  The message sequence number.
    114  * @return              The computed ICMP reply data key.
    115  */
    116 #define ICMP_GET_REPLY_KEY(id, sequence) \
    117         (((id) << 16) | (sequence & 0xFFFF))
    118 
    119 
    120 /** ICMP global data. */
    121 icmp_globals_t  icmp_globals;
    122 
    123 INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t);
    124 INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t);
    125 
    126 /** Releases the packet and returns the result.
    127  *
    128  * @param[in] packet    The packet queue to be released.
    129  * @param[in] result    The result to be returned.
    130  * @return              The result parameter.
    131  */
    132 static int icmp_release_and_return(packet_t *packet, int result)
    133 {
    134         pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
    135         return result;
    136 }
    137 
    138 /** Sends the ICMP message.
    139  *
    140  * Sets the message type and code and computes the checksum.
     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 */
     116        int result;
     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.
    141181 * Error messages are sent only if allowed in the configuration.
    142  * Releases the packet on errors.
    143  *
    144  * @param[in] type      The message type.
    145  * @param[in] code      The message code.
    146  * @param[in] packet    The message packet to be sent.
    147  * @param[in] header    The ICMP header.
    148  * @param[in] error     The error service to be announced. Should be
    149  *                      SERVICE_ICMP or zero.
    150  * @param[in] ttl       The time to live.
    151  * @param[in] tos       The type of service.
    152  * @param[in] dont_fragment The value indicating whether the datagram must not
    153  *                      be fragmented. Is used as a MTU discovery.
    154  * @return              EOK on success.
    155  * @return              EPERM if the error message is not allowed.
    156  */
    157 static int icmp_send_packet(icmp_type_t type, icmp_code_t code, packet_t *packet,
    158     icmp_header_t *header, services_t error, ip_ttl_t ttl, ip_tos_t tos,
    159     int dont_fragment)
    160 {
    161         int rc;
    162 
     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{
    163202        /* Do not send an error if disabled */
    164         if (error && !icmp_globals.error_reporting)
    165                 return icmp_release_and_return(packet, EPERM);
    166 
     203        if ((error) && (!error_reporting)) {
     204                icmp_release(packet);
     205                return EPERM;
     206        }
     207       
    167208        header->type = type;
    168209        header->code = code;
     210       
     211        /*
     212         * The checksum needs to be calculated
     213         * with a virtual checksum field set to
     214         * zero.
     215         */
    169216        header->checksum = 0;
    170217        header->checksum = ICMP_CHECKSUM(header,
    171218            packet_get_data_length(packet));
    172219       
    173         rc = ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl, tos,
     220        int rc = ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl, tos,
    174221            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.
     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 *
    188237 * @return The prefixed ICMP header.
    189238 * @return NULL on errors.
     239 *
    190240 */
    191241static icmp_header_t *icmp_prepare_packet(packet_t *packet)
    192242{
    193         icmp_header_t *header;
    194         size_t header_length;
    195         size_t total_length;
    196 
    197         total_length = packet_get_data_length(packet);
     243        size_t total_length = packet_get_data_length(packet);
    198244        if (total_length <= 0)
    199245                return NULL;
    200 
    201         header_length = ip_client_header_length(packet);
     246       
     247        size_t header_length = ip_client_header_length(packet);
    202248        if (header_length <= 0)
    203249                return NULL;
    204 
     250       
    205251        /* Truncate if longer than 64 bits (without the IP header) */
    206252        if ((total_length > header_length + ICMP_KEEP_LENGTH) &&
    207253            (packet_trim(packet, 0,
    208             total_length - header_length - ICMP_KEEP_LENGTH) != EOK)) {
     254            total_length - header_length - ICMP_KEEP_LENGTH) != EOK))
    209255                return NULL;
    210         }
    211 
    212         header = PACKET_PREFIX(packet, icmp_header_t);
     256       
     257        icmp_header_t *header = PACKET_PREFIX(packet, icmp_header_t);
    213258        if (!header)
    214259                return NULL;
    215 
     260       
    216261        bzero(header, sizeof(*header));
    217262        return header;
    218263}
    219264
    220 /** Requests an echo message.
    221  *
    222  * Sends a packet with specified parameters to the target host and waits for
    223  * the reply upto the given timeout.
    224  * Blocks the caller until the reply or the timeout occurs.
    225  *
    226  * @param[in] id        The message identifier.
    227  * @param[in] sequence  The message sequence parameter.
    228  * @param[in] size      The message data length in bytes.
    229  * @param[in] timeout   The timeout in miliseconds.
    230  * @param[in] ttl       The time to live.
    231  * @param[in] tos       The type of service.
    232  * @param[in] dont_fragment The value indicating whether the datagram must not
    233  *                      be fragmented. Is used as a MTU discovery.
    234  * @param[in] addr      The target host address.
    235  * @param[in] addrlen   The torget host address length.
    236  * @return              ICMP_ECHO on success.
    237  * @return              ETIMEOUT if the reply has not arrived before the
    238  *                      timeout.
    239  * @return              ICMP type of the received error notification.
    240  * @return              EINVAL if the addrlen parameter is less or equal to
    241  *                      zero.
    242  * @return              ENOMEM if there is not enough memory left.
    243  * @return              EPARTY if there was an internal error.
     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 *
    244289 */
    245290static int icmp_echo(icmp_param_t id, icmp_param_t sequence, size_t size,
    246     mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment,
    247     const struct sockaddr * addr, socklen_t addrlen)
    248 {
    249         icmp_header_t *header;
    250         packet_t *packet;
    251         size_t length;
    252         uint8_t *data;
    253         icmp_reply_t *reply;
    254         int reply_key;
    255         int index;
    256         int rc;
    257 
     291    mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, bool dont_fragment,
     292    const struct sockaddr *addr, socklen_t addrlen)
     293{
    258294        if (addrlen <= 0)
    259295                return EINVAL;
    260 
    261         length = (size_t) addrlen;
    262         /* TODO do not ask all the time */
    263         rc = ip_packet_size_req(icmp_globals.ip_phone, -1,
    264             &icmp_globals.packet_dimension);
    265         if (rc != EOK)
    266                 return rc;
    267 
    268         packet = packet_get_4_remote(icmp_globals.net_phone, size,
    269             icmp_globals.packet_dimension.addr_len,
    270             ICMP_HEADER_SIZE + icmp_globals.packet_dimension.prefix,
    271             icmp_globals.packet_dimension.suffix);
     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);
    272302        if (!packet)
    273303                return ENOMEM;
    274 
     304       
    275305        /* 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 
     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       
    280312        /* Allocate space in the packet */
    281         data = (uint8_t *) packet_suffix(packet, size);
    282         if (!data)
    283                 return icmp_release_and_return(packet, ENOMEM);
    284 
     313        uint8_t *data = (uint8_t *) packet_suffix(packet, size);
     314        if (!data) {
     315                icmp_release(packet);
     316                return ENOMEM;
     317        }
     318       
    285319        /* Fill the data */
    286320        length = 0;
     
    290324        }
    291325        memcpy(data + length, ICMP_ECHO_TEXT, size - length);
    292 
     326       
    293327        /* Prefix the header */
    294         header = PACKET_PREFIX(packet, icmp_header_t);
    295         if (!header)
    296                 return icmp_release_and_return(packet, ENOMEM);
    297 
    298         bzero(header, sizeof(*header));
     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));
    299335        header->un.echo.identifier = id;
    300336        header->un.echo.sequence_number = sequence;
    301 
     337       
    302338        /* Prepare the reply structure */
    303         reply = malloc(sizeof(*reply));
    304         if (!reply)
    305                 return icmp_release_and_return(packet, ENOMEM);
    306 
    307         fibril_mutex_initialize(&reply->mutex);
    308         fibril_mutex_lock(&reply->mutex);
     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;
    309347        fibril_condvar_initialize(&reply->condvar);
    310         reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier,
    311             header->un.echo.sequence_number);
    312         index = icmp_replies_add(&icmp_globals.replies, reply_key, reply);
    313         if (index < 0) {
    314                 free(reply);
    315                 return icmp_release_and_return(packet, index);
    316         }
    317 
    318         /* Unlock the globals so that we can wait for the reply */
    319         fibril_rwlock_write_unlock(&icmp_globals.lock);
    320 
     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       
    321355        /* Send the request */
    322356        icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos,
    323357            dont_fragment);
    324 
     358       
    325359        /* Wait for the reply. Timeout in microseconds. */
    326         rc = fibril_condvar_wait_timeout(&reply->condvar, &reply->mutex,
     360        rc = fibril_condvar_wait_timeout(&reply->condvar, &reply_lock,
    327361            timeout * 1000);
    328362        if (rc == EOK)
    329363                rc = reply->result;
    330 
    331         /* Drop the reply mutex before locking the globals again */
    332         fibril_mutex_unlock(&reply->mutex);
    333         fibril_rwlock_write_lock(&icmp_globals.lock);
    334 
    335         /* Destroy the reply structure */
    336         icmp_replies_exclude_index(&icmp_globals.replies, index);
    337 
     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       
    338372        return rc;
    339373}
    340374
    341 static int icmp_destination_unreachable_msg_local(int icmp_phone,
    342     icmp_code_t code, icmp_param_t mtu, packet_t *packet)
    343 {
    344         icmp_header_t *header;
    345 
    346         header = icmp_prepare_packet(packet);
    347         if (!header)
    348                 return icmp_release_and_return(packet, ENOMEM);
    349 
     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       
    350384        if (mtu)
    351385                header->un.frag.mtu = mtu;
    352 
     386       
    353387        return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header,
    354             SERVICE_ICMP, 0, 0, 0);
    355 }
    356 
    357 static int icmp_source_quench_msg_local(int icmp_phone, packet_t *packet)
    358 {
    359         icmp_header_t *header;
    360 
    361         header = icmp_prepare_packet(packet);
    362         if (!header)
    363                 return icmp_release_and_return(packet, ENOMEM);
    364 
     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       
    365399        return icmp_send_packet(ICMP_SOURCE_QUENCH, 0, packet, header,
    366             SERVICE_ICMP, 0, 0, 0);
    367 }
    368 
    369 static int icmp_time_exceeded_msg_local(int icmp_phone, icmp_code_t code,
     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,
    370416    packet_t *packet)
    371417{
    372         icmp_header_t *header;
    373 
    374         header = icmp_prepare_packet(packet);
    375         if (!header)
    376                 return icmp_release_and_return(packet, ENOMEM);
    377 
    378         return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header,
    379             SERVICE_ICMP, 0, 0, 0);
    380 }
    381 
    382 static int icmp_parameter_problem_msg_local(int icmp_phone, icmp_code_t code,
    383     icmp_param_t pointer, packet_t *packet)
    384 {
    385         icmp_header_t *header;
    386 
    387         header = icmp_prepare_packet(packet);
    388         if (!header)
    389                 return icmp_release_and_return(packet, ENOMEM);
    390 
     418        icmp_header_t *header = icmp_prepare_packet(packet);
     419        if (!header) {
     420                icmp_release(packet);
     421                return ENOMEM;
     422        }
     423       
    391424        header->un.param.pointer = pointer;
    392425        return icmp_send_packet(ICMP_PARAMETERPROB, code, packet, header,
    393             SERVICE_ICMP, 0, 0, 0);
    394 }
    395 
    396 /** Initializes the ICMP module.
    397  *
    398  * @param[in] client_connection The client connection processing function. The
    399  *                      module skeleton propagates its own one.
    400  * @return              EOK on success.
    401  * @return              ENOMEM if there is not enough memory left.
    402  */
    403 int icmp_initialize(async_client_conn_t client_connection)
     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{
     486        icmp_type_t type;
     487        icmp_code_t code;
     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       
     515        length = packet_get_data_length(packet);
     516        if (length <= 0)
     517                return EINVAL;
     518       
     519        if (length < ICMP_HEADER_SIZE)
     520                return EINVAL;
     521       
     522        void *data = packet_get_data(packet);
     523        if (!data)
     524                return EINVAL;
     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;
     540                                }
     541                        }
     542                       
     543                        return EINVAL;
     544                }
     545        }
     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;
     578                        }
     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);
     627                        }
     628                       
     629                        async_answer_0(iid, (sysarg_t) rc);
     630                        break;
     631                case IPC_M_PHONE_HUNGUP:
     632                        loop = false;
     633                        continue;
     634                default:
     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)
    404651{
    405652        measured_string_t names[] = {
     
    416663        size_t count = sizeof(names) / sizeof(measured_string_t);
    417664        uint8_t *data;
    418         int rc;
    419 
    420         fibril_rwlock_initialize(&icmp_globals.lock);
    421         fibril_rwlock_write_lock(&icmp_globals.lock);
    422         icmp_replies_initialize(&icmp_globals.replies);
    423         icmp_echo_data_initialize(&icmp_globals.echo_data);
    424        
    425         icmp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_ICMP,
    426             SERVICE_ICMP, client_connection);
    427         if (icmp_globals.ip_phone < 0) {
    428                 fibril_rwlock_write_unlock(&icmp_globals.lock);
    429                 return icmp_globals.ip_phone;
    430         }
    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);
     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)
    436680                return rc;
    437         }
    438 
    439         icmp_globals.packet_dimension.prefix += ICMP_HEADER_SIZE;
    440         icmp_globals.packet_dimension.content -= ICMP_HEADER_SIZE;
    441 
    442         icmp_globals.error_reporting = NET_DEFAULT_ICMP_ERROR_REPORTING;
    443         icmp_globals.echo_replying = NET_DEFAULT_ICMP_ECHO_REPLYING;
    444 
     681       
     682        icmp_dimension.prefix += ICMP_HEADER_SIZE;
     683        icmp_dimension.content -= ICMP_HEADER_SIZE;
     684       
    445685        /* Get configuration */
    446686        configuration = &names[0];
    447         rc = net_get_conf_req(icmp_globals.net_phone, &configuration, count,
    448             &data);
    449         if (rc != EOK) {
    450                 fibril_rwlock_write_unlock(&icmp_globals.lock);
     687        rc = net_get_conf_req(phone_net, &configuration, count, &data);
     688        if (rc != EOK)
    451689                return rc;
    452         }
    453690       
    454691        if (configuration) {
    455                 if (configuration[0].value) {
    456                         icmp_globals.error_reporting =
    457                             (configuration[0].value[0] == 'y');
    458                 }
    459                 if (configuration[1].value) {
    460                         icmp_globals.echo_replying =
    461                             (configuration[1].value[0] == 'y');
    462                 }
     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               
    463698                net_free_settings(configuration, data);
    464699        }
    465 
    466         fibril_rwlock_write_unlock(&icmp_globals.lock);
     700       
    467701        return EOK;
    468702}
    469703
    470 /** Tries to set the pending reply result as the received message type.
    471  *
    472  * If the reply data is not present, the reply timed out and the other fibril
    473  * is already awake.
    474  * Releases the packet.
    475  *
    476  * @param[in] packet    The received reply message.
    477  * @param[in] header    The ICMP message header.
    478  * @param[in] type      The received reply message type.
    479  * @param[in] code      The received reply message code.
    480  */
    481 static void  icmp_process_echo_reply(packet_t *packet, icmp_header_t *header,
    482     icmp_type_t type, icmp_code_t code)
    483 {
    484         int reply_key;
    485         icmp_reply_t *reply;
    486 
    487         /* Compute the reply key */
    488         reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier,
    489             header->un.echo.sequence_number);
    490         pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
    491 
    492         /* Find the pending reply */
    493         fibril_rwlock_write_lock(&icmp_globals.lock);
    494         reply = icmp_replies_find(&icmp_globals.replies, reply_key);
    495         if (reply) {
    496                 reply->result = type;
    497                 fibril_condvar_signal(&reply->condvar);
    498         }
    499         fibril_rwlock_write_unlock(&icmp_globals.lock);
    500 }
    501 
    502 /** Processes the received ICMP packet.
    503  *
    504  * Notifies the destination socket application.
    505  *
    506  * @param[in,out] packet The received packet.
    507  * @param[in] error     The packet error reporting service. Prefixes the
    508  *                      received packet.
    509  * @return              EOK on success.
    510  * @return              EINVAL if the packet is not valid.
    511  * @return              EINVAL if the stored packet address is not the an_addr_t.
    512  * @return              EINVAL if the packet does not contain any data.
    513  * @return              NO_DATA if the packet content is shorter than the user
    514  *                      datagram header.
    515  * @return              ENOMEM if there is not enough memory left.
    516  * @return              EADDRNOTAVAIL if the destination socket does not exist.
    517  * @return              Other error codes as defined for the
    518  *                      ip_client_process_packet() function.
    519  */
    520 static int icmp_process_packet(packet_t *packet, services_t error)
    521 {
    522         size_t length;
    523         uint8_t *src;
    524         int addrlen;
    525         int result;
    526         void *data;
    527         icmp_header_t *header;
    528         icmp_type_t type;
    529         icmp_code_t code;
     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;
    530745        int rc;
    531746       
    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);
     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);
    544752                if (rc != EOK)
    545753                        return rc;
    546                 break;
    547         default:
    548                 return ENOTSUP;
    549         }
    550 
    551         /* Get rid of the IP header */
    552         length = ip_client_header_length(packet);
    553         rc = packet_trim(packet, length, 0);
    554         if (rc != EOK)
     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++;
    555762                return rc;
    556 
    557         length = packet_get_data_length(packet);
    558         if (length <= 0)
    559                 return EINVAL;
    560 
    561         if (length < ICMP_HEADER_SIZE)
    562                 return EINVAL;
    563 
    564         data = packet_get_data(packet);
    565         if (!data)
    566                 return EINVAL;
    567 
    568         /* Get ICMP header */
    569         header = (icmp_header_t *) data;
    570 
    571         if (header->checksum) {
    572                 while (ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO) {
    573                         /*
    574                          * Set the original message type on error notification.
    575                          * Type swap observed in Qemu.
    576                          */
    577                         if (error) {
    578                                 switch (header->type) {
    579                                 case ICMP_ECHOREPLY:
    580                                         header->type = ICMP_ECHO;
    581                                         continue;
    582                                 }
    583                         }
    584                         return EINVAL;
    585                 }
    586         }
    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;
    618                         }
    619 
    620                         return EINVAL;
    621                 }
    622 
    623                 return EPERM;
    624 
    625         case ICMP_DEST_UNREACH:
    626         case ICMP_SOURCE_QUENCH:
    627         case ICMP_REDIRECT:
    628         case ICMP_ALTERNATE_ADDR:
    629         case ICMP_ROUTER_ADV:
    630         case ICMP_ROUTER_SOL:
    631         case ICMP_TIME_EXCEEDED:
    632         case ICMP_PARAMETERPROB:
    633         case ICMP_CONVERSION_ERROR:
    634         case ICMP_REDIRECT_MOBILE:
    635         case ICMP_SKIP:
    636         case ICMP_PHOTURIS:
    637                 ip_received_error_msg(icmp_globals.ip_phone, -1, packet,
    638                     SERVICE_IP, SERVICE_ICMP);
    639                 return EOK;
    640 
    641         default:
    642                 return ENOTSUP;
    643         }
    644 }
    645 
    646 /** Processes the received ICMP packet.
    647  *
    648  * Is used as an entry point from the underlying IP module.
    649  * Releases the packet on error.
    650  *
    651  * @param device_id     The device identifier. Ignored parameter.
    652  * @param[in,out] packet The received packet.
    653  * @param receiver      The target service. Ignored parameter.
    654  * @param[in] error     The packet error reporting service. Prefixes the
    655  *                      received packet.
    656  * @return              EOK on success.
    657  * @return              Other error codes as defined for the
    658  *                      icmp_process_packet() function.
    659  */
    660 static int icmp_received_msg_local(device_id_t device_id, packet_t *packet,
    661     services_t receiver, services_t error)
    662 {
    663         int rc;
    664 
    665         rc = icmp_process_packet(packet, error);
    666         if (rc != EOK)
    667                 return icmp_release_and_return(packet, rc);
    668 
    669         return EOK;
    670 }
    671 
    672 /** Processes the generic client messages.
    673  *
    674  * @param[in] call      The message parameters.
    675  * @return              EOK on success.
    676  * @return              ENOTSUP if the message is not known.
    677  * @return              Other error codes as defined for the packet_translate()
    678  *                      function.
    679  * @return              Other error codes as defined for the
    680  *                      icmp_destination_unreachable_msg_local() function.
    681  * @return              Other error codes as defined for the
    682  *                      icmp_source_quench_msg_local() function.
    683  * @return              Other error codes as defined for the
    684  *                      icmp_time_exceeded_msg_local() function.
    685  * @return              Other error codes as defined for the
    686  *                      icmp_parameter_problem_msg_local() function.
    687  *
    688  * @see icmp_interface.h
    689  */
    690 static int icmp_process_message(ipc_call_t *call)
    691 {
    692         packet_t *packet;
    693         int rc;
    694 
    695         switch (IPC_GET_IMETHOD(*call)) {
     763       
    696764        case NET_ICMP_DEST_UNREACH:
    697                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    698                     IPC_GET_PACKET(call));
     765                rc = packet_translate_remote(phone_net, &packet,
     766                    IPC_GET_PACKET(*call));
    699767                if (rc != EOK)
    700768                        return rc;
    701                 return icmp_destination_unreachable_msg_local(0,
    702                     ICMP_GET_CODE(call), ICMP_GET_MTU(call), packet);
     769               
     770                return icmp_destination_unreachable(ICMP_GET_CODE(*call),
     771                    ICMP_GET_MTU(*call), packet);
     772       
    703773        case NET_ICMP_SOURCE_QUENCH:
    704                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    705                     IPC_GET_PACKET(call));
     774                rc = packet_translate_remote(phone_net, &packet,
     775                    IPC_GET_PACKET(*call));
    706776                if (rc != EOK)
    707777                        return rc;
    708                 return icmp_source_quench_msg_local(0, packet);
     778               
     779                return icmp_source_quench(packet);
     780       
    709781        case NET_ICMP_TIME_EXCEEDED:
    710                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    711                     IPC_GET_PACKET(call));
     782                rc = packet_translate_remote(phone_net, &packet,
     783                    IPC_GET_PACKET(*call));
    712784                if (rc != EOK)
    713785                        return rc;
    714                 return icmp_time_exceeded_msg_local(0, ICMP_GET_CODE(call),
    715                     packet);
     786               
     787                return icmp_time_exceeded(ICMP_GET_CODE(*call), packet);
     788       
    716789        case NET_ICMP_PARAMETERPROB:
    717                 rc = packet_translate_remote(icmp_globals.net_phone, &packet,
    718                     IPC_GET_PACKET(call));
     790                rc = packet_translate_remote(phone_net, &packet,
     791                    IPC_GET_PACKET(*call));
    719792                if (rc != EOK)
    720793                        return rc;
    721                 return icmp_parameter_problem_msg_local(0, ICMP_GET_CODE(call),
    722                     ICMP_GET_POINTER(call), packet);
    723         default:
    724                 return ENOTSUP;
    725         }
    726 }
    727 
    728 /** Assigns a new identifier for the connection.
    729  *
    730  * Fills the echo data parameter with the assigned values.
    731  *
    732  * @param[in,out] echo_data The echo data to be bound.
    733  * @return              Index of the inserted echo data.
    734  * @return              EBADMEM if the echo_data parameter is NULL.
    735  * @return              ENOTCONN if no free identifier have been found.
    736  */
    737 static int icmp_bind_free_id(icmp_echo_t *echo_data)
    738 {
    739         icmp_param_t index;
    740 
    741         if (!echo_data)
    742                 return EBADMEM;
    743 
    744         /* From the last used one */
    745         index = icmp_globals.last_used_id;
    746         do {
    747                 index++;
    748                 /* til the range end */
    749                 if (index >= ICMP_FREE_IDS_END) {
    750                         /* start from the range beginning */
    751                         index = ICMP_FREE_IDS_START - 1;
    752                         do {
    753                                 index++;
    754                                 /* til the last used one */
    755                                 if (index >= icmp_globals.last_used_id) {
    756                                         /* none found */
    757                                         return ENOTCONN;
    758                                 }
    759                         } while(icmp_echo_data_find(&icmp_globals.echo_data,
    760                             index) != NULL);
    761 
    762                         /* Found, break immediately */
    763                         break;
    764                 }
    765         } while (icmp_echo_data_find(&icmp_globals.echo_data, index) != NULL);
    766 
    767         echo_data->identifier = index;
    768         echo_data->sequence_number = 0;
    769 
    770         return icmp_echo_data_add(&icmp_globals.echo_data, index, echo_data);
    771 }
    772 
    773 /** Processes the client messages.
    774  *
    775  * Remembers the assigned identifier and sequence numbers.
    776  * Runs until the client module disconnects.
    777  *
    778  * @param[in] callid    The message identifier.
    779  * @param[in] call      The message parameters.
    780  * @return EOK.
    781  *
    782  * @see icmp_interface.h
    783  * @see icmp_api.h
    784  */
    785 static int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
    786 {
    787         bool keep_on_going = true;
    788         ipc_call_t answer;
    789         int answer_count;
    790         size_t length;
    791         struct sockaddr *addr;
    792         ipc_callid_t data_callid;
    793         icmp_echo_t *echo_data;
    794         int rc = EOK;
    795 
    796         /*
    797          * Accept the connection
    798          *  - Answer the first NET_ICMP_INIT call.
    799          */
    800         answer_count = 0;
    801 
    802         echo_data = (icmp_echo_t *) malloc(sizeof(*echo_data));
    803         if (!echo_data)
    804                 return ENOMEM;
    805 
    806         /* Assign a new identifier */
    807         fibril_rwlock_write_lock(&icmp_globals.lock);
    808         rc = icmp_bind_free_id(echo_data);
    809         fibril_rwlock_write_unlock(&icmp_globals.lock);
    810         if (rc < 0) {
    811                 free(echo_data);
    812                 return rc;
    813         }
    814 
    815         while (keep_on_going) {
    816                 /* Answer the call */
    817                 answer_call(callid, rc, &answer, answer_count);
    818 
    819                 /* Refresh data */
    820                 refresh_answer(&answer, &answer_count);
    821 
    822                 /* Get the next call */
    823                 callid = async_get_call(&call);
    824 
    825                 /* Process the call */
    826                 switch (IPC_GET_IMETHOD(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;
    835                                 break;
    836                         }
    837                        
    838                         addr = malloc(length);
    839                         if (!addr) {
    840                                 rc = ENOMEM;
    841                                 break;
    842                         }
    843                        
    844                         rc = async_data_write_finalize(data_callid, addr,
    845                             length);
    846                         if (rc != EOK) {
    847                                 free(addr);
    848                                 break;
    849                         }
    850 
    851                         fibril_rwlock_write_lock(&icmp_globals.lock);
    852                         rc = icmp_echo(echo_data->identifier,
    853                             echo_data->sequence_number, ICMP_GET_SIZE(call),
    854                             ICMP_GET_TIMEOUT(call), ICMP_GET_TTL(call),
    855                             ICMP_GET_TOS(call), ICMP_GET_DONT_FRAGMENT(call),
    856                             addr, (socklen_t) length);
    857                         fibril_rwlock_write_unlock(&icmp_globals.lock);
    858 
    859                         free(addr);
    860 
    861                         if (echo_data->sequence_number < UINT16_MAX)
    862                                 echo_data->sequence_number++;
    863                         else
    864                                 echo_data->sequence_number = 0;
    865 
    866                         break;
    867 
    868                 default:
    869                         rc = icmp_process_message(&call);
    870                 }
    871 
    872         }
    873 
    874         /* Release the identifier */
    875         fibril_rwlock_write_lock(&icmp_globals.lock);
    876         icmp_echo_data_exclude(&icmp_globals.echo_data, echo_data->identifier);
    877         fibril_rwlock_write_unlock(&icmp_globals.lock);
    878 
    879         return rc;
    880 }
    881 
    882 /** Processes the ICMP message.
    883  *
    884  * @param[in] callid    The message identifier.
    885  * @param[in] call      The message parameters.
    886  * @param[out] answer   The message answer parameters.
    887  * @param[out] answer_count The last parameter for the actual answer in the
    888  *                      answer parameter.
    889  * @return              EOK on success.
    890  * @return              ENOTSUP if the message is not known.
    891  *
    892  * @see icmp_interface.h
    893  * @see IS_NET_ICMP_MESSAGE()
    894  */
    895 int icmp_message_standalone(ipc_callid_t callid, ipc_call_t *call,
    896     ipc_call_t *answer, int *answer_count)
    897 {
    898         packet_t *packet;
    899         int rc;
    900 
    901         *answer_count = 0;
    902         switch (IPC_GET_IMETHOD(*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 
     794               
     795                return icmp_parameter_problem(ICMP_GET_CODE(*call),
     796                    ICMP_GET_POINTER(*call), packet);
     797        }
     798       
    918799        return ENOTSUP;
    919800}
    920801
    921 
    922 /** Default thread for new connections.
    923  *
    924  * @param[in] iid The initial message identifier.
    925  * @param[in] icall The initial message call structure.
    926  *
    927  */
    928 static void tl_client_connection(ipc_callid_t iid, ipc_call_t *icall)
    929 {
    930         /*
    931          * Accept the connection
    932          *  - Answer the first IPC_M_CONNECT_ME_TO call.
    933          */
    934         ipc_answer_0(iid, EOK);
    935        
    936         while (true) {
    937                 ipc_call_t answer;
    938                 int answer_count;
    939                
    940                 /* Clear the answer structure */
    941                 refresh_answer(&answer, &answer_count);
    942                
    943                 /* Fetch the next message */
    944                 ipc_call_t call;
    945                 ipc_callid_t callid = async_get_call(&call);
    946                
    947                 /* Process the message */
    948                 int res = tl_module_message_standalone(callid, &call, &answer,
    949                     &answer_count);
    950                
    951                 /*
    952                  * End if told to either by the message or the processing
    953                  * result.
    954                  */
    955                 if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||
    956                     (res == EHANGUP))
    957                         return;
    958                
    959                 /* Answer the message */
    960                 answer_call(callid, res, &answer, answer_count);
    961         }
    962 }
    963 
    964 /** Starts the module.
    965  *
    966  * @return              EOK on success.
    967  * @return              Other error codes as defined for each specific module
    968  *                      start function.
    969  */
    970802int main(int argc, char *argv[])
    971803{
    972         int rc;
    973        
    974804        /* Start the module */
    975         rc = tl_module_start_standalone(tl_client_connection);
    976         return rc;
     805        return tl_module_start(SERVICE_ICMP);
    977806}
    978807
    979808/** @}
    980809 */
    981 
Note: See TracChangeset for help on using the changeset viewer.