1 /* $Id: bootp_subr.c,v 1.14 1998/08/18 00:32:47 bde Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Gordon Ross, Adam Glass 5 * Copyright (c) 1992 Regents of the University of California. 6 * All rights reserved. 7 * 8 * This software was developed by the Computer Systems Engineering group 9 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 10 * contributed to Berkeley. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Lawrence Berkeley Laboratory and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * based on: 41 * nfs/krpc_subr.c 42 * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $ 43 */ 44 45 #include "opt_bootp.h" 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/kernel.h> 50 #include <sys/sockio.h> 51 #include <sys/proc.h> 52 #include <sys/mount.h> 53 #include <sys/mbuf.h> 54 #include <sys/socket.h> 55 #include <sys/socketvar.h> 56 #include <sys/uio.h> 57 58 #include <net/if.h> 59 #include <net/route.h> 60 61 #include <netinet/in.h> 62 #include <net/if_types.h> 63 #include <net/if_dl.h> 64 65 #include <nfs/rpcv2.h> 66 #include <nfs/nfsproto.h> 67 #include <nfs/nfs.h> 68 #include <nfs/nfsdiskless.h> 69 #include <nfs/krpc.h> 70 #include <nfs/xdr_subs.h> 71 72 73 #define BOOTP_MIN_LEN 300 /* Minimum size of bootp udp packet */ 74 75 /* 76 * What is the longest we will wait before re-sending a request? 77 * Note this is also the frequency of "RPC timeout" messages. 78 * The re-send loop count sup linearly to this maximum, so the 79 * first complaint will happen after (1+2+3+4+5)=15 seconds. 80 */ 81 #define MAX_RESEND_DELAY 5 /* seconds */ 82 83 /* Definitions from RFC951 */ 84 struct bootp_packet { 85 u_int8_t op; 86 u_int8_t htype; 87 u_int8_t hlen; 88 u_int8_t hops; 89 u_int32_t xid; 90 u_int16_t secs; 91 u_int16_t flags; 92 struct in_addr ciaddr; 93 struct in_addr yiaddr; 94 struct in_addr siaddr; 95 struct in_addr giaddr; 96 unsigned char chaddr[16]; 97 char sname[64]; 98 char file[128]; 99 unsigned char vend[256]; 100 }; 101 102 #define IPPORT_BOOTPC 68 103 #define IPPORT_BOOTPS 67 104 105 extern int nfs_diskless_valid; 106 extern struct nfsv3_diskless nfsv3_diskless; 107 108 /* mountd RPC */ 109 static int md_mount __P((struct sockaddr_in *mdsin, char *path, 110 u_char *fhp, int *fhsizep, struct nfs_args *args,struct proc *procp)); 111 static int md_lookup_swap __P((struct sockaddr_in *mdsin,char *path, 112 u_char *fhp, int *fhsizep, 113 struct nfs_args *args, 114 struct proc *procp)); 115 static int setfs __P((struct sockaddr_in *addr, char *path, char *p)); 116 static int getdec __P((char **ptr)); 117 static char *substr __P((char *a,char *b)); 118 static void mountopts __P((struct nfs_args *args, char *p)); 119 static int xdr_opaque_decode __P((struct mbuf **ptr,u_char *buf, 120 int len)); 121 static int xdr_int_decode __P((struct mbuf **ptr,int *iptr)); 122 static void printip __P((char *prefix,struct in_addr addr)); 123 124 #ifdef BOOTP_DEBUG 125 void bootpboot_p_sa(struct sockaddr *sa,struct sockaddr *ma); 126 void bootpboot_p_ma(struct sockaddr *ma); 127 void bootpboot_p_rtentry(struct rtentry *rt); 128 void bootpboot_p_tree(struct radix_node *rn); 129 void bootpboot_p_rtlist(void); 130 void bootpboot_p_iflist(void); 131 #endif 132 133 static int bootpc_call(struct bootp_packet *call, 134 struct bootp_packet *reply, 135 struct proc *procp); 136 137 static int bootpc_fakeup_interface(struct ifreq *ireq, 138 struct socket *so, 139 struct proc *procp); 140 141 static int 142 bootpc_adjust_interface(struct ifreq *ireq,struct socket *so, 143 struct sockaddr_in *myaddr, 144 struct sockaddr_in *netmask, 145 struct sockaddr_in *gw, 146 struct proc *procp); 147 148 void bootpc_init(void); 149 150 #ifdef BOOTP_DEBUG 151 void bootpboot_p_sa(sa,ma) 152 struct sockaddr *sa; 153 struct sockaddr *ma; 154 { 155 if (!sa) { 156 printf("(sockaddr *) <null>"); 157 return; 158 } 159 switch (sa->sa_family) { 160 case AF_INET: 161 { 162 struct sockaddr_in *sin = (struct sockaddr_in *) sa; 163 printf("inet %x",ntohl(sin->sin_addr.s_addr)); 164 if (ma) { 165 struct sockaddr_in *sin = (struct sockaddr_in *) ma; 166 printf(" mask %x",ntohl(sin->sin_addr.s_addr)); 167 } 168 } 169 break; 170 case AF_LINK: 171 { 172 struct sockaddr_dl *sli = (struct sockaddr_dl *) sa; 173 int i; 174 printf("link %.*s ",sli->sdl_nlen,sli->sdl_data); 175 for (i=0;i<sli->sdl_alen;i++) { 176 if (i>0) 177 printf(":"); 178 printf("%x",(unsigned char) sli->sdl_data[i+sli->sdl_nlen]); 179 } 180 } 181 break; 182 default: 183 printf("af%d",sa->sa_family); 184 } 185 } 186 187 void bootpboot_p_ma(ma) 188 struct sockaddr *ma; 189 { 190 if (!ma) { 191 printf("<null>"); 192 return; 193 } 194 printf("%x",*(int*)ma); 195 } 196 197 void bootpboot_p_rtentry(rt) 198 struct rtentry *rt; 199 { 200 bootpboot_p_sa(rt_key(rt),rt_mask(rt)); 201 printf(" "); 202 bootpboot_p_ma(rt->rt_genmask); 203 printf(" "); 204 bootpboot_p_sa(rt->rt_gateway,NULL); 205 printf(" "); 206 printf("flags %x",(unsigned short) rt->rt_flags); 207 printf(" %d",rt->rt_rmx.rmx_expire); 208 printf(" %s%d\n",rt->rt_ifp->if_name,rt->rt_ifp->if_unit); 209 } 210 void bootpboot_p_tree(rn) 211 struct radix_node *rn; 212 { 213 while (rn) { 214 if (rn->rn_b < 0) { 215 if (rn->rn_flags & RNF_ROOT) { 216 } else { 217 bootpboot_p_rtentry((struct rtentry *) rn); 218 } 219 rn = rn->rn_dupedkey; 220 } else { 221 bootpboot_p_tree(rn->rn_l); 222 bootpboot_p_tree(rn->rn_r); 223 return; 224 } 225 226 } 227 } 228 229 void bootpboot_p_rtlist(void) 230 { 231 printf("Routing table:\n"); 232 bootpboot_p_tree(rt_tables[AF_INET]->rnh_treetop); 233 } 234 235 void bootpboot_p_iflist(void) 236 { 237 struct ifnet *ifp; 238 struct ifaddr *ifa; 239 printf("Interface list:\n"); 240 for (ifp = TAILQ_FIRST(&ifnet); ifp != 0; ifp = TAILQ_NEXT(ifp,if_link)) 241 { 242 for (ifa = TAILQ_FIRST(&ifp->if_addrhead) ;ifa; 243 ifa=TAILQ_NEXT(ifa,ifa_link)) 244 if (ifa->ifa_addr->sa_family == AF_INET ) { 245 printf("%s%d flags %x, addr %x, bcast %x, net %x\n", 246 ifp->if_name,ifp->if_unit, 247 (unsigned short) ifp->if_flags, 248 ntohl(((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr), 249 ntohl(((struct sockaddr_in *) ifa->ifa_dstaddr)->sin_addr.s_addr), 250 ntohl(((struct sockaddr_in *) ifa->ifa_netmask)->sin_addr.s_addr) 251 ); 252 } 253 } 254 } 255 #endif 256 257 static int 258 bootpc_call(call,reply,procp) 259 struct bootp_packet *call; 260 struct bootp_packet *reply; /* output */ 261 struct proc *procp; 262 { 263 struct socket *so; 264 struct sockaddr_in *sin, sa; 265 struct mbuf *m; 266 struct uio auio; 267 struct sockopt sopt; 268 struct iovec aio; 269 struct timeval tv; 270 int error, on, len, rcvflg, secs, timo; 271 u_int tport; 272 273 /* 274 * Create socket and set its recieve timeout. 275 */ 276 if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp))) 277 goto out; 278 279 tv.tv_sec = 1; 280 tv.tv_usec = 0; 281 bzero(&sopt, sizeof sopt); 282 sopt.sopt_level = SOL_SOCKET; 283 sopt.sopt_name = SO_RCVTIMEO; 284 sopt.sopt_val = &tv; 285 sopt.sopt_valsize = sizeof tv; 286 287 if (error = sosetopt(so, &sopt)) 288 goto out; 289 290 /* 291 * Enable broadcast. 292 */ 293 on = 1; 294 sopt.sopt_val = &on; 295 sopt.sopt_valsize = sizeof on; 296 sopt.sopt_name = SO_BROADCAST; 297 if (error = sosetopt(so, &sopt)) 298 goto out; 299 300 /* 301 * Bind the local endpoint to a bootp client port. 302 */ 303 sin = &sa; 304 bzero(sin, sizeof *sin); 305 sin->sin_len = sizeof(*sin); 306 sin->sin_family = AF_INET; 307 sin->sin_addr.s_addr = INADDR_ANY; 308 sin->sin_port = htons(IPPORT_BOOTPC); 309 error = sobind(so, (struct sockaddr *)sin, procp); 310 if (error) { 311 printf("bind failed\n"); 312 goto out; 313 } 314 315 /* 316 * Setup socket address for the server. 317 */ 318 sin = &sa; 319 bzero(sin, sizeof *sin); 320 sin->sin_len = sizeof(*sin); 321 sin->sin_family = AF_INET; 322 sin->sin_addr.s_addr = INADDR_BROADCAST; 323 sin->sin_port = htons(IPPORT_BOOTPS); 324 325 /* 326 * Send it, repeatedly, until a reply is received, 327 * but delay each re-send by an increasing amount. 328 * If the delay hits the maximum, start complaining. 329 */ 330 timo = 0; 331 for (;;) { 332 /* Send BOOTP request (or re-send). */ 333 334 aio.iov_base = (caddr_t) call; 335 aio.iov_len = sizeof(*call); 336 337 auio.uio_iov = &aio; 338 auio.uio_iovcnt = 1; 339 auio.uio_segflg = UIO_SYSSPACE; 340 auio.uio_rw = UIO_WRITE; 341 auio.uio_offset = 0; 342 auio.uio_resid = sizeof(*call); 343 auio.uio_procp = procp; 344 345 error = sosend(so, (struct sockaddr *)sin, &auio, NULL, 346 NULL, 0, procp); 347 if (error) { 348 printf("bootpc_call: sosend: %d\n", error); 349 goto out; 350 } 351 352 /* Determine new timeout. */ 353 if (timo < MAX_RESEND_DELAY) 354 timo++; 355 else 356 printf("BOOTP timeout for server 0x%lx\n", 357 (u_long)ntohl(sin->sin_addr.s_addr)); 358 359 /* 360 * Wait for up to timo seconds for a reply. 361 * The socket receive timeout was set to 1 second. 362 */ 363 secs = timo; 364 while (secs > 0) { 365 aio.iov_base = (caddr_t) reply; 366 aio.iov_len = sizeof(*reply); 367 368 auio.uio_iov = &aio; 369 auio.uio_iovcnt = 1; 370 auio.uio_segflg = UIO_SYSSPACE; 371 auio.uio_rw = UIO_READ; 372 auio.uio_offset = 0; 373 auio.uio_resid = sizeof(*reply); 374 auio.uio_procp = procp; 375 376 rcvflg = 0; 377 error = soreceive(so, NULL, &auio, NULL, NULL, &rcvflg); 378 if (error == EWOULDBLOCK) { 379 secs--; 380 call->secs=htons(ntohs(call->secs)+1); 381 continue; 382 } 383 if (error) 384 goto out; 385 len = sizeof(*reply) - auio.uio_resid; 386 387 /* Do we have the required number of bytes ? */ 388 if (len < BOOTP_MIN_LEN) 389 continue; 390 391 /* Is it the right reply? */ 392 if (reply->op != 2) 393 continue; 394 395 if (reply->xid != call->xid) 396 continue; 397 398 if (reply->hlen != call->hlen) 399 continue; 400 401 if (bcmp(reply->chaddr,call->chaddr,call->hlen)) 402 continue; 403 404 goto gotreply; /* break two levels */ 405 406 } /* while secs */ 407 } /* forever send/receive */ 408 409 error = ETIMEDOUT; 410 goto out; 411 412 gotreply: 413 out: 414 soclose(so); 415 return error; 416 } 417 418 static int 419 bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so, 420 struct proc *procp) 421 { 422 struct sockaddr_in *sin; 423 int error; 424 struct sockaddr_in dst; 425 struct sockaddr_in gw; 426 struct sockaddr_in mask; 427 428 /* 429 * Bring up the interface. 430 * 431 * Get the old interface flags and or IFF_UP into them; if 432 * IFF_UP set blindly, interface selection can be clobbered. 433 */ 434 error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp); 435 if (error) 436 panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error); 437 ireq->ifr_flags |= IFF_UP; 438 error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, procp); 439 if (error) 440 panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error); 441 442 /* 443 * Do enough of ifconfig(8) so that the chosen interface 444 * can talk to the servers. (just set the address) 445 */ 446 447 /* addr is 0.0.0.0 */ 448 449 sin = (struct sockaddr_in *)&ireq->ifr_addr; 450 bzero((caddr_t)sin, sizeof(*sin)); 451 sin->sin_len = sizeof(*sin); 452 sin->sin_family = AF_INET; 453 sin->sin_addr.s_addr = INADDR_ANY; 454 error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); 455 if (error) 456 panic("bootpc_fakeup_interface: set if addr, error=%d", error); 457 458 /* netmask is 0.0.0.0 */ 459 460 sin = (struct sockaddr_in *)&ireq->ifr_addr; 461 bzero((caddr_t)sin, sizeof(*sin)); 462 sin->sin_len = sizeof(*sin); 463 sin->sin_family = AF_INET; 464 sin->sin_addr.s_addr = INADDR_ANY; 465 error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp); 466 if (error) 467 panic("bootpc_fakeup_interface: set if net addr, error=%d", error); 468 469 /* Broadcast is 255.255.255.255 */ 470 471 sin = (struct sockaddr_in *)&ireq->ifr_addr; 472 bzero((caddr_t)sin, sizeof(*sin)); 473 sin->sin_len = sizeof(*sin); 474 sin->sin_family = AF_INET; 475 sin->sin_addr.s_addr = INADDR_BROADCAST; 476 error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp); 477 if (error) 478 panic("bootpc_fakeup_interface: set if broadcast addr, error=%d", error); 479 480 /* Add default route to 0.0.0.0 so we can send data */ 481 482 bzero((caddr_t) &dst, sizeof(dst)); 483 dst.sin_len=sizeof(dst); 484 dst.sin_family=AF_INET; 485 dst.sin_addr.s_addr = htonl(0); 486 487 bzero((caddr_t) &gw, sizeof(gw)); 488 gw.sin_len=sizeof(gw); 489 gw.sin_family=AF_INET; 490 gw.sin_addr.s_addr = htonl(0x0); 491 492 bzero((caddr_t) &mask, sizeof(mask)); 493 mask.sin_len=sizeof(mask); 494 mask.sin_family=AF_INET; 495 mask.sin_addr.s_addr = htonl(0); 496 497 error = rtrequest(RTM_ADD, 498 (struct sockaddr *) &dst, 499 (struct sockaddr *) &gw, 500 (struct sockaddr *) &mask, 501 RTF_UP | RTF_STATIC 502 , NULL); 503 if (error) 504 printf("bootpc_fakeup_interface: add default route, error=%d\n", error); 505 return error; 506 } 507 508 static int 509 bootpc_adjust_interface(struct ifreq *ireq,struct socket *so, 510 struct sockaddr_in *myaddr, 511 struct sockaddr_in *netmask, 512 struct sockaddr_in *gw, 513 struct proc *procp) 514 { 515 int error; 516 struct sockaddr_in oldgw; 517 struct sockaddr_in olddst; 518 struct sockaddr_in oldmask; 519 struct sockaddr_in *sin; 520 521 /* Remove old default route to 0.0.0.0 */ 522 523 bzero((caddr_t) &olddst, sizeof(olddst)); 524 olddst.sin_len=sizeof(olddst); 525 olddst.sin_family=AF_INET; 526 olddst.sin_addr.s_addr = INADDR_ANY; 527 528 bzero((caddr_t) &oldgw, sizeof(oldgw)); 529 oldgw.sin_len=sizeof(oldgw); 530 oldgw.sin_family=AF_INET; 531 oldgw.sin_addr.s_addr = INADDR_ANY; 532 533 bzero((caddr_t) &oldmask, sizeof(oldmask)); 534 oldmask.sin_len=sizeof(oldmask); 535 oldmask.sin_family=AF_INET; 536 oldmask.sin_addr.s_addr = INADDR_ANY; 537 538 error = rtrequest(RTM_DELETE, 539 (struct sockaddr *) &olddst, 540 (struct sockaddr *) &oldgw, 541 (struct sockaddr *) &oldmask, 542 (RTF_UP | RTF_STATIC), NULL); 543 if (error) { 544 printf("nfs_boot: del default route, error=%d\n", error); 545 return error; 546 } 547 548 /* 549 * Do enough of ifconfig(8) so that the chosen interface 550 * can talk to the servers. (just set the address) 551 */ 552 bcopy(netmask,&ireq->ifr_addr,sizeof(*netmask)); 553 error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp); 554 if (error) 555 panic("nfs_boot: set if netmask, error=%d", error); 556 557 /* Broadcast is with host part of IP address all 1's */ 558 559 sin = (struct sockaddr_in *)&ireq->ifr_addr; 560 bzero((caddr_t)sin, sizeof(*sin)); 561 sin->sin_len = sizeof(*sin); 562 sin->sin_family = AF_INET; 563 sin->sin_addr.s_addr = myaddr->sin_addr.s_addr | ~ netmask->sin_addr.s_addr; 564 error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp); 565 if (error) 566 panic("bootpc_call: set if broadcast addr, error=%d", error); 567 568 bcopy(myaddr,&ireq->ifr_addr,sizeof(*myaddr)); 569 error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); 570 if (error) 571 panic("nfs_boot: set if addr, error=%d", error); 572 573 /* Add new default route */ 574 575 error = rtrequest(RTM_ADD, 576 (struct sockaddr *) &olddst, 577 (struct sockaddr *) gw, 578 (struct sockaddr *) &oldmask, 579 (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL); 580 if (error) { 581 printf("nfs_boot: add net route, error=%d\n", error); 582 return error; 583 } 584 585 return 0; 586 } 587 588 static int setfs(addr, path, p) 589 struct sockaddr_in *addr; 590 char *path; 591 char *p; 592 { 593 unsigned ip = 0; 594 int val; 595 596 if (((val = getdec(&p)) < 0) || (val > 255)) return(0); 597 ip = val << 24; 598 if (*p != '.') return(0); 599 p++; 600 if (((val = getdec(&p)) < 0) || (val > 255)) return(0); 601 ip |= (val << 16); 602 if (*p != '.') return(0); 603 p++; 604 if (((val = getdec(&p)) < 0) || (val > 255)) return(0); 605 ip |= (val << 8); 606 if (*p != '.') return(0); 607 p++; 608 if (((val = getdec(&p)) < 0) || (val > 255)) return(0); 609 ip |= val; 610 if (*p != ':') return(0); 611 p++; 612 613 addr->sin_addr.s_addr = htonl(ip); 614 addr->sin_len = sizeof(struct sockaddr_in); 615 addr->sin_family = AF_INET; 616 617 strncpy(path,p,MNAMELEN-1); 618 return(1); 619 } 620 621 static int getdec(ptr) 622 char **ptr; 623 { 624 char *p = *ptr; 625 int ret=0; 626 if ((*p < '0') || (*p > '9')) return(-1); 627 while ((*p >= '0') && (*p <= '9')) { 628 ret = ret*10 + (*p - '0'); 629 p++; 630 } 631 *ptr = p; 632 return(ret); 633 } 634 635 static char *substr(a,b) 636 char *a,*b; 637 { 638 char *loc1; 639 char *loc2; 640 641 while (*a != '\0') { 642 loc1 = a; 643 loc2 = b; 644 while (*loc1 == *loc2++) { 645 if (*loc1 == '\0') return (0); 646 loc1++; 647 if (*loc2 == '\0') return (loc1); 648 } 649 a++; 650 } 651 return (0); 652 } 653 654 static void mountopts(args,p) 655 struct nfs_args *args; 656 char *p; 657 { 658 char *tmp; 659 660 args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT; 661 args->sotype = SOCK_DGRAM; 662 if ((tmp = (char *)substr(p,"rsize="))) 663 args->rsize=getdec(&tmp); 664 if ((tmp = (char *)substr(p,"wsize="))) 665 args->wsize=getdec(&tmp); 666 if ((tmp = (char *)substr(p,"intr"))) 667 args->flags |= NFSMNT_INT; 668 if ((tmp = (char *)substr(p,"soft"))) 669 args->flags |= NFSMNT_SOFT; 670 if ((tmp = (char *)substr(p,"noconn"))) 671 args->flags |= NFSMNT_NOCONN; 672 if ((tmp = (char *)substr(p, "tcp"))) 673 args->sotype = SOCK_STREAM; 674 } 675 676 static int xdr_opaque_decode(mptr,buf,len) 677 struct mbuf **mptr; 678 u_char *buf; 679 int len; 680 { 681 struct mbuf *m; 682 int alignedlen; 683 684 m = *mptr; 685 alignedlen = ( len + 3 ) & ~3; 686 687 if (m->m_len < alignedlen) { 688 m = m_pullup(m,alignedlen); 689 if (m == NULL) { 690 *mptr = NULL; 691 return EBADRPC; 692 } 693 } 694 bcopy(mtod(m,u_char *),buf,len); 695 m_adj(m,alignedlen); 696 *mptr = m; 697 return 0; 698 } 699 700 static int xdr_int_decode(mptr,iptr) 701 struct mbuf **mptr; 702 int *iptr; 703 { 704 u_int32_t i; 705 if (xdr_opaque_decode(mptr,(u_char *) &i,sizeof(u_int32_t))) 706 return EBADRPC; 707 *iptr = fxdr_unsigned(u_int32_t,i); 708 return 0; 709 } 710 711 static void printip(char *prefix,struct in_addr addr) 712 { 713 unsigned int ip; 714 715 ip = ntohl(addr.s_addr); 716 717 printf("%s is %d.%d.%d.%d\n",prefix, 718 ip >> 24, (ip >> 16) & 255 ,(ip >> 8) & 255 ,ip & 255 ); 719 } 720 721 void 722 bootpc_init(void) 723 { 724 struct bootp_packet call; 725 struct bootp_packet reply; 726 static u_int32_t xid = ~0xFF; 727 728 struct ifreq ireq; 729 struct ifnet *ifp; 730 struct socket *so; 731 int error; 732 int code,ncode,len; 733 int i,j; 734 char *p; 735 unsigned int ip; 736 737 struct sockaddr_in myaddr; 738 struct sockaddr_in netmask; 739 struct sockaddr_in gw; 740 int gotgw=0; 741 int gotnetmask=0; 742 int gotrootpath=0; 743 int gotswappath=0; 744 char lookup_path[24]; 745 746 #define EALEN 6 747 unsigned char ea[EALEN]; 748 struct ifaddr *ifa; 749 struct sockaddr_dl *sdl = NULL; 750 char *delim; 751 752 struct nfsv3_diskless *nd = &nfsv3_diskless; 753 struct proc *procp = curproc; 754 755 /* 756 * If already filled in, don't touch it here 757 */ 758 if (nfs_diskless_valid) 759 return; 760 761 /* 762 * Wait until arp entries can be handled. 763 */ 764 while (time_second == 0) 765 tsleep(&time_second, PZERO+8, "arpkludge", 10); 766 767 /* 768 * Find a network interface. 769 */ 770 #ifdef BOOTP_WIRED_TO 771 printf("bootpc_init: wired to interface '%s'\n", 772 __XSTRING(BOOTP_WIRED_TO)); 773 #endif 774 bzero(&ireq, sizeof(ireq)); 775 for (ifp = TAILQ_FIRST(&ifnet); ifp != 0; ifp = TAILQ_NEXT(ifp,if_link)) 776 { 777 sprintf(ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit); 778 #ifdef BOOTP_WIRED_TO 779 if (strcmp(ireq.ifr_name, __XSTRING(BOOTP_WIRED_TO)) == 0) 780 break; 781 #else 782 if ((ifp->if_flags & 783 (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) 784 break; 785 #endif 786 } 787 if (ifp == NULL) 788 panic("bootpc_init: no suitable interface"); 789 strcpy(nd->myif.ifra_name,ireq.ifr_name); 790 printf("bootpc_init: using network interface '%s'\n", 791 ireq.ifr_name); 792 793 if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)) != 0) 794 panic("nfs_boot: socreate, error=%d", error); 795 796 bootpc_fakeup_interface(&ireq,so,procp); 797 798 printf("Bootpc testing starting\n"); 799 800 /* Get HW address */ 801 802 for (ifa = TAILQ_FIRST(&ifp->if_addrhead) ;ifa; 803 ifa=TAILQ_NEXT(ifa,ifa_link)) 804 if (ifa->ifa_addr->sa_family == AF_LINK && 805 (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) && 806 sdl->sdl_type == IFT_ETHER) 807 break; 808 809 if (!sdl) 810 panic("bootpc: Unable to find HW address"); 811 if (sdl->sdl_alen != EALEN ) 812 panic("bootpc: HW address len is %d, expected value is %d", 813 sdl->sdl_alen,EALEN); 814 815 printf("bootpc hw address is "); 816 delim=""; 817 for (j=0;j<sdl->sdl_alen;j++) { 818 printf("%s%x",delim,((unsigned char *)LLADDR(sdl))[j]); 819 delim=":"; 820 } 821 printf("\n"); 822 823 #if 0 824 bootpboot_p_iflist(); 825 bootpboot_p_rtlist(); 826 #endif 827 828 bzero((caddr_t) &call, sizeof(call)); 829 830 /* bootpc part */ 831 call.op = 1; /* BOOTREQUEST */ 832 call.htype= 1; /* 10mb ethernet */ 833 call.hlen=sdl->sdl_alen; /* Hardware address length */ 834 call.hops=0; 835 xid++; 836 call.xid = txdr_unsigned(xid); 837 bcopy(LLADDR(sdl),&call.chaddr,sdl->sdl_alen); 838 839 call.vend[0]=99; 840 call.vend[1]=130; 841 call.vend[2]=83; 842 call.vend[3]=99; 843 call.vend[4]=255; 844 845 call.secs = 0; 846 call.flags = htons(0x8000); /* We need an broadcast answer */ 847 848 error = bootpc_call(&call,&reply,procp); 849 850 if (error) { 851 #ifdef BOOTP_NFSROOT 852 panic("BOOTP call failed"); 853 #endif 854 return; 855 } 856 857 bzero(&myaddr,sizeof(myaddr)); 858 bzero(&netmask,sizeof(netmask)); 859 bzero(&gw,sizeof(gw)); 860 861 myaddr.sin_len = sizeof(myaddr); 862 myaddr.sin_family = AF_INET; 863 864 netmask.sin_len = sizeof(netmask); 865 netmask.sin_family = AF_INET; 866 867 gw.sin_len = sizeof(gw); 868 gw.sin_family= AF_INET; 869 870 nd->root_args.version = NFS_ARGSVERSION; 871 nd->root_args.rsize = 8192; 872 nd->root_args.wsize = 8192; 873 nd->root_args.sotype = SOCK_DGRAM; 874 nd->root_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT); 875 876 nd->swap_saddr.sin_len = sizeof(gw); 877 nd->swap_saddr.sin_family = AF_INET; 878 879 nd->swap_args.version = NFS_ARGSVERSION; 880 nd->swap_args.rsize = 8192; 881 nd->swap_args.wsize = 8192; 882 nd->swap_args.sotype = SOCK_DGRAM; 883 nd->swap_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT); 884 885 myaddr.sin_addr = reply.yiaddr; 886 887 ip = ntohl(myaddr.sin_addr.s_addr); 888 sprintf(lookup_path,"swap.%d.%d.%d.%d", 889 ip >> 24, (ip >> 16) & 255 ,(ip >> 8) & 255 ,ip & 255 ); 890 891 printip("My ip address",myaddr.sin_addr); 892 893 printip("Server ip address",reply.siaddr); 894 895 gw.sin_addr = reply.giaddr; 896 printip("Gateway ip address",reply.giaddr); 897 898 if (reply.sname[0]) 899 printf("Server name is %s\n",reply.sname); 900 if (reply.file[0]) 901 printf("boot file is %s\n",reply.file); 902 if (reply.vend[0]==99 && reply.vend[1]==130 && 903 reply.vend[2]==83 && reply.vend[3]==99) { 904 j=4; 905 ncode = reply.vend[j]; 906 while (j<sizeof(reply.vend)) { 907 code = reply.vend[j] = ncode; 908 if (code==255) 909 break; 910 if (code==0) { 911 j++; 912 continue; 913 } 914 len = reply.vend[j+1]; 915 j+=2; 916 if (len+j>=sizeof(reply.vend)) { 917 printf("Truncated field"); 918 break; 919 } 920 ncode = reply.vend[j+len]; 921 reply.vend[j+len]='\0'; 922 p = &reply.vend[j]; 923 switch (code) { 924 case 1: 925 if (len!=4) 926 panic("bootpc: subnet mask len is %d",len); 927 bcopy(&reply.vend[j],&netmask.sin_addr,4); 928 gotnetmask=1; 929 printip("Subnet mask",netmask.sin_addr); 930 break; 931 case 6: /* Domain Name servers. Unused */ 932 case 16: /* Swap server IP address. unused */ 933 case 2: 934 /* Time offset */ 935 break; 936 case 3: 937 /* Routers */ 938 if (len % 4) 939 panic("bootpc: Router Len is %d",len); 940 if (len > 0) { 941 bcopy(&reply.vend[j],&gw.sin_addr,4); 942 printip("Router",gw.sin_addr); 943 gotgw=1; 944 } 945 break; 946 case 17: 947 if (setfs(&nd->root_saddr, nd->root_hostnam, p)) { 948 printf("rootfs is %s\n",p); 949 gotrootpath=1; 950 } else 951 panic("Failed to set rootfs to %s",p); 952 break; 953 case 12: 954 if (len>=MAXHOSTNAMELEN) 955 panic("bootpc: hostname >=%d bytes",MAXHOSTNAMELEN); 956 strncpy(nd->my_hostnam,&reply.vend[j],len); 957 nd->my_hostnam[len]=0; 958 strncpy(hostname,&reply.vend[j],len); 959 hostname[len]=0; 960 printf("Hostname is %s\n",hostname); 961 break; 962 case 128: 963 if (setfs(&nd->swap_saddr, nd->swap_hostnam, p)) { 964 gotswappath=1; 965 printf("swapfs is %s\n",p); 966 } else 967 panic("Failed to set swapfs to %s",p); 968 break; 969 case 129: 970 { 971 int swaplen; 972 if (len!=4) 973 panic("bootpc: Expected 4 bytes for swaplen, not %d bytes",len); 974 bcopy(&reply.vend[j],&swaplen,4); 975 nd->swap_nblks = ntohl(swaplen); 976 printf("bootpc: Swap size is %d KB\n",nd->swap_nblks); 977 } 978 break; 979 case 130: /* root mount options */ 980 mountopts(&nd->root_args,p); 981 break; 982 case 131: /* swap mount options */ 983 mountopts(&nd->swap_args,p); 984 break; 985 default: 986 printf("Ignoring field type %d\n",code); 987 } 988 j+=len; 989 } 990 } 991 992 if (!gotswappath) 993 nd->swap_nblks = 0; 994 #ifdef BOOTP_NFSROOT 995 if (!gotrootpath) 996 panic("bootpc: No root path offered"); 997 #endif 998 999 if (!gotnetmask) { 1000 if (IN_CLASSA(ntohl(myaddr.sin_addr.s_addr))) 1001 netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET); 1002 else if (IN_CLASSB(ntohl(myaddr.sin_addr.s_addr))) 1003 netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET); 1004 else 1005 netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET); 1006 } 1007 if (!gotgw) { 1008 /* Use proxyarp */ 1009 gw.sin_addr.s_addr = myaddr.sin_addr.s_addr; 1010 } 1011 1012 #if 0 1013 bootpboot_p_iflist(); 1014 bootpboot_p_rtlist(); 1015 #endif 1016 error = bootpc_adjust_interface(&ireq,so, 1017 &myaddr,&netmask,&gw,procp); 1018 1019 soclose(so); 1020 1021 #if 0 1022 bootpboot_p_iflist(); 1023 bootpboot_p_rtlist(); 1024 #endif 1025 1026 if (gotrootpath) { 1027 1028 error = md_mount(&nd->root_saddr, nd->root_hostnam, 1029 nd->root_fh, &nd->root_fhsize, 1030 &nd->root_args,procp); 1031 if (error) 1032 panic("nfs_boot: mountd root, error=%d", error); 1033 1034 if (gotswappath) { 1035 1036 error = md_mount(&nd->swap_saddr, 1037 nd->swap_hostnam, 1038 nd->swap_fh, &nd->swap_fhsize,&nd->swap_args,procp); 1039 if (error) 1040 panic("nfs_boot: mountd swap, error=%d", error); 1041 1042 error = md_lookup_swap(&nd->swap_saddr,lookup_path,nd->swap_fh, 1043 &nd->swap_fhsize, &nd->swap_args,procp); 1044 if (error) 1045 panic("nfs_boot: lookup swap, error=%d", error); 1046 } 1047 nfs_diskless_valid = 3; 1048 } 1049 1050 1051 bcopy(&myaddr,&nd->myif.ifra_addr,sizeof(myaddr)); 1052 bcopy(&myaddr,&nd->myif.ifra_broadaddr,sizeof(myaddr)); 1053 ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr = 1054 myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr; 1055 bcopy(&netmask,&nd->myif.ifra_mask,sizeof(netmask)); 1056 1057 #if 0 1058 bootpboot_p_iflist(); 1059 bootpboot_p_rtlist(); 1060 #endif 1061 return; 1062 } 1063 1064 /* 1065 * RPC: mountd/mount 1066 * Given a server pathname, get an NFS file handle. 1067 * Also, sets sin->sin_port to the NFS service port. 1068 */ 1069 static int 1070 md_mount(mdsin, path, fhp, fhsizep, args, procp) 1071 struct sockaddr_in *mdsin; /* mountd server address */ 1072 char *path; 1073 u_char *fhp; 1074 int *fhsizep; 1075 struct nfs_args *args; 1076 struct proc *procp; 1077 { 1078 struct mbuf *m; 1079 int error; 1080 int authunixok; 1081 int authcount; 1082 int authver; 1083 1084 #ifdef BOOTP_NFSV3 1085 /* First try NFS v3 */ 1086 /* Get port number for MOUNTD. */ 1087 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3, 1088 &mdsin->sin_port, procp); 1089 if (!error) { 1090 m = xdr_string_encode(path, strlen(path)); 1091 1092 /* Do RPC to mountd. */ 1093 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3, 1094 RPCMNT_MOUNT, &m, NULL, curproc); 1095 } 1096 if (!error) { 1097 args->flags |= NFSMNT_NFSV3; 1098 } else { 1099 #endif 1100 /* Fallback to NFS v2 */ 1101 1102 /* Get port number for MOUNTD. */ 1103 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, 1104 &mdsin->sin_port, procp); 1105 if (error) return error; 1106 1107 m = xdr_string_encode(path, strlen(path)); 1108 1109 /* Do RPC to mountd. */ 1110 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, 1111 RPCMNT_MOUNT, &m, NULL, curproc); 1112 if (error) 1113 return error; /* message already freed */ 1114 1115 #ifdef BOOTP_NFSV3 1116 } 1117 #endif 1118 1119 if (xdr_int_decode(&m,&error) || error) 1120 goto bad; 1121 1122 if (args->flags & NFSMNT_NFSV3) { 1123 if (xdr_int_decode(&m,fhsizep) || 1124 *fhsizep > NFSX_V3FHMAX || *fhsizep <= 0 ) 1125 goto bad; 1126 } else 1127 *fhsizep = NFSX_V2FH; 1128 1129 if (xdr_opaque_decode(&m,fhp,*fhsizep)) 1130 goto bad; 1131 1132 if (args->flags & NFSMNT_NFSV3) { 1133 if (xdr_int_decode(&m,&authcount)) 1134 goto bad; 1135 authunixok = 0; 1136 if (authcount<0 || authcount>100) 1137 goto bad; 1138 while (authcount>0) { 1139 if (xdr_int_decode(&m,&authver)) 1140 goto bad; 1141 if (authver == RPCAUTH_UNIX) 1142 authunixok = 1; 1143 authcount--; 1144 } 1145 if (!authunixok) 1146 goto bad; 1147 } 1148 1149 /* Set port number for NFS use. */ 1150 error = krpc_portmap(mdsin, NFS_PROG, 1151 (args->flags & NFSMNT_NFSV3)?NFS_VER3:NFS_VER2, 1152 &mdsin->sin_port, procp); 1153 1154 goto out; 1155 1156 bad: 1157 error = EBADRPC; 1158 1159 out: 1160 m_freem(m); 1161 return error; 1162 } 1163 1164 1165 static int md_lookup_swap(mdsin, path, fhp, fhsizep, args, procp) 1166 struct sockaddr_in *mdsin; /* mountd server address */ 1167 char *path; 1168 u_char *fhp; 1169 int *fhsizep; 1170 struct nfs_args *args; 1171 struct proc *procp; 1172 { 1173 struct mbuf *m; 1174 int error; 1175 int size = -1; 1176 int attribs_present; 1177 int status; 1178 union { 1179 u_int32_t v2[17]; 1180 u_int32_t v3[21]; 1181 } fattribs; 1182 1183 m = m_get(M_WAIT,MT_DATA); 1184 if (!m) 1185 return ENOBUFS; 1186 1187 if (args->flags & NFSMNT_NFSV3) { 1188 *mtod(m,u_int32_t *) = txdr_unsigned(*fhsizep); 1189 bcopy(fhp,mtod(m,u_char *)+sizeof(u_int32_t),*fhsizep); 1190 m->m_len = *fhsizep + sizeof(u_int32_t); 1191 } else { 1192 bcopy(fhp,mtod(m,u_char *),NFSX_V2FH); 1193 m->m_len = NFSX_V2FH; 1194 } 1195 1196 m->m_next = xdr_string_encode(path, strlen(path)); 1197 if (!m->m_next) { 1198 error = ENOBUFS; 1199 goto out; 1200 } 1201 1202 /* Do RPC to nfsd. */ 1203 if (args->flags & NFSMNT_NFSV3) 1204 error = krpc_call(mdsin, NFS_PROG, NFS_VER3, 1205 NFSPROC_LOOKUP, &m, NULL, procp); 1206 else 1207 error = krpc_call(mdsin, NFS_PROG, NFS_VER2, 1208 NFSV2PROC_LOOKUP, &m, NULL, procp); 1209 if (error) 1210 return error; /* message already freed */ 1211 1212 if (xdr_int_decode(&m,&status)) 1213 goto bad; 1214 if (status) { 1215 error = ENOENT; 1216 goto out; 1217 } 1218 1219 if (args->flags & NFSMNT_NFSV3) { 1220 if (xdr_int_decode(&m,fhsizep) || 1221 *fhsizep > NFSX_V3FHMAX || *fhsizep <= 0 ) 1222 goto bad; 1223 } else 1224 *fhsizep = NFSX_V2FH; 1225 1226 if (xdr_opaque_decode(&m, fhp, *fhsizep)) 1227 goto bad; 1228 1229 if (args->flags & NFSMNT_NFSV3) { 1230 if (xdr_int_decode(&m,&attribs_present)) 1231 goto bad; 1232 if (attribs_present) { 1233 if (xdr_opaque_decode(&m,(u_char *) &fattribs.v3, 1234 sizeof(u_int32_t)*21)) 1235 goto bad; 1236 size = fxdr_unsigned(u_int32_t, fattribs.v3[6]); 1237 } 1238 } else { 1239 if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2, 1240 sizeof(u_int32_t)*17)) 1241 goto bad; 1242 size = fxdr_unsigned(u_int32_t, fattribs.v2[5]); 1243 } 1244 1245 if (!nfsv3_diskless.swap_nblks && size!= -1) { 1246 nfsv3_diskless.swap_nblks = size/1024; 1247 printf("md_lookup_swap: Swap size is %d KB\n", 1248 nfsv3_diskless.swap_nblks); 1249 } 1250 1251 goto out; 1252 1253 bad: 1254 error = EBADRPC; 1255 1256 out: 1257 m_freem(m); 1258 return error; 1259 } 1260