1 /* $NetBSD: nfs_bootdhcp.c,v 1.50 2009/07/10 02:41:39 roy Exp $ */
4 * Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Adam Glass and Gordon W. Ross.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Support for NFS diskless booting with BOOTP (RFC951, RFC1048)
37 * Tor Egge developed the initial version of this code based on
38 * the Sun RPC/bootparam sources nfs_boot.c and krpc_subr.c and
39 * submitted that work to NetBSD as bugreport "kern/2351" on
42 * Gordon Ross reorganized Tor's version into this form and
43 * integrated it into the NetBSD sources during Aug 1997.
46 #include <sys/cdefs.h>
47 __KERNEL_RCSID(0, "$NetBSD: nfs_bootdhcp.c,v 1.50 2009/07/10 02:41:39 roy Exp $");
50 #include "opt_nfs_boot.h"
51 #include "opt_tftproot.h"
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/kernel.h>
57 #include <sys/device.h>
58 #include <sys/ioctl.h>
60 #include <sys/mount.h>
62 #include <sys/reboot.h>
63 #include <sys/socket.h>
64 #include <sys/socketvar.h>
67 #include <net/if_types.h>
68 #include <net/if_arp.h> /* ARPHRD_ETHER, etc. */
69 #include <net/if_dl.h>
70 #include <net/if_ether.h>
71 #include <net/route.h>
73 #include <netinet/in.h>
74 #include <netinet/if_inarp.h>
76 #include <nfs/rpcv2.h>
78 #include <nfs/nfsproto.h>
80 #include <nfs/nfsmount.h>
81 #include <nfs/nfsdiskless.h>
84 * There are two implementations of NFS diskless boot.
85 * This implementation uses BOOTP (RFC951, RFC1048), and
86 * the other uses Sun RPC/bootparams (nfs_bootparam.c).
88 * This method gets everything it needs with one BOOTP
89 * request and reply. Note that this actually uses only
90 * the old BOOTP functionality subset of DHCP. It is not
91 * clear that DHCP provides any advantage over BOOTP for
92 * diskless boot. DHCP allows the server to assign an IP
93 * address without any a-priori knowledge of the client,
94 * but we require that the server has a-priori knowledge
95 * of the client so it can export our (unique) NFS root.
96 * Given that the server needs a-priori knowledge about
97 * the client anyway, it might as well assign a fixed IP
98 * address for the client and support BOOTP.
100 * On the other hand, disk-FULL clients may use DHCP, but
101 * in that case the DHCP client should be user-mode code,
102 * and has no bearing on the code below. -gwr
105 /* Begin stuff from bootp.h */
106 /* Definitions from RFC951 */
107 #define BP_CHADDR_LEN 16
108 #define BP_SNAME_LEN 64
109 #define BP_FILE_LEN 128
110 #define BP_VEND_LEN 64
112 u_int8_t bp_op
; /* packet opcode type */
113 u_int8_t bp_htype
; /* hardware addr type */
114 u_int8_t bp_hlen
; /* hardware addr length */
115 u_int8_t bp_hops
; /* gateway hops */
116 u_int32_t bp_xid
; /* transaction ID */
117 u_int16_t bp_secs
; /* seconds since boot began */
118 u_int16_t bp_flags
; /* RFC1532 broadcast, etc. */
119 struct in_addr bp_ciaddr
; /* client IP address */
120 struct in_addr bp_yiaddr
; /* 'your' IP address */
121 struct in_addr bp_siaddr
; /* server IP address */
122 struct in_addr bp_giaddr
; /* gateway IP address */
123 u_int8_t bp_chaddr
[BP_CHADDR_LEN
]; /* client hardware address */
124 char bp_sname
[BP_SNAME_LEN
]; /* server host name */
125 char bp_file
[BP_FILE_LEN
]; /* boot file name */
126 u_int8_t bp_vend
[BP_VEND_LEN
]; /* RFC1048 options */
128 * Note that BOOTP packets are allowed to be longer
129 * (see RFC 1532 sect. 2.1) and common practice is to
130 * allow the option data in bp_vend to extend into the
131 * additional space provided in longer packets.
135 #define IPPORT_BOOTPS 67
136 #define IPPORT_BOOTPC 68
138 #define BOOTREQUEST 1
142 * Is this available from the sockaddr_dl somehow?
143 * Perhaps (struct arphdr)->ar_hrd = ARPHRD_ETHER?
144 * The interface has ->if_type but not the ARP fmt.
146 #define HTYPE_ETHERNET 1
147 #define HTYPE_IEEE802 6
150 * Vendor magic cookie (v_magic) for RFC1048
152 static const u_int8_t vm_rfc1048
[4] = { 99, 130, 83, 99 };
155 * Tag values used to specify what information is being supplied in
156 * the vendor (options) data area of the packet.
159 #define TAG_END ((unsigned char) 255)
160 #define TAG_PAD ((unsigned char) 0)
161 #define TAG_SUBNET_MASK ((unsigned char) 1)
162 #define TAG_TIME_OFFSET ((unsigned char) 2)
163 #define TAG_GATEWAY ((unsigned char) 3)
164 #define TAG_TIME_SERVER ((unsigned char) 4)
165 #define TAG_NAME_SERVER ((unsigned char) 5)
166 #define TAG_DOMAIN_SERVER ((unsigned char) 6)
167 #define TAG_LOG_SERVER ((unsigned char) 7)
168 #define TAG_COOKIE_SERVER ((unsigned char) 8)
169 #define TAG_LPR_SERVER ((unsigned char) 9)
170 #define TAG_IMPRESS_SERVER ((unsigned char) 10)
171 #define TAG_RLP_SERVER ((unsigned char) 11)
172 #define TAG_HOST_NAME ((unsigned char) 12)
173 #define TAG_BOOT_SIZE ((unsigned char) 13)
175 #define TAG_DUMP_FILE ((unsigned char) 14)
176 #define TAG_DOMAIN_NAME ((unsigned char) 15)
177 #define TAG_SWAP_SERVER ((unsigned char) 16)
178 #define TAG_ROOT_PATH ((unsigned char) 17)
179 /* End of stuff from bootp.h */
182 #define TAG_REQ_ADDR ((unsigned char) 50)
183 #define TAG_LEASETIME ((unsigned char) 51)
184 #define TAG_OVERLOAD ((unsigned char) 52)
185 #define TAG_DHCP_MSGTYPE ((unsigned char) 53)
186 #define TAG_SERVERID ((unsigned char) 54)
187 #define TAG_PARAM_REQ ((unsigned char) 55)
188 #define TAG_MSG ((unsigned char) 56)
189 #define TAG_MAXSIZE ((unsigned char) 57)
190 #define TAG_T1 ((unsigned char) 58)
191 #define TAG_T2 ((unsigned char) 59)
192 #define TAG_CLASSID ((unsigned char) 60)
193 #define TAG_CLIENTID ((unsigned char) 61)
197 #define DHCPDISCOVER 1
199 #define DHCPREQUEST 3
200 #define DHCPDECLINE 4
203 #define DHCPRELEASE 7
207 #define BOOTP_SIZE_MAX (sizeof(struct bootp)+312-64)
210 * The "extended" size is somewhat arbitrary, but is
211 * constrained by the maximum message size specified
212 * by RFC1533 (567 total). This value increases the
213 * space for options from 64 bytes to 256 bytes.
215 #define BOOTP_SIZE_MAX (sizeof(struct bootp)+256-64)
217 #define BOOTP_SIZE_MIN (sizeof(struct bootp))
219 /* Convenience macro */
220 #define INTOHL(ina) ((u_int32_t)ntohl((ina).s_addr))
222 static int bootpc_call (struct nfs_diskless
*, struct lwp
*, int *);
223 static void bootp_extract (struct bootp
*, int, struct nfs_diskless
*, int *);
225 #ifdef DEBUG_NFS_BOOT_DHCP
226 #define DPRINTF(s) printf s
233 * Get our boot parameters using BOOTP.
236 nfs_bootdhcp(struct nfs_diskless
*nd
, struct lwp
*lwp
, int *flags
)
238 struct ifnet
*ifp
= nd
->nd_ifp
;
242 * Do enough of ifconfig(8) so that the chosen interface
243 * can talk to the servers. Use address zero for now.
245 error
= nfs_boot_setaddress(ifp
, lwp
,
246 *flags
& NFS_BOOT_HAS_MYIP
? nd
->nd_myip
.s_addr
: INADDR_ANY
,
247 *flags
& NFS_BOOT_HAS_MASK
? nd
->nd_mask
.s_addr
: INADDR_ANY
,
250 printf("nfs_boot: set ifaddr zero, error=%d\n", error
);
254 /* This function call does the real send/recv work. */
255 error
= bootpc_call(nd
, lwp
, flags
);
257 /* Get rid of the temporary (zero) IP address. */
258 (void) nfs_boot_deladdress(ifp
, lwp
, INADDR_ANY
);
260 /* NOW we can test the error from bootpc_call. */
265 * Do ifconfig with our real IP address and mask.
267 error
= nfs_boot_setaddress(ifp
, lwp
, nd
->nd_myip
.s_addr
,
268 nd
->nd_mask
.s_addr
, INADDR_ANY
);
270 printf("nfs_boot: set ifaddr real, error=%d\n", error
);
274 if ((*flags
& NFS_BOOT_ALLINFO
) != NFS_BOOT_ALLINFO
) {
275 printf("nfs_boot: missing options (need IP, netmask, "
276 "gateway, next-server, root-path)\n");
277 return EADDRNOTAVAIL
;
282 (void) nfs_boot_ifupdown(ifp
, lwp
, 0);
283 nfs_boot_flushrt(ifp
);
288 struct bootpcontext
{
292 struct bootp
*replybuf
;
295 char expected_dhcpmsgtype
, dhcp_ok
;
296 struct in_addr dhcp_serverip
;
300 static int bootpset (struct mbuf
*, void*, int);
301 static int bootpcheck (struct mbuf
*, void*);
304 bootpset(struct mbuf
*m
, void *context
, int waited
)
308 /* we know it's contigous (in 1 mbuf cluster) */
309 bootp
= mtod(m
, struct bootp
*);
311 bootp
->bp_secs
= htons(waited
);
317 bootpcheck(struct mbuf
*m
, void *context
)
320 struct bootpcontext
*bpc
= context
;
325 * Is this a valid reply?
327 if (m
->m_pkthdr
.len
< BOOTP_SIZE_MIN
) {
328 DPRINTF(("bootpcheck: short packet %d < %zu\n",
329 m
->m_pkthdr
.len
, BOOTP_SIZE_MIN
));
332 if (m
->m_pkthdr
.len
> BOOTP_SIZE_MAX
) {
333 DPRINTF(("Bootpcheck: long packet %d > %zu\n",
334 m
->m_pkthdr
.len
, BOOTP_SIZE_MAX
));
339 * don't make first checks more expensive than necessary
341 if (m
->m_len
< offsetof(struct bootp
, bp_sname
)) {
342 m
= m_pullup(m
, offsetof(struct bootp
, bp_sname
));
344 DPRINTF(("bootpcheck: m_pullup failed\n"));
348 bootp
= mtod(m
, struct bootp
*);
350 if (bootp
->bp_op
!= BOOTREPLY
) {
351 DPRINTF(("bootpcheck: op %d is not reply\n", bootp
->bp_op
));
354 if (bootp
->bp_hlen
!= bpc
->halen
) {
355 DPRINTF(("bootpcheck: hlen %d != %d\n", bootp
->bp_hlen
,
359 if (memcmp(bootp
->bp_chaddr
, bpc
->haddr
, bpc
->halen
)) {
360 #ifdef DEBUG_NFS_BOOT_DHCP
361 char *bp_chaddr
, *haddr
;
363 bp_chaddr
= malloc(3 * bpc
->halen
, M_TEMP
, M_WAITOK
);
364 haddr
= malloc(3 * bpc
->halen
, M_TEMP
, M_WAITOK
);
366 DPRINTF(("bootpcheck: incorrect hwaddr %s != %s\n",
367 ether_snprintf(bp_chaddr
, 3 * bpc
->halen
,
369 ether_snprintf(haddr
, 3 * bpc
->halen
, bpc
->haddr
)));
371 free(bp_chaddr
, M_TEMP
);
376 if (bootp
->bp_xid
!= bpc
->xid
) {
377 DPRINTF(("bootpcheck: xid %d != %d\n", bootp
->bp_xid
,
383 * OK, it's worth to look deeper.
384 * We copy the mbuf into a flat buffer here because
385 * m_pullup() is a bit limited for this purpose
386 * (doesn't allocate a cluster if necessary).
388 bpc
->replylen
= m
->m_pkthdr
.len
;
389 m_copydata(m
, 0, bpc
->replylen
, (void *)bpc
->replybuf
);
390 bootp
= bpc
->replybuf
;
393 * Check if the IP address we get looks correct.
394 * (DHCP servers can send junk to unknown clients.)
395 * XXX more checks might be needed
397 if (bootp
->bp_yiaddr
.s_addr
== INADDR_ANY
||
398 bootp
->bp_yiaddr
.s_addr
== INADDR_BROADCAST
) {
399 printf("nfs_boot: wrong IP addr %s",
400 inet_ntoa(bootp
->bp_yiaddr
));
405 * Check the vendor data.
407 if (memcmp(bootp
->bp_vend
, vm_rfc1048
, 4)) {
408 printf("nfs_boot: reply missing options");
411 p
= &bootp
->bp_vend
[4];
412 limit
= ((u_char
*)bootp
) + bpc
->replylen
;
420 if ((p
+ len
) > limit
) {
421 printf("nfs_boot: option %d too long", tag
);
426 case TAG_DHCP_MSGTYPE
:
427 if (*p
!= bpc
->expected_dhcpmsgtype
)
432 memcpy(&bpc
->dhcp_serverip
.s_addr
, p
,
433 sizeof(bpc
->dhcp_serverip
.s_addr
));
444 printf(" (bad reply from %s)\n", inet_ntoa(bootp
->bp_siaddr
));
449 bootp_addvend(u_char
*area
)
455 *area
++ = TAG_PARAM_REQ
;
457 *area
++ = TAG_SUBNET_MASK
;
458 *area
++ = TAG_GATEWAY
;
459 *area
++ = TAG_HOST_NAME
;
460 *area
++ = TAG_DOMAIN_NAME
;
461 *area
++ = TAG_ROOT_PATH
;
462 *area
++ = TAG_SWAP_SERVER
;
464 /* Insert a NetBSD Vendor Class Identifier option. */
465 snprintf(vci
, sizeof(vci
), "%s:%s:kernel:%s", ostype
, MACHINE
,
467 vcilen
= strlen(vci
);
468 *area
++ = TAG_CLASSID
;
470 (void)memcpy(area
, vci
, vcilen
);
477 bootpc_call(struct nfs_diskless
*nd
, struct lwp
*lwp
, int *flags
)
480 struct ifnet
*ifp
= nd
->nd_ifp
;
481 static u_int32_t xid
= ~0xFF;
482 struct bootp
*bootp
; /* request */
483 struct mbuf
*m
, *nam
;
484 struct sockaddr_in
*sin
;
488 struct bootpcontext bpc
;
491 error
= socreate(AF_INET
, &so
, SOCK_DGRAM
, 0, lwp
, NULL
);
493 printf("bootp: socreate, error=%d\n", error
);
498 * Initialize to NULL anything that will hold an allocation,
499 * and free each at the end if not null.
504 /* Record our H/W (Ethernet) address. */
505 { const struct sockaddr_dl
*sdl
= ifp
->if_sadl
;
506 switch (sdl
->sdl_type
) {
508 hafmt
= HTYPE_IEEE802
;
512 hafmt
= HTYPE_ETHERNET
;
515 printf("bootp: unsupported interface type %d\n",
520 halen
= sdl
->sdl_alen
;
521 haddr
= (const unsigned char *)CLLADDR(sdl
);
525 * Skip the route table when sending on this socket.
526 * If this is not done, ip_output finds the loopback
527 * interface (why?) and then fails because broadcast
528 * is not supported on that interface...
533 error
= so_setsockopt(NULL
, so
, SOL_SOCKET
, SO_DONTROUTE
, &opt
,
537 DPRINTF(("bootpc_call: SO_DONTROUTE failed %d\n", error
));
541 /* Enable broadcast. */
542 if ((error
= nfs_boot_enbroadcast(so
))) {
543 DPRINTF(("bootpc_call: SO_BROADCAST failed %d\n", error
));
548 * Set some TTL so we can boot through routers.
549 * Real BOOTP forwarding agents don't need this; they obey "bp_hops"
550 * and set "bp_giaddr", thus rewrite the packet anyway.
551 * The "helper-address" feature of some popular router vendor seems
552 * to do simple IP forwarding and drops packets with (ip_ttl == 1).
557 error
= so_setsockopt(NULL
, so
, IPPROTO_IP
, IP_MULTICAST_TTL
,
561 DPRINTF(("bootpc_call: IP_MULTICAST_TTL failed %d\n", error
));
565 /* Set the receive timeout for the socket. */
566 if ((error
= nfs_boot_setrecvtimo(so
))) {
567 DPRINTF(("bootpc_call: SO_RCVTIMEO failed %d\n", error
));
572 * Bind the local endpoint to a bootp client port.
574 if ((error
= nfs_boot_sobind_ipport(so
, IPPORT_BOOTPC
, lwp
))) {
575 DPRINTF(("bootpc_call: bind failed %d\n", error
));
580 * Setup socket address for the server.
582 nam
= m_get(M_WAIT
, MT_SONAME
);
583 sin
= mtod(nam
, struct sockaddr_in
*);
584 sin
->sin_len
= nam
->m_len
= sizeof(*sin
);
585 sin
->sin_family
= AF_INET
;
586 sin
->sin_addr
.s_addr
= INADDR_BROADCAST
;
587 sin
->sin_port
= htons(IPPORT_BOOTPS
);
590 * Allocate buffer used for request
592 m
= m_gethdr(M_WAIT
, MT_DATA
);
594 bootp
= mtod(m
, struct bootp
*);
595 m
->m_pkthdr
.len
= m
->m_len
= BOOTP_SIZE_MAX
;
596 m
->m_pkthdr
.rcvif
= NULL
;
599 * Build the BOOTP reqest message.
600 * Note: xid is host order! (opaque to server)
602 memset((void *)bootp
, 0, BOOTP_SIZE_MAX
);
603 bootp
->bp_op
= BOOTREQUEST
;
604 bootp
->bp_htype
= hafmt
;
605 bootp
->bp_hlen
= halen
; /* Hardware address length */
606 bootp
->bp_xid
= ++xid
;
607 memcpy(bootp
->bp_chaddr
, haddr
, halen
);
608 #ifdef NFS_BOOT_BOOTP_REQFILE
609 strncpy(bootp
->bp_file
, NFS_BOOT_BOOTP_REQFILE
, sizeof(bootp
->bp_file
));
611 /* Fill-in the vendor data. */
612 memcpy(bootp
->bp_vend
, vm_rfc1048
, 4);
615 bootp
->bp_vend
[index
++] = TAG_DHCP_MSGTYPE
;
616 bootp
->bp_vend
[index
++] = 1;
617 bootp
->bp_vend
[index
++] = DHCPDISCOVER
;
619 bootp_addvend(&bootp
->bp_vend
[index
]);
624 bpc
.replybuf
= malloc(BOOTP_SIZE_MAX
, M_DEVBUF
, M_WAITOK
);
625 if (bpc
.replybuf
== NULL
)
626 panic("nfs_boot: malloc reply buf");
628 bpc
.expected_dhcpmsgtype
= DHCPOFFER
;
632 error
= nfs_boot_sendrecv(so
, nam
, bootpset
, m
,
633 bootpcheck
, 0, 0, &bpc
, lwp
);
641 bootp
->bp_vend
[index
++] = DHCPREQUEST
;
642 bootp
->bp_vend
[index
++] = TAG_REQ_ADDR
;
643 bootp
->bp_vend
[index
++] = 4;
644 memcpy(&bootp
->bp_vend
[index
], &bpc
.replybuf
->bp_yiaddr
, 4);
646 bootp
->bp_vend
[index
++] = TAG_SERVERID
;
647 bootp
->bp_vend
[index
++] = 4;
648 memcpy(&bootp
->bp_vend
[index
], &bpc
.dhcp_serverip
.s_addr
, 4);
650 bootp
->bp_vend
[index
++] = TAG_LEASETIME
;
651 bootp
->bp_vend
[index
++] = 4;
652 leasetime
= htonl(300);
653 memcpy(&bootp
->bp_vend
[index
], &leasetime
, 4);
655 bootp_addvend(&bootp
->bp_vend
[index
]);
657 bpc
.expected_dhcpmsgtype
= DHCPACK
;
659 error
= nfs_boot_sendrecv(so
, nam
, bootpset
, m
,
660 bootpcheck
, 0, 0, &bpc
, lwp
);
667 * bootpcheck() has copied the receive mbuf into
668 * the buffer at bpc.replybuf.
671 printf("nfs_boot: %s next-server: %s\n",
672 (bpc
.dhcp_ok
? "DHCP" : "BOOTP"),
674 printf("nfs_boot: BOOTP next-server: %s\n",
676 inet_ntoa(bpc
.replybuf
->bp_siaddr
));
678 bootp_extract(bpc
.replybuf
, bpc
.replylen
, nd
, flags
);
682 free(bpc
.replybuf
, M_DEVBUF
);
692 bootp_extract(struct bootp
*bootp
, int replylen
,
693 struct nfs_diskless
*nd
, int *flags
)
695 struct sockaddr_in
*sin
;
696 struct in_addr netmask
;
697 struct in_addr gateway
;
698 struct in_addr rootserver
;
699 char *myname
; /* my hostname */
700 char *mydomain
; /* my domainname */
709 /* Default these to "unspecified". */
712 mydomain
= myname
= rootpath
= NULL
;
713 mydomainlen
= mynamelen
= rootpathlen
= 0;
715 /* default root server to bootp next-server */
716 rootserver
= bootp
->bp_siaddr
;
717 /* assume that server name field is not overloaded by default */
720 p
= &bootp
->bp_vend
[4];
721 limit
= ((u_char
*)bootp
) + replylen
;
729 #if 0 /* already done in bootpcheck() */
730 if ((p
+ len
) > limit
) {
731 printf("nfs_boot: option %d too long\n", tag
);
736 case TAG_SUBNET_MASK
:
738 printf("nfs_boot: subnet mask < 4 bytes\n");
741 memcpy(&netmask
, p
, 4);
746 printf("nfs_boot: routers < 4 bytes\n");
749 memcpy(&gateway
, p
, 4);
752 if (len
>= sizeof(hostname
)) {
753 printf("nfs_boot: host name >= %lu bytes\n",
754 (u_long
)sizeof(hostname
));
760 case TAG_DOMAIN_NAME
:
761 if (len
>= sizeof(domainname
)) {
762 printf("nfs_boot: domain name >= %lu bytes\n",
763 (u_long
)sizeof(domainname
));
770 /* Leave some room for the server name. */
771 if (len
>= (MNAMELEN
-10)) {
772 printf("nfs_boot: rootpath >= %d bytes\n",
779 case TAG_SWAP_SERVER
:
780 /* override NFS server address */
782 printf("nfs_boot: swap server < 4 bytes\n");
785 memcpy(&rootserver
, p
, 4);
789 if (len
> 0 && ((*p
& 0x02) != 0))
791 * The server name field in the dhcp packet
792 * is overloaded and we can't find server
805 * Store and print network config info.
808 myname
[mynamelen
] = '\0';
809 strncpy(hostname
, myname
, sizeof(hostname
));
810 hostnamelen
= mynamelen
;
811 printf("nfs_boot: my_name=%s\n", hostname
);
814 mydomain
[mydomainlen
] = '\0';
815 strncpy(domainname
, mydomain
, sizeof(domainname
));
816 domainnamelen
= mydomainlen
;
817 printf("nfs_boot: my_domain=%s\n", domainname
);
819 if (!(*flags
& NFS_BOOT_HAS_MYIP
)) {
820 nd
->nd_myip
= bootp
->bp_yiaddr
;
821 printf("nfs_boot: my_addr=%s\n", inet_ntoa(nd
->nd_myip
));
822 *flags
|= NFS_BOOT_HAS_MYIP
;
824 if (!(*flags
& NFS_BOOT_HAS_MASK
)) {
825 nd
->nd_mask
= netmask
;
826 printf("nfs_boot: my_mask=%s\n", inet_ntoa(nd
->nd_mask
));
827 *flags
|= NFS_BOOT_HAS_MASK
;
829 if (!(*flags
& NFS_BOOT_HAS_GWIP
)) {
830 nd
->nd_gwip
= gateway
;
831 printf("nfs_boot: gateway=%s\n", inet_ntoa(nd
->nd_gwip
));
832 *flags
|= NFS_BOOT_HAS_GWIP
;
836 * Store the information about our NFS root mount.
837 * The caller will print it, so be silent here.
840 struct nfs_dlmount
*ndm
= &nd
->nd_root
;
843 if (!(*flags
& NFS_BOOT_HAS_SERVADDR
)) {
844 /* Server IP address. */
845 sin
= (struct sockaddr_in
*) &ndm
->ndm_saddr
;
846 memset((void *)sin
, 0, sizeof(*sin
));
847 sin
->sin_len
= sizeof(*sin
);
848 sin
->sin_family
= AF_INET
;
849 sin
->sin_addr
= rootserver
;
850 *flags
|= NFS_BOOT_HAS_SERVADDR
;
853 if (!(*flags
& NFS_BOOT_HAS_SERVER
)) {
855 if (!overloaded
&& bootp
->bp_sname
[0] != 0 &&
856 !memcmp(&rootserver
, &bootp
->bp_siaddr
,
857 sizeof(struct in_addr
)))
859 /* standard root server, we have the name */
860 strncpy(ndm
->ndm_host
, bootp
->bp_sname
,
862 *flags
|= NFS_BOOT_HAS_SERVER
;
864 /* Show the server IP address numerically. */
865 strncpy(ndm
->ndm_host
, inet_ntoa(rootserver
),
867 *flags
|= NFS_BOOT_HAS_SERVER
;
871 if (!(*flags
& NFS_BOOT_HAS_ROOTPATH
)) {
872 len
= strlen(ndm
->ndm_host
);
874 len
+ 1 + rootpathlen
+ 1 <= sizeof(ndm
->ndm_host
))
876 ndm
->ndm_host
[len
++] = ':';
877 strncpy(ndm
->ndm_host
+ len
,
878 rootpath
, rootpathlen
);
879 ndm
->ndm_host
[len
+ rootpathlen
] = '\0';
880 *flags
|= NFS_BOOT_HAS_ROOTPATH
;
881 } /* else: upper layer will handle error */
886 #if BP_FILE_LEN > MNAMELEN
887 #define BOOTFILELEN MNAMELEN
889 #define BOOTFILELEN BP_FILE_LEN
891 strncpy(nd
->nd_bootfile
, bootp
->bp_file
, BOOTFILELEN
);
892 nd
->nd_bootfile
[BOOTFILELEN
- 1] = '\0';
894 #endif /* TFTPROOT */