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