xref: /freebsd/sys/nfs/bootp_subr.c (revision d32d350eeb3a34e1032d5187bb16bae2fd19f28d)
17c208ed6SRick Macklem /*-
27c208ed6SRick Macklem  * Copyright (c) 1995 Gordon Ross, Adam Glass
37c208ed6SRick Macklem  * Copyright (c) 1992 Regents of the University of California.
47c208ed6SRick Macklem  * All rights reserved.
57c208ed6SRick Macklem  *
67c208ed6SRick Macklem  * This software was developed by the Computer Systems Engineering group
77c208ed6SRick Macklem  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
87c208ed6SRick Macklem  * contributed to Berkeley.
97c208ed6SRick Macklem  *
107c208ed6SRick Macklem  * Redistribution and use in source and binary forms, with or without
117c208ed6SRick Macklem  * modification, are permitted provided that the following conditions
127c208ed6SRick Macklem  * are met:
137c208ed6SRick Macklem  * 1. Redistributions of source code must retain the above copyright
147c208ed6SRick Macklem  *    notice, this list of conditions and the following disclaimer.
157c208ed6SRick Macklem  * 2. Redistributions in binary form must reproduce the above copyright
167c208ed6SRick Macklem  *    notice, this list of conditions and the following disclaimer in the
177c208ed6SRick Macklem  *    documentation and/or other materials provided with the distribution.
187c208ed6SRick Macklem  * 3. All advertising materials mentioning features or use of this software
197c208ed6SRick Macklem  *    must display the following acknowledgement:
207c208ed6SRick Macklem  *	This product includes software developed by the University of
217c208ed6SRick Macklem  *	California, Lawrence Berkeley Laboratory and its contributors.
227c208ed6SRick Macklem  * 4. Neither the name of the University nor the names of its contributors
237c208ed6SRick Macklem  *    may be used to endorse or promote products derived from this software
247c208ed6SRick Macklem  *    without specific prior written permission.
257c208ed6SRick Macklem  *
267c208ed6SRick Macklem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
277c208ed6SRick Macklem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
287c208ed6SRick Macklem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
297c208ed6SRick Macklem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
307c208ed6SRick Macklem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
317c208ed6SRick Macklem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
327c208ed6SRick Macklem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
337c208ed6SRick Macklem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
347c208ed6SRick Macklem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
357c208ed6SRick Macklem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
367c208ed6SRick Macklem  * SUCH DAMAGE.
377c208ed6SRick Macklem  *
387c208ed6SRick Macklem  * based on:
397c208ed6SRick Macklem  *      nfs/krpc_subr.c
407c208ed6SRick Macklem  *	$NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $
417c208ed6SRick Macklem  */
427c208ed6SRick Macklem 
437c208ed6SRick Macklem #include <sys/cdefs.h>
447c208ed6SRick Macklem __FBSDID("$FreeBSD$");
457c208ed6SRick Macklem 
467c208ed6SRick Macklem #include "opt_bootp.h"
47acd73f50SGrzegorz Bernacki #include "opt_nfs.h"
486cbd933bSIan Lepore #include "opt_rootdevname.h"
497c208ed6SRick Macklem 
507c208ed6SRick Macklem #include <sys/param.h>
517c208ed6SRick Macklem #include <sys/systm.h>
52a6c14908SIan Lepore #include <sys/endian.h>
537c208ed6SRick Macklem #include <sys/jail.h>
547c208ed6SRick Macklem #include <sys/kernel.h>
557c208ed6SRick Macklem #include <sys/sockio.h>
567c208ed6SRick Macklem #include <sys/malloc.h>
577c208ed6SRick Macklem #include <sys/mount.h>
587c208ed6SRick Macklem #include <sys/mbuf.h>
597c208ed6SRick Macklem #include <sys/proc.h>
606cbd933bSIan Lepore #include <sys/reboot.h>
617c208ed6SRick Macklem #include <sys/socket.h>
627c208ed6SRick Macklem #include <sys/socketvar.h>
637c208ed6SRick Macklem #include <sys/sysctl.h>
647c208ed6SRick Macklem #include <sys/uio.h>
657c208ed6SRick Macklem 
667c208ed6SRick Macklem #include <net/if.h>
6776039bc8SGleb Smirnoff #include <net/if_var.h>
687c208ed6SRick Macklem #include <net/route.h>
6961eee0e2SAlexander V. Chernikov #ifdef BOOTP_DEBUG
7061eee0e2SAlexander V. Chernikov #include <net/route_var.h>
7161eee0e2SAlexander V. Chernikov #endif
727c208ed6SRick Macklem 
737c208ed6SRick Macklem #include <netinet/in.h>
746bfaa839SGleb Smirnoff #include <netinet/in_var.h>
757c208ed6SRick Macklem #include <net/if_types.h>
767c208ed6SRick Macklem #include <net/if_dl.h>
777c208ed6SRick Macklem #include <net/vnet.h>
787c208ed6SRick Macklem 
797c208ed6SRick Macklem #include <nfs/nfsproto.h>
807c208ed6SRick Macklem #include <nfsclient/nfs.h>
817c208ed6SRick Macklem #include <nfs/nfsdiskless.h>
827c208ed6SRick Macklem #include <nfs/krpc.h>
837c208ed6SRick Macklem #include <nfs/xdr_subs.h>
847c208ed6SRick Macklem 
857c208ed6SRick Macklem 
867c208ed6SRick Macklem #define BOOTP_MIN_LEN		300	/* Minimum size of bootp udp packet */
877c208ed6SRick Macklem 
887c208ed6SRick Macklem #ifndef BOOTP_SETTLE_DELAY
897c208ed6SRick Macklem #define BOOTP_SETTLE_DELAY 3
907c208ed6SRick Macklem #endif
917c208ed6SRick Macklem 
927c208ed6SRick Macklem /*
931d4c5e51SOleksandr Tymoshenko  * Wait 10 seconds for interface appearance
94c6fd18e0SOleksandr Tymoshenko  * USB ethernet adapters might require some time to pop up
951d4c5e51SOleksandr Tymoshenko  */
961d4c5e51SOleksandr Tymoshenko #ifndef	BOOTP_IFACE_WAIT_TIMEOUT
971d4c5e51SOleksandr Tymoshenko #define	BOOTP_IFACE_WAIT_TIMEOUT	10
981d4c5e51SOleksandr Tymoshenko #endif
991d4c5e51SOleksandr Tymoshenko 
1001d4c5e51SOleksandr Tymoshenko /*
1017c208ed6SRick Macklem  * What is the longest we will wait before re-sending a request?
1027c208ed6SRick Macklem  * Note this is also the frequency of "RPC timeout" messages.
1037c208ed6SRick Macklem  * The re-send loop count sup linearly to this maximum, so the
1047c208ed6SRick Macklem  * first complaint will happen after (1+2+3+4+5)=15 seconds.
1057c208ed6SRick Macklem  */
1067c208ed6SRick Macklem #define	MAX_RESEND_DELAY 5	/* seconds */
1077c208ed6SRick Macklem 
1087c208ed6SRick Macklem /* Definitions from RFC951 */
1097c208ed6SRick Macklem struct bootp_packet {
1107c208ed6SRick Macklem 	u_int8_t op;
1117c208ed6SRick Macklem 	u_int8_t htype;
1127c208ed6SRick Macklem 	u_int8_t hlen;
1137c208ed6SRick Macklem 	u_int8_t hops;
1147c208ed6SRick Macklem 	u_int32_t xid;
1157c208ed6SRick Macklem 	u_int16_t secs;
1167c208ed6SRick Macklem 	u_int16_t flags;
1177c208ed6SRick Macklem 	struct in_addr ciaddr;
1187c208ed6SRick Macklem 	struct in_addr yiaddr;
1197c208ed6SRick Macklem 	struct in_addr siaddr;
1207c208ed6SRick Macklem 	struct in_addr giaddr;
1217c208ed6SRick Macklem 	unsigned char chaddr[16];
1227c208ed6SRick Macklem 	char sname[64];
1237c208ed6SRick Macklem 	char file[128];
1247c208ed6SRick Macklem 	unsigned char vend[1222];
1257c208ed6SRick Macklem };
1267c208ed6SRick Macklem 
1277c208ed6SRick Macklem struct bootpc_ifcontext {
1286bfaa839SGleb Smirnoff 	STAILQ_ENTRY(bootpc_ifcontext) next;
1297c208ed6SRick Macklem 	struct bootp_packet call;
1307c208ed6SRick Macklem 	struct bootp_packet reply;
1317c208ed6SRick Macklem 	int replylen;
1327c208ed6SRick Macklem 	int overload;
1336bfaa839SGleb Smirnoff 	union {
1346bfaa839SGleb Smirnoff 		struct ifreq _ifreq;
1356bfaa839SGleb Smirnoff 		struct in_aliasreq _in_alias_req;
1366bfaa839SGleb Smirnoff 	} _req;
1376bfaa839SGleb Smirnoff #define	ireq	_req._ifreq
1386bfaa839SGleb Smirnoff #define	iareq	_req._in_alias_req
1397c208ed6SRick Macklem 	struct ifnet *ifp;
1407c208ed6SRick Macklem 	struct sockaddr_dl *sdl;
1417c208ed6SRick Macklem 	struct sockaddr_in myaddr;
1427c208ed6SRick Macklem 	struct sockaddr_in netmask;
1437c208ed6SRick Macklem 	struct sockaddr_in gw;
1447c208ed6SRick Macklem 	int gotgw;
1457c208ed6SRick Macklem 	int gotnetmask;
1467c208ed6SRick Macklem 	int gotrootpath;
1477c208ed6SRick Macklem 	int outstanding;
1487c208ed6SRick Macklem 	int sentmsg;
1497c208ed6SRick Macklem 	u_int32_t xid;
1507c208ed6SRick Macklem 	enum {
1517c208ed6SRick Macklem 		IF_BOOTP_UNRESOLVED,
1527c208ed6SRick Macklem 		IF_BOOTP_RESOLVED,
1537c208ed6SRick Macklem 		IF_BOOTP_FAILED,
1547c208ed6SRick Macklem 		IF_DHCP_UNRESOLVED,
1557c208ed6SRick Macklem 		IF_DHCP_OFFERED,
1567c208ed6SRick Macklem 		IF_DHCP_RESOLVED,
1577c208ed6SRick Macklem 		IF_DHCP_FAILED,
1587c208ed6SRick Macklem 	} state;
1597c208ed6SRick Macklem 	int dhcpquerytype;		/* dhcp type sent */
1607c208ed6SRick Macklem 	struct in_addr dhcpserver;
1617c208ed6SRick Macklem 	int gotdhcpserver;
162a6c14908SIan Lepore 	uint16_t mtu;
1637c208ed6SRick Macklem };
1647c208ed6SRick Macklem 
1657c208ed6SRick Macklem #define TAG_MAXLEN 1024
1667c208ed6SRick Macklem struct bootpc_tagcontext {
1677c208ed6SRick Macklem 	char buf[TAG_MAXLEN + 1];
1687c208ed6SRick Macklem 	int overload;
1697c208ed6SRick Macklem 	int badopt;
1707c208ed6SRick Macklem 	int badtag;
1717c208ed6SRick Macklem 	int foundopt;
1727c208ed6SRick Macklem 	int taglen;
1737c208ed6SRick Macklem };
1747c208ed6SRick Macklem 
1757c208ed6SRick Macklem struct bootpc_globalcontext {
1766bfaa839SGleb Smirnoff 	STAILQ_HEAD(, bootpc_ifcontext) interfaces;
1777c208ed6SRick Macklem 	u_int32_t xid;
1786cbd933bSIan Lepore 	int any_root_overrides;
1797c208ed6SRick Macklem 	int gotrootpath;
1807c208ed6SRick Macklem 	int gotgw;
1817c208ed6SRick Macklem 	int ifnum;
1827c208ed6SRick Macklem 	int secs;
1837c208ed6SRick Macklem 	int starttime;
1847c208ed6SRick Macklem 	struct bootp_packet reply;
1857c208ed6SRick Macklem 	int replylen;
1867c208ed6SRick Macklem 	struct bootpc_ifcontext *setrootfs;
1877c208ed6SRick Macklem 	struct bootpc_ifcontext *sethostname;
1887c208ed6SRick Macklem 	struct bootpc_tagcontext tmptag;
1897c208ed6SRick Macklem 	struct bootpc_tagcontext tag;
1907c208ed6SRick Macklem };
1917c208ed6SRick Macklem 
1927c208ed6SRick Macklem #define IPPORT_BOOTPC 68
1937c208ed6SRick Macklem #define IPPORT_BOOTPS 67
1947c208ed6SRick Macklem 
1957c208ed6SRick Macklem #define BOOTP_REQUEST 1
1967c208ed6SRick Macklem #define BOOTP_REPLY 2
1977c208ed6SRick Macklem 
1987c208ed6SRick Macklem /* Common tags */
1997c208ed6SRick Macklem #define TAG_PAD		  0  /* Pad option, implicit length 1 */
2007c208ed6SRick Macklem #define TAG_SUBNETMASK	  1  /* RFC 950 subnet mask */
2017c208ed6SRick Macklem #define TAG_ROUTERS	  3  /* Routers (in order of preference) */
2027c208ed6SRick Macklem #define TAG_HOSTNAME	 12  /* Client host name */
2037c208ed6SRick Macklem #define TAG_ROOT	 17  /* Root path */
204a6c14908SIan Lepore #define TAG_INTF_MTU	 26  /* Interface MTU Size (RFC2132) */
2057c208ed6SRick Macklem 
2067c208ed6SRick Macklem /* DHCP specific tags */
2077c208ed6SRick Macklem #define TAG_OVERLOAD	 52  /* Option Overload */
2087c208ed6SRick Macklem #define TAG_MAXMSGSIZE   57  /* Maximum DHCP Message Size */
2097c208ed6SRick Macklem 
2107c208ed6SRick Macklem #define TAG_END		255  /* End Option (i.e. no more options) */
2117c208ed6SRick Macklem 
2127c208ed6SRick Macklem /* Overload values */
2137c208ed6SRick Macklem #define OVERLOAD_FILE     1
2147c208ed6SRick Macklem #define OVERLOAD_SNAME    2
2157c208ed6SRick Macklem 
2167c208ed6SRick Macklem /* Site specific tags: */
2177c208ed6SRick Macklem #define TAG_ROOTOPTS	130
2187c208ed6SRick Macklem #define TAG_COOKIE	134	/* ascii info for userland, via sysctl */
2197c208ed6SRick Macklem 
2207c208ed6SRick Macklem #define TAG_DHCP_MSGTYPE 53
2217c208ed6SRick Macklem #define TAG_DHCP_REQ_ADDR 50
2227c208ed6SRick Macklem #define TAG_DHCP_SERVERID 54
2237c208ed6SRick Macklem #define TAG_DHCP_LEASETIME 51
2247c208ed6SRick Macklem 
2257c208ed6SRick Macklem #define TAG_VENDOR_INDENTIFIER 60
2267c208ed6SRick Macklem 
2277c208ed6SRick Macklem #define DHCP_NOMSG    0
2287c208ed6SRick Macklem #define DHCP_DISCOVER 1
2297c208ed6SRick Macklem #define DHCP_OFFER    2
2307c208ed6SRick Macklem #define DHCP_REQUEST  3
2317c208ed6SRick Macklem #define DHCP_ACK      5
2327c208ed6SRick Macklem 
2337c208ed6SRick Macklem /* NFS read/write block size */
2347c208ed6SRick Macklem #ifndef BOOTP_BLOCKSIZE
2357c208ed6SRick Macklem #define	BOOTP_BLOCKSIZE	8192
2367c208ed6SRick Macklem #endif
2377c208ed6SRick Macklem 
2387c208ed6SRick Macklem static char bootp_cookie[128];
2396bfaa839SGleb Smirnoff static struct socket *bootp_so;
2407c208ed6SRick Macklem SYSCTL_STRING(_kern, OID_AUTO, bootp_cookie, CTLFLAG_RD,
2417c208ed6SRick Macklem 	bootp_cookie, 0, "Cookie (T134) supplied by bootp server");
2427c208ed6SRick Macklem 
2437c208ed6SRick Macklem /* mountd RPC */
2447c208ed6SRick Macklem static int	md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp,
2457c208ed6SRick Macklem 		    int *fhsizep, struct nfs_args *args, struct thread *td);
2467c208ed6SRick Macklem static int	setfs(struct sockaddr_in *addr, char *path, char *p,
2477c208ed6SRick Macklem 		    const struct in_addr *siaddr);
2487c208ed6SRick Macklem static int	getdec(char **ptr);
2497c208ed6SRick Macklem static int	getip(char **ptr, struct in_addr *ip);
2507c208ed6SRick Macklem static void	mountopts(struct nfs_args *args, char *p);
2517c208ed6SRick Macklem static int	xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len);
2527c208ed6SRick Macklem static int	xdr_int_decode(struct mbuf **ptr, int *iptr);
2537c208ed6SRick Macklem static void	print_in_addr(struct in_addr addr);
2547c208ed6SRick Macklem static void	print_sin_addr(struct sockaddr_in *addr);
2557c208ed6SRick Macklem static void	clear_sinaddr(struct sockaddr_in *sin);
2567c208ed6SRick Macklem static void	allocifctx(struct bootpc_globalcontext *gctx);
2577c208ed6SRick Macklem static void	bootpc_compose_query(struct bootpc_ifcontext *ifctx,
2586bfaa839SGleb Smirnoff 		    struct thread *td);
2597c208ed6SRick Macklem static unsigned char *bootpc_tag(struct bootpc_tagcontext *tctx,
2607c208ed6SRick Macklem 		    struct bootp_packet *bp, int len, int tag);
2617c208ed6SRick Macklem static void bootpc_tag_helper(struct bootpc_tagcontext *tctx,
2627c208ed6SRick Macklem 		    unsigned char *start, int len, int tag);
2637c208ed6SRick Macklem 
2647c208ed6SRick Macklem #ifdef BOOTP_DEBUG
2657c208ed6SRick Macklem void bootpboot_p_sa(struct sockaddr *sa, struct sockaddr *ma);
2667c208ed6SRick Macklem void bootpboot_p_rtentry(struct rtentry *rt);
2677c208ed6SRick Macklem void bootpboot_p_tree(struct radix_node *rn);
2687c208ed6SRick Macklem void bootpboot_p_rtlist(void);
2697c208ed6SRick Macklem void bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa);
2707c208ed6SRick Macklem void bootpboot_p_iflist(void);
2717c208ed6SRick Macklem #endif
2727c208ed6SRick Macklem 
2737c208ed6SRick Macklem static int	bootpc_call(struct bootpc_globalcontext *gctx,
2747c208ed6SRick Macklem 		    struct thread *td);
2757c208ed6SRick Macklem 
2766bfaa839SGleb Smirnoff static void	bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
2776bfaa839SGleb Smirnoff 		    struct thread *td);
2787c208ed6SRick Macklem 
279*d32d350eSIan Lepore static void	bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
2807c208ed6SRick Macklem 		    struct bootpc_globalcontext *gctx, struct thread *td);
2817c208ed6SRick Macklem 
2827c208ed6SRick Macklem static void	bootpc_decode_reply(struct nfsv3_diskless *nd,
2837c208ed6SRick Macklem 		    struct bootpc_ifcontext *ifctx,
2847c208ed6SRick Macklem 		    struct bootpc_globalcontext *gctx);
2857c208ed6SRick Macklem 
2867c208ed6SRick Macklem static int	bootpc_received(struct bootpc_globalcontext *gctx,
2877c208ed6SRick Macklem 		    struct bootpc_ifcontext *ifctx);
2887c208ed6SRick Macklem 
2897c208ed6SRick Macklem static __inline int bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx);
2907c208ed6SRick Macklem static __inline int bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx);
2917c208ed6SRick Macklem static __inline int bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx);
2927c208ed6SRick Macklem 
2937c208ed6SRick Macklem /*
2947c208ed6SRick Macklem  * In order to have multiple active interfaces with address 0.0.0.0
2956bfaa839SGleb Smirnoff  * and be able to send data to a selected interface, we first set
2966bfaa839SGleb Smirnoff  * mask to /8 on all interfaces, and temporarily set it to /0 when
2976bfaa839SGleb Smirnoff  * doing sosend().
2987c208ed6SRick Macklem  */
2997c208ed6SRick Macklem 
3007c208ed6SRick Macklem #ifdef BOOTP_DEBUG
3017c208ed6SRick Macklem void
3027c208ed6SRick Macklem bootpboot_p_sa(struct sockaddr *sa, struct sockaddr *ma)
3037c208ed6SRick Macklem {
3047c208ed6SRick Macklem 
3057c208ed6SRick Macklem 	if (sa == NULL) {
3067c208ed6SRick Macklem 		printf("(sockaddr *) <null>");
3077c208ed6SRick Macklem 		return;
3087c208ed6SRick Macklem 	}
3097c208ed6SRick Macklem 	switch (sa->sa_family) {
3107c208ed6SRick Macklem 	case AF_INET:
3117c208ed6SRick Macklem 	{
3127c208ed6SRick Macklem 		struct sockaddr_in *sin;
3137c208ed6SRick Macklem 
3147c208ed6SRick Macklem 		sin = (struct sockaddr_in *) sa;
3157c208ed6SRick Macklem 		printf("inet ");
3167c208ed6SRick Macklem 		print_sin_addr(sin);
3177c208ed6SRick Macklem 		if (ma != NULL) {
3187c208ed6SRick Macklem 			sin = (struct sockaddr_in *) ma;
3197c208ed6SRick Macklem 			printf(" mask ");
3207c208ed6SRick Macklem 			print_sin_addr(sin);
3217c208ed6SRick Macklem 		}
3227c208ed6SRick Macklem 	}
3237c208ed6SRick Macklem 	break;
3247c208ed6SRick Macklem 	case AF_LINK:
3257c208ed6SRick Macklem 	{
3267c208ed6SRick Macklem 		struct sockaddr_dl *sli;
3277c208ed6SRick Macklem 		int i;
3287c208ed6SRick Macklem 
3297c208ed6SRick Macklem 		sli = (struct sockaddr_dl *) sa;
3307c208ed6SRick Macklem 		printf("link %.*s ", sli->sdl_nlen, sli->sdl_data);
3317c208ed6SRick Macklem 		for (i = 0; i < sli->sdl_alen; i++) {
3327c208ed6SRick Macklem 			if (i > 0)
3337c208ed6SRick Macklem 				printf(":");
3347c208ed6SRick Macklem 			printf("%x", ((unsigned char *) LLADDR(sli))[i]);
3357c208ed6SRick Macklem 		}
3367c208ed6SRick Macklem 	}
3377c208ed6SRick Macklem 	break;
3387c208ed6SRick Macklem 	default:
3397c208ed6SRick Macklem 		printf("af%d", sa->sa_family);
3407c208ed6SRick Macklem 	}
3417c208ed6SRick Macklem }
3427c208ed6SRick Macklem 
3437c208ed6SRick Macklem void
3447c208ed6SRick Macklem bootpboot_p_rtentry(struct rtentry *rt)
3457c208ed6SRick Macklem {
3467c208ed6SRick Macklem 
3477c208ed6SRick Macklem 	bootpboot_p_sa(rt_key(rt), rt_mask(rt));
3487c208ed6SRick Macklem 	printf(" ");
3497c208ed6SRick Macklem 	bootpboot_p_sa(rt->rt_gateway, NULL);
3507c208ed6SRick Macklem 	printf(" ");
3517c208ed6SRick Macklem 	printf("flags %x", (unsigned short) rt->rt_flags);
352e3a7aa6fSGleb Smirnoff 	printf(" %d", (int) rt->rt_expire);
3537c208ed6SRick Macklem 	printf(" %s\n", rt->rt_ifp->if_xname);
3547c208ed6SRick Macklem }
3557c208ed6SRick Macklem 
3567c208ed6SRick Macklem void
3577c208ed6SRick Macklem bootpboot_p_tree(struct radix_node *rn)
3587c208ed6SRick Macklem {
3597c208ed6SRick Macklem 
3607c208ed6SRick Macklem 	while (rn != NULL) {
3617c208ed6SRick Macklem 		if (rn->rn_bit < 0) {
3627c208ed6SRick Macklem 			if ((rn->rn_flags & RNF_ROOT) != 0) {
3637c208ed6SRick Macklem 			} else {
3647c208ed6SRick Macklem 				bootpboot_p_rtentry((struct rtentry *) rn);
3657c208ed6SRick Macklem 			}
3667c208ed6SRick Macklem 			rn = rn->rn_dupedkey;
3677c208ed6SRick Macklem 		} else {
3687c208ed6SRick Macklem 			bootpboot_p_tree(rn->rn_left);
3697c208ed6SRick Macklem 			bootpboot_p_tree(rn->rn_right);
3707c208ed6SRick Macklem 			return;
3717c208ed6SRick Macklem 		}
3727c208ed6SRick Macklem 	}
3737c208ed6SRick Macklem }
3747c208ed6SRick Macklem 
3757c208ed6SRick Macklem void
3767c208ed6SRick Macklem bootpboot_p_rtlist(void)
3777c208ed6SRick Macklem {
37861eee0e2SAlexander V. Chernikov 	struct rib_head *rnh;
3797c208ed6SRick Macklem 
3807c208ed6SRick Macklem 	printf("Routing table:\n");
3817c208ed6SRick Macklem 	rnh = rt_tables_get_rnh(0, AF_INET);
3827c208ed6SRick Macklem 	if (rnh == NULL)
3837c208ed6SRick Macklem 		return;
38461eee0e2SAlexander V. Chernikov 	RIB_RLOCK(rnh);	/* could sleep XXX */
3857c208ed6SRick Macklem 	bootpboot_p_tree(rnh->rnh_treetop);
38661eee0e2SAlexander V. Chernikov 	RIB_RUNLOCK(rnh);
3877c208ed6SRick Macklem }
3887c208ed6SRick Macklem 
3897c208ed6SRick Macklem void
3907c208ed6SRick Macklem bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa)
3917c208ed6SRick Macklem {
3927c208ed6SRick Macklem 
3937c208ed6SRick Macklem 	printf("%s flags %x, addr ",
3947c208ed6SRick Macklem 	       ifp->if_xname, ifp->if_flags);
3957c208ed6SRick Macklem 	print_sin_addr((struct sockaddr_in *) ifa->ifa_addr);
3967c208ed6SRick Macklem 	printf(", broadcast ");
3977c208ed6SRick Macklem 	print_sin_addr((struct sockaddr_in *) ifa->ifa_dstaddr);
3987c208ed6SRick Macklem 	printf(", netmask ");
3997c208ed6SRick Macklem 	print_sin_addr((struct sockaddr_in *) ifa->ifa_netmask);
4007c208ed6SRick Macklem 	printf("\n");
4017c208ed6SRick Macklem }
4027c208ed6SRick Macklem 
4037c208ed6SRick Macklem void
4047c208ed6SRick Macklem bootpboot_p_iflist(void)
4057c208ed6SRick Macklem {
4067c208ed6SRick Macklem 	struct ifnet *ifp;
4077c208ed6SRick Macklem 	struct ifaddr *ifa;
4087c208ed6SRick Macklem 
4097c208ed6SRick Macklem 	printf("Interface list:\n");
4107c208ed6SRick Macklem 	IFNET_RLOCK();
4117c208ed6SRick Macklem 	for (ifp = TAILQ_FIRST(&V_ifnet);
4127c208ed6SRick Macklem 	     ifp != NULL;
4137c208ed6SRick Macklem 	     ifp = TAILQ_NEXT(ifp, if_link)) {
4147c208ed6SRick Macklem 		for (ifa = TAILQ_FIRST(&ifp->if_addrhead);
4157c208ed6SRick Macklem 		     ifa != NULL;
4167c208ed6SRick Macklem 		     ifa = TAILQ_NEXT(ifa, ifa_link))
4177c208ed6SRick Macklem 			if (ifa->ifa_addr->sa_family == AF_INET)
4187c208ed6SRick Macklem 				bootpboot_p_if(ifp, ifa);
4197c208ed6SRick Macklem 	}
4207c208ed6SRick Macklem 	IFNET_RUNLOCK();
4217c208ed6SRick Macklem }
4227c208ed6SRick Macklem #endif /* defined(BOOTP_DEBUG) */
4237c208ed6SRick Macklem 
4247c208ed6SRick Macklem static void
4257c208ed6SRick Macklem clear_sinaddr(struct sockaddr_in *sin)
4267c208ed6SRick Macklem {
4277c208ed6SRick Macklem 
4287c208ed6SRick Macklem 	bzero(sin, sizeof(*sin));
4297c208ed6SRick Macklem 	sin->sin_len = sizeof(*sin);
4307c208ed6SRick Macklem 	sin->sin_family = AF_INET;
4317c208ed6SRick Macklem 	sin->sin_addr.s_addr = INADDR_ANY; /* XXX: htonl(INAADDR_ANY) ? */
4327c208ed6SRick Macklem 	sin->sin_port = 0;
4337c208ed6SRick Macklem }
4347c208ed6SRick Macklem 
4357c208ed6SRick Macklem static void
4367c208ed6SRick Macklem allocifctx(struct bootpc_globalcontext *gctx)
4377c208ed6SRick Macklem {
4387c208ed6SRick Macklem 	struct bootpc_ifcontext *ifctx;
4397c208ed6SRick Macklem 
4406bfaa839SGleb Smirnoff 	ifctx = malloc(sizeof(*ifctx), M_TEMP, M_WAITOK | M_ZERO);
4417c208ed6SRick Macklem 	ifctx->xid = gctx->xid;
4427c208ed6SRick Macklem #ifdef BOOTP_NO_DHCP
4437c208ed6SRick Macklem 	ifctx->state = IF_BOOTP_UNRESOLVED;
4447c208ed6SRick Macklem #else
4457c208ed6SRick Macklem 	ifctx->state = IF_DHCP_UNRESOLVED;
4467c208ed6SRick Macklem #endif
4477c208ed6SRick Macklem 	gctx->xid += 0x100;
4486bfaa839SGleb Smirnoff 	STAILQ_INSERT_TAIL(&gctx->interfaces, ifctx, next);
4497c208ed6SRick Macklem }
4507c208ed6SRick Macklem 
4517c208ed6SRick Macklem static __inline int
4527c208ed6SRick Macklem bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx)
4537c208ed6SRick Macklem {
4547c208ed6SRick Macklem 
4557c208ed6SRick Macklem 	if (ifctx->state == IF_BOOTP_RESOLVED ||
4567c208ed6SRick Macklem 	    ifctx->state == IF_DHCP_RESOLVED)
4577c208ed6SRick Macklem 		return 1;
4587c208ed6SRick Macklem 	return 0;
4597c208ed6SRick Macklem }
4607c208ed6SRick Macklem 
4617c208ed6SRick Macklem static __inline int
4627c208ed6SRick Macklem bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx)
4637c208ed6SRick Macklem {
4647c208ed6SRick Macklem 
4657c208ed6SRick Macklem 	if (ifctx->state == IF_BOOTP_UNRESOLVED ||
4667c208ed6SRick Macklem 	    ifctx->state == IF_DHCP_UNRESOLVED)
4677c208ed6SRick Macklem 		return 1;
4687c208ed6SRick Macklem 	return 0;
4697c208ed6SRick Macklem }
4707c208ed6SRick Macklem 
4717c208ed6SRick Macklem static __inline int
4727c208ed6SRick Macklem bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx)
4737c208ed6SRick Macklem {
4747c208ed6SRick Macklem 
4757c208ed6SRick Macklem 	if (ifctx->state == IF_BOOTP_FAILED ||
4767c208ed6SRick Macklem 	    ifctx->state == IF_DHCP_FAILED)
4777c208ed6SRick Macklem 		return 1;
4787c208ed6SRick Macklem 	return 0;
4797c208ed6SRick Macklem }
4807c208ed6SRick Macklem 
4817c208ed6SRick Macklem static int
4827c208ed6SRick Macklem bootpc_received(struct bootpc_globalcontext *gctx,
4837c208ed6SRick Macklem     struct bootpc_ifcontext *ifctx)
4847c208ed6SRick Macklem {
4857c208ed6SRick Macklem 	unsigned char dhcpreplytype;
4867c208ed6SRick Macklem 	char *p;
4877c208ed6SRick Macklem 
4887c208ed6SRick Macklem 	/*
4897c208ed6SRick Macklem 	 * Need timeout for fallback to less
4907c208ed6SRick Macklem 	 * desirable alternative.
4917c208ed6SRick Macklem 	 */
4927c208ed6SRick Macklem 
4937c208ed6SRick Macklem 	/* This call used for the side effect (badopt flag) */
4947c208ed6SRick Macklem 	(void) bootpc_tag(&gctx->tmptag, &gctx->reply,
4957c208ed6SRick Macklem 			  gctx->replylen,
4967c208ed6SRick Macklem 			  TAG_END);
4977c208ed6SRick Macklem 
4987c208ed6SRick Macklem 	/* If packet is invalid, ignore it */
4997c208ed6SRick Macklem 	if (gctx->tmptag.badopt != 0)
5007c208ed6SRick Macklem 		return 0;
5017c208ed6SRick Macklem 
5027c208ed6SRick Macklem 	p = bootpc_tag(&gctx->tmptag, &gctx->reply,
5037c208ed6SRick Macklem 		       gctx->replylen, TAG_DHCP_MSGTYPE);
5047c208ed6SRick Macklem 	if (p != NULL)
5057c208ed6SRick Macklem 		dhcpreplytype = *p;
5067c208ed6SRick Macklem 	else
5077c208ed6SRick Macklem 		dhcpreplytype = DHCP_NOMSG;
5087c208ed6SRick Macklem 
5097c208ed6SRick Macklem 	switch (ifctx->dhcpquerytype) {
5107c208ed6SRick Macklem 	case DHCP_DISCOVER:
5117c208ed6SRick Macklem 		if (dhcpreplytype != DHCP_OFFER 	/* Normal DHCP offer */
5127c208ed6SRick Macklem #ifndef BOOTP_FORCE_DHCP
5137c208ed6SRick Macklem 		    && dhcpreplytype != DHCP_NOMSG	/* Fallback to BOOTP */
5147c208ed6SRick Macklem #endif
5157c208ed6SRick Macklem 			)
5167c208ed6SRick Macklem 			return 0;
5177c208ed6SRick Macklem 		break;
5187c208ed6SRick Macklem 	case DHCP_REQUEST:
5197c208ed6SRick Macklem 		if (dhcpreplytype != DHCP_ACK)
5207c208ed6SRick Macklem 			return 0;
5217c208ed6SRick Macklem 	case DHCP_NOMSG:
5227c208ed6SRick Macklem 		break;
5237c208ed6SRick Macklem 	}
5247c208ed6SRick Macklem 
5257c208ed6SRick Macklem 	/* Ignore packet unless it gives us a root tag we didn't have */
5267c208ed6SRick Macklem 
5277c208ed6SRick Macklem 	if ((ifctx->state == IF_BOOTP_RESOLVED ||
5287c208ed6SRick Macklem 	     (ifctx->dhcpquerytype == DHCP_DISCOVER &&
5297c208ed6SRick Macklem 	      (ifctx->state == IF_DHCP_OFFERED ||
5307c208ed6SRick Macklem 	       ifctx->state == IF_DHCP_RESOLVED))) &&
5317c208ed6SRick Macklem 	    (bootpc_tag(&gctx->tmptag, &ifctx->reply,
5327c208ed6SRick Macklem 			ifctx->replylen,
5337c208ed6SRick Macklem 			TAG_ROOT) != NULL ||
5347c208ed6SRick Macklem 	     bootpc_tag(&gctx->tmptag, &gctx->reply,
5357c208ed6SRick Macklem 			gctx->replylen,
5367c208ed6SRick Macklem 			TAG_ROOT) == NULL))
5377c208ed6SRick Macklem 		return 0;
5387c208ed6SRick Macklem 
5397c208ed6SRick Macklem 	bcopy(&gctx->reply, &ifctx->reply, gctx->replylen);
5407c208ed6SRick Macklem 	ifctx->replylen = gctx->replylen;
5417c208ed6SRick Macklem 
5427c208ed6SRick Macklem 	/* XXX: Only reset if 'perfect' response */
5437c208ed6SRick Macklem 	if (ifctx->state == IF_BOOTP_UNRESOLVED)
5447c208ed6SRick Macklem 		ifctx->state = IF_BOOTP_RESOLVED;
5457c208ed6SRick Macklem 	else if (ifctx->state == IF_DHCP_UNRESOLVED &&
5467c208ed6SRick Macklem 		 ifctx->dhcpquerytype == DHCP_DISCOVER) {
5477c208ed6SRick Macklem 		if (dhcpreplytype == DHCP_OFFER)
5487c208ed6SRick Macklem 			ifctx->state = IF_DHCP_OFFERED;
5497c208ed6SRick Macklem 		else
5507c208ed6SRick Macklem 			ifctx->state = IF_BOOTP_RESOLVED;	/* Fallback */
5517c208ed6SRick Macklem 	} else if (ifctx->state == IF_DHCP_OFFERED &&
5527c208ed6SRick Macklem 		   ifctx->dhcpquerytype == DHCP_REQUEST)
5537c208ed6SRick Macklem 		ifctx->state = IF_DHCP_RESOLVED;
5547c208ed6SRick Macklem 
5557c208ed6SRick Macklem 
5567c208ed6SRick Macklem 	if (ifctx->dhcpquerytype == DHCP_DISCOVER &&
5577c208ed6SRick Macklem 	    ifctx->state != IF_BOOTP_RESOLVED) {
5587c208ed6SRick Macklem 		p = bootpc_tag(&gctx->tmptag, &ifctx->reply,
5597c208ed6SRick Macklem 			       ifctx->replylen, TAG_DHCP_SERVERID);
5607c208ed6SRick Macklem 		if (p != NULL && gctx->tmptag.taglen == 4) {
5617c208ed6SRick Macklem 			memcpy(&ifctx->dhcpserver, p, 4);
5627c208ed6SRick Macklem 			ifctx->gotdhcpserver = 1;
5637c208ed6SRick Macklem 		} else
5647c208ed6SRick Macklem 			ifctx->gotdhcpserver = 0;
5657c208ed6SRick Macklem 		return 1;
5667c208ed6SRick Macklem 	}
5677c208ed6SRick Macklem 
5687c208ed6SRick Macklem 	ifctx->gotrootpath = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
5697c208ed6SRick Macklem 					 ifctx->replylen,
5707c208ed6SRick Macklem 					 TAG_ROOT) != NULL);
5717c208ed6SRick Macklem 	ifctx->gotgw = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
5727c208ed6SRick Macklem 				   ifctx->replylen,
5737c208ed6SRick Macklem 				   TAG_ROUTERS) != NULL);
5747c208ed6SRick Macklem 	ifctx->gotnetmask = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
5757c208ed6SRick Macklem 					ifctx->replylen,
5767c208ed6SRick Macklem 					TAG_SUBNETMASK) != NULL);
5777c208ed6SRick Macklem 	return 1;
5787c208ed6SRick Macklem }
5797c208ed6SRick Macklem 
5807c208ed6SRick Macklem static int
5817c208ed6SRick Macklem bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
5827c208ed6SRick Macklem {
5837c208ed6SRick Macklem 	struct sockaddr_in *sin, dst;
5847c208ed6SRick Macklem 	struct uio auio;
5857c208ed6SRick Macklem 	struct sockopt sopt;
5867c208ed6SRick Macklem 	struct iovec aio;
5877c208ed6SRick Macklem 	int error, on, rcvflg, timo, len;
5887c208ed6SRick Macklem 	time_t atimo;
5897c208ed6SRick Macklem 	time_t rtimo;
5907c208ed6SRick Macklem 	struct timeval tv;
5917c208ed6SRick Macklem 	struct bootpc_ifcontext *ifctx;
5927c208ed6SRick Macklem 	int outstanding;
5937c208ed6SRick Macklem 	int gotrootpath;
5947c208ed6SRick Macklem 	int retry;
5957c208ed6SRick Macklem 	const char *s;
5967c208ed6SRick Macklem 
5977c208ed6SRick Macklem 	tv.tv_sec = 1;
5987c208ed6SRick Macklem 	tv.tv_usec = 0;
5997c208ed6SRick Macklem 	bzero(&sopt, sizeof(sopt));
6007c208ed6SRick Macklem 	sopt.sopt_dir = SOPT_SET;
6017c208ed6SRick Macklem 	sopt.sopt_level = SOL_SOCKET;
6027c208ed6SRick Macklem 	sopt.sopt_name = SO_RCVTIMEO;
6037c208ed6SRick Macklem 	sopt.sopt_val = &tv;
6047c208ed6SRick Macklem 	sopt.sopt_valsize = sizeof tv;
6057c208ed6SRick Macklem 
6066bfaa839SGleb Smirnoff 	error = sosetopt(bootp_so, &sopt);
6077c208ed6SRick Macklem 	if (error != 0)
6087c208ed6SRick Macklem 		goto out;
6097c208ed6SRick Macklem 
6107c208ed6SRick Macklem 	/*
6117c208ed6SRick Macklem 	 * Enable broadcast.
6127c208ed6SRick Macklem 	 */
6137c208ed6SRick Macklem 	on = 1;
6147c208ed6SRick Macklem 	sopt.sopt_name = SO_BROADCAST;
6157c208ed6SRick Macklem 	sopt.sopt_val = &on;
6167c208ed6SRick Macklem 	sopt.sopt_valsize = sizeof on;
6177c208ed6SRick Macklem 
6186bfaa839SGleb Smirnoff 	error = sosetopt(bootp_so, &sopt);
6197c208ed6SRick Macklem 	if (error != 0)
6207c208ed6SRick Macklem 		goto out;
6217c208ed6SRick Macklem 
6227c208ed6SRick Macklem 	/*
6237c208ed6SRick Macklem 	 * Disable routing.
6247c208ed6SRick Macklem 	 */
6257c208ed6SRick Macklem 
6267c208ed6SRick Macklem 	on = 1;
6277c208ed6SRick Macklem 	sopt.sopt_name = SO_DONTROUTE;
6287c208ed6SRick Macklem 	sopt.sopt_val = &on;
6297c208ed6SRick Macklem 	sopt.sopt_valsize = sizeof on;
6307c208ed6SRick Macklem 
6316bfaa839SGleb Smirnoff 	error = sosetopt(bootp_so, &sopt);
6327c208ed6SRick Macklem 	if (error != 0)
6337c208ed6SRick Macklem 		goto out;
6347c208ed6SRick Macklem 
6357c208ed6SRick Macklem 	/*
6367c208ed6SRick Macklem 	 * Bind the local endpoint to a bootp client port.
6377c208ed6SRick Macklem 	 */
6387c208ed6SRick Macklem 	sin = &dst;
6397c208ed6SRick Macklem 	clear_sinaddr(sin);
6407c208ed6SRick Macklem 	sin->sin_port = htons(IPPORT_BOOTPC);
6416bfaa839SGleb Smirnoff 	error = sobind(bootp_so, (struct sockaddr *)sin, td);
6427c208ed6SRick Macklem 	if (error != 0) {
6437c208ed6SRick Macklem 		printf("bind failed\n");
6447c208ed6SRick Macklem 		goto out;
6457c208ed6SRick Macklem 	}
6467c208ed6SRick Macklem 
6477c208ed6SRick Macklem 	/*
6487c208ed6SRick Macklem 	 * Setup socket address for the server.
6497c208ed6SRick Macklem 	 */
6507c208ed6SRick Macklem 	sin = &dst;
6517c208ed6SRick Macklem 	clear_sinaddr(sin);
6527c208ed6SRick Macklem 	sin->sin_addr.s_addr = INADDR_BROADCAST;
6537c208ed6SRick Macklem 	sin->sin_port = htons(IPPORT_BOOTPS);
6547c208ed6SRick Macklem 
6557c208ed6SRick Macklem 	/*
6567c208ed6SRick Macklem 	 * Send it, repeatedly, until a reply is received,
6577c208ed6SRick Macklem 	 * but delay each re-send by an increasing amount.
6587c208ed6SRick Macklem 	 * If the delay hits the maximum, start complaining.
6597c208ed6SRick Macklem 	 */
6607c208ed6SRick Macklem 	timo = 0;
6617c208ed6SRick Macklem 	rtimo = 0;
6627c208ed6SRick Macklem 	for (;;) {
6637c208ed6SRick Macklem 
6647c208ed6SRick Macklem 		outstanding = 0;
6657c208ed6SRick Macklem 		gotrootpath = 0;
6667c208ed6SRick Macklem 
6676bfaa839SGleb Smirnoff 		STAILQ_FOREACH(ifctx, &gctx->interfaces, next) {
6687c208ed6SRick Macklem 			if (bootpc_ifctx_isresolved(ifctx) != 0 &&
6697c208ed6SRick Macklem 			    bootpc_tag(&gctx->tmptag, &ifctx->reply,
6707c208ed6SRick Macklem 				       ifctx->replylen,
6717c208ed6SRick Macklem 				       TAG_ROOT) != NULL)
6727c208ed6SRick Macklem 				gotrootpath = 1;
6737c208ed6SRick Macklem 		}
6747c208ed6SRick Macklem 
6756bfaa839SGleb Smirnoff 		STAILQ_FOREACH(ifctx, &gctx->interfaces, next) {
6766bfaa839SGleb Smirnoff 			struct in_aliasreq *ifra = &ifctx->iareq;
6776bfaa839SGleb Smirnoff 			sin = (struct sockaddr_in *)&ifra->ifra_mask;
6786bfaa839SGleb Smirnoff 
6797c208ed6SRick Macklem 			ifctx->outstanding = 0;
6807c208ed6SRick Macklem 			if (bootpc_ifctx_isresolved(ifctx)  != 0 &&
6817c208ed6SRick Macklem 			    gotrootpath != 0) {
6827c208ed6SRick Macklem 				continue;
6837c208ed6SRick Macklem 			}
6847c208ed6SRick Macklem 			if (bootpc_ifctx_isfailed(ifctx) != 0)
6857c208ed6SRick Macklem 				continue;
6867c208ed6SRick Macklem 
6877c208ed6SRick Macklem 			outstanding++;
6887c208ed6SRick Macklem 			ifctx->outstanding = 1;
6897c208ed6SRick Macklem 
6907c208ed6SRick Macklem 			/* Proceed to next step in DHCP negotiation */
6917c208ed6SRick Macklem 			if ((ifctx->state == IF_DHCP_OFFERED &&
6927c208ed6SRick Macklem 			     ifctx->dhcpquerytype != DHCP_REQUEST) ||
6937c208ed6SRick Macklem 			    (ifctx->state == IF_DHCP_UNRESOLVED &&
6947c208ed6SRick Macklem 			     ifctx->dhcpquerytype != DHCP_DISCOVER) ||
6957c208ed6SRick Macklem 			    (ifctx->state == IF_BOOTP_UNRESOLVED &&
6967c208ed6SRick Macklem 			     ifctx->dhcpquerytype != DHCP_NOMSG)) {
6977c208ed6SRick Macklem 				ifctx->sentmsg = 0;
6986bfaa839SGleb Smirnoff 				bootpc_compose_query(ifctx, td);
6997c208ed6SRick Macklem 			}
7007c208ed6SRick Macklem 
7017c208ed6SRick Macklem 			/* Send BOOTP request (or re-send). */
7027c208ed6SRick Macklem 
7037c208ed6SRick Macklem 			if (ifctx->sentmsg == 0) {
7047c208ed6SRick Macklem 				switch(ifctx->dhcpquerytype) {
7057c208ed6SRick Macklem 				case DHCP_DISCOVER:
7067c208ed6SRick Macklem 					s = "DHCP Discover";
7077c208ed6SRick Macklem 					break;
7087c208ed6SRick Macklem 				case DHCP_REQUEST:
7097c208ed6SRick Macklem 					s = "DHCP Request";
7107c208ed6SRick Macklem 					break;
7117c208ed6SRick Macklem 				case DHCP_NOMSG:
7127c208ed6SRick Macklem 				default:
7137c208ed6SRick Macklem 					s = "BOOTP Query";
7147c208ed6SRick Macklem 					break;
7157c208ed6SRick Macklem 				}
7167c208ed6SRick Macklem 				printf("Sending %s packet from "
7177c208ed6SRick Macklem 				       "interface %s (%*D)\n",
7187c208ed6SRick Macklem 				       s,
7197c208ed6SRick Macklem 				       ifctx->ireq.ifr_name,
7207c208ed6SRick Macklem 				       ifctx->sdl->sdl_alen,
7217c208ed6SRick Macklem 				       (unsigned char *) LLADDR(ifctx->sdl),
7227c208ed6SRick Macklem 				       ":");
7237c208ed6SRick Macklem 				ifctx->sentmsg = 1;
7247c208ed6SRick Macklem 			}
7257c208ed6SRick Macklem 
7267c208ed6SRick Macklem 			aio.iov_base = (caddr_t) &ifctx->call;
7277c208ed6SRick Macklem 			aio.iov_len = sizeof(ifctx->call);
7287c208ed6SRick Macklem 
7297c208ed6SRick Macklem 			auio.uio_iov = &aio;
7307c208ed6SRick Macklem 			auio.uio_iovcnt = 1;
7317c208ed6SRick Macklem 			auio.uio_segflg = UIO_SYSSPACE;
7327c208ed6SRick Macklem 			auio.uio_rw = UIO_WRITE;
7337c208ed6SRick Macklem 			auio.uio_offset = 0;
7347c208ed6SRick Macklem 			auio.uio_resid = sizeof(ifctx->call);
7357c208ed6SRick Macklem 			auio.uio_td = td;
7367c208ed6SRick Macklem 
7377c208ed6SRick Macklem 			/* Set netmask to 0.0.0.0 */
7387c208ed6SRick Macklem 			clear_sinaddr(sin);
7396bfaa839SGleb Smirnoff 			error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra,
7406bfaa839SGleb Smirnoff 			    td);
7417c208ed6SRick Macklem 			if (error != 0)
7426bfaa839SGleb Smirnoff 				panic("%s: SIOCAIFADDR, error=%d", __func__,
7437c208ed6SRick Macklem 				    error);
7447c208ed6SRick Macklem 
7456bfaa839SGleb Smirnoff 			error = sosend(bootp_so, (struct sockaddr *) &dst,
7467c208ed6SRick Macklem 				       &auio, NULL, NULL, 0, td);
7476bfaa839SGleb Smirnoff 			if (error != 0)
7486bfaa839SGleb Smirnoff 				printf("%s: sosend: %d state %08x\n", __func__,
7496bfaa839SGleb Smirnoff 				    error, (int )bootp_so->so_state);
7507c208ed6SRick Macklem 
7517c208ed6SRick Macklem 			/* Set netmask to 255.0.0.0 */
7526bfaa839SGleb Smirnoff 			sin->sin_addr.s_addr = htonl(IN_CLASSA_NET);
7536bfaa839SGleb Smirnoff 			error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra,
7546bfaa839SGleb Smirnoff 			    td);
7557c208ed6SRick Macklem 			if (error != 0)
7566bfaa839SGleb Smirnoff 				panic("%s: SIOCAIFADDR, error=%d", __func__,
7577c208ed6SRick Macklem 				    error);
7587c208ed6SRick Macklem 		}
7597c208ed6SRick Macklem 
7607c208ed6SRick Macklem 		if (outstanding == 0 &&
7617c208ed6SRick Macklem 		    (rtimo == 0 || time_second >= rtimo)) {
7627c208ed6SRick Macklem 			error = 0;
7636bfaa839SGleb Smirnoff 			goto out;
7647c208ed6SRick Macklem 		}
7657c208ed6SRick Macklem 
7667c208ed6SRick Macklem 		/* Determine new timeout. */
7677c208ed6SRick Macklem 		if (timo < MAX_RESEND_DELAY)
7687c208ed6SRick Macklem 			timo++;
7697c208ed6SRick Macklem 		else {
7707c208ed6SRick Macklem 			printf("DHCP/BOOTP timeout for server ");
7717c208ed6SRick Macklem 			print_sin_addr(&dst);
7727c208ed6SRick Macklem 			printf("\n");
7737c208ed6SRick Macklem 		}
7747c208ed6SRick Macklem 
7757c208ed6SRick Macklem 		/*
7767c208ed6SRick Macklem 		 * Wait for up to timo seconds for a reply.
7777c208ed6SRick Macklem 		 * The socket receive timeout was set to 1 second.
7787c208ed6SRick Macklem 		 */
7797c208ed6SRick Macklem 		atimo = timo + time_second;
7807c208ed6SRick Macklem 		while (time_second < atimo) {
7817c208ed6SRick Macklem 			aio.iov_base = (caddr_t) &gctx->reply;
7827c208ed6SRick Macklem 			aio.iov_len = sizeof(gctx->reply);
7837c208ed6SRick Macklem 
7847c208ed6SRick Macklem 			auio.uio_iov = &aio;
7857c208ed6SRick Macklem 			auio.uio_iovcnt = 1;
7867c208ed6SRick Macklem 			auio.uio_segflg = UIO_SYSSPACE;
7877c208ed6SRick Macklem 			auio.uio_rw = UIO_READ;
7887c208ed6SRick Macklem 			auio.uio_offset = 0;
7897c208ed6SRick Macklem 			auio.uio_resid = sizeof(gctx->reply);
7907c208ed6SRick Macklem 			auio.uio_td = td;
7917c208ed6SRick Macklem 
7927c208ed6SRick Macklem 			rcvflg = 0;
7936bfaa839SGleb Smirnoff 			error = soreceive(bootp_so, NULL, &auio,
7947c208ed6SRick Macklem 					  NULL, NULL, &rcvflg);
7957c208ed6SRick Macklem 			gctx->secs = time_second - gctx->starttime;
7966bfaa839SGleb Smirnoff 			STAILQ_FOREACH(ifctx, &gctx->interfaces, next) {
7977c208ed6SRick Macklem 				if (bootpc_ifctx_isresolved(ifctx) != 0 ||
7987c208ed6SRick Macklem 				    bootpc_ifctx_isfailed(ifctx) != 0)
7997c208ed6SRick Macklem 					continue;
8007c208ed6SRick Macklem 
8017c208ed6SRick Macklem 				ifctx->call.secs = htons(gctx->secs);
8027c208ed6SRick Macklem 			}
8037c208ed6SRick Macklem 			if (error == EWOULDBLOCK)
8047c208ed6SRick Macklem 				continue;
8057c208ed6SRick Macklem 			if (error != 0)
8067c208ed6SRick Macklem 				goto out;
8077c208ed6SRick Macklem 			len = sizeof(gctx->reply) - auio.uio_resid;
8087c208ed6SRick Macklem 
8097c208ed6SRick Macklem 			/* Do we have the required number of bytes ? */
8107c208ed6SRick Macklem 			if (len < BOOTP_MIN_LEN)
8117c208ed6SRick Macklem 				continue;
8127c208ed6SRick Macklem 			gctx->replylen = len;
8137c208ed6SRick Macklem 
8147c208ed6SRick Macklem 			/* Is it a reply? */
8157c208ed6SRick Macklem 			if (gctx->reply.op != BOOTP_REPLY)
8167c208ed6SRick Macklem 				continue;
8177c208ed6SRick Macklem 
8187c208ed6SRick Macklem 			/* Is this an answer to our query */
8196bfaa839SGleb Smirnoff 			STAILQ_FOREACH(ifctx, &gctx->interfaces, next) {
8207c208ed6SRick Macklem 				if (gctx->reply.xid != ifctx->call.xid)
8217c208ed6SRick Macklem 					continue;
8227c208ed6SRick Macklem 
8237c208ed6SRick Macklem 				/* Same HW address size ? */
8247c208ed6SRick Macklem 				if (gctx->reply.hlen != ifctx->call.hlen)
8257c208ed6SRick Macklem 					continue;
8267c208ed6SRick Macklem 
8277c208ed6SRick Macklem 				/* Correct HW address ? */
8287c208ed6SRick Macklem 				if (bcmp(gctx->reply.chaddr,
8297c208ed6SRick Macklem 					 ifctx->call.chaddr,
8307c208ed6SRick Macklem 					 ifctx->call.hlen) != 0)
8317c208ed6SRick Macklem 					continue;
8327c208ed6SRick Macklem 
8337c208ed6SRick Macklem 				break;
8347c208ed6SRick Macklem 			}
8357c208ed6SRick Macklem 
8367c208ed6SRick Macklem 			if (ifctx != NULL) {
8377c208ed6SRick Macklem 				s =  bootpc_tag(&gctx->tmptag,
8387c208ed6SRick Macklem 						&gctx->reply,
8397c208ed6SRick Macklem 						gctx->replylen,
8407c208ed6SRick Macklem 						TAG_DHCP_MSGTYPE);
8417c208ed6SRick Macklem 				if (s != NULL) {
8427c208ed6SRick Macklem 					switch (*s) {
8437c208ed6SRick Macklem 					case DHCP_OFFER:
8447c208ed6SRick Macklem 						s = "DHCP Offer";
8457c208ed6SRick Macklem 						break;
8467c208ed6SRick Macklem 					case DHCP_ACK:
8477c208ed6SRick Macklem 						s = "DHCP Ack";
8487c208ed6SRick Macklem 						break;
8497c208ed6SRick Macklem 					default:
8507c208ed6SRick Macklem 						s = "DHCP (unexpected)";
8517c208ed6SRick Macklem 						break;
8527c208ed6SRick Macklem 					}
8537c208ed6SRick Macklem 				} else
8547c208ed6SRick Macklem 					s = "BOOTP Reply";
8557c208ed6SRick Macklem 
8567c208ed6SRick Macklem 				printf("Received %s packet"
8577c208ed6SRick Macklem 				       " on %s from ",
8587c208ed6SRick Macklem 				       s,
8597c208ed6SRick Macklem 				       ifctx->ireq.ifr_name);
8607c208ed6SRick Macklem 				print_in_addr(gctx->reply.siaddr);
8617c208ed6SRick Macklem 				if (gctx->reply.giaddr.s_addr !=
8627c208ed6SRick Macklem 				    htonl(INADDR_ANY)) {
8637c208ed6SRick Macklem 					printf(" via ");
8647c208ed6SRick Macklem 					print_in_addr(gctx->reply.giaddr);
8657c208ed6SRick Macklem 				}
8667c208ed6SRick Macklem 				if (bootpc_received(gctx, ifctx) != 0) {
8677c208ed6SRick Macklem 					printf(" (accepted)");
8687c208ed6SRick Macklem 					if (ifctx->outstanding) {
8697c208ed6SRick Macklem 						ifctx->outstanding = 0;
8707c208ed6SRick Macklem 						outstanding--;
8717c208ed6SRick Macklem 					}
8727c208ed6SRick Macklem 					/* Network settle delay */
8737c208ed6SRick Macklem 					if (outstanding == 0)
8747c208ed6SRick Macklem 						atimo = time_second +
8757c208ed6SRick Macklem 							BOOTP_SETTLE_DELAY;
8767c208ed6SRick Macklem 				} else
8777c208ed6SRick Macklem 					printf(" (ignored)");
8786cbd933bSIan Lepore 				if (ifctx->gotrootpath ||
8796cbd933bSIan Lepore 				    gctx->any_root_overrides) {
8807c208ed6SRick Macklem 					gotrootpath = 1;
8817c208ed6SRick Macklem 					rtimo = time_second +
8827c208ed6SRick Macklem 						BOOTP_SETTLE_DELAY;
8836cbd933bSIan Lepore 					if (ifctx->gotrootpath)
8847c208ed6SRick Macklem 						printf(" (got root path)");
8856cbd933bSIan Lepore 				}
8867c208ed6SRick Macklem 				printf("\n");
8877c208ed6SRick Macklem 			}
8887c208ed6SRick Macklem 		} /* while secs */
8897c208ed6SRick Macklem #ifdef BOOTP_TIMEOUT
8907c208ed6SRick Macklem 		if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0)
8917c208ed6SRick Macklem 			break;
8927c208ed6SRick Macklem #endif
8937c208ed6SRick Macklem 		/* Force a retry if halfway in DHCP negotiation */
8947c208ed6SRick Macklem 		retry = 0;
8956bfaa839SGleb Smirnoff 		STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
8967c208ed6SRick Macklem 			if (ifctx->state == IF_DHCP_OFFERED) {
8977c208ed6SRick Macklem 				if (ifctx->dhcpquerytype == DHCP_DISCOVER)
8987c208ed6SRick Macklem 					retry = 1;
8997c208ed6SRick Macklem 				else
9007c208ed6SRick Macklem 					ifctx->state = IF_DHCP_UNRESOLVED;
9017c208ed6SRick Macklem 			}
9027c208ed6SRick Macklem 
9037c208ed6SRick Macklem 		if (retry != 0)
9047c208ed6SRick Macklem 			continue;
9057c208ed6SRick Macklem 
9067c208ed6SRick Macklem 		if (gotrootpath != 0) {
9077c208ed6SRick Macklem 			gctx->gotrootpath = gotrootpath;
9087c208ed6SRick Macklem 			if (rtimo != 0 && time_second >= rtimo)
9097c208ed6SRick Macklem 				break;
9107c208ed6SRick Macklem 		}
9117c208ed6SRick Macklem 	} /* forever send/receive */
9127c208ed6SRick Macklem 
9137c208ed6SRick Macklem 	/*
9147c208ed6SRick Macklem 	 * XXX: These are errors of varying seriousness being silently
9157c208ed6SRick Macklem 	 * ignored
9167c208ed6SRick Macklem 	 */
9177c208ed6SRick Macklem 
9186bfaa839SGleb Smirnoff 	STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
9197c208ed6SRick Macklem 		if (bootpc_ifctx_isresolved(ifctx) == 0) {
9207c208ed6SRick Macklem 			printf("%s timeout for interface %s\n",
9217c208ed6SRick Macklem 			       ifctx->dhcpquerytype != DHCP_NOMSG ?
9227c208ed6SRick Macklem 			       "DHCP" : "BOOTP",
9237c208ed6SRick Macklem 			       ifctx->ireq.ifr_name);
9247c208ed6SRick Macklem 		}
9256bfaa839SGleb Smirnoff 
9267c208ed6SRick Macklem 	if (gctx->gotrootpath != 0) {
9277c208ed6SRick Macklem #if 0
9287c208ed6SRick Macklem 		printf("Got a root path, ignoring remaining timeout\n");
9297c208ed6SRick Macklem #endif
9307c208ed6SRick Macklem 		error = 0;
9317c208ed6SRick Macklem 		goto out;
9327c208ed6SRick Macklem 	}
9337c208ed6SRick Macklem #ifndef BOOTP_NFSROOT
9346bfaa839SGleb Smirnoff 	STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
9357c208ed6SRick Macklem 		if (bootpc_ifctx_isresolved(ifctx) != 0) {
9367c208ed6SRick Macklem 			error = 0;
9377c208ed6SRick Macklem 			goto out;
9387c208ed6SRick Macklem 		}
9397c208ed6SRick Macklem #endif
9407c208ed6SRick Macklem 	error = ETIMEDOUT;
9417c208ed6SRick Macklem 
9427c208ed6SRick Macklem out:
9436bfaa839SGleb Smirnoff 	return (error);
9447c208ed6SRick Macklem }
9457c208ed6SRick Macklem 
9466bfaa839SGleb Smirnoff static void
9476bfaa839SGleb Smirnoff bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx, struct thread *td)
9487c208ed6SRick Macklem {
9496bfaa839SGleb Smirnoff 	struct ifreq *ifr;
9506bfaa839SGleb Smirnoff 	struct in_aliasreq *ifra;
9517c208ed6SRick Macklem 	struct sockaddr_in *sin;
9527c208ed6SRick Macklem 	int error;
9537c208ed6SRick Macklem 
9546bfaa839SGleb Smirnoff 	ifr = &ifctx->ireq;
9556bfaa839SGleb Smirnoff 	ifra = &ifctx->iareq;
9567c208ed6SRick Macklem 
9577c208ed6SRick Macklem 	/*
9587c208ed6SRick Macklem 	 * Bring up the interface.
9597c208ed6SRick Macklem 	 *
9607c208ed6SRick Macklem 	 * Get the old interface flags and or IFF_UP into them; if
9617c208ed6SRick Macklem 	 * IFF_UP set blindly, interface selection can be clobbered.
9627c208ed6SRick Macklem 	 */
9636bfaa839SGleb Smirnoff 	error = ifioctl(bootp_so, SIOCGIFFLAGS, (caddr_t)ifr, td);
9647c208ed6SRick Macklem 	if (error != 0)
9656bfaa839SGleb Smirnoff 		panic("%s: SIOCGIFFLAGS, error=%d", __func__, error);
9666bfaa839SGleb Smirnoff 	ifr->ifr_flags |= IFF_UP;
9676bfaa839SGleb Smirnoff 	error = ifioctl(bootp_so, SIOCSIFFLAGS, (caddr_t)ifr, td);
9687c208ed6SRick Macklem 	if (error != 0)
9696bfaa839SGleb Smirnoff 		panic("%s: SIOCSIFFLAGS, error=%d", __func__, error);
9707c208ed6SRick Macklem 
9717c208ed6SRick Macklem 	/*
9727c208ed6SRick Macklem 	 * Do enough of ifconfig(8) so that the chosen interface
9736bfaa839SGleb Smirnoff 	 * can talk to the servers. Set address to 0.0.0.0/8 and
9746bfaa839SGleb Smirnoff 	 * broadcast address to local broadcast.
9757c208ed6SRick Macklem 	 */
9766bfaa839SGleb Smirnoff 	sin = (struct sockaddr_in *)&ifra->ifra_addr;
9777c208ed6SRick Macklem 	clear_sinaddr(sin);
9786bfaa839SGleb Smirnoff 	sin = (struct sockaddr_in *)&ifra->ifra_mask;
9797c208ed6SRick Macklem 	clear_sinaddr(sin);
9806bfaa839SGleb Smirnoff 	sin->sin_addr.s_addr = htonl(IN_CLASSA_NET);
9816bfaa839SGleb Smirnoff 	sin = (struct sockaddr_in *)&ifra->ifra_broadaddr;
9827c208ed6SRick Macklem 	clear_sinaddr(sin);
9837c208ed6SRick Macklem 	sin->sin_addr.s_addr = htonl(INADDR_BROADCAST);
9846bfaa839SGleb Smirnoff 	error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, td);
9857c208ed6SRick Macklem 	if (error != 0)
9866bfaa839SGleb Smirnoff 		panic("%s: SIOCAIFADDR, error=%d", __func__, error);
9877c208ed6SRick Macklem }
9887c208ed6SRick Macklem 
9896bfaa839SGleb Smirnoff static void
9906bfaa839SGleb Smirnoff bootpc_shutdown_interface(struct bootpc_ifcontext *ifctx, struct thread *td)
9916bfaa839SGleb Smirnoff {
9926bfaa839SGleb Smirnoff 	struct ifreq *ifr;
9936bfaa839SGleb Smirnoff 	struct sockaddr_in *sin;
9946bfaa839SGleb Smirnoff 	int error;
9957c208ed6SRick Macklem 
9966bfaa839SGleb Smirnoff 	ifr = &ifctx->ireq;
9976bfaa839SGleb Smirnoff 
9986bfaa839SGleb Smirnoff 	printf("Shutdown interface %s\n", ifctx->ireq.ifr_name);
9996bfaa839SGleb Smirnoff 	error = ifioctl(bootp_so, SIOCGIFFLAGS, (caddr_t)ifr, td);
10006bfaa839SGleb Smirnoff 	if (error != 0)
10016bfaa839SGleb Smirnoff 		panic("%s: SIOCGIFFLAGS, error=%d", __func__, error);
10026bfaa839SGleb Smirnoff 	ifr->ifr_flags &= ~IFF_UP;
10036bfaa839SGleb Smirnoff 	error = ifioctl(bootp_so, SIOCSIFFLAGS, (caddr_t)ifr, td);
10046bfaa839SGleb Smirnoff 	if (error != 0)
10056bfaa839SGleb Smirnoff 		panic("%s: SIOCSIFFLAGS, error=%d", __func__, error);
10066bfaa839SGleb Smirnoff 
10076bfaa839SGleb Smirnoff 	sin = (struct sockaddr_in *) &ifr->ifr_addr;
10086bfaa839SGleb Smirnoff 	clear_sinaddr(sin);
10096bfaa839SGleb Smirnoff 	error = ifioctl(bootp_so, SIOCDIFADDR, (caddr_t) ifr, td);
10106bfaa839SGleb Smirnoff 	if (error != 0)
10116bfaa839SGleb Smirnoff 		panic("%s: SIOCDIFADDR, error=%d", __func__, error);
10127c208ed6SRick Macklem }
10137c208ed6SRick Macklem 
1014*d32d350eSIan Lepore static void
10157c208ed6SRick Macklem bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
10167c208ed6SRick Macklem     struct bootpc_globalcontext *gctx, struct thread *td)
10177c208ed6SRick Macklem {
10187c208ed6SRick Macklem 	int error;
10197c208ed6SRick Macklem 	struct sockaddr_in defdst;
10207c208ed6SRick Macklem 	struct sockaddr_in defmask;
10217c208ed6SRick Macklem 	struct sockaddr_in *sin;
10226bfaa839SGleb Smirnoff 	struct ifreq *ifr;
10236bfaa839SGleb Smirnoff 	struct in_aliasreq *ifra;
10247c208ed6SRick Macklem 	struct sockaddr_in *myaddr;
10257c208ed6SRick Macklem 	struct sockaddr_in *netmask;
10267c208ed6SRick Macklem 	struct sockaddr_in *gw;
10277c208ed6SRick Macklem 
10286bfaa839SGleb Smirnoff 	ifr = &ifctx->ireq;
10296bfaa839SGleb Smirnoff 	ifra = &ifctx->iareq;
10307c208ed6SRick Macklem 	myaddr = &ifctx->myaddr;
10317c208ed6SRick Macklem 	netmask = &ifctx->netmask;
10327c208ed6SRick Macklem 	gw = &ifctx->gw;
10337c208ed6SRick Macklem 
10347c208ed6SRick Macklem 	if (bootpc_ifctx_isresolved(ifctx) == 0) {
10357c208ed6SRick Macklem 		/* Shutdown interfaces where BOOTP failed */
10366bfaa839SGleb Smirnoff 		bootpc_shutdown_interface(ifctx, td);
1037*d32d350eSIan Lepore 		return;
10387c208ed6SRick Macklem 	}
10397c208ed6SRick Macklem 
1040a6c14908SIan Lepore 	printf("Adjusted interface %s", ifctx->ireq.ifr_name);
1041a6c14908SIan Lepore 
1042a6c14908SIan Lepore 	/* Do BOOTP interface options */
1043a6c14908SIan Lepore 	if (ifctx->mtu != 0) {
1044a6c14908SIan Lepore 		printf(" (MTU=%d%s)", ifctx->mtu,
1045a6c14908SIan Lepore 		    (ifctx->mtu > 1514) ? "/JUMBO" : "");
1046a6c14908SIan Lepore 		ifr->ifr_mtu = ifctx->mtu;
1047a6c14908SIan Lepore 		error = ifioctl(bootp_so, SIOCSIFMTU, (caddr_t) ifr, td);
1048a6c14908SIan Lepore 		if (error != 0)
1049a6c14908SIan Lepore 			panic("%s: SIOCSIFMTU, error=%d", __func__, error);
1050a6c14908SIan Lepore 	}
1051a6c14908SIan Lepore 	printf("\n");
1052a6c14908SIan Lepore 
10537c208ed6SRick Macklem 	/*
10547c208ed6SRick Macklem 	 * Do enough of ifconfig(8) so that the chosen interface
10557c208ed6SRick Macklem 	 * can talk to the servers.  (just set the address)
10567c208ed6SRick Macklem 	 */
10576bfaa839SGleb Smirnoff 	sin = (struct sockaddr_in *) &ifr->ifr_addr;
10587c208ed6SRick Macklem 	clear_sinaddr(sin);
10596bfaa839SGleb Smirnoff 	error = ifioctl(bootp_so, SIOCDIFADDR, (caddr_t) ifr, td);
10607c208ed6SRick Macklem 	if (error != 0)
10616bfaa839SGleb Smirnoff 		panic("%s: SIOCDIFADDR, error=%d", __func__, error);
10627c208ed6SRick Macklem 
10636bfaa839SGleb Smirnoff 	bcopy(myaddr, &ifra->ifra_addr, sizeof(*myaddr));
10646bfaa839SGleb Smirnoff 	bcopy(netmask, &ifra->ifra_mask, sizeof(*netmask));
10656bfaa839SGleb Smirnoff 	clear_sinaddr(&ifra->ifra_broadaddr);
10666bfaa839SGleb Smirnoff 	ifra->ifra_broadaddr.sin_addr.s_addr = myaddr->sin_addr.s_addr |
10676bfaa839SGleb Smirnoff 	    ~netmask->sin_addr.s_addr;
10686bfaa839SGleb Smirnoff 
10696bfaa839SGleb Smirnoff 	error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, td);
10706bfaa839SGleb Smirnoff 	if (error != 0)
10716bfaa839SGleb Smirnoff 		panic("%s: SIOCAIFADDR, error=%d", __func__, error);
10727c208ed6SRick Macklem 
10737c208ed6SRick Macklem 	/* Add new default route */
10747c208ed6SRick Macklem 
10757c208ed6SRick Macklem 	if (ifctx->gotgw != 0 || gctx->gotgw == 0) {
10767c208ed6SRick Macklem 		clear_sinaddr(&defdst);
10777c208ed6SRick Macklem 		clear_sinaddr(&defmask);
10787c208ed6SRick Macklem 		/* XXX MRT just table 0 */
10797c208ed6SRick Macklem 		error = rtrequest_fib(RTM_ADD,
108081d5d46bSBjoern A. Zeeb 		    (struct sockaddr *) &defdst, (struct sockaddr *) gw,
10817c208ed6SRick Macklem 		    (struct sockaddr *) &defmask,
108281d5d46bSBjoern A. Zeeb 		    (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, RT_DEFAULT_FIB);
10837c208ed6SRick Macklem 		if (error != 0) {
10846bfaa839SGleb Smirnoff 			printf("%s: RTM_ADD, error=%d\n", __func__, error);
1085*d32d350eSIan Lepore 			return;
10867c208ed6SRick Macklem 		}
10877c208ed6SRick Macklem 	}
10887c208ed6SRick Macklem }
10897c208ed6SRick Macklem 
10907c208ed6SRick Macklem static int
10917c208ed6SRick Macklem setfs(struct sockaddr_in *addr, char *path, char *p,
10927c208ed6SRick Macklem     const struct in_addr *siaddr)
10937c208ed6SRick Macklem {
10947c208ed6SRick Macklem 
10957c208ed6SRick Macklem 	if (getip(&p, &addr->sin_addr) == 0) {
10967c208ed6SRick Macklem 		if (siaddr != NULL && *p == '/')
10977c208ed6SRick Macklem 			bcopy(siaddr, &addr->sin_addr, sizeof(struct in_addr));
10987c208ed6SRick Macklem 		else
10997c208ed6SRick Macklem 			return 0;
11007c208ed6SRick Macklem 	} else {
11017c208ed6SRick Macklem 		if (*p != ':')
11027c208ed6SRick Macklem 			return 0;
11037c208ed6SRick Macklem 		p++;
11047c208ed6SRick Macklem 	}
11057c208ed6SRick Macklem 
11067c208ed6SRick Macklem 	addr->sin_len = sizeof(struct sockaddr_in);
11077c208ed6SRick Macklem 	addr->sin_family = AF_INET;
11087c208ed6SRick Macklem 
11097c208ed6SRick Macklem 	strlcpy(path, p, MNAMELEN);
11107c208ed6SRick Macklem 	return 1;
11117c208ed6SRick Macklem }
11127c208ed6SRick Macklem 
11137c208ed6SRick Macklem static int
11147c208ed6SRick Macklem getip(char **ptr, struct in_addr *addr)
11157c208ed6SRick Macklem {
11167c208ed6SRick Macklem 	char *p;
11177c208ed6SRick Macklem 	unsigned int ip;
11187c208ed6SRick Macklem 	int val;
11197c208ed6SRick Macklem 
11207c208ed6SRick Macklem 	p = *ptr;
11217c208ed6SRick Macklem 	ip = 0;
11227c208ed6SRick Macklem 	if (((val = getdec(&p)) < 0) || (val > 255))
11237c208ed6SRick Macklem 		return 0;
11247c208ed6SRick Macklem 	ip = val << 24;
11257c208ed6SRick Macklem 	if (*p != '.')
11267c208ed6SRick Macklem 		return 0;
11277c208ed6SRick Macklem 	p++;
11287c208ed6SRick Macklem 	if (((val = getdec(&p)) < 0) || (val > 255))
11297c208ed6SRick Macklem 		return 0;
11307c208ed6SRick Macklem 	ip |= (val << 16);
11317c208ed6SRick Macklem 	if (*p != '.')
11327c208ed6SRick Macklem 		return 0;
11337c208ed6SRick Macklem 	p++;
11347c208ed6SRick Macklem 	if (((val = getdec(&p)) < 0) || (val > 255))
11357c208ed6SRick Macklem 		return 0;
11367c208ed6SRick Macklem 	ip |= (val << 8);
11377c208ed6SRick Macklem 	if (*p != '.')
11387c208ed6SRick Macklem 		return 0;
11397c208ed6SRick Macklem 	p++;
11407c208ed6SRick Macklem 	if (((val = getdec(&p)) < 0) || (val > 255))
11417c208ed6SRick Macklem 		return 0;
11427c208ed6SRick Macklem 	ip |= val;
11437c208ed6SRick Macklem 
11447c208ed6SRick Macklem 	addr->s_addr = htonl(ip);
11457c208ed6SRick Macklem 	*ptr = p;
11467c208ed6SRick Macklem 	return 1;
11477c208ed6SRick Macklem }
11487c208ed6SRick Macklem 
11497c208ed6SRick Macklem static int
11507c208ed6SRick Macklem getdec(char **ptr)
11517c208ed6SRick Macklem {
11527c208ed6SRick Macklem 	char *p;
11537c208ed6SRick Macklem 	int ret;
11547c208ed6SRick Macklem 
11557c208ed6SRick Macklem 	p = *ptr;
11567c208ed6SRick Macklem 	ret = 0;
11577c208ed6SRick Macklem 	if ((*p < '0') || (*p > '9'))
11587c208ed6SRick Macklem 		return -1;
11597c208ed6SRick Macklem 	while ((*p >= '0') && (*p <= '9')) {
11607c208ed6SRick Macklem 		ret = ret * 10 + (*p - '0');
11617c208ed6SRick Macklem 		p++;
11627c208ed6SRick Macklem 	}
11637c208ed6SRick Macklem 	*ptr = p;
11647c208ed6SRick Macklem 	return ret;
11657c208ed6SRick Macklem }
11667c208ed6SRick Macklem 
11677c208ed6SRick Macklem static void
11687c208ed6SRick Macklem mountopts(struct nfs_args *args, char *p)
11697c208ed6SRick Macklem {
11707c208ed6SRick Macklem 	args->version = NFS_ARGSVERSION;
11717c208ed6SRick Macklem 	args->rsize = BOOTP_BLOCKSIZE;
11727c208ed6SRick Macklem 	args->wsize = BOOTP_BLOCKSIZE;
11737c208ed6SRick Macklem 	args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
11747c208ed6SRick Macklem 	args->sotype = SOCK_DGRAM;
11757c208ed6SRick Macklem 	if (p != NULL)
11767c208ed6SRick Macklem 		nfs_parse_options(p, args);
11777c208ed6SRick Macklem }
11787c208ed6SRick Macklem 
11797c208ed6SRick Macklem static int
11807c208ed6SRick Macklem xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len)
11817c208ed6SRick Macklem {
11827c208ed6SRick Macklem 	struct mbuf *m;
11837c208ed6SRick Macklem 	int alignedlen;
11847c208ed6SRick Macklem 
11857c208ed6SRick Macklem 	m = *mptr;
11867c208ed6SRick Macklem 	alignedlen = ( len + 3 ) & ~3;
11877c208ed6SRick Macklem 
11887c208ed6SRick Macklem 	if (m->m_len < alignedlen) {
11897c208ed6SRick Macklem 		m = m_pullup(m, alignedlen);
11907c208ed6SRick Macklem 		if (m == NULL) {
11917c208ed6SRick Macklem 			*mptr = NULL;
11927c208ed6SRick Macklem 			return EBADRPC;
11937c208ed6SRick Macklem 		}
11947c208ed6SRick Macklem 	}
11957c208ed6SRick Macklem 	bcopy(mtod(m, u_char *), buf, len);
11967c208ed6SRick Macklem 	m_adj(m, alignedlen);
11977c208ed6SRick Macklem 	*mptr = m;
11987c208ed6SRick Macklem 	return 0;
11997c208ed6SRick Macklem }
12007c208ed6SRick Macklem 
12017c208ed6SRick Macklem static int
12027c208ed6SRick Macklem xdr_int_decode(struct mbuf **mptr, int *iptr)
12037c208ed6SRick Macklem {
12047c208ed6SRick Macklem 	u_int32_t i;
12057c208ed6SRick Macklem 
12067c208ed6SRick Macklem 	if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0)
12077c208ed6SRick Macklem 		return EBADRPC;
12087c208ed6SRick Macklem 	*iptr = fxdr_unsigned(u_int32_t, i);
12097c208ed6SRick Macklem 	return 0;
12107c208ed6SRick Macklem }
12117c208ed6SRick Macklem 
12127c208ed6SRick Macklem static void
12137c208ed6SRick Macklem print_sin_addr(struct sockaddr_in *sin)
12147c208ed6SRick Macklem {
12157c208ed6SRick Macklem 
12167c208ed6SRick Macklem 	print_in_addr(sin->sin_addr);
12177c208ed6SRick Macklem }
12187c208ed6SRick Macklem 
12197c208ed6SRick Macklem static void
12207c208ed6SRick Macklem print_in_addr(struct in_addr addr)
12217c208ed6SRick Macklem {
12227c208ed6SRick Macklem 	unsigned int ip;
12237c208ed6SRick Macklem 
12247c208ed6SRick Macklem 	ip = ntohl(addr.s_addr);
12257c208ed6SRick Macklem 	printf("%d.%d.%d.%d",
12267c208ed6SRick Macklem 	       ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
12277c208ed6SRick Macklem }
12287c208ed6SRick Macklem 
12297c208ed6SRick Macklem static void
12306bfaa839SGleb Smirnoff bootpc_compose_query(struct bootpc_ifcontext *ifctx, struct thread *td)
12317c208ed6SRick Macklem {
12327c208ed6SRick Macklem 	unsigned char *vendp;
12337c208ed6SRick Macklem 	unsigned char vendor_client[64];
12347c208ed6SRick Macklem 	uint32_t leasetime;
12357c208ed6SRick Macklem 	uint8_t vendor_client_len;
12367c208ed6SRick Macklem 
12377c208ed6SRick Macklem 	ifctx->gotrootpath = 0;
12387c208ed6SRick Macklem 
12397c208ed6SRick Macklem 	bzero((caddr_t) &ifctx->call, sizeof(ifctx->call));
12407c208ed6SRick Macklem 
12417c208ed6SRick Macklem 	/* bootpc part */
12427c208ed6SRick Macklem 	ifctx->call.op = BOOTP_REQUEST; 	/* BOOTREQUEST */
12437c208ed6SRick Macklem 	ifctx->call.htype = 1;			/* 10mb ethernet */
12447c208ed6SRick Macklem 	ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */
12457c208ed6SRick Macklem 	ifctx->call.hops = 0;
12467c208ed6SRick Macklem 	if (bootpc_ifctx_isunresolved(ifctx) != 0)
12477c208ed6SRick Macklem 		ifctx->xid++;
12487c208ed6SRick Macklem 	ifctx->call.xid = txdr_unsigned(ifctx->xid);
12497c208ed6SRick Macklem 	bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen);
12507c208ed6SRick Macklem 
12517c208ed6SRick Macklem 	vendp = ifctx->call.vend;
12527c208ed6SRick Macklem 	*vendp++ = 99;		/* RFC1048 cookie */
12537c208ed6SRick Macklem 	*vendp++ = 130;
12547c208ed6SRick Macklem 	*vendp++ = 83;
12557c208ed6SRick Macklem 	*vendp++ = 99;
12567c208ed6SRick Macklem 	*vendp++ = TAG_MAXMSGSIZE;
12577c208ed6SRick Macklem 	*vendp++ = 2;
12587c208ed6SRick Macklem 	*vendp++ = (sizeof(struct bootp_packet) >> 8) & 255;
12597c208ed6SRick Macklem 	*vendp++ = sizeof(struct bootp_packet) & 255;
12607c208ed6SRick Macklem 
12617c208ed6SRick Macklem 	snprintf(vendor_client, sizeof(vendor_client), "%s:%s:%s",
12627c208ed6SRick Macklem 		ostype, MACHINE, osrelease);
12637c208ed6SRick Macklem 	vendor_client_len = strlen(vendor_client);
12647c208ed6SRick Macklem 	*vendp++ = TAG_VENDOR_INDENTIFIER;
12657c208ed6SRick Macklem 	*vendp++ = vendor_client_len;
12667c208ed6SRick Macklem 	memcpy(vendp, vendor_client, vendor_client_len);
12677c208ed6SRick Macklem 	vendp += vendor_client_len;
12687c208ed6SRick Macklem 	ifctx->dhcpquerytype = DHCP_NOMSG;
12697c208ed6SRick Macklem 	switch (ifctx->state) {
12707c208ed6SRick Macklem 	case IF_DHCP_UNRESOLVED:
12717c208ed6SRick Macklem 		*vendp++ = TAG_DHCP_MSGTYPE;
12727c208ed6SRick Macklem 		*vendp++ = 1;
12737c208ed6SRick Macklem 		*vendp++ = DHCP_DISCOVER;
12747c208ed6SRick Macklem 		ifctx->dhcpquerytype = DHCP_DISCOVER;
12757c208ed6SRick Macklem 		ifctx->gotdhcpserver = 0;
12767c208ed6SRick Macklem 		break;
12777c208ed6SRick Macklem 	case IF_DHCP_OFFERED:
12787c208ed6SRick Macklem 		*vendp++ = TAG_DHCP_MSGTYPE;
12797c208ed6SRick Macklem 		*vendp++ = 1;
12807c208ed6SRick Macklem 		*vendp++ = DHCP_REQUEST;
12817c208ed6SRick Macklem 		ifctx->dhcpquerytype = DHCP_REQUEST;
12827c208ed6SRick Macklem 		*vendp++ = TAG_DHCP_REQ_ADDR;
12837c208ed6SRick Macklem 		*vendp++ = 4;
12847c208ed6SRick Macklem 		memcpy(vendp, &ifctx->reply.yiaddr, 4);
12857c208ed6SRick Macklem 		vendp += 4;
12867c208ed6SRick Macklem 		if (ifctx->gotdhcpserver != 0) {
12877c208ed6SRick Macklem 			*vendp++ = TAG_DHCP_SERVERID;
12887c208ed6SRick Macklem 			*vendp++ = 4;
12897c208ed6SRick Macklem 			memcpy(vendp, &ifctx->dhcpserver, 4);
12907c208ed6SRick Macklem 			vendp += 4;
12917c208ed6SRick Macklem 		}
12927c208ed6SRick Macklem 		*vendp++ = TAG_DHCP_LEASETIME;
12937c208ed6SRick Macklem 		*vendp++ = 4;
12947c208ed6SRick Macklem 		leasetime = htonl(300);
12957c208ed6SRick Macklem 		memcpy(vendp, &leasetime, 4);
12967c208ed6SRick Macklem 		vendp += 4;
12977c208ed6SRick Macklem 		break;
12987c208ed6SRick Macklem 	default:
12997c208ed6SRick Macklem 		break;
13007c208ed6SRick Macklem 	}
13017c208ed6SRick Macklem 	*vendp = TAG_END;
13027c208ed6SRick Macklem 
13037c208ed6SRick Macklem 	ifctx->call.secs = 0;
13047c208ed6SRick Macklem 	ifctx->call.flags = htons(0x8000); /* We need a broadcast answer */
13057c208ed6SRick Macklem }
13067c208ed6SRick Macklem 
13077c208ed6SRick Macklem static int
13087c208ed6SRick Macklem bootpc_hascookie(struct bootp_packet *bp)
13097c208ed6SRick Macklem {
13107c208ed6SRick Macklem 
13117c208ed6SRick Macklem 	return (bp->vend[0] == 99 && bp->vend[1] == 130 &&
13127c208ed6SRick Macklem 		bp->vend[2] == 83 && bp->vend[3] == 99);
13137c208ed6SRick Macklem }
13147c208ed6SRick Macklem 
13157c208ed6SRick Macklem static void
13167c208ed6SRick Macklem bootpc_tag_helper(struct bootpc_tagcontext *tctx,
13177c208ed6SRick Macklem     unsigned char *start, int len, int tag)
13187c208ed6SRick Macklem {
13197c208ed6SRick Macklem 	unsigned char *j;
13207c208ed6SRick Macklem 	unsigned char *ej;
13217c208ed6SRick Macklem 	unsigned char code;
13227c208ed6SRick Macklem 
13237c208ed6SRick Macklem 	if (tctx->badtag != 0 || tctx->badopt != 0)
13247c208ed6SRick Macklem 		return;
13257c208ed6SRick Macklem 
13267c208ed6SRick Macklem 	j = start;
13277c208ed6SRick Macklem 	ej = j + len;
13287c208ed6SRick Macklem 
13297c208ed6SRick Macklem 	while (j < ej) {
13307c208ed6SRick Macklem 		code = *j++;
13317c208ed6SRick Macklem 		if (code == TAG_PAD)
13327c208ed6SRick Macklem 			continue;
13337c208ed6SRick Macklem 		if (code == TAG_END)
13347c208ed6SRick Macklem 			return;
13357c208ed6SRick Macklem 		if (j >= ej || j + *j + 1 > ej) {
13367c208ed6SRick Macklem 			tctx->badopt = 1;
13377c208ed6SRick Macklem 			return;
13387c208ed6SRick Macklem 		}
13397c208ed6SRick Macklem 		len = *j++;
13407c208ed6SRick Macklem 		if (code == tag) {
13417c208ed6SRick Macklem 			if (tctx->taglen + len > TAG_MAXLEN) {
13427c208ed6SRick Macklem 				tctx->badtag = 1;
13437c208ed6SRick Macklem 				return;
13447c208ed6SRick Macklem 			}
13457c208ed6SRick Macklem 			tctx->foundopt = 1;
13467c208ed6SRick Macklem 			if (len > 0)
13477c208ed6SRick Macklem 				memcpy(tctx->buf + tctx->taglen,
13487c208ed6SRick Macklem 				       j, len);
13497c208ed6SRick Macklem 			tctx->taglen += len;
13507c208ed6SRick Macklem 		}
13517c208ed6SRick Macklem 		if (code == TAG_OVERLOAD)
13527c208ed6SRick Macklem 			tctx->overload = *j;
13537c208ed6SRick Macklem 
13547c208ed6SRick Macklem 		j += len;
13557c208ed6SRick Macklem 	}
13567c208ed6SRick Macklem }
13577c208ed6SRick Macklem 
13587c208ed6SRick Macklem static unsigned char *
13597c208ed6SRick Macklem bootpc_tag(struct bootpc_tagcontext *tctx,
13607c208ed6SRick Macklem     struct bootp_packet *bp, int len, int tag)
13617c208ed6SRick Macklem {
13627c208ed6SRick Macklem 	tctx->overload = 0;
13637c208ed6SRick Macklem 	tctx->badopt = 0;
13647c208ed6SRick Macklem 	tctx->badtag = 0;
13657c208ed6SRick Macklem 	tctx->foundopt = 0;
13667c208ed6SRick Macklem 	tctx->taglen = 0;
13677c208ed6SRick Macklem 
13687c208ed6SRick Macklem 	if (bootpc_hascookie(bp) == 0)
13697c208ed6SRick Macklem 		return NULL;
13707c208ed6SRick Macklem 
13717c208ed6SRick Macklem 	bootpc_tag_helper(tctx, &bp->vend[4],
13727c208ed6SRick Macklem 			  (unsigned char *) bp + len - &bp->vend[4], tag);
13737c208ed6SRick Macklem 
13747c208ed6SRick Macklem 	if ((tctx->overload & OVERLOAD_FILE) != 0)
13757c208ed6SRick Macklem 		bootpc_tag_helper(tctx,
13767c208ed6SRick Macklem 				  (unsigned char *) bp->file,
13777c208ed6SRick Macklem 				  sizeof(bp->file),
13787c208ed6SRick Macklem 				  tag);
13797c208ed6SRick Macklem 	if ((tctx->overload & OVERLOAD_SNAME) != 0)
13807c208ed6SRick Macklem 		bootpc_tag_helper(tctx,
13817c208ed6SRick Macklem 				  (unsigned char *) bp->sname,
13827c208ed6SRick Macklem 				  sizeof(bp->sname),
13837c208ed6SRick Macklem 				  tag);
13847c208ed6SRick Macklem 
13857c208ed6SRick Macklem 	if (tctx->badopt != 0 || tctx->badtag != 0 || tctx->foundopt == 0)
13867c208ed6SRick Macklem 		return NULL;
13877c208ed6SRick Macklem 	tctx->buf[tctx->taglen] = '\0';
13887c208ed6SRick Macklem 	return tctx->buf;
13897c208ed6SRick Macklem }
13907c208ed6SRick Macklem 
13917c208ed6SRick Macklem static void
13927c208ed6SRick Macklem bootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx,
13937c208ed6SRick Macklem     struct bootpc_globalcontext *gctx)
13947c208ed6SRick Macklem {
13956cbd933bSIan Lepore 	char *p, *s;
13967c208ed6SRick Macklem 	unsigned int ip;
13977c208ed6SRick Macklem 
13987c208ed6SRick Macklem 	ifctx->gotgw = 0;
13997c208ed6SRick Macklem 	ifctx->gotnetmask = 0;
14007c208ed6SRick Macklem 
14017c208ed6SRick Macklem 	clear_sinaddr(&ifctx->myaddr);
14027c208ed6SRick Macklem 	clear_sinaddr(&ifctx->netmask);
14037c208ed6SRick Macklem 	clear_sinaddr(&ifctx->gw);
14047c208ed6SRick Macklem 
14057c208ed6SRick Macklem 	ifctx->myaddr.sin_addr = ifctx->reply.yiaddr;
14067c208ed6SRick Macklem 
14077c208ed6SRick Macklem 	ip = ntohl(ifctx->myaddr.sin_addr.s_addr);
14087c208ed6SRick Macklem 
14097c208ed6SRick Macklem 	printf("%s at ", ifctx->ireq.ifr_name);
14107c208ed6SRick Macklem 	print_sin_addr(&ifctx->myaddr);
14117c208ed6SRick Macklem 	printf(" server ");
14127c208ed6SRick Macklem 	print_in_addr(ifctx->reply.siaddr);
14137c208ed6SRick Macklem 
14147c208ed6SRick Macklem 	ifctx->gw.sin_addr = ifctx->reply.giaddr;
14157c208ed6SRick Macklem 	if (ifctx->reply.giaddr.s_addr != htonl(INADDR_ANY)) {
14167c208ed6SRick Macklem 		printf(" via gateway ");
14177c208ed6SRick Macklem 		print_in_addr(ifctx->reply.giaddr);
14187c208ed6SRick Macklem 	}
14197c208ed6SRick Macklem 
14207c208ed6SRick Macklem 	/* This call used for the side effect (overload flag) */
14217c208ed6SRick Macklem 	(void) bootpc_tag(&gctx->tmptag,
14227c208ed6SRick Macklem 			  &ifctx->reply, ifctx->replylen, TAG_END);
14237c208ed6SRick Macklem 
14247c208ed6SRick Macklem 	if ((gctx->tmptag.overload & OVERLOAD_SNAME) == 0)
14257c208ed6SRick Macklem 		if (ifctx->reply.sname[0] != '\0')
14267c208ed6SRick Macklem 			printf(" server name %s", ifctx->reply.sname);
14277c208ed6SRick Macklem 	if ((gctx->tmptag.overload & OVERLOAD_FILE) == 0)
14287c208ed6SRick Macklem 		if (ifctx->reply.file[0] != '\0')
14297c208ed6SRick Macklem 			printf(" boot file %s", ifctx->reply.file);
14307c208ed6SRick Macklem 
14317c208ed6SRick Macklem 	printf("\n");
14327c208ed6SRick Macklem 
14337c208ed6SRick Macklem 	p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
14347c208ed6SRick Macklem 		       TAG_SUBNETMASK);
14357c208ed6SRick Macklem 	if (p != NULL) {
14367c208ed6SRick Macklem 		if (gctx->tag.taglen != 4)
14377c208ed6SRick Macklem 			panic("bootpc: subnet mask len is %d",
14387c208ed6SRick Macklem 			      gctx->tag.taglen);
14397c208ed6SRick Macklem 		bcopy(p, &ifctx->netmask.sin_addr, 4);
14407c208ed6SRick Macklem 		ifctx->gotnetmask = 1;
14417c208ed6SRick Macklem 		printf("subnet mask ");
14427c208ed6SRick Macklem 		print_sin_addr(&ifctx->netmask);
14437c208ed6SRick Macklem 		printf(" ");
14447c208ed6SRick Macklem 	}
14457c208ed6SRick Macklem 
14467c208ed6SRick Macklem 	p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
14477c208ed6SRick Macklem 		       TAG_ROUTERS);
14487c208ed6SRick Macklem 	if (p != NULL) {
14497c208ed6SRick Macklem 		/* Routers */
14507c208ed6SRick Macklem 		if (gctx->tag.taglen % 4)
14517c208ed6SRick Macklem 			panic("bootpc: Router Len is %d", gctx->tag.taglen);
14527c208ed6SRick Macklem 		if (gctx->tag.taglen > 0) {
14537c208ed6SRick Macklem 			bcopy(p, &ifctx->gw.sin_addr, 4);
14547c208ed6SRick Macklem 			printf("router ");
14557c208ed6SRick Macklem 			print_sin_addr(&ifctx->gw);
14567c208ed6SRick Macklem 			printf(" ");
14577c208ed6SRick Macklem 			ifctx->gotgw = 1;
14587c208ed6SRick Macklem 			gctx->gotgw = 1;
14597c208ed6SRick Macklem 		}
14607c208ed6SRick Macklem 	}
14617c208ed6SRick Macklem 
14626cbd933bSIan Lepore 	/*
14636cbd933bSIan Lepore 	 * Choose a root filesystem.  If a value is forced in the environment
14646cbd933bSIan Lepore 	 * and it contains "nfs:", use it unconditionally.  Otherwise, if the
14656cbd933bSIan Lepore 	 * kernel is compiled with the ROOTDEVNAME option, then use it if:
14666cbd933bSIan Lepore 	 *  - The server doesn't provide a pathname.
14676cbd933bSIan Lepore 	 *  - The boothowto flags include RB_DFLTROOT (user said to override
14686cbd933bSIan Lepore 	 *    the server value).
14696cbd933bSIan Lepore 	 */
14706cbd933bSIan Lepore 	p = NULL;
14712be111bfSDavide Italiano 	if ((s = kern_getenv("vfs.root.mountfrom")) != NULL) {
14726cbd933bSIan Lepore 		if ((p = strstr(s, "nfs:")) != NULL)
14736cbd933bSIan Lepore 			p = strdup(p + 4, M_TEMP);
14746cbd933bSIan Lepore 		freeenv(s);
14756cbd933bSIan Lepore 	}
14766cbd933bSIan Lepore 	if (p == NULL) {
14777c208ed6SRick Macklem 		p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
14787c208ed6SRick Macklem 		       TAG_ROOT);
1479eb2d4f02SIan Lepore 		if (p != NULL)
1480eb2d4f02SIan Lepore 			ifctx->gotrootpath = 1;
14816cbd933bSIan Lepore 	}
14826cbd933bSIan Lepore #ifdef ROOTDEVNAME
14836cbd933bSIan Lepore 	if ((p == NULL || (boothowto & RB_DFLTROOT) != 0) &&
14846cbd933bSIan Lepore 	    (p = strstr(ROOTDEVNAME, "nfs:")) != NULL) {
14856cbd933bSIan Lepore 		p += 4;
14866cbd933bSIan Lepore 	}
14876cbd933bSIan Lepore #endif
14887c208ed6SRick Macklem 	if (p != NULL) {
14897c208ed6SRick Macklem 		if (gctx->setrootfs != NULL) {
14907c208ed6SRick Macklem 			printf("rootfs %s (ignored) ", p);
14917c208ed6SRick Macklem 		} else 	if (setfs(&nd->root_saddr,
14927c208ed6SRick Macklem 				  nd->root_hostnam, p, &ifctx->reply.siaddr)) {
14937c208ed6SRick Macklem 			if (*p == '/') {
14947c208ed6SRick Macklem 				printf("root_server ");
14957c208ed6SRick Macklem 				print_sin_addr(&nd->root_saddr);
14967c208ed6SRick Macklem 				printf(" ");
14977c208ed6SRick Macklem 			}
14987c208ed6SRick Macklem 			printf("rootfs %s ", p);
14997c208ed6SRick Macklem 			gctx->gotrootpath = 1;
15007c208ed6SRick Macklem 			gctx->setrootfs = ifctx;
15017c208ed6SRick Macklem 
15027c208ed6SRick Macklem 			p = bootpc_tag(&gctx->tag, &ifctx->reply,
15037c208ed6SRick Macklem 				       ifctx->replylen,
15047c208ed6SRick Macklem 				       TAG_ROOTOPTS);
15057c208ed6SRick Macklem 			if (p != NULL) {
15067c208ed6SRick Macklem 				mountopts(&nd->root_args, p);
15077c208ed6SRick Macklem 				printf("rootopts %s ", p);
15087c208ed6SRick Macklem 			}
15097c208ed6SRick Macklem 		} else
15107c208ed6SRick Macklem 			panic("Failed to set rootfs to %s", p);
15117c208ed6SRick Macklem 	}
15127c208ed6SRick Macklem 
15137c208ed6SRick Macklem 	p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
15147c208ed6SRick Macklem 		       TAG_HOSTNAME);
15157c208ed6SRick Macklem 	if (p != NULL) {
15167c208ed6SRick Macklem 		if (gctx->tag.taglen >= MAXHOSTNAMELEN)
15177c208ed6SRick Macklem 			panic("bootpc: hostname >= %d bytes",
15187c208ed6SRick Macklem 			      MAXHOSTNAMELEN);
15197c208ed6SRick Macklem 		if (gctx->sethostname != NULL) {
15207c208ed6SRick Macklem 			printf("hostname %s (ignored) ", p);
15217c208ed6SRick Macklem 		} else {
15227c208ed6SRick Macklem 			strcpy(nd->my_hostnam, p);
15237c208ed6SRick Macklem 			mtx_lock(&prison0.pr_mtx);
15247c208ed6SRick Macklem 			strcpy(prison0.pr_hostname, p);
15257c208ed6SRick Macklem 			mtx_unlock(&prison0.pr_mtx);
15267c208ed6SRick Macklem 			printf("hostname %s ", p);
15277c208ed6SRick Macklem 			gctx->sethostname = ifctx;
15287c208ed6SRick Macklem 		}
15297c208ed6SRick Macklem 	}
15307c208ed6SRick Macklem 	p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
15317c208ed6SRick Macklem 			TAG_COOKIE);
15327c208ed6SRick Macklem 	if (p != NULL) {        /* store in a sysctl variable */
15337c208ed6SRick Macklem 		int i, l = sizeof(bootp_cookie) - 1;
15347c208ed6SRick Macklem 		for (i = 0; i < l && p[i] != '\0'; i++)
15357c208ed6SRick Macklem 			bootp_cookie[i] = p[i];
15367c208ed6SRick Macklem 		p[i] = '\0';
15377c208ed6SRick Macklem 	}
15387c208ed6SRick Macklem 
1539a6c14908SIan Lepore 	p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1540a6c14908SIan Lepore 		       TAG_INTF_MTU);
1541a6c14908SIan Lepore 	if (p != NULL) {
1542a6c14908SIan Lepore 		ifctx->mtu = be16dec(p);
1543a6c14908SIan Lepore 	}
15447c208ed6SRick Macklem 
15457c208ed6SRick Macklem 	printf("\n");
15467c208ed6SRick Macklem 
15477c208ed6SRick Macklem 	if (ifctx->gotnetmask == 0) {
15487c208ed6SRick Macklem 		if (IN_CLASSA(ntohl(ifctx->myaddr.sin_addr.s_addr)))
15497c208ed6SRick Macklem 			ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET);
15507c208ed6SRick Macklem 		else if (IN_CLASSB(ntohl(ifctx->myaddr.sin_addr.s_addr)))
15517c208ed6SRick Macklem 			ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET);
15527c208ed6SRick Macklem 		else
15537c208ed6SRick Macklem 			ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET);
15547c208ed6SRick Macklem 	}
15557c208ed6SRick Macklem 	if (ifctx->gotgw == 0) {
15567c208ed6SRick Macklem 		/* Use proxyarp */
15577c208ed6SRick Macklem 		ifctx->gw.sin_addr.s_addr = ifctx->myaddr.sin_addr.s_addr;
15587c208ed6SRick Macklem 	}
15597c208ed6SRick Macklem }
15607c208ed6SRick Macklem 
15617c208ed6SRick Macklem void
15627c208ed6SRick Macklem bootpc_init(void)
15637c208ed6SRick Macklem {
15646bfaa839SGleb Smirnoff 	struct bootpc_ifcontext *ifctx;		/* Interface BOOTP contexts */
15657c208ed6SRick Macklem 	struct bootpc_globalcontext *gctx; 	/* Global BOOTP context */
15667c208ed6SRick Macklem 	struct ifnet *ifp;
15676bfaa839SGleb Smirnoff 	struct sockaddr_dl *sdl;
15686bfaa839SGleb Smirnoff 	struct ifaddr *ifa;
15697c208ed6SRick Macklem 	int error;
15707c208ed6SRick Macklem #ifndef BOOTP_WIRED_TO
15717c208ed6SRick Macklem 	int ifcnt;
15727c208ed6SRick Macklem #endif
15737c208ed6SRick Macklem 	struct nfsv3_diskless *nd;
15747c208ed6SRick Macklem 	struct thread *td;
1575c6fd18e0SOleksandr Tymoshenko 	int timeout;
1576c6fd18e0SOleksandr Tymoshenko 	int delay;
1577c6fd18e0SOleksandr Tymoshenko 
1578c6fd18e0SOleksandr Tymoshenko 	timeout = BOOTP_IFACE_WAIT_TIMEOUT * hz;
1579c6fd18e0SOleksandr Tymoshenko 	delay = hz / 10;
15807c208ed6SRick Macklem 
15817c208ed6SRick Macklem 	nd = &nfsv3_diskless;
15827c208ed6SRick Macklem 	td = curthread;
15837c208ed6SRick Macklem 
15847c208ed6SRick Macklem 	/*
15857c208ed6SRick Macklem 	 * If already filled in, don't touch it here
15867c208ed6SRick Macklem 	 */
15877c208ed6SRick Macklem 	if (nfs_diskless_valid != 0)
15887c208ed6SRick Macklem 		return;
15897c208ed6SRick Macklem 
15907c208ed6SRick Macklem 	gctx = malloc(sizeof(*gctx), M_TEMP, M_WAITOK | M_ZERO);
15916bfaa839SGleb Smirnoff 	STAILQ_INIT(&gctx->interfaces);
15927c208ed6SRick Macklem 	gctx->xid = ~0xFFFF;
15937c208ed6SRick Macklem 	gctx->starttime = time_second;
15947c208ed6SRick Macklem 
15957c208ed6SRick Macklem 	/*
15966cbd933bSIan Lepore 	 * If ROOTDEVNAME is defined or vfs.root.mountfrom is set then we have
15976cbd933bSIan Lepore 	 * root-path overrides that can potentially let us boot even if we don't
15986cbd933bSIan Lepore 	 * get a root path from the server, so we can treat that as a non-error.
15996cbd933bSIan Lepore 	 */
16006cbd933bSIan Lepore #ifdef ROOTDEVNAME
16016cbd933bSIan Lepore 	gctx->any_root_overrides = 1;
16026cbd933bSIan Lepore #else
16036cbd933bSIan Lepore 	gctx->any_root_overrides = testenv("vfs.root.mountfrom");
16046cbd933bSIan Lepore #endif
16056cbd933bSIan Lepore 
16066cbd933bSIan Lepore 	/*
16077c208ed6SRick Macklem 	 * Find a network interface.
16087c208ed6SRick Macklem 	 */
16097c208ed6SRick Macklem 	CURVNET_SET(TD_TO_VNET(td));
16107c208ed6SRick Macklem #ifdef BOOTP_WIRED_TO
16116bfaa839SGleb Smirnoff 	printf("%s: wired to interface '%s'\n", __func__,
16127c208ed6SRick Macklem 	       __XSTRING(BOOTP_WIRED_TO));
16137c208ed6SRick Macklem 	allocifctx(gctx);
16147c208ed6SRick Macklem #else
16157c208ed6SRick Macklem 	/*
16167c208ed6SRick Macklem 	 * Preallocate interface context storage, if another interface
16177c208ed6SRick Macklem 	 * attaches and wins the race, it won't be eligible for bootp.
16187c208ed6SRick Macklem 	 */
16196bfaa839SGleb Smirnoff 	ifcnt = 0;
16207c208ed6SRick Macklem 	IFNET_RLOCK();
16216bfaa839SGleb Smirnoff 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
16227c208ed6SRick Macklem 		if ((ifp->if_flags &
16237c208ed6SRick Macklem 		     (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) !=
16247c208ed6SRick Macklem 		    IFF_BROADCAST)
16257c208ed6SRick Macklem 			continue;
16266bfaa839SGleb Smirnoff 		switch (ifp->if_alloctype) {
16276bfaa839SGleb Smirnoff 			case IFT_ETHER:
16286bfaa839SGleb Smirnoff 			case IFT_FDDI:
16296bfaa839SGleb Smirnoff 			case IFT_ISO88025:
16306bfaa839SGleb Smirnoff 				break;
16316bfaa839SGleb Smirnoff 			default:
16326bfaa839SGleb Smirnoff 				continue;
16336bfaa839SGleb Smirnoff 		}
16347c208ed6SRick Macklem 		ifcnt++;
16357c208ed6SRick Macklem 	}
16367c208ed6SRick Macklem 	IFNET_RUNLOCK();
16377c208ed6SRick Macklem 	if (ifcnt == 0)
16386bfaa839SGleb Smirnoff 		panic("%s: no eligible interfaces", __func__);
16397c208ed6SRick Macklem 	for (; ifcnt > 0; ifcnt--)
16407c208ed6SRick Macklem 		allocifctx(gctx);
16417c208ed6SRick Macklem #endif
16427c208ed6SRick Macklem 
16431d4c5e51SOleksandr Tymoshenko retry:
16446bfaa839SGleb Smirnoff 	ifctx = STAILQ_FIRST(&gctx->interfaces);
16457c208ed6SRick Macklem 	IFNET_RLOCK();
16466bfaa839SGleb Smirnoff 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
16476bfaa839SGleb Smirnoff 		if (ifctx == NULL)
16486bfaa839SGleb Smirnoff 			break;
16497c208ed6SRick Macklem #ifdef BOOTP_WIRED_TO
16506bfaa839SGleb Smirnoff 		if (strcmp(ifp->if_xname, __XSTRING(BOOTP_WIRED_TO)) != 0)
16517c208ed6SRick Macklem 			continue;
16527c208ed6SRick Macklem #else
16537c208ed6SRick Macklem 		if ((ifp->if_flags &
16547c208ed6SRick Macklem 		     (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) !=
16557c208ed6SRick Macklem 		    IFF_BROADCAST)
16567c208ed6SRick Macklem 			continue;
16576bfaa839SGleb Smirnoff 		switch (ifp->if_alloctype) {
16586bfaa839SGleb Smirnoff 			case IFT_ETHER:
16596bfaa839SGleb Smirnoff 			case IFT_FDDI:
16606bfaa839SGleb Smirnoff 			case IFT_ISO88025:
16616bfaa839SGleb Smirnoff 				break;
16626bfaa839SGleb Smirnoff 			default:
16636bfaa839SGleb Smirnoff 				continue;
16646bfaa839SGleb Smirnoff 		}
16657c208ed6SRick Macklem #endif
16666bfaa839SGleb Smirnoff 		strlcpy(ifctx->ireq.ifr_name, ifp->if_xname,
16676bfaa839SGleb Smirnoff 		    sizeof(ifctx->ireq.ifr_name));
16687c208ed6SRick Macklem 		ifctx->ifp = ifp;
16696bfaa839SGleb Smirnoff 
16706bfaa839SGleb Smirnoff 		/* Get HW address */
16716bfaa839SGleb Smirnoff 		sdl = NULL;
16726bfaa839SGleb Smirnoff 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
16736bfaa839SGleb Smirnoff 			if (ifa->ifa_addr->sa_family == AF_LINK) {
16746bfaa839SGleb Smirnoff 				sdl = (struct sockaddr_dl *)ifa->ifa_addr;
16756bfaa839SGleb Smirnoff 				if (sdl->sdl_type == IFT_ETHER)
16766bfaa839SGleb Smirnoff 					break;
16776bfaa839SGleb Smirnoff 			}
16786bfaa839SGleb Smirnoff 		if (sdl == NULL)
16796bfaa839SGleb Smirnoff 			panic("bootpc: Unable to find HW address for %s",
16806bfaa839SGleb Smirnoff 			    ifctx->ireq.ifr_name);
16816bfaa839SGleb Smirnoff 		ifctx->sdl = sdl;
16826bfaa839SGleb Smirnoff 
16836bfaa839SGleb Smirnoff 		ifctx = STAILQ_NEXT(ifctx, next);
16847c208ed6SRick Macklem 	}
16857c208ed6SRick Macklem 	IFNET_RUNLOCK();
16867c208ed6SRick Macklem 	CURVNET_RESTORE();
16877c208ed6SRick Macklem 
16886bfaa839SGleb Smirnoff 	if (STAILQ_EMPTY(&gctx->interfaces) ||
16896bfaa839SGleb Smirnoff 	    STAILQ_FIRST(&gctx->interfaces)->ifp == NULL) {
16901d4c5e51SOleksandr Tymoshenko 		if (timeout > 0) {
16911d4c5e51SOleksandr Tymoshenko 			pause("bootpc", delay);
16921d4c5e51SOleksandr Tymoshenko 			timeout -= delay;
16931d4c5e51SOleksandr Tymoshenko 			goto retry;
16941d4c5e51SOleksandr Tymoshenko 		}
16957c208ed6SRick Macklem #ifdef BOOTP_WIRED_TO
16966bfaa839SGleb Smirnoff 		panic("%s: Could not find interface specified "
16977c208ed6SRick Macklem 		      "by BOOTP_WIRED_TO: "
16986bfaa839SGleb Smirnoff 		      __XSTRING(BOOTP_WIRED_TO), __func__);
16997c208ed6SRick Macklem #else
17006bfaa839SGleb Smirnoff 		panic("%s: no suitable interface", __func__);
17017c208ed6SRick Macklem #endif
17027c208ed6SRick Macklem 	}
17037c208ed6SRick Macklem 
17046bfaa839SGleb Smirnoff 	error = socreate(AF_INET, &bootp_so, SOCK_DGRAM, 0, td->td_ucred, td);
17056bfaa839SGleb Smirnoff 	if (error != 0)
17066bfaa839SGleb Smirnoff 		panic("%s: socreate, error=%d", __func__, error);
17077c208ed6SRick Macklem 
17086bfaa839SGleb Smirnoff 	STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
17096bfaa839SGleb Smirnoff 		bootpc_fakeup_interface(ifctx, td);
17106bfaa839SGleb Smirnoff 
17116bfaa839SGleb Smirnoff 	STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
17126bfaa839SGleb Smirnoff 		bootpc_compose_query(ifctx, td);
17137c208ed6SRick Macklem 
17147c208ed6SRick Macklem 	error = bootpc_call(gctx, td);
17157c208ed6SRick Macklem 	if (error != 0) {
17167c208ed6SRick Macklem 		printf("BOOTP call failed\n");
17177c208ed6SRick Macklem 	}
17187c208ed6SRick Macklem 
17197c208ed6SRick Macklem 	mountopts(&nd->root_args, NULL);
17207c208ed6SRick Macklem 
17216bfaa839SGleb Smirnoff 	STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
17227c208ed6SRick Macklem 		if (bootpc_ifctx_isresolved(ifctx) != 0)
17237c208ed6SRick Macklem 			bootpc_decode_reply(nd, ifctx, gctx);
17247c208ed6SRick Macklem 
17257c208ed6SRick Macklem #ifdef BOOTP_NFSROOT
17266cbd933bSIan Lepore 	if (gctx->gotrootpath == 0 && gctx->any_root_overrides == 0)
17277c208ed6SRick Macklem 		panic("bootpc: No root path offered");
17287c208ed6SRick Macklem #endif
17297c208ed6SRick Macklem 
17306bfaa839SGleb Smirnoff 	STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
17317c208ed6SRick Macklem 		bootpc_adjust_interface(ifctx, gctx, td);
17327c208ed6SRick Macklem 
17336bfaa839SGleb Smirnoff 	soclose(bootp_so);
17347c208ed6SRick Macklem 
17356bfaa839SGleb Smirnoff 	STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
17367c208ed6SRick Macklem 		if (ifctx->gotrootpath != 0)
17377c208ed6SRick Macklem 			break;
17387c208ed6SRick Macklem 	if (ifctx == NULL) {
17396bfaa839SGleb Smirnoff 		STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
17407c208ed6SRick Macklem 			if (bootpc_ifctx_isresolved(ifctx) != 0)
17417c208ed6SRick Macklem 				break;
17427c208ed6SRick Macklem 	}
17437c208ed6SRick Macklem 	if (ifctx == NULL)
17447c208ed6SRick Macklem 		goto out;
17457c208ed6SRick Macklem 
17467c208ed6SRick Macklem 	if (gctx->gotrootpath != 0) {
17477c208ed6SRick Macklem 
17482be111bfSDavide Italiano 		kern_setenv("boot.netif.name", ifctx->ifp->if_xname);
17497c208ed6SRick Macklem 
17507c208ed6SRick Macklem 		error = md_mount(&nd->root_saddr, nd->root_hostnam,
17517c208ed6SRick Macklem 				 nd->root_fh, &nd->root_fhsize,
17527c208ed6SRick Macklem 				 &nd->root_args, td);
17536cbd933bSIan Lepore 		if (error != 0) {
17546cbd933bSIan Lepore 			if (gctx->any_root_overrides == 0)
17556cbd933bSIan Lepore 				panic("nfs_boot: mount root, error=%d", error);
17566cbd933bSIan Lepore 			else
17576cbd933bSIan Lepore 				goto out;
17586cbd933bSIan Lepore 		}
17596cbd933bSIan Lepore 		rootdevnames[0] = "nfs:";
17607c208ed6SRick Macklem 		nfs_diskless_valid = 3;
17617c208ed6SRick Macklem 	}
17627c208ed6SRick Macklem 
17637c208ed6SRick Macklem 	strcpy(nd->myif.ifra_name, ifctx->ireq.ifr_name);
17647c208ed6SRick Macklem 	bcopy(&ifctx->myaddr, &nd->myif.ifra_addr, sizeof(ifctx->myaddr));
17657c208ed6SRick Macklem 	bcopy(&ifctx->myaddr, &nd->myif.ifra_broadaddr, sizeof(ifctx->myaddr));
17667c208ed6SRick Macklem 	((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
17677c208ed6SRick Macklem 		ifctx->myaddr.sin_addr.s_addr |
17687c208ed6SRick Macklem 		~ ifctx->netmask.sin_addr.s_addr;
17697c208ed6SRick Macklem 	bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask));
17707c208ed6SRick Macklem 
17717c208ed6SRick Macklem out:
17726bfaa839SGleb Smirnoff 	while((ifctx = STAILQ_FIRST(&gctx->interfaces)) != NULL) {
17736bfaa839SGleb Smirnoff 		STAILQ_REMOVE_HEAD(&gctx->interfaces, next);
17747c208ed6SRick Macklem 		free(ifctx, M_TEMP);
17757c208ed6SRick Macklem 	}
17767c208ed6SRick Macklem 	free(gctx, M_TEMP);
17777c208ed6SRick Macklem }
17787c208ed6SRick Macklem 
17797c208ed6SRick Macklem /*
17807c208ed6SRick Macklem  * RPC: mountd/mount
17817c208ed6SRick Macklem  * Given a server pathname, get an NFS file handle.
17827c208ed6SRick Macklem  * Also, sets sin->sin_port to the NFS service port.
17837c208ed6SRick Macklem  */
17847c208ed6SRick Macklem static int
17857c208ed6SRick Macklem md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp, int *fhsizep,
17867c208ed6SRick Macklem     struct nfs_args *args, struct thread *td)
17877c208ed6SRick Macklem {
17887c208ed6SRick Macklem 	struct mbuf *m;
17897c208ed6SRick Macklem 	int error;
17907c208ed6SRick Macklem 	int authunixok;
17917c208ed6SRick Macklem 	int authcount;
17927c208ed6SRick Macklem 	int authver;
17937c208ed6SRick Macklem 
17947c208ed6SRick Macklem #define	RPCPROG_MNT	100005
17957c208ed6SRick Macklem #define	RPCMNT_VER1	1
17967c208ed6SRick Macklem #define RPCMNT_VER3	3
17977c208ed6SRick Macklem #define	RPCMNT_MOUNT	1
17987c208ed6SRick Macklem #define	AUTH_SYS	1		/* unix style (uid, gids) */
17997c208ed6SRick Macklem #define AUTH_UNIX	AUTH_SYS
18007c208ed6SRick Macklem 
18017c208ed6SRick Macklem 	/* XXX honor v2/v3 flags in args->flags? */
18027c208ed6SRick Macklem #ifdef BOOTP_NFSV3
18037c208ed6SRick Macklem 	/* First try NFS v3 */
18047c208ed6SRick Macklem 	/* Get port number for MOUNTD. */
18057c208ed6SRick Macklem 	error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
18067c208ed6SRick Macklem 			     &mdsin->sin_port, td);
18077c208ed6SRick Macklem 	if (error == 0) {
18087c208ed6SRick Macklem 		m = xdr_string_encode(path, strlen(path));
18097c208ed6SRick Macklem 
18107c208ed6SRick Macklem 		/* Do RPC to mountd. */
18117c208ed6SRick Macklem 		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
18127c208ed6SRick Macklem 				  RPCMNT_MOUNT, &m, NULL, td);
18137c208ed6SRick Macklem 	}
18147c208ed6SRick Macklem 	if (error == 0) {
18157c208ed6SRick Macklem 		args->flags |= NFSMNT_NFSV3;
18167c208ed6SRick Macklem 	} else {
18177c208ed6SRick Macklem #endif
18187c208ed6SRick Macklem 		/* Fallback to NFS v2 */
18197c208ed6SRick Macklem 
18207c208ed6SRick Macklem 		/* Get port number for MOUNTD. */
18217c208ed6SRick Macklem 		error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
18227c208ed6SRick Macklem 				     &mdsin->sin_port, td);
18237c208ed6SRick Macklem 		if (error != 0)
18247c208ed6SRick Macklem 			return error;
18257c208ed6SRick Macklem 
18267c208ed6SRick Macklem 		m = xdr_string_encode(path, strlen(path));
18277c208ed6SRick Macklem 
18287c208ed6SRick Macklem 		/* Do RPC to mountd. */
18297c208ed6SRick Macklem 		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
18307c208ed6SRick Macklem 				  RPCMNT_MOUNT, &m, NULL, td);
18317c208ed6SRick Macklem 		if (error != 0)
18327c208ed6SRick Macklem 			return error;	/* message already freed */
18337c208ed6SRick Macklem 
18347c208ed6SRick Macklem #ifdef BOOTP_NFSV3
18357c208ed6SRick Macklem 	}
18367c208ed6SRick Macklem #endif
18377c208ed6SRick Macklem 
18387c208ed6SRick Macklem 	if (xdr_int_decode(&m, &error) != 0 || error != 0)
18397c208ed6SRick Macklem 		goto bad;
18407c208ed6SRick Macklem 
18417c208ed6SRick Macklem 	if ((args->flags & NFSMNT_NFSV3) != 0) {
18427c208ed6SRick Macklem 		if (xdr_int_decode(&m, fhsizep) != 0 ||
18437c208ed6SRick Macklem 		    *fhsizep > NFSX_V3FHMAX ||
18447c208ed6SRick Macklem 		    *fhsizep <= 0)
18457c208ed6SRick Macklem 			goto bad;
18467c208ed6SRick Macklem 	} else
18477c208ed6SRick Macklem 		*fhsizep = NFSX_V2FH;
18487c208ed6SRick Macklem 
18497c208ed6SRick Macklem 	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
18507c208ed6SRick Macklem 		goto bad;
18517c208ed6SRick Macklem 
18527c208ed6SRick Macklem 	if (args->flags & NFSMNT_NFSV3) {
18537c208ed6SRick Macklem 		if (xdr_int_decode(&m, &authcount) != 0)
18547c208ed6SRick Macklem 			goto bad;
18557c208ed6SRick Macklem 		authunixok = 0;
18567c208ed6SRick Macklem 		if (authcount < 0 || authcount > 100)
18577c208ed6SRick Macklem 			goto bad;
18587c208ed6SRick Macklem 		while (authcount > 0) {
18597c208ed6SRick Macklem 			if (xdr_int_decode(&m, &authver) != 0)
18607c208ed6SRick Macklem 				goto bad;
18617c208ed6SRick Macklem 			if (authver == AUTH_UNIX)
18627c208ed6SRick Macklem 				authunixok = 1;
18637c208ed6SRick Macklem 			authcount--;
18647c208ed6SRick Macklem 		}
18657c208ed6SRick Macklem 		if (authunixok == 0)
18667c208ed6SRick Macklem 			goto bad;
18677c208ed6SRick Macklem 	}
18687c208ed6SRick Macklem 
18697c208ed6SRick Macklem 	/* Set port number for NFS use. */
18707c208ed6SRick Macklem 	error = krpc_portmap(mdsin, NFS_PROG,
18717c208ed6SRick Macklem 			     (args->flags &
18727c208ed6SRick Macklem 			      NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
18737c208ed6SRick Macklem 			     &mdsin->sin_port, td);
18747c208ed6SRick Macklem 
18757c208ed6SRick Macklem 	goto out;
18767c208ed6SRick Macklem 
18777c208ed6SRick Macklem bad:
18787c208ed6SRick Macklem 	error = EBADRPC;
18797c208ed6SRick Macklem 
18807c208ed6SRick Macklem out:
18817c208ed6SRick Macklem 	m_freem(m);
18827c208ed6SRick Macklem 	return error;
18837c208ed6SRick Macklem }
18847c208ed6SRick Macklem 
18857c208ed6SRick Macklem SYSINIT(bootp_rootconf, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, bootpc_init, NULL);
1886