Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

inet.c

Go to the documentation of this file.
00001 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
00002 /*
00003  * Copyright (c) 1994, 1995, 1996, 1997, 1998
00004  *  The Regents of the University of California.  All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *  This product includes software developed by the Computer Systems
00017  *  Engineering Group at Lawrence Berkeley Laboratory.
00018  * 4. Neither the name of the University nor of the Laboratory may be used
00019  *    to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  */
00034 
00035 #ifndef lint
00036 static const char rcsid[] _U_ =
00037     "@(#) $Header: /tcpdump/master/libpcap/inet.c,v 1.59 2003/11/15 23:24:00 guy Exp $ (LBL)";
00038 #endif
00039 
00040 #ifdef HAVE_CONFIG_H
00041 #include "config.h"
00042 #endif
00043 
00044 #ifdef WIN32
00045 #include <pcap-stdinc.h>
00046 #else /* WIN32 */
00047 
00048 #include <sys/param.h>
00049 #include <sys/file.h>
00050 #include <sys/ioctl.h>
00051 #include <sys/socket.h>
00052 #ifdef HAVE_SYS_SOCKIO_H
00053 #include <sys/sockio.h>
00054 #endif
00055 #include <sys/time.h>               /* concession to AIX */
00056 
00057 struct mbuf;        /* Squelch compiler warnings on some platforms for */
00058 struct rtentry;     /* declarations in <net/if.h> */
00059 #include <net/if.h>
00060 #include <netinet/in.h>
00061 #endif /* WIN32 */
00062 
00063 #include <ctype.h>
00064 #include <errno.h>
00065 #include <memory.h>
00066 #include <stdio.h>
00067 #include <stdlib.h>
00068 #include <string.h>
00069 #ifndef WIN32
00070 #include <unistd.h>
00071 #endif /* WIN32 */
00072 #ifdef HAVE_LIMITS_H
00073 #include <limits.h>
00074 #else
00075 #define INT_MAX     2147483647
00076 #endif
00077 #ifdef HAVE_IFADDRS_H
00078 #include <ifaddrs.h>
00079 #endif
00080 
00081 #include "pcap-int.h"
00082 
00083 #ifdef HAVE_OS_PROTO_H
00084 #include "os-proto.h"
00085 #endif
00086 
00087 /* Not all systems have IFF_LOOPBACK */
00088 #ifdef IFF_LOOPBACK
00089 #define ISLOOPBACK(name, flags) ((flags) & IFF_LOOPBACK)
00090 #else
00091 #define ISLOOPBACK(name, flags) ((name)[0] == 'l' && (name)[1] == 'o' && \
00092     (isdigit((unsigned char)((name)[2])) || (name)[2] == '\0'))
00093 #endif
00094 
00095 struct sockaddr *
00096 dup_sockaddr(struct sockaddr *sa, size_t sa_length)
00097 {
00098     struct sockaddr *newsa;
00099 
00100     if ((newsa = malloc(sa_length)) == NULL)
00101         return (NULL);
00102     return (memcpy(newsa, sa, sa_length));
00103 }
00104 
00105 static int
00106 get_instance(const char *name)
00107 {
00108     const char *cp, *endcp;
00109     int n;
00110 
00111     if (strcmp(name, "any") == 0) {
00112         /*
00113          * Give the "any" device an artificially high instance
00114          * number, so it shows up after all other non-loopback
00115          * interfaces.
00116          */
00117         return INT_MAX;
00118     }
00119 
00120     endcp = name + strlen(name);
00121     for (cp = name; cp < endcp && !isdigit((unsigned char)*cp); ++cp)
00122         continue;
00123 
00124     if (isdigit((unsigned char)*cp))
00125         n = atoi(cp);
00126     else
00127         n = 0;
00128     return (n);
00129 }
00130 
00131 int
00132 add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name,
00133     u_int flags, const char *description, char *errbuf)
00134 {
00135     pcap_if_t *curdev, *prevdev, *nextdev;
00136     int this_instance;
00137 
00138     /*
00139      * Is there already an entry in the list for this interface?
00140      */
00141     for (curdev = *alldevs; curdev != NULL; curdev = curdev->next) {
00142         if (strcmp(name, curdev->name) == 0)
00143             break;  /* yes, we found it */
00144     }
00145     if (curdev == NULL) {
00146         /*
00147          * No, we didn't find it.
00148          * Allocate a new entry.
00149          */
00150         curdev = malloc(sizeof(pcap_if_t));
00151         if (curdev == NULL) {
00152             (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
00153                 "malloc: %s", pcap_strerror(errno));
00154             return (-1);
00155         }
00156 
00157         /*
00158          * Fill in the entry.
00159          */
00160         curdev->next = NULL;
00161         curdev->name = malloc(strlen(name) + 1);
00162         strcpy(curdev->name, name);
00163         if (description != NULL) {
00164             /*
00165              * We have a description for this interface.
00166              */
00167             curdev->description = malloc(strlen(description) + 1);
00168             strcpy(curdev->description, description);
00169         } else {
00170             /*
00171              * We don't.
00172              */
00173             curdev->description = NULL;
00174         }
00175         curdev->addresses = NULL;   /* list starts out as empty */
00176         curdev->flags = 0;
00177         if (ISLOOPBACK(name, flags))
00178             curdev->flags |= PCAP_IF_LOOPBACK;
00179 
00180         /*
00181          * Add it to the list, in the appropriate location.
00182          * First, get the instance number of this interface.
00183          */
00184         this_instance = get_instance(name);
00185 
00186         /*
00187          * Now look for the last interface with an instance number
00188          * less than or equal to the new interface's instance
00189          * number - except that non-loopback interfaces are
00190          * arbitrarily treated as having interface numbers less
00191          * than those of loopback interfaces, so the loopback
00192          * interfaces are put at the end of the list.
00193          *
00194          * We start with "prevdev" being NULL, meaning we're before
00195          * the first element in the list.
00196          */
00197         prevdev = NULL;
00198         for (;;) {
00199             /*
00200              * Get the interface after this one.
00201              */
00202             if (prevdev == NULL) {
00203                 /*
00204                  * The next element is the first element.
00205                  */
00206                 nextdev = *alldevs;
00207             } else
00208                 nextdev = prevdev->next;
00209 
00210             /*
00211              * Are we at the end of the list?
00212              */
00213             if (nextdev == NULL) {
00214                 /*
00215                  * Yes - we have to put the new entry
00216                  * after "prevdev".
00217                  */
00218                 break;
00219             }
00220 
00221             /*
00222              * Is the new interface a non-loopback interface
00223              * and the next interface a loopback interface?
00224              */
00225             if (!(curdev->flags & PCAP_IF_LOOPBACK) &&
00226                 (nextdev->flags & PCAP_IF_LOOPBACK)) {
00227                 /*
00228                  * Yes, we should put the new entry
00229                  * before "nextdev", i.e. after "prevdev".
00230                  */
00231                 break;
00232             }
00233 
00234             /*
00235              * Is the new interface's instance number less
00236              * than the next interface's instance number,
00237              * and is it the case that the new interface is a
00238              * non-loopback interface or the next interface is
00239              * a loopback interface?
00240              *
00241              * (The goal of both loopback tests is to make
00242              * sure that we never put a loopback interface
00243              * before any non-loopback interface and that we
00244              * always put a non-loopback interface before all
00245              * loopback interfaces.)
00246              */
00247             if (this_instance < get_instance(nextdev->name) &&
00248                 (!(curdev->flags & PCAP_IF_LOOPBACK) ||
00249                    (nextdev->flags & PCAP_IF_LOOPBACK))) {
00250                 /*
00251                  * Yes - we should put the new entry
00252                  * before "nextdev", i.e. after "prevdev".
00253                  */
00254                 break;
00255             }
00256 
00257             prevdev = nextdev;
00258         }
00259 
00260         /*
00261          * Insert before "nextdev".
00262          */
00263         curdev->next = nextdev;
00264 
00265         /*
00266          * Insert after "prevdev" - unless "prevdev" is null,
00267          * in which case this is the first interface.
00268          */
00269         if (prevdev == NULL) {
00270             /*
00271              * This is the first interface.  Pass back a
00272              * pointer to it, and put "curdev" before
00273              * "nextdev".
00274              */
00275             *alldevs = curdev;
00276         } else
00277             prevdev->next = curdev;
00278     }
00279 
00280     *curdev_ret = curdev;
00281     return (0);
00282 }
00283 
00284 int
00285 add_addr_to_iflist(pcap_if_t **alldevs, char *name, u_int flags,
00286     struct sockaddr *addr, size_t addr_size,
00287     struct sockaddr *netmask, size_t netmask_size,
00288     struct sockaddr *broadaddr, size_t broadaddr_size,
00289     struct sockaddr *dstaddr, size_t dstaddr_size,
00290     char *errbuf)
00291 {
00292     pcap_if_t *curdev;
00293     pcap_addr_t *curaddr, *prevaddr, *nextaddr;
00294 
00295     if (add_or_find_if(&curdev, alldevs, name, flags, NULL, errbuf) == -1) {
00296         /*
00297          * Error - give up.
00298          */
00299         return (-1);
00300     }
00301     if (curdev == NULL) {
00302         /*
00303          * Device wasn't added because it can't be opened.
00304          * Not a fatal error.
00305          */
00306         return (0);
00307     }
00308 
00309     /*
00310      * "curdev" is an entry for this interface; add an entry for this
00311      * address to its list of addresses.
00312      *
00313      * Allocate the new entry and fill it in.
00314      */
00315     curaddr = malloc(sizeof(pcap_addr_t));
00316     if (curaddr == NULL) {
00317         (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
00318             "malloc: %s", pcap_strerror(errno));
00319         return (-1);
00320     }
00321 
00322     curaddr->next = NULL;
00323     if (addr != NULL) {
00324         curaddr->addr = dup_sockaddr(addr, addr_size);
00325         if (curaddr->addr == NULL) {
00326             (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
00327                 "malloc: %s", pcap_strerror(errno));
00328             free(curaddr);
00329             return (-1);
00330         }
00331     } else
00332         curaddr->addr = NULL;
00333 
00334     if (netmask != NULL) {
00335         curaddr->netmask = dup_sockaddr(netmask, netmask_size);
00336         if (curaddr->netmask == NULL) {
00337             (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
00338                 "malloc: %s", pcap_strerror(errno));
00339             free(curaddr);
00340             return (-1);
00341         }
00342     } else
00343         curaddr->netmask = NULL;
00344 
00345     if (broadaddr != NULL) {
00346         curaddr->broadaddr = dup_sockaddr(broadaddr, broadaddr_size);
00347         if (curaddr->broadaddr == NULL) {
00348             (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
00349                 "malloc: %s", pcap_strerror(errno));
00350             free(curaddr);
00351             return (-1);
00352         }
00353     } else
00354         curaddr->broadaddr = NULL;
00355 
00356     if (dstaddr != NULL) {
00357         curaddr->dstaddr = dup_sockaddr(dstaddr, dstaddr_size);
00358         if (curaddr->dstaddr == NULL) {
00359             (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
00360                 "malloc: %s", pcap_strerror(errno));
00361             free(curaddr);
00362             return (-1);
00363         }
00364     } else
00365         curaddr->dstaddr = NULL;
00366 
00367     /*
00368      * Find the end of the list of addresses.
00369      */
00370     for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) {
00371         nextaddr = prevaddr->next;
00372         if (nextaddr == NULL) {
00373             /*
00374              * This is the end of the list.
00375              */
00376             break;
00377         }
00378     }
00379 
00380     if (prevaddr == NULL) {
00381         /*
00382          * The list was empty; this is the first member.
00383          */
00384         curdev->addresses = curaddr;
00385     } else {
00386         /*
00387          * "prevaddr" is the last member of the list; append
00388          * this member to it.
00389          */
00390         prevaddr->next = curaddr;
00391     }
00392 
00393     return (0);
00394 }
00395 
00396 int
00397 pcap_add_if(pcap_if_t **devlist, char *name, u_int flags,
00398     const char *description, char *errbuf)
00399 {
00400     pcap_if_t *curdev;
00401 
00402     return (add_or_find_if(&curdev, devlist, name, flags, description,
00403         errbuf));
00404 }
00405 
00406 
00407 /*
00408  * Free a list of interfaces.
00409  */
00410 void
00411 pcap_freealldevs(pcap_if_t *alldevs)
00412 {
00413     pcap_if_t *curdev, *nextdev;
00414     pcap_addr_t *curaddr, *nextaddr;
00415 
00416     for (curdev = alldevs; curdev != NULL; curdev = nextdev) {
00417         nextdev = curdev->next;
00418 
00419         /*
00420          * Free all addresses.
00421          */
00422         for (curaddr = curdev->addresses; curaddr != NULL; curaddr = nextaddr) {
00423             nextaddr = curaddr->next;
00424             if (curaddr->addr)
00425                 free(curaddr->addr);
00426             if (curaddr->netmask)
00427                 free(curaddr->netmask);
00428             if (curaddr->broadaddr)
00429                 free(curaddr->broadaddr);
00430             if (curaddr->dstaddr)
00431                 free(curaddr->dstaddr);
00432             free(curaddr);
00433         }
00434 
00435         /*
00436          * Free the name string.
00437          */
00438         free(curdev->name);
00439 
00440         /*
00441          * Free the description string, if any.
00442          */
00443         if (curdev->description != NULL)
00444             free(curdev->description);
00445 
00446         /*
00447          * Free the interface.
00448          */
00449         free(curdev);
00450     }
00451 }
00452 
00453 #ifndef WIN32
00454 
00455 /*
00456  * Return the name of a network interface attached to the system, or NULL
00457  * if none can be found.  The interface must be configured up; the
00458  * lowest unit number is preferred; loopback is ignored.
00459  */
00460 char *
00461 pcap_lookupdev(errbuf)
00462     register char *errbuf;
00463 {
00464     pcap_if_t *alldevs;
00465 /* for old BSD systems, including bsdi3 */
00466 #ifndef IF_NAMESIZE
00467 #define IF_NAMESIZE IFNAMSIZ
00468 #endif
00469     static char device[IF_NAMESIZE + 1];
00470     char *ret;
00471 
00472     if (pcap_findalldevs(&alldevs, errbuf) == -1)
00473         return (NULL);
00474 
00475     if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) {
00476         /*
00477          * There are no devices on the list, or the first device
00478          * on the list is a loopback device, which means there
00479          * are no non-loopback devices on the list.  This means
00480          * we can't return any device.
00481          *
00482          * XXX - why not return a loopback device?  If we can't
00483          * capture on it, it won't be on the list, and if it's
00484          * on the list, there aren't any non-loopback devices,
00485          * so why not just supply it as the default device?
00486          */
00487         (void)strlcpy(errbuf, "no suitable device found",
00488             PCAP_ERRBUF_SIZE);
00489         ret = NULL;
00490     } else {
00491         /*
00492          * Return the name of the first device on the list.
00493          */
00494         (void)strlcpy(device, alldevs->name, sizeof(device));
00495         ret = device;
00496     }
00497 
00498     pcap_freealldevs(alldevs);
00499     return (ret);
00500 }
00501 
00502 int
00503 pcap_lookupnet(device, netp, maskp, errbuf)
00504     register const char *device;
00505     register bpf_u_int32 *netp, *maskp;
00506     register char *errbuf;
00507 {
00508     register int fd;
00509     register struct sockaddr_in *sin;
00510     struct ifreq ifr;
00511 
00512     /*
00513      * The pseudo-device "any" listens on all interfaces and therefore
00514      * has the network address and -mask "0.0.0.0" therefore catching
00515      * all traffic. Using NULL for the interface is the same as "any".
00516      */
00517     if (!device || strcmp(device, "any") == 0
00518 #ifdef HAVE_DAG_API
00519         || strstr(device, "dag") != NULL
00520 #endif
00521         ) {
00522         *netp = *maskp = 0;
00523         return 0;
00524     }
00525 
00526     fd = socket(AF_INET, SOCK_DGRAM, 0);
00527     if (fd < 0) {
00528         (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s",
00529             pcap_strerror(errno));
00530         return (-1);
00531     }
00532     memset(&ifr, 0, sizeof(ifr));
00533 #ifdef linux
00534     /* XXX Work around Linux kernel bug */
00535     ifr.ifr_addr.sa_family = AF_INET;
00536 #endif
00537     (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
00538     if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
00539         if (errno == EADDRNOTAVAIL) {
00540             (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
00541                 "%s: no IPv4 address assigned", device);
00542         } else {
00543             (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
00544                 "SIOCGIFADDR: %s: %s",
00545                 device, pcap_strerror(errno));
00546         }
00547         (void)close(fd);
00548         return (-1);
00549     }
00550     sin = (struct sockaddr_in *)&ifr.ifr_addr;
00551     *netp = sin->sin_addr.s_addr;
00552     if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
00553         (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
00554             "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno));
00555         (void)close(fd);
00556         return (-1);
00557     }
00558     (void)close(fd);
00559     *maskp = sin->sin_addr.s_addr;
00560     if (*maskp == 0) {
00561         if (IN_CLASSA(*netp))
00562             *maskp = IN_CLASSA_NET;
00563         else if (IN_CLASSB(*netp))
00564             *maskp = IN_CLASSB_NET;
00565         else if (IN_CLASSC(*netp))
00566             *maskp = IN_CLASSC_NET;
00567         else {
00568             (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
00569                 "inet class for 0x%x unknown", *netp);
00570             return (-1);
00571         }
00572     }
00573     *netp &= *maskp;
00574     return (0);
00575 }
00576 
00577 #else /* WIN32 */
00578 
00579 /*
00580  * Return the name of a network interface attached to the system, or NULL
00581  * if none can be found.  The interface must be configured up; the
00582  * lowest unit number is preferred; loopback is ignored.
00583  */
00584 char *
00585 pcap_lookupdev(errbuf)
00586     register char *errbuf;
00587 {
00588     DWORD dwVersion;
00589     DWORD dwWindowsMajorVersion;
00590     dwVersion = GetVersion();   /* get the OS version */
00591     dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
00592     
00593     if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) {
00594         /*
00595          * Windows 95, 98, ME.
00596          */
00597         ULONG NameLength = 8192;
00598         static char AdaptersName[8192];
00599         
00600         PacketGetAdapterNames(AdaptersName,&NameLength);
00601         
00602         return (AdaptersName);
00603     } else {
00604         /*
00605          * Windows NT (NT 4.0, W2K, WXP). Convert the names to UNICODE for backward compatibility
00606          */
00607         ULONG NameLength = 8192;
00608         static WCHAR AdaptersName[8192];
00609         char *tAstr;
00610         WCHAR *tUstr;
00611         WCHAR *TAdaptersName = (WCHAR*)malloc(8192 * sizeof(WCHAR));
00612         int NAdapts = 0;
00613 
00614         if(TAdaptersName == NULL)
00615         {
00616             (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure");
00617             return NULL;
00618         }
00619 
00620         PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength);
00621 
00622         tAstr = (char*)TAdaptersName;
00623         tUstr = (WCHAR*)AdaptersName;
00624 
00625         /*
00626          * Convert and copy the device names
00627          */
00628         while(sscanf(tAstr, "%S", tUstr) > 0)
00629         {
00630             tAstr += strlen(tAstr) + 1;
00631             tUstr += wcslen(tUstr) + 1;
00632             NAdapts ++;
00633         }
00634 
00635         tAstr++;
00636         *tUstr = 0;
00637         tUstr++;
00638 
00639         /*
00640          * Copy the descriptions
00641          */
00642         while(NAdapts--)
00643         {
00644             strcpy((char*)tUstr, tAstr);
00645             (char*)tUstr += strlen(tAstr) + 1;;
00646             tAstr += strlen(tAstr) + 1;
00647         }
00648 
00649         return (char *)(AdaptersName);
00650     }   
00651 }
00652 
00653 
00654 int
00655 pcap_lookupnet(device, netp, maskp, errbuf)
00656     const register char *device;
00657     register bpf_u_int32 *netp, *maskp;
00658     register char *errbuf;
00659 {
00660     /* 
00661      * We need only the first IPv4 address, so we must scan the array returned by PacketGetNetInfo()
00662      * in order to skip non IPv4 (i.e. IPv6 addresses)
00663      */
00664     npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES];
00665     LONG if_addr_size = 1;
00666     struct sockaddr_in *t_addr;
00667     unsigned int i;
00668 
00669     if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) {
00670         *netp = *maskp = 0;
00671         return (0);
00672     }
00673 
00674     for(i=0; i<MAX_NETWORK_ADDRESSES; i++)
00675     {
00676         if(if_addrs[i].IPAddress.ss_family == AF_INET)
00677         {
00678             t_addr = (struct sockaddr_in *) &(if_addrs[i].IPAddress);
00679             *netp = t_addr->sin_addr.S_un.S_addr;
00680             t_addr = (struct sockaddr_in *) &(if_addrs[i].SubnetMask);
00681             *maskp = t_addr->sin_addr.S_un.S_addr;
00682 
00683             *netp &= *maskp;
00684             return (0);
00685         }
00686                 
00687     }
00688 
00689     *netp = *maskp = 0;
00690     return (0);
00691 }
00692 
00693 #endif /* WIN32 */

documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.