1 /* $OpenBSD: device.c,v 1.4 2000/02/20 17:45:33 bitblt Exp $ */ 2 3 /* 4 * Copyright (c) 1993-95 Mats O Jansson. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Mats O Jansson. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #ifndef LINT 33 static char rcsid[] = "$OpenBSD: device.c,v 1.4 2000/02/20 17:45:33 bitblt Exp $"; 34 #endif 35 36 #include "os.h" 37 #include "common/common.h" 38 #include "common/mopdef.h" 39 40 struct if_info *iflist; /* Interface List */ 41 42 void mopReadDL(); 43 void mopReadRC(); 44 #ifdef NO__P 45 int mopOpenDL(/* struct if_info *, int */); 46 int mopOpenRC(/* struct if_info *, int */); 47 #else 48 int mopOpenDL(struct if_info *, int); 49 int mopOpenRC(struct if_info *, int); 50 #endif 51 int pfTrans(); 52 int pfInit(); 53 int pfWrite(); 54 55 #ifdef DEV_NEW_CONF 56 /* 57 * Return ethernet adress for interface 58 */ 59 60 void 61 deviceEthAddr(ifname, eaddr) 62 char *ifname; 63 u_char *eaddr; 64 { 65 char inbuf[8192]; 66 struct ifconf ifc; 67 struct ifreq *ifr; 68 struct sockaddr_dl *sdl; 69 int fd; 70 int i, len; 71 72 /* We cannot use SIOCGIFADDR on the BPF descriptor. 73 We must instead get all the interfaces with SIOCGIFCONF 74 and find the right one. */ 75 76 /* Use datagram socket to get Ethernet address. */ 77 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 78 syslog(LOG_ERR, "deviceEthAddr: socket: %m"); 79 exit(1); 80 } 81 82 ifc.ifc_len = sizeof(inbuf); 83 ifc.ifc_buf = inbuf; 84 if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 || 85 ifc.ifc_len < sizeof(struct ifreq)) { 86 syslog(LOG_ERR, "deviceEthAddr: SIOGIFCONF: %m"); 87 exit(1); 88 } 89 ifr = ifc.ifc_req; 90 for (i = 0; i < ifc.ifc_len; 91 i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) { 92 len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len; 93 sdl = (struct sockaddr_dl *)&ifr->ifr_addr; 94 if (sdl->sdl_family != AF_LINK || sdl->sdl_type != IFT_ETHER || 95 sdl->sdl_alen != 6) 96 continue; 97 if (!strncmp(ifr->ifr_name, ifname, sizeof(ifr->ifr_name))) { 98 bcopy((caddr_t)LLADDR(sdl), (caddr_t)eaddr, 6); 99 return; 100 } 101 } 102 103 syslog(LOG_ERR, "deviceEthAddr: Never saw interface `%s'!", ifname); 104 exit(1); 105 } 106 #endif /* DEV_NEW_CONF */ 107 108 void 109 deviceOpen(ifname, proto, trans) 110 char *ifname; 111 u_short proto; 112 int trans; 113 { 114 struct if_info *p, tmp; 115 116 strncpy(tmp.if_name,ifname,sizeof(tmp.if_name) - 1); 117 tmp.if_name[sizeof(tmp.if_name)] = 0; 118 tmp.iopen = pfInit; 119 120 switch (proto) { 121 case MOP_K_PROTO_RC: 122 tmp.read = mopReadRC; 123 tmp.fd = mopOpenRC(&tmp, trans); 124 break; 125 case MOP_K_PROTO_DL: 126 tmp.read = mopReadDL; 127 tmp.fd = mopOpenDL(&tmp, trans); 128 break; 129 default: 130 break; 131 } 132 133 if (tmp.fd != -1) { 134 135 p = (struct if_info *)malloc(sizeof(*p)); 136 if (p == 0) { 137 syslog(LOG_ERR, "deviceOpen: malloc: %m"); 138 exit(1); 139 } 140 141 p->next = iflist; 142 iflist = p; 143 144 strncpy(p->if_name,tmp.if_name, IFNAME_SIZE -1); 145 p->if_name[IFNAME_SIZE -1] = 0; 146 p->iopen = tmp.iopen; 147 p->write = pfWrite; 148 p->read = tmp.read; 149 bzero((char *)p->eaddr,sizeof(p->eaddr)); 150 p->fd = tmp.fd; 151 152 #ifdef DEV_NEW_CONF 153 deviceEthAddr(p->if_name,&p->eaddr[0]); 154 #else 155 p->eaddr[0]= tmp.eaddr[0]; 156 p->eaddr[1]= tmp.eaddr[1]; 157 p->eaddr[2]= tmp.eaddr[2]; 158 p->eaddr[3]= tmp.eaddr[3]; 159 p->eaddr[4]= tmp.eaddr[4]; 160 p->eaddr[5]= tmp.eaddr[5]; 161 #endif /* DEV_NEW_CONF */ 162 163 #ifdef LINUX2_PF 164 { 165 int s; 166 167 s = socket(AF_INET,SOCK_DGRAM,0); 168 pfEthAddr(s,p->if_name,&p->eaddr[0]); 169 (void) close(s); 170 171 } 172 #endif 173 } 174 } 175 176 void 177 deviceInitOne(ifname) 178 char *ifname; 179 { 180 char interface[IFNAME_SIZE]; 181 struct if_info *p; 182 int trans; 183 #ifdef _AIX 184 char dev[IFNAME_SIZE]; 185 int unit,j; 186 187 unit = 0; 188 for (j = 0; j < strlen(ifname); j++) { 189 if (isalpha(ifname[j])) { 190 dev[j] = ifname[j]; 191 } else { 192 if (isdigit(ifname[j])) { 193 unit = unit*10 + ifname[j] - '0'; 194 dev[j] = '\0'; 195 } 196 } 197 } 198 199 if ((strlen(dev) == 2) && 200 (dev[0] == 'e') && 201 ((dev[1] == 'n') || (dev[1] == 't'))) { 202 snprintf(interface,sizeof(interface),"ent%d\0",unit); 203 } else { 204 snprintf(interface,sizeof(interface),"%s%d\0",dev,unit); 205 } 206 #else 207 snprintf(interface,sizeof(interface),"%s",ifname); 208 #endif /* _AIX */ 209 210 /* Ok, init it just once */ 211 212 p = iflist; 213 for (p = iflist; p; p = p->next) { 214 if (strcmp(p->if_name,interface) == 0) { 215 return; 216 } 217 } 218 219 syslog(LOG_INFO, "Initialized %s", interface); 220 221 /* Ok, get transport information */ 222 223 trans = pfTrans(interface); 224 225 #ifndef NORC 226 /* Start with MOP Remote Console */ 227 228 switch (trans) { 229 case TRANS_ETHER: 230 deviceOpen(interface,MOP_K_PROTO_RC,TRANS_ETHER); 231 break; 232 case TRANS_8023: 233 deviceOpen(interface,MOP_K_PROTO_RC,TRANS_8023); 234 break; 235 case TRANS_ETHER+TRANS_8023: 236 deviceOpen(interface,MOP_K_PROTO_RC,TRANS_ETHER); 237 deviceOpen(interface,MOP_K_PROTO_RC,TRANS_8023); 238 break; 239 case TRANS_ETHER+TRANS_8023+TRANS_AND: 240 deviceOpen(interface,MOP_K_PROTO_RC,TRANS_ETHER+TRANS_8023); 241 break; 242 } 243 #endif 244 245 #ifndef NODL 246 /* and next MOP Dump/Load */ 247 248 switch (trans) { 249 case TRANS_ETHER: 250 deviceOpen(interface,MOP_K_PROTO_DL,TRANS_ETHER); 251 break; 252 case TRANS_8023: 253 deviceOpen(interface,MOP_K_PROTO_DL,TRANS_8023); 254 break; 255 case TRANS_ETHER+TRANS_8023: 256 deviceOpen(interface,MOP_K_PROTO_DL,TRANS_ETHER); 257 deviceOpen(interface,MOP_K_PROTO_DL,TRANS_8023); 258 break; 259 case TRANS_ETHER+TRANS_8023+TRANS_AND: 260 deviceOpen(interface,MOP_K_PROTO_DL,TRANS_ETHER+TRANS_8023); 261 break; 262 } 263 #endif 264 265 } 266 267 /* 268 * Initialize all "candidate" interfaces that are in the system 269 * configuration list. A "candidate" is up, not loopback and not 270 * point to point. 271 */ 272 void 273 deviceInitAll() 274 { 275 #ifdef DEV_NEW_CONF 276 char inbuf[8192]; 277 struct ifconf ifc; 278 struct ifreq *ifr; 279 struct sockaddr_dl *sdl; 280 int fd; 281 int i, len; 282 283 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 284 syslog(LOG_ERR, "deviceInitAll: socket: %m"); 285 exit(1); 286 } 287 288 ifc.ifc_len = sizeof(inbuf); 289 ifc.ifc_buf = inbuf; 290 if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 || 291 ifc.ifc_len < sizeof(struct ifreq)) { 292 syslog(LOG_ERR, "deviceInitAll: SIOCGIFCONF: %m"); 293 exit(1); 294 } 295 ifr = ifc.ifc_req; 296 for (i = 0; i < ifc.ifc_len; 297 i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) { 298 len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len; 299 sdl = (struct sockaddr_dl *)&ifr->ifr_addr; 300 if (sdl->sdl_family != AF_LINK || sdl->sdl_type != IFT_ETHER || 301 sdl->sdl_alen != 6) 302 continue; 303 if (ioctl(fd, SIOCGIFFLAGS, (caddr_t)ifr) < 0) { 304 syslog(LOG_ERR, "deviceInitAll: SIOCGIFFLAGS: %m"); 305 continue; 306 } 307 if ((ifr->ifr_flags & 308 (IFF_UP | IFF_LOOPBACK | IFF_POINTOPOINT)) != IFF_UP) 309 continue; 310 deviceInitOne(ifr->ifr_name); 311 } 312 (void) close(fd); 313 #else 314 int fd; 315 int n; 316 struct ifreq ibuf[8], *ifrp; 317 struct ifconf ifc; 318 319 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 320 syslog(LOG_ERR, "deviceInitAll: old socket: %m"); 321 exit(1); 322 } 323 ifc.ifc_len = sizeof ibuf; 324 ifc.ifc_buf = (caddr_t)ibuf; 325 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || 326 ifc.ifc_len < sizeof(struct ifreq)) { 327 syslog(LOG_ERR, "deviceInitAll: old SIOCGIFCONF: %m"); 328 exit(1); 329 } 330 ifrp = ibuf; 331 n = ifc.ifc_len / sizeof(*ifrp); 332 for (; --n >= 0; ++ifrp) { 333 if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) { 334 continue; 335 } 336 if (/*(ifrp->ifr_flags & IFF_UP) == 0 ||*/ 337 ifrp->ifr_flags & IFF_LOOPBACK || 338 ifrp->ifr_flags & IFF_POINTOPOINT) 339 continue; 340 deviceInitOne(ifrp->ifr_name); 341 } 342 343 (void) close(fd); 344 #endif /* DEV_NEW_CONF */ 345 } 346