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