net.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Lukas Mejdrech
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00038 #include "net.h"
00039 
00040 #include <async.h>
00041 #include <ctype.h>
00042 #include <ddi.h>
00043 #include <errno.h>
00044 #include <malloc.h>
00045 #include <stdio.h>
00046 #include <str.h>
00047 #include <str_error.h>
00048 
00049 #include <ipc/services.h>
00050 #include <ipc/net.h>
00051 #include <ipc/net_net.h>
00052 #include <ipc/il.h>
00053 #include <ipc/nil.h>
00054 
00055 #include <net/modules.h>
00056 #include <net/packet.h>
00057 #include <net/device.h>
00058 
00059 #include <adt/char_map.h>
00060 #include <adt/generic_char_map.h>
00061 #include <adt/measured_strings.h>
00062 #include <adt/module_map.h>
00063 
00064 #include <netif_remote.h>
00065 #include <nil_remote.h>
00066 #include <net_interface.h>
00067 #include <ip_interface.h>
00068 
00070 #define NAME  "net"
00071 
00073 #define BUFFER_SIZE  256
00074 
00076 net_globals_t net_globals;
00077 
00078 GENERIC_CHAR_MAP_IMPLEMENT(measured_strings, measured_string_t);
00079 DEVICE_MAP_IMPLEMENT(netifs, netif_t);
00080 
00081 static int startup(void);
00082 
00093 int add_configuration(measured_strings_t *configuration, const uint8_t *name,
00094     const uint8_t *value)
00095 {
00096         int rc;
00097         
00098         measured_string_t *setting =
00099             measured_string_create_bulk(value, 0);
00100         if (!setting)
00101                 return ENOMEM;
00102         
00103         /* Add the configuration setting */
00104         rc = measured_strings_add(configuration, name, 0, setting);
00105         if (rc != EOK) {
00106                 free(setting);
00107                 return rc;
00108         }
00109         
00110         return EOK;
00111 }
00112 
00117 static device_id_t generate_new_device_id(void)
00118 {
00119         return device_assign_devno();
00120 }
00121 
00122 static int parse_line(measured_strings_t *configuration, uint8_t *line)
00123 {
00124         int rc;
00125         
00126         /* From the beginning */
00127         uint8_t *name = line;
00128         
00129         /* Skip comments and blank lines */
00130         if ((*name == '#') || (*name == '\0'))
00131                 return EOK;
00132         
00133         /* Skip spaces */
00134         while (isspace(*name))
00135                 name++;
00136         
00137         /* Remember the name start */
00138         uint8_t *value = name;
00139         
00140         /* Skip the name */
00141         while (isalnum(*value) || (*value == '_'))
00142                 value++;
00143         
00144         if (*value == '=') {
00145                 /* Terminate the name */
00146                 *value = '\0';
00147         } else {
00148                 /* Terminate the name */
00149                 *value = '\0';
00150                 
00151                 /* Skip until '=' */
00152                 value++;
00153                 while ((*value) && (*value != '='))
00154                         value++;
00155                 
00156                 /* Not found? */
00157                 if (*value != '=')
00158                         return EINVAL;
00159         }
00160         
00161         value++;
00162         
00163         /* Skip spaces */
00164         while (isspace(*value))
00165                 value++;
00166         
00167         /* Create a bulk measured string till the end */
00168         measured_string_t *setting =
00169             measured_string_create_bulk(value, 0);
00170         if (!setting)
00171                 return ENOMEM;
00172         
00173         /* Add the configuration setting */
00174         rc = measured_strings_add(configuration, name, 0, setting);
00175         if (rc != EOK) {
00176                 free(setting);
00177                 return rc;
00178         }
00179         
00180         return EOK;
00181 }
00182 
00183 static int read_configuration_file(const char *directory, const char *filename,
00184     measured_strings_t *configuration)
00185 {
00186         printf("%s: Reading configuration file %s/%s\n", NAME, directory, filename);
00187         
00188         /* Construct the full filename */
00189         char fname[BUFFER_SIZE];
00190         if (snprintf(fname, BUFFER_SIZE, "%s/%s", directory, filename) > BUFFER_SIZE)
00191                 return EOVERFLOW;
00192         
00193         /* Open the file */
00194         FILE *cfg = fopen(fname, "r");
00195         if (!cfg)
00196                 return ENOENT;
00197         
00198         /*
00199          * Read the configuration line by line
00200          * until an error or the end of file
00201          */
00202         unsigned int line_number = 0;
00203         size_t index = 0;
00204         uint8_t line[BUFFER_SIZE];
00205         
00206         while (!ferror(cfg) && !feof(cfg)) {
00207                 int read = fgetc(cfg);
00208                 if ((read > 0) && (read != '\n') && (read != '\r')) {
00209                         if (index >= BUFFER_SIZE) {
00210                                 line[BUFFER_SIZE - 1] = '\0';
00211                                 fprintf(stderr, "%s: Configuration line %u too "
00212                                     "long: %s\n", NAME, line_number, (char *) line);
00213                                 
00214                                 /* No space left in the line buffer */
00215                                 return EOVERFLOW;
00216                         }
00217                         /* Append the character */
00218                         line[index] = (uint8_t) read;
00219                         index++;
00220                 } else {
00221                         /* On error or new line */
00222                         line[index] = '\0';
00223                         line_number++;
00224                         if (parse_line(configuration, line) != EOK) {
00225                                 fprintf(stderr, "%s: Configuration error on "
00226                                     "line %u: %s\n", NAME, line_number, (char *) line);
00227                         }
00228                         
00229                         index = 0;
00230                 }
00231         }
00232         
00233         fclose(cfg);
00234         return EOK;
00235 }
00236 
00246 static int read_netif_configuration(const char *name, netif_t *netif)
00247 {
00248         return read_configuration_file(CONF_DIR, name, &netif->configuration);
00249 }
00250 
00257 static int read_configuration(void)
00258 {
00259         return read_configuration_file(CONF_DIR, CONF_GENERAL_FILE,
00260             &net_globals.configuration);
00261 }
00262 
00273 static int net_initialize(async_client_conn_t client_connection)
00274 {
00275         int rc;
00276         
00277         netifs_initialize(&net_globals.netifs);
00278         char_map_initialize(&net_globals.netif_names);
00279         modules_initialize(&net_globals.modules);
00280         measured_strings_initialize(&net_globals.configuration);
00281         
00282         /* TODO: dynamic configuration */
00283         rc = read_configuration();
00284         if (rc != EOK)
00285                 return rc;
00286         
00287         rc = add_module(NULL, &net_globals.modules, (uint8_t *) LO_NAME,
00288             (uint8_t *) LO_FILENAME, SERVICE_LO, 0, connect_to_service);
00289         if (rc != EOK)
00290                 return rc;
00291         
00292         rc = add_module(NULL, &net_globals.modules, (uint8_t *) NE2000_NAME,
00293             (uint8_t *) NE2000_FILENAME, SERVICE_NE2000, 0, connect_to_service);
00294         if (rc != EOK)
00295                 return rc;
00296         
00297         rc = add_module(NULL, &net_globals.modules, (uint8_t *) ETHERNET_NAME,
00298             (uint8_t *) ETHERNET_FILENAME, SERVICE_ETHERNET, 0, connect_to_service);
00299         if (rc != EOK)
00300                 return rc;
00301         
00302         rc = add_module(NULL, &net_globals.modules, (uint8_t *) NILDUMMY_NAME,
00303             (uint8_t *) NILDUMMY_FILENAME, SERVICE_NILDUMMY, 0, connect_to_service);
00304         if (rc != EOK)
00305                 return rc;
00306         
00307         /* Build specific initialization */
00308         return net_initialize_build(client_connection);
00309 }
00310 
00328 static int net_module_start(async_client_conn_t client_connection)
00329 {
00330         int rc;
00331         
00332         async_set_client_connection(client_connection);
00333         rc = pm_init();
00334         if (rc != EOK)
00335                 return rc;
00336         
00337         rc = net_initialize(client_connection);
00338         if (rc != EOK)
00339                 goto out;
00340         
00341         rc = async_connect_to_me(PHONE_NS, SERVICE_NETWORKING, 0, 0, NULL);
00342         if (rc != EOK)
00343                 goto out;
00344         
00345         rc = startup();
00346         if (rc != EOK)
00347                 goto out;
00348         
00349         task_retval(0);
00350         async_manager();
00351 
00352 out:
00353         pm_destroy();
00354         return rc;
00355 }
00356 
00369 static int net_get_conf(measured_strings_t *netif_conf,
00370     measured_string_t *configuration, size_t count, uint8_t **data)
00371 {
00372         if (data)
00373                 *data = NULL;
00374         
00375         size_t index;
00376         for (index = 0; index < count; index++) {
00377                 measured_string_t *setting =
00378                     measured_strings_find(netif_conf, configuration[index].value, 0);
00379                 if (!setting)
00380                         setting = measured_strings_find(&net_globals.configuration,
00381                             configuration[index].value, 0);
00382                 
00383                 if (setting) {
00384                         configuration[index].length = setting->length;
00385                         configuration[index].value = setting->value;
00386                 } else {
00387                         configuration[index].length = 0;
00388                         configuration[index].value = NULL;
00389                 }
00390         }
00391         
00392         return EOK;
00393 }
00394 
00395 int net_get_conf_req(int net_phone, measured_string_t **configuration,
00396     size_t count, uint8_t **data)
00397 {
00398         if (!configuration || (count <= 0))
00399                 return EINVAL;
00400         
00401         return net_get_conf(NULL, *configuration, count, data);
00402 }
00403 
00404 int net_get_device_conf_req(int net_phone, device_id_t device_id,
00405     measured_string_t **configuration, size_t count, uint8_t **data)
00406 {
00407         if ((!configuration) || (count == 0))
00408                 return EINVAL;
00409 
00410         netif_t *netif = netifs_find(&net_globals.netifs, device_id);
00411         if (netif)
00412                 return net_get_conf(&netif->configuration, *configuration, count, data);
00413         else
00414                 return net_get_conf(NULL, *configuration, count, data);
00415 }
00416 
00417 void net_free_settings(measured_string_t *settings, uint8_t *data)
00418 {
00419 }
00420 
00437 static int start_device(netif_t *netif)
00438 {
00439         int rc;
00440         
00441         /* Mandatory netif */
00442         measured_string_t *setting =
00443             measured_strings_find(&netif->configuration, (uint8_t *) CONF_NETIF, 0);
00444         
00445         netif->driver = get_running_module(&net_globals.modules, setting->value);
00446         if (!netif->driver) {
00447                 fprintf(stderr, "%s: Failed to start network interface driver '%s'\n",
00448                     NAME, setting->value);
00449                 return EINVAL;
00450         }
00451         
00452         /* Optional network interface layer */
00453         setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_NIL, 0);
00454         if (setting) {
00455                 netif->nil = get_running_module(&net_globals.modules, setting->value);
00456                 if (!netif->nil) {
00457                         fprintf(stderr, "%s: Failed to start network interface layer '%s'\n",
00458                             NAME, setting->value);
00459                         return EINVAL;
00460                 }
00461         } else
00462                 netif->nil = NULL;
00463         
00464         /* Mandatory internet layer */
00465         setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_IL, 0);
00466         netif->il = get_running_module(&net_globals.modules, setting->value);
00467         if (!netif->il) {
00468                 fprintf(stderr, "%s: Failed to start internet layer '%s'\n",
00469                     NAME, setting->value);
00470                 return EINVAL;
00471         }
00472         
00473         /* Hardware configuration */
00474         setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_IRQ, 0);
00475         int irq = setting ? strtol((char *) setting->value, NULL, 10) : 0;
00476         
00477         setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_IO, 0);
00478         uintptr_t io = setting ? strtol((char *) setting->value, NULL, 16) : 0;
00479         
00480         rc = netif_probe_req(netif->driver->phone, netif->id, irq, (void *) io);
00481         if (rc != EOK)
00482                 return rc;
00483         
00484         /* Network interface layer startup */
00485         services_t internet_service;
00486         if (netif->nil) {
00487                 setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_MTU, 0);
00488                 if (!setting)
00489                         setting = measured_strings_find(&net_globals.configuration,
00490                             (uint8_t *) CONF_MTU, 0);
00491                 
00492                 int mtu = setting ? strtol((char *) setting->value, NULL, 10) : 0;
00493                 
00494                 rc = nil_device_req(netif->nil->phone, netif->id, mtu,
00495                     netif->driver->service);
00496                 if (rc != EOK)
00497                         return rc;
00498                 
00499                 internet_service = netif->nil->service;
00500         } else
00501                 internet_service = netif->driver->service;
00502         
00503         /* Inter-network layer startup */
00504         switch (netif->il->service) {
00505         case SERVICE_IP:
00506                 rc = ip_device_req(netif->il->phone, netif->id,
00507                     internet_service);
00508                 if (rc != EOK)
00509                         return rc;
00510                 break;
00511         default:
00512                 return ENOENT;
00513         }
00514         
00515         return netif_start_req(netif->driver->phone, netif->id);
00516 }
00517 
00531 static int startup(void)
00532 {
00533         const char *conf_files[] = {
00534                 "lo",
00535                 "ne2k"
00536         };
00537         size_t count = sizeof(conf_files) / sizeof(char *);
00538         int rc;
00539         
00540         size_t i;
00541         for (i = 0; i < count; i++) {
00542                 netif_t *netif = (netif_t *) malloc(sizeof(netif_t));
00543                 if (!netif)
00544                         return ENOMEM;
00545                 
00546                 netif->id = generate_new_device_id();
00547                 if (!netif->id)
00548                         return EXDEV;
00549                 
00550                 rc = measured_strings_initialize(&netif->configuration);
00551                 if (rc != EOK)
00552                         return rc;
00553                 
00554                 /* Read configuration files */
00555                 rc = read_netif_configuration(conf_files[i], netif);
00556                 if (rc != EOK) {
00557                         measured_strings_destroy(&netif->configuration, free);
00558                         free(netif);
00559                         return rc;
00560                 }
00561                 
00562                 /* Mandatory name */
00563                 measured_string_t *setting =
00564                     measured_strings_find(&netif->configuration, (uint8_t *) CONF_NAME, 0);
00565                 if (!setting) {
00566                         fprintf(stderr, "%s: Network interface name is missing\n", NAME);
00567                         measured_strings_destroy(&netif->configuration, free);
00568                         free(netif);
00569                         return EINVAL;
00570                 }
00571                 netif->name = setting->value;
00572                 
00573                 /* Add to the netifs map */
00574                 int index = netifs_add(&net_globals.netifs, netif->id, netif);
00575                 if (index < 0) {
00576                         measured_strings_destroy(&netif->configuration, free);
00577                         free(netif);
00578                         return index;
00579                 }
00580                 
00581                 /*
00582                  * Add to the netif names map and start network interfaces
00583                  * and needed modules.
00584                  */
00585                 rc = char_map_add(&net_globals.netif_names, netif->name, 0,
00586                     index);
00587                 if (rc != EOK) {
00588                         measured_strings_destroy(&netif->configuration, free);
00589                         netifs_exclude_index(&net_globals.netifs, index, free);
00590                         return rc;
00591                 }
00592                 
00593                 rc = start_device(netif);
00594                 if (rc != EOK) {
00595                         printf("%s: Ignoring failed interface %s (%s)\n", NAME,
00596                             netif->name, str_error(rc));
00597                         measured_strings_destroy(&netif->configuration, free);
00598                         netifs_exclude_index(&net_globals.netifs, index, free);
00599                         continue;
00600                 }
00601                 
00602                 /* Increment modules' usage */
00603                 netif->driver->usage++;
00604                 if (netif->nil)
00605                         netif->nil->usage++;
00606                 netif->il->usage++;
00607                 
00608                 printf("%s: Network interface started (name: %s, id: %d, driver: %s, "
00609                     "nil: %s, il: %s)\n", NAME, netif->name, netif->id,
00610                     netif->driver->name, netif->nil ? (char *) netif->nil->name : "[none]",
00611                     netif->il->name);
00612         }
00613         
00614         return EOK;
00615 }
00616 
00632 int net_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
00633     size_t *answer_count)
00634 {
00635         measured_string_t *strings;
00636         uint8_t *data;
00637         int rc;
00638         
00639         *answer_count = 0;
00640         switch (IPC_GET_IMETHOD(*call)) {
00641         case IPC_M_PHONE_HUNGUP:
00642                 return EOK;
00643         case NET_NET_GET_DEVICE_CONF:
00644                 rc = measured_strings_receive(&strings, &data,
00645                     IPC_GET_COUNT(*call));
00646                 if (rc != EOK)
00647                         return rc;
00648                 net_get_device_conf_req(0, IPC_GET_DEVICE(*call), &strings,
00649                     IPC_GET_COUNT(*call), NULL);
00650                 
00651                 /* Strings should not contain received data anymore */
00652                 free(data);
00653                 
00654                 rc = measured_strings_reply(strings, IPC_GET_COUNT(*call));
00655                 free(strings);
00656                 return rc;
00657         case NET_NET_GET_CONF:
00658                 rc = measured_strings_receive(&strings, &data,
00659                     IPC_GET_COUNT(*call));
00660                 if (rc != EOK)
00661                         return rc;
00662                 net_get_conf_req(0, &strings, IPC_GET_COUNT(*call), NULL);
00663                 
00664                 /* Strings should not contain received data anymore */
00665                 free(data);
00666                 
00667                 rc = measured_strings_reply(strings, IPC_GET_COUNT(*call));
00668                 free(strings);
00669                 return rc;
00670         case NET_NET_STARTUP:
00671                 return startup();
00672         }
00673         
00674         return ENOTSUP;
00675 }
00676 
00683 static void net_client_connection(ipc_callid_t iid, ipc_call_t *icall)
00684 {
00685         /*
00686          * Accept the connection
00687          *  - Answer the first IPC_M_CONNECT_ME_TO call.
00688          */
00689         async_answer_0(iid, EOK);
00690         
00691         while (true) {
00692                 /* Clear the answer structure */
00693                 ipc_call_t answer;
00694                 size_t answer_count;
00695                 refresh_answer(&answer, &answer_count);
00696                 
00697                 /* Fetch the next message */
00698                 ipc_call_t call;
00699                 ipc_callid_t callid = async_get_call(&call);
00700                 
00701                 /* Process the message */
00702                 int res = net_module_message(callid, &call, &answer, &answer_count);
00703                 
00704                 /* End if told to either by the message or the processing result */
00705                 if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) || (res == EHANGUP))
00706                         return;
00707                 
00708                 /* Answer the message */
00709                 answer_call(callid, res, &answer, answer_count);
00710         }
00711 }
00712 
00713 int main(int argc, char *argv[])
00714 {
00715         return net_module_start(net_client_connection);
00716 }
00717 

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