1139823Simp/*- 225723Stegge * Copyright (c) 1995 Gordon Ross, Adam Glass 325723Stegge * Copyright (c) 1992 Regents of the University of California. 425723Stegge * All rights reserved. 525723Stegge * 625723Stegge * This software was developed by the Computer Systems Engineering group 725723Stegge * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 825723Stegge * contributed to Berkeley. 925723Stegge * 1025723Stegge * Redistribution and use in source and binary forms, with or without 1125723Stegge * modification, are permitted provided that the following conditions 1225723Stegge * are met: 1325723Stegge * 1. Redistributions of source code must retain the above copyright 1425723Stegge * notice, this list of conditions and the following disclaimer. 1525723Stegge * 2. Redistributions in binary form must reproduce the above copyright 1625723Stegge * notice, this list of conditions and the following disclaimer in the 1725723Stegge * documentation and/or other materials provided with the distribution. 1825723Stegge * 3. All advertising materials mentioning features or use of this software 1925723Stegge * must display the following acknowledgement: 2025723Stegge * This product includes software developed by the University of 2125723Stegge * California, Lawrence Berkeley Laboratory and its contributors. 2225723Stegge * 4. Neither the name of the University nor the names of its contributors 2325723Stegge * may be used to endorse or promote products derived from this software 2425723Stegge * without specific prior written permission. 2525723Stegge * 2625723Stegge * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2725723Stegge * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2825723Stegge * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2925723Stegge * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3025723Stegge * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3125723Stegge * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3225723Stegge * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3325723Stegge * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3425723Stegge * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3525723Stegge * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3625723Stegge * SUCH DAMAGE. 3725723Stegge * 3825723Stegge * based on: 3925723Stegge * nfs/krpc_subr.c 4025723Stegge * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $ 4125723Stegge */ 4225723Stegge 4383651Speter#include <sys/cdefs.h> 4483651Speter__FBSDID("$FreeBSD$"); 4583651Speter 46131840Sbrian#include "opt_bootp.h" 47223673Sgber#include "opt_nfs.h" 48253847Sian#include "opt_rootdevname.h" 49131840Sbrian 5025723Stegge#include <sys/param.h> 5125723Stegge#include <sys/systm.h> 52193066Sjamie#include <sys/jail.h> 5325723Stegge#include <sys/kernel.h> 5425723Stegge#include <sys/sockio.h> 5567834Stegge#include <sys/malloc.h> 5625723Stegge#include <sys/mount.h> 5725723Stegge#include <sys/mbuf.h> 5888743Srwatson#include <sys/proc.h> 59253847Sian#include <sys/reboot.h> 6025723Stegge#include <sys/socket.h> 6125723Stegge#include <sys/socketvar.h> 6292219Sluigi#include <sys/sysctl.h> 6334924Sbde#include <sys/uio.h> 6425723Stegge 6525723Stegge#include <net/if.h> 6625723Stegge#include <net/route.h> 6725723Stegge 6825723Stegge#include <netinet/in.h> 69228455Sglebius#include <netinet/in_var.h> 7025723Stegge#include <net/if_types.h> 7125723Stegge#include <net/if_dl.h> 72185571Sbz#include <net/vnet.h> 7325723Stegge 7425723Stegge#include <nfs/nfsproto.h> 7583651Speter#include <nfsclient/nfs.h> 76221032Srmacklem#include <nfs/nfsdiskless.h> 77221032Srmacklem#include <nfs/krpc.h> 7825723Stegge#include <nfs/xdr_subs.h> 7925723Stegge 8025723Stegge 8132609Stegge#define BOOTP_MIN_LEN 300 /* Minimum size of bootp udp packet */ 8225723Stegge 8367834Stegge#ifndef BOOTP_SETTLE_DELAY 8467834Stegge#define BOOTP_SETTLE_DELAY 3 8567834Stegge#endif 8667834Stegge 87239318Sgonzo/* 88239318Sgonzo * Wait 10 seconds for interface appearance 89239337Sgonzo * USB ethernet adapters might require some time to pop up 90239318Sgonzo */ 91239318Sgonzo#ifndef BOOTP_IFACE_WAIT_TIMEOUT 92239318Sgonzo#define BOOTP_IFACE_WAIT_TIMEOUT 10 93239318Sgonzo#endif 94239318Sgonzo 9525723Stegge/* 9625723Stegge * What is the longest we will wait before re-sending a request? 9725723Stegge * Note this is also the frequency of "RPC timeout" messages. 9825723Stegge * The re-send loop count sup linearly to this maximum, so the 9925723Stegge * first complaint will happen after (1+2+3+4+5)=15 seconds. 10025723Stegge */ 10125723Stegge#define MAX_RESEND_DELAY 5 /* seconds */ 10225723Stegge 10325723Stegge/* Definitions from RFC951 */ 10425723Steggestruct bootp_packet { 10567531Stegge u_int8_t op; 10667531Stegge u_int8_t htype; 10767531Stegge u_int8_t hlen; 10867531Stegge u_int8_t hops; 10967531Stegge u_int32_t xid; 11067531Stegge u_int16_t secs; 11167531Stegge u_int16_t flags; 11267531Stegge struct in_addr ciaddr; 11367531Stegge struct in_addr yiaddr; 11467531Stegge struct in_addr siaddr; 11567531Stegge struct in_addr giaddr; 11667531Stegge unsigned char chaddr[16]; 11767531Stegge char sname[64]; 11867531Stegge char file[128]; 11988680Sambrisko unsigned char vend[1222]; 12025723Stegge}; 12125723Stegge 12267834Steggestruct bootpc_ifcontext { 123228455Sglebius STAILQ_ENTRY(bootpc_ifcontext) next; 12467834Stegge struct bootp_packet call; 12567834Stegge struct bootp_packet reply; 12667834Stegge int replylen; 12767834Stegge int overload; 128228455Sglebius union { 129228455Sglebius struct ifreq _ifreq; 130228455Sglebius struct in_aliasreq _in_alias_req; 131228455Sglebius } _req; 132228455Sglebius#define ireq _req._ifreq 133228455Sglebius#define iareq _req._in_alias_req 13467834Stegge struct ifnet *ifp; 13567834Stegge struct sockaddr_dl *sdl; 13667834Stegge struct sockaddr_in myaddr; 13767834Stegge struct sockaddr_in netmask; 13867834Stegge struct sockaddr_in gw; 13967834Stegge int gotgw; 14067834Stegge int gotnetmask; 14167834Stegge int gotrootpath; 14267834Stegge int outstanding; 14367834Stegge int sentmsg; 14467834Stegge u_int32_t xid; 14567834Stegge enum { 14667834Stegge IF_BOOTP_UNRESOLVED, 14767834Stegge IF_BOOTP_RESOLVED, 14871915Stegge IF_BOOTP_FAILED, 14971915Stegge IF_DHCP_UNRESOLVED, 15067834Stegge IF_DHCP_OFFERED, 15167834Stegge IF_DHCP_RESOLVED, 15271915Stegge IF_DHCP_FAILED, 15367834Stegge } state; 15471915Stegge int dhcpquerytype; /* dhcp type sent */ 15571915Stegge struct in_addr dhcpserver; 15671915Stegge int gotdhcpserver; 15767834Stegge}; 15867834Stegge 15967834Stegge#define TAG_MAXLEN 1024 16067834Steggestruct bootpc_tagcontext { 16167834Stegge char buf[TAG_MAXLEN + 1]; 16267834Stegge int overload; 16367834Stegge int badopt; 16467834Stegge int badtag; 16567834Stegge int foundopt; 16667834Stegge int taglen; 16767834Stegge}; 16867834Stegge 16967834Steggestruct bootpc_globalcontext { 170228455Sglebius STAILQ_HEAD(, bootpc_ifcontext) interfaces; 17167834Stegge u_int32_t xid; 172253847Sian int any_root_overrides; 17367834Stegge int gotrootpath; 17467834Stegge int gotgw; 17567834Stegge int ifnum; 17667834Stegge int secs; 17767834Stegge int starttime; 17867834Stegge struct bootp_packet reply; 17967834Stegge int replylen; 18067834Stegge struct bootpc_ifcontext *setrootfs; 18167834Stegge struct bootpc_ifcontext *sethostname; 18267834Stegge struct bootpc_tagcontext tmptag; 18367834Stegge struct bootpc_tagcontext tag; 18467834Stegge}; 18567834Stegge 18625723Stegge#define IPPORT_BOOTPC 68 18725723Stegge#define IPPORT_BOOTPS 67 18825723Stegge 18967834Stegge#define BOOTP_REQUEST 1 19067834Stegge#define BOOTP_REPLY 2 19167834Stegge 19267834Stegge/* Common tags */ 19367834Stegge#define TAG_PAD 0 /* Pad option, implicit length 1 */ 19467834Stegge#define TAG_SUBNETMASK 1 /* RFC 950 subnet mask */ 19567834Stegge#define TAG_ROUTERS 3 /* Routers (in order of preference) */ 19667834Stegge#define TAG_HOSTNAME 12 /* Client host name */ 19767834Stegge#define TAG_ROOT 17 /* Root path */ 19867834Stegge 19967834Stegge/* DHCP specific tags */ 20067834Stegge#define TAG_OVERLOAD 52 /* Option Overload */ 20167834Stegge#define TAG_MAXMSGSIZE 57 /* Maximum DHCP Message Size */ 20267834Stegge 20367834Stegge#define TAG_END 255 /* End Option (i.e. no more options) */ 20467834Stegge 20567834Stegge/* Overload values */ 20667834Stegge#define OVERLOAD_FILE 1 20767834Stegge#define OVERLOAD_SNAME 2 20867834Stegge 20967834Stegge/* Site specific tags: */ 21067834Stegge#define TAG_ROOTOPTS 130 21192219Sluigi#define TAG_COOKIE 134 /* ascii info for userland, via sysctl */ 21267834Stegge 21371915Stegge#define TAG_DHCP_MSGTYPE 53 21471915Stegge#define TAG_DHCP_REQ_ADDR 50 21571915Stegge#define TAG_DHCP_SERVERID 54 21671915Stegge#define TAG_DHCP_LEASETIME 51 21771915Stegge 21896825Sambrisko#define TAG_VENDOR_INDENTIFIER 60 21996825Sambrisko 22071915Stegge#define DHCP_NOMSG 0 22171915Stegge#define DHCP_DISCOVER 1 22271915Stegge#define DHCP_OFFER 2 22371915Stegge#define DHCP_REQUEST 3 22471915Stegge#define DHCP_ACK 5 22571915Stegge 226179039Sbenno/* NFS read/write block size */ 227179039Sbenno#ifndef BOOTP_BLOCKSIZE 228179039Sbenno#define BOOTP_BLOCKSIZE 8192 229179039Sbenno#endif 230179039Sbenno 23192219Sluigistatic char bootp_cookie[128]; 232228455Sglebiusstatic struct socket *bootp_so; 23392219SluigiSYSCTL_STRING(_kern, OID_AUTO, bootp_cookie, CTLFLAG_RD, 23492219Sluigi bootp_cookie, 0, "Cookie (T134) supplied by bootp server"); 23592219Sluigi 23625723Stegge/* mountd RPC */ 23783651Speterstatic int md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp, 23883651Speter int *fhsizep, struct nfs_args *args, struct thread *td); 239126888Sbrooksstatic int setfs(struct sockaddr_in *addr, char *path, char *p, 240126888Sbrooks const struct in_addr *siaddr); 24183651Speterstatic int getdec(char **ptr); 242126888Sbrooksstatic int getip(char **ptr, struct in_addr *ip); 24383651Speterstatic void mountopts(struct nfs_args *args, char *p); 24483651Speterstatic int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len); 24583651Speterstatic int xdr_int_decode(struct mbuf **ptr, int *iptr); 24683651Speterstatic void print_in_addr(struct in_addr addr); 24783651Speterstatic void print_sin_addr(struct sockaddr_in *addr); 24883651Speterstatic void clear_sinaddr(struct sockaddr_in *sin); 249118639Sbillfstatic void allocifctx(struct bootpc_globalcontext *gctx); 25083651Speterstatic void bootpc_compose_query(struct bootpc_ifcontext *ifctx, 251228455Sglebius struct thread *td); 25267834Steggestatic unsigned char *bootpc_tag(struct bootpc_tagcontext *tctx, 25383651Speter struct bootp_packet *bp, int len, int tag); 25467834Steggestatic void bootpc_tag_helper(struct bootpc_tagcontext *tctx, 25583651Speter unsigned char *start, int len, int tag); 25625723Stegge 25725723Stegge#ifdef BOOTP_DEBUG 25883651Spetervoid bootpboot_p_sa(struct sockaddr *sa, struct sockaddr *ma); 25925723Steggevoid bootpboot_p_rtentry(struct rtentry *rt); 26025723Steggevoid bootpboot_p_tree(struct radix_node *rn); 26125723Steggevoid bootpboot_p_rtlist(void); 26267834Steggevoid bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa); 26325723Steggevoid bootpboot_p_iflist(void); 26425723Stegge#endif 26525723Stegge 26683651Speterstatic int bootpc_call(struct bootpc_globalcontext *gctx, 26783651Speter struct thread *td); 26825723Stegge 269228455Sglebiusstatic void bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx, 270228455Sglebius struct thread *td); 27125723Stegge 27283651Speterstatic int bootpc_adjust_interface(struct bootpc_ifcontext *ifctx, 27383651Speter struct bootpc_globalcontext *gctx, struct thread *td); 27425723Stegge 27583651Speterstatic void bootpc_decode_reply(struct nfsv3_diskless *nd, 27683651Speter struct bootpc_ifcontext *ifctx, 27783651Speter struct bootpc_globalcontext *gctx); 27867834Stegge 27983651Speterstatic int bootpc_received(struct bootpc_globalcontext *gctx, 28083651Speter struct bootpc_ifcontext *ifctx); 28167834Stegge 28271915Steggestatic __inline int bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx); 28371915Steggestatic __inline int bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx); 28471915Steggestatic __inline int bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx); 28571915Stegge 28667834Stegge/* 28767834Stegge * In order to have multiple active interfaces with address 0.0.0.0 288228455Sglebius * and be able to send data to a selected interface, we first set 289228455Sglebius * mask to /8 on all interfaces, and temporarily set it to /0 when 290228455Sglebius * doing sosend(). 29167834Stegge */ 29267834Stegge 29325723Stegge#ifdef BOOTP_DEBUG 29467531Steggevoid 29583651Speterbootpboot_p_sa(struct sockaddr *sa, struct sockaddr *ma) 29625723Stegge{ 29783651Speter 29867531Stegge if (sa == NULL) { 29967531Stegge printf("(sockaddr *) <null>"); 30067531Stegge return; 30167531Stegge } 30267531Stegge switch (sa->sa_family) { 30367531Stegge case AF_INET: 30467531Stegge { 30567531Stegge struct sockaddr_in *sin; 30683651Speter 30767531Stegge sin = (struct sockaddr_in *) sa; 30867834Stegge printf("inet "); 30967834Stegge print_sin_addr(sin); 31067531Stegge if (ma != NULL) { 31167531Stegge sin = (struct sockaddr_in *) ma; 31267834Stegge printf(" mask "); 31367834Stegge print_sin_addr(sin); 31467531Stegge } 31567531Stegge } 31667531Stegge break; 31767531Stegge case AF_LINK: 31867531Stegge { 31967531Stegge struct sockaddr_dl *sli; 32067531Stegge int i; 32183651Speter 32267531Stegge sli = (struct sockaddr_dl *) sa; 32367531Stegge printf("link %.*s ", sli->sdl_nlen, sli->sdl_data); 32467531Stegge for (i = 0; i < sli->sdl_alen; i++) { 32567531Stegge if (i > 0) 32667531Stegge printf(":"); 32767531Stegge printf("%x", ((unsigned char *) LLADDR(sli))[i]); 32867531Stegge } 32967531Stegge } 33067531Stegge break; 33167531Stegge default: 33267531Stegge printf("af%d", sa->sa_family); 33367531Stegge } 33425723Stegge} 33525723Stegge 33667531Steggevoid 33767531Steggebootpboot_p_rtentry(struct rtentry *rt) 33825723Stegge{ 33983651Speter 34067531Stegge bootpboot_p_sa(rt_key(rt), rt_mask(rt)); 34167531Stegge printf(" "); 34267531Stegge bootpboot_p_sa(rt->rt_gateway, NULL); 34367531Stegge printf(" "); 34467531Stegge printf("flags %x", (unsigned short) rt->rt_flags); 345263478Sglebius printf(" %d", (int) rt->rt_expire); 346121816Sbrooks printf(" %s\n", rt->rt_ifp->if_xname); 34725723Stegge} 34867531Stegge 34967531Steggevoid 35067531Steggebootpboot_p_tree(struct radix_node *rn) 35125723Stegge{ 35283651Speter 35367531Stegge while (rn != NULL) { 35467534Stegge if (rn->rn_bit < 0) { 35567531Stegge if ((rn->rn_flags & RNF_ROOT) != 0) { 35667531Stegge } else { 35767531Stegge bootpboot_p_rtentry((struct rtentry *) rn); 35867531Stegge } 35967531Stegge rn = rn->rn_dupedkey; 36067531Stegge } else { 36167534Stegge bootpboot_p_tree(rn->rn_left); 36267534Stegge bootpboot_p_tree(rn->rn_right); 36367531Stegge return; 36467531Stegge } 36567531Stegge } 36625723Stegge} 36725723Stegge 36867531Steggevoid 36967531Steggebootpboot_p_rtlist(void) 37025723Stegge{ 371193232Sbz struct radix_node_head *rnh; 37283651Speter 37367531Stegge printf("Routing table:\n"); 374193232Sbz rnh = rt_tables_get_rnh(0, AF_INET); 375193232Sbz if (rnh == NULL) 376193232Sbz return; 377193232Sbz RADIX_NODE_HEAD_RLOCK(rnh); /* could sleep XXX */ 378193232Sbz bootpboot_p_tree(rnh->rnh_treetop); 379193232Sbz RADIX_NODE_HEAD_RUNLOCK(rnh); 38025723Stegge} 38125723Stegge 38267531Steggevoid 38367834Steggebootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa) 38467834Stegge{ 38583651Speter 386121816Sbrooks printf("%s flags %x, addr ", 387121816Sbrooks ifp->if_xname, ifp->if_flags); 38867834Stegge print_sin_addr((struct sockaddr_in *) ifa->ifa_addr); 38967834Stegge printf(", broadcast "); 39067834Stegge print_sin_addr((struct sockaddr_in *) ifa->ifa_dstaddr); 39167834Stegge printf(", netmask "); 39267834Stegge print_sin_addr((struct sockaddr_in *) ifa->ifa_netmask); 39367834Stegge printf("\n"); 39467834Stegge} 39567834Stegge 39667834Steggevoid 39767531Steggebootpboot_p_iflist(void) 39825723Stegge{ 39967531Stegge struct ifnet *ifp; 40067531Stegge struct ifaddr *ifa; 40183651Speter 40267531Stegge printf("Interface list:\n"); 403196481Srwatson IFNET_RLOCK(); 404181803Sbz for (ifp = TAILQ_FIRST(&V_ifnet); 40567531Stegge ifp != NULL; 40667834Stegge ifp = TAILQ_NEXT(ifp, if_link)) { 40767531Stegge for (ifa = TAILQ_FIRST(&ifp->if_addrhead); 40867531Stegge ifa != NULL; 40967834Stegge ifa = TAILQ_NEXT(ifa, ifa_link)) 41067834Stegge if (ifa->ifa_addr->sa_family == AF_INET) 41167834Stegge bootpboot_p_if(ifp, ifa); 41225723Stegge } 413108172Shsu IFNET_RUNLOCK(); 41425723Stegge} 41567834Stegge#endif /* defined(BOOTP_DEBUG) */ 41625723Stegge 41767834Steggestatic void 41867834Steggeclear_sinaddr(struct sockaddr_in *sin) 41967834Stegge{ 42083651Speter 42167834Stegge bzero(sin, sizeof(*sin)); 42267834Stegge sin->sin_len = sizeof(*sin); 42367834Stegge sin->sin_family = AF_INET; 42467834Stegge sin->sin_addr.s_addr = INADDR_ANY; /* XXX: htonl(INAADDR_ANY) ? */ 42567834Stegge sin->sin_port = 0; 42667834Stegge} 42767834Stegge 428118639Sbillfstatic void 42967834Steggeallocifctx(struct bootpc_globalcontext *gctx) 43067834Stegge{ 43167834Stegge struct bootpc_ifcontext *ifctx; 43283651Speter 433228455Sglebius ifctx = malloc(sizeof(*ifctx), M_TEMP, M_WAITOK | M_ZERO); 43467834Stegge ifctx->xid = gctx->xid; 43571915Stegge#ifdef BOOTP_NO_DHCP 43671915Stegge ifctx->state = IF_BOOTP_UNRESOLVED; 43771915Stegge#else 43871915Stegge ifctx->state = IF_DHCP_UNRESOLVED; 43971915Stegge#endif 44067834Stegge gctx->xid += 0x100; 441228455Sglebius STAILQ_INSERT_TAIL(&gctx->interfaces, ifctx, next); 44267834Stegge} 44367834Stegge 44471915Steggestatic __inline int 44571915Steggebootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx) 44671915Stegge{ 44783651Speter 44871915Stegge if (ifctx->state == IF_BOOTP_RESOLVED || 44971915Stegge ifctx->state == IF_DHCP_RESOLVED) 45071915Stegge return 1; 45171915Stegge return 0; 45271915Stegge} 45371915Stegge 45471915Steggestatic __inline int 45571915Steggebootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx) 45671915Stegge{ 45783651Speter 45871915Stegge if (ifctx->state == IF_BOOTP_UNRESOLVED || 45971915Stegge ifctx->state == IF_DHCP_UNRESOLVED) 46071915Stegge return 1; 46171915Stegge return 0; 46271915Stegge} 46371915Stegge 46471915Steggestatic __inline int 46571915Steggebootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx) 46671915Stegge{ 46783651Speter 46871915Stegge if (ifctx->state == IF_BOOTP_FAILED || 46971915Stegge ifctx->state == IF_DHCP_FAILED) 47071915Stegge return 1; 47171915Stegge return 0; 47271915Stegge} 47371915Stegge 47433181Seivindstatic int 47567834Steggebootpc_received(struct bootpc_globalcontext *gctx, 47683651Speter struct bootpc_ifcontext *ifctx) 47767834Stegge{ 47871915Stegge unsigned char dhcpreplytype; 47971915Stegge char *p; 48083651Speter 48167834Stegge /* 48267834Stegge * Need timeout for fallback to less 48367834Stegge * desirable alternative. 48467834Stegge */ 48567834Stegge 48667834Stegge /* This call used for the side effect (badopt flag) */ 48767834Stegge (void) bootpc_tag(&gctx->tmptag, &gctx->reply, 48867834Stegge gctx->replylen, 48967834Stegge TAG_END); 49067834Stegge 49167834Stegge /* If packet is invalid, ignore it */ 49267834Stegge if (gctx->tmptag.badopt != 0) 49367834Stegge return 0; 49483651Speter 49571915Stegge p = bootpc_tag(&gctx->tmptag, &gctx->reply, 49671915Stegge gctx->replylen, TAG_DHCP_MSGTYPE); 49771915Stegge if (p != NULL) 49871915Stegge dhcpreplytype = *p; 49971915Stegge else 50071915Stegge dhcpreplytype = DHCP_NOMSG; 50183651Speter 50271915Stegge switch (ifctx->dhcpquerytype) { 50371915Stegge case DHCP_DISCOVER: 50471915Stegge if (dhcpreplytype != DHCP_OFFER /* Normal DHCP offer */ 50571915Stegge#ifndef BOOTP_FORCE_DHCP 50671915Stegge && dhcpreplytype != DHCP_NOMSG /* Fallback to BOOTP */ 50771915Stegge#endif 50871915Stegge ) 50971915Stegge return 0; 51071915Stegge break; 51171915Stegge case DHCP_REQUEST: 51271915Stegge if (dhcpreplytype != DHCP_ACK) 51371915Stegge return 0; 51471915Stegge case DHCP_NOMSG: 51597211Speter break; 51671915Stegge } 51783651Speter 51867834Stegge /* Ignore packet unless it gives us a root tag we didn't have */ 51983651Speter 52071915Stegge if ((ifctx->state == IF_BOOTP_RESOLVED || 52171915Stegge (ifctx->dhcpquerytype == DHCP_DISCOVER && 52271915Stegge (ifctx->state == IF_DHCP_OFFERED || 52371915Stegge ifctx->state == IF_DHCP_RESOLVED))) && 52467834Stegge (bootpc_tag(&gctx->tmptag, &ifctx->reply, 52567834Stegge ifctx->replylen, 52667834Stegge TAG_ROOT) != NULL || 52767834Stegge bootpc_tag(&gctx->tmptag, &gctx->reply, 52867834Stegge gctx->replylen, 52967834Stegge TAG_ROOT) == NULL)) 53067834Stegge return 0; 53183651Speter 53283651Speter bcopy(&gctx->reply, &ifctx->reply, gctx->replylen); 53367834Stegge ifctx->replylen = gctx->replylen; 53483651Speter 53567834Stegge /* XXX: Only reset if 'perfect' response */ 53671915Stegge if (ifctx->state == IF_BOOTP_UNRESOLVED) 53771915Stegge ifctx->state = IF_BOOTP_RESOLVED; 53871915Stegge else if (ifctx->state == IF_DHCP_UNRESOLVED && 53971915Stegge ifctx->dhcpquerytype == DHCP_DISCOVER) { 54071915Stegge if (dhcpreplytype == DHCP_OFFER) 54171915Stegge ifctx->state = IF_DHCP_OFFERED; 54271915Stegge else 54371915Stegge ifctx->state = IF_BOOTP_RESOLVED; /* Fallback */ 54471915Stegge } else if (ifctx->state == IF_DHCP_OFFERED && 54571915Stegge ifctx->dhcpquerytype == DHCP_REQUEST) 54671915Stegge ifctx->state = IF_DHCP_RESOLVED; 54783651Speter 54883651Speter 54971915Stegge if (ifctx->dhcpquerytype == DHCP_DISCOVER && 55071915Stegge ifctx->state != IF_BOOTP_RESOLVED) { 55171915Stegge p = bootpc_tag(&gctx->tmptag, &ifctx->reply, 55271915Stegge ifctx->replylen, TAG_DHCP_SERVERID); 55371915Stegge if (p != NULL && gctx->tmptag.taglen == 4) { 55471915Stegge memcpy(&ifctx->dhcpserver, p, 4); 55571915Stegge ifctx->gotdhcpserver = 1; 55671915Stegge } else 55771915Stegge ifctx->gotdhcpserver = 0; 55871915Stegge return 1; 55971915Stegge } 56083651Speter 56167834Stegge ifctx->gotrootpath = (bootpc_tag(&gctx->tmptag, &ifctx->reply, 56267834Stegge ifctx->replylen, 56367834Stegge TAG_ROOT) != NULL); 56467834Stegge ifctx->gotgw = (bootpc_tag(&gctx->tmptag, &ifctx->reply, 56567834Stegge ifctx->replylen, 56667834Stegge TAG_ROUTERS) != NULL); 56767834Stegge ifctx->gotnetmask = (bootpc_tag(&gctx->tmptag, &ifctx->reply, 56867834Stegge ifctx->replylen, 56967834Stegge TAG_SUBNETMASK) != NULL); 57067834Stegge return 1; 57167834Stegge} 57267834Stegge 57367834Steggestatic int 57483651Speterbootpc_call(struct bootpc_globalcontext *gctx, struct thread *td) 57525723Stegge{ 57667834Stegge struct sockaddr_in *sin, dst; 57725723Stegge struct uio auio; 57838482Swollman struct sockopt sopt; 57925723Stegge struct iovec aio; 58067834Stegge int error, on, rcvflg, timo, len; 58167834Stegge time_t atimo; 58267834Stegge time_t rtimo; 58338482Swollman struct timeval tv; 58467834Stegge struct bootpc_ifcontext *ifctx; 58567834Stegge int outstanding; 58667834Stegge int gotrootpath; 58771915Stegge int retry; 58871915Stegge const char *s; 58983651Speter 59038482Swollman tv.tv_sec = 1; 59138482Swollman tv.tv_usec = 0; 59267834Stegge bzero(&sopt, sizeof(sopt)); 593120755Sjeff sopt.sopt_dir = SOPT_SET; 59438482Swollman sopt.sopt_level = SOL_SOCKET; 59538482Swollman sopt.sopt_name = SO_RCVTIMEO; 59638482Swollman sopt.sopt_val = &tv; 59738482Swollman sopt.sopt_valsize = sizeof tv; 59883651Speter 599228455Sglebius error = sosetopt(bootp_so, &sopt); 60067834Stegge if (error != 0) 60125723Stegge goto out; 60283651Speter 60325723Stegge /* 60425723Stegge * Enable broadcast. 60525723Stegge */ 60638482Swollman on = 1; 60767834Stegge sopt.sopt_name = SO_BROADCAST; 60838482Swollman sopt.sopt_val = &on; 60938482Swollman sopt.sopt_valsize = sizeof on; 61067834Stegge 611228455Sglebius error = sosetopt(bootp_so, &sopt); 61267834Stegge if (error != 0) 61338482Swollman goto out; 61425723Stegge 61525723Stegge /* 61667834Stegge * Disable routing. 61767834Stegge */ 61867834Stegge 61967834Stegge on = 1; 62067834Stegge sopt.sopt_name = SO_DONTROUTE; 62167834Stegge sopt.sopt_val = &on; 62267834Stegge sopt.sopt_valsize = sizeof on; 62367834Stegge 624228455Sglebius error = sosetopt(bootp_so, &sopt); 62567834Stegge if (error != 0) 62667834Stegge goto out; 62783651Speter 62867834Stegge /* 62925723Stegge * Bind the local endpoint to a bootp client port. 63025723Stegge */ 63167834Stegge sin = &dst; 63267834Stegge clear_sinaddr(sin); 63325723Stegge sin->sin_port = htons(IPPORT_BOOTPC); 634228455Sglebius error = sobind(bootp_so, (struct sockaddr *)sin, td); 63567834Stegge if (error != 0) { 63625723Stegge printf("bind failed\n"); 63725723Stegge goto out; 63825723Stegge } 63983651Speter 64025723Stegge /* 64125723Stegge * Setup socket address for the server. 64225723Stegge */ 64367834Stegge sin = &dst; 64467834Stegge clear_sinaddr(sin); 64525723Stegge sin->sin_addr.s_addr = INADDR_BROADCAST; 64625723Stegge sin->sin_port = htons(IPPORT_BOOTPS); 64783651Speter 64825723Stegge /* 64925723Stegge * Send it, repeatedly, until a reply is received, 65025723Stegge * but delay each re-send by an increasing amount. 65125723Stegge * If the delay hits the maximum, start complaining. 65225723Stegge */ 65325723Stegge timo = 0; 65467834Stegge rtimo = 0; 65525723Stegge for (;;) { 65683651Speter 65767834Stegge outstanding = 0; 65867834Stegge gotrootpath = 0; 65967834Stegge 660228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) { 66171915Stegge if (bootpc_ifctx_isresolved(ifctx) != 0 && 66267834Stegge bootpc_tag(&gctx->tmptag, &ifctx->reply, 66367834Stegge ifctx->replylen, 66467834Stegge TAG_ROOT) != NULL) 66567834Stegge gotrootpath = 1; 66667834Stegge } 66783651Speter 668228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) { 669228455Sglebius struct in_aliasreq *ifra = &ifctx->iareq; 670228455Sglebius sin = (struct sockaddr_in *)&ifra->ifra_mask; 671228455Sglebius 67267834Stegge ifctx->outstanding = 0; 67371915Stegge if (bootpc_ifctx_isresolved(ifctx) != 0 && 67467834Stegge gotrootpath != 0) { 67567834Stegge continue; 67667834Stegge } 67771915Stegge if (bootpc_ifctx_isfailed(ifctx) != 0) 67867834Stegge continue; 67925723Stegge 68067834Stegge outstanding++; 68167834Stegge ifctx->outstanding = 1; 68267834Stegge 68371915Stegge /* Proceed to next step in DHCP negotiation */ 68471915Stegge if ((ifctx->state == IF_DHCP_OFFERED && 68571915Stegge ifctx->dhcpquerytype != DHCP_REQUEST) || 68671915Stegge (ifctx->state == IF_DHCP_UNRESOLVED && 68771915Stegge ifctx->dhcpquerytype != DHCP_DISCOVER) || 68871915Stegge (ifctx->state == IF_BOOTP_UNRESOLVED && 68971915Stegge ifctx->dhcpquerytype != DHCP_NOMSG)) { 69071915Stegge ifctx->sentmsg = 0; 691228455Sglebius bootpc_compose_query(ifctx, td); 69271915Stegge } 69383651Speter 69467834Stegge /* Send BOOTP request (or re-send). */ 69583651Speter 69667834Stegge if (ifctx->sentmsg == 0) { 69771915Stegge switch(ifctx->dhcpquerytype) { 69871915Stegge case DHCP_DISCOVER: 69971915Stegge s = "DHCP Discover"; 70071915Stegge break; 70171915Stegge case DHCP_REQUEST: 70271915Stegge s = "DHCP Request"; 70371915Stegge break; 70471915Stegge case DHCP_NOMSG: 70571915Stegge default: 70671915Stegge s = "BOOTP Query"; 70771915Stegge break; 70871915Stegge } 70971915Stegge printf("Sending %s packet from " 71067834Stegge "interface %s (%*D)\n", 71171915Stegge s, 71267834Stegge ifctx->ireq.ifr_name, 71367834Stegge ifctx->sdl->sdl_alen, 71467834Stegge (unsigned char *) LLADDR(ifctx->sdl), 71567834Stegge ":"); 71667834Stegge ifctx->sentmsg = 1; 71767834Stegge } 71867834Stegge 71967834Stegge aio.iov_base = (caddr_t) &ifctx->call; 72067834Stegge aio.iov_len = sizeof(ifctx->call); 72183651Speter 72267834Stegge auio.uio_iov = &aio; 72367834Stegge auio.uio_iovcnt = 1; 72467834Stegge auio.uio_segflg = UIO_SYSSPACE; 72567834Stegge auio.uio_rw = UIO_WRITE; 72667834Stegge auio.uio_offset = 0; 72767834Stegge auio.uio_resid = sizeof(ifctx->call); 72883366Sjulian auio.uio_td = td; 72983651Speter 73067834Stegge /* Set netmask to 0.0.0.0 */ 73167834Stegge clear_sinaddr(sin); 732228455Sglebius error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, 733228455Sglebius td); 73467834Stegge if (error != 0) 735228455Sglebius panic("%s: SIOCAIFADDR, error=%d", __func__, 736228455Sglebius error); 73783651Speter 738228455Sglebius error = sosend(bootp_so, (struct sockaddr *) &dst, 73983366Sjulian &auio, NULL, NULL, 0, td); 740228455Sglebius if (error != 0) 741228455Sglebius printf("%s: sosend: %d state %08x\n", __func__, 742228455Sglebius error, (int )bootp_so->so_state); 74367834Stegge 74467834Stegge /* Set netmask to 255.0.0.0 */ 745228455Sglebius sin->sin_addr.s_addr = htonl(IN_CLASSA_NET); 746228455Sglebius error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, 747228455Sglebius td); 74867834Stegge if (error != 0) 749228455Sglebius panic("%s: SIOCAIFADDR, error=%d", __func__, 750228455Sglebius error); 75125723Stegge } 75283651Speter 75367834Stegge if (outstanding == 0 && 75467834Stegge (rtimo == 0 || time_second >= rtimo)) { 75567834Stegge error = 0; 756228455Sglebius goto out; 75767834Stegge } 75883651Speter 75925723Stegge /* Determine new timeout. */ 76025723Stegge if (timo < MAX_RESEND_DELAY) 76125723Stegge timo++; 76267834Stegge else { 76371915Stegge printf("DHCP/BOOTP timeout for server "); 76467834Stegge print_sin_addr(&dst); 76567834Stegge printf("\n"); 76667834Stegge } 76783651Speter 76825723Stegge /* 76925723Stegge * Wait for up to timo seconds for a reply. 77025723Stegge * The socket receive timeout was set to 1 second. 77125723Stegge */ 77267834Stegge atimo = timo + time_second; 77367834Stegge while (time_second < atimo) { 77467834Stegge aio.iov_base = (caddr_t) &gctx->reply; 77567834Stegge aio.iov_len = sizeof(gctx->reply); 77683651Speter 77725723Stegge auio.uio_iov = &aio; 77825723Stegge auio.uio_iovcnt = 1; 77925723Stegge auio.uio_segflg = UIO_SYSSPACE; 78025723Stegge auio.uio_rw = UIO_READ; 78125723Stegge auio.uio_offset = 0; 78267834Stegge auio.uio_resid = sizeof(gctx->reply); 78383366Sjulian auio.uio_td = td; 78483651Speter 78525723Stegge rcvflg = 0; 786228455Sglebius error = soreceive(bootp_so, NULL, &auio, 78767531Stegge NULL, NULL, &rcvflg); 78867834Stegge gctx->secs = time_second - gctx->starttime; 789228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) { 79071915Stegge if (bootpc_ifctx_isresolved(ifctx) != 0 || 79171915Stegge bootpc_ifctx_isfailed(ifctx) != 0) 79267834Stegge continue; 79383651Speter 79467834Stegge ifctx->call.secs = htons(gctx->secs); 79567834Stegge } 79667834Stegge if (error == EWOULDBLOCK) 79725723Stegge continue; 79867834Stegge if (error != 0) 79925723Stegge goto out; 80067834Stegge len = sizeof(gctx->reply) - auio.uio_resid; 80183651Speter 80232609Stegge /* Do we have the required number of bytes ? */ 80332609Stegge if (len < BOOTP_MIN_LEN) 80425723Stegge continue; 80567834Stegge gctx->replylen = len; 80683651Speter 80767834Stegge /* Is it a reply? */ 80867834Stegge if (gctx->reply.op != BOOTP_REPLY) 80967531Stegge continue; 81083651Speter 81167834Stegge /* Is this an answer to our query */ 812228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) { 81367834Stegge if (gctx->reply.xid != ifctx->call.xid) 81467834Stegge continue; 81583651Speter 81667834Stegge /* Same HW address size ? */ 81767834Stegge if (gctx->reply.hlen != ifctx->call.hlen) 81867834Stegge continue; 81983651Speter 82067834Stegge /* Correct HW address ? */ 82167834Stegge if (bcmp(gctx->reply.chaddr, 82267834Stegge ifctx->call.chaddr, 82367834Stegge ifctx->call.hlen) != 0) 82467834Stegge continue; 82525723Stegge 82667834Stegge break; 82767834Stegge } 82825723Stegge 82967834Stegge if (ifctx != NULL) { 83071915Stegge s = bootpc_tag(&gctx->tmptag, 83171915Stegge &gctx->reply, 83271915Stegge gctx->replylen, 83371915Stegge TAG_DHCP_MSGTYPE); 83471915Stegge if (s != NULL) { 83571915Stegge switch (*s) { 83671915Stegge case DHCP_OFFER: 83771915Stegge s = "DHCP Offer"; 83871915Stegge break; 83971915Stegge case DHCP_ACK: 84071915Stegge s = "DHCP Ack"; 84171915Stegge break; 84271915Stegge default: 84371915Stegge s = "DHCP (unexpected)"; 84471915Stegge break; 84571915Stegge } 84671915Stegge } else 84771915Stegge s = "BOOTP Reply"; 84871915Stegge 84971915Stegge printf("Received %s packet" 85067834Stegge " on %s from ", 85171915Stegge s, 85267834Stegge ifctx->ireq.ifr_name); 85367834Stegge print_in_addr(gctx->reply.siaddr); 85467834Stegge if (gctx->reply.giaddr.s_addr != 85567834Stegge htonl(INADDR_ANY)) { 85667834Stegge printf(" via "); 85767834Stegge print_in_addr(gctx->reply.giaddr); 85867834Stegge } 85967834Stegge if (bootpc_received(gctx, ifctx) != 0) { 86067834Stegge printf(" (accepted)"); 86167834Stegge if (ifctx->outstanding) { 86267834Stegge ifctx->outstanding = 0; 86367834Stegge outstanding--; 86467834Stegge } 86567834Stegge /* Network settle delay */ 86667834Stegge if (outstanding == 0) 86767834Stegge atimo = time_second + 86867834Stegge BOOTP_SETTLE_DELAY; 86967834Stegge } else 87067834Stegge printf(" (ignored)"); 871253847Sian if (ifctx->gotrootpath || 872253847Sian gctx->any_root_overrides) { 87367834Stegge gotrootpath = 1; 87467834Stegge rtimo = time_second + 87567834Stegge BOOTP_SETTLE_DELAY; 876253847Sian if (ifctx->gotrootpath) 877253847Sian printf(" (got root path)"); 878253847Sian } 87967834Stegge printf("\n"); 88067834Stegge } 88125723Stegge } /* while secs */ 88267834Stegge#ifdef BOOTP_TIMEOUT 88367834Stegge if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0) 88467834Stegge break; 88567834Stegge#endif 88671915Stegge /* Force a retry if halfway in DHCP negotiation */ 88771915Stegge retry = 0; 888228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 88971915Stegge if (ifctx->state == IF_DHCP_OFFERED) { 89071915Stegge if (ifctx->dhcpquerytype == DHCP_DISCOVER) 89171915Stegge retry = 1; 89271915Stegge else 89371915Stegge ifctx->state = IF_DHCP_UNRESOLVED; 89471915Stegge } 89583651Speter 89671915Stegge if (retry != 0) 89771915Stegge continue; 89883651Speter 89967834Stegge if (gotrootpath != 0) { 90067834Stegge gctx->gotrootpath = gotrootpath; 90167834Stegge if (rtimo != 0 && time_second >= rtimo) 90267834Stegge break; 90367834Stegge } 90425723Stegge } /* forever send/receive */ 90583651Speter 90683651Speter /* 90767834Stegge * XXX: These are errors of varying seriousness being silently 90867834Stegge * ignored 90967834Stegge */ 91025723Stegge 911228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 91271915Stegge if (bootpc_ifctx_isresolved(ifctx) == 0) { 91371915Stegge printf("%s timeout for interface %s\n", 91471915Stegge ifctx->dhcpquerytype != DHCP_NOMSG ? 91571915Stegge "DHCP" : "BOOTP", 91667834Stegge ifctx->ireq.ifr_name); 91767834Stegge } 918228455Sglebius 91967834Stegge if (gctx->gotrootpath != 0) { 92067834Stegge#if 0 92167834Stegge printf("Got a root path, ignoring remaining timeout\n"); 92267834Stegge#endif 92367834Stegge error = 0; 92467834Stegge goto out; 92567834Stegge } 926131840Sbrian#ifndef BOOTP_NFSROOT 927228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 928131840Sbrian if (bootpc_ifctx_isresolved(ifctx) != 0) { 929131840Sbrian error = 0; 930131840Sbrian goto out; 93167834Stegge } 932131840Sbrian#endif 93325723Stegge error = ETIMEDOUT; 93483651Speter 93567531Steggeout: 936228455Sglebius return (error); 93725723Stegge} 93825723Stegge 939228455Sglebiusstatic void 940228455Sglebiusbootpc_fakeup_interface(struct bootpc_ifcontext *ifctx, struct thread *td) 94125723Stegge{ 942228455Sglebius struct ifreq *ifr; 943228455Sglebius struct in_aliasreq *ifra; 94467531Stegge struct sockaddr_in *sin; 94567531Stegge int error; 94625723Stegge 947228455Sglebius ifr = &ifctx->ireq; 948228455Sglebius ifra = &ifctx->iareq; 94983651Speter 95067531Stegge /* 95167531Stegge * Bring up the interface. 95267531Stegge * 95367531Stegge * Get the old interface flags and or IFF_UP into them; if 95467531Stegge * IFF_UP set blindly, interface selection can be clobbered. 95567531Stegge */ 956228455Sglebius error = ifioctl(bootp_so, SIOCGIFFLAGS, (caddr_t)ifr, td); 95767834Stegge if (error != 0) 958228455Sglebius panic("%s: SIOCGIFFLAGS, error=%d", __func__, error); 959228455Sglebius ifr->ifr_flags |= IFF_UP; 960228455Sglebius error = ifioctl(bootp_so, SIOCSIFFLAGS, (caddr_t)ifr, td); 96167834Stegge if (error != 0) 962228455Sglebius panic("%s: SIOCSIFFLAGS, error=%d", __func__, error); 96383651Speter 96467531Stegge /* 96567531Stegge * Do enough of ifconfig(8) so that the chosen interface 966228455Sglebius * can talk to the servers. Set address to 0.0.0.0/8 and 967228455Sglebius * broadcast address to local broadcast. 96867531Stegge */ 969228455Sglebius sin = (struct sockaddr_in *)&ifra->ifra_addr; 97067834Stegge clear_sinaddr(sin); 971228455Sglebius sin = (struct sockaddr_in *)&ifra->ifra_mask; 97267834Stegge clear_sinaddr(sin); 973228455Sglebius sin->sin_addr.s_addr = htonl(IN_CLASSA_NET); 974228455Sglebius sin = (struct sockaddr_in *)&ifra->ifra_broadaddr; 97567834Stegge clear_sinaddr(sin); 97667834Stegge sin->sin_addr.s_addr = htonl(INADDR_BROADCAST); 977228455Sglebius error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, td); 97867834Stegge if (error != 0) 979228455Sglebius panic("%s: SIOCAIFADDR, error=%d", __func__, error); 980228455Sglebius} 98183651Speter 982228455Sglebiusstatic void 983228455Sglebiusbootpc_shutdown_interface(struct bootpc_ifcontext *ifctx, struct thread *td) 984228455Sglebius{ 985228455Sglebius struct ifreq *ifr; 986228455Sglebius struct sockaddr_in *sin; 987228455Sglebius int error; 98883651Speter 989228455Sglebius ifr = &ifctx->ireq; 99083651Speter 991228455Sglebius printf("Shutdown interface %s\n", ifctx->ireq.ifr_name); 992228455Sglebius error = ifioctl(bootp_so, SIOCGIFFLAGS, (caddr_t)ifr, td); 993228455Sglebius if (error != 0) 994228455Sglebius panic("%s: SIOCGIFFLAGS, error=%d", __func__, error); 995228455Sglebius ifr->ifr_flags &= ~IFF_UP; 996228455Sglebius error = ifioctl(bootp_so, SIOCSIFFLAGS, (caddr_t)ifr, td); 997228455Sglebius if (error != 0) 998228455Sglebius panic("%s: SIOCSIFFLAGS, error=%d", __func__, error); 99983651Speter 1000228455Sglebius sin = (struct sockaddr_in *) &ifr->ifr_addr; 1001228455Sglebius clear_sinaddr(sin); 1002228455Sglebius error = ifioctl(bootp_so, SIOCDIFADDR, (caddr_t) ifr, td); 1003228455Sglebius if (error != 0) 1004228455Sglebius panic("%s: SIOCDIFADDR, error=%d", __func__, error); 100525723Stegge} 100625723Stegge 100767531Steggestatic int 100867834Steggebootpc_adjust_interface(struct bootpc_ifcontext *ifctx, 100983651Speter struct bootpc_globalcontext *gctx, struct thread *td) 101025723Stegge{ 101167531Stegge int error; 101267834Stegge struct sockaddr_in defdst; 101367834Stegge struct sockaddr_in defmask; 101467531Stegge struct sockaddr_in *sin; 1015228455Sglebius struct ifreq *ifr; 1016228455Sglebius struct in_aliasreq *ifra; 101767834Stegge struct sockaddr_in *myaddr; 101867834Stegge struct sockaddr_in *netmask; 101967834Stegge struct sockaddr_in *gw; 102025723Stegge 1021228455Sglebius ifr = &ifctx->ireq; 1022228455Sglebius ifra = &ifctx->iareq; 102367834Stegge myaddr = &ifctx->myaddr; 102467834Stegge netmask = &ifctx->netmask; 102567834Stegge gw = &ifctx->gw; 102667834Stegge 102771915Stegge if (bootpc_ifctx_isresolved(ifctx) == 0) { 102867834Stegge /* Shutdown interfaces where BOOTP failed */ 1029228455Sglebius bootpc_shutdown_interface(ifctx, td); 1030228455Sglebius return (0); 103167531Stegge } 103225723Stegge 103367834Stegge printf("Adjusted interface %s\n", ifctx->ireq.ifr_name); 103467531Stegge /* 103567531Stegge * Do enough of ifconfig(8) so that the chosen interface 103667531Stegge * can talk to the servers. (just set the address) 103767531Stegge */ 1038228455Sglebius sin = (struct sockaddr_in *) &ifr->ifr_addr; 1039228455Sglebius clear_sinaddr(sin); 1040228455Sglebius error = ifioctl(bootp_so, SIOCDIFADDR, (caddr_t) ifr, td); 104167531Stegge if (error != 0) 1042228455Sglebius panic("%s: SIOCDIFADDR, error=%d", __func__, error); 104383651Speter 1044228455Sglebius bcopy(myaddr, &ifra->ifra_addr, sizeof(*myaddr)); 1045228455Sglebius bcopy(netmask, &ifra->ifra_mask, sizeof(*netmask)); 1046228455Sglebius clear_sinaddr(&ifra->ifra_broadaddr); 1047228455Sglebius ifra->ifra_broadaddr.sin_addr.s_addr = myaddr->sin_addr.s_addr | 1048228455Sglebius ~netmask->sin_addr.s_addr; 104983651Speter 1050228455Sglebius error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, td); 105167531Stegge if (error != 0) 1052228455Sglebius panic("%s: SIOCAIFADDR, error=%d", __func__, error); 105383651Speter 105467531Stegge /* Add new default route */ 105525723Stegge 105667834Stegge if (ifctx->gotgw != 0 || gctx->gotgw == 0) { 105767834Stegge clear_sinaddr(&defdst); 105867834Stegge clear_sinaddr(&defmask); 1059178888Sjulian /* XXX MRT just table 0 */ 1060178888Sjulian error = rtrequest_fib(RTM_ADD, 1061231852Sbz (struct sockaddr *) &defdst, (struct sockaddr *) gw, 1062231852Sbz (struct sockaddr *) &defmask, 1063231852Sbz (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, RT_DEFAULT_FIB); 106467834Stegge if (error != 0) { 1065228455Sglebius printf("%s: RTM_ADD, error=%d\n", __func__, error); 1066228455Sglebius return (error); 106767834Stegge } 106867531Stegge } 106983651Speter 1070228455Sglebius return (0); 107125723Stegge} 107225723Stegge 107367531Steggestatic int 1074126888Sbrookssetfs(struct sockaddr_in *addr, char *path, char *p, 1075126888Sbrooks const struct in_addr *siaddr) 107625723Stegge{ 1077126888Sbrooks 1078126888Sbrooks if (getip(&p, &addr->sin_addr) == 0) { 1079126888Sbrooks if (siaddr != NULL && *p == '/') 1080126888Sbrooks bcopy(siaddr, &addr->sin_addr, sizeof(struct in_addr)); 1081126888Sbrooks else 1082126888Sbrooks return 0; 1083126888Sbrooks } else { 1084126888Sbrooks if (*p != ':') 1085126888Sbrooks return 0; 1086126888Sbrooks p++; 1087126888Sbrooks } 1088126888Sbrooks 1089126888Sbrooks addr->sin_len = sizeof(struct sockaddr_in); 1090126888Sbrooks addr->sin_family = AF_INET; 1091126888Sbrooks 1092126888Sbrooks strlcpy(path, p, MNAMELEN); 1093126888Sbrooks return 1; 1094126888Sbrooks} 1095126888Sbrooks 1096126888Sbrooksstatic int 1097126888Sbrooksgetip(char **ptr, struct in_addr *addr) 1098126888Sbrooks{ 1099126888Sbrooks char *p; 110067531Stegge unsigned int ip; 110125804Stegge int val; 110283651Speter 1103126888Sbrooks p = *ptr; 110467531Stegge ip = 0; 110567531Stegge if (((val = getdec(&p)) < 0) || (val > 255)) 110667531Stegge return 0; 110725804Stegge ip = val << 24; 110867531Stegge if (*p != '.') 110967531Stegge return 0; 111025804Stegge p++; 111167531Stegge if (((val = getdec(&p)) < 0) || (val > 255)) 111267531Stegge return 0; 111325804Stegge ip |= (val << 16); 111467531Stegge if (*p != '.') 111567531Stegge return 0; 111625804Stegge p++; 111767531Stegge if (((val = getdec(&p)) < 0) || (val > 255)) 111867531Stegge return 0; 111925804Stegge ip |= (val << 8); 112067531Stegge if (*p != '.') 112167531Stegge return 0; 112225804Stegge p++; 112367531Stegge if (((val = getdec(&p)) < 0) || (val > 255)) 112467531Stegge return 0; 112525804Stegge ip |= val; 112683651Speter 1127126888Sbrooks addr->s_addr = htonl(ip); 1128126888Sbrooks *ptr = p; 112967531Stegge return 1; 113025804Stegge} 113125804Stegge 113267531Steggestatic int 113367531Steggegetdec(char **ptr) 113425804Stegge{ 113567531Stegge char *p; 113667531Stegge int ret; 113767531Stegge 113867531Stegge p = *ptr; 113967531Stegge ret = 0; 114067531Stegge if ((*p < '0') || (*p > '9')) 114167531Stegge return -1; 114225804Stegge while ((*p >= '0') && (*p <= '9')) { 114367531Stegge ret = ret * 10 + (*p - '0'); 114425804Stegge p++; 114525723Stegge } 114625804Stegge *ptr = p; 114767531Stegge return ret; 114825723Stegge} 114925723Stegge 115067531Steggestatic void 115167531Steggemountopts(struct nfs_args *args, char *p) 115225804Stegge{ 115367834Stegge args->version = NFS_ARGSVERSION; 1154179039Sbenno args->rsize = BOOTP_BLOCKSIZE; 1155179039Sbenno args->wsize = BOOTP_BLOCKSIZE; 115625804Stegge args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT; 115725804Stegge args->sotype = SOCK_DGRAM; 1158164934Ssam if (p != NULL) 1159164934Ssam nfs_parse_options(p, args); 116025804Stegge} 116125804Stegge 116267531Steggestatic int 116367531Steggexdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len) 116426581Stegge{ 116567531Stegge struct mbuf *m; 116667531Stegge int alignedlen; 116783651Speter 116867531Stegge m = *mptr; 116967531Stegge alignedlen = ( len + 3 ) & ~3; 117083651Speter 117167531Stegge if (m->m_len < alignedlen) { 117267531Stegge m = m_pullup(m, alignedlen); 117367531Stegge if (m == NULL) { 117467531Stegge *mptr = NULL; 117567531Stegge return EBADRPC; 117667531Stegge } 117767531Stegge } 117867531Stegge bcopy(mtod(m, u_char *), buf, len); 117967531Stegge m_adj(m, alignedlen); 118067531Stegge *mptr = m; 118167531Stegge return 0; 118267531Stegge} 118326581Stegge 118467531Steggestatic int 118567531Steggexdr_int_decode(struct mbuf **mptr, int *iptr) 118626581Stegge{ 118767531Stegge u_int32_t i; 118883651Speter 118967531Stegge if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0) 119067531Stegge return EBADRPC; 119167531Stegge *iptr = fxdr_unsigned(u_int32_t, i); 119267531Stegge return 0; 119326581Stegge} 119426581Stegge 119567531Steggestatic void 119667834Steggeprint_sin_addr(struct sockaddr_in *sin) 119726581Stegge{ 119883651Speter 119967834Stegge print_in_addr(sin->sin_addr); 120067834Stegge} 120167834Stegge 120267834Steggestatic void 120367834Steggeprint_in_addr(struct in_addr addr) 120467834Stegge{ 120567531Stegge unsigned int ip; 120683651Speter 120767531Stegge ip = ntohl(addr.s_addr); 120867834Stegge printf("%d.%d.%d.%d", 120967531Stegge ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255); 121026581Stegge} 121126581Stegge 121267834Steggestatic void 1213228455Sglebiusbootpc_compose_query(struct bootpc_ifcontext *ifctx, struct thread *td) 121467834Stegge{ 121571915Stegge unsigned char *vendp; 121696825Sambrisko unsigned char vendor_client[64]; 121771915Stegge uint32_t leasetime; 121896825Sambrisko uint8_t vendor_client_len; 121971915Stegge 122067834Stegge ifctx->gotrootpath = 0; 122171915Stegge 122267834Stegge bzero((caddr_t) &ifctx->call, sizeof(ifctx->call)); 122383651Speter 122467834Stegge /* bootpc part */ 122567834Stegge ifctx->call.op = BOOTP_REQUEST; /* BOOTREQUEST */ 122667834Stegge ifctx->call.htype = 1; /* 10mb ethernet */ 122767834Stegge ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */ 122867834Stegge ifctx->call.hops = 0; 122971915Stegge if (bootpc_ifctx_isunresolved(ifctx) != 0) 123071915Stegge ifctx->xid++; 123167834Stegge ifctx->call.xid = txdr_unsigned(ifctx->xid); 123267834Stegge bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen); 123383651Speter 123471915Stegge vendp = ifctx->call.vend; 123571915Stegge *vendp++ = 99; /* RFC1048 cookie */ 123671915Stegge *vendp++ = 130; 123771915Stegge *vendp++ = 83; 123871915Stegge *vendp++ = 99; 123971915Stegge *vendp++ = TAG_MAXMSGSIZE; 124071915Stegge *vendp++ = 2; 124171915Stegge *vendp++ = (sizeof(struct bootp_packet) >> 8) & 255; 124271915Stegge *vendp++ = sizeof(struct bootp_packet) & 255; 124396825Sambrisko 124496825Sambrisko snprintf(vendor_client, sizeof(vendor_client), "%s:%s:%s", 124596825Sambrisko ostype, MACHINE, osrelease); 124696825Sambrisko vendor_client_len = strlen(vendor_client); 124796825Sambrisko *vendp++ = TAG_VENDOR_INDENTIFIER; 124896825Sambrisko *vendp++ = vendor_client_len; 124996825Sambrisko memcpy(vendp, vendor_client, vendor_client_len); 1250201758Smbr vendp += vendor_client_len; 125171915Stegge ifctx->dhcpquerytype = DHCP_NOMSG; 125271915Stegge switch (ifctx->state) { 125371915Stegge case IF_DHCP_UNRESOLVED: 125471915Stegge *vendp++ = TAG_DHCP_MSGTYPE; 125571915Stegge *vendp++ = 1; 125671915Stegge *vendp++ = DHCP_DISCOVER; 125771915Stegge ifctx->dhcpquerytype = DHCP_DISCOVER; 125871915Stegge ifctx->gotdhcpserver = 0; 125971915Stegge break; 126071915Stegge case IF_DHCP_OFFERED: 126171915Stegge *vendp++ = TAG_DHCP_MSGTYPE; 126271915Stegge *vendp++ = 1; 126371915Stegge *vendp++ = DHCP_REQUEST; 126471915Stegge ifctx->dhcpquerytype = DHCP_REQUEST; 126571915Stegge *vendp++ = TAG_DHCP_REQ_ADDR; 126671915Stegge *vendp++ = 4; 126771915Stegge memcpy(vendp, &ifctx->reply.yiaddr, 4); 126871915Stegge vendp += 4; 126971915Stegge if (ifctx->gotdhcpserver != 0) { 127071915Stegge *vendp++ = TAG_DHCP_SERVERID; 127171915Stegge *vendp++ = 4; 127271915Stegge memcpy(vendp, &ifctx->dhcpserver, 4); 127371915Stegge vendp += 4; 127471915Stegge } 127571915Stegge *vendp++ = TAG_DHCP_LEASETIME; 127671915Stegge *vendp++ = 4; 127771915Stegge leasetime = htonl(300); 127871915Stegge memcpy(vendp, &leasetime, 4); 127971915Stegge vendp += 4; 1280115533Sphk break; 128171915Stegge default: 1282115533Sphk break; 128371915Stegge } 128471915Stegge *vendp = TAG_END; 128583651Speter 128667834Stegge ifctx->call.secs = 0; 1287108470Sschweikh ifctx->call.flags = htons(0x8000); /* We need a broadcast answer */ 128867834Stegge} 128967531Stegge 129067834Steggestatic int 129167834Steggebootpc_hascookie(struct bootp_packet *bp) 129225723Stegge{ 129383651Speter 129467834Stegge return (bp->vend[0] == 99 && bp->vend[1] == 130 && 129567834Stegge bp->vend[2] == 83 && bp->vend[3] == 99); 129667834Stegge} 129767834Stegge 129867834Steggestatic void 129967834Steggebootpc_tag_helper(struct bootpc_tagcontext *tctx, 130083651Speter unsigned char *start, int len, int tag) 130167834Stegge{ 130267834Stegge unsigned char *j; 130367834Stegge unsigned char *ej; 130467834Stegge unsigned char code; 130567834Stegge 130667834Stegge if (tctx->badtag != 0 || tctx->badopt != 0) 130767834Stegge return; 130883651Speter 130967834Stegge j = start; 131067834Stegge ej = j + len; 131183651Speter 131267834Stegge while (j < ej) { 131367834Stegge code = *j++; 131467834Stegge if (code == TAG_PAD) 131567834Stegge continue; 131667834Stegge if (code == TAG_END) 131767834Stegge return; 131867834Stegge if (j >= ej || j + *j + 1 > ej) { 131967834Stegge tctx->badopt = 1; 132067834Stegge return; 132167834Stegge } 132267834Stegge len = *j++; 132367834Stegge if (code == tag) { 132467834Stegge if (tctx->taglen + len > TAG_MAXLEN) { 132567834Stegge tctx->badtag = 1; 132667834Stegge return; 132767834Stegge } 132867834Stegge tctx->foundopt = 1; 132967834Stegge if (len > 0) 133067834Stegge memcpy(tctx->buf + tctx->taglen, 133167834Stegge j, len); 133267834Stegge tctx->taglen += len; 133367834Stegge } 133467834Stegge if (code == TAG_OVERLOAD) 133567834Stegge tctx->overload = *j; 133683651Speter 133767834Stegge j += len; 133867834Stegge } 133967834Stegge} 134067834Stegge 134167834Steggestatic unsigned char * 134267834Steggebootpc_tag(struct bootpc_tagcontext *tctx, 134383651Speter struct bootp_packet *bp, int len, int tag) 134467834Stegge{ 134567834Stegge tctx->overload = 0; 134667834Stegge tctx->badopt = 0; 134767834Stegge tctx->badtag = 0; 134867834Stegge tctx->foundopt = 0; 134967834Stegge tctx->taglen = 0; 135067834Stegge 135167834Stegge if (bootpc_hascookie(bp) == 0) 135267834Stegge return NULL; 135383651Speter 135467834Stegge bootpc_tag_helper(tctx, &bp->vend[4], 135567834Stegge (unsigned char *) bp + len - &bp->vend[4], tag); 135683651Speter 135767834Stegge if ((tctx->overload & OVERLOAD_FILE) != 0) 135867834Stegge bootpc_tag_helper(tctx, 135967834Stegge (unsigned char *) bp->file, 136067834Stegge sizeof(bp->file), 136167834Stegge tag); 136267834Stegge if ((tctx->overload & OVERLOAD_SNAME) != 0) 136367834Stegge bootpc_tag_helper(tctx, 136467834Stegge (unsigned char *) bp->sname, 136567834Stegge sizeof(bp->sname), 136667834Stegge tag); 136783651Speter 136867834Stegge if (tctx->badopt != 0 || tctx->badtag != 0 || tctx->foundopt == 0) 136967834Stegge return NULL; 137067834Stegge tctx->buf[tctx->taglen] = '\0'; 137167834Stegge return tctx->buf; 137267834Stegge} 137367834Stegge 137467834Steggestatic void 137583651Speterbootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx, 137683651Speter struct bootpc_globalcontext *gctx) 137767834Stegge{ 1378253847Sian char *p, *s; 137967531Stegge unsigned int ip; 138025723Stegge 138167834Stegge ifctx->gotgw = 0; 138267834Stegge ifctx->gotnetmask = 0; 138325723Stegge 138467834Stegge clear_sinaddr(&ifctx->myaddr); 138567834Stegge clear_sinaddr(&ifctx->netmask); 138667834Stegge clear_sinaddr(&ifctx->gw); 138783651Speter 138867834Stegge ifctx->myaddr.sin_addr = ifctx->reply.yiaddr; 138983651Speter 139067834Stegge ip = ntohl(ifctx->myaddr.sin_addr.s_addr); 139183651Speter 139267834Stegge printf("%s at ", ifctx->ireq.ifr_name); 139367834Stegge print_sin_addr(&ifctx->myaddr); 139467834Stegge printf(" server "); 139567834Stegge print_in_addr(ifctx->reply.siaddr); 139683651Speter 139767834Stegge ifctx->gw.sin_addr = ifctx->reply.giaddr; 139867834Stegge if (ifctx->reply.giaddr.s_addr != htonl(INADDR_ANY)) { 139967834Stegge printf(" via gateway "); 140067834Stegge print_in_addr(ifctx->reply.giaddr); 140167834Stegge } 140225723Stegge 140367834Stegge /* This call used for the side effect (overload flag) */ 140467834Stegge (void) bootpc_tag(&gctx->tmptag, 140567834Stegge &ifctx->reply, ifctx->replylen, TAG_END); 140683651Speter 140767834Stegge if ((gctx->tmptag.overload & OVERLOAD_SNAME) == 0) 140867834Stegge if (ifctx->reply.sname[0] != '\0') 140967834Stegge printf(" server name %s", ifctx->reply.sname); 141067834Stegge if ((gctx->tmptag.overload & OVERLOAD_FILE) == 0) 141167834Stegge if (ifctx->reply.file[0] != '\0') 141267834Stegge printf(" boot file %s", ifctx->reply.file); 141383651Speter 141467834Stegge printf("\n"); 141567834Stegge 141667834Stegge p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 141767834Stegge TAG_SUBNETMASK); 141867834Stegge if (p != NULL) { 141967834Stegge if (gctx->tag.taglen != 4) 142067834Stegge panic("bootpc: subnet mask len is %d", 142167834Stegge gctx->tag.taglen); 142267834Stegge bcopy(p, &ifctx->netmask.sin_addr, 4); 142367834Stegge ifctx->gotnetmask = 1; 142467834Stegge printf("subnet mask "); 142567834Stegge print_sin_addr(&ifctx->netmask); 142667834Stegge printf(" "); 142767834Stegge } 142883651Speter 142967834Stegge p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 143067834Stegge TAG_ROUTERS); 143167834Stegge if (p != NULL) { 143267834Stegge /* Routers */ 143367834Stegge if (gctx->tag.taglen % 4) 143467834Stegge panic("bootpc: Router Len is %d", gctx->tag.taglen); 143567834Stegge if (gctx->tag.taglen > 0) { 143667834Stegge bcopy(p, &ifctx->gw.sin_addr, 4); 143767834Stegge printf("router "); 143867834Stegge print_sin_addr(&ifctx->gw); 143967834Stegge printf(" "); 144067834Stegge ifctx->gotgw = 1; 144167834Stegge gctx->gotgw = 1; 144267834Stegge } 144367834Stegge } 144483651Speter 1445253847Sian /* 1446253847Sian * Choose a root filesystem. If a value is forced in the environment 1447253847Sian * and it contains "nfs:", use it unconditionally. Otherwise, if the 1448253847Sian * kernel is compiled with the ROOTDEVNAME option, then use it if: 1449253847Sian * - The server doesn't provide a pathname. 1450253847Sian * - The boothowto flags include RB_DFLTROOT (user said to override 1451253847Sian * the server value). 1452253847Sian */ 1453253847Sian p = NULL; 1454253847Sian if ((s = getenv("vfs.root.mountfrom")) != NULL) { 1455253847Sian if ((p = strstr(s, "nfs:")) != NULL) 1456253847Sian p = strdup(p + 4, M_TEMP); 1457253847Sian freeenv(s); 1458253847Sian } 1459253847Sian if (p == NULL) { 1460253847Sian p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 146167834Stegge TAG_ROOT); 1462253847Sian } 1463253847Sian#ifdef ROOTDEVNAME 1464253847Sian if ((p == NULL || (boothowto & RB_DFLTROOT) != 0) && 1465253847Sian (p = strstr(ROOTDEVNAME, "nfs:")) != NULL) { 1466253847Sian p += 4; 1467253847Sian } 1468253847Sian#endif 146967834Stegge if (p != NULL) { 147067834Stegge if (gctx->setrootfs != NULL) { 147167834Stegge printf("rootfs %s (ignored) ", p); 147267834Stegge } else if (setfs(&nd->root_saddr, 1473126888Sbrooks nd->root_hostnam, p, &ifctx->reply.siaddr)) { 1474126888Sbrooks if (*p == '/') { 1475126888Sbrooks printf("root_server "); 1476126888Sbrooks print_sin_addr(&nd->root_saddr); 1477126888Sbrooks printf(" "); 1478126888Sbrooks } 147983651Speter printf("rootfs %s ", p); 148067834Stegge gctx->gotrootpath = 1; 148167834Stegge ifctx->gotrootpath = 1; 148267834Stegge gctx->setrootfs = ifctx; 148383651Speter 148467834Stegge p = bootpc_tag(&gctx->tag, &ifctx->reply, 148567834Stegge ifctx->replylen, 148667834Stegge TAG_ROOTOPTS); 148767834Stegge if (p != NULL) { 148867834Stegge mountopts(&nd->root_args, p); 148967834Stegge printf("rootopts %s ", p); 149067834Stegge } 149167834Stegge } else 149283651Speter panic("Failed to set rootfs to %s", p); 149367834Stegge } 149467834Stegge 149567834Stegge p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 149667834Stegge TAG_HOSTNAME); 149767834Stegge if (p != NULL) { 149867834Stegge if (gctx->tag.taglen >= MAXHOSTNAMELEN) 149967834Stegge panic("bootpc: hostname >= %d bytes", 150067834Stegge MAXHOSTNAMELEN); 150167834Stegge if (gctx->sethostname != NULL) { 150267834Stegge printf("hostname %s (ignored) ", p); 150367834Stegge } else { 150467834Stegge strcpy(nd->my_hostnam, p); 1505193066Sjamie mtx_lock(&prison0.pr_mtx); 1506194118Sjamie strcpy(prison0.pr_hostname, p); 1507193066Sjamie mtx_unlock(&prison0.pr_mtx); 1508193066Sjamie printf("hostname %s ", p); 150967834Stegge gctx->sethostname = ifctx; 151067834Stegge } 151167834Stegge } 151292219Sluigi p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 151392219Sluigi TAG_COOKIE); 151492219Sluigi if (p != NULL) { /* store in a sysctl variable */ 151592219Sluigi int i, l = sizeof(bootp_cookie) - 1; 151692219Sluigi for (i = 0; i < l && p[i] != '\0'; i++) 151792219Sluigi bootp_cookie[i] = p[i]; 151892219Sluigi p[i] = '\0'; 151992219Sluigi } 152067834Stegge 152192219Sluigi 152267834Stegge printf("\n"); 152383651Speter 152467834Stegge if (ifctx->gotnetmask == 0) { 152567834Stegge if (IN_CLASSA(ntohl(ifctx->myaddr.sin_addr.s_addr))) 152667834Stegge ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET); 152767834Stegge else if (IN_CLASSB(ntohl(ifctx->myaddr.sin_addr.s_addr))) 152867834Stegge ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET); 152967834Stegge else 153067834Stegge ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET); 153167834Stegge } 153267834Stegge if (ifctx->gotgw == 0) { 153367834Stegge /* Use proxyarp */ 153467834Stegge ifctx->gw.sin_addr.s_addr = ifctx->myaddr.sin_addr.s_addr; 153567834Stegge } 153667834Stegge} 153767834Stegge 153867834Steggevoid 153967834Steggebootpc_init(void) 154067834Stegge{ 1541228455Sglebius struct bootpc_ifcontext *ifctx; /* Interface BOOTP contexts */ 154267834Stegge struct bootpc_globalcontext *gctx; /* Global BOOTP context */ 154367834Stegge struct ifnet *ifp; 1544228455Sglebius struct sockaddr_dl *sdl; 1545228455Sglebius struct ifaddr *ifa; 1546131840Sbrian int error; 1547131840Sbrian#ifndef BOOTP_WIRED_TO 1548118639Sbillf int ifcnt; 1549131840Sbrian#endif 155067531Stegge struct nfsv3_diskless *nd; 155183366Sjulian struct thread *td; 1552239337Sgonzo int timeout; 1553239337Sgonzo int delay; 155425723Stegge 1555239337Sgonzo timeout = BOOTP_IFACE_WAIT_TIMEOUT * hz; 1556239337Sgonzo delay = hz / 10; 1557239337Sgonzo 155867531Stegge nd = &nfsv3_diskless; 155983366Sjulian td = curthread; 156083651Speter 156167531Stegge /* 156267531Stegge * If already filled in, don't touch it here 156367531Stegge */ 156467531Stegge if (nfs_diskless_valid != 0) 156567531Stegge return; 156625723Stegge 1567118639Sbillf gctx = malloc(sizeof(*gctx), M_TEMP, M_WAITOK | M_ZERO); 1568228455Sglebius STAILQ_INIT(&gctx->interfaces); 156967834Stegge gctx->xid = ~0xFFFF; 157067834Stegge gctx->starttime = time_second; 157183651Speter 157267531Stegge /* 1573253847Sian * If ROOTDEVNAME is defined or vfs.root.mountfrom is set then we have 1574253847Sian * root-path overrides that can potentially let us boot even if we don't 1575253847Sian * get a root path from the server, so we can treat that as a non-error. 1576253847Sian */ 1577253847Sian#ifdef ROOTDEVNAME 1578253847Sian gctx->any_root_overrides = 1; 1579253847Sian#else 1580253847Sian gctx->any_root_overrides = testenv("vfs.root.mountfrom"); 1581253847Sian#endif 1582253847Sian 1583253847Sian /* 158467531Stegge * Find a network interface. 158567531Stegge */ 1586218757Sbz CURVNET_SET(TD_TO_VNET(td)); 1587131840Sbrian#ifdef BOOTP_WIRED_TO 1588228455Sglebius printf("%s: wired to interface '%s'\n", __func__, 1589131840Sbrian __XSTRING(BOOTP_WIRED_TO)); 1590131840Sbrian allocifctx(gctx); 1591131840Sbrian#else 1592131840Sbrian /* 1593131840Sbrian * Preallocate interface context storage, if another interface 1594131840Sbrian * attaches and wins the race, it won't be eligible for bootp. 1595131840Sbrian */ 1596228455Sglebius ifcnt = 0; 1597131840Sbrian IFNET_RLOCK(); 1598228455Sglebius TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1599131840Sbrian if ((ifp->if_flags & 1600131840Sbrian (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) != 1601131840Sbrian IFF_BROADCAST) 1602131840Sbrian continue; 1603228455Sglebius switch (ifp->if_alloctype) { 1604228455Sglebius case IFT_ETHER: 1605228455Sglebius case IFT_FDDI: 1606228455Sglebius case IFT_ISO88025: 1607228455Sglebius break; 1608228455Sglebius default: 1609228455Sglebius continue; 1610228455Sglebius } 1611131840Sbrian ifcnt++; 1612131840Sbrian } 1613131840Sbrian IFNET_RUNLOCK(); 1614131840Sbrian if (ifcnt == 0) 1615228455Sglebius panic("%s: no eligible interfaces", __func__); 1616131840Sbrian for (; ifcnt > 0; ifcnt--) 1617131814Sbrian allocifctx(gctx); 1618131840Sbrian#endif 1619118639Sbillf 1620239318Sgonzoretry: 1621228455Sglebius ifctx = STAILQ_FIRST(&gctx->interfaces); 1622118639Sbillf IFNET_RLOCK(); 1623228455Sglebius TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1624228455Sglebius if (ifctx == NULL) 1625228455Sglebius break; 1626131840Sbrian#ifdef BOOTP_WIRED_TO 1627228455Sglebius if (strcmp(ifp->if_xname, __XSTRING(BOOTP_WIRED_TO)) != 0) 1628131840Sbrian continue; 1629131840Sbrian#else 1630131840Sbrian if ((ifp->if_flags & 1631131840Sbrian (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) != 163267834Stegge IFF_BROADCAST) 163367834Stegge continue; 1634228455Sglebius switch (ifp->if_alloctype) { 1635228455Sglebius case IFT_ETHER: 1636228455Sglebius case IFT_FDDI: 1637228455Sglebius case IFT_ISO88025: 1638228455Sglebius break; 1639228455Sglebius default: 1640228455Sglebius continue; 1641228455Sglebius } 1642131840Sbrian#endif 1643228455Sglebius strlcpy(ifctx->ireq.ifr_name, ifp->if_xname, 1644228455Sglebius sizeof(ifctx->ireq.ifr_name)); 164567834Stegge ifctx->ifp = ifp; 1646228455Sglebius 1647228455Sglebius /* Get HW address */ 1648228455Sglebius sdl = NULL; 1649228455Sglebius TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 1650228455Sglebius if (ifa->ifa_addr->sa_family == AF_LINK) { 1651228455Sglebius sdl = (struct sockaddr_dl *)ifa->ifa_addr; 1652228455Sglebius if (sdl->sdl_type == IFT_ETHER) 1653228455Sglebius break; 1654228455Sglebius } 1655228455Sglebius if (sdl == NULL) 1656228455Sglebius panic("bootpc: Unable to find HW address for %s", 1657228455Sglebius ifctx->ireq.ifr_name); 1658228455Sglebius ifctx->sdl = sdl; 1659228455Sglebius 1660228455Sglebius ifctx = STAILQ_NEXT(ifctx, next); 166167531Stegge } 1662108172Shsu IFNET_RUNLOCK(); 1663218757Sbz CURVNET_RESTORE(); 166483651Speter 1665228455Sglebius if (STAILQ_EMPTY(&gctx->interfaces) || 1666228455Sglebius STAILQ_FIRST(&gctx->interfaces)->ifp == NULL) { 1667239318Sgonzo if (timeout > 0) { 1668239318Sgonzo pause("bootpc", delay); 1669239318Sgonzo timeout -= delay; 1670239318Sgonzo goto retry; 1671239318Sgonzo } 1672131840Sbrian#ifdef BOOTP_WIRED_TO 1673228455Sglebius panic("%s: Could not find interface specified " 1674131840Sbrian "by BOOTP_WIRED_TO: " 1675228455Sglebius __XSTRING(BOOTP_WIRED_TO), __func__); 1676131840Sbrian#else 1677228455Sglebius panic("%s: no suitable interface", __func__); 1678131840Sbrian#endif 167967531Stegge } 168083651Speter 1681228455Sglebius error = socreate(AF_INET, &bootp_so, SOCK_DGRAM, 0, td->td_ucred, td); 1682228455Sglebius if (error != 0) 1683228455Sglebius panic("%s: socreate, error=%d", __func__, error); 168483651Speter 1685228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 1686228455Sglebius bootpc_fakeup_interface(ifctx, td); 168783651Speter 1688228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 1689228455Sglebius bootpc_compose_query(ifctx, td); 1690228455Sglebius 169183366Sjulian error = bootpc_call(gctx, td); 169267531Stegge if (error != 0) { 1693131840Sbrian printf("BOOTP call failed\n"); 169467531Stegge } 169583651Speter 169667834Stegge mountopts(&nd->root_args, NULL); 169783651Speter 1698228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 169971915Stegge if (bootpc_ifctx_isresolved(ifctx) != 0) 170067834Stegge bootpc_decode_reply(nd, ifctx, gctx); 170183651Speter 1702131840Sbrian#ifdef BOOTP_NFSROOT 1703253847Sian if (gctx->gotrootpath == 0 && gctx->any_root_overrides == 0) 170467531Stegge panic("bootpc: No root path offered"); 1705131840Sbrian#endif 170683651Speter 1707228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 170883366Sjulian bootpc_adjust_interface(ifctx, gctx, td); 170983651Speter 1710228455Sglebius soclose(bootp_so); 171125723Stegge 1712228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 171367834Stegge if (ifctx->gotrootpath != 0) 171467834Stegge break; 171567834Stegge if (ifctx == NULL) { 1716228455Sglebius STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 171771915Stegge if (bootpc_ifctx_isresolved(ifctx) != 0) 171867834Stegge break; 171967531Stegge } 172067834Stegge if (ifctx == NULL) 172167834Stegge goto out; 172283651Speter 172367834Stegge if (gctx->gotrootpath != 0) { 172483651Speter 1725145570Sdes setenv("boot.netif.name", ifctx->ifp->if_xname); 1726145570Sdes 172767531Stegge error = md_mount(&nd->root_saddr, nd->root_hostnam, 172867531Stegge nd->root_fh, &nd->root_fhsize, 172983366Sjulian &nd->root_args, td); 1730253847Sian if (error != 0) { 1731253847Sian if (gctx->any_root_overrides == 0) 1732253847Sian panic("nfs_boot: mount root, error=%d", error); 1733253847Sian else 1734253847Sian goto out; 1735253847Sian } 1736253847Sian rootdevnames[0] = "nfs:"; 1737253847Sian#ifdef NFSCLIENT 1738253847Sian rootdevnames[1] = "oldnfs:"; 1739253847Sian#endif 174067531Stegge nfs_diskless_valid = 3; 174167531Stegge } 174283651Speter 174367834Stegge strcpy(nd->myif.ifra_name, ifctx->ireq.ifr_name); 174467834Stegge bcopy(&ifctx->myaddr, &nd->myif.ifra_addr, sizeof(ifctx->myaddr)); 174567834Stegge bcopy(&ifctx->myaddr, &nd->myif.ifra_broadaddr, sizeof(ifctx->myaddr)); 174667531Stegge ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr = 174767834Stegge ifctx->myaddr.sin_addr.s_addr | 174867834Stegge ~ ifctx->netmask.sin_addr.s_addr; 174967834Stegge bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask)); 175083651Speter 175167834Steggeout: 1752228455Sglebius while((ifctx = STAILQ_FIRST(&gctx->interfaces)) != NULL) { 1753228455Sglebius STAILQ_REMOVE_HEAD(&gctx->interfaces, next); 175467834Stegge free(ifctx, M_TEMP); 175567834Stegge } 175667834Stegge free(gctx, M_TEMP); 175725723Stegge} 175825723Stegge 175925723Stegge/* 176025723Stegge * RPC: mountd/mount 176125723Stegge * Given a server pathname, get an NFS file handle. 176225723Stegge * Also, sets sin->sin_port to the NFS service port. 176325723Stegge */ 176425723Steggestatic int 176583651Spetermd_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp, int *fhsizep, 176683651Speter struct nfs_args *args, struct thread *td) 176725723Stegge{ 176825723Stegge struct mbuf *m; 176925723Stegge int error; 177025723Stegge int authunixok; 177125723Stegge int authcount; 177225723Stegge int authver; 177383651Speter 1774195202Sdfr#define RPCPROG_MNT 100005 1775195202Sdfr#define RPCMNT_VER1 1 1776195202Sdfr#define RPCMNT_VER3 3 1777195202Sdfr#define RPCMNT_MOUNT 1 1778195202Sdfr#define AUTH_SYS 1 /* unix style (uid, gids) */ 1779195202Sdfr#define AUTH_UNIX AUTH_SYS 1780195202Sdfr 1781164934Ssam /* XXX honor v2/v3 flags in args->flags? */ 1782131840Sbrian#ifdef BOOTP_NFSV3 1783131840Sbrian /* First try NFS v3 */ 1784131840Sbrian /* Get port number for MOUNTD. */ 1785131840Sbrian error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3, 1786131840Sbrian &mdsin->sin_port, td); 1787131840Sbrian if (error == 0) { 1788131840Sbrian m = xdr_string_encode(path, strlen(path)); 178983651Speter 1790131840Sbrian /* Do RPC to mountd. */ 1791131840Sbrian error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3, 1792131840Sbrian RPCMNT_MOUNT, &m, NULL, td); 1793131840Sbrian } 1794131840Sbrian if (error == 0) { 1795131840Sbrian args->flags |= NFSMNT_NFSV3; 1796131840Sbrian } else { 1797131840Sbrian#endif 179867531Stegge /* Fallback to NFS v2 */ 179983651Speter 180067531Stegge /* Get port number for MOUNTD. */ 180167531Stegge error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, 180283366Sjulian &mdsin->sin_port, td); 180367531Stegge if (error != 0) 180467531Stegge return error; 180583651Speter 180667531Stegge m = xdr_string_encode(path, strlen(path)); 180783651Speter 180867531Stegge /* Do RPC to mountd. */ 180967531Stegge error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, 181083366Sjulian RPCMNT_MOUNT, &m, NULL, td); 181167531Stegge if (error != 0) 181267531Stegge return error; /* message already freed */ 1813131840Sbrian 1814131840Sbrian#ifdef BOOTP_NFSV3 181525723Stegge } 1816131840Sbrian#endif 181725723Stegge 181867531Stegge if (xdr_int_decode(&m, &error) != 0 || error != 0) 181967531Stegge goto bad; 182083651Speter 182167531Stegge if ((args->flags & NFSMNT_NFSV3) != 0) { 182267531Stegge if (xdr_int_decode(&m, fhsizep) != 0 || 182367531Stegge *fhsizep > NFSX_V3FHMAX || 182467531Stegge *fhsizep <= 0) 182567531Stegge goto bad; 182667531Stegge } else 182767531Stegge *fhsizep = NFSX_V2FH; 182825723Stegge 182967531Stegge if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0) 183067531Stegge goto bad; 183125723Stegge 183225723Stegge if (args->flags & NFSMNT_NFSV3) { 183367531Stegge if (xdr_int_decode(&m, &authcount) != 0) 183467531Stegge goto bad; 183567531Stegge authunixok = 0; 183667531Stegge if (authcount < 0 || authcount > 100) 183767531Stegge goto bad; 183867531Stegge while (authcount > 0) { 183967531Stegge if (xdr_int_decode(&m, &authver) != 0) 184067531Stegge goto bad; 1841195202Sdfr if (authver == AUTH_UNIX) 184267531Stegge authunixok = 1; 184367531Stegge authcount--; 184467531Stegge } 184567531Stegge if (authunixok == 0) 184667531Stegge goto bad; 184725723Stegge } 184883651Speter 184925723Stegge /* Set port number for NFS use. */ 185067531Stegge error = krpc_portmap(mdsin, NFS_PROG, 185167531Stegge (args->flags & 185267531Stegge NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2, 185383366Sjulian &mdsin->sin_port, td); 185483651Speter 185525723Stegge goto out; 185683651Speter 185725723Steggebad: 185825723Stegge error = EBADRPC; 185983651Speter 186025723Steggeout: 186125723Stegge m_freem(m); 186225723Stegge return error; 186325723Stegge} 1864132808Sphk 1865132808SphkSYSINIT(bootp_rootconf, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, bootpc_init, NULL); 1866