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