xref: /dragonfly/libexec/bootpd/getif.c (revision 1de703da)
1 /*
2  * getif.c : get an interface structure
3  *
4  * $FreeBSD: src/libexec/bootpd/getif.c,v 1.7 1999/08/28 00:09:18 peter Exp $
5  * $DragonFly: src/libexec/bootpd/getif.c,v 1.2 2003/06/17 04:27:07 dillon Exp $
6  */
7 
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <sys/ioctl.h>
11 
12 #if defined(SUNOS) || defined(SVR4)
13 #include <sys/sockio.h>
14 #endif
15 #ifdef	SVR4
16 #include <sys/stropts.h>
17 #endif
18 
19 #include <sys/time.h>		/* for struct timeval in net/if.h */
20 #include <net/if.h>				/* for struct ifreq */
21 #include <netinet/in.h>
22 
23 #ifndef	NO_UNISTD
24 #include <unistd.h>
25 #endif
26 #include <syslog.h>
27 #include <errno.h>
28 #include <assert.h>
29 
30 #include "getif.h"
31 #include "report.h"
32 
33 #ifdef	__bsdi__
34 #define BSD 43
35 #endif
36 
37 static struct ifreq ifreq[10];	/* Holds interface configuration */
38 static struct ifconf ifconf;	/* points to ifreq */
39 
40 static int nmatch();
41 
42 /* Return a pointer to the interface struct for the passed address. */
43 struct ifreq *
44 getif(s, addrp)
45 	int s;						/* socket file descriptor */
46 	struct in_addr *addrp;		/* destination address on interface */
47 {
48 	int maxmatch;
49 	int len, m, incr;
50 	struct ifreq *ifrq, *ifrmax;
51 	struct sockaddr_in *sip;
52 	char *p;
53 
54 	/* If no address was supplied, just return NULL. */
55 	if (!addrp)
56 		return (struct ifreq *) 0;
57 
58 	/* Get the interface config if not done already. */
59 	if (ifconf.ifc_len == 0) {
60 #ifdef	SVR4
61 		/*
62 		 * SysVr4 returns garbage if you do this the obvious way!
63 		 * This one took a while to figure out... -gwr
64 		 */
65 		struct strioctl ioc;
66 		ioc.ic_cmd = SIOCGIFCONF;
67 		ioc.ic_timout = 0;
68 		ioc.ic_len = sizeof(ifreq);
69 		ioc.ic_dp = (char *) ifreq;
70 		m = ioctl(s, I_STR, (char *) &ioc);
71 		ifconf.ifc_len = ioc.ic_len;
72 		ifconf.ifc_req = ifreq;
73 #else	/* SVR4 */
74 		ifconf.ifc_len = sizeof(ifreq);
75 		ifconf.ifc_req = ifreq;
76 		m = ioctl(s, SIOCGIFCONF, (caddr_t) & ifconf);
77 #endif	/* SVR4 */
78 		if ((m < 0) || (ifconf.ifc_len <= 0)) {
79 			report(LOG_ERR, "ioctl SIOCGIFCONF");
80 			return (struct ifreq *) 0;
81 		}
82 	}
83 	maxmatch = 7;				/* this many bits or less... */
84 	ifrmax = (struct ifreq *) 0;/* ... is not a valid match  */
85 	p = (char *) ifreq;
86 	len = ifconf.ifc_len;
87 	while (len > 0) {
88 		ifrq = (struct ifreq *) p;
89 		sip = (struct sockaddr_in *) &ifrq->ifr_addr;
90 		m = nmatch(addrp, &(sip->sin_addr));
91 		if (m > maxmatch) {
92 			maxmatch = m;
93 			ifrmax = ifrq;
94 		}
95 #ifndef IFNAMSIZ
96 		/* BSD not defined or earlier than 4.3 */
97 		incr = sizeof(*ifrq);
98 #else
99 		incr = ifrq->ifr_addr.sa_len + IFNAMSIZ;
100 #endif
101 
102 		p += incr;
103 		len -= incr;
104 	}
105 
106 	return ifrmax;
107 }
108 
109 /*
110  * Return the number of leading bits matching in the
111  * internet addresses supplied.
112  */
113 static int
114 nmatch(ca, cb)
115 	u_char *ca, *cb;			/* ptrs to IP address, network order */
116 {
117 	u_int m = 0;				/* count of matching bits */
118 	u_int n = 4;				/* bytes left, then bitmask */
119 
120 	/* Count matching bytes. */
121 	while (n && (*ca == *cb)) {
122 		ca++;
123 		cb++;
124 		m += 8;
125 		n--;
126 	}
127 	/* Now count matching bits. */
128 	if (n) {
129 		n = 0x80;
130 		while (n && ((*ca & n) == (*cb & n))) {
131 			m++;
132 			n >>= 1;
133 		}
134 	}
135 	return (m);
136 }
137 
138 /*
139  * Local Variables:
140  * tab-width: 4
141  * c-indent-level: 4
142  * c-argdecl-indent: 4
143  * c-continued-statement-offset: 4
144  * c-continued-brace-offset: -4
145  * c-label-offset: -4
146  * c-brace-offset: 0
147  * End:
148  */
149