1 /* 2 * Copyright (c) 1995 Gordon Ross, Adam Glass 3 * Copyright (c) 1992 Regents of the University of California. 4 * All rights reserved. 5 * 6 * This software was developed by the Computer Systems Engineering group 7 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 8 * contributed to Berkeley. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Lawrence Berkeley Laboratory and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * nfs/krpc_subr.c 39 * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $ 40 * $FreeBSD: src/sys/nfs/bootp_subr.c,v 1.20.2.9 2003/04/24 16:51:08 ambrisko Exp $ 41 */ 42 /* 43 * Procedures used by NFS_ROOT and BOOTP to do an NFS mount rpc to obtain 44 * the nfs root file handle for a NFS-based root mount point. This module 45 * is not used by normal operating code because the 'mount' command has a 46 * far more sophisticated implementation. 47 */ 48 #include "opt_bootp.h" 49 #include "opt_nfsroot.h" 50 51 #if defined(BOOTP) || defined(NFS_ROOT) 52 53 #include <sys/param.h> 54 #include <sys/systm.h> 55 #include <sys/kernel.h> 56 #include <sys/sockio.h> 57 #include <sys/proc.h> 58 #include <sys/malloc.h> 59 #include <sys/mount.h> 60 #include <sys/mbuf.h> 61 #include <sys/socket.h> 62 #include <sys/socketvar.h> 63 #include <sys/sysctl.h> 64 #include <sys/uio.h> 65 66 #include <net/if.h> 67 #include <net/route.h> 68 69 #include <netinet/in.h> 70 #include <net/if_types.h> 71 #include <net/if_dl.h> 72 73 #include "rpcv2.h" 74 #include "nfsproto.h" 75 #include "nfs.h" 76 #include "nfsdiskless.h" 77 #include "krpc.h" 78 #include "xdr_subs.h" 79 #include "nfsmountrpc.h" 80 81 /* 82 * What is the longest we will wait before re-sending a request? 83 * Note this is also the frequency of "RPC timeout" messages. 84 * The re-send loop count sup linearly to this maximum, so the 85 * first complaint will happen after (1+2+3+4+5)=15 seconds. 86 */ 87 88 static int getdec(char **ptr); 89 static char *substr(char *a,char *b); 90 static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len); 91 static int xdr_int_decode(struct mbuf **ptr, int *iptr); 92 93 void 94 nfs_mountopts(struct nfs_args *args, char *p) 95 { 96 char *tmp; 97 98 args->version = NFS_ARGSVERSION; 99 args->rsize = 8192; 100 args->wsize = 8192; 101 args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT; 102 args->sotype = SOCK_STREAM; 103 if (p == NULL) 104 return; 105 if ((tmp = substr(p, "rsize="))) 106 args->rsize = getdec(&tmp); 107 if ((tmp = substr(p, "wsize="))) 108 args->wsize = getdec(&tmp); 109 if ((tmp = substr(p, "intr"))) 110 args->flags |= NFSMNT_INT; 111 if ((tmp = substr(p, "soft"))) 112 args->flags |= NFSMNT_SOFT; 113 if ((tmp = substr(p, "noconn"))) 114 args->flags |= NFSMNT_NOCONN; 115 if ((tmp = substr(p, "udp"))) 116 args->sotype = SOCK_DGRAM; 117 } 118 119 /* 120 * RPC: mountd/mount 121 * Given a server pathname, get an NFS file handle. 122 * Also, sets sin->sin_port to the NFS service port. 123 */ 124 int 125 md_mount(struct sockaddr_in *mdsin, /* mountd server address */ 126 char *path, 127 u_char *fhp, 128 int *fhsizep, 129 struct nfs_args *args, 130 struct thread *td) 131 { 132 struct mbuf *m; 133 int error; 134 int authunixok; 135 int authcount; 136 int authver; 137 138 /* First try NFS v3 */ 139 /* Get port number for MOUNTD. */ 140 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3, 141 &mdsin->sin_port, td); 142 if (error == 0) { 143 m = xdr_string_encode(path, strlen(path)); 144 145 /* Do RPC to mountd. */ 146 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3, 147 RPCMNT_MOUNT, &m, NULL, td); 148 } 149 if (error == 0) { 150 args->flags |= NFSMNT_NFSV3; 151 } else { 152 /* Fallback to NFS v2 */ 153 154 /* Get port number for MOUNTD. */ 155 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, 156 &mdsin->sin_port, td); 157 if (error != 0) 158 return error; 159 160 m = xdr_string_encode(path, strlen(path)); 161 162 /* Do RPC to mountd. */ 163 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, 164 RPCMNT_MOUNT, &m, NULL, td); 165 if (error != 0) 166 return error; /* message already freed */ 167 args->flags &= ~NFSMNT_NFSV3; 168 } 169 170 if (xdr_int_decode(&m, &error) != 0 || error != 0) 171 goto bad; 172 173 if ((args->flags & NFSMNT_NFSV3) != 0) { 174 if (xdr_int_decode(&m, fhsizep) != 0 || 175 *fhsizep > NFSX_V3FHMAX || 176 *fhsizep <= 0) 177 goto bad; 178 } else 179 *fhsizep = NFSX_V2FH; 180 181 if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0) 182 goto bad; 183 184 if (args->flags & NFSMNT_NFSV3) { 185 if (xdr_int_decode(&m, &authcount) != 0) 186 goto bad; 187 authunixok = 0; 188 if (authcount < 0 || authcount > 100) 189 goto bad; 190 while (authcount > 0) { 191 if (xdr_int_decode(&m, &authver) != 0) 192 goto bad; 193 if (authver == RPCAUTH_UNIX) 194 authunixok = 1; 195 authcount--; 196 } 197 if (authunixok == 0) 198 goto bad; 199 } 200 201 /* Set port number for NFS use. */ 202 error = krpc_portmap(mdsin, NFS_PROG, 203 (args->flags & 204 NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2, 205 &mdsin->sin_port, td); 206 207 goto out; 208 209 bad: 210 error = EBADRPC; 211 212 out: 213 m_freem(m); 214 return error; 215 } 216 217 int 218 md_lookup_swap(struct sockaddr_in *mdsin, /* mountd server address */ 219 char *path, 220 u_char *fhp, 221 int *fhsizep, 222 struct nfs_args *args, 223 struct thread *td) 224 { 225 struct mbuf *m; 226 int error; 227 int size = -1; 228 int attribs_present; 229 int status; 230 union { 231 u_int32_t v2[17]; 232 u_int32_t v3[21]; 233 } fattribs; 234 235 m = m_get(M_WAITOK,MT_DATA); 236 if (m == NULL) 237 return ENOBUFS; 238 239 if ((args->flags & NFSMNT_NFSV3) != 0) { 240 *mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep); 241 bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep); 242 m->m_len = *fhsizep + sizeof(u_int32_t); 243 } else { 244 bcopy(fhp, mtod(m, u_char *), NFSX_V2FH); 245 m->m_len = NFSX_V2FH; 246 } 247 248 m->m_next = xdr_string_encode(path, strlen(path)); 249 if (m->m_next == NULL) { 250 error = ENOBUFS; 251 goto out; 252 } 253 254 /* Do RPC to nfsd. */ 255 if ((args->flags & NFSMNT_NFSV3) != 0) 256 error = krpc_call(mdsin, NFS_PROG, NFS_VER3, 257 NFSPROC_LOOKUP, &m, NULL, td); 258 else 259 error = krpc_call(mdsin, NFS_PROG, NFS_VER2, 260 NFSV2PROC_LOOKUP, &m, NULL, td); 261 if (error != 0) 262 return error; /* message already freed */ 263 264 if (xdr_int_decode(&m, &status) != 0) 265 goto bad; 266 if (status != 0) { 267 error = ENOENT; 268 goto out; 269 } 270 271 if ((args->flags & NFSMNT_NFSV3) != 0) { 272 if (xdr_int_decode(&m, fhsizep) != 0 || 273 *fhsizep > NFSX_V3FHMAX || 274 *fhsizep <= 0) 275 goto bad; 276 } else 277 *fhsizep = NFSX_V2FH; 278 279 if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0) 280 goto bad; 281 282 if ((args->flags & NFSMNT_NFSV3) != 0) { 283 if (xdr_int_decode(&m, &attribs_present) != 0) 284 goto bad; 285 if (attribs_present != 0) { 286 if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3, 287 sizeof(u_int32_t) * 21) != 0) 288 goto bad; 289 size = fxdr_unsigned(u_int32_t, fattribs.v3[6]); 290 } 291 } else { 292 if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2, 293 sizeof(u_int32_t) * 17) != 0) 294 goto bad; 295 size = fxdr_unsigned(u_int32_t, fattribs.v2[5]); 296 } 297 298 if (nfsv3_diskless.swap_nblks == 0 && size != -1) { 299 nfsv3_diskless.swap_nblks = size / 1024; 300 kprintf("md_lookup_swap: Swap size is %d KB\n", 301 nfsv3_diskless.swap_nblks); 302 } 303 304 goto out; 305 306 bad: 307 error = EBADRPC; 308 309 out: 310 m_freem(m); 311 return error; 312 } 313 314 int 315 setfs(struct sockaddr_in *addr, char *path, char *p) 316 { 317 unsigned int ip; 318 int val; 319 320 ip = 0; 321 if (((val = getdec(&p)) < 0) || (val > 255)) 322 return 0; 323 ip = val << 24; 324 if (*p != '.') 325 return 0; 326 p++; 327 if (((val = getdec(&p)) < 0) || (val > 255)) 328 return 0; 329 ip |= (val << 16); 330 if (*p != '.') 331 return 0; 332 p++; 333 if (((val = getdec(&p)) < 0) || (val > 255)) 334 return 0; 335 ip |= (val << 8); 336 if (*p != '.') 337 return 0; 338 p++; 339 if (((val = getdec(&p)) < 0) || (val > 255)) 340 return 0; 341 ip |= val; 342 if (*p != ':') 343 return 0; 344 p++; 345 346 addr->sin_addr.s_addr = htonl(ip); 347 addr->sin_len = sizeof(struct sockaddr_in); 348 addr->sin_family = AF_INET; 349 350 strncpy(path, p, MNAMELEN - 1); 351 return 1; 352 } 353 354 static int 355 getdec(char **ptr) 356 { 357 char *p; 358 int ret; 359 360 p = *ptr; 361 ret = 0; 362 if ((*p < '0') || (*p > '9')) 363 return -1; 364 while ((*p >= '0') && (*p <= '9')) { 365 ret = ret * 10 + (*p - '0'); 366 p++; 367 } 368 *ptr = p; 369 return ret; 370 } 371 372 static char * 373 substr(char *a, char *b) 374 { 375 char *loc1; 376 char *loc2; 377 378 while (*a != '\0') { 379 loc1 = a; 380 loc2 = b; 381 while (*loc1 == *loc2++) { 382 if (*loc1 == '\0') 383 return 0; 384 loc1++; 385 if (*loc2 == '\0') 386 return loc1; 387 } 388 a++; 389 } 390 return 0; 391 } 392 393 static int 394 xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len) 395 { 396 struct mbuf *m; 397 int alignedlen; 398 399 m = *mptr; 400 alignedlen = ( len + 3 ) & ~3; 401 402 if (m->m_len < alignedlen) { 403 m = m_pullup(m, alignedlen); 404 if (m == NULL) { 405 *mptr = NULL; 406 return EBADRPC; 407 } 408 } 409 bcopy(mtod(m, u_char *), buf, len); 410 m_adj(m, alignedlen); 411 *mptr = m; 412 return 0; 413 } 414 415 static int 416 xdr_int_decode(struct mbuf **mptr, int *iptr) 417 { 418 u_int32_t i; 419 if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0) 420 return EBADRPC; 421 *iptr = fxdr_unsigned(u_int32_t, i); 422 return 0; 423 } 424 425 #endif /* BOOTP && NFS_ROOT */ 426 427