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 /* 43 * Return a pointer to the interface struct for the passed address. 44 * 45 * s socket file descriptor 46 * addrp destination address on interface 47 */ 48 struct ifreq * 49 getif(int s, struct in_addr *addrp) 50 { 51 int maxmatch; 52 int len, m, incr; 53 struct ifreq *ifrq, *ifrmax; 54 struct sockaddr_in *sip; 55 char *p; 56 57 /* If no address was supplied, just return NULL. */ 58 if (!addrp) 59 return NULL; 60 61 /* Get the interface config if not done already. */ 62 if (ifconf.ifc_len == 0) { 63 #ifdef SVR4 64 /* 65 * SysVr4 returns garbage if you do this the obvious way! 66 * This one took a while to figure out... -gwr 67 */ 68 struct strioctl ioc; 69 ioc.ic_cmd = SIOCGIFCONF; 70 ioc.ic_timout = 0; 71 ioc.ic_len = sizeof(ifreq); 72 ioc.ic_dp = (char *) ifreq; 73 m = ioctl(s, I_STR, (char *) &ioc); 74 ifconf.ifc_len = ioc.ic_len; 75 ifconf.ifc_req = ifreq; 76 #else /* SVR4 */ 77 ifconf.ifc_len = sizeof(ifreq); 78 ifconf.ifc_req = ifreq; 79 m = ioctl(s, SIOCGIFCONF, (caddr_t) & ifconf); 80 #endif /* SVR4 */ 81 if ((m < 0) || (ifconf.ifc_len <= 0)) { 82 report(LOG_ERR, "ioctl SIOCGIFCONF"); 83 return NULL; 84 } 85 } 86 maxmatch = 7; /* this many bits or less... */ 87 ifrmax = NULL; /* ... is not a valid match */ 88 p = (char *) ifreq; 89 len = ifconf.ifc_len; 90 while (len > 0) { 91 ifrq = (struct ifreq *) p; 92 sip = (struct sockaddr_in *) &ifrq->ifr_addr; 93 m = nmatch(addrp, &(sip->sin_addr)); 94 if (m > maxmatch) { 95 maxmatch = m; 96 ifrmax = ifrq; 97 } 98 #ifndef IFNAMSIZ 99 /* BSD not defined or earlier than 4.3 */ 100 incr = sizeof(*ifrq); 101 #else 102 incr = ifrq->ifr_addr.sa_len + IFNAMSIZ; 103 #endif 104 105 p += incr; 106 len -= incr; 107 } 108 109 return ifrmax; 110 } 111 112 /* 113 * Return the number of leading bits matching in the 114 * internet addresses supplied. 115 * 116 * ca, cb ptrs to IP address, network order 117 */ 118 static int 119 nmatch(u_char *ca, u_char *cb) 120 { 121 u_int m = 0; /* count of matching bits */ 122 u_int n = 4; /* bytes left, then bitmask */ 123 124 /* Count matching bytes. */ 125 while (n && (*ca == *cb)) { 126 ca++; 127 cb++; 128 m += 8; 129 n--; 130 } 131 /* Now count matching bits. */ 132 if (n) { 133 n = 0x80; 134 while (n && ((*ca & n) == (*cb & n))) { 135 m++; 136 n >>= 1; 137 } 138 } 139 return (m); 140 } 141 142 /* 143 * Local Variables: 144 * tab-width: 4 145 * c-indent-level: 4 146 * c-argdecl-indent: 4 147 * c-continued-statement-offset: 4 148 * c-continued-brace-offset: -4 149 * c-label-offset: -4 150 * c-brace-offset: 0 151 * End: 152 */ 153