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