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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a8e5051 was d0d1f4f, checked in by Jakub Jermar <jakub@…>, 15 years ago

Cleanup net.

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