17c208ed6SRick Macklem /*-
2df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni *
47c208ed6SRick Macklem * Copyright (c) 1995 Gordon Ross, Adam Glass
57c208ed6SRick Macklem * Copyright (c) 1992 Regents of the University of California.
67c208ed6SRick Macklem * All rights reserved.
77c208ed6SRick Macklem *
87c208ed6SRick Macklem * This software was developed by the Computer Systems Engineering group
97c208ed6SRick Macklem * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
107c208ed6SRick Macklem * contributed to Berkeley.
117c208ed6SRick Macklem *
127c208ed6SRick Macklem * Redistribution and use in source and binary forms, with or without
137c208ed6SRick Macklem * modification, are permitted provided that the following conditions
147c208ed6SRick Macklem * are met:
157c208ed6SRick Macklem * 1. Redistributions of source code must retain the above copyright
167c208ed6SRick Macklem * notice, this list of conditions and the following disclaimer.
177c208ed6SRick Macklem * 2. Redistributions in binary form must reproduce the above copyright
187c208ed6SRick Macklem * notice, this list of conditions and the following disclaimer in the
197c208ed6SRick Macklem * documentation and/or other materials provided with the distribution.
207c208ed6SRick Macklem * 3. All advertising materials mentioning features or use of this software
217c208ed6SRick Macklem * must display the following acknowledgement:
227c208ed6SRick Macklem * This product includes software developed by the University of
237c208ed6SRick Macklem * California, Lawrence Berkeley Laboratory and its contributors.
247c208ed6SRick Macklem * 4. Neither the name of the University nor the names of its contributors
257c208ed6SRick Macklem * may be used to endorse or promote products derived from this software
267c208ed6SRick Macklem * without specific prior written permission.
277c208ed6SRick Macklem *
287c208ed6SRick Macklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
297c208ed6SRick Macklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
307c208ed6SRick Macklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
317c208ed6SRick Macklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
327c208ed6SRick Macklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
337c208ed6SRick Macklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
347c208ed6SRick Macklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
357c208ed6SRick Macklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
367c208ed6SRick Macklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
377c208ed6SRick Macklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
387c208ed6SRick Macklem * SUCH DAMAGE.
397c208ed6SRick Macklem *
407c208ed6SRick Macklem * based on:
417c208ed6SRick Macklem * nfs/krpc_subr.c
427c208ed6SRick Macklem * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $
437c208ed6SRick Macklem */
447c208ed6SRick Macklem
452f35e7d9SMike Karels #define IN_HISTORICAL_NETS /* include class masks */
462f35e7d9SMike Karels
477c208ed6SRick Macklem #include <sys/cdefs.h>
487c208ed6SRick Macklem #include "opt_bootp.h"
49acd73f50SGrzegorz Bernacki #include "opt_nfs.h"
506cbd933bSIan Lepore #include "opt_rootdevname.h"
517c208ed6SRick Macklem
527c208ed6SRick Macklem #include <sys/param.h>
537c208ed6SRick Macklem #include <sys/systm.h>
54a6c14908SIan Lepore #include <sys/endian.h>
557c208ed6SRick Macklem #include <sys/jail.h>
567c208ed6SRick Macklem #include <sys/kernel.h>
577c208ed6SRick Macklem #include <sys/sockio.h>
587c208ed6SRick Macklem #include <sys/malloc.h>
597c208ed6SRick Macklem #include <sys/mount.h>
607c208ed6SRick Macklem #include <sys/mbuf.h>
617c208ed6SRick Macklem #include <sys/proc.h>
626cbd933bSIan Lepore #include <sys/reboot.h>
637c208ed6SRick Macklem #include <sys/socket.h>
647c208ed6SRick Macklem #include <sys/socketvar.h>
657c208ed6SRick Macklem #include <sys/sysctl.h>
667c208ed6SRick Macklem #include <sys/uio.h>
677c208ed6SRick Macklem
687c208ed6SRick Macklem #include <net/if.h>
6976039bc8SGleb Smirnoff #include <net/if_var.h>
707c208ed6SRick Macklem #include <net/route.h>
71e1c05fd2SAlexander V. Chernikov #include <net/route/route_ctl.h>
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 #define BOOTP_MIN_LEN 300 /* Minimum size of bootp udp packet */
867c208ed6SRick Macklem
877c208ed6SRick Macklem #ifndef BOOTP_SETTLE_DELAY
887c208ed6SRick Macklem #define BOOTP_SETTLE_DELAY 3
897c208ed6SRick Macklem #endif
907c208ed6SRick Macklem
917c208ed6SRick Macklem /*
921d4c5e51SOleksandr Tymoshenko * Wait 10 seconds for interface appearance
93c6fd18e0SOleksandr Tymoshenko * USB ethernet adapters might require some time to pop up
941d4c5e51SOleksandr Tymoshenko */
951d4c5e51SOleksandr Tymoshenko #ifndef BOOTP_IFACE_WAIT_TIMEOUT
961d4c5e51SOleksandr Tymoshenko #define BOOTP_IFACE_WAIT_TIMEOUT 10
971d4c5e51SOleksandr Tymoshenko #endif
981d4c5e51SOleksandr Tymoshenko
991d4c5e51SOleksandr Tymoshenko /*
1007c208ed6SRick Macklem * What is the longest we will wait before re-sending a request?
1017c208ed6SRick Macklem * Note this is also the frequency of "RPC timeout" messages.
1027c208ed6SRick Macklem * The re-send loop count sup linearly to this maximum, so the
1037c208ed6SRick Macklem * first complaint will happen after (1+2+3+4+5)=15 seconds.
1047c208ed6SRick Macklem */
1057c208ed6SRick Macklem #define MAX_RESEND_DELAY 5 /* seconds */
1067c208ed6SRick Macklem
1077c208ed6SRick Macklem /* Definitions from RFC951 */
1087c208ed6SRick Macklem struct bootp_packet {
1097c208ed6SRick Macklem u_int8_t op;
1107c208ed6SRick Macklem u_int8_t htype;
1117c208ed6SRick Macklem u_int8_t hlen;
1127c208ed6SRick Macklem u_int8_t hops;
1137c208ed6SRick Macklem u_int32_t xid;
1147c208ed6SRick Macklem u_int16_t secs;
1157c208ed6SRick Macklem u_int16_t flags;
1167c208ed6SRick Macklem struct in_addr ciaddr;
1177c208ed6SRick Macklem struct in_addr yiaddr;
1187c208ed6SRick Macklem struct in_addr siaddr;
1197c208ed6SRick Macklem struct in_addr giaddr;
1207c208ed6SRick Macklem unsigned char chaddr[16];
1217c208ed6SRick Macklem char sname[64];
1227c208ed6SRick Macklem char file[128];
1237c208ed6SRick Macklem unsigned char vend[1222];
1247c208ed6SRick Macklem };
1257c208ed6SRick Macklem
1267c208ed6SRick Macklem struct bootpc_ifcontext {
1276bfaa839SGleb Smirnoff STAILQ_ENTRY(bootpc_ifcontext) next;
1287c208ed6SRick Macklem struct bootp_packet call;
1297c208ed6SRick Macklem struct bootp_packet reply;
1307c208ed6SRick Macklem int replylen;
1317c208ed6SRick Macklem int overload;
1326bfaa839SGleb Smirnoff union {
1336bfaa839SGleb Smirnoff struct ifreq _ifreq;
1346bfaa839SGleb Smirnoff struct in_aliasreq _in_alias_req;
1356bfaa839SGleb Smirnoff } _req;
1366bfaa839SGleb Smirnoff #define ireq _req._ifreq
1376bfaa839SGleb Smirnoff #define iareq _req._in_alias_req
138*0785c323SJustin Hibbits if_t ifp;
1397c208ed6SRick Macklem struct sockaddr_dl *sdl;
1407c208ed6SRick Macklem struct sockaddr_in myaddr;
1417c208ed6SRick Macklem struct sockaddr_in netmask;
1427c208ed6SRick Macklem struct sockaddr_in gw;
1437c208ed6SRick Macklem int gotgw;
1447c208ed6SRick Macklem int gotnetmask;
1457c208ed6SRick Macklem int gotrootpath;
1467c208ed6SRick Macklem int outstanding;
1477c208ed6SRick Macklem int sentmsg;
1487c208ed6SRick Macklem u_int32_t xid;
1497c208ed6SRick Macklem enum {
1507c208ed6SRick Macklem IF_BOOTP_UNRESOLVED,
1517c208ed6SRick Macklem IF_BOOTP_RESOLVED,
1527c208ed6SRick Macklem IF_BOOTP_FAILED,
1537c208ed6SRick Macklem IF_DHCP_UNRESOLVED,
1547c208ed6SRick Macklem IF_DHCP_OFFERED,
1557c208ed6SRick Macklem IF_DHCP_RESOLVED,
1567c208ed6SRick Macklem IF_DHCP_FAILED,
1577c208ed6SRick Macklem } state;
1587c208ed6SRick Macklem int dhcpquerytype; /* dhcp type sent */
1597c208ed6SRick Macklem struct in_addr dhcpserver;
1607c208ed6SRick Macklem int gotdhcpserver;
161a6c14908SIan Lepore uint16_t mtu;
1627c208ed6SRick Macklem };
1637c208ed6SRick Macklem
1647c208ed6SRick Macklem #define TAG_MAXLEN 1024
1657c208ed6SRick Macklem struct bootpc_tagcontext {
1667c208ed6SRick Macklem char buf[TAG_MAXLEN + 1];
1677c208ed6SRick Macklem int overload;
1687c208ed6SRick Macklem int badopt;
1697c208ed6SRick Macklem int badtag;
1707c208ed6SRick Macklem int foundopt;
1717c208ed6SRick Macklem int taglen;
1727c208ed6SRick Macklem };
1737c208ed6SRick Macklem
1747c208ed6SRick Macklem struct bootpc_globalcontext {
1756bfaa839SGleb Smirnoff STAILQ_HEAD(, bootpc_ifcontext) interfaces;
1767c208ed6SRick Macklem u_int32_t xid;
1776cbd933bSIan Lepore int any_root_overrides;
1787c208ed6SRick Macklem int gotrootpath;
1797c208ed6SRick Macklem int gotgw;
1807c208ed6SRick Macklem int ifnum;
1817c208ed6SRick Macklem int secs;
1827c208ed6SRick Macklem int starttime;
1837c208ed6SRick Macklem struct bootp_packet reply;
1847c208ed6SRick Macklem int replylen;
1857c208ed6SRick Macklem struct bootpc_ifcontext *setrootfs;
1867c208ed6SRick Macklem struct bootpc_ifcontext *sethostname;
1877c208ed6SRick Macklem struct bootpc_tagcontext tmptag;
1887c208ed6SRick Macklem struct bootpc_tagcontext tag;
1897c208ed6SRick Macklem };
1907c208ed6SRick Macklem
1917c208ed6SRick Macklem #define IPPORT_BOOTPC 68
1927c208ed6SRick Macklem #define IPPORT_BOOTPS 67
1937c208ed6SRick Macklem
1947c208ed6SRick Macklem #define BOOTP_REQUEST 1
1957c208ed6SRick Macklem #define BOOTP_REPLY 2
1967c208ed6SRick Macklem
1977c208ed6SRick Macklem /* Common tags */
1987c208ed6SRick Macklem #define TAG_PAD 0 /* Pad option, implicit length 1 */
1997c208ed6SRick Macklem #define TAG_SUBNETMASK 1 /* RFC 950 subnet mask */
2007c208ed6SRick Macklem #define TAG_ROUTERS 3 /* Routers (in order of preference) */
2017c208ed6SRick Macklem #define TAG_HOSTNAME 12 /* Client host name */
2027c208ed6SRick Macklem #define TAG_ROOT 17 /* Root path */
203a6c14908SIan Lepore #define TAG_INTF_MTU 26 /* Interface MTU Size (RFC2132) */
2047c208ed6SRick Macklem
2057c208ed6SRick Macklem /* DHCP specific tags */
2067c208ed6SRick Macklem #define TAG_OVERLOAD 52 /* Option Overload */
2077c208ed6SRick Macklem #define TAG_MAXMSGSIZE 57 /* Maximum DHCP Message Size */
2087c208ed6SRick Macklem
2097c208ed6SRick Macklem #define TAG_END 255 /* End Option (i.e. no more options) */
2107c208ed6SRick Macklem
2117c208ed6SRick Macklem /* Overload values */
2127c208ed6SRick Macklem #define OVERLOAD_FILE 1
2137c208ed6SRick Macklem #define OVERLOAD_SNAME 2
2147c208ed6SRick Macklem
2157c208ed6SRick Macklem /* Site specific tags: */
2167c208ed6SRick Macklem #define TAG_ROOTOPTS 130
2177c208ed6SRick Macklem #define TAG_COOKIE 134 /* ascii info for userland, via sysctl */
2187c208ed6SRick Macklem
2197c208ed6SRick Macklem #define TAG_DHCP_MSGTYPE 53
2207c208ed6SRick Macklem #define TAG_DHCP_REQ_ADDR 50
2217c208ed6SRick Macklem #define TAG_DHCP_SERVERID 54
2227c208ed6SRick Macklem #define TAG_DHCP_LEASETIME 51
2237c208ed6SRick Macklem
2247c208ed6SRick Macklem #define TAG_VENDOR_INDENTIFIER 60
2257c208ed6SRick Macklem
2267c208ed6SRick Macklem #define DHCP_NOMSG 0
2277c208ed6SRick Macklem #define DHCP_DISCOVER 1
2287c208ed6SRick Macklem #define DHCP_OFFER 2
2297c208ed6SRick Macklem #define DHCP_REQUEST 3
2307c208ed6SRick Macklem #define DHCP_ACK 5
2317c208ed6SRick Macklem
2327c208ed6SRick Macklem /* NFS read/write block size */
2337c208ed6SRick Macklem #ifndef BOOTP_BLOCKSIZE
2347c208ed6SRick Macklem #define BOOTP_BLOCKSIZE 8192
2357c208ed6SRick Macklem #endif
2367c208ed6SRick Macklem
2377c208ed6SRick Macklem static char bootp_cookie[128];
2386bfaa839SGleb Smirnoff static struct socket *bootp_so;
2397c208ed6SRick Macklem SYSCTL_STRING(_kern, OID_AUTO, bootp_cookie, CTLFLAG_RD,
2407c208ed6SRick Macklem bootp_cookie, 0, "Cookie (T134) supplied by bootp server");
2417c208ed6SRick Macklem
2427c208ed6SRick Macklem /* mountd RPC */
2437c208ed6SRick Macklem static int md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp,
2447c208ed6SRick Macklem int *fhsizep, struct nfs_args *args, struct thread *td);
2457c208ed6SRick Macklem static int setfs(struct sockaddr_in *addr, char *path, char *p,
2467c208ed6SRick Macklem const struct in_addr *siaddr);
2477c208ed6SRick Macklem static int getdec(char **ptr);
2487c208ed6SRick Macklem static int getip(char **ptr, struct in_addr *ip);
2497c208ed6SRick Macklem static void mountopts(struct nfs_args *args, char *p);
2507c208ed6SRick Macklem static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len);
2517c208ed6SRick Macklem static int xdr_int_decode(struct mbuf **ptr, int *iptr);
2527c208ed6SRick Macklem static void print_in_addr(struct in_addr addr);
2537c208ed6SRick Macklem static void print_sin_addr(struct sockaddr_in *addr);
2547c208ed6SRick Macklem static void clear_sinaddr(struct sockaddr_in *sin);
2557c208ed6SRick Macklem static void allocifctx(struct bootpc_globalcontext *gctx);
2567c208ed6SRick Macklem static void bootpc_compose_query(struct bootpc_ifcontext *ifctx,
2576bfaa839SGleb Smirnoff struct thread *td);
2587c208ed6SRick Macklem static unsigned char *bootpc_tag(struct bootpc_tagcontext *tctx,
2597c208ed6SRick Macklem struct bootp_packet *bp, int len, int tag);
2607c208ed6SRick Macklem static void bootpc_tag_helper(struct bootpc_tagcontext *tctx,
2617c208ed6SRick Macklem unsigned char *start, int len, int tag);
2627c208ed6SRick Macklem
2637c208ed6SRick Macklem #ifdef BOOTP_DEBUG
2647c208ed6SRick Macklem void bootpboot_p_iflist(void);
2657c208ed6SRick Macklem #endif
2667c208ed6SRick Macklem
2677c208ed6SRick Macklem static int bootpc_call(struct bootpc_globalcontext *gctx,
2687c208ed6SRick Macklem struct thread *td);
2697c208ed6SRick Macklem
2706bfaa839SGleb Smirnoff static void bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
2716bfaa839SGleb Smirnoff struct thread *td);
2727c208ed6SRick Macklem
273d32d350eSIan Lepore static void bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
2747c208ed6SRick Macklem struct bootpc_globalcontext *gctx, struct thread *td);
2757c208ed6SRick Macklem
2767c208ed6SRick Macklem static void bootpc_decode_reply(struct nfsv3_diskless *nd,
2777c208ed6SRick Macklem struct bootpc_ifcontext *ifctx,
2787c208ed6SRick Macklem struct bootpc_globalcontext *gctx);
2797c208ed6SRick Macklem
2807c208ed6SRick Macklem static int bootpc_received(struct bootpc_globalcontext *gctx,
2817c208ed6SRick Macklem struct bootpc_ifcontext *ifctx);
2827c208ed6SRick Macklem
2837c208ed6SRick Macklem static __inline int bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx);
2847c208ed6SRick Macklem static __inline int bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx);
2857c208ed6SRick Macklem static __inline int bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx);
2867c208ed6SRick Macklem
2877c208ed6SRick Macklem /*
2887c208ed6SRick Macklem * In order to have multiple active interfaces with address 0.0.0.0
2896bfaa839SGleb Smirnoff * and be able to send data to a selected interface, we first set
2906bfaa839SGleb Smirnoff * mask to /8 on all interfaces, and temporarily set it to /0 when
2916bfaa839SGleb Smirnoff * doing sosend().
2927c208ed6SRick Macklem */
2937c208ed6SRick Macklem
2947c208ed6SRick Macklem #ifdef BOOTP_DEBUG
295*0785c323SJustin Hibbits static u_int
bootpboot_p_ifa(void * ifp,struct ifaddr * ifa,u_int count __unused)296*0785c323SJustin Hibbits bootpboot_p_ifa(void *ifp, struct ifaddr *ifa, u_int count __unused)
2977c208ed6SRick Macklem {
2987c208ed6SRick Macklem
2997c208ed6SRick Macklem printf("%s flags %x, addr ",
300*0785c323SJustin Hibbits if_name(ifp), if_getflags(ifp));
3017c208ed6SRick Macklem print_sin_addr((struct sockaddr_in *) ifa->ifa_addr);
3027c208ed6SRick Macklem printf(", broadcast ");
3037c208ed6SRick Macklem print_sin_addr((struct sockaddr_in *) ifa->ifa_dstaddr);
3047c208ed6SRick Macklem printf(", netmask ");
3057c208ed6SRick Macklem print_sin_addr((struct sockaddr_in *) ifa->ifa_netmask);
3067c208ed6SRick Macklem printf("\n");
307*0785c323SJustin Hibbits
308*0785c323SJustin Hibbits return (0);
3097c208ed6SRick Macklem }
3107c208ed6SRick Macklem
3117c208ed6SRick Macklem void
bootpboot_p_iflist(void)3127c208ed6SRick Macklem bootpboot_p_iflist(void)
3137c208ed6SRick Macklem {
314*0785c323SJustin Hibbits struct epoch_tracker et;
315*0785c323SJustin Hibbits struct if_iter iter;
316*0785c323SJustin Hibbits if_t ifp;
3177c208ed6SRick Macklem
3187c208ed6SRick Macklem printf("Interface list:\n");
319*0785c323SJustin Hibbits NET_EPOCH_ENTER(et);
320*0785c323SJustin Hibbits for (ifp = if_iter_start(&iter); ifp != NULL; ifp = if_iter_next(&iter))
321*0785c323SJustin Hibbits if_foreach_addr_type(ifp, AF_INET, bootpboot_p_ifa, ifp);
322*0785c323SJustin Hibbits if_iter_finish(&iter);
323*0785c323SJustin Hibbits NET_EPOCH_EXIT(et);
3247c208ed6SRick Macklem }
3257c208ed6SRick Macklem #endif /* defined(BOOTP_DEBUG) */
3267c208ed6SRick Macklem
3277c208ed6SRick Macklem static void
clear_sinaddr(struct sockaddr_in * sin)3287c208ed6SRick Macklem clear_sinaddr(struct sockaddr_in *sin)
3297c208ed6SRick Macklem {
3307c208ed6SRick Macklem
3317c208ed6SRick Macklem bzero(sin, sizeof(*sin));
3327c208ed6SRick Macklem sin->sin_len = sizeof(*sin);
3337c208ed6SRick Macklem sin->sin_family = AF_INET;
3347c208ed6SRick Macklem sin->sin_addr.s_addr = INADDR_ANY; /* XXX: htonl(INAADDR_ANY) ? */
3357c208ed6SRick Macklem sin->sin_port = 0;
3367c208ed6SRick Macklem }
3377c208ed6SRick Macklem
3387c208ed6SRick Macklem static void
allocifctx(struct bootpc_globalcontext * gctx)3397c208ed6SRick Macklem allocifctx(struct bootpc_globalcontext *gctx)
3407c208ed6SRick Macklem {
3417c208ed6SRick Macklem struct bootpc_ifcontext *ifctx;
3427c208ed6SRick Macklem
3436bfaa839SGleb Smirnoff ifctx = malloc(sizeof(*ifctx), M_TEMP, M_WAITOK | M_ZERO);
3447c208ed6SRick Macklem ifctx->xid = gctx->xid;
3457c208ed6SRick Macklem #ifdef BOOTP_NO_DHCP
3467c208ed6SRick Macklem ifctx->state = IF_BOOTP_UNRESOLVED;
3477c208ed6SRick Macklem #else
3487c208ed6SRick Macklem ifctx->state = IF_DHCP_UNRESOLVED;
3497c208ed6SRick Macklem #endif
3507c208ed6SRick Macklem gctx->xid += 0x100;
3516bfaa839SGleb Smirnoff STAILQ_INSERT_TAIL(&gctx->interfaces, ifctx, next);
3527c208ed6SRick Macklem }
3537c208ed6SRick Macklem
3547c208ed6SRick Macklem static __inline int
bootpc_ifctx_isresolved(struct bootpc_ifcontext * ifctx)3557c208ed6SRick Macklem bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx)
3567c208ed6SRick Macklem {
3577c208ed6SRick Macklem
3587c208ed6SRick Macklem if (ifctx->state == IF_BOOTP_RESOLVED ||
3597c208ed6SRick Macklem ifctx->state == IF_DHCP_RESOLVED)
3607c208ed6SRick Macklem return 1;
3617c208ed6SRick Macklem return 0;
3627c208ed6SRick Macklem }
3637c208ed6SRick Macklem
3647c208ed6SRick Macklem static __inline int
bootpc_ifctx_isunresolved(struct bootpc_ifcontext * ifctx)3657c208ed6SRick Macklem bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx)
3667c208ed6SRick Macklem {
3677c208ed6SRick Macklem
3687c208ed6SRick Macklem if (ifctx->state == IF_BOOTP_UNRESOLVED ||
3697c208ed6SRick Macklem ifctx->state == IF_DHCP_UNRESOLVED)
3707c208ed6SRick Macklem return 1;
3717c208ed6SRick Macklem return 0;
3727c208ed6SRick Macklem }
3737c208ed6SRick Macklem
3747c208ed6SRick Macklem static __inline int
bootpc_ifctx_isfailed(struct bootpc_ifcontext * ifctx)3757c208ed6SRick Macklem bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx)
3767c208ed6SRick Macklem {
3777c208ed6SRick Macklem
3787c208ed6SRick Macklem if (ifctx->state == IF_BOOTP_FAILED ||
3797c208ed6SRick Macklem ifctx->state == IF_DHCP_FAILED)
3807c208ed6SRick Macklem return 1;
3817c208ed6SRick Macklem return 0;
3827c208ed6SRick Macklem }
3837c208ed6SRick Macklem
3847c208ed6SRick Macklem static int
bootpc_received(struct bootpc_globalcontext * gctx,struct bootpc_ifcontext * ifctx)3857c208ed6SRick Macklem bootpc_received(struct bootpc_globalcontext *gctx,
3867c208ed6SRick Macklem struct bootpc_ifcontext *ifctx)
3877c208ed6SRick Macklem {
3887c208ed6SRick Macklem unsigned char dhcpreplytype;
3897c208ed6SRick Macklem char *p;
3907c208ed6SRick Macklem
3917c208ed6SRick Macklem /*
3927c208ed6SRick Macklem * Need timeout for fallback to less
3937c208ed6SRick Macklem * desirable alternative.
3947c208ed6SRick Macklem */
3957c208ed6SRick Macklem
3967c208ed6SRick Macklem /* This call used for the side effect (badopt flag) */
3977c208ed6SRick Macklem (void) bootpc_tag(&gctx->tmptag, &gctx->reply,
3987c208ed6SRick Macklem gctx->replylen,
3997c208ed6SRick Macklem TAG_END);
4007c208ed6SRick Macklem
4017c208ed6SRick Macklem /* If packet is invalid, ignore it */
4027c208ed6SRick Macklem if (gctx->tmptag.badopt != 0)
4037c208ed6SRick Macklem return 0;
4047c208ed6SRick Macklem
4057c208ed6SRick Macklem p = bootpc_tag(&gctx->tmptag, &gctx->reply,
4067c208ed6SRick Macklem gctx->replylen, TAG_DHCP_MSGTYPE);
4077c208ed6SRick Macklem if (p != NULL)
4087c208ed6SRick Macklem dhcpreplytype = *p;
4097c208ed6SRick Macklem else
4107c208ed6SRick Macklem dhcpreplytype = DHCP_NOMSG;
4117c208ed6SRick Macklem
4127c208ed6SRick Macklem switch (ifctx->dhcpquerytype) {
4137c208ed6SRick Macklem case DHCP_DISCOVER:
4147c208ed6SRick Macklem if (dhcpreplytype != DHCP_OFFER /* Normal DHCP offer */
4157c208ed6SRick Macklem #ifndef BOOTP_FORCE_DHCP
4167c208ed6SRick Macklem && dhcpreplytype != DHCP_NOMSG /* Fallback to BOOTP */
4177c208ed6SRick Macklem #endif
4187c208ed6SRick Macklem )
4197c208ed6SRick Macklem return 0;
4207c208ed6SRick Macklem break;
4217c208ed6SRick Macklem case DHCP_REQUEST:
4227c208ed6SRick Macklem if (dhcpreplytype != DHCP_ACK)
4237c208ed6SRick Macklem return 0;
4247c208ed6SRick Macklem case DHCP_NOMSG:
4257c208ed6SRick Macklem break;
4267c208ed6SRick Macklem }
4277c208ed6SRick Macklem
4287c208ed6SRick Macklem /* Ignore packet unless it gives us a root tag we didn't have */
4297c208ed6SRick Macklem
4307c208ed6SRick Macklem if ((ifctx->state == IF_BOOTP_RESOLVED ||
4317c208ed6SRick Macklem (ifctx->dhcpquerytype == DHCP_DISCOVER &&
4327c208ed6SRick Macklem (ifctx->state == IF_DHCP_OFFERED ||
4337c208ed6SRick Macklem ifctx->state == IF_DHCP_RESOLVED))) &&
4347c208ed6SRick Macklem (bootpc_tag(&gctx->tmptag, &ifctx->reply,
4357c208ed6SRick Macklem ifctx->replylen,
4367c208ed6SRick Macklem TAG_ROOT) != NULL ||
4377c208ed6SRick Macklem bootpc_tag(&gctx->tmptag, &gctx->reply,
4387c208ed6SRick Macklem gctx->replylen,
4397c208ed6SRick Macklem TAG_ROOT) == NULL))
4407c208ed6SRick Macklem return 0;
4417c208ed6SRick Macklem
4427c208ed6SRick Macklem bcopy(&gctx->reply, &ifctx->reply, gctx->replylen);
4437c208ed6SRick Macklem ifctx->replylen = gctx->replylen;
4447c208ed6SRick Macklem
4457c208ed6SRick Macklem /* XXX: Only reset if 'perfect' response */
4467c208ed6SRick Macklem if (ifctx->state == IF_BOOTP_UNRESOLVED)
4477c208ed6SRick Macklem ifctx->state = IF_BOOTP_RESOLVED;
4487c208ed6SRick Macklem else if (ifctx->state == IF_DHCP_UNRESOLVED &&
4497c208ed6SRick Macklem ifctx->dhcpquerytype == DHCP_DISCOVER) {
4507c208ed6SRick Macklem if (dhcpreplytype == DHCP_OFFER)
4517c208ed6SRick Macklem ifctx->state = IF_DHCP_OFFERED;
4527c208ed6SRick Macklem else
4537c208ed6SRick Macklem ifctx->state = IF_BOOTP_RESOLVED; /* Fallback */
4547c208ed6SRick Macklem } else if (ifctx->state == IF_DHCP_OFFERED &&
4557c208ed6SRick Macklem ifctx->dhcpquerytype == DHCP_REQUEST)
4567c208ed6SRick Macklem ifctx->state = IF_DHCP_RESOLVED;
4577c208ed6SRick Macklem
4587c208ed6SRick Macklem if (ifctx->dhcpquerytype == DHCP_DISCOVER &&
4597c208ed6SRick Macklem ifctx->state != IF_BOOTP_RESOLVED) {
4607c208ed6SRick Macklem p = bootpc_tag(&gctx->tmptag, &ifctx->reply,
4617c208ed6SRick Macklem ifctx->replylen, TAG_DHCP_SERVERID);
4627c208ed6SRick Macklem if (p != NULL && gctx->tmptag.taglen == 4) {
4637c208ed6SRick Macklem memcpy(&ifctx->dhcpserver, p, 4);
4647c208ed6SRick Macklem ifctx->gotdhcpserver = 1;
4657c208ed6SRick Macklem } else
4667c208ed6SRick Macklem ifctx->gotdhcpserver = 0;
4677c208ed6SRick Macklem return 1;
4687c208ed6SRick Macklem }
4697c208ed6SRick Macklem
4707c208ed6SRick Macklem ifctx->gotrootpath = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
4717c208ed6SRick Macklem ifctx->replylen,
4727c208ed6SRick Macklem TAG_ROOT) != NULL);
4737c208ed6SRick Macklem ifctx->gotgw = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
4747c208ed6SRick Macklem ifctx->replylen,
4757c208ed6SRick Macklem TAG_ROUTERS) != NULL);
4767c208ed6SRick Macklem ifctx->gotnetmask = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
4777c208ed6SRick Macklem ifctx->replylen,
4787c208ed6SRick Macklem TAG_SUBNETMASK) != NULL);
4797c208ed6SRick Macklem return 1;
4807c208ed6SRick Macklem }
4817c208ed6SRick Macklem
4827c208ed6SRick Macklem static int
bootpc_call(struct bootpc_globalcontext * gctx,struct thread * td)4837c208ed6SRick Macklem bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
4847c208ed6SRick Macklem {
4857c208ed6SRick Macklem struct sockaddr_in *sin, dst;
4867c208ed6SRick Macklem struct uio auio;
4877c208ed6SRick Macklem struct sockopt sopt;
4887c208ed6SRick Macklem struct iovec aio;
4897c208ed6SRick Macklem int error, on, rcvflg, timo, len;
4907c208ed6SRick Macklem time_t atimo;
4917c208ed6SRick Macklem time_t rtimo;
4927c208ed6SRick Macklem struct timeval tv;
4937c208ed6SRick Macklem struct bootpc_ifcontext *ifctx;
4947c208ed6SRick Macklem int outstanding;
4957c208ed6SRick Macklem int gotrootpath;
4967c208ed6SRick Macklem int retry;
4977c208ed6SRick Macklem const char *s;
4987c208ed6SRick Macklem
4997c208ed6SRick Macklem tv.tv_sec = 1;
5007c208ed6SRick Macklem tv.tv_usec = 0;
5017c208ed6SRick Macklem bzero(&sopt, sizeof(sopt));
5027c208ed6SRick Macklem sopt.sopt_dir = SOPT_SET;
5037c208ed6SRick Macklem sopt.sopt_level = SOL_SOCKET;
5047c208ed6SRick Macklem sopt.sopt_name = SO_RCVTIMEO;
5057c208ed6SRick Macklem sopt.sopt_val = &tv;
5067c208ed6SRick Macklem sopt.sopt_valsize = sizeof tv;
5077c208ed6SRick Macklem
5086bfaa839SGleb Smirnoff error = sosetopt(bootp_so, &sopt);
5097c208ed6SRick Macklem if (error != 0)
5107c208ed6SRick Macklem goto out;
5117c208ed6SRick Macklem
5127c208ed6SRick Macklem /*
5137c208ed6SRick Macklem * Enable broadcast.
5147c208ed6SRick Macklem */
5157c208ed6SRick Macklem on = 1;
5167c208ed6SRick Macklem sopt.sopt_name = SO_BROADCAST;
5177c208ed6SRick Macklem sopt.sopt_val = &on;
5187c208ed6SRick Macklem sopt.sopt_valsize = sizeof on;
5197c208ed6SRick Macklem
5206bfaa839SGleb Smirnoff error = sosetopt(bootp_so, &sopt);
5217c208ed6SRick Macklem if (error != 0)
5227c208ed6SRick Macklem goto out;
5237c208ed6SRick Macklem
5247c208ed6SRick Macklem /*
5257c208ed6SRick Macklem * Disable routing.
5267c208ed6SRick Macklem */
5277c208ed6SRick Macklem
5287c208ed6SRick Macklem on = 1;
5297c208ed6SRick Macklem sopt.sopt_name = SO_DONTROUTE;
5307c208ed6SRick Macklem sopt.sopt_val = &on;
5317c208ed6SRick Macklem sopt.sopt_valsize = sizeof on;
5327c208ed6SRick Macklem
5336bfaa839SGleb Smirnoff error = sosetopt(bootp_so, &sopt);
5347c208ed6SRick Macklem if (error != 0)
5357c208ed6SRick Macklem goto out;
5367c208ed6SRick Macklem
5377c208ed6SRick Macklem /*
5387c208ed6SRick Macklem * Bind the local endpoint to a bootp client port.
5397c208ed6SRick Macklem */
5407c208ed6SRick Macklem sin = &dst;
5417c208ed6SRick Macklem clear_sinaddr(sin);
5427c208ed6SRick Macklem sin->sin_port = htons(IPPORT_BOOTPC);
5436bfaa839SGleb Smirnoff error = sobind(bootp_so, (struct sockaddr *)sin, td);
5447c208ed6SRick Macklem if (error != 0) {
5457c208ed6SRick Macklem printf("bind failed\n");
5467c208ed6SRick Macklem goto out;
5477c208ed6SRick Macklem }
5487c208ed6SRick Macklem
5497c208ed6SRick Macklem /*
5507c208ed6SRick Macklem * Setup socket address for the server.
5517c208ed6SRick Macklem */
5527c208ed6SRick Macklem sin = &dst;
5537c208ed6SRick Macklem clear_sinaddr(sin);
5547c208ed6SRick Macklem sin->sin_addr.s_addr = INADDR_BROADCAST;
5557c208ed6SRick Macklem sin->sin_port = htons(IPPORT_BOOTPS);
5567c208ed6SRick Macklem
5577c208ed6SRick Macklem /*
5587c208ed6SRick Macklem * Send it, repeatedly, until a reply is received,
5597c208ed6SRick Macklem * but delay each re-send by an increasing amount.
5607c208ed6SRick Macklem * If the delay hits the maximum, start complaining.
5617c208ed6SRick Macklem */
5627c208ed6SRick Macklem timo = 0;
5637c208ed6SRick Macklem rtimo = 0;
5647c208ed6SRick Macklem for (;;) {
5657c208ed6SRick Macklem outstanding = 0;
5667c208ed6SRick Macklem gotrootpath = 0;
5677c208ed6SRick Macklem
5686bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) {
5697c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) != 0 &&
5707c208ed6SRick Macklem bootpc_tag(&gctx->tmptag, &ifctx->reply,
5717c208ed6SRick Macklem ifctx->replylen,
5727c208ed6SRick Macklem TAG_ROOT) != NULL)
5737c208ed6SRick Macklem gotrootpath = 1;
5747c208ed6SRick Macklem }
5757c208ed6SRick Macklem
5766bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) {
5776bfaa839SGleb Smirnoff struct in_aliasreq *ifra = &ifctx->iareq;
5786bfaa839SGleb Smirnoff sin = (struct sockaddr_in *)&ifra->ifra_mask;
5796bfaa839SGleb Smirnoff
5807c208ed6SRick Macklem ifctx->outstanding = 0;
5817c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) != 0 &&
5827c208ed6SRick Macklem gotrootpath != 0) {
5837c208ed6SRick Macklem continue;
5847c208ed6SRick Macklem }
5857c208ed6SRick Macklem if (bootpc_ifctx_isfailed(ifctx) != 0)
5867c208ed6SRick Macklem continue;
5877c208ed6SRick Macklem
5887c208ed6SRick Macklem outstanding++;
5897c208ed6SRick Macklem ifctx->outstanding = 1;
5907c208ed6SRick Macklem
5917c208ed6SRick Macklem /* Proceed to next step in DHCP negotiation */
5927c208ed6SRick Macklem if ((ifctx->state == IF_DHCP_OFFERED &&
5937c208ed6SRick Macklem ifctx->dhcpquerytype != DHCP_REQUEST) ||
5947c208ed6SRick Macklem (ifctx->state == IF_DHCP_UNRESOLVED &&
5957c208ed6SRick Macklem ifctx->dhcpquerytype != DHCP_DISCOVER) ||
5967c208ed6SRick Macklem (ifctx->state == IF_BOOTP_UNRESOLVED &&
5977c208ed6SRick Macklem ifctx->dhcpquerytype != DHCP_NOMSG)) {
5987c208ed6SRick Macklem ifctx->sentmsg = 0;
5996bfaa839SGleb Smirnoff bootpc_compose_query(ifctx, td);
6007c208ed6SRick Macklem }
6017c208ed6SRick Macklem
6027c208ed6SRick Macklem /* Send BOOTP request (or re-send). */
6037c208ed6SRick Macklem
6047c208ed6SRick Macklem if (ifctx->sentmsg == 0) {
6057c208ed6SRick Macklem switch(ifctx->dhcpquerytype) {
6067c208ed6SRick Macklem case DHCP_DISCOVER:
6077c208ed6SRick Macklem s = "DHCP Discover";
6087c208ed6SRick Macklem break;
6097c208ed6SRick Macklem case DHCP_REQUEST:
6107c208ed6SRick Macklem s = "DHCP Request";
6117c208ed6SRick Macklem break;
6127c208ed6SRick Macklem case DHCP_NOMSG:
6137c208ed6SRick Macklem default:
6147c208ed6SRick Macklem s = "BOOTP Query";
6157c208ed6SRick Macklem break;
6167c208ed6SRick Macklem }
6177c208ed6SRick Macklem printf("Sending %s packet from "
6187c208ed6SRick Macklem "interface %s (%*D)\n",
6197c208ed6SRick Macklem s,
6207c208ed6SRick Macklem ifctx->ireq.ifr_name,
6217c208ed6SRick Macklem ifctx->sdl->sdl_alen,
6227c208ed6SRick Macklem (unsigned char *) LLADDR(ifctx->sdl),
6237c208ed6SRick Macklem ":");
6247c208ed6SRick Macklem ifctx->sentmsg = 1;
6257c208ed6SRick Macklem }
6267c208ed6SRick Macklem
6277c208ed6SRick Macklem aio.iov_base = (caddr_t) &ifctx->call;
6287c208ed6SRick Macklem aio.iov_len = sizeof(ifctx->call);
6297c208ed6SRick Macklem
6307c208ed6SRick Macklem auio.uio_iov = &aio;
6317c208ed6SRick Macklem auio.uio_iovcnt = 1;
6327c208ed6SRick Macklem auio.uio_segflg = UIO_SYSSPACE;
6337c208ed6SRick Macklem auio.uio_rw = UIO_WRITE;
6347c208ed6SRick Macklem auio.uio_offset = 0;
6357c208ed6SRick Macklem auio.uio_resid = sizeof(ifctx->call);
6367c208ed6SRick Macklem auio.uio_td = td;
6377c208ed6SRick Macklem
6387c208ed6SRick Macklem /* Set netmask to 0.0.0.0 */
6397c208ed6SRick Macklem clear_sinaddr(sin);
6406bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra,
6416bfaa839SGleb Smirnoff td);
6427c208ed6SRick Macklem if (error != 0)
6436bfaa839SGleb Smirnoff panic("%s: SIOCAIFADDR, error=%d", __func__,
6447c208ed6SRick Macklem error);
6457c208ed6SRick Macklem
6466bfaa839SGleb Smirnoff error = sosend(bootp_so, (struct sockaddr *) &dst,
6477c208ed6SRick Macklem &auio, NULL, NULL, 0, td);
6486bfaa839SGleb Smirnoff if (error != 0)
6496bfaa839SGleb Smirnoff printf("%s: sosend: %d state %08x\n", __func__,
6506bfaa839SGleb Smirnoff error, (int )bootp_so->so_state);
6517c208ed6SRick Macklem
6527c208ed6SRick Macklem /* Set netmask to 255.0.0.0 */
65320d59403SMike Karels sin->sin_addr.s_addr = htonl(0xff000000);
6546bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra,
6556bfaa839SGleb Smirnoff td);
6567c208ed6SRick Macklem if (error != 0)
6576bfaa839SGleb Smirnoff panic("%s: SIOCAIFADDR, error=%d", __func__,
6587c208ed6SRick Macklem error);
6597c208ed6SRick Macklem }
6607c208ed6SRick Macklem
6617c208ed6SRick Macklem if (outstanding == 0 &&
6627c208ed6SRick Macklem (rtimo == 0 || time_second >= rtimo)) {
6637c208ed6SRick Macklem error = 0;
6646bfaa839SGleb Smirnoff goto out;
6657c208ed6SRick Macklem }
6667c208ed6SRick Macklem
6677c208ed6SRick Macklem /* Determine new timeout. */
6687c208ed6SRick Macklem if (timo < MAX_RESEND_DELAY)
6697c208ed6SRick Macklem timo++;
6707c208ed6SRick Macklem else {
6717c208ed6SRick Macklem printf("DHCP/BOOTP timeout for server ");
6727c208ed6SRick Macklem print_sin_addr(&dst);
6737c208ed6SRick Macklem printf("\n");
6747c208ed6SRick Macklem }
6757c208ed6SRick Macklem
6767c208ed6SRick Macklem /*
6777c208ed6SRick Macklem * Wait for up to timo seconds for a reply.
6787c208ed6SRick Macklem * The socket receive timeout was set to 1 second.
6797c208ed6SRick Macklem */
6807c208ed6SRick Macklem atimo = timo + time_second;
6817c208ed6SRick Macklem while (time_second < atimo) {
6827c208ed6SRick Macklem aio.iov_base = (caddr_t) &gctx->reply;
6837c208ed6SRick Macklem aio.iov_len = sizeof(gctx->reply);
6847c208ed6SRick Macklem
6857c208ed6SRick Macklem auio.uio_iov = &aio;
6867c208ed6SRick Macklem auio.uio_iovcnt = 1;
6877c208ed6SRick Macklem auio.uio_segflg = UIO_SYSSPACE;
6887c208ed6SRick Macklem auio.uio_rw = UIO_READ;
6897c208ed6SRick Macklem auio.uio_offset = 0;
6907c208ed6SRick Macklem auio.uio_resid = sizeof(gctx->reply);
6917c208ed6SRick Macklem auio.uio_td = td;
6927c208ed6SRick Macklem
6937c208ed6SRick Macklem rcvflg = 0;
6946bfaa839SGleb Smirnoff error = soreceive(bootp_so, NULL, &auio,
6957c208ed6SRick Macklem NULL, NULL, &rcvflg);
6967c208ed6SRick Macklem gctx->secs = time_second - gctx->starttime;
6976bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) {
6987c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) != 0 ||
6997c208ed6SRick Macklem bootpc_ifctx_isfailed(ifctx) != 0)
7007c208ed6SRick Macklem continue;
7017c208ed6SRick Macklem
7027c208ed6SRick Macklem ifctx->call.secs = htons(gctx->secs);
7037c208ed6SRick Macklem }
7047c208ed6SRick Macklem if (error == EWOULDBLOCK)
7057c208ed6SRick Macklem continue;
7067c208ed6SRick Macklem if (error != 0)
7077c208ed6SRick Macklem goto out;
7087c208ed6SRick Macklem len = sizeof(gctx->reply) - auio.uio_resid;
7097c208ed6SRick Macklem
7107c208ed6SRick Macklem /* Do we have the required number of bytes ? */
7117c208ed6SRick Macklem if (len < BOOTP_MIN_LEN)
7127c208ed6SRick Macklem continue;
7137c208ed6SRick Macklem gctx->replylen = len;
7147c208ed6SRick Macklem
7157c208ed6SRick Macklem /* Is it a reply? */
7167c208ed6SRick Macklem if (gctx->reply.op != BOOTP_REPLY)
7177c208ed6SRick Macklem continue;
7187c208ed6SRick Macklem
7197c208ed6SRick Macklem /* Is this an answer to our query */
7206bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) {
7217c208ed6SRick Macklem if (gctx->reply.xid != ifctx->call.xid)
7227c208ed6SRick Macklem continue;
7237c208ed6SRick Macklem
7247c208ed6SRick Macklem /* Same HW address size ? */
7257c208ed6SRick Macklem if (gctx->reply.hlen != ifctx->call.hlen)
7267c208ed6SRick Macklem continue;
7277c208ed6SRick Macklem
7287c208ed6SRick Macklem /* Correct HW address ? */
7297c208ed6SRick Macklem if (bcmp(gctx->reply.chaddr,
7307c208ed6SRick Macklem ifctx->call.chaddr,
7317c208ed6SRick Macklem ifctx->call.hlen) != 0)
7327c208ed6SRick Macklem continue;
7337c208ed6SRick Macklem
7347c208ed6SRick Macklem break;
7357c208ed6SRick Macklem }
7367c208ed6SRick Macklem
7377c208ed6SRick Macklem if (ifctx != NULL) {
7387c208ed6SRick Macklem s = bootpc_tag(&gctx->tmptag,
7397c208ed6SRick Macklem &gctx->reply,
7407c208ed6SRick Macklem gctx->replylen,
7417c208ed6SRick Macklem TAG_DHCP_MSGTYPE);
7427c208ed6SRick Macklem if (s != NULL) {
7437c208ed6SRick Macklem switch (*s) {
7447c208ed6SRick Macklem case DHCP_OFFER:
7457c208ed6SRick Macklem s = "DHCP Offer";
7467c208ed6SRick Macklem break;
7477c208ed6SRick Macklem case DHCP_ACK:
7487c208ed6SRick Macklem s = "DHCP Ack";
7497c208ed6SRick Macklem break;
7507c208ed6SRick Macklem default:
7517c208ed6SRick Macklem s = "DHCP (unexpected)";
7527c208ed6SRick Macklem break;
7537c208ed6SRick Macklem }
7547c208ed6SRick Macklem } else
7557c208ed6SRick Macklem s = "BOOTP Reply";
7567c208ed6SRick Macklem
7577c208ed6SRick Macklem printf("Received %s packet"
7587c208ed6SRick Macklem " on %s from ",
7597c208ed6SRick Macklem s,
7607c208ed6SRick Macklem ifctx->ireq.ifr_name);
7617c208ed6SRick Macklem print_in_addr(gctx->reply.siaddr);
7627c208ed6SRick Macklem if (gctx->reply.giaddr.s_addr !=
7637c208ed6SRick Macklem htonl(INADDR_ANY)) {
7647c208ed6SRick Macklem printf(" via ");
7657c208ed6SRick Macklem print_in_addr(gctx->reply.giaddr);
7667c208ed6SRick Macklem }
7677c208ed6SRick Macklem if (bootpc_received(gctx, ifctx) != 0) {
7687c208ed6SRick Macklem printf(" (accepted)");
7697c208ed6SRick Macklem if (ifctx->outstanding) {
7707c208ed6SRick Macklem ifctx->outstanding = 0;
7717c208ed6SRick Macklem outstanding--;
7727c208ed6SRick Macklem }
7737c208ed6SRick Macklem /* Network settle delay */
7747c208ed6SRick Macklem if (outstanding == 0)
7757c208ed6SRick Macklem atimo = time_second +
7767c208ed6SRick Macklem BOOTP_SETTLE_DELAY;
7777c208ed6SRick Macklem } else
7787c208ed6SRick Macklem printf(" (ignored)");
7796cbd933bSIan Lepore if (ifctx->gotrootpath ||
7806cbd933bSIan Lepore gctx->any_root_overrides) {
7817c208ed6SRick Macklem gotrootpath = 1;
7827c208ed6SRick Macklem rtimo = time_second +
7837c208ed6SRick Macklem BOOTP_SETTLE_DELAY;
7846cbd933bSIan Lepore if (ifctx->gotrootpath)
7857c208ed6SRick Macklem printf(" (got root path)");
7866cbd933bSIan Lepore }
7877c208ed6SRick Macklem printf("\n");
7887c208ed6SRick Macklem }
7897c208ed6SRick Macklem } /* while secs */
7907c208ed6SRick Macklem #ifdef BOOTP_TIMEOUT
7917c208ed6SRick Macklem if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0)
7927c208ed6SRick Macklem break;
7937c208ed6SRick Macklem #endif
7947c208ed6SRick Macklem /* Force a retry if halfway in DHCP negotiation */
7957c208ed6SRick Macklem retry = 0;
7966bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
7977c208ed6SRick Macklem if (ifctx->state == IF_DHCP_OFFERED) {
7987c208ed6SRick Macklem if (ifctx->dhcpquerytype == DHCP_DISCOVER)
7997c208ed6SRick Macklem retry = 1;
8007c208ed6SRick Macklem else
8017c208ed6SRick Macklem ifctx->state = IF_DHCP_UNRESOLVED;
8027c208ed6SRick Macklem }
8037c208ed6SRick Macklem
8047c208ed6SRick Macklem if (retry != 0)
8057c208ed6SRick Macklem continue;
8067c208ed6SRick Macklem
8077c208ed6SRick Macklem if (gotrootpath != 0) {
8087c208ed6SRick Macklem gctx->gotrootpath = gotrootpath;
8097c208ed6SRick Macklem if (rtimo != 0 && time_second >= rtimo)
8107c208ed6SRick Macklem break;
8117c208ed6SRick Macklem }
8127c208ed6SRick Macklem } /* forever send/receive */
8137c208ed6SRick Macklem
8147c208ed6SRick Macklem /*
8157c208ed6SRick Macklem * XXX: These are errors of varying seriousness being silently
8167c208ed6SRick Macklem * ignored
8177c208ed6SRick Macklem */
8187c208ed6SRick Macklem
8196bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
8207c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) == 0) {
8217c208ed6SRick Macklem printf("%s timeout for interface %s\n",
8227c208ed6SRick Macklem ifctx->dhcpquerytype != DHCP_NOMSG ?
8237c208ed6SRick Macklem "DHCP" : "BOOTP",
8247c208ed6SRick Macklem ifctx->ireq.ifr_name);
8257c208ed6SRick Macklem }
8266bfaa839SGleb Smirnoff
8277c208ed6SRick Macklem if (gctx->gotrootpath != 0) {
8287c208ed6SRick Macklem #if 0
8297c208ed6SRick Macklem printf("Got a root path, ignoring remaining timeout\n");
8307c208ed6SRick Macklem #endif
8317c208ed6SRick Macklem error = 0;
8327c208ed6SRick Macklem goto out;
8337c208ed6SRick Macklem }
8347c208ed6SRick Macklem #ifndef BOOTP_NFSROOT
8356bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
8367c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) != 0) {
8377c208ed6SRick Macklem error = 0;
8387c208ed6SRick Macklem goto out;
8397c208ed6SRick Macklem }
8407c208ed6SRick Macklem #endif
8417c208ed6SRick Macklem error = ETIMEDOUT;
8427c208ed6SRick Macklem
8437c208ed6SRick Macklem out:
8446bfaa839SGleb Smirnoff return (error);
8457c208ed6SRick Macklem }
8467c208ed6SRick Macklem
8476bfaa839SGleb Smirnoff static void
bootpc_fakeup_interface(struct bootpc_ifcontext * ifctx,struct thread * td)8486bfaa839SGleb Smirnoff bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx, struct thread *td)
8497c208ed6SRick Macklem {
8506bfaa839SGleb Smirnoff struct ifreq *ifr;
8516bfaa839SGleb Smirnoff struct in_aliasreq *ifra;
8527c208ed6SRick Macklem struct sockaddr_in *sin;
8537c208ed6SRick Macklem int error;
8547c208ed6SRick Macklem
8556bfaa839SGleb Smirnoff ifr = &ifctx->ireq;
8566bfaa839SGleb Smirnoff ifra = &ifctx->iareq;
8577c208ed6SRick Macklem
8587c208ed6SRick Macklem /*
8597c208ed6SRick Macklem * Bring up the interface.
8607c208ed6SRick Macklem *
8617c208ed6SRick Macklem * Get the old interface flags and or IFF_UP into them; if
8627c208ed6SRick Macklem * IFF_UP set blindly, interface selection can be clobbered.
8637c208ed6SRick Macklem */
8646bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCGIFFLAGS, (caddr_t)ifr, td);
8657c208ed6SRick Macklem if (error != 0)
8666bfaa839SGleb Smirnoff panic("%s: SIOCGIFFLAGS, error=%d", __func__, error);
8676bfaa839SGleb Smirnoff ifr->ifr_flags |= IFF_UP;
8686bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCSIFFLAGS, (caddr_t)ifr, td);
8697c208ed6SRick Macklem if (error != 0)
8706bfaa839SGleb Smirnoff panic("%s: SIOCSIFFLAGS, error=%d", __func__, error);
8717c208ed6SRick Macklem
8727c208ed6SRick Macklem /*
8737c208ed6SRick Macklem * Do enough of ifconfig(8) so that the chosen interface
8746bfaa839SGleb Smirnoff * can talk to the servers. Set address to 0.0.0.0/8 and
8756bfaa839SGleb Smirnoff * broadcast address to local broadcast.
8767c208ed6SRick Macklem */
8776bfaa839SGleb Smirnoff sin = (struct sockaddr_in *)&ifra->ifra_addr;
8787c208ed6SRick Macklem clear_sinaddr(sin);
8796bfaa839SGleb Smirnoff sin = (struct sockaddr_in *)&ifra->ifra_mask;
8807c208ed6SRick Macklem clear_sinaddr(sin);
88120d59403SMike Karels sin->sin_addr.s_addr = htonl(0xff000000);
8826bfaa839SGleb Smirnoff sin = (struct sockaddr_in *)&ifra->ifra_broadaddr;
8837c208ed6SRick Macklem clear_sinaddr(sin);
8847c208ed6SRick Macklem sin->sin_addr.s_addr = htonl(INADDR_BROADCAST);
8856bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, td);
8867c208ed6SRick Macklem if (error != 0)
8876bfaa839SGleb Smirnoff panic("%s: SIOCAIFADDR, error=%d", __func__, error);
8887c208ed6SRick Macklem }
8897c208ed6SRick Macklem
8906bfaa839SGleb Smirnoff static void
bootpc_shutdown_interface(struct bootpc_ifcontext * ifctx,struct thread * td)8916bfaa839SGleb Smirnoff bootpc_shutdown_interface(struct bootpc_ifcontext *ifctx, struct thread *td)
8926bfaa839SGleb Smirnoff {
8936bfaa839SGleb Smirnoff struct ifreq *ifr;
8946bfaa839SGleb Smirnoff struct sockaddr_in *sin;
8956bfaa839SGleb Smirnoff int error;
8967c208ed6SRick Macklem
8976bfaa839SGleb Smirnoff ifr = &ifctx->ireq;
8986bfaa839SGleb Smirnoff
8996bfaa839SGleb Smirnoff printf("Shutdown interface %s\n", ifctx->ireq.ifr_name);
9006bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCGIFFLAGS, (caddr_t)ifr, td);
9016bfaa839SGleb Smirnoff if (error != 0)
9026bfaa839SGleb Smirnoff panic("%s: SIOCGIFFLAGS, error=%d", __func__, error);
9036bfaa839SGleb Smirnoff ifr->ifr_flags &= ~IFF_UP;
9046bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCSIFFLAGS, (caddr_t)ifr, td);
9056bfaa839SGleb Smirnoff if (error != 0)
9066bfaa839SGleb Smirnoff panic("%s: SIOCSIFFLAGS, error=%d", __func__, error);
9076bfaa839SGleb Smirnoff
9086bfaa839SGleb Smirnoff sin = (struct sockaddr_in *) &ifr->ifr_addr;
9096bfaa839SGleb Smirnoff clear_sinaddr(sin);
9106bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCDIFADDR, (caddr_t) ifr, td);
9116bfaa839SGleb Smirnoff if (error != 0)
9126bfaa839SGleb Smirnoff panic("%s: SIOCDIFADDR, error=%d", __func__, error);
9137c208ed6SRick Macklem }
9147c208ed6SRick Macklem
915d32d350eSIan Lepore static void
bootpc_adjust_interface(struct bootpc_ifcontext * ifctx,struct bootpc_globalcontext * gctx,struct thread * td)9167c208ed6SRick Macklem bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
9177c208ed6SRick Macklem struct bootpc_globalcontext *gctx, struct thread *td)
9187c208ed6SRick Macklem {
9197c208ed6SRick Macklem int error;
9207c208ed6SRick Macklem struct sockaddr_in *sin;
9216bfaa839SGleb Smirnoff struct ifreq *ifr;
9226bfaa839SGleb Smirnoff struct in_aliasreq *ifra;
9237c208ed6SRick Macklem struct sockaddr_in *myaddr;
9247c208ed6SRick Macklem struct sockaddr_in *netmask;
9257c208ed6SRick Macklem
9266bfaa839SGleb Smirnoff ifr = &ifctx->ireq;
9276bfaa839SGleb Smirnoff ifra = &ifctx->iareq;
9287c208ed6SRick Macklem myaddr = &ifctx->myaddr;
9297c208ed6SRick Macklem netmask = &ifctx->netmask;
9307c208ed6SRick Macklem
9317c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) == 0) {
9327c208ed6SRick Macklem /* Shutdown interfaces where BOOTP failed */
9336bfaa839SGleb Smirnoff bootpc_shutdown_interface(ifctx, td);
934d32d350eSIan Lepore return;
9357c208ed6SRick Macklem }
9367c208ed6SRick Macklem
937a6c14908SIan Lepore printf("Adjusted interface %s", ifctx->ireq.ifr_name);
938a6c14908SIan Lepore
939a6c14908SIan Lepore /* Do BOOTP interface options */
940a6c14908SIan Lepore if (ifctx->mtu != 0) {
941a6c14908SIan Lepore printf(" (MTU=%d%s)", ifctx->mtu,
942a6c14908SIan Lepore (ifctx->mtu > 1514) ? "/JUMBO" : "");
943a6c14908SIan Lepore ifr->ifr_mtu = ifctx->mtu;
944a6c14908SIan Lepore error = ifioctl(bootp_so, SIOCSIFMTU, (caddr_t) ifr, td);
945a6c14908SIan Lepore if (error != 0)
946a6c14908SIan Lepore panic("%s: SIOCSIFMTU, error=%d", __func__, error);
947a6c14908SIan Lepore }
948a6c14908SIan Lepore printf("\n");
949a6c14908SIan Lepore
9507c208ed6SRick Macklem /*
9517c208ed6SRick Macklem * Do enough of ifconfig(8) so that the chosen interface
9527c208ed6SRick Macklem * can talk to the servers. (just set the address)
9537c208ed6SRick Macklem */
9546bfaa839SGleb Smirnoff sin = (struct sockaddr_in *) &ifr->ifr_addr;
9557c208ed6SRick Macklem clear_sinaddr(sin);
9566bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCDIFADDR, (caddr_t) ifr, td);
9577c208ed6SRick Macklem if (error != 0)
9586bfaa839SGleb Smirnoff panic("%s: SIOCDIFADDR, error=%d", __func__, error);
9597c208ed6SRick Macklem
9606bfaa839SGleb Smirnoff bcopy(myaddr, &ifra->ifra_addr, sizeof(*myaddr));
9616bfaa839SGleb Smirnoff bcopy(netmask, &ifra->ifra_mask, sizeof(*netmask));
9626bfaa839SGleb Smirnoff clear_sinaddr(&ifra->ifra_broadaddr);
9636bfaa839SGleb Smirnoff ifra->ifra_broadaddr.sin_addr.s_addr = myaddr->sin_addr.s_addr |
9646bfaa839SGleb Smirnoff ~netmask->sin_addr.s_addr;
9656bfaa839SGleb Smirnoff
9666bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, td);
9676bfaa839SGleb Smirnoff if (error != 0)
9686bfaa839SGleb Smirnoff panic("%s: SIOCAIFADDR, error=%d", __func__, error);
9692596e591SIan Lepore }
9707c208ed6SRick Macklem
9712596e591SIan Lepore static void
bootpc_add_default_route(struct bootpc_ifcontext * ifctx)9722596e591SIan Lepore bootpc_add_default_route(struct bootpc_ifcontext *ifctx)
9732596e591SIan Lepore {
9742596e591SIan Lepore int error;
9752596e591SIan Lepore struct sockaddr_in defdst;
9762596e591SIan Lepore struct sockaddr_in defmask;
977e1c05fd2SAlexander V. Chernikov struct rt_addrinfo info;
978e1c05fd2SAlexander V. Chernikov struct rib_cmd_info rc;
9797c208ed6SRick Macklem
9802596e591SIan Lepore if (ifctx->gw.sin_addr.s_addr == htonl(INADDR_ANY))
9812596e591SIan Lepore return;
9822596e591SIan Lepore
9837c208ed6SRick Macklem clear_sinaddr(&defdst);
9847c208ed6SRick Macklem clear_sinaddr(&defmask);
9852596e591SIan Lepore
986e1c05fd2SAlexander V. Chernikov bzero((caddr_t)&info, sizeof(info));
987e1c05fd2SAlexander V. Chernikov info.rti_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
988e1c05fd2SAlexander V. Chernikov info.rti_info[RTAX_DST] = (struct sockaddr *)&defdst;
989e1c05fd2SAlexander V. Chernikov info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&defmask;
990e1c05fd2SAlexander V. Chernikov info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&ifctx->gw;
991e1c05fd2SAlexander V. Chernikov
992e1c05fd2SAlexander V. Chernikov error = rib_action(RT_DEFAULT_FIB, RTM_ADD, &info, &rc);
993e1c05fd2SAlexander V. Chernikov
9947c208ed6SRick Macklem if (error != 0) {
9956bfaa839SGleb Smirnoff printf("%s: RTM_ADD, error=%d\n", __func__, error);
9967c208ed6SRick Macklem }
9977c208ed6SRick Macklem }
9982596e591SIan Lepore
9992596e591SIan Lepore static void
bootpc_remove_default_route(struct bootpc_ifcontext * ifctx)10002596e591SIan Lepore bootpc_remove_default_route(struct bootpc_ifcontext *ifctx)
10012596e591SIan Lepore {
10022596e591SIan Lepore int error;
10032596e591SIan Lepore struct sockaddr_in defdst;
10042596e591SIan Lepore struct sockaddr_in defmask;
1005e1c05fd2SAlexander V. Chernikov struct rt_addrinfo info;
1006e1c05fd2SAlexander V. Chernikov struct rib_cmd_info rc;
10072596e591SIan Lepore
10082596e591SIan Lepore if (ifctx->gw.sin_addr.s_addr == htonl(INADDR_ANY))
10092596e591SIan Lepore return;
10102596e591SIan Lepore
10112596e591SIan Lepore clear_sinaddr(&defdst);
10122596e591SIan Lepore clear_sinaddr(&defmask);
10132596e591SIan Lepore
1014e1c05fd2SAlexander V. Chernikov bzero((caddr_t)&info, sizeof(info));
1015e1c05fd2SAlexander V. Chernikov info.rti_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
1016e1c05fd2SAlexander V. Chernikov info.rti_info[RTAX_DST] = (struct sockaddr *)&defdst;
1017e1c05fd2SAlexander V. Chernikov info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&defmask;
1018e1c05fd2SAlexander V. Chernikov info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&ifctx->gw;
1019e1c05fd2SAlexander V. Chernikov
1020e1c05fd2SAlexander V. Chernikov error = rib_action(RT_DEFAULT_FIB, RTM_DELETE, &info, &rc);
10212596e591SIan Lepore if (error != 0) {
10222596e591SIan Lepore printf("%s: RTM_DELETE, error=%d\n", __func__, error);
10232596e591SIan Lepore }
10247c208ed6SRick Macklem }
10257c208ed6SRick Macklem
10267c208ed6SRick Macklem static int
setfs(struct sockaddr_in * addr,char * path,char * p,const struct in_addr * siaddr)10277c208ed6SRick Macklem setfs(struct sockaddr_in *addr, char *path, char *p,
10287c208ed6SRick Macklem const struct in_addr *siaddr)
10297c208ed6SRick Macklem {
10307c208ed6SRick Macklem
10317c208ed6SRick Macklem if (getip(&p, &addr->sin_addr) == 0) {
10327c208ed6SRick Macklem if (siaddr != NULL && *p == '/')
10337c208ed6SRick Macklem bcopy(siaddr, &addr->sin_addr, sizeof(struct in_addr));
10347c208ed6SRick Macklem else
10357c208ed6SRick Macklem return 0;
10367c208ed6SRick Macklem } else {
10377c208ed6SRick Macklem if (*p != ':')
10387c208ed6SRick Macklem return 0;
10397c208ed6SRick Macklem p++;
10407c208ed6SRick Macklem }
10417c208ed6SRick Macklem
10427c208ed6SRick Macklem addr->sin_len = sizeof(struct sockaddr_in);
10437c208ed6SRick Macklem addr->sin_family = AF_INET;
10447c208ed6SRick Macklem
10457c208ed6SRick Macklem strlcpy(path, p, MNAMELEN);
10467c208ed6SRick Macklem return 1;
10477c208ed6SRick Macklem }
10487c208ed6SRick Macklem
10497c208ed6SRick Macklem static int
getip(char ** ptr,struct in_addr * addr)10507c208ed6SRick Macklem getip(char **ptr, struct in_addr *addr)
10517c208ed6SRick Macklem {
10527c208ed6SRick Macklem char *p;
10537c208ed6SRick Macklem unsigned int ip;
10547c208ed6SRick Macklem int val;
10557c208ed6SRick Macklem
10567c208ed6SRick Macklem p = *ptr;
10577c208ed6SRick Macklem ip = 0;
10587c208ed6SRick Macklem if (((val = getdec(&p)) < 0) || (val > 255))
10597c208ed6SRick Macklem return 0;
10607c208ed6SRick Macklem ip = val << 24;
10617c208ed6SRick Macklem if (*p != '.')
10627c208ed6SRick Macklem return 0;
10637c208ed6SRick Macklem p++;
10647c208ed6SRick Macklem if (((val = getdec(&p)) < 0) || (val > 255))
10657c208ed6SRick Macklem return 0;
10667c208ed6SRick Macklem ip |= (val << 16);
10677c208ed6SRick Macklem if (*p != '.')
10687c208ed6SRick Macklem return 0;
10697c208ed6SRick Macklem p++;
10707c208ed6SRick Macklem if (((val = getdec(&p)) < 0) || (val > 255))
10717c208ed6SRick Macklem return 0;
10727c208ed6SRick Macklem ip |= (val << 8);
10737c208ed6SRick Macklem if (*p != '.')
10747c208ed6SRick Macklem return 0;
10757c208ed6SRick Macklem p++;
10767c208ed6SRick Macklem if (((val = getdec(&p)) < 0) || (val > 255))
10777c208ed6SRick Macklem return 0;
10787c208ed6SRick Macklem ip |= val;
10797c208ed6SRick Macklem
10807c208ed6SRick Macklem addr->s_addr = htonl(ip);
10817c208ed6SRick Macklem *ptr = p;
10827c208ed6SRick Macklem return 1;
10837c208ed6SRick Macklem }
10847c208ed6SRick Macklem
10857c208ed6SRick Macklem static int
getdec(char ** ptr)10867c208ed6SRick Macklem getdec(char **ptr)
10877c208ed6SRick Macklem {
10887c208ed6SRick Macklem char *p;
10897c208ed6SRick Macklem int ret;
10907c208ed6SRick Macklem
10917c208ed6SRick Macklem p = *ptr;
10927c208ed6SRick Macklem ret = 0;
10937c208ed6SRick Macklem if ((*p < '0') || (*p > '9'))
10947c208ed6SRick Macklem return -1;
10957c208ed6SRick Macklem while ((*p >= '0') && (*p <= '9')) {
10967c208ed6SRick Macklem ret = ret * 10 + (*p - '0');
10977c208ed6SRick Macklem p++;
10987c208ed6SRick Macklem }
10997c208ed6SRick Macklem *ptr = p;
11007c208ed6SRick Macklem return ret;
11017c208ed6SRick Macklem }
11027c208ed6SRick Macklem
11037c208ed6SRick Macklem static void
mountopts(struct nfs_args * args,char * p)11047c208ed6SRick Macklem mountopts(struct nfs_args *args, char *p)
11057c208ed6SRick Macklem {
11067c208ed6SRick Macklem args->version = NFS_ARGSVERSION;
11077c208ed6SRick Macklem args->rsize = BOOTP_BLOCKSIZE;
11087c208ed6SRick Macklem args->wsize = BOOTP_BLOCKSIZE;
11097c208ed6SRick Macklem args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
11107c208ed6SRick Macklem args->sotype = SOCK_DGRAM;
11117c208ed6SRick Macklem if (p != NULL)
11127c208ed6SRick Macklem nfs_parse_options(p, args);
11137c208ed6SRick Macklem }
11147c208ed6SRick Macklem
11157c208ed6SRick Macklem static int
xdr_opaque_decode(struct mbuf ** mptr,u_char * buf,int len)11167c208ed6SRick Macklem xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len)
11177c208ed6SRick Macklem {
11187c208ed6SRick Macklem struct mbuf *m;
11197c208ed6SRick Macklem int alignedlen;
11207c208ed6SRick Macklem
11217c208ed6SRick Macklem m = *mptr;
11227c208ed6SRick Macklem alignedlen = ( len + 3 ) & ~3;
11237c208ed6SRick Macklem
11247c208ed6SRick Macklem if (m->m_len < alignedlen) {
11257c208ed6SRick Macklem m = m_pullup(m, alignedlen);
11267c208ed6SRick Macklem if (m == NULL) {
11277c208ed6SRick Macklem *mptr = NULL;
11287c208ed6SRick Macklem return EBADRPC;
11297c208ed6SRick Macklem }
11307c208ed6SRick Macklem }
11317c208ed6SRick Macklem bcopy(mtod(m, u_char *), buf, len);
11327c208ed6SRick Macklem m_adj(m, alignedlen);
11337c208ed6SRick Macklem *mptr = m;
11347c208ed6SRick Macklem return 0;
11357c208ed6SRick Macklem }
11367c208ed6SRick Macklem
11377c208ed6SRick Macklem static int
xdr_int_decode(struct mbuf ** mptr,int * iptr)11387c208ed6SRick Macklem xdr_int_decode(struct mbuf **mptr, int *iptr)
11397c208ed6SRick Macklem {
11407c208ed6SRick Macklem u_int32_t i;
11417c208ed6SRick Macklem
11427c208ed6SRick Macklem if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0)
11437c208ed6SRick Macklem return EBADRPC;
11447c208ed6SRick Macklem *iptr = fxdr_unsigned(u_int32_t, i);
11457c208ed6SRick Macklem return 0;
11467c208ed6SRick Macklem }
11477c208ed6SRick Macklem
11487c208ed6SRick Macklem static void
print_sin_addr(struct sockaddr_in * sin)11497c208ed6SRick Macklem print_sin_addr(struct sockaddr_in *sin)
11507c208ed6SRick Macklem {
11517c208ed6SRick Macklem
11527c208ed6SRick Macklem print_in_addr(sin->sin_addr);
11537c208ed6SRick Macklem }
11547c208ed6SRick Macklem
11557c208ed6SRick Macklem static void
print_in_addr(struct in_addr addr)11567c208ed6SRick Macklem print_in_addr(struct in_addr addr)
11577c208ed6SRick Macklem {
11587c208ed6SRick Macklem unsigned int ip;
11597c208ed6SRick Macklem
11607c208ed6SRick Macklem ip = ntohl(addr.s_addr);
11617c208ed6SRick Macklem printf("%d.%d.%d.%d",
11627c208ed6SRick Macklem ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
11637c208ed6SRick Macklem }
11647c208ed6SRick Macklem
11657c208ed6SRick Macklem static void
bootpc_compose_query(struct bootpc_ifcontext * ifctx,struct thread * td)11666bfaa839SGleb Smirnoff bootpc_compose_query(struct bootpc_ifcontext *ifctx, struct thread *td)
11677c208ed6SRick Macklem {
11687c208ed6SRick Macklem unsigned char *vendp;
11697c208ed6SRick Macklem unsigned char vendor_client[64];
11707c208ed6SRick Macklem uint32_t leasetime;
11717c208ed6SRick Macklem uint8_t vendor_client_len;
11727c208ed6SRick Macklem
11737c208ed6SRick Macklem ifctx->gotrootpath = 0;
11747c208ed6SRick Macklem
11757c208ed6SRick Macklem bzero((caddr_t) &ifctx->call, sizeof(ifctx->call));
11767c208ed6SRick Macklem
11777c208ed6SRick Macklem /* bootpc part */
11787c208ed6SRick Macklem ifctx->call.op = BOOTP_REQUEST; /* BOOTREQUEST */
11797c208ed6SRick Macklem ifctx->call.htype = 1; /* 10mb ethernet */
11807c208ed6SRick Macklem ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */
11817c208ed6SRick Macklem ifctx->call.hops = 0;
11827c208ed6SRick Macklem if (bootpc_ifctx_isunresolved(ifctx) != 0)
11837c208ed6SRick Macklem ifctx->xid++;
11847c208ed6SRick Macklem ifctx->call.xid = txdr_unsigned(ifctx->xid);
11857c208ed6SRick Macklem bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen);
11867c208ed6SRick Macklem
11877c208ed6SRick Macklem vendp = ifctx->call.vend;
11887c208ed6SRick Macklem *vendp++ = 99; /* RFC1048 cookie */
11897c208ed6SRick Macklem *vendp++ = 130;
11907c208ed6SRick Macklem *vendp++ = 83;
11917c208ed6SRick Macklem *vendp++ = 99;
11927c208ed6SRick Macklem *vendp++ = TAG_MAXMSGSIZE;
11937c208ed6SRick Macklem *vendp++ = 2;
11947c208ed6SRick Macklem *vendp++ = (sizeof(struct bootp_packet) >> 8) & 255;
11957c208ed6SRick Macklem *vendp++ = sizeof(struct bootp_packet) & 255;
11967c208ed6SRick Macklem
11977c208ed6SRick Macklem snprintf(vendor_client, sizeof(vendor_client), "%s:%s:%s",
11987c208ed6SRick Macklem ostype, MACHINE, osrelease);
11997c208ed6SRick Macklem vendor_client_len = strlen(vendor_client);
12007c208ed6SRick Macklem *vendp++ = TAG_VENDOR_INDENTIFIER;
12017c208ed6SRick Macklem *vendp++ = vendor_client_len;
12027c208ed6SRick Macklem memcpy(vendp, vendor_client, vendor_client_len);
12037c208ed6SRick Macklem vendp += vendor_client_len;
12047c208ed6SRick Macklem ifctx->dhcpquerytype = DHCP_NOMSG;
12057c208ed6SRick Macklem switch (ifctx->state) {
12067c208ed6SRick Macklem case IF_DHCP_UNRESOLVED:
12077c208ed6SRick Macklem *vendp++ = TAG_DHCP_MSGTYPE;
12087c208ed6SRick Macklem *vendp++ = 1;
12097c208ed6SRick Macklem *vendp++ = DHCP_DISCOVER;
12107c208ed6SRick Macklem ifctx->dhcpquerytype = DHCP_DISCOVER;
12117c208ed6SRick Macklem ifctx->gotdhcpserver = 0;
12127c208ed6SRick Macklem break;
12137c208ed6SRick Macklem case IF_DHCP_OFFERED:
12147c208ed6SRick Macklem *vendp++ = TAG_DHCP_MSGTYPE;
12157c208ed6SRick Macklem *vendp++ = 1;
12167c208ed6SRick Macklem *vendp++ = DHCP_REQUEST;
12177c208ed6SRick Macklem ifctx->dhcpquerytype = DHCP_REQUEST;
12187c208ed6SRick Macklem *vendp++ = TAG_DHCP_REQ_ADDR;
12197c208ed6SRick Macklem *vendp++ = 4;
12207c208ed6SRick Macklem memcpy(vendp, &ifctx->reply.yiaddr, 4);
12217c208ed6SRick Macklem vendp += 4;
12227c208ed6SRick Macklem if (ifctx->gotdhcpserver != 0) {
12237c208ed6SRick Macklem *vendp++ = TAG_DHCP_SERVERID;
12247c208ed6SRick Macklem *vendp++ = 4;
12257c208ed6SRick Macklem memcpy(vendp, &ifctx->dhcpserver, 4);
12267c208ed6SRick Macklem vendp += 4;
12277c208ed6SRick Macklem }
12287c208ed6SRick Macklem *vendp++ = TAG_DHCP_LEASETIME;
12297c208ed6SRick Macklem *vendp++ = 4;
12307c208ed6SRick Macklem leasetime = htonl(300);
12317c208ed6SRick Macklem memcpy(vendp, &leasetime, 4);
12327c208ed6SRick Macklem vendp += 4;
12337c208ed6SRick Macklem break;
12347c208ed6SRick Macklem default:
12357c208ed6SRick Macklem break;
12367c208ed6SRick Macklem }
12377c208ed6SRick Macklem *vendp = TAG_END;
12387c208ed6SRick Macklem
12397c208ed6SRick Macklem ifctx->call.secs = 0;
12407c208ed6SRick Macklem ifctx->call.flags = htons(0x8000); /* We need a broadcast answer */
12417c208ed6SRick Macklem }
12427c208ed6SRick Macklem
12437c208ed6SRick Macklem static int
bootpc_hascookie(struct bootp_packet * bp)12447c208ed6SRick Macklem bootpc_hascookie(struct bootp_packet *bp)
12457c208ed6SRick Macklem {
12467c208ed6SRick Macklem
12477c208ed6SRick Macklem return (bp->vend[0] == 99 && bp->vend[1] == 130 &&
12487c208ed6SRick Macklem bp->vend[2] == 83 && bp->vend[3] == 99);
12497c208ed6SRick Macklem }
12507c208ed6SRick Macklem
12517c208ed6SRick Macklem static void
bootpc_tag_helper(struct bootpc_tagcontext * tctx,unsigned char * start,int len,int tag)12527c208ed6SRick Macklem bootpc_tag_helper(struct bootpc_tagcontext *tctx,
12537c208ed6SRick Macklem unsigned char *start, int len, int tag)
12547c208ed6SRick Macklem {
12557c208ed6SRick Macklem unsigned char *j;
12567c208ed6SRick Macklem unsigned char *ej;
12577c208ed6SRick Macklem unsigned char code;
12587c208ed6SRick Macklem
12597c208ed6SRick Macklem if (tctx->badtag != 0 || tctx->badopt != 0)
12607c208ed6SRick Macklem return;
12617c208ed6SRick Macklem
12627c208ed6SRick Macklem j = start;
12637c208ed6SRick Macklem ej = j + len;
12647c208ed6SRick Macklem
12657c208ed6SRick Macklem while (j < ej) {
12667c208ed6SRick Macklem code = *j++;
12677c208ed6SRick Macklem if (code == TAG_PAD)
12687c208ed6SRick Macklem continue;
12697c208ed6SRick Macklem if (code == TAG_END)
12707c208ed6SRick Macklem return;
12717c208ed6SRick Macklem if (j >= ej || j + *j + 1 > ej) {
12727c208ed6SRick Macklem tctx->badopt = 1;
12737c208ed6SRick Macklem return;
12747c208ed6SRick Macklem }
12757c208ed6SRick Macklem len = *j++;
12767c208ed6SRick Macklem if (code == tag) {
12777c208ed6SRick Macklem if (tctx->taglen + len > TAG_MAXLEN) {
12787c208ed6SRick Macklem tctx->badtag = 1;
12797c208ed6SRick Macklem return;
12807c208ed6SRick Macklem }
12817c208ed6SRick Macklem tctx->foundopt = 1;
12827c208ed6SRick Macklem if (len > 0)
12837c208ed6SRick Macklem memcpy(tctx->buf + tctx->taglen,
12847c208ed6SRick Macklem j, len);
12857c208ed6SRick Macklem tctx->taglen += len;
12867c208ed6SRick Macklem }
12877c208ed6SRick Macklem if (code == TAG_OVERLOAD)
12887c208ed6SRick Macklem tctx->overload = *j;
12897c208ed6SRick Macklem
12907c208ed6SRick Macklem j += len;
12917c208ed6SRick Macklem }
12927c208ed6SRick Macklem }
12937c208ed6SRick Macklem
12947c208ed6SRick Macklem static unsigned char *
bootpc_tag(struct bootpc_tagcontext * tctx,struct bootp_packet * bp,int len,int tag)12957c208ed6SRick Macklem bootpc_tag(struct bootpc_tagcontext *tctx,
12967c208ed6SRick Macklem struct bootp_packet *bp, int len, int tag)
12977c208ed6SRick Macklem {
12987c208ed6SRick Macklem tctx->overload = 0;
12997c208ed6SRick Macklem tctx->badopt = 0;
13007c208ed6SRick Macklem tctx->badtag = 0;
13017c208ed6SRick Macklem tctx->foundopt = 0;
13027c208ed6SRick Macklem tctx->taglen = 0;
13037c208ed6SRick Macklem
13047c208ed6SRick Macklem if (bootpc_hascookie(bp) == 0)
13057c208ed6SRick Macklem return NULL;
13067c208ed6SRick Macklem
13077c208ed6SRick Macklem bootpc_tag_helper(tctx, &bp->vend[4],
13087c208ed6SRick Macklem (unsigned char *) bp + len - &bp->vend[4], tag);
13097c208ed6SRick Macklem
13107c208ed6SRick Macklem if ((tctx->overload & OVERLOAD_FILE) != 0)
13117c208ed6SRick Macklem bootpc_tag_helper(tctx,
13127c208ed6SRick Macklem (unsigned char *) bp->file,
13137c208ed6SRick Macklem sizeof(bp->file),
13147c208ed6SRick Macklem tag);
13157c208ed6SRick Macklem if ((tctx->overload & OVERLOAD_SNAME) != 0)
13167c208ed6SRick Macklem bootpc_tag_helper(tctx,
13177c208ed6SRick Macklem (unsigned char *) bp->sname,
13187c208ed6SRick Macklem sizeof(bp->sname),
13197c208ed6SRick Macklem tag);
13207c208ed6SRick Macklem
13217c208ed6SRick Macklem if (tctx->badopt != 0 || tctx->badtag != 0 || tctx->foundopt == 0)
13227c208ed6SRick Macklem return NULL;
13237c208ed6SRick Macklem tctx->buf[tctx->taglen] = '\0';
13247c208ed6SRick Macklem return tctx->buf;
13257c208ed6SRick Macklem }
13267c208ed6SRick Macklem
13277c208ed6SRick Macklem static void
bootpc_decode_reply(struct nfsv3_diskless * nd,struct bootpc_ifcontext * ifctx,struct bootpc_globalcontext * gctx)13287c208ed6SRick Macklem bootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx,
13297c208ed6SRick Macklem struct bootpc_globalcontext *gctx)
13307c208ed6SRick Macklem {
13316cbd933bSIan Lepore char *p, *s;
13327c208ed6SRick Macklem
13337c208ed6SRick Macklem ifctx->gotgw = 0;
13347c208ed6SRick Macklem ifctx->gotnetmask = 0;
13357c208ed6SRick Macklem
13367c208ed6SRick Macklem clear_sinaddr(&ifctx->myaddr);
13377c208ed6SRick Macklem clear_sinaddr(&ifctx->netmask);
13387c208ed6SRick Macklem clear_sinaddr(&ifctx->gw);
13397c208ed6SRick Macklem
13407c208ed6SRick Macklem ifctx->myaddr.sin_addr = ifctx->reply.yiaddr;
13417c208ed6SRick Macklem
13427c208ed6SRick Macklem printf("%s at ", ifctx->ireq.ifr_name);
13437c208ed6SRick Macklem print_sin_addr(&ifctx->myaddr);
13447c208ed6SRick Macklem printf(" server ");
13457c208ed6SRick Macklem print_in_addr(ifctx->reply.siaddr);
13467c208ed6SRick Macklem
13477c208ed6SRick Macklem ifctx->gw.sin_addr = ifctx->reply.giaddr;
13487c208ed6SRick Macklem if (ifctx->reply.giaddr.s_addr != htonl(INADDR_ANY)) {
13497c208ed6SRick Macklem printf(" via gateway ");
13507c208ed6SRick Macklem print_in_addr(ifctx->reply.giaddr);
13517c208ed6SRick Macklem }
13527c208ed6SRick Macklem
13537c208ed6SRick Macklem /* This call used for the side effect (overload flag) */
13547c208ed6SRick Macklem (void) bootpc_tag(&gctx->tmptag,
13557c208ed6SRick Macklem &ifctx->reply, ifctx->replylen, TAG_END);
13567c208ed6SRick Macklem
13577c208ed6SRick Macklem if ((gctx->tmptag.overload & OVERLOAD_SNAME) == 0)
13587c208ed6SRick Macklem if (ifctx->reply.sname[0] != '\0')
13597c208ed6SRick Macklem printf(" server name %s", ifctx->reply.sname);
13607c208ed6SRick Macklem if ((gctx->tmptag.overload & OVERLOAD_FILE) == 0)
13617c208ed6SRick Macklem if (ifctx->reply.file[0] != '\0')
13627c208ed6SRick Macklem printf(" boot file %s", ifctx->reply.file);
13637c208ed6SRick Macklem
13647c208ed6SRick Macklem printf("\n");
13657c208ed6SRick Macklem
13667c208ed6SRick Macklem p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
13677c208ed6SRick Macklem TAG_SUBNETMASK);
13687c208ed6SRick Macklem if (p != NULL) {
13697c208ed6SRick Macklem if (gctx->tag.taglen != 4)
13707c208ed6SRick Macklem panic("bootpc: subnet mask len is %d",
13717c208ed6SRick Macklem gctx->tag.taglen);
13727c208ed6SRick Macklem bcopy(p, &ifctx->netmask.sin_addr, 4);
13737c208ed6SRick Macklem ifctx->gotnetmask = 1;
13747c208ed6SRick Macklem printf("subnet mask ");
13757c208ed6SRick Macklem print_sin_addr(&ifctx->netmask);
13767c208ed6SRick Macklem printf(" ");
13777c208ed6SRick Macklem }
13787c208ed6SRick Macklem
13797c208ed6SRick Macklem p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
13807c208ed6SRick Macklem TAG_ROUTERS);
13817c208ed6SRick Macklem if (p != NULL) {
13827c208ed6SRick Macklem /* Routers */
13837c208ed6SRick Macklem if (gctx->tag.taglen % 4)
13847c208ed6SRick Macklem panic("bootpc: Router Len is %d", gctx->tag.taglen);
13857c208ed6SRick Macklem if (gctx->tag.taglen > 0) {
13867c208ed6SRick Macklem bcopy(p, &ifctx->gw.sin_addr, 4);
13877c208ed6SRick Macklem printf("router ");
13887c208ed6SRick Macklem print_sin_addr(&ifctx->gw);
13897c208ed6SRick Macklem printf(" ");
13907c208ed6SRick Macklem ifctx->gotgw = 1;
13917c208ed6SRick Macklem gctx->gotgw = 1;
13927c208ed6SRick Macklem }
13937c208ed6SRick Macklem }
13947c208ed6SRick Macklem
13956cbd933bSIan Lepore /*
13966cbd933bSIan Lepore * Choose a root filesystem. If a value is forced in the environment
13976cbd933bSIan Lepore * and it contains "nfs:", use it unconditionally. Otherwise, if the
13986cbd933bSIan Lepore * kernel is compiled with the ROOTDEVNAME option, then use it if:
13996cbd933bSIan Lepore * - The server doesn't provide a pathname.
14006cbd933bSIan Lepore * - The boothowto flags include RB_DFLTROOT (user said to override
14016cbd933bSIan Lepore * the server value).
14026cbd933bSIan Lepore */
14036cbd933bSIan Lepore p = NULL;
14042be111bfSDavide Italiano if ((s = kern_getenv("vfs.root.mountfrom")) != NULL) {
14056cbd933bSIan Lepore if ((p = strstr(s, "nfs:")) != NULL)
14066cbd933bSIan Lepore p = strdup(p + 4, M_TEMP);
14076cbd933bSIan Lepore freeenv(s);
14086cbd933bSIan Lepore }
14096cbd933bSIan Lepore if (p == NULL) {
14107c208ed6SRick Macklem p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
14117c208ed6SRick Macklem TAG_ROOT);
1412eb2d4f02SIan Lepore if (p != NULL)
1413eb2d4f02SIan Lepore ifctx->gotrootpath = 1;
14146cbd933bSIan Lepore }
14156cbd933bSIan Lepore #ifdef ROOTDEVNAME
14166cbd933bSIan Lepore if ((p == NULL || (boothowto & RB_DFLTROOT) != 0) &&
14176cbd933bSIan Lepore (p = strstr(ROOTDEVNAME, "nfs:")) != NULL) {
14186cbd933bSIan Lepore p += 4;
14196cbd933bSIan Lepore }
14206cbd933bSIan Lepore #endif
14217c208ed6SRick Macklem if (p != NULL) {
14227c208ed6SRick Macklem if (gctx->setrootfs != NULL) {
14237c208ed6SRick Macklem printf("rootfs %s (ignored) ", p);
14247c208ed6SRick Macklem } else if (setfs(&nd->root_saddr,
14257c208ed6SRick Macklem nd->root_hostnam, p, &ifctx->reply.siaddr)) {
14267c208ed6SRick Macklem if (*p == '/') {
14277c208ed6SRick Macklem printf("root_server ");
14287c208ed6SRick Macklem print_sin_addr(&nd->root_saddr);
14297c208ed6SRick Macklem printf(" ");
14307c208ed6SRick Macklem }
14317c208ed6SRick Macklem printf("rootfs %s ", p);
14327c208ed6SRick Macklem gctx->gotrootpath = 1;
14337c208ed6SRick Macklem gctx->setrootfs = ifctx;
14347c208ed6SRick Macklem
14357c208ed6SRick Macklem p = bootpc_tag(&gctx->tag, &ifctx->reply,
14367c208ed6SRick Macklem ifctx->replylen,
14377c208ed6SRick Macklem TAG_ROOTOPTS);
14387c208ed6SRick Macklem if (p != NULL) {
14397c208ed6SRick Macklem mountopts(&nd->root_args, p);
14407c208ed6SRick Macklem printf("rootopts %s ", p);
14417c208ed6SRick Macklem }
14427c208ed6SRick Macklem } else
14437c208ed6SRick Macklem panic("Failed to set rootfs to %s", p);
14447c208ed6SRick Macklem }
14457c208ed6SRick Macklem
14467c208ed6SRick Macklem p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
14477c208ed6SRick Macklem TAG_HOSTNAME);
14487c208ed6SRick Macklem if (p != NULL) {
14497c208ed6SRick Macklem if (gctx->tag.taglen >= MAXHOSTNAMELEN)
14507c208ed6SRick Macklem panic("bootpc: hostname >= %d bytes",
14517c208ed6SRick Macklem MAXHOSTNAMELEN);
14527c208ed6SRick Macklem if (gctx->sethostname != NULL) {
14537c208ed6SRick Macklem printf("hostname %s (ignored) ", p);
14547c208ed6SRick Macklem } else {
14557c208ed6SRick Macklem strcpy(nd->my_hostnam, p);
14567c208ed6SRick Macklem mtx_lock(&prison0.pr_mtx);
14577c208ed6SRick Macklem strcpy(prison0.pr_hostname, p);
14587c208ed6SRick Macklem mtx_unlock(&prison0.pr_mtx);
14597c208ed6SRick Macklem printf("hostname %s ", p);
14607c208ed6SRick Macklem gctx->sethostname = ifctx;
14617c208ed6SRick Macklem }
14627c208ed6SRick Macklem }
14637c208ed6SRick Macklem p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
14647c208ed6SRick Macklem TAG_COOKIE);
14657c208ed6SRick Macklem if (p != NULL) { /* store in a sysctl variable */
14667c208ed6SRick Macklem int i, l = sizeof(bootp_cookie) - 1;
14677c208ed6SRick Macklem for (i = 0; i < l && p[i] != '\0'; i++)
14687c208ed6SRick Macklem bootp_cookie[i] = p[i];
14697c208ed6SRick Macklem p[i] = '\0';
14707c208ed6SRick Macklem }
14717c208ed6SRick Macklem
1472a6c14908SIan Lepore p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1473a6c14908SIan Lepore TAG_INTF_MTU);
1474a6c14908SIan Lepore if (p != NULL) {
1475a6c14908SIan Lepore ifctx->mtu = be16dec(p);
1476a6c14908SIan Lepore }
14777c208ed6SRick Macklem
14787c208ed6SRick Macklem printf("\n");
14797c208ed6SRick Macklem
14807c208ed6SRick Macklem if (ifctx->gotnetmask == 0) {
148120d59403SMike Karels /*
14822f35e7d9SMike Karels * If there is no netmask, use historical default,
14832f35e7d9SMike Karels * but we really need the right mask from the server.
148420d59403SMike Karels */
148520d59403SMike Karels printf("%s: no netmask received!\n", ifctx->ireq.ifr_name);
14862f35e7d9SMike Karels if (IN_CLASSA(ntohl(ifctx->myaddr.sin_addr.s_addr)))
14872f35e7d9SMike Karels ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET);
14882f35e7d9SMike Karels else if (IN_CLASSB(ntohl(ifctx->myaddr.sin_addr.s_addr)))
14892f35e7d9SMike Karels ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET);
14902f35e7d9SMike Karels else
14912f35e7d9SMike Karels ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET);
14927c208ed6SRick Macklem }
14937c208ed6SRick Macklem }
14947c208ed6SRick Macklem
1495*0785c323SJustin Hibbits static u_int
bootpc_init_ifa_cb(void * arg,struct ifaddr * ifa,u_int count)1496*0785c323SJustin Hibbits bootpc_init_ifa_cb(void *arg, struct ifaddr *ifa, u_int count)
1497*0785c323SJustin Hibbits {
1498*0785c323SJustin Hibbits struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
1499*0785c323SJustin Hibbits
1500*0785c323SJustin Hibbits if (count != 0)
1501*0785c323SJustin Hibbits return (0);
1502*0785c323SJustin Hibbits
1503*0785c323SJustin Hibbits if (sdl->sdl_type != IFT_ETHER)
1504*0785c323SJustin Hibbits return (0);
1505*0785c323SJustin Hibbits
1506*0785c323SJustin Hibbits *(struct sockaddr_dl **)arg = sdl;
1507*0785c323SJustin Hibbits
1508*0785c323SJustin Hibbits return (1);
1509*0785c323SJustin Hibbits }
1510*0785c323SJustin Hibbits
15117c208ed6SRick Macklem void
bootpc_init(void)15127c208ed6SRick Macklem bootpc_init(void)
15137c208ed6SRick Macklem {
1514*0785c323SJustin Hibbits struct epoch_tracker et;
15150b1b30d6SAlfredo Dal'Ava Junior struct bootpc_ifcontext *ifctx = NULL; /* Interface BOOTP contexts */
15167c208ed6SRick Macklem struct bootpc_globalcontext *gctx; /* Global BOOTP context */
15176bfaa839SGleb Smirnoff struct sockaddr_dl *sdl;
1518*0785c323SJustin Hibbits struct if_iter iter;
1519*0785c323SJustin Hibbits if_t ifp;
15207c208ed6SRick Macklem int error;
15217c208ed6SRick Macklem #ifndef BOOTP_WIRED_TO
15227c208ed6SRick Macklem int ifcnt;
15237c208ed6SRick Macklem #endif
15247c208ed6SRick Macklem struct nfsv3_diskless *nd;
15257c208ed6SRick Macklem struct thread *td;
1526c6fd18e0SOleksandr Tymoshenko int timeout;
1527c6fd18e0SOleksandr Tymoshenko int delay;
15283cb9f197SAlfredo Dal'Ava Junior char *s;
1529c6fd18e0SOleksandr Tymoshenko
1530c6fd18e0SOleksandr Tymoshenko timeout = BOOTP_IFACE_WAIT_TIMEOUT * hz;
1531c6fd18e0SOleksandr Tymoshenko delay = hz / 10;
15327c208ed6SRick Macklem
15337c208ed6SRick Macklem nd = &nfsv3_diskless;
15347c208ed6SRick Macklem td = curthread;
15357c208ed6SRick Macklem
15367c208ed6SRick Macklem /*
15377c208ed6SRick Macklem * If already filled in, don't touch it here
15387c208ed6SRick Macklem */
15397c208ed6SRick Macklem if (nfs_diskless_valid != 0)
15407c208ed6SRick Macklem return;
15417c208ed6SRick Macklem
15423cb9f197SAlfredo Dal'Ava Junior /*
15433cb9f197SAlfredo Dal'Ava Junior * If "vfs.root.mountfrom" is set and the value is something other
15443cb9f197SAlfredo Dal'Ava Junior * than "nfs:", it means the user doesn't want to mount root via nfs,
15453cb9f197SAlfredo Dal'Ava Junior * there's no reason to continue with bootpc
15463cb9f197SAlfredo Dal'Ava Junior */
15473cb9f197SAlfredo Dal'Ava Junior if ((s = kern_getenv("vfs.root.mountfrom")) != NULL) {
15483cb9f197SAlfredo Dal'Ava Junior if ((strncmp(s, "nfs:", 4)) != 0) {
15493cb9f197SAlfredo Dal'Ava Junior printf("%s: vfs.root.mountfrom set to %s. "
15503cb9f197SAlfredo Dal'Ava Junior "BOOTP aborted.\n", __func__, s);
15513cb9f197SAlfredo Dal'Ava Junior freeenv(s);
15523cb9f197SAlfredo Dal'Ava Junior return;
15533cb9f197SAlfredo Dal'Ava Junior }
15543cb9f197SAlfredo Dal'Ava Junior freeenv(s);
15553cb9f197SAlfredo Dal'Ava Junior }
15563cb9f197SAlfredo Dal'Ava Junior
15577c208ed6SRick Macklem gctx = malloc(sizeof(*gctx), M_TEMP, M_WAITOK | M_ZERO);
15586bfaa839SGleb Smirnoff STAILQ_INIT(&gctx->interfaces);
15597c208ed6SRick Macklem gctx->xid = ~0xFFFF;
15607c208ed6SRick Macklem gctx->starttime = time_second;
15617c208ed6SRick Macklem
15627c208ed6SRick Macklem /*
15636cbd933bSIan Lepore * If ROOTDEVNAME is defined or vfs.root.mountfrom is set then we have
15646cbd933bSIan Lepore * root-path overrides that can potentially let us boot even if we don't
15656cbd933bSIan Lepore * get a root path from the server, so we can treat that as a non-error.
15666cbd933bSIan Lepore */
15676cbd933bSIan Lepore #ifdef ROOTDEVNAME
15686cbd933bSIan Lepore gctx->any_root_overrides = 1;
15696cbd933bSIan Lepore #else
15706cbd933bSIan Lepore gctx->any_root_overrides = testenv("vfs.root.mountfrom");
15716cbd933bSIan Lepore #endif
15726cbd933bSIan Lepore
15736cbd933bSIan Lepore /*
15747c208ed6SRick Macklem * Find a network interface.
15757c208ed6SRick Macklem */
15767c208ed6SRick Macklem CURVNET_SET(TD_TO_VNET(td));
15777c208ed6SRick Macklem #ifdef BOOTP_WIRED_TO
15786bfaa839SGleb Smirnoff printf("%s: wired to interface '%s'\n", __func__,
15797c208ed6SRick Macklem __XSTRING(BOOTP_WIRED_TO));
15807c208ed6SRick Macklem allocifctx(gctx);
15817c208ed6SRick Macklem #else
15827c208ed6SRick Macklem /*
15837c208ed6SRick Macklem * Preallocate interface context storage, if another interface
15847c208ed6SRick Macklem * attaches and wins the race, it won't be eligible for bootp.
15857c208ed6SRick Macklem */
15866bfaa839SGleb Smirnoff ifcnt = 0;
1587*0785c323SJustin Hibbits NET_EPOCH_ENTER(et);
1588*0785c323SJustin Hibbits for (if_t ifp = if_iter_start(&iter); ifp != NULL; ifp = if_iter_next(&iter)) {
1589*0785c323SJustin Hibbits if ((if_getflags(ifp) &
1590*0785c323SJustin Hibbits (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) ==
15917c208ed6SRick Macklem IFF_BROADCAST)
15927c208ed6SRick Macklem ifcnt++;
15937c208ed6SRick Macklem }
1594*0785c323SJustin Hibbits if_iter_finish(&iter);
1595*0785c323SJustin Hibbits NET_EPOCH_EXIT(et);
15960b1b30d6SAlfredo Dal'Ava Junior if (ifcnt == 0) {
15970b1b30d6SAlfredo Dal'Ava Junior printf("WARNING: BOOTP found no eligible network interfaces, skipping!\n");
15980b1b30d6SAlfredo Dal'Ava Junior goto out;
15990b1b30d6SAlfredo Dal'Ava Junior }
16000b1b30d6SAlfredo Dal'Ava Junior
16017c208ed6SRick Macklem for (; ifcnt > 0; ifcnt--)
16027c208ed6SRick Macklem allocifctx(gctx);
16037c208ed6SRick Macklem #endif
16047c208ed6SRick Macklem
16051d4c5e51SOleksandr Tymoshenko retry:
16066bfaa839SGleb Smirnoff ifctx = STAILQ_FIRST(&gctx->interfaces);
1607*0785c323SJustin Hibbits NET_EPOCH_ENTER(et);
1608*0785c323SJustin Hibbits for (ifp = if_iter_start(&iter); ifp != NULL; ifp = if_iter_next(&iter)) {
16096bfaa839SGleb Smirnoff if (ifctx == NULL)
16106bfaa839SGleb Smirnoff break;
16117c208ed6SRick Macklem #ifdef BOOTP_WIRED_TO
1612*0785c323SJustin Hibbits if (strcmp(if_name(ifp), __XSTRING(BOOTP_WIRED_TO)) != 0)
16137c208ed6SRick Macklem continue;
16147c208ed6SRick Macklem #else
1615*0785c323SJustin Hibbits if ((if_getflags(ifp) &
16167c208ed6SRick Macklem (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) !=
16177c208ed6SRick Macklem IFF_BROADCAST)
1618*0785c323SJustin Hibbits break;
1619*0785c323SJustin Hibbits switch (if_getalloctype(ifp)) {
16206bfaa839SGleb Smirnoff case IFT_ETHER:
16216bfaa839SGleb Smirnoff break;
16226bfaa839SGleb Smirnoff default:
16236bfaa839SGleb Smirnoff continue;
16246bfaa839SGleb Smirnoff }
16257c208ed6SRick Macklem #endif
1626*0785c323SJustin Hibbits strlcpy(ifctx->ireq.ifr_name, if_name(ifp),
16276bfaa839SGleb Smirnoff sizeof(ifctx->ireq.ifr_name));
16287c208ed6SRick Macklem ifctx->ifp = ifp;
16296bfaa839SGleb Smirnoff
16306bfaa839SGleb Smirnoff /* Get HW address */
16316bfaa839SGleb Smirnoff sdl = NULL;
1632*0785c323SJustin Hibbits if_foreach_addr_type(ifp, AF_LINK, bootpc_init_ifa_cb, &sdl);
16336bfaa839SGleb Smirnoff if (sdl == NULL)
16346bfaa839SGleb Smirnoff panic("bootpc: Unable to find HW address for %s",
16356bfaa839SGleb Smirnoff ifctx->ireq.ifr_name);
16366bfaa839SGleb Smirnoff ifctx->sdl = sdl;
16376bfaa839SGleb Smirnoff
16386bfaa839SGleb Smirnoff ifctx = STAILQ_NEXT(ifctx, next);
16397c208ed6SRick Macklem }
1640*0785c323SJustin Hibbits if_iter_finish(&iter);
1641*0785c323SJustin Hibbits NET_EPOCH_EXIT(et);
16427c208ed6SRick Macklem CURVNET_RESTORE();
16437c208ed6SRick Macklem
16446bfaa839SGleb Smirnoff if (STAILQ_EMPTY(&gctx->interfaces) ||
16456bfaa839SGleb Smirnoff STAILQ_FIRST(&gctx->interfaces)->ifp == NULL) {
16461d4c5e51SOleksandr Tymoshenko if (timeout > 0) {
16471d4c5e51SOleksandr Tymoshenko pause("bootpc", delay);
16481d4c5e51SOleksandr Tymoshenko timeout -= delay;
16491d4c5e51SOleksandr Tymoshenko goto retry;
16501d4c5e51SOleksandr Tymoshenko }
16517c208ed6SRick Macklem #ifdef BOOTP_WIRED_TO
16526bfaa839SGleb Smirnoff panic("%s: Could not find interface specified "
16537c208ed6SRick Macklem "by BOOTP_WIRED_TO: "
16546bfaa839SGleb Smirnoff __XSTRING(BOOTP_WIRED_TO), __func__);
16557c208ed6SRick Macklem #else
16566bfaa839SGleb Smirnoff panic("%s: no suitable interface", __func__);
16577c208ed6SRick Macklem #endif
16587c208ed6SRick Macklem }
16597c208ed6SRick Macklem
16606bfaa839SGleb Smirnoff error = socreate(AF_INET, &bootp_so, SOCK_DGRAM, 0, td->td_ucred, td);
16616bfaa839SGleb Smirnoff if (error != 0)
16626bfaa839SGleb Smirnoff panic("%s: socreate, error=%d", __func__, error);
16637c208ed6SRick Macklem
16646bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
16656bfaa839SGleb Smirnoff bootpc_fakeup_interface(ifctx, td);
16666bfaa839SGleb Smirnoff
16676bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
16686bfaa839SGleb Smirnoff bootpc_compose_query(ifctx, td);
16697c208ed6SRick Macklem
16707c208ed6SRick Macklem error = bootpc_call(gctx, td);
16717c208ed6SRick Macklem if (error != 0) {
16727c208ed6SRick Macklem printf("BOOTP call failed\n");
16737c208ed6SRick Macklem }
16747c208ed6SRick Macklem
16757c208ed6SRick Macklem mountopts(&nd->root_args, NULL);
16767c208ed6SRick Macklem
16776bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
16787c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) != 0)
16797c208ed6SRick Macklem bootpc_decode_reply(nd, ifctx, gctx);
16807c208ed6SRick Macklem
16817c208ed6SRick Macklem #ifdef BOOTP_NFSROOT
16826cbd933bSIan Lepore if (gctx->gotrootpath == 0 && gctx->any_root_overrides == 0)
16837c208ed6SRick Macklem panic("bootpc: No root path offered");
16847c208ed6SRick Macklem #endif
16857c208ed6SRick Macklem
16866bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
16877c208ed6SRick Macklem bootpc_adjust_interface(ifctx, gctx, td);
16887c208ed6SRick Macklem
16896bfaa839SGleb Smirnoff soclose(bootp_so);
16907c208ed6SRick Macklem
16916bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
16927c208ed6SRick Macklem if (ifctx->gotrootpath != 0)
16937c208ed6SRick Macklem break;
16947c208ed6SRick Macklem if (ifctx == NULL) {
16956bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
16967c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) != 0)
16977c208ed6SRick Macklem break;
16987c208ed6SRick Macklem }
16997c208ed6SRick Macklem if (ifctx == NULL)
17007c208ed6SRick Macklem goto out;
17017c208ed6SRick Macklem
17027c208ed6SRick Macklem if (gctx->gotrootpath != 0) {
17032bbab0afSAlexander V. Chernikov struct epoch_tracker et;
17047c208ed6SRick Macklem
1705*0785c323SJustin Hibbits kern_setenv("boot.netif.name", if_name(ifctx->ifp));
17067c208ed6SRick Macklem
17072bbab0afSAlexander V. Chernikov NET_EPOCH_ENTER(et);
17082596e591SIan Lepore bootpc_add_default_route(ifctx);
170998727c6cSBrandon Bergren NET_EPOCH_EXIT(et);
17107c208ed6SRick Macklem error = md_mount(&nd->root_saddr, nd->root_hostnam,
17117c208ed6SRick Macklem nd->root_fh, &nd->root_fhsize,
17127c208ed6SRick Macklem &nd->root_args, td);
171398727c6cSBrandon Bergren NET_EPOCH_ENTER(et);
17142596e591SIan Lepore bootpc_remove_default_route(ifctx);
17152bbab0afSAlexander V. Chernikov NET_EPOCH_EXIT(et);
17166cbd933bSIan Lepore if (error != 0) {
17176cbd933bSIan Lepore if (gctx->any_root_overrides == 0)
17186cbd933bSIan Lepore panic("nfs_boot: mount root, error=%d", error);
17196cbd933bSIan Lepore else
17206cbd933bSIan Lepore goto out;
17216cbd933bSIan Lepore }
17226cbd933bSIan Lepore rootdevnames[0] = "nfs:";
17237c208ed6SRick Macklem nfs_diskless_valid = 3;
17247c208ed6SRick Macklem }
17257c208ed6SRick Macklem
17267c208ed6SRick Macklem strcpy(nd->myif.ifra_name, ifctx->ireq.ifr_name);
17277c208ed6SRick Macklem bcopy(&ifctx->myaddr, &nd->myif.ifra_addr, sizeof(ifctx->myaddr));
17287c208ed6SRick Macklem bcopy(&ifctx->myaddr, &nd->myif.ifra_broadaddr, sizeof(ifctx->myaddr));
17297c208ed6SRick Macklem ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
17307c208ed6SRick Macklem ifctx->myaddr.sin_addr.s_addr |
17317c208ed6SRick Macklem ~ ifctx->netmask.sin_addr.s_addr;
17327c208ed6SRick Macklem bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask));
17332596e591SIan Lepore bcopy(&ifctx->gw, &nd->mygateway, sizeof(ifctx->gw));
17347c208ed6SRick Macklem
17357c208ed6SRick Macklem out:
17366bfaa839SGleb Smirnoff while((ifctx = STAILQ_FIRST(&gctx->interfaces)) != NULL) {
17376bfaa839SGleb Smirnoff STAILQ_REMOVE_HEAD(&gctx->interfaces, next);
17387c208ed6SRick Macklem free(ifctx, M_TEMP);
17397c208ed6SRick Macklem }
17407c208ed6SRick Macklem free(gctx, M_TEMP);
17417c208ed6SRick Macklem }
17427c208ed6SRick Macklem
17437c208ed6SRick Macklem /*
17447c208ed6SRick Macklem * RPC: mountd/mount
17457c208ed6SRick Macklem * Given a server pathname, get an NFS file handle.
17467c208ed6SRick Macklem * Also, sets sin->sin_port to the NFS service port.
17477c208ed6SRick Macklem */
17487c208ed6SRick Macklem static int
md_mount(struct sockaddr_in * mdsin,char * path,u_char * fhp,int * fhsizep,struct nfs_args * args,struct thread * td)17497c208ed6SRick Macklem md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp, int *fhsizep,
17507c208ed6SRick Macklem struct nfs_args *args, struct thread *td)
17517c208ed6SRick Macklem {
17527c208ed6SRick Macklem struct mbuf *m;
17537c208ed6SRick Macklem int error;
17547c208ed6SRick Macklem int authunixok;
17557c208ed6SRick Macklem int authcount;
17567c208ed6SRick Macklem int authver;
17577c208ed6SRick Macklem
17587c208ed6SRick Macklem #define RPCPROG_MNT 100005
17597c208ed6SRick Macklem #define RPCMNT_VER1 1
17607c208ed6SRick Macklem #define RPCMNT_VER3 3
17617c208ed6SRick Macklem #define RPCMNT_MOUNT 1
17627c208ed6SRick Macklem #define AUTH_SYS 1 /* unix style (uid, gids) */
17637c208ed6SRick Macklem #define AUTH_UNIX AUTH_SYS
17647c208ed6SRick Macklem
17657c208ed6SRick Macklem /* XXX honor v2/v3 flags in args->flags? */
17667c208ed6SRick Macklem #ifdef BOOTP_NFSV3
17677c208ed6SRick Macklem /* First try NFS v3 */
17687c208ed6SRick Macklem /* Get port number for MOUNTD. */
17697c208ed6SRick Macklem error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
17707c208ed6SRick Macklem &mdsin->sin_port, td);
17717c208ed6SRick Macklem if (error == 0) {
17727c208ed6SRick Macklem m = xdr_string_encode(path, strlen(path));
17737c208ed6SRick Macklem
17747c208ed6SRick Macklem /* Do RPC to mountd. */
17757c208ed6SRick Macklem error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
17767c208ed6SRick Macklem RPCMNT_MOUNT, &m, NULL, td);
17777c208ed6SRick Macklem }
17787c208ed6SRick Macklem if (error == 0) {
17797c208ed6SRick Macklem args->flags |= NFSMNT_NFSV3;
17807c208ed6SRick Macklem } else {
17817c208ed6SRick Macklem #endif
17827c208ed6SRick Macklem /* Fallback to NFS v2 */
17837c208ed6SRick Macklem
17847c208ed6SRick Macklem /* Get port number for MOUNTD. */
17857c208ed6SRick Macklem error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
17867c208ed6SRick Macklem &mdsin->sin_port, td);
17877c208ed6SRick Macklem if (error != 0)
17887c208ed6SRick Macklem return error;
17897c208ed6SRick Macklem
17907c208ed6SRick Macklem m = xdr_string_encode(path, strlen(path));
17917c208ed6SRick Macklem
17927c208ed6SRick Macklem /* Do RPC to mountd. */
17937c208ed6SRick Macklem error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
17947c208ed6SRick Macklem RPCMNT_MOUNT, &m, NULL, td);
17957c208ed6SRick Macklem if (error != 0)
17967c208ed6SRick Macklem return error; /* message already freed */
17977c208ed6SRick Macklem
17987c208ed6SRick Macklem #ifdef BOOTP_NFSV3
17997c208ed6SRick Macklem }
18007c208ed6SRick Macklem #endif
18017c208ed6SRick Macklem
18027c208ed6SRick Macklem if (xdr_int_decode(&m, &error) != 0 || error != 0)
18037c208ed6SRick Macklem goto bad;
18047c208ed6SRick Macklem
18057c208ed6SRick Macklem if ((args->flags & NFSMNT_NFSV3) != 0) {
18067c208ed6SRick Macklem if (xdr_int_decode(&m, fhsizep) != 0 ||
18077c208ed6SRick Macklem *fhsizep > NFSX_V3FHMAX ||
18087c208ed6SRick Macklem *fhsizep <= 0)
18097c208ed6SRick Macklem goto bad;
18107c208ed6SRick Macklem } else
18117c208ed6SRick Macklem *fhsizep = NFSX_V2FH;
18127c208ed6SRick Macklem
18137c208ed6SRick Macklem if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
18147c208ed6SRick Macklem goto bad;
18157c208ed6SRick Macklem
18167c208ed6SRick Macklem if (args->flags & NFSMNT_NFSV3) {
18177c208ed6SRick Macklem if (xdr_int_decode(&m, &authcount) != 0)
18187c208ed6SRick Macklem goto bad;
18197c208ed6SRick Macklem authunixok = 0;
18207c208ed6SRick Macklem if (authcount < 0 || authcount > 100)
18217c208ed6SRick Macklem goto bad;
18227c208ed6SRick Macklem while (authcount > 0) {
18237c208ed6SRick Macklem if (xdr_int_decode(&m, &authver) != 0)
18247c208ed6SRick Macklem goto bad;
18257c208ed6SRick Macklem if (authver == AUTH_UNIX)
18267c208ed6SRick Macklem authunixok = 1;
18277c208ed6SRick Macklem authcount--;
18287c208ed6SRick Macklem }
18297c208ed6SRick Macklem if (authunixok == 0)
18307c208ed6SRick Macklem goto bad;
18317c208ed6SRick Macklem }
18327c208ed6SRick Macklem
18337c208ed6SRick Macklem /* Set port number for NFS use. */
18347c208ed6SRick Macklem error = krpc_portmap(mdsin, NFS_PROG,
18357c208ed6SRick Macklem (args->flags &
18367c208ed6SRick Macklem NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
18377c208ed6SRick Macklem &mdsin->sin_port, td);
18387c208ed6SRick Macklem
18397c208ed6SRick Macklem goto out;
18407c208ed6SRick Macklem
18417c208ed6SRick Macklem bad:
18427c208ed6SRick Macklem error = EBADRPC;
18437c208ed6SRick Macklem
18447c208ed6SRick Macklem out:
18457c208ed6SRick Macklem m_freem(m);
18467c208ed6SRick Macklem return error;
18477c208ed6SRick Macklem }
18487c208ed6SRick Macklem
18497c208ed6SRick Macklem SYSINIT(bootp_rootconf, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, bootpc_init, NULL);
1850