source: mainline/uspace/srv/net/net/net.c@ ffa2c8ef

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ffa2c8ef was ffa2c8ef, checked in by Martin Decky <martin@…>, 15 years ago

do not intermix low-level IPC methods with async framework methods

  • 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 rc = add_module(NULL, &net_globals.modules, (uint8_t *) NE2000_NAME,
292 (uint8_t *) NE2000_FILENAME, SERVICE_NE2000, 0, connect_to_service);
293 if (rc != EOK)
294 return rc;
295 rc = add_module(NULL, &net_globals.modules, (uint8_t *) ETHERNET_NAME,
296 (uint8_t *) ETHERNET_FILENAME, SERVICE_ETHERNET, 0, connect_to_service);
297 if (rc != EOK)
298 return rc;
299 rc = add_module(NULL, &net_globals.modules, (uint8_t *) NILDUMMY_NAME,
300 (uint8_t *) NILDUMMY_FILENAME, SERVICE_NILDUMMY, 0, connect_to_service);
301 if (rc != EOK)
302 return rc;
303
304 /* Build specific initialization */
305 return net_initialize_build(client_connection);
306}
307
308/** Start the networking module.
309 *
310 * Initializes the client connection serving function,
311 * initializes the module, registers the module service
312 * and starts the async manager, processing IPC messages
313 * in an infinite loop.
314 *
315 * @param[in] client_connection The client connection
316 * processing function. The
317 * module skeleton propagates
318 * its own one.
319 *
320 * @return EOK on successful module termination.
321 * @return Other error codes as defined for the net_initialize() function.
322 * @return Other error codes as defined for the REGISTER_ME() macro function.
323 *
324 */
325static int net_module_start(async_client_conn_t client_connection)
326{
327 int rc;
328
329 async_set_client_connection(client_connection);
330 rc = pm_init();
331 if (rc != EOK)
332 return rc;
333
334 rc = net_initialize(client_connection);
335 if (rc != EOK)
336 goto out;
337
338 rc = async_connect_to_me(PHONE_NS, SERVICE_NETWORKING, 0, 0, NULL);
339 if (rc != EOK)
340 goto out;
341
342 rc = startup();
343 if (rc != EOK)
344 goto out;
345
346 task_retval(0);
347 async_manager();
348
349out:
350 pm_destroy();
351 return rc;
352}
353
354/** Return the configured values.
355 *
356 * The network interface configuration is searched first.
357 *
358 * @param[in] netif_conf The network interface configuration setting.
359 * @param[out] configuration The found configured values.
360 * @param[in] count The desired settings count.
361 * @param[out] data The found configuration settings data.
362 *
363 * @return EOK.
364 *
365 */
366static int net_get_conf(measured_strings_t *netif_conf,
367 measured_string_t *configuration, size_t count, uint8_t **data)
368{
369 if (data)
370 *data = NULL;
371
372 size_t index;
373 for (index = 0; index < count; index++) {
374 measured_string_t *setting =
375 measured_strings_find(netif_conf, configuration[index].value, 0);
376 if (!setting)
377 setting = measured_strings_find(&net_globals.configuration,
378 configuration[index].value, 0);
379
380 if (setting) {
381 configuration[index].length = setting->length;
382 configuration[index].value = setting->value;
383 } else {
384 configuration[index].length = 0;
385 configuration[index].value = NULL;
386 }
387 }
388
389 return EOK;
390}
391
392int net_get_conf_req(int net_phone, measured_string_t **configuration,
393 size_t count, uint8_t **data)
394{
395 if (!configuration || (count <= 0))
396 return EINVAL;
397
398 return net_get_conf(NULL, *configuration, count, data);
399}
400
401int net_get_device_conf_req(int net_phone, device_id_t device_id,
402 measured_string_t **configuration, size_t count, uint8_t **data)
403{
404 if ((!configuration) || (count == 0))
405 return EINVAL;
406
407 netif_t *netif = netifs_find(&net_globals.netifs, device_id);
408 if (netif)
409 return net_get_conf(&netif->configuration, *configuration, count, data);
410 else
411 return net_get_conf(NULL, *configuration, count, data);
412}
413
414void net_free_settings(measured_string_t *settings, uint8_t *data)
415{
416}
417
418/** Start the network interface according to its configuration.
419 *
420 * Register the network interface with the subsystem modules.
421 * Start the needed subsystem modules.
422 *
423 * @param[in] netif The network interface specific data.
424 *
425 * @return EOK on success.
426 * @return EINVAL if there are some settings missing.
427 * @return ENOENT if the internet protocol module is not known.
428 * @return Other error codes as defined for the netif_probe_req() function.
429 * @return Other error codes as defined for the nil_device_req() function.
430 * @return Other error codes as defined for the needed internet layer
431 * registering function.
432 *
433 */
434static int start_device(netif_t *netif)
435{
436 int rc;
437
438 /* Mandatory netif */
439 measured_string_t *setting =
440 measured_strings_find(&netif->configuration, (uint8_t *) CONF_NETIF, 0);
441
442 netif->driver = get_running_module(&net_globals.modules, setting->value);
443 if (!netif->driver) {
444 fprintf(stderr, "%s: Failed to start network interface driver '%s'\n",
445 NAME, setting->value);
446 return EINVAL;
447 }
448
449 /* Optional network interface layer */
450 setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_NIL, 0);
451 if (setting) {
452 netif->nil = get_running_module(&net_globals.modules, setting->value);
453 if (!netif->nil) {
454 fprintf(stderr, "%s: Failed to start network interface layer '%s'\n",
455 NAME, setting->value);
456 return EINVAL;
457 }
458 } else
459 netif->nil = NULL;
460
461 /* Mandatory internet layer */
462 setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_IL, 0);
463 netif->il = get_running_module(&net_globals.modules, setting->value);
464 if (!netif->il) {
465 fprintf(stderr, "%s: Failed to start internet layer '%s'\n",
466 NAME, setting->value);
467 return EINVAL;
468 }
469
470 /* Hardware configuration */
471 setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_IRQ, 0);
472 int irq = setting ? strtol((char *) setting->value, NULL, 10) : 0;
473
474 setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_IO, 0);
475 uintptr_t io = setting ? strtol((char *) setting->value, NULL, 16) : 0;
476
477 rc = netif_probe_req(netif->driver->phone, netif->id, irq, (void *) io);
478 if (rc != EOK)
479 return rc;
480
481 /* Network interface layer startup */
482 services_t internet_service;
483 if (netif->nil) {
484 setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_MTU, 0);
485 if (!setting)
486 setting = measured_strings_find(&net_globals.configuration,
487 (uint8_t *) CONF_MTU, 0);
488
489 int mtu = setting ? strtol((char *) setting->value, NULL, 10) : 0;
490
491 rc = nil_device_req(netif->nil->phone, netif->id, mtu,
492 netif->driver->service);
493 if (rc != EOK)
494 return rc;
495
496 internet_service = netif->nil->service;
497 } else
498 internet_service = netif->driver->service;
499
500 /* Inter-network layer startup */
501 switch (netif->il->service) {
502 case SERVICE_IP:
503 rc = ip_device_req(netif->il->phone, netif->id,
504 internet_service);
505 if (rc != EOK)
506 return rc;
507 break;
508 default:
509 return ENOENT;
510 }
511
512 return netif_start_req(netif->driver->phone, netif->id);
513}
514
515/** Read the configuration and start all network interfaces.
516 *
517 * @return EOK on success.
518 * @return EXDEV if there is no available system-unique device identifier.
519 * @return EINVAL if any of the network interface names are not configured.
520 * @return ENOMEM if there is not enough memory left.
521 * @return Other error codes as defined for the read_configuration()
522 * function.
523 * @return Other error codes as defined for the read_netif_configuration()
524 * function.
525 * @return Other error codes as defined for the start_device() function.
526 *
527 */
528static int startup(void)
529{
530 const char *conf_files[] = {
531 "lo",
532 "ne2k"
533 };
534 size_t count = sizeof(conf_files) / sizeof(char *);
535 int rc;
536
537 size_t i;
538 for (i = 0; i < count; i++) {
539 netif_t *netif = (netif_t *) malloc(sizeof(netif_t));
540 if (!netif)
541 return ENOMEM;
542
543 netif->id = generate_new_device_id();
544 if (!netif->id)
545 return EXDEV;
546
547 rc = measured_strings_initialize(&netif->configuration);
548 if (rc != EOK)
549 return rc;
550
551 /* Read configuration files */
552 rc = read_netif_configuration(conf_files[i], netif);
553 if (rc != EOK) {
554 measured_strings_destroy(&netif->configuration);
555 free(netif);
556 return rc;
557 }
558
559 /* Mandatory name */
560 measured_string_t *setting =
561 measured_strings_find(&netif->configuration, (uint8_t *) CONF_NAME, 0);
562 if (!setting) {
563 fprintf(stderr, "%s: Network interface name is missing\n", NAME);
564 measured_strings_destroy(&netif->configuration);
565 free(netif);
566 return EINVAL;
567 }
568 netif->name = setting->value;
569
570 /* Add to the netifs map */
571 int index = netifs_add(&net_globals.netifs, netif->id, netif);
572 if (index < 0) {
573 measured_strings_destroy(&netif->configuration);
574 free(netif);
575 return index;
576 }
577
578 /*
579 * Add to the netif names map and start network interfaces
580 * and needed modules.
581 */
582 rc = char_map_add(&net_globals.netif_names, netif->name, 0,
583 index);
584 if (rc != EOK) {
585 measured_strings_destroy(&netif->configuration);
586 netifs_exclude_index(&net_globals.netifs, index);
587 return rc;
588 }
589
590 rc = start_device(netif);
591 if (rc != EOK) {
592 printf("%s: Error starting interface %s (%s)\n", NAME,
593 netif->name, str_error(rc));
594 measured_strings_destroy(&netif->configuration);
595 netifs_exclude_index(&net_globals.netifs, index);
596
597 return rc;
598 }
599
600 /* Increment modules' usage */
601 netif->driver->usage++;
602 if (netif->nil)
603 netif->nil->usage++;
604 netif->il->usage++;
605
606 printf("%s: Network interface started (name: %s, id: %d, driver: %s, "
607 "nil: %s, il: %s)\n", NAME, netif->name, netif->id,
608 netif->driver->name, netif->nil ? (char *) netif->nil->name : "[none]",
609 netif->il->name);
610 }
611
612 return EOK;
613}
614
615/** Process the networking message.
616 *
617 * @param[in] callid The message identifier.
618 * @param[in] call The message parameters.
619 * @param[out] answer The message answer parameters.
620 * @param[out] answer_count The last parameter for the actual answer
621 * in the answer parameter.
622 *
623 * @return EOK on success.
624 * @return ENOTSUP if the message is not known.
625 *
626 * @see net_interface.h
627 * @see IS_NET_NET_MESSAGE()
628 *
629 */
630int net_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
631 size_t *answer_count)
632{
633 measured_string_t *strings;
634 uint8_t *data;
635 int rc;
636
637 *answer_count = 0;
638 switch (IPC_GET_IMETHOD(*call)) {
639 case IPC_M_PHONE_HUNGUP:
640 return EOK;
641 case NET_NET_GET_DEVICE_CONF:
642 rc = measured_strings_receive(&strings, &data,
643 IPC_GET_COUNT(*call));
644 if (rc != EOK)
645 return rc;
646 net_get_device_conf_req(0, IPC_GET_DEVICE(*call), &strings,
647 IPC_GET_COUNT(*call), NULL);
648
649 /* Strings should not contain received data anymore */
650 free(data);
651
652 rc = measured_strings_reply(strings, IPC_GET_COUNT(*call));
653 free(strings);
654 return rc;
655 case NET_NET_GET_CONF:
656 rc = measured_strings_receive(&strings, &data,
657 IPC_GET_COUNT(*call));
658 if (rc != EOK)
659 return rc;
660 net_get_conf_req(0, &strings, IPC_GET_COUNT(*call), NULL);
661
662 /* Strings should not contain received data anymore */
663 free(data);
664
665 rc = measured_strings_reply(strings, IPC_GET_COUNT(*call));
666 free(strings);
667 return rc;
668 case NET_NET_STARTUP:
669 return startup();
670 }
671
672 return ENOTSUP;
673}
674
675/** Default thread for new connections.
676 *
677 * @param[in] iid The initial message identifier.
678 * @param[in] icall The initial message call structure.
679 *
680 */
681static void net_client_connection(ipc_callid_t iid, ipc_call_t *icall)
682{
683 /*
684 * Accept the connection
685 * - Answer the first IPC_M_CONNECT_ME_TO call.
686 */
687 async_answer_0(iid, EOK);
688
689 while (true) {
690 /* Clear the answer structure */
691 ipc_call_t answer;
692 size_t answer_count;
693 refresh_answer(&answer, &answer_count);
694
695 /* Fetch the next message */
696 ipc_call_t call;
697 ipc_callid_t callid = async_get_call(&call);
698
699 /* Process the message */
700 int res = net_module_message(callid, &call, &answer, &answer_count);
701
702 /* End if told to either by the message or the processing result */
703 if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) || (res == EHANGUP))
704 return;
705
706 /* Answer the message */
707 answer_call(callid, res, &answer, answer_count);
708 }
709}
710
711int main(int argc, char *argv[])
712{
713 return net_module_start(net_client_connection);
714}
715
716/** @}
717 */
Note: See TracBrowser for help on using the repository browser.