Subversion Repositories HelenOS

Rev

Rev 4735 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2009 Lukas Mejdrech
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup ip
  30.  *  @{
  31.  */
  32.  
  33. /** @file
  34.  *  IP module implementation.
  35.  *  @see arp.h
  36.  *  \todo
  37.  */
  38.  
  39. #include <async.h>
  40. #include <errno.h>
  41. #include <fibril_sync.h>
  42. #include <stdio.h>
  43. #include <string.h>
  44.  
  45. #include <ipc/ipc.h>
  46. #include <ipc/services.h>
  47.  
  48. #include <sys/types.h>
  49.  
  50. #include "../../err.h"
  51. #include "../../messages.h"
  52. #include "../../modules.h"
  53.  
  54. #include "../../include/arp_interface.h"
  55. #include "../../include/byteorder.h"
  56. #include "../../include/checksum.h"
  57. #include "../../include/device.h"
  58. #include "../../include/icmp_client.h"
  59. #include "../../include/icmp_codes.h"
  60. #include "../../include/icmp_interface.h"
  61. #include "../../include/il_interface.h"
  62. #include "../../include/in.h"
  63. #include "../../include/in6.h"
  64. #include "../../include/inet.h"
  65. #include "../../include/ip_client.h"
  66. #include "../../include/ip_interface.h"
  67. #include "../../include/net_interface.h"
  68. #include "../../include/nil_interface.h"
  69. #include "../../include/tl_interface.h"
  70. #include "../../include/socket_codes.h"
  71. #include "../../include/socket_errno.h"
  72. #include "../../structures/measured_strings.h"
  73. #include "../../structures/module_map.h"
  74. #include "../../structures/packet/packet_client.h"
  75.  
  76. #include "../../nil/nil_messages.h"
  77.  
  78. #include "../il_messages.h"
  79.  
  80. #include "ip.h"
  81. #include "ip_header.h"
  82. #include "ip_messages.h"
  83. #include "ip_module.h"
  84.  
  85. /** IP version 4.
  86.  */
  87. #define IPV4                4
  88.  
  89. /** Default network interface IP version.
  90.  */
  91. #define NET_DEFAULT_IPV     IPV4
  92.  
  93. /** Default network interface IP routing.
  94.  */
  95. #define NET_DEFAULT_IP_ROUTING  false
  96.  
  97. /** Minimum IP packet content.
  98.  */
  99. #define IP_MIN_CONTENT  576
  100.  
  101. /** ARP module name.
  102.  */
  103. #define ARP_NAME                "arp"
  104.  
  105. /** ARP module filename.
  106.  */
  107. #define ARP_FILENAME            "/srv/arp"
  108.  
  109. /** IP packet address length.
  110.  */
  111. #define IP_ADDR                         sizeof( struct sockaddr_in6 )
  112.  
  113. /** IP packet prefix length.
  114.  */
  115. #define IP_PREFIX                       sizeof( ip_header_t )
  116.  
  117. /** IP packet suffix length.
  118.  */
  119. #define IP_SUFFIX                       0
  120.  
  121. /** IP packet maximum content length.
  122.  */
  123. #define IP_MAX_CONTENT                  65535
  124.  
  125. /** The IP localhost address.
  126.  */
  127. #define IPV4_LOCALHOST_ADDRESS  htonl(( 127 << 24 ) + 1 )
  128.  
  129. /** IP global data.
  130.  */
  131. ip_globals_t    ip_globals;
  132.  
  133. DEVICE_MAP_IMPLEMENT( ip_netifs, ip_netif_t )
  134.  
  135. INT_MAP_IMPLEMENT( ip_protos, ip_proto_t )
  136.  
  137. GENERIC_FIELD_IMPLEMENT( ip_routes, ip_route_t )
  138.  
  139. /** Updates the device content length according to the new MTU value.
  140.  *  @param device_id The device identifier. Input parameter.
  141.  *  @param mtu The new mtu value. Input parameter.
  142.  *  @returns EOK on success.
  143.  *  @returns ENOENT if device is not found.
  144.  */
  145. int ip_mtu_changed_message( device_id_t device_id, size_t mtu );
  146.  
  147. /** Updates the device state.
  148.  *  @param device_id The device identifier. Input parameter.
  149.  *  @param state The new state value. Input parameter.
  150.  *  @returns EOK on success.
  151.  *  @returns ENOENT if device is not found.
  152.  */
  153. int ip_device_state_message( device_id_t device_id, device_state_t state );
  154.  
  155. int ip_register( int protocol, services_t service, int phone, tl_received_msg_t tl_received_msg );
  156.  
  157. /** Initializes a new network interface specific data.
  158.  *  Connects to the network interface layer module, reads the netif configuration, starts an ARP module if needed and sets the netif routing table.
  159.  *  The device identifier and the nil service has to be set.
  160.  *  @param ip_netif Network interface specific data. Input/output parameter.
  161.  *  @returns EOK on success.
  162.  *  @returns ENOTSUP if DHCP is configured.
  163.  *  @returns ENOTSUP if IPv6 is configured.
  164.  *  @returns EINVAL if any of the addresses is invalid.
  165.  *  @returns EINVAL if the used ARP module is not known.
  166.  *  @returns ENOMEM if there is not enough memory left.
  167.  *  @returns Other error codes as defined for the net_get_device_conf_req() function.
  168.  *  @returns Other error codes as defined for the bind_service() function.
  169.  *  @returns Other error codes as defined for the specific arp_device_req() function.
  170.  *  @returns Other error codes as defined for the nil_packet_size_req() function.
  171.  */
  172. int ip_netif_initialize( ip_netif_ref ip_netif );
  173.  
  174. int ip_send_route( packet_t packet, ip_netif_ref netif, ip_route_ref route, in_addr_t * src, in_addr_t dest, services_t error );
  175. int ip_prepare_packet( in_addr_t * source, in_addr_t dest, packet_t packet, measured_string_ref destination );
  176.  
  177. packet_t    ip_split_packet( packet_t packet, size_t prefix, size_t content, size_t suffix, socklen_t addr_len, services_t error );
  178. int ip_fragment_packet( packet_t packet, size_t length, size_t prefix, size_t suffix, socklen_t addr_len );
  179. int ip_fragment_packet_data( packet_t packet, packet_t new_packet, ip_header_ref header, ip_header_ref new_header, size_t length, const struct sockaddr * src, const struct sockaddr * dest, socklen_t addrlen );
  180. ip_header_ref   ip_create_middle_header( packet_t packet, ip_header_ref last );
  181. void ip_create_last_header( ip_header_ref last, ip_header_ref first );
  182.  
  183. in_addr_t * ip_netif_address( ip_netif_ref netif );
  184. ip_route_ref    ip_find_route( in_addr_t destination );
  185. ip_route_ref    ip_netif_find_route( ip_netif_ref netif, in_addr_t destination );
  186.  
  187. /** Processes the received IP packet.
  188.  *  @param device_id The source device identifier. Input parameter.
  189.  *  @param packet The received packet. Input/output parameter.
  190.  *  @returns EOK on success and the packet is no longer needed.
  191.  *  @returns EINVAL if the packet is too small to carry the IP packet.
  192.  *  @returns EINVAL if the received address lengths differs from the registered values.
  193.  *  @returns ENOENT if the device is not found in the cache.
  194.  *  @returns ENOENT if the protocol for the device is not found in the cache.
  195.  *  @returns ENOMEM if there is not enough memory left.
  196.  */
  197. int ip_receive_message( device_id_t device_id, packet_t packet );
  198.  
  199. int ip_process_packet( device_id_t device_id, packet_t packet );
  200. in_addr_t   ip_get_destination( ip_header_ref header );
  201. int ip_deliver_local( device_id_t device_id, packet_t packet, ip_header_ref header, services_t error );
  202.  
  203. int ip_prepare_icmp_and_get_phone( services_t error, packet_t packet, ip_header_ref header );
  204. int ip_get_icmp_phone( void );
  205. int ip_prepare_icmp( packet_t packet, ip_header_ref header );
  206.  
  207. int ip_release_and_return( packet_t packet, int result );
  208.  
  209. int ip_initialize( async_client_conn_t client_connection ){
  210.     ERROR_DECLARE;
  211.  
  212.     fibril_rwlock_initialize( & ip_globals.lock );
  213.     fibril_rwlock_write_lock( & ip_globals.lock );
  214.     fibril_rwlock_initialize( & ip_globals.protos_lock );
  215.     fibril_rwlock_initialize( & ip_globals.netifs_lock );
  216.     ip_globals.packet_counter = 0;
  217.     ip_globals.gateway.address.s_addr = 0;
  218.     ip_globals.gateway.netmask.s_addr = 0;
  219.     ip_globals.gateway.gateway.s_addr = 0;
  220.     ip_globals.gateway.netif = NULL;
  221.     ERROR_PROPAGATE( ip_netifs_initialize( & ip_globals.netifs ));
  222.     ERROR_PROPAGATE( ip_protos_initialize( & ip_globals.protos ));
  223.     ip_globals.client_connection = client_connection;
  224.     ERROR_PROPAGATE( modules_initialize( & ip_globals.modules ));
  225.     ERROR_PROPAGATE( add_module( NULL, & ip_globals.modules, ARP_NAME, ARP_FILENAME, SERVICE_ARP, arp_task_get_id(), arp_connect_module ));
  226.     fibril_rwlock_write_unlock( & ip_globals.lock );
  227.     return EOK;
  228. }
  229.  
  230. int ip_device_req( int il_phone, device_id_t device_id, services_t netif ){
  231.     ERROR_DECLARE;
  232.  
  233.     ip_netif_ref    ip_netif;
  234.     ip_route_ref    route;
  235.     int             index;
  236.     char *          data;
  237.  
  238.     ip_netif = ( ip_netif_ref ) malloc( sizeof( ip_netif_t ));
  239.     if( ! ip_netif ) return ENOMEM;
  240.     if( ERROR_OCCURRED( ip_routes_initialize( & ip_netif->routes ))){
  241.         free( ip_netif );
  242.         return ERROR_CODE;
  243.     }
  244.     ip_netif->device_id = device_id;
  245.     ip_netif->service = netif;
  246.     ip_netif->state = NETIF_STOPPED;
  247.     fibril_rwlock_write_lock( & ip_globals.netifs_lock );
  248.     if( ERROR_OCCURRED( ip_netif_initialize( ip_netif ))){
  249.         fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
  250.         ip_routes_destroy( & ip_netif->routes );
  251.         free( ip_netif );
  252.         return ERROR_CODE;
  253.     }
  254.     if( ip_netif->arp ) ++ ip_netif->arp->usage;
  255.     // print the settings
  256.     printf( "New device registered:\n\tid\t= %d\n\tphone\t= %d\n\tIPV\t= %d\n", ip_netif->device_id, ip_netif->phone, ip_netif->ipv );
  257.     printf( "\tconfiguration\t= %s\n", ip_netif->dhcp ? "dhcp" : "static" );
  258.     // TODO ipv6 addresses
  259.     data = ( char * ) malloc( INET_ADDRSTRLEN );
  260.     if( data ){
  261.         for( index = 0; index < ip_routes_count( & ip_netif->routes ); ++ index ){
  262.             route = ip_routes_get_index( & ip_netif->routes, index );
  263.             if( route ){
  264.                 printf( "\tRouting %d:\n", index );
  265.                 inet_ntop( AF_INET, ( uint8_t * ) & route->address.s_addr, data, INET_ADDRSTRLEN );
  266.                 printf( "\t\taddress\t= %s\n", data );
  267.                 inet_ntop( AF_INET, ( uint8_t * ) & route->netmask.s_addr, data, INET_ADDRSTRLEN );
  268.                 printf( "\t\tnetmask\t= %s\n", data );
  269.                 inet_ntop( AF_INET, ( uint8_t * ) & route->gateway.s_addr, data, INET_ADDRSTRLEN );
  270.                 printf( "\t\tgateway\t= %s\n", data );
  271.             }
  272.         }
  273.         inet_ntop( AF_INET, ( uint8_t * ) & ip_netif->broadcast.s_addr, data, INET_ADDRSTRLEN );
  274.         printf( "\t\tbroadcast\t= %s\n", data );
  275.         free( data );
  276.     }
  277.     fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
  278.     return EOK;
  279. }
  280.  
  281. int ip_netif_initialize( ip_netif_ref ip_netif ){
  282.     ERROR_DECLARE;
  283.  
  284.     measured_string_t   names[] = {{ "IPV", 3 }, { "IP_CONFIG", 9 }, { "IP_ADDR", 7 }, { "IP_NETMASK", 10 }, { "IP_GATEWAY", 10 }, { "IP_BROADCAST", 12 }, { "ARP", 3 }, { "IP_ROUTING", 10 }};
  285.     measured_string_ref configuration;
  286.     size_t              count = sizeof( names ) / sizeof( measured_string_t );
  287.     char *              data;
  288.     measured_string_t   address;
  289.     int                 index;
  290.     ip_route_ref        route;
  291.     in_addr_t           gateway;
  292.  
  293.     ip_netif->arp = NULL;
  294.     route = NULL;
  295.     ip_netif->ipv = NET_DEFAULT_IPV;
  296.     ip_netif->dhcp = false;
  297.     ip_netif->routing = NET_DEFAULT_IP_ROUTING;
  298.     configuration = & names[ 0 ];
  299.     // get configuration
  300.     ERROR_PROPAGATE( net_get_device_conf_req( ip_globals.net_phone, ip_netif->device_id, & configuration, count, & data ));
  301.     if( configuration ){
  302.         if( configuration[ 0 ].value ){
  303.             ip_netif->ipv = strtol( configuration[ 0 ].value, NULL, 0 );
  304.         }
  305.         ip_netif->dhcp = ! str_lcmp( configuration[ 1 ].value, "dhcp", configuration[ 1 ].length );
  306.         if( ip_netif->dhcp ){
  307.             // TODO dhcp
  308.             net_free_settings( configuration, data );
  309.             return ENOTSUP;
  310.         }else if( ip_netif->ipv == IPV4 ){
  311.             route = ( ip_route_ref ) malloc( sizeof( ip_route_t ));
  312.             if( ! route ){
  313.                 net_free_settings( configuration, data );
  314.                 return ENOMEM;
  315.             }
  316.             route->address.s_addr = 0;
  317.             route->netmask.s_addr = 0;
  318.             route->gateway.s_addr = 0;
  319.             route->netif = ip_netif;
  320.             index = ip_routes_add( & ip_netif->routes, route );
  321.             if( index < 0 ){
  322.                 net_free_settings( configuration, data );
  323.                 free( route );
  324.                 return index;
  325.             }
  326.             if( ERROR_OCCURRED( inet_pton( AF_INET, configuration[ 2 ].value, ( uint8_t * ) & route->address.s_addr ))
  327.             || ERROR_OCCURRED( inet_pton( AF_INET, configuration[ 3 ].value, ( uint8_t * ) & route->netmask.s_addr ))
  328.             || ( inet_pton( AF_INET, configuration[ 4 ].value, ( uint8_t * ) & gateway.s_addr ) == EINVAL )
  329.             || ( inet_pton( AF_INET, configuration[ 5 ].value, ( uint8_t * ) & ip_netif->broadcast.s_addr ) == EINVAL )){
  330.                 net_free_settings( configuration, data );
  331.                 return EINVAL;
  332.             }
  333.         }else{
  334.             // TODO ipv6 in separate module
  335.             net_free_settings( configuration, data );
  336.             return ENOTSUP;
  337.         }
  338.         if( configuration[ 6 ].value ){
  339.             ip_netif->arp = get_running_module( & ip_globals.modules, configuration[ 6 ].value );
  340.             if( ! ip_netif->arp ){
  341.                 printf( "Failed to start the arp %s\n", configuration[ 6 ].value );
  342.                 net_free_settings( configuration, data );
  343.                 return EINVAL;
  344.             }
  345.         }
  346.         if( configuration[ 7 ].value ){
  347.             ip_netif->routing = ( configuration[ 7 ].value[ 0 ] == 'y' );
  348.         }
  349.         net_free_settings( configuration, data );
  350.     }
  351.     // binds the netif service which also initializes the device
  352.     ip_netif->phone = nil_bind_service( ip_netif->service, ( ipcarg_t ) ip_netif->device_id, SERVICE_IP, ip_globals.client_connection );
  353.     if( ip_netif->phone < 0 ){
  354.         printf( "Failed to contact the nil service %d\n", ip_netif->service );
  355.         return ip_netif->phone;
  356.     }
  357.     // has to be after the device netif module initialization
  358.     if( ip_netif->arp ){
  359.         if( route ){
  360.             address.value = ( char * ) & route->address.s_addr;
  361.             address.length = CONVERT_SIZE( in_addr_t, char, 1 );
  362.             ERROR_PROPAGATE( arp_device_req( ip_netif->arp->phone, ip_netif->device_id, SERVICE_IP, ip_netif->service, & address ));
  363.         }else{
  364.             ip_netif->arp = 0;
  365.         }
  366.     }
  367.     // get packet dimensions
  368.     ERROR_PROPAGATE( nil_packet_size_req( ip_netif->phone, ip_netif->device_id, & ip_netif->addr_len, & ip_netif->prefix, & ip_netif->content, & ip_netif->suffix ));
  369.     if( ip_netif->content < IP_MIN_CONTENT ){
  370.         printf( "Maximum transmission unit %d bytes is too small, at least %d bytes are needed\n", ip_netif->content, IP_MIN_CONTENT );
  371.         ip_netif->content = IP_MIN_CONTENT;
  372.     }
  373.     index = ip_netifs_add( & ip_globals.netifs, ip_netif->device_id, ip_netif );
  374.     if( index < 0 ) return index;
  375.     if( gateway.s_addr ){
  376.         // the default gateway
  377.         ip_globals.gateway.address.s_addr = 0;
  378.         ip_globals.gateway.netmask.s_addr = 0;
  379.         ip_globals.gateway.gateway.s_addr = gateway.s_addr;
  380.         ip_globals.gateway.netif = ip_netif;
  381.     }
  382.     return EOK;
  383. }
  384.  
  385. int ip_mtu_changed_message( device_id_t device_id, size_t mtu ){
  386.     ip_netif_ref    netif;
  387.  
  388.     fibril_rwlock_write_lock( & ip_globals.netifs_lock );
  389.     netif = ip_netifs_find( & ip_globals.netifs, device_id );
  390.     if( ! netif ){
  391.         fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
  392.         return ENOENT;
  393.     }
  394.     netif->content = mtu;
  395.     printf( "ip - device %d changed mtu to %d\n\n", device_id, mtu );
  396.     fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
  397.     return EOK;
  398. }
  399.  
  400. int ip_device_state_message( device_id_t device_id, device_state_t state ){
  401.     ip_netif_ref    netif;
  402.  
  403.     fibril_rwlock_write_lock( & ip_globals.netifs_lock );
  404.     // find the device
  405.     netif = ip_netifs_find( & ip_globals.netifs, device_id );
  406.     if( ! netif ){
  407.         fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
  408.         return ENOENT;
  409.     }
  410.     netif->state = state;
  411.     printf( "ip - device %d changed state to %d\n\n", device_id, state );
  412.     fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
  413.     return EOK;
  414. }
  415.  
  416. int ip_connect_module( services_t service ){
  417.     return EOK;
  418. }
  419.  
  420. int ip_bind_service( services_t service, int protocol, services_t me, async_client_conn_t receiver, tl_received_msg_t received_msg ){
  421.     return ip_register( protocol, me, 0, received_msg );
  422. }
  423.  
  424. int ip_register( int protocol, services_t service, int phone, tl_received_msg_t received_msg ){
  425.     ip_proto_ref    proto;
  426.     int             index;
  427.  
  428.     if( !( protocol && service && (( phone > 0 ) || ( received_msg )))) return EINVAL;
  429.     proto = ( ip_proto_ref ) malloc( sizeof( ip_protos_t ));
  430.     if( ! proto ) return ENOMEM;
  431.     proto->protocol = protocol;
  432.     proto->service = service;
  433.     proto->phone = phone;
  434.     proto->received_msg = received_msg;
  435.     fibril_rwlock_write_lock( & ip_globals.protos_lock );
  436.     index = ip_protos_add( & ip_globals.protos, proto->protocol, proto );
  437.     if( index < 0 ){
  438.         fibril_rwlock_write_unlock( & ip_globals.protos_lock );
  439.         free( proto );
  440.         return index;
  441.     }
  442.     printf( "New protocol registered:\n\tprotocol\t= %d\n\tphone\t= %d\n", proto->protocol, proto->phone );
  443.     fibril_rwlock_write_unlock( & ip_globals.protos_lock );
  444.     return EOK;
  445. }
  446.  
  447. int ip_send_msg( int il_phone, device_id_t device_id, packet_t packet, services_t sender, services_t error ){
  448.     ERROR_DECLARE;
  449.  
  450.     int                 addrlen;
  451.     ip_netif_ref        netif;
  452.     ip_route_ref        route;
  453.     struct sockaddr *       addr;
  454.     struct sockaddr_in *    address_in;
  455. //  struct sockaddr_in6 *   address_in6;
  456.     in_addr_t *         dest;
  457.     in_addr_t *         src;
  458.     int                 phone;
  459.  
  460.     // addresses in the host byte order
  461.     // should be the next hop address or the target destination address
  462.     addrlen = packet_get_addr( packet, NULL, ( uint8_t ** ) & addr );
  463.     if( addrlen < 0 ){
  464.         return ip_release_and_return( packet, addrlen );
  465.     }
  466.     if(( size_t ) addrlen < sizeof( struct sockaddr )){
  467.         return ip_release_and_return( packet, EINVAL );
  468.     }
  469.     switch( addr->sa_family ){
  470.         case AF_INET:
  471.             if( addrlen != sizeof( struct sockaddr_in )){
  472.                 return ip_release_and_return( packet, EINVAL );
  473.             }
  474.             address_in = ( struct sockaddr_in * ) addr;
  475.             dest = & address_in->sin_addr;
  476.             break;
  477.         // TODO IPv6
  478. /*      case AF_INET6:
  479.             if( addrlen != sizeof( struct sockaddr_in6 )) return EINVAL;
  480.             address_in6 = ( struct sockaddr_in6 * ) dest;
  481.             address_in6.sin6_addr.s6_addr;
  482. */      default:
  483.             return ip_release_and_return( packet, EAFNOSUPPORT );
  484.     }
  485.     fibril_rwlock_read_lock( & ip_globals.netifs_lock );
  486.     // device specified?
  487.     if( device_id > 0 ){
  488.         netif = ip_netifs_find( & ip_globals.netifs, device_id );
  489.         route = ip_netif_find_route( netif, * dest );
  490.         if( netif && ( ! route ) && ( ip_globals.gateway.netif == netif )){
  491.             route = & ip_globals.gateway;
  492.         }
  493.     }else{
  494.         route = ip_find_route( * dest );
  495.         netif = route ? route->netif : NULL;
  496.     }
  497.     if( !( netif && route )){
  498.         fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
  499.         phone = ip_prepare_icmp_and_get_phone( error, packet, NULL );
  500.         if( phone >= 0 ){
  501.             // unreachable ICMP if no routing
  502.             icmp_destination_unreachable_msg( phone, ICMP_NET_UNREACH, 0, packet );
  503.         }
  504.         return ENOENT;
  505.     }
  506.     if( error ){
  507.         // do not send for broadcast, anycast packets or network broadcast
  508.         if(( ! dest->s_addr )
  509.         || ( !( ~ dest->s_addr ))
  510.         || ( !( ~(( dest->s_addr & ( ~ route->netmask.s_addr )) | route->netmask.s_addr )))
  511.         || ( !( dest->s_addr & ( ~ route->netmask.s_addr )))){
  512.             return ip_release_and_return( packet, EINVAL );
  513.         }
  514.     }
  515.     if( route->address.s_addr == dest->s_addr ){
  516.         // find the loopback device to deliver
  517.         dest->s_addr = IPV4_LOCALHOST_ADDRESS;
  518.         route = ip_find_route( * dest );
  519.         netif = route ? route->netif : NULL;
  520.         if( !( netif && route )){
  521.             fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
  522.             phone = ip_prepare_icmp_and_get_phone( error, packet, NULL );
  523.             if( phone >= 0 ){
  524.                 // unreachable ICMP if no routing
  525.                 icmp_destination_unreachable_msg( phone, ICMP_HOST_UNREACH, 0, packet );
  526.             }
  527.             return ENOENT;
  528.         }
  529.     }
  530.     src = ip_netif_address( netif );
  531.     if( ! src ){
  532.         fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
  533.         return ip_release_and_return( packet, ENOENT );
  534.     }
  535.     ERROR_CODE = ip_send_route( packet, netif, route, src, * dest, error );
  536.     fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
  537.     return ERROR_CODE;
  538. }
  539.  
  540. in_addr_t * ip_netif_address( ip_netif_ref netif ){
  541.     ip_route_ref    route;
  542.  
  543.     route = ip_routes_get_index( & netif->routes, 0 );
  544.     return route ? & route->address : NULL;
  545. }
  546.  
  547. int ip_send_route( packet_t packet, ip_netif_ref netif, ip_route_ref route, in_addr_t * src, in_addr_t dest, services_t error ){
  548.     ERROR_DECLARE;
  549.  
  550.     measured_string_t   destination;
  551.     measured_string_ref translation;
  552.     char *              data;
  553.     int                 phone;
  554.  
  555.     // get destination hardware address
  556.     if( netif->arp && ( route->address.s_addr != dest.s_addr )){
  557.         destination.value = route->gateway.s_addr ? ( char * ) & route->gateway.s_addr : ( char * ) & dest.s_addr;
  558.         destination.length = CONVERT_SIZE( dest.s_addr, char, 1 );
  559.         if( ERROR_OCCURRED( arp_translate_req( netif->arp->phone, netif->device_id, SERVICE_IP, & destination, & translation, & data ))){
  560. //          sleep( 1 );
  561. //          ERROR_PROPAGATE( arp_translate_req( netif->arp->phone, netif->device_id, SERVICE_IP, & destination, & translation, & data ));
  562.             pq_release( ip_globals.net_phone, packet_get_id( packet ));
  563.             return ERROR_CODE;
  564.         }
  565.         if( !( translation && translation->value )){
  566.             if( translation ){
  567.                 free( translation );
  568.                 free( data );
  569.             }
  570.             phone = ip_prepare_icmp_and_get_phone( error, packet, NULL );
  571.             if( phone >= 0 ){
  572.                 // unreachable ICMP if no routing
  573.                 icmp_destination_unreachable_msg( phone, ICMP_HOST_UNREACH, 0, packet );
  574.             }
  575.             return EINVAL;
  576.         }
  577.     }else translation = NULL;
  578.     if( ERROR_OCCURRED( ip_prepare_packet( src, dest, packet, translation ))){
  579.         pq_release( ip_globals.net_phone, packet_get_id( packet ));
  580.     }else{
  581.         packet = ip_split_packet( packet, netif->prefix, netif->content, netif->suffix, netif->addr_len, error );
  582.         if( packet ){
  583.             nil_send_msg( netif->phone, netif->device_id, packet, SERVICE_IP );
  584.         }
  585.     }
  586.     if( translation ){
  587.         free( translation );
  588.         free( data );
  589.     }
  590.     return ERROR_CODE;
  591. }
  592.  
  593. int ip_prepare_packet( in_addr_t * source, in_addr_t dest, packet_t packet, measured_string_ref destination ){
  594.     ERROR_DECLARE;
  595.  
  596.     size_t              length;
  597.     ip_header_ref       header;
  598.     ip_header_ref       last_header;
  599.     ip_header_ref       middle_header;
  600.     packet_t            next;
  601.  
  602.     length = packet_get_data_length( packet );
  603.     if(( length < sizeof( ip_header_t )) || ( length > IP_MAX_CONTENT )) return EINVAL;
  604.     header = ( ip_header_ref ) packet_get_data( packet );
  605.     if( destination ){
  606.         ERROR_PROPAGATE( packet_set_addr( packet, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length )));
  607.     }else{
  608.         ERROR_PROPAGATE( packet_set_addr( packet, NULL, NULL, 0 ));
  609.     }
  610.     header->version = IPV4;
  611.     header->fragment_offset_high = 0;
  612.     header->fragment_offset_low = 0;
  613.     header->header_checksum = 0;
  614.     if( source ) header->source_address = source->s_addr;
  615.     header->destination_address = dest.s_addr;
  616.     fibril_rwlock_write_lock( & ip_globals.lock );
  617.     ++ ip_globals.packet_counter;
  618.     header->identification = htons( ip_globals.packet_counter );
  619.     fibril_rwlock_write_unlock( & ip_globals.lock );
  620. //  length = packet_get_data_length( packet );
  621.     if( pq_next( packet )){
  622.         last_header = ( ip_header_ref ) malloc( IP_HEADER_LENGTH( header ));
  623.         if( ! last_header ) return ENOMEM;
  624.         ip_create_last_header( last_header, header );
  625.         next = pq_next( packet );
  626.         while( pq_next( next )){
  627.             middle_header = ( ip_header_ref ) packet_prefix( next, IP_HEADER_LENGTH( last_header ));
  628.             if( ! middle_header ) return ENOMEM;
  629.             memcpy( middle_header, last_header, IP_HEADER_LENGTH( last_header ));
  630.             header->flags |= IPFLAG_MORE_FRAGMENTS;
  631.             middle_header->total_length = htons( packet_get_data_length( next ));
  632.             middle_header->fragment_offset_high = IP_COMPUTE_FRAGMENT_OFFSET_HIGH( length );
  633.             middle_header->fragment_offset_low = IP_COMPUTE_FRAGMENT_OFFSET_LOW( length );
  634.             middle_header->header_checksum = IP_HEADER_CHECKSUM( middle_header );
  635.             if( destination ){
  636.                 ERROR_PROPAGATE( packet_set_addr( next, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length )));
  637.             }
  638.             length += packet_get_data_length( next );
  639.             next = pq_next( next );
  640.         }
  641.         middle_header = ( ip_header_ref ) packet_prefix( next, IP_HEADER_LENGTH( last_header ));
  642.         if( ! middle_header ) return ENOMEM;
  643.         memcpy( middle_header, last_header, IP_HEADER_LENGTH( last_header ));
  644.         middle_header->total_length = htons( packet_get_data_length( next ));
  645.         middle_header->fragment_offset_high = IP_COMPUTE_FRAGMENT_OFFSET_HIGH( length );
  646.         middle_header->fragment_offset_low = IP_COMPUTE_FRAGMENT_OFFSET_LOW( length );
  647.         middle_header->header_checksum = IP_HEADER_CHECKSUM( middle_header );
  648.         if( destination ){
  649.             ERROR_PROPAGATE( packet_set_addr( next, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length )));
  650.         }
  651.         length += packet_get_data_length( next );
  652.         free( last_header );
  653.         header->flags |= IPFLAG_MORE_FRAGMENTS;
  654.     }
  655.     header->total_length = htons( length );
  656.     // unnecessary for all protocols
  657.     header->header_checksum = IP_HEADER_CHECKSUM( header );
  658.     return EOK;
  659. }
  660.  
  661. int ip_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
  662.     ERROR_DECLARE;
  663.  
  664.     packet_t                packet;
  665.     struct sockaddr *       addr;
  666.     size_t                  addrlen;
  667.     ip_pseudo_header_ref    header;
  668.     size_t                  headerlen;
  669.  
  670.     * answer_count = 0;
  671.     switch( IPC_GET_METHOD( * call )){
  672.         case IPC_M_PHONE_HUNGUP:
  673.             return EOK;
  674.         case NET_IL_DEVICE:
  675.             return ip_device_req( 0, IPC_GET_DEVICE( call ), IPC_GET_SERVICE( call ));
  676.         case IPC_M_CONNECT_TO_ME:
  677.             return ip_register( IL_GET_PROTO( call ), IL_GET_SERVICE( call ), IPC_GET_PHONE( call ), NULL );
  678.         case NET_IL_SEND:
  679.             ERROR_PROPAGATE( packet_translate( ip_globals.net_phone, & packet, IPC_GET_PACKET( call )));
  680.             return ip_send_msg( 0, IPC_GET_DEVICE( call ), packet, 0, IPC_GET_ERROR( call ));
  681.         case NET_IL_DEVICE_STATE:
  682.             return ip_device_state_message( IPC_GET_DEVICE( call ), IPC_GET_STATE( call ));
  683.         case NET_IL_RECEIVED:
  684.             ERROR_PROPAGATE( packet_translate( ip_globals.net_phone, & packet, IPC_GET_PACKET( call )));
  685.             return ip_receive_message( IPC_GET_DEVICE( call ), packet );
  686.         case NET_IP_RECEIVED_ERROR:
  687.             ERROR_PROPAGATE( packet_translate( ip_globals.net_phone, & packet, IPC_GET_PACKET( call )));
  688.             return ip_received_error_msg( 0, IPC_GET_DEVICE( call ), packet, IPC_GET_TARGET( call ), IPC_GET_ERROR( call ));
  689.         case NET_IP_ADD_ROUTE:
  690.             return ip_add_route_req( 0, IPC_GET_DEVICE( call ), IP_GET_ADDRESS( call ), IP_GET_NETMASK( call ), IP_GET_GATEWAY( call ));
  691.         case NET_IP_SET_GATEWAY:
  692.             return ip_set_gateway_req( 0, IPC_GET_DEVICE( call ), IP_GET_GATEWAY( call ));
  693.         case NET_IP_GET_ROUTE:
  694.             ERROR_PROPAGATE( data_receive(( void ** ) & addr, & addrlen ));
  695.             ERROR_PROPAGATE( ip_get_route_req( 0, IP_GET_PROTOCOL( call ), addr, ( socklen_t ) addrlen, IPC_SET_DEVICE( answer ), & header, & headerlen ));
  696.             * IP_SET_HEADERLEN( answer ) = headerlen;
  697.             * answer_count = 2;
  698.             if( ! ERROR_OCCURRED( data_reply( & headerlen, sizeof( headerlen )))){
  699.                 ERROR_CODE = data_reply( header, headerlen );
  700.             }
  701.             free( header );
  702.             return ERROR_CODE;
  703.         case NET_IL_PACKET_SPACE:
  704.             ERROR_PROPAGATE( ip_packet_size_req( 0, IPC_GET_DEVICE( call ), IPC_SET_ADDR( answer ), IPC_SET_PREFIX( answer ), IPC_SET_CONTENT( answer ), IPC_SET_SUFFIX( answer )));
  705.             * answer_count = 3;
  706.             return EOK;
  707.         case NET_IL_MTU_CHANGED:
  708.             return ip_mtu_changed_message( IPC_GET_DEVICE( call ), IPC_GET_MTU( call ));
  709.     }
  710.     return ENOTSUP;
  711. }
  712.  
  713. int ip_packet_size_req( int ip_phone, device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix ){
  714.     ip_netif_ref    netif;
  715.     int             index;
  716.  
  717.     if( !( addr_len && prefix && content && suffix )) return EBADMEM;
  718.     * content = IP_MAX_CONTENT - IP_PREFIX;
  719.     fibril_rwlock_read_lock( & ip_globals.netifs_lock );
  720.     if( device_id < 0 ){
  721.         * addr_len = IP_ADDR;
  722.         * prefix = 0;
  723.         * suffix = 0;
  724.         for( index = ip_netifs_count( & ip_globals.netifs ) - 1; index >= 0; -- index ){
  725.             netif = ip_netifs_get_index( & ip_globals.netifs, index );
  726.             if( netif ){
  727.                 if( netif->addr_len > * addr_len ) * addr_len = netif->addr_len;
  728.                 if( netif->prefix > * prefix ) * prefix = netif->prefix;
  729.                 if( netif->suffix > * suffix ) * suffix = netif->suffix;
  730.             }
  731.         }
  732.         * prefix = * prefix + IP_PREFIX;
  733.         * suffix = * suffix + IP_SUFFIX;
  734.     }else{
  735.         netif = ip_netifs_find( & ip_globals.netifs, device_id );
  736.         if( ! netif ){
  737.             fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
  738.             return ENOENT;
  739.         }
  740.         * addr_len = ( netif->addr_len > IP_ADDR ) ? netif->addr_len : IP_ADDR;
  741.         * prefix = netif->prefix + IP_PREFIX;
  742.         * suffix = netif->suffix + IP_SUFFIX;
  743.     }
  744.     fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
  745.     return EOK;
  746. }
  747.  
  748. int ip_add_route_req( int ip_phone, device_id_t device_id, in_addr_t address, in_addr_t netmask, in_addr_t gateway ){
  749.     ip_route_ref    route;
  750.     ip_netif_ref    netif;
  751.     int             index;
  752.  
  753.     fibril_rwlock_write_lock( & ip_globals.netifs_lock );
  754.     netif = ip_netifs_find( & ip_globals.netifs, device_id );
  755.     if( ! netif ){
  756.         fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
  757.         return ENOENT;
  758.     }
  759.     route = ( ip_route_ref ) malloc( sizeof( ip_route_t ));
  760.     if( ! route ){
  761.         fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
  762.         return ENOMEM;
  763.     }
  764.     route->address.s_addr = address.s_addr;
  765.     route->netmask.s_addr = netmask.s_addr;
  766.     route->gateway.s_addr = gateway.s_addr;
  767.     route->netif = netif;
  768.     index = ip_routes_add( & netif->routes, route );
  769.     if( index < 0 ) free( route );
  770.     fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
  771.     return index;
  772. }
  773.  
  774. ip_route_ref ip_find_route( in_addr_t destination ){
  775.     int             index;
  776.     ip_route_ref    route;
  777.     ip_netif_ref    netif;
  778.  
  779.     // start with the last netif - the newest one
  780.     index = ip_netifs_count( & ip_globals.netifs ) - 1;
  781.     while( index >= 0 ){
  782.         netif = ip_netifs_get_index( & ip_globals.netifs, index );
  783.         if( netif && ( netif->state == NETIF_ACTIVE )){
  784.             route = ip_netif_find_route( netif, destination );
  785.             if( route ) return route;
  786.         }
  787.         -- index;
  788.     }
  789.     return & ip_globals.gateway;
  790. }
  791.  
  792. ip_route_ref ip_netif_find_route( ip_netif_ref netif, in_addr_t destination ){
  793.     int             index;
  794.     ip_route_ref    route;
  795.  
  796.     if( netif ){
  797.         // start with the first one - the direct route
  798.         for( index = 0; index < ip_routes_count( & netif->routes ); ++ index ){
  799.             route = ip_routes_get_index( & netif->routes, index );
  800.             if( route && (( route->address.s_addr & route->netmask.s_addr ) == ( destination.s_addr & route->netmask.s_addr ))){
  801.                 return route;
  802.             }
  803.         }
  804.     }
  805.     return NULL;
  806. }
  807.  
  808. int ip_set_gateway_req( int ip_phone, device_id_t device_id, in_addr_t gateway ){
  809.     ip_netif_ref    netif;
  810.  
  811.     fibril_rwlock_write_lock( & ip_globals.netifs_lock );
  812.     netif = ip_netifs_find( & ip_globals.netifs, device_id );
  813.     if( ! netif ){
  814.         fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
  815.         return ENOENT;
  816.     }
  817.     ip_globals.gateway.address.s_addr = 0;
  818.     ip_globals.gateway.netmask.s_addr = 0;
  819.     ip_globals.gateway.gateway.s_addr = gateway.s_addr;
  820.     ip_globals.gateway.netif = netif;
  821.     fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
  822.     return EOK;
  823. }
  824.  
  825. packet_t ip_split_packet( packet_t packet, size_t prefix, size_t content, size_t suffix, socklen_t addr_len, services_t error ){
  826.     size_t          length;
  827.     packet_t        next;
  828.     packet_t        new_packet;
  829.     int             result;
  830.     int             phone;
  831.  
  832.     next = packet;
  833.     // check all packets
  834.     while( next ){
  835.         length = packet_get_data_length( next );
  836.         // too long?
  837.         if( length > content ){
  838.             result = ip_fragment_packet( next, content, prefix, suffix, addr_len );
  839.             if( result != EOK ){
  840.                 new_packet = pq_detach( next );
  841.                 if( next == packet ){
  842.                     // the new first packet of the queue
  843.                     packet = new_packet;
  844.                 }
  845.                 // fragmentation needed?
  846.                 if( result == EPERM ){
  847.                     phone = ip_prepare_icmp_and_get_phone( error, next, NULL );
  848.                     if( phone >= 0 ){
  849.                         // fragmentation necessary ICMP
  850.                         icmp_destination_unreachable_msg( phone, ICMP_FRAG_NEEDED, content, next );
  851.                     }
  852.                 }else{
  853.                     pq_release( ip_globals.net_phone, packet_get_id( next ));
  854.                 }
  855.                 next = new_packet;
  856.                 continue;
  857.             }
  858.         }
  859.         next = pq_next( next );
  860.     }
  861.     return packet;
  862. }
  863.  
  864. int ip_fragment_packet( packet_t packet, size_t length, size_t prefix, size_t suffix, socklen_t addr_len ){
  865.     ERROR_DECLARE;
  866.  
  867.     packet_t        new_packet;
  868.     ip_header_ref   header;
  869.     ip_header_ref   middle_header;
  870.     ip_header_ref   last_header;
  871.     struct sockaddr *       src;
  872.     struct sockaddr *       dest;
  873.     socklen_t       addrlen;
  874.     int             result;
  875.  
  876.     result = packet_get_addr( packet, ( uint8_t ** ) & src, ( uint8_t ** ) & dest );
  877.     if( result <= 0 ) return EINVAL;
  878.     addrlen = ( socklen_t ) result;
  879.     if( packet_get_data_length( packet ) <= sizeof( ip_header_t )) return ENOMEM;
  880.     // get header
  881.     header = ( ip_header_ref ) packet_get_data( packet );
  882.     if( ! header ) return EINVAL;
  883.     // fragmentation forbidden?
  884.     if( header->flags & IPFLAG_DONT_FRAGMENT ){
  885.         return EPERM;
  886.     }
  887.     // create the last fragment
  888.     new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, (( addrlen > addr_len ) ? addrlen : addr_len ));
  889.     if( ! new_packet ) return ENOMEM;
  890.     // allocate as much as originally
  891.     last_header = ( ip_header_ref ) packet_suffix( new_packet, IP_HEADER_LENGTH( header ));
  892.     if( ! last_header ){
  893.         return ip_release_and_return( packet, ENOMEM );
  894.     }
  895.     ip_create_last_header( last_header, header );
  896.     // trim the unused space
  897.     if( ERROR_OCCURRED( packet_trim( new_packet, 0, IP_HEADER_LENGTH( header ) - IP_HEADER_LENGTH( last_header )))){
  898.         return ip_release_and_return( packet, ERROR_CODE );
  899.     }
  900.     // biggest multiple of 8 lower than content
  901.     // TODO even fragmentation?
  902.     length = length & ( ~ 0x7 );// ( content / 8 ) * 8
  903.     if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, last_header, (( IP_HEADER_DATA_LENGTH( header ) - (( length - IP_HEADER_LENGTH( header )) & ( ~ 0x7 ))) % (( length - IP_HEADER_LENGTH( last_header )) & ( ~ 0x7 ))), src, dest, addrlen ))){
  904.         return ip_release_and_return( packet, ERROR_CODE );
  905.     }
  906.     // mark the first as fragmented
  907.     header->flags |= IPFLAG_MORE_FRAGMENTS;
  908.     // create middle framgents
  909.     while( IP_TOTAL_LENGTH( header ) > length ){
  910.         new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, (( addrlen >= addr_len ) ? addrlen : addr_len ));
  911.         if( ! new_packet ) return ENOMEM;
  912.         middle_header = ip_create_middle_header( new_packet, last_header );
  913.         if( ! middle_header ){
  914.             return ip_release_and_return( packet, ENOMEM );
  915.         }
  916.         if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, middle_header, ( length - IP_HEADER_LENGTH( middle_header )) & ( ~ 0x7 ), src, dest, addrlen ))){
  917.             return ip_release_and_return( packet, ERROR_CODE );
  918.         }
  919.     }
  920.     // finish the first fragment
  921.     header->header_checksum = IP_HEADER_CHECKSUM( header );
  922.     return EOK;
  923. }
  924.  
  925. int ip_fragment_packet_data( packet_t packet, packet_t new_packet, ip_header_ref header, ip_header_ref new_header, size_t length, const struct sockaddr * src, const struct sockaddr * dest, socklen_t addrlen ){
  926.     ERROR_DECLARE;
  927.  
  928.     void *          data;
  929.     size_t          offset;
  930.  
  931.     data = packet_suffix( new_packet, length );
  932.     if( ! data ) return ENOMEM;
  933.     memcpy( data, (( void * ) header ) + IP_TOTAL_LENGTH( header ) - length, length );
  934.     ERROR_PROPAGATE( packet_trim( packet, 0, length ));
  935.     header->total_length = htons( IP_TOTAL_LENGTH( header ) - length );
  936.     new_header->total_length = htons( IP_HEADER_LENGTH( new_header ) + length );
  937.     offset = IP_FRAGMENT_OFFSET( header ) + IP_HEADER_DATA_LENGTH( header );
  938.     new_header->fragment_offset_high = IP_COMPUTE_FRAGMENT_OFFSET_HIGH( offset );
  939.     new_header->fragment_offset_low = IP_COMPUTE_FRAGMENT_OFFSET_LOW( offset );
  940.     new_header->header_checksum = IP_HEADER_CHECKSUM( new_header );
  941.     ERROR_PROPAGATE( packet_set_addr( new_packet, ( const uint8_t * ) src, ( const uint8_t * ) dest, addrlen ));
  942.     return pq_insert_after( packet, new_packet );
  943. }
  944.  
  945. ip_header_ref ip_create_middle_header( packet_t packet, ip_header_ref last ){
  946.     ip_header_ref   middle;
  947.  
  948.     middle = ( ip_header_ref ) packet_suffix( packet, IP_HEADER_LENGTH( last ));
  949.     if( ! middle ) return NULL;
  950.     memcpy( middle, last, IP_HEADER_LENGTH( last ));
  951.     middle->flags |= IPFLAG_MORE_FRAGMENTS;
  952.     return middle;
  953. }
  954.  
  955. void ip_create_last_header( ip_header_ref last, ip_header_ref first ){
  956.     ip_option_ref   option;
  957.     size_t          next;
  958.     size_t          length;
  959.  
  960.     // copy first itself
  961.     memcpy( last, first, sizeof( ip_header_t ));
  962.     length = sizeof( ip_header_t );
  963.     next = sizeof( ip_header_t );
  964.     // process all ip options
  965.     while( next < first->header_length ){
  966.         option = ( ip_option_ref ) ((( uint8_t * ) first ) + next );
  967.         // skip end or noop
  968.         if(( option->type == IPOPT_END ) || ( option->type == IPOPT_NOOP )){
  969.             ++ next;
  970.         }else{
  971.             // copy if said so or skip
  972.             if( IPOPT_COPIED( option->type )){
  973.                 memcpy((( uint8_t * ) last ) + length, (( uint8_t * ) first ) + next, option->length );
  974.                 length += option->length;
  975.             }
  976.             // next option
  977.             next += option->length;
  978.         }
  979.     }
  980.     // align 4 byte boundary
  981.     if( length % 4 ){
  982.         bzero((( uint8_t * ) last ) + length, 4 - ( length % 4 ));
  983.         last->header_length = length / 4 + 1;
  984.     }else{
  985.         last->header_length = length / 4;
  986.     }
  987.     last->header_checksum = 0;
  988. }
  989.  
  990. int ip_receive_message( device_id_t device_id, packet_t packet ){
  991.     packet_t        next;
  992.  
  993.     do{
  994.         next = pq_detach( packet );
  995.         ip_process_packet( device_id, packet );
  996.         packet = next;
  997.     }while( packet );
  998.     return EOK;
  999. }
  1000.  
  1001. int ip_process_packet( device_id_t device_id, packet_t packet ){
  1002.     ERROR_DECLARE;
  1003.  
  1004.     ip_header_ref   header;
  1005.     in_addr_t       dest;
  1006.     ip_route_ref    route;
  1007.     int             phone;
  1008.     struct sockaddr *   addr;
  1009.     struct sockaddr_in  addr_in;
  1010. //  struct sockaddr_in  addr_in6;
  1011.     socklen_t       addrlen;
  1012.  
  1013.     header = ( ip_header_ref ) packet_get_data( packet );
  1014.     if( ! header ){
  1015.         return ip_release_and_return( packet, ENOMEM );
  1016.     }
  1017.     // checksum
  1018.     if(( header->header_checksum ) && ( IP_HEADER_CHECKSUM( header ))){
  1019.         phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
  1020.         if( phone >= 0 ){
  1021.             // checksum error ICMP
  1022.             icmp_parameter_problem_msg( phone, ICMP_PARAM_POINTER, (( size_t ) (( void * ) & header->header_checksum )) - (( size_t ) (( void * ) header )), packet );
  1023.         }
  1024.         return EINVAL;
  1025.     }
  1026.     if( header->ttl <= 1 ){
  1027.         phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
  1028.         if( phone >= 0 ){
  1029.             // ttl oxceeded ICMP
  1030.             icmp_time_exceeded_msg( phone, ICMP_EXC_TTL, packet );
  1031.         }
  1032.         return EINVAL;
  1033.     }
  1034.     // process ipopt and get destination
  1035.     dest = ip_get_destination( header );
  1036.     // set the addrination address
  1037.     switch( header->version ){
  1038.         case IPVERSION:
  1039.             addrlen = sizeof( addr_in );
  1040.             bzero( & addr_in, addrlen );
  1041.             addr_in.sin_family = AF_INET;
  1042.             memcpy( & addr_in.sin_addr.s_addr, & dest, sizeof( dest ));
  1043.             addr = ( struct sockaddr * ) & addr_in;
  1044.             break;
  1045. /*      case IPv6VERSION:
  1046.             addrlen = sizeof( dest_in6 );
  1047.             bzero( & dest_in6, addrlen );
  1048.             dest_in6.sin6_family = AF_INET6;
  1049.             memcpy( & dest_in6.sin6_addr.s6_addr, );
  1050.             dest = ( struct sockaddr * ) & dest_in;
  1051.             break;
  1052. */      default:
  1053.             return EAFNOSUPPORT;
  1054.     }
  1055.     ERROR_PROPAGATE( packet_set_addr( packet, NULL, ( uint8_t * ) & addr, addrlen ));
  1056.     route = ip_find_route( dest );
  1057.     if( ! route ){
  1058.         phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
  1059.         if( phone >= 0 ){
  1060.             // unreachable ICMP
  1061.             icmp_destination_unreachable_msg( phone, ICMP_HOST_UNREACH, 0, packet );
  1062.         }
  1063.         return ENOENT;
  1064.     }
  1065.     if( route->address.s_addr == dest.s_addr ){
  1066.         // local delivery
  1067.         return ip_deliver_local( device_id, packet, header, 0 );
  1068.     }else{
  1069.         // only if routing enabled
  1070.         if( route->netif->routing ){
  1071.             -- header->ttl;
  1072.             return ip_send_route( packet, route->netif, route, NULL, dest, 0 );
  1073.         }else{
  1074.             phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
  1075.             if( phone >= 0 ){
  1076.                 // unreachable ICMP if no routing
  1077.                 icmp_destination_unreachable_msg( phone, ICMP_HOST_UNREACH, 0, packet );
  1078.             }
  1079.             return ENOENT;
  1080.         }
  1081.     }
  1082. }
  1083.  
  1084. int ip_received_error_msg( int ip_phone, device_id_t device_id, packet_t packet, services_t target, services_t error ){
  1085.     uint8_t *           data;
  1086.     int                 offset;
  1087.     icmp_type_t         type;
  1088.     icmp_code_t         code;
  1089.     ip_netif_ref        netif;
  1090.     measured_string_t   address;
  1091.     ip_route_ref        route;
  1092.     ip_header_ref       header;
  1093.  
  1094.     switch( error ){
  1095.         case SERVICE_ICMP:
  1096.             offset = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
  1097.             if( offset < 0 ){
  1098.                 return ip_release_and_return( packet, ENOMEM );
  1099.             }
  1100.             data = packet_get_data( packet );
  1101.             header = ( ip_header_ref )( data + offset );
  1102.             // destination host unreachable?
  1103.             if(( type == ICMP_DEST_UNREACH ) && ( code == ICMP_HOST_UNREACH )){
  1104.                 fibril_rwlock_read_lock( & ip_globals.netifs_lock );
  1105.                 netif = ip_netifs_find( & ip_globals.netifs, device_id );
  1106.                 if( netif && netif->arp ){
  1107.                     route = ip_routes_get_index( & netif->routes, 0 );
  1108.                     // from the same network?
  1109.                     if( route && (( route->address.s_addr & route->netmask.s_addr ) == ( header->destination_address & route->netmask.s_addr ))){
  1110.                         // clear the ARP mapping if any
  1111.                         address.value = ( char * ) & header->destination_address;
  1112.                         address.length = CONVERT_SIZE( uint8_t, char, sizeof( header->destination_address ));
  1113.                         arp_clear_address_req( netif->arp->phone, netif->device_id, SERVICE_IP, & address );
  1114.                     }
  1115.                 }
  1116.                 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
  1117.             }
  1118.             break;
  1119.         default:
  1120.             return ip_release_and_return( packet, ENOTSUP );
  1121.     }
  1122.     return ip_deliver_local( device_id, packet, header, error );
  1123. }
  1124.  
  1125. int ip_deliver_local( device_id_t device_id, packet_t packet, ip_header_ref header, services_t error ){
  1126.     ERROR_DECLARE;
  1127.  
  1128.     ip_proto_ref    proto;
  1129.     int             phone;
  1130.     services_t      service;
  1131.     tl_received_msg_t   received_msg;
  1132.     struct sockaddr *   src;
  1133.     struct sockaddr *   dest;
  1134.     struct sockaddr_in  src_in;
  1135.     struct sockaddr_in  dest_in;
  1136. //  struct sockaddr_in  src_in6;
  1137. //  struct sockaddr_in  dest_in6;
  1138.     socklen_t       addrlen;
  1139.  
  1140.     if(( header->flags & IPFLAG_MORE_FRAGMENTS ) || IP_FRAGMENT_OFFSET( header )){
  1141.         // TODO fragmented
  1142.         return ENOTSUP;
  1143.     }else{
  1144.         switch( header->version ){
  1145.             case IPVERSION:
  1146.                 addrlen = sizeof( src_in );
  1147.                 bzero( & src_in, addrlen );
  1148.                 src_in.sin_family = AF_INET;
  1149.                 memcpy( & dest_in, & src_in, addrlen );
  1150.                 memcpy( & src_in.sin_addr.s_addr, & header->source_address, sizeof( header->source_address ));
  1151.                 memcpy( & dest_in.sin_addr.s_addr, & header->destination_address, sizeof( header->destination_address ));
  1152.                 src = ( struct sockaddr * ) & src_in;
  1153.                 dest = ( struct sockaddr * ) & dest_in;
  1154.                 break;
  1155. /*          case IPv6VERSION:
  1156.                 addrlen = sizeof( src_in6 );
  1157.                 bzero( & src_in6, addrlen );
  1158.                 src_in6.sin6_family = AF_INET6;
  1159.                 memcpy( & dest_in6, & src_in6, addrlen );
  1160.                 memcpy( & src_in6.sin6_addr.s6_addr, );
  1161.                 memcpy( & dest_in6.sin6_addr.s6_addr, );
  1162.                 src = ( struct sockaddr * ) & src_in;
  1163.                 dest = ( struct sockaddr * ) & dest_in;
  1164.                 break;
  1165. */          default:
  1166.                 return ip_release_and_return( packet, EAFNOSUPPORT );
  1167.         }
  1168.         if( ERROR_OCCURRED( packet_set_addr( packet, ( uint8_t * ) src, ( uint8_t * ) dest, addrlen ))){
  1169.             return ip_release_and_return( packet, ERROR_CODE );
  1170.         }
  1171.         // trim padding if present
  1172.         if(( ! error ) && ( IP_TOTAL_LENGTH( header ) < packet_get_data_length( packet ))){
  1173.             if( ERROR_OCCURRED( packet_trim( packet, 0, packet_get_data_length( packet ) - IP_TOTAL_LENGTH( header )))){
  1174.                 return ip_release_and_return( packet, ERROR_CODE );
  1175.             }
  1176.         }
  1177.         fibril_rwlock_read_lock( & ip_globals.protos_lock );
  1178.         proto = ip_protos_find( & ip_globals.protos, header->protocol );
  1179.         if( ! proto ){
  1180.             fibril_rwlock_read_unlock( & ip_globals.protos_lock );
  1181.             phone = ip_prepare_icmp_and_get_phone( error, packet, header );
  1182.             if( phone >= 0 ){
  1183.                 // unreachable ICMP
  1184.                 icmp_destination_unreachable_msg( phone, ICMP_PROT_UNREACH, 0, packet );
  1185.             }
  1186.             return ENOENT;
  1187.         }
  1188.         if( proto->received_msg ){
  1189.             service = proto->service;
  1190.             received_msg = proto->received_msg;
  1191.             fibril_rwlock_read_unlock( & ip_globals.protos_lock );
  1192.             ERROR_CODE = received_msg( device_id, packet, service, error );
  1193.         }else{
  1194.             ERROR_CODE = tl_received_msg( proto->phone, device_id, packet, proto->service, error );
  1195.             fibril_rwlock_read_unlock( & ip_globals.protos_lock );
  1196.         }
  1197.         return ERROR_CODE;
  1198.     }
  1199. }
  1200.  
  1201. in_addr_t ip_get_destination( ip_header_ref header ){
  1202.     in_addr_t   destination;
  1203.  
  1204.     // TODO search set ipopt route?
  1205.     destination.s_addr = header->destination_address;
  1206.     return destination;
  1207. }
  1208.  
  1209. int ip_prepare_icmp( packet_t packet, ip_header_ref header ){
  1210.     packet_t    next;
  1211.     struct sockaddr *   dest;
  1212.     struct sockaddr_in  dest_in;
  1213. //  struct sockaddr_in  dest_in6;
  1214.     socklen_t       addrlen;
  1215.  
  1216.     // detach the first packet and release the others
  1217.     next = pq_detach( packet );
  1218.     if( next ){
  1219.         pq_release( ip_globals.net_phone, packet_get_id( next ));
  1220.     }
  1221.     if( ! header ){
  1222.         if( packet_get_data_length( packet ) <= sizeof( ip_header_t )) return ENOMEM;
  1223.         // get header
  1224.         header = ( ip_header_ref ) packet_get_data( packet );
  1225.         if( ! header ) return EINVAL;
  1226.     }
  1227.     // only for the first fragment
  1228.     if( IP_FRAGMENT_OFFSET( header )) return EINVAL;
  1229.     // set the destination address
  1230.     switch( header->version ){
  1231.         case IPVERSION:
  1232.             addrlen = sizeof( dest_in );
  1233.             bzero( & dest_in, addrlen );
  1234.             dest_in.sin_family = AF_INET;
  1235.             memcpy( & dest_in.sin_addr.s_addr, & header->source_address, sizeof( header->source_address ));
  1236.             dest = ( struct sockaddr * ) & dest_in;
  1237.             break;
  1238. /*      case IPv6VERSION:
  1239.             addrlen = sizeof( dest_in6 );
  1240.             bzero( & dest_in6, addrlen );
  1241.             dest_in6.sin6_family = AF_INET6;
  1242.             memcpy( & dest_in6.sin6_addr.s6_addr, );
  1243.             dest = ( struct sockaddr * ) & dest_in;
  1244.             break;
  1245. */      default:
  1246.             return EAFNOSUPPORT;
  1247.     }
  1248.     return packet_set_addr( packet, NULL, ( uint8_t * ) dest, addrlen );
  1249. }
  1250.  
  1251. int ip_get_icmp_phone( void ){
  1252.     ip_proto_ref    proto;
  1253.     int             phone;
  1254.  
  1255.     fibril_rwlock_read_lock( & ip_globals.protos_lock );
  1256.     proto = ip_protos_find( & ip_globals.protos, IPPROTO_ICMP );
  1257.     phone = proto ? proto->phone : ENOENT;
  1258.     fibril_rwlock_read_unlock( & ip_globals.protos_lock );
  1259.     return phone;
  1260. }
  1261.  
  1262. int ip_prepare_icmp_and_get_phone( services_t error, packet_t packet, ip_header_ref header ){
  1263.     int phone;
  1264.  
  1265.     phone = ip_get_icmp_phone();
  1266.     if( error || ( phone < 0 ) || ip_prepare_icmp( packet, header )){
  1267.         return ip_release_and_return( packet, EINVAL );
  1268.     }
  1269.     return phone;
  1270. }
  1271.  
  1272. int ip_release_and_return( packet_t packet, int result ){
  1273.     pq_release( ip_globals.net_phone, packet_get_id( packet ));
  1274.     return result;
  1275. }
  1276.  
  1277. int ip_get_route_req( int ip_phone, ip_protocol_t protocol, const struct sockaddr * destination, socklen_t addrlen, device_id_t * device_id, ip_pseudo_header_ref * header, size_t * headerlen ){
  1278.     struct sockaddr_in *    address_in;
  1279. //  struct sockaddr_in6 *   address_in6;
  1280.     in_addr_t *             dest;
  1281.     in_addr_t *             src;
  1282.     ip_route_ref            route;
  1283.     ipv4_pseudo_header_ref  header_in;
  1284.  
  1285.     if( !( destination && ( addrlen > 0 ))) return EINVAL;
  1286.     if( !( device_id && header && headerlen )) return EBADMEM;
  1287.     if(( size_t ) addrlen < sizeof( struct sockaddr )){
  1288.         return EINVAL;
  1289.     }
  1290.     switch( destination->sa_family ){
  1291.         case AF_INET:
  1292.             if( addrlen != sizeof( struct sockaddr_in )){
  1293.                 return EINVAL;
  1294.             }
  1295.             address_in = ( struct sockaddr_in * ) destination;
  1296.             dest = & address_in->sin_addr;
  1297.             break;
  1298.         // TODO IPv6
  1299. /*      case AF_INET6:
  1300.             if( addrlen != sizeof( struct sockaddr_in6 )) return EINVAL;
  1301.             address_in6 = ( struct sockaddr_in6 * ) dest;
  1302.             address_in6.sin6_addr.s6_addr;
  1303. */      default:
  1304.             return EAFNOSUPPORT;
  1305.     }
  1306.     fibril_rwlock_read_lock( & ip_globals.lock );
  1307.     route = ip_find_route( * dest );
  1308.     if( !( route && route->netif )){
  1309.         fibril_rwlock_read_unlock( & ip_globals.lock );
  1310.         return ENOENT;
  1311.     }
  1312.     * device_id = route->netif->device_id;
  1313.     src = ip_netif_address( route->netif );
  1314.     fibril_rwlock_read_unlock( & ip_globals.lock );
  1315.     * headerlen = sizeof( * header_in );
  1316.     header_in = ( ipv4_pseudo_header_ref ) malloc( * headerlen );
  1317.     if( ! header_in ) return ENOMEM;
  1318.     bzero( header_in, * headerlen );
  1319.     header_in->destination_address = dest->s_addr;
  1320.     header_in->source_address = src->s_addr;
  1321.     header_in->protocol = protocol;
  1322.     header_in->data_length = 0;
  1323.     * header = ( ip_pseudo_header_ref ) header_in;
  1324.     return EOK;
  1325. }
  1326.  
  1327. /** @}
  1328.  */
  1329.