diff --git a/src/Makefile.mk b/src/Makefile.mk index 3b8870f..4ca09c7 100644 --- a/src/Makefile.mk +++ b/src/Makefile.mk @@ -52,6 +52,7 @@ LINKER = $(CC) LDFLAGS = LDOUTF = -o LIBS = +NETLIBS = -lpcap # Variables specific to this makefile setup # SRC and MAKE_CENV are normally overridden. @@ -230,13 +231,13 @@ DINTFLAGS = \ ## kn10-ks: $(OFILES_KS) - $(LINKER) $(LDFLAGS) $(LDOUTF) kn10-ks $(OFILES_KS) $(LIBS) + $(LINKER) $(LDFLAGS) $(LDOUTF) kn10-ks $(OFILES_KS) $(NETLIBS) $(LIBS) kn10-ks-its: $(OFILES_KS) - $(LINKER) $(LDFLAGS) $(LDOUTF) kn10-ks-its $(OFILES_KS) $(LIBS) + $(LINKER) $(LDFLAGS) $(LDOUTF) kn10-ks-its $(OFILES_KS) $(NETLIBS) $(LIBS) kn10-kl: $(OFILES_KL) - $(LINKER) $(LDFLAGS) $(LDOUTF) kn10-kl $(OFILES_KL) $(LIBS) + $(LINKER) $(LDFLAGS) $(LDOUTF) kn10-kl $(OFILES_KL) $(NETLIBS) $(LIBS) #################################################################### @@ -299,6 +300,7 @@ base-ks-its: "CFLAGS = $(CFLAGS) $(CFLAGS_AUX)" \ "LDFLAGS = $(LDFLAGS)" \ "LIBS = $(LIBS)" \ + "NETLIBS = $(NETLIBS)" \ "CENVFLAGS = $(CENVFLAGS)" \ "CONFFLAGS = \ -DKLH10_CPU_KS=1 \ @@ -326,6 +328,7 @@ base-ks: "CFLAGS = $(CFLAGS) $(CFLAGS_AUX)" \ "LDFLAGS = $(LDFLAGS)" \ "LIBS = $(LIBS)" \ + "NETLIBS = $(NETLIBS)" \ "CENVFLAGS = $(CENVFLAGS)" \ "CONFFLAGS = \ -DKLH10_CPU_KS=1 \ @@ -349,6 +352,7 @@ base-kl: "CFLAGS = $(CFLAGS) $(CFLAGS_AUX)" \ "LDFLAGS = $(LDFLAGS)" \ "LIBS = $(LIBS)" \ + "NETLIBS = $(NETLIBS)" \ "CENVFLAGS = $(CENVFLAGS)" \ "CONFFLAGS = \ -DKLH10_CPU_KLX=1 \ @@ -399,6 +403,7 @@ lint-ks-its: "CFLAGS = $(CFLAGS) $(CFLAGS_AUX) $(CFLAGS_LINT)" \ "LDFLAGS = $(LDFLAGS)" \ "LIBS = $(LIBS)" \ + "NETLIBS = $(NETLIBS)" \ "CENVFLAGS = $(CENVFLAGS)" \ "CONFFLAGS = $(CONFFLAGS) $(CONFFLAGS_AUX)" @@ -409,6 +414,7 @@ lint-ks: "CFLAGS = $(CFLAGS) $(CFLAGS_AUX) $(CFLAGS_LINT)" \ "LDFLAGS = $(LDFLAGS)" \ "LIBS = $(LIBS)" \ + "NETLIBS = $(NETLIBS)" \ "CENVFLAGS = $(CENVFLAGS)" \ "CONFFLAGS = $(CONFFLAGS) $(CONFFLAGS_AUX)" @@ -419,6 +425,7 @@ lint-kl: "CFLAGS = $(CFLAGS) $(CFLAGS_AUX) $(CFLAGS_LINT)" \ "LDFLAGS = $(LDFLAGS)" \ "LIBS = $(LIBS)" \ + "NETLIBS = $(NETLIBS)" \ "CENVFLAGS = $(CENVFLAGS)" \ "CONFFLAGS = $(CONFFLAGS) $(CONFFLAGS_AUX)" @@ -439,6 +446,7 @@ port-ks: "CFLAGS = $(CFLAGS) $(CFLAGS_AUX)" \ "LDFLAGS = $(LDFLAGS)" \ "LIBS = $(LIBS)" \ + "NETLIBS = $(NETLIBS)" \ "CENVFLAGS = $(CENVFLAGS)" \ "CONFFLAGS = \ -DKLH10_CPU_KS=1 \ @@ -463,6 +471,7 @@ kl0i-sync: "CFLAGS = $(CFLAGS) $(CFLAGS_AUX)" \ "LDFLAGS = $(LDFLAGS)" \ "LIBS = $(LIBS)" \ + "NETLIBS = $(NETLIBS)" \ "CENVFLAGS = $(CENVFLAGS)" \ "CONFFLAGS = \ -DKLH10_CPU_KL0=1 \ @@ -486,6 +495,7 @@ kl0i-rtmopt: "CFLAGS = $(CFLAGS) $(CFLAGS_AUX)" \ "LDFLAGS = $(LDFLAGS)" \ "LIBS = $(LIBS)" \ + "NETLIBS = $(NETLIBS)" \ "CENVFLAGS = $(CENVFLAGS)" \ "CONFFLAGS = \ -DKLH10_CPU_KL0=1 \ @@ -535,7 +545,7 @@ dpni20.o: $(SRC)/dpni20.c $(SRC)/dpni20.h $(SRC)/dpsup.h $(BUILDMOD) $(SRC)/dpni20.c dpni20: dpni20.o dpsup.o - $(LINKER) $(LDFLAGS) $(LDOUTF) dpni20 dpni20.o dpsup.o $(LIBS) + $(LINKER) $(LDFLAGS) $(LDOUTF) dpni20 dpni20.o dpsup.o $(NETLIBS) $(LIBS) # --------- IMP subprocess (ITS KS only; counterpart for dvlhdh) @@ -544,7 +554,7 @@ dpimp.o: $(SRC)/dpimp.c $(SRC)/dpimp.h $(SRC)/dpsup.h $(BUILDMOD) $(SRC)/dpimp.c dpimp: dpimp.o dpsup.o - $(LINKER) $(LDFLAGS) $(LDOUTF) dpimp dpimp.o dpsup.o $(LIBS) + $(LINKER) $(LDFLAGS) $(LDOUTF) dpimp dpimp.o dpsup.o $(NETLIBS) $(LIBS) #################################################################### @@ -615,7 +625,7 @@ enaddr.o: $(SRC)/enaddr.c $(SRC)/osdnet.h $(SRC)/osdnet.c $(CC) $(CFLAGS) $(CENVFLAGS) $(CONFFLAGS) $(SRC)/enaddr.c enaddr: enaddr.o - $(LINKER) $(LDFLAGS) $(LDOUTF) enaddr enaddr.o $(LIBS) + $(LINKER) $(LDFLAGS) $(LDOUTF) enaddr enaddr.o $(NETLIBS) $(LIBS) #################################################################### diff --git a/src/dpimp.c b/src/dpimp.c index ddcdeb6..d6d0c31 100644 --- a/src/dpimp.c +++ b/src/dpimp.c @@ -659,7 +659,7 @@ net_init(register struct dpimp_s *dpimp) */ if ((!dpimp->dpimp_ifnam[0] && !dpimp->dpimp_dedic) || (dpimp->dpimp_doarp & DPIMP_ARPF_OCHK)) { - if (osn_iftab_init(IFTAB_IPS) <= 0) + if (osn_iftab_init() <= 0) esfatal(0, "Couldn't find interface information"); /* Found at least one! Pick first one, if a default is needed. */ @@ -699,7 +699,7 @@ net_init(register struct dpimp_s *dpimp) if (gwdef_ip.s_addr == -1 || gwdef_ip.s_addr == 0) efatal(1, "No default prime gateway specified"); -#endif +#endif /* !KLH10_NET_TUN */ /* Set up appropriate net fd and packet filter. ** Should also determine interface's ethernet addr, if possible, @@ -1635,7 +1635,7 @@ imptohost(register struct dpimp_s *dpimp) /* Small enough to constitute one IMP message, so pass it on! */ ihl_hhsend(dpimp, cnt, buffp + ETHER_HDRSIZ); } -#else +#else /* !KLH10_NET_TUN */ if (cnt > SI_MAXMSG) ihl_frag(cnt, buffp); else diff --git a/src/dpni20.c b/src/dpni20.c index bc755d2..02f40e3 100644 --- a/src/dpni20.c +++ b/src/dpni20.c @@ -475,10 +475,11 @@ void net_init(register struct dpni20_s *dpni) ** cannot be found by iftab_init). ** Also grab native IP and ethernet addresses, if ARP might need them. */ + if (osn_iftab_init() <= 0) + esfatal(0, "Couldn't find interface information"); + if ((!dpni->dpni_ifnam[0] && !dpni->dpni_dedic) || (dpni->dpni_doarp & DPNI_ARPF_OCHK)) { - if (osn_iftab_init(IFTAB_IPS) <= 0) - esfatal(0, "Couldn't find interface information"); /* Found at least one! Pick first one, if a default is needed. */ if (!dpni->dpni_ifnam[0]) { @@ -1338,8 +1339,7 @@ int arp_myreply(register unsigned char *buf, register int cnt) /* Found it! ife now points to matching entry */ if (!ife->ife_gotea) { - if (!osn_ifeaget(-1, ife->ife_name, ife->ife_ea, - (unsigned char *)NULL)) { + if (!osn_ifeaget2(ife->ife_name, ife->ife_ea)) { error("ARP MyReply failed, no E/N addr for %s", ife->ife_name); return FALSE; } diff --git a/src/enaddr.c b/src/enaddr.c index 1694f13..2683bce 100644 --- a/src/enaddr.c +++ b/src/enaddr.c @@ -115,22 +115,10 @@ Usage: enaddr [-v] [ [default | ] [+] [-]]\n\ Set up for eventual extraction into a separate module */ -#if 1 /* ENADDR */ -# define LOG_EOL "\n" -# undef LOG_DP -# define LOG_PROGNAME "enaddr" -# define DP_DBGFLG debugf -#else -# define LOG_EOL "\r\n" -# define LOG_DP dp -# if KLH10_SIMP -# define LOG_PROGNAME "simp" -# elif KLH10_DEV_DPIMP -# define LOG_PROGNAME "dpimp" -# elif KLH10_DEV_DPNI20 -# define LOG_PROGNAME "dpni20" -# endif -#endif +#define LOG_EOL "\n" +#undef LOG_DP +#define LOG_PROGNAME "enaddr" +#define DP_DBGFLG debugf #if 1 /* Error and diagnostic stuff */ @@ -142,7 +130,7 @@ Usage: enaddr [-v] [ [default | ] [+] [-]]\n\ static const char *log_progname = LOG_PROGNAME; -char *log_strerror(err) +char *log_strerror(int err) { if (err == -1 && errno != err) return log_strerror(errno); @@ -265,6 +253,7 @@ static void logfatal_ser(int num, char *fmt, ...) #endif /* Error and Diagnostic stuff */ +int main(int argc, char **argv) { int i; @@ -324,9 +313,7 @@ main(int argc, char **argv) } /* First, show interface info if desired */ - if (debugf) { - osn_iftab_init(IFTAB_ALL); - } + osn_iftab_init(); /* Now mung interface if one given */ if (ifc) { @@ -337,7 +324,8 @@ main(int argc, char **argv) } /* Read the default and current MAC address */ - (void) osn_ifeaget(s, ifc, pa_cur, pa_def); + (void) osn_ifealookup(ifc, pa_cur); /* pa_def not looked up */ + /* Print the MAC addresses */ penetaddr(ifc, pa_cur, pa_def); @@ -350,7 +338,8 @@ main(int argc, char **argv) (void) osn_ifeaset(s, ifc, (endef ? pa_def : pa_new)); /* Read back to confirm */ - (void) osn_ifeaget(s, ifc, pa_cur, pa_def); + osn_iftab_init(); + (void) osn_ifealookup(ifc, pa_cur); /* pa_def not looked up */ penetaddr(ifc, pa_cur, pa_def); } diff --git a/src/osdnet.c b/src/osdnet.c index 851f27a..77fd87d 100644 --- a/src/osdnet.c +++ b/src/osdnet.c @@ -1,6 +1,6 @@ /* OSDNET.C - OS Dependent Network facilities */ -/* $Id: osdnet.c,v 2.8 2003/02/23 18:22:08 klh Exp $ +/* From: $Id: osdnet.c,v 2.8 2003/02/23 18:22:08 klh Exp $ */ /* Copyright © 1999, 2001 Kenneth L. Harrenstien ** All Rights Reserved @@ -15,21 +15,6 @@ ** This notice (including the copyright and warranty disclaimer) ** must be included in all copies or derivations of this software. */ -/* - * $Log: osdnet.c,v $ - * Revision 2.8 2003/02/23 18:22:08 klh - * Fix various problems for NetBSD/Alpha 1.6. - * - * Revision 2.7 2002/03/18 04:25:03 klh - * Add support for promiscuous mode, fix minor ARP error output - * - * Revision 2.6 2001/11/19 10:32:34 klh - * Solaris port fixups. - * - * Revision 2.5 2001/11/10 21:28:59 klh - * Final 2.0 distribution checkin - * - */ /* This file, like DPSUP.C, is intended to be included directly into source code rather than compiled separately and then linked @@ -39,6 +24,7 @@ */ #include /* For basic Unix syscalls */ +#include /* The possible configuration macro definitions, with defaults: */ @@ -50,14 +36,10 @@ # include "osdnet.h" /* Insurance to make sure our defs are there */ #endif -#ifdef RCSID - RCSID(osdnet_c,"$Id: osdnet.c,v 2.8 2003/02/23 18:22:08 klh Exp $") -#endif - /* Local predeclarations */ struct ifent *osn_iflookup(char *ifnam); -int osn_ifealookup(char *ifnam, unsigned char *eap); + /* Get a socket descriptor suitable for general net interface examination and manipulation; this is not necessarily suitable for @@ -107,66 +89,12 @@ ip_adrsprint(char *cp, unsigned char *ia) /* Interface Table initialization ** Gets info about all net interfaces known to the native system. ** Used for several purposes, hence fairly general. +** This table is used as much as possible, instead of using +** system specific lookup +** A sticky point remains the ethernet addresses. They may or may +** not be reported, and if they are it is in a system specific way. +** Therefore we need to keep the system-specific functions for that. ** -*/ -/* - SIOCGIFCONF documentation is virtually non-existent. The following - info comes from looking at source code. - struct ifconf ifconf; - s = socket(AF_INET, SOCK_DGRAM, 0); - ioctl(s, SIOCGIFCONF, &ifconf); - - ifconf has only two elements: - : struct ifconf - caddr_t ifcu_buf; Buffer to use - int ifc_len; Buffer size in bytes (or # bytes used) - - On return, the buffer holds a series of "struct ifreq" entries, each of - which holds an interface name and address. On older systems, each - such entry was a fixed size, but this was later changed in order to - accomodate longer addresses and consequently, - =====>> EACH ENTRY MAY BE OF VARYING SIZE!!!! <<====== - - This, by the way, is why SIOCGIFCONF appeared to be broken on OSF/1 when - used with a single ifreq's worth of buffer -- since it needed a larger - "ifreq" than the buffer had room for, it returned nothing. - - Although the second element of "struct ifreq" is a union, SIOCGIFCONF always - uses it to return a sockaddr: - : struct ifreq - char ifr_name[16] interface name, eg "de0" - struct sockaddr ifr_addr interface address - : struct sockaddr - unsigned char sa_len # bytes in this sockaddr - unsigned char sa_family address type, AF_xxx - char sa_data[14] actually up to 253 bytes! - - Note that the sa_len field is new; older versions of sockaddr had - just sa_family and sa_data. - - To repeat, the actual size of an ifreq depends on the size of the - sockaddr it contains. This is ALWAYS at least sizeof(struct sockaddr), - so trickiness is only needed when sa_len is greater than this default - size. - -#define _SIZEOF_ADDR_IFREQ(p) \ - ((p)->ifr_addr.sa_len <= sizeof(struct sockaddr) \ - ? sizeof(struct ifreq) \ - : (sizeof(struct ifreq)-sizeof(struct sockaddr)+(p)->ifr_addr.sa_len)) - -or alternatively: - -#define _SIZEOF_ADDR_IFREQ(ifr) \ - ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) \ - ? (sizeof(struct ifreq) - sizeof(struct sockaddr) + (ifr).ifr_addr.sa_len) \ - : sizeof(struct ifreq)) - - This has been made trickier by NetBSD 5.0, which doesn't put a sockaddr - but a (union with as largest member a) sockaddr_storage in the ifreq. - Now the size is always the same again, but not sizeof(struct sockaddr). - This can (probably) be recognised by the existence of - #define ifr_space ifr_ifru.ifru_space / * sockaddr_storage * / - */ /* Note that searching for AF_INET or IP addresses only finds interfaces that @@ -180,86 +108,107 @@ or alternatively: interface; there is none. */ -/* Complete table as returned from system by SIOCGIFCONF - * Currently static for debugging, could be dynamic. - */ -static struct ifconf ifctab; -static char ifcbuf[sizeof(struct ifreq) * NETIFC_MAX]; - -/* Our own internal table of interface entries, filtered - to keep only the ones we're interested in. +/* Our own internal table of interface entries. */ static int iftab_initf = 0; static int iftab_nifs = 0; static struct ifent iftab[NETIFC_MAX]; -static void osn_iftab_pass(int opts, int npass, int s, struct ifconf *ifc); +static struct ifent * +osn_iftab_addaddress(char *name, struct sockaddr *addr); /* Get table of all interfaces, using our own generic entry format. - * Routine works as follows: * - * First, grabs a IFCONF table of all interfaces from the kernel. - * Each IFR entry contains a name and an address. + * This uses either getifaddrs(3) (available on at least BSD, linux, + * OS X) or otherwise pcap_findalldevs(3). * - * Second, scan this IFCONF table (pass 1) to build our own table of IFE - * entries, made of all IFR entries that pass the following filter - * flags: - * IFTAB_IPS - if set, accepts AF_INET interfaces (with IP address) - * IFTAB_ETHS - if set, accepts LINK interfaces with Ether-like addrs. - * IFTAB_OTH - if set, accepts all others (with unknown addr) + * getifaddrs(3) will provide link-level (ethernet) addresses on at + * least NetBSD 1.5+, FreeBSD 4.1+, MacOS X 10.6+, Linux. * - * Third, make another scan of IFCONF (pass 2) that grabs *all* information - * about any interface present in our IFE table, regardless of what caused - * it to be inserted. + * pcap_findalldevs(3) may omit interfaces that are not IFF_UP. + * It will provide ethernet addresses on at least NetBSD, FreeBSD, Linux. */ int -osn_iftab_init(int opts) +osn_iftab_init(void) { - int s; - struct ifconf *ifc = &ifctab; - register struct ifent *ifet; + struct ifent *ife; /* Start out with empty table */ + memset(&iftab[0], sizeof(iftab), 0); iftab_nifs = 0; - ifet = &iftab[0]; - /* Open socket with AF_INET family to get at IP stuff. - */ +#if HAVE_GETIFADDRS + struct ifaddrs *ifp; + + getifaddrs(&ifp); + + while (ifp) { + if (!ifp->ifa_name) + continue; + ife = osn_iftab_addaddress(ifp->ifa_name, ifp->ifa_addr); + + if (ife) { + ife->ife_flags = ifp->ifa_flags; + } + + ifp = ifp->ifa_next; + } + freeifaddrs(ifp); + +#elif HAVE_LIBPCAP + char errbuf[PCAP_ERRBUF_SIZE]; + pcap_if_t *alldevs; + struct ifreq ifr; + int s; + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - esfatal(1, "osn_iftab_init socket()"); + syserr(errno, "Can't get socket for SIOCGIFFLAGS"); + return FALSE; } - /* Gobble table of config info about all interfaces, including name - and IP address. + /* + * This may only find interfaces that are IFF_UP. */ - ifc->ifc_len = sizeof(ifcbuf); - ifc->ifc_buf = (caddr_t)ifcbuf; - if (ioctl(s, SIOCGIFCONF, (char *)ifc) < 0) { - close(s); - esfatal(1, "osn_iftab_init SIOCGIFCONF"); + if (pcap_findalldevs(&alldevs, errbuf) == -1) { + error("pcap_findalldevs: %s", errbuf); + return; } - if (ifc->ifc_len < sizeof(struct ifreq)) { - if (DP_DBGFLG) - dbprintln("SIOCGIFCONF only got %d bytes (need %d)", - (int)ifc->ifc_len, (int)sizeof(struct ifreq)); - close(s); - return 0; /* Assume no interfaces */ + + while (alldevs) { + pcap_addr_t *addr; + + if (!alldevs->name) + continue; + + /* These ioctls should work for all interfaces */ + strncpy(ifr.ifr_name, alldevs->name, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCGIFFLAGS, (char *)&ifr) < 0) { + syserr(errno, "SIOCGIFFLAGS for \"%s\"", alldevs->name); + continue; + } + + addr = alldevs->addresses; + + while (addr) { + ife = osn_iftab_addaddress(alldevs->name, addr->addr); + addr = addr->next; + } + + if (ife) { + ife->ife_flags = ifr.ifr_flags; + } + + alldevs = alldevs->next; } - if (DP_DBGFLG) - dbprintln("SIOCGIFCONF returned %d bytes (%d ifcs?)", - (int)ifc->ifc_len, (int)(ifc->ifc_len/sizeof(struct ifreq))); - if (DP_DBGFLG) - osn_ifctab_show(stdout, ifc); - - /* Grabbed everything from OS, now grovel through it */ - osn_iftab_pass(opts, 1, s, ifc); /* Do pass 1 scan */ - osn_iftab_pass(opts, 2, s, ifc); /* Do pass 2 scan */ - iftab_initf = opts; /* Inited! */ + pcap_freealldevs(alldevs); close(s); +#endif + if (DP_DBGFLG) osn_iftab_show(stdout, &iftab[0], iftab_nifs); + return iftab_nifs; } @@ -269,239 +218,80 @@ osn_nifents(void) return iftab_nifs; } -static void -osn_iftab_pass(int opts, int npass, int s, struct ifconf *ifc) +/* + * Remember a specific address for an interface. + * + * If multiple addresses are found, they overwrite each other. + * + * For AF_LINK addresses, in NetBSD at least it seems that the first one + * is the default hardware address, and later ones were set with + * "ifconfig re0 link " or removed with "ifconfig re0 link + * -alias". The default hardware address can't be removed this way. + * The net effect is that the last address set up (which is presumably + * the one in use) is remembered. + * + * Maybe we should simply remember an array of addresses of each type. + */ + +static struct ifent * +osn_iftab_addaddress(char *name, struct sockaddr *addr) { - register int i; - int offset; - struct ifreq ifr; - register struct ifreq *ifp, *ifend, *ifnext; - register struct ifent *ife, *ifet; - - /* Start out with empty table */ - if (npass == 1) - iftab_nifs = 0; - - ifet = &iftab[0]; - - ifp = ifc->ifc_req; - ifend = (struct ifreq *)((char *)ifp + ifc->ifc_len); - for (; ifp < ifend; ifp = ifnext) { - - /* Find next pointer now, to simplify structure of code. - This is complicated by the fact that the returned table format - has changed under different OS versions. The "new regime" - uses a variable-size "ifreq" entry! Choke... - */ - ifnext = ifp + 1; /* Assume normal entry at first */ -#if NETIF_HAS_SALEN && !defined(ifr_space) - if (ifp->ifr_addr.sa_len > sizeof(struct sockaddr)) { - offset = ifp->ifr_addr.sa_len - sizeof(struct sockaddr); - ifnext = (struct ifreq *)((char *)ifnext + offset); - } -#endif - /* See whether this entry is already in table. - */ - for (i = 0; i < iftab_nifs; ++i) { - if (strncmp(ifp->ifr_name, ifet[i].ife_name, sizeof(ifp->ifr_name)) - == 0) { - /* Found existing entry! Use its pointer */ - ife = &ifet[i]; - break; - } - } - if (i >= iftab_nifs) { - if (npass == 2) - continue; - /* Pass1, decide now whether to create entry or not */ - /* See if it's something we're interested in. */ - if ((opts & IFTAB_IPS) && (ifp->ifr_addr.sa_family == AF_INET)) { - /* yes */ -#if NETIF_HAS_ETHLINK - } else if ((opts & IFTAB_ETHS) - && (ifp->ifr_addr.sa_family == AF_LINK) - && (((struct sockaddr_dl *)&ifp->ifr_addr)->sdl_alen - == ETHER_ADRSIZ)){ - /* yes */ -#endif - } else if (opts & IFTAB_OTH) { - /* yes */ - } else { - /* Nope, ignore this one */ - continue; - } - - /* Yes, create this entry */ - if (iftab_nifs >= NETIFC_MAX-1) { - error("ifc table overflow, max %d", NETIFC_MAX); - return; /* Stop now */ - } - ife = &ifet[iftab_nifs++]; /* New table entry to fill out */ - - /* Copy interface name and ensure null-terminated - even if sizes someday get out of synch. - */ - strncpy(ife->ife_name, ifp->ifr_name, - (sizeof(ife->ife_name) < sizeof(ifp->ifr_name)) - ? sizeof(ife->ife_name) : sizeof(ifp->ifr_name)); - ife->ife_name[sizeof(ife->ife_name)-1] = '\0'; - - /* These ioctls should work for all interfaces */ - strncpy(ifr.ifr_name, ifp->ifr_name, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCGIFFLAGS, (char *)&ifr) < 0) { - syserr(errno, "SIOCGIFFLAGS for \"%s\"", ife->ife_name); - continue; /* Discard entry */ - } - ife->ife_flags = ifr.ifr_flags; - - /* SIOCGIFMTU: ifr_mtu */ - /* SIOCGIFMETRIC: ifr_metric */ - continue; - } - if (npass == 1) - continue; - - /* Pass 2 and dealing with an existing entry. Flesh it out! */ - switch (ifp->ifr_addr.sa_family) { - case AF_INET: - ife->ife_gotip4 = TRUE; - ife->ife_ipint = ((struct sockaddr_in *) - &ifp->ifr_addr)->sin_addr.s_addr; - break; -#if NETIF_HAS_ETHLINK - case AF_LINK: - if (((struct sockaddr_dl *)&ifp->ifr_addr)->sdl_alen - == ETHER_ADRSIZ) { - /* Looks like Ethernet physical link, save addr */ - struct sockaddr_dl *dla = (struct sockaddr_dl *)&ifp->ifr_addr; - memcpy(ife->ife_ea, LLADDR(dla), dla->sdl_alen); - ife->ife_gotea = TRUE; - break; - } -#endif - /* Else drop through to "other" case */ - default: - break; - } - } -} - -#include - -void -osn_ifctab_show(FILE *f, struct ifconf *ifc) -{ - register struct ifreq *ifr; - struct ifreq *ifrend; - int len; + struct ifent *ife, *ifet; int i; - unsigned char *cp; - int nents = 0; - int nvary = 0; + int idx; - fprintf(f, "sizeof struct ifreq = %d\r\n", (int) sizeof(struct ifreq)); - fprintf(f, "IFNAMSIZ = %d\r\n", (int) IFNAMSIZ); -#if CENV_SYS_NETBSD - fprintf(f, "offset of struct sockaddr_storage = %d\r\n", (int) offsetof(struct ifreq, ifr_space)); -#endif - fprintf(f, "sizeof struct sockaddr = %d\r\n", (int) sizeof(struct sockaddr)); - fprintf(f, "sizeof struct sockaddr_storage = %d\r\n", (int) sizeof(struct sockaddr_storage)); - fprintf(f, "sizeof union ifr_ifru = %d\r\n", (int) sizeof(ifr->ifr_ifru)); + /* First see if the name is already known */ - fprintf(f, "Interface table: %ld bytes (%d entries if std addr len %d)\r\n", - (long)ifc->ifc_len, (int)(ifc->ifc_len/sizeof(struct ifreq)), - (int)sizeof(struct sockaddr)); - - ifr = ifc->ifc_req; - ifrend = (struct ifreq *)((char *)(ifc->ifc_req) + ifc->ifc_len); - for (i = 0; ifr < ifrend; ++i) { - ++nents; - -#if NETIF_HAS_SALEN - len = ifr->ifr_addr.sa_len; -#else - len = sizeof(struct sockaddr); -#endif - - fprintf(f, "offset: %d\r\n", (int)((char *)ifr - (char *)ifc->ifc_req)); - /* Output entry data */ - fprintf(f, "%2d: \"%.*s\" sockaddr.sa_family %d, .sa_len %d", - i, (int)sizeof(ifr->ifr_name), ifr->ifr_name, - ifr->ifr_addr.sa_family, len); - if (len) { - cp = (unsigned char *) ifr->ifr_addr.sa_data; - fprintf(f, " = (sockaddr.sa_data) %x", *cp); - for (--len; len > 0; --len) { - fprintf(f, ":%x", *++cp); - } + idx = -1; + for (i = iftab_nifs - 1; i >= 0; i--) { + if (strcmp(iftab[i].ife_name, name) == 0) { + idx = i; + break; } - fprintf(f, "\r\n"); - - cp = (unsigned char *) ifr->ifr_addr.sa_data; - switch (ifr->ifr_addr.sa_family) { - case AF_INET: - { - struct sockaddr_in *skin = (struct sockaddr_in *) &ifr->ifr_addr; - struct in_addr *in = &skin->sin_addr; - unsigned char *ucp = (unsigned char *) &in->s_addr; - - fprintf(f, " AF_INET = port %d, IP %d.%d.%d.%d\r\n", - (int)skin->sin_port, - ucp[0], ucp[1], ucp[2], ucp[3]); - } - break; - -#if NETIF_HAS_ETHLINK - case AF_LINK: - { - struct sockaddr_dl *dla = (struct sockaddr_dl *) &ifr->ifr_addr; - fprintf(f, " AF_LINK = type %d, sdl_alen %d", - dla->sdl_type, dla->sdl_alen); - if (len = dla->sdl_alen) { - cp = (unsigned char *) LLADDR(dla); - fprintf(f, " = %x", *cp); - for (--len; len > 0; --len) { - fprintf(f, ":%x", *++cp); - } - } - fprintf(f, "\r\n"); - } - break; -#endif - -#if defined(AF_INET6) - case AF_INET6: - fprintf(f, " AF_INET6 (No handler for this)\r\n"); - break; -#endif - default: - fprintf(f, " No handler for this family\r\n"); - } - - - /* Move onto next entry */ -#if NETIF_HAS_SALEN && !defined(ifr_space) - if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)) { - ++nvary; - ifr = (struct ifreq *)((char *)(ifr + 1) + - (ifr->ifr_addr.sa_len - sizeof(struct sockaddr))); - } else -#endif - ifr++; } - if (nvary) - fprintf(f, "Interface summary: %d entries of varying length\r\n", - nents); - else - fprintf(f, "Interface summary: %d entries of std length %d\r\n", - nents, (int)sizeof(struct ifreq)); -} + if (idx < 0) { + idx = iftab_nifs++; + if (idx >= NETIFC_MAX) + return NULL; /* doesn't fit */ + strncpy(iftab[idx].ife_name, name, IFNAMSIZ); + iftab[idx].ife_name[IFNAMSIZ] = '\0'; + } + + ifet = &iftab[idx]; + + switch (addr->sa_family) { + case AF_INET: { + struct sockaddr_in *sin = (struct sockaddr_in *)addr; + ifet->ife_ipia = sin->sin_addr; + ifet->ife_gotip4 = TRUE; + break; + } +#if defined(AF_LINK) + case AF_LINK: { + struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; + if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == ETHER_ADRSIZ) { + ea_set(ifet->ife_ea, LLADDR(sdl)); + ifet->ife_gotea = TRUE; + } + } +#endif /* AF_LINK*/ +#if defined(AF_PACKET) + case AF_PACKET: { + struct sockaddr_ll *sll = (struct sockaddr_ll *)addr; + if (sll->sll_hatype == ARPHRD_ETHER && sll->sll_halen == ETHER_ADRSIZ) { + ea_set(ifet->ife_ea, &sll->sll_addr); + ifet->ife_gotea = TRUE; + } + } +#endif /* AF_PACKET*/ + } +} void osn_iftab_show(FILE *f, struct ifent *ifents, int nents) { - register struct ifent *ife; + struct ifent *ife; int i; fprintf(f, "Filtered IFE table: %d entries\r\n", nents); @@ -528,8 +318,8 @@ osn_iftab_show(FILE *f, struct ifent *ifents, int nents) struct ifent * osn_iftab_arp(struct in_addr ia) { - register int i = 0; - register struct ifent *ife = iftab; + int i = 0; + struct ifent *ife = iftab; for (; i < iftab_nifs; ++i, ++ife) if (ife->ife_ipia.s_addr == ia.s_addr) @@ -542,7 +332,7 @@ osn_iftab_arp(struct in_addr ia) int osn_iftab_arpget(struct in_addr ia, unsigned char *eap) { - register struct ifent *ife; + struct ifent *ife; if ((ife = osn_iftab_arp(ia)) && ife->ife_gotea) { ea_set(eap, ife->ife_ea); @@ -558,8 +348,8 @@ osn_iftab_arpget(struct in_addr ia, unsigned char *eap) struct ifent * osn_ipdefault(void) { - register int i = 0; - register struct ifent *ife = iftab; + int i = 0; + struct ifent *ife = iftab; for (; i < iftab_nifs; ++i, ++ife) if ((ife->ife_flags & IFF_UP) && !(ife->ife_flags & IFF_LOOPBACK)) @@ -572,8 +362,8 @@ osn_ipdefault(void) struct ifent * osn_iflookup(char *ifnam) { - register int i = 0; - register struct ifent *ife = iftab; + int i = 0; + struct ifent *ife = iftab; for (; i < iftab_nifs; ++i, ++ife) if (strcmp(ifnam, ife->ife_name) == 0) @@ -588,18 +378,18 @@ int osn_ifealookup(char *ifnam, /* Interface name */ unsigned char *eap) /* Where to write ether address */ { -#if NETIF_HAS_ETHLINK - register struct ifent *ife; + struct ifent *ife; - if ((ife = osn_iflookup(ifnam)) - && ife->ife_gotea) { + if (ife = osn_iflookup(ifnam)) { + if (!ife->ife_gotea) { + ife->ife_gotea = osn_ifeaget2(ifnam, ife->ife_ea); + } + if (ife->ife_gotea) { ea_set(eap, ife->ife_ea); return TRUE; + } } return FALSE; -#else - return osn_ifeaget(-1, ifnam, eap, (unsigned char *)NULL); -#endif } /* OSN_ARP_STUFF - stuff emulated-host ARP entry into kernel. @@ -782,11 +572,17 @@ osn_ifnmget(int s, /* Socket for (AF_INET, SOCK_DGRAM, 0) */ } -/* OSN_IFEAGET - get physical ethernet address for a given interface name. +/* OSN_IFEAGET2 - get physical ethernet address for a given interface name. * * This is fairly tricky as the OSD mechanism for this tends to * be *very* poorly documented. * + * Usually this information was already found by the information from + * either getifaddrs(3) or pcap_findalldevs(3). + * + * In the cases where it wasn't, we have fallbacks for DECOSF + * and via ARP. + * * Apparently only DEC OSF/1 and Linux can find this directly. * However, other systems seem to be divided into either of two * camps: @@ -797,117 +593,50 @@ osn_ifnmget(int s, /* Socket for (AF_INET, SOCK_DGRAM, 0) */ * AF_LINK family address in the ifconf table. */ int -osn_ifeaget(int s, /* Socket for (AF_INET, SOCK_DGRAM, 0) */ - char *ifnam, /* Interface name */ - unsigned char *eap, /* Current ether address */ - unsigned char *def) /* Default (hardware) ether address */ +osn_ifeaget2(char *ifnam, /* Interface name */ + unsigned char *eap) /* Current ether address */ { char eastr[OSN_EASTRSIZ]; #if CENV_SYS_DECOSF /* Direct approach */ - { - int ownsock = FALSE; - struct ifdevea ifdev; + { + int ownsock = FALSE; + struct ifdevea ifdev; - if (s == -1) { if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syserr(errno, "Can't get EN addr for \"%s\": socket()", ifnam); return FALSE; } - ownsock = TRUE; - } - strncpy(ifdev.ifr_name, ifnam, sizeof(ifdev.ifr_name)); - if (ioctl(s, SIOCRPHYSADDR, &ifdev) < 0) { - syserr(errno, "Can't get EN addr for \"%s\": SIOCRPHYSADDR", ifnam); - if (ownsock) close(s); - return FALSE; - } - if (ownsock) - close(s); - ea_set(eap, ifdev.current_pa); - if (def) - ea_set(def, ifdev.default_pa); - } -#elif CENV_SYS_LINUX - { - int ownsock = FALSE; - struct ifreq ifr; - - if (s == -1) { - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - syserr(errno, "Can't get EN addr for \"%s\": socket()", ifnam); + strncpy(ifdev.ifr_name, ifnam, sizeof(ifdev.ifr_name)); + if (ioctl(s, SIOCRPHYSADDR, &ifdev) < 0) { + syserr(errno, "Can't get EN addr for \"%s\": SIOCRPHYSADDR", ifnam); + if (ownsock) close(s); return FALSE; } - ownsock = TRUE; - } - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0 ) { - syserr(errno, "SIOCGIFHWADDR of %s failed", ifnam); - if (ownsock) close(s); - return FALSE; - } - - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { - error("%s is not an ethernet - ARPHRD type %d", - ifnam, ifr.ifr_hwaddr.sa_family); - if (ownsock) close(s); - return FALSE; - } - if (ownsock) close(s); - ea_set(eap, &ifr.ifr_addr.sa_data[0]); /* Return the ether address */ - if (def) - memset(def, 0, ETHER_ADRSIZ); - } - -#elif NETIF_HAS_ARPIOCTL - { - /* Much more general hack */ - unsigned char ipchr[IP_ADRSIZ]; - char ipstr[OSN_IPSTRSIZ]; - - /* Get IP address for this interface, as an argument for ARP lookup */ - if (!osn_ifipget(s, ifnam, ipchr)) { - error("Can't get EN addr for \"%s\": osn_ifipget failed", ifnam); - return FALSE; + ea_set(eap, ifdev.current_pa); } - /* Have IP address, now do ARP lookup hackery */ - if (!osn_arp_look((struct in_addr *)ipchr, eap)) { - syserr(errno,"Can't find EN addr for \"%s\" %s using ARP", - ifnam, ip_adrsprint(ipstr, ipchr)); - return FALSE; - } - if (def) - memset(def, 0, ETHER_ADRSIZ); - } - -#elif NETIF_HAS_ETHLINK - /* Should never happen unless osn_ifeaget() is called directly - without going through osn_ifealookup(). If so, attempt - to do right thing anyway. - */ - { - register struct ifent *ife; - - if (iftab_initf == 0) { - /* Try to initialize iftab, ignore errors */ - (void) osn_iftab_init(IFTAB_ETHS); - } - if (!(ife = osn_iflookup(ifnam)) - || !(ife->ife_gotea)) { - error("No EN addr in iftab for \"%s\"", ifnam); - return FALSE; - } - ea_set(eap, ife->ife_ea); - if (def) - memset(def, 0, ETHER_ADRSIZ); - } - #else -# error "Unimplemented OS routine osn_ifeaget()" + { + /* Much more general hack */ + unsigned char ipchr[IP_ADRSIZ]; + char ipstr[OSN_IPSTRSIZ]; + + /* Get IP address for this interface, as an argument for ARP lookup */ + if (!osn_ifipget(-1, ifnam, ipchr)) { + error("Can't get EN addr for \"%s\": osn_ifipget failed", ifnam); + return FALSE; + } + + /* Have IP address, now do ARP lookup hackery */ + if (!osn_arp_look((struct in_addr *)ipchr, eap)) { + syserr(errno,"Can't find EN addr for \"%s\" %s using ARP", + ifnam, ip_adrsprint(ipstr, ipchr)); + return FALSE; + } + } #endif dbprintln("EN addr for \"%s\" = %s", ifnam, eth_adrsprint(eastr, eap)); @@ -999,7 +728,7 @@ osn_pfeaget(int pfs, /* Packetfilter socket or FD */ return FALSE; } #else - if (!osn_ifeaget(pfs, ifnam, eap, (unsigned char *)NULL)) + if (!osn_ifealookup(ifnam, eap)) return FALSE; #endif @@ -1485,7 +1214,7 @@ osn_pfinit(struct osnpf *osnpf, void *pfarg) #if KLH10_NET_BPF int -osn_pfinit(register struct osnpf *osnpf, void *arg) +osn_pfinit(struct osnpf *osnpf, void *arg) { int fd; struct bpf_version bv; @@ -1523,6 +1252,25 @@ osn_pfinit(register struct osnpf *osnpf, void *arg) if (ioctl(fd, BIOCIMMEDIATE, (char *) &i) < 0) esfatal(1, "BIOCIMMEDIATE failed"); + /* BIOCSFEEDBACK causes packets that we send via bpf to be + * seen as incoming by the host OS. + * Without this, there is no working communication between + * the host and the guest OS (just in one direction). + */ +#if !defined(BIOCSFEEDBACK) && defined(BIOCFEEDBACK) +# define BIOCSFEEDBACK BIOCSFEEDBACK +#endif +//#if defined(__NetBSD_Version__) && __NetBSD_Version__ < 799002500 +//# undef BIOCSFEEDBACK /* buggy before NetBSD 7.99.24 or 7.1 */ +//#endif +#if defined(BIOCSFEEDBACK) + error("trying BIOCSFEEDBACK"); + errno = 0; + i = 1; + if (ioctl(fd, BIOCSFEEDBACK, (char *) &i) < 0) + syserr(errno, "BIOCSFEEDBACK failed"); +#endif + /* Set the read() buffer size. Must be set before interface is attached! */ @@ -1647,7 +1395,7 @@ The ifra_mask field is ignored (left as-is or zeroed if new) unless */ int -osn_pfinit(register struct osnpf *osnpf, void *arg) +osn_pfinit(struct osnpf *osnpf, void *arg) { int allowextern = TRUE; /* For now, always try for external access */ int fd; @@ -1678,7 +1426,7 @@ osn_pfinit(register struct osnpf *osnpf, void *arg) exist, if there is no hardware interface) */ if (allowextern) { - if (osn_iftab_init(IFTAB_IPS) && (ife = osn_ipdefault())) { + if (osn_iftab_init() && (ife = osn_ipdefault())) { iplocal = ife->ife_ipia; } else { error("Cannot find default IP interface for host"); @@ -1707,13 +1455,13 @@ osn_pfinit(register struct osnpf *osnpf, void *arg) if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) /* turn it on */ esfatal(0, "Couldn't set tun device"); strcpy(ifnam, ifr.ifr_name); /* get device name (typically "tun0") */ -#else +#else /* not CENV_SYS_LINUX */ do { #if OSN_USE_IPONLY sprintf(tunname, "/dev/tun%d", ++i); #else sprintf(tunname, "/dev/tap%d", ++i); -#endif +#endif /* not CENV_SYS_LINUX */ } while ((fd = open(tunname, O_RDWR)) < 0 && errno == EBUSY); if (fd < 0) @@ -2012,7 +1760,8 @@ osn_pfinit(struct osnpf *osnpf, void *arg) /* * Too bad that this is never called... */ -osn_pfdeinit() +void +osn_pfdeinit(void) { #if KLH10_NET_TAP_BRIDGE void tap_bridge_close(); @@ -2022,7 +1771,7 @@ osn_pfdeinit() #if KLH10_NET_TAP_BRIDGE -osn_pfinit(register struct osnpf *osnpf, void *arg) +osn_pfinit(struct osnpf *osnpf, void *arg) { int fd; char *ifnam = osnpf->osnpf_ifnam; diff --git a/src/osdnet.h b/src/osdnet.h index da9d10e..2334084 100644 --- a/src/osdnet.h +++ b/src/osdnet.h @@ -201,12 +201,14 @@ /* Determine whether: * (1) sockaddr contains sa_len (NETIF_HAS_SALEN) - * (2) ifconf provides physical link addrs (NETIF_HAS_ETHLINK) + * (2) ifconf provides physical link addrs (NETIF_HAS_AF_LINK or + * NETIF_HAS_AF_PACKET) * (3) ARP ioctls exist (NETIF_HAS_ARPIOCTL) * * 4.4BSD DECOSF SunOS Solaris Linux * NETIF_HAS_SALEN yes yes no no no - * NETIF_HAS_ETHLINK yes yes no no no + * NETIF_HAS_AF_LINK yes yes no no no + * NETIF_HAS_AF_PACKET no ? ? ? yes * NETIF_HAS_ARPIOCTL no yes yes yes yes */ #ifndef NETIF_HAS_SALEN /* If not explicitly told, see if known OS */ @@ -224,17 +226,31 @@ # endif #endif +#if !defined(NETIF_HAS_AF_PACKET) +#if CENV_SYS_LINUX || defined(AF_PACKET) +#define NETIF_HAS_AF_PACKET 1 +#else +#define NETIF_HAS_AF_PACKET 0 +#endif +#endif /* !defined(NETIF_HAS_AF_PACKET) */ + +#if NETIF_HAS_AF_PACKET +#include /* For struct sockaddr_ll */ +#endif /* NETIF_HAS_AF_PACKET */ + + #if NETIF_HAS_SALEN # ifdef AF_LINK # include /* For sockaddr_dl */ +# include /* For IFT_ETHER */ # endif # ifdef LLADDR /* Double-check, make sure this is defined */ -# define NETIF_HAS_ETHLINK 1 +# define NETIF_HAS_AF_LINK 1 # else -# define NETIF_HAS_ETHLINK 0 +# define NETIF_HAS_AF_LINK 0 # endif #else -# define NETIF_HAS_ETHLINK 0 +# define NETIF_HAS_AF_LINK 0 #endif #ifdef SIOCGARP @@ -243,6 +259,19 @@ # define NETIF_HAS_ARPIOCTL 0 #endif +#define HAVE_GETIFADDRS 1 /* assume this for now */ +#define HAVE_LIBPCAP 1 /* assume this for now */ + +#if HAVE_LIBPCAP +#include +#endif +#if HAVE_GETIFADDRS +#include +#endif + +#if !HAVE_LIBPCAP && !HAVE_GETIFADDRS +#error "Sorry, can't lookup ethernet interfaces without libpcap or getifaddrs(3)" +#endif /* Interface table entry. This is needed to provide a more generic format that can @@ -351,7 +380,7 @@ union ipaddr { struct in_addr ia_addr; }; -int osn_iftab_init(int); +int osn_iftab_init(void); int osn_nifents(void); /* # of entries cached by osn_iftab_init */ int osn_ifsock(char *ifnam, ossock_t *); @@ -361,7 +390,7 @@ void osn_ifctab_show(FILE *f, struct ifconf *ifc); int osn_ifipget(int s, char *ifnam, unsigned char *ipa); int osn_ifnmget(int s, char *ifnam, unsigned char *ipa); int osn_pfeaget(int s, char *ifnam, unsigned char *eap); -int osn_ifeaget(int s, char *ifnam, unsigned char *eap, unsigned char *def); +int osn_ifeaget2(char *ifnam, unsigned char *eap); #if !OSN_USE_IPONLY int osn_ifeaset(int s, char *ifnam, unsigned char *newpa); int osn_ifmcset(int s, char *ifc, int delf, unsigned char *pa); @@ -371,6 +400,8 @@ struct ifent *osn_ipdefault(void); struct ifent *osn_iftab_arp(struct in_addr ia); int osn_iftab_arpget(struct in_addr ia, unsigned char *eap); +int osn_ifealookup(char *ifnam, unsigned char *eap); + #define OSN_EASTRSIZ sizeof("xx:xx:xx:xx:xx:xxZZ") char *eth_adrsprint(char *cp, unsigned char *ea); @@ -390,5 +421,6 @@ struct osnpf { /* Arg struct for common initialization params */ struct ether_addr osnpf_ea; /* OUT: ether address of ifc */ }; int osn_pfinit(struct osnpf *, void *); +void osn_pfdeinit(void); #endif /* ifndef OSDNET_INCLUDED */