17c208ed6SRick Macklem /*- 27c208ed6SRick Macklem * Copyright (c) 1995 Gordon Ross, Adam Glass 37c208ed6SRick Macklem * Copyright (c) 1992 Regents of the University of California. 47c208ed6SRick Macklem * All rights reserved. 57c208ed6SRick Macklem * 67c208ed6SRick Macklem * This software was developed by the Computer Systems Engineering group 77c208ed6SRick Macklem * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 87c208ed6SRick Macklem * contributed to Berkeley. 97c208ed6SRick Macklem * 107c208ed6SRick Macklem * Redistribution and use in source and binary forms, with or without 117c208ed6SRick Macklem * modification, are permitted provided that the following conditions 127c208ed6SRick Macklem * are met: 137c208ed6SRick Macklem * 1. Redistributions of source code must retain the above copyright 147c208ed6SRick Macklem * notice, this list of conditions and the following disclaimer. 157c208ed6SRick Macklem * 2. Redistributions in binary form must reproduce the above copyright 167c208ed6SRick Macklem * notice, this list of conditions and the following disclaimer in the 177c208ed6SRick Macklem * documentation and/or other materials provided with the distribution. 187c208ed6SRick Macklem * 3. All advertising materials mentioning features or use of this software 197c208ed6SRick Macklem * must display the following acknowledgement: 207c208ed6SRick Macklem * This product includes software developed by the University of 217c208ed6SRick Macklem * California, Lawrence Berkeley Laboratory and its contributors. 227c208ed6SRick Macklem * 4. Neither the name of the University nor the names of its contributors 237c208ed6SRick Macklem * may be used to endorse or promote products derived from this software 247c208ed6SRick Macklem * without specific prior written permission. 257c208ed6SRick Macklem * 267c208ed6SRick Macklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 277c208ed6SRick Macklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 287c208ed6SRick Macklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 297c208ed6SRick Macklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 307c208ed6SRick Macklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 317c208ed6SRick Macklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 327c208ed6SRick Macklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 337c208ed6SRick Macklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 347c208ed6SRick Macklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 357c208ed6SRick Macklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 367c208ed6SRick Macklem * SUCH DAMAGE. 377c208ed6SRick Macklem * 387c208ed6SRick Macklem * based on: 397c208ed6SRick Macklem * nfs/krpc_subr.c 407c208ed6SRick Macklem * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $ 417c208ed6SRick Macklem */ 427c208ed6SRick Macklem 437c208ed6SRick Macklem #include <sys/cdefs.h> 447c208ed6SRick Macklem __FBSDID("$FreeBSD$"); 457c208ed6SRick Macklem 467c208ed6SRick Macklem #include "opt_bootp.h" 47acd73f50SGrzegorz Bernacki #include "opt_nfs.h" 486cbd933bSIan Lepore #include "opt_rootdevname.h" 497c208ed6SRick Macklem 507c208ed6SRick Macklem #include <sys/param.h> 517c208ed6SRick Macklem #include <sys/systm.h> 527c208ed6SRick Macklem #include <sys/jail.h> 537c208ed6SRick Macklem #include <sys/kernel.h> 547c208ed6SRick Macklem #include <sys/sockio.h> 557c208ed6SRick Macklem #include <sys/malloc.h> 567c208ed6SRick Macklem #include <sys/mount.h> 577c208ed6SRick Macklem #include <sys/mbuf.h> 587c208ed6SRick Macklem #include <sys/proc.h> 596cbd933bSIan Lepore #include <sys/reboot.h> 607c208ed6SRick Macklem #include <sys/socket.h> 617c208ed6SRick Macklem #include <sys/socketvar.h> 627c208ed6SRick Macklem #include <sys/sysctl.h> 637c208ed6SRick Macklem #include <sys/uio.h> 647c208ed6SRick Macklem 657c208ed6SRick Macklem #include <net/if.h> 6676039bc8SGleb Smirnoff #include <net/if_var.h> 677c208ed6SRick Macklem #include <net/route.h> 687c208ed6SRick Macklem 697c208ed6SRick Macklem #include <netinet/in.h> 706bfaa839SGleb Smirnoff #include <netinet/in_var.h> 717c208ed6SRick Macklem #include <net/if_types.h> 727c208ed6SRick Macklem #include <net/if_dl.h> 737c208ed6SRick Macklem #include <net/vnet.h> 747c208ed6SRick Macklem 757c208ed6SRick Macklem #include <nfs/nfsproto.h> 767c208ed6SRick Macklem #include <nfsclient/nfs.h> 777c208ed6SRick Macklem #include <nfs/nfsdiskless.h> 787c208ed6SRick Macklem #include <nfs/krpc.h> 797c208ed6SRick Macklem #include <nfs/xdr_subs.h> 807c208ed6SRick Macklem 817c208ed6SRick Macklem 827c208ed6SRick Macklem #define BOOTP_MIN_LEN 300 /* Minimum size of bootp udp packet */ 837c208ed6SRick Macklem 847c208ed6SRick Macklem #ifndef BOOTP_SETTLE_DELAY 857c208ed6SRick Macklem #define BOOTP_SETTLE_DELAY 3 867c208ed6SRick Macklem #endif 877c208ed6SRick Macklem 887c208ed6SRick Macklem /* 891d4c5e51SOleksandr Tymoshenko * Wait 10 seconds for interface appearance 90c6fd18e0SOleksandr Tymoshenko * USB ethernet adapters might require some time to pop up 911d4c5e51SOleksandr Tymoshenko */ 921d4c5e51SOleksandr Tymoshenko #ifndef BOOTP_IFACE_WAIT_TIMEOUT 931d4c5e51SOleksandr Tymoshenko #define BOOTP_IFACE_WAIT_TIMEOUT 10 941d4c5e51SOleksandr Tymoshenko #endif 951d4c5e51SOleksandr Tymoshenko 961d4c5e51SOleksandr Tymoshenko /* 977c208ed6SRick Macklem * What is the longest we will wait before re-sending a request? 987c208ed6SRick Macklem * Note this is also the frequency of "RPC timeout" messages. 997c208ed6SRick Macklem * The re-send loop count sup linearly to this maximum, so the 1007c208ed6SRick Macklem * first complaint will happen after (1+2+3+4+5)=15 seconds. 1017c208ed6SRick Macklem */ 1027c208ed6SRick Macklem #define MAX_RESEND_DELAY 5 /* seconds */ 1037c208ed6SRick Macklem 1047c208ed6SRick Macklem /* Definitions from RFC951 */ 1057c208ed6SRick Macklem struct bootp_packet { 1067c208ed6SRick Macklem u_int8_t op; 1077c208ed6SRick Macklem u_int8_t htype; 1087c208ed6SRick Macklem u_int8_t hlen; 1097c208ed6SRick Macklem u_int8_t hops; 1107c208ed6SRick Macklem u_int32_t xid; 1117c208ed6SRick Macklem u_int16_t secs; 1127c208ed6SRick Macklem u_int16_t flags; 1137c208ed6SRick Macklem struct in_addr ciaddr; 1147c208ed6SRick Macklem struct in_addr yiaddr; 1157c208ed6SRick Macklem struct in_addr siaddr; 1167c208ed6SRick Macklem struct in_addr giaddr; 1177c208ed6SRick Macklem unsigned char chaddr[16]; 1187c208ed6SRick Macklem char sname[64]; 1197c208ed6SRick Macklem char file[128]; 1207c208ed6SRick Macklem unsigned char vend[1222]; 1217c208ed6SRick Macklem }; 1227c208ed6SRick Macklem 1237c208ed6SRick Macklem struct bootpc_ifcontext { 1246bfaa839SGleb Smirnoff STAILQ_ENTRY(bootpc_ifcontext) next; 1257c208ed6SRick Macklem struct bootp_packet call; 1267c208ed6SRick Macklem struct bootp_packet reply; 1277c208ed6SRick Macklem int replylen; 1287c208ed6SRick Macklem int overload; 1296bfaa839SGleb Smirnoff union { 1306bfaa839SGleb Smirnoff struct ifreq _ifreq; 1316bfaa839SGleb Smirnoff struct in_aliasreq _in_alias_req; 1326bfaa839SGleb Smirnoff } _req; 1336bfaa839SGleb Smirnoff #define ireq _req._ifreq 1346bfaa839SGleb Smirnoff #define iareq _req._in_alias_req 1357c208ed6SRick Macklem struct ifnet *ifp; 1367c208ed6SRick Macklem struct sockaddr_dl *sdl; 1377c208ed6SRick Macklem struct sockaddr_in myaddr; 1387c208ed6SRick Macklem struct sockaddr_in netmask; 1397c208ed6SRick Macklem struct sockaddr_in gw; 1407c208ed6SRick Macklem int gotgw; 1417c208ed6SRick Macklem int gotnetmask; 1427c208ed6SRick Macklem int gotrootpath; 1437c208ed6SRick Macklem int outstanding; 1447c208ed6SRick Macklem int sentmsg; 1457c208ed6SRick Macklem u_int32_t xid; 1467c208ed6SRick Macklem enum { 1477c208ed6SRick Macklem IF_BOOTP_UNRESOLVED, 1487c208ed6SRick Macklem IF_BOOTP_RESOLVED, 1497c208ed6SRick Macklem IF_BOOTP_FAILED, 1507c208ed6SRick Macklem IF_DHCP_UNRESOLVED, 1517c208ed6SRick Macklem IF_DHCP_OFFERED, 1527c208ed6SRick Macklem IF_DHCP_RESOLVED, 1537c208ed6SRick Macklem IF_DHCP_FAILED, 1547c208ed6SRick Macklem } state; 1557c208ed6SRick Macklem int dhcpquerytype; /* dhcp type sent */ 1567c208ed6SRick Macklem struct in_addr dhcpserver; 1577c208ed6SRick Macklem int gotdhcpserver; 1587c208ed6SRick Macklem }; 1597c208ed6SRick Macklem 1607c208ed6SRick Macklem #define TAG_MAXLEN 1024 1617c208ed6SRick Macklem struct bootpc_tagcontext { 1627c208ed6SRick Macklem char buf[TAG_MAXLEN + 1]; 1637c208ed6SRick Macklem int overload; 1647c208ed6SRick Macklem int badopt; 1657c208ed6SRick Macklem int badtag; 1667c208ed6SRick Macklem int foundopt; 1677c208ed6SRick Macklem int taglen; 1687c208ed6SRick Macklem }; 1697c208ed6SRick Macklem 1707c208ed6SRick Macklem struct bootpc_globalcontext { 1716bfaa839SGleb Smirnoff STAILQ_HEAD(, bootpc_ifcontext) interfaces; 1727c208ed6SRick Macklem u_int32_t xid; 1736cbd933bSIan Lepore int any_root_overrides; 1747c208ed6SRick Macklem int gotrootpath; 1757c208ed6SRick Macklem int gotgw; 1767c208ed6SRick Macklem int ifnum; 1777c208ed6SRick Macklem int secs; 1787c208ed6SRick Macklem int starttime; 1797c208ed6SRick Macklem struct bootp_packet reply; 1807c208ed6SRick Macklem int replylen; 1817c208ed6SRick Macklem struct bootpc_ifcontext *setrootfs; 1827c208ed6SRick Macklem struct bootpc_ifcontext *sethostname; 1837c208ed6SRick Macklem struct bootpc_tagcontext tmptag; 1847c208ed6SRick Macklem struct bootpc_tagcontext tag; 1857c208ed6SRick Macklem }; 1867c208ed6SRick Macklem 1877c208ed6SRick Macklem #define IPPORT_BOOTPC 68 1887c208ed6SRick Macklem #define IPPORT_BOOTPS 67 1897c208ed6SRick Macklem 1907c208ed6SRick Macklem #define BOOTP_REQUEST 1 1917c208ed6SRick Macklem #define BOOTP_REPLY 2 1927c208ed6SRick Macklem 1937c208ed6SRick Macklem /* Common tags */ 1947c208ed6SRick Macklem #define TAG_PAD 0 /* Pad option, implicit length 1 */ 1957c208ed6SRick Macklem #define TAG_SUBNETMASK 1 /* RFC 950 subnet mask */ 1967c208ed6SRick Macklem #define TAG_ROUTERS 3 /* Routers (in order of preference) */ 1977c208ed6SRick Macklem #define TAG_HOSTNAME 12 /* Client host name */ 1987c208ed6SRick Macklem #define TAG_ROOT 17 /* Root path */ 1997c208ed6SRick Macklem 2007c208ed6SRick Macklem /* DHCP specific tags */ 2017c208ed6SRick Macklem #define TAG_OVERLOAD 52 /* Option Overload */ 2027c208ed6SRick Macklem #define TAG_MAXMSGSIZE 57 /* Maximum DHCP Message Size */ 2037c208ed6SRick Macklem 2047c208ed6SRick Macklem #define TAG_END 255 /* End Option (i.e. no more options) */ 2057c208ed6SRick Macklem 2067c208ed6SRick Macklem /* Overload values */ 2077c208ed6SRick Macklem #define OVERLOAD_FILE 1 2087c208ed6SRick Macklem #define OVERLOAD_SNAME 2 2097c208ed6SRick Macklem 2107c208ed6SRick Macklem /* Site specific tags: */ 2117c208ed6SRick Macklem #define TAG_ROOTOPTS 130 2127c208ed6SRick Macklem #define TAG_COOKIE 134 /* ascii info for userland, via sysctl */ 2137c208ed6SRick Macklem 2147c208ed6SRick Macklem #define TAG_DHCP_MSGTYPE 53 2157c208ed6SRick Macklem #define TAG_DHCP_REQ_ADDR 50 2167c208ed6SRick Macklem #define TAG_DHCP_SERVERID 54 2177c208ed6SRick Macklem #define TAG_DHCP_LEASETIME 51 2187c208ed6SRick Macklem 2197c208ed6SRick Macklem #define TAG_VENDOR_INDENTIFIER 60 2207c208ed6SRick Macklem 2217c208ed6SRick Macklem #define DHCP_NOMSG 0 2227c208ed6SRick Macklem #define DHCP_DISCOVER 1 2237c208ed6SRick Macklem #define DHCP_OFFER 2 2247c208ed6SRick Macklem #define DHCP_REQUEST 3 2257c208ed6SRick Macklem #define DHCP_ACK 5 2267c208ed6SRick Macklem 2277c208ed6SRick Macklem /* NFS read/write block size */ 2287c208ed6SRick Macklem #ifndef BOOTP_BLOCKSIZE 2297c208ed6SRick Macklem #define BOOTP_BLOCKSIZE 8192 2307c208ed6SRick Macklem #endif 2317c208ed6SRick Macklem 2327c208ed6SRick Macklem static char bootp_cookie[128]; 2336bfaa839SGleb Smirnoff static struct socket *bootp_so; 2347c208ed6SRick Macklem SYSCTL_STRING(_kern, OID_AUTO, bootp_cookie, CTLFLAG_RD, 2357c208ed6SRick Macklem bootp_cookie, 0, "Cookie (T134) supplied by bootp server"); 2367c208ed6SRick Macklem 2377c208ed6SRick Macklem /* mountd RPC */ 2387c208ed6SRick Macklem static int md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp, 2397c208ed6SRick Macklem int *fhsizep, struct nfs_args *args, struct thread *td); 2407c208ed6SRick Macklem static int setfs(struct sockaddr_in *addr, char *path, char *p, 2417c208ed6SRick Macklem const struct in_addr *siaddr); 2427c208ed6SRick Macklem static int getdec(char **ptr); 2437c208ed6SRick Macklem static int getip(char **ptr, struct in_addr *ip); 2447c208ed6SRick Macklem static void mountopts(struct nfs_args *args, char *p); 2457c208ed6SRick Macklem static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len); 2467c208ed6SRick Macklem static int xdr_int_decode(struct mbuf **ptr, int *iptr); 2477c208ed6SRick Macklem static void print_in_addr(struct in_addr addr); 2487c208ed6SRick Macklem static void print_sin_addr(struct sockaddr_in *addr); 2497c208ed6SRick Macklem static void clear_sinaddr(struct sockaddr_in *sin); 2507c208ed6SRick Macklem static void allocifctx(struct bootpc_globalcontext *gctx); 2517c208ed6SRick Macklem static void bootpc_compose_query(struct bootpc_ifcontext *ifctx, 2526bfaa839SGleb Smirnoff struct thread *td); 2537c208ed6SRick Macklem static unsigned char *bootpc_tag(struct bootpc_tagcontext *tctx, 2547c208ed6SRick Macklem struct bootp_packet *bp, int len, int tag); 2557c208ed6SRick Macklem static void bootpc_tag_helper(struct bootpc_tagcontext *tctx, 2567c208ed6SRick Macklem unsigned char *start, int len, int tag); 2577c208ed6SRick Macklem 2587c208ed6SRick Macklem #ifdef BOOTP_DEBUG 2597c208ed6SRick Macklem void bootpboot_p_sa(struct sockaddr *sa, struct sockaddr *ma); 2607c208ed6SRick Macklem void bootpboot_p_rtentry(struct rtentry *rt); 2617c208ed6SRick Macklem void bootpboot_p_tree(struct radix_node *rn); 2627c208ed6SRick Macklem void bootpboot_p_rtlist(void); 2637c208ed6SRick Macklem void bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa); 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 2737c208ed6SRick Macklem static int 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 2957c208ed6SRick Macklem void 2967c208ed6SRick Macklem bootpboot_p_sa(struct sockaddr *sa, struct sockaddr *ma) 2977c208ed6SRick Macklem { 2987c208ed6SRick Macklem 2997c208ed6SRick Macklem if (sa == NULL) { 3007c208ed6SRick Macklem printf("(sockaddr *) <null>"); 3017c208ed6SRick Macklem return; 3027c208ed6SRick Macklem } 3037c208ed6SRick Macklem switch (sa->sa_family) { 3047c208ed6SRick Macklem case AF_INET: 3057c208ed6SRick Macklem { 3067c208ed6SRick Macklem struct sockaddr_in *sin; 3077c208ed6SRick Macklem 3087c208ed6SRick Macklem sin = (struct sockaddr_in *) sa; 3097c208ed6SRick Macklem printf("inet "); 3107c208ed6SRick Macklem print_sin_addr(sin); 3117c208ed6SRick Macklem if (ma != NULL) { 3127c208ed6SRick Macklem sin = (struct sockaddr_in *) ma; 3137c208ed6SRick Macklem printf(" mask "); 3147c208ed6SRick Macklem print_sin_addr(sin); 3157c208ed6SRick Macklem } 3167c208ed6SRick Macklem } 3177c208ed6SRick Macklem break; 3187c208ed6SRick Macklem case AF_LINK: 3197c208ed6SRick Macklem { 3207c208ed6SRick Macklem struct sockaddr_dl *sli; 3217c208ed6SRick Macklem int i; 3227c208ed6SRick Macklem 3237c208ed6SRick Macklem sli = (struct sockaddr_dl *) sa; 3247c208ed6SRick Macklem printf("link %.*s ", sli->sdl_nlen, sli->sdl_data); 3257c208ed6SRick Macklem for (i = 0; i < sli->sdl_alen; i++) { 3267c208ed6SRick Macklem if (i > 0) 3277c208ed6SRick Macklem printf(":"); 3287c208ed6SRick Macklem printf("%x", ((unsigned char *) LLADDR(sli))[i]); 3297c208ed6SRick Macklem } 3307c208ed6SRick Macklem } 3317c208ed6SRick Macklem break; 3327c208ed6SRick Macklem default: 3337c208ed6SRick Macklem printf("af%d", sa->sa_family); 3347c208ed6SRick Macklem } 3357c208ed6SRick Macklem } 3367c208ed6SRick Macklem 3377c208ed6SRick Macklem void 3387c208ed6SRick Macklem bootpboot_p_rtentry(struct rtentry *rt) 3397c208ed6SRick Macklem { 3407c208ed6SRick Macklem 3417c208ed6SRick Macklem bootpboot_p_sa(rt_key(rt), rt_mask(rt)); 3427c208ed6SRick Macklem printf(" "); 3437c208ed6SRick Macklem bootpboot_p_sa(rt->rt_gateway, NULL); 3447c208ed6SRick Macklem printf(" "); 3457c208ed6SRick Macklem printf("flags %x", (unsigned short) rt->rt_flags); 346e3a7aa6fSGleb Smirnoff printf(" %d", (int) rt->rt_expire); 3477c208ed6SRick Macklem printf(" %s\n", rt->rt_ifp->if_xname); 3487c208ed6SRick Macklem } 3497c208ed6SRick Macklem 3507c208ed6SRick Macklem void 3517c208ed6SRick Macklem bootpboot_p_tree(struct radix_node *rn) 3527c208ed6SRick Macklem { 3537c208ed6SRick Macklem 3547c208ed6SRick Macklem while (rn != NULL) { 3557c208ed6SRick Macklem if (rn->rn_bit < 0) { 3567c208ed6SRick Macklem if ((rn->rn_flags & RNF_ROOT) != 0) { 3577c208ed6SRick Macklem } else { 3587c208ed6SRick Macklem bootpboot_p_rtentry((struct rtentry *) rn); 3597c208ed6SRick Macklem } 3607c208ed6SRick Macklem rn = rn->rn_dupedkey; 3617c208ed6SRick Macklem } else { 3627c208ed6SRick Macklem bootpboot_p_tree(rn->rn_left); 3637c208ed6SRick Macklem bootpboot_p_tree(rn->rn_right); 3647c208ed6SRick Macklem return; 3657c208ed6SRick Macklem } 3667c208ed6SRick Macklem } 3677c208ed6SRick Macklem } 3687c208ed6SRick Macklem 3697c208ed6SRick Macklem void 3707c208ed6SRick Macklem bootpboot_p_rtlist(void) 3717c208ed6SRick Macklem { 3727c208ed6SRick Macklem struct radix_node_head *rnh; 3737c208ed6SRick Macklem 3747c208ed6SRick Macklem printf("Routing table:\n"); 3757c208ed6SRick Macklem rnh = rt_tables_get_rnh(0, AF_INET); 3767c208ed6SRick Macklem if (rnh == NULL) 3777c208ed6SRick Macklem return; 3787c208ed6SRick Macklem RADIX_NODE_HEAD_RLOCK(rnh); /* could sleep XXX */ 3797c208ed6SRick Macklem bootpboot_p_tree(rnh->rnh_treetop); 3807c208ed6SRick Macklem RADIX_NODE_HEAD_RUNLOCK(rnh); 3817c208ed6SRick Macklem } 3827c208ed6SRick Macklem 3837c208ed6SRick Macklem void 3847c208ed6SRick Macklem bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa) 3857c208ed6SRick Macklem { 3867c208ed6SRick Macklem 3877c208ed6SRick Macklem printf("%s flags %x, addr ", 3887c208ed6SRick Macklem ifp->if_xname, ifp->if_flags); 3897c208ed6SRick Macklem print_sin_addr((struct sockaddr_in *) ifa->ifa_addr); 3907c208ed6SRick Macklem printf(", broadcast "); 3917c208ed6SRick Macklem print_sin_addr((struct sockaddr_in *) ifa->ifa_dstaddr); 3927c208ed6SRick Macklem printf(", netmask "); 3937c208ed6SRick Macklem print_sin_addr((struct sockaddr_in *) ifa->ifa_netmask); 3947c208ed6SRick Macklem printf("\n"); 3957c208ed6SRick Macklem } 3967c208ed6SRick Macklem 3977c208ed6SRick Macklem void 3987c208ed6SRick Macklem bootpboot_p_iflist(void) 3997c208ed6SRick Macklem { 4007c208ed6SRick Macklem struct ifnet *ifp; 4017c208ed6SRick Macklem struct ifaddr *ifa; 4027c208ed6SRick Macklem 4037c208ed6SRick Macklem printf("Interface list:\n"); 4047c208ed6SRick Macklem IFNET_RLOCK(); 4057c208ed6SRick Macklem for (ifp = TAILQ_FIRST(&V_ifnet); 4067c208ed6SRick Macklem ifp != NULL; 4077c208ed6SRick Macklem ifp = TAILQ_NEXT(ifp, if_link)) { 4087c208ed6SRick Macklem for (ifa = TAILQ_FIRST(&ifp->if_addrhead); 4097c208ed6SRick Macklem ifa != NULL; 4107c208ed6SRick Macklem ifa = TAILQ_NEXT(ifa, ifa_link)) 4117c208ed6SRick Macklem if (ifa->ifa_addr->sa_family == AF_INET) 4127c208ed6SRick Macklem bootpboot_p_if(ifp, ifa); 4137c208ed6SRick Macklem } 4147c208ed6SRick Macklem IFNET_RUNLOCK(); 4157c208ed6SRick Macklem } 4167c208ed6SRick Macklem #endif /* defined(BOOTP_DEBUG) */ 4177c208ed6SRick Macklem 4187c208ed6SRick Macklem static void 4197c208ed6SRick Macklem clear_sinaddr(struct sockaddr_in *sin) 4207c208ed6SRick Macklem { 4217c208ed6SRick Macklem 4227c208ed6SRick Macklem bzero(sin, sizeof(*sin)); 4237c208ed6SRick Macklem sin->sin_len = sizeof(*sin); 4247c208ed6SRick Macklem sin->sin_family = AF_INET; 4257c208ed6SRick Macklem sin->sin_addr.s_addr = INADDR_ANY; /* XXX: htonl(INAADDR_ANY) ? */ 4267c208ed6SRick Macklem sin->sin_port = 0; 4277c208ed6SRick Macklem } 4287c208ed6SRick Macklem 4297c208ed6SRick Macklem static void 4307c208ed6SRick Macklem allocifctx(struct bootpc_globalcontext *gctx) 4317c208ed6SRick Macklem { 4327c208ed6SRick Macklem struct bootpc_ifcontext *ifctx; 4337c208ed6SRick Macklem 4346bfaa839SGleb Smirnoff ifctx = malloc(sizeof(*ifctx), M_TEMP, M_WAITOK | M_ZERO); 4357c208ed6SRick Macklem ifctx->xid = gctx->xid; 4367c208ed6SRick Macklem #ifdef BOOTP_NO_DHCP 4377c208ed6SRick Macklem ifctx->state = IF_BOOTP_UNRESOLVED; 4387c208ed6SRick Macklem #else 4397c208ed6SRick Macklem ifctx->state = IF_DHCP_UNRESOLVED; 4407c208ed6SRick Macklem #endif 4417c208ed6SRick Macklem gctx->xid += 0x100; 4426bfaa839SGleb Smirnoff STAILQ_INSERT_TAIL(&gctx->interfaces, ifctx, next); 4437c208ed6SRick Macklem } 4447c208ed6SRick Macklem 4457c208ed6SRick Macklem static __inline int 4467c208ed6SRick Macklem bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx) 4477c208ed6SRick Macklem { 4487c208ed6SRick Macklem 4497c208ed6SRick Macklem if (ifctx->state == IF_BOOTP_RESOLVED || 4507c208ed6SRick Macklem ifctx->state == IF_DHCP_RESOLVED) 4517c208ed6SRick Macklem return 1; 4527c208ed6SRick Macklem return 0; 4537c208ed6SRick Macklem } 4547c208ed6SRick Macklem 4557c208ed6SRick Macklem static __inline int 4567c208ed6SRick Macklem bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx) 4577c208ed6SRick Macklem { 4587c208ed6SRick Macklem 4597c208ed6SRick Macklem if (ifctx->state == IF_BOOTP_UNRESOLVED || 4607c208ed6SRick Macklem ifctx->state == IF_DHCP_UNRESOLVED) 4617c208ed6SRick Macklem return 1; 4627c208ed6SRick Macklem return 0; 4637c208ed6SRick Macklem } 4647c208ed6SRick Macklem 4657c208ed6SRick Macklem static __inline int 4667c208ed6SRick Macklem bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx) 4677c208ed6SRick Macklem { 4687c208ed6SRick Macklem 4697c208ed6SRick Macklem if (ifctx->state == IF_BOOTP_FAILED || 4707c208ed6SRick Macklem ifctx->state == IF_DHCP_FAILED) 4717c208ed6SRick Macklem return 1; 4727c208ed6SRick Macklem return 0; 4737c208ed6SRick Macklem } 4747c208ed6SRick Macklem 4757c208ed6SRick Macklem static int 4767c208ed6SRick Macklem bootpc_received(struct bootpc_globalcontext *gctx, 4777c208ed6SRick Macklem struct bootpc_ifcontext *ifctx) 4787c208ed6SRick Macklem { 4797c208ed6SRick Macklem unsigned char dhcpreplytype; 4807c208ed6SRick Macklem char *p; 4817c208ed6SRick Macklem 4827c208ed6SRick Macklem /* 4837c208ed6SRick Macklem * Need timeout for fallback to less 4847c208ed6SRick Macklem * desirable alternative. 4857c208ed6SRick Macklem */ 4867c208ed6SRick Macklem 4877c208ed6SRick Macklem /* This call used for the side effect (badopt flag) */ 4887c208ed6SRick Macklem (void) bootpc_tag(&gctx->tmptag, &gctx->reply, 4897c208ed6SRick Macklem gctx->replylen, 4907c208ed6SRick Macklem TAG_END); 4917c208ed6SRick Macklem 4927c208ed6SRick Macklem /* If packet is invalid, ignore it */ 4937c208ed6SRick Macklem if (gctx->tmptag.badopt != 0) 4947c208ed6SRick Macklem return 0; 4957c208ed6SRick Macklem 4967c208ed6SRick Macklem p = bootpc_tag(&gctx->tmptag, &gctx->reply, 4977c208ed6SRick Macklem gctx->replylen, TAG_DHCP_MSGTYPE); 4987c208ed6SRick Macklem if (p != NULL) 4997c208ed6SRick Macklem dhcpreplytype = *p; 5007c208ed6SRick Macklem else 5017c208ed6SRick Macklem dhcpreplytype = DHCP_NOMSG; 5027c208ed6SRick Macklem 5037c208ed6SRick Macklem switch (ifctx->dhcpquerytype) { 5047c208ed6SRick Macklem case DHCP_DISCOVER: 5057c208ed6SRick Macklem if (dhcpreplytype != DHCP_OFFER /* Normal DHCP offer */ 5067c208ed6SRick Macklem #ifndef BOOTP_FORCE_DHCP 5077c208ed6SRick Macklem && dhcpreplytype != DHCP_NOMSG /* Fallback to BOOTP */ 5087c208ed6SRick Macklem #endif 5097c208ed6SRick Macklem ) 5107c208ed6SRick Macklem return 0; 5117c208ed6SRick Macklem break; 5127c208ed6SRick Macklem case DHCP_REQUEST: 5137c208ed6SRick Macklem if (dhcpreplytype != DHCP_ACK) 5147c208ed6SRick Macklem return 0; 5157c208ed6SRick Macklem case DHCP_NOMSG: 5167c208ed6SRick Macklem break; 5177c208ed6SRick Macklem } 5187c208ed6SRick Macklem 5197c208ed6SRick Macklem /* Ignore packet unless it gives us a root tag we didn't have */ 5207c208ed6SRick Macklem 5217c208ed6SRick Macklem if ((ifctx->state == IF_BOOTP_RESOLVED || 5227c208ed6SRick Macklem (ifctx->dhcpquerytype == DHCP_DISCOVER && 5237c208ed6SRick Macklem (ifctx->state == IF_DHCP_OFFERED || 5247c208ed6SRick Macklem ifctx->state == IF_DHCP_RESOLVED))) && 5257c208ed6SRick Macklem (bootpc_tag(&gctx->tmptag, &ifctx->reply, 5267c208ed6SRick Macklem ifctx->replylen, 5277c208ed6SRick Macklem TAG_ROOT) != NULL || 5287c208ed6SRick Macklem bootpc_tag(&gctx->tmptag, &gctx->reply, 5297c208ed6SRick Macklem gctx->replylen, 5307c208ed6SRick Macklem TAG_ROOT) == NULL)) 5317c208ed6SRick Macklem return 0; 5327c208ed6SRick Macklem 5337c208ed6SRick Macklem bcopy(&gctx->reply, &ifctx->reply, gctx->replylen); 5347c208ed6SRick Macklem ifctx->replylen = gctx->replylen; 5357c208ed6SRick Macklem 5367c208ed6SRick Macklem /* XXX: Only reset if 'perfect' response */ 5377c208ed6SRick Macklem if (ifctx->state == IF_BOOTP_UNRESOLVED) 5387c208ed6SRick Macklem ifctx->state = IF_BOOTP_RESOLVED; 5397c208ed6SRick Macklem else if (ifctx->state == IF_DHCP_UNRESOLVED && 5407c208ed6SRick Macklem ifctx->dhcpquerytype == DHCP_DISCOVER) { 5417c208ed6SRick Macklem if (dhcpreplytype == DHCP_OFFER) 5427c208ed6SRick Macklem ifctx->state = IF_DHCP_OFFERED; 5437c208ed6SRick Macklem else 5447c208ed6SRick Macklem ifctx->state = IF_BOOTP_RESOLVED; /* Fallback */ 5457c208ed6SRick Macklem } else if (ifctx->state == IF_DHCP_OFFERED && 5467c208ed6SRick Macklem ifctx->dhcpquerytype == DHCP_REQUEST) 5477c208ed6SRick Macklem ifctx->state = IF_DHCP_RESOLVED; 5487c208ed6SRick Macklem 5497c208ed6SRick Macklem 5507c208ed6SRick Macklem if (ifctx->dhcpquerytype == DHCP_DISCOVER && 5517c208ed6SRick Macklem ifctx->state != IF_BOOTP_RESOLVED) { 5527c208ed6SRick Macklem p = bootpc_tag(&gctx->tmptag, &ifctx->reply, 5537c208ed6SRick Macklem ifctx->replylen, TAG_DHCP_SERVERID); 5547c208ed6SRick Macklem if (p != NULL && gctx->tmptag.taglen == 4) { 5557c208ed6SRick Macklem memcpy(&ifctx->dhcpserver, p, 4); 5567c208ed6SRick Macklem ifctx->gotdhcpserver = 1; 5577c208ed6SRick Macklem } else 5587c208ed6SRick Macklem ifctx->gotdhcpserver = 0; 5597c208ed6SRick Macklem return 1; 5607c208ed6SRick Macklem } 5617c208ed6SRick Macklem 5627c208ed6SRick Macklem ifctx->gotrootpath = (bootpc_tag(&gctx->tmptag, &ifctx->reply, 5637c208ed6SRick Macklem ifctx->replylen, 5647c208ed6SRick Macklem TAG_ROOT) != NULL); 5657c208ed6SRick Macklem ifctx->gotgw = (bootpc_tag(&gctx->tmptag, &ifctx->reply, 5667c208ed6SRick Macklem ifctx->replylen, 5677c208ed6SRick Macklem TAG_ROUTERS) != NULL); 5687c208ed6SRick Macklem ifctx->gotnetmask = (bootpc_tag(&gctx->tmptag, &ifctx->reply, 5697c208ed6SRick Macklem ifctx->replylen, 5707c208ed6SRick Macklem TAG_SUBNETMASK) != NULL); 5717c208ed6SRick Macklem return 1; 5727c208ed6SRick Macklem } 5737c208ed6SRick Macklem 5747c208ed6SRick Macklem static int 5757c208ed6SRick Macklem bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td) 5767c208ed6SRick Macklem { 5777c208ed6SRick Macklem struct sockaddr_in *sin, dst; 5787c208ed6SRick Macklem struct uio auio; 5797c208ed6SRick Macklem struct sockopt sopt; 5807c208ed6SRick Macklem struct iovec aio; 5817c208ed6SRick Macklem int error, on, rcvflg, timo, len; 5827c208ed6SRick Macklem time_t atimo; 5837c208ed6SRick Macklem time_t rtimo; 5847c208ed6SRick Macklem struct timeval tv; 5857c208ed6SRick Macklem struct bootpc_ifcontext *ifctx; 5867c208ed6SRick Macklem int outstanding; 5877c208ed6SRick Macklem int gotrootpath; 5887c208ed6SRick Macklem int retry; 5897c208ed6SRick Macklem const char *s; 5907c208ed6SRick Macklem 5917c208ed6SRick Macklem tv.tv_sec = 1; 5927c208ed6SRick Macklem tv.tv_usec = 0; 5937c208ed6SRick Macklem bzero(&sopt, sizeof(sopt)); 5947c208ed6SRick Macklem sopt.sopt_dir = SOPT_SET; 5957c208ed6SRick Macklem sopt.sopt_level = SOL_SOCKET; 5967c208ed6SRick Macklem sopt.sopt_name = SO_RCVTIMEO; 5977c208ed6SRick Macklem sopt.sopt_val = &tv; 5987c208ed6SRick Macklem sopt.sopt_valsize = sizeof tv; 5997c208ed6SRick Macklem 6006bfaa839SGleb Smirnoff error = sosetopt(bootp_so, &sopt); 6017c208ed6SRick Macklem if (error != 0) 6027c208ed6SRick Macklem goto out; 6037c208ed6SRick Macklem 6047c208ed6SRick Macklem /* 6057c208ed6SRick Macklem * Enable broadcast. 6067c208ed6SRick Macklem */ 6077c208ed6SRick Macklem on = 1; 6087c208ed6SRick Macklem sopt.sopt_name = SO_BROADCAST; 6097c208ed6SRick Macklem sopt.sopt_val = &on; 6107c208ed6SRick Macklem sopt.sopt_valsize = sizeof on; 6117c208ed6SRick Macklem 6126bfaa839SGleb Smirnoff error = sosetopt(bootp_so, &sopt); 6137c208ed6SRick Macklem if (error != 0) 6147c208ed6SRick Macklem goto out; 6157c208ed6SRick Macklem 6167c208ed6SRick Macklem /* 6177c208ed6SRick Macklem * Disable routing. 6187c208ed6SRick Macklem */ 6197c208ed6SRick Macklem 6207c208ed6SRick Macklem on = 1; 6217c208ed6SRick Macklem sopt.sopt_name = SO_DONTROUTE; 6227c208ed6SRick Macklem sopt.sopt_val = &on; 6237c208ed6SRick Macklem sopt.sopt_valsize = sizeof on; 6247c208ed6SRick Macklem 6256bfaa839SGleb Smirnoff error = sosetopt(bootp_so, &sopt); 6267c208ed6SRick Macklem if (error != 0) 6277c208ed6SRick Macklem goto out; 6287c208ed6SRick Macklem 6297c208ed6SRick Macklem /* 6307c208ed6SRick Macklem * Bind the local endpoint to a bootp client port. 6317c208ed6SRick Macklem */ 6327c208ed6SRick Macklem sin = &dst; 6337c208ed6SRick Macklem clear_sinaddr(sin); 6347c208ed6SRick Macklem sin->sin_port = htons(IPPORT_BOOTPC); 6356bfaa839SGleb Smirnoff error = sobind(bootp_so, (struct sockaddr *)sin, td); 6367c208ed6SRick Macklem if (error != 0) { 6377c208ed6SRick Macklem printf("bind failed\n"); 6387c208ed6SRick Macklem goto out; 6397c208ed6SRick Macklem } 6407c208ed6SRick Macklem 6417c208ed6SRick Macklem /* 6427c208ed6SRick Macklem * Setup socket address for the server. 6437c208ed6SRick Macklem */ 6447c208ed6SRick Macklem sin = &dst; 6457c208ed6SRick Macklem clear_sinaddr(sin); 6467c208ed6SRick Macklem sin->sin_addr.s_addr = INADDR_BROADCAST; 6477c208ed6SRick Macklem sin->sin_port = htons(IPPORT_BOOTPS); 6487c208ed6SRick Macklem 6497c208ed6SRick Macklem /* 6507c208ed6SRick Macklem * Send it, repeatedly, until a reply is received, 6517c208ed6SRick Macklem * but delay each re-send by an increasing amount. 6527c208ed6SRick Macklem * If the delay hits the maximum, start complaining. 6537c208ed6SRick Macklem */ 6547c208ed6SRick Macklem timo = 0; 6557c208ed6SRick Macklem rtimo = 0; 6567c208ed6SRick Macklem for (;;) { 6577c208ed6SRick Macklem 6587c208ed6SRick Macklem outstanding = 0; 6597c208ed6SRick Macklem gotrootpath = 0; 6607c208ed6SRick Macklem 6616bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) { 6627c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) != 0 && 6637c208ed6SRick Macklem bootpc_tag(&gctx->tmptag, &ifctx->reply, 6647c208ed6SRick Macklem ifctx->replylen, 6657c208ed6SRick Macklem TAG_ROOT) != NULL) 6667c208ed6SRick Macklem gotrootpath = 1; 6677c208ed6SRick Macklem } 6687c208ed6SRick Macklem 6696bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) { 6706bfaa839SGleb Smirnoff struct in_aliasreq *ifra = &ifctx->iareq; 6716bfaa839SGleb Smirnoff sin = (struct sockaddr_in *)&ifra->ifra_mask; 6726bfaa839SGleb Smirnoff 6737c208ed6SRick Macklem ifctx->outstanding = 0; 6747c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) != 0 && 6757c208ed6SRick Macklem gotrootpath != 0) { 6767c208ed6SRick Macklem continue; 6777c208ed6SRick Macklem } 6787c208ed6SRick Macklem if (bootpc_ifctx_isfailed(ifctx) != 0) 6797c208ed6SRick Macklem continue; 6807c208ed6SRick Macklem 6817c208ed6SRick Macklem outstanding++; 6827c208ed6SRick Macklem ifctx->outstanding = 1; 6837c208ed6SRick Macklem 6847c208ed6SRick Macklem /* Proceed to next step in DHCP negotiation */ 6857c208ed6SRick Macklem if ((ifctx->state == IF_DHCP_OFFERED && 6867c208ed6SRick Macklem ifctx->dhcpquerytype != DHCP_REQUEST) || 6877c208ed6SRick Macklem (ifctx->state == IF_DHCP_UNRESOLVED && 6887c208ed6SRick Macklem ifctx->dhcpquerytype != DHCP_DISCOVER) || 6897c208ed6SRick Macklem (ifctx->state == IF_BOOTP_UNRESOLVED && 6907c208ed6SRick Macklem ifctx->dhcpquerytype != DHCP_NOMSG)) { 6917c208ed6SRick Macklem ifctx->sentmsg = 0; 6926bfaa839SGleb Smirnoff bootpc_compose_query(ifctx, td); 6937c208ed6SRick Macklem } 6947c208ed6SRick Macklem 6957c208ed6SRick Macklem /* Send BOOTP request (or re-send). */ 6967c208ed6SRick Macklem 6977c208ed6SRick Macklem if (ifctx->sentmsg == 0) { 6987c208ed6SRick Macklem switch(ifctx->dhcpquerytype) { 6997c208ed6SRick Macklem case DHCP_DISCOVER: 7007c208ed6SRick Macklem s = "DHCP Discover"; 7017c208ed6SRick Macklem break; 7027c208ed6SRick Macklem case DHCP_REQUEST: 7037c208ed6SRick Macklem s = "DHCP Request"; 7047c208ed6SRick Macklem break; 7057c208ed6SRick Macklem case DHCP_NOMSG: 7067c208ed6SRick Macklem default: 7077c208ed6SRick Macklem s = "BOOTP Query"; 7087c208ed6SRick Macklem break; 7097c208ed6SRick Macklem } 7107c208ed6SRick Macklem printf("Sending %s packet from " 7117c208ed6SRick Macklem "interface %s (%*D)\n", 7127c208ed6SRick Macklem s, 7137c208ed6SRick Macklem ifctx->ireq.ifr_name, 7147c208ed6SRick Macklem ifctx->sdl->sdl_alen, 7157c208ed6SRick Macklem (unsigned char *) LLADDR(ifctx->sdl), 7167c208ed6SRick Macklem ":"); 7177c208ed6SRick Macklem ifctx->sentmsg = 1; 7187c208ed6SRick Macklem } 7197c208ed6SRick Macklem 7207c208ed6SRick Macklem aio.iov_base = (caddr_t) &ifctx->call; 7217c208ed6SRick Macklem aio.iov_len = sizeof(ifctx->call); 7227c208ed6SRick Macklem 7237c208ed6SRick Macklem auio.uio_iov = &aio; 7247c208ed6SRick Macklem auio.uio_iovcnt = 1; 7257c208ed6SRick Macklem auio.uio_segflg = UIO_SYSSPACE; 7267c208ed6SRick Macklem auio.uio_rw = UIO_WRITE; 7277c208ed6SRick Macklem auio.uio_offset = 0; 7287c208ed6SRick Macklem auio.uio_resid = sizeof(ifctx->call); 7297c208ed6SRick Macklem auio.uio_td = td; 7307c208ed6SRick Macklem 7317c208ed6SRick Macklem /* Set netmask to 0.0.0.0 */ 7327c208ed6SRick Macklem clear_sinaddr(sin); 7336bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, 7346bfaa839SGleb Smirnoff td); 7357c208ed6SRick Macklem if (error != 0) 7366bfaa839SGleb Smirnoff panic("%s: SIOCAIFADDR, error=%d", __func__, 7377c208ed6SRick Macklem error); 7387c208ed6SRick Macklem 7396bfaa839SGleb Smirnoff error = sosend(bootp_so, (struct sockaddr *) &dst, 7407c208ed6SRick Macklem &auio, NULL, NULL, 0, td); 7416bfaa839SGleb Smirnoff if (error != 0) 7426bfaa839SGleb Smirnoff printf("%s: sosend: %d state %08x\n", __func__, 7436bfaa839SGleb Smirnoff error, (int )bootp_so->so_state); 7447c208ed6SRick Macklem 7457c208ed6SRick Macklem /* Set netmask to 255.0.0.0 */ 7466bfaa839SGleb Smirnoff sin->sin_addr.s_addr = htonl(IN_CLASSA_NET); 7476bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, 7486bfaa839SGleb Smirnoff td); 7497c208ed6SRick Macklem if (error != 0) 7506bfaa839SGleb Smirnoff panic("%s: SIOCAIFADDR, error=%d", __func__, 7517c208ed6SRick Macklem error); 7527c208ed6SRick Macklem } 7537c208ed6SRick Macklem 7547c208ed6SRick Macklem if (outstanding == 0 && 7557c208ed6SRick Macklem (rtimo == 0 || time_second >= rtimo)) { 7567c208ed6SRick Macklem error = 0; 7576bfaa839SGleb Smirnoff goto out; 7587c208ed6SRick Macklem } 7597c208ed6SRick Macklem 7607c208ed6SRick Macklem /* Determine new timeout. */ 7617c208ed6SRick Macklem if (timo < MAX_RESEND_DELAY) 7627c208ed6SRick Macklem timo++; 7637c208ed6SRick Macklem else { 7647c208ed6SRick Macklem printf("DHCP/BOOTP timeout for server "); 7657c208ed6SRick Macklem print_sin_addr(&dst); 7667c208ed6SRick Macklem printf("\n"); 7677c208ed6SRick Macklem } 7687c208ed6SRick Macklem 7697c208ed6SRick Macklem /* 7707c208ed6SRick Macklem * Wait for up to timo seconds for a reply. 7717c208ed6SRick Macklem * The socket receive timeout was set to 1 second. 7727c208ed6SRick Macklem */ 7737c208ed6SRick Macklem atimo = timo + time_second; 7747c208ed6SRick Macklem while (time_second < atimo) { 7757c208ed6SRick Macklem aio.iov_base = (caddr_t) &gctx->reply; 7767c208ed6SRick Macklem aio.iov_len = sizeof(gctx->reply); 7777c208ed6SRick Macklem 7787c208ed6SRick Macklem auio.uio_iov = &aio; 7797c208ed6SRick Macklem auio.uio_iovcnt = 1; 7807c208ed6SRick Macklem auio.uio_segflg = UIO_SYSSPACE; 7817c208ed6SRick Macklem auio.uio_rw = UIO_READ; 7827c208ed6SRick Macklem auio.uio_offset = 0; 7837c208ed6SRick Macklem auio.uio_resid = sizeof(gctx->reply); 7847c208ed6SRick Macklem auio.uio_td = td; 7857c208ed6SRick Macklem 7867c208ed6SRick Macklem rcvflg = 0; 7876bfaa839SGleb Smirnoff error = soreceive(bootp_so, NULL, &auio, 7887c208ed6SRick Macklem NULL, NULL, &rcvflg); 7897c208ed6SRick Macklem gctx->secs = time_second - gctx->starttime; 7906bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) { 7917c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) != 0 || 7927c208ed6SRick Macklem bootpc_ifctx_isfailed(ifctx) != 0) 7937c208ed6SRick Macklem continue; 7947c208ed6SRick Macklem 7957c208ed6SRick Macklem ifctx->call.secs = htons(gctx->secs); 7967c208ed6SRick Macklem } 7977c208ed6SRick Macklem if (error == EWOULDBLOCK) 7987c208ed6SRick Macklem continue; 7997c208ed6SRick Macklem if (error != 0) 8007c208ed6SRick Macklem goto out; 8017c208ed6SRick Macklem len = sizeof(gctx->reply) - auio.uio_resid; 8027c208ed6SRick Macklem 8037c208ed6SRick Macklem /* Do we have the required number of bytes ? */ 8047c208ed6SRick Macklem if (len < BOOTP_MIN_LEN) 8057c208ed6SRick Macklem continue; 8067c208ed6SRick Macklem gctx->replylen = len; 8077c208ed6SRick Macklem 8087c208ed6SRick Macklem /* Is it a reply? */ 8097c208ed6SRick Macklem if (gctx->reply.op != BOOTP_REPLY) 8107c208ed6SRick Macklem continue; 8117c208ed6SRick Macklem 8127c208ed6SRick Macklem /* Is this an answer to our query */ 8136bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) { 8147c208ed6SRick Macklem if (gctx->reply.xid != ifctx->call.xid) 8157c208ed6SRick Macklem continue; 8167c208ed6SRick Macklem 8177c208ed6SRick Macklem /* Same HW address size ? */ 8187c208ed6SRick Macklem if (gctx->reply.hlen != ifctx->call.hlen) 8197c208ed6SRick Macklem continue; 8207c208ed6SRick Macklem 8217c208ed6SRick Macklem /* Correct HW address ? */ 8227c208ed6SRick Macklem if (bcmp(gctx->reply.chaddr, 8237c208ed6SRick Macklem ifctx->call.chaddr, 8247c208ed6SRick Macklem ifctx->call.hlen) != 0) 8257c208ed6SRick Macklem continue; 8267c208ed6SRick Macklem 8277c208ed6SRick Macklem break; 8287c208ed6SRick Macklem } 8297c208ed6SRick Macklem 8307c208ed6SRick Macklem if (ifctx != NULL) { 8317c208ed6SRick Macklem s = bootpc_tag(&gctx->tmptag, 8327c208ed6SRick Macklem &gctx->reply, 8337c208ed6SRick Macklem gctx->replylen, 8347c208ed6SRick Macklem TAG_DHCP_MSGTYPE); 8357c208ed6SRick Macklem if (s != NULL) { 8367c208ed6SRick Macklem switch (*s) { 8377c208ed6SRick Macklem case DHCP_OFFER: 8387c208ed6SRick Macklem s = "DHCP Offer"; 8397c208ed6SRick Macklem break; 8407c208ed6SRick Macklem case DHCP_ACK: 8417c208ed6SRick Macklem s = "DHCP Ack"; 8427c208ed6SRick Macklem break; 8437c208ed6SRick Macklem default: 8447c208ed6SRick Macklem s = "DHCP (unexpected)"; 8457c208ed6SRick Macklem break; 8467c208ed6SRick Macklem } 8477c208ed6SRick Macklem } else 8487c208ed6SRick Macklem s = "BOOTP Reply"; 8497c208ed6SRick Macklem 8507c208ed6SRick Macklem printf("Received %s packet" 8517c208ed6SRick Macklem " on %s from ", 8527c208ed6SRick Macklem s, 8537c208ed6SRick Macklem ifctx->ireq.ifr_name); 8547c208ed6SRick Macklem print_in_addr(gctx->reply.siaddr); 8557c208ed6SRick Macklem if (gctx->reply.giaddr.s_addr != 8567c208ed6SRick Macklem htonl(INADDR_ANY)) { 8577c208ed6SRick Macklem printf(" via "); 8587c208ed6SRick Macklem print_in_addr(gctx->reply.giaddr); 8597c208ed6SRick Macklem } 8607c208ed6SRick Macklem if (bootpc_received(gctx, ifctx) != 0) { 8617c208ed6SRick Macklem printf(" (accepted)"); 8627c208ed6SRick Macklem if (ifctx->outstanding) { 8637c208ed6SRick Macklem ifctx->outstanding = 0; 8647c208ed6SRick Macklem outstanding--; 8657c208ed6SRick Macklem } 8667c208ed6SRick Macklem /* Network settle delay */ 8677c208ed6SRick Macklem if (outstanding == 0) 8687c208ed6SRick Macklem atimo = time_second + 8697c208ed6SRick Macklem BOOTP_SETTLE_DELAY; 8707c208ed6SRick Macklem } else 8717c208ed6SRick Macklem printf(" (ignored)"); 8726cbd933bSIan Lepore if (ifctx->gotrootpath || 8736cbd933bSIan Lepore gctx->any_root_overrides) { 8747c208ed6SRick Macklem gotrootpath = 1; 8757c208ed6SRick Macklem rtimo = time_second + 8767c208ed6SRick Macklem BOOTP_SETTLE_DELAY; 8776cbd933bSIan Lepore if (ifctx->gotrootpath) 8787c208ed6SRick Macklem printf(" (got root path)"); 8796cbd933bSIan Lepore } 8807c208ed6SRick Macklem printf("\n"); 8817c208ed6SRick Macklem } 8827c208ed6SRick Macklem } /* while secs */ 8837c208ed6SRick Macklem #ifdef BOOTP_TIMEOUT 8847c208ed6SRick Macklem if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0) 8857c208ed6SRick Macklem break; 8867c208ed6SRick Macklem #endif 8877c208ed6SRick Macklem /* Force a retry if halfway in DHCP negotiation */ 8887c208ed6SRick Macklem retry = 0; 8896bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 8907c208ed6SRick Macklem if (ifctx->state == IF_DHCP_OFFERED) { 8917c208ed6SRick Macklem if (ifctx->dhcpquerytype == DHCP_DISCOVER) 8927c208ed6SRick Macklem retry = 1; 8937c208ed6SRick Macklem else 8947c208ed6SRick Macklem ifctx->state = IF_DHCP_UNRESOLVED; 8957c208ed6SRick Macklem } 8967c208ed6SRick Macklem 8977c208ed6SRick Macklem if (retry != 0) 8987c208ed6SRick Macklem continue; 8997c208ed6SRick Macklem 9007c208ed6SRick Macklem if (gotrootpath != 0) { 9017c208ed6SRick Macklem gctx->gotrootpath = gotrootpath; 9027c208ed6SRick Macklem if (rtimo != 0 && time_second >= rtimo) 9037c208ed6SRick Macklem break; 9047c208ed6SRick Macklem } 9057c208ed6SRick Macklem } /* forever send/receive */ 9067c208ed6SRick Macklem 9077c208ed6SRick Macklem /* 9087c208ed6SRick Macklem * XXX: These are errors of varying seriousness being silently 9097c208ed6SRick Macklem * ignored 9107c208ed6SRick Macklem */ 9117c208ed6SRick Macklem 9126bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 9137c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) == 0) { 9147c208ed6SRick Macklem printf("%s timeout for interface %s\n", 9157c208ed6SRick Macklem ifctx->dhcpquerytype != DHCP_NOMSG ? 9167c208ed6SRick Macklem "DHCP" : "BOOTP", 9177c208ed6SRick Macklem ifctx->ireq.ifr_name); 9187c208ed6SRick Macklem } 9196bfaa839SGleb Smirnoff 9207c208ed6SRick Macklem if (gctx->gotrootpath != 0) { 9217c208ed6SRick Macklem #if 0 9227c208ed6SRick Macklem printf("Got a root path, ignoring remaining timeout\n"); 9237c208ed6SRick Macklem #endif 9247c208ed6SRick Macklem error = 0; 9257c208ed6SRick Macklem goto out; 9267c208ed6SRick Macklem } 9277c208ed6SRick Macklem #ifndef BOOTP_NFSROOT 9286bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 9297c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) != 0) { 9307c208ed6SRick Macklem error = 0; 9317c208ed6SRick Macklem goto out; 9327c208ed6SRick Macklem } 9337c208ed6SRick Macklem #endif 9347c208ed6SRick Macklem error = ETIMEDOUT; 9357c208ed6SRick Macklem 9367c208ed6SRick Macklem out: 9376bfaa839SGleb Smirnoff return (error); 9387c208ed6SRick Macklem } 9397c208ed6SRick Macklem 9406bfaa839SGleb Smirnoff static void 9416bfaa839SGleb Smirnoff bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx, struct thread *td) 9427c208ed6SRick Macklem { 9436bfaa839SGleb Smirnoff struct ifreq *ifr; 9446bfaa839SGleb Smirnoff struct in_aliasreq *ifra; 9457c208ed6SRick Macklem struct sockaddr_in *sin; 9467c208ed6SRick Macklem int error; 9477c208ed6SRick Macklem 9486bfaa839SGleb Smirnoff ifr = &ifctx->ireq; 9496bfaa839SGleb Smirnoff ifra = &ifctx->iareq; 9507c208ed6SRick Macklem 9517c208ed6SRick Macklem /* 9527c208ed6SRick Macklem * Bring up the interface. 9537c208ed6SRick Macklem * 9547c208ed6SRick Macklem * Get the old interface flags and or IFF_UP into them; if 9557c208ed6SRick Macklem * IFF_UP set blindly, interface selection can be clobbered. 9567c208ed6SRick Macklem */ 9576bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCGIFFLAGS, (caddr_t)ifr, td); 9587c208ed6SRick Macklem if (error != 0) 9596bfaa839SGleb Smirnoff panic("%s: SIOCGIFFLAGS, error=%d", __func__, error); 9606bfaa839SGleb Smirnoff ifr->ifr_flags |= IFF_UP; 9616bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCSIFFLAGS, (caddr_t)ifr, td); 9627c208ed6SRick Macklem if (error != 0) 9636bfaa839SGleb Smirnoff panic("%s: SIOCSIFFLAGS, error=%d", __func__, error); 9647c208ed6SRick Macklem 9657c208ed6SRick Macklem /* 9667c208ed6SRick Macklem * Do enough of ifconfig(8) so that the chosen interface 9676bfaa839SGleb Smirnoff * can talk to the servers. Set address to 0.0.0.0/8 and 9686bfaa839SGleb Smirnoff * broadcast address to local broadcast. 9697c208ed6SRick Macklem */ 9706bfaa839SGleb Smirnoff sin = (struct sockaddr_in *)&ifra->ifra_addr; 9717c208ed6SRick Macklem clear_sinaddr(sin); 9726bfaa839SGleb Smirnoff sin = (struct sockaddr_in *)&ifra->ifra_mask; 9737c208ed6SRick Macklem clear_sinaddr(sin); 9746bfaa839SGleb Smirnoff sin->sin_addr.s_addr = htonl(IN_CLASSA_NET); 9756bfaa839SGleb Smirnoff sin = (struct sockaddr_in *)&ifra->ifra_broadaddr; 9767c208ed6SRick Macklem clear_sinaddr(sin); 9777c208ed6SRick Macklem sin->sin_addr.s_addr = htonl(INADDR_BROADCAST); 9786bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, td); 9797c208ed6SRick Macklem if (error != 0) 9806bfaa839SGleb Smirnoff panic("%s: SIOCAIFADDR, error=%d", __func__, error); 9817c208ed6SRick Macklem } 9827c208ed6SRick Macklem 9836bfaa839SGleb Smirnoff static void 9846bfaa839SGleb Smirnoff bootpc_shutdown_interface(struct bootpc_ifcontext *ifctx, struct thread *td) 9856bfaa839SGleb Smirnoff { 9866bfaa839SGleb Smirnoff struct ifreq *ifr; 9876bfaa839SGleb Smirnoff struct sockaddr_in *sin; 9886bfaa839SGleb Smirnoff int error; 9897c208ed6SRick Macklem 9906bfaa839SGleb Smirnoff ifr = &ifctx->ireq; 9916bfaa839SGleb Smirnoff 9926bfaa839SGleb Smirnoff printf("Shutdown interface %s\n", ifctx->ireq.ifr_name); 9936bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCGIFFLAGS, (caddr_t)ifr, td); 9946bfaa839SGleb Smirnoff if (error != 0) 9956bfaa839SGleb Smirnoff panic("%s: SIOCGIFFLAGS, error=%d", __func__, error); 9966bfaa839SGleb Smirnoff ifr->ifr_flags &= ~IFF_UP; 9976bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCSIFFLAGS, (caddr_t)ifr, td); 9986bfaa839SGleb Smirnoff if (error != 0) 9996bfaa839SGleb Smirnoff panic("%s: SIOCSIFFLAGS, error=%d", __func__, error); 10006bfaa839SGleb Smirnoff 10016bfaa839SGleb Smirnoff sin = (struct sockaddr_in *) &ifr->ifr_addr; 10026bfaa839SGleb Smirnoff clear_sinaddr(sin); 10036bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCDIFADDR, (caddr_t) ifr, td); 10046bfaa839SGleb Smirnoff if (error != 0) 10056bfaa839SGleb Smirnoff panic("%s: SIOCDIFADDR, error=%d", __func__, error); 10067c208ed6SRick Macklem } 10077c208ed6SRick Macklem 10087c208ed6SRick Macklem static int 10097c208ed6SRick Macklem bootpc_adjust_interface(struct bootpc_ifcontext *ifctx, 10107c208ed6SRick Macklem struct bootpc_globalcontext *gctx, struct thread *td) 10117c208ed6SRick Macklem { 10127c208ed6SRick Macklem int error; 10137c208ed6SRick Macklem struct sockaddr_in defdst; 10147c208ed6SRick Macklem struct sockaddr_in defmask; 10157c208ed6SRick Macklem struct sockaddr_in *sin; 10166bfaa839SGleb Smirnoff struct ifreq *ifr; 10176bfaa839SGleb Smirnoff struct in_aliasreq *ifra; 10187c208ed6SRick Macklem struct sockaddr_in *myaddr; 10197c208ed6SRick Macklem struct sockaddr_in *netmask; 10207c208ed6SRick Macklem struct sockaddr_in *gw; 10217c208ed6SRick Macklem 10226bfaa839SGleb Smirnoff ifr = &ifctx->ireq; 10236bfaa839SGleb Smirnoff ifra = &ifctx->iareq; 10247c208ed6SRick Macklem myaddr = &ifctx->myaddr; 10257c208ed6SRick Macklem netmask = &ifctx->netmask; 10267c208ed6SRick Macklem gw = &ifctx->gw; 10277c208ed6SRick Macklem 10287c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) == 0) { 10297c208ed6SRick Macklem /* Shutdown interfaces where BOOTP failed */ 10306bfaa839SGleb Smirnoff bootpc_shutdown_interface(ifctx, td); 10316bfaa839SGleb Smirnoff return (0); 10327c208ed6SRick Macklem } 10337c208ed6SRick Macklem 10347c208ed6SRick Macklem printf("Adjusted interface %s\n", ifctx->ireq.ifr_name); 10357c208ed6SRick Macklem /* 10367c208ed6SRick Macklem * Do enough of ifconfig(8) so that the chosen interface 10377c208ed6SRick Macklem * can talk to the servers. (just set the address) 10387c208ed6SRick Macklem */ 10396bfaa839SGleb Smirnoff sin = (struct sockaddr_in *) &ifr->ifr_addr; 10407c208ed6SRick Macklem clear_sinaddr(sin); 10416bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCDIFADDR, (caddr_t) ifr, td); 10427c208ed6SRick Macklem if (error != 0) 10436bfaa839SGleb Smirnoff panic("%s: SIOCDIFADDR, error=%d", __func__, error); 10447c208ed6SRick Macklem 10456bfaa839SGleb Smirnoff bcopy(myaddr, &ifra->ifra_addr, sizeof(*myaddr)); 10466bfaa839SGleb Smirnoff bcopy(netmask, &ifra->ifra_mask, sizeof(*netmask)); 10476bfaa839SGleb Smirnoff clear_sinaddr(&ifra->ifra_broadaddr); 10486bfaa839SGleb Smirnoff ifra->ifra_broadaddr.sin_addr.s_addr = myaddr->sin_addr.s_addr | 10496bfaa839SGleb Smirnoff ~netmask->sin_addr.s_addr; 10506bfaa839SGleb Smirnoff 10516bfaa839SGleb Smirnoff error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, td); 10526bfaa839SGleb Smirnoff if (error != 0) 10536bfaa839SGleb Smirnoff panic("%s: SIOCAIFADDR, error=%d", __func__, error); 10547c208ed6SRick Macklem 10557c208ed6SRick Macklem /* Add new default route */ 10567c208ed6SRick Macklem 10577c208ed6SRick Macklem if (ifctx->gotgw != 0 || gctx->gotgw == 0) { 10587c208ed6SRick Macklem clear_sinaddr(&defdst); 10597c208ed6SRick Macklem clear_sinaddr(&defmask); 10607c208ed6SRick Macklem /* XXX MRT just table 0 */ 10617c208ed6SRick Macklem error = rtrequest_fib(RTM_ADD, 106281d5d46bSBjoern A. Zeeb (struct sockaddr *) &defdst, (struct sockaddr *) gw, 10637c208ed6SRick Macklem (struct sockaddr *) &defmask, 106481d5d46bSBjoern A. Zeeb (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, RT_DEFAULT_FIB); 10657c208ed6SRick Macklem if (error != 0) { 10666bfaa839SGleb Smirnoff printf("%s: RTM_ADD, error=%d\n", __func__, error); 10676bfaa839SGleb Smirnoff return (error); 10687c208ed6SRick Macklem } 10697c208ed6SRick Macklem } 10707c208ed6SRick Macklem 10716bfaa839SGleb Smirnoff return (0); 10727c208ed6SRick Macklem } 10737c208ed6SRick Macklem 10747c208ed6SRick Macklem static int 10757c208ed6SRick Macklem setfs(struct sockaddr_in *addr, char *path, char *p, 10767c208ed6SRick Macklem const struct in_addr *siaddr) 10777c208ed6SRick Macklem { 10787c208ed6SRick Macklem 10797c208ed6SRick Macklem if (getip(&p, &addr->sin_addr) == 0) { 10807c208ed6SRick Macklem if (siaddr != NULL && *p == '/') 10817c208ed6SRick Macklem bcopy(siaddr, &addr->sin_addr, sizeof(struct in_addr)); 10827c208ed6SRick Macklem else 10837c208ed6SRick Macklem return 0; 10847c208ed6SRick Macklem } else { 10857c208ed6SRick Macklem if (*p != ':') 10867c208ed6SRick Macklem return 0; 10877c208ed6SRick Macklem p++; 10887c208ed6SRick Macklem } 10897c208ed6SRick Macklem 10907c208ed6SRick Macklem addr->sin_len = sizeof(struct sockaddr_in); 10917c208ed6SRick Macklem addr->sin_family = AF_INET; 10927c208ed6SRick Macklem 10937c208ed6SRick Macklem strlcpy(path, p, MNAMELEN); 10947c208ed6SRick Macklem return 1; 10957c208ed6SRick Macklem } 10967c208ed6SRick Macklem 10977c208ed6SRick Macklem static int 10987c208ed6SRick Macklem getip(char **ptr, struct in_addr *addr) 10997c208ed6SRick Macklem { 11007c208ed6SRick Macklem char *p; 11017c208ed6SRick Macklem unsigned int ip; 11027c208ed6SRick Macklem int val; 11037c208ed6SRick Macklem 11047c208ed6SRick Macklem p = *ptr; 11057c208ed6SRick Macklem ip = 0; 11067c208ed6SRick Macklem if (((val = getdec(&p)) < 0) || (val > 255)) 11077c208ed6SRick Macklem return 0; 11087c208ed6SRick Macklem ip = val << 24; 11097c208ed6SRick Macklem if (*p != '.') 11107c208ed6SRick Macklem return 0; 11117c208ed6SRick Macklem p++; 11127c208ed6SRick Macklem if (((val = getdec(&p)) < 0) || (val > 255)) 11137c208ed6SRick Macklem return 0; 11147c208ed6SRick Macklem ip |= (val << 16); 11157c208ed6SRick Macklem if (*p != '.') 11167c208ed6SRick Macklem return 0; 11177c208ed6SRick Macklem p++; 11187c208ed6SRick Macklem if (((val = getdec(&p)) < 0) || (val > 255)) 11197c208ed6SRick Macklem return 0; 11207c208ed6SRick Macklem ip |= (val << 8); 11217c208ed6SRick Macklem if (*p != '.') 11227c208ed6SRick Macklem return 0; 11237c208ed6SRick Macklem p++; 11247c208ed6SRick Macklem if (((val = getdec(&p)) < 0) || (val > 255)) 11257c208ed6SRick Macklem return 0; 11267c208ed6SRick Macklem ip |= val; 11277c208ed6SRick Macklem 11287c208ed6SRick Macklem addr->s_addr = htonl(ip); 11297c208ed6SRick Macklem *ptr = p; 11307c208ed6SRick Macklem return 1; 11317c208ed6SRick Macklem } 11327c208ed6SRick Macklem 11337c208ed6SRick Macklem static int 11347c208ed6SRick Macklem getdec(char **ptr) 11357c208ed6SRick Macklem { 11367c208ed6SRick Macklem char *p; 11377c208ed6SRick Macklem int ret; 11387c208ed6SRick Macklem 11397c208ed6SRick Macklem p = *ptr; 11407c208ed6SRick Macklem ret = 0; 11417c208ed6SRick Macklem if ((*p < '0') || (*p > '9')) 11427c208ed6SRick Macklem return -1; 11437c208ed6SRick Macklem while ((*p >= '0') && (*p <= '9')) { 11447c208ed6SRick Macklem ret = ret * 10 + (*p - '0'); 11457c208ed6SRick Macklem p++; 11467c208ed6SRick Macklem } 11477c208ed6SRick Macklem *ptr = p; 11487c208ed6SRick Macklem return ret; 11497c208ed6SRick Macklem } 11507c208ed6SRick Macklem 11517c208ed6SRick Macklem static void 11527c208ed6SRick Macklem mountopts(struct nfs_args *args, char *p) 11537c208ed6SRick Macklem { 11547c208ed6SRick Macklem args->version = NFS_ARGSVERSION; 11557c208ed6SRick Macklem args->rsize = BOOTP_BLOCKSIZE; 11567c208ed6SRick Macklem args->wsize = BOOTP_BLOCKSIZE; 11577c208ed6SRick Macklem args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT; 11587c208ed6SRick Macklem args->sotype = SOCK_DGRAM; 11597c208ed6SRick Macklem if (p != NULL) 11607c208ed6SRick Macklem nfs_parse_options(p, args); 11617c208ed6SRick Macklem } 11627c208ed6SRick Macklem 11637c208ed6SRick Macklem static int 11647c208ed6SRick Macklem xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len) 11657c208ed6SRick Macklem { 11667c208ed6SRick Macklem struct mbuf *m; 11677c208ed6SRick Macklem int alignedlen; 11687c208ed6SRick Macklem 11697c208ed6SRick Macklem m = *mptr; 11707c208ed6SRick Macklem alignedlen = ( len + 3 ) & ~3; 11717c208ed6SRick Macklem 11727c208ed6SRick Macklem if (m->m_len < alignedlen) { 11737c208ed6SRick Macklem m = m_pullup(m, alignedlen); 11747c208ed6SRick Macklem if (m == NULL) { 11757c208ed6SRick Macklem *mptr = NULL; 11767c208ed6SRick Macklem return EBADRPC; 11777c208ed6SRick Macklem } 11787c208ed6SRick Macklem } 11797c208ed6SRick Macklem bcopy(mtod(m, u_char *), buf, len); 11807c208ed6SRick Macklem m_adj(m, alignedlen); 11817c208ed6SRick Macklem *mptr = m; 11827c208ed6SRick Macklem return 0; 11837c208ed6SRick Macklem } 11847c208ed6SRick Macklem 11857c208ed6SRick Macklem static int 11867c208ed6SRick Macklem xdr_int_decode(struct mbuf **mptr, int *iptr) 11877c208ed6SRick Macklem { 11887c208ed6SRick Macklem u_int32_t i; 11897c208ed6SRick Macklem 11907c208ed6SRick Macklem if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0) 11917c208ed6SRick Macklem return EBADRPC; 11927c208ed6SRick Macklem *iptr = fxdr_unsigned(u_int32_t, i); 11937c208ed6SRick Macklem return 0; 11947c208ed6SRick Macklem } 11957c208ed6SRick Macklem 11967c208ed6SRick Macklem static void 11977c208ed6SRick Macklem print_sin_addr(struct sockaddr_in *sin) 11987c208ed6SRick Macklem { 11997c208ed6SRick Macklem 12007c208ed6SRick Macklem print_in_addr(sin->sin_addr); 12017c208ed6SRick Macklem } 12027c208ed6SRick Macklem 12037c208ed6SRick Macklem static void 12047c208ed6SRick Macklem print_in_addr(struct in_addr addr) 12057c208ed6SRick Macklem { 12067c208ed6SRick Macklem unsigned int ip; 12077c208ed6SRick Macklem 12087c208ed6SRick Macklem ip = ntohl(addr.s_addr); 12097c208ed6SRick Macklem printf("%d.%d.%d.%d", 12107c208ed6SRick Macklem ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255); 12117c208ed6SRick Macklem } 12127c208ed6SRick Macklem 12137c208ed6SRick Macklem static void 12146bfaa839SGleb Smirnoff bootpc_compose_query(struct bootpc_ifcontext *ifctx, struct thread *td) 12157c208ed6SRick Macklem { 12167c208ed6SRick Macklem unsigned char *vendp; 12177c208ed6SRick Macklem unsigned char vendor_client[64]; 12187c208ed6SRick Macklem uint32_t leasetime; 12197c208ed6SRick Macklem uint8_t vendor_client_len; 12207c208ed6SRick Macklem 12217c208ed6SRick Macklem ifctx->gotrootpath = 0; 12227c208ed6SRick Macklem 12237c208ed6SRick Macklem bzero((caddr_t) &ifctx->call, sizeof(ifctx->call)); 12247c208ed6SRick Macklem 12257c208ed6SRick Macklem /* bootpc part */ 12267c208ed6SRick Macklem ifctx->call.op = BOOTP_REQUEST; /* BOOTREQUEST */ 12277c208ed6SRick Macklem ifctx->call.htype = 1; /* 10mb ethernet */ 12287c208ed6SRick Macklem ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */ 12297c208ed6SRick Macklem ifctx->call.hops = 0; 12307c208ed6SRick Macklem if (bootpc_ifctx_isunresolved(ifctx) != 0) 12317c208ed6SRick Macklem ifctx->xid++; 12327c208ed6SRick Macklem ifctx->call.xid = txdr_unsigned(ifctx->xid); 12337c208ed6SRick Macklem bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen); 12347c208ed6SRick Macklem 12357c208ed6SRick Macklem vendp = ifctx->call.vend; 12367c208ed6SRick Macklem *vendp++ = 99; /* RFC1048 cookie */ 12377c208ed6SRick Macklem *vendp++ = 130; 12387c208ed6SRick Macklem *vendp++ = 83; 12397c208ed6SRick Macklem *vendp++ = 99; 12407c208ed6SRick Macklem *vendp++ = TAG_MAXMSGSIZE; 12417c208ed6SRick Macklem *vendp++ = 2; 12427c208ed6SRick Macklem *vendp++ = (sizeof(struct bootp_packet) >> 8) & 255; 12437c208ed6SRick Macklem *vendp++ = sizeof(struct bootp_packet) & 255; 12447c208ed6SRick Macklem 12457c208ed6SRick Macklem snprintf(vendor_client, sizeof(vendor_client), "%s:%s:%s", 12467c208ed6SRick Macklem ostype, MACHINE, osrelease); 12477c208ed6SRick Macklem vendor_client_len = strlen(vendor_client); 12487c208ed6SRick Macklem *vendp++ = TAG_VENDOR_INDENTIFIER; 12497c208ed6SRick Macklem *vendp++ = vendor_client_len; 12507c208ed6SRick Macklem memcpy(vendp, vendor_client, vendor_client_len); 12517c208ed6SRick Macklem vendp += vendor_client_len; 12527c208ed6SRick Macklem ifctx->dhcpquerytype = DHCP_NOMSG; 12537c208ed6SRick Macklem switch (ifctx->state) { 12547c208ed6SRick Macklem case IF_DHCP_UNRESOLVED: 12557c208ed6SRick Macklem *vendp++ = TAG_DHCP_MSGTYPE; 12567c208ed6SRick Macklem *vendp++ = 1; 12577c208ed6SRick Macklem *vendp++ = DHCP_DISCOVER; 12587c208ed6SRick Macklem ifctx->dhcpquerytype = DHCP_DISCOVER; 12597c208ed6SRick Macklem ifctx->gotdhcpserver = 0; 12607c208ed6SRick Macklem break; 12617c208ed6SRick Macklem case IF_DHCP_OFFERED: 12627c208ed6SRick Macklem *vendp++ = TAG_DHCP_MSGTYPE; 12637c208ed6SRick Macklem *vendp++ = 1; 12647c208ed6SRick Macklem *vendp++ = DHCP_REQUEST; 12657c208ed6SRick Macklem ifctx->dhcpquerytype = DHCP_REQUEST; 12667c208ed6SRick Macklem *vendp++ = TAG_DHCP_REQ_ADDR; 12677c208ed6SRick Macklem *vendp++ = 4; 12687c208ed6SRick Macklem memcpy(vendp, &ifctx->reply.yiaddr, 4); 12697c208ed6SRick Macklem vendp += 4; 12707c208ed6SRick Macklem if (ifctx->gotdhcpserver != 0) { 12717c208ed6SRick Macklem *vendp++ = TAG_DHCP_SERVERID; 12727c208ed6SRick Macklem *vendp++ = 4; 12737c208ed6SRick Macklem memcpy(vendp, &ifctx->dhcpserver, 4); 12747c208ed6SRick Macklem vendp += 4; 12757c208ed6SRick Macklem } 12767c208ed6SRick Macklem *vendp++ = TAG_DHCP_LEASETIME; 12777c208ed6SRick Macklem *vendp++ = 4; 12787c208ed6SRick Macklem leasetime = htonl(300); 12797c208ed6SRick Macklem memcpy(vendp, &leasetime, 4); 12807c208ed6SRick Macklem vendp += 4; 12817c208ed6SRick Macklem break; 12827c208ed6SRick Macklem default: 12837c208ed6SRick Macklem break; 12847c208ed6SRick Macklem } 12857c208ed6SRick Macklem *vendp = TAG_END; 12867c208ed6SRick Macklem 12877c208ed6SRick Macklem ifctx->call.secs = 0; 12887c208ed6SRick Macklem ifctx->call.flags = htons(0x8000); /* We need a broadcast answer */ 12897c208ed6SRick Macklem } 12907c208ed6SRick Macklem 12917c208ed6SRick Macklem static int 12927c208ed6SRick Macklem bootpc_hascookie(struct bootp_packet *bp) 12937c208ed6SRick Macklem { 12947c208ed6SRick Macklem 12957c208ed6SRick Macklem return (bp->vend[0] == 99 && bp->vend[1] == 130 && 12967c208ed6SRick Macklem bp->vend[2] == 83 && bp->vend[3] == 99); 12977c208ed6SRick Macklem } 12987c208ed6SRick Macklem 12997c208ed6SRick Macklem static void 13007c208ed6SRick Macklem bootpc_tag_helper(struct bootpc_tagcontext *tctx, 13017c208ed6SRick Macklem unsigned char *start, int len, int tag) 13027c208ed6SRick Macklem { 13037c208ed6SRick Macklem unsigned char *j; 13047c208ed6SRick Macklem unsigned char *ej; 13057c208ed6SRick Macklem unsigned char code; 13067c208ed6SRick Macklem 13077c208ed6SRick Macklem if (tctx->badtag != 0 || tctx->badopt != 0) 13087c208ed6SRick Macklem return; 13097c208ed6SRick Macklem 13107c208ed6SRick Macklem j = start; 13117c208ed6SRick Macklem ej = j + len; 13127c208ed6SRick Macklem 13137c208ed6SRick Macklem while (j < ej) { 13147c208ed6SRick Macklem code = *j++; 13157c208ed6SRick Macklem if (code == TAG_PAD) 13167c208ed6SRick Macklem continue; 13177c208ed6SRick Macklem if (code == TAG_END) 13187c208ed6SRick Macklem return; 13197c208ed6SRick Macklem if (j >= ej || j + *j + 1 > ej) { 13207c208ed6SRick Macklem tctx->badopt = 1; 13217c208ed6SRick Macklem return; 13227c208ed6SRick Macklem } 13237c208ed6SRick Macklem len = *j++; 13247c208ed6SRick Macklem if (code == tag) { 13257c208ed6SRick Macklem if (tctx->taglen + len > TAG_MAXLEN) { 13267c208ed6SRick Macklem tctx->badtag = 1; 13277c208ed6SRick Macklem return; 13287c208ed6SRick Macklem } 13297c208ed6SRick Macklem tctx->foundopt = 1; 13307c208ed6SRick Macklem if (len > 0) 13317c208ed6SRick Macklem memcpy(tctx->buf + tctx->taglen, 13327c208ed6SRick Macklem j, len); 13337c208ed6SRick Macklem tctx->taglen += len; 13347c208ed6SRick Macklem } 13357c208ed6SRick Macklem if (code == TAG_OVERLOAD) 13367c208ed6SRick Macklem tctx->overload = *j; 13377c208ed6SRick Macklem 13387c208ed6SRick Macklem j += len; 13397c208ed6SRick Macklem } 13407c208ed6SRick Macklem } 13417c208ed6SRick Macklem 13427c208ed6SRick Macklem static unsigned char * 13437c208ed6SRick Macklem bootpc_tag(struct bootpc_tagcontext *tctx, 13447c208ed6SRick Macklem struct bootp_packet *bp, int len, int tag) 13457c208ed6SRick Macklem { 13467c208ed6SRick Macklem tctx->overload = 0; 13477c208ed6SRick Macklem tctx->badopt = 0; 13487c208ed6SRick Macklem tctx->badtag = 0; 13497c208ed6SRick Macklem tctx->foundopt = 0; 13507c208ed6SRick Macklem tctx->taglen = 0; 13517c208ed6SRick Macklem 13527c208ed6SRick Macklem if (bootpc_hascookie(bp) == 0) 13537c208ed6SRick Macklem return NULL; 13547c208ed6SRick Macklem 13557c208ed6SRick Macklem bootpc_tag_helper(tctx, &bp->vend[4], 13567c208ed6SRick Macklem (unsigned char *) bp + len - &bp->vend[4], tag); 13577c208ed6SRick Macklem 13587c208ed6SRick Macklem if ((tctx->overload & OVERLOAD_FILE) != 0) 13597c208ed6SRick Macklem bootpc_tag_helper(tctx, 13607c208ed6SRick Macklem (unsigned char *) bp->file, 13617c208ed6SRick Macklem sizeof(bp->file), 13627c208ed6SRick Macklem tag); 13637c208ed6SRick Macklem if ((tctx->overload & OVERLOAD_SNAME) != 0) 13647c208ed6SRick Macklem bootpc_tag_helper(tctx, 13657c208ed6SRick Macklem (unsigned char *) bp->sname, 13667c208ed6SRick Macklem sizeof(bp->sname), 13677c208ed6SRick Macklem tag); 13687c208ed6SRick Macklem 13697c208ed6SRick Macklem if (tctx->badopt != 0 || tctx->badtag != 0 || tctx->foundopt == 0) 13707c208ed6SRick Macklem return NULL; 13717c208ed6SRick Macklem tctx->buf[tctx->taglen] = '\0'; 13727c208ed6SRick Macklem return tctx->buf; 13737c208ed6SRick Macklem } 13747c208ed6SRick Macklem 13757c208ed6SRick Macklem static void 13767c208ed6SRick Macklem bootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx, 13777c208ed6SRick Macklem struct bootpc_globalcontext *gctx) 13787c208ed6SRick Macklem { 13796cbd933bSIan Lepore char *p, *s; 13807c208ed6SRick Macklem unsigned int ip; 13817c208ed6SRick Macklem 13827c208ed6SRick Macklem ifctx->gotgw = 0; 13837c208ed6SRick Macklem ifctx->gotnetmask = 0; 13847c208ed6SRick Macklem 13857c208ed6SRick Macklem clear_sinaddr(&ifctx->myaddr); 13867c208ed6SRick Macklem clear_sinaddr(&ifctx->netmask); 13877c208ed6SRick Macklem clear_sinaddr(&ifctx->gw); 13887c208ed6SRick Macklem 13897c208ed6SRick Macklem ifctx->myaddr.sin_addr = ifctx->reply.yiaddr; 13907c208ed6SRick Macklem 13917c208ed6SRick Macklem ip = ntohl(ifctx->myaddr.sin_addr.s_addr); 13927c208ed6SRick Macklem 13937c208ed6SRick Macklem printf("%s at ", ifctx->ireq.ifr_name); 13947c208ed6SRick Macklem print_sin_addr(&ifctx->myaddr); 13957c208ed6SRick Macklem printf(" server "); 13967c208ed6SRick Macklem print_in_addr(ifctx->reply.siaddr); 13977c208ed6SRick Macklem 13987c208ed6SRick Macklem ifctx->gw.sin_addr = ifctx->reply.giaddr; 13997c208ed6SRick Macklem if (ifctx->reply.giaddr.s_addr != htonl(INADDR_ANY)) { 14007c208ed6SRick Macklem printf(" via gateway "); 14017c208ed6SRick Macklem print_in_addr(ifctx->reply.giaddr); 14027c208ed6SRick Macklem } 14037c208ed6SRick Macklem 14047c208ed6SRick Macklem /* This call used for the side effect (overload flag) */ 14057c208ed6SRick Macklem (void) bootpc_tag(&gctx->tmptag, 14067c208ed6SRick Macklem &ifctx->reply, ifctx->replylen, TAG_END); 14077c208ed6SRick Macklem 14087c208ed6SRick Macklem if ((gctx->tmptag.overload & OVERLOAD_SNAME) == 0) 14097c208ed6SRick Macklem if (ifctx->reply.sname[0] != '\0') 14107c208ed6SRick Macklem printf(" server name %s", ifctx->reply.sname); 14117c208ed6SRick Macklem if ((gctx->tmptag.overload & OVERLOAD_FILE) == 0) 14127c208ed6SRick Macklem if (ifctx->reply.file[0] != '\0') 14137c208ed6SRick Macklem printf(" boot file %s", ifctx->reply.file); 14147c208ed6SRick Macklem 14157c208ed6SRick Macklem printf("\n"); 14167c208ed6SRick Macklem 14177c208ed6SRick Macklem p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 14187c208ed6SRick Macklem TAG_SUBNETMASK); 14197c208ed6SRick Macklem if (p != NULL) { 14207c208ed6SRick Macklem if (gctx->tag.taglen != 4) 14217c208ed6SRick Macklem panic("bootpc: subnet mask len is %d", 14227c208ed6SRick Macklem gctx->tag.taglen); 14237c208ed6SRick Macklem bcopy(p, &ifctx->netmask.sin_addr, 4); 14247c208ed6SRick Macklem ifctx->gotnetmask = 1; 14257c208ed6SRick Macklem printf("subnet mask "); 14267c208ed6SRick Macklem print_sin_addr(&ifctx->netmask); 14277c208ed6SRick Macklem printf(" "); 14287c208ed6SRick Macklem } 14297c208ed6SRick Macklem 14307c208ed6SRick Macklem p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 14317c208ed6SRick Macklem TAG_ROUTERS); 14327c208ed6SRick Macklem if (p != NULL) { 14337c208ed6SRick Macklem /* Routers */ 14347c208ed6SRick Macklem if (gctx->tag.taglen % 4) 14357c208ed6SRick Macklem panic("bootpc: Router Len is %d", gctx->tag.taglen); 14367c208ed6SRick Macklem if (gctx->tag.taglen > 0) { 14377c208ed6SRick Macklem bcopy(p, &ifctx->gw.sin_addr, 4); 14387c208ed6SRick Macklem printf("router "); 14397c208ed6SRick Macklem print_sin_addr(&ifctx->gw); 14407c208ed6SRick Macklem printf(" "); 14417c208ed6SRick Macklem ifctx->gotgw = 1; 14427c208ed6SRick Macklem gctx->gotgw = 1; 14437c208ed6SRick Macklem } 14447c208ed6SRick Macklem } 14457c208ed6SRick Macklem 14466cbd933bSIan Lepore /* 14476cbd933bSIan Lepore * Choose a root filesystem. If a value is forced in the environment 14486cbd933bSIan Lepore * and it contains "nfs:", use it unconditionally. Otherwise, if the 14496cbd933bSIan Lepore * kernel is compiled with the ROOTDEVNAME option, then use it if: 14506cbd933bSIan Lepore * - The server doesn't provide a pathname. 14516cbd933bSIan Lepore * - The boothowto flags include RB_DFLTROOT (user said to override 14526cbd933bSIan Lepore * the server value). 14536cbd933bSIan Lepore */ 14546cbd933bSIan Lepore p = NULL; 1455*2be111bfSDavide Italiano if ((s = kern_getenv("vfs.root.mountfrom")) != NULL) { 14566cbd933bSIan Lepore if ((p = strstr(s, "nfs:")) != NULL) 14576cbd933bSIan Lepore p = strdup(p + 4, M_TEMP); 14586cbd933bSIan Lepore freeenv(s); 14596cbd933bSIan Lepore } 14606cbd933bSIan Lepore if (p == NULL) { 14617c208ed6SRick Macklem p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 14627c208ed6SRick Macklem TAG_ROOT); 14636cbd933bSIan Lepore } 14646cbd933bSIan Lepore #ifdef ROOTDEVNAME 14656cbd933bSIan Lepore if ((p == NULL || (boothowto & RB_DFLTROOT) != 0) && 14666cbd933bSIan Lepore (p = strstr(ROOTDEVNAME, "nfs:")) != NULL) { 14676cbd933bSIan Lepore p += 4; 14686cbd933bSIan Lepore } 14696cbd933bSIan Lepore #endif 14707c208ed6SRick Macklem if (p != NULL) { 14717c208ed6SRick Macklem if (gctx->setrootfs != NULL) { 14727c208ed6SRick Macklem printf("rootfs %s (ignored) ", p); 14737c208ed6SRick Macklem } else if (setfs(&nd->root_saddr, 14747c208ed6SRick Macklem nd->root_hostnam, p, &ifctx->reply.siaddr)) { 14757c208ed6SRick Macklem if (*p == '/') { 14767c208ed6SRick Macklem printf("root_server "); 14777c208ed6SRick Macklem print_sin_addr(&nd->root_saddr); 14787c208ed6SRick Macklem printf(" "); 14797c208ed6SRick Macklem } 14807c208ed6SRick Macklem printf("rootfs %s ", p); 14817c208ed6SRick Macklem gctx->gotrootpath = 1; 14827c208ed6SRick Macklem ifctx->gotrootpath = 1; 14837c208ed6SRick Macklem gctx->setrootfs = ifctx; 14847c208ed6SRick Macklem 14857c208ed6SRick Macklem p = bootpc_tag(&gctx->tag, &ifctx->reply, 14867c208ed6SRick Macklem ifctx->replylen, 14877c208ed6SRick Macklem TAG_ROOTOPTS); 14887c208ed6SRick Macklem if (p != NULL) { 14897c208ed6SRick Macklem mountopts(&nd->root_args, p); 14907c208ed6SRick Macklem printf("rootopts %s ", p); 14917c208ed6SRick Macklem } 14927c208ed6SRick Macklem } else 14937c208ed6SRick Macklem panic("Failed to set rootfs to %s", p); 14947c208ed6SRick Macklem } 14957c208ed6SRick Macklem 14967c208ed6SRick Macklem p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 14977c208ed6SRick Macklem TAG_HOSTNAME); 14987c208ed6SRick Macklem if (p != NULL) { 14997c208ed6SRick Macklem if (gctx->tag.taglen >= MAXHOSTNAMELEN) 15007c208ed6SRick Macklem panic("bootpc: hostname >= %d bytes", 15017c208ed6SRick Macklem MAXHOSTNAMELEN); 15027c208ed6SRick Macklem if (gctx->sethostname != NULL) { 15037c208ed6SRick Macklem printf("hostname %s (ignored) ", p); 15047c208ed6SRick Macklem } else { 15057c208ed6SRick Macklem strcpy(nd->my_hostnam, p); 15067c208ed6SRick Macklem mtx_lock(&prison0.pr_mtx); 15077c208ed6SRick Macklem strcpy(prison0.pr_hostname, p); 15087c208ed6SRick Macklem mtx_unlock(&prison0.pr_mtx); 15097c208ed6SRick Macklem printf("hostname %s ", p); 15107c208ed6SRick Macklem gctx->sethostname = ifctx; 15117c208ed6SRick Macklem } 15127c208ed6SRick Macklem } 15137c208ed6SRick Macklem p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 15147c208ed6SRick Macklem TAG_COOKIE); 15157c208ed6SRick Macklem if (p != NULL) { /* store in a sysctl variable */ 15167c208ed6SRick Macklem int i, l = sizeof(bootp_cookie) - 1; 15177c208ed6SRick Macklem for (i = 0; i < l && p[i] != '\0'; i++) 15187c208ed6SRick Macklem bootp_cookie[i] = p[i]; 15197c208ed6SRick Macklem p[i] = '\0'; 15207c208ed6SRick Macklem } 15217c208ed6SRick Macklem 15227c208ed6SRick Macklem 15237c208ed6SRick Macklem printf("\n"); 15247c208ed6SRick Macklem 15257c208ed6SRick Macklem if (ifctx->gotnetmask == 0) { 15267c208ed6SRick Macklem if (IN_CLASSA(ntohl(ifctx->myaddr.sin_addr.s_addr))) 15277c208ed6SRick Macklem ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET); 15287c208ed6SRick Macklem else if (IN_CLASSB(ntohl(ifctx->myaddr.sin_addr.s_addr))) 15297c208ed6SRick Macklem ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET); 15307c208ed6SRick Macklem else 15317c208ed6SRick Macklem ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET); 15327c208ed6SRick Macklem } 15337c208ed6SRick Macklem if (ifctx->gotgw == 0) { 15347c208ed6SRick Macklem /* Use proxyarp */ 15357c208ed6SRick Macklem ifctx->gw.sin_addr.s_addr = ifctx->myaddr.sin_addr.s_addr; 15367c208ed6SRick Macklem } 15377c208ed6SRick Macklem } 15387c208ed6SRick Macklem 15397c208ed6SRick Macklem void 15407c208ed6SRick Macklem bootpc_init(void) 15417c208ed6SRick Macklem { 15426bfaa839SGleb Smirnoff struct bootpc_ifcontext *ifctx; /* Interface BOOTP contexts */ 15437c208ed6SRick Macklem struct bootpc_globalcontext *gctx; /* Global BOOTP context */ 15447c208ed6SRick Macklem struct ifnet *ifp; 15456bfaa839SGleb Smirnoff struct sockaddr_dl *sdl; 15466bfaa839SGleb Smirnoff struct ifaddr *ifa; 15477c208ed6SRick Macklem int error; 15487c208ed6SRick Macklem #ifndef BOOTP_WIRED_TO 15497c208ed6SRick Macklem int ifcnt; 15507c208ed6SRick Macklem #endif 15517c208ed6SRick Macklem struct nfsv3_diskless *nd; 15527c208ed6SRick Macklem struct thread *td; 1553c6fd18e0SOleksandr Tymoshenko int timeout; 1554c6fd18e0SOleksandr Tymoshenko int delay; 1555c6fd18e0SOleksandr Tymoshenko 1556c6fd18e0SOleksandr Tymoshenko timeout = BOOTP_IFACE_WAIT_TIMEOUT * hz; 1557c6fd18e0SOleksandr Tymoshenko delay = hz / 10; 15587c208ed6SRick Macklem 15597c208ed6SRick Macklem nd = &nfsv3_diskless; 15607c208ed6SRick Macklem td = curthread; 15617c208ed6SRick Macklem 15627c208ed6SRick Macklem /* 15637c208ed6SRick Macklem * If already filled in, don't touch it here 15647c208ed6SRick Macklem */ 15657c208ed6SRick Macklem if (nfs_diskless_valid != 0) 15667c208ed6SRick Macklem return; 15677c208ed6SRick Macklem 15687c208ed6SRick Macklem gctx = malloc(sizeof(*gctx), M_TEMP, M_WAITOK | M_ZERO); 15696bfaa839SGleb Smirnoff STAILQ_INIT(&gctx->interfaces); 15707c208ed6SRick Macklem gctx->xid = ~0xFFFF; 15717c208ed6SRick Macklem gctx->starttime = time_second; 15727c208ed6SRick Macklem 15737c208ed6SRick Macklem /* 15746cbd933bSIan Lepore * If ROOTDEVNAME is defined or vfs.root.mountfrom is set then we have 15756cbd933bSIan Lepore * root-path overrides that can potentially let us boot even if we don't 15766cbd933bSIan Lepore * get a root path from the server, so we can treat that as a non-error. 15776cbd933bSIan Lepore */ 15786cbd933bSIan Lepore #ifdef ROOTDEVNAME 15796cbd933bSIan Lepore gctx->any_root_overrides = 1; 15806cbd933bSIan Lepore #else 15816cbd933bSIan Lepore gctx->any_root_overrides = testenv("vfs.root.mountfrom"); 15826cbd933bSIan Lepore #endif 15836cbd933bSIan Lepore 15846cbd933bSIan Lepore /* 15857c208ed6SRick Macklem * Find a network interface. 15867c208ed6SRick Macklem */ 15877c208ed6SRick Macklem CURVNET_SET(TD_TO_VNET(td)); 15887c208ed6SRick Macklem #ifdef BOOTP_WIRED_TO 15896bfaa839SGleb Smirnoff printf("%s: wired to interface '%s'\n", __func__, 15907c208ed6SRick Macklem __XSTRING(BOOTP_WIRED_TO)); 15917c208ed6SRick Macklem allocifctx(gctx); 15927c208ed6SRick Macklem #else 15937c208ed6SRick Macklem /* 15947c208ed6SRick Macklem * Preallocate interface context storage, if another interface 15957c208ed6SRick Macklem * attaches and wins the race, it won't be eligible for bootp. 15967c208ed6SRick Macklem */ 15976bfaa839SGleb Smirnoff ifcnt = 0; 15987c208ed6SRick Macklem IFNET_RLOCK(); 15996bfaa839SGleb Smirnoff TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 16007c208ed6SRick Macklem if ((ifp->if_flags & 16017c208ed6SRick Macklem (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) != 16027c208ed6SRick Macklem IFF_BROADCAST) 16037c208ed6SRick Macklem continue; 16046bfaa839SGleb Smirnoff switch (ifp->if_alloctype) { 16056bfaa839SGleb Smirnoff case IFT_ETHER: 16066bfaa839SGleb Smirnoff case IFT_FDDI: 16076bfaa839SGleb Smirnoff case IFT_ISO88025: 16086bfaa839SGleb Smirnoff break; 16096bfaa839SGleb Smirnoff default: 16106bfaa839SGleb Smirnoff continue; 16116bfaa839SGleb Smirnoff } 16127c208ed6SRick Macklem ifcnt++; 16137c208ed6SRick Macklem } 16147c208ed6SRick Macklem IFNET_RUNLOCK(); 16157c208ed6SRick Macklem if (ifcnt == 0) 16166bfaa839SGleb Smirnoff panic("%s: no eligible interfaces", __func__); 16177c208ed6SRick Macklem for (; ifcnt > 0; ifcnt--) 16187c208ed6SRick Macklem allocifctx(gctx); 16197c208ed6SRick Macklem #endif 16207c208ed6SRick Macklem 16211d4c5e51SOleksandr Tymoshenko retry: 16226bfaa839SGleb Smirnoff ifctx = STAILQ_FIRST(&gctx->interfaces); 16237c208ed6SRick Macklem IFNET_RLOCK(); 16246bfaa839SGleb Smirnoff TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 16256bfaa839SGleb Smirnoff if (ifctx == NULL) 16266bfaa839SGleb Smirnoff break; 16277c208ed6SRick Macklem #ifdef BOOTP_WIRED_TO 16286bfaa839SGleb Smirnoff if (strcmp(ifp->if_xname, __XSTRING(BOOTP_WIRED_TO)) != 0) 16297c208ed6SRick Macklem continue; 16307c208ed6SRick Macklem #else 16317c208ed6SRick Macklem if ((ifp->if_flags & 16327c208ed6SRick Macklem (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) != 16337c208ed6SRick Macklem IFF_BROADCAST) 16347c208ed6SRick Macklem continue; 16356bfaa839SGleb Smirnoff switch (ifp->if_alloctype) { 16366bfaa839SGleb Smirnoff case IFT_ETHER: 16376bfaa839SGleb Smirnoff case IFT_FDDI: 16386bfaa839SGleb Smirnoff case IFT_ISO88025: 16396bfaa839SGleb Smirnoff break; 16406bfaa839SGleb Smirnoff default: 16416bfaa839SGleb Smirnoff continue; 16426bfaa839SGleb Smirnoff } 16437c208ed6SRick Macklem #endif 16446bfaa839SGleb Smirnoff strlcpy(ifctx->ireq.ifr_name, ifp->if_xname, 16456bfaa839SGleb Smirnoff sizeof(ifctx->ireq.ifr_name)); 16467c208ed6SRick Macklem ifctx->ifp = ifp; 16476bfaa839SGleb Smirnoff 16486bfaa839SGleb Smirnoff /* Get HW address */ 16496bfaa839SGleb Smirnoff sdl = NULL; 16506bfaa839SGleb Smirnoff TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 16516bfaa839SGleb Smirnoff if (ifa->ifa_addr->sa_family == AF_LINK) { 16526bfaa839SGleb Smirnoff sdl = (struct sockaddr_dl *)ifa->ifa_addr; 16536bfaa839SGleb Smirnoff if (sdl->sdl_type == IFT_ETHER) 16546bfaa839SGleb Smirnoff break; 16556bfaa839SGleb Smirnoff } 16566bfaa839SGleb Smirnoff if (sdl == NULL) 16576bfaa839SGleb Smirnoff panic("bootpc: Unable to find HW address for %s", 16586bfaa839SGleb Smirnoff ifctx->ireq.ifr_name); 16596bfaa839SGleb Smirnoff ifctx->sdl = sdl; 16606bfaa839SGleb Smirnoff 16616bfaa839SGleb Smirnoff ifctx = STAILQ_NEXT(ifctx, next); 16627c208ed6SRick Macklem } 16637c208ed6SRick Macklem IFNET_RUNLOCK(); 16647c208ed6SRick Macklem CURVNET_RESTORE(); 16657c208ed6SRick Macklem 16666bfaa839SGleb Smirnoff if (STAILQ_EMPTY(&gctx->interfaces) || 16676bfaa839SGleb Smirnoff STAILQ_FIRST(&gctx->interfaces)->ifp == NULL) { 16681d4c5e51SOleksandr Tymoshenko if (timeout > 0) { 16691d4c5e51SOleksandr Tymoshenko pause("bootpc", delay); 16701d4c5e51SOleksandr Tymoshenko timeout -= delay; 16711d4c5e51SOleksandr Tymoshenko goto retry; 16721d4c5e51SOleksandr Tymoshenko } 16737c208ed6SRick Macklem #ifdef BOOTP_WIRED_TO 16746bfaa839SGleb Smirnoff panic("%s: Could not find interface specified " 16757c208ed6SRick Macklem "by BOOTP_WIRED_TO: " 16766bfaa839SGleb Smirnoff __XSTRING(BOOTP_WIRED_TO), __func__); 16777c208ed6SRick Macklem #else 16786bfaa839SGleb Smirnoff panic("%s: no suitable interface", __func__); 16797c208ed6SRick Macklem #endif 16807c208ed6SRick Macklem } 16817c208ed6SRick Macklem 16826bfaa839SGleb Smirnoff error = socreate(AF_INET, &bootp_so, SOCK_DGRAM, 0, td->td_ucred, td); 16836bfaa839SGleb Smirnoff if (error != 0) 16846bfaa839SGleb Smirnoff panic("%s: socreate, error=%d", __func__, error); 16857c208ed6SRick Macklem 16866bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 16876bfaa839SGleb Smirnoff bootpc_fakeup_interface(ifctx, td); 16886bfaa839SGleb Smirnoff 16896bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 16906bfaa839SGleb Smirnoff bootpc_compose_query(ifctx, td); 16917c208ed6SRick Macklem 16927c208ed6SRick Macklem error = bootpc_call(gctx, td); 16937c208ed6SRick Macklem if (error != 0) { 16947c208ed6SRick Macklem printf("BOOTP call failed\n"); 16957c208ed6SRick Macklem } 16967c208ed6SRick Macklem 16977c208ed6SRick Macklem mountopts(&nd->root_args, NULL); 16987c208ed6SRick Macklem 16996bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 17007c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) != 0) 17017c208ed6SRick Macklem bootpc_decode_reply(nd, ifctx, gctx); 17027c208ed6SRick Macklem 17037c208ed6SRick Macklem #ifdef BOOTP_NFSROOT 17046cbd933bSIan Lepore if (gctx->gotrootpath == 0 && gctx->any_root_overrides == 0) 17057c208ed6SRick Macklem panic("bootpc: No root path offered"); 17067c208ed6SRick Macklem #endif 17077c208ed6SRick Macklem 17086bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 17097c208ed6SRick Macklem bootpc_adjust_interface(ifctx, gctx, td); 17107c208ed6SRick Macklem 17116bfaa839SGleb Smirnoff soclose(bootp_so); 17127c208ed6SRick Macklem 17136bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 17147c208ed6SRick Macklem if (ifctx->gotrootpath != 0) 17157c208ed6SRick Macklem break; 17167c208ed6SRick Macklem if (ifctx == NULL) { 17176bfaa839SGleb Smirnoff STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 17187c208ed6SRick Macklem if (bootpc_ifctx_isresolved(ifctx) != 0) 17197c208ed6SRick Macklem break; 17207c208ed6SRick Macklem } 17217c208ed6SRick Macklem if (ifctx == NULL) 17227c208ed6SRick Macklem goto out; 17237c208ed6SRick Macklem 17247c208ed6SRick Macklem if (gctx->gotrootpath != 0) { 17257c208ed6SRick Macklem 1726*2be111bfSDavide Italiano kern_setenv("boot.netif.name", ifctx->ifp->if_xname); 17277c208ed6SRick Macklem 17287c208ed6SRick Macklem error = md_mount(&nd->root_saddr, nd->root_hostnam, 17297c208ed6SRick Macklem nd->root_fh, &nd->root_fhsize, 17307c208ed6SRick Macklem &nd->root_args, td); 17316cbd933bSIan Lepore if (error != 0) { 17326cbd933bSIan Lepore if (gctx->any_root_overrides == 0) 17336cbd933bSIan Lepore panic("nfs_boot: mount root, error=%d", error); 17346cbd933bSIan Lepore else 17356cbd933bSIan Lepore goto out; 17366cbd933bSIan Lepore } 17376cbd933bSIan Lepore rootdevnames[0] = "nfs:"; 17386cbd933bSIan Lepore #ifdef NFSCLIENT 17396cbd933bSIan Lepore rootdevnames[1] = "oldnfs:"; 17406cbd933bSIan Lepore #endif 17417c208ed6SRick Macklem nfs_diskless_valid = 3; 17427c208ed6SRick Macklem } 17437c208ed6SRick Macklem 17447c208ed6SRick Macklem strcpy(nd->myif.ifra_name, ifctx->ireq.ifr_name); 17457c208ed6SRick Macklem bcopy(&ifctx->myaddr, &nd->myif.ifra_addr, sizeof(ifctx->myaddr)); 17467c208ed6SRick Macklem bcopy(&ifctx->myaddr, &nd->myif.ifra_broadaddr, sizeof(ifctx->myaddr)); 17477c208ed6SRick Macklem ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr = 17487c208ed6SRick Macklem ifctx->myaddr.sin_addr.s_addr | 17497c208ed6SRick Macklem ~ ifctx->netmask.sin_addr.s_addr; 17507c208ed6SRick Macklem bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask)); 17517c208ed6SRick Macklem 17527c208ed6SRick Macklem out: 17536bfaa839SGleb Smirnoff while((ifctx = STAILQ_FIRST(&gctx->interfaces)) != NULL) { 17546bfaa839SGleb Smirnoff STAILQ_REMOVE_HEAD(&gctx->interfaces, next); 17557c208ed6SRick Macklem free(ifctx, M_TEMP); 17567c208ed6SRick Macklem } 17577c208ed6SRick Macklem free(gctx, M_TEMP); 17587c208ed6SRick Macklem } 17597c208ed6SRick Macklem 17607c208ed6SRick Macklem /* 17617c208ed6SRick Macklem * RPC: mountd/mount 17627c208ed6SRick Macklem * Given a server pathname, get an NFS file handle. 17637c208ed6SRick Macklem * Also, sets sin->sin_port to the NFS service port. 17647c208ed6SRick Macklem */ 17657c208ed6SRick Macklem static int 17667c208ed6SRick Macklem md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp, int *fhsizep, 17677c208ed6SRick Macklem struct nfs_args *args, struct thread *td) 17687c208ed6SRick Macklem { 17697c208ed6SRick Macklem struct mbuf *m; 17707c208ed6SRick Macklem int error; 17717c208ed6SRick Macklem int authunixok; 17727c208ed6SRick Macklem int authcount; 17737c208ed6SRick Macklem int authver; 17747c208ed6SRick Macklem 17757c208ed6SRick Macklem #define RPCPROG_MNT 100005 17767c208ed6SRick Macklem #define RPCMNT_VER1 1 17777c208ed6SRick Macklem #define RPCMNT_VER3 3 17787c208ed6SRick Macklem #define RPCMNT_MOUNT 1 17797c208ed6SRick Macklem #define AUTH_SYS 1 /* unix style (uid, gids) */ 17807c208ed6SRick Macklem #define AUTH_UNIX AUTH_SYS 17817c208ed6SRick Macklem 17827c208ed6SRick Macklem /* XXX honor v2/v3 flags in args->flags? */ 17837c208ed6SRick Macklem #ifdef BOOTP_NFSV3 17847c208ed6SRick Macklem /* First try NFS v3 */ 17857c208ed6SRick Macklem /* Get port number for MOUNTD. */ 17867c208ed6SRick Macklem error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3, 17877c208ed6SRick Macklem &mdsin->sin_port, td); 17887c208ed6SRick Macklem if (error == 0) { 17897c208ed6SRick Macklem m = xdr_string_encode(path, strlen(path)); 17907c208ed6SRick Macklem 17917c208ed6SRick Macklem /* Do RPC to mountd. */ 17927c208ed6SRick Macklem error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3, 17937c208ed6SRick Macklem RPCMNT_MOUNT, &m, NULL, td); 17947c208ed6SRick Macklem } 17957c208ed6SRick Macklem if (error == 0) { 17967c208ed6SRick Macklem args->flags |= NFSMNT_NFSV3; 17977c208ed6SRick Macklem } else { 17987c208ed6SRick Macklem #endif 17997c208ed6SRick Macklem /* Fallback to NFS v2 */ 18007c208ed6SRick Macklem 18017c208ed6SRick Macklem /* Get port number for MOUNTD. */ 18027c208ed6SRick Macklem error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, 18037c208ed6SRick Macklem &mdsin->sin_port, td); 18047c208ed6SRick Macklem if (error != 0) 18057c208ed6SRick Macklem return error; 18067c208ed6SRick Macklem 18077c208ed6SRick Macklem m = xdr_string_encode(path, strlen(path)); 18087c208ed6SRick Macklem 18097c208ed6SRick Macklem /* Do RPC to mountd. */ 18107c208ed6SRick Macklem error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, 18117c208ed6SRick Macklem RPCMNT_MOUNT, &m, NULL, td); 18127c208ed6SRick Macklem if (error != 0) 18137c208ed6SRick Macklem return error; /* message already freed */ 18147c208ed6SRick Macklem 18157c208ed6SRick Macklem #ifdef BOOTP_NFSV3 18167c208ed6SRick Macklem } 18177c208ed6SRick Macklem #endif 18187c208ed6SRick Macklem 18197c208ed6SRick Macklem if (xdr_int_decode(&m, &error) != 0 || error != 0) 18207c208ed6SRick Macklem goto bad; 18217c208ed6SRick Macklem 18227c208ed6SRick Macklem if ((args->flags & NFSMNT_NFSV3) != 0) { 18237c208ed6SRick Macklem if (xdr_int_decode(&m, fhsizep) != 0 || 18247c208ed6SRick Macklem *fhsizep > NFSX_V3FHMAX || 18257c208ed6SRick Macklem *fhsizep <= 0) 18267c208ed6SRick Macklem goto bad; 18277c208ed6SRick Macklem } else 18287c208ed6SRick Macklem *fhsizep = NFSX_V2FH; 18297c208ed6SRick Macklem 18307c208ed6SRick Macklem if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0) 18317c208ed6SRick Macklem goto bad; 18327c208ed6SRick Macklem 18337c208ed6SRick Macklem if (args->flags & NFSMNT_NFSV3) { 18347c208ed6SRick Macklem if (xdr_int_decode(&m, &authcount) != 0) 18357c208ed6SRick Macklem goto bad; 18367c208ed6SRick Macklem authunixok = 0; 18377c208ed6SRick Macklem if (authcount < 0 || authcount > 100) 18387c208ed6SRick Macklem goto bad; 18397c208ed6SRick Macklem while (authcount > 0) { 18407c208ed6SRick Macklem if (xdr_int_decode(&m, &authver) != 0) 18417c208ed6SRick Macklem goto bad; 18427c208ed6SRick Macklem if (authver == AUTH_UNIX) 18437c208ed6SRick Macklem authunixok = 1; 18447c208ed6SRick Macklem authcount--; 18457c208ed6SRick Macklem } 18467c208ed6SRick Macklem if (authunixok == 0) 18477c208ed6SRick Macklem goto bad; 18487c208ed6SRick Macklem } 18497c208ed6SRick Macklem 18507c208ed6SRick Macklem /* Set port number for NFS use. */ 18517c208ed6SRick Macklem error = krpc_portmap(mdsin, NFS_PROG, 18527c208ed6SRick Macklem (args->flags & 18537c208ed6SRick Macklem NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2, 18547c208ed6SRick Macklem &mdsin->sin_port, td); 18557c208ed6SRick Macklem 18567c208ed6SRick Macklem goto out; 18577c208ed6SRick Macklem 18587c208ed6SRick Macklem bad: 18597c208ed6SRick Macklem error = EBADRPC; 18607c208ed6SRick Macklem 18617c208ed6SRick Macklem out: 18627c208ed6SRick Macklem m_freem(m); 18637c208ed6SRick Macklem return error; 18647c208ed6SRick Macklem } 18657c208ed6SRick Macklem 18667c208ed6SRick Macklem SYSINIT(bootp_rootconf, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, bootpc_init, NULL); 1867