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


Ignore:
Timestamp:
2011-04-13T14:45:41Z (15 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
88634420
Parents:
cefb126 (diff), 17279ead (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

File:
1 edited

Legend:

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

    rcefb126 r89c57b6  
    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>
    44 
    45 #include <net_err.h>
    46 #include <net_messages.h>
    47 #include <net_modules.h>
     43#include <ipc/net.h>
     44#include <ipc/tl.h>
     45#include <ipc/socket.h>
    4846#include <adt/dynamic_fifo.h>
    49 #include <packet/packet_client.h>
     47#include <errno.h>
     48
     49#include <net/socket_codes.h>
     50#include <net/ip_protocols.h>
     51#include <net/in.h>
     52#include <net/in6.h>
     53#include <net/inet.h>
     54#include <net/modules.h>
     55
     56#include <packet_client.h>
    5057#include <packet_remote.h>
    5158#include <net_checksum.h>
    52 #include <in.h>
    53 #include <in6.h>
    54 #include <inet.h>
    5559#include <ip_client.h>
    5660#include <ip_interface.h>
    57 #include <ip_protocols.h>
    5861#include <icmp_client.h>
    59 #include <icmp_interface.h>
     62#include <icmp_remote.h>
    6063#include <net_interface.h>
    61 #include <socket_codes.h>
    62 #include <socket_errno.h>
    6364#include <socket_core.h>
    64 #include <socket_messages.h>
    6565#include <tl_common.h>
    66 #include <tl_local.h>
    67 #include <tl_interface.h>
    68 #include <tl_messages.h>
     66#include <tl_remote.h>
     67#include <tl_skel.h>
    6968
    7069#include "udp.h"
    7170#include "udp_header.h"
    72 #include "udp_module.h"
    73 
    74 /** UDP module name.
    75  */
    76 #define NAME    "UDP protocol"
    77 
    78 /** Default UDP checksum computing.
    79  */
     71
     72/** UDP module name. */
     73#define NAME  "udp"
     74
     75/** Default UDP checksum computing. */
    8076#define NET_DEFAULT_UDP_CHECKSUM_COMPUTING      true
    8177
    82 /** Default UDP autobind when sending via unbound sockets.
    83  */
     78/** Default UDP autobind when sending via unbound sockets. */
    8479#define NET_DEFAULT_UDP_AUTOBINDING     true
    8580
    86 /** Maximum UDP fragment size.
    87  */
    88 #define MAX_UDP_FRAGMENT_SIZE   65535
    89 
    90 /** Free ports pool start.
    91  */
    92 #define UDP_FREE_PORTS_START    1025
    93 
    94 /** Free ports pool end.
    95  */
     81/** Maximum UDP fragment size. */
     82#define MAX_UDP_FRAGMENT_SIZE           65535
     83
     84/** Free ports pool start. */
     85#define UDP_FREE_PORTS_START            1025
     86
     87/** Free ports pool end. */
    9688#define UDP_FREE_PORTS_END              65535
    9789
     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
    98105/** Processes the received UDP packet queue.
    99  *  Is used as an entry point from the underlying IP module.
    100  *  Locks the global lock and calls udp_process_packet() function.
    101  *  @param[in] device_id The receiving device identifier.
    102  *  @param[in,out] packet The received packet queue.
    103  *  @param receiver The target service. Ignored parameter.
    104  *  @param[in] error The packet error reporting service. Prefixes the received packet.
    105  *  @returns EOK on success.
    106  *  @returns Other error codes as defined for the udp_process_packet() function.
    107  */
    108 int udp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error);
     106 *
     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
     113 *                      received packet.
     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}
    109307
    110308/** Processes the received UDP packet queue.
    111  *  Notifies the destination socket application.
    112  *  Releases the packet on error or sends an ICMP error notification..
    113  *  @param[in] device_id The receiving device identifier.
    114  *  @param[in,out] packet The received packet queue.
    115  *  @param[in] error The packet error reporting service. Prefixes the received packet.
    116  *  @returns EOK on success.
    117  *  @returns EINVAL if the packet is not valid.
    118  *  @returns EINVAL if the stored packet address is not the an_addr_t.
    119  *  @returns EINVAL if the packet does not contain any data.
    120  *  @returns NO_DATA if the packet content is shorter than the user datagram header.
    121  *  @returns ENOMEM if there is not enough memory left.
    122  *  @returns EADDRNOTAVAIL if the destination socket does not exist.
    123  *  @returns Other error codes as defined for the ip_client_process_packet() function.
    124  */
    125 int udp_process_packet(device_id_t device_id, packet_t packet, services_t error);
    126 
    127 /** Releases the packet and returns the result.
    128  *  @param[in] packet The packet queue to be released.
    129  *  @param[in] result The result to be returned.
    130  *  @return The result parameter.
    131  */
    132 int udp_release_and_return(packet_t packet, int result);
    133 
    134 /** @name Socket messages processing functions
    135  */
    136 /*@{*/
    137 
    138 /** Processes the socket client messages.
    139  *  Runs until the client module disconnects.
    140  *  @param[in] callid The message identifier.
    141  *  @param[in] call The message parameters.
    142  *  @returns EOK on success.
    143  *  @see socket.h
    144  */
    145 int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call);
    146 
    147 /** Sends data from the socket to the remote address.
    148  *  Binds the socket to a free port if not already connected/bound.
    149  *  Handles the NET_SOCKET_SENDTO message.
    150  *  Supports AF_INET and AF_INET6 address families.
    151  *  @param[in,out] local_sockets The application local sockets.
    152  *  @param[in] socket_id Socket identifier.
    153  *  @param[in] addr The destination address.
    154  *  @param[in] addrlen The address length.
    155  *  @param[in] fragments The number of data fragments.
    156  *  @param[out] data_fragment_size The data fragment size in bytes.
    157  *  @param[in] flags Various send flags.
    158  *  @returns EOK on success.
    159  *  @returns EAFNOTSUPPORT if the address family is not supported.
    160  *  @returns ENOTSOCK if the socket is not found.
    161  *  @returns EINVAL if the address is invalid.
    162  *  @returns ENOTCONN if the sending socket is not and cannot be bound.
    163  *  @returns ENOMEM if there is not enough memory left.
    164  *  @returns Other error codes as defined for the socket_read_packet_data() function.
    165  *  @returns Other error codes as defined for the ip_client_prepare_packet() function.
    166  *  @returns Other error codes as defined for the ip_send_msg() function.
    167  */
    168 int udp_sendto_message(socket_cores_ref local_sockets, int socket_id, const struct sockaddr * addr, socklen_t addrlen, int fragments, size_t * data_fragment_size, int flags);
    169 
    170 /** Receives data to the socket.
    171  *  Handles the NET_SOCKET_RECVFROM message.
    172  *  Replies the source address as well.
    173  *  @param[in] local_sockets The application local sockets.
    174  *  @param[in] socket_id Socket identifier.
    175  *  @param[in] flags Various receive flags.
    176  *  @param[out] addrlen The source address length.
    177  *  @returns The number of bytes received.
    178  *  @returns ENOTSOCK if the socket is not found.
    179  *  @returns NO_DATA if there are no received packets or data.
    180  *  @returns ENOMEM if there is not enough memory left.
    181  *  @returns EINVAL if the received address is not an IP address.
    182  *  @returns Other error codes as defined for the packet_translate() function.
    183  *  @returns Other error codes as defined for the data_reply() function.
    184  */
    185 int udp_recvfrom_message(socket_cores_ref local_sockets, int socket_id, int flags, size_t * addrlen);
    186 
    187 /*@}*/
    188 
    189 /** UDP global data.
    190  */
    191 udp_globals_t   udp_globals;
    192 
    193 int udp_initialize(async_client_conn_t client_connection){
    194         ERROR_DECLARE;
    195 
    196         measured_string_t names[] = {{str_dup("UDP_CHECKSUM_COMPUTING"), 22}, {str_dup("UDP_AUTOBINDING"), 15}};
    197         measured_string_ref configuration;
     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
     320 *                      udp_process_packet() function.
     321 */
     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{
     375        measured_string_t names[] = {
     376                {
     377                        (uint8_t *) "UDP_CHECKSUM_COMPUTING",
     378                        22
     379                },
     380                {
     381                        (uint8_t *) "UDP_AUTOBINDING",
     382                        15
     383                }
     384        };
     385        measured_string_t *configuration;
    198386        size_t count = sizeof(names) / sizeof(measured_string_t);
    199         char * data;
    200 
     387        uint8_t *data;
     388       
    201389        fibril_rwlock_initialize(&udp_globals.lock);
    202390        fibril_rwlock_write_lock(&udp_globals.lock);
    203         udp_globals.icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT);
    204         udp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_UDP, SERVICE_UDP, client_connection, udp_received_msg);
    205         if(udp_globals.ip_phone < 0){
     391       
     392        udp_globals.net_phone = net_phone;
     393       
     394        udp_globals.icmp_phone = icmp_connect_module(ICMP_CONNECT_TIMEOUT);
     395       
     396        udp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_UDP,
     397            SERVICE_UDP, udp_receiver);
     398        if (udp_globals.ip_phone < 0) {
     399                fibril_rwlock_write_unlock(&udp_globals.lock);
    206400                return udp_globals.ip_phone;
    207401        }
    208         // read default packet dimensions
    209         ERROR_PROPAGATE(ip_packet_size_req(udp_globals.ip_phone, -1, &udp_globals.packet_dimension));
    210         ERROR_PROPAGATE(socket_ports_initialize(&udp_globals.sockets));
    211         if(ERROR_OCCURRED(packet_dimensions_initialize(&udp_globals.dimensions))){
    212                 socket_ports_destroy(&udp_globals.sockets);
    213                 return ERROR_CODE;
    214         }
     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       
    215424        udp_globals.packet_dimension.prefix += sizeof(udp_header_t);
    216425        udp_globals.packet_dimension.content -= sizeof(udp_header_t);
    217426        udp_globals.last_used_port = UDP_FREE_PORTS_START - 1;
    218         // get configuration
     427
    219428        udp_globals.checksum_computing = NET_DEFAULT_UDP_CHECKSUM_COMPUTING;
    220429        udp_globals.autobinding = NET_DEFAULT_UDP_AUTOBINDING;
     430
     431        /* Get configuration */
    221432        configuration = &names[0];
    222         ERROR_PROPAGATE(net_get_conf_req(udp_globals.net_phone, &configuration, count, &data));
    223         if(configuration){
    224                 if(configuration[0].value){
    225                         udp_globals.checksum_computing = (configuration[0].value[0] == 'y');
    226                 }
    227                 if(configuration[1].value){
    228                         udp_globals.autobinding = (configuration[1].value[0] == 'y');
    229                 }
     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       
     441        if (configuration) {
     442                if (configuration[0].value)
     443                        udp_globals.checksum_computing =
     444                            (configuration[0].value[0] == 'y');
     445               
     446                if (configuration[1].value)
     447                        udp_globals.autobinding =
     448                            (configuration[1].value[0] == 'y');
     449
    230450                net_free_settings(configuration, data);
    231451        }
     452
    232453        fibril_rwlock_write_unlock(&udp_globals.lock);
    233454        return EOK;
    234455}
    235456
    236 int udp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error){
    237         int result;
    238 
    239         fibril_rwlock_write_lock(&udp_globals.lock);
    240         result = udp_process_packet(device_id, packet, error);
    241         if(result != EOK){
    242                 fibril_rwlock_write_unlock(&udp_globals.lock);
    243         }
    244 
    245         return result;
    246 }
    247 
    248 int udp_process_packet(device_id_t device_id, packet_t packet, services_t error){
    249         ERROR_DECLARE;
    250 
    251         size_t length;
    252         size_t offset;
    253         int result;
    254         udp_header_ref header;
    255         socket_core_ref socket;
    256         packet_t next_packet;
    257         size_t total_length;
    258         uint32_t checksum;
    259         int fragments;
    260         packet_t tmp_packet;
    261         icmp_type_t type;
    262         icmp_code_t code;
    263         void *ip_header;
    264         struct sockaddr * src;
    265         struct sockaddr * dest;
    266         packet_dimension_ref packet_dimension;
    267 
    268         if(error){
    269                 switch(error){
    270                         case SERVICE_ICMP:
    271                                 // ignore error
    272                                 // length = icmp_client_header_length(packet);
    273                                 // process error
    274                                 result = icmp_client_process_packet(packet, &type, &code, NULL, NULL);
    275                                 if(result < 0){
    276                                         return udp_release_and_return(packet, result);
    277                                 }
    278                                 length = (size_t) result;
    279                                 if(ERROR_OCCURRED(packet_trim(packet, length, 0))){
    280                                         return udp_release_and_return(packet, ERROR_CODE);
    281                                 }
    282                                 break;
    283                         default:
    284                                 return udp_release_and_return(packet, ENOTSUP);
    285                 }
    286         }
    287         // TODO process received ipopts?
    288         result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
    289         if(result < 0){
    290                 return udp_release_and_return(packet, result);
    291         }
    292         offset = (size_t) result;
    293 
    294         length = packet_get_data_length(packet);
    295         if(length <= 0){
    296                 return udp_release_and_return(packet, EINVAL);
    297         }
    298         if(length < UDP_HEADER_SIZE + offset){
    299                 return udp_release_and_return(packet, NO_DATA);
    300         }
    301 
    302         // trim all but UDP header
    303         if(ERROR_OCCURRED(packet_trim(packet, offset, 0))){
    304                 return udp_release_and_return(packet, ERROR_CODE);
    305         }
    306 
    307         // get udp header
    308         header = (udp_header_ref) packet_get_data(packet);
    309         if(! header){
    310                 return udp_release_and_return(packet, NO_DATA);
    311         }
    312         // find the destination socket
    313         socket = socket_port_find(&udp_globals.sockets, ntohs(header->destination_port), SOCKET_MAP_KEY_LISTENING, 0);
    314         if(! socket){
    315                 if(tl_prepare_icmp_packet(udp_globals.net_phone, udp_globals.icmp_phone, packet, error) == EOK){
    316                         icmp_destination_unreachable_msg(udp_globals.icmp_phone, ICMP_PORT_UNREACH, 0, packet);
    317                 }
    318                 return EADDRNOTAVAIL;
    319         }
    320 
    321         // count the received packet fragments
    322         next_packet = packet;
    323         fragments = 0;
    324         total_length = ntohs(header->total_length);
    325         // compute header checksum if set
    326         if(header->checksum && (! error)){
    327                 result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest);
    328                 if(result <= 0){
    329                         return udp_release_and_return(packet, result);
    330                 }
    331                 if(ERROR_OCCURRED(ip_client_get_pseudo_header(IPPROTO_UDP, src, result, dest, result, total_length, &ip_header, &length))){
    332                         return udp_release_and_return(packet, ERROR_CODE);
    333                 }else{
    334                         checksum = compute_checksum(0, ip_header, length);
    335                         // the udp header checksum will be added with the first fragment later
    336                         free(ip_header);
    337                 }
    338         }else{
    339                 header->checksum = 0;
    340                 checksum = 0;
    341         }
    342 
    343         do{
    344                 ++ fragments;
    345                 length = packet_get_data_length(next_packet);
    346                 if(length <= 0){
    347                         return udp_release_and_return(packet, NO_DATA);
    348                 }
    349                 if(total_length < length){
    350                         if(ERROR_OCCURRED(packet_trim(next_packet, 0, length - total_length))){
    351                                 return udp_release_and_return(packet, ERROR_CODE);
    352                         }
    353                         // add partial checksum if set
    354                         if(header->checksum){
    355                                 checksum = compute_checksum(checksum, packet_get_data(packet), packet_get_data_length(packet));
    356                         }
    357                         // relese the rest of the packet fragments
    358                         tmp_packet = pq_next(next_packet);
    359                         while(tmp_packet){
    360                                 next_packet = pq_detach(tmp_packet);
    361                                 pq_release_remote(udp_globals.net_phone, packet_get_id(tmp_packet));
    362                                 tmp_packet = next_packet;
    363                         }
    364                         // exit the loop
    365                         break;
    366                 }
    367                 total_length -= length;
    368                 // add partial checksum if set
    369                 if(header->checksum){
    370                         checksum = compute_checksum(checksum, packet_get_data(packet), packet_get_data_length(packet));
    371                 }
    372         }while((next_packet = pq_next(next_packet)) && (total_length > 0));
    373 
    374         // check checksum
    375         if(header->checksum){
    376                 if(flip_checksum(compact_checksum(checksum)) != IP_CHECKSUM_ZERO){
    377                         if(tl_prepare_icmp_packet(udp_globals.net_phone, udp_globals.icmp_phone, packet, error) == EOK){
    378                                 // checksum error ICMP
    379                                 icmp_parameter_problem_msg(udp_globals.icmp_phone, ICMP_PARAM_POINTER, ((size_t) ((void *) &header->checksum)) - ((size_t) ((void *) header)), packet);
    380                         }
    381                         return EINVAL;
    382                 }
    383         }
    384 
    385         // queue the received packet
    386         if(ERROR_OCCURRED(dyn_fifo_push(&socket->received, packet_get_id(packet), SOCKET_MAX_RECEIVED_SIZE))
    387             || ERROR_OCCURRED(tl_get_ip_packet_dimension(udp_globals.ip_phone, &udp_globals.dimensions, device_id, &packet_dimension))){
    388                 return udp_release_and_return(packet, ERROR_CODE);
    389         }
    390 
    391         // notify the destination socket
    392         fibril_rwlock_write_unlock(&udp_globals.lock);
    393         async_msg_5(socket->phone, NET_SOCKET_RECEIVED, (ipcarg_t) socket->socket_id, packet_dimension->content, 0, 0, (ipcarg_t) fragments);
    394         return EOK;
    395 }
    396 
    397 int udp_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
    398         ERROR_DECLARE;
    399 
    400         packet_t packet;
    401 
    402         *answer_count = 0;
    403         switch(IPC_GET_METHOD(*call)){
    404                 case NET_TL_RECEIVED:
    405                         if(! ERROR_OCCURRED(packet_translate_remote(udp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
    406                                 ERROR_CODE = udp_received_msg(IPC_GET_DEVICE(call), packet, SERVICE_UDP, IPC_GET_ERROR(call));
    407                         }
    408                         return ERROR_CODE;
    409                 case IPC_M_CONNECT_TO_ME:
    410                         return udp_process_client_messages(callid, * call);
    411         }
    412         return ENOTSUP;
    413 }
    414 
    415 int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call){
    416         int res;
    417         bool keep_on_going = true;
    418         socket_cores_t local_sockets;
    419         int app_phone = IPC_GET_PHONE(&call);
    420         struct sockaddr * addr;
    421         int socket_id;
    422         size_t addrlen;
    423         size_t size;
    424         ipc_call_t answer;
    425         int answer_count;
    426         packet_dimension_ref packet_dimension;
    427 
    428         /*
    429          * Accept the connection
    430          *  - Answer the first IPC_M_CONNECT_TO_ME call.
    431          */
    432         res = EOK;
    433         answer_count = 0;
    434 
    435         // The client connection is only in one fibril and therefore no additional locks are needed.
    436 
    437         socket_cores_initialize(&local_sockets);
    438 
    439         while(keep_on_going){
    440 
    441                 // answer the call
    442                 answer_call(callid, res, &answer, answer_count);
    443 
    444                 // refresh data
    445                 refresh_answer(&answer, &answer_count);
    446 
    447                 // get the next call
    448                 callid = async_get_call(&call);
    449 
    450                 // process the call
    451                 switch(IPC_GET_METHOD(call)){
    452                         case IPC_M_PHONE_HUNGUP:
    453                                 keep_on_going = false;
    454                                 res = EHANGUP;
    455                                 break;
    456                         case NET_SOCKET:
    457                                 socket_id = SOCKET_GET_SOCKET_ID(call);
    458                                 res = socket_create(&local_sockets, app_phone, NULL, &socket_id);
    459                                 SOCKET_SET_SOCKET_ID(answer, socket_id);
    460 
    461                                 if(res == EOK){
    462                                         if (tl_get_ip_packet_dimension(udp_globals.ip_phone, &udp_globals.dimensions, DEVICE_INVALID_ID, &packet_dimension) == EOK){
    463                                                 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, packet_dimension->content);
    464                                         }
    465 //                                      SOCKET_SET_DATA_FRAGMENT_SIZE(answer, MAX_UDP_FRAGMENT_SIZE);
    466                                         SOCKET_SET_HEADER_SIZE(answer, UDP_HEADER_SIZE);
    467                                         answer_count = 3;
    468                                 }
    469                                 break;
    470                         case NET_SOCKET_BIND:
    471                                 res = data_receive((void **) &addr, &addrlen);
    472                                 if(res == EOK){
    473                                         fibril_rwlock_write_lock(&udp_globals.lock);
    474                                         res = socket_bind(&local_sockets, &udp_globals.sockets, SOCKET_GET_SOCKET_ID(call), addr, addrlen, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port);
    475                                         fibril_rwlock_write_unlock(&udp_globals.lock);
    476                                         free(addr);
    477                                 }
    478                                 break;
    479                         case NET_SOCKET_SENDTO:
    480                                 res = data_receive((void **) &addr, &addrlen);
    481                                 if(res == EOK){
    482                                         fibril_rwlock_write_lock(&udp_globals.lock);
    483                                         res = udp_sendto_message(&local_sockets, SOCKET_GET_SOCKET_ID(call), addr, addrlen, SOCKET_GET_DATA_FRAGMENTS(call), &size, SOCKET_GET_FLAGS(call));
    484                                         SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
    485                                         if(res != EOK){
    486                                                 fibril_rwlock_write_unlock(&udp_globals.lock);
    487                                         }else{
    488                                                 answer_count = 2;
    489                                         }
    490                                         free(addr);
    491                                 }
    492                                 break;
    493                         case NET_SOCKET_RECVFROM:
    494                                 fibril_rwlock_write_lock(&udp_globals.lock);
    495                                 res = udp_recvfrom_message(&local_sockets, SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call), &addrlen);
    496                                 fibril_rwlock_write_unlock(&udp_globals.lock);
    497                                 if(res > 0){
    498                                         SOCKET_SET_READ_DATA_LENGTH(answer, res);
    499                                         SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
    500                                         answer_count = 3;
    501                                         res = EOK;
    502                                 }
    503                                 break;
    504                         case NET_SOCKET_CLOSE:
    505                                 fibril_rwlock_write_lock(&udp_globals.lock);
    506                                 res = socket_destroy(udp_globals.net_phone, SOCKET_GET_SOCKET_ID(call), &local_sockets, &udp_globals.sockets, NULL);
    507                                 fibril_rwlock_write_unlock(&udp_globals.lock);
    508                                 break;
    509                         case NET_SOCKET_GETSOCKOPT:
    510                         case NET_SOCKET_SETSOCKOPT:
    511                         default:
    512                                 res = ENOTSUP;
    513                                 break;
    514                 }
    515         }
    516 
    517         // release the application phone
    518         ipc_hangup(app_phone);
    519 
    520         // release all local sockets
    521         socket_cores_release(udp_globals.net_phone, &local_sockets, &udp_globals.sockets, NULL);
    522 
    523         return res;
    524 }
    525 
    526 int udp_sendto_message(socket_cores_ref local_sockets, int socket_id, const struct sockaddr * addr, socklen_t addrlen, int fragments, size_t * data_fragment_size, int flags){
    527         ERROR_DECLARE;
    528 
    529         socket_core_ref socket;
    530         packet_t packet;
    531         packet_t next_packet;
    532         udp_header_ref header;
     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;
    533492        int index;
    534493        size_t total_length;
     
    539498        size_t headerlen;
    540499        device_id_t device_id;
    541         packet_dimension_ref packet_dimension;
    542 
    543         ERROR_PROPAGATE(tl_get_address_port(addr, addrlen, &dest_port));
     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;
    544510
    545511        socket = socket_cores_find(local_sockets, socket_id);
    546         if(! socket){
     512        if (!socket)
    547513                return ENOTSOCK;
    548         }
    549 
    550         if((socket->port <= 0) && udp_globals.autobinding){
    551                 // bind the socket to a random free port if not bound
    552 //              do{
    553                         // try to find a free port
    554 //                      fibril_rwlock_read_unlock(&udp_globals.lock);
    555 //                      fibril_rwlock_write_lock(&udp_globals.lock);
    556                         // might be changed in the meantime
    557 //                      if(socket->port <= 0){
    558                                 if(ERROR_OCCURRED(socket_bind_free_port(&udp_globals.sockets, socket, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port))){
    559 //                                      fibril_rwlock_write_unlock(&udp_globals.lock);
    560 //                                      fibril_rwlock_read_lock(&udp_globals.lock);
    561                                         return ERROR_CODE;
    562                                 }
    563                                 // set the next port as the search starting port number
    564                                 udp_globals.last_used_port = socket->port;
    565 //                      }
    566 //                      fibril_rwlock_write_unlock(&udp_globals.lock);
    567 //                      fibril_rwlock_read_lock(&udp_globals.lock);
    568                         // might be changed in the meantime
    569 //              }while(socket->port <= 0);
    570         }
    571 
    572         if(udp_globals.checksum_computing){
    573                 if(ERROR_OCCURRED(ip_get_route_req(udp_globals.ip_phone, IPPROTO_UDP, addr, addrlen, &device_id, &ip_header, &headerlen))){
    574                         return udp_release_and_return(packet, ERROR_CODE);
    575                 }
    576                 // get the device packet dimension
    577 //              ERROR_PROPAGATE(tl_get_ip_packet_dimension(udp_globals.ip_phone, &udp_globals.dimensions, device_id, &packet_dimension));
    578         }
    579 //      }else{
    580                 // do not ask all the time
    581                 ERROR_PROPAGATE(ip_packet_size_req(udp_globals.ip_phone, -1, &udp_globals.packet_dimension));
     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;
    582543                packet_dimension = &udp_globals.packet_dimension;
    583544//      }
    584545
    585         // read the first packet fragment
    586         result = tl_socket_read_packet_data(udp_globals.net_phone, &packet, UDP_HEADER_SIZE, packet_dimension, addr, addrlen);
    587         if(result < 0){
     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)
    588560                return result;
    589         }
     561
    590562        total_length = (size_t) result;
    591         if(udp_globals.checksum_computing){
    592                 checksum = compute_checksum(0, packet_get_data(packet), packet_get_data_length(packet));
    593         }else{
     563        if (udp_globals.checksum_computing)
     564                checksum = compute_checksum(0, packet_get_data(packet),
     565                    packet_get_data_length(packet));
     566        else
    594567                checksum = 0;
    595         }
    596         // prefix the udp header
     568
     569        /* Prefix the UDP header */
    597570        header = PACKET_PREFIX(packet, udp_header_t);
    598         if(! header){
     571        if (!header)
    599572                return udp_release_and_return(packet, ENOMEM);
    600         }
     573
    601574        bzero(header, sizeof(*header));
    602         // read the rest of the packet fragments
    603         for(index = 1; index < fragments; ++ index){
    604                 result = tl_socket_read_packet_data(udp_globals.net_phone, &next_packet, 0, packet_dimension, addr, addrlen);
    605                 if(result < 0){
     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)
    606581                        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));
    607592                }
    608                 if(ERROR_OCCURRED(pq_add(&packet, next_packet, index, 0))){
    609                         return udp_release_and_return(packet, ERROR_CODE);
    610                 }
    611                 total_length += (size_t) result;
    612                 if(udp_globals.checksum_computing){
    613                         checksum = compute_checksum(checksum, packet_get_data(next_packet), packet_get_data_length(next_packet));
    614                 }
    615         }
    616         // set the udp header
     593        }
     594
     595        /* Set the UDP header */
    617596        header->source_port = htons((socket->port > 0) ? socket->port : 0);
    618597        header->destination_port = htons(dest_port);
    619598        header->total_length = htons(total_length + sizeof(*header));
    620599        header->checksum = 0;
    621         if(udp_globals.checksum_computing){
    622                 // update the pseudo header
    623                 if(ERROR_OCCURRED(ip_client_set_pseudo_header_data_length(ip_header, headerlen, total_length + UDP_HEADER_SIZE))){
     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) {
    624606                        free(ip_header);
    625                         return udp_release_and_return(packet, ERROR_CODE);
     607                        return udp_release_and_return(packet, rc);
    626608                }
    627                 // finish the checksum computation
     609
     610                /* Finish the checksum computation */
    628611                checksum = compute_checksum(checksum, ip_header, headerlen);
    629                 checksum = compute_checksum(checksum, (uint8_t *) header, sizeof(*header));
    630                 header->checksum = htons(flip_checksum(compact_checksum(checksum)));
     612                checksum = compute_checksum(checksum, (uint8_t *) header,
     613                    sizeof(*header));
     614                header->checksum =
     615                    htons(flip_checksum(compact_checksum(checksum)));
    631616                free(ip_header);
    632         }else{
     617        } else {
    633618                device_id = DEVICE_INVALID_ID;
    634619        }
    635         // prepare the first packet fragment
    636         if(ERROR_OCCURRED(ip_client_prepare_packet(packet, IPPROTO_UDP, 0, 0, 0, 0))){
    637                 return udp_release_and_return(packet, ERROR_CODE);
    638         }
    639         // send the packet
     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. */
    640627        fibril_rwlock_write_unlock(&udp_globals.lock);
     628
     629        /* Send the packet */
    641630        ip_send_msg(udp_globals.ip_phone, device_id, packet, SERVICE_UDP, 0);
     631
    642632        return EOK;
    643633}
    644634
    645 int udp_recvfrom_message(socket_cores_ref local_sockets, int socket_id, int flags, size_t * addrlen){
    646         ERROR_DECLARE;
    647 
    648         socket_core_ref socket;
     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;
    649658        int packet_id;
    650         packet_t packet;
    651         udp_header_ref header;
    652         struct sockaddr * addr;
     659        packet_t *packet;
     660        udp_header_t *header;
     661        struct sockaddr *addr;
    653662        size_t length;
    654         uint8_t * data;
     663        uint8_t *data;
    655664        int result;
    656 
    657         // find the socket
     665        int rc;
     666
     667        /* Find the socket */
    658668        socket = socket_cores_find(local_sockets, socket_id);
    659         if(! socket){
     669        if (!socket)
    660670                return ENOTSOCK;
    661         }
    662         // get the next received packet
     671
     672        /* Get the next received packet */
    663673        packet_id = dyn_fifo_value(&socket->received);
    664         if(packet_id < 0){
     674        if (packet_id < 0)
    665675                return NO_DATA;
    666         }
    667         ERROR_PROPAGATE(packet_translate_remote(udp_globals.net_phone, &packet, packet_id));
    668         // get udp header
     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 */
    669684        data = packet_get_data(packet);
    670         if(! data){
    671                 pq_release_remote(udp_globals.net_phone, packet_id);
    672                 return NO_DATA;
    673         }
    674         header = (udp_header_ref) data;
    675 
    676         // set the source address port
     685        if (!data) {
     686                (void) dyn_fifo_pop(&socket->received);
     687                return udp_release_and_return(packet, NO_DATA);
     688        }
     689        header = (udp_header_t *) data;
     690
     691        /* Set the source address port */
    677692        result = packet_get_addr(packet, (uint8_t **) &addr, NULL);
    678         if(ERROR_OCCURRED(tl_set_address_port(addr, result, ntohs(header->source_port)))){
    679                 pq_release_remote(udp_globals.net_phone, packet_id);
    680                 return ERROR_CODE;
     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);
    681697        }
    682698        *addrlen = (size_t) result;
    683         // send the source address
    684         ERROR_PROPAGATE(data_reply(addr, * addrlen));
    685 
    686         // trim the header
    687         ERROR_PROPAGATE(packet_trim(packet, UDP_HEADER_SIZE, 0));
    688 
    689         // reply the packets
    690         ERROR_PROPAGATE(socket_reply_packets(packet, &length));
    691 
    692         // release the packet
    693         dyn_fifo_pop(&socket->received);
    694         pq_release_remote(udp_globals.net_phone, packet_get_id(packet));
    695         // return the total length
    696         return (int) length;
    697 }
    698 
    699 int udp_release_and_return(packet_t packet, int result){
    700         pq_release_remote(udp_globals.net_phone, packet_get_id(packet));
    701         return result;
    702 }
    703 
    704 /** Default thread for new connections.
    705  *
    706  *  @param[in] iid The initial message identifier.
    707  *  @param[in] icall The initial message call structure.
    708  *
    709  */
    710 static void tl_client_connection(ipc_callid_t iid, ipc_call_t * icall)
    711 {
     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)
     748{
     749        int res;
     750        bool keep_on_going = true;
     751        socket_cores_t local_sockets;
     752        int app_phone = IPC_GET_PHONE(call);
     753        struct sockaddr *addr;
     754        int socket_id;
     755        size_t addrlen;
     756        size_t size;
     757        ipc_call_t answer;
     758        size_t answer_count;
     759        packet_dimension_t *packet_dimension;
     760
    712761        /*
    713762         * Accept the connection
    714          *  - Answer the first IPC_M_CONNECT_ME_TO call.
     763         *  - Answer the first IPC_M_CONNECT_TO_ME call.
    715764         */
    716         ipc_answer_0(iid, EOK);
    717        
    718         while(true) {
    719                 ipc_call_t answer;
    720                 int answer_count;
    721                
    722                 /* Clear the answer structure */
     765        res = EOK;
     766        answer_count = 0;
     767
     768        /*
     769         * The client connection is only in one fibril and therefore no
     770         * additional locks are needed.
     771         */
     772
     773        socket_cores_initialize(&local_sockets);
     774
     775        while (keep_on_going) {
     776
     777                /* Answer the call */
     778                answer_call(callid, res, &answer, answer_count);
     779
     780                /* Refresh data */
    723781                refresh_answer(&answer, &answer_count);
    724                
    725                 /* Fetch the next message */
    726                 ipc_call_t call;
    727                 ipc_callid_t callid = async_get_call(&call);
    728                
    729                 /* Process the message */
    730                 int res = tl_module_message_standalone(callid, &call, &answer,
    731                     &answer_count);
    732                
    733                 /* End if said to either by the message or the processing result */
    734                 if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) || (res == EHANGUP))
    735                         return;
    736                
    737                 /* Answer the message */
    738                 answer_call(callid, res, &answer, answer_count);
    739         }
    740 }
    741 
    742 /** Starts the module.
    743  *
    744  *  @param argc The count of the command line arguments. Ignored parameter.
    745  *  @param argv The command line parameters. Ignored parameter.
    746  *
    747  *  @returns EOK on success.
    748  *  @returns Other error codes as defined for each specific module start function.
    749  *
    750  */
     782
     783                /* Get the next call */
     784                callid = async_get_call(&call);
     785
     786                /* Process the call */
     787                switch (IPC_GET_IMETHOD(call)) {
     788                case IPC_M_PHONE_HUNGUP:
     789                        keep_on_going = false;
     790                        res = EHANGUP;
     791                        break;
     792
     793                case NET_SOCKET:
     794                        socket_id = SOCKET_GET_SOCKET_ID(call);
     795                        res = socket_create(&local_sockets, app_phone, NULL,
     796                            &socket_id);
     797                        SOCKET_SET_SOCKET_ID(answer, socket_id);
     798
     799                        if (res != EOK)
     800                                break;
     801                       
     802                        size = MAX_UDP_FRAGMENT_SIZE;
     803                        if (tl_get_ip_packet_dimension(udp_globals.ip_phone,
     804                            &udp_globals.dimensions, DEVICE_INVALID_ID,
     805                            &packet_dimension) == EOK) {
     806                                if (packet_dimension->content < size)
     807                                        size = packet_dimension->content;
     808                        }
     809                        SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
     810                        SOCKET_SET_HEADER_SIZE(answer, UDP_HEADER_SIZE);
     811                        answer_count = 3;
     812                        break;
     813
     814                case NET_SOCKET_BIND:
     815                        res = async_data_write_accept((void **) &addr, false,
     816                            0, 0, 0, &addrlen);
     817                        if (res != EOK)
     818                                break;
     819                        fibril_rwlock_write_lock(&udp_globals.lock);
     820                        res = socket_bind(&local_sockets, &udp_globals.sockets,
     821                            SOCKET_GET_SOCKET_ID(call), addr, addrlen,
     822                            UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
     823                            udp_globals.last_used_port);
     824                        fibril_rwlock_write_unlock(&udp_globals.lock);
     825                        free(addr);
     826                        break;
     827
     828                case NET_SOCKET_SENDTO:
     829                        res = async_data_write_accept((void **) &addr, false,
     830                            0, 0, 0, &addrlen);
     831                        if (res != EOK)
     832                                break;
     833
     834                        fibril_rwlock_write_lock(&udp_globals.lock);
     835                        res = udp_sendto_message(&local_sockets,
     836                            SOCKET_GET_SOCKET_ID(call), addr, addrlen,
     837                            SOCKET_GET_DATA_FRAGMENTS(call), &size,
     838                            SOCKET_GET_FLAGS(call));
     839                        SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
     840
     841                        if (res != EOK)
     842                                fibril_rwlock_write_unlock(&udp_globals.lock);
     843                        else
     844                                answer_count = 2;
     845                       
     846                        free(addr);
     847                        break;
     848
     849                case NET_SOCKET_RECVFROM:
     850                        fibril_rwlock_write_lock(&udp_globals.lock);
     851                        res = udp_recvfrom_message(&local_sockets,
     852                             SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call),
     853                             &addrlen);
     854                        fibril_rwlock_write_unlock(&udp_globals.lock);
     855
     856                        if (res <= 0)
     857                                break;
     858
     859                        SOCKET_SET_READ_DATA_LENGTH(answer, res);
     860                        SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
     861                        answer_count = 3;
     862                        res = EOK;
     863                        break;
     864                       
     865                case NET_SOCKET_CLOSE:
     866                        fibril_rwlock_write_lock(&udp_globals.lock);
     867                        res = socket_destroy(udp_globals.net_phone,
     868                            SOCKET_GET_SOCKET_ID(call), &local_sockets,
     869                            &udp_globals.sockets, NULL);
     870                        fibril_rwlock_write_unlock(&udp_globals.lock);
     871                        break;
     872
     873                case NET_SOCKET_GETSOCKOPT:
     874                case NET_SOCKET_SETSOCKOPT:
     875                default:
     876                        res = ENOTSUP;
     877                        break;
     878                }
     879        }
     880
     881        /* Release the application phone */
     882        async_hangup(app_phone);
     883
     884        /* Release all local sockets */
     885        socket_cores_release(udp_globals.net_phone, &local_sockets,
     886            &udp_globals.sockets, NULL);
     887
     888        return res;
     889}
     890
     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
    751924int main(int argc, char *argv[])
    752925{
    753         ERROR_DECLARE;
    754        
    755926        /* Start the module */
    756         if (ERROR_OCCURRED(tl_module_start_standalone(tl_client_connection)))
    757                 return ERROR_CODE;
    758        
    759         return EOK;
     927        return tl_module_start(SERVICE_UDP);
    760928}
    761929
Note: See TracChangeset for help on using the changeset viewer.