Subversion Repositories HelenOS

Rev

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