source: mainline/uspace/srv/net/net/net.c@ 5fe7692

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5fe7692 was 5fe7692, checked in by Petr Koupy <petr.koupy@…>, 15 years ago

Removed side effects from map ADTs.

  • Property mode set to 100644
File size: 18.8 KB
Line 
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 * Networking subsystem central module implementation.
35 *
36 */
37
38#include "net.h"
39
40#include <async.h>
41#include <ctype.h>
42#include <ddi.h>
43#include <errno.h>
44#include <malloc.h>
45#include <stdio.h>
46#include <str.h>
47#include <str_error.h>
48
49#include <ipc/services.h>
50#include <ipc/net.h>
51#include <ipc/net_net.h>
52#include <ipc/il.h>
53#include <ipc/nil.h>
54
55#include <net/modules.h>
56#include <net/packet.h>
57#include <net/device.h>
58
59#include <adt/char_map.h>
60#include <adt/generic_char_map.h>
61#include <adt/measured_strings.h>
62#include <adt/module_map.h>
63
64#include <netif_remote.h>
65#include <nil_remote.h>
66#include <net_interface.h>
67#include <ip_interface.h>
68
69/** Networking module name. */
70#define NAME "net"
71
72/** File read buffer size. */
73#define BUFFER_SIZE 256
74
75/** Networking module global data. */
76net_globals_t net_globals;
77
78GENERIC_CHAR_MAP_IMPLEMENT(measured_strings, measured_string_t);
79DEVICE_MAP_IMPLEMENT(netifs, netif_t);
80
81static int startup(void);
82
83/** Add the configured setting to the configuration map.
84 *
85 * @param[in] configuration The configuration map.
86 * @param[in] name The setting name.
87 * @param[in] value The setting value.
88 *
89 * @return EOK on success.
90 * @return ENOMEM if there is not enough memory left.
91 *
92 */
93int add_configuration(measured_strings_t *configuration, const uint8_t *name,
94 const uint8_t *value)
95{
96 int rc;
97
98 measured_string_t *setting =
99 measured_string_create_bulk(value, 0);
100 if (!setting)
101 return ENOMEM;
102
103 /* Add the configuration setting */
104 rc = measured_strings_add(configuration, name, 0, setting);
105 if (rc != EOK) {
106 free(setting);
107 return rc;
108 }
109
110 return EOK;
111}
112
113/** Generate new system-unique device identifier.
114 *
115 * @return The system-unique devic identifier.
116 */
117static device_id_t generate_new_device_id(void)
118{
119 return device_assign_devno();
120}
121
122static int parse_line(measured_strings_t *configuration, uint8_t *line)
123{
124 int rc;
125
126 /* From the beginning */
127 uint8_t *name = line;
128
129 /* Skip comments and blank lines */
130 if ((*name == '#') || (*name == '\0'))
131 return EOK;
132
133 /* Skip spaces */
134 while (isspace(*name))
135 name++;
136
137 /* Remember the name start */
138 uint8_t *value = name;
139
140 /* Skip the name */
141 while (isalnum(*value) || (*value == '_'))
142 value++;
143
144 if (*value == '=') {
145 /* Terminate the name */
146 *value = '\0';
147 } else {
148 /* Terminate the name */
149 *value = '\0';
150
151 /* Skip until '=' */
152 value++;
153 while ((*value) && (*value != '='))
154 value++;
155
156 /* Not found? */
157 if (*value != '=')
158 return EINVAL;
159 }
160
161 value++;
162
163 /* Skip spaces */
164 while (isspace(*value))
165 value++;
166
167 /* Create a bulk measured string till the end */
168 measured_string_t *setting =
169 measured_string_create_bulk(value, 0);
170 if (!setting)
171 return ENOMEM;
172
173 /* Add the configuration setting */
174 rc = measured_strings_add(configuration, name, 0, setting);
175 if (rc != EOK) {
176 free(setting);
177 return rc;
178 }
179
180 return EOK;
181}
182
183static int read_configuration_file(const char *directory, const char *filename,
184 measured_strings_t *configuration)
185{
186 printf("%s: Reading configuration file %s/%s\n", NAME, directory, filename);
187
188 /* Construct the full filename */
189 char fname[BUFFER_SIZE];
190 if (snprintf(fname, BUFFER_SIZE, "%s/%s", directory, filename) > BUFFER_SIZE)
191 return EOVERFLOW;
192
193 /* Open the file */
194 FILE *cfg = fopen(fname, "r");
195 if (!cfg)
196 return ENOENT;
197
198 /*
199 * Read the configuration line by line
200 * until an error or the end of file
201 */
202 unsigned int line_number = 0;
203 size_t index = 0;
204 uint8_t line[BUFFER_SIZE];
205
206 while (!ferror(cfg) && !feof(cfg)) {
207 int read = fgetc(cfg);
208 if ((read > 0) && (read != '\n') && (read != '\r')) {
209 if (index >= BUFFER_SIZE) {
210 line[BUFFER_SIZE - 1] = '\0';
211 fprintf(stderr, "%s: Configuration line %u too "
212 "long: %s\n", NAME, line_number, (char *) line);
213
214 /* No space left in the line buffer */
215 return EOVERFLOW;
216 }
217 /* Append the character */
218 line[index] = (uint8_t) read;
219 index++;
220 } else {
221 /* On error or new line */
222 line[index] = '\0';
223 line_number++;
224 if (parse_line(configuration, line) != EOK) {
225 fprintf(stderr, "%s: Configuration error on "
226 "line %u: %s\n", NAME, line_number, (char *) line);
227 }
228
229 index = 0;
230 }
231 }
232
233 fclose(cfg);
234 return EOK;
235}
236
237/** Read the network interface specific configuration.
238 *
239 * @param[in] name The network interface name.
240 * @param[in,out] netif The network interface structure.
241 *
242 * @return EOK on success.
243 * @return Other error codes as defined for the add_configuration() function.
244 *
245 */
246static int read_netif_configuration(const char *name, netif_t *netif)
247{
248 return read_configuration_file(CONF_DIR, name, &netif->configuration);
249}
250
251/** Read the networking subsystem global configuration.
252 *
253 * @return EOK on success.
254 * @return Other error codes as defined for the add_configuration() function.
255 *
256 */
257static int read_configuration(void)
258{
259 return read_configuration_file(CONF_DIR, CONF_GENERAL_FILE,
260 &net_globals.configuration);
261}
262
263/** Initialize the networking module.
264 *
265 * @param[in] client_connection The client connection processing
266 * function. The module skeleton propagates
267 * its own one.
268 *
269 * @return EOK on success.
270 * @return ENOMEM if there is not enough memory left.
271 *
272 */
273static int net_initialize(async_client_conn_t client_connection)
274{
275 int rc;
276
277 netifs_initialize(&net_globals.netifs);
278 char_map_initialize(&net_globals.netif_names);
279 modules_initialize(&net_globals.modules);
280 measured_strings_initialize(&net_globals.configuration);
281
282 /* TODO: dynamic configuration */
283 rc = read_configuration();
284 if (rc != EOK)
285 return rc;
286
287 rc = add_module(NULL, &net_globals.modules, (uint8_t *) LO_NAME,
288 (uint8_t *) LO_FILENAME, SERVICE_LO, 0, connect_to_service);
289 if (rc != EOK)
290 return rc;
291
292 rc = add_module(NULL, &net_globals.modules, (uint8_t *) NE2000_NAME,
293 (uint8_t *) NE2000_FILENAME, SERVICE_NE2000, 0, connect_to_service);
294 if (rc != EOK)
295 return rc;
296
297 rc = add_module(NULL, &net_globals.modules, (uint8_t *) ETHERNET_NAME,
298 (uint8_t *) ETHERNET_FILENAME, SERVICE_ETHERNET, 0, connect_to_service);
299 if (rc != EOK)
300 return rc;
301
302 rc = add_module(NULL, &net_globals.modules, (uint8_t *) NILDUMMY_NAME,
303 (uint8_t *) NILDUMMY_FILENAME, SERVICE_NILDUMMY, 0, connect_to_service);
304 if (rc != EOK)
305 return rc;
306
307 /* Build specific initialization */
308 return net_initialize_build(client_connection);
309}
310
311/** Start the networking module.
312 *
313 * Initializes the client connection serving function,
314 * initializes the module, registers the module service
315 * and starts the async manager, processing IPC messages
316 * in an infinite loop.
317 *
318 * @param[in] client_connection The client connection
319 * processing function. The
320 * module skeleton propagates
321 * its own one.
322 *
323 * @return EOK on successful module termination.
324 * @return Other error codes as defined for the net_initialize() function.
325 * @return Other error codes as defined for the REGISTER_ME() macro function.
326 *
327 */
328static int net_module_start(async_client_conn_t client_connection)
329{
330 int rc;
331
332 async_set_client_connection(client_connection);
333 rc = pm_init();
334 if (rc != EOK)
335 return rc;
336
337 rc = net_initialize(client_connection);
338 if (rc != EOK)
339 goto out;
340
341 rc = async_connect_to_me(PHONE_NS, SERVICE_NETWORKING, 0, 0, NULL);
342 if (rc != EOK)
343 goto out;
344
345 rc = startup();
346 if (rc != EOK)
347 goto out;
348
349 task_retval(0);
350 async_manager();
351
352out:
353 pm_destroy();
354 return rc;
355}
356
357/** Return the configured values.
358 *
359 * The network interface configuration is searched first.
360 *
361 * @param[in] netif_conf The network interface configuration setting.
362 * @param[out] configuration The found configured values.
363 * @param[in] count The desired settings count.
364 * @param[out] data The found configuration settings data.
365 *
366 * @return EOK.
367 *
368 */
369static int net_get_conf(measured_strings_t *netif_conf,
370 measured_string_t *configuration, size_t count, uint8_t **data)
371{
372 if (data)
373 *data = NULL;
374
375 size_t index;
376 for (index = 0; index < count; index++) {
377 measured_string_t *setting =
378 measured_strings_find(netif_conf, configuration[index].value, 0);
379 if (!setting)
380 setting = measured_strings_find(&net_globals.configuration,
381 configuration[index].value, 0);
382
383 if (setting) {
384 configuration[index].length = setting->length;
385 configuration[index].value = setting->value;
386 } else {
387 configuration[index].length = 0;
388 configuration[index].value = NULL;
389 }
390 }
391
392 return EOK;
393}
394
395int net_get_conf_req(int net_phone, measured_string_t **configuration,
396 size_t count, uint8_t **data)
397{
398 if (!configuration || (count <= 0))
399 return EINVAL;
400
401 return net_get_conf(NULL, *configuration, count, data);
402}
403
404int net_get_device_conf_req(int net_phone, device_id_t device_id,
405 measured_string_t **configuration, size_t count, uint8_t **data)
406{
407 if ((!configuration) || (count == 0))
408 return EINVAL;
409
410 netif_t *netif = netifs_find(&net_globals.netifs, device_id);
411 if (netif)
412 return net_get_conf(&netif->configuration, *configuration, count, data);
413 else
414 return net_get_conf(NULL, *configuration, count, data);
415}
416
417void net_free_settings(measured_string_t *settings, uint8_t *data)
418{
419}
420
421/** Start the network interface according to its configuration.
422 *
423 * Register the network interface with the subsystem modules.
424 * Start the needed subsystem modules.
425 *
426 * @param[in] netif The network interface specific data.
427 *
428 * @return EOK on success.
429 * @return EINVAL if there are some settings missing.
430 * @return ENOENT if the internet protocol module is not known.
431 * @return Other error codes as defined for the netif_probe_req() function.
432 * @return Other error codes as defined for the nil_device_req() function.
433 * @return Other error codes as defined for the needed internet layer
434 * registering function.
435 *
436 */
437static int start_device(netif_t *netif)
438{
439 int rc;
440
441 /* Mandatory netif */
442 measured_string_t *setting =
443 measured_strings_find(&netif->configuration, (uint8_t *) CONF_NETIF, 0);
444
445 netif->driver = get_running_module(&net_globals.modules, setting->value);
446 if (!netif->driver) {
447 fprintf(stderr, "%s: Failed to start network interface driver '%s'\n",
448 NAME, setting->value);
449 return EINVAL;
450 }
451
452 /* Optional network interface layer */
453 setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_NIL, 0);
454 if (setting) {
455 netif->nil = get_running_module(&net_globals.modules, setting->value);
456 if (!netif->nil) {
457 fprintf(stderr, "%s: Failed to start network interface layer '%s'\n",
458 NAME, setting->value);
459 return EINVAL;
460 }
461 } else
462 netif->nil = NULL;
463
464 /* Mandatory internet layer */
465 setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_IL, 0);
466 netif->il = get_running_module(&net_globals.modules, setting->value);
467 if (!netif->il) {
468 fprintf(stderr, "%s: Failed to start internet layer '%s'\n",
469 NAME, setting->value);
470 return EINVAL;
471 }
472
473 /* Hardware configuration */
474 setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_IRQ, 0);
475 int irq = setting ? strtol((char *) setting->value, NULL, 10) : 0;
476
477 setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_IO, 0);
478 uintptr_t io = setting ? strtol((char *) setting->value, NULL, 16) : 0;
479
480 rc = netif_probe_req(netif->driver->phone, netif->id, irq, (void *) io);
481 if (rc != EOK)
482 return rc;
483
484 /* Network interface layer startup */
485 services_t internet_service;
486 if (netif->nil) {
487 setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_MTU, 0);
488 if (!setting)
489 setting = measured_strings_find(&net_globals.configuration,
490 (uint8_t *) CONF_MTU, 0);
491
492 int mtu = setting ? strtol((char *) setting->value, NULL, 10) : 0;
493
494 rc = nil_device_req(netif->nil->phone, netif->id, mtu,
495 netif->driver->service);
496 if (rc != EOK)
497 return rc;
498
499 internet_service = netif->nil->service;
500 } else
501 internet_service = netif->driver->service;
502
503 /* Inter-network layer startup */
504 switch (netif->il->service) {
505 case SERVICE_IP:
506 rc = ip_device_req(netif->il->phone, netif->id,
507 internet_service);
508 if (rc != EOK)
509 return rc;
510 break;
511 default:
512 return ENOENT;
513 }
514
515 return netif_start_req(netif->driver->phone, netif->id);
516}
517
518/** Read the configuration and start all network interfaces.
519 *
520 * @return EOK on success.
521 * @return EXDEV if there is no available system-unique device identifier.
522 * @return EINVAL if any of the network interface names are not configured.
523 * @return ENOMEM if there is not enough memory left.
524 * @return Other error codes as defined for the read_configuration()
525 * function.
526 * @return Other error codes as defined for the read_netif_configuration()
527 * function.
528 * @return Other error codes as defined for the start_device() function.
529 *
530 */
531static int startup(void)
532{
533 const char *conf_files[] = {
534 "lo",
535 "ne2k"
536 };
537 size_t count = sizeof(conf_files) / sizeof(char *);
538 int rc;
539
540 size_t i;
541 for (i = 0; i < count; i++) {
542 netif_t *netif = (netif_t *) malloc(sizeof(netif_t));
543 if (!netif)
544 return ENOMEM;
545
546 netif->id = generate_new_device_id();
547 if (!netif->id)
548 return EXDEV;
549
550 rc = measured_strings_initialize(&netif->configuration);
551 if (rc != EOK)
552 return rc;
553
554 /* Read configuration files */
555 rc = read_netif_configuration(conf_files[i], netif);
556 if (rc != EOK) {
557 measured_strings_destroy(&netif->configuration, free);
558 free(netif);
559 return rc;
560 }
561
562 /* Mandatory name */
563 measured_string_t *setting =
564 measured_strings_find(&netif->configuration, (uint8_t *) CONF_NAME, 0);
565 if (!setting) {
566 fprintf(stderr, "%s: Network interface name is missing\n", NAME);
567 measured_strings_destroy(&netif->configuration, free);
568 free(netif);
569 return EINVAL;
570 }
571 netif->name = setting->value;
572
573 /* Add to the netifs map */
574 int index = netifs_add(&net_globals.netifs, netif->id, netif);
575 if (index < 0) {
576 measured_strings_destroy(&netif->configuration, free);
577 free(netif);
578 return index;
579 }
580
581 /*
582 * Add to the netif names map and start network interfaces
583 * and needed modules.
584 */
585 rc = char_map_add(&net_globals.netif_names, netif->name, 0,
586 index);
587 if (rc != EOK) {
588 measured_strings_destroy(&netif->configuration, free);
589 netifs_exclude_index(&net_globals.netifs, index, free);
590 return rc;
591 }
592
593 rc = start_device(netif);
594 if (rc != EOK) {
595 printf("%s: Ignoring failed interface %s (%s)\n", NAME,
596 netif->name, str_error(rc));
597 measured_strings_destroy(&netif->configuration, free);
598 netifs_exclude_index(&net_globals.netifs, index, free);
599 continue;
600 }
601
602 /* Increment modules' usage */
603 netif->driver->usage++;
604 if (netif->nil)
605 netif->nil->usage++;
606 netif->il->usage++;
607
608 printf("%s: Network interface started (name: %s, id: %d, driver: %s, "
609 "nil: %s, il: %s)\n", NAME, netif->name, netif->id,
610 netif->driver->name, netif->nil ? (char *) netif->nil->name : "[none]",
611 netif->il->name);
612 }
613
614 return EOK;
615}
616
617/** Process the networking message.
618 *
619 * @param[in] callid The message identifier.
620 * @param[in] call The message parameters.
621 * @param[out] answer The message answer parameters.
622 * @param[out] answer_count The last parameter for the actual answer
623 * in the answer parameter.
624 *
625 * @return EOK on success.
626 * @return ENOTSUP if the message is not known.
627 *
628 * @see net_interface.h
629 * @see IS_NET_NET_MESSAGE()
630 *
631 */
632int net_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
633 size_t *answer_count)
634{
635 measured_string_t *strings;
636 uint8_t *data;
637 int rc;
638
639 *answer_count = 0;
640 switch (IPC_GET_IMETHOD(*call)) {
641 case IPC_M_PHONE_HUNGUP:
642 return EOK;
643 case NET_NET_GET_DEVICE_CONF:
644 rc = measured_strings_receive(&strings, &data,
645 IPC_GET_COUNT(*call));
646 if (rc != EOK)
647 return rc;
648 net_get_device_conf_req(0, IPC_GET_DEVICE(*call), &strings,
649 IPC_GET_COUNT(*call), NULL);
650
651 /* Strings should not contain received data anymore */
652 free(data);
653
654 rc = measured_strings_reply(strings, IPC_GET_COUNT(*call));
655 free(strings);
656 return rc;
657 case NET_NET_GET_CONF:
658 rc = measured_strings_receive(&strings, &data,
659 IPC_GET_COUNT(*call));
660 if (rc != EOK)
661 return rc;
662 net_get_conf_req(0, &strings, IPC_GET_COUNT(*call), NULL);
663
664 /* Strings should not contain received data anymore */
665 free(data);
666
667 rc = measured_strings_reply(strings, IPC_GET_COUNT(*call));
668 free(strings);
669 return rc;
670 case NET_NET_STARTUP:
671 return startup();
672 }
673
674 return ENOTSUP;
675}
676
677/** Default thread for new connections.
678 *
679 * @param[in] iid The initial message identifier.
680 * @param[in] icall The initial message call structure.
681 *
682 */
683static void net_client_connection(ipc_callid_t iid, ipc_call_t *icall)
684{
685 /*
686 * Accept the connection
687 * - Answer the first IPC_M_CONNECT_ME_TO call.
688 */
689 async_answer_0(iid, EOK);
690
691 while (true) {
692 /* Clear the answer structure */
693 ipc_call_t answer;
694 size_t answer_count;
695 refresh_answer(&answer, &answer_count);
696
697 /* Fetch the next message */
698 ipc_call_t call;
699 ipc_callid_t callid = async_get_call(&call);
700
701 /* Process the message */
702 int res = net_module_message(callid, &call, &answer, &answer_count);
703
704 /* End if told to either by the message or the processing result */
705 if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) || (res == EHANGUP))
706 return;
707
708 /* Answer the message */
709 answer_call(callid, res, &answer, answer_count);
710 }
711}
712
713int main(int argc, char *argv[])
714{
715 return net_module_start(net_client_connection);
716}
717
718/** @}
719 */
Note: See TracBrowser for help on using the repository browser.