blob: ad8507d70be54e5191519690982d1aa710069cb8 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2002-2003 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26#include <windows.h>
27#include <winsock2.h>
28#include <assert.h>
29
30#include "jni_util.h"
31
32#include "NetworkInterface.h"
33
34/*
35 * Windows 9x specific routines to enumerate network interfaces and the
36 * IP addresses bound to those interfaces.
37 *
38 * Windows 95 does not include IP helper library support by default.
39 * Additionally Windows 98 can have its IP helper library support
40 * trashed by certain IE installations. For these environments we
41 * combine information from the registry with the list of IP addresses
42 * obtained via SIO_GET_INTERFACE_LIST.
43 */
44
45/*
46 * Header files are missing these
47 */
48#if !defined(SIO_GET_INTERFACE_LIST)
49#define SIO_GET_INTERFACE_LIST _IOR('t', 127, u_long)
50
51struct in_addr6 {
52 u_char s6_addr[16];
53};
54
55struct sockaddr_in6 {
56 short sin6_family;
57 u_short sin6_port;
58 u_long sin6_flowinfo;
59 struct in_addr6 sin6_addr;
60};
61
62typedef union sockaddr_gen{
63 struct sockaddr Address;
64 struct sockaddr_in AddressIn;
65 struct sockaddr_in6 AddressIn6;
66} sockaddr_gen;
67
68typedef struct _INTERFACE_INFO
69{
70 u_long iiFlags;
71 sockaddr_gen iiAddress;
72 sockaddr_gen iiBroadcastAddress;
73 sockaddr_gen iiNetmask;
74} INTERFACE_INFO;
75
76#define IFF_UP 0x00000001
77#endif
78
79
80#define MAX_STR_LEN 256
81
82
83/*
84 * A network adapter (similiar to the netif structure except contains
85 * Windows 9x specific fields).
86 */
87typedef struct _adapter {
88 char *name;
89 char *displayName;
90 int index;
91 char *reg_key;
92 int is_wan_driver;
93 netaddr *addrs;
94 struct _adapter *next;
95} adapter;
96
97
98/*
99 * Cached adapter list.
100 */
101static CRITICAL_SECTION cacheLock;
102static adapter *cachedAdapterList;
103
104/*
105 * Initialize cache
106 */
107void init_win9x() {
108 InitializeCriticalSection(&cacheLock);
109}
110
111
112/*
113 * Free adapter list and any addresses bound to the adpater.
114 */
115static void free_adapters(adapter *adapterP) {
116 adapter *curr = adapterP;
117 while (curr != NULL) {
118 if (curr->name != NULL)
119 free(curr->name);
120
121 if (curr->displayName != NULL)
122 free(curr->displayName);
123
124 if (curr->reg_key != NULL)
125 free(curr->reg_key);
126
127 if (curr->addrs != NULL)
128 free_netaddr(curr->addrs);
129
130 adapterP = adapterP->next;
131 free(curr);
132 curr = adapterP;
133 }
134}
135
136
137/*
138 * Returns the SIO_GET_INTERFACE_LIST output
139 */
140static int getInterfaceList(JNIEnv *env, INTERFACE_INFO *infoP, DWORD dwSize) {
141 SOCKET sock;
142 DWORD ret;
143
144 /* create a socket and do the ioctl */
145 sock = socket(AF_INET, SOCK_DGRAM, 0);
146 if (sock == INVALID_SOCKET) {
147 JNU_ThrowByName(env, "java/lang/Error", "socket failed");
148 return -1;
149 }
150 ret = WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0,
151 infoP, dwSize, &dwSize, NULL, NULL);
152 closesocket(sock);
153 if (ret == SOCKET_ERROR) {
154 JNU_ThrowByName(env, "java/lang/Error", "WSAIoctl failed");
155 return -1;
156 }
157 return dwSize;
158}
159
160
161/*
162 * Gross, ugly, and crude way of guessing if this is a WAN (dial-up) driver.
163 * Returns 1 if it's the normal PPCMAC VxD, otherwise 0.
164 */
165static int isWanDriver(char *driver) {
166 LONG ret;
167 HKEY hKey;
168 DWORD dwLen;
169 ULONG ulType;
170 char key[MAX_STR_LEN];
171 char vxd[MAX_STR_LEN];
172
173 sprintf(key, "System\\CurrentControlSet\\Services\\Class\\%s", driver);
174 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, (PHKEY)&hKey);
175 if (ret != ERROR_SUCCESS) {
176 return 0;
177 }
178 dwLen = sizeof(vxd);
179 ret = RegQueryValueEx(hKey, "DeviceVxDs", NULL, &ulType,
180 (LPBYTE)vxd, &dwLen);
181 RegCloseKey(hKey);
182 if (ret != ERROR_SUCCESS) {
183 return 0;
184 }
185 return (strcmp(vxd, "pppmac.vxd") == 0);
186}
187
188/*
189 * Windows 9x routine to get the network adapters using the registry.
190 * We enumerate HKEY_LOCAL_MACHINE\Enum and iterate through the tree
191 * looking for devices of class "Net". As these devices may not have a
192 * unique name we assign them a generated name.
193 *
194 * Returns a list of adapters without IP addresses (addrs member is NULL).
195 */
196static int getAdapters(JNIEnv *env, adapter **adapterPP)
197{
198 LONG ret;
199 HKEY enumKey;
200 DWORD dwLen;
201 DWORD dwEnumKeys;
202 DWORD enumIndex;
203 ULONG ulType;
204 int adapterCount = 0;
205 adapter *adapterP = NULL;
206 adapter *curr;
207
208 /*
209 * Start at HKEY_LOCAL_MACHINE\Enum
210 */
211 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Enum", 0, KEY_READ, (PHKEY)&enumKey);
212 if (ret != ERROR_SUCCESS) {
213 return -1;
214 }
215 ret = RegQueryInfoKey(enumKey, NULL, NULL, NULL, &dwEnumKeys,
216 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
217 if (ret != ERROR_SUCCESS) {
218 RegCloseKey(enumKey);
219 return -1;
220 }
221
222 /*
223 * Iterate through the sub-keys (PCI, Root, ...)
224 */
225 for(enumIndex = 0; enumIndex<dwEnumKeys; enumIndex++) {
226 TCHAR deviceType[MAX_STR_LEN];
227 HKEY deviceKey;
228 DWORD deviceIndex;
229 DWORD dwDeviceKeys;
230
231 dwLen = sizeof(deviceType);
232 ret = RegEnumKeyEx(enumKey, enumIndex, deviceType, &dwLen, NULL, NULL, NULL, NULL);
233 if (ret != ERROR_SUCCESS) {
234 /* ignore this tree */
235 continue;
236 }
237
238 ret = RegOpenKeyEx(enumKey, deviceType, 0, KEY_READ, (PHKEY)&deviceKey);
239 if (ret != ERROR_SUCCESS) {
240 /* ignore this tree */
241 continue;
242 }
243 ret = RegQueryInfoKey(deviceKey, NULL, NULL, NULL, &dwDeviceKeys,
244 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
245 if (ret != ERROR_SUCCESS) {
246 /* ignore this tree */
247 RegCloseKey(deviceKey);
248 continue;
249 }
250
251 /*
252 * Iterate through each of the sub-keys under PCI, Root, ...
253 */
254 for (deviceIndex=0; deviceIndex<dwDeviceKeys; deviceIndex++) {
255 TCHAR name[MAX_STR_LEN];
256 HKEY nameKey;
257 DWORD nameIndex;
258 DWORD dwNameKeys;
259
260 dwLen = sizeof(name);
261 ret = RegEnumKeyEx(deviceKey, deviceIndex, name, &dwLen, NULL, NULL, NULL, NULL);
262
263 if (ret != ERROR_SUCCESS) {
264 /* ignore this sub-tree */
265 continue;
266 }
267
268 ret = RegOpenKeyEx(deviceKey, name, 0, KEY_READ, (PHKEY)&nameKey);
269 if (ret != ERROR_SUCCESS) {
270 /* ignore this sub-tree */
271 continue;
272 }
273 ret = RegQueryInfoKey(nameKey, NULL, NULL, NULL, &dwNameKeys,
274 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
275 if (ret != ERROR_SUCCESS) {
276 RegCloseKey(nameKey);
277 /* ignore this sub-tree */
278 continue;
279 }
280
281 /*
282 * Finally iterate through the Enum\Root\Net level keys
283 */
284 for (nameIndex=0; nameIndex<dwNameKeys; nameIndex++) {
285 TCHAR dev[MAX_STR_LEN];
286 TCHAR cls[MAX_STR_LEN];
287 HKEY clsKey;
288
289 dwLen = sizeof(dev);
290 ret = RegEnumKeyEx(nameKey, nameIndex, dev, &dwLen, NULL, NULL, NULL, NULL);
291 if (ret != ERROR_SUCCESS) {
292 continue;
293 }
294
295 ret = RegOpenKeyEx(nameKey, dev, 0, KEY_READ, (PHKEY)&clsKey);
296 if (ret == ERROR_SUCCESS) {
297 dwLen = sizeof(cls);
298 ret = RegQueryValueEx(clsKey, "Class", NULL, &ulType,
299 (LPBYTE)cls, &dwLen);
300
301 if (ret == ERROR_SUCCESS) {
302 if (strcmp(cls, "Net") == 0) {
303 TCHAR deviceDesc[MAX_STR_LEN];
304
305 dwLen = sizeof(deviceDesc);
306 ret = RegQueryValueEx(clsKey, "DeviceDesc", NULL, &ulType,
307 (LPBYTE)deviceDesc, &dwLen);
308
309 if (ret == ERROR_SUCCESS) {
310 char key_name[MAX_STR_LEN];
311 char ps_name[8];
312 char driver[MAX_STR_LEN];
313 int wan_device;
314
315 /*
316 * Generate a pseudo device name
317 */
318 sprintf(ps_name, "net%d", adapterCount);
319
320 /*
321 * Try to determine if this a WAN adapter. This is
322 * useful when we try to eliminate WAN adapters from
323 * the interface list when probing for DHCP info
324 */
325 dwLen = sizeof(driver);
326 ret = RegQueryValueEx(clsKey, "Driver", NULL,
327 &ulType, (LPBYTE)driver, &dwLen);
328 if (ret == ERROR_SUCCESS) {
329 wan_device = isWanDriver(driver);
330 } else {
331 wan_device = 0;
332 }
333
334 /*
335 * We have found a Net device. In order to get the
336 * static IP addresses we must note the key.
337 */
338 sprintf(key_name, "Enum\\%s\\%s\\%s", deviceType, name, dev);
339
340 /*
341 * Create the net adapter
342 */
343 curr = (adapter *)calloc(1, sizeof(adapter));
344 if (curr != NULL) {
345 curr->is_wan_driver = wan_device;
346 curr->name = (char *)malloc(strlen(ps_name) + 1);
347 if (curr->name) {
348 curr->displayName = (char *)malloc(strlen(deviceDesc) + 1);
349 if (curr->displayName) {
350 curr->reg_key = (char *)malloc(strlen(key_name)+1);
351 if (curr->reg_key == NULL) {
352 free(curr->displayName);
353 free(curr->name);
354 free(curr);
355 curr = NULL;
356 }
357 } else {
358 free(curr->name);
359 free(curr);
360 curr = NULL;
361 }
362 } else {
363 free(curr);
364 curr = NULL;
365 }
366 }
367
368 /* At OutOfMemory occurred */
369 if (curr == NULL) {
370 JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
371 free_adapters(adapterP);
372 RegCloseKey(clsKey);
373 RegCloseKey(nameKey);
374 RegCloseKey(deviceKey);
375 RegCloseKey(enumKey);
376 return -1;
377 }
378
379 /* index starts at 1 (not 0) */
380 curr->index = ++adapterCount;
381
382 strcpy(curr->name, ps_name);
383 strcpy(curr->displayName, deviceDesc);
384 strcpy(curr->reg_key, key_name);
385
386 /*
387 * Put the adapter at the end of the list.
388 */
389 if (adapterP == NULL) {
390 adapterP = curr;
391 } else {
392 adapter *tail = adapterP;
393 while (tail->next != NULL) {
394 tail = tail->next;
395 }
396 tail->next = curr;
397 }
398 }
399 }
400 }
401 }
402 RegCloseKey(clsKey);
403 }
404 RegCloseKey(nameKey);
405 }
406 RegCloseKey(deviceKey);
407 }
408 RegCloseKey(enumKey);
409
410 /*
411 * Insert an entry for the loopback interface
412 */
413 curr = (adapter *)calloc(1, sizeof(adapter));
414 if (curr == NULL) {
415 JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
416 free_adapters(adapterP);
417 return -1;
418 }
419 curr->index = ++adapterCount;
420 curr->name = strdup("lo");
421 curr->displayName = strdup("TCP Loopback interface");
422 curr->next = adapterP;
423 *adapterPP = curr;
424
425 return adapterCount;
426}
427
428/*
429 * Windows 9x routine to obtain any static addresses for a specified
430 * TCP/IP binding.
431 *
432 * We first open Enum\Network\${binding} and check that the driver
433 * is TCP/IP. If so we pick up the driver and check for any IP addresses
434 * in System\\CurrentControlSet\\Services\\Class\\${driver}
435 *
436 * Returns 0 if found, otherwise -1.
437 */
438static int getStaticAddressEntry(char *binding, char *addresses) {
439 LONG ret;
440 HKEY hKey;
441 char name[255];
442 char desc[255];
443 char driver[255];
444 char ipaddr[255];
445 DWORD dwName;
446 ULONG ulType;
447
448 /* assume nothing will be returned */
449 strcpy(addresses, "");
450
451 /*
452 * Open the binding and check that it's TCP/IP
453 */
454 sprintf(name, "Enum\\Network\\%s", binding);
455 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, name, 0, KEY_READ, (PHKEY)&hKey);
456 if (ret != ERROR_SUCCESS) {
457 return -1;
458 }
459 dwName = sizeof(desc);
460 ret = RegQueryValueEx(hKey, "DeviceDesc", NULL, &ulType,
461 (LPBYTE)desc, &dwName);
462 if (ret != ERROR_SUCCESS) {
463 RegCloseKey(hKey);
464 return -1;
465 }
466 if (strcmp(desc, "TCP/IP") != 0) {
467 /* ignore non-TCP/IP bindings */
468 RegCloseKey(hKey);
469 return -1;
470 }
471
472 /*
473 * Get the driver for this TCP/IP binding
474 */
475 dwName = sizeof(driver);
476 ret = RegQueryValueEx(hKey, "Driver", NULL, &ulType,
477 (LPBYTE)driver, &dwName);
478 RegCloseKey(hKey);
479 if (ret != ERROR_SUCCESS) {
480 return -1;
481 }
482
483 /*
484 * Finally check if there is an IPAddress value for this driver.
485 */
486 sprintf(name, "System\\CurrentControlSet\\Services\\Class\\%s", driver);
487 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, name, 0, KEY_READ, (PHKEY)&hKey);
488 if (ret != ERROR_SUCCESS) {
489 return -1;
490 }
491 dwName = sizeof(ipaddr);
492 ret = RegQueryValueEx(hKey, "IPAddress", NULL, &ulType,
493 (LPBYTE)ipaddr, &dwName);
494 RegCloseKey(hKey);
495 if (ret != ERROR_SUCCESS) {
496 return -1;
497 }
498
499 /* Return the address(es) */
500 strcpy( addresses, ipaddr );
501 return 0;
502}
503
504/*
505 * Windows 9x routine to enumerate the static IP addresses on a
506 * particular interface using the registry.
507 *
508 * Returns a count of the number of addresses found.
509 */
510static int getStaticAddresses(JNIEnv *env, char *reg_key, netaddr **netaddrPP)
511{
512 LONG ret;
513 HKEY enumKey, bindingKey;
514 DWORD dwLen;
515 ULONG ulType;
516 TCHAR driver[MAX_STR_LEN];
517 char addresses[MAX_STR_LEN];
518 unsigned long addr; /* IPv4 address */
519 unsigned char byte;
520 netaddr *netaddrP, *curr;
521 int i, addrCount, if_count;
522
523 /*
524 * Open the HKEY_LOCAL_MACHINE\Enum\%s\%s\%s key
525 */
526 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, reg_key, 0, KEY_READ,
527 (PHKEY)&enumKey);
528 if (ret != ERROR_SUCCESS) {
529 /* interface has been removed */
530 *netaddrPP = NULL;
531 return 0;
532 }
533
534 /*
535 * Iterate through each of the bindings to find any TCP/IP bindings
536 * and any static address assoicated with the binding.
537 */
538 strcpy(addresses, "");
539 addrCount = 0;
540 netaddrP = NULL;
541
542 ret = RegOpenKeyEx(enumKey, "Bindings", 0, KEY_READ, (PHKEY)&bindingKey);
543 if (ret == ERROR_SUCCESS) {
544 DWORD dwBindingKeys;
545 DWORD dwBindingIndex;
546
547 ret = RegQueryInfoKey(bindingKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwBindingKeys,
548 NULL, NULL, NULL, NULL);
549 if (ret == ERROR_SUCCESS) {
550 TCHAR binding[MAX_STR_LEN];
551
552 dwBindingIndex=0;
553 while (dwBindingIndex<dwBindingKeys) {
554 dwLen = sizeof(binding);
555 ret = RegEnumValue(bindingKey, dwBindingIndex, binding, &dwLen,
556 NULL, &ulType, NULL, NULL);
557 if (ret == ERROR_SUCCESS) {
558 if (getStaticAddressEntry(binding, addresses) == 0) {
559 /*
560 * On Windows 9x IP addresses are strings. Multi-homed hosts have
561 * the IP addresses seperated by commas.
562 */
563 addr = 0;
564 byte = 0;
565 i = 0;
566 while ((DWORD)i < strlen(addresses)+1) {
567 /* eof or seperator */
568 if (addresses[i] == ',' || addresses[i] == 0) {
569 if (addr != 0) {
570 addr = (addr << 8) | byte;
571
572 curr = (netaddr *)malloc(sizeof(netaddr));
573 if (curr == NULL) {
574 JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
575 free_netaddr(netaddrP);
576 RegCloseKey(enumKey);
577 return -1;
578 }
579 curr->addr.him4.sin_family = AF_INET;
580 curr->addr.him4.sin_addr.s_addr = htonl(addr);
581 curr->next = netaddrP;
582
583 netaddrP = curr;
584 addrCount++;
585
586 /* reset the address for the next iteration */
587 addr = 0;
588 }
589 byte = 0;
590 } else {
591 if (addresses[i] == '.') {
592 addr = (addr << 8) | byte;
593 byte = 0;
594 } else {
595 byte = (byte * 10) + (addresses[i] - '0');
596 }
597 }
598 i++;
599 }
600 }
601 }
602 if (addrCount > 0) {
603 break;
604 }
605 dwBindingIndex++;
606 }
607 }
608 RegCloseKey(bindingKey);
609 }
610
611 /* close the registry */
612 RegCloseKey(enumKey);
613
614
615 /* return the list */
616 *netaddrPP = netaddrP;
617 return addrCount;
618}
619
620/*
621 * Windows 9x routine to probe the registry for a DHCP allocated address.
622 * This routine is only useful if we know that only one interface has its
623 * address allocated using DHCP. Returns 0.0.0.0 if none or multiple
624 * addresses found.0
625 */
626static DWORD getDHCPAddress()
627{
628 LONG ret;
629 HKEY hKey;
630 DWORD dwLen;
631 ULONG ulType;
632 char key[MAX_STR_LEN];
633 int index;
634 DWORD dhcp_addr = 0;
635
636 index = 0;
637 while (index < 99) {
638 DWORD addr;
639
640 sprintf(key, "SYSTEM\\CurrentControlSet\\Services\\VxD\\DHCP\\DhcpInfo%02d", index);
641
642 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, (PHKEY)&hKey);
643 if (ret != ERROR_SUCCESS) {
644 return dhcp_addr;
645 }
646
647 /*
648 * On Windows 9x the DHCP address is in the DhcpIPAddress key. We
649 * are assuming here that this is Windows Socket 2. If Windows
650 * Sockets is the original 1.1 release then this doesn't work because
651 * the IP address if in the DhcpInfo key (a blob with the first 4
652 * bytes set to the IP address).
653 */
654 dwLen = sizeof(addr);
655 ret = RegQueryValueEx(hKey, "DhcpIPAddress", NULL, &ulType,
656 (LPBYTE)&addr, &dwLen);
657 RegCloseKey(hKey);
658
659 if (ret == ERROR_SUCCESS) {
660 if (addr) {
661 /* more than 1 DHCP address in registry */
662 if (dhcp_addr) {
663 return 0;
664 }
665 dhcp_addr = htonl(addr);
666 }
667 }
668 index++;
669 }
670
671 /* if we get here it means we've examined 100 registry entries */
672 return 0;
673}
674
675
676/*
677 * Attempt to allocate the remaining addresses on addrList to the adpaters
678 * on adapterList. Returns the number of address remaining.
679 */
680int allocateRemaining(adapter *adapterList, int address_count, netaddr *addrList) {
681 adapter *adapterP = adapterList;
682 adapter *nobindingsP = NULL;
683
684 /*
685 * If all addresses have been assigned there's nothing to do.
686 */
687 if (address_count == 0) {
688 return 0;
689 }
690
691 /*
692 * Determine if there is only one adapter without an address
693 */
694 while (adapterP != NULL) {
695 if (adapterP->addrs == NULL) {
696 if (nobindingsP == NULL) {
697 nobindingsP = adapterP;
698 } else {
699 nobindingsP = NULL;
700 break;
701 }
702 }
703 adapterP = adapterP->next;
704 }
705
706 /*
707 * Found (only one)
708 */
709 if (nobindingsP) {
710 nobindingsP->addrs = addrList;
711 address_count = 0;
712 }
713
714 return address_count;
715}
716
717
718/*
719 * 1. Network adapters are enumerated by traversing through the
720 * HKEY_LOCAL_MACHINE\Enum tree and picking out class "Net" devices.
721 *
722 * 2. Address enumeration starts with the list of IP addresses returned
723 * by SIO_GET_INTERFACE_LIST and then we "allocate" the addresses to
724 * the network adapters enumerated in step 1. Allocation works as
725 * follows :-
726 *
727 * i. Loopback address is assigned to the loopback interface. If there
728 * is one network adapter then all other addresses must be bound
729 * to that adapter.
730 *
731 * ii. Enumerate all static IP addresses using the registry. This allows
732 * us to allocate all static IP address to the corresponding adapter.
733 *
734 * iii. After step ii. if there is one network adapter that has not been
735 * allocated an IP address then we know that the remaining IP addresses
736 * must be bound to this adapter.
737 *
738 * iv. If we get to this step it means we are dealing with a complex
739 * configuration whereby multiple network adapters have their address
740 * configured dynamically (eg: NIC using DHCP plus modem using PPP).
741 * We employ a gross hack based on a crude determination done in step 1.
742 * If there is a DHCP address configured and if one remaining
743 * network adapter that is not a WAN adapter then the DHCP address
744 * must be bound to it.
745 */
746static adapter *loadConfig(JNIEnv *env) {
747 adapter *adapterList;
748 int adapter_count;
749 INTERFACE_INFO interfaceInfo[8];
750 DWORD dwSize;
751 int address_count, i;
752 netaddr *addrList;
753
754 /*
755 * Enumerate the network adapters
756 */
757 adapter_count = getAdapters(env, &adapterList);
758 if (adapter_count < 0) {
759 return NULL;
760 }
761 /* minimum of loopback interface */
762 assert(adapter_count >= 1);
763
764 /*
765 * Enumerate all IP addresses as known to winsock
766 */
767 dwSize = getInterfaceList(env, interfaceInfo, sizeof(interfaceInfo));
768 if (dwSize < 0) {
769 free_adapters(adapterList);
770 return NULL;
771 }
772 address_count = dwSize/sizeof(INTERFACE_INFO);
773
774 /* minimum of loopback address */
775 assert(address_count >= 1);
776
777 /*
778 * Create an address list (addrList) from the INTERFACE_INFO
779 * structure.
780 */
781 addrList = NULL;
782 for (i=0; i<address_count; i++) {
783 netaddr *addrP = (netaddr *)calloc(1, sizeof(netaddr));
784 if (addrP == NULL) {
785 JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
786 free_netaddr(addrList);
787 free(adapterList);
788 return NULL;
789 }
790
791 addrP->addr.him4.sin_family = AF_INET;
792 addrP->addr.him4.sin_addr.s_addr =
793 ((SOCKADDR_IN *)&(interfaceInfo[i].iiAddress))->sin_addr.S_un.S_addr;
794
795 addrP->next = addrList;
796 addrList = addrP;
797 }
798
799
800 /*
801 * First we assign the loopback address to the lo adapter.
802 * If lo is the only adapter then we are done.
803 */
804 {
805 adapter *loopbackAdapter;
806 netaddr *addrP, *prevP;
807
808 /* find the loopback adapter */
809 loopbackAdapter = adapterList;
810 while (strcmp(loopbackAdapter->name, "lo") != 0) {
811 loopbackAdapter = loopbackAdapter->next;
812 }
813 assert(loopbackAdapter != NULL);
814
815 /* find the loopback address and move it to the loopback adapter */
816 addrP = addrList;
817 prevP = NULL;
818 while (addrP != NULL) {
819 if (addrP->addr.him4.sin_addr.s_addr == htonl(0x7f000001)) {
820 loopbackAdapter->addrs = addrP;
821 if (prevP == NULL) {
822 addrList = addrP->next;
823 } else {
824 prevP->next = addrP->next;
825 }
826 loopbackAdapter->addrs->next = NULL;
827 address_count--;
828 break;
829 }
830 prevP = addrP;
831 addrP = addrP->next;
832 }
833 }
834
835
836 /*
837 * Special case. If there's only one network adapter then all remaining
838 * IP addresses must be bound to that adapter.
839 */
840 address_count = allocateRemaining(adapterList, address_count, addrList);
841 if (address_count == 0) {
842 return adapterList;
843 }
844
845 /*
846 * Locate any static IP addresses defined in the registry. Validate the
847 * addresses against the SIO_GET_INTERFACE_LIST (as registry may have
848 * stale settings). If valid we move the addresses from addrList to
849 * the adapter.
850 */
851 {
852 adapter *adapterP;
853
854 adapterP = adapterList;
855 while (adapterP != NULL) {
856 int cnt;
857 netaddr *static_addrP;
858
859 /*
860 * Skip loopback
861 */
862 if (strcmp(adapterP->name, "lo") == 0) {
863 adapterP = adapterP->next;
864 continue;
865 }
866
867 /*
868 * Get the static addresses for this adapter.
869 */
870 cnt = getStaticAddresses(env, adapterP->reg_key, &static_addrP);
871 if (cnt < 0) {
872 free_netaddr(addrList);
873 free(adapterList);
874 return NULL;
875 }
876
877 /*
878 * Validate against the SIO_GET_INTERFACE_LIST.
879 * (avoids stale registry settings).
880 */
881 while (static_addrP != NULL) {
882 netaddr *addrP = addrList;
883 netaddr *prev = NULL;
884
885 while (addrP != NULL) {
886 if (addrP->addr.him4.sin_addr.s_addr == static_addrP->addr.him4.sin_addr.s_addr)
887 break;
888
889 prev = addrP;
890 addrP = addrP->next;
891 }
892
893 /*
894 * if addrP is not NULL it means we have a match
895 * (ie: address from the registry is valid).
896 */
897 if (addrP != NULL) {
898 /* remove from addrList */
899 if (prev == NULL) {
900 addrList = addrP->next;
901 } else {
902 prev->next = addrP->next;
903 }
904 address_count--;
905
906 /* add to adapter list */
907 addrP->next = adapterP->addrs;
908 adapterP->addrs = addrP;
909 }
910
911 /*
912 * On the next static address.
913 */
914 static_addrP = static_addrP->next;
915 }
916
917 /* not needed */
918 free_netaddr(static_addrP);
919
920 adapterP = adapterP->next;
921 }
922 }
923
924
925 /*
926 * Static addresses are now assigned so try again to allocate the
927 * remaining addresses. This will succeed if there is one adapter
928 * with a dynamically assigned address (DHCP or PPP).
929 */
930 address_count = allocateRemaining(adapterList, address_count, addrList);
931 if (address_count == 0) {
932 return adapterList;
933 }
934
935 /*
936 * Next we see if there is a DHCP address in the registry. If there is
937 * an address (and it's valid) then we know it must be bound to a LAN
938 * adapter. Additionally, when we enumerate the network adapters
939 * we made a crude determination on if an adapter is dial-up. Thus if
940 * we know there is one remaining LAN adapter without an IP address
941 * then the DHCP address must be bound to it.
942 */
943 {
944 long dhcp_addr = getDHCPAddress(); /* returns in network order */
945 if (dhcp_addr) {
946 netaddr *addrP, *prevP;
947
948 /*
949 * Check that the DHCP address is valid
950 */
951 addrP = addrList;
952 prevP = NULL;
953 while (addrP != NULL) {
954 if (addrP->addr.him4.sin_addr.s_addr == dhcp_addr) {
955 break;
956 }
957 prevP = addrP;
958 addrP = addrP->next;
959 }
960
961 /*
962 * Address is valid - now check how many non-WAN adapters
963 * don't have addresses yet.
964 */
965 if (addrP != NULL) {
966 adapter *adapterP = adapterList;
967 adapter *nobindingsP = NULL;
968
969 while (adapterP != NULL) {
970 if (adapterP->addrs == NULL && !adapterP->is_wan_driver) {
971 if (nobindingsP == NULL) {
972 nobindingsP = adapterP;
973 } else {
974 /* already found one */
975 nobindingsP = NULL;
976 break;
977 }
978 }
979 adapterP = adapterP->next;
980 }
981
982 /*
983 * One non-WAN adapter remaining
984 */
985 if (nobindingsP != NULL) {
986 nobindingsP->addrs = addrP;
987
988 /* remove from addrList */
989 if (prevP == NULL) {
990 addrList = addrP->next;
991 } else {
992 prevP->next = addrP->next;
993 }
994 addrP->next = NULL;
995 address_count--;
996 }
997 }
998 }
999 }
1000
1001 /*
1002 * Finally we do one final attempt to re-assign any remaining
1003 * addresses. This catches the case of 2 adapters that have their
1004 * addresses dynamically assigned (specifically NIC with DHCP, and
1005 * Modem using RAS/PPP).
1006 */
1007 address_count = allocateRemaining(adapterList, address_count, addrList);
1008 if (address_count == 0) {
1009 return adapterList;
1010 }
1011
1012 /*
1013 * Free any unallocated addresses
1014 */
1015 if (address_count > 0) {
1016 free_netaddr(addrList);
1017 }
1018
1019 /*
1020 * Return the adapter List.
1021 */
1022 return adapterList;
1023
1024}
1025
1026
1027/*
1028 * Enumerate network interfaces. If successful returns the number of
1029 * network interfaces and netifPP returning a list of netif structures.
1030 * Returns -1 with exception thrown if error.
1031 */
1032int enumInterfaces_win9x(JNIEnv *env, netif **netifPP) {
1033 adapter *adapters, *adapterP;
1034 int cnt = 0;
1035 netif *netifP = NULL;
1036
1037 /* enumerate network configuration */
1038 adapters = loadConfig(env);
1039 if (adapters == NULL) {
1040 return -1;
1041 }
1042
1043 /*
1044 * loadConfig returns an adapter list - we need to create a corresponding
1045 * list of netif structures.
1046 */
1047 adapterP = adapters;
1048 while (adapterP != NULL) {
1049 netif *ifs = (netif *)calloc(1, sizeof(netif));
1050
1051 if (ifs == NULL) {
1052 JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
1053 free_adapters(adapters);
1054 free_netif(netifP);
1055 return -1;
1056 }
1057
1058 ifs->name = strdup(adapterP->name);
1059 ifs->displayName = strdup(adapterP->displayName);
1060 ifs->dwIndex = adapterP->index;
1061 ifs->index = adapterP->index;
1062 ifs->next = netifP;
1063 netifP = ifs;
1064
1065 if (ifs->name == NULL || ifs->displayName == NULL) {
1066 JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
1067 free_adapters(adapters);
1068 free_netif(netifP);
1069 return -1;
1070 }
1071
1072 cnt++;
1073 adapterP = adapterP->next;
1074 }
1075
1076 /*
1077 * Put the adapter list in the cache
1078 */
1079 EnterCriticalSection(&cacheLock);
1080 {
1081 if (cachedAdapterList != NULL) {
1082 free_adapters(cachedAdapterList);
1083 }
1084 cachedAdapterList = adapters;
1085 }
1086 LeaveCriticalSection(&cacheLock);
1087
1088 /*
1089 * Return the netif list
1090 */
1091 *netifPP = netifP;
1092 return cnt;
1093}
1094
1095/*
1096 * Enumerate the addresses for the specified network interface. If successful
1097 * returns the number of addresses bound to the interface and sets netaddrPP
1098 * to be a list of netaddr structures. Returns -1 if error.
1099 */
1100int enumAddresses_win9x(JNIEnv *env, netif *netifP, netaddr **netaddrPP) {
1101
1102 EnterCriticalSection(&cacheLock);
1103 {
1104 adapter *adapterP = cachedAdapterList;
1105 while (adapterP != NULL) {
1106 if (strcmp(adapterP->name, netifP->name) == 0) {
1107
1108 netaddr *newlist = NULL;
1109 netaddr *curr = adapterP->addrs;
1110 int cnt = 0;
1111
1112 while (curr != NULL) {
1113 /*
1114 * Clone the netaddr and add it to newlist.
1115 */
1116 netaddr *tmp = (netaddr *)calloc(1, sizeof(netaddr));
1117 if (tmp == NULL) {
1118 LeaveCriticalSection(&cacheLock);
1119 JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
1120 free_netaddr(newlist);
1121 return -1;
1122 }
1123 tmp->addr = curr->addr;
1124 tmp->next = newlist;
1125 newlist = tmp;
1126
1127 cnt++;
1128 curr = curr->next;
1129 }
1130
1131 *netaddrPP = newlist;
1132 LeaveCriticalSection(&cacheLock);
1133 return cnt;
1134 }
1135 adapterP = adapterP->next;
1136 }
1137 }
1138 LeaveCriticalSection(&cacheLock);
1139
1140 *netaddrPP = NULL;
1141 return 0;
1142}