source: mainline/uspace/srv/net/net/net.c@ 522253c1

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

Move Internet layer modules messages definitions to standard library.

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