Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/il/ip/ip.c

    rffa2c8ef r7e752b2  
    3636 */
    3737
     38#include "ip.h"
     39#include "ip_module.h"
     40
    3841#include <async.h>
    3942#include <errno.h>
     
    4144#include <stdio.h>
    4245#include <str.h>
     46#include <ipc/ipc.h>
    4347#include <ipc/services.h>
    4448#include <ipc/net.h>
     
    4852#include <sys/types.h>
    4953#include <byteorder.h>
    50 #include "ip.h"
    5154
    5255#include <adt/measured_strings.h>
     
    6669#include <net_checksum.h>
    6770#include <icmp_client.h>
    68 #include <icmp_remote.h>
     71#include <icmp_interface.h>
     72#include <il_interface.h>
    6973#include <ip_client.h>
    7074#include <ip_interface.h>
    7175#include <ip_header.h>
    7276#include <net_interface.h>
    73 #include <nil_remote.h>
    74 #include <tl_remote.h>
     77#include <nil_interface.h>
     78#include <tl_interface.h>
    7579#include <packet_remote.h>
    76 #include <il_remote.h>
    77 #include <il_skel.h>
     80#include <il_local.h>
    7881
    7982/** IP module name. */
     
    119122INT_MAP_IMPLEMENT(ip_protos, ip_proto_t);
    120123GENERIC_FIELD_IMPLEMENT(ip_routes, ip_route_t);
    121 
    122 static void ip_receiver(ipc_callid_t, ipc_call_t *);
    123124
    124125/** Releases the packet and returns the result.
     
    243244}
    244245
    245 int il_initialize(int net_phone)
    246 {
     246/** Initializes the IP module.
     247 *
     248 * @param[in] client_connection The client connection processing function. The
     249 *                      module skeleton propagates its own one.
     250 * @return              EOK on success.
     251 * @return              ENOMEM if there is not enough memory left.
     252 */
     253int ip_initialize(async_client_conn_t client_connection)
     254{
     255        int rc;
     256
    247257        fibril_rwlock_initialize(&ip_globals.lock);
    248258        fibril_rwlock_write_lock(&ip_globals.lock);
    249259        fibril_rwlock_initialize(&ip_globals.protos_lock);
    250260        fibril_rwlock_initialize(&ip_globals.netifs_lock);
    251        
    252         ip_globals.net_phone = net_phone;
    253261        ip_globals.packet_counter = 0;
    254262        ip_globals.gateway.address.s_addr = 0;
     
    256264        ip_globals.gateway.gateway.s_addr = 0;
    257265        ip_globals.gateway.netif = NULL;
    258        
    259         int rc = ip_netifs_initialize(&ip_globals.netifs);
     266        ip_globals.client_connection = client_connection;
     267       
     268        rc = ip_netifs_initialize(&ip_globals.netifs);
    260269        if (rc != EOK)
    261270                goto out;
     
    266275        if (rc != EOK)
    267276                goto out;
    268         rc = add_module(NULL, &ip_globals.modules, (uint8_t *) ARP_NAME,
    269             (uint8_t *) ARP_FILENAME, SERVICE_ARP, 0, arp_connect_module);
     277        rc = add_module(NULL, &ip_globals.modules, ARP_NAME, ARP_FILENAME,
     278            SERVICE_ARP, 0, arp_connect_module);
    270279
    271280out:
     
    303312        measured_string_t names[] = {
    304313                {
    305                         (uint8_t *) "IPV",
     314                        (char *) "IPV",
    306315                        3
    307316                },
    308317                {
    309                         (uint8_t *) "IP_CONFIG",
     318                        (char *) "IP_CONFIG",
    310319                        9
    311320                },
    312321                {
    313                         (uint8_t *) "IP_ADDR",
     322                        (char *) "IP_ADDR",
    314323                        7
    315324                },
    316325                {
    317                         (uint8_t *) "IP_NETMASK",
     326                        (char *) "IP_NETMASK",
    318327                        10
    319328                },
    320329                {
    321                         (uint8_t *) "IP_GATEWAY",
     330                        (char *) "IP_GATEWAY",
    322331                        10
    323332                },
    324333                {
    325                         (uint8_t *) "IP_BROADCAST",
     334                        (char *) "IP_BROADCAST",
    326335                        12
    327336                },
    328337                {
    329                         (uint8_t *) "ARP",
     338                        (char *) "ARP",
    330339                        3
    331340                },
    332341                {
    333                         (uint8_t *) "IP_ROUTING",
     342                        (char *) "IP_ROUTING",
    334343                        10
    335344                }
     
    337346        measured_string_t *configuration;
    338347        size_t count = sizeof(names) / sizeof(measured_string_t);
    339         uint8_t *data;
     348        char *data;
    340349        measured_string_t address;
    341350        ip_route_t *route;
     
    359368        if (configuration) {
    360369                if (configuration[0].value)
    361                         ip_netif->ipv = strtol((char *) configuration[0].value, NULL, 0);
    362                
    363                 ip_netif->dhcp = !str_lcmp((char *) configuration[1].value, "dhcp",
     370                        ip_netif->ipv = strtol(configuration[0].value, NULL, 0);
     371
     372                ip_netif->dhcp = !str_lcmp(configuration[1].value, "dhcp",
    364373                    configuration[1].length);
    365374               
     
    385394                        }
    386395                       
    387                         if ((inet_pton(AF_INET, (char *) configuration[2].value,
     396                        if ((inet_pton(AF_INET, configuration[2].value,
    388397                            (uint8_t *) &route->address.s_addr) != EOK) ||
    389                             (inet_pton(AF_INET, (char *) configuration[3].value,
     398                            (inet_pton(AF_INET, configuration[3].value,
    390399                            (uint8_t *) &route->netmask.s_addr) != EOK) ||
    391                             (inet_pton(AF_INET, (char *) configuration[4].value,
     400                            (inet_pton(AF_INET, configuration[4].value,
    392401                            (uint8_t *) &gateway.s_addr) == EINVAL) ||
    393                             (inet_pton(AF_INET, (char *) configuration[5].value,
     402                            (inet_pton(AF_INET, configuration[5].value,
    394403                            (uint8_t *) &ip_netif->broadcast.s_addr) == EINVAL))
    395404                            {
     
    421430        // binds the netif service which also initializes the device
    422431        ip_netif->phone = nil_bind_service(ip_netif->service,
    423             (sysarg_t) ip_netif->device_id, SERVICE_IP,
    424             ip_receiver);
     432            (ipcarg_t) ip_netif->device_id, SERVICE_IP,
     433            ip_globals.client_connection);
    425434        if (ip_netif->phone < 0) {
    426435                printf("Failed to contact the nil service %d\n",
     
    432441        if (ip_netif->arp) {
    433442                if (route) {
    434                         address.value = (uint8_t *) &route->address.s_addr;
    435                         address.length = sizeof(in_addr_t);
     443                        address.value = (char *) &route->address.s_addr;
     444                        address.length = CONVERT_SIZE(in_addr_t, char, 1);
    436445                       
    437446                        rc = arp_device_req(ip_netif->arp->phone,
     
    468477                ip_globals.gateway.gateway.s_addr = gateway.s_addr;
    469478                ip_globals.gateway.netif = ip_netif;
    470                
    471                 char defgateway[INET_ADDRSTRLEN];
    472                 inet_ntop(AF_INET, (uint8_t *) &gateway.s_addr,
    473                     defgateway, INET_ADDRSTRLEN);
    474                 printf("%s: Default gateway (%s)\n", NAME, defgateway);
    475479        }
    476480
     
    478482}
    479483
    480 static int ip_device_req_local(int il_phone, device_id_t device_id,
    481     services_t netif)
    482 {
    483         ip_netif_t *ip_netif;
    484         ip_route_t *route;
    485         int index;
    486         int rc;
    487 
    488         ip_netif = (ip_netif_t *) malloc(sizeof(ip_netif_t));
    489         if (!ip_netif)
    490                 return ENOMEM;
    491 
    492         rc = ip_routes_initialize(&ip_netif->routes);
    493         if (rc != EOK) {
    494                 free(ip_netif);
    495                 return rc;
    496         }
    497 
    498         ip_netif->device_id = device_id;
    499         ip_netif->service = netif;
    500         ip_netif->state = NETIF_STOPPED;
     484/** Updates the device content length according to the new MTU value.
     485 *
     486 * @param[in] device_id The device identifier.
     487 * @param[in] mtu       The new mtu value.
     488 * @return              EOK on success.
     489 * @return              ENOENT if device is not found.
     490 */
     491static int ip_mtu_changed_message(device_id_t device_id, size_t mtu)
     492{
     493        ip_netif_t *netif;
    501494
    502495        fibril_rwlock_write_lock(&ip_globals.netifs_lock);
    503 
    504         rc = ip_netif_initialize(ip_netif);
    505         if (rc != EOK) {
     496        netif = ip_netifs_find(&ip_globals.netifs, device_id);
     497        if (!netif) {
    506498                fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
    507                 ip_routes_destroy(&ip_netif->routes);
    508                 free(ip_netif);
    509                 return rc;
    510         }
    511         if (ip_netif->arp)
    512                 ip_netif->arp->usage++;
    513 
    514         // print the settings
    515         printf("%s: Device registered (id: %d, phone: %d, ipv: %d, conf: %s)\n",
    516             NAME, ip_netif->device_id, ip_netif->phone, ip_netif->ipv,
    517             ip_netif->dhcp ? "dhcp" : "static");
    518        
    519         // TODO ipv6 addresses
    520        
    521         char address[INET_ADDRSTRLEN];
    522         char netmask[INET_ADDRSTRLEN];
    523         char gateway[INET_ADDRSTRLEN];
    524        
    525         for (index = 0; index < ip_routes_count(&ip_netif->routes); index++) {
    526                 route = ip_routes_get_index(&ip_netif->routes, index);
    527                 if (route) {
    528                         inet_ntop(AF_INET, (uint8_t *) &route->address.s_addr,
    529                             address, INET_ADDRSTRLEN);
    530                         inet_ntop(AF_INET, (uint8_t *) &route->netmask.s_addr,
    531                             netmask, INET_ADDRSTRLEN);
    532                         inet_ntop(AF_INET, (uint8_t *) &route->gateway.s_addr,
    533                             gateway, INET_ADDRSTRLEN);
    534                         printf("%s: Route %d (address: %s, netmask: %s, "
    535                             "gateway: %s)\n", NAME, index, address, netmask,
    536                             gateway);
    537                 }
    538         }
    539        
    540         inet_ntop(AF_INET, (uint8_t *) &ip_netif->broadcast.s_addr, address,
    541             INET_ADDRSTRLEN);
     499                return ENOENT;
     500        }
     501        netif->packet_dimension.content = mtu;
    542502        fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
    543503
    544         printf("%s: Broadcast (%s)\n", NAME, address);
     504        printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
    545505
    546506        return EOK;
    547507}
    548508
    549 /** Searches the network interfaces if there is a suitable route.
    550  *
    551  * @param[in] netif     The network interface to be searched for routes. May be
    552  *                      NULL.
    553  * @param[in] destination The destination address.
    554  * @return              The found route.
    555  * @return              NULL if no route was found.
    556  */
    557 static ip_route_t *ip_netif_find_route(ip_netif_t *netif,
    558     in_addr_t destination)
    559 {
    560         int index;
    561         ip_route_t *route;
    562        
    563         if (!netif)
     509/** Updates the device state.
     510 *
     511 * @param[in] device_id The device identifier.
     512 * @param[in] state     The new state value.
     513 * @return              EOK on success.
     514 * @return              ENOENT if device is not found.
     515 */
     516static int ip_device_state_message(device_id_t device_id, device_state_t state)
     517{
     518        ip_netif_t *netif;
     519
     520        fibril_rwlock_write_lock(&ip_globals.netifs_lock);
     521        // find the device
     522        netif = ip_netifs_find(&ip_globals.netifs, device_id);
     523        if (!netif) {
     524                fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
     525                return ENOENT;
     526        }
     527        netif->state = state;
     528        fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
     529
     530        printf("%s: Device %d changed state to %d\n", NAME, device_id, state);
     531
     532        return EOK;
     533}
     534
     535
     536/** Prefixes a middle fragment header based on the last fragment header to the
     537 * packet.
     538 *
     539 * @param[in] packet    The packet to be prefixed.
     540 * @param[in] last      The last header to be copied.
     541 * @return              The prefixed middle header.
     542 * @return              NULL on error.
     543 */
     544static ip_header_t *
     545ip_create_middle_header(packet_t *packet, ip_header_t *last)
     546{
     547        ip_header_t *middle;
     548
     549        middle = (ip_header_t *) packet_suffix(packet, IP_HEADER_LENGTH(last));
     550        if (!middle)
    564551                return NULL;
    565        
    566         /* Start with the first one (the direct route) */
    567         for (index = 0; index < ip_routes_count(&netif->routes); index++) {
    568                 route = ip_routes_get_index(&netif->routes, index);
    569                 if ((route) &&
    570                     ((route->address.s_addr & route->netmask.s_addr) ==
    571                     (destination.s_addr & route->netmask.s_addr)))
    572                         return route;
    573         }
    574 
    575         return NULL;
    576 }
    577 
    578 /** Searches all network interfaces if there is a suitable route.
    579  *
    580  * @param[in] destination The destination address.
    581  * @return              The found route.
    582  * @return              NULL if no route was found.
    583  */
    584 static ip_route_t *ip_find_route(in_addr_t destination) {
    585         int index;
    586         ip_route_t *route;
    587         ip_netif_t *netif;
    588 
    589         // start with the last netif - the newest one
    590         index = ip_netifs_count(&ip_globals.netifs) - 1;
    591         while (index >= 0) {
    592                 netif = ip_netifs_get_index(&ip_globals.netifs, index);
    593                 if (netif && (netif->state == NETIF_ACTIVE)) {
    594                         route = ip_netif_find_route(netif, destination);
    595                         if (route)
    596                                 return route;
    597                 }
    598                 index--;
    599         }
    600 
    601         return &ip_globals.gateway;
    602 }
    603 
    604 /** Returns the network interface's IP address.
    605  *
    606  * @param[in] netif     The network interface.
    607  * @return              The IP address.
    608  * @return              NULL if no IP address was found.
    609  */
    610 static in_addr_t *ip_netif_address(ip_netif_t *netif)
    611 {
    612         ip_route_t *route;
    613 
    614         route = ip_routes_get_index(&netif->routes, 0);
    615         return route ? &route->address : NULL;
     552        memcpy(middle, last, IP_HEADER_LENGTH(last));
     553        middle->flags |= IPFLAG_MORE_FRAGMENTS;
     554        return middle;
    616555}
    617556
     
    682621 *                      function.
    683622 */
    684 static int ip_prepare_packet(in_addr_t *source, in_addr_t dest,
    685     packet_t *packet, measured_string_t *destination)
     623static int
     624ip_prepare_packet(in_addr_t *source, in_addr_t dest, packet_t *packet,
     625    measured_string_t *destination)
    686626{
    687627        size_t length;
     
    699639        if (destination) {
    700640                rc = packet_set_addr(packet, NULL, (uint8_t *) destination->value,
    701                     destination->length);
     641                    CONVERT_SIZE(char, uint8_t, destination->length));
    702642        } else {
    703643                rc = packet_set_addr(packet, NULL, NULL, 0);
     
    747687                                rc = packet_set_addr(next, NULL,
    748688                                    (uint8_t *) destination->value,
    749                                     destination->length);
     689                                    CONVERT_SIZE(char, uint8_t,
     690                                    destination->length));
    750691                                if (rc != EOK) {
    751692                                        free(last_header);
     
    777718                        rc = packet_set_addr(next, NULL,
    778719                            (uint8_t *) destination->value,
    779                             destination->length);
     720                            CONVERT_SIZE(char, uint8_t, destination->length));
    780721                        if (rc != EOK) {
    781722                                free(last_header);
     
    812753 *                      function.
    813754 */
    814 static int ip_fragment_packet_data(packet_t *packet, packet_t *new_packet,
     755static int
     756ip_fragment_packet_data(packet_t *packet, packet_t *new_packet,
    815757    ip_header_t *header, ip_header_t *new_header, size_t length,
    816758    const struct sockaddr *src, const struct sockaddr *dest, socklen_t addrlen)
     
    846788
    847789        return pq_insert_after(packet, new_packet);
    848 }
    849 
    850 /** Prefixes a middle fragment header based on the last fragment header to the
    851  * packet.
    852  *
    853  * @param[in] packet    The packet to be prefixed.
    854  * @param[in] last      The last header to be copied.
    855  * @return              The prefixed middle header.
    856  * @return              NULL on error.
    857  */
    858 static ip_header_t *ip_create_middle_header(packet_t *packet,
    859     ip_header_t *last)
    860 {
    861         ip_header_t *middle;
    862 
    863         middle = (ip_header_t *) packet_suffix(packet, IP_HEADER_LENGTH(last));
    864         if (!middle)
    865                 return NULL;
    866         memcpy(middle, last, IP_HEADER_LENGTH(last));
    867         middle->flags |= IPFLAG_MORE_FRAGMENTS;
    868         return middle;
    869790}
    870791
     
    1071992 *                      function.
    1072993 */
    1073 static int ip_send_route(packet_t *packet, ip_netif_t *netif,
    1074     ip_route_t *route, in_addr_t *src, in_addr_t dest, services_t error)
     994static int
     995ip_send_route(packet_t *packet, ip_netif_t *netif, ip_route_t *route,
     996    in_addr_t *src, in_addr_t dest, services_t error)
    1075997{
    1076998        measured_string_t destination;
    1077999        measured_string_t *translation;
    1078         uint8_t *data;
     1000        char *data;
    10791001        int phone;
    10801002        int rc;
     
    10831005        if (netif->arp && (route->address.s_addr != dest.s_addr)) {
    10841006                destination.value = route->gateway.s_addr ?
    1085                     (uint8_t *) &route->gateway.s_addr : (uint8_t *) &dest.s_addr;
    1086                 destination.length = sizeof(dest.s_addr);
     1007                    (char *) &route->gateway.s_addr : (char *) &dest.s_addr;
     1008                destination.length = CONVERT_SIZE(dest.s_addr, char, 1);
    10871009
    10881010                rc = arp_translate_req(netif->arp->phone, netif->device_id,
     
    11351057}
    11361058
    1137 static int ip_send_msg_local(int il_phone, device_id_t device_id,
    1138     packet_t *packet, services_t sender, services_t error)
     1059/** Searches the network interfaces if there is a suitable route.
     1060 *
     1061 * @param[in] netif     The network interface to be searched for routes. May be
     1062 *                      NULL.
     1063 * @param[in] destination The destination address.
     1064 * @return              The found route.
     1065 * @return              NULL if no route was found.
     1066 */
     1067static ip_route_t *
     1068ip_netif_find_route(ip_netif_t *netif, in_addr_t destination)
     1069{
     1070        int index;
     1071        ip_route_t *route;
     1072
     1073        if (!netif)
     1074                return NULL;
     1075
     1076        // start with the first one - the direct route
     1077        for (index = 0; index < ip_routes_count(&netif->routes); index++) {
     1078                route = ip_routes_get_index(&netif->routes, index);
     1079                if (route &&
     1080                    ((route->address.s_addr & route->netmask.s_addr) ==
     1081                    (destination.s_addr & route->netmask.s_addr))) {
     1082                        return route;
     1083                }
     1084        }
     1085
     1086        return NULL;
     1087}
     1088
     1089/** Searches all network interfaces if there is a suitable route.
     1090 *
     1091 * @param[in] destination The destination address.
     1092 * @return              The found route.
     1093 * @return              NULL if no route was found.
     1094 */
     1095static ip_route_t *ip_find_route(in_addr_t destination) {
     1096        int index;
     1097        ip_route_t *route;
     1098        ip_netif_t *netif;
     1099
     1100        // start with the last netif - the newest one
     1101        index = ip_netifs_count(&ip_globals.netifs) - 1;
     1102        while (index >= 0) {
     1103                netif = ip_netifs_get_index(&ip_globals.netifs, index);
     1104                if (netif && (netif->state == NETIF_ACTIVE)) {
     1105                        route = ip_netif_find_route(netif, destination);
     1106                        if (route)
     1107                                return route;
     1108                }
     1109                index--;
     1110        }
     1111
     1112        return &ip_globals.gateway;
     1113}
     1114
     1115/** Returns the network interface's IP address.
     1116 *
     1117 * @param[in] netif     The network interface.
     1118 * @return              The IP address.
     1119 * @return              NULL if no IP address was found.
     1120 */
     1121static in_addr_t *ip_netif_address(ip_netif_t *netif)
     1122{
     1123        ip_route_t *route;
     1124
     1125        route = ip_routes_get_index(&netif->routes, 0);
     1126        return route ? &route->address : NULL;
     1127}
     1128
     1129/** Registers the transport layer protocol.
     1130 *
     1131 * The traffic of this protocol will be supplied using either the receive
     1132 * function or IPC message.
     1133 *
     1134 * @param[in] protocol  The transport layer module protocol.
     1135 * @param[in] service   The transport layer module service.
     1136 * @param[in] phone     The transport layer module phone.
     1137 * @param[in] received_msg The receiving function.
     1138 * @return              EOK on success.
     1139 * @return              EINVAL if the protocol parameter and/or the service
     1140 *                      parameter is zero.
     1141 * @return              EINVAL if the phone parameter is not a positive number
     1142 *                      and the tl_receive_msg is NULL.
     1143 * @return              ENOMEM if there is not enough memory left.
     1144 */
     1145static int
     1146ip_register(int protocol, services_t service, int phone,
     1147    tl_received_msg_t received_msg)
     1148{
     1149        ip_proto_t *proto;
     1150        int index;
     1151
     1152        if (!protocol || !service || ((phone < 0) && !received_msg))
     1153                return EINVAL;
     1154
     1155        proto = (ip_proto_t *) malloc(sizeof(ip_protos_t));
     1156        if (!proto)
     1157                return ENOMEM;
     1158
     1159        proto->protocol = protocol;
     1160        proto->service = service;
     1161        proto->phone = phone;
     1162        proto->received_msg = received_msg;
     1163
     1164        fibril_rwlock_write_lock(&ip_globals.protos_lock);
     1165        index = ip_protos_add(&ip_globals.protos, proto->protocol, proto);
     1166        if (index < 0) {
     1167                fibril_rwlock_write_unlock(&ip_globals.protos_lock);
     1168                free(proto);
     1169                return index;
     1170        }
     1171        fibril_rwlock_write_unlock(&ip_globals.protos_lock);
     1172
     1173        printf("%s: Protocol registered (protocol: %d, phone: %d)\n",
     1174            NAME, proto->protocol, proto->phone);
     1175
     1176        return EOK;
     1177}
     1178
     1179static int
     1180ip_device_req_local(int il_phone, device_id_t device_id, services_t netif)
     1181{
     1182        ip_netif_t *ip_netif;
     1183        ip_route_t *route;
     1184        int index;
     1185        int rc;
     1186
     1187        ip_netif = (ip_netif_t *) malloc(sizeof(ip_netif_t));
     1188        if (!ip_netif)
     1189                return ENOMEM;
     1190
     1191        rc = ip_routes_initialize(&ip_netif->routes);
     1192        if (rc != EOK) {
     1193                free(ip_netif);
     1194                return rc;
     1195        }
     1196
     1197        ip_netif->device_id = device_id;
     1198        ip_netif->service = netif;
     1199        ip_netif->state = NETIF_STOPPED;
     1200
     1201        fibril_rwlock_write_lock(&ip_globals.netifs_lock);
     1202
     1203        rc = ip_netif_initialize(ip_netif);
     1204        if (rc != EOK) {
     1205                fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
     1206                ip_routes_destroy(&ip_netif->routes);
     1207                free(ip_netif);
     1208                return rc;
     1209        }
     1210        if (ip_netif->arp)
     1211                ip_netif->arp->usage++;
     1212
     1213        // print the settings
     1214        printf("%s: Device registered (id: %d, phone: %d, ipv: %d, conf: %s)\n",
     1215            NAME, ip_netif->device_id, ip_netif->phone, ip_netif->ipv,
     1216            ip_netif->dhcp ? "dhcp" : "static");
     1217       
     1218        // TODO ipv6 addresses
     1219       
     1220        char address[INET_ADDRSTRLEN];
     1221        char netmask[INET_ADDRSTRLEN];
     1222        char gateway[INET_ADDRSTRLEN];
     1223       
     1224        for (index = 0; index < ip_routes_count(&ip_netif->routes); index++) {
     1225                route = ip_routes_get_index(&ip_netif->routes, index);
     1226                if (route) {
     1227                        inet_ntop(AF_INET, (uint8_t *) &route->address.s_addr,
     1228                            address, INET_ADDRSTRLEN);
     1229                        inet_ntop(AF_INET, (uint8_t *) &route->netmask.s_addr,
     1230                            netmask, INET_ADDRSTRLEN);
     1231                        inet_ntop(AF_INET, (uint8_t *) &route->gateway.s_addr,
     1232                            gateway, INET_ADDRSTRLEN);
     1233                        printf("%s: Route %d (address: %s, netmask: %s, "
     1234                            "gateway: %s)\n", NAME, index, address, netmask,
     1235                            gateway);
     1236                }
     1237        }
     1238       
     1239        inet_ntop(AF_INET, (uint8_t *) &ip_netif->broadcast.s_addr, address,
     1240            INET_ADDRSTRLEN);
     1241        fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
     1242
     1243        printf("%s: Broadcast (%s)\n", NAME, address);
     1244
     1245        return EOK;
     1246}
     1247
     1248static int
     1249ip_send_msg_local(int il_phone, device_id_t device_id, packet_t *packet,
     1250    services_t sender, services_t error)
    11391251{
    11401252        int addrlen;
     
    11771289        if (device_id > 0) {
    11781290                netif = ip_netifs_find(&ip_globals.netifs, device_id);
    1179                 route = ip_netif_find_route(netif, *dest);
     1291                route = ip_netif_find_route(netif, * dest);
    11801292                if (netif && !route && (ip_globals.gateway.netif == netif))
    11811293                        route = &ip_globals.gateway;
     
    12071319                }
    12081320        }
    1209        
     1321
    12101322        // if the local host is the destination
    12111323        if ((route->address.s_addr == dest->s_addr) &&
     
    12401352}
    12411353
    1242 /** Updates the device state.
    1243  *
     1354/** Returns the device packet dimensions for sending.
     1355 *
     1356 * @param[in] phone     The service module phone.
     1357 * @param[in] message   The service specific message.
    12441358 * @param[in] device_id The device identifier.
    1245  * @param[in] state     The new state value.
     1359 * @param[out] addr_len The minimum reserved address length.
     1360 * @param[out] prefix   The minimum reserved prefix size.
     1361 * @param[out] content  The maximum content size.
     1362 * @param[out] suffix   The minimum reserved suffix size.
    12461363 * @return              EOK on success.
    1247  * @return              ENOENT if device is not found.
    1248  */
    1249 static int ip_device_state_message(device_id_t device_id, device_state_t state)
     1364 */
     1365static int
     1366ip_packet_size_message(device_id_t device_id, size_t *addr_len, size_t *prefix,
     1367    size_t *content, size_t *suffix)
    12501368{
    12511369        ip_netif_t *netif;
    1252 
    1253         fibril_rwlock_write_lock(&ip_globals.netifs_lock);
    1254         // find the device
    1255         netif = ip_netifs_find(&ip_globals.netifs, device_id);
    1256         if (!netif) {
    1257                 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
    1258                 return ENOENT;
    1259         }
    1260         netif->state = state;
    1261         fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
    1262 
    1263         printf("%s: Device %d changed state to %d\n", NAME, device_id, state);
     1370        int index;
     1371
     1372        if (!addr_len || !prefix || !content || !suffix)
     1373                return EBADMEM;
     1374
     1375        *content = IP_MAX_CONTENT - IP_PREFIX;
     1376        fibril_rwlock_read_lock(&ip_globals.netifs_lock);
     1377        if (device_id < 0) {
     1378                *addr_len = IP_ADDR;
     1379                *prefix = 0;
     1380                *suffix = 0;
     1381
     1382                for (index = ip_netifs_count(&ip_globals.netifs) - 1;
     1383                    index >= 0; index--) {
     1384                        netif = ip_netifs_get_index(&ip_globals.netifs, index);
     1385                        if (!netif)
     1386                                continue;
     1387                       
     1388                        if (netif->packet_dimension.addr_len > *addr_len)
     1389                                *addr_len = netif->packet_dimension.addr_len;
     1390                       
     1391                        if (netif->packet_dimension.prefix > *prefix)
     1392                                *prefix = netif->packet_dimension.prefix;
     1393                               
     1394                        if (netif->packet_dimension.suffix > *suffix)
     1395                                *suffix = netif->packet_dimension.suffix;
     1396                }
     1397
     1398                *prefix = *prefix + IP_PREFIX;
     1399                *suffix = *suffix + IP_SUFFIX;
     1400        } else {
     1401                netif = ip_netifs_find(&ip_globals.netifs, device_id);
     1402                if (!netif) {
     1403                        fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
     1404                        return ENOENT;
     1405                }
     1406
     1407                *addr_len = (netif->packet_dimension.addr_len > IP_ADDR) ?
     1408                    netif->packet_dimension.addr_len : IP_ADDR;
     1409                *prefix = netif->packet_dimension.prefix + IP_PREFIX;
     1410                *suffix = netif->packet_dimension.suffix + IP_SUFFIX;
     1411        }
     1412        fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
    12641413
    12651414        return EOK;
     
    13011450 *                      tl_received_msg() function.
    13021451 */
    1303 static int ip_deliver_local(device_id_t device_id, packet_t *packet,
    1304     ip_header_t *header, services_t error)
     1452static int
     1453ip_deliver_local(device_id_t device_id, packet_t *packet, ip_header_t *header,
     1454    services_t error)
    13051455{
    13061456        ip_proto_t *proto;
     
    14021552 *                      is disabled.
    14031553 */
    1404 static int ip_process_packet(device_id_t device_id, packet_t *packet)
     1554static int
     1555ip_process_packet(device_id_t device_id, packet_t *packet)
    14051556{
    14061557        ip_header_t *header;
     
    14121563        socklen_t addrlen;
    14131564        int rc;
    1414        
     1565
    14151566        header = (ip_header_t *) packet_get_data(packet);
    14161567        if (!header)
     
    14381589                return EINVAL;
    14391590        }
    1440        
     1591
    14411592        // process ipopt and get destination
    14421593        dest = ip_get_destination(header);
     
    14591610        if (rc != EOK)
    14601611                return rc;
    1461        
     1612
    14621613        route = ip_find_route(dest);
    14631614        if (!route) {
     
    14911642        return ENOENT;
    14921643}
    1493 
    1494 /** Returns the device packet dimensions for sending.
    1495  *
    1496  * @param[in] phone     The service module phone.
    1497  * @param[in] message   The service specific message.
    1498  * @param[in] device_id The device identifier.
    1499  * @param[out] addr_len The minimum reserved address length.
    1500  * @param[out] prefix   The minimum reserved prefix size.
    1501  * @param[out] content  The maximum content size.
    1502  * @param[out] suffix   The minimum reserved suffix size.
    1503  * @return              EOK on success.
    1504  */
    1505 static int ip_packet_size_message(device_id_t device_id, size_t *addr_len,
    1506     size_t *prefix, size_t *content, size_t *suffix)
    1507 {
    1508         ip_netif_t *netif;
    1509         int index;
    1510 
    1511         if (!addr_len || !prefix || !content || !suffix)
    1512                 return EBADMEM;
    1513 
    1514         *content = IP_MAX_CONTENT - IP_PREFIX;
    1515         fibril_rwlock_read_lock(&ip_globals.netifs_lock);
    1516         if (device_id < 0) {
    1517                 *addr_len = IP_ADDR;
    1518                 *prefix = 0;
    1519                 *suffix = 0;
    1520 
    1521                 for (index = ip_netifs_count(&ip_globals.netifs) - 1;
    1522                     index >= 0; index--) {
    1523                         netif = ip_netifs_get_index(&ip_globals.netifs, index);
    1524                         if (!netif)
    1525                                 continue;
    1526                        
    1527                         if (netif->packet_dimension.addr_len > *addr_len)
    1528                                 *addr_len = netif->packet_dimension.addr_len;
    1529                        
    1530                         if (netif->packet_dimension.prefix > *prefix)
    1531                                 *prefix = netif->packet_dimension.prefix;
    1532                                
    1533                         if (netif->packet_dimension.suffix > *suffix)
    1534                                 *suffix = netif->packet_dimension.suffix;
    1535                 }
    1536 
    1537                 *prefix = *prefix + IP_PREFIX;
    1538                 *suffix = *suffix + IP_SUFFIX;
    1539         } else {
    1540                 netif = ip_netifs_find(&ip_globals.netifs, device_id);
    1541                 if (!netif) {
    1542                         fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
    1543                         return ENOENT;
    1544                 }
    1545 
    1546                 *addr_len = (netif->packet_dimension.addr_len > IP_ADDR) ?
    1547                     netif->packet_dimension.addr_len : IP_ADDR;
    1548                 *prefix = netif->packet_dimension.prefix + IP_PREFIX;
    1549                 *suffix = netif->packet_dimension.suffix + IP_SUFFIX;
    1550         }
    1551         fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
    1552 
    1553         return EOK;
    1554 }
    1555 
    1556 /** Updates the device content length according to the new MTU value.
    1557  *
    1558  * @param[in] device_id The device identifier.
    1559  * @param[in] mtu       The new mtu value.
    1560  * @return              EOK on success.
    1561  * @return              ENOENT if device is not found.
    1562  */
    1563 static int ip_mtu_changed_message(device_id_t device_id, size_t mtu)
    1564 {
    1565         ip_netif_t *netif;
    1566 
    1567         fibril_rwlock_write_lock(&ip_globals.netifs_lock);
    1568         netif = ip_netifs_find(&ip_globals.netifs, device_id);
    1569         if (!netif) {
    1570                 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
    1571                 return ENOENT;
    1572         }
    1573         netif->packet_dimension.content = mtu;
    1574         fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
    1575 
    1576         printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
    1577 
    1578         return EOK;
    1579 }
    1580 
    1581 /** Process IPC messages from the registered device driver modules
    1582  *
    1583  * @param[in]     iid   Message identifier.
    1584  * @param[in,out] icall Message parameters.
    1585  *
    1586  */
    1587 static void ip_receiver(ipc_callid_t iid, ipc_call_t *icall)
    1588 {
    1589         packet_t *packet;
    1590         int rc;
    1591        
    1592         while (true) {
    1593                 switch (IPC_GET_IMETHOD(*icall)) {
    1594                 case NET_IL_DEVICE_STATE:
    1595                         rc = ip_device_state_message(IPC_GET_DEVICE(*icall),
    1596                             IPC_GET_STATE(*icall));
    1597                         async_answer_0(iid, (sysarg_t) rc);
    1598                         break;
    1599                
    1600                 case NET_IL_RECEIVED:
    1601                         rc = packet_translate_remote(ip_globals.net_phone, &packet,
    1602                             IPC_GET_PACKET(*icall));
    1603                         if (rc == EOK) {
    1604                                 do {
    1605                                         packet_t *next = pq_detach(packet);
    1606                                         ip_process_packet(IPC_GET_DEVICE(*icall), packet);
    1607                                         packet = next;
    1608                                 } while (packet);
    1609                         }
    1610                        
    1611                         async_answer_0(iid, (sysarg_t) rc);
    1612                         break;
    1613                
    1614                 case NET_IL_MTU_CHANGED:
    1615                         rc = ip_mtu_changed_message(IPC_GET_DEVICE(*icall),
    1616                             IPC_GET_MTU(*icall));
    1617                         async_answer_0(iid, (sysarg_t) rc);
    1618                         break;
    1619                
    1620                 default:
    1621                         async_answer_0(iid, (sysarg_t) ENOTSUP);
    1622                 }
    1623                
    1624                 iid = async_get_call(icall);
    1625         }
    1626 }
    1627 
    1628 /** Registers the transport layer protocol.
    1629  *
    1630  * The traffic of this protocol will be supplied using either the receive
    1631  * function or IPC message.
    1632  *
    1633  * @param[in] protocol  The transport layer module protocol.
    1634  * @param[in] service   The transport layer module service.
    1635  * @param[in] phone     The transport layer module phone.
    1636  * @param[in] received_msg The receiving function.
    1637  * @return              EOK on success.
    1638  * @return              EINVAL if the protocol parameter and/or the service
    1639  *                      parameter is zero.
    1640  * @return              EINVAL if the phone parameter is not a positive number
    1641  *                      and the tl_receive_msg is NULL.
    1642  * @return              ENOMEM if there is not enough memory left.
    1643  */
    1644 static int
    1645 ip_register(int protocol, services_t service, int phone,
    1646     tl_received_msg_t received_msg)
    1647 {
    1648         ip_proto_t *proto;
    1649         int index;
    1650 
    1651         if (!protocol || !service || ((phone < 0) && !received_msg))
    1652                 return EINVAL;
    1653 
    1654         proto = (ip_proto_t *) malloc(sizeof(ip_protos_t));
    1655         if (!proto)
    1656                 return ENOMEM;
    1657 
    1658         proto->protocol = protocol;
    1659         proto->service = service;
    1660         proto->phone = phone;
    1661         proto->received_msg = received_msg;
    1662 
    1663         fibril_rwlock_write_lock(&ip_globals.protos_lock);
    1664         index = ip_protos_add(&ip_globals.protos, proto->protocol, proto);
    1665         if (index < 0) {
    1666                 fibril_rwlock_write_unlock(&ip_globals.protos_lock);
    1667                 free(proto);
    1668                 return index;
    1669         }
    1670         fibril_rwlock_write_unlock(&ip_globals.protos_lock);
    1671 
    1672         printf("%s: Protocol registered (protocol: %d, phone: %d)\n",
    1673             NAME, proto->protocol, proto->phone);
    1674 
    1675         return EOK;
    1676 }
    1677 
    16781644
    16791645static int
     
    17911757                    (header->destination_address & route->netmask.s_addr))) {
    17921758                        // clear the ARP mapping if any
    1793                         address.value = (uint8_t *) &header->destination_address;
    1794                         address.length = sizeof(header->destination_address);
     1759                        address.value = (char *) &header->destination_address;
     1760                        address.length = CONVERT_SIZE(uint8_t, char,
     1761                            sizeof(header->destination_address));
    17951762                        arp_clear_address_req(netif->arp->phone,
    17961763                            netif->device_id, SERVICE_IP, &address);
     
    18761843}
    18771844
     1845/** Processes the received IP packet or the packet queue one by one.
     1846 *
     1847 * The packet is either passed to another module or released on error.
     1848 *
     1849 * @param[in] device_id The source device identifier.
     1850 * @param[in,out] packet The received packet.
     1851 * @return              EOK on success and the packet is no longer needed.
     1852 * @return              EINVAL if the packet is too small to carry the IP
     1853 *                      packet.
     1854 * @return              EINVAL if the received address lengths differs from the
     1855 *                      registered values.
     1856 * @return              ENOENT if the device is not found in the cache.
     1857 * @return              ENOENT if the protocol for the device is not found in
     1858 *                      the cache.
     1859 * @return              ENOMEM if there is not enough memory left.
     1860 */
     1861static int ip_receive_message(device_id_t device_id, packet_t *packet)
     1862{
     1863        packet_t *next;
     1864
     1865        do {
     1866                next = pq_detach(packet);
     1867                ip_process_packet(device_id, packet);
     1868                packet = next;
     1869        } while (packet);
     1870
     1871        return EOK;
     1872}
     1873
    18781874/** Processes the IP message.
    18791875 *
     
    18871883 *
    18881884 * @see ip_interface.h
    1889  * @see il_remote.h
     1885 * @see il_interface.h
    18901886 * @see IS_NET_IP_MESSAGE()
    18911887 */
    1892 int il_module_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
    1893     size_t *answer_count)
     1888int
     1889ip_message_standalone(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
     1890    int *answer_count)
    18941891{
    18951892        packet_t *packet;
    18961893        struct sockaddr *addr;
    1897         void *header;
    1898         size_t headerlen;
    18991894        size_t addrlen;
    19001895        size_t prefix;
    19011896        size_t suffix;
    19021897        size_t content;
     1898        void *header;
     1899        size_t headerlen;
    19031900        device_id_t device_id;
    19041901        int rc;
    19051902       
    19061903        *answer_count = 0;
    1907         switch (IPC_GET_IMETHOD(*call)) {
     1904        switch (IPC_GET_METHOD(*call)) {
    19081905        case IPC_M_PHONE_HUNGUP:
    19091906                return EOK;
    19101907       
    19111908        case IPC_M_CONNECT_TO_ME:
    1912                 return ip_register(IL_GET_PROTO(*call), IL_GET_SERVICE(*call),
    1913                     IPC_GET_PHONE(*call), NULL);
    1914        
    1915         case NET_IP_DEVICE:
    1916                 return ip_device_req_local(0, IPC_GET_DEVICE(*call),
    1917                     IPC_GET_SERVICE(*call));
     1909                return ip_register(IL_GET_PROTO(call), IL_GET_SERVICE(call),
     1910                    IPC_GET_PHONE(call), NULL);
     1911       
     1912        case NET_IL_DEVICE:
     1913                return ip_device_req_local(0, IPC_GET_DEVICE(call),
     1914                    IPC_GET_SERVICE(call));
     1915       
     1916        case NET_IL_SEND:
     1917                rc = packet_translate_remote(ip_globals.net_phone, &packet,
     1918                    IPC_GET_PACKET(call));
     1919                if (rc != EOK)
     1920                        return rc;
     1921                return ip_send_msg_local(0, IPC_GET_DEVICE(call), packet, 0,
     1922                    IPC_GET_ERROR(call));
     1923       
     1924        case NET_IL_DEVICE_STATE:
     1925                return ip_device_state_message(IPC_GET_DEVICE(call),
     1926                    IPC_GET_STATE(call));
     1927       
     1928        case NET_IL_RECEIVED:
     1929                rc = packet_translate_remote(ip_globals.net_phone, &packet,
     1930                    IPC_GET_PACKET(call));
     1931                if (rc != EOK)
     1932                        return rc;
     1933                return ip_receive_message(IPC_GET_DEVICE(call), packet);
    19181934       
    19191935        case NET_IP_RECEIVED_ERROR:
    19201936                rc = packet_translate_remote(ip_globals.net_phone, &packet,
    1921                     IPC_GET_PACKET(*call));
     1937                    IPC_GET_PACKET(call));
    19221938                if (rc != EOK)
    19231939                        return rc;
    1924                 return ip_received_error_msg_local(0, IPC_GET_DEVICE(*call),
    1925                     packet, IPC_GET_TARGET(*call), IPC_GET_ERROR(*call));
     1940                return ip_received_error_msg_local(0, IPC_GET_DEVICE(call),
     1941                    packet, IPC_GET_TARGET(call), IPC_GET_ERROR(call));
    19261942       
    19271943        case NET_IP_ADD_ROUTE:
    1928                 return ip_add_route_req_local(0, IPC_GET_DEVICE(*call),
    1929                     IP_GET_ADDRESS(*call), IP_GET_NETMASK(*call),
    1930                     IP_GET_GATEWAY(*call));
     1944                return ip_add_route_req_local(0, IPC_GET_DEVICE(call),
     1945                    IP_GET_ADDRESS(call), IP_GET_NETMASK(call),
     1946                    IP_GET_GATEWAY(call));
    19311947
    19321948        case NET_IP_SET_GATEWAY:
    1933                 return ip_set_gateway_req_local(0, IPC_GET_DEVICE(*call),
    1934                     IP_GET_GATEWAY(*call));
     1949                return ip_set_gateway_req_local(0, IPC_GET_DEVICE(call),
     1950                    IP_GET_GATEWAY(call));
    19351951
    19361952        case NET_IP_GET_ROUTE:
    1937                 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0,
    1938                     &addrlen);
     1953                rc = data_receive((void **) &addr, &addrlen);
    19391954                if (rc != EOK)
    19401955                        return rc;
    19411956               
    1942                 rc = ip_get_route_req_local(0, IP_GET_PROTOCOL(*call), addr,
     1957                rc = ip_get_route_req_local(0, IP_GET_PROTOCOL(call), addr,
    19431958                    (socklen_t) addrlen, &device_id, &header, &headerlen);
    19441959                if (rc != EOK)
    19451960                        return rc;
    19461961               
    1947                 IPC_SET_DEVICE(*answer, device_id);
    1948                 IP_SET_HEADERLEN(*answer, headerlen);
     1962                IPC_SET_DEVICE(answer, device_id);
     1963                IP_SET_HEADERLEN(answer, headerlen);
    19491964               
    19501965                *answer_count = 2;
     
    19571972                return rc;
    19581973       
    1959         case NET_IP_PACKET_SPACE:
    1960                 rc = ip_packet_size_message(IPC_GET_DEVICE(*call), &addrlen,
     1974        case NET_IL_PACKET_SPACE:
     1975                rc = ip_packet_size_message(IPC_GET_DEVICE(call), &addrlen,
    19611976                    &prefix, &content, &suffix);
    19621977                if (rc != EOK)
    19631978                        return rc;
    19641979               
    1965                 IPC_SET_ADDR(*answer, addrlen);
    1966                 IPC_SET_PREFIX(*answer, prefix);
    1967                 IPC_SET_CONTENT(*answer, content);
    1968                 IPC_SET_SUFFIX(*answer, suffix);
     1980                IPC_SET_ADDR(answer, addrlen);
     1981                IPC_SET_PREFIX(answer, prefix);
     1982                IPC_SET_CONTENT(answer, content);
     1983                IPC_SET_SUFFIX(answer, suffix);
    19691984                *answer_count = 4;
    19701985                return EOK;
    19711986       
    1972         case NET_IP_SEND:
    1973                 rc = packet_translate_remote(ip_globals.net_phone, &packet,
    1974                     IPC_GET_PACKET(*call));
    1975                 if (rc != EOK)
    1976                         return rc;
     1987        case NET_IL_MTU_CHANGED:
     1988                return ip_mtu_changed_message(IPC_GET_DEVICE(call),
     1989                    IPC_GET_MTU(call));
     1990        }
     1991       
     1992        return ENOTSUP;
     1993}
     1994
     1995/** Default thread for new connections.
     1996 *
     1997 * @param[in] iid       The initial message identifier.
     1998 * @param[in] icall     The initial message call structure.
     1999 */
     2000static void il_client_connection(ipc_callid_t iid, ipc_call_t *icall)
     2001{
     2002        /*
     2003         * Accept the connection
     2004         *  - Answer the first IPC_M_CONNECT_ME_TO call.
     2005         */
     2006        ipc_answer_0(iid, EOK);
     2007       
     2008        while (true) {
     2009                ipc_call_t answer;
     2010                int answer_count;
    19772011               
    1978                 return ip_send_msg_local(0, IPC_GET_DEVICE(*call), packet, 0,
    1979                     IPC_GET_ERROR(*call));
    1980         }
    1981        
    1982         return ENOTSUP;
    1983 }
    1984 
     2012                /* Clear the answer structure */
     2013                refresh_answer(&answer, &answer_count);
     2014               
     2015                /* Fetch the next message */
     2016                ipc_call_t call;
     2017                ipc_callid_t callid = async_get_call(&call);
     2018               
     2019                /* Process the message */
     2020                int res = il_module_message_standalone(callid, &call, &answer,
     2021                    &answer_count);
     2022               
     2023                /*
     2024                 * End if told to either by the message or the processing
     2025                 * result.
     2026                 */
     2027                if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) ||
     2028                    (res == EHANGUP)) {
     2029                        return;
     2030                }
     2031               
     2032                /* Answer the message */
     2033                answer_call(callid, res, &answer, answer_count);
     2034        }
     2035}
     2036
     2037/** Starts the module.
     2038 *
     2039 * @return EOK on success.
     2040 * @return Other error codes as defined for each specific module start function.
     2041 */
    19852042int main(int argc, char *argv[])
    19862043{
     2044        int rc;
     2045       
    19872046        /* Start the module */
    1988         return il_module_start(SERVICE_IP);
     2047        rc = il_module_start_standalone(il_client_connection);
     2048        return rc;
    19892049}
    19902050
Note: See TracChangeset for help on using the changeset viewer.