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