ip.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 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 <errno.h>
00040 #include <fibril_synch.h>
00041 #include <stdio.h>
00042 #include <str.h>
00043 #include <ipc/services.h>
00044 #include <ipc/net.h>
00045 #include <ipc/nil.h>
00046 #include <ipc/il.h>
00047 #include <ipc/ip.h>
00048 #include <sys/types.h>
00049 #include <byteorder.h>
00050 #include "ip.h"
00051 
00052 #include <adt/measured_strings.h>
00053 #include <adt/module_map.h>
00054 
00055 #include <packet_client.h>
00056 #include <net/socket_codes.h>
00057 #include <net/in.h>
00058 #include <net/in6.h>
00059 #include <net/inet.h>
00060 #include <net/modules.h>
00061 #include <net/device.h>
00062 #include <net/packet.h>
00063 #include <net/icmp_codes.h>
00064 
00065 #include <arp_interface.h>
00066 #include <net_checksum.h>
00067 #include <icmp_client.h>
00068 #include <icmp_remote.h>
00069 #include <ip_client.h>
00070 #include <ip_interface.h>
00071 #include <ip_header.h>
00072 #include <net_interface.h>
00073 #include <nil_remote.h>
00074 #include <tl_remote.h>
00075 #include <packet_remote.h>
00076 #include <il_remote.h>
00077 #include <il_skel.h>
00078 
00080 #define NAME                    "ip"
00081 
00083 #define IPV4                    4
00084 
00086 #define NET_DEFAULT_IPV         IPV4
00087 
00089 #define NET_DEFAULT_IP_ROUTING  false
00090 
00092 #define IP_MIN_CONTENT          576
00093 
00095 #define ARP_NAME                "arp"
00096 
00098 #define ARP_FILENAME            "/srv/arp"
00099 
00101 #define IP_ADDR                 sizeof(struct sockaddr_in6)
00102 
00104 #define IP_PREFIX               sizeof(ip_header_t)
00105 
00107 #define IP_SUFFIX               0
00108 
00110 #define IP_MAX_CONTENT          65535
00111 
00113 #define IPV4_LOCALHOST_ADDRESS  htonl((127 << 24) + 1)
00114 
00116 ip_globals_t ip_globals;
00117 
00118 DEVICE_MAP_IMPLEMENT(ip_netifs, ip_netif_t);
00119 INT_MAP_IMPLEMENT(ip_protos, ip_proto_t);
00120 GENERIC_FIELD_IMPLEMENT(ip_routes, ip_route_t);
00121 
00122 static void ip_receiver(ipc_callid_t, ipc_call_t *);
00123 
00130 static int ip_release_and_return(packet_t *packet, int result)
00131 {
00132         pq_release_remote(ip_globals.net_phone, packet_get_id(packet));
00133         return result;
00134 }
00135 
00143 static int ip_get_icmp_phone(void)
00144 {
00145         ip_proto_t *proto;
00146         int phone;
00147 
00148         fibril_rwlock_read_lock(&ip_globals.protos_lock);
00149         proto = ip_protos_find(&ip_globals.protos, IPPROTO_ICMP);
00150         phone = proto ? proto->phone : ENOENT;
00151         fibril_rwlock_read_unlock(&ip_globals.protos_lock);
00152         return phone;
00153 }
00154 
00171 static int ip_prepare_icmp(packet_t *packet, ip_header_t *header)
00172 {
00173         packet_t *next;
00174         struct sockaddr *dest;
00175         struct sockaddr_in dest_in;
00176         socklen_t addrlen;
00177 
00178         /* Detach the first packet and release the others */
00179         next = pq_detach(packet);
00180         if (next)
00181                 pq_release_remote(ip_globals.net_phone, packet_get_id(next));
00182 
00183         if (!header) {
00184                 if (packet_get_data_length(packet) <= sizeof(ip_header_t))
00185                         return ENOMEM;
00186 
00187                 /* Get header */
00188                 header = (ip_header_t *) packet_get_data(packet);
00189                 if (!header)
00190                         return EINVAL;
00191 
00192         }
00193 
00194         /* Only for the first fragment */
00195         if (IP_FRAGMENT_OFFSET(header))
00196                 return EINVAL;
00197 
00198         /* Not for the ICMP protocol */
00199         if (header->protocol == IPPROTO_ICMP)
00200                 return EPERM;
00201 
00202         /* Set the destination address */
00203         switch (GET_IP_HEADER_VERSION(header)) {
00204         case IPVERSION:
00205                 addrlen = sizeof(dest_in);
00206                 bzero(&dest_in, addrlen);
00207                 dest_in.sin_family = AF_INET;
00208                 memcpy(&dest_in.sin_addr.s_addr, &header->source_address,
00209                     sizeof(header->source_address));
00210                 dest = (struct sockaddr *) &dest_in;
00211                 break;
00212 
00213         default:
00214                 return EAFNOSUPPORT;
00215         }
00216 
00217         return packet_set_addr(packet, NULL, (uint8_t *) dest, addrlen);
00218 }
00219 
00233 static int
00234 ip_prepare_icmp_and_get_phone(services_t error, packet_t *packet,
00235     ip_header_t *header)
00236 {
00237         int phone;
00238 
00239         phone = ip_get_icmp_phone();
00240         if (error || (phone < 0) || ip_prepare_icmp(packet, header))
00241                 return ip_release_and_return(packet, EINVAL);
00242         return phone;
00243 }
00244 
00245 int il_initialize(int net_phone)
00246 {
00247         fibril_rwlock_initialize(&ip_globals.lock);
00248         fibril_rwlock_write_lock(&ip_globals.lock);
00249         fibril_rwlock_initialize(&ip_globals.protos_lock);
00250         fibril_rwlock_initialize(&ip_globals.netifs_lock);
00251         
00252         ip_globals.net_phone = net_phone;
00253         ip_globals.packet_counter = 0;
00254         ip_globals.gateway.address.s_addr = 0;
00255         ip_globals.gateway.netmask.s_addr = 0;
00256         ip_globals.gateway.gateway.s_addr = 0;
00257         ip_globals.gateway.netif = NULL;
00258         
00259         int rc = ip_netifs_initialize(&ip_globals.netifs);
00260         if (rc != EOK)
00261                 goto out;
00262         rc = ip_protos_initialize(&ip_globals.protos);
00263         if (rc != EOK)
00264                 goto out;
00265         rc = modules_initialize(&ip_globals.modules);
00266         if (rc != EOK)
00267                 goto out;
00268         rc = add_module(NULL, &ip_globals.modules, (uint8_t *) ARP_NAME,
00269             (uint8_t *) ARP_FILENAME, SERVICE_ARP, 0, arp_connect_module);
00270 
00271 out:
00272         fibril_rwlock_write_unlock(&ip_globals.lock);
00273 
00274         return rc;
00275 }
00276 
00301 static int ip_netif_initialize(ip_netif_t *ip_netif)
00302 {
00303         measured_string_t names[] = {
00304                 {
00305                         (uint8_t *) "IPV",
00306                         3
00307                 },
00308                 {
00309                         (uint8_t *) "IP_CONFIG",
00310                         9
00311                 },
00312                 {
00313                         (uint8_t *) "IP_ADDR",
00314                         7
00315                 },
00316                 {
00317                         (uint8_t *) "IP_NETMASK",
00318                         10
00319                 },
00320                 {
00321                         (uint8_t *) "IP_GATEWAY",
00322                         10
00323                 },
00324                 {
00325                         (uint8_t *) "IP_BROADCAST",
00326                         12
00327                 },
00328                 {
00329                         (uint8_t *) "ARP",
00330                         3
00331                 },
00332                 {
00333                         (uint8_t *) "IP_ROUTING",
00334                         10
00335                 }
00336         };
00337         measured_string_t *configuration;
00338         size_t count = sizeof(names) / sizeof(measured_string_t);
00339         uint8_t *data;
00340         measured_string_t address;
00341         ip_route_t *route;
00342         in_addr_t gateway;
00343         int index;
00344         int rc;
00345 
00346         ip_netif->arp = NULL;
00347         route = NULL;
00348         ip_netif->ipv = NET_DEFAULT_IPV;
00349         ip_netif->dhcp = false;
00350         ip_netif->routing = NET_DEFAULT_IP_ROUTING;
00351         configuration = &names[0];
00352 
00353         /* Get configuration */
00354         rc = net_get_device_conf_req(ip_globals.net_phone, ip_netif->device_id,
00355             &configuration, count, &data);
00356         if (rc != EOK)
00357                 return rc;
00358         
00359         if (configuration) {
00360                 if (configuration[0].value)
00361                         ip_netif->ipv = strtol((char *) configuration[0].value, NULL, 0);
00362                 
00363                 ip_netif->dhcp = !str_lcmp((char *) configuration[1].value, "dhcp",
00364                     configuration[1].length);
00365                 
00366                 if (ip_netif->dhcp) {
00367                         // TODO dhcp
00368                         net_free_settings(configuration, data);
00369                         return ENOTSUP;
00370                 } else if (ip_netif->ipv == IPV4) {
00371                         route = (ip_route_t *) malloc(sizeof(ip_route_t));
00372                         if (!route) {
00373                                 net_free_settings(configuration, data);
00374                                 return ENOMEM;
00375                         }
00376                         route->address.s_addr = 0;
00377                         route->netmask.s_addr = 0;
00378                         route->gateway.s_addr = 0;
00379                         route->netif = ip_netif;
00380                         index = ip_routes_add(&ip_netif->routes, route);
00381                         if (index < 0) {
00382                                 net_free_settings(configuration, data);
00383                                 free(route);
00384                                 return index;
00385                         }
00386                         
00387                         if ((inet_pton(AF_INET, (char *) configuration[2].value,
00388                             (uint8_t *) &route->address.s_addr) != EOK) ||
00389                             (inet_pton(AF_INET, (char *) configuration[3].value,
00390                             (uint8_t *) &route->netmask.s_addr) != EOK) ||
00391                             (inet_pton(AF_INET, (char *) configuration[4].value,
00392                             (uint8_t *) &gateway.s_addr) == EINVAL) ||
00393                             (inet_pton(AF_INET, (char *) configuration[5].value,
00394                             (uint8_t *) &ip_netif->broadcast.s_addr) == EINVAL))
00395                             {
00396                                 net_free_settings(configuration, data);
00397                                 return EINVAL;
00398                         }
00399                 } else {
00400                         // TODO ipv6 in separate module
00401                         net_free_settings(configuration, data);
00402                         return ENOTSUP;
00403                 }
00404 
00405                 if (configuration[6].value) {
00406                         ip_netif->arp = get_running_module(&ip_globals.modules,
00407                             configuration[6].value);
00408                         if (!ip_netif->arp) {
00409                                 printf("Failed to start the arp %s\n",
00410                                     configuration[6].value);
00411                                 net_free_settings(configuration, data);
00412                                 return EINVAL;
00413                         }
00414                 }
00415                 if (configuration[7].value)
00416                         ip_netif->routing = (configuration[7].value[0] == 'y');
00417 
00418                 net_free_settings(configuration, data);
00419         }
00420 
00421         /* Bind netif service which also initializes the device */
00422         ip_netif->phone = nil_bind_service(ip_netif->service,
00423             (sysarg_t) ip_netif->device_id, SERVICE_IP,
00424             ip_receiver);
00425         if (ip_netif->phone < 0) {
00426                 printf("Failed to contact the nil service %d\n",
00427                     ip_netif->service);
00428                 return ip_netif->phone;
00429         }
00430 
00431         /* Has to be after the device netif module initialization */
00432         if (ip_netif->arp) {
00433                 if (route) {
00434                         address.value = (uint8_t *) &route->address.s_addr;
00435                         address.length = sizeof(in_addr_t);
00436                         
00437                         rc = arp_device_req(ip_netif->arp->phone,
00438                             ip_netif->device_id, SERVICE_IP, ip_netif->service,
00439                             &address);
00440                         if (rc != EOK)
00441                                 return rc;
00442                 } else {
00443                         ip_netif->arp = 0;
00444                 }
00445         }
00446 
00447         /* Get packet dimensions */
00448         rc = nil_packet_size_req(ip_netif->phone, ip_netif->device_id,
00449             &ip_netif->packet_dimension);
00450         if (rc != EOK)
00451                 return rc;
00452         
00453         if (ip_netif->packet_dimension.content < IP_MIN_CONTENT) {
00454                 printf("Maximum transmission unit %zu bytes is too small, at "
00455                     "least %d bytes are needed\n",
00456                     ip_netif->packet_dimension.content, IP_MIN_CONTENT);
00457                 ip_netif->packet_dimension.content = IP_MIN_CONTENT;
00458         }
00459 
00460         index = ip_netifs_add(&ip_globals.netifs, ip_netif->device_id, ip_netif);
00461         if (index < 0)
00462                 return index;
00463         
00464         if (gateway.s_addr) {
00465                 /* The default gateway */
00466                 ip_globals.gateway.address.s_addr = 0;
00467                 ip_globals.gateway.netmask.s_addr = 0;
00468                 ip_globals.gateway.gateway.s_addr = gateway.s_addr;
00469                 ip_globals.gateway.netif = ip_netif;
00470                 
00471                 char defgateway[INET_ADDRSTRLEN];
00472                 inet_ntop(AF_INET, (uint8_t *) &gateway.s_addr,
00473                     defgateway, INET_ADDRSTRLEN);
00474                 printf("%s: Default gateway (%s)\n", NAME, defgateway);
00475         }
00476 
00477         return EOK;
00478 }
00479 
00480 static int ip_device_req_local(int il_phone, device_id_t device_id,
00481     services_t netif)
00482 {
00483         ip_netif_t *ip_netif;
00484         ip_route_t *route;
00485         int index;
00486         int rc;
00487 
00488         ip_netif = (ip_netif_t *) malloc(sizeof(ip_netif_t));
00489         if (!ip_netif)
00490                 return ENOMEM;
00491 
00492         rc = ip_routes_initialize(&ip_netif->routes);
00493         if (rc != EOK) {
00494                 free(ip_netif);
00495                 return rc;
00496         }
00497 
00498         ip_netif->device_id = device_id;
00499         ip_netif->service = netif;
00500         ip_netif->state = NETIF_STOPPED;
00501 
00502         fibril_rwlock_write_lock(&ip_globals.netifs_lock);
00503 
00504         rc = ip_netif_initialize(ip_netif);
00505         if (rc != EOK) {
00506                 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
00507                 ip_routes_destroy(&ip_netif->routes, free);
00508                 free(ip_netif);
00509                 return rc;
00510         }
00511         if (ip_netif->arp)
00512                 ip_netif->arp->usage++;
00513 
00514         /* Print the settings */
00515         printf("%s: Device registered (id: %d, phone: %d, ipv: %d, conf: %s)\n",
00516             NAME, ip_netif->device_id, ip_netif->phone, ip_netif->ipv,
00517             ip_netif->dhcp ? "dhcp" : "static");
00518         
00519         // TODO ipv6 addresses
00520         
00521         char address[INET_ADDRSTRLEN];
00522         char netmask[INET_ADDRSTRLEN];
00523         char gateway[INET_ADDRSTRLEN];
00524         
00525         for (index = 0; index < ip_routes_count(&ip_netif->routes); index++) {
00526                 route = ip_routes_get_index(&ip_netif->routes, index);
00527                 if (route) {
00528                         inet_ntop(AF_INET, (uint8_t *) &route->address.s_addr,
00529                             address, INET_ADDRSTRLEN);
00530                         inet_ntop(AF_INET, (uint8_t *) &route->netmask.s_addr,
00531                             netmask, INET_ADDRSTRLEN);
00532                         inet_ntop(AF_INET, (uint8_t *) &route->gateway.s_addr,
00533                             gateway, INET_ADDRSTRLEN);
00534                         printf("%s: Route %d (address: %s, netmask: %s, "
00535                             "gateway: %s)\n", NAME, index, address, netmask,
00536                             gateway);
00537                 }
00538         }
00539         
00540         inet_ntop(AF_INET, (uint8_t *) &ip_netif->broadcast.s_addr, address,
00541             INET_ADDRSTRLEN);
00542         fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
00543 
00544         printf("%s: Broadcast (%s)\n", NAME, address);
00545 
00546         return EOK;
00547 }
00548 
00557 static ip_route_t *ip_netif_find_route(ip_netif_t *netif,
00558     in_addr_t destination)
00559 {
00560         int index;
00561         ip_route_t *route;
00562         
00563         if (!netif)
00564                 return NULL;
00565         
00566         /* Start with the first one (the direct route) */
00567         for (index = 0; index < ip_routes_count(&netif->routes); index++) {
00568                 route = ip_routes_get_index(&netif->routes, index);
00569                 if ((route) &&
00570                     ((route->address.s_addr & route->netmask.s_addr) ==
00571                     (destination.s_addr & route->netmask.s_addr)))
00572                         return route;
00573         }
00574 
00575         return NULL;
00576 }
00577 
00584 static ip_route_t *ip_find_route(in_addr_t destination) {
00585         int index;
00586         ip_route_t *route;
00587         ip_netif_t *netif;
00588 
00589         /* Start with the last netif - the newest one */
00590         index = ip_netifs_count(&ip_globals.netifs) - 1;
00591         while (index >= 0) {
00592                 netif = ip_netifs_get_index(&ip_globals.netifs, index);
00593                 if (netif && (netif->state == NETIF_ACTIVE)) {
00594                         route = ip_netif_find_route(netif, destination);
00595                         if (route)
00596                                 return route;
00597                 }
00598                 index--;
00599         }
00600 
00601         return &ip_globals.gateway;
00602 }
00603 
00610 static in_addr_t *ip_netif_address(ip_netif_t *netif)
00611 {
00612         ip_route_t *route;
00613 
00614         route = ip_routes_get_index(&netif->routes, 0);
00615         return route ? &route->address : NULL;
00616 }
00617 
00625 static void ip_create_last_header(ip_header_t *last, ip_header_t *first)
00626 {
00627         ip_option_t *option;
00628         size_t next;
00629         size_t length;
00630 
00631         /* Copy first itself */
00632         memcpy(last, first, sizeof(ip_header_t));
00633         length = sizeof(ip_header_t);
00634         next = sizeof(ip_header_t);
00635 
00636         /* Process all IP options */
00637         while (next < GET_IP_HEADER_LENGTH(first)) {
00638                 option = (ip_option_t *) (((uint8_t *) first) + next);
00639                 /* Skip end or noop */
00640                 if ((option->type == IPOPT_END) ||
00641                     (option->type == IPOPT_NOOP)) {
00642                         next++;
00643                 } else {
00644                         /* Copy if told so or skip */
00645                         if (IPOPT_COPIED(option->type)) {
00646                                 memcpy(((uint8_t *) last) + length,
00647                                     ((uint8_t *) first) + next, option->length);
00648                                 length += option->length;
00649                         }
00650                         /* Next option */
00651                         next += option->length;
00652                 }
00653         }
00654 
00655         /* Align 4 byte boundary */
00656         if (length % 4) {
00657                 bzero(((uint8_t *) last) + length, 4 - (length % 4));
00658                 SET_IP_HEADER_LENGTH(last, (length / 4 + 1));
00659         } else {
00660                 SET_IP_HEADER_LENGTH(last, (length / 4));
00661         }
00662 
00663         last->header_checksum = 0;
00664 }
00665 
00684 static int ip_prepare_packet(in_addr_t *source, in_addr_t dest,
00685     packet_t *packet, measured_string_t *destination)
00686 {
00687         size_t length;
00688         ip_header_t *header;
00689         ip_header_t *last_header;
00690         ip_header_t *middle_header;
00691         packet_t *next;
00692         int rc;
00693 
00694         length = packet_get_data_length(packet);
00695         if ((length < sizeof(ip_header_t)) || (length > IP_MAX_CONTENT))
00696                 return EINVAL;
00697 
00698         header = (ip_header_t *) packet_get_data(packet);
00699         if (destination) {
00700                 rc = packet_set_addr(packet, NULL, (uint8_t *) destination->value,
00701                     destination->length);
00702         } else {
00703                 rc = packet_set_addr(packet, NULL, NULL, 0);
00704         }
00705         if (rc != EOK)
00706                 return rc;
00707         
00708         SET_IP_HEADER_VERSION(header, IPV4);
00709         SET_IP_HEADER_FRAGMENT_OFFSET_HIGH(header, 0);
00710         header->fragment_offset_low = 0;
00711         header->header_checksum = 0;
00712         if (source)
00713                 header->source_address = source->s_addr;
00714         header->destination_address = dest.s_addr;
00715 
00716         fibril_rwlock_write_lock(&ip_globals.lock);
00717         ip_globals.packet_counter++;
00718         header->identification = htons(ip_globals.packet_counter);
00719         fibril_rwlock_write_unlock(&ip_globals.lock);
00720 
00721         if (pq_next(packet)) {
00722                 last_header = (ip_header_t *) malloc(IP_HEADER_LENGTH(header));
00723                 if (!last_header)
00724                         return ENOMEM;
00725                 ip_create_last_header(last_header, header);
00726                 next = pq_next(packet);
00727                 while (pq_next(next)) {
00728                         middle_header = (ip_header_t *) packet_prefix(next,
00729                             IP_HEADER_LENGTH(last_header));
00730                         if (!middle_header) {
00731                                 free(last_header);
00732                                 return ENOMEM;
00733                         }
00734 
00735                         memcpy(middle_header, last_header,
00736                             IP_HEADER_LENGTH(last_header));
00737                         SET_IP_HEADER_FLAGS(header,
00738                             (GET_IP_HEADER_FLAGS(header) | IPFLAG_MORE_FRAGMENTS));
00739                         middle_header->total_length =
00740                             htons(packet_get_data_length(next));
00741                         SET_IP_HEADER_FRAGMENT_OFFSET_HIGH(middle_header,
00742                             IP_COMPUTE_FRAGMENT_OFFSET_HIGH(length));
00743                         middle_header->fragment_offset_low =
00744                             IP_COMPUTE_FRAGMENT_OFFSET_LOW(length);
00745                         middle_header->header_checksum =
00746                             IP_HEADER_CHECKSUM(middle_header);
00747                         if (destination) {
00748                                 rc = packet_set_addr(next, NULL,
00749                                     (uint8_t *) destination->value,
00750                                     destination->length);
00751                                 if (rc != EOK) {
00752                                         free(last_header);
00753                                         return rc;
00754                                 }
00755                         }
00756                         length += packet_get_data_length(next);
00757                         next = pq_next(next);
00758                 }
00759 
00760                 middle_header = (ip_header_t *) packet_prefix(next,
00761                     IP_HEADER_LENGTH(last_header));
00762                 if (!middle_header) {
00763                         free(last_header);
00764                         return ENOMEM;
00765                 }
00766 
00767                 memcpy(middle_header, last_header,
00768                     IP_HEADER_LENGTH(last_header));
00769                 middle_header->total_length =
00770                     htons(packet_get_data_length(next));
00771                 SET_IP_HEADER_FRAGMENT_OFFSET_HIGH(middle_header,
00772                     IP_COMPUTE_FRAGMENT_OFFSET_HIGH(length));
00773                 middle_header->fragment_offset_low =
00774                     IP_COMPUTE_FRAGMENT_OFFSET_LOW(length);
00775                 middle_header->header_checksum =
00776                     IP_HEADER_CHECKSUM(middle_header);
00777                 if (destination) {
00778                         rc = packet_set_addr(next, NULL,
00779                             (uint8_t *) destination->value,
00780                             destination->length);
00781                         if (rc != EOK) {
00782                                 free(last_header);
00783                                 return rc;
00784                         }
00785                 }
00786                 length += packet_get_data_length(next);
00787                 free(last_header);
00788                 SET_IP_HEADER_FLAGS(header,
00789                     (GET_IP_HEADER_FLAGS(header) | IPFLAG_MORE_FRAGMENTS));
00790         }
00791 
00792         header->total_length = htons(length);
00793         /* Unnecessary for all protocols */
00794         header->header_checksum = IP_HEADER_CHECKSUM(header);
00795 
00796         return EOK;
00797 }
00798 
00816 static int ip_fragment_packet_data(packet_t *packet, packet_t *new_packet,
00817     ip_header_t *header, ip_header_t *new_header, size_t length,
00818     const struct sockaddr *src, const struct sockaddr *dest, socklen_t addrlen)
00819 {
00820         void *data;
00821         size_t offset;
00822         int rc;
00823 
00824         data = packet_suffix(new_packet, length);
00825         if (!data)
00826                 return ENOMEM;
00827 
00828         memcpy(data, ((void *) header) + IP_TOTAL_LENGTH(header) - length,
00829             length);
00830         
00831         rc = packet_trim(packet, 0, length);
00832         if (rc != EOK)
00833                 return rc;
00834         
00835         header->total_length = htons(IP_TOTAL_LENGTH(header) - length);
00836         new_header->total_length = htons(IP_HEADER_LENGTH(new_header) + length);
00837         offset = IP_FRAGMENT_OFFSET(header) + IP_HEADER_DATA_LENGTH(header);
00838         SET_IP_HEADER_FRAGMENT_OFFSET_HIGH(new_header,
00839             IP_COMPUTE_FRAGMENT_OFFSET_HIGH(offset));
00840         new_header->fragment_offset_low =
00841             IP_COMPUTE_FRAGMENT_OFFSET_LOW(offset);
00842         new_header->header_checksum = IP_HEADER_CHECKSUM(new_header);
00843         
00844         rc = packet_set_addr(new_packet, (const uint8_t *) src,
00845             (const uint8_t *) dest, addrlen);
00846         if (rc != EOK)
00847                 return rc;
00848 
00849         return pq_insert_after(packet, new_packet);
00850 }
00851 
00860 static ip_header_t *ip_create_middle_header(packet_t *packet,
00861     ip_header_t *last)
00862 {
00863         ip_header_t *middle;
00864 
00865         middle = (ip_header_t *) packet_suffix(packet, IP_HEADER_LENGTH(last));
00866         if (!middle)
00867                 return NULL;
00868         memcpy(middle, last, IP_HEADER_LENGTH(last));
00869         SET_IP_HEADER_FLAGS(middle,
00870             (GET_IP_HEADER_FLAGS(middle) | IPFLAG_MORE_FRAGMENTS));
00871         return middle;
00872 }
00873 
00899 static int
00900 ip_fragment_packet(packet_t *packet, size_t length, size_t prefix, size_t suffix,
00901     socklen_t addr_len)
00902 {
00903         packet_t *new_packet;
00904         ip_header_t *header;
00905         ip_header_t *middle_header;
00906         ip_header_t *last_header;
00907         struct sockaddr *src;
00908         struct sockaddr *dest;
00909         socklen_t addrlen;
00910         int result;
00911         int rc;
00912 
00913         result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest);
00914         if (result <= 0)
00915                 return EINVAL;
00916 
00917         addrlen = (socklen_t) result;
00918         if (packet_get_data_length(packet) <= sizeof(ip_header_t))
00919                 return ENOMEM;
00920 
00921         /* Get header */
00922         header = (ip_header_t *) packet_get_data(packet);
00923         if (!header)
00924                 return EINVAL;
00925 
00926         /* Fragmentation forbidden? */
00927         if(GET_IP_HEADER_FLAGS(header) & IPFLAG_DONT_FRAGMENT)
00928                 return EPERM;
00929 
00930         /* Create the last fragment */
00931         new_packet = packet_get_4_remote(ip_globals.net_phone, prefix, length,
00932             suffix, ((addrlen > addr_len) ? addrlen : addr_len));
00933         if (!new_packet)
00934                 return ENOMEM;
00935 
00936         /* Allocate as much as originally */
00937         last_header = (ip_header_t *) packet_suffix(new_packet,
00938             IP_HEADER_LENGTH(header));
00939         if (!last_header)
00940                 return ip_release_and_return(packet, ENOMEM);
00941 
00942         ip_create_last_header(last_header, header);
00943 
00944         /* Trim the unused space */
00945         rc = packet_trim(new_packet, 0,
00946             IP_HEADER_LENGTH(header) - IP_HEADER_LENGTH(last_header));
00947         if (rc != EOK)
00948                 return ip_release_and_return(packet, rc);
00949 
00950         /* Greatest multiple of 8 lower than content */
00951         // TODO even fragmentation?
00952         length = length & ~0x7;
00953         
00954         rc = ip_fragment_packet_data(packet, new_packet, header, last_header,
00955             ((IP_HEADER_DATA_LENGTH(header) -
00956             ((length - IP_HEADER_LENGTH(header)) & ~0x7)) %
00957             ((length - IP_HEADER_LENGTH(last_header)) & ~0x7)),
00958             src, dest, addrlen);
00959         if (rc != EOK)
00960                 return ip_release_and_return(packet, rc);
00961 
00962         /* Mark the first as fragmented */
00963         SET_IP_HEADER_FLAGS(header,
00964             (GET_IP_HEADER_FLAGS(header) | IPFLAG_MORE_FRAGMENTS));
00965 
00966         /* Create middle fragments */
00967         while (IP_TOTAL_LENGTH(header) > length) {
00968                 new_packet = packet_get_4_remote(ip_globals.net_phone, prefix,
00969                     length, suffix,
00970                     ((addrlen >= addr_len) ? addrlen : addr_len));
00971                 if (!new_packet)
00972                         return ENOMEM;
00973 
00974                 middle_header = ip_create_middle_header(new_packet,
00975                     last_header);
00976                 if (!middle_header)
00977                         return ip_release_and_return(packet, ENOMEM);
00978 
00979                 rc = ip_fragment_packet_data(packet, new_packet, header,
00980                     middle_header,
00981                     (length - IP_HEADER_LENGTH(middle_header)) & ~0x7,
00982                     src, dest, addrlen);
00983                 if (rc != EOK)
00984                         return ip_release_and_return(packet, rc);
00985         }
00986 
00987         /* Finish the first fragment */
00988         header->header_checksum = IP_HEADER_CHECKSUM(header);
00989 
00990         return EOK;
00991 }
00992 
01007 static packet_t *
01008 ip_split_packet(packet_t *packet, size_t prefix, size_t content, size_t suffix,
01009     socklen_t addr_len, services_t error)
01010 {
01011         size_t length;
01012         packet_t *next;
01013         packet_t *new_packet;
01014         int result;
01015         int phone;
01016 
01017         next = packet;
01018         /* Check all packets */
01019         while (next) {
01020                 length = packet_get_data_length(next);
01021                 
01022                 if (length <= content) {
01023                         next = pq_next(next);
01024                         continue;
01025                 }
01026 
01027                 /* Too long */
01028                 result = ip_fragment_packet(next, content, prefix,
01029                     suffix, addr_len);
01030                 if (result != EOK) {
01031                         new_packet = pq_detach(next);
01032                         if (next == packet) {
01033                                 /* The new first packet of the queue */
01034                                 packet = new_packet;
01035                         }
01036                         /* Fragmentation needed? */
01037                         if (result == EPERM) {
01038                                 phone = ip_prepare_icmp_and_get_phone(
01039                                     error, next, NULL);
01040                                 if (phone >= 0) {
01041                                         /* Fragmentation necessary ICMP */
01042                                         icmp_destination_unreachable_msg(phone,
01043                                             ICMP_FRAG_NEEDED, content, next);
01044                                 }
01045                         } else {
01046                                 pq_release_remote(ip_globals.net_phone,
01047                                     packet_get_id(next));
01048                         }
01049 
01050                         next = new_packet;
01051                         continue;
01052                 }
01053 
01054                 next = pq_next(next);
01055         }
01056 
01057         return packet;
01058 }
01059 
01077 static int ip_send_route(packet_t *packet, ip_netif_t *netif,
01078     ip_route_t *route, in_addr_t *src, in_addr_t dest, services_t error)
01079 {
01080         measured_string_t destination;
01081         measured_string_t *translation;
01082         uint8_t *data;
01083         int phone;
01084         int rc;
01085 
01086         /* Get destination hardware address */
01087         if (netif->arp && (route->address.s_addr != dest.s_addr)) {
01088                 destination.value = route->gateway.s_addr ?
01089                     (uint8_t *) &route->gateway.s_addr : (uint8_t *) &dest.s_addr;
01090                 destination.length = sizeof(dest.s_addr);
01091 
01092                 rc = arp_translate_req(netif->arp->phone, netif->device_id,
01093                     SERVICE_IP, &destination, &translation, &data);
01094                 if (rc != EOK) {
01095                         pq_release_remote(ip_globals.net_phone,
01096                             packet_get_id(packet));
01097                         return rc;
01098                 }
01099 
01100                 if (!translation || !translation->value) {
01101                         if (translation) {
01102                                 free(translation);
01103                                 free(data);
01104                         }
01105                         phone = ip_prepare_icmp_and_get_phone(error, packet,
01106                             NULL);
01107                         if (phone >= 0) {
01108                                 /* Unreachable ICMP if no routing */
01109                                 icmp_destination_unreachable_msg(phone,
01110                                     ICMP_HOST_UNREACH, 0, packet);
01111                         }
01112                         return EINVAL;
01113                 }
01114 
01115         } else {
01116                 translation = NULL;
01117         }
01118 
01119         rc = ip_prepare_packet(src, dest, packet, translation);
01120         if (rc != EOK) {
01121                 pq_release_remote(ip_globals.net_phone, packet_get_id(packet));
01122         } else {
01123                 packet = ip_split_packet(packet, netif->packet_dimension.prefix,
01124                     netif->packet_dimension.content,
01125                     netif->packet_dimension.suffix,
01126                     netif->packet_dimension.addr_len, error);
01127                 if (packet) {
01128                         nil_send_msg(netif->phone, netif->device_id, packet,
01129                             SERVICE_IP);
01130                 }
01131         }
01132 
01133         if (translation) {
01134                 free(translation);
01135                 free(data);
01136         }
01137 
01138         return rc;
01139 }
01140 
01141 static int ip_send_msg_local(int il_phone, device_id_t device_id,
01142     packet_t *packet, services_t sender, services_t error)
01143 {
01144         int addrlen;
01145         ip_netif_t *netif;
01146         ip_route_t *route;
01147         struct sockaddr *addr;
01148         struct sockaddr_in *address_in;
01149         in_addr_t *dest;
01150         in_addr_t *src;
01151         int phone;
01152         int rc;
01153 
01154         /*
01155          * Addresses in the host byte order
01156          * Should be the next hop address or the target destination address
01157          */
01158         addrlen = packet_get_addr(packet, NULL, (uint8_t **) &addr);
01159         if (addrlen < 0)
01160                 return ip_release_and_return(packet, addrlen);
01161         if ((size_t) addrlen < sizeof(struct sockaddr))
01162                 return ip_release_and_return(packet, EINVAL);
01163 
01164         switch (addr->sa_family) {
01165         case AF_INET:
01166                 if (addrlen != sizeof(struct sockaddr_in))
01167                         return ip_release_and_return(packet, EINVAL);
01168                 address_in = (struct sockaddr_in *) addr;
01169                 dest = &address_in->sin_addr;
01170                 if (!dest->s_addr)
01171                         dest->s_addr = IPV4_LOCALHOST_ADDRESS;
01172                 break;
01173         case AF_INET6:
01174         default:
01175                 return ip_release_and_return(packet, EAFNOSUPPORT);
01176         }
01177 
01178         netif = NULL;
01179         route = NULL;
01180         fibril_rwlock_read_lock(&ip_globals.netifs_lock);
01181 
01182         /* Device specified? */
01183         if (device_id > 0) {
01184                 netif = ip_netifs_find(&ip_globals.netifs, device_id);
01185                 route = ip_netif_find_route(netif, *dest);
01186                 if (netif && !route && (ip_globals.gateway.netif == netif))
01187                         route = &ip_globals.gateway;
01188         }
01189 
01190         if (!route) {
01191                 route = ip_find_route(*dest);
01192                 netif = route ? route->netif : NULL;
01193         }
01194         if (!netif || !route) {
01195                 fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
01196                 phone = ip_prepare_icmp_and_get_phone(error, packet, NULL);
01197                 if (phone >= 0) {
01198                         /* Unreachable ICMP if no routing */
01199                         icmp_destination_unreachable_msg(phone,
01200                             ICMP_NET_UNREACH, 0, packet);
01201                 }
01202                 return ENOENT;
01203         }
01204 
01205         if (error) {
01206                 /*
01207                  * Do not send for broadcast, anycast packets or network
01208                  * broadcast.
01209                  */
01210                 if (!dest->s_addr || !(~dest->s_addr) ||
01211                     !(~((dest->s_addr & ~route->netmask.s_addr) |
01212                     route->netmask.s_addr)) ||
01213                     (!(dest->s_addr & ~route->netmask.s_addr))) {
01214                         return ip_release_and_return(packet, EINVAL);
01215                 }
01216         }
01217         
01218         /* If the local host is the destination */
01219         if ((route->address.s_addr == dest->s_addr) &&
01220             (dest->s_addr != IPV4_LOCALHOST_ADDRESS)) {
01221                 /* Find the loopback device to deliver */
01222                 dest->s_addr = IPV4_LOCALHOST_ADDRESS;
01223                 route = ip_find_route(*dest);
01224                 netif = route ? route->netif : NULL;
01225                 if (!netif || !route) {
01226                         fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
01227                         phone = ip_prepare_icmp_and_get_phone(error, packet,
01228                             NULL);
01229                         if (phone >= 0) {
01230                                 /* Unreachable ICMP if no routing */
01231                                 icmp_destination_unreachable_msg(phone,
01232                                     ICMP_HOST_UNREACH, 0, packet);
01233                         }
01234                         return ENOENT;
01235                 }
01236         }
01237         
01238         src = ip_netif_address(netif);
01239         if (!src) {
01240                 fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
01241                 return ip_release_and_return(packet, ENOENT);
01242         }
01243 
01244         rc = ip_send_route(packet, netif, route, src, *dest, error);
01245         fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
01246 
01247         return rc;
01248 }
01249 
01257 static int ip_device_state_message(device_id_t device_id, device_state_t state)
01258 {
01259         ip_netif_t *netif;
01260 
01261         fibril_rwlock_write_lock(&ip_globals.netifs_lock);
01262         /* Find the device */
01263         netif = ip_netifs_find(&ip_globals.netifs, device_id);
01264         if (!netif) {
01265                 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
01266                 return ENOENT;
01267         }
01268         netif->state = state;
01269         fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
01270 
01271         printf("%s: Device %d changed state to %d\n", NAME, device_id, state);
01272 
01273         return EOK;
01274 }
01275 
01281 static in_addr_t ip_get_destination(ip_header_t *header)
01282 {
01283         in_addr_t destination;
01284 
01285         // TODO search set ipopt route?
01286         destination.s_addr = header->destination_address;
01287         return destination;
01288 }
01289 
01311 static int ip_deliver_local(device_id_t device_id, packet_t *packet,
01312     ip_header_t *header, services_t error)
01313 {
01314         ip_proto_t *proto;
01315         int phone;
01316         services_t service;
01317         tl_received_msg_t received_msg;
01318         struct sockaddr *src;
01319         struct sockaddr *dest;
01320         struct sockaddr_in src_in;
01321         struct sockaddr_in dest_in;
01322         socklen_t addrlen;
01323         int rc;
01324 
01325         if ((GET_IP_HEADER_FLAGS(header) & IPFLAG_MORE_FRAGMENTS) ||
01326             IP_FRAGMENT_OFFSET(header)) {
01327                 // TODO fragmented
01328                 return ENOTSUP;
01329         }
01330         
01331         switch (GET_IP_HEADER_VERSION(header)) {
01332         case IPVERSION:
01333                 addrlen = sizeof(src_in);
01334                 bzero(&src_in, addrlen);
01335                 src_in.sin_family = AF_INET;
01336                 memcpy(&dest_in, &src_in, addrlen);
01337                 memcpy(&src_in.sin_addr.s_addr, &header->source_address,
01338                     sizeof(header->source_address));
01339                 memcpy(&dest_in.sin_addr.s_addr, &header->destination_address,
01340                     sizeof(header->destination_address));
01341                 src = (struct sockaddr *) &src_in;
01342                 dest = (struct sockaddr *) &dest_in;
01343                 break;
01344 
01345         default:
01346                 return ip_release_and_return(packet, EAFNOSUPPORT);
01347         }
01348 
01349         rc = packet_set_addr(packet, (uint8_t *) src, (uint8_t *) dest,
01350             addrlen);
01351         if (rc != EOK)
01352                 return ip_release_and_return(packet, rc);
01353 
01354         /* Trim padding if present */
01355         if (!error &&
01356             (IP_TOTAL_LENGTH(header) < packet_get_data_length(packet))) {
01357                 rc = packet_trim(packet, 0,
01358                     packet_get_data_length(packet) - IP_TOTAL_LENGTH(header));
01359                 if (rc != EOK)
01360                         return ip_release_and_return(packet, rc);
01361         }
01362 
01363         fibril_rwlock_read_lock(&ip_globals.protos_lock);
01364 
01365         proto = ip_protos_find(&ip_globals.protos, header->protocol);
01366         if (!proto) {
01367                 fibril_rwlock_read_unlock(&ip_globals.protos_lock);
01368                 phone = ip_prepare_icmp_and_get_phone(error, packet, header);
01369                 if (phone >= 0) {
01370                         /* Unreachable ICMP */
01371                         icmp_destination_unreachable_msg(phone,
01372                             ICMP_PROT_UNREACH, 0, packet);
01373                 }
01374                 return ENOENT;
01375         }
01376 
01377         if (proto->received_msg) {
01378                 service = proto->service;
01379                 received_msg = proto->received_msg;
01380                 fibril_rwlock_read_unlock(&ip_globals.protos_lock);
01381                 rc = received_msg(device_id, packet, service, error);
01382         } else {
01383                 rc = tl_received_msg(proto->phone, device_id, packet,
01384                     proto->service, error);
01385                 fibril_rwlock_read_unlock(&ip_globals.protos_lock);
01386         }
01387 
01388         return rc;
01389 }
01390 
01412 static int ip_process_packet(device_id_t device_id, packet_t *packet)
01413 {
01414         ip_header_t *header;
01415         in_addr_t dest;
01416         ip_route_t *route;
01417         int phone;
01418         struct sockaddr *addr;
01419         struct sockaddr_in addr_in;
01420         socklen_t addrlen;
01421         int rc;
01422         
01423         header = (ip_header_t *) packet_get_data(packet);
01424         if (!header)
01425                 return ip_release_and_return(packet, ENOMEM);
01426 
01427         /* Checksum */
01428         if ((header->header_checksum) &&
01429             (IP_HEADER_CHECKSUM(header) != IP_CHECKSUM_ZERO)) {
01430                 phone = ip_prepare_icmp_and_get_phone(0, packet, header);
01431                 if (phone >= 0) {
01432                         /* Checksum error ICMP */
01433                         icmp_parameter_problem_msg(phone, ICMP_PARAM_POINTER,
01434                             ((size_t) ((void *) &header->header_checksum)) -
01435                             ((size_t) ((void *) header)), packet);
01436                 }
01437                 return EINVAL;
01438         }
01439 
01440         if (header->ttl <= 1) {
01441                 phone = ip_prepare_icmp_and_get_phone(0, packet, header);
01442                 if (phone >= 0) {
01443                         /* TTL exceeded ICMP */
01444                         icmp_time_exceeded_msg(phone, ICMP_EXC_TTL, packet);
01445                 }
01446                 return EINVAL;
01447         }
01448         
01449         /* Process ipopt and get destination */
01450         dest = ip_get_destination(header);
01451 
01452         /* Set the destination address */
01453         switch (GET_IP_HEADER_VERSION(header)) {
01454         case IPVERSION:
01455                 addrlen = sizeof(addr_in);
01456                 bzero(&addr_in, addrlen);
01457                 addr_in.sin_family = AF_INET;
01458                 memcpy(&addr_in.sin_addr.s_addr, &dest, sizeof(dest));
01459                 addr = (struct sockaddr *) &addr_in;
01460                 break;
01461 
01462         default:
01463                 return ip_release_and_return(packet, EAFNOSUPPORT);
01464         }
01465 
01466         rc = packet_set_addr(packet, NULL, (uint8_t *) &addr, addrlen);
01467         if (rc != EOK)
01468                 return rc;
01469         
01470         route = ip_find_route(dest);
01471         if (!route) {
01472                 phone = ip_prepare_icmp_and_get_phone(0, packet, header);
01473                 if (phone >= 0) {
01474                         /* Unreachable ICMP */
01475                         icmp_destination_unreachable_msg(phone,
01476                             ICMP_HOST_UNREACH, 0, packet);
01477                 }
01478                 return ENOENT;
01479         }
01480 
01481         if (route->address.s_addr == dest.s_addr) {
01482                 /* Local delivery */
01483                 return ip_deliver_local(device_id, packet, header, 0);
01484         }
01485 
01486         if (route->netif->routing) {
01487                 header->ttl--;
01488                 return ip_send_route(packet, route->netif, route, NULL, dest,
01489                     0);
01490         }
01491 
01492         phone = ip_prepare_icmp_and_get_phone(0, packet, header);
01493         if (phone >= 0) {
01494                 /* Unreachable ICMP if no routing */
01495                 icmp_destination_unreachable_msg(phone, ICMP_HOST_UNREACH, 0,
01496                     packet);
01497         }
01498         
01499         return ENOENT;
01500 }
01501 
01513 static int ip_packet_size_message(device_id_t device_id, size_t *addr_len,
01514     size_t *prefix, size_t *content, size_t *suffix)
01515 {
01516         ip_netif_t *netif;
01517         int index;
01518 
01519         if (!addr_len || !prefix || !content || !suffix)
01520                 return EBADMEM;
01521 
01522         *content = IP_MAX_CONTENT - IP_PREFIX;
01523         fibril_rwlock_read_lock(&ip_globals.netifs_lock);
01524         if (device_id < 0) {
01525                 *addr_len = IP_ADDR;
01526                 *prefix = 0;
01527                 *suffix = 0;
01528 
01529                 for (index = ip_netifs_count(&ip_globals.netifs) - 1;
01530                     index >= 0; index--) {
01531                         netif = ip_netifs_get_index(&ip_globals.netifs, index);
01532                         if (!netif)
01533                                 continue;
01534                         
01535                         if (netif->packet_dimension.addr_len > *addr_len)
01536                                 *addr_len = netif->packet_dimension.addr_len;
01537                         
01538                         if (netif->packet_dimension.prefix > *prefix)
01539                                 *prefix = netif->packet_dimension.prefix;
01540                                 
01541                         if (netif->packet_dimension.suffix > *suffix)
01542                                 *suffix = netif->packet_dimension.suffix;
01543                 }
01544 
01545                 *prefix = *prefix + IP_PREFIX;
01546                 *suffix = *suffix + IP_SUFFIX;
01547         } else {
01548                 netif = ip_netifs_find(&ip_globals.netifs, device_id);
01549                 if (!netif) {
01550                         fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
01551                         return ENOENT;
01552                 }
01553 
01554                 *addr_len = (netif->packet_dimension.addr_len > IP_ADDR) ?
01555                     netif->packet_dimension.addr_len : IP_ADDR;
01556                 *prefix = netif->packet_dimension.prefix + IP_PREFIX;
01557                 *suffix = netif->packet_dimension.suffix + IP_SUFFIX;
01558         }
01559         fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
01560 
01561         return EOK;
01562 }
01563 
01571 static int ip_mtu_changed_message(device_id_t device_id, size_t mtu)
01572 {
01573         ip_netif_t *netif;
01574 
01575         fibril_rwlock_write_lock(&ip_globals.netifs_lock);
01576         netif = ip_netifs_find(&ip_globals.netifs, device_id);
01577         if (!netif) {
01578                 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
01579                 return ENOENT;
01580         }
01581         netif->packet_dimension.content = mtu;
01582         fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
01583 
01584         printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
01585 
01586         return EOK;
01587 }
01588 
01595 static void ip_receiver(ipc_callid_t iid, ipc_call_t *icall)
01596 {
01597         packet_t *packet;
01598         int rc;
01599         
01600         while (true) {
01601                 switch (IPC_GET_IMETHOD(*icall)) {
01602                 case NET_IL_DEVICE_STATE:
01603                         rc = ip_device_state_message(IPC_GET_DEVICE(*icall),
01604                             IPC_GET_STATE(*icall));
01605                         async_answer_0(iid, (sysarg_t) rc);
01606                         break;
01607                 
01608                 case NET_IL_RECEIVED:
01609                         rc = packet_translate_remote(ip_globals.net_phone, &packet,
01610                             IPC_GET_PACKET(*icall));
01611                         if (rc == EOK) {
01612                                 do {
01613                                         packet_t *next = pq_detach(packet);
01614                                         ip_process_packet(IPC_GET_DEVICE(*icall), packet);
01615                                         packet = next;
01616                                 } while (packet);
01617                         }
01618                         
01619                         async_answer_0(iid, (sysarg_t) rc);
01620                         break;
01621                 
01622                 case NET_IL_MTU_CHANGED:
01623                         rc = ip_mtu_changed_message(IPC_GET_DEVICE(*icall),
01624                             IPC_GET_MTU(*icall));
01625                         async_answer_0(iid, (sysarg_t) rc);
01626                         break;
01627                 
01628                 default:
01629                         async_answer_0(iid, (sysarg_t) ENOTSUP);
01630                 }
01631                 
01632                 iid = async_get_call(icall);
01633         }
01634 }
01635 
01652 static int
01653 ip_register(int protocol, services_t service, int phone,
01654     tl_received_msg_t received_msg)
01655 {
01656         ip_proto_t *proto;
01657         int index;
01658 
01659         if (!protocol || !service || ((phone < 0) && !received_msg))
01660                 return EINVAL;
01661 
01662         proto = (ip_proto_t *) malloc(sizeof(ip_protos_t));
01663         if (!proto)
01664                 return ENOMEM;
01665 
01666         proto->protocol = protocol;
01667         proto->service = service;
01668         proto->phone = phone;
01669         proto->received_msg = received_msg;
01670 
01671         fibril_rwlock_write_lock(&ip_globals.protos_lock);
01672         index = ip_protos_add(&ip_globals.protos, proto->protocol, proto);
01673         if (index < 0) {
01674                 fibril_rwlock_write_unlock(&ip_globals.protos_lock);
01675                 free(proto);
01676                 return index;
01677         }
01678         fibril_rwlock_write_unlock(&ip_globals.protos_lock);
01679 
01680         printf("%s: Protocol registered (protocol: %d, phone: %d)\n",
01681             NAME, proto->protocol, proto->phone);
01682 
01683         return EOK;
01684 }
01685 
01686 
01687 static int
01688 ip_add_route_req_local(int ip_phone, device_id_t device_id, in_addr_t address,
01689     in_addr_t netmask, in_addr_t gateway)
01690 {
01691         ip_route_t *route;
01692         ip_netif_t *netif;
01693         int index;
01694 
01695         fibril_rwlock_write_lock(&ip_globals.netifs_lock);
01696 
01697         netif = ip_netifs_find(&ip_globals.netifs, device_id);
01698         if (!netif) {
01699                 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
01700                 return ENOENT;
01701         }
01702 
01703         route = (ip_route_t *) malloc(sizeof(ip_route_t));
01704         if (!route) {
01705                 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
01706                 return ENOMEM;
01707         }
01708 
01709         route->address.s_addr = address.s_addr;
01710         route->netmask.s_addr = netmask.s_addr;
01711         route->gateway.s_addr = gateway.s_addr;
01712         route->netif = netif;
01713         index = ip_routes_add(&netif->routes, route);
01714         if (index < 0)
01715                 free(route);
01716 
01717         fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
01718         
01719         return index;
01720 }
01721 
01722 static int
01723 ip_set_gateway_req_local(int ip_phone, device_id_t device_id, in_addr_t gateway)
01724 {
01725         ip_netif_t *netif;
01726 
01727         fibril_rwlock_write_lock(&ip_globals.netifs_lock);
01728 
01729         netif = ip_netifs_find(&ip_globals.netifs, device_id);
01730         if (!netif) {
01731                 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
01732                 return ENOENT;
01733         }
01734 
01735         ip_globals.gateway.address.s_addr = 0;
01736         ip_globals.gateway.netmask.s_addr = 0;
01737         ip_globals.gateway.gateway.s_addr = gateway.s_addr;
01738         ip_globals.gateway.netif = netif;
01739         
01740         fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
01741         
01742         return EOK;
01743 }
01744 
01757 static int
01758 ip_received_error_msg_local(int ip_phone, device_id_t device_id,
01759     packet_t *packet, services_t target, services_t error)
01760 {
01761         uint8_t *data;
01762         int offset;
01763         icmp_type_t type;
01764         icmp_code_t code;
01765         ip_netif_t *netif;
01766         measured_string_t address;
01767         ip_route_t *route;
01768         ip_header_t *header;
01769 
01770         switch (error) {
01771         case SERVICE_ICMP:
01772                 offset = icmp_client_process_packet(packet, &type, &code, NULL,
01773                     NULL);
01774                 if (offset < 0)
01775                         return ip_release_and_return(packet, ENOMEM);
01776 
01777                 data = packet_get_data(packet);
01778                 header = (ip_header_t *)(data + offset);
01779 
01780                 /* Destination host unreachable? */
01781                 if ((type != ICMP_DEST_UNREACH) ||
01782                     (code != ICMP_HOST_UNREACH)) {
01783                         /* No, something else */
01784                         break;
01785                 }
01786 
01787                 fibril_rwlock_read_lock(&ip_globals.netifs_lock);
01788 
01789                 netif = ip_netifs_find(&ip_globals.netifs, device_id);
01790                 if (!netif || !netif->arp) {
01791                         fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
01792                         break;
01793                 }
01794 
01795                 route = ip_routes_get_index(&netif->routes, 0);
01796 
01797                 /* From the same network? */
01798                 if (route && ((route->address.s_addr & route->netmask.s_addr) ==
01799                     (header->destination_address & route->netmask.s_addr))) {
01800                         /* Clear the ARP mapping if any */
01801                         address.value = (uint8_t *) &header->destination_address;
01802                         address.length = sizeof(header->destination_address);
01803                         arp_clear_address_req(netif->arp->phone,
01804                             netif->device_id, SERVICE_IP, &address);
01805                 }
01806 
01807                 fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
01808                 break;
01809 
01810         default:
01811                 return ip_release_and_return(packet, ENOTSUP);
01812         }
01813 
01814         return ip_deliver_local(device_id, packet, header, error);
01815 }
01816 
01817 static int
01818 ip_get_route_req_local(int ip_phone, ip_protocol_t protocol,
01819     const struct sockaddr *destination, socklen_t addrlen,
01820     device_id_t *device_id, void **header, size_t *headerlen)
01821 {
01822         struct sockaddr_in *address_in;
01823         in_addr_t *dest;
01824         in_addr_t *src;
01825         ip_route_t *route;
01826         ipv4_pseudo_header_t *header_in;
01827 
01828         if (!destination || (addrlen <= 0))
01829                 return EINVAL;
01830 
01831         if (!device_id || !header || !headerlen)
01832                 return EBADMEM;
01833 
01834         if ((size_t) addrlen < sizeof(struct sockaddr))
01835                 return EINVAL;
01836 
01837         switch (destination->sa_family) {
01838         case AF_INET:
01839                 if (addrlen != sizeof(struct sockaddr_in))
01840                         return EINVAL;
01841                 address_in = (struct sockaddr_in *) destination;
01842                 dest = &address_in->sin_addr;
01843                 if (!dest->s_addr)
01844                         dest->s_addr = IPV4_LOCALHOST_ADDRESS;
01845                 break;
01846 
01847         case AF_INET6:
01848         default:
01849                 return EAFNOSUPPORT;
01850         }
01851 
01852         fibril_rwlock_read_lock(&ip_globals.lock);
01853         route = ip_find_route(*dest);
01854         /* If the local host is the destination */
01855         if (route && (route->address.s_addr == dest->s_addr) &&
01856             (dest->s_addr != IPV4_LOCALHOST_ADDRESS)) {
01857                 /* Find the loopback device to deliver */
01858                 dest->s_addr = IPV4_LOCALHOST_ADDRESS;
01859                 route = ip_find_route(*dest);
01860         }
01861 
01862         if (!route || !route->netif) {
01863                 fibril_rwlock_read_unlock(&ip_globals.lock);
01864                 return ENOENT;
01865         }
01866 
01867         *device_id = route->netif->device_id;
01868         src = ip_netif_address(route->netif);
01869         fibril_rwlock_read_unlock(&ip_globals.lock);
01870 
01871         *headerlen = sizeof(*header_in);
01872         header_in = (ipv4_pseudo_header_t *) malloc(*headerlen);
01873         if (!header_in)
01874                 return ENOMEM;
01875 
01876         bzero(header_in, *headerlen);
01877         header_in->destination_address = dest->s_addr;
01878         header_in->source_address = src->s_addr;
01879         header_in->protocol = protocol;
01880         header_in->data_length = 0;
01881         *header = header_in;
01882 
01883         return EOK;
01884 }
01885 
01900 int il_module_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
01901     size_t *answer_count)
01902 {
01903         packet_t *packet;
01904         struct sockaddr *addr;
01905         void *header;
01906         size_t headerlen;
01907         size_t addrlen;
01908         size_t prefix;
01909         size_t suffix;
01910         size_t content;
01911         device_id_t device_id;
01912         int rc;
01913         
01914         *answer_count = 0;
01915         switch (IPC_GET_IMETHOD(*call)) {
01916         case IPC_M_PHONE_HUNGUP:
01917                 return EOK;
01918         
01919         case IPC_M_CONNECT_TO_ME:
01920                 return ip_register(IL_GET_PROTO(*call), IL_GET_SERVICE(*call),
01921                     IPC_GET_PHONE(*call), NULL);
01922         
01923         case NET_IP_DEVICE:
01924                 return ip_device_req_local(0, IPC_GET_DEVICE(*call),
01925                     IPC_GET_SERVICE(*call));
01926         
01927         case NET_IP_RECEIVED_ERROR:
01928                 rc = packet_translate_remote(ip_globals.net_phone, &packet,
01929                     IPC_GET_PACKET(*call));
01930                 if (rc != EOK)
01931                         return rc;
01932                 return ip_received_error_msg_local(0, IPC_GET_DEVICE(*call),
01933                     packet, IPC_GET_TARGET(*call), IPC_GET_ERROR(*call));
01934         
01935         case NET_IP_ADD_ROUTE:
01936                 return ip_add_route_req_local(0, IPC_GET_DEVICE(*call),
01937                     IP_GET_ADDRESS(*call), IP_GET_NETMASK(*call),
01938                     IP_GET_GATEWAY(*call));
01939 
01940         case NET_IP_SET_GATEWAY:
01941                 return ip_set_gateway_req_local(0, IPC_GET_DEVICE(*call),
01942                     IP_GET_GATEWAY(*call));
01943 
01944         case NET_IP_GET_ROUTE:
01945                 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0,
01946                     &addrlen);
01947                 if (rc != EOK)
01948                         return rc;
01949                 
01950                 rc = ip_get_route_req_local(0, IP_GET_PROTOCOL(*call), addr,
01951                     (socklen_t) addrlen, &device_id, &header, &headerlen);
01952                 if (rc != EOK)
01953                         return rc;
01954                 
01955                 IPC_SET_DEVICE(*answer, device_id);
01956                 IP_SET_HEADERLEN(*answer, headerlen);
01957                 
01958                 *answer_count = 2;
01959                 
01960                 rc = data_reply(&headerlen, sizeof(headerlen));
01961                 if (rc == EOK)
01962                         rc = data_reply(header, headerlen);
01963                         
01964                 free(header);
01965                 return rc;
01966         
01967         case NET_IP_PACKET_SPACE:
01968                 rc = ip_packet_size_message(IPC_GET_DEVICE(*call), &addrlen,
01969                     &prefix, &content, &suffix);
01970                 if (rc != EOK)
01971                         return rc;
01972                 
01973                 IPC_SET_ADDR(*answer, addrlen);
01974                 IPC_SET_PREFIX(*answer, prefix);
01975                 IPC_SET_CONTENT(*answer, content);
01976                 IPC_SET_SUFFIX(*answer, suffix);
01977                 *answer_count = 4;
01978                 return EOK;
01979         
01980         case NET_IP_SEND:
01981                 rc = packet_translate_remote(ip_globals.net_phone, &packet,
01982                     IPC_GET_PACKET(*call));
01983                 if (rc != EOK)
01984                         return rc;
01985                 
01986                 return ip_send_msg_local(0, IPC_GET_DEVICE(*call), packet, 0,
01987                     IPC_GET_ERROR(*call));
01988         }
01989         
01990         return ENOTSUP;
01991 }
01992 
01993 int main(int argc, char *argv[])
01994 {
01995         /* Start the module */
01996         return il_module_start(SERVICE_IP);
01997 }
01998 

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