annotate src/windows/native/java/net/NetworkInterface.c @ 8035:353c0eb4aace

7158636: InterfaceAddress.getBroadcast() returns invalid broadcast address on WLAN Summary: Update Windows native code to infer WLAN interface type in Windows Vista and later Reviewed-by: chegar, alanb
author robm
date Thu, 28 Aug 2014 18:01:16 +0100
parents 95eeca6dc691
children f048af4f93eb
rev   line source
duke@0 1 /*
ohair@2486 2 * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
duke@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0 4 *
duke@0 5 * This code is free software; you can redistribute it and/or modify it
duke@0 6 * under the terms of the GNU General Public License version 2 only, as
ohair@2486 7 * published by the Free Software Foundation. Oracle designates this
duke@0 8 * particular file as subject to the "Classpath" exception as provided
ohair@2486 9 * by Oracle in the LICENSE file that accompanied this code.
duke@0 10 *
duke@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@0 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@0 15 * accompanied this code).
duke@0 16 *
duke@0 17 * You should have received a copy of the GNU General Public License version
duke@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0 20 *
ohair@2486 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@2486 22 * or visit www.oracle.com if you need additional information or have any
ohair@2486 23 * questions.
duke@0 24 */
duke@0 25
duke@0 26 #include <stdlib.h>
duke@0 27 #include <windows.h>
duke@0 28 #include <winsock2.h> /* needed for htonl */
duke@0 29 #include <iprtrmib.h>
duke@0 30 #include <assert.h>
duke@0 31
duke@0 32 #include "java_net_NetworkInterface.h"
duke@0 33 #include "jni_util.h"
duke@0 34
duke@0 35 #include "NetworkInterface.h"
duke@0 36
duke@0 37 /*
duke@0 38 * Windows implementation of the java.net.NetworkInterface native methods.
duke@0 39 * This module provides the implementations of getAll, getByName, getByIndex,
duke@0 40 * and getByAddress.
duke@0 41 *
duke@0 42 * Interfaces and addresses are enumerated using the IP helper routines
duke@0 43 * GetIfTable, GetIfAddrTable resp. These routines are available on Windows
duke@0 44 * 98, NT SP+4, 2000, and XP. They are also available on Windows 95 if
duke@0 45 * IE is upgraded to 5.x.
duke@0 46 *
duke@0 47 * Windows does not have any standard for device names so we are forced
duke@0 48 * to use our own convention which is based on the normal Unix naming
duke@0 49 * convention ("lo" for the loopback, eth0, eth1, .. for ethernet devices,
duke@0 50 * tr0, tr1, .. for token ring, and so on). This convention gives us
duke@0 51 * consistency across multiple Windows editions and also consistency with
duke@0 52 * Solaris/Linux device names. Note that we always enumerate in index
duke@0 53 * order and this ensures consistent device number across invocations.
duke@0 54 */
duke@0 55
duke@0 56 /* various JNI ids */
duke@0 57
duke@0 58 jclass ni_class; /* NetworkInterface */
duke@0 59
duke@0 60 jmethodID ni_ctor; /* NetworkInterface() */
duke@0 61
duke@0 62 jfieldID ni_indexID; /* NetworkInterface.index */
duke@0 63 jfieldID ni_addrsID; /* NetworkInterface.addrs */
duke@0 64 jfieldID ni_bindsID; /* NetworkInterface.bindings */
duke@0 65 jfieldID ni_nameID; /* NetworkInterface.name */
duke@0 66 jfieldID ni_displayNameID; /* NetworkInterface.displayName */
duke@0 67 jfieldID ni_childsID; /* NetworkInterface.childs */
duke@0 68 jclass ni_iacls; /* InetAddress */
duke@0 69
duke@0 70 jclass ni_ia4cls; /* Inet4Address */
duke@0 71 jmethodID ni_ia4Ctor; /* Inet4Address() */
duke@0 72
duke@0 73 jclass ni_ia6cls; /* Inet6Address */
duke@0 74 jmethodID ni_ia6ctrID; /* Inet6Address() */
duke@0 75
duke@0 76 jclass ni_ibcls; /* InterfaceAddress */
duke@0 77 jmethodID ni_ibctrID; /* InterfaceAddress() */
duke@0 78 jfieldID ni_ibaddressID; /* InterfaceAddress.address */
duke@0 79 jfieldID ni_ibbroadcastID; /* InterfaceAddress.broadcast */
duke@0 80 jfieldID ni_ibmaskID; /* InterfaceAddress.maskLength */
duke@0 81
duke@0 82 /*
duke@0 83 * Support routines to free netif and netaddr lists
duke@0 84 */
duke@0 85 void free_netif(netif *netifP) {
duke@0 86 netif *curr = netifP;
duke@0 87 while (curr != NULL) {
duke@0 88 if (curr->name != NULL)
duke@0 89 free(curr->name);
duke@0 90 if (curr->displayName != NULL)
duke@0 91 free(curr->displayName);
duke@0 92 if (curr->addrs != NULL)
duke@0 93 free_netaddr (curr->addrs);
duke@0 94 netifP = netifP->next;
duke@0 95 free(curr);
duke@0 96 curr = netifP;
duke@0 97 }
duke@0 98 }
duke@0 99
duke@0 100 void free_netaddr(netaddr *netaddrP) {
duke@0 101 netaddr *curr = netaddrP;
duke@0 102 while (curr != NULL) {
duke@0 103 netaddrP = netaddrP->next;
duke@0 104 free(curr);
duke@0 105 curr = netaddrP;
duke@0 106 }
duke@0 107 }
duke@0 108
duke@0 109 /*
duke@0 110 * Returns the interface structure from the table with the matching index.
duke@0 111 */
duke@0 112 MIB_IFROW *getIF(jint index) {
duke@0 113 MIB_IFTABLE *tableP;
duke@0 114 MIB_IFROW *ifrowP, *ret = NULL;
duke@0 115 ULONG size;
duke@0 116 DWORD i, count;
duke@0 117 jint ifindex;
duke@0 118
duke@0 119 /*
duke@0 120 * Ask the IP Helper library to enumerate the adapters
duke@0 121 */
duke@0 122 size = sizeof(MIB_IFTABLE);
duke@0 123 tableP = (MIB_IFTABLE *)malloc(size);
chegar@4049 124 count = GetIfTable(tableP, &size, TRUE);
duke@0 125 if (count == ERROR_INSUFFICIENT_BUFFER || count == ERROR_BUFFER_OVERFLOW) {
duke@0 126 tableP = (MIB_IFTABLE *)realloc(tableP, size);
chegar@4049 127 count = GetIfTable(tableP, &size, TRUE);
duke@0 128 }
duke@0 129
duke@0 130 if (count != NO_ERROR) {
duke@0 131 if (tableP != NULL)
duke@0 132 free(tableP);
duke@0 133 return NULL;
duke@0 134 }
duke@0 135
duke@0 136 if (tableP != NULL) {
duke@0 137 ifrowP = tableP->table;
duke@0 138 for (i=0; i<tableP->dwNumEntries; i++) {
duke@0 139 /*
duke@0 140 * Warning the real index is obtained by GetFriendlyIfIndex()
duke@0 141 */
chegar@4049 142 ifindex = GetFriendlyIfIndex(ifrowP->dwIndex);
duke@0 143 if (ifindex == index) {
duke@0 144 /*
duke@0 145 * Create a copy of the entry so that we can free the table.
duke@0 146 */
duke@0 147 ret = (MIB_IFROW *) malloc(sizeof(MIB_IFROW));
duke@0 148 memcpy(ret, ifrowP, sizeof(MIB_IFROW));
duke@0 149 break;
duke@0 150 }
duke@0 151
duke@0 152 /* onto the next interface */
duke@0 153 ifrowP++;
duke@0 154 }
duke@0 155 free(tableP);
duke@0 156 }
duke@0 157 return ret;
duke@0 158 }
duke@0 159
duke@0 160 /*
duke@0 161 * Enumerate network interfaces using IP Helper Library routine GetIfTable.
duke@0 162 * We use GetIfTable rather than other IP helper routines because it's
duke@0 163 * available on 98 & NT SP4+.
duke@0 164 *
duke@0 165 * Returns the number of interfaces found or -1 if error. If no error
duke@0 166 * occurs then netifPP be returned as list of netif structures or NULL
duke@0 167 * if no interfaces are found.
duke@0 168 */
chegar@4049 169 int enumInterfaces(JNIEnv *env, netif **netifPP)
duke@0 170 {
duke@0 171 MIB_IFTABLE *tableP;
duke@0 172 MIB_IFROW *ifrowP;
duke@0 173 ULONG size;
duke@0 174 DWORD ret;
duke@0 175 int count;
duke@0 176 netif *netifP;
duke@0 177 DWORD i;
robm@7961 178 int lo=0, eth=0, tr=0, fddi=0, ppp=0, sl=0, wlan=0, net=0, wlen=0;
duke@0 179
duke@0 180 /*
duke@0 181 * Ask the IP Helper library to enumerate the adapters
duke@0 182 */
duke@0 183 size = sizeof(MIB_IFTABLE);
duke@0 184 tableP = (MIB_IFTABLE *)malloc(size);
chegar@4049 185 ret = GetIfTable(tableP, &size, TRUE);
duke@0 186 if (ret == ERROR_INSUFFICIENT_BUFFER || ret == ERROR_BUFFER_OVERFLOW) {
duke@0 187 tableP = (MIB_IFTABLE *)realloc(tableP, size);
chegar@4049 188 ret = GetIfTable(tableP, &size, TRUE);
duke@0 189 }
duke@0 190
duke@0 191 if (ret != NO_ERROR) {
duke@0 192 if (tableP != NULL)
duke@0 193 free(tableP);
duke@0 194
duke@0 195 JNU_ThrowByName(env, "java/lang/Error",
duke@0 196 "IP Helper Library GetIfTable function failed");
duke@0 197
duke@0 198 return -1;
duke@0 199 }
duke@0 200
duke@0 201 /*
duke@0 202 * Iterate through the list of adapters
duke@0 203 */
duke@0 204 count = 0;
duke@0 205 netifP = NULL;
duke@0 206
duke@0 207 ifrowP = tableP->table;
duke@0 208 for (i=0; i<tableP->dwNumEntries; i++) {
duke@0 209 char dev_name[8];
duke@0 210 netif *curr;
duke@0 211
duke@0 212 /*
duke@0 213 * Generate a name for the device as Windows doesn't have any
duke@0 214 * real concept of a device name.
duke@0 215 */
duke@0 216 switch (ifrowP->dwType) {
duke@0 217 case MIB_IF_TYPE_ETHERNET:
robm@7961 218 _snprintf_s(dev_name, 8, _TRUNCATE, "eth%d", eth++);
duke@0 219 break;
duke@0 220
duke@0 221 case MIB_IF_TYPE_TOKENRING:
robm@7961 222 _snprintf_s(dev_name, 8, _TRUNCATE, "tr%d", tr++);
duke@0 223 break;
duke@0 224
duke@0 225 case MIB_IF_TYPE_FDDI:
robm@7961 226 _snprintf_s(dev_name, 8, _TRUNCATE, "fddi%d", fddi++);
duke@0 227 break;
duke@0 228
duke@0 229 case MIB_IF_TYPE_LOOPBACK:
duke@0 230 /* There should only be only IPv4 loopback address */
duke@0 231 if (lo > 0) {
duke@0 232 continue;
duke@0 233 }
robm@7961 234 strncpy_s(dev_name, 8, "lo", _TRUNCATE);
duke@0 235 lo++;
duke@0 236 break;
duke@0 237
duke@0 238 case MIB_IF_TYPE_PPP:
robm@7961 239 _snprintf_s(dev_name, 8, _TRUNCATE, "ppp%d", ppp++);
duke@0 240 break;
duke@0 241
duke@0 242 case MIB_IF_TYPE_SLIP:
robm@7961 243 _snprintf_s(dev_name, 8, _TRUNCATE, "sl%d", sl++);
robm@7961 244 break;
robm@7961 245
robm@7961 246 case IF_TYPE_IEEE80211:
robm@7961 247 _snprintf_s(dev_name, 8, _TRUNCATE, "wlan%d", wlan++);
duke@0 248 break;
duke@0 249
duke@0 250 default:
robm@7961 251 _snprintf_s(dev_name, 8, _TRUNCATE, "net%d", net++);
duke@0 252 }
duke@0 253
duke@0 254 /*
duke@0 255 * Allocate a netif structure and space for the name and
duke@0 256 * display name (description in this case).
duke@0 257 */
duke@0 258 curr = (netif *)calloc(1, sizeof(netif));
duke@0 259 if (curr != NULL) {
dingxmin@6341 260 wlen = MultiByteToWideChar(CP_OEMCP, 0, ifrowP->bDescr,
dingxmin@6341 261 ifrowP->dwDescrLen, NULL, 0);
dingxmin@6341 262 if(wlen == 0) {
dingxmin@6341 263 // MultiByteToWideChar should not fail
dingxmin@6341 264 // But in rare case it fails, we allow 'char' to be displayed
dingxmin@6341 265 curr->displayName = (char *)malloc(ifrowP->dwDescrLen + 1);
dingxmin@6341 266 } else {
dingxmin@6341 267 curr->displayName = (wchar_t *)malloc(wlen*(sizeof(wchar_t))+1);
dingxmin@6341 268 }
dingxmin@6341 269
duke@0 270 curr->name = (char *)malloc(strlen(dev_name) + 1);
duke@0 271
duke@0 272 if (curr->name == NULL || curr->displayName == NULL) {
duke@0 273 if (curr->name) free(curr->name);
duke@0 274 if (curr->displayName) free(curr->displayName);
duke@0 275 curr = NULL;
duke@0 276 }
duke@0 277 }
duke@0 278 if (curr == NULL) {
zhouyx@6218 279 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
duke@0 280 free_netif(netifP);
duke@0 281 free(tableP);
duke@0 282 return -1;
duke@0 283 }
duke@0 284
duke@0 285 /*
duke@0 286 * Populate the interface. Note that we need to convert the
duke@0 287 * index into its "friendly" value as otherwise we will expose
duke@0 288 * 32-bit numbers as index values.
duke@0 289 */
duke@0 290 strcpy(curr->name, dev_name);
dingxmin@6341 291 if (wlen == 0) {
dingxmin@6341 292 // display char type in case of MultiByteToWideChar failure
dingxmin@6341 293 strncpy(curr->displayName, ifrowP->bDescr, ifrowP->dwDescrLen);
dingxmin@6341 294 curr->displayName[ifrowP->dwDescrLen] = '\0';
dingxmin@6341 295 } else {
dingxmin@6341 296 // call MultiByteToWideChar again to fill curr->displayName
dingxmin@6341 297 // it should not fail, because we have called it once before
dingxmin@6341 298 if (MultiByteToWideChar(CP_OEMCP, 0, ifrowP->bDescr,
dingxmin@6341 299 ifrowP->dwDescrLen, curr->displayName, wlen) == 0) {
dingxmin@6341 300 JNU_ThrowByName(env, "java/lang/Error",
dingxmin@6341 301 "Cannot get multibyte char for interface display name");
dingxmin@6341 302 free_netif(netifP);
dingxmin@6341 303 free(tableP);
dingxmin@6341 304 free(curr->name);
dingxmin@6341 305 free(curr->displayName);
dingxmin@6341 306 free(curr);
dingxmin@6341 307 return -1;
dingxmin@6341 308 } else {
dingxmin@6341 309 curr->displayName[wlen*(sizeof(wchar_t))] = '\0';
dingxmin@6341 310 curr->dNameIsUnicode = TRUE;
dingxmin@6341 311 }
dingxmin@6341 312 }
dingxmin@6341 313
duke@0 314 curr->dwIndex = ifrowP->dwIndex;
duke@0 315 curr->ifType = ifrowP->dwType;
chegar@4049 316 curr->index = GetFriendlyIfIndex(ifrowP->dwIndex);
duke@0 317
duke@0 318 /*
duke@0 319 * Put the interface at tail of list as GetIfTable(,,TRUE) is
duke@0 320 * returning the interfaces in index order.
duke@0 321 */
duke@0 322 count++;
duke@0 323 if (netifP == NULL) {
duke@0 324 netifP = curr;
duke@0 325 } else {
duke@0 326 netif *tail = netifP;
duke@0 327 while (tail->next != NULL) {
duke@0 328 tail = tail->next;
duke@0 329 }
duke@0 330 tail->next = curr;
duke@0 331 }
duke@0 332
duke@0 333 /* onto the next interface */
duke@0 334 ifrowP++;
duke@0 335 }
duke@0 336
duke@0 337 /*
duke@0 338 * Free the interface table and return the interface list
duke@0 339 */
duke@0 340 if (tableP) {
duke@0 341 free(tableP);
duke@0 342 }
duke@0 343 *netifPP = netifP;
duke@0 344 return count;
duke@0 345 }
duke@0 346
duke@0 347 /*
duke@0 348 * Enumerate the IP addresses on an interface using the IP helper library
duke@0 349 * routine GetIfAddrTable and matching based on the index name. There are
duke@0 350 * more efficient routines but we use GetIfAddrTable because it's avaliable
duke@0 351 * on 98 and NT.
duke@0 352 *
duke@0 353 * Returns the count of addresses, or -1 if error. If no error occurs then
duke@0 354 * netaddrPP will return a list of netaddr structures with the IP addresses.
duke@0 355 */
duke@0 356 int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP)
duke@0 357 {
duke@0 358 MIB_IPADDRTABLE *tableP;
duke@0 359 ULONG size;
duke@0 360 DWORD ret;
duke@0 361 DWORD i;
duke@0 362 netaddr *netaddrP;
duke@0 363 int count = 0;
duke@0 364 unsigned long mask;
duke@0 365
duke@0 366 /*
duke@0 367 * Use GetIpAddrTable to enumerate the IP Addresses
duke@0 368 */
duke@0 369 size = sizeof(MIB_IPADDRTABLE);
duke@0 370 tableP = (MIB_IPADDRTABLE *)malloc(size);
duke@0 371
chegar@4049 372 ret = GetIpAddrTable(tableP, &size, FALSE);
duke@0 373 if (ret == ERROR_INSUFFICIENT_BUFFER || ret == ERROR_BUFFER_OVERFLOW) {
duke@0 374 tableP = (MIB_IPADDRTABLE *)realloc(tableP, size);
chegar@4049 375 ret = GetIpAddrTable(tableP, &size, FALSE);
duke@0 376 }
duke@0 377 if (ret != NO_ERROR) {
duke@0 378 if (tableP) {
duke@0 379 free(tableP);
duke@0 380 }
duke@0 381 JNU_ThrowByName(env, "java/lang/Error",
duke@0 382 "IP Helper Library GetIpAddrTable function failed");
duke@0 383 return -1;
duke@0 384 }
duke@0 385
duke@0 386 /*
duke@0 387 * Iterate through the table to find the addresses with the
duke@0 388 * matching dwIndex. Ignore 0.0.0.0 addresses.
duke@0 389 */
duke@0 390 count = 0;
duke@0 391 netaddrP = NULL;
duke@0 392
duke@0 393 i = 0;
duke@0 394 while (i<tableP->dwNumEntries) {
duke@0 395 if (tableP->table[i].dwIndex == netifP->dwIndex &&
duke@0 396 tableP->table[i].dwAddr != 0) {
duke@0 397
duke@0 398 netaddr *curr = (netaddr *)malloc(sizeof(netaddr));
duke@0 399 if (curr == NULL) {
zhouyx@6218 400 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
duke@0 401 free_netaddr(netaddrP);
duke@0 402 free(tableP);
duke@0 403 return -1;
duke@0 404 }
duke@0 405
duke@0 406 curr->addr.him4.sin_family = AF_INET;
duke@0 407 curr->addr.him4.sin_addr.s_addr = tableP->table[i].dwAddr;
duke@0 408 /*
duke@0 409 * Get netmask / broadcast address
duke@0 410 */
duke@0 411 switch (netifP->ifType) {
duke@0 412 case MIB_IF_TYPE_ETHERNET:
duke@0 413 case MIB_IF_TYPE_TOKENRING:
duke@0 414 case MIB_IF_TYPE_FDDI:
duke@0 415 case MIB_IF_TYPE_LOOPBACK:
robm@7961 416 case IF_TYPE_IEEE80211:
duke@0 417 /**
duke@0 418 * Contrary to what it seems to indicate, dwBCastAddr doesn't
duke@0 419 * contain the broadcast address but 0 or 1 depending on whether
duke@0 420 * the broadcast address should set the bits of the host part
duke@0 421 * to 0 or 1.
duke@0 422 * Yes, I know it's stupid, but what can I say, it's MSFTs API.
duke@0 423 */
duke@0 424 curr->brdcast.him4.sin_family = AF_INET;
duke@0 425 if (tableP->table[i].dwBCastAddr == 1)
duke@0 426 curr->brdcast.him4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask) | (0xffffffff ^ tableP->table[i].dwMask);
duke@0 427 else
duke@0 428 curr->brdcast.him4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask);
duke@0 429 mask = ntohl(tableP->table[i].dwMask);
duke@0 430 curr->mask = 0;
duke@0 431 while (mask) {
duke@0 432 mask <<= 1;
duke@0 433 curr->mask++;
duke@0 434 }
duke@0 435 break;
duke@0 436 case MIB_IF_TYPE_PPP:
duke@0 437 case MIB_IF_TYPE_SLIP:
duke@0 438 default:
duke@0 439 /**
duke@0 440 * these don't have broadcast/subnet
duke@0 441 */
duke@0 442 curr->mask = -1;
duke@0 443 break;
duke@0 444 }
duke@0 445
duke@0 446 curr->next = netaddrP;
duke@0 447 netaddrP = curr;
duke@0 448 count++;
duke@0 449 }
duke@0 450 i++;
duke@0 451 }
duke@0 452
duke@0 453 *netaddrPP = netaddrP;
duke@0 454 free(tableP);
duke@0 455 return count;
duke@0 456 }
duke@0 457
duke@0 458 /*
duke@0 459 * Class: java_net_NetworkInterface
duke@0 460 * Method: init
duke@0 461 * Signature: ()V
duke@0 462 */
duke@0 463 JNIEXPORT void JNICALL
duke@0 464 Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls)
duke@0 465 {
duke@0 466 /*
duke@0 467 * Get the various JNI ids that we require
duke@0 468 */
duke@0 469 ni_class = (*env)->NewGlobalRef(env, cls);
duke@0 470 ni_nameID = (*env)->GetFieldID(env, ni_class, "name", "Ljava/lang/String;");
duke@0 471 ni_displayNameID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;");
duke@0 472 ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
duke@0 473 ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;");
duke@0 474 ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;");
duke@0 475 ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;");
duke@0 476 ni_ctor = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
duke@0 477
chegar@514 478 ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
duke@0 479 ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
duke@0 480
chegar@514 481 ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
duke@0 482 ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
duke@0 483 ni_ia4Ctor = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
duke@0 484
duke@0 485 ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address");
duke@0 486 ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls);
duke@0 487 ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V");
duke@0 488
duke@0 489 ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
duke@0 490 ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
duke@0 491 ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
duke@0 492 ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;");
duke@0 493 ni_ibbroadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;");
duke@0 494 ni_ibmaskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
duke@0 495
duke@0 496 }
duke@0 497
duke@0 498 /*
duke@0 499 * Create a NetworkInterface object, populate the name and index, and
duke@0 500 * populate the InetAddress array based on the IP addresses for this
duke@0 501 * interface.
duke@0 502 */
chegar@4049 503 jobject createNetworkInterface
chegar@4049 504 (JNIEnv *env, netif *ifs, int netaddrCount, netaddr *netaddrP)
duke@0 505 {
duke@0 506 jobject netifObj;
duke@0 507 jobject name, displayName;
duke@0 508 jobjectArray addrArr, bindsArr, childArr;
duke@0 509 netaddr *addrs;
duke@0 510 jint addr_index;
duke@0 511 jint bind_index;
duke@0 512
duke@0 513 /*
duke@0 514 * Create a NetworkInterface object and populate it
duke@0 515 */
duke@0 516 netifObj = (*env)->NewObject(env, ni_class, ni_ctor);
duke@0 517 name = (*env)->NewStringUTF(env, ifs->name);
duke@0 518 if (ifs->dNameIsUnicode) {
chegar@4049 519 displayName = (*env)->NewString(env, (PWCHAR)ifs->displayName,
chegar@4049 520 (jsize)wcslen ((PWCHAR)ifs->displayName));
duke@0 521 } else {
duke@0 522 displayName = (*env)->NewStringUTF(env, ifs->displayName);
duke@0 523 }
duke@0 524 if (netifObj == NULL || name == NULL || displayName == NULL) {
duke@0 525 return NULL;
duke@0 526 }
duke@0 527 (*env)->SetObjectField(env, netifObj, ni_nameID, name);
duke@0 528 (*env)->SetObjectField(env, netifObj, ni_displayNameID, displayName);
duke@0 529 (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
duke@0 530
duke@0 531 /*
duke@0 532 * Get the IP addresses for this interface if necessary
duke@0 533 * Note that 0 is a valid number of addresses.
duke@0 534 */
duke@0 535 if (netaddrCount < 0) {
chegar@4049 536 netaddrCount = enumAddresses_win(env, ifs, &netaddrP);
luchsh@6070 537 if (netaddrCount == -1) {
duke@0 538 return NULL;
duke@0 539 }
duke@0 540 }
duke@0 541 addrArr = (*env)->NewObjectArray(env, netaddrCount, ni_iacls, NULL);
duke@0 542 if (addrArr == NULL) {
duke@0 543 free_netaddr(netaddrP);
duke@0 544 return NULL;
duke@0 545 }
duke@0 546
duke@0 547 bindsArr = (*env)->NewObjectArray(env, netaddrCount, ni_ibcls, NULL);
duke@0 548 if (bindsArr == NULL) {
duke@0 549 free_netaddr(netaddrP);
duke@0 550 return NULL;
duke@0 551 }
duke@0 552 addrs = netaddrP;
duke@0 553 addr_index = 0;
duke@0 554 bind_index = 0;
duke@0 555 while (addrs != NULL) {
duke@0 556 jobject iaObj, ia2Obj;
duke@0 557 jobject ibObj = NULL;
duke@0 558 if (addrs->addr.him.sa_family == AF_INET) {
duke@0 559 iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4Ctor);
duke@0 560 if (iaObj == NULL) {
duke@0 561 free_netaddr(netaddrP);
duke@0 562 return NULL;
duke@0 563 }
duke@0 564 /* default ctor will set family to AF_INET */
duke@0 565
michaelm@5642 566 setInetAddress_addr(env, iaObj, ntohl(addrs->addr.him4.sin_addr.s_addr));
duke@0 567 if (addrs->mask != -1) {
duke@0 568 ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
duke@0 569 if (ibObj == NULL) {
duke@0 570 free_netaddr(netaddrP);
duke@0 571 return NULL;
duke@0 572 }
duke@0 573 (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
duke@0 574 ia2Obj = (*env)->NewObject(env, ni_ia4cls, ni_ia4Ctor);
duke@0 575 if (ia2Obj == NULL) {
duke@0 576 free_netaddr(netaddrP);
duke@0 577 return NULL;
duke@0 578 }
michaelm@5642 579 setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.him4.sin_addr.s_addr));
duke@0 580 (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj);
duke@0 581 (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
duke@0 582 (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
duke@0 583 }
duke@0 584 } else /* AF_INET6 */ {
duke@0 585 int scope;
duke@0 586 iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
duke@0 587 if (iaObj) {
michaelm@6791 588 int ret = setInet6Address_ipaddress(env, iaObj, (jbyte *)&(addrs->addr.him6.sin6_addr.s6_addr));
michaelm@6791 589 if (ret == JNI_FALSE) {
duke@0 590 return NULL;
duke@0 591 }
michaelm@6791 592
duke@0 593 scope = addrs->addr.him6.sin6_scope_id;
duke@0 594 if (scope != 0) { /* zero is default value, no need to set */
michaelm@6791 595 setInet6Address_scopeid(env, iaObj, scope);
michaelm@6791 596 setInet6Address_scopeifname(env, iaObj, netifObj);
duke@0 597 }
duke@0 598 ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
duke@0 599 if (ibObj == NULL) {
duke@0 600 free_netaddr(netaddrP);
duke@0 601 return NULL;
duke@0 602 }
duke@0 603 (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
duke@0 604 (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
duke@0 605 (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
duke@0 606 }
duke@0 607 }
duke@0 608 (*env)->SetObjectArrayElement(env, addrArr, addr_index, iaObj);
duke@0 609 addrs = addrs->next;
duke@0 610 addr_index++;
duke@0 611 }
duke@0 612 (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
duke@0 613 (*env)->SetObjectField(env, netifObj, ni_bindsID, bindsArr);
duke@0 614
duke@0 615 free_netaddr(netaddrP);
duke@0 616
duke@0 617 /*
duke@0 618 * Windows doesn't have virtual interfaces, so child array
duke@0 619 * is always empty.
duke@0 620 */
duke@0 621 childArr = (*env)->NewObjectArray(env, 0, ni_class, NULL);
duke@0 622 if (childArr == NULL) {
duke@0 623 return NULL;
duke@0 624 }
duke@0 625 (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
duke@0 626
duke@0 627 /* return the NetworkInterface */
duke@0 628 return netifObj;
duke@0 629 }
duke@0 630
duke@0 631 /*
duke@0 632 * Class: java_net_NetworkInterface
duke@0 633 * Method: getByName0
duke@0 634 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
duke@0 635 */
duke@0 636 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0
duke@0 637 (JNIEnv *env, jclass cls, jstring name)
duke@0 638 {
duke@0 639 netif *ifList, *curr;
duke@0 640 jboolean isCopy;
duke@0 641 const char *name_utf;
duke@0 642 jobject netifObj = NULL;
duke@0 643
chegar@4049 644 // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
chegar@4049 645 if (ipv6_available()) {
duke@0 646 return Java_java_net_NetworkInterface_getByName0_XP (env, cls, name);
duke@0 647 }
duke@0 648
duke@0 649 /* get the list of interfaces */
chegar@4049 650 if (enumInterfaces(env, &ifList) < 0) {
duke@0 651 return NULL;
duke@0 652 }
duke@0 653
duke@0 654 /* get the name as a C string */
duke@0 655 name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
duke@0 656
duke@0 657 /* Search by name */
duke@0 658 curr = ifList;
duke@0 659 while (curr != NULL) {
duke@0 660 if (strcmp(name_utf, curr->name) == 0) {
duke@0 661 break;
duke@0 662 }
duke@0 663 curr = curr->next;
duke@0 664 }
duke@0 665
duke@0 666 /* if found create a NetworkInterface */
duke@0 667 if (curr != NULL) {;
duke@0 668 netifObj = createNetworkInterface(env, curr, -1, NULL);
duke@0 669 }
duke@0 670
duke@0 671 /* release the UTF string */
duke@0 672 (*env)->ReleaseStringUTFChars(env, name, name_utf);
duke@0 673
duke@0 674 /* release the interface list */
duke@0 675 free_netif(ifList);
duke@0 676
duke@0 677 return netifObj;
duke@0 678 }
duke@0 679
duke@0 680 /*
duke@0 681 * Class: NetworkInterface
jccollet@517 682 * Method: getByIndex0
duke@0 683 * Signature: (I)LNetworkInterface;
duke@0 684 */
jccollet@517 685 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0
duke@0 686 (JNIEnv *env, jclass cls, jint index)
duke@0 687 {
duke@0 688 netif *ifList, *curr;
duke@0 689 jobject netifObj = NULL;
duke@0 690
chegar@4049 691 // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
chegar@4049 692 if (ipv6_available()) {
jccollet@517 693 return Java_java_net_NetworkInterface_getByIndex0_XP (env, cls, index);
duke@0 694 }
duke@0 695
duke@0 696 /* get the list of interfaces */
chegar@4049 697 if (enumInterfaces(env, &ifList) < 0) {
duke@0 698 return NULL;
duke@0 699 }
duke@0 700
duke@0 701 /* search by index */
duke@0 702 curr = ifList;
duke@0 703 while (curr != NULL) {
duke@0 704 if (index == curr->index) {
duke@0 705 break;
duke@0 706 }
duke@0 707 curr = curr->next;
duke@0 708 }
duke@0 709
duke@0 710 /* if found create a NetworkInterface */
duke@0 711 if (curr != NULL) {
duke@0 712 netifObj = createNetworkInterface(env, curr, -1, NULL);
duke@0 713 }
duke@0 714
duke@0 715 /* release the interface list */
duke@0 716 free_netif(ifList);
duke@0 717
duke@0 718 return netifObj;
duke@0 719 }
duke@0 720
duke@0 721 /*
duke@0 722 * Class: java_net_NetworkInterface
duke@0 723 * Method: getByInetAddress0
duke@0 724 * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
duke@0 725 */
duke@0 726 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
duke@0 727 (JNIEnv *env, jclass cls, jobject iaObj)
duke@0 728 {
duke@0 729 netif *ifList, *curr;
michaelm@5642 730 jint addr = getInetAddress_addr(env, iaObj);
duke@0 731 jobject netifObj = NULL;
duke@0 732
chegar@4049 733 // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
chegar@4049 734 if (ipv6_available()) {
duke@0 735 return Java_java_net_NetworkInterface_getByInetAddress0_XP (env, cls, iaObj);
duke@0 736 }
duke@0 737
duke@0 738 /* get the list of interfaces */
chegar@4049 739 if (enumInterfaces(env, &ifList) < 0) {
duke@0 740 return NULL;
duke@0 741 }
duke@0 742
duke@0 743 /*
duke@0 744 * Enumerate the addresses on each interface until we find a
duke@0 745 * matching address.
duke@0 746 */
duke@0 747 curr = ifList;
duke@0 748 while (curr != NULL) {
duke@0 749 int count;
duke@0 750 netaddr *addrList;
duke@0 751 netaddr *addrP;
duke@0 752
duke@0 753 /* enumerate the addresses on this interface */
chegar@4049 754 count = enumAddresses_win(env, curr, &addrList);
duke@0 755 if (count < 0) {
duke@0 756 free_netif(ifList);
duke@0 757 return NULL;
duke@0 758 }
duke@0 759
duke@0 760 /* iterate through each address */
duke@0 761 addrP = addrList;
duke@0 762
duke@0 763 while (addrP != NULL) {
duke@0 764 if ((unsigned long)addr == ntohl(addrP->addr.him4.sin_addr.s_addr)) {
duke@0 765 break;
duke@0 766 }
duke@0 767 addrP = addrP->next;
duke@0 768 }
duke@0 769
duke@0 770 /*
duke@0 771 * Address matched so create NetworkInterface for this interface
duke@0 772 * and address list.
duke@0 773 */
duke@0 774 if (addrP != NULL) {
duke@0 775 /* createNetworkInterface will free addrList */
duke@0 776 netifObj = createNetworkInterface(env, curr, count, addrList);
duke@0 777 break;
duke@0 778 }
duke@0 779
duke@0 780 /* on next interface */
duke@0 781 curr = curr->next;
duke@0 782 }
duke@0 783
duke@0 784 /* release the interface list */
duke@0 785 free_netif(ifList);
duke@0 786
duke@0 787 return netifObj;
duke@0 788 }
duke@0 789
duke@0 790 /*
duke@0 791 * Class: java_net_NetworkInterface
duke@0 792 * Method: getAll
duke@0 793 * Signature: ()[Ljava/net/NetworkInterface;
duke@0 794 */
duke@0 795 JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll
duke@0 796 (JNIEnv *env, jclass cls)
duke@0 797 {
duke@0 798 int count;
duke@0 799 netif *ifList, *curr;
duke@0 800 jobjectArray netIFArr;
duke@0 801 jint arr_index;
duke@0 802
chegar@4049 803 // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
chegar@4049 804 if (ipv6_available()) {
duke@0 805 return Java_java_net_NetworkInterface_getAll_XP (env, cls);
duke@0 806 }
duke@0 807
duke@0 808 /*
duke@0 809 * Get list of interfaces
duke@0 810 */
chegar@4049 811 count = enumInterfaces(env, &ifList);
duke@0 812 if (count < 0) {
duke@0 813 return NULL;
duke@0 814 }
duke@0 815
duke@0 816 /* allocate a NetworkInterface array */
duke@0 817 netIFArr = (*env)->NewObjectArray(env, count, cls, NULL);
duke@0 818 if (netIFArr == NULL) {
duke@0 819 return NULL;
duke@0 820 }
duke@0 821
duke@0 822 /*
duke@0 823 * Iterate through the interfaces, create a NetworkInterface instance
duke@0 824 * for each array element and populate the object.
duke@0 825 */
duke@0 826 curr = ifList;
duke@0 827 arr_index = 0;
duke@0 828 while (curr != NULL) {
duke@0 829 jobject netifObj;
duke@0 830
duke@0 831 netifObj = createNetworkInterface(env, curr, -1, NULL);
duke@0 832 if (netifObj == NULL) {
duke@0 833 return NULL;
duke@0 834 }
duke@0 835
duke@0 836 /* put the NetworkInterface into the array */
duke@0 837 (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
duke@0 838
duke@0 839 curr = curr->next;
duke@0 840 }
duke@0 841
duke@0 842 /* release the interface list */
duke@0 843 free_netif(ifList);
duke@0 844
duke@0 845 return netIFArr;
duke@0 846 }
duke@0 847
duke@0 848 /*
duke@0 849 * Class: java_net_NetworkInterface
duke@0 850 * Method: isUp0
duke@0 851 * Signature: (Ljava/lang/String;)Z
duke@0 852 */
duke@0 853 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0
duke@0 854 (JNIEnv *env, jclass cls, jstring name, jint index) {
duke@0 855 jboolean ret = JNI_FALSE;
duke@0 856
chegar@4049 857 // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
chegar@4049 858 if (ipv6_available()) {
duke@0 859 return Java_java_net_NetworkInterface_isUp0_XP(env, cls, name, index);
duke@0 860 } else {
duke@0 861 MIB_IFROW *ifRowP;
duke@0 862 ifRowP = getIF(index);
duke@0 863 if (ifRowP != NULL) {
chegar@4049 864 ret = ifRowP->dwAdminStatus == 1 &&
chegar@4049 865 (ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL ||
chegar@4049 866 ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED);
duke@0 867 free(ifRowP);
duke@0 868 }
duke@0 869 }
duke@0 870 return ret;
duke@0 871 }
duke@0 872
duke@0 873 /*
duke@0 874 * Class: java_net_NetworkInterface
duke@0 875 * Method: isP2P0
duke@0 876 * Signature: (Ljava/lang/String;I)Z
duke@0 877 */
chegar@4049 878 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0
chegar@4049 879 (JNIEnv *env, jclass cls, jstring name, jint index) {
duke@0 880 MIB_IFROW *ifRowP;
duke@0 881 jboolean ret = JNI_FALSE;
duke@0 882
chegar@4049 883 // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
chegar@4049 884 if (ipv6_available()) {
duke@0 885 return Java_java_net_NetworkInterface_isP2P0_XP(env, cls, name, index);
duke@0 886 } else {
duke@0 887 ifRowP = getIF(index);
duke@0 888 if (ifRowP != NULL) {
duke@0 889 switch(ifRowP->dwType) {
duke@0 890 case MIB_IF_TYPE_PPP:
duke@0 891 case MIB_IF_TYPE_SLIP:
duke@0 892 ret = JNI_TRUE;
duke@0 893 break;
duke@0 894 }
duke@0 895 free(ifRowP);
duke@0 896 }
duke@0 897 }
duke@0 898 return ret;
duke@0 899 }
duke@0 900
duke@0 901 /*
duke@0 902 * Class: java_net_NetworkInterface
duke@0 903 * Method: isLoopback0
duke@0 904 * Signature: (Ljava/lang/String;I)Z
duke@0 905 */
duke@0 906 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0
duke@0 907 (JNIEnv *env, jclass cls, jstring name, jint index) {
duke@0 908 MIB_IFROW *ifRowP;
duke@0 909 jboolean ret = JNI_FALSE;
duke@0 910
chegar@4049 911 // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
chegar@4049 912 if (ipv6_available()) {
duke@0 913 return Java_java_net_NetworkInterface_isLoopback0_XP(env, cls, name, index);
duke@0 914 } else {
duke@0 915 ifRowP = getIF(index);
duke@0 916 if (ifRowP != NULL) {
duke@0 917 if (ifRowP->dwType == MIB_IF_TYPE_LOOPBACK)
duke@0 918 ret = JNI_TRUE;
duke@0 919 free(ifRowP);
duke@0 920 }
duke@0 921 return ret;
duke@0 922 }
duke@0 923 }
duke@0 924
duke@0 925 /*
duke@0 926 * Class: java_net_NetworkInterface
duke@0 927 * Method: supportsMulticast0
duke@0 928 * Signature: (Ljava/lang/String;I)Z
duke@0 929 */
duke@0 930 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0
duke@0 931 (JNIEnv *env, jclass cls, jstring name, jint index) {
chegar@4049 932 return Java_java_net_NetworkInterface_supportsMulticast0_XP(env, cls,
duke@0 933 name, index);
duke@0 934 }
duke@0 935
duke@0 936 /*
duke@0 937 * Class: java_net_NetworkInterface
duke@0 938 * Method: getMacAddr0
duke@0 939 * Signature: ([bLjava/lang/String;I)[b
duke@0 940 */
chegar@4049 941 JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0
chegar@4049 942 (JNIEnv *env, jclass class, jbyteArray addrArray, jstring name, jint index) {
duke@0 943 jbyteArray ret = NULL;
duke@0 944 int len;
duke@0 945 MIB_IFROW *ifRowP;
duke@0 946
chegar@4049 947 // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
chegar@4049 948 if (ipv6_available()) {
duke@0 949 return Java_java_net_NetworkInterface_getMacAddr0_XP(env, class, name, index);
duke@0 950 } else {
duke@0 951 ifRowP = getIF(index);
duke@0 952 if (ifRowP != NULL) {
duke@0 953 switch(ifRowP->dwType) {
duke@0 954 case MIB_IF_TYPE_ETHERNET:
duke@0 955 case MIB_IF_TYPE_TOKENRING:
duke@0 956 case MIB_IF_TYPE_FDDI:
robm@7961 957 case IF_TYPE_IEEE80211:
duke@0 958 len = ifRowP->dwPhysAddrLen;
duke@0 959 ret = (*env)->NewByteArray(env, len);
duke@0 960 if (!IS_NULL(ret)) {
duke@0 961 (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr);
duke@0 962 }
duke@0 963 break;
duke@0 964 }
duke@0 965 free(ifRowP);
duke@0 966 }
duke@0 967 return ret;
duke@0 968 }
duke@0 969 }
duke@0 970
duke@0 971 /*
duke@0 972 * Class: java_net_NetworkInterface
duke@0 973 * Method: getMTU0
duke@0 974 * Signature: ([bLjava/lang/String;I)I
duke@0 975 */
chegar@4049 976 JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0
chegar@4049 977 (JNIEnv *env, jclass class, jstring name, jint index) {
duke@0 978 jint ret = -1;
duke@0 979 MIB_IFROW *ifRowP;
duke@0 980
chegar@4049 981 // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
chegar@4049 982 if (ipv6_available()) {
duke@0 983 return Java_java_net_NetworkInterface_getMTU0_XP(env, class, name, index);
duke@0 984 } else {
duke@0 985 ifRowP = getIF(index);
duke@0 986 if (ifRowP != NULL) {
duke@0 987 ret = ifRowP->dwMtu;
duke@0 988 free(ifRowP);
duke@0 989 }
duke@0 990 return ret;
duke@0 991 }
duke@0 992 }