summaryrefslogtreecommitdiffstats
path: root/libexec/bootpd/getif.c
blob: ec7cd8f716dbf5300da0e622e65ebc85f9c1f86b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * 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();

/* 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(addrp, &(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:
 */
OpenPOWER on IntegriCloud