1 /* 2 * Copyright (c) 1992 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Lawrence Berkeley Laboratory and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * from @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp (LBL) 38 * $Id: bootp.c,v 1.1 1994/05/08 16:11:17 brezak Exp $ 39 */ 40 41 #include <sys/types.h> 42 #include <netinet/in.h> 43 #include <netinet/in_systm.h> 44 45 #include <string.h> 46 47 #include "stand.h" 48 #include "net.h" 49 #include "netif.h" 50 #include "bootp.h" 51 52 static n_long nmask, smask; 53 54 static time_t bot; 55 56 static char vm_rfc1048[4] = VM_RFC1048; 57 static char vm_cmu[4] = VM_CMU; 58 59 /* Local forwards */ 60 static int bootpsend __P((struct iodesc *, void *, int)); 61 static int bootprecv __P((struct iodesc*, void *, int)); 62 static void vend_cmu __P((u_char *)); 63 static void vend_rfc1048 __P((u_char *, u_int)); 64 65 /* Fetch required bootp infomation */ 66 void 67 bootp(sock) 68 int sock; 69 { 70 struct iodesc *d; 71 register struct bootp *bp; 72 register void *pkt; 73 struct { 74 u_char header[HEADER_SIZE]; 75 struct bootp wbootp; 76 } wbuf; 77 union { 78 u_char buffer[RECV_SIZE]; 79 struct { 80 u_char header[HEADER_SIZE]; 81 struct bootp xrbootp; 82 }xrbuf; 83 #define rbootp xrbuf.xrbootp 84 } rbuf; 85 86 #ifdef BOOTP_DEBUG 87 if (debug) 88 printf("bootp: socket=%d\n", sock); 89 #endif 90 if (!bot) 91 bot = getsecs(); 92 93 if (!(d = socktodesc(sock))) { 94 printf("bootp: bad socket. %d\n", sock); 95 return; 96 } 97 #ifdef BOOTP_DEBUG 98 if (debug) 99 printf("bootp: d=%x\n", (u_int)d); 100 #endif 101 bp = &wbuf.wbootp; 102 pkt = &rbuf.rbootp; 103 pkt -= HEADER_SIZE; 104 105 bzero(bp, sizeof(*bp)); 106 107 bp->bp_op = BOOTREQUEST; 108 bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ 109 bp->bp_hlen = 6; 110 MACPY(d->myea, bp->bp_chaddr); 111 112 d->xid = 0; 113 d->myip = myip; 114 d->myport = IPPORT_BOOTPC; 115 d->destip = INADDR_BROADCAST; 116 d->destport = IPPORT_BOOTPS; 117 118 (void)sendrecv(d, 119 bootpsend, bp, sizeof(*bp), 120 bootprecv, pkt, RECV_SIZE); 121 } 122 123 /* Transmit a bootp request */ 124 static int 125 bootpsend(d, pkt, len) 126 register struct iodesc *d; 127 register void *pkt; 128 register int len; 129 { 130 register struct bootp *bp; 131 132 #ifdef BOOTP_DEBUG 133 if (debug) 134 printf("bootpsend: d=%x called.\n", (u_int)d); 135 #endif 136 bp = pkt; 137 bzero(bp->bp_file, sizeof(bp->bp_file)); 138 bcopy(vm_rfc1048, bp->bp_vend, sizeof(long)); 139 bp->bp_xid = d->xid; 140 bp->bp_secs = (u_long)(getsecs() - bot); 141 #ifdef BOOTP_DEBUG 142 if (debug) 143 printf("bootpsend: calling sendudp\n"); 144 #endif 145 return (sendudp(d, pkt, len)); 146 } 147 148 /* Returns 0 if this is the packet we're waiting for else -1 (and errno == 0) */ 149 static int 150 bootprecv(d, pkt, len) 151 register struct iodesc *d; 152 register void *pkt; 153 int len; 154 { 155 register struct bootp *bp; 156 157 #ifdef BOOTP_DEBUG 158 if (debug) 159 printf("bootprecv: called\n"); 160 #endif 161 bp = (struct bootp *)checkudp(d, pkt, &len); 162 #ifdef BOOTP_DEBUG 163 if (debug) 164 printf("bootprecv: checked. bp = 0x%x, len = %d\n", 165 (unsigned)bp, len); 166 #endif 167 if (bp == NULL || len < sizeof(*bp) || bp->bp_xid != d->xid) { 168 #ifdef BOOTP_DEBUG 169 if (debug) { 170 printf("bootprecv: not for us.\n"); 171 if (bp == NULL) 172 printf("bootprecv: bp null\n"); 173 else { 174 if (len < sizeof(*bp)) 175 printf("bootprecv: expected %d bytes, got %d\n", 176 sizeof(*bp), len); 177 if (bp->bp_xid != d->xid) 178 printf("bootprecv: expected xid 0x%x, got 0x%x\n", 179 d->xid, bp->bp_xid); 180 } 181 } 182 #endif 183 errno = 0; 184 return (-1); 185 } 186 187 /* Bump xid so next request will be unique */ 188 ++d->xid; 189 190 #ifdef BOOTP_DEBUG 191 if (debug) 192 printf("bootprecv: got one!\n"); 193 #endif 194 195 /* Pick up our ip address (and natural netmask) */ 196 myip = d->myip = ntohl(bp->bp_yiaddr.s_addr); 197 #ifdef BOOTP_DEBUG 198 if (debug) 199 printf("our ip address is %s\n", intoa(d->myip)); 200 #endif 201 if (IN_CLASSA(d->myip)) 202 nmask = IN_CLASSA_NET; 203 else if (IN_CLASSB(d->myip)) 204 nmask = IN_CLASSB_NET; 205 else 206 nmask = IN_CLASSC_NET; 207 #ifdef BOOTP_DEBUG 208 if (debug) 209 printf("'native netmask' is %s\n", intoa(nmask)); 210 #endif 211 212 /* Pick up root or swap server address and file spec */ 213 if (bp->bp_siaddr.s_addr != 0) { 214 rootip = ntohl(bp->bp_siaddr.s_addr); 215 } 216 if (bp->bp_file[0] != '\0') { 217 strncpy(bootfile, (char *)bp->bp_file, 218 sizeof(bootfile)); 219 bootfile[sizeof(bootfile) - 1] = '\0'; 220 } 221 222 /* Suck out vendor info */ 223 if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0) 224 vend_cmu(bp->bp_vend); 225 else if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) 226 vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)); 227 else 228 printf("bootprecv: unknown vendor 0x%x\n", (int)bp->bp_vend); 229 230 /* Check subnet mask against net mask; toss if bogus */ 231 if ((nmask & smask) != nmask) { 232 #ifdef BOOTP_DEBUG 233 if (debug) 234 printf("subnet mask (%s) bad\n", intoa(smask)); 235 #endif 236 smask = 0; 237 } 238 239 /* Get subnet (or natural net) mask */ 240 mask = nmask; 241 if (smask) 242 mask = smask; 243 #ifdef BOOTP_DEBUG 244 if (debug) 245 printf("mask: %s\n", intoa(mask)); 246 #endif 247 248 /* We need a gateway if root or swap is on a different net */ 249 if (!SAMENET(d->myip, rootip, mask)) { 250 #ifdef BOOTP_DEBUG 251 if (debug) 252 printf("need gateway for root ip\n"); 253 #endif 254 } 255 if (!SAMENET(d->myip, swapip, mask)) { 256 #ifdef BOOTP_DEBUG 257 if (debug) 258 printf("need gateway for swap ip\n"); 259 #endif 260 } 261 262 /* Toss gateway if on a different net */ 263 if (!SAMENET(d->myip, gateip, mask)) { 264 #ifdef BOOTP_DEBUG 265 if (debug) 266 printf("gateway ip (%s) bad\n", intoa(gateip)); 267 #endif 268 gateip = 0; 269 } 270 return (0); 271 } 272 273 static void 274 vend_cmu(cp) 275 u_char *cp; 276 { 277 register struct cmu_vend *vp; 278 279 #ifdef BOOTP_DEBUG 280 if (debug) 281 printf("vend_cmu bootp info.\n"); 282 #endif 283 vp = (struct cmu_vend *)cp; 284 285 if (vp->v_smask.s_addr != 0) { 286 smask = ntohl(vp->v_smask.s_addr); 287 } 288 if (vp->v_dgate.s_addr != 0) { 289 gateip = ntohl(vp->v_dgate.s_addr); 290 } 291 } 292 293 static void 294 vend_rfc1048(cp, len) 295 register u_char *cp; 296 u_int len; 297 { 298 register u_char *ep; 299 register int size; 300 register u_char tag; 301 302 #ifdef BOOTP_DEBUG 303 if (debug) 304 printf("vend_rfc1048 bootp info. len=%d\n", len); 305 #endif 306 ep = cp + len; 307 308 /* Step over magic cookie */ 309 cp += sizeof(long); 310 311 while (cp < ep) { 312 tag = *cp++; 313 size = *cp++; 314 if (tag == TAG_END) 315 break; 316 317 if (tag == TAG_SUBNET_MASK) { 318 bcopy(cp, &smask, sizeof(smask)); 319 smask = ntohl(smask); 320 } 321 if (tag == TAG_GATEWAY) { 322 bcopy(cp, &gateip, sizeof(gateip)); 323 gateip = ntohl(gateip); 324 } 325 if (tag == TAG_SWAPSERVER) { 326 bcopy(cp, &swapip, sizeof(swapip)); 327 swapip = ntohl(swapip); 328 } 329 if (tag == TAG_DOMAIN_SERVER) { 330 bcopy(cp, &nameip, sizeof(nameip)); 331 nameip = ntohl(nameip); 332 } 333 if (tag == TAG_ROOTPATH) { 334 strncpy(rootpath, cp, sizeof(rootpath)); 335 rootpath[size] = '\0'; 336 } 337 if (tag == TAG_HOSTNAME) { 338 strncpy(hostname, cp, sizeof(hostname)); 339 hostname[size] = '\0'; 340 } 341 if (tag == TAG_DOMAINNAME) { 342 strncpy(domainname, cp, sizeof(domainname)); 343 domainname[size] = '\0'; 344 } 345 cp += size; 346 } 347 } 348