|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /* Copyright (c) 1995, 1997 NeXT Computer, Inc. All Rights Reserved */
23: /*
24: * Copyright (c) 1994 Adam Glass, Gordon Ross
25: * All rights reserved.
26: *
27: * This software was developed by the Computer Systems Engineering group
28: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
29: * contributed to Berkeley.
30: *
31: * Redistribution and use in source and binary forms, with or without
32: * modification, are permitted provided that the following conditions
33: * are met:
34: * 1. Redistributions of source code must retain the above copyright
35: * notice, this list of conditions and the following disclaimer.
36: * 2. Redistributions in binary form must reproduce the above copyright
37: * notice, this list of conditions and the following disclaimer in the
38: * documentation and/or other materials provided with the distribution.
39: * 3. All advertising materials mentioning features or use of this software
40: * must display the following acknowledgement:
41: * This product includes software developed by the University of
42: * California, Lawrence Berkeley Laboratory and its contributors.
43: * 4. Neither the name of the University nor the names of its contributors
44: * may be used to endorse or promote products derived from this software
45: * without specific prior written permission.
46: *
47: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57: * SUCH DAMAGE.
58: *
59: * History:
60: * 14-March-97 Dieter Siegmund ([email protected])
61: * - Use BOOTP instead of RARP to get the IP address at boot time
62: *
63: * 23-May-97 Umesh Vaishampayan ([email protected])
64: * - Added the ability to mount "/private" separately.
65: *
66: * 30-May-97 Dieter Siegmund ([email protected])
67: * - Clear out the ireq structure before using it to prevent
68: * our sending using a bogus source IP address, we should use
69: * an IP address of all zeroes
70: * - Right after BOOTP, get the correct netmask using AUTONETMASK
71: * 18-Jul-97 Dieter Siegmund ([email protected])
72: * - we can't restrict the netmask until we have a default route,
73: * removed AUTONETMASK call (ifdef'd out)
74: * 5-Aug-97 Dieter Siegmund ([email protected])
75: * - use the default route from the bpwhoami call, enabled autonetmask
76: * again
77: * 19-Feb-1999 Dieter Siegmund ([email protected])
78: * - use new BOOTP routine to get the subnet mask and router
79: * and stop using SIOCAUTOADDR
80: * - don't bother mounting private separately if it's not
81: * specified or not required because they are substrings of
82: * one another ie. root=host:/A and private=host:/A/private
83: * - allow the root path to be specified in the boot variable
84: * "rp" (AKA "rootpath")
85: * 19-Jul-1999 Dieter Siegmund ([email protected])
86: * - replaced big automatic arrays with MALLOC'd data
87: */
88:
89: #include <sys/param.h>
90: #include <sys/systm.h>
91: #include <sys/kernel.h>
92: #include <sys/conf.h>
93: #include <sys/ioctl.h>
94: #include <sys/proc.h>
95: #include <sys/mount.h>
96: #include <sys/mbuf.h>
97:
98: #include <sys/malloc.h>
99: #include <sys/socket.h>
100: #include <sys/reboot.h>
101:
102: #include <net/if.h>
103: #include <net/if_dl.h>
104: #include <net/if_types.h>
105: #include <net/route.h>
106:
107: #include <netinet/in.h>
108: #include <netinet/if_ether.h>
109:
110: #include <nfs/rpcv2.h>
111: #include <nfs/nfsproto.h>
112: #include <nfs/nfs.h>
113: #include <nfs/nfsdiskless.h>
114: #include <nfs/krpc.h>
115:
116: #include <pexpert/pexpert.h>
117:
118: #include "ether.h"
119:
120: #include <libkern/libkern.h>
121:
122: extern char *strchr(const char *str, int ch);
123:
124: #if NETHER == 0
125:
126: int nfs_boot_init(nd, procp)
127: struct nfs_diskless *nd;
128: struct proc *procp;
129: {
130: panic("nfs_boot_init: no ether");
131: }
132:
133: #else /* NETHER */
134:
135: /*
136: * Support for NFS diskless booting, specifically getting information
137: * about where to boot from, what pathnames, etc.
138: *
139: * This implememtation uses RARP and the bootparam RPC.
140: * We are forced to implement RPC anyway (to get file handles)
141: * so we might as well take advantage of it for bootparam too.
142: *
143: * The diskless boot sequence goes as follows:
144: * (1) Use RARP to get our interface address
145: * (2) Use RPC/bootparam/whoami to get our hostname,
146: * our IP address, and the server's IP address.
147: * (3) Use RPC/bootparam/getfile to get the root path
148: * (4) Use RPC/mountd to get the root file handle
149: * (5) Use RPC/bootparam/getfile to get the swap path
150: * (6) Use RPC/mountd to get the swap file handle
151: *
152: * (This happens to be the way Sun does it too.)
153: */
154:
155: extern int bootp(struct ifnet * ifp, struct in_addr * iaddr_p, int max_retry,
156: struct in_addr * netmask_p, struct in_addr * router_p,
157: struct proc * procp);
158:
159: /* bootparam RPC */
160: static int bp_whoami __P((struct sockaddr_in *bpsin,
161: struct in_addr *my_ip, struct in_addr *gw_ip));
162: static int bp_getfile __P((struct sockaddr_in *bpsin, char *key,
163: struct sockaddr_in *mdsin, char *servname, char *path));
164:
165: static boolean_t path_getfile __P((char * image_path,
166: struct sockaddr_in * sin_p,
167: char * serv_name, char * pathname));
168:
169: static __inline__
170: u_long iptohl(struct in_addr ip)
171: {
172: return (ntohl(ip.s_addr));
173: }
174:
175: static __inline__ boolean_t
176: same_subnet(struct in_addr addr1, struct in_addr addr2, struct in_addr mask)
177: {
178: u_long m = iptohl(mask);
179: if ((iptohl(addr1) & m) != (iptohl(addr2) & m))
180: return (FALSE);
181: return (TRUE);
182: }
183:
184: /* mountd RPC */
185: static int md_mount __P((struct sockaddr_in *mdsin, char *path,
186: u_char *fh));
187:
188: /* other helpers */
189: static void get_file_handle __P((char *pathname, struct nfs_dlmount *ndmntp));
190:
191: #define IP_FORMAT "%d.%d.%d.%d"
192: #define IP_CH(ip) ((u_char *)ip)
193: #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
194: /*
195: * Called with an empty nfs_diskless struct to be filled in.
196: */
197: int
198: nfs_boot_init(nd, procp)
199: struct nfs_diskless *nd;
200: struct proc *procp;
201: {
202: char * booter_path = NULL;
203: boolean_t do_bpwhoami = TRUE;
204: boolean_t do_bpgetfile = TRUE;
205: struct ifreq ireq;
206: struct in_addr my_ip;
207: struct sockaddr_in bp_sin;
208: struct sockaddr_in *sin;
209: struct ifnet *ifp;
210: struct in_addr gw_ip;
211: struct socket *so;
212: struct in_addr my_netmask;
213: int error;
214: char * root_path = NULL;
215:
216: MALLOC(booter_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
217: MALLOC(root_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
218:
219: /* booter-supplied path */
220: if (!PE_parse_boot_arg("rp", booter_path)
221: && !PE_parse_boot_arg("rootpath", booter_path)) {
222: booter_path[0] = 0;
223: }
224:
225: root_path[0] = 0;
226:
227: gw_ip.s_addr = 0;
228:
229: /* clear out the request structure */
230: bzero(&ireq, sizeof(ireq));
231:
232: /*
233: * Find an interface, rarp for its ip address, stuff it, the
234: * implied broadcast addr, and netmask into a nfs_diskless struct.
235: *
236: * This was moved here from nfs_vfsops.c because this procedure
237: * would be quite different if someone decides to write (i.e.) a
238: * BOOTP version of this file (might not use RARP, etc.)
239: */
240:
241: /*
242: * Find a network interface.
243: */
244: ifp = NULL;
245: { /* if the root device is set, use it */
246: extern char rootdevice[];
247: if (rootdevice[0])
248: ifp = ifunit(rootdevice);
249: }
250: if (ifp == NULL) { /* search for network device */
251: /* for (ifp = ifnet; ifp; ifp = ifp->if_next)*/
252: TAILQ_FOREACH(ifp, &ifnet, if_link)
253: if ((ifp->if_flags &
254: (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
255: break;
256: }
257: if (ifp == NULL)
258: panic("nfs_boot: no suitable interface");
259: sprintf(ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
260: printf("nfs_boot: using network interface '%s'\n", ireq.ifr_name);
261:
262: /*
263: * Bring up the interface.
264: */
265: if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0)
266: panic("nfs_boot: socreate, error=%d", error);
267: ireq.ifr_flags = ifp->if_flags | IFF_UP;
268: error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp);
269: if (error)
270: panic("nfs_boot: SIFFLAGS, error=%d", error);
271:
272: #define DO_BOOTP
273: #ifdef DO_BOOTP
274: { /* use BOOTP to retrieve IP address, netmask and router */
275: struct sockaddr_in sockin;
276: struct in_addr router;
277: struct in_addr netmask;
278:
279: my_ip.s_addr = 0;
280: netmask.s_addr = 0;
281: router.s_addr = 0;
282: sockin.sin_family = AF_INET;
283: sockin.sin_len = sizeof(sockin);
284: sockin.sin_addr.s_addr = 0;
285: #define RETRY_COUNT 32
286: while ((error = bootp(ifp, &my_ip, RETRY_COUNT,
287: &netmask, &router, procp))) {
288: if (error == ETIMEDOUT)
289: printf("nfs_boot: BOOTP timed out, retrying...\n");
290:
291: else {
292: printf("nfs_boot: bootp() failed, error = %d\n", error);
293: panic("nfs_boot");
294: }
295: }
296: /* clear the netmask */
297: ((struct sockaddr_in *)&ireq.ifr_addr)->sin_addr.s_addr = 0;
298: error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)&ireq, procp);
299: if (error)
300: printf("nfs_boot: SIOCSIFNETMASK failed: %d\n", error);
301:
302: if (netmask.s_addr) {
303: /* set our new subnet mask */
304: sockin.sin_addr = netmask;
305: *((struct sockaddr_in *)&ireq.ifr_addr) = sockin;
306: error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)&ireq, procp);
307: if (error)
308: printf("nfs_boot: SIOCSIFNETMASK failed: %d\n", error);
309: }
310:
311: /* set our address */
312: sockin.sin_addr = my_ip;
313: *((struct sockaddr_in *)&ireq.ifr_addr) = sockin;
314: error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp);
315: if (error) {
316: printf("SIOCSIFADDR failed: %d\n", error);
317: panic("nfs_boot.c");
318: }
319: printf("nfs_boot: IP address " IP_FORMAT, IP_LIST(&my_ip));
320: if (netmask.s_addr)
321: printf(" netmask " IP_FORMAT, IP_LIST(&netmask));
322: if (router.s_addr) {
323: gw_ip = router;
324: printf(" router " IP_FORMAT, IP_LIST(&router));
325: }
326: printf("\n");
327: }
328: #else
329: /*
330: * Do RARP for the interface address.
331: */
332: if ((error = revarpwhoami(&my_ip, ifp)) != 0)
333: panic("revarp failed, error=%d", error);
334: printf("nfs_boot: client_addr=0x%x\n", ntohl(my_ip.s_addr));
335:
336: /*
337: * Do enough of ifconfig(8) so that the chosen interface
338: * can talk to the servers. (just set the address)
339: */
340: sin = (struct sockaddr_in *)&ireq.ifr_addr;
341: bzero((caddr_t)sin, sizeof(*sin));
342: sin->sin_len = sizeof(*sin);
343: sin->sin_family = AF_INET;
344: sin->sin_addr.s_addr = my_ip.s_addr;
345: error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp);
346: if (error)
347: panic("nfs_boot: set if addr, error=%d", error);
348: #endif DO_BOOTP
349:
350: /* need netmask to determine whether NFS server local */
351: sin = (struct sockaddr_in *)&ireq.ifr_addr;
352: bzero((caddr_t)sin, sizeof(*sin));
353: sin->sin_len = sizeof(*sin);
354: sin->sin_family = AF_INET;
355: error = ifioctl(so, SIOCGIFNETMASK, (caddr_t)&ireq, procp);
356: if (error)
357: panic("nfs_boot: SIOCGIFNETMASK error=%d", error);
358: my_netmask = sin->sin_addr;
359:
360: soclose(so);
361:
362: /* check for a booter-specified path */
363: if (booter_path[0]) {
364: nd->nd_root.ndm_saddr.sin_addr.s_addr = 0;
365: nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
366: if (path_getfile(booter_path, &nd->nd_root.ndm_saddr,
367: nd->nd_root.ndm_host, root_path)) {
368: do_bpgetfile = FALSE;
369: printf("nfs_boot: using booter-supplied path '%s'\n",
370: booter_path);
371: if (same_subnet(nd->nd_root.ndm_saddr.sin_addr,
372: my_ip, my_netmask)
373: || gw_ip.s_addr) {
374: do_bpwhoami = FALSE;
375: }
376: else {
377: /* do bpwhoami to attempt to get the router */
378: }
379: }
380: else {
381: printf("nfs_boot: ignoring badly formed bootpath '%s'\n",
382: booter_path);
383: }
384: }
385:
386: if (do_bpwhoami) {
387: /*
388: * Get client name and gateway address.
389: * RPC: bootparam/whoami
390: * Use the old broadcast address for the WHOAMI
391: * call because we do not yet know our netmask.
392: * The server address returned by the WHOAMI call
393: * is used for all subsequent booptaram RPCs.
394: */
395: bzero((caddr_t)&bp_sin, sizeof(bp_sin));
396: bp_sin.sin_len = sizeof(bp_sin);
397: bp_sin.sin_family = AF_INET;
398: bp_sin.sin_addr.s_addr = INADDR_BROADCAST;
399: hostnamelen = MAXHOSTNAMELEN;
400:
401: { /* bpwhoami also returns gateway IP address */
402:
403: struct in_addr router;
404:
405: router.s_addr = 0;
406: error = bp_whoami(&bp_sin, &my_ip, &router);
407: if (error) {
408: printf("nfs_boot: bootparam whoami, error=%d", error);
409: panic("nfs_boot: bootparam whoami\n");
410: }
411: /* if not already set by BOOTP, use the one from BPWHOAMI */
412: if (gw_ip.s_addr == 0)
413: gw_ip = router;
414: }
415: printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n",
416: IP_LIST(&bp_sin.sin_addr));
417: printf("nfs_boot: hostname %s\n", hostname);
418: }
419: #define NFS_BOOT_GATEWAY 1
420: #ifdef NFS_BOOT_GATEWAY
421: /*
422: * DWS 2/18/1999
423: * The comment below does not apply to gw_ip discovered
424: * via BOOTP (see DO_BOOTP loop above) since BOOTP servers
425: * are supposed to be more trustworthy.
426: */
427: /*
428: * XXX - This code is conditionally compiled only because
429: * many bootparam servers (in particular, SunOS 4.1.3)
430: * always set the gateway address to their own address.
431: * The bootparam server is not necessarily the gateway.
432: * We could just believe the server, and at worst you would
433: * need to delete the incorrect default route before adding
434: * the correct one, but for simplicity, ignore the gateway.
435: * If your server is OK, you can turn on this option.
436: *
437: * If the gateway address is set, add a default route.
438: * (The mountd RPCs may go across a gateway.)
439: */
440: if (gw_ip.s_addr) {
441: struct sockaddr dst, gw, mask;
442: /* Destination: (default) */
443: bzero((caddr_t)&dst, sizeof(dst));
444: dst.sa_len = sizeof(dst);
445: dst.sa_family = AF_INET;
446: /* Gateway: */
447: bzero((caddr_t)&gw, sizeof(gw));
448: sin = (struct sockaddr_in *)&gw;
449: sin->sin_len = sizeof(gw);
450: sin->sin_family = AF_INET;
451: sin->sin_addr.s_addr = gw_ip.s_addr;
452: /* Mask: (zero length) */
453: bzero(&mask, sizeof(mask));
454: printf("nfs_boot: adding default route " IP_FORMAT "\n",
455: IP_LIST(&gw_ip));
456: /* add, dest, gw, mask, flags, 0 */
457: error = rtrequest(RTM_ADD, &dst, (struct sockaddr *)&gw,
458: &mask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
459: if (error)
460: printf("nfs_boot: add route, error=%d\n", error);
461: }
462: #endif
463: if (do_bpgetfile) {
464: error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr,
465: nd->nd_root.ndm_host, root_path);
466: if (error) {
467: printf("nfs_boot: bootparam get root: %d\n", error);
468: panic("nfs_boot: bootparam get root");
469: }
470: }
471:
472: get_file_handle(root_path, &nd->nd_root);
473:
474: #if !defined(NO_MOUNT_PRIVATE)
475: if (do_bpgetfile) { /* get private path */
476: char * private_path = NULL;
477:
478: MALLOC(private_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
479: error = bp_getfile(&bp_sin, "private",
480: &nd->nd_private.ndm_saddr,
481: nd->nd_private.ndm_host, private_path);
482: if (!error) {
483: char * check_path = NULL;
484:
485: MALLOC(check_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
486: sprintf(check_path, "%s/private", root_path);
487: if ((nd->nd_root.ndm_saddr.sin_addr.s_addr
488: == nd->nd_private.ndm_saddr.sin_addr.s_addr)
489: && (strcmp(check_path, private_path) == 0)) {
490: /* private path is prefix of root path, don't mount */
491: nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
492: }
493: else {
494: get_file_handle(private_path, &nd->nd_private);
495: }
496: _FREE(check_path, M_TEMP);
497: }
498: else {
499: /* private key not defined, don't mount */
500: nd->nd_private.ndm_saddr.sin_addr.s_addr = 0;
501: }
502: _FREE(private_path, M_TEMP);
503: }
504: #endif NO_MOUNT_PRIVATE
505: _FREE(booter_path, M_TEMP);
506: _FREE(root_path, M_TEMP);
507: return (0);
508: }
509:
510: int
511: inet_aton(char * cp, struct in_addr * pin)
512: {
513: u_char * b = (char *)pin;
514: int i;
515: char * p;
516:
517: for (p = cp, i = 0; i < 4; i++) {
518: u_long l = strtoul(p, 0, 0);
519: if (l > 255)
520: return (FALSE);
521: b[i] = l;
522: p = strchr(p, '.');
523: if (i < 3 && p == NULL)
524: return (FALSE);
525: p++;
526: }
527: return (TRUE);
528: }
529:
530: /*
531: * Function: parse_image_path
532: * Purpose:
533: * Parse a string of the form "<IP>:<host>:<path>" into
534: * the given ip address and host and pathnames.
535: * Example:
536: * "17.202.16.17:seaport:/release/.images/Image9/CurrentHera"
537: */
538: static __inline__ boolean_t
539: parse_image_path(char * c, struct in_addr * iaddr_p, char * hostname,
540: char * pathname)
541: {
542: char * d;
543: char * p;
544: #define TMP_SIZE 128
545: char tmp[TMP_SIZE];
546:
547: p = strchr(c, ':');
548: if (p == NULL)
549: return (FALSE);
550: if ((p - c) >= TMP_SIZE)
551: return (FALSE);
552: strncpy(tmp, c, p - c);
553: tmp[p - c] = 0;
554: if (inet_aton(tmp, iaddr_p) != 1)
555: return (FALSE);
556: p++;
557: d = strchr(p, ':');
558: if (d == NULL)
559: return (FALSE);
560: strncpy(hostname, p, d - p);
561: hostname[d - p] = 0;
562: d++;
563: strcpy(pathname, d);
564: return (TRUE);
565: }
566:
567: static boolean_t
568: path_getfile(char * image_path, struct sockaddr_in * sin_p,
569: char * serv_name, char * pathname)
570: {
571: bzero((caddr_t)sin_p, sizeof(*sin_p));
572: sin_p->sin_len = sizeof(*sin_p);
573: sin_p->sin_family = AF_INET;
574: if (parse_image_path(image_path, &sin_p->sin_addr, serv_name, pathname)
575: == FALSE)
576: return (FALSE);
577: return (TRUE);
578: }
579:
580: static void
581: get_file_handle(pathname, ndmntp)
582: char *pathname; /* path on server */
583: struct nfs_dlmount *ndmntp; /* output */
584: {
585: char *sp, *dp, *endp;
586: int error;
587:
588: /*
589: * Get file handle for "key" (root or swap)
590: * using RPC to mountd/mount
591: */
592: error = md_mount(&ndmntp->ndm_saddr, pathname, ndmntp->ndm_fh);
593: if (error)
594: panic("nfs_boot: mountd, error=%d", error);
595:
596: /* Construct remote path (for getmntinfo(3)) */
597: dp = ndmntp->ndm_host;
598: endp = dp + MNAMELEN - 1;
599: dp += strlen(dp);
600: *dp++ = ':';
601: for (sp = pathname; *sp && dp < endp;)
602: *dp++ = *sp++;
603: *dp = '\0';
604:
605: }
606:
607:
608: /*
609: * Get an mbuf with the given length, and
610: * initialize the pkthdr length field.
611: */
612: static struct mbuf *
613: m_get_len(int msg_len)
614: {
615: struct mbuf *m;
616: m = m_gethdr(M_WAIT, MT_DATA);
617: if (m == NULL)
618: return NULL;
619: if (msg_len > MHLEN) {
620: if (msg_len > MCLBYTES)
621: panic("nfs_boot: msg_len > MCLBYTES");
622: MCLGET(m, M_WAIT);
623: if (m == NULL)
624: return NULL;
625: }
626: m->m_len = msg_len;
627: m->m_pkthdr.len = m->m_len;
628: return (m);
629: }
630:
631:
632: /*
633: * String representation for RPC.
634: */
635: struct rpc_string {
636: u_long len; /* length without null or padding */
637: u_char data[4]; /* data (longer, of course) */
638: /* data is padded to a long-word boundary */
639: };
640: /* Compute space used given string length. */
641: #define RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3))
642:
643: /*
644: * Inet address in RPC messages
645: * (Note, really four longs, NOT chars. Blech.)
646: */
647: struct bp_inaddr {
648: u_long atype;
649: long addr[4];
650: };
651:
652:
653: /*
654: * RPC: bootparam/whoami
655: * Given client IP address, get:
656: * client name (hostname)
657: * domain name (domainname)
658: * gateway address
659: *
660: * The hostname and domainname are set here for convenience.
661: *
662: * Note - bpsin is initialized to the broadcast address,
663: * and will be replaced with the bootparam server address
664: * after this call is complete. Have to use PMAP_PROC_CALL
665: * to make sure we get responses only from a servers that
666: * know about us (don't want to broadcast a getport call).
667: */
668: static int
669: bp_whoami(bpsin, my_ip, gw_ip)
670: struct sockaddr_in *bpsin;
671: struct in_addr *my_ip;
672: struct in_addr *gw_ip;
673: {
674: /* RPC structures for PMAPPROC_CALLIT */
675: struct whoami_call {
676: u_long call_prog;
677: u_long call_vers;
678: u_long call_proc;
679: u_long call_arglen;
680: struct bp_inaddr call_ia;
681: } *call;
682:
683: struct rpc_string *str;
684: struct bp_inaddr *bia;
685: struct mbuf *m;
686: struct sockaddr_in *sin;
687: int error, msg_len;
688: int cn_len, dn_len;
689: u_char *p;
690: long *lp;
691:
692: /*
693: * Get message buffer of sufficient size.
694: */
695: msg_len = sizeof(*call);
696: m = m_get_len(msg_len);
697: if (m == NULL)
698: return ENOBUFS;
699:
700: /*
701: * Build request message for PMAPPROC_CALLIT.
702: */
703: call = mtod(m, struct whoami_call *);
704: call->call_prog = htonl(BOOTPARAM_PROG);
705: call->call_vers = htonl(BOOTPARAM_VERS);
706: call->call_proc = htonl(BOOTPARAM_WHOAMI);
707: call->call_arglen = htonl(sizeof(struct bp_inaddr));
708:
709: /* client IP address */
710: call->call_ia.atype = htonl(1);
711: p = (u_char*)my_ip;
712: lp = call->call_ia.addr;
713: *lp++ = htonl(*p); p++;
714: *lp++ = htonl(*p); p++;
715: *lp++ = htonl(*p); p++;
716: *lp++ = htonl(*p); p++;
717:
718: /* RPC: portmap/callit */
719: bpsin->sin_port = htons(PMAPPORT);
720:
721: error = krpc_call(bpsin, PMAPPROG, PMAPVERS,
722: PMAPPROC_CALLIT, &m, &sin);
723: if (error)
724: return error;
725:
726: /*
727: * Parse result message.
728: */
729: msg_len = m->m_len;
730: lp = mtod(m, long *);
731:
732: /* bootparam server port (also grab from address). */
733: if (msg_len < sizeof(*lp))
734: goto bad;
735: msg_len -= sizeof(*lp);
736: bpsin->sin_port = htons((short)ntohl(*lp++));
737: bpsin->sin_addr.s_addr = sin->sin_addr.s_addr;
738:
739: /* length of encapsulated results */
740: if (msg_len < (ntohl(*lp) + sizeof(*lp)))
741: goto bad;
742: msg_len = ntohl(*lp++);
743: p = (char*)lp;
744:
745: /* client name */
746: if (msg_len < sizeof(*str))
747: goto bad;
748: str = (struct rpc_string *)p;
749: cn_len = ntohl(str->len);
750: if (msg_len < cn_len)
751: goto bad;
752: if (cn_len >= MAXHOSTNAMELEN)
753: goto bad;
754: bcopy(str->data, hostname, cn_len);
755: hostname[cn_len] = '\0';
756: hostnamelen = cn_len;
757: p += RPC_STR_SIZE(cn_len);
758: msg_len -= RPC_STR_SIZE(cn_len);
759:
760: /* domain name */
761: if (msg_len < sizeof(*str))
762: goto bad;
763: str = (struct rpc_string *)p;
764: dn_len = ntohl(str->len);
765: if (msg_len < dn_len)
766: goto bad;
767: if (dn_len >= MAXHOSTNAMELEN)
768: goto bad;
769: bcopy(str->data, domainname, dn_len);
770: domainname[dn_len] = '\0';
771: domainnamelen = dn_len;
772: p += RPC_STR_SIZE(dn_len);
773: msg_len -= RPC_STR_SIZE(dn_len);
774:
775: /* gateway address */
776: if (msg_len < sizeof(*bia))
777: goto bad;
778: bia = (struct bp_inaddr *)p;
779: if (bia->atype != htonl(1))
780: goto bad;
781: p = (u_char*)gw_ip;
782: *p++ = ntohl(bia->addr[0]);
783: *p++ = ntohl(bia->addr[1]);
784: *p++ = ntohl(bia->addr[2]);
785: *p++ = ntohl(bia->addr[3]);
786: goto out;
787:
788: bad:
789: printf("nfs_boot: bootparam_whoami: bad reply\n");
790: error = EBADRPC;
791:
792: out:
793: if (sin)
794: FREE(sin, M_SONAME);
795:
796: m_freem(m);
797: return(error);
798: }
799:
800:
801: /*
802: * RPC: bootparam/getfile
803: * Given client name and file "key", get:
804: * server name
805: * server IP address
806: * server pathname
807: */
808: static int
809: bp_getfile(bpsin, key, md_sin, serv_name, pathname)
810: struct sockaddr_in *bpsin;
811: char *key;
812: struct sockaddr_in *md_sin;
813: char *serv_name;
814: char *pathname;
815: {
816: struct rpc_string *str;
817: struct mbuf *m;
818: struct bp_inaddr *bia;
819: struct sockaddr_in *sin;
820: u_char *p, *q;
821: int error, msg_len;
822: int cn_len, key_len, sn_len, path_len;
823:
824: /*
825: * Get message buffer of sufficient size.
826: */
827: cn_len = hostnamelen;
828: key_len = strlen(key);
829: msg_len = 0;
830: msg_len += RPC_STR_SIZE(cn_len);
831: msg_len += RPC_STR_SIZE(key_len);
832: m = m_get_len(msg_len);
833: if (m == NULL)
834: return ENOBUFS;
835:
836: /*
837: * Build request message.
838: */
839: p = mtod(m, u_char *);
840: bzero(p, msg_len);
841: /* client name (hostname) */
842: str = (struct rpc_string *)p;
843: str->len = htonl(cn_len);
844: bcopy(hostname, str->data, cn_len);
845: p += RPC_STR_SIZE(cn_len);
846: /* key name (root or swap) */
847: str = (struct rpc_string *)p;
848: str->len = htonl(key_len);
849: bcopy(key, str->data, key_len);
850:
851: /* RPC: bootparam/getfile */
852: error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS,
853: BOOTPARAM_GETFILE, &m, NULL);
854: if (error)
855: return error;
856:
857: /*
858: * Parse result message.
859: */
860: p = mtod(m, u_char *);
861: msg_len = m->m_len;
862:
863: /* server name */
864: if (msg_len < sizeof(*str))
865: goto bad;
866: str = (struct rpc_string *)p;
867: sn_len = ntohl(str->len);
868: if (msg_len < sn_len)
869: goto bad;
870: if (sn_len >= MNAMELEN)
871: goto bad;
872: bcopy(str->data, serv_name, sn_len);
873: serv_name[sn_len] = '\0';
874: p += RPC_STR_SIZE(sn_len);
875: msg_len -= RPC_STR_SIZE(sn_len);
876:
877: /* server IP address (mountd) */
878: if (msg_len < sizeof(*bia))
879: goto bad;
880: bia = (struct bp_inaddr *)p;
881: if (bia->atype != htonl(1))
882: goto bad;
883: sin = md_sin;
884: bzero((caddr_t)sin, sizeof(*sin));
885: sin->sin_len = sizeof(*sin);
886: sin->sin_family = AF_INET;
887: q = (u_char*) &sin->sin_addr;
888: *q++ = ntohl(bia->addr[0]);
889: *q++ = ntohl(bia->addr[1]);
890: *q++ = ntohl(bia->addr[2]);
891: *q++ = ntohl(bia->addr[3]);
892: p += sizeof(*bia);
893: msg_len -= sizeof(*bia);
894:
895: /* server pathname */
896: if (msg_len < sizeof(*str))
897: goto bad;
898: str = (struct rpc_string *)p;
899: path_len = ntohl(str->len);
900: if (msg_len < path_len)
901: goto bad;
902: if (path_len >= MAXPATHLEN)
903: goto bad;
904: bcopy(str->data, pathname, path_len);
905: pathname[path_len] = '\0';
906: goto out;
907:
908: bad:
909: printf("nfs_boot: bootparam_getfile: bad reply\n");
910: error = EBADRPC;
911:
912: out:
913: m_freem(m);
914: return(0);
915: }
916:
917:
918: /*
919: * RPC: mountd/mount
920: * Given a server pathname, get an NFS file handle.
921: * Also, sets sin->sin_port to the NFS service port.
922: */
923: static int
924: md_mount(mdsin, path, fhp)
925: struct sockaddr_in *mdsin; /* mountd server address */
926: char *path;
927: u_char *fhp;
928: {
929: /* The RPC structures */
930: struct rpc_string *str;
931: struct rdata {
932: u_long errno;
933: u_char fh[NFSX_V2FH];
934: } *rdata;
935: struct mbuf *m;
936: int error, mlen, slen;
937:
938: /* Get port number for MOUNTD. */
939: error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
940: &mdsin->sin_port);
941: if (error) return error;
942:
943: slen = strlen(path);
944: mlen = RPC_STR_SIZE(slen);
945:
946: m = m_get_len(mlen);
947: if (m == NULL)
948: return ENOBUFS;
949: str = mtod(m, struct rpc_string *);
950: str->len = htonl(slen);
951: bcopy(path, str->data, slen);
952:
953: /* Do RPC to mountd. */
954: error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
955: RPCMNT_MOUNT, &m, NULL);
956: if (error)
957: return error; /* message already freed */
958:
959: mlen = m->m_len;
960: if (mlen < sizeof(*rdata))
961: goto bad;
962: rdata = mtod(m, struct rdata *);
963: error = ntohl(rdata->errno);
964: if (error)
965: goto bad;
966: bcopy(rdata->fh, fhp, NFSX_V2FH);
967:
968: /* Set port number for NFS use. */
969: error = krpc_portmap(mdsin, NFS_PROG, NFS_VER2,
970: &mdsin->sin_port);
971: goto out;
972:
973: bad:
974: error = EBADRPC;
975:
976: out:
977: m_freem(m);
978: return error;
979: }
980:
981: #endif /* NETHER */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.