1 1.3 pgoyette /* $NetBSD: bootp_subr.c,v 1.3 2016/12/13 22:52:46 pgoyette Exp $ */ 2 1.1 dholland /*- 3 1.1 dholland * Copyright (c) 1995 Gordon Ross, Adam Glass 4 1.1 dholland * Copyright (c) 1992 Regents of the University of California. 5 1.1 dholland * All rights reserved. 6 1.1 dholland * 7 1.1 dholland * This software was developed by the Computer Systems Engineering group 8 1.1 dholland * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 1.1 dholland * contributed to Berkeley. 10 1.1 dholland * 11 1.1 dholland * Redistribution and use in source and binary forms, with or without 12 1.1 dholland * modification, are permitted provided that the following conditions 13 1.1 dholland * are met: 14 1.1 dholland * 1. Redistributions of source code must retain the above copyright 15 1.1 dholland * notice, this list of conditions and the following disclaimer. 16 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 dholland * notice, this list of conditions and the following disclaimer in the 18 1.1 dholland * documentation and/or other materials provided with the distribution. 19 1.1 dholland * 3. All advertising materials mentioning features or use of this software 20 1.1 dholland * must display the following acknowledgement: 21 1.1 dholland * This product includes software developed by the University of 22 1.1 dholland * California, Lawrence Berkeley Laboratory and its contributors. 23 1.1 dholland * 4. Neither the name of the University nor the names of its contributors 24 1.1 dholland * may be used to endorse or promote products derived from this software 25 1.1 dholland * without specific prior written permission. 26 1.1 dholland * 27 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 1.1 dholland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 1.1 dholland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 1.1 dholland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 1.1 dholland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 1.1 dholland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 1.1 dholland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 1.1 dholland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 1.1 dholland * SUCH DAMAGE. 38 1.1 dholland * 39 1.1 dholland * based on: 40 1.1 dholland * nfs/krpc_subr.c 41 1.1 dholland * NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp 42 1.1 dholland */ 43 1.1 dholland 44 1.1 dholland #include <sys/cdefs.h> 45 1.2 pgoyette /* __FBSDID("FreeBSD: head/sys/nfs/bootp_subr.c 297326 2016-03-27 23:16:37Z ian "); */ 46 1.3 pgoyette __RCSID("$NetBSD: bootp_subr.c,v 1.3 2016/12/13 22:52:46 pgoyette Exp $"); 47 1.1 dholland 48 1.2 pgoyette #ifdef _KERNEL_OPT 49 1.2 pgoyette #include "opt_newnfs.h" 50 1.2 pgoyette #endif 51 1.1 dholland 52 1.1 dholland #include <sys/param.h> 53 1.1 dholland #include <sys/systm.h> 54 1.2 pgoyette #include <sys/endian.h> 55 1.1 dholland #include <sys/kernel.h> 56 1.1 dholland #include <sys/sockio.h> 57 1.1 dholland #include <sys/malloc.h> 58 1.1 dholland #include <sys/mount.h> 59 1.1 dholland #include <sys/mbuf.h> 60 1.1 dholland #include <sys/proc.h> 61 1.1 dholland #include <sys/reboot.h> 62 1.1 dholland #include <sys/socket.h> 63 1.1 dholland #include <sys/socketvar.h> 64 1.1 dholland #include <sys/sysctl.h> 65 1.1 dholland #include <sys/uio.h> 66 1.3 pgoyette #include <sys/kauth.h> 67 1.3 pgoyette #include <sys/lwp.h> 68 1.3 pgoyette #include <sys/vnode.h> 69 1.3 pgoyette #include <sys/mutex.h> 70 1.3 pgoyette 71 1.3 pgoyette #if 0 72 1.3 pgoyette #include <src/include/rpc/auth.h> 73 1.3 pgoyette #endif 74 1.1 dholland 75 1.1 dholland #include <net/if.h> 76 1.1 dholland #include <net/route.h> 77 1.2 pgoyette #ifdef BOOTP_DEBUG 78 1.2 pgoyette #include <net/route_var.h> 79 1.2 pgoyette #endif 80 1.1 dholland 81 1.1 dholland #include <netinet/in.h> 82 1.1 dholland #include <netinet/in_var.h> 83 1.1 dholland #include <net/if_types.h> 84 1.1 dholland #include <net/if_dl.h> 85 1.1 dholland 86 1.2 pgoyette #include <fs/nfs/common/nfsproto.h> 87 1.3 pgoyette #include <fs/nfs/common/nfsport.h> 88 1.3 pgoyette #include <fs/nfs/common/nfs.h> 89 1.3 pgoyette #include <fs/nfs/client/nfsmount.h> 90 1.3 pgoyette #include <fs/nfs/client/nfsnode.h> 91 1.2 pgoyette #include <fs/nfs/client/nfs.h> 92 1.2 pgoyette #include <fs/nfs/common/nfsdiskless.h> 93 1.2 pgoyette #include <fs/nfs/common/krpc.h> 94 1.2 pgoyette #include <fs/nfs/common/xdr_subs.h> 95 1.1 dholland 96 1.1 dholland 97 1.1 dholland #define BOOTP_MIN_LEN 300 /* Minimum size of bootp udp packet */ 98 1.1 dholland 99 1.1 dholland #ifndef BOOTP_SETTLE_DELAY 100 1.1 dholland #define BOOTP_SETTLE_DELAY 3 101 1.1 dholland #endif 102 1.1 dholland 103 1.1 dholland /* 104 1.1 dholland * Wait 10 seconds for interface appearance 105 1.1 dholland * USB ethernet adapters might require some time to pop up 106 1.1 dholland */ 107 1.1 dholland #ifndef BOOTP_IFACE_WAIT_TIMEOUT 108 1.1 dholland #define BOOTP_IFACE_WAIT_TIMEOUT 10 109 1.1 dholland #endif 110 1.1 dholland 111 1.1 dholland /* 112 1.1 dholland * What is the longest we will wait before re-sending a request? 113 1.1 dholland * Note this is also the frequency of "RPC timeout" messages. 114 1.1 dholland * The re-send loop count sup linearly to this maximum, so the 115 1.1 dholland * first complaint will happen after (1+2+3+4+5)=15 seconds. 116 1.1 dholland */ 117 1.1 dholland #define MAX_RESEND_DELAY 5 /* seconds */ 118 1.1 dholland 119 1.1 dholland /* Definitions from RFC951 */ 120 1.1 dholland struct bootp_packet { 121 1.1 dholland u_int8_t op; 122 1.1 dholland u_int8_t htype; 123 1.1 dholland u_int8_t hlen; 124 1.1 dholland u_int8_t hops; 125 1.1 dholland u_int32_t xid; 126 1.1 dholland u_int16_t secs; 127 1.1 dholland u_int16_t flags; 128 1.1 dholland struct in_addr ciaddr; 129 1.1 dholland struct in_addr yiaddr; 130 1.1 dholland struct in_addr siaddr; 131 1.1 dholland struct in_addr giaddr; 132 1.1 dholland unsigned char chaddr[16]; 133 1.1 dholland char sname[64]; 134 1.1 dholland char file[128]; 135 1.1 dholland unsigned char vend[1222]; 136 1.1 dholland }; 137 1.1 dholland 138 1.1 dholland struct bootpc_ifcontext { 139 1.1 dholland STAILQ_ENTRY(bootpc_ifcontext) next; 140 1.1 dholland struct bootp_packet call; 141 1.1 dholland struct bootp_packet reply; 142 1.1 dholland int replylen; 143 1.1 dholland int overload; 144 1.1 dholland union { 145 1.1 dholland struct ifreq _ifreq; 146 1.1 dholland struct in_aliasreq _in_alias_req; 147 1.1 dholland } _req; 148 1.1 dholland #define ireq _req._ifreq 149 1.1 dholland #define iareq _req._in_alias_req 150 1.1 dholland struct ifnet *ifp; 151 1.1 dholland struct sockaddr_dl *sdl; 152 1.1 dholland struct sockaddr_in myaddr; 153 1.1 dholland struct sockaddr_in netmask; 154 1.1 dholland struct sockaddr_in gw; 155 1.1 dholland int gotgw; 156 1.1 dholland int gotnetmask; 157 1.1 dholland int gotrootpath; 158 1.1 dholland int outstanding; 159 1.1 dholland int sentmsg; 160 1.1 dholland u_int32_t xid; 161 1.1 dholland enum { 162 1.1 dholland IF_BOOTP_UNRESOLVED, 163 1.1 dholland IF_BOOTP_RESOLVED, 164 1.1 dholland IF_BOOTP_FAILED, 165 1.1 dholland IF_DHCP_UNRESOLVED, 166 1.1 dholland IF_DHCP_OFFERED, 167 1.1 dholland IF_DHCP_RESOLVED, 168 1.1 dholland IF_DHCP_FAILED, 169 1.1 dholland } state; 170 1.1 dholland int dhcpquerytype; /* dhcp type sent */ 171 1.1 dholland struct in_addr dhcpserver; 172 1.1 dholland int gotdhcpserver; 173 1.2 pgoyette uint16_t mtu; 174 1.1 dholland }; 175 1.1 dholland 176 1.1 dholland #define TAG_MAXLEN 1024 177 1.1 dholland struct bootpc_tagcontext { 178 1.1 dholland char buf[TAG_MAXLEN + 1]; 179 1.1 dholland int overload; 180 1.1 dholland int badopt; 181 1.1 dholland int badtag; 182 1.1 dholland int foundopt; 183 1.1 dholland int taglen; 184 1.1 dholland }; 185 1.1 dholland 186 1.1 dholland struct bootpc_globalcontext { 187 1.1 dholland STAILQ_HEAD(, bootpc_ifcontext) interfaces; 188 1.1 dholland u_int32_t xid; 189 1.1 dholland int any_root_overrides; 190 1.1 dholland int gotrootpath; 191 1.1 dholland int gotgw; 192 1.1 dholland int ifnum; 193 1.1 dholland int secs; 194 1.1 dholland int starttime; 195 1.1 dholland struct bootp_packet reply; 196 1.1 dholland int replylen; 197 1.1 dholland struct bootpc_ifcontext *setrootfs; 198 1.1 dholland struct bootpc_ifcontext *sethostname; 199 1.1 dholland struct bootpc_tagcontext tmptag; 200 1.1 dholland struct bootpc_tagcontext tag; 201 1.1 dholland }; 202 1.1 dholland 203 1.1 dholland #define IPPORT_BOOTPC 68 204 1.1 dholland #define IPPORT_BOOTPS 67 205 1.1 dholland 206 1.1 dholland #define BOOTP_REQUEST 1 207 1.1 dholland #define BOOTP_REPLY 2 208 1.1 dholland 209 1.1 dholland /* Common tags */ 210 1.1 dholland #define TAG_PAD 0 /* Pad option, implicit length 1 */ 211 1.1 dholland #define TAG_SUBNETMASK 1 /* RFC 950 subnet mask */ 212 1.1 dholland #define TAG_ROUTERS 3 /* Routers (in order of preference) */ 213 1.1 dholland #define TAG_HOSTNAME 12 /* Client host name */ 214 1.1 dholland #define TAG_ROOT 17 /* Root path */ 215 1.2 pgoyette #define TAG_INTF_MTU 26 /* Interface MTU Size (RFC2132) */ 216 1.1 dholland 217 1.1 dholland /* DHCP specific tags */ 218 1.1 dholland #define TAG_OVERLOAD 52 /* Option Overload */ 219 1.1 dholland #define TAG_MAXMSGSIZE 57 /* Maximum DHCP Message Size */ 220 1.1 dholland 221 1.1 dholland #define TAG_END 255 /* End Option (i.e. no more options) */ 222 1.1 dholland 223 1.1 dholland /* Overload values */ 224 1.1 dholland #define OVERLOAD_FILE 1 225 1.1 dholland #define OVERLOAD_SNAME 2 226 1.1 dholland 227 1.1 dholland /* Site specific tags: */ 228 1.1 dholland #define TAG_ROOTOPTS 130 229 1.1 dholland #define TAG_COOKIE 134 /* ascii info for userland, via sysctl */ 230 1.1 dholland 231 1.1 dholland #define TAG_DHCP_MSGTYPE 53 232 1.1 dholland #define TAG_DHCP_REQ_ADDR 50 233 1.1 dholland #define TAG_DHCP_SERVERID 54 234 1.1 dholland #define TAG_DHCP_LEASETIME 51 235 1.1 dholland 236 1.1 dholland #define TAG_VENDOR_INDENTIFIER 60 237 1.1 dholland 238 1.1 dholland #define DHCP_NOMSG 0 239 1.1 dholland #define DHCP_DISCOVER 1 240 1.1 dholland #define DHCP_OFFER 2 241 1.1 dholland #define DHCP_REQUEST 3 242 1.1 dholland #define DHCP_ACK 5 243 1.1 dholland 244 1.1 dholland /* NFS read/write block size */ 245 1.1 dholland #ifndef BOOTP_BLOCKSIZE 246 1.1 dholland #define BOOTP_BLOCKSIZE 8192 247 1.1 dholland #endif 248 1.1 dholland 249 1.1 dholland static char bootp_cookie[128]; 250 1.1 dholland static struct socket *bootp_so; 251 1.3 pgoyette 252 1.3 pgoyette #if 0 /* Need to init sysctl variables in the module initialization code */ 253 1.1 dholland SYSCTL_STRING(_kern, OID_AUTO, bootp_cookie, CTLFLAG_RD, 254 1.1 dholland bootp_cookie, 0, "Cookie (T134) supplied by bootp server"); 255 1.3 pgoyette #endif 256 1.1 dholland 257 1.1 dholland /* mountd RPC */ 258 1.1 dholland static int md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp, 259 1.3 pgoyette int *fhsizep, struct nfs_args *args, struct lwp *td); 260 1.3 pgoyette static int setmyfs(struct sockaddr_in *addr, char *path, char *p, 261 1.1 dholland const struct in_addr *siaddr); 262 1.1 dholland static int getdec(char **ptr); 263 1.1 dholland static int getip(char **ptr, struct in_addr *ip); 264 1.1 dholland static void mountopts(struct nfs_args *args, char *p); 265 1.1 dholland static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len); 266 1.1 dholland static int xdr_int_decode(struct mbuf **ptr, int *iptr); 267 1.1 dholland static void print_in_addr(struct in_addr addr); 268 1.1 dholland static void print_sin_addr(struct sockaddr_in *addr); 269 1.1 dholland static void clear_sinaddr(struct sockaddr_in *sin); 270 1.1 dholland static void allocifctx(struct bootpc_globalcontext *gctx); 271 1.1 dholland static void bootpc_compose_query(struct bootpc_ifcontext *ifctx, 272 1.3 pgoyette struct lwp *td); 273 1.1 dholland static unsigned char *bootpc_tag(struct bootpc_tagcontext *tctx, 274 1.1 dholland struct bootp_packet *bp, int len, int tag); 275 1.1 dholland static void bootpc_tag_helper(struct bootpc_tagcontext *tctx, 276 1.1 dholland unsigned char *start, int len, int tag); 277 1.1 dholland 278 1.1 dholland #ifdef BOOTP_DEBUG 279 1.1 dholland void bootpboot_p_sa(struct sockaddr *sa, struct sockaddr *ma); 280 1.1 dholland void bootpboot_p_rtentry(struct rtentry *rt); 281 1.1 dholland void bootpboot_p_tree(struct radix_node *rn); 282 1.1 dholland void bootpboot_p_rtlist(void); 283 1.1 dholland void bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa); 284 1.1 dholland void bootpboot_p_iflist(void); 285 1.1 dholland #endif 286 1.1 dholland 287 1.1 dholland static int bootpc_call(struct bootpc_globalcontext *gctx, 288 1.3 pgoyette struct lwp *td); 289 1.1 dholland 290 1.1 dholland static void bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx, 291 1.3 pgoyette struct lwp *td); 292 1.1 dholland 293 1.2 pgoyette static void bootpc_adjust_interface(struct bootpc_ifcontext *ifctx, 294 1.3 pgoyette struct bootpc_globalcontext *gctx, struct lwp *td); 295 1.1 dholland 296 1.1 dholland static void bootpc_decode_reply(struct nfsv3_diskless *nd, 297 1.1 dholland struct bootpc_ifcontext *ifctx, 298 1.1 dholland struct bootpc_globalcontext *gctx); 299 1.1 dholland 300 1.1 dholland static int bootpc_received(struct bootpc_globalcontext *gctx, 301 1.1 dholland struct bootpc_ifcontext *ifctx); 302 1.1 dholland 303 1.1 dholland static __inline int bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx); 304 1.1 dholland static __inline int bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx); 305 1.1 dholland static __inline int bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx); 306 1.1 dholland 307 1.1 dholland /* 308 1.1 dholland * In order to have multiple active interfaces with address 0.0.0.0 309 1.1 dholland * and be able to send data to a selected interface, we first set 310 1.1 dholland * mask to /8 on all interfaces, and temporarily set it to /0 when 311 1.1 dholland * doing sosend(). 312 1.1 dholland */ 313 1.1 dholland 314 1.1 dholland #ifdef BOOTP_DEBUG 315 1.1 dholland void 316 1.1 dholland bootpboot_p_sa(struct sockaddr *sa, struct sockaddr *ma) 317 1.1 dholland { 318 1.1 dholland 319 1.1 dholland if (sa == NULL) { 320 1.1 dholland printf("(sockaddr *) <null>"); 321 1.1 dholland return; 322 1.1 dholland } 323 1.1 dholland switch (sa->sa_family) { 324 1.1 dholland case AF_INET: 325 1.1 dholland { 326 1.1 dholland struct sockaddr_in *sin; 327 1.1 dholland 328 1.1 dholland sin = (struct sockaddr_in *) sa; 329 1.1 dholland printf("inet "); 330 1.1 dholland print_sin_addr(sin); 331 1.1 dholland if (ma != NULL) { 332 1.1 dholland sin = (struct sockaddr_in *) ma; 333 1.1 dholland printf(" mask "); 334 1.1 dholland print_sin_addr(sin); 335 1.1 dholland } 336 1.1 dholland } 337 1.1 dholland break; 338 1.1 dholland case AF_LINK: 339 1.1 dholland { 340 1.1 dholland struct sockaddr_dl *sli; 341 1.1 dholland int i; 342 1.1 dholland 343 1.1 dholland sli = (struct sockaddr_dl *) sa; 344 1.1 dholland printf("link %.*s ", sli->sdl_nlen, sli->sdl_data); 345 1.1 dholland for (i = 0; i < sli->sdl_alen; i++) { 346 1.1 dholland if (i > 0) 347 1.1 dholland printf(":"); 348 1.1 dholland printf("%x", ((unsigned char *) LLADDR(sli))[i]); 349 1.1 dholland } 350 1.1 dholland } 351 1.1 dholland break; 352 1.1 dholland default: 353 1.1 dholland printf("af%d", sa->sa_family); 354 1.1 dholland } 355 1.1 dholland } 356 1.1 dholland 357 1.1 dholland void 358 1.1 dholland bootpboot_p_rtentry(struct rtentry *rt) 359 1.1 dholland { 360 1.1 dholland 361 1.1 dholland bootpboot_p_sa(rt_key(rt), rt_mask(rt)); 362 1.1 dholland printf(" "); 363 1.1 dholland bootpboot_p_sa(rt->rt_gateway, NULL); 364 1.1 dholland printf(" "); 365 1.1 dholland printf("flags %x", (unsigned short) rt->rt_flags); 366 1.2 pgoyette printf(" %d", (int) rt->rt_expire); 367 1.1 dholland printf(" %s\n", rt->rt_ifp->if_xname); 368 1.1 dholland } 369 1.1 dholland 370 1.1 dholland void 371 1.1 dholland bootpboot_p_tree(struct radix_node *rn) 372 1.1 dholland { 373 1.1 dholland 374 1.1 dholland while (rn != NULL) { 375 1.1 dholland if (rn->rn_bit < 0) { 376 1.1 dholland if ((rn->rn_flags & RNF_ROOT) != 0) { 377 1.1 dholland } else { 378 1.1 dholland bootpboot_p_rtentry((struct rtentry *) rn); 379 1.1 dholland } 380 1.1 dholland rn = rn->rn_dupedkey; 381 1.1 dholland } else { 382 1.1 dholland bootpboot_p_tree(rn->rn_left); 383 1.1 dholland bootpboot_p_tree(rn->rn_right); 384 1.1 dholland return; 385 1.1 dholland } 386 1.1 dholland } 387 1.1 dholland } 388 1.1 dholland 389 1.1 dholland void 390 1.1 dholland bootpboot_p_rtlist(void) 391 1.1 dholland { 392 1.2 pgoyette struct rib_head *rnh; 393 1.1 dholland 394 1.1 dholland printf("Routing table:\n"); 395 1.1 dholland rnh = rt_tables_get_rnh(0, AF_INET); 396 1.1 dholland if (rnh == NULL) 397 1.1 dholland return; 398 1.2 pgoyette RIB_RLOCK(rnh); /* could sleep XXX */ 399 1.1 dholland bootpboot_p_tree(rnh->rnh_treetop); 400 1.2 pgoyette RIB_RUNLOCK(rnh); 401 1.1 dholland } 402 1.1 dholland 403 1.1 dholland void 404 1.1 dholland bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa) 405 1.1 dholland { 406 1.1 dholland 407 1.1 dholland printf("%s flags %x, addr ", 408 1.1 dholland ifp->if_xname, ifp->if_flags); 409 1.1 dholland print_sin_addr((struct sockaddr_in *) ifa->ifa_addr); 410 1.1 dholland printf(", broadcast "); 411 1.1 dholland print_sin_addr((struct sockaddr_in *) ifa->ifa_dstaddr); 412 1.1 dholland printf(", netmask "); 413 1.1 dholland print_sin_addr((struct sockaddr_in *) ifa->ifa_netmask); 414 1.1 dholland printf("\n"); 415 1.1 dholland } 416 1.1 dholland 417 1.1 dholland void 418 1.1 dholland bootpboot_p_iflist(void) 419 1.1 dholland { 420 1.1 dholland struct ifnet *ifp; 421 1.1 dholland struct ifaddr *ifa; 422 1.1 dholland 423 1.1 dholland printf("Interface list:\n"); 424 1.1 dholland IFNET_RLOCK(); 425 1.1 dholland for (ifp = TAILQ_FIRST(&V_ifnet); 426 1.1 dholland ifp != NULL; 427 1.1 dholland ifp = TAILQ_NEXT(ifp, if_link)) { 428 1.1 dholland for (ifa = TAILQ_FIRST(&ifp->if_addrhead); 429 1.1 dholland ifa != NULL; 430 1.1 dholland ifa = TAILQ_NEXT(ifa, ifa_link)) 431 1.1 dholland if (ifa->ifa_addr->sa_family == AF_INET) 432 1.1 dholland bootpboot_p_if(ifp, ifa); 433 1.1 dholland } 434 1.1 dholland IFNET_RUNLOCK(); 435 1.1 dholland } 436 1.1 dholland #endif /* defined(BOOTP_DEBUG) */ 437 1.1 dholland 438 1.1 dholland static void 439 1.1 dholland clear_sinaddr(struct sockaddr_in *sin) 440 1.1 dholland { 441 1.1 dholland 442 1.1 dholland bzero(sin, sizeof(*sin)); 443 1.1 dholland sin->sin_len = sizeof(*sin); 444 1.1 dholland sin->sin_family = AF_INET; 445 1.1 dholland sin->sin_addr.s_addr = INADDR_ANY; /* XXX: htonl(INAADDR_ANY) ? */ 446 1.1 dholland sin->sin_port = 0; 447 1.1 dholland } 448 1.1 dholland 449 1.1 dholland static void 450 1.1 dholland allocifctx(struct bootpc_globalcontext *gctx) 451 1.1 dholland { 452 1.1 dholland struct bootpc_ifcontext *ifctx; 453 1.1 dholland 454 1.1 dholland ifctx = malloc(sizeof(*ifctx), M_TEMP, M_WAITOK | M_ZERO); 455 1.1 dholland ifctx->xid = gctx->xid; 456 1.1 dholland #ifdef BOOTP_NO_DHCP 457 1.1 dholland ifctx->state = IF_BOOTP_UNRESOLVED; 458 1.1 dholland #else 459 1.1 dholland ifctx->state = IF_DHCP_UNRESOLVED; 460 1.1 dholland #endif 461 1.1 dholland gctx->xid += 0x100; 462 1.1 dholland STAILQ_INSERT_TAIL(&gctx->interfaces, ifctx, next); 463 1.1 dholland } 464 1.1 dholland 465 1.1 dholland static __inline int 466 1.1 dholland bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx) 467 1.1 dholland { 468 1.1 dholland 469 1.1 dholland if (ifctx->state == IF_BOOTP_RESOLVED || 470 1.1 dholland ifctx->state == IF_DHCP_RESOLVED) 471 1.1 dholland return 1; 472 1.1 dholland return 0; 473 1.1 dholland } 474 1.1 dholland 475 1.1 dholland static __inline int 476 1.1 dholland bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx) 477 1.1 dholland { 478 1.1 dholland 479 1.1 dholland if (ifctx->state == IF_BOOTP_UNRESOLVED || 480 1.1 dholland ifctx->state == IF_DHCP_UNRESOLVED) 481 1.1 dholland return 1; 482 1.1 dholland return 0; 483 1.1 dholland } 484 1.1 dholland 485 1.1 dholland static __inline int 486 1.1 dholland bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx) 487 1.1 dholland { 488 1.1 dholland 489 1.1 dholland if (ifctx->state == IF_BOOTP_FAILED || 490 1.1 dholland ifctx->state == IF_DHCP_FAILED) 491 1.1 dholland return 1; 492 1.1 dholland return 0; 493 1.1 dholland } 494 1.1 dholland 495 1.1 dholland static int 496 1.1 dholland bootpc_received(struct bootpc_globalcontext *gctx, 497 1.1 dholland struct bootpc_ifcontext *ifctx) 498 1.1 dholland { 499 1.1 dholland unsigned char dhcpreplytype; 500 1.1 dholland char *p; 501 1.1 dholland 502 1.1 dholland /* 503 1.1 dholland * Need timeout for fallback to less 504 1.1 dholland * desirable alternative. 505 1.1 dholland */ 506 1.1 dholland 507 1.1 dholland /* This call used for the side effect (badopt flag) */ 508 1.1 dholland (void) bootpc_tag(&gctx->tmptag, &gctx->reply, 509 1.1 dholland gctx->replylen, 510 1.1 dholland TAG_END); 511 1.1 dholland 512 1.1 dholland /* If packet is invalid, ignore it */ 513 1.1 dholland if (gctx->tmptag.badopt != 0) 514 1.1 dholland return 0; 515 1.1 dholland 516 1.1 dholland p = bootpc_tag(&gctx->tmptag, &gctx->reply, 517 1.1 dholland gctx->replylen, TAG_DHCP_MSGTYPE); 518 1.1 dholland if (p != NULL) 519 1.1 dholland dhcpreplytype = *p; 520 1.1 dholland else 521 1.1 dholland dhcpreplytype = DHCP_NOMSG; 522 1.1 dholland 523 1.1 dholland switch (ifctx->dhcpquerytype) { 524 1.1 dholland case DHCP_DISCOVER: 525 1.1 dholland if (dhcpreplytype != DHCP_OFFER /* Normal DHCP offer */ 526 1.1 dholland #ifndef BOOTP_FORCE_DHCP 527 1.1 dholland && dhcpreplytype != DHCP_NOMSG /* Fallback to BOOTP */ 528 1.1 dholland #endif 529 1.1 dholland ) 530 1.1 dholland return 0; 531 1.1 dholland break; 532 1.1 dholland case DHCP_REQUEST: 533 1.1 dholland if (dhcpreplytype != DHCP_ACK) 534 1.1 dholland return 0; 535 1.1 dholland case DHCP_NOMSG: 536 1.1 dholland break; 537 1.1 dholland } 538 1.1 dholland 539 1.1 dholland /* Ignore packet unless it gives us a root tag we didn't have */ 540 1.1 dholland 541 1.1 dholland if ((ifctx->state == IF_BOOTP_RESOLVED || 542 1.1 dholland (ifctx->dhcpquerytype == DHCP_DISCOVER && 543 1.1 dholland (ifctx->state == IF_DHCP_OFFERED || 544 1.1 dholland ifctx->state == IF_DHCP_RESOLVED))) && 545 1.1 dholland (bootpc_tag(&gctx->tmptag, &ifctx->reply, 546 1.1 dholland ifctx->replylen, 547 1.1 dholland TAG_ROOT) != NULL || 548 1.1 dholland bootpc_tag(&gctx->tmptag, &gctx->reply, 549 1.1 dholland gctx->replylen, 550 1.1 dholland TAG_ROOT) == NULL)) 551 1.1 dholland return 0; 552 1.1 dholland 553 1.1 dholland bcopy(&gctx->reply, &ifctx->reply, gctx->replylen); 554 1.1 dholland ifctx->replylen = gctx->replylen; 555 1.1 dholland 556 1.1 dholland /* XXX: Only reset if 'perfect' response */ 557 1.1 dholland if (ifctx->state == IF_BOOTP_UNRESOLVED) 558 1.1 dholland ifctx->state = IF_BOOTP_RESOLVED; 559 1.1 dholland else if (ifctx->state == IF_DHCP_UNRESOLVED && 560 1.1 dholland ifctx->dhcpquerytype == DHCP_DISCOVER) { 561 1.1 dholland if (dhcpreplytype == DHCP_OFFER) 562 1.1 dholland ifctx->state = IF_DHCP_OFFERED; 563 1.1 dholland else 564 1.1 dholland ifctx->state = IF_BOOTP_RESOLVED; /* Fallback */ 565 1.1 dholland } else if (ifctx->state == IF_DHCP_OFFERED && 566 1.1 dholland ifctx->dhcpquerytype == DHCP_REQUEST) 567 1.1 dholland ifctx->state = IF_DHCP_RESOLVED; 568 1.1 dholland 569 1.1 dholland 570 1.1 dholland if (ifctx->dhcpquerytype == DHCP_DISCOVER && 571 1.1 dholland ifctx->state != IF_BOOTP_RESOLVED) { 572 1.1 dholland p = bootpc_tag(&gctx->tmptag, &ifctx->reply, 573 1.1 dholland ifctx->replylen, TAG_DHCP_SERVERID); 574 1.1 dholland if (p != NULL && gctx->tmptag.taglen == 4) { 575 1.1 dholland memcpy(&ifctx->dhcpserver, p, 4); 576 1.1 dholland ifctx->gotdhcpserver = 1; 577 1.1 dholland } else 578 1.1 dholland ifctx->gotdhcpserver = 0; 579 1.1 dholland return 1; 580 1.1 dholland } 581 1.1 dholland 582 1.1 dholland ifctx->gotrootpath = (bootpc_tag(&gctx->tmptag, &ifctx->reply, 583 1.1 dholland ifctx->replylen, 584 1.1 dholland TAG_ROOT) != NULL); 585 1.1 dholland ifctx->gotgw = (bootpc_tag(&gctx->tmptag, &ifctx->reply, 586 1.1 dholland ifctx->replylen, 587 1.1 dholland TAG_ROUTERS) != NULL); 588 1.1 dholland ifctx->gotnetmask = (bootpc_tag(&gctx->tmptag, &ifctx->reply, 589 1.1 dholland ifctx->replylen, 590 1.1 dholland TAG_SUBNETMASK) != NULL); 591 1.1 dholland return 1; 592 1.1 dholland } 593 1.1 dholland 594 1.1 dholland static int 595 1.3 pgoyette bootpc_call(struct bootpc_globalcontext *gctx, struct lwp *td) 596 1.1 dholland { 597 1.1 dholland struct sockaddr_in *sin, dst; 598 1.1 dholland struct uio auio; 599 1.1 dholland struct sockopt sopt; 600 1.1 dholland struct iovec aio; 601 1.1 dholland int error, on, rcvflg, timo, len; 602 1.1 dholland time_t atimo; 603 1.1 dholland time_t rtimo; 604 1.1 dholland struct timeval tv; 605 1.1 dholland struct bootpc_ifcontext *ifctx; 606 1.1 dholland int outstanding; 607 1.1 dholland int gotrootpath; 608 1.1 dholland int retry; 609 1.1 dholland const char *s; 610 1.1 dholland 611 1.1 dholland tv.tv_sec = 1; 612 1.1 dholland tv.tv_usec = 0; 613 1.3 pgoyette sockopt_init(&sopt, SOL_SOCKET, SO_RCVTIMEO, sizeof(tv)); 614 1.3 pgoyette error = sockopt_set(&sopt, &tv, sizeof(tv)); 615 1.3 pgoyette sockopt_destroy(&sopt); 616 1.1 dholland 617 1.1 dholland if (error != 0) 618 1.1 dholland goto out; 619 1.1 dholland 620 1.1 dholland /* 621 1.1 dholland * Enable broadcast. 622 1.1 dholland */ 623 1.1 dholland on = 1; 624 1.3 pgoyette sockopt_init(&sopt, SOL_SOCKET, SO_BROADCAST, sizeof(on)); 625 1.3 pgoyette error = sockopt_set(&sopt, &on, sizeof(on)); 626 1.3 pgoyette sockopt_destroy(&sopt); 627 1.1 dholland 628 1.1 dholland if (error != 0) 629 1.1 dholland goto out; 630 1.1 dholland 631 1.1 dholland /* 632 1.1 dholland * Disable routing. 633 1.1 dholland */ 634 1.1 dholland 635 1.1 dholland on = 1; 636 1.3 pgoyette sockopt_init(&sopt, SOL_SOCKET, SO_DONTROUTE, sizeof(on)); 637 1.3 pgoyette error = sockopt_set(&sopt, &on, sizeof(on)); 638 1.3 pgoyette sockopt_destroy(&sopt); 639 1.1 dholland 640 1.1 dholland if (error != 0) 641 1.1 dholland goto out; 642 1.1 dholland 643 1.1 dholland /* 644 1.1 dholland * Bind the local endpoint to a bootp client port. 645 1.1 dholland */ 646 1.1 dholland sin = &dst; 647 1.1 dholland clear_sinaddr(sin); 648 1.1 dholland sin->sin_port = htons(IPPORT_BOOTPC); 649 1.1 dholland error = sobind(bootp_so, (struct sockaddr *)sin, td); 650 1.1 dholland if (error != 0) { 651 1.1 dholland printf("bind failed\n"); 652 1.1 dholland goto out; 653 1.1 dholland } 654 1.1 dholland 655 1.1 dholland /* 656 1.1 dholland * Setup socket address for the server. 657 1.1 dholland */ 658 1.1 dholland sin = &dst; 659 1.1 dholland clear_sinaddr(sin); 660 1.1 dholland sin->sin_addr.s_addr = INADDR_BROADCAST; 661 1.1 dholland sin->sin_port = htons(IPPORT_BOOTPS); 662 1.1 dholland 663 1.1 dholland /* 664 1.1 dholland * Send it, repeatedly, until a reply is received, 665 1.1 dholland * but delay each re-send by an increasing amount. 666 1.1 dholland * If the delay hits the maximum, start complaining. 667 1.1 dholland */ 668 1.1 dholland timo = 0; 669 1.1 dholland rtimo = 0; 670 1.1 dholland for (;;) { 671 1.1 dholland 672 1.1 dholland outstanding = 0; 673 1.1 dholland gotrootpath = 0; 674 1.1 dholland 675 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) { 676 1.1 dholland if (bootpc_ifctx_isresolved(ifctx) != 0 && 677 1.1 dholland bootpc_tag(&gctx->tmptag, &ifctx->reply, 678 1.1 dholland ifctx->replylen, 679 1.1 dholland TAG_ROOT) != NULL) 680 1.1 dholland gotrootpath = 1; 681 1.1 dholland } 682 1.1 dholland 683 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) { 684 1.1 dholland struct in_aliasreq *ifra = &ifctx->iareq; 685 1.1 dholland sin = (struct sockaddr_in *)&ifra->ifra_mask; 686 1.1 dholland 687 1.1 dholland ifctx->outstanding = 0; 688 1.1 dholland if (bootpc_ifctx_isresolved(ifctx) != 0 && 689 1.1 dholland gotrootpath != 0) { 690 1.1 dholland continue; 691 1.1 dholland } 692 1.1 dholland if (bootpc_ifctx_isfailed(ifctx) != 0) 693 1.1 dholland continue; 694 1.1 dholland 695 1.1 dholland outstanding++; 696 1.1 dholland ifctx->outstanding = 1; 697 1.1 dholland 698 1.1 dholland /* Proceed to next step in DHCP negotiation */ 699 1.1 dholland if ((ifctx->state == IF_DHCP_OFFERED && 700 1.1 dholland ifctx->dhcpquerytype != DHCP_REQUEST) || 701 1.1 dholland (ifctx->state == IF_DHCP_UNRESOLVED && 702 1.1 dholland ifctx->dhcpquerytype != DHCP_DISCOVER) || 703 1.1 dholland (ifctx->state == IF_BOOTP_UNRESOLVED && 704 1.1 dholland ifctx->dhcpquerytype != DHCP_NOMSG)) { 705 1.1 dholland ifctx->sentmsg = 0; 706 1.1 dholland bootpc_compose_query(ifctx, td); 707 1.1 dholland } 708 1.1 dholland 709 1.1 dholland /* Send BOOTP request (or re-send). */ 710 1.1 dholland 711 1.1 dholland if (ifctx->sentmsg == 0) { 712 1.1 dholland switch(ifctx->dhcpquerytype) { 713 1.1 dholland case DHCP_DISCOVER: 714 1.1 dholland s = "DHCP Discover"; 715 1.1 dholland break; 716 1.1 dholland case DHCP_REQUEST: 717 1.1 dholland s = "DHCP Request"; 718 1.1 dholland break; 719 1.1 dholland case DHCP_NOMSG: 720 1.1 dholland default: 721 1.1 dholland s = "BOOTP Query"; 722 1.1 dholland break; 723 1.1 dholland } 724 1.1 dholland printf("Sending %s packet from " 725 1.3 pgoyette "interface %s (%*ld):\n", 726 1.1 dholland s, 727 1.1 dholland ifctx->ireq.ifr_name, 728 1.1 dholland ifctx->sdl->sdl_alen, 729 1.3 pgoyette (unsigned char *) LLADDR(ifctx->sdl) ); 730 1.1 dholland ifctx->sentmsg = 1; 731 1.1 dholland } 732 1.1 dholland 733 1.3 pgoyette aio.iov_base = (void *) &ifctx->call; 734 1.1 dholland aio.iov_len = sizeof(ifctx->call); 735 1.1 dholland 736 1.1 dholland auio.uio_iov = &aio; 737 1.1 dholland auio.uio_iovcnt = 1; 738 1.1 dholland auio.uio_segflg = UIO_SYSSPACE; 739 1.1 dholland auio.uio_rw = UIO_WRITE; 740 1.1 dholland auio.uio_offset = 0; 741 1.1 dholland auio.uio_resid = sizeof(ifctx->call); 742 1.1 dholland auio.uio_td = td; 743 1.1 dholland 744 1.1 dholland /* Set netmask to 0.0.0.0 */ 745 1.1 dholland clear_sinaddr(sin); 746 1.3 pgoyette error = ifioctl(bootp_so, SIOCAIFADDR, (void *)ifra, 747 1.1 dholland td); 748 1.1 dholland if (error != 0) 749 1.1 dholland panic("%s: SIOCAIFADDR, error=%d", __func__, 750 1.1 dholland error); 751 1.1 dholland 752 1.1 dholland error = sosend(bootp_so, (struct sockaddr *) &dst, 753 1.1 dholland &auio, NULL, NULL, 0, td); 754 1.1 dholland if (error != 0) 755 1.1 dholland printf("%s: sosend: %d state %08x\n", __func__, 756 1.1 dholland error, (int )bootp_so->so_state); 757 1.1 dholland 758 1.1 dholland /* Set netmask to 255.0.0.0 */ 759 1.1 dholland sin->sin_addr.s_addr = htonl(IN_CLASSA_NET); 760 1.3 pgoyette error = ifioctl(bootp_so, SIOCAIFADDR, (void *)ifra, 761 1.1 dholland td); 762 1.1 dholland if (error != 0) 763 1.1 dholland panic("%s: SIOCAIFADDR, error=%d", __func__, 764 1.1 dholland error); 765 1.1 dholland } 766 1.1 dholland 767 1.1 dholland if (outstanding == 0 && 768 1.1 dholland (rtimo == 0 || time_second >= rtimo)) { 769 1.1 dholland error = 0; 770 1.1 dholland goto out; 771 1.1 dholland } 772 1.1 dholland 773 1.1 dholland /* Determine new timeout. */ 774 1.1 dholland if (timo < MAX_RESEND_DELAY) 775 1.1 dholland timo++; 776 1.1 dholland else { 777 1.1 dholland printf("DHCP/BOOTP timeout for server "); 778 1.1 dholland print_sin_addr(&dst); 779 1.1 dholland printf("\n"); 780 1.1 dholland } 781 1.1 dholland 782 1.1 dholland /* 783 1.1 dholland * Wait for up to timo seconds for a reply. 784 1.1 dholland * The socket receive timeout was set to 1 second. 785 1.1 dholland */ 786 1.1 dholland atimo = timo + time_second; 787 1.1 dholland while (time_second < atimo) { 788 1.3 pgoyette aio.iov_base = (void *) &gctx->reply; 789 1.1 dholland aio.iov_len = sizeof(gctx->reply); 790 1.1 dholland 791 1.1 dholland auio.uio_iov = &aio; 792 1.1 dholland auio.uio_iovcnt = 1; 793 1.1 dholland auio.uio_segflg = UIO_SYSSPACE; 794 1.1 dholland auio.uio_rw = UIO_READ; 795 1.1 dholland auio.uio_offset = 0; 796 1.1 dholland auio.uio_resid = sizeof(gctx->reply); 797 1.1 dholland auio.uio_td = td; 798 1.1 dholland 799 1.1 dholland rcvflg = 0; 800 1.1 dholland error = soreceive(bootp_so, NULL, &auio, 801 1.1 dholland NULL, NULL, &rcvflg); 802 1.1 dholland gctx->secs = time_second - gctx->starttime; 803 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) { 804 1.1 dholland if (bootpc_ifctx_isresolved(ifctx) != 0 || 805 1.1 dholland bootpc_ifctx_isfailed(ifctx) != 0) 806 1.1 dholland continue; 807 1.1 dholland 808 1.1 dholland ifctx->call.secs = htons(gctx->secs); 809 1.1 dholland } 810 1.1 dholland if (error == EWOULDBLOCK) 811 1.1 dholland continue; 812 1.1 dholland if (error != 0) 813 1.1 dholland goto out; 814 1.1 dholland len = sizeof(gctx->reply) - auio.uio_resid; 815 1.1 dholland 816 1.1 dholland /* Do we have the required number of bytes ? */ 817 1.1 dholland if (len < BOOTP_MIN_LEN) 818 1.1 dholland continue; 819 1.1 dholland gctx->replylen = len; 820 1.1 dholland 821 1.1 dholland /* Is it a reply? */ 822 1.1 dholland if (gctx->reply.op != BOOTP_REPLY) 823 1.1 dholland continue; 824 1.1 dholland 825 1.1 dholland /* Is this an answer to our query */ 826 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) { 827 1.1 dholland if (gctx->reply.xid != ifctx->call.xid) 828 1.1 dholland continue; 829 1.1 dholland 830 1.1 dholland /* Same HW address size ? */ 831 1.1 dholland if (gctx->reply.hlen != ifctx->call.hlen) 832 1.1 dholland continue; 833 1.1 dholland 834 1.1 dholland /* Correct HW address ? */ 835 1.1 dholland if (bcmp(gctx->reply.chaddr, 836 1.1 dholland ifctx->call.chaddr, 837 1.1 dholland ifctx->call.hlen) != 0) 838 1.1 dholland continue; 839 1.1 dholland 840 1.1 dholland break; 841 1.1 dholland } 842 1.1 dholland 843 1.1 dholland if (ifctx != NULL) { 844 1.1 dholland s = bootpc_tag(&gctx->tmptag, 845 1.1 dholland &gctx->reply, 846 1.1 dholland gctx->replylen, 847 1.1 dholland TAG_DHCP_MSGTYPE); 848 1.1 dholland if (s != NULL) { 849 1.1 dholland switch (*s) { 850 1.1 dholland case DHCP_OFFER: 851 1.1 dholland s = "DHCP Offer"; 852 1.1 dholland break; 853 1.1 dholland case DHCP_ACK: 854 1.1 dholland s = "DHCP Ack"; 855 1.1 dholland break; 856 1.1 dholland default: 857 1.1 dholland s = "DHCP (unexpected)"; 858 1.1 dholland break; 859 1.1 dholland } 860 1.1 dholland } else 861 1.1 dholland s = "BOOTP Reply"; 862 1.1 dholland 863 1.1 dholland printf("Received %s packet" 864 1.1 dholland " on %s from ", 865 1.1 dholland s, 866 1.1 dholland ifctx->ireq.ifr_name); 867 1.1 dholland print_in_addr(gctx->reply.siaddr); 868 1.1 dholland if (gctx->reply.giaddr.s_addr != 869 1.1 dholland htonl(INADDR_ANY)) { 870 1.1 dholland printf(" via "); 871 1.1 dholland print_in_addr(gctx->reply.giaddr); 872 1.1 dholland } 873 1.1 dholland if (bootpc_received(gctx, ifctx) != 0) { 874 1.1 dholland printf(" (accepted)"); 875 1.1 dholland if (ifctx->outstanding) { 876 1.1 dholland ifctx->outstanding = 0; 877 1.1 dholland outstanding--; 878 1.1 dholland } 879 1.1 dholland /* Network settle delay */ 880 1.1 dholland if (outstanding == 0) 881 1.1 dholland atimo = time_second + 882 1.1 dholland BOOTP_SETTLE_DELAY; 883 1.1 dholland } else 884 1.1 dholland printf(" (ignored)"); 885 1.1 dholland if (ifctx->gotrootpath || 886 1.1 dholland gctx->any_root_overrides) { 887 1.1 dholland gotrootpath = 1; 888 1.1 dholland rtimo = time_second + 889 1.1 dholland BOOTP_SETTLE_DELAY; 890 1.1 dholland if (ifctx->gotrootpath) 891 1.1 dholland printf(" (got root path)"); 892 1.1 dholland } 893 1.1 dholland printf("\n"); 894 1.1 dholland } 895 1.1 dholland } /* while secs */ 896 1.1 dholland #ifdef BOOTP_TIMEOUT 897 1.1 dholland if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0) 898 1.1 dholland break; 899 1.1 dholland #endif 900 1.1 dholland /* Force a retry if halfway in DHCP negotiation */ 901 1.1 dholland retry = 0; 902 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 903 1.1 dholland if (ifctx->state == IF_DHCP_OFFERED) { 904 1.1 dholland if (ifctx->dhcpquerytype == DHCP_DISCOVER) 905 1.1 dholland retry = 1; 906 1.1 dholland else 907 1.1 dholland ifctx->state = IF_DHCP_UNRESOLVED; 908 1.1 dholland } 909 1.1 dholland 910 1.1 dholland if (retry != 0) 911 1.1 dholland continue; 912 1.1 dholland 913 1.1 dholland if (gotrootpath != 0) { 914 1.1 dholland gctx->gotrootpath = gotrootpath; 915 1.1 dholland if (rtimo != 0 && time_second >= rtimo) 916 1.1 dholland break; 917 1.1 dholland } 918 1.1 dholland } /* forever send/receive */ 919 1.1 dholland 920 1.1 dholland /* 921 1.1 dholland * XXX: These are errors of varying seriousness being silently 922 1.1 dholland * ignored 923 1.1 dholland */ 924 1.1 dholland 925 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 926 1.1 dholland if (bootpc_ifctx_isresolved(ifctx) == 0) { 927 1.1 dholland printf("%s timeout for interface %s\n", 928 1.1 dholland ifctx->dhcpquerytype != DHCP_NOMSG ? 929 1.1 dholland "DHCP" : "BOOTP", 930 1.1 dholland ifctx->ireq.ifr_name); 931 1.1 dholland } 932 1.1 dholland 933 1.1 dholland if (gctx->gotrootpath != 0) { 934 1.1 dholland #if 0 935 1.1 dholland printf("Got a root path, ignoring remaining timeout\n"); 936 1.1 dholland #endif 937 1.1 dholland error = 0; 938 1.1 dholland goto out; 939 1.1 dholland } 940 1.1 dholland #ifndef BOOTP_NFSROOT 941 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 942 1.1 dholland if (bootpc_ifctx_isresolved(ifctx) != 0) { 943 1.1 dholland error = 0; 944 1.1 dholland goto out; 945 1.1 dholland } 946 1.1 dholland #endif 947 1.1 dholland error = ETIMEDOUT; 948 1.1 dholland 949 1.1 dholland out: 950 1.1 dholland return (error); 951 1.1 dholland } 952 1.1 dholland 953 1.1 dholland static void 954 1.3 pgoyette bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx, struct lwp *td) 955 1.1 dholland { 956 1.1 dholland struct ifreq *ifr; 957 1.1 dholland struct in_aliasreq *ifra; 958 1.1 dholland struct sockaddr_in *sin; 959 1.1 dholland int error; 960 1.1 dholland 961 1.1 dholland ifr = &ifctx->ireq; 962 1.1 dholland ifra = &ifctx->iareq; 963 1.1 dholland 964 1.1 dholland /* 965 1.1 dholland * Bring up the interface. 966 1.1 dholland * 967 1.1 dholland * Get the old interface flags and or IFF_UP into them; if 968 1.1 dholland * IFF_UP set blindly, interface selection can be clobbered. 969 1.1 dholland */ 970 1.3 pgoyette error = ifioctl(bootp_so, SIOCGIFFLAGS, (void *)ifr, td); 971 1.1 dholland if (error != 0) 972 1.1 dholland panic("%s: SIOCGIFFLAGS, error=%d", __func__, error); 973 1.1 dholland ifr->ifr_flags |= IFF_UP; 974 1.3 pgoyette error = ifioctl(bootp_so, SIOCSIFFLAGS, (void *)ifr, td); 975 1.1 dholland if (error != 0) 976 1.1 dholland panic("%s: SIOCSIFFLAGS, error=%d", __func__, error); 977 1.1 dholland 978 1.1 dholland /* 979 1.1 dholland * Do enough of ifconfig(8) so that the chosen interface 980 1.1 dholland * can talk to the servers. Set address to 0.0.0.0/8 and 981 1.1 dholland * broadcast address to local broadcast. 982 1.1 dholland */ 983 1.1 dholland sin = (struct sockaddr_in *)&ifra->ifra_addr; 984 1.1 dholland clear_sinaddr(sin); 985 1.1 dholland sin = (struct sockaddr_in *)&ifra->ifra_mask; 986 1.1 dholland clear_sinaddr(sin); 987 1.1 dholland sin->sin_addr.s_addr = htonl(IN_CLASSA_NET); 988 1.1 dholland sin = (struct sockaddr_in *)&ifra->ifra_broadaddr; 989 1.1 dholland clear_sinaddr(sin); 990 1.1 dholland sin->sin_addr.s_addr = htonl(INADDR_BROADCAST); 991 1.3 pgoyette error = ifioctl(bootp_so, SIOCAIFADDR, (void *)ifra, td); 992 1.1 dholland if (error != 0) 993 1.1 dholland panic("%s: SIOCAIFADDR, error=%d", __func__, error); 994 1.1 dholland } 995 1.1 dholland 996 1.1 dholland static void 997 1.3 pgoyette bootpc_shutdown_interface(struct bootpc_ifcontext *ifctx, struct lwp *td) 998 1.1 dholland { 999 1.1 dholland struct ifreq *ifr; 1000 1.1 dholland struct sockaddr_in *sin; 1001 1.1 dholland int error; 1002 1.1 dholland 1003 1.1 dholland ifr = &ifctx->ireq; 1004 1.1 dholland 1005 1.1 dholland printf("Shutdown interface %s\n", ifctx->ireq.ifr_name); 1006 1.3 pgoyette error = ifioctl(bootp_so, SIOCGIFFLAGS, (void *)ifr, td); 1007 1.1 dholland if (error != 0) 1008 1.1 dholland panic("%s: SIOCGIFFLAGS, error=%d", __func__, error); 1009 1.1 dholland ifr->ifr_flags &= ~IFF_UP; 1010 1.3 pgoyette error = ifioctl(bootp_so, SIOCSIFFLAGS, (void *)ifr, td); 1011 1.1 dholland if (error != 0) 1012 1.1 dholland panic("%s: SIOCSIFFLAGS, error=%d", __func__, error); 1013 1.1 dholland 1014 1.1 dholland sin = (struct sockaddr_in *) &ifr->ifr_addr; 1015 1.1 dholland clear_sinaddr(sin); 1016 1.3 pgoyette error = ifioctl(bootp_so, SIOCDIFADDR, (void *) ifr, td); 1017 1.1 dholland if (error != 0) 1018 1.1 dholland panic("%s: SIOCDIFADDR, error=%d", __func__, error); 1019 1.1 dholland } 1020 1.1 dholland 1021 1.2 pgoyette static void 1022 1.1 dholland bootpc_adjust_interface(struct bootpc_ifcontext *ifctx, 1023 1.3 pgoyette struct bootpc_globalcontext *gctx, struct lwp *td) 1024 1.1 dholland { 1025 1.1 dholland int error; 1026 1.1 dholland struct sockaddr_in *sin; 1027 1.1 dholland struct ifreq *ifr; 1028 1.1 dholland struct in_aliasreq *ifra; 1029 1.1 dholland struct sockaddr_in *myaddr; 1030 1.1 dholland struct sockaddr_in *netmask; 1031 1.1 dholland 1032 1.1 dholland ifr = &ifctx->ireq; 1033 1.1 dholland ifra = &ifctx->iareq; 1034 1.1 dholland myaddr = &ifctx->myaddr; 1035 1.1 dholland netmask = &ifctx->netmask; 1036 1.1 dholland 1037 1.1 dholland if (bootpc_ifctx_isresolved(ifctx) == 0) { 1038 1.1 dholland /* Shutdown interfaces where BOOTP failed */ 1039 1.1 dholland bootpc_shutdown_interface(ifctx, td); 1040 1.2 pgoyette return; 1041 1.2 pgoyette } 1042 1.2 pgoyette 1043 1.2 pgoyette printf("Adjusted interface %s", ifctx->ireq.ifr_name); 1044 1.2 pgoyette 1045 1.2 pgoyette /* Do BOOTP interface options */ 1046 1.2 pgoyette if (ifctx->mtu != 0) { 1047 1.2 pgoyette printf(" (MTU=%d%s)", ifctx->mtu, 1048 1.2 pgoyette (ifctx->mtu > 1514) ? "/JUMBO" : ""); 1049 1.2 pgoyette ifr->ifr_mtu = ifctx->mtu; 1050 1.3 pgoyette error = ifioctl(bootp_so, SIOCSIFMTU, (void *) ifr, td); 1051 1.2 pgoyette if (error != 0) 1052 1.2 pgoyette panic("%s: SIOCSIFMTU, error=%d", __func__, error); 1053 1.1 dholland } 1054 1.2 pgoyette printf("\n"); 1055 1.1 dholland 1056 1.1 dholland /* 1057 1.1 dholland * Do enough of ifconfig(8) so that the chosen interface 1058 1.1 dholland * can talk to the servers. (just set the address) 1059 1.1 dholland */ 1060 1.1 dholland sin = (struct sockaddr_in *) &ifr->ifr_addr; 1061 1.1 dholland clear_sinaddr(sin); 1062 1.3 pgoyette error = ifioctl(bootp_so, SIOCDIFADDR, (void *) ifr, td); 1063 1.1 dholland if (error != 0) 1064 1.1 dholland panic("%s: SIOCDIFADDR, error=%d", __func__, error); 1065 1.1 dholland 1066 1.1 dholland bcopy(myaddr, &ifra->ifra_addr, sizeof(*myaddr)); 1067 1.1 dholland bcopy(netmask, &ifra->ifra_mask, sizeof(*netmask)); 1068 1.1 dholland clear_sinaddr(&ifra->ifra_broadaddr); 1069 1.1 dholland ifra->ifra_broadaddr.sin_addr.s_addr = myaddr->sin_addr.s_addr | 1070 1.1 dholland ~netmask->sin_addr.s_addr; 1071 1.1 dholland 1072 1.3 pgoyette error = ifioctl(bootp_so, SIOCAIFADDR, (void *)ifra, td); 1073 1.1 dholland if (error != 0) 1074 1.1 dholland panic("%s: SIOCAIFADDR, error=%d", __func__, error); 1075 1.2 pgoyette } 1076 1.2 pgoyette 1077 1.2 pgoyette static void 1078 1.2 pgoyette bootpc_add_default_route(struct bootpc_ifcontext *ifctx) 1079 1.2 pgoyette { 1080 1.2 pgoyette int error; 1081 1.2 pgoyette struct sockaddr_in defdst; 1082 1.2 pgoyette struct sockaddr_in defmask; 1083 1.2 pgoyette 1084 1.2 pgoyette if (ifctx->gw.sin_addr.s_addr == htonl(INADDR_ANY)) 1085 1.2 pgoyette return; 1086 1.1 dholland 1087 1.2 pgoyette clear_sinaddr(&defdst); 1088 1.2 pgoyette clear_sinaddr(&defmask); 1089 1.1 dholland 1090 1.2 pgoyette error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&defdst, 1091 1.2 pgoyette (struct sockaddr *) &ifctx->gw, (struct sockaddr *)&defmask, 1092 1.2 pgoyette (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, RT_DEFAULT_FIB); 1093 1.2 pgoyette if (error != 0) { 1094 1.2 pgoyette printf("%s: RTM_ADD, error=%d\n", __func__, error); 1095 1.1 dholland } 1096 1.2 pgoyette } 1097 1.2 pgoyette 1098 1.2 pgoyette static void 1099 1.2 pgoyette bootpc_remove_default_route(struct bootpc_ifcontext *ifctx) 1100 1.2 pgoyette { 1101 1.2 pgoyette int error; 1102 1.2 pgoyette struct sockaddr_in defdst; 1103 1.2 pgoyette struct sockaddr_in defmask; 1104 1.2 pgoyette 1105 1.2 pgoyette if (ifctx->gw.sin_addr.s_addr == htonl(INADDR_ANY)) 1106 1.2 pgoyette return; 1107 1.2 pgoyette 1108 1.2 pgoyette clear_sinaddr(&defdst); 1109 1.2 pgoyette clear_sinaddr(&defmask); 1110 1.1 dholland 1111 1.2 pgoyette error = rtrequest_fib(RTM_DELETE, (struct sockaddr *)&defdst, 1112 1.2 pgoyette (struct sockaddr *) &ifctx->gw, (struct sockaddr *)&defmask, 1113 1.2 pgoyette (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, RT_DEFAULT_FIB); 1114 1.2 pgoyette if (error != 0) { 1115 1.2 pgoyette printf("%s: RTM_DELETE, error=%d\n", __func__, error); 1116 1.2 pgoyette } 1117 1.1 dholland } 1118 1.1 dholland 1119 1.1 dholland static int 1120 1.3 pgoyette setmyfs(struct sockaddr_in *addr, char *path, char *p, 1121 1.1 dholland const struct in_addr *siaddr) 1122 1.1 dholland { 1123 1.1 dholland 1124 1.1 dholland if (getip(&p, &addr->sin_addr) == 0) { 1125 1.1 dholland if (siaddr != NULL && *p == '/') 1126 1.1 dholland bcopy(siaddr, &addr->sin_addr, sizeof(struct in_addr)); 1127 1.1 dholland else 1128 1.1 dholland return 0; 1129 1.1 dholland } else { 1130 1.1 dholland if (*p != ':') 1131 1.1 dholland return 0; 1132 1.1 dholland p++; 1133 1.1 dholland } 1134 1.1 dholland 1135 1.1 dholland addr->sin_len = sizeof(struct sockaddr_in); 1136 1.1 dholland addr->sin_family = AF_INET; 1137 1.1 dholland 1138 1.1 dholland strlcpy(path, p, MNAMELEN); 1139 1.1 dholland return 1; 1140 1.1 dholland } 1141 1.1 dholland 1142 1.1 dholland static int 1143 1.1 dholland getip(char **ptr, struct in_addr *addr) 1144 1.1 dholland { 1145 1.1 dholland char *p; 1146 1.1 dholland unsigned int ip; 1147 1.1 dholland int val; 1148 1.1 dholland 1149 1.1 dholland p = *ptr; 1150 1.1 dholland ip = 0; 1151 1.1 dholland if (((val = getdec(&p)) < 0) || (val > 255)) 1152 1.1 dholland return 0; 1153 1.1 dholland ip = val << 24; 1154 1.1 dholland if (*p != '.') 1155 1.1 dholland return 0; 1156 1.1 dholland p++; 1157 1.1 dholland if (((val = getdec(&p)) < 0) || (val > 255)) 1158 1.1 dholland return 0; 1159 1.1 dholland ip |= (val << 16); 1160 1.1 dholland if (*p != '.') 1161 1.1 dholland return 0; 1162 1.1 dholland p++; 1163 1.1 dholland if (((val = getdec(&p)) < 0) || (val > 255)) 1164 1.1 dholland return 0; 1165 1.1 dholland ip |= (val << 8); 1166 1.1 dholland if (*p != '.') 1167 1.1 dholland return 0; 1168 1.1 dholland p++; 1169 1.1 dholland if (((val = getdec(&p)) < 0) || (val > 255)) 1170 1.1 dholland return 0; 1171 1.1 dholland ip |= val; 1172 1.1 dholland 1173 1.1 dholland addr->s_addr = htonl(ip); 1174 1.1 dholland *ptr = p; 1175 1.1 dholland return 1; 1176 1.1 dholland } 1177 1.1 dholland 1178 1.1 dholland static int 1179 1.1 dholland getdec(char **ptr) 1180 1.1 dholland { 1181 1.1 dholland char *p; 1182 1.1 dholland int ret; 1183 1.1 dholland 1184 1.1 dholland p = *ptr; 1185 1.1 dholland ret = 0; 1186 1.1 dholland if ((*p < '0') || (*p > '9')) 1187 1.1 dholland return -1; 1188 1.1 dholland while ((*p >= '0') && (*p <= '9')) { 1189 1.1 dholland ret = ret * 10 + (*p - '0'); 1190 1.1 dholland p++; 1191 1.1 dholland } 1192 1.1 dholland *ptr = p; 1193 1.1 dholland return ret; 1194 1.1 dholland } 1195 1.1 dholland 1196 1.1 dholland static void 1197 1.1 dholland mountopts(struct nfs_args *args, char *p) 1198 1.1 dholland { 1199 1.1 dholland args->version = NFS_ARGSVERSION; 1200 1.1 dholland args->rsize = BOOTP_BLOCKSIZE; 1201 1.1 dholland args->wsize = BOOTP_BLOCKSIZE; 1202 1.1 dholland args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT; 1203 1.1 dholland args->sotype = SOCK_DGRAM; 1204 1.1 dholland if (p != NULL) 1205 1.1 dholland nfs_parse_options(p, args); 1206 1.1 dholland } 1207 1.1 dholland 1208 1.1 dholland static int 1209 1.1 dholland xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len) 1210 1.1 dholland { 1211 1.1 dholland struct mbuf *m; 1212 1.1 dholland int alignedlen; 1213 1.1 dholland 1214 1.1 dholland m = *mptr; 1215 1.1 dholland alignedlen = ( len + 3 ) & ~3; 1216 1.1 dholland 1217 1.1 dholland if (m->m_len < alignedlen) { 1218 1.1 dholland m = m_pullup(m, alignedlen); 1219 1.1 dholland if (m == NULL) { 1220 1.1 dholland *mptr = NULL; 1221 1.1 dholland return EBADRPC; 1222 1.1 dholland } 1223 1.1 dholland } 1224 1.1 dholland bcopy(mtod(m, u_char *), buf, len); 1225 1.1 dholland m_adj(m, alignedlen); 1226 1.1 dholland *mptr = m; 1227 1.1 dholland return 0; 1228 1.1 dholland } 1229 1.1 dholland 1230 1.1 dholland static int 1231 1.1 dholland xdr_int_decode(struct mbuf **mptr, int *iptr) 1232 1.1 dholland { 1233 1.1 dholland u_int32_t i; 1234 1.1 dholland 1235 1.1 dholland if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0) 1236 1.1 dholland return EBADRPC; 1237 1.1 dholland *iptr = fxdr_unsigned(u_int32_t, i); 1238 1.1 dholland return 0; 1239 1.1 dholland } 1240 1.1 dholland 1241 1.1 dholland static void 1242 1.1 dholland print_sin_addr(struct sockaddr_in *sin) 1243 1.1 dholland { 1244 1.1 dholland 1245 1.1 dholland print_in_addr(sin->sin_addr); 1246 1.1 dholland } 1247 1.1 dholland 1248 1.1 dholland static void 1249 1.1 dholland print_in_addr(struct in_addr addr) 1250 1.1 dholland { 1251 1.1 dholland unsigned int ip; 1252 1.1 dholland 1253 1.1 dholland ip = ntohl(addr.s_addr); 1254 1.1 dholland printf("%d.%d.%d.%d", 1255 1.1 dholland ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255); 1256 1.1 dholland } 1257 1.1 dholland 1258 1.1 dholland static void 1259 1.3 pgoyette bootpc_compose_query(struct bootpc_ifcontext *ifctx, struct lwp *td) 1260 1.1 dholland { 1261 1.1 dholland unsigned char *vendp; 1262 1.1 dholland unsigned char vendor_client[64]; 1263 1.1 dholland uint32_t leasetime; 1264 1.1 dholland uint8_t vendor_client_len; 1265 1.1 dholland 1266 1.1 dholland ifctx->gotrootpath = 0; 1267 1.1 dholland 1268 1.3 pgoyette bzero((void *) &ifctx->call, sizeof(ifctx->call)); 1269 1.1 dholland 1270 1.1 dholland /* bootpc part */ 1271 1.1 dholland ifctx->call.op = BOOTP_REQUEST; /* BOOTREQUEST */ 1272 1.1 dholland ifctx->call.htype = 1; /* 10mb ethernet */ 1273 1.1 dholland ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */ 1274 1.1 dholland ifctx->call.hops = 0; 1275 1.1 dholland if (bootpc_ifctx_isunresolved(ifctx) != 0) 1276 1.1 dholland ifctx->xid++; 1277 1.1 dholland ifctx->call.xid = txdr_unsigned(ifctx->xid); 1278 1.1 dholland bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen); 1279 1.1 dholland 1280 1.1 dholland vendp = ifctx->call.vend; 1281 1.1 dholland *vendp++ = 99; /* RFC1048 cookie */ 1282 1.1 dholland *vendp++ = 130; 1283 1.1 dholland *vendp++ = 83; 1284 1.1 dholland *vendp++ = 99; 1285 1.1 dholland *vendp++ = TAG_MAXMSGSIZE; 1286 1.1 dholland *vendp++ = 2; 1287 1.1 dholland *vendp++ = (sizeof(struct bootp_packet) >> 8) & 255; 1288 1.1 dholland *vendp++ = sizeof(struct bootp_packet) & 255; 1289 1.1 dholland 1290 1.1 dholland snprintf(vendor_client, sizeof(vendor_client), "%s:%s:%s", 1291 1.1 dholland ostype, MACHINE, osrelease); 1292 1.1 dholland vendor_client_len = strlen(vendor_client); 1293 1.1 dholland *vendp++ = TAG_VENDOR_INDENTIFIER; 1294 1.1 dholland *vendp++ = vendor_client_len; 1295 1.1 dholland memcpy(vendp, vendor_client, vendor_client_len); 1296 1.1 dholland vendp += vendor_client_len; 1297 1.1 dholland ifctx->dhcpquerytype = DHCP_NOMSG; 1298 1.1 dholland switch (ifctx->state) { 1299 1.1 dholland case IF_DHCP_UNRESOLVED: 1300 1.1 dholland *vendp++ = TAG_DHCP_MSGTYPE; 1301 1.1 dholland *vendp++ = 1; 1302 1.1 dholland *vendp++ = DHCP_DISCOVER; 1303 1.1 dholland ifctx->dhcpquerytype = DHCP_DISCOVER; 1304 1.1 dholland ifctx->gotdhcpserver = 0; 1305 1.1 dholland break; 1306 1.1 dholland case IF_DHCP_OFFERED: 1307 1.1 dholland *vendp++ = TAG_DHCP_MSGTYPE; 1308 1.1 dholland *vendp++ = 1; 1309 1.1 dholland *vendp++ = DHCP_REQUEST; 1310 1.1 dholland ifctx->dhcpquerytype = DHCP_REQUEST; 1311 1.1 dholland *vendp++ = TAG_DHCP_REQ_ADDR; 1312 1.1 dholland *vendp++ = 4; 1313 1.1 dholland memcpy(vendp, &ifctx->reply.yiaddr, 4); 1314 1.1 dholland vendp += 4; 1315 1.1 dholland if (ifctx->gotdhcpserver != 0) { 1316 1.1 dholland *vendp++ = TAG_DHCP_SERVERID; 1317 1.1 dholland *vendp++ = 4; 1318 1.1 dholland memcpy(vendp, &ifctx->dhcpserver, 4); 1319 1.1 dholland vendp += 4; 1320 1.1 dholland } 1321 1.1 dholland *vendp++ = TAG_DHCP_LEASETIME; 1322 1.1 dholland *vendp++ = 4; 1323 1.1 dholland leasetime = htonl(300); 1324 1.1 dholland memcpy(vendp, &leasetime, 4); 1325 1.1 dholland vendp += 4; 1326 1.1 dholland break; 1327 1.1 dholland default: 1328 1.1 dholland break; 1329 1.1 dholland } 1330 1.1 dholland *vendp = TAG_END; 1331 1.1 dholland 1332 1.1 dholland ifctx->call.secs = 0; 1333 1.1 dholland ifctx->call.flags = htons(0x8000); /* We need a broadcast answer */ 1334 1.1 dholland } 1335 1.1 dholland 1336 1.1 dholland static int 1337 1.1 dholland bootpc_hascookie(struct bootp_packet *bp) 1338 1.1 dholland { 1339 1.1 dholland 1340 1.1 dholland return (bp->vend[0] == 99 && bp->vend[1] == 130 && 1341 1.1 dholland bp->vend[2] == 83 && bp->vend[3] == 99); 1342 1.1 dholland } 1343 1.1 dholland 1344 1.1 dholland static void 1345 1.1 dholland bootpc_tag_helper(struct bootpc_tagcontext *tctx, 1346 1.1 dholland unsigned char *start, int len, int tag) 1347 1.1 dholland { 1348 1.1 dholland unsigned char *j; 1349 1.1 dholland unsigned char *ej; 1350 1.1 dholland unsigned char code; 1351 1.1 dholland 1352 1.1 dholland if (tctx->badtag != 0 || tctx->badopt != 0) 1353 1.1 dholland return; 1354 1.1 dholland 1355 1.1 dholland j = start; 1356 1.1 dholland ej = j + len; 1357 1.1 dholland 1358 1.1 dholland while (j < ej) { 1359 1.1 dholland code = *j++; 1360 1.1 dholland if (code == TAG_PAD) 1361 1.1 dholland continue; 1362 1.1 dholland if (code == TAG_END) 1363 1.1 dholland return; 1364 1.1 dholland if (j >= ej || j + *j + 1 > ej) { 1365 1.1 dholland tctx->badopt = 1; 1366 1.1 dholland return; 1367 1.1 dholland } 1368 1.1 dholland len = *j++; 1369 1.1 dholland if (code == tag) { 1370 1.1 dholland if (tctx->taglen + len > TAG_MAXLEN) { 1371 1.1 dholland tctx->badtag = 1; 1372 1.1 dholland return; 1373 1.1 dholland } 1374 1.1 dholland tctx->foundopt = 1; 1375 1.1 dholland if (len > 0) 1376 1.1 dholland memcpy(tctx->buf + tctx->taglen, 1377 1.1 dholland j, len); 1378 1.1 dholland tctx->taglen += len; 1379 1.1 dholland } 1380 1.1 dholland if (code == TAG_OVERLOAD) 1381 1.1 dholland tctx->overload = *j; 1382 1.1 dholland 1383 1.1 dholland j += len; 1384 1.1 dholland } 1385 1.1 dholland } 1386 1.1 dholland 1387 1.1 dholland static unsigned char * 1388 1.1 dholland bootpc_tag(struct bootpc_tagcontext *tctx, 1389 1.1 dholland struct bootp_packet *bp, int len, int tag) 1390 1.1 dholland { 1391 1.1 dholland tctx->overload = 0; 1392 1.1 dholland tctx->badopt = 0; 1393 1.1 dholland tctx->badtag = 0; 1394 1.1 dholland tctx->foundopt = 0; 1395 1.1 dholland tctx->taglen = 0; 1396 1.1 dholland 1397 1.1 dholland if (bootpc_hascookie(bp) == 0) 1398 1.1 dholland return NULL; 1399 1.1 dholland 1400 1.1 dholland bootpc_tag_helper(tctx, &bp->vend[4], 1401 1.1 dholland (unsigned char *) bp + len - &bp->vend[4], tag); 1402 1.1 dholland 1403 1.1 dholland if ((tctx->overload & OVERLOAD_FILE) != 0) 1404 1.1 dholland bootpc_tag_helper(tctx, 1405 1.1 dholland (unsigned char *) bp->file, 1406 1.1 dholland sizeof(bp->file), 1407 1.1 dholland tag); 1408 1.1 dholland if ((tctx->overload & OVERLOAD_SNAME) != 0) 1409 1.1 dholland bootpc_tag_helper(tctx, 1410 1.1 dholland (unsigned char *) bp->sname, 1411 1.1 dholland sizeof(bp->sname), 1412 1.1 dholland tag); 1413 1.1 dholland 1414 1.1 dholland if (tctx->badopt != 0 || tctx->badtag != 0 || tctx->foundopt == 0) 1415 1.1 dholland return NULL; 1416 1.1 dholland tctx->buf[tctx->taglen] = '\0'; 1417 1.1 dholland return tctx->buf; 1418 1.1 dholland } 1419 1.1 dholland 1420 1.1 dholland static void 1421 1.1 dholland bootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx, 1422 1.1 dholland struct bootpc_globalcontext *gctx) 1423 1.1 dholland { 1424 1.1 dholland char *p, *s; 1425 1.1 dholland 1426 1.1 dholland ifctx->gotgw = 0; 1427 1.1 dholland ifctx->gotnetmask = 0; 1428 1.1 dholland 1429 1.1 dholland clear_sinaddr(&ifctx->myaddr); 1430 1.1 dholland clear_sinaddr(&ifctx->netmask); 1431 1.1 dholland clear_sinaddr(&ifctx->gw); 1432 1.1 dholland 1433 1.1 dholland ifctx->myaddr.sin_addr = ifctx->reply.yiaddr; 1434 1.1 dholland 1435 1.1 dholland printf("%s at ", ifctx->ireq.ifr_name); 1436 1.1 dholland print_sin_addr(&ifctx->myaddr); 1437 1.1 dholland printf(" server "); 1438 1.1 dholland print_in_addr(ifctx->reply.siaddr); 1439 1.1 dholland 1440 1.1 dholland ifctx->gw.sin_addr = ifctx->reply.giaddr; 1441 1.1 dholland if (ifctx->reply.giaddr.s_addr != htonl(INADDR_ANY)) { 1442 1.1 dholland printf(" via gateway "); 1443 1.1 dholland print_in_addr(ifctx->reply.giaddr); 1444 1.1 dholland } 1445 1.1 dholland 1446 1.1 dholland /* This call used for the side effect (overload flag) */ 1447 1.1 dholland (void) bootpc_tag(&gctx->tmptag, 1448 1.1 dholland &ifctx->reply, ifctx->replylen, TAG_END); 1449 1.1 dholland 1450 1.1 dholland if ((gctx->tmptag.overload & OVERLOAD_SNAME) == 0) 1451 1.1 dholland if (ifctx->reply.sname[0] != '\0') 1452 1.1 dholland printf(" server name %s", ifctx->reply.sname); 1453 1.1 dholland if ((gctx->tmptag.overload & OVERLOAD_FILE) == 0) 1454 1.1 dholland if (ifctx->reply.file[0] != '\0') 1455 1.1 dholland printf(" boot file %s", ifctx->reply.file); 1456 1.1 dholland 1457 1.1 dholland printf("\n"); 1458 1.1 dholland 1459 1.1 dholland p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 1460 1.1 dholland TAG_SUBNETMASK); 1461 1.1 dholland if (p != NULL) { 1462 1.1 dholland if (gctx->tag.taglen != 4) 1463 1.1 dholland panic("bootpc: subnet mask len is %d", 1464 1.1 dholland gctx->tag.taglen); 1465 1.1 dholland bcopy(p, &ifctx->netmask.sin_addr, 4); 1466 1.1 dholland ifctx->gotnetmask = 1; 1467 1.1 dholland printf("subnet mask "); 1468 1.1 dholland print_sin_addr(&ifctx->netmask); 1469 1.1 dholland printf(" "); 1470 1.1 dholland } 1471 1.1 dholland 1472 1.1 dholland p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 1473 1.1 dholland TAG_ROUTERS); 1474 1.1 dholland if (p != NULL) { 1475 1.1 dholland /* Routers */ 1476 1.1 dholland if (gctx->tag.taglen % 4) 1477 1.1 dholland panic("bootpc: Router Len is %d", gctx->tag.taglen); 1478 1.1 dholland if (gctx->tag.taglen > 0) { 1479 1.1 dholland bcopy(p, &ifctx->gw.sin_addr, 4); 1480 1.1 dholland printf("router "); 1481 1.1 dholland print_sin_addr(&ifctx->gw); 1482 1.1 dholland printf(" "); 1483 1.1 dholland ifctx->gotgw = 1; 1484 1.1 dholland gctx->gotgw = 1; 1485 1.1 dholland } 1486 1.1 dholland } 1487 1.1 dholland 1488 1.1 dholland /* 1489 1.1 dholland * Choose a root filesystem. If a value is forced in the environment 1490 1.1 dholland * and it contains "nfs:", use it unconditionally. Otherwise, if the 1491 1.1 dholland * kernel is compiled with the ROOTDEVNAME option, then use it if: 1492 1.1 dholland * - The server doesn't provide a pathname. 1493 1.1 dholland * - The boothowto flags include RB_DFLTROOT (user said to override 1494 1.1 dholland * the server value). 1495 1.1 dholland */ 1496 1.1 dholland p = NULL; 1497 1.2 pgoyette if ((s = kern_getenv("vfs.root.mountfrom")) != NULL) { 1498 1.1 dholland if ((p = strstr(s, "nfs:")) != NULL) 1499 1.1 dholland p = strdup(p + 4, M_TEMP); 1500 1.1 dholland freeenv(s); 1501 1.1 dholland } 1502 1.1 dholland if (p == NULL) { 1503 1.1 dholland p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 1504 1.1 dholland TAG_ROOT); 1505 1.2 pgoyette if (p != NULL) 1506 1.2 pgoyette ifctx->gotrootpath = 1; 1507 1.1 dholland } 1508 1.1 dholland #ifdef ROOTDEVNAME 1509 1.1 dholland if ((p == NULL || (boothowto & RB_DFLTROOT) != 0) && 1510 1.1 dholland (p = strstr(ROOTDEVNAME, "nfs:")) != NULL) { 1511 1.1 dholland p += 4; 1512 1.1 dholland } 1513 1.1 dholland #endif 1514 1.1 dholland if (p != NULL) { 1515 1.1 dholland if (gctx->setrootfs != NULL) { 1516 1.1 dholland printf("rootfs %s (ignored) ", p); 1517 1.3 pgoyette } else if (setmyfs(&nd->root_saddr, 1518 1.1 dholland nd->root_hostnam, p, &ifctx->reply.siaddr)) { 1519 1.1 dholland if (*p == '/') { 1520 1.1 dholland printf("root_server "); 1521 1.1 dholland print_sin_addr(&nd->root_saddr); 1522 1.1 dholland printf(" "); 1523 1.1 dholland } 1524 1.1 dholland printf("rootfs %s ", p); 1525 1.1 dholland gctx->gotrootpath = 1; 1526 1.1 dholland gctx->setrootfs = ifctx; 1527 1.1 dholland 1528 1.1 dholland p = bootpc_tag(&gctx->tag, &ifctx->reply, 1529 1.1 dholland ifctx->replylen, 1530 1.1 dholland TAG_ROOTOPTS); 1531 1.1 dholland if (p != NULL) { 1532 1.1 dholland mountopts(&nd->root_args, p); 1533 1.1 dholland printf("rootopts %s ", p); 1534 1.1 dholland } 1535 1.1 dholland } else 1536 1.1 dholland panic("Failed to set rootfs to %s", p); 1537 1.1 dholland } 1538 1.1 dholland 1539 1.1 dholland p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 1540 1.1 dholland TAG_HOSTNAME); 1541 1.1 dholland if (p != NULL) { 1542 1.1 dholland if (gctx->tag.taglen >= MAXHOSTNAMELEN) 1543 1.1 dholland panic("bootpc: hostname >= %d bytes", 1544 1.1 dholland MAXHOSTNAMELEN); 1545 1.1 dholland if (gctx->sethostname != NULL) { 1546 1.1 dholland printf("hostname %s (ignored) ", p); 1547 1.1 dholland } else { 1548 1.1 dholland strcpy(nd->my_hostnam, p); 1549 1.3 pgoyette mutex_enter(&prison0.pr_mtx); 1550 1.1 dholland strcpy(prison0.pr_hostname, p); 1551 1.3 pgoyette mutex_exit(&prison0.pr_mtx); 1552 1.1 dholland printf("hostname %s ", p); 1553 1.1 dholland gctx->sethostname = ifctx; 1554 1.1 dholland } 1555 1.1 dholland } 1556 1.1 dholland p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 1557 1.1 dholland TAG_COOKIE); 1558 1.1 dholland if (p != NULL) { /* store in a sysctl variable */ 1559 1.1 dholland int i, l = sizeof(bootp_cookie) - 1; 1560 1.1 dholland for (i = 0; i < l && p[i] != '\0'; i++) 1561 1.1 dholland bootp_cookie[i] = p[i]; 1562 1.1 dholland p[i] = '\0'; 1563 1.1 dholland } 1564 1.1 dholland 1565 1.2 pgoyette p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, 1566 1.2 pgoyette TAG_INTF_MTU); 1567 1.2 pgoyette if (p != NULL) { 1568 1.2 pgoyette ifctx->mtu = be16dec(p); 1569 1.2 pgoyette } 1570 1.1 dholland 1571 1.1 dholland printf("\n"); 1572 1.1 dholland 1573 1.1 dholland if (ifctx->gotnetmask == 0) { 1574 1.1 dholland if (IN_CLASSA(ntohl(ifctx->myaddr.sin_addr.s_addr))) 1575 1.1 dholland ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET); 1576 1.1 dholland else if (IN_CLASSB(ntohl(ifctx->myaddr.sin_addr.s_addr))) 1577 1.1 dholland ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET); 1578 1.1 dholland else 1579 1.1 dholland ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET); 1580 1.1 dholland } 1581 1.1 dholland } 1582 1.1 dholland 1583 1.1 dholland void 1584 1.1 dholland bootpc_init(void) 1585 1.1 dholland { 1586 1.1 dholland struct bootpc_ifcontext *ifctx; /* Interface BOOTP contexts */ 1587 1.1 dholland struct bootpc_globalcontext *gctx; /* Global BOOTP context */ 1588 1.1 dholland struct ifnet *ifp; 1589 1.1 dholland struct sockaddr_dl *sdl; 1590 1.1 dholland struct ifaddr *ifa; 1591 1.1 dholland int error; 1592 1.1 dholland #ifndef BOOTP_WIRED_TO 1593 1.1 dholland int ifcnt; 1594 1.1 dholland #endif 1595 1.1 dholland struct nfsv3_diskless *nd; 1596 1.3 pgoyette struct lwp *td; 1597 1.1 dholland int timeout; 1598 1.1 dholland int delay; 1599 1.1 dholland 1600 1.1 dholland timeout = BOOTP_IFACE_WAIT_TIMEOUT * hz; 1601 1.1 dholland delay = hz / 10; 1602 1.1 dholland 1603 1.1 dholland nd = &nfsv3_diskless; 1604 1.3 pgoyette td = curlwp; 1605 1.1 dholland 1606 1.1 dholland /* 1607 1.1 dholland * If already filled in, don't touch it here 1608 1.1 dholland */ 1609 1.1 dholland if (nfs_diskless_valid != 0) 1610 1.1 dholland return; 1611 1.1 dholland 1612 1.1 dholland gctx = malloc(sizeof(*gctx), M_TEMP, M_WAITOK | M_ZERO); 1613 1.1 dholland STAILQ_INIT(&gctx->interfaces); 1614 1.1 dholland gctx->xid = ~0xFFFF; 1615 1.1 dholland gctx->starttime = time_second; 1616 1.1 dholland 1617 1.1 dholland /* 1618 1.1 dholland * If ROOTDEVNAME is defined or vfs.root.mountfrom is set then we have 1619 1.1 dholland * root-path overrides that can potentially let us boot even if we don't 1620 1.1 dholland * get a root path from the server, so we can treat that as a non-error. 1621 1.1 dholland */ 1622 1.1 dholland #ifdef ROOTDEVNAME 1623 1.1 dholland gctx->any_root_overrides = 1; 1624 1.1 dholland #else 1625 1.1 dholland gctx->any_root_overrides = testenv("vfs.root.mountfrom"); 1626 1.1 dholland #endif 1627 1.1 dholland 1628 1.1 dholland /* 1629 1.1 dholland * Find a network interface. 1630 1.1 dholland */ 1631 1.1 dholland CURVNET_SET(TD_TO_VNET(td)); 1632 1.1 dholland #ifdef BOOTP_WIRED_TO 1633 1.1 dholland printf("%s: wired to interface '%s'\n", __func__, 1634 1.1 dholland __XSTRING(BOOTP_WIRED_TO)); 1635 1.1 dholland allocifctx(gctx); 1636 1.1 dholland #else 1637 1.1 dholland /* 1638 1.1 dholland * Preallocate interface context storage, if another interface 1639 1.1 dholland * attaches and wins the race, it won't be eligible for bootp. 1640 1.1 dholland */ 1641 1.1 dholland ifcnt = 0; 1642 1.1 dholland IFNET_RLOCK(); 1643 1.3 pgoyette TAILQ_FOREACH(ifp, &V_ifnet, if_list) { 1644 1.1 dholland if ((ifp->if_flags & 1645 1.1 dholland (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) != 1646 1.1 dholland IFF_BROADCAST) 1647 1.1 dholland continue; 1648 1.3 pgoyette switch (ifp->if_type) { 1649 1.1 dholland case IFT_ETHER: 1650 1.1 dholland case IFT_FDDI: 1651 1.1 dholland case IFT_ISO88025: 1652 1.1 dholland break; 1653 1.1 dholland default: 1654 1.1 dholland continue; 1655 1.1 dholland } 1656 1.1 dholland ifcnt++; 1657 1.1 dholland } 1658 1.1 dholland IFNET_RUNLOCK(); 1659 1.1 dholland if (ifcnt == 0) 1660 1.1 dholland panic("%s: no eligible interfaces", __func__); 1661 1.1 dholland for (; ifcnt > 0; ifcnt--) 1662 1.1 dholland allocifctx(gctx); 1663 1.1 dholland #endif 1664 1.1 dholland 1665 1.1 dholland retry: 1666 1.1 dholland ifctx = STAILQ_FIRST(&gctx->interfaces); 1667 1.1 dholland IFNET_RLOCK(); 1668 1.3 pgoyette TAILQ_FOREACH(ifp, &V_ifnet, if_list) { 1669 1.1 dholland if (ifctx == NULL) 1670 1.1 dholland break; 1671 1.1 dholland #ifdef BOOTP_WIRED_TO 1672 1.1 dholland if (strcmp(ifp->if_xname, __XSTRING(BOOTP_WIRED_TO)) != 0) 1673 1.1 dholland continue; 1674 1.1 dholland #else 1675 1.1 dholland if ((ifp->if_flags & 1676 1.1 dholland (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) != 1677 1.1 dholland IFF_BROADCAST) 1678 1.1 dholland continue; 1679 1.3 pgoyette switch (ifp->if_type) { 1680 1.1 dholland case IFT_ETHER: 1681 1.1 dholland case IFT_FDDI: 1682 1.1 dholland case IFT_ISO88025: 1683 1.1 dholland break; 1684 1.1 dholland default: 1685 1.1 dholland continue; 1686 1.1 dholland } 1687 1.1 dholland #endif 1688 1.1 dholland strlcpy(ifctx->ireq.ifr_name, ifp->if_xname, 1689 1.1 dholland sizeof(ifctx->ireq.ifr_name)); 1690 1.1 dholland ifctx->ifp = ifp; 1691 1.1 dholland 1692 1.1 dholland /* Get HW address */ 1693 1.1 dholland sdl = NULL; 1694 1.3 pgoyette TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 1695 1.1 dholland if (ifa->ifa_addr->sa_family == AF_LINK) { 1696 1.1 dholland sdl = (struct sockaddr_dl *)ifa->ifa_addr; 1697 1.1 dholland if (sdl->sdl_type == IFT_ETHER) 1698 1.1 dholland break; 1699 1.1 dholland } 1700 1.1 dholland if (sdl == NULL) 1701 1.1 dholland panic("bootpc: Unable to find HW address for %s", 1702 1.1 dholland ifctx->ireq.ifr_name); 1703 1.1 dholland ifctx->sdl = sdl; 1704 1.1 dholland 1705 1.1 dholland ifctx = STAILQ_NEXT(ifctx, next); 1706 1.1 dholland } 1707 1.1 dholland IFNET_RUNLOCK(); 1708 1.1 dholland CURVNET_RESTORE(); 1709 1.1 dholland 1710 1.1 dholland if (STAILQ_EMPTY(&gctx->interfaces) || 1711 1.1 dholland STAILQ_FIRST(&gctx->interfaces)->ifp == NULL) { 1712 1.1 dholland if (timeout > 0) { 1713 1.1 dholland pause("bootpc", delay); 1714 1.1 dholland timeout -= delay; 1715 1.1 dholland goto retry; 1716 1.1 dholland } 1717 1.1 dholland #ifdef BOOTP_WIRED_TO 1718 1.1 dholland panic("%s: Could not find interface specified " 1719 1.1 dholland "by BOOTP_WIRED_TO: " 1720 1.1 dholland __XSTRING(BOOTP_WIRED_TO), __func__); 1721 1.1 dholland #else 1722 1.1 dholland panic("%s: no suitable interface", __func__); 1723 1.1 dholland #endif 1724 1.1 dholland } 1725 1.1 dholland 1726 1.3 pgoyette error = socreate(AF_INET, &bootp_so, SOCK_DGRAM, 0, td, NULL); 1727 1.1 dholland if (error != 0) 1728 1.1 dholland panic("%s: socreate, error=%d", __func__, error); 1729 1.1 dholland 1730 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 1731 1.1 dholland bootpc_fakeup_interface(ifctx, td); 1732 1.1 dholland 1733 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 1734 1.1 dholland bootpc_compose_query(ifctx, td); 1735 1.1 dholland 1736 1.1 dholland error = bootpc_call(gctx, td); 1737 1.1 dholland if (error != 0) { 1738 1.1 dholland printf("BOOTP call failed\n"); 1739 1.1 dholland } 1740 1.1 dholland 1741 1.1 dholland mountopts(&nd->root_args, NULL); 1742 1.1 dholland 1743 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 1744 1.1 dholland if (bootpc_ifctx_isresolved(ifctx) != 0) 1745 1.1 dholland bootpc_decode_reply(nd, ifctx, gctx); 1746 1.1 dholland 1747 1.1 dholland #ifdef BOOTP_NFSROOT 1748 1.1 dholland if (gctx->gotrootpath == 0 && gctx->any_root_overrides == 0) 1749 1.1 dholland panic("bootpc: No root path offered"); 1750 1.1 dholland #endif 1751 1.1 dholland 1752 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 1753 1.1 dholland bootpc_adjust_interface(ifctx, gctx, td); 1754 1.1 dholland 1755 1.1 dholland soclose(bootp_so); 1756 1.1 dholland 1757 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 1758 1.1 dholland if (ifctx->gotrootpath != 0) 1759 1.1 dholland break; 1760 1.1 dholland if (ifctx == NULL) { 1761 1.1 dholland STAILQ_FOREACH(ifctx, &gctx->interfaces, next) 1762 1.1 dholland if (bootpc_ifctx_isresolved(ifctx) != 0) 1763 1.1 dholland break; 1764 1.1 dholland } 1765 1.1 dholland if (ifctx == NULL) 1766 1.1 dholland goto out; 1767 1.1 dholland 1768 1.1 dholland if (gctx->gotrootpath != 0) { 1769 1.1 dholland 1770 1.2 pgoyette kern_setenv("boot.netif.name", ifctx->ifp->if_xname); 1771 1.1 dholland 1772 1.2 pgoyette bootpc_add_default_route(ifctx); 1773 1.1 dholland error = md_mount(&nd->root_saddr, nd->root_hostnam, 1774 1.1 dholland nd->root_fh, &nd->root_fhsize, 1775 1.1 dholland &nd->root_args, td); 1776 1.2 pgoyette bootpc_remove_default_route(ifctx); 1777 1.1 dholland if (error != 0) { 1778 1.1 dholland if (gctx->any_root_overrides == 0) 1779 1.1 dholland panic("nfs_boot: mount root, error=%d", error); 1780 1.1 dholland else 1781 1.1 dholland goto out; 1782 1.1 dholland } 1783 1.1 dholland rootdevnames[0] = "nfs:"; 1784 1.1 dholland nfs_diskless_valid = 3; 1785 1.1 dholland } 1786 1.1 dholland 1787 1.1 dholland strcpy(nd->myif.ifra_name, ifctx->ireq.ifr_name); 1788 1.1 dholland bcopy(&ifctx->myaddr, &nd->myif.ifra_addr, sizeof(ifctx->myaddr)); 1789 1.1 dholland bcopy(&ifctx->myaddr, &nd->myif.ifra_broadaddr, sizeof(ifctx->myaddr)); 1790 1.1 dholland ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr = 1791 1.1 dholland ifctx->myaddr.sin_addr.s_addr | 1792 1.1 dholland ~ ifctx->netmask.sin_addr.s_addr; 1793 1.1 dholland bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask)); 1794 1.2 pgoyette bcopy(&ifctx->gw, &nd->mygateway, sizeof(ifctx->gw)); 1795 1.1 dholland 1796 1.1 dholland out: 1797 1.1 dholland while((ifctx = STAILQ_FIRST(&gctx->interfaces)) != NULL) { 1798 1.1 dholland STAILQ_REMOVE_HEAD(&gctx->interfaces, next); 1799 1.1 dholland free(ifctx, M_TEMP); 1800 1.1 dholland } 1801 1.1 dholland free(gctx, M_TEMP); 1802 1.1 dholland } 1803 1.1 dholland 1804 1.1 dholland /* 1805 1.1 dholland * RPC: mountd/mount 1806 1.1 dholland * Given a server pathname, get an NFS file handle. 1807 1.1 dholland * Also, sets sin->sin_port to the NFS service port. 1808 1.1 dholland */ 1809 1.1 dholland static int 1810 1.1 dholland md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp, int *fhsizep, 1811 1.3 pgoyette struct nfs_args *args, struct lwp *td) 1812 1.1 dholland { 1813 1.1 dholland struct mbuf *m; 1814 1.1 dholland int error; 1815 1.1 dholland int authunixok; 1816 1.1 dholland int authcount; 1817 1.1 dholland int authver; 1818 1.1 dholland 1819 1.1 dholland #define RPCPROG_MNT 100005 1820 1.1 dholland #define RPCMNT_VER1 1 1821 1.1 dholland #define RPCMNT_VER3 3 1822 1.1 dholland #define RPCMNT_MOUNT 1 1823 1.1 dholland #define AUTH_SYS 1 /* unix style (uid, gids) */ 1824 1.1 dholland #define AUTH_UNIX AUTH_SYS 1825 1.1 dholland 1826 1.1 dholland /* XXX honor v2/v3 flags in args->flags? */ 1827 1.1 dholland #ifdef BOOTP_NFSV3 1828 1.1 dholland /* First try NFS v3 */ 1829 1.1 dholland /* Get port number for MOUNTD. */ 1830 1.1 dholland error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3, 1831 1.1 dholland &mdsin->sin_port, td); 1832 1.1 dholland if (error == 0) { 1833 1.1 dholland m = xdr_string_encode(path, strlen(path)); 1834 1.1 dholland 1835 1.1 dholland /* Do RPC to mountd. */ 1836 1.1 dholland error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3, 1837 1.1 dholland RPCMNT_MOUNT, &m, NULL, td); 1838 1.1 dholland } 1839 1.1 dholland if (error == 0) { 1840 1.1 dholland args->flags |= NFSMNT_NFSV3; 1841 1.1 dholland } else { 1842 1.1 dholland #endif 1843 1.1 dholland /* Fallback to NFS v2 */ 1844 1.1 dholland 1845 1.1 dholland /* Get port number for MOUNTD. */ 1846 1.1 dholland error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, 1847 1.1 dholland &mdsin->sin_port, td); 1848 1.1 dholland if (error != 0) 1849 1.1 dholland return error; 1850 1.1 dholland 1851 1.1 dholland m = xdr_string_encode(path, strlen(path)); 1852 1.1 dholland 1853 1.1 dholland /* Do RPC to mountd. */ 1854 1.1 dholland error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, 1855 1.1 dholland RPCMNT_MOUNT, &m, NULL, td); 1856 1.1 dholland if (error != 0) 1857 1.1 dholland return error; /* message already freed */ 1858 1.1 dholland 1859 1.1 dholland #ifdef BOOTP_NFSV3 1860 1.1 dholland } 1861 1.1 dholland #endif 1862 1.1 dholland 1863 1.1 dholland if (xdr_int_decode(&m, &error) != 0 || error != 0) 1864 1.1 dholland goto bad; 1865 1.1 dholland 1866 1.1 dholland if ((args->flags & NFSMNT_NFSV3) != 0) { 1867 1.1 dholland if (xdr_int_decode(&m, fhsizep) != 0 || 1868 1.1 dholland *fhsizep > NFSX_V3FHMAX || 1869 1.1 dholland *fhsizep <= 0) 1870 1.1 dholland goto bad; 1871 1.1 dholland } else 1872 1.1 dholland *fhsizep = NFSX_V2FH; 1873 1.1 dholland 1874 1.1 dholland if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0) 1875 1.1 dholland goto bad; 1876 1.1 dholland 1877 1.1 dholland if (args->flags & NFSMNT_NFSV3) { 1878 1.1 dholland if (xdr_int_decode(&m, &authcount) != 0) 1879 1.1 dholland goto bad; 1880 1.1 dholland authunixok = 0; 1881 1.1 dholland if (authcount < 0 || authcount > 100) 1882 1.1 dholland goto bad; 1883 1.1 dholland while (authcount > 0) { 1884 1.1 dholland if (xdr_int_decode(&m, &authver) != 0) 1885 1.1 dholland goto bad; 1886 1.1 dholland if (authver == AUTH_UNIX) 1887 1.1 dholland authunixok = 1; 1888 1.1 dholland authcount--; 1889 1.1 dholland } 1890 1.1 dholland if (authunixok == 0) 1891 1.1 dholland goto bad; 1892 1.1 dholland } 1893 1.1 dholland 1894 1.1 dholland /* Set port number for NFS use. */ 1895 1.1 dholland error = krpc_portmap(mdsin, NFS_PROG, 1896 1.1 dholland (args->flags & 1897 1.1 dholland NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2, 1898 1.1 dholland &mdsin->sin_port, td); 1899 1.1 dholland 1900 1.1 dholland goto out; 1901 1.1 dholland 1902 1.1 dholland bad: 1903 1.1 dholland error = EBADRPC; 1904 1.1 dholland 1905 1.1 dholland out: 1906 1.1 dholland m_freem(m); 1907 1.1 dholland return error; 1908 1.1 dholland } 1909 1.1 dholland 1910 1.3 pgoyette #if 0 /* Need to call bootpc_init from module initialization routine */ 1911 1.1 dholland SYSINIT(bootp_rootconf, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, bootpc_init, NULL); 1912 1.3 pgoyette #endif 1913