freebsd-skq/libexec/bootpd/getif.c
Robert Watson 45c0d45bb5 Emply contemporary function prototypes in bootpd, rather than relying on
locally defined K&R prototypes in .c files; use appropriate casts for
pointer types now that types for arguments are available at compile time.
This ensures that compilers with multiple incompatible calling conventions
can select the correct calling convention for external functions.

Sponsored by:	DARPA, AFRL
MFC after:	1 week
2017-03-26 14:37:12 +00:00

148 lines
3.0 KiB
C

/*
* getif.c : get an interface structure
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#if defined(SUNOS) || defined(SVR4)
#include <sys/sockio.h>
#endif
#ifdef SVR4
#include <sys/stropts.h>
#endif
#include <sys/time.h> /* for struct timeval in net/if.h */
#include <net/if.h> /* for struct ifreq */
#include <netinet/in.h>
#ifndef NO_UNISTD
#include <unistd.h>
#endif
#include <syslog.h>
#include <errno.h>
#include <assert.h>
#include "getif.h"
#include "report.h"
#ifdef __bsdi__
#define BSD 43
#endif
static struct ifreq ifreq[10]; /* Holds interface configuration */
static struct ifconf ifconf; /* points to ifreq */
static int nmatch(u_char *ca, u_char *cb);
/* Return a pointer to the interface struct for the passed address. */
struct ifreq *
getif(s, addrp)
int s; /* socket file descriptor */
struct in_addr *addrp; /* destination address on interface */
{
int maxmatch;
int len, m, incr;
struct ifreq *ifrq, *ifrmax;
struct sockaddr_in *sip;
char *p;
/* If no address was supplied, just return NULL. */
if (!addrp)
return (struct ifreq *) 0;
/* Get the interface config if not done already. */
if (ifconf.ifc_len == 0) {
#ifdef SVR4
/*
* SysVr4 returns garbage if you do this the obvious way!
* This one took a while to figure out... -gwr
*/
struct strioctl ioc;
ioc.ic_cmd = SIOCGIFCONF;
ioc.ic_timout = 0;
ioc.ic_len = sizeof(ifreq);
ioc.ic_dp = (char *) ifreq;
m = ioctl(s, I_STR, (char *) &ioc);
ifconf.ifc_len = ioc.ic_len;
ifconf.ifc_req = ifreq;
#else /* SVR4 */
ifconf.ifc_len = sizeof(ifreq);
ifconf.ifc_req = ifreq;
m = ioctl(s, SIOCGIFCONF, (caddr_t) & ifconf);
#endif /* SVR4 */
if ((m < 0) || (ifconf.ifc_len <= 0)) {
report(LOG_ERR, "ioctl SIOCGIFCONF");
return (struct ifreq *) 0;
}
}
maxmatch = 7; /* this many bits or less... */
ifrmax = (struct ifreq *) 0;/* ... is not a valid match */
p = (char *) ifreq;
len = ifconf.ifc_len;
while (len > 0) {
ifrq = (struct ifreq *) p;
sip = (struct sockaddr_in *) &ifrq->ifr_addr;
m = nmatch((u_char *)addrp, (u_char *)&(sip->sin_addr));
if (m > maxmatch) {
maxmatch = m;
ifrmax = ifrq;
}
#ifndef IFNAMSIZ
/* BSD not defined or earlier than 4.3 */
incr = sizeof(*ifrq);
#else
incr = ifrq->ifr_addr.sa_len + IFNAMSIZ;
#endif
p += incr;
len -= incr;
}
return ifrmax;
}
/*
* Return the number of leading bits matching in the
* internet addresses supplied.
*/
static int
nmatch(ca, cb)
u_char *ca, *cb; /* ptrs to IP address, network order */
{
u_int m = 0; /* count of matching bits */
u_int n = 4; /* bytes left, then bitmask */
/* Count matching bytes. */
while (n && (*ca == *cb)) {
ca++;
cb++;
m += 8;
n--;
}
/* Now count matching bits. */
if (n) {
n = 0x80;
while (n && ((*ca & n) == (*cb & n))) {
m++;
n >>= 1;
}
}
return (m);
}
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/