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