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


Ignore:
Timestamp:
2011-05-12T16:49:44Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f36787d7
Parents:
e80329d6 (diff), 750636a (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified uspace/srv/net/tl/udp/udp.c

    re80329d6 rb5e68c8  
    2828
    2929/** @addtogroup udp
    30  *  @{
     30 * @{
    3131 */
    3232
    3333/** @file
    34  *  UDP module implementation.
    35  *  @see udp.h
     34 * UDP module implementation.
     35 * @see udp.h
    3636 */
    3737
     
    4040#include <malloc.h>
    4141#include <stdio.h>
    42 #include <ipc/ipc.h>
    4342#include <ipc/services.h>
    4443#include <ipc/net.h>
    4544#include <ipc/tl.h>
    4645#include <ipc/socket.h>
     46#include <adt/dynamic_fifo.h>
    4747#include <errno.h>
    48 #include <err.h>
    4948
    5049#include <net/socket_codes.h>
     
    5554#include <net/modules.h>
    5655
    57 #include <adt/dynamic_fifo.h>
    5856#include <packet_client.h>
    5957#include <packet_remote.h>
     
    6260#include <ip_interface.h>
    6361#include <icmp_client.h>
    64 #include <icmp_interface.h>
     62#include <icmp_remote.h>
    6563#include <net_interface.h>
    6664#include <socket_core.h>
    6765#include <tl_common.h>
    68 #include <tl_local.h>
    69 #include <tl_interface.h>
     66#include <tl_remote.h>
     67#include <tl_skel.h>
    7068
    7169#include "udp.h"
    7270#include "udp_header.h"
    73 #include "udp_module.h"
    7471
    7572/** UDP module name. */
    76 #define NAME    "UDP protocol"
     73#define NAME  "udp"
    7774
    7875/** Default UDP checksum computing. */
     
    9188#define UDP_FREE_PORTS_END              65535
    9289
     90/** UDP global data.  */
     91udp_globals_t udp_globals;
     92
     93/** Releases the packet and returns the result.
     94 *
     95 * @param[in] packet    The packet queue to be released.
     96 * @param[in] result    The result to be returned.
     97 * @return              The result parameter.
     98 */
     99static int udp_release_and_return(packet_t *packet, int result)
     100{
     101        pq_release_remote(udp_globals.net_phone, packet_get_id(packet));
     102        return result;
     103}
     104
    93105/** Processes the received UDP packet queue.
    94106 *
    95  *  Is used as an entry point from the underlying IP module.
    96  *  Locks the global lock and calls udp_process_packet() function.
    97  *
    98  *  @param[in] device_id The receiving device identifier.
    99  *  @param[in,out] packet The received packet queue.
    100  *  @param receiver     The target service. Ignored parameter.
    101  *  @param[in] error    The packet error reporting service. Prefixes the
     107 * Notifies the destination socket application.
     108 * Releases the packet on error or sends an ICMP error notification.
     109 *
     110 * @param[in] device_id The receiving device identifier.
     111 * @param[in,out] packet The received packet queue.
     112 * @param[in] error     The packet error reporting service. Prefixes the
    102113 *                      received packet.
    103  *  @returns            EOK on success.
    104  *  @returns            Other error codes as defined for the
     114 * @return              EOK on success.
     115 * @return              EINVAL if the packet is not valid.
     116 * @return              EINVAL if the stored packet address is not the
     117 *                      an_addr_t.
     118 * @return              EINVAL if the packet does not contain any data.
     119 * @return              NO_DATA if the packet content is shorter than the user
     120 *                      datagram header.
     121 * @return              ENOMEM if there is not enough memory left.
     122 * @return              EADDRNOTAVAIL if the destination socket does not exist.
     123 * @return              Other error codes as defined for the
     124 *                      ip_client_process_packet() function.
     125 */
     126static int udp_process_packet(device_id_t device_id, packet_t *packet,
     127    services_t error)
     128{
     129        size_t length;
     130        size_t offset;
     131        int result;
     132        udp_header_t *header;
     133        socket_core_t *socket;
     134        packet_t *next_packet;
     135        size_t total_length;
     136        uint32_t checksum;
     137        int fragments;
     138        packet_t *tmp_packet;
     139        icmp_type_t type;
     140        icmp_code_t code;
     141        void *ip_header;
     142        struct sockaddr *src;
     143        struct sockaddr *dest;
     144        packet_dimension_t *packet_dimension;
     145        int rc;
     146
     147        switch (error) {
     148        case SERVICE_NONE:
     149                break;
     150        case SERVICE_ICMP:
     151                /* Ignore error */
     152                // length = icmp_client_header_length(packet);
     153
     154                /* Process error */
     155                result = icmp_client_process_packet(packet, &type,
     156                    &code, NULL, NULL);
     157                if (result < 0)
     158                        return udp_release_and_return(packet, result);
     159                length = (size_t) result;
     160                rc = packet_trim(packet, length, 0);
     161                if (rc != EOK)
     162                        return udp_release_and_return(packet, rc);
     163                break;
     164        default:
     165                return udp_release_and_return(packet, ENOTSUP);
     166        }
     167
     168        /* TODO process received ipopts? */
     169        result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
     170        if (result < 0)
     171                return udp_release_and_return(packet, result);
     172        offset = (size_t) result;
     173
     174        length = packet_get_data_length(packet);
     175        if (length <= 0)
     176                return udp_release_and_return(packet, EINVAL);
     177        if (length < UDP_HEADER_SIZE + offset)
     178                return udp_release_and_return(packet, NO_DATA);
     179
     180        /* Trim all but UDP header */
     181        rc = packet_trim(packet, offset, 0);
     182        if (rc != EOK)
     183                return udp_release_and_return(packet, rc);
     184
     185        /* Get UDP header */
     186        header = (udp_header_t *) packet_get_data(packet);
     187        if (!header)
     188                return udp_release_and_return(packet, NO_DATA);
     189
     190        /* Find the destination socket */
     191        socket = socket_port_find(&udp_globals.sockets,
     192            ntohs(header->destination_port), (uint8_t *) SOCKET_MAP_KEY_LISTENING, 0);
     193        if (!socket) {
     194                if (tl_prepare_icmp_packet(udp_globals.net_phone,
     195                    udp_globals.icmp_phone, packet, error) == EOK) {
     196                        icmp_destination_unreachable_msg(udp_globals.icmp_phone,
     197                            ICMP_PORT_UNREACH, 0, packet);
     198                }
     199                return EADDRNOTAVAIL;
     200        }
     201
     202        /* Count the received packet fragments */
     203        next_packet = packet;
     204        fragments = 0;
     205        total_length = ntohs(header->total_length);
     206
     207        /* Compute header checksum if set */
     208        if (header->checksum && !error) {
     209                result = packet_get_addr(packet, (uint8_t **) &src,
     210                    (uint8_t **) &dest);
     211                if (result <= 0)
     212                        return udp_release_and_return(packet, result);
     213               
     214                rc = ip_client_get_pseudo_header(IPPROTO_UDP, src, result, dest,
     215                    result, total_length, &ip_header, &length);
     216                if (rc != EOK) {
     217                        return udp_release_and_return(packet, rc);
     218                } else {
     219                        checksum = compute_checksum(0, ip_header, length);
     220                        /*
     221                         * The udp header checksum will be added with the first
     222                         * fragment later.
     223                         */
     224                        free(ip_header);
     225                }
     226        } else {
     227                header->checksum = 0;
     228                checksum = 0;
     229        }
     230
     231        do {
     232                fragments++;
     233                length = packet_get_data_length(next_packet);
     234                if (length <= 0)
     235                        return udp_release_and_return(packet, NO_DATA);
     236
     237                if (total_length < length) {
     238                        rc = packet_trim(next_packet, 0, length - total_length);
     239                        if (rc != EOK)
     240                                return udp_release_and_return(packet, rc);
     241
     242                        /* Add partial checksum if set */
     243                        if (header->checksum) {
     244                                checksum = compute_checksum(checksum,
     245                                    packet_get_data(packet),
     246                                    packet_get_data_length(packet));
     247                        }
     248
     249                        /* Relese the rest of the packet fragments */
     250                        tmp_packet = pq_next(next_packet);
     251                        while (tmp_packet) {
     252                                next_packet = pq_detach(tmp_packet);
     253                                pq_release_remote(udp_globals.net_phone,
     254                                    packet_get_id(tmp_packet));
     255                                tmp_packet = next_packet;
     256                        }
     257
     258                        /* Exit the loop */
     259                        break;
     260                }
     261                total_length -= length;
     262
     263                /* Add partial checksum if set */
     264                if (header->checksum) {
     265                        checksum = compute_checksum(checksum,
     266                            packet_get_data(packet),
     267                            packet_get_data_length(packet));
     268                }
     269
     270        } while ((next_packet = pq_next(next_packet)) && (total_length > 0));
     271
     272        /* Verify checksum */
     273        if (header->checksum) {
     274                if (flip_checksum(compact_checksum(checksum)) !=
     275                    IP_CHECKSUM_ZERO) {
     276                        if (tl_prepare_icmp_packet(udp_globals.net_phone,
     277                            udp_globals.icmp_phone, packet, error) == EOK) {
     278                                /* Checksum error ICMP */
     279                                icmp_parameter_problem_msg(
     280                                    udp_globals.icmp_phone, ICMP_PARAM_POINTER,
     281                                    ((size_t) ((void *) &header->checksum)) -
     282                                    ((size_t) ((void *) header)), packet);
     283                        }
     284                        return EINVAL;
     285                }
     286        }
     287
     288        /* Queue the received packet */
     289        rc = dyn_fifo_push(&socket->received, packet_get_id(packet),
     290            SOCKET_MAX_RECEIVED_SIZE);
     291        if (rc != EOK)
     292                return udp_release_and_return(packet, rc);
     293               
     294        rc = tl_get_ip_packet_dimension(udp_globals.ip_phone,
     295            &udp_globals.dimensions, device_id, &packet_dimension);
     296        if (rc != EOK)
     297                return udp_release_and_return(packet, rc);
     298
     299        /* Notify the destination socket */
     300        fibril_rwlock_write_unlock(&udp_globals.lock);
     301        async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
     302            (sysarg_t) socket->socket_id, packet_dimension->content, 0, 0,
     303            (sysarg_t) fragments);
     304
     305        return EOK;
     306}
     307
     308/** Processes the received UDP packet queue.
     309 *
     310 * Is used as an entry point from the underlying IP module.
     311 * Locks the global lock and calls udp_process_packet() function.
     312 *
     313 * @param[in] device_id The receiving device identifier.
     314 * @param[in,out] packet The received packet queue.
     315 * @param receiver      The target service. Ignored parameter.
     316 * @param[in] error     The packet error reporting service. Prefixes the
     317 *                      received packet.
     318 * @return              EOK on success.
     319 * @return              Other error codes as defined for the
    105320 *                      udp_process_packet() function.
    106321 */
    107 int
    108 udp_received_msg(device_id_t device_id, packet_t packet, services_t receiver,
    109     services_t error);
    110 
    111 /** Processes the received UDP packet queue.
    112  *
    113  *  Notifies the destination socket application.
    114  *  Releases the packet on error or sends an ICMP error notification.
    115  *
    116  *  @param[in] device_id The receiving device identifier.
    117  *  @param[in,out] packet The received packet queue.
    118  *  @param[in] error    The packet error reporting service. Prefixes the
    119  *                      received packet.
    120  *  @returns            EOK on success.
    121  *  @returns            EINVAL if the packet is not valid.
    122  *  @returns            EINVAL if the stored packet address is not the
    123  *                      an_addr_t.
    124  *  @returns            EINVAL if the packet does not contain any data.
    125  *  @returns            NO_DATA if the packet content is shorter than the user
    126  *                      datagram header.
    127  *  @returns            ENOMEM if there is not enough memory left.
    128  *  @returns            EADDRNOTAVAIL if the destination socket does not exist.
    129  *  @returns            Other error codes as defined for the
    130  *                      ip_client_process_packet() function.
    131  */
    132 int
    133 udp_process_packet(device_id_t device_id, packet_t packet, services_t error);
    134 
    135 /** Releases the packet and returns the result.
    136  *
    137  *  @param[in] packet   The packet queue to be released.
    138  *  @param[in] result   The result to be returned.
    139  *  @return             The result parameter.
    140  */
    141 int udp_release_and_return(packet_t packet, int result);
    142 
    143 /** @name Socket messages processing functions
    144  */
    145 /*@{*/
    146 
    147 /** Processes the socket client messages.
    148  *
    149  *  Runs until the client module disconnects.
    150  *
    151  *  @param[in] callid   The message identifier.
    152  *  @param[in] call     The message parameters.
    153  *  @returns            EOK on success.
    154  *  @see                socket.h
    155  */
    156 int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call);
    157 
    158 /** Sends data from the socket to the remote address.
    159  *
    160  *  Binds the socket to a free port if not already connected/bound.
    161  *  Handles the NET_SOCKET_SENDTO message.
    162  *  Supports AF_INET and AF_INET6 address families.
    163  *
    164  *  @param[in,out] local_sockets The application local sockets.
    165  *  @param[in] socket_id Socket identifier.
    166  *  @param[in] addr     The destination address.
    167  *  @param[in] addrlen  The address length.
    168  *  @param[in] fragments The number of data fragments.
    169  *  @param[out] data_fragment_size The data fragment size in bytes.
    170  *  @param[in] flags    Various send flags.
    171  *  @returns            EOK on success.
    172  *  @returns            EAFNOTSUPPORT if the address family is not supported.
    173  *  @returns            ENOTSOCK if the socket is not found.
    174  *  @returns            EINVAL if the address is invalid.
    175  *  @returns            ENOTCONN if the sending socket is not and cannot be
    176  *                      bound.
    177  *  @returns            ENOMEM if there is not enough memory left.
    178  *  @returns            Other error codes as defined for the
    179  *                      socket_read_packet_data() function.
    180  *  @returns            Other error codes as defined for the
    181  *                      ip_client_prepare_packet() function.
    182  *  @returns            Other error codes as defined for the ip_send_msg()
    183  *                      function.
    184  */
    185 int
    186 udp_sendto_message(socket_cores_ref local_sockets, int socket_id,
    187     const struct sockaddr * addr, socklen_t addrlen, int fragments,
    188     size_t * data_fragment_size, int flags);
    189 
    190 /** Receives data to the socket.
    191  *
    192  *  Handles the NET_SOCKET_RECVFROM message.
    193  *  Replies the source address as well.
    194  *
    195  *  @param[in] local_sockets The application local sockets.
    196  *  @param[in] socket_id Socket identifier.
    197  *  @param[in] flags    Various receive flags.
    198  *  @param[out] addrlen The source address length.
    199  *  @returns            The number of bytes received.
    200  *  @returns            ENOTSOCK if the socket is not found.
    201  *  @returns            NO_DATA if there are no received packets or data.
    202  *  @returns            ENOMEM if there is not enough memory left.
    203  *  @returns            EINVAL if the received address is not an IP address.
    204  *  @returns            Other error codes as defined for the packet_translate()
    205  *                      function.
    206  *  @returns            Other error codes as defined for the data_reply()
    207  *                      function.
    208  */
    209 int
    210 udp_recvfrom_message(socket_cores_ref local_sockets, int socket_id, int flags,
    211     size_t * addrlen);
    212 
    213 /*@}*/
    214 
    215 /** UDP global data.
    216  */
    217 udp_globals_t udp_globals;
    218 
    219 int udp_initialize(async_client_conn_t client_connection)
    220 {
    221         ERROR_DECLARE;
    222 
     322static int udp_received_msg(device_id_t device_id, packet_t *packet,
     323    services_t receiver, services_t error)
     324{
     325        int result;
     326
     327        fibril_rwlock_write_lock(&udp_globals.lock);
     328        result = udp_process_packet(device_id, packet, error);
     329        if (result != EOK)
     330                fibril_rwlock_write_unlock(&udp_globals.lock);
     331
     332        return result;
     333}
     334
     335/** Process IPC messages from the IP module
     336 *
     337 * @param[in]     iid   Message identifier.
     338 * @param[in,out] icall Message parameters.
     339 *
     340 */
     341static void udp_receiver(ipc_callid_t iid, ipc_call_t *icall)
     342{
     343        packet_t *packet;
     344        int rc;
     345       
     346        while (true) {
     347                switch (IPC_GET_IMETHOD(*icall)) {
     348                case NET_TL_RECEIVED:
     349                        rc = packet_translate_remote(udp_globals.net_phone, &packet,
     350                            IPC_GET_PACKET(*icall));
     351                        if (rc == EOK)
     352                                rc = udp_received_msg(IPC_GET_DEVICE(*icall), packet,
     353                                    SERVICE_UDP, IPC_GET_ERROR(*icall));
     354                       
     355                        async_answer_0(iid, (sysarg_t) rc);
     356                        break;
     357                default:
     358                        async_answer_0(iid, (sysarg_t) ENOTSUP);
     359                }
     360               
     361                iid = async_get_call(icall);
     362        }
     363}
     364
     365/** Initialize the UDP module.
     366 *
     367 * @param[in] net_phone Network module phone.
     368 *
     369 * @return EOK on success.
     370 * @return ENOMEM if there is not enough memory left.
     371 *
     372 */
     373int tl_initialize(int net_phone)
     374{
    223375        measured_string_t names[] = {
    224376                {
    225                         str_dup("UDP_CHECKSUM_COMPUTING"),
     377                        (uint8_t *) "UDP_CHECKSUM_COMPUTING",
    226378                        22
    227379                },
    228380                {
    229                         str_dup("UDP_AUTOBINDING"),
     381                        (uint8_t *) "UDP_AUTOBINDING",
    230382                        15
    231383                }
    232384        };
    233         measured_string_ref configuration;
     385        measured_string_t *configuration;
    234386        size_t count = sizeof(names) / sizeof(measured_string_t);
    235         char * data;
    236 
     387        uint8_t *data;
     388       
    237389        fibril_rwlock_initialize(&udp_globals.lock);
    238390        fibril_rwlock_write_lock(&udp_globals.lock);
    239 
    240         udp_globals.icmp_phone = icmp_connect_module(SERVICE_ICMP,
    241             ICMP_CONNECT_TIMEOUT);
     391       
     392        udp_globals.net_phone = net_phone;
     393       
     394        udp_globals.icmp_phone = icmp_connect_module(ICMP_CONNECT_TIMEOUT);
     395       
    242396        udp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_UDP,
    243             SERVICE_UDP, client_connection);
    244         if (udp_globals.ip_phone < 0)
     397            SERVICE_UDP, udp_receiver);
     398        if (udp_globals.ip_phone < 0) {
     399                fibril_rwlock_write_unlock(&udp_globals.lock);
    245400                return udp_globals.ip_phone;
    246 
    247         // read default packet dimensions
    248         ERROR_PROPAGATE(ip_packet_size_req(udp_globals.ip_phone, -1,
    249             &udp_globals.packet_dimension));
    250         ERROR_PROPAGATE(socket_ports_initialize(&udp_globals.sockets));
    251         if (ERROR_OCCURRED(packet_dimensions_initialize(
    252             &udp_globals.dimensions))) {
    253                 socket_ports_destroy(&udp_globals.sockets);
    254                 return ERROR_CODE;
    255         }
     401        }
     402       
     403        /* Read default packet dimensions */
     404        int rc = ip_packet_size_req(udp_globals.ip_phone, -1,
     405            &udp_globals.packet_dimension);
     406        if (rc != EOK) {
     407                fibril_rwlock_write_unlock(&udp_globals.lock);
     408                return rc;
     409        }
     410       
     411        rc = socket_ports_initialize(&udp_globals.sockets);
     412        if (rc != EOK) {
     413                fibril_rwlock_write_unlock(&udp_globals.lock);
     414                return rc;
     415        }
     416       
     417        rc = packet_dimensions_initialize(&udp_globals.dimensions);
     418        if (rc != EOK) {
     419                socket_ports_destroy(&udp_globals.sockets, free);
     420                fibril_rwlock_write_unlock(&udp_globals.lock);
     421                return rc;
     422        }
     423       
    256424        udp_globals.packet_dimension.prefix += sizeof(udp_header_t);
    257425        udp_globals.packet_dimension.content -= sizeof(udp_header_t);
    258426        udp_globals.last_used_port = UDP_FREE_PORTS_START - 1;
    259427
    260         // get configuration
    261428        udp_globals.checksum_computing = NET_DEFAULT_UDP_CHECKSUM_COMPUTING;
    262429        udp_globals.autobinding = NET_DEFAULT_UDP_AUTOBINDING;
     430
     431        /* Get configuration */
    263432        configuration = &names[0];
    264         ERROR_PROPAGATE(net_get_conf_req(udp_globals.net_phone, &configuration,
    265             count, &data));
     433        rc = net_get_conf_req(udp_globals.net_phone, &configuration, count,
     434            &data);
     435        if (rc != EOK) {
     436                socket_ports_destroy(&udp_globals.sockets, free);
     437                fibril_rwlock_write_unlock(&udp_globals.lock);
     438                return rc;
     439        }
     440       
    266441        if (configuration) {
    267442                if (configuration[0].value)
     
    280455}
    281456
    282 int
    283 udp_received_msg(device_id_t device_id, packet_t packet, services_t receiver,
    284     services_t error)
    285 {
     457/** Sends data from the socket to the remote address.
     458 *
     459 * Binds the socket to a free port if not already connected/bound.
     460 * Handles the NET_SOCKET_SENDTO message.
     461 * Supports AF_INET and AF_INET6 address families.
     462 *
     463 * @param[in,out] local_sockets The application local sockets.
     464 * @param[in] socket_id Socket identifier.
     465 * @param[in] addr      The destination address.
     466 * @param[in] addrlen   The address length.
     467 * @param[in] fragments The number of data fragments.
     468 * @param[out] data_fragment_size The data fragment size in bytes.
     469 * @param[in] flags     Various send flags.
     470 * @return              EOK on success.
     471 * @return              EAFNOTSUPPORT if the address family is not supported.
     472 * @return              ENOTSOCK if the socket is not found.
     473 * @return              EINVAL if the address is invalid.
     474 * @return              ENOTCONN if the sending socket is not and cannot be
     475 *                      bound.
     476 * @return              ENOMEM if there is not enough memory left.
     477 * @return              Other error codes as defined for the
     478 *                      socket_read_packet_data() function.
     479 * @return              Other error codes as defined for the
     480 *                      ip_client_prepare_packet() function.
     481 * @return              Other error codes as defined for the ip_send_msg()
     482 *                      function.
     483 */
     484static int udp_sendto_message(socket_cores_t *local_sockets, int socket_id,
     485    const struct sockaddr *addr, socklen_t addrlen, int fragments,
     486    size_t *data_fragment_size, int flags)
     487{
     488        socket_core_t *socket;
     489        packet_t *packet;
     490        packet_t *next_packet;
     491        udp_header_t *header;
     492        int index;
     493        size_t total_length;
    286494        int result;
    287 
    288         fibril_rwlock_write_lock(&udp_globals.lock);
    289         result = udp_process_packet(device_id, packet, error);
    290         if (result != EOK)
    291                 fibril_rwlock_write_unlock(&udp_globals.lock);
    292 
    293         return result;
    294 }
    295 
    296 int udp_process_packet(device_id_t device_id, packet_t packet, services_t error)
    297 {
    298         ERROR_DECLARE;
    299 
     495        uint16_t dest_port;
     496        uint32_t checksum;
     497        void *ip_header;
     498        size_t headerlen;
     499        device_id_t device_id;
     500        packet_dimension_t *packet_dimension;
     501        size_t size;
     502        int rc;
     503
     504        /* In case of error, do not update the data fragment size. */
     505        *data_fragment_size = 0;
     506       
     507        rc = tl_get_address_port(addr, addrlen, &dest_port);
     508        if (rc != EOK)
     509                return rc;
     510
     511        socket = socket_cores_find(local_sockets, socket_id);
     512        if (!socket)
     513                return ENOTSOCK;
     514
     515        if ((socket->port <= 0) && udp_globals.autobinding) {
     516                /* Bind the socket to a random free port if not bound */
     517                rc = socket_bind_free_port(&udp_globals.sockets, socket,
     518                    UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
     519                    udp_globals.last_used_port);
     520                if (rc != EOK)
     521                        return rc;
     522                /* Set the next port as the search starting port number */
     523                udp_globals.last_used_port = socket->port;
     524        }
     525
     526        if (udp_globals.checksum_computing) {
     527                rc = ip_get_route_req(udp_globals.ip_phone, IPPROTO_UDP, addr,
     528                    addrlen, &device_id, &ip_header, &headerlen);
     529                if (rc != EOK)
     530                        return rc;
     531                /* Get the device packet dimension */
     532//              rc = tl_get_ip_packet_dimension(udp_globals.ip_phone,
     533//                  &udp_globals.dimensions, device_id, &packet_dimension);
     534//              if (rc != EOK)
     535//                      return rc;
     536        }
     537//      } else {
     538                /* Do not ask all the time */
     539                rc = ip_packet_size_req(udp_globals.ip_phone, -1,
     540                    &udp_globals.packet_dimension);
     541                if (rc != EOK)
     542                        return rc;
     543                packet_dimension = &udp_globals.packet_dimension;
     544//      }
     545
     546        /*
     547         * Update the data fragment size based on what the lower layers can
     548         * handle without fragmentation, but not more than the maximum allowed
     549         * for UDP.
     550         */
     551        size = MAX_UDP_FRAGMENT_SIZE;
     552        if (packet_dimension->content < size)
     553            size = packet_dimension->content;
     554        *data_fragment_size = size;
     555
     556        /* Read the first packet fragment */
     557        result = tl_socket_read_packet_data(udp_globals.net_phone, &packet,
     558            UDP_HEADER_SIZE, packet_dimension, addr, addrlen);
     559        if (result < 0)
     560                return result;
     561
     562        total_length = (size_t) result;
     563        if (udp_globals.checksum_computing)
     564                checksum = compute_checksum(0, packet_get_data(packet),
     565                    packet_get_data_length(packet));
     566        else
     567                checksum = 0;
     568
     569        /* Prefix the UDP header */
     570        header = PACKET_PREFIX(packet, udp_header_t);
     571        if (!header)
     572                return udp_release_and_return(packet, ENOMEM);
     573
     574        bzero(header, sizeof(*header));
     575
     576        /* Read the rest of the packet fragments */
     577        for (index = 1; index < fragments; index++) {
     578                result = tl_socket_read_packet_data(udp_globals.net_phone,
     579                    &next_packet, 0, packet_dimension, addr, addrlen);
     580                if (result < 0)
     581                        return udp_release_and_return(packet, result);
     582
     583                rc = pq_add(&packet, next_packet, index, 0);
     584                if (rc != EOK)
     585                        return udp_release_and_return(packet, rc);
     586
     587                total_length += (size_t) result;
     588                if (udp_globals.checksum_computing) {
     589                        checksum = compute_checksum(checksum,
     590                            packet_get_data(next_packet),
     591                            packet_get_data_length(next_packet));
     592                }
     593        }
     594
     595        /* Set the UDP header */
     596        header->source_port = htons((socket->port > 0) ? socket->port : 0);
     597        header->destination_port = htons(dest_port);
     598        header->total_length = htons(total_length + sizeof(*header));
     599        header->checksum = 0;
     600
     601        if (udp_globals.checksum_computing) {
     602                /* Update the pseudo header */
     603                rc = ip_client_set_pseudo_header_data_length(ip_header,
     604                    headerlen, total_length + UDP_HEADER_SIZE);
     605                if (rc != EOK) {
     606                        free(ip_header);
     607                        return udp_release_and_return(packet, rc);
     608                }
     609
     610                /* Finish the checksum computation */
     611                checksum = compute_checksum(checksum, ip_header, headerlen);
     612                checksum = compute_checksum(checksum, (uint8_t *) header,
     613                    sizeof(*header));
     614                header->checksum =
     615                    htons(flip_checksum(compact_checksum(checksum)));
     616                free(ip_header);
     617        } else {
     618                device_id = DEVICE_INVALID_ID;
     619        }
     620
     621        /* Prepare the first packet fragment */
     622        rc = ip_client_prepare_packet(packet, IPPROTO_UDP, 0, 0, 0, 0);
     623        if (rc != EOK)
     624                return udp_release_and_return(packet, rc);
     625
     626        /* Release the UDP global lock on success. */
     627        fibril_rwlock_write_unlock(&udp_globals.lock);
     628
     629        /* Send the packet */
     630        ip_send_msg(udp_globals.ip_phone, device_id, packet, SERVICE_UDP, 0);
     631
     632        return EOK;
     633}
     634
     635/** Receives data to the socket.
     636 *
     637 * Handles the NET_SOCKET_RECVFROM message.
     638 * Replies the source address as well.
     639 *
     640 * @param[in] local_sockets The application local sockets.
     641 * @param[in] socket_id Socket identifier.
     642 * @param[in] flags     Various receive flags.
     643 * @param[out] addrlen  The source address length.
     644 * @return              The number of bytes received.
     645 * @return              ENOTSOCK if the socket is not found.
     646 * @return              NO_DATA if there are no received packets or data.
     647 * @return              ENOMEM if there is not enough memory left.
     648 * @return              EINVAL if the received address is not an IP address.
     649 * @return              Other error codes as defined for the packet_translate()
     650 *                      function.
     651 * @return              Other error codes as defined for the data_reply()
     652 *                      function.
     653 */
     654static int udp_recvfrom_message(socket_cores_t *local_sockets, int socket_id,
     655    int flags, size_t *addrlen)
     656{
     657        socket_core_t *socket;
     658        int packet_id;
     659        packet_t *packet;
     660        udp_header_t *header;
     661        struct sockaddr *addr;
    300662        size_t length;
    301         size_t offset;
     663        uint8_t *data;
    302664        int result;
    303         udp_header_ref header;
    304         socket_core_ref socket;
    305         packet_t next_packet;
    306         size_t total_length;
    307         uint32_t checksum;
    308         int fragments;
    309         packet_t tmp_packet;
    310         icmp_type_t type;
    311         icmp_code_t code;
    312         void *ip_header;
    313         struct sockaddr *src;
    314         struct sockaddr *dest;
    315         packet_dimension_ref packet_dimension;
    316 
    317         if (error) {
    318                 switch (error) {
    319                 case SERVICE_ICMP:
    320                         // ignore error
    321                         // length = icmp_client_header_length(packet);
    322                         // process error
    323                         result = icmp_client_process_packet(packet, &type,
    324                             &code, NULL, NULL);
    325                         if (result < 0)
    326                                 return udp_release_and_return(packet, result);
    327                         length = (size_t) result;
    328                         if (ERROR_OCCURRED(packet_trim(packet, length, 0)))
    329                                 return udp_release_and_return(packet,
    330                                     ERROR_CODE);
    331                         break;
    332                 default:
    333                         return udp_release_and_return(packet, ENOTSUP);
    334                 }
    335         }
    336 
    337         // TODO process received ipopts?
    338         result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
    339         if (result < 0)
    340                 return udp_release_and_return(packet, result);
    341         offset = (size_t) result;
    342 
    343         length = packet_get_data_length(packet);
    344         if (length <= 0)
    345                 return udp_release_and_return(packet, EINVAL);
    346         if (length < UDP_HEADER_SIZE + offset)
     665        int rc;
     666
     667        /* Find the socket */
     668        socket = socket_cores_find(local_sockets, socket_id);
     669        if (!socket)
     670                return ENOTSOCK;
     671
     672        /* Get the next received packet */
     673        packet_id = dyn_fifo_value(&socket->received);
     674        if (packet_id < 0)
     675                return NO_DATA;
     676       
     677        rc = packet_translate_remote(udp_globals.net_phone, &packet, packet_id);
     678        if (rc != EOK) {
     679                (void) dyn_fifo_pop(&socket->received);
     680                return rc;
     681        }
     682
     683        /* Get UDP header */
     684        data = packet_get_data(packet);
     685        if (!data) {
     686                (void) dyn_fifo_pop(&socket->received);
    347687                return udp_release_and_return(packet, NO_DATA);
    348 
    349         // trim all but UDP header
    350         if (ERROR_OCCURRED(packet_trim(packet, offset, 0)))
    351                 return udp_release_and_return(packet, ERROR_CODE);
    352 
    353         // get udp header
    354         header = (udp_header_ref) packet_get_data(packet);
    355         if (!header)
    356                 return udp_release_and_return(packet, NO_DATA);
    357 
    358         // find the destination socket
    359         socket = socket_port_find(&udp_globals.sockets,
    360         ntohs(header->destination_port), SOCKET_MAP_KEY_LISTENING, 0);
    361         if (!socket) {
    362                 if (tl_prepare_icmp_packet(udp_globals.net_phone,
    363                     udp_globals.icmp_phone, packet, error) == EOK) {
    364                         icmp_destination_unreachable_msg(udp_globals.icmp_phone,
    365                             ICMP_PORT_UNREACH, 0, packet);
    366                 }
    367                 return EADDRNOTAVAIL;
    368         }
    369 
    370         // count the received packet fragments
    371         next_packet = packet;
    372         fragments = 0;
    373         total_length = ntohs(header->total_length);
    374 
    375         // compute header checksum if set
    376         if (header->checksum && (!error)) {
    377                 result = packet_get_addr(packet, (uint8_t **) &src,
    378                     (uint8_t **) &dest);
    379                 if( result <= 0)
    380                         return udp_release_and_return(packet, result);
    381 
    382                 if (ERROR_OCCURRED(ip_client_get_pseudo_header(IPPROTO_UDP,
    383                     src, result, dest, result, total_length, &ip_header,
    384                     &length))) {
    385                         return udp_release_and_return(packet, ERROR_CODE);
    386                 } else {
    387                         checksum = compute_checksum(0, ip_header, length);
    388                         // the udp header checksum will be added with the first
    389                         // fragment later
    390                         free(ip_header);
    391                 }
    392         } else {
    393                 header->checksum = 0;
    394                 checksum = 0;
    395         }
    396 
    397         do {
    398                 ++ fragments;
    399                 length = packet_get_data_length(next_packet);
    400                 if (length <= 0)
    401                         return udp_release_and_return(packet, NO_DATA);
    402 
    403                 if (total_length < length) {
    404                         if (ERROR_OCCURRED(packet_trim(next_packet, 0,
    405                             length - total_length))) {
    406                                 return udp_release_and_return(packet,
    407                                     ERROR_CODE);
    408                         }
    409 
    410                         // add partial checksum if set
    411                         if (header->checksum) {
    412                                 checksum = compute_checksum(checksum,
    413                                     packet_get_data(packet),
    414                                     packet_get_data_length(packet));
    415                         }
    416 
    417                         // relese the rest of the packet fragments
    418                         tmp_packet = pq_next(next_packet);
    419                         while (tmp_packet) {
    420                                 next_packet = pq_detach(tmp_packet);
    421                                 pq_release_remote(udp_globals.net_phone,
    422                                     packet_get_id(tmp_packet));
    423                                 tmp_packet = next_packet;
    424                         }
    425 
    426                         // exit the loop
    427                         break;
    428                 }
    429                 total_length -= length;
    430 
    431                 // add partial checksum if set
    432                 if (header->checksum) {
    433                         checksum = compute_checksum(checksum,
    434                             packet_get_data(packet),
    435                             packet_get_data_length(packet));
    436                 }
    437 
    438         } while ((next_packet = pq_next(next_packet)) && (total_length > 0));
    439 
    440         // check checksum
    441         if (header->checksum) {
    442                 if (flip_checksum(compact_checksum(checksum)) !=
    443                     IP_CHECKSUM_ZERO) {
    444                         if (tl_prepare_icmp_packet(udp_globals.net_phone,
    445                             udp_globals.icmp_phone, packet, error) == EOK) {
    446                                 // checksum error ICMP
    447                                 icmp_parameter_problem_msg(
    448                                     udp_globals.icmp_phone, ICMP_PARAM_POINTER,
    449                                     ((size_t) ((void *) &header->checksum)) -
    450                                     ((size_t) ((void *) header)), packet);
    451                         }
    452                         return EINVAL;
    453                 }
    454         }
    455 
    456         // queue the received packet
    457         if (ERROR_OCCURRED(dyn_fifo_push(&socket->received,
    458             packet_get_id(packet), SOCKET_MAX_RECEIVED_SIZE)) ||
    459             ERROR_OCCURRED(tl_get_ip_packet_dimension(udp_globals.ip_phone,
    460             &udp_globals.dimensions, device_id, &packet_dimension))) {
    461                 return udp_release_and_return(packet, ERROR_CODE);
    462         }
    463 
    464         // notify the destination socket
    465         fibril_rwlock_write_unlock(&udp_globals.lock);
    466         async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
    467             (ipcarg_t) socket->socket_id, packet_dimension->content, 0, 0,
    468             (ipcarg_t) fragments);
    469 
    470         return EOK;
    471 }
    472 
    473 int
    474 udp_message_standalone(ipc_callid_t callid, ipc_call_t * call,
    475     ipc_call_t * answer, int * answer_count)
    476 {
    477         ERROR_DECLARE;
    478 
    479         packet_t packet;
    480 
    481         *answer_count = 0;
    482 
    483         switch (IPC_GET_METHOD(*call)) {
    484         case NET_TL_RECEIVED:
    485                 if (!ERROR_OCCURRED(packet_translate_remote(
    486                     udp_globals.net_phone, &packet, IPC_GET_PACKET(call)))) {
    487                         ERROR_CODE = udp_received_msg(IPC_GET_DEVICE(call),
    488                             packet, SERVICE_UDP, IPC_GET_ERROR(call));
    489                 }
    490                 return ERROR_CODE;
    491        
    492         case IPC_M_CONNECT_TO_ME:
    493                 return udp_process_client_messages(callid, * call);
    494         }
    495 
    496         return ENOTSUP;
    497 }
    498 
    499 int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
     688        }
     689        header = (udp_header_t *) data;
     690
     691        /* Set the source address port */
     692        result = packet_get_addr(packet, (uint8_t **) &addr, NULL);
     693        rc = tl_set_address_port(addr, result, ntohs(header->source_port));
     694        if (rc != EOK) {
     695                (void) dyn_fifo_pop(&socket->received);
     696                return udp_release_and_return(packet, rc);
     697        }
     698        *addrlen = (size_t) result;
     699
     700        /* Send the source address */
     701        rc = data_reply(addr, *addrlen);
     702        switch (rc) {
     703        case EOK:
     704                break;
     705        case EOVERFLOW:
     706                return rc;
     707        default:
     708                (void) dyn_fifo_pop(&socket->received);
     709                return udp_release_and_return(packet, rc);
     710        }
     711
     712        /* Trim the header */
     713        rc = packet_trim(packet, UDP_HEADER_SIZE, 0);
     714        if (rc != EOK) {
     715                (void) dyn_fifo_pop(&socket->received);
     716                return udp_release_and_return(packet, rc);
     717        }
     718
     719        /* Reply the packets */
     720        rc = socket_reply_packets(packet, &length);
     721        switch (rc) {
     722        case EOK:
     723                break;
     724        case EOVERFLOW:
     725                return rc;
     726        default:
     727                (void) dyn_fifo_pop(&socket->received);
     728                return udp_release_and_return(packet, rc);
     729        }
     730
     731        (void) dyn_fifo_pop(&socket->received);
     732
     733        /* Release the packet and return the total length */
     734        return udp_release_and_return(packet, (int) length);
     735}
     736
     737/** Processes the socket client messages.
     738 *
     739 * Runs until the client module disconnects.
     740 *
     741 * @param[in] callid    The message identifier.
     742 * @param[in] call      The message parameters.
     743 * @return              EOK on success.
     744 *
     745 * @see socket.h
     746 */
     747static int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
    500748{
    501749        int res;
    502750        bool keep_on_going = true;
    503751        socket_cores_t local_sockets;
    504         int app_phone = IPC_GET_PHONE(&call);
     752        int app_phone = IPC_GET_PHONE(call);
    505753        struct sockaddr *addr;
    506754        int socket_id;
     
    508756        size_t size;
    509757        ipc_call_t answer;
    510         int answer_count;
    511         packet_dimension_ref packet_dimension;
     758        size_t answer_count;
     759        packet_dimension_t *packet_dimension;
    512760
    513761        /*
     
    518766        answer_count = 0;
    519767
    520         // The client connection is only in one fibril and therefore no
    521         // additional locks are needed.
     768        /*
     769         * The client connection is only in one fibril and therefore no
     770         * additional locks are needed.
     771         */
    522772
    523773        socket_cores_initialize(&local_sockets);
     
    525775        while (keep_on_going) {
    526776
    527                 // answer the call
     777                /* Answer the call */
    528778                answer_call(callid, res, &answer, answer_count);
    529779
    530                 // refresh data
     780                /* Refresh data */
    531781                refresh_answer(&answer, &answer_count);
    532782
    533                 // get the next call
     783                /* Get the next call */
    534784                callid = async_get_call(&call);
    535785
    536                 // process the call
    537                 switch (IPC_GET_METHOD(call)) {
     786                /* Process the call */
     787                switch (IPC_GET_IMETHOD(call)) {
    538788                case IPC_M_PHONE_HUNGUP:
    539789                        keep_on_going = false;
     
    550800                                break;
    551801                       
     802                        size = MAX_UDP_FRAGMENT_SIZE;
    552803                        if (tl_get_ip_packet_dimension(udp_globals.ip_phone,
    553804                            &udp_globals.dimensions, DEVICE_INVALID_ID,
    554805                            &packet_dimension) == EOK) {
    555                                 SOCKET_SET_DATA_FRAGMENT_SIZE(answer,
    556                                     packet_dimension->content);
     806                                if (packet_dimension->content < size)
     807                                        size = packet_dimension->content;
    557808                        }
    558 
    559 //                      SOCKET_SET_DATA_FRAGMENT_SIZE(answer,
    560 //                          MAX_UDP_FRAGMENT_SIZE);
     809                        SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
    561810                        SOCKET_SET_HEADER_SIZE(answer, UDP_HEADER_SIZE);
    562811                        answer_count = 3;
     
    564813
    565814                case NET_SOCKET_BIND:
    566                         res = data_receive((void **) &addr, &addrlen);
     815                        res = async_data_write_accept((void **) &addr, false,
     816                            0, 0, 0, &addrlen);
    567817                        if (res != EOK)
    568818                                break;
     
    577827
    578828                case NET_SOCKET_SENDTO:
    579                         res = data_receive((void **) &addr, &addrlen);
     829                        res = async_data_write_accept((void **) &addr, false,
     830                            0, 0, 0, &addrlen);
    580831                        if (res != EOK)
    581832                                break;
     
    628879        }
    629880
    630         // release the application phone
    631         ipc_hangup(app_phone);
    632 
    633         // release all local sockets
     881        /* Release the application phone */
     882        async_hangup(app_phone);
     883
     884        /* Release all local sockets */
    634885        socket_cores_release(udp_globals.net_phone, &local_sockets,
    635886            &udp_globals.sockets, NULL);
     
    638889}
    639890
    640 int
    641 udp_sendto_message(socket_cores_ref local_sockets, int socket_id,
    642     const struct sockaddr *addr, socklen_t addrlen, int fragments,
    643     size_t *data_fragment_size, int flags)
    644 {
    645         ERROR_DECLARE;
    646 
    647         socket_core_ref socket;
    648         packet_t packet;
    649         packet_t next_packet;
    650         udp_header_ref header;
    651         int index;
    652         size_t total_length;
    653         int result;
    654         uint16_t dest_port;
    655         uint32_t checksum;
    656         void *ip_header;
    657         size_t headerlen;
    658         device_id_t device_id;
    659         packet_dimension_ref packet_dimension;
    660 
    661         ERROR_PROPAGATE(tl_get_address_port(addr, addrlen, &dest_port));
    662 
    663         socket = socket_cores_find(local_sockets, socket_id);
    664         if (!socket)
    665                 return ENOTSOCK;
    666 
    667         if ((socket->port <= 0) && udp_globals.autobinding) {
    668                 // bind the socket to a random free port if not bound
    669 //              do {
    670                         // try to find a free port
    671 //                      fibril_rwlock_read_unlock(&udp_globals.lock);
    672 //                      fibril_rwlock_write_lock(&udp_globals.lock);
    673                         // might be changed in the meantime
    674 //                      if (socket->port <= 0) {
    675                                 if (ERROR_OCCURRED(socket_bind_free_port(
    676                                     &udp_globals.sockets, socket,
    677                                     UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
    678                                     udp_globals.last_used_port))) {
    679 //                                      fibril_rwlock_write_unlock(
    680 //                                          &udp_globals.lock);
    681 //                                      fibril_rwlock_read_lock(
    682 //                                          &udp_globals.lock);
    683                                         return ERROR_CODE;
    684                                 }
    685                                 // set the next port as the search starting port
    686                                 // number
    687                                 udp_globals.last_used_port = socket->port;
    688 //                      }
    689 //                      fibril_rwlock_write_unlock(&udp_globals.lock);
    690 //                      fibril_rwlock_read_lock(&udp_globals.lock);
    691                         // might be changed in the meantime
    692 //              } while (socket->port <= 0);
    693         }
    694 
    695         if (udp_globals.checksum_computing) {
    696                 if (ERROR_OCCURRED(ip_get_route_req(udp_globals.ip_phone,
    697                     IPPROTO_UDP, addr, addrlen, &device_id, &ip_header,
    698                     &headerlen))) {
    699                         return udp_release_and_return(packet, ERROR_CODE);
    700                 }
    701                 // get the device packet dimension
    702 //              ERROR_PROPAGATE(tl_get_ip_packet_dimension(udp_globals.ip_phone,
    703 //                  &udp_globals.dimensions, device_id, &packet_dimension));
    704         }
    705 //      } else {
    706                 // do not ask all the time
    707                 ERROR_PROPAGATE(ip_packet_size_req(udp_globals.ip_phone, -1,
    708                     &udp_globals.packet_dimension));
    709                 packet_dimension = &udp_globals.packet_dimension;
    710 //      }
    711 
    712         // read the first packet fragment
    713         result = tl_socket_read_packet_data(udp_globals.net_phone, &packet,
    714             UDP_HEADER_SIZE, packet_dimension, addr, addrlen);
    715         if (result < 0)
    716                 return result;
    717 
    718         total_length = (size_t) result;
    719         if (udp_globals.checksum_computing)
    720                 checksum = compute_checksum(0, packet_get_data(packet),
    721                     packet_get_data_length(packet));
    722         else
    723                 checksum = 0;
    724 
    725         // prefix the udp header
    726         header = PACKET_PREFIX(packet, udp_header_t);
    727         if(! header)
    728                 return udp_release_and_return(packet, ENOMEM);
    729 
    730         bzero(header, sizeof(*header));
    731         // read the rest of the packet fragments
    732         for (index = 1; index < fragments; ++ index) {
    733                 result = tl_socket_read_packet_data(udp_globals.net_phone,
    734                     &next_packet, 0, packet_dimension, addr, addrlen);
    735                 if (result < 0)
    736                         return udp_release_and_return(packet, result);
    737 
    738                 if (ERROR_OCCURRED(pq_add(&packet, next_packet, index, 0)))
    739                         return udp_release_and_return(packet, ERROR_CODE);
    740 
    741                 total_length += (size_t) result;
    742                 if (udp_globals.checksum_computing) {
    743                         checksum = compute_checksum(checksum,
    744                             packet_get_data(next_packet),
    745                             packet_get_data_length(next_packet));
    746                 }
    747         }
    748 
    749         // set the udp header
    750         header->source_port = htons((socket->port > 0) ? socket->port : 0);
    751         header->destination_port = htons(dest_port);
    752         header->total_length = htons(total_length + sizeof(*header));
    753         header->checksum = 0;
    754         if (udp_globals.checksum_computing) {
    755                 // update the pseudo header
    756                 if (ERROR_OCCURRED(ip_client_set_pseudo_header_data_length(
    757                     ip_header, headerlen, total_length + UDP_HEADER_SIZE))) {
    758                         free(ip_header);
    759                         return udp_release_and_return(packet, ERROR_CODE);
    760                 }
    761 
    762                 // finish the checksum computation
    763                 checksum = compute_checksum(checksum, ip_header, headerlen);
    764                 checksum = compute_checksum(checksum, (uint8_t *) header,
    765                     sizeof(*header));
    766                 header->checksum =
    767                     htons(flip_checksum(compact_checksum(checksum)));
    768                 free(ip_header);
    769         } else {
    770                 device_id = DEVICE_INVALID_ID;
    771         }
    772 
    773         // prepare the first packet fragment
    774         if (ERROR_OCCURRED(ip_client_prepare_packet(packet, IPPROTO_UDP, 0, 0,
    775             0, 0))) {
    776                 return udp_release_and_return(packet, ERROR_CODE);
    777         }
    778 
    779         // send the packet
    780         fibril_rwlock_write_unlock(&udp_globals.lock);
    781         ip_send_msg(udp_globals.ip_phone, device_id, packet, SERVICE_UDP, 0);
    782 
    783         return EOK;
    784 }
    785 
    786 int
    787 udp_recvfrom_message(socket_cores_ref local_sockets, int socket_id, int flags,
    788     size_t *addrlen)
    789 {
    790         ERROR_DECLARE;
    791 
    792         socket_core_ref socket;
    793         int packet_id;
    794         packet_t packet;
    795         udp_header_ref header;
    796         struct sockaddr *addr;
    797         size_t length;
    798         uint8_t *data;
    799         int result;
    800 
    801         // find the socket
    802         socket = socket_cores_find(local_sockets, socket_id);
    803         if (!socket)
    804                 return ENOTSOCK;
    805 
    806         // get the next received packet
    807         packet_id = dyn_fifo_value(&socket->received);
    808         if (packet_id < 0)
    809                 return NO_DATA;
    810 
    811         ERROR_PROPAGATE(packet_translate_remote(udp_globals.net_phone, &packet,
    812             packet_id));
    813 
    814         // get udp header
    815         data = packet_get_data(packet);
    816         if (!data) {
    817                 pq_release_remote(udp_globals.net_phone, packet_id);
    818                 return NO_DATA;
    819         }
    820         header = (udp_header_ref) data;
    821 
    822         // set the source address port
    823         result = packet_get_addr(packet, (uint8_t **) &addr, NULL);
    824         if (ERROR_OCCURRED(tl_set_address_port(addr, result,
    825             ntohs(header->source_port)))) {
    826                 pq_release_remote(udp_globals.net_phone, packet_id);
    827                 return ERROR_CODE;
    828         }
    829         *addrlen = (size_t) result;
    830 
    831         // send the source address
    832         ERROR_PROPAGATE(data_reply(addr, * addrlen));
    833 
    834         // trim the header
    835         ERROR_PROPAGATE(packet_trim(packet, UDP_HEADER_SIZE, 0));
    836 
    837         // reply the packets
    838         ERROR_PROPAGATE(socket_reply_packets(packet, &length));
    839 
    840         // release the packet
    841         dyn_fifo_pop(&socket->received);
    842         pq_release_remote(udp_globals.net_phone, packet_get_id(packet));
    843 
    844         // return the total length
    845         return (int) length;
    846 }
    847 
    848 int udp_release_and_return(packet_t packet, int result)
    849 {
    850         pq_release_remote(udp_globals.net_phone, packet_get_id(packet));
    851         return result;
    852 }
    853 
    854 /** Default thread for new connections.
    855  *
    856  *  @param[in] iid      The initial message identifier.
    857  *  @param[in] icall    The initial message call structure.
    858  *
    859  */
    860 static void tl_client_connection(ipc_callid_t iid, ipc_call_t * icall)
    861 {
    862         /*
    863          * Accept the connection
    864          *  - Answer the first IPC_M_CONNECT_ME_TO call.
    865          */
    866         ipc_answer_0(iid, EOK);
    867        
    868         while (true) {
    869                 ipc_call_t answer;
    870                 int answer_count;
    871                
    872                 /* Clear the answer structure */
    873                 refresh_answer(&answer, &answer_count);
    874                
    875                 /* Fetch the next message */
    876                 ipc_call_t call;
    877                 ipc_callid_t callid = async_get_call(&call);
    878                
    879                 /* Process the message */
    880                 int res = tl_module_message_standalone(callid, &call, &answer,
    881                     &answer_count);
    882                
    883                 /*
    884                  * End if said to either by the message or the processing result
    885                  */
    886                 if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) ||
    887                     (res == EHANGUP))
    888                         return;
    889                
    890                 /* Answer the message */
    891                 answer_call(callid, res, &answer, answer_count);
    892         }
    893 }
    894 
    895 /** Starts the module.
    896  *
    897  *  @param argc         The count of the command line arguments. Ignored
    898  *                      parameter.
    899  *  @param argv         The command line parameters. Ignored parameter.
    900  *
    901  *  @returns            EOK on success.
    902  *  @returns            Other error codes as defined for each specific module
    903  *                      start function.
    904  */
     891/** Per-connection initialization
     892 *
     893 */
     894void tl_connection(void)
     895{
     896}
     897
     898/** Processes the UDP message.
     899 *
     900 * @param[in] callid    The message identifier.
     901 * @param[in] call      The message parameters.
     902 * @param[out] answer   The message answer parameters.
     903 * @param[out] answer_count The last parameter for the actual answer in the
     904 *                      answer parameter.
     905 * @return              EOK on success.
     906 * @return              ENOTSUP if the message is not known.
     907 *
     908 * @see udp_interface.h
     909 * @see IS_NET_UDP_MESSAGE()
     910 */
     911int tl_message(ipc_callid_t callid, ipc_call_t *call,
     912    ipc_call_t *answer, size_t *answer_count)
     913{
     914        *answer_count = 0;
     915
     916        switch (IPC_GET_IMETHOD(*call)) {
     917        case IPC_M_CONNECT_TO_ME:
     918                return udp_process_client_messages(callid, *call);
     919        }
     920
     921        return ENOTSUP;
     922}
     923
    905924int main(int argc, char *argv[])
    906925{
    907         ERROR_DECLARE;
    908        
    909926        /* Start the module */
    910         if (ERROR_OCCURRED(tl_module_start_standalone(tl_client_connection)))
    911                 return ERROR_CODE;
    912        
    913         return EOK;
     927        return tl_module_start(SERVICE_UDP);
    914928}
    915929
Note: See TracChangeset for help on using the changeset viewer.