1/*
2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel D��rfler, axeld@pinc-software.de
7 */
8
9
10#include "ancillary_data.h"
11#include "device_interfaces.h"
12#include "domains.h"
13#include "interfaces.h"
14#include "link.h"
15#include "stack_private.h"
16#include "utility.h"
17
18#include <net_datalink_protocol.h>
19#include <net_device.h>
20#include <net_protocol.h>
21#include <net_stack.h>
22
23#include <lock.h>
24#include <util/AutoLock.h>
25
26#include <KernelExport.h>
27
28#include <net/if_types.h>
29#include <new>
30#include <stdarg.h>
31#include <stdlib.h>
32#include <string.h>
33
34
35//#define TRACE_STACK
36#ifdef TRACE_STACK
37#	define TRACE(x) dprintf x
38#else
39#	define TRACE(x) ;
40#endif
41
42#define MAX_CHAIN_MODULES 5
43
44struct chain;
45typedef DoublyLinkedList<chain> ChainList;
46
47struct chain_key {
48	int		family;
49	int		type;
50	int		protocol;
51};
52
53struct family {
54	family(int type);
55
56	void Acquire();
57	void Release();
58
59	static int Compare(void* _family, const void* _key);
60	static uint32 Hash(void* _family, const void* _key, uint32 range);
61	static struct family* Lookup(int type);
62	static struct family* Add(int type);
63
64	struct family*	next;
65	int				type;
66	int32			ref_count;
67	ChainList		chains;
68};
69
70struct ChainHash;
71
72struct chain : DoublyLinkedListLinkImpl<chain> {
73	chain(int family, int type, int protocol);
74	~chain();
75
76	status_t Acquire();
77	void Release();
78	void Uninitialize();
79
80	static struct chain* Lookup(BOpenHashTable<ChainHash>* chains,
81		int family, int type, int protocol);
82	static struct chain* Add(BOpenHashTable<ChainHash>* chains,
83		int family, int type, int protocol, va_list modules);
84	static struct chain* Add(BOpenHashTable<ChainHash>* chains,
85		int family, int type, int protocol, ...);
86	static void DeleteChains(BOpenHashTable<ChainHash>* chains);
87
88	chain*			next;
89	struct family*	parent;
90
91	int 			family;
92	int				type;
93	int				protocol;
94
95	int32			ref_count;
96	uint32			flags;
97	const char*		modules[MAX_CHAIN_MODULES + 1];
98	module_info*	infos[MAX_CHAIN_MODULES + 1];
99};
100
101struct ChainHash {
102	typedef chain_key	KeyType;
103	typedef	chain		ValueType;
104
105// TODO: check if this makes a good hash...
106#define HASH(o) ((uint32)(((o)->family) ^ ((o)->type) ^ ((o)->protocol)))
107
108	size_t HashKey(KeyType key) const
109	{
110		return HASH(&key);
111	}
112
113	size_t Hash(ValueType* value) const
114	{
115		return HASH(value);
116	}
117
118#undef HASH
119
120	bool Compare(KeyType key, ValueType* chain) const
121	{
122		if (chain->family == key.family
123			&& chain->type == key.type
124			&& chain->protocol == key.protocol)
125			return true;
126
127		return false;
128	}
129
130	ValueType*& GetLink(ValueType* value) const
131	{
132		return value->next;
133	}
134};
135
136struct FamilyHash {
137	typedef int			KeyType;
138	typedef	family		ValueType;
139
140	size_t HashKey(KeyType key) const
141	{
142		return key;
143	}
144
145	size_t Hash(ValueType* value) const
146	{
147		return value->type;
148	}
149
150	bool Compare(KeyType key, ValueType* family) const
151	{
152		return family->type == key;
153	}
154
155	ValueType*& GetLink(ValueType* value) const
156	{
157		return value->next;
158	}
159};
160
161typedef BOpenHashTable<ChainHash> ChainTable;
162typedef BOpenHashTable<FamilyHash> FamilyTable;
163
164#define CHAIN_MISSING_MODULE	0x02
165#define CHAIN_INITIALIZED		0x01
166
167static mutex sChainLock;
168static mutex sInitializeChainLock;
169static ChainTable* sProtocolChains;
170static ChainTable* sDatalinkProtocolChains;
171static ChainTable* sReceivingProtocolChains;
172static FamilyTable* sFamilies;
173static bool sInitialized;
174
175
176family::family(int _type)
177	:
178	type(_type),
179	ref_count(0)
180{
181}
182
183
184void
185family::Acquire()
186{
187	atomic_add(&ref_count, 1);
188}
189
190
191void
192family::Release()
193{
194	if (atomic_add(&ref_count, -1) > 1)
195		return;
196
197	TRACE(("family %d unused, uninit chains\n", type));
198	MutexLocker _(sChainLock);
199
200	ChainList::Iterator iterator = chains.GetIterator();
201	while (struct chain* chain = iterator.Next()) {
202		chain->Uninitialize();
203	}
204}
205
206
207/*static*/ struct family*
208family::Lookup(int type)
209{
210	return sFamilies->Lookup(type);
211}
212
213
214/*static*/ struct family*
215family::Add(int type)
216{
217	struct family* family = new (std::nothrow) ::family(type);
218	if (family == NULL)
219		return NULL;
220
221	if (sFamilies->Insert(family) != B_OK) {
222		delete family;
223		return NULL;
224	}
225
226	return family;
227}
228
229
230//	#pragma mark -
231
232
233chain::chain(int _family, int _type, int _protocol)
234	:
235	family(_family),
236	type(_type),
237	protocol(_protocol),
238	ref_count(0),
239	flags(0)
240{
241	parent = ::family::Lookup(family);
242	if (parent == NULL)
243		parent = ::family::Add(family);
244
245	//parent->chains.Add(this);
246
247	for (int32 i = 0; i < MAX_CHAIN_MODULES; i++) {
248		modules[i] = NULL;
249		infos[i] = NULL;
250	}
251}
252
253
254chain::~chain()
255{
256	for (int32 i = 0; i < MAX_CHAIN_MODULES; i++) {
257		free((char*)modules[i]);
258	}
259
260	//parent->chains.Remove(this);
261}
262
263
264status_t
265chain::Acquire()
266{
267	if (atomic_add(&ref_count, 1) > 0) {
268		if ((flags & CHAIN_MISSING_MODULE) != 0) {
269			atomic_add(&ref_count, -1);
270			return EAFNOSUPPORT;
271		}
272
273		while ((flags & CHAIN_INITIALIZED) == 0) {
274			mutex_lock(&sInitializeChainLock);
275			mutex_unlock(&sInitializeChainLock);
276		}
277		return B_OK;
278	}
279
280	parent->Acquire();
281
282	if ((flags & CHAIN_INITIALIZED) != 0)
283		return B_OK;
284
285	TRACE(("initializing chain %d.%d.%d\n", family, type, protocol));
286	MutexLocker locker(&sInitializeChainLock);
287
288	for (int32 i = 0; modules[i] != NULL; i++) {
289		if (get_module(modules[i], &infos[i]) < B_OK) {
290			flags |= CHAIN_MISSING_MODULE;
291
292			// put already opened modules
293			while (i-- > 0) {
294				put_module(modules[i]);
295			}
296			return EAFNOSUPPORT;
297		}
298	}
299
300	flags |= CHAIN_INITIALIZED;
301	return B_OK;
302}
303
304
305void
306chain::Release()
307{
308	if (atomic_add(&ref_count, -1) > 1)
309		return;
310
311	TRACE(("chain %d.%d.%d unused\n", family, type, protocol));
312	parent->Release();
313}
314
315
316void
317chain::Uninitialize()
318{
319	if ((flags & CHAIN_INITIALIZED) == 0)
320		return;
321
322	TRACE(("uninit chain %d.%d.%d\n", family, type, protocol));
323	MutexLocker _(sInitializeChainLock);
324
325	for (int32 i = 0; modules[i] != NULL; i++) {
326		put_module(modules[i]);
327	}
328
329	flags &= ~CHAIN_INITIALIZED;
330}
331
332
333/*static*/ struct chain*
334chain::Lookup(ChainTable* chains, int family, int type, int protocol)
335{
336	struct chain_key key = { family, type, protocol };
337	return chains->Lookup(key);
338}
339
340
341/*static*/ struct chain*
342chain::Add(ChainTable* chains, int family, int type, int protocol,
343	va_list modules)
344{
345	struct chain* chain = new (std::nothrow) ::chain(family, type, protocol);
346	if (chain == NULL)
347		return NULL;
348
349	if (chain->parent == NULL || chains->Insert(chain) != B_OK) {
350		delete chain;
351		return NULL;
352	}
353
354	TRACE(("Add chain %d.%d.%d:\n", family, type, protocol));
355	const char* module;
356	int32 count = 0;
357
358	while (true) {
359		module = va_arg(modules, const char*);
360		if (module == NULL)
361			break;
362
363		TRACE(("  [%" B_PRId32 "] %s\n", count, module));
364		chain->modules[count] = strdup(module);
365		if (chain->modules[count] == NULL
366			|| ++count >= MAX_CHAIN_MODULES) {
367			chains->Remove(chain);
368			delete chain;
369			return NULL;
370		}
371	}
372
373	if (chains == sProtocolChains && count == 0) {
374		chains->Remove(chain);
375		delete chain;
376		return NULL;
377	}
378
379	return chain;
380}
381
382
383/*static*/ struct chain*
384chain::Add(ChainTable* chains, int family, int type, int protocol, ...)
385{
386	va_list modules;
387	va_start(modules, protocol);
388
389	struct chain* chain = Add(chains, family, type, 0, modules);
390
391	va_end(modules);
392	return chain;
393}
394
395
396/*static*/ void
397chain::DeleteChains(ChainTable* chains)
398{
399	struct chain* current;
400	current = chains->Clear(true);
401	while (current) {
402		struct chain* next = current->next;
403
404		current->Uninitialize();
405		delete current;
406		current = next;
407	}
408}
409
410
411//	#pragma mark -
412
413
414static void
415uninit_domain_protocols(net_socket* socket)
416{
417	net_protocol* protocol = socket->first_protocol;
418	while (protocol != NULL) {
419		net_protocol* next = protocol->next;
420		protocol->module->uninit_protocol(protocol);
421
422		protocol = next;
423	}
424
425	socket->first_protocol = NULL;
426	socket->first_info = NULL;
427}
428
429
430status_t
431get_domain_protocols(net_socket* socket)
432{
433	struct chain* chain;
434
435	{
436		MutexLocker _(sChainLock);
437
438		chain = chain::Lookup(sProtocolChains, socket->family, socket->type,
439			socket->type == SOCK_RAW ? 0 : socket->protocol);
440			// in SOCK_RAW mode, we ignore the protocol information
441		if (chain == NULL) {
442			// TODO: if we want to be POSIX compatible, we should also support
443			//	the error codes EPROTONOSUPPORT and EPROTOTYPE.
444			return EAFNOSUPPORT;
445		}
446	}
447
448	// create net_protocol objects for the protocols in the chain
449
450	status_t status = chain->Acquire();
451	if (status != B_OK)
452		return status;
453
454	net_protocol* last = NULL;
455
456	for (int32 i = 0; chain->infos[i] != NULL; i++) {
457		net_protocol* protocol =
458			((net_protocol_module_info*)chain->infos[i])->init_protocol(socket);
459		if (protocol == NULL) {
460			// free protocols we already initialized
461			uninit_domain_protocols(socket);
462			chain->Release();
463			return B_NO_MEMORY;
464		}
465
466		protocol->module = (net_protocol_module_info*)chain->infos[i];
467		protocol->socket = socket;
468		protocol->next = NULL;
469
470		if (last == NULL) {
471			socket->first_protocol = protocol;
472			socket->first_info = protocol->module;
473		} else
474			last->next = protocol;
475
476		last = protocol;
477	}
478
479	return B_OK;
480}
481
482
483status_t
484put_domain_protocols(net_socket* socket)
485{
486	struct chain* chain;
487
488	{
489		MutexLocker _(sChainLock);
490
491		chain = chain::Lookup(sProtocolChains, socket->family, socket->type,
492			socket->protocol);
493		if (chain == NULL)
494			return B_ERROR;
495	}
496
497	uninit_domain_protocols(socket);
498	chain->Release();
499	return B_OK;
500}
501
502
503static void
504uninit_domain_datalink_protocols(domain_datalink* datalink)
505{
506	TRACE(("%s(datalink %p)\n", __FUNCTION__, datalink));
507
508	if (datalink == NULL)
509		return;
510
511	net_datalink_protocol* protocol = datalink->first_protocol;
512	while (protocol != NULL) {
513		net_datalink_protocol* next = protocol->next;
514		protocol->module->uninit_protocol(protocol);
515
516		protocol = next;
517	}
518
519	datalink->first_protocol = NULL;
520	datalink->first_info = NULL;
521}
522
523
524status_t
525get_domain_datalink_protocols(Interface* interface, net_domain* domain)
526{
527	TRACE(("%s(interface %p, domain %d)\n", __FUNCTION__, interface,
528		domain->family));
529
530	struct chain* chain;
531
532	{
533		MutexLocker _(sChainLock);
534
535		chain = chain::Lookup(sDatalinkProtocolChains, domain->family,
536			interface->DeviceInterface()->device->type, 0);
537		if (chain == NULL)
538			return EAFNOSUPPORT;
539	}
540
541	domain_datalink* datalink = interface->DomainDatalink(domain->family);
542	if (datalink == NULL)
543		return B_BAD_VALUE;
544	if (datalink->first_protocol != NULL)
545		return B_NAME_IN_USE;
546
547	// create net_protocol objects for the protocols in the chain
548
549	status_t status = chain->Acquire();
550	if (status != B_OK)
551		return status;
552
553	net_datalink_protocol* last = NULL;
554
555	for (int32 i = 0; chain->infos[i] != NULL; i++) {
556		net_datalink_protocol* protocol;
557		status_t status = ((net_datalink_protocol_module_info*)
558			chain->infos[i])->init_protocol(interface, domain, &protocol);
559		if (status != B_OK) {
560			// free protocols we already initialized
561			uninit_domain_datalink_protocols(datalink);
562			chain->Release();
563			return status;
564		}
565
566		protocol->module = (net_datalink_protocol_module_info*)chain->infos[i];
567		protocol->interface = interface;
568		protocol->domain = domain;
569		protocol->next = NULL;
570
571		if (last == NULL) {
572			datalink->first_protocol = protocol;
573			datalink->first_info = protocol->module;
574		} else
575			last->next = protocol;
576
577		last = protocol;
578	}
579
580	return B_OK;
581}
582
583
584status_t
585put_domain_datalink_protocols(Interface* interface, net_domain* domain)
586{
587	TRACE(("%s(interface %p, domain %d)\n", __FUNCTION__, interface,
588		domain->family));
589
590	struct chain* chain;
591
592	{
593		MutexLocker _(sChainLock);
594
595		chain = chain::Lookup(sDatalinkProtocolChains, domain->family,
596			interface->DeviceInterface()->device->type, 0);
597		if (chain == NULL)
598			return B_ERROR;
599	}
600
601	uninit_domain_datalink_protocols(interface->DomainDatalink(domain->family));
602	chain->Release();
603	return B_OK;
604}
605
606
607status_t
608get_domain_receiving_protocol(net_domain* _domain, uint32 type,
609	net_protocol_module_info** _module)
610{
611	struct net_domain_private* domain = (net_domain_private*)_domain;
612	struct chain* chain;
613
614	TRACE(("get_domain_receiving_protocol(family %d, type %" B_PRIu32 ")\n",
615		domain->family, type));
616
617	{
618		MutexLocker _(sChainLock);
619
620		chain = chain::Lookup(sReceivingProtocolChains, domain->family,
621			type, 0);
622		if (chain == NULL)
623			return EAFNOSUPPORT;
624	}
625
626	status_t status = chain->Acquire();
627	if (status != B_OK)
628		return status;
629
630	*_module = (net_protocol_module_info*)chain->infos[0];
631	return B_OK;
632}
633
634
635status_t
636put_domain_receiving_protocol(net_domain* _domain, uint32 type)
637{
638	struct net_domain_private* domain = (net_domain_private*)_domain;
639	struct chain* chain;
640
641	{
642		MutexLocker _(sChainLock);
643
644		chain = chain::Lookup(sReceivingProtocolChains, domain->family,
645			type, 0);
646		if (chain == NULL)
647			return B_ERROR;
648	}
649
650	chain->Release();
651	return B_OK;
652}
653
654
655status_t
656register_domain_protocols(int family, int type, int protocol, ...)
657{
658	if (type == SOCK_RAW) {
659		// in SOCK_RAW mode, we ignore the protocol information
660		protocol = 0;
661	}
662
663	MutexLocker locker(&sChainLock);
664
665	struct chain* chain = chain::Lookup(sProtocolChains, family, type, protocol);
666	if (chain != NULL)
667		return B_OK;
668
669	va_list modules;
670	va_start(modules, protocol);
671
672	chain = chain::Add(sProtocolChains, family, type, protocol, modules);
673
674	va_end(modules);
675
676	if (chain == NULL)
677		return B_NO_MEMORY;
678
679	return B_OK;
680}
681
682
683status_t
684register_domain_datalink_protocols(int family, int type, ...)
685{
686	TRACE(("register_domain_datalink_protocol(%d.%d)\n", family, type));
687	MutexLocker locker(&sChainLock);
688
689	struct chain* chain
690		= chain::Lookup(sDatalinkProtocolChains, family, type, 0);
691	if (chain != NULL)
692		return B_OK;
693
694	va_list modules;
695	va_start(modules, type);
696
697	chain = chain::Add(sDatalinkProtocolChains, family, type, 0, modules);
698
699	va_end(modules);
700
701	if (chain == NULL)
702		return B_NO_MEMORY;
703
704	// Add datalink interface protocol as the last protocol in the chain; it's
705	// name stays unset, so that it won't be part of the release/acquire process.
706
707	uint32 count = 0;
708	while (chain->modules[count] != NULL) {
709		count++;
710	}
711
712	chain->infos[count] = (module_info*)&gDatalinkInterfaceProtocolModule;
713	return B_OK;
714}
715
716
717static status_t
718register_domain_receiving_protocol(int family, int type, const char* moduleName)
719{
720	TRACE(("register_domain_receiving_protocol(%d.%d, %s)\n", family, type,
721		moduleName));
722
723	MutexLocker _(sChainLock);
724
725	struct chain* chain
726		= chain::Lookup(sReceivingProtocolChains, family, type, 0);
727	if (chain != NULL)
728		return B_OK;
729
730	chain = chain::Add(sReceivingProtocolChains, family, type, 0, moduleName,
731		NULL);
732	if (chain == NULL)
733		return B_NO_MEMORY;
734
735	return B_OK;
736}
737
738
739static void
740scan_modules(const char* path)
741{
742	void* cookie = open_module_list(path);
743	if (cookie == NULL)
744		return;
745
746	while (true) {
747		char name[B_FILE_NAME_LENGTH];
748		size_t length = sizeof(name);
749		if (read_next_module_name(cookie, name, &length) != B_OK)
750			break;
751
752		TRACE(("scan %s\n", name));
753
754		module_info* module;
755		if (get_module(name, &module) == B_OK) {
756			// we don't need the module right now, but we give it a chance
757			// to register itself
758			put_module(name);
759		}
760	}
761
762	close_module_list(cookie);
763}
764
765
766status_t
767init_stack()
768{
769	status_t status = init_domains();
770	if (status != B_OK)
771		return status;
772
773	status = init_interfaces();
774	if (status != B_OK)
775		goto err1;
776
777	status = init_device_interfaces();
778	if (status != B_OK)
779		goto err2;
780
781	status = init_timers();
782	if (status != B_OK)
783		goto err3;
784
785	status = init_notifications();
786	if (status < B_OK) {
787		// If this fails, it just means there won't be any notifications,
788		// it's not a fatal error.
789		dprintf("networking stack notifications could not be initialized: %s\n",
790			strerror(status));
791	}
792
793	module_info* dummy;
794	status = get_module(NET_SOCKET_MODULE_NAME, &dummy);
795	if (status != B_OK)
796		goto err4;
797
798	mutex_init(&sChainLock, "net chains");
799	mutex_init(&sInitializeChainLock, "net intialize chains");
800
801	sFamilies = new(std::nothrow) FamilyTable();
802	if (sFamilies == NULL || sFamilies->Init(10) != B_OK) {
803		status = B_NO_MEMORY;
804		goto err5;
805	}
806
807	sProtocolChains = new(std::nothrow) ChainTable();
808	if (sProtocolChains == NULL || sProtocolChains->Init(10) != B_OK) {
809		status = B_NO_MEMORY;
810		goto err6;
811	}
812
813	sDatalinkProtocolChains = new(std::nothrow) ChainTable();
814	if (sDatalinkProtocolChains == NULL
815			|| sDatalinkProtocolChains->Init(10) != B_OK) {
816		status = B_NO_MEMORY;
817		goto err7;
818	}
819
820	sReceivingProtocolChains = new(std::nothrow) ChainTable();
821	if (sReceivingProtocolChains == NULL
822			|| sReceivingProtocolChains->Init(10) != B_OK) {
823		status = B_NO_MEMORY;
824		goto err8;
825	}
826
827	sInitialized = true;
828
829	link_init();
830	scan_modules("network/protocols");
831	scan_modules("network/datalink_protocols");
832
833	// TODO: for now!
834	register_domain_datalink_protocols(AF_INET, IFT_LOOP,
835		"network/datalink_protocols/loopback_frame/v1", NULL);
836	register_domain_datalink_protocols(AF_INET, IFT_TUNNEL,
837		"network/datalink_protocols/loopback_frame/v1", NULL);
838#if 0 // PPP is not (currently) included in the build
839	register_domain_datalink_protocols(AF_INET, IFT_PPP,
840		"network/datalink_protocols/ppp_frame/v1", NULL);
841#endif
842	register_domain_datalink_protocols(AF_INET6, IFT_LOOP,
843		"network/datalink_protocols/loopback_frame/v1", NULL);
844	register_domain_datalink_protocols(AF_INET, IFT_ETHER,
845		"network/datalink_protocols/arp/v1",
846		"network/datalink_protocols/ethernet_frame/v1",
847		NULL);
848	register_domain_datalink_protocols(AF_INET6, IFT_ETHER,
849		"network/datalink_protocols/ipv6_datagram/v1",
850		"network/datalink_protocols/ethernet_frame/v1",
851		NULL);
852
853	return B_OK;
854
855err8:
856	delete sDatalinkProtocolChains;
857err7:
858	delete sProtocolChains;
859err6:
860	delete sFamilies;
861err5:
862	mutex_destroy(&sInitializeChainLock);
863	mutex_destroy(&sChainLock);
864err4:
865	uninit_timers();
866err3:
867	uninit_device_interfaces();
868err2:
869	uninit_interfaces();
870err1:
871	uninit_domains();
872	return status;
873}
874
875
876status_t
877uninit_stack()
878{
879	TRACE(("Unloading network stack\n"));
880
881	put_module(NET_SOCKET_MODULE_NAME);
882	uninit_notifications();
883
884	// remove chains and families
885
886	chain::DeleteChains(sProtocolChains);
887	chain::DeleteChains(sDatalinkProtocolChains);
888	chain::DeleteChains(sReceivingProtocolChains);
889
890	mutex_destroy(&sChainLock);
891	mutex_destroy(&sInitializeChainLock);
892
893	uninit_timers();
894	uninit_device_interfaces();
895	uninit_interfaces();
896	uninit_domains();
897
898	struct family* current;
899	current = sFamilies->Clear(true);
900	while (current) {
901		struct family* next = current->next;
902
903		delete current;
904		current = next;
905	}
906
907	delete sProtocolChains;
908	delete sDatalinkProtocolChains;
909	delete sReceivingProtocolChains;
910	delete sFamilies;
911
912	return B_OK;
913}
914
915
916static status_t
917stack_std_ops(int32 op, ...)
918{
919	switch (op) {
920		case B_MODULE_INIT:
921			return sInitialized ? B_OK : B_BUSY;
922		case B_MODULE_UNINIT:
923			return B_OK;
924
925		default:
926			return B_ERROR;
927	}
928}
929
930
931net_stack_module_info gNetStackModule = {
932	{
933		NET_STACK_MODULE_NAME,
934		0,
935		stack_std_ops
936	},
937
938	register_domain,
939	unregister_domain,
940	get_domain,
941
942	register_domain_protocols,
943	register_domain_datalink_protocols,
944	register_domain_receiving_protocol,
945
946	get_domain_receiving_protocol,
947	put_domain_receiving_protocol,
948
949	register_device_deframer,
950	unregister_device_deframer,
951	register_domain_device_handler,
952	register_device_handler,
953	unregister_device_handler,
954	register_device_monitor,
955	unregister_device_monitor,
956	device_link_changed,
957	device_removed,
958	device_enqueue_buffer,
959
960	notify_socket,
961
962	checksum,
963
964	init_fifo,
965	uninit_fifo,
966	fifo_enqueue_buffer,
967	fifo_dequeue_buffer,
968	clear_fifo,
969	fifo_socket_enqueue_buffer,
970
971	init_timer,
972	set_timer,
973	cancel_timer,
974	wait_for_timer,
975	is_timer_active,
976	is_timer_running,
977
978	is_syscall,
979	is_restarted_syscall,
980	store_syscall_restart_timeout,
981	restore_syscall_restart_timeout,
982
983	create_ancillary_data_container,
984	delete_ancillary_data_container,
985	add_ancillary_data,
986	remove_ancillary_data,
987	move_ancillary_data,
988	next_ancillary_data
989};
990
991module_info* modules[] = {
992	(module_info*)&gNetStackModule,
993	(module_info*)&gNetBufferModule,
994	(module_info*)&gNetSocketModule,
995	(module_info*)&gNetDatalinkModule,
996	(module_info*)&gLinkModule,
997	(module_info*)&gNetStackInterfaceModule,
998	NULL
999};
1000