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