1 /* $Id: bootp_subr.c,v 1.17 1998/12/04 22:54:54 archie 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 uio auio; 266 struct sockopt sopt; 267 struct iovec aio; 268 struct timeval tv; 269 int error, on, len, rcvflg, secs, timo; 270 271 /* 272 * Create socket and set its recieve timeout. 273 */ 274 if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp))) 275 goto out; 276 277 tv.tv_sec = 1; 278 tv.tv_usec = 0; 279 bzero(&sopt, sizeof sopt); 280 sopt.sopt_level = SOL_SOCKET; 281 sopt.sopt_name = SO_RCVTIMEO; 282 sopt.sopt_val = &tv; 283 sopt.sopt_valsize = sizeof tv; 284 285 if (error = sosetopt(so, &sopt)) 286 goto out; 287 288 /* 289 * Enable broadcast. 290 */ 291 on = 1; 292 sopt.sopt_val = &on; 293 sopt.sopt_valsize = sizeof on; 294 sopt.sopt_name = SO_BROADCAST; 295 if (error = sosetopt(so, &sopt)) 296 goto out; 297 298 /* 299 * Bind the local endpoint to a bootp client port. 300 */ 301 sin = &sa; 302 bzero(sin, sizeof *sin); 303 sin->sin_len = sizeof(*sin); 304 sin->sin_family = AF_INET; 305 sin->sin_addr.s_addr = INADDR_ANY; 306 sin->sin_port = htons(IPPORT_BOOTPC); 307 error = sobind(so, (struct sockaddr *)sin, procp); 308 if (error) { 309 printf("bind failed\n"); 310 goto out; 311 } 312 313 /* 314 * Setup socket address for the server. 315 */ 316 sin = &sa; 317 bzero(sin, sizeof *sin); 318 sin->sin_len = sizeof(*sin); 319 sin->sin_family = AF_INET; 320 sin->sin_addr.s_addr = INADDR_BROADCAST; 321 sin->sin_port = htons(IPPORT_BOOTPS); 322 323 /* 324 * Send it, repeatedly, until a reply is received, 325 * but delay each re-send by an increasing amount. 326 * If the delay hits the maximum, start complaining. 327 */ 328 timo = 0; 329 for (;;) { 330 /* Send BOOTP request (or re-send). */ 331 332 aio.iov_base = (caddr_t) call; 333 aio.iov_len = sizeof(*call); 334 335 auio.uio_iov = &aio; 336 auio.uio_iovcnt = 1; 337 auio.uio_segflg = UIO_SYSSPACE; 338 auio.uio_rw = UIO_WRITE; 339 auio.uio_offset = 0; 340 auio.uio_resid = sizeof(*call); 341 auio.uio_procp = procp; 342 343 error = sosend(so, (struct sockaddr *)sin, &auio, NULL, 344 NULL, 0, procp); 345 if (error) { 346 printf("bootpc_call: sosend: %d state %08x\n", error, (int)so->so_state); 347 goto out; 348 } 349 350 /* Determine new timeout. */ 351 if (timo < MAX_RESEND_DELAY) 352 timo++; 353 else 354 printf("BOOTP timeout for server 0x%lx\n", 355 (u_long)ntohl(sin->sin_addr.s_addr)); 356 357 /* 358 * Wait for up to timo seconds for a reply. 359 * The socket receive timeout was set to 1 second. 360 */ 361 secs = timo; 362 while (secs > 0) { 363 aio.iov_base = (caddr_t) reply; 364 aio.iov_len = sizeof(*reply); 365 366 auio.uio_iov = &aio; 367 auio.uio_iovcnt = 1; 368 auio.uio_segflg = UIO_SYSSPACE; 369 auio.uio_rw = UIO_READ; 370 auio.uio_offset = 0; 371 auio.uio_resid = sizeof(*reply); 372 auio.uio_procp = procp; 373 374 rcvflg = 0; 375 error = soreceive(so, NULL, &auio, NULL, NULL, &rcvflg); 376 if (error == EWOULDBLOCK) { 377 secs--; 378 call->secs=htons(ntohs(call->secs)+1); 379 continue; 380 } 381 if (error) 382 goto out; 383 len = sizeof(*reply) - auio.uio_resid; 384 385 /* Do we have the required number of bytes ? */ 386 if (len < BOOTP_MIN_LEN) 387 continue; 388 389 /* Is it the right reply? */ 390 if (reply->op != 2) 391 continue; 392 393 if (reply->xid != call->xid) 394 continue; 395 396 if (reply->hlen != call->hlen) 397 continue; 398 399 if (bcmp(reply->chaddr,call->chaddr,call->hlen)) 400 continue; 401 402 goto gotreply; /* break two levels */ 403 404 } /* while secs */ 405 } /* forever send/receive */ 406 407 error = ETIMEDOUT; 408 goto out; 409 410 gotreply: 411 out: 412 soclose(so); 413 return error; 414 } 415 416 static int 417 bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so, 418 struct proc *procp) 419 { 420 struct sockaddr_in *sin; 421 int error; 422 struct sockaddr_in dst; 423 struct sockaddr_in gw; 424 struct sockaddr_in mask; 425 426 /* 427 * Bring up the interface. 428 * 429 * Get the old interface flags and or IFF_UP into them; if 430 * IFF_UP set blindly, interface selection can be clobbered. 431 */ 432 error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp); 433 if (error) 434 panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error); 435 ireq->ifr_flags |= IFF_UP; 436 error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, procp); 437 if (error) 438 panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error); 439 440 /* 441 * Do enough of ifconfig(8) so that the chosen interface 442 * can talk to the servers. (just set the address) 443 */ 444 445 /* addr is 0.0.0.0 */ 446 447 sin = (struct sockaddr_in *)&ireq->ifr_addr; 448 bzero((caddr_t)sin, sizeof(*sin)); 449 sin->sin_len = sizeof(*sin); 450 sin->sin_family = AF_INET; 451 sin->sin_addr.s_addr = INADDR_ANY; 452 error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); 453 if (error) 454 panic("bootpc_fakeup_interface: set if addr, error=%d", error); 455 456 /* netmask is 0.0.0.0 */ 457 458 sin = (struct sockaddr_in *)&ireq->ifr_addr; 459 bzero((caddr_t)sin, sizeof(*sin)); 460 sin->sin_len = sizeof(*sin); 461 sin->sin_family = AF_INET; 462 sin->sin_addr.s_addr = INADDR_ANY; 463 error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp); 464 if (error) 465 panic("bootpc_fakeup_interface: set if net addr, error=%d", error); 466 467 /* Broadcast is 255.255.255.255 */ 468 469 sin = (struct sockaddr_in *)&ireq->ifr_addr; 470 bzero((caddr_t)sin, sizeof(*sin)); 471 sin->sin_len = sizeof(*sin); 472 sin->sin_family = AF_INET; 473 sin->sin_addr.s_addr = INADDR_BROADCAST; 474 error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp); 475 if (error) 476 panic("bootpc_fakeup_interface: set if broadcast addr, error=%d", error); 477 478 /* Add default route to 0.0.0.0 so we can send data */ 479 480 bzero((caddr_t) &dst, sizeof(dst)); 481 dst.sin_len=sizeof(dst); 482 dst.sin_family=AF_INET; 483 dst.sin_addr.s_addr = htonl(0); 484 485 bzero((caddr_t) &gw, sizeof(gw)); 486 gw.sin_len=sizeof(gw); 487 gw.sin_family=AF_INET; 488 gw.sin_addr.s_addr = htonl(0x0); 489 490 bzero((caddr_t) &mask, sizeof(mask)); 491 mask.sin_len=sizeof(mask); 492 mask.sin_family=AF_INET; 493 mask.sin_addr.s_addr = htonl(0); 494 495 error = rtrequest(RTM_ADD, 496 (struct sockaddr *) &dst, 497 (struct sockaddr *) &gw, 498 (struct sockaddr *) &mask, 499 RTF_UP | RTF_STATIC 500 , NULL); 501 if (error) 502 printf("bootpc_fakeup_interface: add default route, error=%d\n", error); 503 return error; 504 } 505 506 static int 507 bootpc_adjust_interface(struct ifreq *ireq,struct socket *so, 508 struct sockaddr_in *myaddr, 509 struct sockaddr_in *netmask, 510 struct sockaddr_in *gw, 511 struct proc *procp) 512 { 513 int error; 514 struct sockaddr_in oldgw; 515 struct sockaddr_in olddst; 516 struct sockaddr_in oldmask; 517 struct sockaddr_in *sin; 518 519 /* Remove old default route to 0.0.0.0 */ 520 521 bzero((caddr_t) &olddst, sizeof(olddst)); 522 olddst.sin_len=sizeof(olddst); 523 olddst.sin_family=AF_INET; 524 olddst.sin_addr.s_addr = INADDR_ANY; 525 526 bzero((caddr_t) &oldgw, sizeof(oldgw)); 527 oldgw.sin_len=sizeof(oldgw); 528 oldgw.sin_family=AF_INET; 529 oldgw.sin_addr.s_addr = INADDR_ANY; 530 531 bzero((caddr_t) &oldmask, sizeof(oldmask)); 532 oldmask.sin_len=sizeof(oldmask); 533 oldmask.sin_family=AF_INET; 534 oldmask.sin_addr.s_addr = INADDR_ANY; 535 536 error = rtrequest(RTM_DELETE, 537 (struct sockaddr *) &olddst, 538 (struct sockaddr *) &oldgw, 539 (struct sockaddr *) &oldmask, 540 (RTF_UP | RTF_STATIC), NULL); 541 if (error) { 542 printf("nfs_boot: del default route, error=%d\n", error); 543 return error; 544 } 545 546 /* 547 * Do enough of ifconfig(8) so that the chosen interface 548 * can talk to the servers. (just set the address) 549 */ 550 bcopy(netmask,&ireq->ifr_addr,sizeof(*netmask)); 551 error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp); 552 if (error) 553 panic("nfs_boot: set if netmask, error=%d", error); 554 555 /* Broadcast is with host part of IP address all 1's */ 556 557 sin = (struct sockaddr_in *)&ireq->ifr_addr; 558 bzero((caddr_t)sin, sizeof(*sin)); 559 sin->sin_len = sizeof(*sin); 560 sin->sin_family = AF_INET; 561 sin->sin_addr.s_addr = myaddr->sin_addr.s_addr | ~ netmask->sin_addr.s_addr; 562 error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp); 563 if (error) 564 panic("bootpc_call: set if broadcast addr, error=%d", error); 565 566 bcopy(myaddr,&ireq->ifr_addr,sizeof(*myaddr)); 567 error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); 568 if (error) 569 panic("nfs_boot: set if addr, error=%d", error); 570 571 /* Add new default route */ 572 573 error = rtrequest(RTM_ADD, 574 (struct sockaddr *) &olddst, 575 (struct sockaddr *) gw, 576 (struct sockaddr *) &oldmask, 577 (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL); 578 if (error) { 579 printf("nfs_boot: add net route, error=%d\n", error); 580 return error; 581 } 582 583 return 0; 584 } 585 586 static int setfs(addr, path, p) 587 struct sockaddr_in *addr; 588 char *path; 589 char *p; 590 { 591 unsigned ip = 0; 592 int val; 593 594 if (((val = getdec(&p)) < 0) || (val > 255)) return(0); 595 ip = val << 24; 596 if (*p != '.') return(0); 597 p++; 598 if (((val = getdec(&p)) < 0) || (val > 255)) return(0); 599 ip |= (val << 16); 600 if (*p != '.') return(0); 601 p++; 602 if (((val = getdec(&p)) < 0) || (val > 255)) return(0); 603 ip |= (val << 8); 604 if (*p != '.') return(0); 605 p++; 606 if (((val = getdec(&p)) < 0) || (val > 255)) return(0); 607 ip |= val; 608 if (*p != ':') return(0); 609 p++; 610 611 addr->sin_addr.s_addr = htonl(ip); 612 addr->sin_len = sizeof(struct sockaddr_in); 613 addr->sin_family = AF_INET; 614 615 strncpy(path,p,MNAMELEN-1); 616 return(1); 617 } 618 619 static int getdec(ptr) 620 char **ptr; 621 { 622 char *p = *ptr; 623 int ret=0; 624 if ((*p < '0') || (*p > '9')) return(-1); 625 while ((*p >= '0') && (*p <= '9')) { 626 ret = ret*10 + (*p - '0'); 627 p++; 628 } 629 *ptr = p; 630 return(ret); 631 } 632 633 static char *substr(a,b) 634 char *a,*b; 635 { 636 char *loc1; 637 char *loc2; 638 639 while (*a != '\0') { 640 loc1 = a; 641 loc2 = b; 642 while (*loc1 == *loc2++) { 643 if (*loc1 == '\0') return (0); 644 loc1++; 645 if (*loc2 == '\0') return (loc1); 646 } 647 a++; 648 } 649 return (0); 650 } 651 652 static void mountopts(args,p) 653 struct nfs_args *args; 654 char *p; 655 { 656 char *tmp; 657 658 args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT; 659 args->sotype = SOCK_DGRAM; 660 if ((tmp = (char *)substr(p,"rsize="))) 661 args->rsize=getdec(&tmp); 662 if ((tmp = (char *)substr(p,"wsize="))) 663 args->wsize=getdec(&tmp); 664 if ((tmp = (char *)substr(p,"intr"))) 665 args->flags |= NFSMNT_INT; 666 if ((tmp = (char *)substr(p,"soft"))) 667 args->flags |= NFSMNT_SOFT; 668 if ((tmp = (char *)substr(p,"noconn"))) 669 args->flags |= NFSMNT_NOCONN; 670 if ((tmp = (char *)substr(p, "tcp"))) 671 args->sotype = SOCK_STREAM; 672 } 673 674 static int xdr_opaque_decode(mptr,buf,len) 675 struct mbuf **mptr; 676 u_char *buf; 677 int len; 678 { 679 struct mbuf *m; 680 int alignedlen; 681 682 m = *mptr; 683 alignedlen = ( len + 3 ) & ~3; 684 685 if (m->m_len < alignedlen) { 686 m = m_pullup(m,alignedlen); 687 if (m == NULL) { 688 *mptr = NULL; 689 return EBADRPC; 690 } 691 } 692 bcopy(mtod(m,u_char *),buf,len); 693 m_adj(m,alignedlen); 694 *mptr = m; 695 return 0; 696 } 697 698 static int xdr_int_decode(mptr,iptr) 699 struct mbuf **mptr; 700 int *iptr; 701 { 702 u_int32_t i; 703 if (xdr_opaque_decode(mptr,(u_char *) &i,sizeof(u_int32_t))) 704 return EBADRPC; 705 *iptr = fxdr_unsigned(u_int32_t,i); 706 return 0; 707 } 708 709 static void printip(char *prefix,struct in_addr addr) 710 { 711 unsigned int ip; 712 713 ip = ntohl(addr.s_addr); 714 715 printf("%s is %d.%d.%d.%d\n",prefix, 716 ip >> 24, (ip >> 16) & 255 ,(ip >> 8) & 255 ,ip & 255 ); 717 } 718 719 void 720 bootpc_init(void) 721 { 722 struct bootp_packet call; 723 struct bootp_packet reply; 724 static u_int32_t xid = ~0xFF; 725 726 struct ifreq ireq; 727 struct ifnet *ifp; 728 struct socket *so; 729 int error; 730 int code,ncode,len; 731 int j; 732 char *p; 733 unsigned int ip; 734 735 struct sockaddr_in myaddr; 736 struct sockaddr_in netmask; 737 struct sockaddr_in gw; 738 int gotgw=0; 739 int gotnetmask=0; 740 int gotrootpath=0; 741 int gotswappath=0; 742 char lookup_path[24]; 743 744 #define EALEN 6 745 struct ifaddr *ifa; 746 struct sockaddr_dl *sdl = NULL; 747 char *delim; 748 749 struct nfsv3_diskless *nd = &nfsv3_diskless; 750 struct proc *procp = curproc; 751 752 /* 753 * If already filled in, don't touch it here 754 */ 755 if (nfs_diskless_valid) 756 return; 757 758 /* 759 * Wait until arp entries can be handled. 760 */ 761 while (time_second == 0) 762 tsleep(&time_second, PZERO+8, "arpkludge", 10); 763 764 /* 765 * Find a network interface. 766 */ 767 #ifdef BOOTP_WIRED_TO 768 printf("bootpc_init: wired to interface '%s'\n", 769 __XSTRING(BOOTP_WIRED_TO)); 770 #endif 771 bzero(&ireq, sizeof(ireq)); 772 for (ifp = TAILQ_FIRST(&ifnet); ifp != 0; ifp = TAILQ_NEXT(ifp,if_link)) 773 { 774 snprintf(ireq.ifr_name, sizeof(ireq.ifr_name), 775 "%s%d", ifp->if_name, ifp->if_unit); 776 #ifdef BOOTP_WIRED_TO 777 if (strcmp(ireq.ifr_name, __XSTRING(BOOTP_WIRED_TO)) == 0) 778 break; 779 #else 780 if ((ifp->if_flags & 781 (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) 782 break; 783 #endif 784 } 785 if (ifp == NULL) 786 panic("bootpc_init: no suitable interface"); 787 strcpy(nd->myif.ifra_name,ireq.ifr_name); 788 printf("bootpc_init: using network interface '%s'\n", 789 ireq.ifr_name); 790 791 if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)) != 0) 792 panic("nfs_boot: socreate, error=%d", error); 793 794 bootpc_fakeup_interface(&ireq,so,procp); 795 796 printf("Bootpc testing starting\n"); 797 798 /* Get HW address */ 799 800 for (ifa = TAILQ_FIRST(&ifp->if_addrhead) ;ifa; 801 ifa=TAILQ_NEXT(ifa,ifa_link)) 802 if (ifa->ifa_addr->sa_family == AF_LINK && 803 (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) && 804 sdl->sdl_type == IFT_ETHER) 805 break; 806 807 if (!sdl) 808 panic("bootpc: Unable to find HW address"); 809 if (sdl->sdl_alen != EALEN ) 810 panic("bootpc: HW address len is %d, expected value is %d", 811 sdl->sdl_alen,EALEN); 812 813 printf("bootpc hw address is "); 814 delim=""; 815 for (j=0;j<sdl->sdl_alen;j++) { 816 printf("%s%x",delim,((unsigned char *)LLADDR(sdl))[j]); 817 delim=":"; 818 } 819 printf("\n"); 820 821 #if 0 822 bootpboot_p_iflist(); 823 bootpboot_p_rtlist(); 824 #endif 825 826 bzero((caddr_t) &call, sizeof(call)); 827 828 /* bootpc part */ 829 call.op = 1; /* BOOTREQUEST */ 830 call.htype= 1; /* 10mb ethernet */ 831 call.hlen=sdl->sdl_alen; /* Hardware address length */ 832 call.hops=0; 833 xid++; 834 call.xid = txdr_unsigned(xid); 835 bcopy(LLADDR(sdl),&call.chaddr,sdl->sdl_alen); 836 837 call.vend[0]=99; 838 call.vend[1]=130; 839 call.vend[2]=83; 840 call.vend[3]=99; 841 call.vend[4]=255; 842 843 call.secs = 0; 844 call.flags = htons(0x8000); /* We need an broadcast answer */ 845 846 error = bootpc_call(&call,&reply,procp); 847 848 if (error) { 849 #ifdef BOOTP_NFSROOT 850 panic("BOOTP call failed"); 851 #endif 852 return; 853 } 854 855 bzero(&myaddr,sizeof(myaddr)); 856 bzero(&netmask,sizeof(netmask)); 857 bzero(&gw,sizeof(gw)); 858 859 myaddr.sin_len = sizeof(myaddr); 860 myaddr.sin_family = AF_INET; 861 862 netmask.sin_len = sizeof(netmask); 863 netmask.sin_family = AF_INET; 864 865 gw.sin_len = sizeof(gw); 866 gw.sin_family= AF_INET; 867 868 nd->root_args.version = NFS_ARGSVERSION; 869 nd->root_args.rsize = 8192; 870 nd->root_args.wsize = 8192; 871 nd->root_args.sotype = SOCK_DGRAM; 872 nd->root_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT); 873 874 nd->swap_saddr.sin_len = sizeof(gw); 875 nd->swap_saddr.sin_family = AF_INET; 876 877 nd->swap_args.version = NFS_ARGSVERSION; 878 nd->swap_args.rsize = 8192; 879 nd->swap_args.wsize = 8192; 880 nd->swap_args.sotype = SOCK_DGRAM; 881 nd->swap_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT); 882 883 myaddr.sin_addr = reply.yiaddr; 884 885 ip = ntohl(myaddr.sin_addr.s_addr); 886 snprintf(lookup_path, sizeof(lookup_path), "swap.%d.%d.%d.%d", 887 ip >> 24, (ip >> 16) & 255 ,(ip >> 8) & 255 ,ip & 255 ); 888 889 printip("My ip address",myaddr.sin_addr); 890 891 printip("Server ip address",reply.siaddr); 892 893 gw.sin_addr = reply.giaddr; 894 printip("Gateway ip address",reply.giaddr); 895 896 if (reply.sname[0]) 897 printf("Server name is %s\n",reply.sname); 898 if (reply.file[0]) 899 printf("boot file is %s\n",reply.file); 900 if (reply.vend[0]==99 && reply.vend[1]==130 && 901 reply.vend[2]==83 && reply.vend[3]==99) { 902 j=4; 903 ncode = reply.vend[j]; 904 while (j<sizeof(reply.vend)) { 905 code = reply.vend[j] = ncode; 906 if (code==255) 907 break; 908 if (code==0) { 909 j++; 910 continue; 911 } 912 len = reply.vend[j+1]; 913 j+=2; 914 if (len+j>=sizeof(reply.vend)) { 915 printf("Truncated field"); 916 break; 917 } 918 ncode = reply.vend[j+len]; 919 reply.vend[j+len]='\0'; 920 p = &reply.vend[j]; 921 switch (code) { 922 case 1: 923 if (len!=4) 924 panic("bootpc: subnet mask len is %d",len); 925 bcopy(&reply.vend[j],&netmask.sin_addr,4); 926 gotnetmask=1; 927 printip("Subnet mask",netmask.sin_addr); 928 break; 929 case 6: /* Domain Name servers. Unused */ 930 case 16: /* Swap server IP address. unused */ 931 case 2: 932 /* Time offset */ 933 break; 934 case 3: 935 /* Routers */ 936 if (len % 4) 937 panic("bootpc: Router Len is %d",len); 938 if (len > 0) { 939 bcopy(&reply.vend[j],&gw.sin_addr,4); 940 printip("Router",gw.sin_addr); 941 gotgw=1; 942 } 943 break; 944 case 17: 945 if (setfs(&nd->root_saddr, nd->root_hostnam, p)) { 946 printf("rootfs is %s\n",p); 947 gotrootpath=1; 948 } else 949 panic("Failed to set rootfs to %s",p); 950 break; 951 case 12: 952 if (len>=MAXHOSTNAMELEN) 953 panic("bootpc: hostname >=%d bytes",MAXHOSTNAMELEN); 954 strncpy(nd->my_hostnam,&reply.vend[j],len); 955 nd->my_hostnam[len]=0; 956 strncpy(hostname,&reply.vend[j],len); 957 hostname[len]=0; 958 printf("Hostname is %s\n",hostname); 959 break; 960 case 128: 961 if (setfs(&nd->swap_saddr, nd->swap_hostnam, p)) { 962 gotswappath=1; 963 printf("swapfs is %s\n",p); 964 } else 965 panic("Failed to set swapfs to %s",p); 966 break; 967 case 129: 968 { 969 int swaplen; 970 if (len!=4) 971 panic("bootpc: Expected 4 bytes for swaplen, not %d bytes",len); 972 bcopy(&reply.vend[j],&swaplen,4); 973 nd->swap_nblks = ntohl(swaplen); 974 printf("bootpc: Swap size is %d KB\n",nd->swap_nblks); 975 } 976 break; 977 case 130: /* root mount options */ 978 mountopts(&nd->root_args,p); 979 break; 980 case 131: /* swap mount options */ 981 mountopts(&nd->swap_args,p); 982 break; 983 default: 984 printf("Ignoring field type %d\n",code); 985 } 986 j+=len; 987 } 988 } 989 990 if (!gotswappath) 991 nd->swap_nblks = 0; 992 #ifdef BOOTP_NFSROOT 993 if (!gotrootpath) 994 panic("bootpc: No root path offered"); 995 #endif 996 997 if (!gotnetmask) { 998 if (IN_CLASSA(ntohl(myaddr.sin_addr.s_addr))) 999 netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET); 1000 else if (IN_CLASSB(ntohl(myaddr.sin_addr.s_addr))) 1001 netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET); 1002 else 1003 netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET); 1004 } 1005 if (!gotgw) { 1006 /* Use proxyarp */ 1007 gw.sin_addr.s_addr = myaddr.sin_addr.s_addr; 1008 } 1009 1010 #if 0 1011 bootpboot_p_iflist(); 1012 bootpboot_p_rtlist(); 1013 #endif 1014 error = bootpc_adjust_interface(&ireq,so, 1015 &myaddr,&netmask,&gw,procp); 1016 1017 soclose(so); 1018 1019 #if 0 1020 bootpboot_p_iflist(); 1021 bootpboot_p_rtlist(); 1022 #endif 1023 1024 if (gotrootpath) { 1025 1026 error = md_mount(&nd->root_saddr, nd->root_hostnam, 1027 nd->root_fh, &nd->root_fhsize, 1028 &nd->root_args,procp); 1029 if (error) 1030 panic("nfs_boot: mountd root, error=%d", error); 1031 1032 if (gotswappath) { 1033 1034 error = md_mount(&nd->swap_saddr, 1035 nd->swap_hostnam, 1036 nd->swap_fh, &nd->swap_fhsize,&nd->swap_args,procp); 1037 if (error) 1038 panic("nfs_boot: mountd swap, error=%d", error); 1039 1040 error = md_lookup_swap(&nd->swap_saddr,lookup_path,nd->swap_fh, 1041 &nd->swap_fhsize, &nd->swap_args,procp); 1042 if (error) 1043 panic("nfs_boot: lookup swap, error=%d", error); 1044 } 1045 nfs_diskless_valid = 3; 1046 } 1047 1048 1049 bcopy(&myaddr,&nd->myif.ifra_addr,sizeof(myaddr)); 1050 bcopy(&myaddr,&nd->myif.ifra_broadaddr,sizeof(myaddr)); 1051 ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr = 1052 myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr; 1053 bcopy(&netmask,&nd->myif.ifra_mask,sizeof(netmask)); 1054 1055 #if 0 1056 bootpboot_p_iflist(); 1057 bootpboot_p_rtlist(); 1058 #endif 1059 return; 1060 } 1061 1062 /* 1063 * RPC: mountd/mount 1064 * Given a server pathname, get an NFS file handle. 1065 * Also, sets sin->sin_port to the NFS service port. 1066 */ 1067 static int 1068 md_mount(mdsin, path, fhp, fhsizep, args, procp) 1069 struct sockaddr_in *mdsin; /* mountd server address */ 1070 char *path; 1071 u_char *fhp; 1072 int *fhsizep; 1073 struct nfs_args *args; 1074 struct proc *procp; 1075 { 1076 struct mbuf *m; 1077 int error; 1078 int authunixok; 1079 int authcount; 1080 int authver; 1081 1082 #ifdef BOOTP_NFSV3 1083 /* First try NFS v3 */ 1084 /* Get port number for MOUNTD. */ 1085 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3, 1086 &mdsin->sin_port, procp); 1087 if (!error) { 1088 m = xdr_string_encode(path, strlen(path)); 1089 1090 /* Do RPC to mountd. */ 1091 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3, 1092 RPCMNT_MOUNT, &m, NULL, curproc); 1093 } 1094 if (!error) { 1095 args->flags |= NFSMNT_NFSV3; 1096 } else { 1097 #endif 1098 /* Fallback to NFS v2 */ 1099 1100 /* Get port number for MOUNTD. */ 1101 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, 1102 &mdsin->sin_port, procp); 1103 if (error) return error; 1104 1105 m = xdr_string_encode(path, strlen(path)); 1106 1107 /* Do RPC to mountd. */ 1108 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, 1109 RPCMNT_MOUNT, &m, NULL, curproc); 1110 if (error) 1111 return error; /* message already freed */ 1112 1113 #ifdef BOOTP_NFSV3 1114 } 1115 #endif 1116 1117 if (xdr_int_decode(&m,&error) || error) 1118 goto bad; 1119 1120 if (args->flags & NFSMNT_NFSV3) { 1121 if (xdr_int_decode(&m,fhsizep) || 1122 *fhsizep > NFSX_V3FHMAX || *fhsizep <= 0 ) 1123 goto bad; 1124 } else 1125 *fhsizep = NFSX_V2FH; 1126 1127 if (xdr_opaque_decode(&m,fhp,*fhsizep)) 1128 goto bad; 1129 1130 if (args->flags & NFSMNT_NFSV3) { 1131 if (xdr_int_decode(&m,&authcount)) 1132 goto bad; 1133 authunixok = 0; 1134 if (authcount<0 || authcount>100) 1135 goto bad; 1136 while (authcount>0) { 1137 if (xdr_int_decode(&m,&authver)) 1138 goto bad; 1139 if (authver == RPCAUTH_UNIX) 1140 authunixok = 1; 1141 authcount--; 1142 } 1143 if (!authunixok) 1144 goto bad; 1145 } 1146 1147 /* Set port number for NFS use. */ 1148 error = krpc_portmap(mdsin, NFS_PROG, 1149 (args->flags & NFSMNT_NFSV3)?NFS_VER3:NFS_VER2, 1150 &mdsin->sin_port, procp); 1151 1152 goto out; 1153 1154 bad: 1155 error = EBADRPC; 1156 1157 out: 1158 m_freem(m); 1159 return error; 1160 } 1161 1162 1163 static int md_lookup_swap(mdsin, path, fhp, fhsizep, args, procp) 1164 struct sockaddr_in *mdsin; /* mountd server address */ 1165 char *path; 1166 u_char *fhp; 1167 int *fhsizep; 1168 struct nfs_args *args; 1169 struct proc *procp; 1170 { 1171 struct mbuf *m; 1172 int error; 1173 int size = -1; 1174 int attribs_present; 1175 int status; 1176 union { 1177 u_int32_t v2[17]; 1178 u_int32_t v3[21]; 1179 } fattribs; 1180 1181 m = m_get(M_WAIT,MT_DATA); 1182 if (!m) 1183 return ENOBUFS; 1184 1185 if (args->flags & NFSMNT_NFSV3) { 1186 *mtod(m,u_int32_t *) = txdr_unsigned(*fhsizep); 1187 bcopy(fhp,mtod(m,u_char *)+sizeof(u_int32_t),*fhsizep); 1188 m->m_len = *fhsizep + sizeof(u_int32_t); 1189 } else { 1190 bcopy(fhp,mtod(m,u_char *),NFSX_V2FH); 1191 m->m_len = NFSX_V2FH; 1192 } 1193 1194 m->m_next = xdr_string_encode(path, strlen(path)); 1195 if (!m->m_next) { 1196 error = ENOBUFS; 1197 goto out; 1198 } 1199 1200 /* Do RPC to nfsd. */ 1201 if (args->flags & NFSMNT_NFSV3) 1202 error = krpc_call(mdsin, NFS_PROG, NFS_VER3, 1203 NFSPROC_LOOKUP, &m, NULL, procp); 1204 else 1205 error = krpc_call(mdsin, NFS_PROG, NFS_VER2, 1206 NFSV2PROC_LOOKUP, &m, NULL, procp); 1207 if (error) 1208 return error; /* message already freed */ 1209 1210 if (xdr_int_decode(&m,&status)) 1211 goto bad; 1212 if (status) { 1213 error = ENOENT; 1214 goto out; 1215 } 1216 1217 if (args->flags & NFSMNT_NFSV3) { 1218 if (xdr_int_decode(&m,fhsizep) || 1219 *fhsizep > NFSX_V3FHMAX || *fhsizep <= 0 ) 1220 goto bad; 1221 } else 1222 *fhsizep = NFSX_V2FH; 1223 1224 if (xdr_opaque_decode(&m, fhp, *fhsizep)) 1225 goto bad; 1226 1227 if (args->flags & NFSMNT_NFSV3) { 1228 if (xdr_int_decode(&m,&attribs_present)) 1229 goto bad; 1230 if (attribs_present) { 1231 if (xdr_opaque_decode(&m,(u_char *) &fattribs.v3, 1232 sizeof(u_int32_t)*21)) 1233 goto bad; 1234 size = fxdr_unsigned(u_int32_t, fattribs.v3[6]); 1235 } 1236 } else { 1237 if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2, 1238 sizeof(u_int32_t)*17)) 1239 goto bad; 1240 size = fxdr_unsigned(u_int32_t, fattribs.v2[5]); 1241 } 1242 1243 if (!nfsv3_diskless.swap_nblks && size!= -1) { 1244 nfsv3_diskless.swap_nblks = size/1024; 1245 printf("md_lookup_swap: Swap size is %d KB\n", 1246 nfsv3_diskless.swap_nblks); 1247 } 1248 1249 goto out; 1250 1251 bad: 1252 error = EBADRPC; 1253 1254 out: 1255 m_freem(m); 1256 return error; 1257 } 1258