udp.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008 Lukas Mejdrech
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00038 #include <async.h>
00039 #include <fibril_synch.h>
00040 #include <malloc.h>
00041 #include <stdio.h>
00042 #include <ipc/services.h>
00043 #include <ipc/net.h>
00044 #include <ipc/tl.h>
00045 #include <ipc/socket.h>
00046 #include <adt/dynamic_fifo.h>
00047 #include <errno.h>
00048 
00049 #include <net/socket_codes.h>
00050 #include <net/ip_protocols.h>
00051 #include <net/in.h>
00052 #include <net/in6.h>
00053 #include <net/inet.h>
00054 #include <net/modules.h>
00055 
00056 #include <packet_client.h>
00057 #include <packet_remote.h>
00058 #include <net_checksum.h>
00059 #include <ip_client.h>
00060 #include <ip_interface.h>
00061 #include <icmp_client.h>
00062 #include <icmp_remote.h>
00063 #include <net_interface.h>
00064 #include <socket_core.h>
00065 #include <tl_common.h>
00066 #include <tl_remote.h>
00067 #include <tl_skel.h>
00068 
00069 #include "udp.h"
00070 #include "udp_header.h"
00071 
00073 #define NAME  "udp"
00074 
00076 #define NET_DEFAULT_UDP_CHECKSUM_COMPUTING      true
00077 
00079 #define NET_DEFAULT_UDP_AUTOBINDING     true
00080 
00082 #define MAX_UDP_FRAGMENT_SIZE           65535
00083 
00085 #define UDP_FREE_PORTS_START            1025
00086 
00088 #define UDP_FREE_PORTS_END              65535
00089 
00091 udp_globals_t udp_globals;
00092 
00099 static int udp_release_and_return(packet_t *packet, int result)
00100 {
00101         pq_release_remote(udp_globals.net_phone, packet_get_id(packet));
00102         return result;
00103 }
00104 
00126 static int udp_process_packet(device_id_t device_id, packet_t *packet,
00127     services_t error)
00128 {
00129         size_t length;
00130         size_t offset;
00131         int result;
00132         udp_header_t *header;
00133         socket_core_t *socket;
00134         packet_t *next_packet;
00135         size_t total_length;
00136         uint32_t checksum;
00137         int fragments;
00138         packet_t *tmp_packet;
00139         icmp_type_t type;
00140         icmp_code_t code;
00141         void *ip_header;
00142         struct sockaddr *src;
00143         struct sockaddr *dest;
00144         packet_dimension_t *packet_dimension;
00145         int rc;
00146 
00147         switch (error) {
00148         case SERVICE_NONE:
00149                 break;
00150         case SERVICE_ICMP:
00151                 /* Ignore error */
00152                 // length = icmp_client_header_length(packet);
00153 
00154                 /* Process error */
00155                 result = icmp_client_process_packet(packet, &type,
00156                     &code, NULL, NULL);
00157                 if (result < 0)
00158                         return udp_release_and_return(packet, result);
00159                 length = (size_t) result;
00160                 rc = packet_trim(packet, length, 0);
00161                 if (rc != EOK)
00162                         return udp_release_and_return(packet, rc);
00163                 break;
00164         default:
00165                 return udp_release_and_return(packet, ENOTSUP);
00166         }
00167 
00168         /* TODO process received ipopts? */
00169         result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
00170         if (result < 0)
00171                 return udp_release_and_return(packet, result);
00172         offset = (size_t) result;
00173 
00174         length = packet_get_data_length(packet);
00175         if (length <= 0)
00176                 return udp_release_and_return(packet, EINVAL);
00177         if (length < UDP_HEADER_SIZE + offset)
00178                 return udp_release_and_return(packet, NO_DATA);
00179 
00180         /* Trim all but UDP header */
00181         rc = packet_trim(packet, offset, 0);
00182         if (rc != EOK)
00183                 return udp_release_and_return(packet, rc);
00184 
00185         /* Get UDP header */
00186         header = (udp_header_t *) packet_get_data(packet);
00187         if (!header)
00188                 return udp_release_and_return(packet, NO_DATA);
00189 
00190         /* Find the destination socket */
00191         socket = socket_port_find(&udp_globals.sockets,
00192             ntohs(header->destination_port), (uint8_t *) SOCKET_MAP_KEY_LISTENING, 0);
00193         if (!socket) {
00194                 if (tl_prepare_icmp_packet(udp_globals.net_phone,
00195                     udp_globals.icmp_phone, packet, error) == EOK) {
00196                         icmp_destination_unreachable_msg(udp_globals.icmp_phone,
00197                             ICMP_PORT_UNREACH, 0, packet);
00198                 }
00199                 return EADDRNOTAVAIL;
00200         }
00201 
00202         /* Count the received packet fragments */
00203         next_packet = packet;
00204         fragments = 0;
00205         total_length = ntohs(header->total_length);
00206 
00207         /* Compute header checksum if set */
00208         if (header->checksum && !error) {
00209                 result = packet_get_addr(packet, (uint8_t **) &src,
00210                     (uint8_t **) &dest);
00211                 if (result <= 0)
00212                         return udp_release_and_return(packet, result);
00213                 
00214                 rc = ip_client_get_pseudo_header(IPPROTO_UDP, src, result, dest,
00215                     result, total_length, &ip_header, &length);
00216                 if (rc != EOK) {
00217                         return udp_release_and_return(packet, rc);
00218                 } else {
00219                         checksum = compute_checksum(0, ip_header, length);
00220                         /*
00221                          * The udp header checksum will be added with the first
00222                          * fragment later.
00223                          */
00224                         free(ip_header);
00225                 }
00226         } else {
00227                 header->checksum = 0;
00228                 checksum = 0;
00229         }
00230 
00231         do {
00232                 fragments++;
00233                 length = packet_get_data_length(next_packet);
00234                 if (length <= 0)
00235                         return udp_release_and_return(packet, NO_DATA);
00236 
00237                 if (total_length < length) {
00238                         rc = packet_trim(next_packet, 0, length - total_length);
00239                         if (rc != EOK)
00240                                 return udp_release_and_return(packet, rc);
00241 
00242                         /* Add partial checksum if set */
00243                         if (header->checksum) {
00244                                 checksum = compute_checksum(checksum,
00245                                     packet_get_data(packet),
00246                                     packet_get_data_length(packet));
00247                         }
00248 
00249                         /* Relese the rest of the packet fragments */
00250                         tmp_packet = pq_next(next_packet);
00251                         while (tmp_packet) {
00252                                 next_packet = pq_detach(tmp_packet);
00253                                 pq_release_remote(udp_globals.net_phone,
00254                                     packet_get_id(tmp_packet));
00255                                 tmp_packet = next_packet;
00256                         }
00257 
00258                         /* Exit the loop */
00259                         break;
00260                 }
00261                 total_length -= length;
00262 
00263                 /* Add partial checksum if set */
00264                 if (header->checksum) {
00265                         checksum = compute_checksum(checksum,
00266                             packet_get_data(packet),
00267                             packet_get_data_length(packet));
00268                 }
00269 
00270         } while ((next_packet = pq_next(next_packet)) && (total_length > 0));
00271 
00272         /* Verify checksum */
00273         if (header->checksum) {
00274                 if (flip_checksum(compact_checksum(checksum)) !=
00275                     IP_CHECKSUM_ZERO) {
00276                         if (tl_prepare_icmp_packet(udp_globals.net_phone,
00277                             udp_globals.icmp_phone, packet, error) == EOK) {
00278                                 /* Checksum error ICMP */
00279                                 icmp_parameter_problem_msg(
00280                                     udp_globals.icmp_phone, ICMP_PARAM_POINTER,
00281                                     ((size_t) ((void *) &header->checksum)) -
00282                                     ((size_t) ((void *) header)), packet);
00283                         }
00284                         return EINVAL;
00285                 }
00286         }
00287 
00288         /* Queue the received packet */
00289         rc = dyn_fifo_push(&socket->received, packet_get_id(packet),
00290             SOCKET_MAX_RECEIVED_SIZE);
00291         if (rc != EOK)
00292                 return udp_release_and_return(packet, rc);
00293                 
00294         rc = tl_get_ip_packet_dimension(udp_globals.ip_phone,
00295             &udp_globals.dimensions, device_id, &packet_dimension);
00296         if (rc != EOK)
00297                 return udp_release_and_return(packet, rc);
00298 
00299         /* Notify the destination socket */
00300         fibril_rwlock_write_unlock(&udp_globals.lock);
00301         async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
00302             (sysarg_t) socket->socket_id, packet_dimension->content, 0, 0,
00303             (sysarg_t) fragments);
00304 
00305         return EOK;
00306 }
00307 
00322 static int udp_received_msg(device_id_t device_id, packet_t *packet,
00323     services_t receiver, services_t error)
00324 {
00325         int result;
00326 
00327         fibril_rwlock_write_lock(&udp_globals.lock);
00328         result = udp_process_packet(device_id, packet, error);
00329         if (result != EOK)
00330                 fibril_rwlock_write_unlock(&udp_globals.lock);
00331 
00332         return result;
00333 }
00334 
00341 static void udp_receiver(ipc_callid_t iid, ipc_call_t *icall)
00342 {
00343         packet_t *packet;
00344         int rc;
00345         
00346         while (true) {
00347                 switch (IPC_GET_IMETHOD(*icall)) {
00348                 case NET_TL_RECEIVED:
00349                         rc = packet_translate_remote(udp_globals.net_phone, &packet,
00350                             IPC_GET_PACKET(*icall));
00351                         if (rc == EOK)
00352                                 rc = udp_received_msg(IPC_GET_DEVICE(*icall), packet,
00353                                     SERVICE_UDP, IPC_GET_ERROR(*icall));
00354                         
00355                         async_answer_0(iid, (sysarg_t) rc);
00356                         break;
00357                 default:
00358                         async_answer_0(iid, (sysarg_t) ENOTSUP);
00359                 }
00360                 
00361                 iid = async_get_call(icall);
00362         }
00363 }
00364 
00373 int tl_initialize(int net_phone)
00374 {
00375         measured_string_t names[] = {
00376                 {
00377                         (uint8_t *) "UDP_CHECKSUM_COMPUTING",
00378                         22
00379                 },
00380                 {
00381                         (uint8_t *) "UDP_AUTOBINDING",
00382                         15
00383                 }
00384         };
00385         measured_string_t *configuration;
00386         size_t count = sizeof(names) / sizeof(measured_string_t);
00387         uint8_t *data;
00388         
00389         fibril_rwlock_initialize(&udp_globals.lock);
00390         fibril_rwlock_write_lock(&udp_globals.lock);
00391         
00392         udp_globals.net_phone = net_phone;
00393         
00394         udp_globals.icmp_phone = icmp_connect_module(ICMP_CONNECT_TIMEOUT);
00395         
00396         udp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_UDP,
00397             SERVICE_UDP, udp_receiver);
00398         if (udp_globals.ip_phone < 0) {
00399                 fibril_rwlock_write_unlock(&udp_globals.lock);
00400                 return udp_globals.ip_phone;
00401         }
00402         
00403         /* Read default packet dimensions */
00404         int rc = ip_packet_size_req(udp_globals.ip_phone, -1,
00405             &udp_globals.packet_dimension);
00406         if (rc != EOK) {
00407                 fibril_rwlock_write_unlock(&udp_globals.lock);
00408                 return rc;
00409         }
00410         
00411         rc = socket_ports_initialize(&udp_globals.sockets);
00412         if (rc != EOK) {
00413                 fibril_rwlock_write_unlock(&udp_globals.lock);
00414                 return rc;
00415         }
00416         
00417         rc = packet_dimensions_initialize(&udp_globals.dimensions);
00418         if (rc != EOK) {
00419                 socket_ports_destroy(&udp_globals.sockets, free);
00420                 fibril_rwlock_write_unlock(&udp_globals.lock);
00421                 return rc;
00422         }
00423         
00424         udp_globals.packet_dimension.prefix += sizeof(udp_header_t);
00425         udp_globals.packet_dimension.content -= sizeof(udp_header_t);
00426         udp_globals.last_used_port = UDP_FREE_PORTS_START - 1;
00427 
00428         udp_globals.checksum_computing = NET_DEFAULT_UDP_CHECKSUM_COMPUTING;
00429         udp_globals.autobinding = NET_DEFAULT_UDP_AUTOBINDING;
00430 
00431         /* Get configuration */
00432         configuration = &names[0];
00433         rc = net_get_conf_req(udp_globals.net_phone, &configuration, count,
00434             &data);
00435         if (rc != EOK) {
00436                 socket_ports_destroy(&udp_globals.sockets, free);
00437                 fibril_rwlock_write_unlock(&udp_globals.lock);
00438                 return rc;
00439         }
00440         
00441         if (configuration) {
00442                 if (configuration[0].value)
00443                         udp_globals.checksum_computing =
00444                             (configuration[0].value[0] == 'y');
00445                 
00446                 if (configuration[1].value)
00447                         udp_globals.autobinding =
00448                             (configuration[1].value[0] == 'y');
00449 
00450                 net_free_settings(configuration, data);
00451         }
00452 
00453         fibril_rwlock_write_unlock(&udp_globals.lock);
00454         return EOK;
00455 }
00456 
00484 static int udp_sendto_message(socket_cores_t *local_sockets, int socket_id,
00485     const struct sockaddr *addr, socklen_t addrlen, int fragments,
00486     size_t *data_fragment_size, int flags)
00487 {
00488         socket_core_t *socket;
00489         packet_t *packet;
00490         packet_t *next_packet;
00491         udp_header_t *header;
00492         int index;
00493         size_t total_length;
00494         int result;
00495         uint16_t dest_port;
00496         uint32_t checksum;
00497         void *ip_header;
00498         size_t headerlen;
00499         device_id_t device_id;
00500         packet_dimension_t *packet_dimension;
00501         size_t size;
00502         int rc;
00503 
00504         /* In case of error, do not update the data fragment size. */
00505         *data_fragment_size = 0;
00506         
00507         rc = tl_get_address_port(addr, addrlen, &dest_port);
00508         if (rc != EOK)
00509                 return rc;
00510 
00511         socket = socket_cores_find(local_sockets, socket_id);
00512         if (!socket)
00513                 return ENOTSOCK;
00514 
00515         if ((socket->port <= 0) && udp_globals.autobinding) {
00516                 /* Bind the socket to a random free port if not bound */
00517                 rc = socket_bind_free_port(&udp_globals.sockets, socket,
00518                     UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
00519                     udp_globals.last_used_port);
00520                 if (rc != EOK)
00521                         return rc;
00522                 /* Set the next port as the search starting port number */
00523                 udp_globals.last_used_port = socket->port;
00524         }
00525 
00526         if (udp_globals.checksum_computing) {
00527                 rc = ip_get_route_req(udp_globals.ip_phone, IPPROTO_UDP, addr,
00528                     addrlen, &device_id, &ip_header, &headerlen);
00529                 if (rc != EOK)
00530                         return rc;
00531                 /* Get the device packet dimension */
00532 //              rc = tl_get_ip_packet_dimension(udp_globals.ip_phone,
00533 //                  &udp_globals.dimensions, device_id, &packet_dimension);
00534 //              if (rc != EOK)
00535 //                      return rc;
00536         }
00537 //      } else {
00538                 /* Do not ask all the time */
00539                 rc = ip_packet_size_req(udp_globals.ip_phone, -1,
00540                     &udp_globals.packet_dimension);
00541                 if (rc != EOK)
00542                         return rc;
00543                 packet_dimension = &udp_globals.packet_dimension;
00544 //      }
00545 
00546         /*
00547          * Update the data fragment size based on what the lower layers can
00548          * handle without fragmentation, but not more than the maximum allowed
00549          * for UDP.
00550          */
00551         size = MAX_UDP_FRAGMENT_SIZE;
00552         if (packet_dimension->content < size)
00553             size = packet_dimension->content;
00554         *data_fragment_size = size;
00555 
00556         /* Read the first packet fragment */
00557         result = tl_socket_read_packet_data(udp_globals.net_phone, &packet,
00558             UDP_HEADER_SIZE, packet_dimension, addr, addrlen);
00559         if (result < 0)
00560                 return result;
00561 
00562         total_length = (size_t) result;
00563         if (udp_globals.checksum_computing)
00564                 checksum = compute_checksum(0, packet_get_data(packet),
00565                     packet_get_data_length(packet));
00566         else
00567                 checksum = 0;
00568 
00569         /* Prefix the UDP header */
00570         header = PACKET_PREFIX(packet, udp_header_t);
00571         if (!header)
00572                 return udp_release_and_return(packet, ENOMEM);
00573 
00574         bzero(header, sizeof(*header));
00575 
00576         /* Read the rest of the packet fragments */
00577         for (index = 1; index < fragments; index++) {
00578                 result = tl_socket_read_packet_data(udp_globals.net_phone,
00579                     &next_packet, 0, packet_dimension, addr, addrlen);
00580                 if (result < 0)
00581                         return udp_release_and_return(packet, result);
00582 
00583                 rc = pq_add(&packet, next_packet, index, 0);
00584                 if (rc != EOK)
00585                         return udp_release_and_return(packet, rc);
00586 
00587                 total_length += (size_t) result;
00588                 if (udp_globals.checksum_computing) {
00589                         checksum = compute_checksum(checksum,
00590                             packet_get_data(next_packet),
00591                             packet_get_data_length(next_packet));
00592                 }
00593         }
00594 
00595         /* Set the UDP header */
00596         header->source_port = htons((socket->port > 0) ? socket->port : 0);
00597         header->destination_port = htons(dest_port);
00598         header->total_length = htons(total_length + sizeof(*header));
00599         header->checksum = 0;
00600 
00601         if (udp_globals.checksum_computing) {
00602                 /* Update the pseudo header */
00603                 rc = ip_client_set_pseudo_header_data_length(ip_header,
00604                     headerlen, total_length + UDP_HEADER_SIZE);
00605                 if (rc != EOK) {
00606                         free(ip_header);
00607                         return udp_release_and_return(packet, rc);
00608                 }
00609 
00610                 /* Finish the checksum computation */
00611                 checksum = compute_checksum(checksum, ip_header, headerlen);
00612                 checksum = compute_checksum(checksum, (uint8_t *) header,
00613                     sizeof(*header));
00614                 header->checksum =
00615                     htons(flip_checksum(compact_checksum(checksum)));
00616                 free(ip_header);
00617         } else {
00618                 device_id = DEVICE_INVALID_ID;
00619         }
00620 
00621         /* Prepare the first packet fragment */
00622         rc = ip_client_prepare_packet(packet, IPPROTO_UDP, 0, 0, 0, 0);
00623         if (rc != EOK)
00624                 return udp_release_and_return(packet, rc);
00625 
00626         /* Release the UDP global lock on success. */
00627         fibril_rwlock_write_unlock(&udp_globals.lock);
00628 
00629         /* Send the packet */
00630         ip_send_msg(udp_globals.ip_phone, device_id, packet, SERVICE_UDP, 0);
00631 
00632         return EOK;
00633 }
00634 
00654 static int udp_recvfrom_message(socket_cores_t *local_sockets, int socket_id,
00655     int flags, size_t *addrlen)
00656 {
00657         socket_core_t *socket;
00658         int packet_id;
00659         packet_t *packet;
00660         udp_header_t *header;
00661         struct sockaddr *addr;
00662         size_t length;
00663         uint8_t *data;
00664         int result;
00665         int rc;
00666 
00667         /* Find the socket */
00668         socket = socket_cores_find(local_sockets, socket_id);
00669         if (!socket)
00670                 return ENOTSOCK;
00671 
00672         /* Get the next received packet */
00673         packet_id = dyn_fifo_value(&socket->received);
00674         if (packet_id < 0)
00675                 return NO_DATA;
00676         
00677         rc = packet_translate_remote(udp_globals.net_phone, &packet, packet_id);
00678         if (rc != EOK) {
00679                 (void) dyn_fifo_pop(&socket->received);
00680                 return rc;
00681         }
00682 
00683         /* Get UDP header */
00684         data = packet_get_data(packet);
00685         if (!data) {
00686                 (void) dyn_fifo_pop(&socket->received);
00687                 return udp_release_and_return(packet, NO_DATA);
00688         }
00689         header = (udp_header_t *) data;
00690 
00691         /* Set the source address port */
00692         result = packet_get_addr(packet, (uint8_t **) &addr, NULL);
00693         rc = tl_set_address_port(addr, result, ntohs(header->source_port));
00694         if (rc != EOK) {
00695                 (void) dyn_fifo_pop(&socket->received);
00696                 return udp_release_and_return(packet, rc);
00697         }
00698         *addrlen = (size_t) result;
00699 
00700         /* Send the source address */
00701         rc = data_reply(addr, *addrlen);
00702         switch (rc) {
00703         case EOK:
00704                 break;
00705         case EOVERFLOW:
00706                 return rc;
00707         default:
00708                 (void) dyn_fifo_pop(&socket->received);
00709                 return udp_release_and_return(packet, rc);
00710         }
00711 
00712         /* Trim the header */
00713         rc = packet_trim(packet, UDP_HEADER_SIZE, 0);
00714         if (rc != EOK) {
00715                 (void) dyn_fifo_pop(&socket->received);
00716                 return udp_release_and_return(packet, rc);
00717         }
00718 
00719         /* Reply the packets */
00720         rc = socket_reply_packets(packet, &length);
00721         switch (rc) {
00722         case EOK:
00723                 break;
00724         case EOVERFLOW:
00725                 return rc;
00726         default:
00727                 (void) dyn_fifo_pop(&socket->received);
00728                 return udp_release_and_return(packet, rc);
00729         }
00730 
00731         (void) dyn_fifo_pop(&socket->received);
00732 
00733         /* Release the packet and return the total length */
00734         return udp_release_and_return(packet, (int) length);
00735 }
00736 
00747 static int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
00748 {
00749         int res;
00750         bool keep_on_going = true;
00751         socket_cores_t local_sockets;
00752         int app_phone = IPC_GET_PHONE(call);
00753         struct sockaddr *addr;
00754         int socket_id;
00755         size_t addrlen;
00756         size_t size;
00757         ipc_call_t answer;
00758         size_t answer_count;
00759         packet_dimension_t *packet_dimension;
00760 
00761         /*
00762          * Accept the connection
00763          *  - Answer the first IPC_M_CONNECT_TO_ME call.
00764          */
00765         res = EOK;
00766         answer_count = 0;
00767 
00768         /*
00769          * The client connection is only in one fibril and therefore no
00770          * additional locks are needed.
00771          */
00772 
00773         socket_cores_initialize(&local_sockets);
00774 
00775         while (keep_on_going) {
00776 
00777                 /* Answer the call */
00778                 answer_call(callid, res, &answer, answer_count);
00779 
00780                 /* Refresh data */
00781                 refresh_answer(&answer, &answer_count);
00782 
00783                 /* Get the next call */
00784                 callid = async_get_call(&call);
00785 
00786                 /* Process the call */
00787                 switch (IPC_GET_IMETHOD(call)) {
00788                 case IPC_M_PHONE_HUNGUP:
00789                         keep_on_going = false;
00790                         res = EHANGUP;
00791                         break;
00792 
00793                 case NET_SOCKET:
00794                         socket_id = SOCKET_GET_SOCKET_ID(call);
00795                         res = socket_create(&local_sockets, app_phone, NULL,
00796                             &socket_id);
00797                         SOCKET_SET_SOCKET_ID(answer, socket_id);
00798 
00799                         if (res != EOK)
00800                                 break;
00801                         
00802                         size = MAX_UDP_FRAGMENT_SIZE;
00803                         if (tl_get_ip_packet_dimension(udp_globals.ip_phone,
00804                             &udp_globals.dimensions, DEVICE_INVALID_ID,
00805                             &packet_dimension) == EOK) {
00806                                 if (packet_dimension->content < size)
00807                                         size = packet_dimension->content;
00808                         }
00809                         SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
00810                         SOCKET_SET_HEADER_SIZE(answer, UDP_HEADER_SIZE);
00811                         answer_count = 3;
00812                         break;
00813 
00814                 case NET_SOCKET_BIND:
00815                         res = async_data_write_accept((void **) &addr, false,
00816                             0, 0, 0, &addrlen);
00817                         if (res != EOK)
00818                                 break;
00819                         fibril_rwlock_write_lock(&udp_globals.lock);
00820                         res = socket_bind(&local_sockets, &udp_globals.sockets,
00821                             SOCKET_GET_SOCKET_ID(call), addr, addrlen,
00822                             UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
00823                             udp_globals.last_used_port);
00824                         fibril_rwlock_write_unlock(&udp_globals.lock);
00825                         free(addr);
00826                         break;
00827 
00828                 case NET_SOCKET_SENDTO:
00829                         res = async_data_write_accept((void **) &addr, false,
00830                             0, 0, 0, &addrlen);
00831                         if (res != EOK)
00832                                 break;
00833 
00834                         fibril_rwlock_write_lock(&udp_globals.lock);
00835                         res = udp_sendto_message(&local_sockets,
00836                             SOCKET_GET_SOCKET_ID(call), addr, addrlen,
00837                             SOCKET_GET_DATA_FRAGMENTS(call), &size,
00838                             SOCKET_GET_FLAGS(call));
00839                         SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
00840 
00841                         if (res != EOK)
00842                                 fibril_rwlock_write_unlock(&udp_globals.lock);
00843                         else
00844                                 answer_count = 2;
00845                         
00846                         free(addr);
00847                         break;
00848 
00849                 case NET_SOCKET_RECVFROM:
00850                         fibril_rwlock_write_lock(&udp_globals.lock);
00851                         res = udp_recvfrom_message(&local_sockets,
00852                              SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call),
00853                              &addrlen);
00854                         fibril_rwlock_write_unlock(&udp_globals.lock);
00855 
00856                         if (res <= 0)
00857                                 break;
00858 
00859                         SOCKET_SET_READ_DATA_LENGTH(answer, res);
00860                         SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
00861                         answer_count = 3;
00862                         res = EOK;
00863                         break;
00864                         
00865                 case NET_SOCKET_CLOSE:
00866                         fibril_rwlock_write_lock(&udp_globals.lock);
00867                         res = socket_destroy(udp_globals.net_phone,
00868                             SOCKET_GET_SOCKET_ID(call), &local_sockets,
00869                             &udp_globals.sockets, NULL);
00870                         fibril_rwlock_write_unlock(&udp_globals.lock);
00871                         break;
00872 
00873                 case NET_SOCKET_GETSOCKOPT:
00874                 case NET_SOCKET_SETSOCKOPT:
00875                 default:
00876                         res = ENOTSUP;
00877                         break;
00878                 }
00879         }
00880 
00881         /* Release the application phone */
00882         async_hangup(app_phone);
00883 
00884         /* Release all local sockets */
00885         socket_cores_release(udp_globals.net_phone, &local_sockets,
00886             &udp_globals.sockets, NULL);
00887 
00888         return res;
00889 }
00890 
00894 void tl_connection(void)
00895 {
00896 }
00897 
00911 int tl_message(ipc_callid_t callid, ipc_call_t *call,
00912     ipc_call_t *answer, size_t *answer_count)
00913 {
00914         *answer_count = 0;
00915 
00916         switch (IPC_GET_IMETHOD(*call)) {
00917         case IPC_M_CONNECT_TO_ME:
00918                 return udp_process_client_messages(callid, *call);
00919         }
00920 
00921         return ENOTSUP;
00922 }
00923 
00924 int main(int argc, char *argv[])
00925 {
00926         /* Start the module */
00927         return tl_module_start(SERVICE_UDP);
00928 }
00929 

Generated on Thu Jun 2 07:45:50 2011 for HelenOS/USB by  doxygen 1.4.7