Subversion Repositories HelenOS

Rev

Rev 3901 | Go to most recent revision | Blame | 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 net
  30.  *  @{
  31.  */
  32.  
  33. /** @file
  34.  */
  35.  
  36. #include <async.h>
  37. #include <ctype.h>
  38. #include <errno.h>
  39. #include <malloc.h>
  40. #include <stdio.h>
  41. #include <task.h>
  42. #include <unistd.h>
  43.  
  44. #include <ipc/ipc.h>
  45. #include <ipc/services.h>
  46.  
  47. #include "../err.h"
  48. #include "../messages.h"
  49. #include "../modules.h"
  50. //#include "../self_test.h"
  51.  
  52. #include "../structures/char_map.h"
  53. #include "../structures/generic_char_map.h"
  54. #include "../structures/measured_strings.h"
  55. #include "../structures/packet/packet.h"
  56. #include "../structures/packet/packet_server.h"
  57.  
  58. #include "../il/ip/ip_messages.h"
  59. #include "../netif/device.h"
  60.  
  61. #if IP_BUNDLE
  62.  
  63.     #include "../ip/ip_module.h"
  64.  
  65. #endif
  66.  
  67. #if TCP_BUNDLE
  68.  
  69.     #include "../tcp/tcp_module.h"
  70.  
  71. #endif
  72.  
  73. #define NAME    "Networking"
  74.  
  75. #define LO_NAME             "lo"
  76. #define LO_FILENAME         "/sbin/lo"
  77. #define DP8390_ISA_NAME         "dp8390_isa"
  78. #define DP8390_ISA_FILENAME     "/sbin/dp8380_isa"
  79. #define ETHERNET_NAME           "ethernet"
  80. #define ETHERNET_FILENAME       "/sbin/ethernet"
  81. #define IP_NAME             "ip"
  82. #define IP_FILENAME         "/sbin/ip"
  83.  
  84. #define IPC_GET_DEVICE( call )  ( device_id_t ) IPC_GET_ARG1( * call )
  85. #define IPC_GET_COUNT( call )   ( int ) IPC_GET_ARG2( * call )
  86.  
  87. typedef struct module_struct    module_t;
  88. typedef module_t *      module_ref;
  89.  
  90. typedef struct netif        netif_t;
  91. typedef netif_t *       netif_ref;
  92.  
  93. typedef struct networking_globals   networking_globals_t;
  94.  
  95. DEVICE_MAP_DECLARE( netifs, netif_t )
  96.  
  97. GENERIC_CHAR_MAP_DECLARE( measured_strings, measured_string_t )
  98.  
  99. GENERIC_CHAR_MAP_DECLARE( modules, module_t )
  100.  
  101. struct module_struct{
  102.     task_id_t   task_id;
  103.     services_t  service;
  104.     int     phone;
  105.     int     usage;
  106.     const char *    name;
  107.     const char *    filename;
  108. };
  109.  
  110. /** A present network interface device.
  111.  */
  112. struct netif{
  113.     /** A system-unique network interface identifier.
  114.      */
  115.     device_id_t     id;
  116.     /** A serving network interface driver module index.
  117.      */
  118.     module_ref      driver;
  119.     /** A serving link layer module index.
  120.      */
  121.     module_ref      nil;
  122.     /** A serving internet layer module index.
  123.      */
  124.     module_ref      il;
  125.     /** A system-unique network interface name.
  126.      */
  127.     char *          name;
  128.     /** Configuration.
  129.      */
  130.     measured_strings_t  configuration;
  131. };
  132.  
  133. /** A networking module global variables.
  134.  */
  135. struct networking_globals{
  136.     /** Present network interfaces.
  137.      */
  138.     netifs_t        netifs;
  139.     /** Network interface structure indices by names.
  140.      */
  141.     char_map_t      netif_names;
  142.     /** Available modules.
  143.      */
  144.     modules_t       modules;
  145.     /** Global configuration.
  146.      */
  147.     measured_strings_t  configuration;
  148. };
  149.  
  150. void    networking_print_name( void );
  151. int     add_module( module_ref * module, modules_ref modules, const char const * name, const char const * filename, services_t service, task_id_t task_id );
  152. static void client_connection( ipc_callid_t iid, ipc_call_t * icall );
  153. measured_string_ref configuration_find( measured_strings_ref configuration, const char * name );
  154. int networking_start_module( async_client_conn_t client_connection );
  155. int     networking_initialize( void );
  156. int networking_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count );
  157. int net_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count );
  158. //int       parse_line( measured_strings_ref configuration, char * line );
  159. int     add_configuration( measured_strings_ref configuration, const char * name, const char * value );
  160. int     read_configuration( void );
  161. task_id_t   spawn( const char * fname );
  162. int     startup( void );
  163. device_id_t generate_new_device_id( void );
  164.  
  165. static networking_globals_t networking_globals;
  166.  
  167. DEVICE_MAP_IMPLEMENT( netifs, netif_t )
  168.  
  169. GENERIC_CHAR_MAP_IMPLEMENT( measured_strings, measured_string_t )
  170.  
  171. GENERIC_CHAR_MAP_IMPLEMENT( modules, module_t )
  172.  
  173. void networking_print_name( void ){
  174.     printf( NAME );
  175. }
  176.  
  177. int add_module( module_ref * module, modules_ref modules, const char * name, const char * filename, services_t service, task_id_t task_id ){
  178.     ERROR_DECLARE;
  179.  
  180.     module_ref  tmp_module;
  181.  
  182.     tmp_module = ( module_ref ) malloc( sizeof( module_t ));
  183.     if( ! tmp_module ) return ENOMEM;
  184.     tmp_module->task_id = task_id;
  185.     tmp_module->phone = 0;
  186.     tmp_module->usage = 0;
  187.     tmp_module->name = name;
  188.     tmp_module->filename = filename;
  189.     tmp_module->service = service;
  190.     if( ERROR_OCCURRED( modules_add( modules, tmp_module->name, 0, tmp_module ))){
  191.         free( tmp_module );
  192.         return ERROR_CODE;
  193.     }
  194.     if( module ) * module = tmp_module;
  195.     return EOK;
  196. }
  197.  
  198. int networking_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
  199. #ifdef NETWORKING_module
  200.         //TODO map to *_message
  201.         if( IS_NET_IL_MESSAGE( call ) || IS_NET_IP_MESSAGE( call )){
  202.             return ip_message( callid, call, answer, answer_count );
  203. /*      }else if( IS_NET_ARP_MESSAGE( call )){
  204.             return arp_message( callid, call, answer, answer_count );
  205. *//*        }else if( IS_NET_RARP_MESSAGE( call )){
  206.             return rarp_message( callid, call, answer, answer_count );
  207. *//*        }else if( IS_NET_ICMP_MESSAGE( call )){
  208.             return icmp_message( callid, call, answer, answer_count );
  209. *//*        }else if( IS_NET_UDP_MESSAGE( call )){
  210.             return udp_message( callid, call, answer, answer_count );
  211. */      }else if( IS_NET_TCP_MESSAGE( call )){
  212.             return tcp_message( callid, call, answer, answer_count );
  213. /*      }else if( IS_NET_SOCKET_MESSAGE( call )){
  214.             return socket_message( callid, call, answer, answer_count );
  215. *//*        }else if( IS_NET_NIL_MESSAGE( call ) || IS_NET_ETHERNET_MESSAGE( call )){
  216.             return ethernet_message( callid, call, answer, answer_count );
  217. */      }else{
  218. #endif
  219.             if( IS_NET_PACKET_MESSAGE( call )){
  220.                 return packet_server_message( callid, call, answer, answer_count );
  221.             }else{
  222.                 return net_message( callid, call, answer, answer_count );
  223.             }
  224. #ifdef NETWORKING_module
  225.         }
  226. #endif
  227. }
  228.  
  229. int networking_start_module( async_client_conn_t client_connection ){
  230.     ERROR_DECLARE;
  231.  
  232.     ipcarg_t    phonehash;
  233.  
  234.     async_set_client_connection( client_connection );
  235.     ERROR_PROPAGATE( networking_initialize());
  236.     ERROR_PROPAGATE( REGISTER_ME( SERVICE_NETWORKING, & phonehash ));
  237.     ERROR_PROPAGATE( pm_init());
  238.     async_manager();
  239.  
  240.     return EOK;
  241. }
  242.  
  243. int networking_initialize( void ){
  244.     ERROR_DECLARE;
  245.  
  246.     task_id_t   task_id;
  247.  
  248.     netifs_initialize( & networking_globals.netifs );
  249.     char_map_initialize( & networking_globals.netif_names );
  250.     modules_initialize( & networking_globals.modules );
  251.     measured_strings_initialize( & networking_globals.configuration );
  252.  
  253.     // run self tests
  254. //  ERROR_PROPAGATE( self_test());
  255.  
  256.     ERROR_PROPAGATE( add_module( NULL, & networking_globals.modules, LO_NAME, LO_FILENAME, SERVICE_LO, 0 ));
  257.     ERROR_PROPAGATE( add_module( NULL, & networking_globals.modules, DP8390_ISA_NAME, DP8390_ISA_FILENAME, SERVICE_DP8390_ISA, 0 ));
  258.     ERROR_PROPAGATE( add_module( NULL, & networking_globals.modules, ETHERNET_NAME, ETHERNET_FILENAME, SERVICE_ETHERNET, 0 ));
  259.  
  260. #ifdef NETWORKING_modular
  261.     task_id = spawn( "/sbin/ip" );
  262.     if( ! task_id ) return EINVAL;
  263.     ERROR_PROPAGATE( add_module( NULL, & networking_globals.modules, IP_NAME, IP_FILENAME, SERVICE_IP, task_id ));
  264. //  if( ! spawn( "/sbin/udp" )) return EINVAL;
  265.     if( ! spawn( "/sbin/tcp" )) return EINVAL;
  266. //  if( ! spawn( "/sbin/socket" )) return EINVAL;
  267. //  not always necesssary
  268. //  if( ! spawn( "/sbin/arp" )) return EINVAL;
  269. //  if( ! spawn( "/sbin/rarp" )) return EINVAL;
  270. //  if( ! spawn( "/sbin/icmp" )) return EINVAL;
  271.  
  272. #else
  273. #ifdef NETWORKING_module
  274.     ipcarg_t    phonehash;
  275.  
  276.     ERROR_PROPAGATE( REGISTER_ME( SERVICE_IP, & phonehash ));
  277.     ERROR_PROPAGATE( add_module( NULL, & networking_globals.modules, IP_NAME, IP_FILENAME, SERVICE_IP, task_get_id()));
  278.     ERROR_PROPAGATE( ip_initialize());
  279. //  ERROR_PROPAGATE( REGISTER_ME( SERVICE_ARP, & phonehash ));
  280. //  ERROR_PROPAGATE( arp_initialize());
  281. //  ERROR_PROPAGATE( REGISTER_ME( SERVICE_RARP, & phonehash ));
  282. //  ERROR_PROPAGATE( rarp_initialize());
  283. //  ERROR_PROPAGATE( REGISTER_ME( SERVICE_ICMP, & phonehash ));
  284. //  ERROR_PROPAGATE( icmp_initialize());
  285. //  ERROR_PROPAGATE( REGISTER_ME( SERVICE_UDP, & phonehash ));
  286. //  ERROR_PROPAGATE( udp_initialize());
  287.     ERROR_PROPAGATE( REGISTER_ME( SERVICE_TCP, & phonehash ));
  288.     ERROR_PROPAGATE( tcp_initialize());
  289. //  ERROR_PROPAGATE( REGISTER_ME( SERVICE_SOCKET, & phonehash ));
  290. //  ERROR_PROPAGATE( socket_initialize());
  291. //  ERROR_PROPAGATE( REGISTER_ME( SERVICE_ETHERNET, & phonehash ));
  292. //  ERROR_PROPAGATE( ethernet_initialize());
  293. #endif
  294. #endif
  295.  
  296.     return EOK;
  297. }
  298.  
  299. //TODO as ip.c
  300. int net_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
  301.     ERROR_DECLARE;
  302.  
  303.     measured_string_ref strings;
  304.     char *          data;
  305.     int         index;
  306.     measured_string_ref setting;
  307.     measured_strings_ref    configuration;
  308.     netif_ref       netif;
  309.  
  310.     * answer_count = 0;
  311.     switch( IPC_GET_METHOD( * call )){
  312.         case IPC_M_PHONE_HUNGUP:
  313.             return EOK;
  314.         case NET_NET_DEVICE:
  315.             // TODO configure, register
  316.             printf( "\nNetworking: new netif %d", IPC_GET_DEVICE( call ));
  317.             return EOK;
  318.         case NET_NET_GET_DEVICE_CONF:
  319.             ERROR_PROPAGATE( measured_strings_receive( & strings, & data, IPC_GET_COUNT( call )));
  320.             netif = netifs_find( & networking_globals.netifs, IPC_GET_DEVICE( call ));
  321.             if( netif ){
  322.                 configuration = & netif->configuration;
  323.             }else{
  324.                 configuration = NULL;
  325.             }
  326.             for( index = 0; index < IPC_GET_COUNT( call ); ++ index ){
  327.                 setting = measured_strings_find( configuration, strings[ index ].value, 0 );
  328.                 if( ! setting ){
  329.                     setting = measured_strings_find( & networking_globals.configuration, strings[ index ].value, 0 );
  330.                 }
  331.                 if( setting ){
  332.                     strings[ index ].length = setting->length;
  333.                     strings[ index ].value = setting->value;
  334.                 }else{
  335.                     strings[ index ].length = 0;
  336.                     strings[ index ].value = NULL;
  337.                 }
  338.             }
  339.             // strings should not contain received data anymore
  340.             free( data );
  341.             ERROR_CODE = measured_strings_reply( strings, IPC_GET_COUNT( call ));
  342.             free( strings );
  343.             return ERROR_CODE;
  344.         case NET_NET_GET_CONF:
  345.             // arg1 = count
  346.             ERROR_PROPAGATE( measured_strings_receive( & strings, & data, IPC_GET_COUNT( call )));
  347.             for( index = 0; index < IPC_GET_COUNT( call ); ++ index ){
  348.                 setting = measured_strings_find( & networking_globals.configuration, strings[ index ].value, 0 );
  349.                 if( setting ){
  350.                     strings[ index ].length = setting->length;
  351.                     strings[ index ].value = setting->value;
  352.                 }else{
  353.                     strings[ index ].length = 0;
  354.                     strings[ index ].value = NULL;
  355.                 }
  356.             }
  357.             // strings should not contain received data anymore
  358.             free( data );
  359.             ERROR_CODE = measured_strings_reply( strings, IPC_GET_COUNT( call ));
  360.             free( strings );
  361.             return ERROR_CODE;
  362.         case NET_NET_STARTUP:
  363.             return startup();
  364.     }
  365.     return ENOTSUP;
  366. }
  367.  
  368. /*
  369. int parse_line( measured_strings_ref configuration, char * line ){
  370.     ERROR_DECLARE;
  371.  
  372.     measured_string_ref setting;
  373.     char *          name;
  374.     char *          value;
  375.  
  376.     // from the beginning
  377.     name = line;
  378.     // skip spaces
  379.     while( isspace( * name )) ++ name;
  380.     // remember the name start
  381.     value = name;
  382.     // skip the name
  383.     while( isalnum( * value ) || ( * value == '_' )){
  384.         // make uppercase
  385. //      * value = toupper( * value );
  386.         ++ value;
  387.     }
  388.     if( * value == '=' ){
  389.         // terminate the name
  390.         * value = '\0';
  391.     }else{
  392.         // terminate the name
  393.         * value = '\0';
  394.         // skip until '='
  395.         ++ value;
  396.         while(( * value ) && ( * value != '=' )) ++ value;
  397.         // not found?
  398.         if( * value != '=' ) return EINVAL;
  399.     }
  400.     ++ value;
  401.     // skip spaces
  402.     while( isspace( * value )) ++ value;
  403.     // create a bulk measured string till the end
  404.     setting = measured_string_create_bulk( value, -1 );
  405.     if( ! setting ) return ENOMEM;
  406.     // add the configuration setting
  407.     if( ERROR_OCCURRED( measured_strings_add( configuration, name, 0, setting ))){
  408.         free( setting );
  409.         return ERROR_CODE;
  410.     }
  411.     return EOK;
  412. }
  413. */
  414.  
  415. int add_configuration( measured_strings_ref configuration, const char * name, const char * value ){
  416.     ERROR_DECLARE;
  417.  
  418.     measured_string_ref setting;
  419.  
  420.     setting = measured_string_create_bulk( value, 0 );
  421.     if( ! setting ) return ENOMEM;
  422.     // add the configuration setting
  423.     if( ERROR_OCCURRED( measured_strings_add( configuration, name, 0, setting ))){
  424.         free( setting );
  425.         return ERROR_CODE;
  426.     }
  427.     return EOK;
  428. }
  429.  
  430. device_id_t generate_new_device_id( void ){
  431.     return netifs_count( & networking_globals.netifs ) + 1;
  432. }
  433.  
  434. int read_configuration( void ){
  435.     ERROR_DECLARE;
  436.  
  437.     netif_ref       netif;
  438.     measured_string_ref setting;
  439.     services_t      internet_service;
  440.     int         index;
  441.  
  442.     // read general configuration
  443.     ERROR_PROPAGATE( add_configuration( & networking_globals.configuration, "IPV", "4" ));
  444.  
  445.     // read network interfaces configuration
  446.  
  447.     // static loopback initialization
  448. //  printf( "\nloopback initialization" );
  449.     netif = ( netif_ref ) malloc( sizeof( netif_t ));
  450.     if( ! netif ) return ENOMEM;
  451.     netif->id = generate_new_device_id();
  452.     ERROR_PROPAGATE( measured_strings_initialize( & netif->configuration ));
  453.     if( ERROR_OCCURRED( add_configuration( & netif->configuration, "NAME", LO_NAME ))
  454.     || ERROR_OCCURRED( add_configuration( & netif->configuration, "NETIF", LO_NAME ))
  455.     || ERROR_OCCURRED( add_configuration( & netif->configuration, "IL", IP_NAME ))
  456.     || ERROR_OCCURRED( add_configuration( & netif->configuration, "MTU", "1500" ))
  457.     || ERROR_OCCURRED( add_configuration( & netif->configuration, "IP_CONFIG", "STATIC" ))
  458.     || ERROR_OCCURRED( add_configuration( & netif->configuration, "IP_ADDR", "127.0.0.1" ))
  459.     || ERROR_OCCURRED( add_configuration( & netif->configuration, "NETMASK", "255.0.0.0" ))){
  460.         measured_strings_destroy( & netif->configuration );
  461.         free( netif );
  462.         return ERROR_CODE;
  463.     }
  464.     // mandatory name
  465. //  printf( "\n\tname" );
  466.     setting = measured_strings_find( & netif->configuration, "NAME", 0 );
  467.     if( ! setting ){
  468.         measured_strings_destroy( & netif->configuration );
  469.         free( netif );
  470.         return EINVAL;
  471.     }
  472.     netif->name = setting->value;
  473. //  printf( " %s OK", netif->name );
  474.     // mandatory netif
  475. //  printf( "\n\tnetif" );
  476.     setting = measured_strings_find( & netif->configuration, "NETIF", 0 );
  477.     if( ! setting ){
  478. //      printf( " unknown" );
  479.         measured_strings_destroy( & netif->configuration );
  480.         free( netif );
  481.         return EINVAL;
  482.     }
  483. //  printf( " find %s in %d?", setting->value, modules_count( & networking_globals.modules ));
  484.     netif->driver = modules_find( & networking_globals.modules, setting->value, 0 );
  485.     if( ! netif->driver ){
  486. //      printf( " not found" );
  487.         // TODO register the unknown one
  488.         measured_strings_destroy( & netif->configuration );
  489.         free( netif );
  490.         return EINVAL;
  491.     }
  492. //  printf( " found" );
  493.     if( ! netif->driver->task_id ){
  494.         netif->driver->task_id = spawn( netif->driver->filename );
  495.         if( ! netif->driver->task_id ){
  496.             measured_strings_destroy( & netif->configuration );
  497.             free( netif );
  498.             return EINVAL;
  499.         }
  500.     }
  501. //  printf( " OK" );
  502.     // optional link layer
  503. //  printf( "\n\tlink layer" );
  504.     setting = measured_strings_find( & netif->configuration, "NIL", 0 );
  505.     if( setting ){
  506.         netif->nil = modules_find( & networking_globals.modules, setting->value, 0 );
  507.         if( ! netif->nil ){
  508.             // TODO register the unknown one
  509.             -- netif->driver->usage;
  510.             measured_strings_destroy( & netif->configuration );
  511.             free( netif );
  512.             return EINVAL;
  513.         }
  514.         if( ! netif->nil->task_id ){
  515.             netif->nil->task_id = spawn( netif->nil->filename );
  516.             if( ! netif->nil->task_id ){
  517.                 -- netif->driver->usage;
  518.                 measured_strings_destroy( & netif->configuration );
  519.                 free( netif );
  520.                 return EINVAL;
  521.             }
  522.         }
  523.     }else{
  524.         netif->nil = NULL;
  525.     }
  526.     // mandatory internet layer
  527. //  printf( "\n\tinternet layer" );
  528.     setting = measured_strings_find( & netif->configuration, "IL", 0 );
  529.     if( ! setting ){
  530.         -- netif->driver->usage;
  531.         -- netif->nil->usage;
  532.         measured_strings_destroy( & netif->configuration );
  533.         free( netif );
  534.         return EINVAL;
  535.     }
  536. //  printf( " set %s", setting->value );
  537.     netif->il = modules_find( & networking_globals.modules, setting->value, 0 );
  538.     if( ! netif->il ){
  539.         // TODO register the unknown one
  540.         -- netif->driver->usage;
  541.         -- netif->nil->usage;
  542.         measured_strings_destroy( & netif->configuration );
  543.         free( netif );
  544.         return EINVAL;
  545.     }
  546. //  printf( " found" );
  547.     if( ! netif->il->task_id ){
  548.         netif->il->task_id = spawn( netif->il->filename );
  549.         if( ! netif->il->task_id ){
  550.             -- netif->driver->usage;
  551.             -- netif->nil->usage;
  552.             measured_strings_destroy( & netif->configuration );
  553.             free( netif );
  554.             return EINVAL;
  555.         }
  556.     }
  557.     index = netifs_add( & networking_globals.netifs, netif->id, netif );
  558.     if( index < 0 ){
  559.         free( netif );
  560.         return ERROR_CODE;
  561.     }
  562.     if( ERROR_OCCURRED( char_map_add( & networking_globals.netif_names, netif->name, 0, index ))){
  563.         netifs_exclude_index( & networking_globals.netifs, index );
  564.         return ERROR_CODE;
  565.     }
  566. //  printf( "\nloopback OK" );
  567.     // end of the static loopback initialization
  568.     // startup the loopback interface
  569.     if( ! netif->driver->phone ){
  570. //      printf( " connect?" );
  571.         netif->driver->phone = connect_to_service( netif->driver->service );
  572.     }
  573. //  printf( " connected" );
  574.     // TODO io, irq
  575.     ERROR_PROPAGATE( async_req_3_0( netif->driver->phone, NET_NETIF_PROBE, netif->id, 0, 0 ));
  576.     ++ netif->driver->usage;
  577.     if( netif->nil ){
  578.         if( ! netif->nil->phone ){
  579.             netif->nil->phone = connect_to_service( netif->nil->service );
  580.         }
  581.         ERROR_PROPAGATE( async_req_2_0( netif->nil->phone, NET_NIL_DEVICE, netif->id, netif->driver->service ));
  582.         ++ netif->nil->usage;
  583.         internet_service = netif->nil->service;
  584. //      printf( " OK" );
  585.     }else{
  586.         internet_service = netif->driver->service;
  587. //      printf( " none" );
  588.     }
  589.     if( ! netif->il->phone ){
  590. //      printf( " connect" );
  591.         netif->il->phone = connect_to_service( netif->il->service );
  592.     }
  593.     // TODO IL_BUNDLE
  594.     ERROR_PROPAGATE( async_req_2_0( netif->il->phone, NET_IL_DEVICE, netif->id, internet_service ));
  595.     ++ netif->il->usage;
  596.     // TODO startup?
  597.     ERROR_PROPAGATE( async_req_1_0( netif->driver->phone, NET_NETIF_START, netif->id ));
  598. //  printf( "\n LO OK" );
  599.     return EOK;
  600. }
  601.  
  602. task_id_t spawn( const char * fname ){
  603.     const char  * argv[ 2 ];
  604.     task_id_t   res;
  605.  
  606. //  printf( "Spawning %s\n", fname );
  607.     argv[ 0 ] = fname;
  608.     argv[ 1 ] = NULL;
  609.     res = task_spawn( fname, argv );
  610.     if( res != 0 ){
  611.         /* Success */
  612.         usleep( 50000 );
  613.     }
  614.     return res;
  615. }
  616.  
  617. int startup( void ){
  618.     ERROR_DECLARE;
  619.  
  620.     // read configuration files
  621.     if( ERROR_OCCURRED( read_configuration())) return ERROR_CODE;
  622.  
  623.     // start network interfaces and needed modules
  624. //  start_device( "/sbin/lo", "/sbin/dummy_link_layer" );
  625.     return EOK;
  626. }
  627.  
  628. /** @}
  629.  */
  630.