Changeset edc5a985 in mainline


Ignore:
Timestamp:
2010-10-31T19:19:19Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
ba1a2fd
Parents:
940bb45
Message:

Cleanup icmp.

Location:
uspace/srv/net/tl/icmp
Files:
4 edited

Legend:

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

    r940bb45 redc5a985  
    2828
    2929/** @addtogroup icmp
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  ICMP module implementation.
    35  *  @see icmp.h
    36  */
     34 * ICMP module implementation.
     35 * @see icmp.h
     36 */
     37
     38#include "icmp.h"
     39#include "icmp_module.h"
    3740
    3841#include <async.h>
     
    5659#include <net/ip_protocols.h>
    5760#include <net/inet.h>
    58 
    5961#include <net/modules.h>
     62#include <net/icmp_api.h>
     63#include <net/icmp_codes.h>
     64#include <net/icmp_common.h>
     65
    6066#include <packet_client.h>
    6167#include <packet_remote.h>
    6268#include <net_checksum.h>
    63 #include <net/icmp_api.h>
    6469#include <icmp_client.h>
    65 #include <net/icmp_codes.h>
    66 #include <net/icmp_common.h>
    6770#include <icmp_interface.h>
    6871#include <il_interface.h>
     
    7477#include <icmp_header.h>
    7578
    76 #include "icmp.h"
    77 #include "icmp_module.h"
    78 
    79 /** ICMP module name.
    80  */
     79/** ICMP module name. */
    8180#define NAME    "ICMP protocol"
    8281
    83 /** Default ICMP error reporting.
    84  */
     82/** Default ICMP error reporting. */
    8583#define NET_DEFAULT_ICMP_ERROR_REPORTING        true
    8684
    87 /** Default ICMP echo replying.
    88  */
     85/** Default ICMP echo replying. */
    8986#define NET_DEFAULT_ICMP_ECHO_REPLYING          true
    9087
    91 /** Original datagram length in bytes transfered to the error notification message.
     88/** Original datagram length in bytes transfered to the error notification
     89 * message.
    9290 */
    9391#define ICMP_KEEP_LENGTH        8
    9492
    95 /** Free identifier numbers pool start.
    96  */
     93/** Free identifier numbers pool start. */
    9794#define ICMP_FREE_IDS_START     1
    9895
    99 /** Free identifier numbers pool end.
    100  */
     96/** Free identifier numbers pool end. */
    10197#define ICMP_FREE_IDS_END       UINT16_MAX
    10298
    10399/** 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."
     100 *
     101 * @param[in,out] header The ICMP datagram header.
     102 * @param[in] length    The total datagram length.
     103 * @returns             The computed checksum.
     104 */
     105#define ICMP_CHECKSUM(header, length) \
     106        htons(ip_checksum((uint8_t *) (header), (length)))
     107
     108/** An echo request datagrams pattern. */
     109#define ICMP_ECHO_TEXT          "Hello from HelenOS."
    113110
    114111/** 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);
     112 *
     113 * @param[in] id        The message identifier.
     114 * @param[in] sequence  The message sequence number.
     115 * @returns             The computed ICMP reply data key.
     116 */
     117#define ICMP_GET_REPLY_KEY(id, sequence) \
     118        (((id) << 16) | (sequence & 0xFFFF))
     119
     120
     121/** ICMP global data. */
     122icmp_globals_t  icmp_globals;
     123
     124INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t);
     125INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t);
    171126
    172127/** 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);
     128 *
     129 * @param[in] packet    The packet queue to be released.
     130 * @param[in] result    The result to be returned.
     131 * @returns             The result parameter.
     132 */
     133static int icmp_release_and_return(packet_t packet, int result)
     134{
     135        pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
     136        return result;
     137}
     138
     139/** Sends the ICMP message.
     140 *
     141 * Sets the message type and code and computes the checksum.
     142 * Error messages are sent only if allowed in the configuration.
     143 * Releases the packet on errors.
     144 *
     145 * @param[in] type      The message type.
     146 * @param[in] code      The message code.
     147 * @param[in] packet    The message packet to be sent.
     148 * @param[in] header    The ICMP header.
     149 * @param[in] error     The error service to be announced. Should be
     150 *                      SERVICE_ICMP or zero.
     151 * @param[in] ttl       The time to live.
     152 * @param[in] tos       The type of service.
     153 * @param[in] dont_fragment The value indicating whether the datagram must not
     154 *                      be fragmented. Is used as a MTU discovery.
     155 * @returns             EOK on success.
     156 * @returns             EPERM if the error message is not allowed.
     157 */
     158static int
     159icmp_send_packet(icmp_type_t type, icmp_code_t code, packet_t packet,
     160    icmp_header_ref header, services_t error, ip_ttl_t ttl, ip_tos_t tos,
     161    int dont_fragment)
     162{
     163        ERROR_DECLARE;
     164
     165        // do not send an error if disabled
     166        if (error && !icmp_globals.error_reporting)
     167                return icmp_release_and_return(packet, EPERM);
     168
     169        header->type = type;
     170        header->code = code;
     171        header->checksum = 0;
     172        header->checksum = ICMP_CHECKSUM(header,
     173            packet_get_data_length(packet));
     174        if (ERROR_OCCURRED(ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl,
     175            tos, dont_fragment, 0))) {
     176                return icmp_release_and_return(packet, ERROR_CODE);
     177        }
     178
     179        return ip_send_msg(icmp_globals.ip_phone, -1, packet, SERVICE_ICMP,
     180            error);
     181}
     182
     183/** Prepares the ICMP error packet.
     184 *
     185 * Truncates the original packet if longer than ICMP_KEEP_LENGTH bytes.
     186 * Prefixes and returns the ICMP header.
     187 *
     188 * @param[in,out] packet The original packet.
     189 * @returns The prefixed ICMP header.
     190 * @returns NULL on errors.
     191 */
     192static icmp_header_ref icmp_prepare_packet(packet_t packet)
     193{
     194        icmp_header_ref header;
     195        size_t header_length;
     196        size_t total_length;
     197
     198        total_length = packet_get_data_length(packet);
     199        if (total_length <= 0)
     200                return NULL;
     201
     202        header_length = ip_client_header_length(packet);
     203        if (header_length <= 0)
     204                return NULL;
     205
     206        // truncate if longer than 64 bits (without the IP header)
     207        if ((total_length > header_length + ICMP_KEEP_LENGTH) &&
     208            (packet_trim(packet, 0,
     209            total_length - header_length - ICMP_KEEP_LENGTH) != EOK)) {
     210                return NULL;
     211        }
     212
     213        header = PACKET_PREFIX(packet, icmp_header_t);
     214        if (!header)
     215                return NULL;
     216
     217        bzero(header, sizeof(*header));
     218        return header;
     219}
    178220
    179221/** Requests an echo message.
    180  *  Sends a packet with specified parameters to the target host and waits for the reply upto the given timeout.
    181  *  Blocks the caller until the reply or the timeout occurs.
    182  *  @param[in] id The message identifier.
    183  *  @param[in] sequence The message sequence parameter.
    184  *  @param[in] size The message data length in bytes.
    185  *  @param[in] timeout The timeout in miliseconds.
    186  *  @param[in] ttl The time to live.
    187  *  @param[in] tos The type of service.
    188  *  @param[in] dont_fragment The value indicating whether the datagram must not be fragmented. Is used as a MTU discovery.
    189  *  @param[in] addr The target host address.
    190  *  @param[in] addrlen The torget host address length.
    191  *  @returns ICMP_ECHO on success.
    192  *  @returns ETIMEOUT if the reply has not arrived before the timeout.
    193  *  @returns ICMP type of the received error notification.
    194  *  @returns EINVAL if the addrlen parameter is less or equal to zero (<=0).
    195  *  @returns ENOMEM if there is not enough memory left.
    196  *  @returns EPARTY if there was an internal error.
    197  */
    198 int icmp_echo(icmp_param_t id, icmp_param_t sequence, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen);
    199 
    200 /** Prepares the ICMP error packet.
    201  *  Truncates the original packet if longer than ICMP_KEEP_LENGTH bytes.
    202  *  Prefixes and returns the ICMP header.
    203  *  @param[in,out] packet The original packet.
    204  *  @returns The prefixed ICMP header.
    205  *  @returns NULL on errors.
    206  */
    207 icmp_header_ref icmp_prepare_packet(packet_t packet);
    208 
    209 /** Sends the ICMP message.
    210  *  Sets the message type and code and computes the checksum.
    211  *  Error messages are sent only if allowed in the configuration.
    212  *  Releases the packet on errors.
    213  *  @param[in] type The message type.
    214  *  @param[in] code The message code.
    215  *  @param[in] packet The message packet to be sent.
    216  *  @param[in] header The ICMP header.
    217  *  @param[in] error The error service to be announced. Should be SERVICE_ICMP or zero (0).
    218  *  @param[in] ttl The time to live.
    219  *  @param[in] tos The type of service.
    220  *  @param[in] dont_fragment The value indicating whether the datagram must not be fragmented. Is used as a MTU discovery.
    221  *  @returns EOK on success.
    222  *  @returns EPERM if the error message is not allowed.
    223  */
    224 int icmp_send_packet(icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header, services_t error, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment);
    225 
    226 /** Tries to set the pending reply result as the received message type.
    227  *  If the reply data is not present, the reply timed out and the other fibril
    228  *  is already awake.
    229  *  Releases the packet.
    230  *  @param[in] packet The received reply message.
    231  *  @param[in] header The ICMP message header.
    232  *  @param[in] type The received reply message type.
    233  *  @param[in] code The received reply message code.
    234  *  @returns EOK.
    235  */
    236 int icmp_process_echo_reply(packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code);
    237 
    238 /** Assigns a new identifier for the connection.
    239  *  Fills the echo data parameter with the assigned values.
    240  *  @param[in,out] echo_data The echo data to be bound.
    241  *  @returns Index of the inserted echo data.
    242  *  @returns EBADMEM if the echo_data parameter is NULL.
    243  *  @returns ENOTCONN if no free identifier have been found.
    244  */
    245 int icmp_bind_free_id(icmp_echo_ref echo_data);
    246 
    247 /** ICMP global data.
    248  */
    249 icmp_globals_t  icmp_globals;
    250 
    251 INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t);
    252 
    253 INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t);
    254 
    255 int icmp_echo_msg(int icmp_phone, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen){
    256         icmp_echo_ref echo_data;
    257         int res;
    258 
    259         fibril_rwlock_write_lock(&icmp_globals.lock);
    260         // use the phone as the echo data index
    261         echo_data = icmp_echo_data_find(&icmp_globals.echo_data, icmp_phone);
    262         if(! echo_data){
    263                 res = ENOENT;
    264         }else{
    265                 res = icmp_echo(echo_data->identifier, echo_data->sequence_number, size, timeout, ttl, tos, dont_fragment, addr, addrlen);
    266                 if(echo_data->sequence_number < UINT16_MAX){
    267                         ++ echo_data->sequence_number;
    268                 }else{
    269                         echo_data->sequence_number = 0;
    270                 }
    271         }
    272         fibril_rwlock_write_unlock(&icmp_globals.lock);
    273         return res;
    274 }
    275 
    276 int icmp_echo(icmp_param_t id, icmp_param_t sequence, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen){
     222 *
     223 * Sends a packet with specified parameters to the target host and waits for
     224 * the reply upto the given timeout.
     225 * Blocks the caller until the reply or the timeout occurs.
     226 *
     227 * @param[in] id        The message identifier.
     228 * @param[in] sequence  The message sequence parameter.
     229 * @param[in] size      The message data length in bytes.
     230 * @param[in] timeout   The timeout in miliseconds.
     231 * @param[in] ttl       The time to live.
     232 * @param[in] tos       The type of service.
     233 * @param[in] dont_fragment The value indicating whether the datagram must not
     234 *                      be fragmented. Is used as a MTU discovery.
     235 * @param[in] addr      The target host address.
     236 * @param[in] addrlen   The torget host address length.
     237 * @returns             ICMP_ECHO on success.
     238 * @returns             ETIMEOUT if the reply has not arrived before the
     239 *                      timeout.
     240 * @returns             ICMP type of the received error notification.
     241 * @returns             EINVAL if the addrlen parameter is less or equal to
     242 *                      zero.
     243 * @returns             ENOMEM if there is not enough memory left.
     244 * @returns             EPARTY if there was an internal error.
     245 */
     246static int
     247icmp_echo(icmp_param_t id, icmp_param_t sequence, size_t size,
     248    mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment,
     249    const struct sockaddr * addr, socklen_t addrlen)
     250{
    277251        ERROR_DECLARE;
    278252
     
    280254        packet_t packet;
    281255        size_t length;
    282         uint8_t * data;
     256        uint8_t *data;
    283257        icmp_reply_ref reply;
    284258        int reply_key;
     
    286260        int index;
    287261
    288         if(addrlen <= 0){
     262        if (addrlen <= 0)
    289263                return EINVAL;
    290         }
     264
    291265        length = (size_t) addrlen;
    292266        // 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){
     267        ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1,
     268            &icmp_globals.packet_dimension));
     269
     270        packet = packet_get_4_remote(icmp_globals.net_phone, size,
     271            icmp_globals.packet_dimension.addr_len,
     272            ICMP_HEADER_SIZE + icmp_globals.packet_dimension.prefix,
     273            icmp_globals.packet_dimension.suffix);
     274        if (!packet)
    296275                return ENOMEM;
    297         }
    298276
    299277        // prepare the requesting packet
    300278        // set the destination address
    301         if(ERROR_OCCURRED(packet_set_addr(packet, NULL, (const uint8_t *) addr, length))){
     279        if (ERROR_OCCURRED(packet_set_addr(packet, NULL, (const uint8_t *) addr,
     280            length))) {
    302281                return icmp_release_and_return(packet, ERROR_CODE);
    303282        }
     283
    304284        // allocate space in the packet
    305285        data = (uint8_t *) packet_suffix(packet, size);
    306         if(! data){
     286        if (!data)
    307287                return icmp_release_and_return(packet, ENOMEM);
    308         }
     288
    309289        // fill the data
    310290        length = 0;
    311         while(size > length + sizeof(ICMP_ECHO_TEXT)){
     291        while (size > length + sizeof(ICMP_ECHO_TEXT)) {
    312292                memcpy(data + length, ICMP_ECHO_TEXT, sizeof(ICMP_ECHO_TEXT));
    313293                length += sizeof(ICMP_ECHO_TEXT);
    314294        }
    315295        memcpy(data + length, ICMP_ECHO_TEXT, size - length);
     296
    316297        // prefix the header
    317298        header = PACKET_PREFIX(packet, icmp_header_t);
    318         if(! header){
     299        if (!header)
    319300                return icmp_release_and_return(packet, ENOMEM);
    320         }
     301
    321302        bzero(header, sizeof(*header));
    322303        header->un.echo.identifier = id;
     
    325306        // prepare the reply structure
    326307        reply = malloc(sizeof(*reply));
    327         if(! reply){
     308        if (!reply)
    328309                return icmp_release_and_return(packet, ENOMEM);
    329         }
     310
    330311        fibril_mutex_initialize(&reply->mutex);
    331312        fibril_mutex_lock(&reply->mutex);
    332313        fibril_condvar_initialize(&reply->condvar);
    333         reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier, header->un.echo.sequence_number);
     314        reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier,
     315            header->un.echo.sequence_number);
    334316        index = icmp_replies_add(&icmp_globals.replies, reply_key, reply);
    335         if(index < 0){
     317        if (index < 0) {
    336318                free(reply);
    337319                return icmp_release_and_return(packet, index);
     
    342324
    343325        // send the request
    344         icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos, dont_fragment);
     326        icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos,
     327            dont_fragment);
    345328
    346329        // wait for the reply
    347330        // timeout in microseconds
    348         if(ERROR_OCCURRED(fibril_condvar_wait_timeout(&reply->condvar, &reply->mutex, timeout * 1000))){
     331        if (ERROR_OCCURRED(fibril_condvar_wait_timeout(&reply->condvar,
     332            &reply->mutex, timeout * 1000))) {
    349333                result = ERROR_CODE;
    350         }else{
     334        } else {
    351335                // read the result
    352336                result = reply->result;
     
    359343        // destroy the reply structure
    360344        icmp_replies_exclude_index(&icmp_globals.replies, index);
     345
    361346        return result;
    362347}
    363348
    364 int icmp_destination_unreachable_msg(int icmp_phone, icmp_code_t code, icmp_param_t mtu, packet_t packet){
     349static int
     350icmp_destination_unreachable_msg_local(int icmp_phone, icmp_code_t code,
     351    icmp_param_t mtu, packet_t packet)
     352{
    365353        icmp_header_ref header;
    366354
    367355        header = icmp_prepare_packet(packet);
    368         if(! header){
     356        if (!header)
    369357                return icmp_release_and_return(packet, ENOMEM);
    370         }
    371         if(mtu){
     358
     359        if (mtu)
    372360                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){
     361
     362        return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header,
     363            SERVICE_ICMP, 0, 0, 0);
     364}
     365
     366static int icmp_source_quench_msg_local(int icmp_phone, packet_t packet)
     367{
    378368        icmp_header_ref header;
    379369
    380370        header = icmp_prepare_packet(packet);
    381         if(! header){
     371        if (!header)
    382372                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){
     373
     374        return icmp_send_packet(ICMP_SOURCE_QUENCH, 0, packet, header,
     375            SERVICE_ICMP, 0, 0, 0);
     376}
     377
     378static int
     379icmp_time_exceeded_msg_local(int icmp_phone, icmp_code_t code, packet_t packet)
     380{
    388381        icmp_header_ref header;
    389382
    390383        header = icmp_prepare_packet(packet);
    391         if(! header){
     384        if (!header)
    392385                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){
     386
     387        return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header,
     388            SERVICE_ICMP, 0, 0, 0);
     389}
     390
     391static int
     392icmp_parameter_problem_msg_local(int icmp_phone, icmp_code_t code,
     393    icmp_param_t pointer, packet_t packet)
     394{
    398395        icmp_header_ref header;
    399396
    400397        header = icmp_prepare_packet(packet);
    401         if(! header){
     398        if (!header)
    402399                return icmp_release_and_return(packet, ENOMEM);
    403         }
     400
    404401        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){
     402        return icmp_send_packet(ICMP_PARAMETERPROB, code, packet, header,
     403            SERVICE_ICMP, 0, 0, 0);
     404}
     405
     406/** Initializes the ICMP module.
     407 *
     408 * @param[in] client_connection The client connection processing function. The
     409 *                      module skeleton propagates its own one.
     410 * @returns             EOK on success.
     411 * @returns             ENOMEM if there is not enough memory left.
     412 */
     413int icmp_initialize(async_client_conn_t client_connection)
     414{
    435415        ERROR_DECLARE;
    436416
    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}};
     417        measured_string_t names[] = {
     418                {
     419                        str_dup("ICMP_ERROR_REPORTING"),
     420                        20
     421                },
     422                {
     423                        str_dup("ICMP_ECHO_REPLYING"),
     424                        18
     425                }
     426        };
    455427        measured_string_ref configuration;
    456428        size_t count = sizeof(names) / sizeof(measured_string_t);
    457         char * data;
     429        char *data;
    458430
    459431        fibril_rwlock_initialize(&icmp_globals.lock);
     
    461433        icmp_replies_initialize(&icmp_globals.replies);
    462434        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){
     435        icmp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_ICMP,
     436            SERVICE_ICMP, client_connection);
     437        if (icmp_globals.ip_phone < 0)
    465438                return icmp_globals.ip_phone;
    466         }
    467         ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1, &icmp_globals.packet_dimension));
     439
     440        ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1,
     441            &icmp_globals.packet_dimension));
    468442        icmp_globals.packet_dimension.prefix += ICMP_HEADER_SIZE;
    469443        icmp_globals.packet_dimension.content -= ICMP_HEADER_SIZE;
    470         // get configuration
     444
    471445        icmp_globals.error_reporting = NET_DEFAULT_ICMP_ERROR_REPORTING;
    472446        icmp_globals.echo_replying = NET_DEFAULT_ICMP_ECHO_REPLYING;
     447
     448        // get configuration
    473449        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');
     450        ERROR_PROPAGATE(net_get_conf_req(icmp_globals.net_phone, &configuration,
     451            count, &data));
     452        if (configuration) {
     453                if (configuration[0].value) {
     454                        icmp_globals.error_reporting =
     455                            (configuration[0].value[0] == 'y');
     456                }
     457                if (configuration[1].value) {
     458                        icmp_globals.echo_replying =
     459                            (configuration[1].value[0] == 'y');
    481460                }
    482461                net_free_settings(configuration, data);
    483462        }
     463
    484464        fibril_rwlock_write_unlock(&icmp_globals.lock);
    485465        return EOK;
    486466}
    487467
    488 int icmp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error){
     468/** Tries to set the pending reply result as the received message type.
     469 *
     470 * If the reply data is not present, the reply timed out and the other fibril
     471 * is already awake.
     472 * Releases the packet.
     473 *
     474 * @param[in] packet    The received reply message.
     475 * @param[in] header    The ICMP message header.
     476 * @param[in] type      The received reply message type.
     477 * @param[in] code      The received reply message code.
     478 */
     479static void
     480icmp_process_echo_reply(packet_t packet, icmp_header_ref header,
     481    icmp_type_t type, icmp_code_t code)
     482{
     483        int reply_key;
     484        icmp_reply_ref reply;
     485
     486        // compute the reply key
     487        reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier,
     488            header->un.echo.sequence_number);
     489        pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
     490
     491        fibril_rwlock_write_lock(&icmp_globals.lock);
     492        // find the pending reply
     493        reply = icmp_replies_find(&icmp_globals.replies, reply_key);
     494        if (reply) {
     495                reply->result = type;
     496                fibril_condvar_signal(&reply->condvar);
     497        }
     498        fibril_rwlock_write_unlock(&icmp_globals.lock);
     499}
     500
     501/** Processes the received ICMP packet.
     502 *
     503 * Notifies the destination socket application.
     504 *
     505 * @param[in,out] packet The received packet.
     506 * @param[in] error     The packet error reporting service. Prefixes the
     507 *                      received packet.
     508 * @returns             EOK on success.
     509 * @returns             EINVAL if the packet is not valid.
     510 * @returns             EINVAL if the stored packet address is not the an_addr_t.
     511 * @returns             EINVAL if the packet does not contain any data.
     512 * @returns             NO_DATA if the packet content is shorter than the user
     513 *                      datagram header.
     514 * @returns             ENOMEM if there is not enough memory left.
     515 * @returns             EADDRNOTAVAIL if the destination socket does not exist.
     516 * @returns             Other error codes as defined for the
     517 *                      ip_client_process_packet() function.
     518 */
     519static int icmp_process_packet(packet_t packet, services_t error)
     520{
    489521        ERROR_DECLARE;
    490522
    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 
    501523        size_t length;
    502         uint8_t * src;
     524        uint8_t *src;
    503525        int addrlen;
    504526        int result;
    505         void * data;
     527        void *data;
    506528        icmp_header_ref header;
    507529        icmp_type_t type;
    508530        icmp_code_t code;
    509531
    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         }
     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                ERROR_PROPAGATE(packet_trim(packet, length, 0));
     544                break;
     545        default:
     546                return ENOTSUP;
     547        }
     548
    526549        // get rid of the ip header
    527550        length = ip_client_header_length(packet);
     
    529552
    530553        length = packet_get_data_length(packet);
    531         if(length <= 0){
     554        if (length <= 0)
    532555                return EINVAL;
    533         }
    534         if(length < ICMP_HEADER_SIZE){
     556
     557        if (length < ICMP_HEADER_SIZE)
    535558                return EINVAL;
    536         }
     559
    537560        data = packet_get_data(packet);
    538         if(! data){
     561        if (!data)
    539562                return EINVAL;
    540         }
     563
    541564        // get icmp header
    542565        header = (icmp_header_ref) data;
    543         // checksum
    544         if(header->checksum){
    545                 while(ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO){
     566
     567        if (header->checksum) {
     568                while (ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO) {
    546569                        // set the original message type on error notification
    547570                        // type swap observed in Qemu
    548                         if(error){
    549                                 switch(header->type){
    550                                         case ICMP_ECHOREPLY:
    551                                                 header->type = ICMP_ECHO;
    552                                                 continue;
     571                        if (error) {
     572                                switch (header->type) {
     573                                case ICMP_ECHOREPLY:
     574                                        header->type = ICMP_ECHO;
     575                                        continue;
    553576                                }
    554577                        }
     
    556579                }
    557580        }
    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);
     581
     582        switch (header->type) {
     583        case ICMP_ECHOREPLY:
     584                if (error)
     585                        icmp_process_echo_reply(packet, header, type, code);
     586                else
     587                        icmp_process_echo_reply(packet, header, ICMP_ECHO, 0);
     588
     589                return EOK;
     590
     591        case ICMP_ECHO:
     592                if (error) {
     593                        icmp_process_echo_reply(packet, header, type, code);
     594                        return EOK;
     595                }
     596               
     597                // do not send a reply if disabled
     598                if (icmp_globals.echo_replying) {
     599                        addrlen = packet_get_addr(packet, &src, NULL);
     600
     601                        // set both addresses to the source one (avoids the
     602                        // source address deletion before setting the
     603                        // destination one)
     604                        if ((addrlen > 0) && (packet_set_addr(packet, src, src,
     605                            (size_t) addrlen) == EOK)) {
     606                                // send the reply
     607                                icmp_send_packet(ICMP_ECHOREPLY, 0, packet,
     608                                    header, 0, 0, 0, 0);
     609                                return EOK;
    564610                        }
    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;
     611
     612                        return EINVAL;
     613                }
     614
     615                return EPERM;
     616
     617        case ICMP_DEST_UNREACH:
     618        case ICMP_SOURCE_QUENCH:
     619        case ICMP_REDIRECT:
     620        case ICMP_ALTERNATE_ADDR:
     621        case ICMP_ROUTER_ADV:
     622        case ICMP_ROUTER_SOL:
     623        case ICMP_TIME_EXCEEDED:
     624        case ICMP_PARAMETERPROB:
     625        case ICMP_CONVERSION_ERROR:
     626        case ICMP_REDIRECT_MOBILE:
     627        case ICMP_SKIP:
     628        case ICMP_PHOTURIS:
     629                ip_received_error_msg(icmp_globals.ip_phone, -1, packet,
     630                    SERVICE_IP, SERVICE_ICMP);
     631                return EOK;
     632
     633        default:
     634                return ENOTSUP;
     635        }
     636}
     637
     638/** Processes the received ICMP packet.
     639 *
     640 * Is used as an entry point from the underlying IP module.
     641 * Releases the packet on error.
     642 *
     643 * @param device_id     The device identifier. Ignored parameter.
     644 * @param[in,out] packet The received packet.
     645 * @param receiver      The target service. Ignored parameter.
     646 * @param[in] error     The packet error reporting service. Prefixes the
     647 *                      received packet.
     648 * @returns             EOK on success.
     649 * @returns             Other error codes as defined for the
     650 *                      icmp_process_packet() function.
     651 */
     652static int
     653icmp_received_msg_local(device_id_t device_id, packet_t packet,
     654    services_t receiver, services_t error)
     655{
     656        ERROR_DECLARE;
     657
     658        if (ERROR_OCCURRED(icmp_process_packet(packet, error)))
     659                return icmp_release_and_return(packet, ERROR_CODE);
     660
     661        return EOK;
     662}
     663
     664/** Processes the generic client messages.
     665 *
     666 * @param[in] call      The message parameters.
     667 * @returns             EOK on success.
     668 * @returns             ENOTSUP if the message is not known.
     669 * @returns             Other error codes as defined for the packet_translate()
     670 *                      function.
     671 * @returns             Other error codes as defined for the
     672 *                      icmp_destination_unreachable_msg_local() function.
     673 * @returns             Other error codes as defined for the
     674 *                      icmp_source_quench_msg_local() function.
     675 * @returns             Other error codes as defined for the
     676 *                      icmp_time_exceeded_msg_local() function.
     677 * @returns             Other error codes as defined for the
     678 *                      icmp_parameter_problem_msg_local() function.
     679 *
     680 * @see icmp_interface.h
     681 */
     682static int icmp_process_message(ipc_call_t *call)
     683{
     684        ERROR_DECLARE;
     685
     686        packet_t packet;
     687
     688        switch (IPC_GET_METHOD(*call)) {
     689        case NET_ICMP_DEST_UNREACH:
     690                if (ERROR_NONE(packet_translate_remote(icmp_globals.net_phone,
     691                    &packet, IPC_GET_PACKET(call)))) {
     692                        ERROR_CODE = icmp_destination_unreachable_msg_local(0,
     693                            ICMP_GET_CODE(call), ICMP_GET_MTU(call), packet);
     694                }
     695                return ERROR_CODE;
     696        case NET_ICMP_SOURCE_QUENCH:
     697                if (ERROR_NONE(packet_translate_remote(icmp_globals.net_phone,
     698                    &packet, IPC_GET_PACKET(call)))) {
     699                        ERROR_CODE = icmp_source_quench_msg_local(0, packet);
     700                }
     701                return ERROR_CODE;
     702        case NET_ICMP_TIME_EXCEEDED:
     703                if (ERROR_NONE(packet_translate_remote(icmp_globals.net_phone,
     704                    &packet, IPC_GET_PACKET(call)))) {
     705                        ERROR_CODE = icmp_time_exceeded_msg_local(0,
     706                            ICMP_GET_CODE(call), packet);
     707                }
     708                return ERROR_CODE;
     709        case NET_ICMP_PARAMETERPROB:
     710                if (ERROR_NONE(packet_translate_remote(icmp_globals.net_phone,
     711                    &packet, IPC_GET_PACKET(call)))) {
     712                        ERROR_CODE = icmp_parameter_problem_msg_local(0,
     713                            ICMP_GET_CODE(call), ICMP_GET_POINTER(call),
     714                            packet);
     715                }
     716                return ERROR_CODE;
     717        default:
     718                return ENOTSUP;
     719        }
     720}
     721
     722/** Assigns a new identifier for the connection.
     723 *
     724 * Fills the echo data parameter with the assigned values.
     725 *
     726 * @param[in,out] echo_data The echo data to be bound.
     727 * @returns             Index of the inserted echo data.
     728 * @returns             EBADMEM if the echo_data parameter is NULL.
     729 * @returns             ENOTCONN if no free identifier have been found.
     730 */
     731static int icmp_bind_free_id(icmp_echo_ref echo_data)
     732{
     733        icmp_param_t index;
     734
     735        if (!echo_data)
     736                return EBADMEM;
     737
     738        // from the last used one
     739        index = icmp_globals.last_used_id;
     740        do {
     741                index++;
     742                // til the range end
     743                if (index >= ICMP_FREE_IDS_END) {
     744                        // start from the range beginning
     745                        index = ICMP_FREE_IDS_START - 1;
     746                        do {
     747                                index++;
     748                                // til the last used one
     749                                if (index >= icmp_globals.last_used_id) {
     750                                        // none found
     751                                        return ENOTCONN;
    579752                                }
    580                         }else{
    581                                 return EPERM;
    582                         }
    583                 case ICMP_DEST_UNREACH:
    584                 case ICMP_SOURCE_QUENCH:
    585                 case ICMP_REDIRECT:
    586                 case ICMP_ALTERNATE_ADDR:
    587                 case ICMP_ROUTER_ADV:
    588                 case ICMP_ROUTER_SOL:
    589                 case ICMP_TIME_EXCEEDED:
    590                 case ICMP_PARAMETERPROB:
    591                 case ICMP_CONVERSION_ERROR:
    592                 case ICMP_REDIRECT_MOBILE:
    593                 case ICMP_SKIP:
    594                 case ICMP_PHOTURIS:
    595                         ip_received_error_msg(icmp_globals.ip_phone, -1, packet, SERVICE_IP, SERVICE_ICMP);
    596                         return EOK;
    597                 default:
    598                         return ENOTSUP;
    599         }
    600 }
    601 
    602 int icmp_process_echo_reply(packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code){
    603         int reply_key;
    604         icmp_reply_ref reply;
    605 
    606         // compute the reply key
    607         reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier, header->un.echo.sequence_number);
    608         pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
    609         // lock the globals
    610         fibril_rwlock_write_lock(&icmp_globals.lock);
    611         // find the pending reply
    612         reply = icmp_replies_find(&icmp_globals.replies, reply_key);
    613         if(reply){
    614                 // set the result
    615                 reply->result = type;
    616                 // notify the waiting fibril
    617                 fibril_condvar_signal(&reply->condvar);
    618         }
    619         fibril_rwlock_write_unlock(&icmp_globals.lock);
    620         return EOK;
    621 }
    622 
    623 int icmp_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
     753                        } while(icmp_echo_data_find(&icmp_globals.echo_data,
     754                            index) != NULL);
     755
     756                        // found, break immediately
     757                        break;
     758                }
     759        } while(icmp_echo_data_find(&icmp_globals.echo_data, index) != NULL);
     760
     761        echo_data->identifier = index;
     762        echo_data->sequence_number = 0;
     763
     764        return icmp_echo_data_add(&icmp_globals.echo_data, index, echo_data);
     765}
     766
     767/** Processes the client messages.
     768 *
     769 * Remembers the assigned identifier and sequence numbers.
     770 * Runs until the client module disconnects.
     771 *
     772 * @param[in] callid    The message identifier.
     773 * @param[in] call      The message parameters.
     774 * @returns EOK.
     775 *
     776 * @see icmp_interface.h
     777 * @see icmp_api.h
     778 */
     779static int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
     780{
    624781        ERROR_DECLARE;
    625782
    626         packet_t packet;
    627 
    628         *answer_count = 0;
    629         switch(IPC_GET_METHOD(*call)){
    630                 case NET_TL_RECEIVED:
    631                         if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
    632                                 ERROR_CODE = icmp_received_msg(IPC_GET_DEVICE(call), packet, SERVICE_ICMP, IPC_GET_ERROR(call));
    633                         }
    634                         return ERROR_CODE;
    635                 case NET_ICMP_INIT:
    636                         return icmp_process_client_messages(callid, * call);
    637                 default:
    638                         return icmp_process_message(call);
    639         }
    640         return ENOTSUP;
    641 }
    642 
    643 int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call){
    644         ERROR_DECLARE;
    645 
    646783        bool keep_on_going = true;
    647 //      fibril_rwlock_t                 lock;
    648784        ipc_call_t answer;
    649785        int answer_count;
    650786        size_t length;
    651         struct sockaddr * addr;
     787        struct sockaddr *addr;
    652788        ipc_callid_t data_callid;
    653789        icmp_echo_ref echo_data;
     
    661797        answer_count = 0;
    662798
    663 //      fibril_rwlock_initialize(&lock);
    664 
    665799        echo_data = (icmp_echo_ref) malloc(sizeof(*echo_data));
    666         if(! echo_data){
     800        if (!echo_data)
    667801                return ENOMEM;
    668         }
    669802
    670803        // assign a new identifier
     
    672805        res = icmp_bind_free_id(echo_data);
    673806        fibril_rwlock_write_unlock(&icmp_globals.lock);
    674         if(res < 0){
     807        if (res < 0) {
    675808                free(echo_data);
    676809                return res;
    677810        }
    678811
    679         while(keep_on_going){
    680 
     812        while (keep_on_going) {
    681813                // answer the call
    682814                answer_call(callid, res, &answer, answer_count);
     
    689821
    690822                // process the call
    691                 switch(IPC_GET_METHOD(call)){
    692                         case IPC_M_PHONE_HUNGUP:
    693                                 keep_on_going = false;
    694                                 res = EHANGUP;
     823                switch (IPC_GET_METHOD(call)) {
     824                case IPC_M_PHONE_HUNGUP:
     825                        keep_on_going = false;
     826                        res = EHANGUP;
     827                        break;
     828               
     829                case NET_ICMP_ECHO:
     830                        if (!async_data_write_receive(&data_callid, &length)) {
     831                                res = EINVAL;
    695832                                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);
     833                        }
     834                       
     835                        addr = malloc(length);
     836                        if (!addr) {
     837                                res = ENOMEM;
    721838                                break;
    722                         default:
    723                                 res = icmp_process_message(&call);
    724                 }
     839                        }
     840                       
     841                        if (ERROR_OCCURRED(async_data_write_finalize(
     842                            data_callid, addr, length))) {
     843                                free(addr);
     844                                res = ERROR_CODE;
     845                                break;
     846                        }
     847
     848                        fibril_rwlock_write_lock(&icmp_globals.lock);
     849                        res = icmp_echo(echo_data->identifier,
     850                            echo_data->sequence_number, ICMP_GET_SIZE(call),
     851                            ICMP_GET_TIMEOUT(call), ICMP_GET_TTL(call),
     852                            ICMP_GET_TOS(call), ICMP_GET_DONT_FRAGMENT(call),
     853                            addr, (socklen_t) length);
     854                        fibril_rwlock_write_unlock(&icmp_globals.lock);
     855
     856                        free(addr);
     857
     858                        if (echo_data->sequence_number < UINT16_MAX)
     859                                echo_data->sequence_number++;
     860                        else
     861                                echo_data->sequence_number = 0;
     862
     863                        break;
     864
     865                default:
     866                        res = icmp_process_message(&call);
     867                }
     868
    725869        }
    726870
     
    729873        icmp_echo_data_exclude(&icmp_globals.echo_data, echo_data->identifier);
    730874        fibril_rwlock_write_unlock(&icmp_globals.lock);
     875
    731876        return res;
    732877}
    733878
    734 int icmp_process_message(ipc_call_t * call){
     879/** Processes the ICMP message.
     880 *
     881 * @param[in] callid    The message identifier.
     882 * @param[in] call      The message parameters.
     883 * @param[out] answer   The message answer parameters.
     884 * @param[out] answer_count The last parameter for the actual answer in the
     885 *                      answer parameter.
     886 * @returns             EOK on success.
     887 * @returns             ENOTSUP if the message is not known.
     888 *
     889 * @see icmp_interface.h
     890 * @see IS_NET_ICMP_MESSAGE()
     891 */
     892int
     893icmp_message_standalone(ipc_callid_t callid, ipc_call_t *call,
     894    ipc_call_t *answer, int *answer_count)
     895{
    735896        ERROR_DECLARE;
    736897
    737898        packet_t packet;
    738899
    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 }
     900        *answer_count = 0;
     901        switch (IPC_GET_METHOD(*call)) {
     902        case NET_TL_RECEIVED:
     903                if (ERROR_NONE(packet_translate_remote(icmp_globals.net_phone,
     904                    &packet, IPC_GET_PACKET(call)))) {
     905                        ERROR_CODE =
     906                            icmp_received_msg_local(IPC_GET_DEVICE(call),
     907                            packet, SERVICE_ICMP, IPC_GET_ERROR(call));
     908                }
     909                return ERROR_CODE;
     910       
     911        case NET_ICMP_INIT:
     912                return icmp_process_client_messages(callid, * call);
     913       
     914        default:
     915                return icmp_process_message(call);
     916        }
     917
     918        return ENOTSUP;
     919}
     920
    800921
    801922/** Default thread for new connections.
    802923 *
    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)
     924 * @param[in] iid The initial message identifier.
     925 * @param[in] icall The initial message call structure.
     926 *
     927 */
     928static void tl_client_connection(ipc_callid_t iid, ipc_call_t *icall)
    808929{
    809930        /*
     
    813934        ipc_answer_0(iid, EOK);
    814935       
    815         while(true) {
     936        while (true) {
    816937                ipc_call_t answer;
    817938                int answer_count;
     
    828949                    &answer_count);
    829950               
    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))
     951                /*
     952                 * End if told to either by the message or the processing
     953                 * result.
     954                 */
     955                if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) ||
     956                    (res == EHANGUP))
    832957                        return;
    833958               
     
    839964/** Starts the module.
    840965 *
    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  *
     966 * @returns             EOK on success.
     967 * @returns             Other error codes as defined for each specific module
     968 *                      start function.
    847969 */
    848970int main(int argc, char *argv[])
     
    851973       
    852974        /* Start the module */
    853         if (ERROR_OCCURRED(tl_module_start_standalone(tl_client_connection)))
    854                 return ERROR_CODE;
    855        
     975        ERROR_PROPAGATE(tl_module_start_standalone(tl_client_connection));
    856976        return EOK;
    857977}
     
    859979/** @}
    860980 */
     981
  • uspace/srv/net/tl/icmp/icmp.h

    r940bb45 redc5a985  
    2828
    2929/** @addtogroup icmp
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  ICMP module.
     34 * ICMP module.
    3535 */
    3636
    37 #ifndef __NET_ICMP_H__
    38 #define __NET_ICMP_H__
     37#ifndef NET_ICMP_H_
     38#define NET_ICMP_H_
    3939
    4040#include <fibril_synch.h>
    4141
    4242#include <net/icmp_codes.h>
     43#include <net/packet.h>
    4344#include <adt/int_map.h>
    4445#include <icmp_header.h>
    4546
    4647/** Type definition of the ICMP reply data.
    47  *  @see icmp_reply
     48 * @see icmp_reply
    4849 */
    49 typedef struct icmp_reply       icmp_reply_t;
     50typedef struct icmp_reply icmp_reply_t;
    5051
    5152/** Type definition of the ICMP reply data pointer.
    52  *  @see icmp_reply
     53 * @see icmp_reply
    5354 */
    54 typedef icmp_reply_t *  icmp_reply_ref;
     55typedef icmp_reply_t *icmp_reply_ref;
    5556
    5657/** Type definition of the ICMP global data.
    57  *  @see icmp_globals
     58 * @see icmp_globals
    5859 */
    59 typedef struct icmp_globals     icmp_globals_t;
     60typedef struct icmp_globals icmp_globals_t;
    6061
    6162/** Pending replies map.
    62  *  Maps message identifiers to the pending replies.
    63  *  Sending fibril waits for its associated reply event.
    64  *  Receiving fibril sets the associated reply with the return value and signals the event.
     63 *
     64 * Maps message identifiers to the pending replies.
     65 * Sending fibril waits for its associated reply event.
     66 * Receiving fibril sets the associated reply with the return value and signals
     67 * the event.
    6568 */
    6669INT_MAP_DECLARE(icmp_replies, icmp_reply_t);
    6770
    6871/** Echo specific data map.
    69  *  The identifier is used in the future semi-remote calls instead of the ICMP phone.
     72 *
     73 * The identifier is used in the future semi-remote calls instead of the ICMP
     74 * phone.
    7075 */
    7176INT_MAP_DECLARE(icmp_echo_data, icmp_echo_t);
    7277
    73 /** ICMP reply data.
    74  */
    75 struct icmp_reply{
    76         /** Reply result.
    77          */
     78/** ICMP reply data. */
     79struct icmp_reply {
     80        /** Reply result. */
    7881        int result;
    79         /** Safety lock.
    80          */
     82        /** Safety lock. */
    8183        fibril_mutex_t mutex;
    82         /** Received or timeouted reply signaling.
    83          */
     84        /** Received or timeouted reply signaling. */
    8485        fibril_condvar_t condvar;
    8586};
    8687
    87 /** ICMP global data.
    88  */
    89 struct  icmp_globals{
    90         /** IP module phone.
    91          */
     88/** ICMP global data. */
     89struct icmp_globals {
     90        /** IP module phone. */
    9291        int ip_phone;
    93         /** Packet dimension.
    94          */
     92        /** Packet dimension. */
    9593        packet_dimension_t packet_dimension;
    96         /** Networking module phone.
    97          */
     94        /** Networking module phone. */
    9895        int net_phone;
    99         /** Indicates whether ICMP error reporting is enabled.
    100          */
     96        /** Indicates whether ICMP error reporting is enabled. */
    10197        int error_reporting;
    102         /** Indicates whether ICMP echo replying (ping) is enabled.
    103          */
     98        /** Indicates whether ICMP echo replying (ping) is enabled. */
    10499        int echo_replying;
    105         /** The last used identifier number.
    106          */
     100        /** The last used identifier number. */
    107101        icmp_param_t last_used_id;
    108         /** The budled modules assigned echo specific data.
    109          */
     102        /** The budled modules assigned echo specific data. */
    110103        icmp_echo_data_t echo_data;
    111         /** Echo timeout locks.
    112          */
     104        /** Echo timeout locks. */
    113105        icmp_replies_t replies;
    114         /** Safety lock.
    115          */
     106        /** Safety lock. */
    116107        fibril_rwlock_t lock;
    117108};
     
    121112/** @}
    122113 */
    123 
  • uspace/srv/net/tl/icmp/icmp_module.c

    r940bb45 redc5a985  
    2828
    2929/** @addtogroup icmp
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  ICMP standalone module implementation.
    35  *  Contains skeleton module functions mapping.
    36  *  The functions are used by the module skeleton as module specific entry points.
    37  *  @see module.c
     34 * ICMP standalone module implementation.
     35 * Contains skeleton module functions mapping.
     36 * The functions are used by the module skeleton as module specific entry points.
     37 * @see module.c
    3838 */
     39
     40#include "icmp.h"
     41#include "icmp_module.h"
    3942
    4043#include <async.h>
     
    4750#include <net/packet.h>
    4851#include <net_interface.h>
     52
    4953#include <tl_local.h>
    5054
    51 #include "icmp.h"
    52 #include "icmp_module.h"
     55/** ICMP module global data. */
     56extern icmp_globals_t icmp_globals;
    5357
    54 /** ICMP module global data.
    55  */
    56 extern icmp_globals_t   icmp_globals;
    57 
    58 /** Starts the ICMP module.
    59  *  Initializes the client connection serving function, initializes the module, registers the module service and starts the async manager, processing IPC messages in an infinite loop.
    60  *  @param[in] client_connection The client connection processing function. The module skeleton propagates its own one.
    61  *  @returns EOK on successful module termination.
    62  *  @returns Other error codes as defined for the arp_initialize() function.
    63  *  @returns Other error codes as defined for the REGISTER_ME() macro function.
    64  */
    65 int tl_module_start_standalone(async_client_conn_t client_connection){
     58int tl_module_start_standalone(async_client_conn_t client_connection)
     59{
    6660        ERROR_DECLARE;
    6761
     
    7064        async_set_client_connection(client_connection);
    7165        icmp_globals.net_phone = net_connect_module();
    72         if(icmp_globals.net_phone < 0){
     66        if (icmp_globals.net_phone < 0)
    7367                return icmp_globals.net_phone;
    74         }
     68
    7569        ERROR_PROPAGATE(pm_init());
    76         if(ERROR_OCCURRED(icmp_initialize(client_connection))
    77                 || ERROR_OCCURRED(REGISTER_ME(SERVICE_ICMP, &phonehash))){
     70        if (ERROR_OCCURRED(icmp_initialize(client_connection)) ||
     71            ERROR_OCCURRED(REGISTER_ME(SERVICE_ICMP, &phonehash))) {
    7872                pm_destroy();
    7973                return ERROR_CODE;
     
    8680}
    8781
    88 /** Processes the ICMP message.
    89  *  @param[in] callid The message identifier.
    90  *  @param[in] call The message parameters.
    91  *  @param[out] answer The message answer parameters.
    92  *  @param[out] answer_count The last parameter for the actual answer in the answer parameter.
    93  *  @returns EOK on success.
    94  *  @returns Other error codes as defined for the icmp_message() function.
    95  */
    96 int tl_module_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
     82int
     83tl_module_message_standalone(ipc_callid_t callid, ipc_call_t *call,
     84    ipc_call_t *answer, int *answer_count)
     85{
    9786        return icmp_message_standalone(callid, call, answer, answer_count);
    9887}
     
    10089/** @}
    10190 */
     91
  • uspace/srv/net/tl/icmp/icmp_module.h

    r940bb45 redc5a985  
    2828
    2929/** @addtogroup icmp
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  ICMP module functions.
    35  *  The functions are used as ICMP module entry points.
     34 * ICMP module functions.
     35 * The functions are used as ICMP module entry points.
    3636 */
    3737
    38 #ifndef __NET_ICMP_MODULE_H__
    39 #define __NET_ICMP_MODULE_H__
     38#ifndef NET_ICMP_MODULE_H_
     39#define NET_ICMP_MODULE_H_
    4040
    4141#include <async.h>
    4242#include <ipc/ipc.h>
    4343
    44 /** Initializes the ICMP module.
    45  *  @param[in] client_connection The client connection processing function. The module skeleton propagates its own one.
    46  *  @returns EOK on success.
    47  *  @returns ENOMEM if there is not enough memory left.
    48  */
    49 int icmp_initialize(async_client_conn_t client_connection);
    50 
    51 /** Processes the ICMP message.
    52  *  @param[in] callid The message identifier.
    53  *  @param[in] call The message parameters.
    54  *  @param[out] answer The message answer parameters.
    55  *  @param[out] answer_count The last parameter for the actual answer in the answer parameter.
    56  *  @returns EOK on success.
    57  *  @returns ENOTSUP if the message is not known.
    58  *  @see icmp_interface.h
    59  *  @see IS_NET_ICMP_MESSAGE()
    60  */
    61 int icmp_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count);
     44extern int icmp_initialize(async_client_conn_t);
     45extern int icmp_message_standalone(ipc_callid_t, ipc_call_t *, ipc_call_t *,
     46    int *);
    6247
    6348#endif
Note: See TracChangeset for help on using the changeset viewer.