Rename printf -> kprintf in sys/ and add some defines where necessary
[dragonfly.git] / sys / vfs / nfs / nfs_mountrpc.c
CommitLineData
0e8ff41a
MD
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 $
086c1d7e 41 * $DragonFly: src/sys/vfs/nfs/nfs_mountrpc.c,v 1.2 2006/12/23 00:41:29 swildner Exp $
0e8ff41a
MD
42 */
43/*
44 * Procedures used by NFS_ROOT and BOOTP to do an NFS mount rpc to obtain
45 * the nfs root file handle for a NFS-based root mount point. This module
46 * is not used by normal operating code because the 'mount' command has a
47 * far more sophisticated implementation.
48 */
49#include "opt_bootp.h"
50#include "opt_nfsroot.h"
51
52#if defined(BOOTP) || defined(NFS_ROOT)
53
54#include <sys/param.h>
55#include <sys/systm.h>
56#include <sys/kernel.h>
57#include <sys/sockio.h>
58#include <sys/proc.h>
59#include <sys/malloc.h>
60#include <sys/mount.h>
61#include <sys/mbuf.h>
62#include <sys/socket.h>
63#include <sys/socketvar.h>
64#include <sys/sysctl.h>
65#include <sys/uio.h>
66
67#include <net/if.h>
68#include <net/route.h>
69
70#include <netinet/in.h>
71#include <net/if_types.h>
72#include <net/if_dl.h>
73
74#include "rpcv2.h"
75#include "nfsproto.h"
76#include "nfs.h"
77#include "nfsdiskless.h"
78#include "krpc.h"
79#include "xdr_subs.h"
80#include "nfsmountrpc.h"
81
82/*
83 * What is the longest we will wait before re-sending a request?
84 * Note this is also the frequency of "RPC timeout" messages.
85 * The re-send loop count sup linearly to this maximum, so the
86 * first complaint will happen after (1+2+3+4+5)=15 seconds.
87 */
88
89extern struct nfsv3_diskless nfsv3_diskless;
90
91static int getdec(char **ptr);
92static char *substr(char *a,char *b);
93static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len);
94static int xdr_int_decode(struct mbuf **ptr, int *iptr);
95
96void
97mountopts(struct nfs_args *args, char *p)
98{
99 char *tmp;
100
101 args->version = NFS_ARGSVERSION;
102 args->rsize = 8192;
103 args->wsize = 8192;
104 args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
105 args->sotype = SOCK_DGRAM;
106 if (p == NULL)
107 return;
108 if ((tmp = (char *)substr(p, "rsize=")))
109 args->rsize = getdec(&tmp);
110 if ((tmp = (char *)substr(p, "wsize=")))
111 args->wsize = getdec(&tmp);
112 if ((tmp = (char *)substr(p, "intr")))
113 args->flags |= NFSMNT_INT;
114 if ((tmp = (char *)substr(p, "soft")))
115 args->flags |= NFSMNT_SOFT;
116 if ((tmp = (char *)substr(p, "noconn")))
117 args->flags |= NFSMNT_NOCONN;
118 if ((tmp = (char *)substr(p, "tcp")))
119 args->sotype = SOCK_STREAM;
120}
121
122/*
123 * RPC: mountd/mount
124 * Given a server pathname, get an NFS file handle.
125 * Also, sets sin->sin_port to the NFS service port.
126 */
127int
128md_mount(struct sockaddr_in *mdsin, /* mountd server address */
129 char *path,
130 u_char *fhp,
131 int *fhsizep,
132 struct nfs_args *args,
133 struct thread *td)
134{
135 struct mbuf *m;
136 int error;
137 int authunixok;
138 int authcount;
139 int authver;
140
141#ifdef BOOTP_NFSV3
142 /* First try NFS v3 */
143 /* Get port number for MOUNTD. */
144 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
145 &mdsin->sin_port, td);
146 if (error == 0) {
147 m = xdr_string_encode(path, strlen(path));
148
149 /* Do RPC to mountd. */
150 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
151 RPCMNT_MOUNT, &m, NULL, td);
152 }
153 if (error == 0) {
154 args->flags |= NFSMNT_NFSV3;
155 } else {
156#endif
157 /* Fallback to NFS v2 */
158
159 /* Get port number for MOUNTD. */
160 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
161 &mdsin->sin_port, td);
162 if (error != 0)
163 return error;
164
165 m = xdr_string_encode(path, strlen(path));
166
167 /* Do RPC to mountd. */
168 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
169 RPCMNT_MOUNT, &m, NULL, td);
170 if (error != 0)
171 return error; /* message already freed */
172
173#ifdef BOOTP_NFSV3
174 }
175#endif
176
177 if (xdr_int_decode(&m, &error) != 0 || error != 0)
178 goto bad;
179
180 if ((args->flags & NFSMNT_NFSV3) != 0) {
181 if (xdr_int_decode(&m, fhsizep) != 0 ||
182 *fhsizep > NFSX_V3FHMAX ||
183 *fhsizep <= 0)
184 goto bad;
185 } else
186 *fhsizep = NFSX_V2FH;
187
188 if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
189 goto bad;
190
191 if (args->flags & NFSMNT_NFSV3) {
192 if (xdr_int_decode(&m, &authcount) != 0)
193 goto bad;
194 authunixok = 0;
195 if (authcount < 0 || authcount > 100)
196 goto bad;
197 while (authcount > 0) {
198 if (xdr_int_decode(&m, &authver) != 0)
199 goto bad;
200 if (authver == RPCAUTH_UNIX)
201 authunixok = 1;
202 authcount--;
203 }
204 if (authunixok == 0)
205 goto bad;
206 }
207
208 /* Set port number for NFS use. */
209 error = krpc_portmap(mdsin, NFS_PROG,
210 (args->flags &
211 NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
212 &mdsin->sin_port, td);
213
214 goto out;
215
216bad:
217 error = EBADRPC;
218
219out:
220 m_freem(m);
221 return error;
222}
223
224int
225md_lookup_swap(struct sockaddr_in *mdsin, /* mountd server address */
226 char *path,
227 u_char *fhp,
228 int *fhsizep,
229 struct nfs_args *args,
230 struct thread *td)
231{
232 struct mbuf *m;
233 int error;
234 int size = -1;
235 int attribs_present;
236 int status;
237 union {
238 u_int32_t v2[17];
239 u_int32_t v3[21];
240 } fattribs;
241
242 m = m_get(MB_WAIT,MT_DATA);
243 if (m == NULL)
244 return ENOBUFS;
245
246 if ((args->flags & NFSMNT_NFSV3) != 0) {
247 *mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep);
248 bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep);
249 m->m_len = *fhsizep + sizeof(u_int32_t);
250 } else {
251 bcopy(fhp, mtod(m, u_char *), NFSX_V2FH);
252 m->m_len = NFSX_V2FH;
253 }
254
255 m->m_next = xdr_string_encode(path, strlen(path));
256 if (m->m_next == NULL) {
257 error = ENOBUFS;
258 goto out;
259 }
260
261 /* Do RPC to nfsd. */
262 if ((args->flags & NFSMNT_NFSV3) != 0)
263 error = krpc_call(mdsin, NFS_PROG, NFS_VER3,
264 NFSPROC_LOOKUP, &m, NULL, td);
265 else
266 error = krpc_call(mdsin, NFS_PROG, NFS_VER2,
267 NFSV2PROC_LOOKUP, &m, NULL, td);
268 if (error != 0)
269 return error; /* message already freed */
270
271 if (xdr_int_decode(&m, &status) != 0)
272 goto bad;
273 if (status != 0) {
274 error = ENOENT;
275 goto out;
276 }
277
278 if ((args->flags & NFSMNT_NFSV3) != 0) {
279 if (xdr_int_decode(&m, fhsizep) != 0 ||
280 *fhsizep > NFSX_V3FHMAX ||
281 *fhsizep <= 0)
282 goto bad;
283 } else
284 *fhsizep = NFSX_V2FH;
285
286 if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
287 goto bad;
288
289 if ((args->flags & NFSMNT_NFSV3) != 0) {
290 if (xdr_int_decode(&m, &attribs_present) != 0)
291 goto bad;
292 if (attribs_present != 0) {
293 if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3,
294 sizeof(u_int32_t) * 21) != 0)
295 goto bad;
296 size = fxdr_unsigned(u_int32_t, fattribs.v3[6]);
297 }
298 } else {
299 if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2,
300 sizeof(u_int32_t) * 17) != 0)
301 goto bad;
302 size = fxdr_unsigned(u_int32_t, fattribs.v2[5]);
303 }
304
305 if (nfsv3_diskless.swap_nblks == 0 && size != -1) {
306 nfsv3_diskless.swap_nblks = size / 1024;
086c1d7e 307 kprintf("md_lookup_swap: Swap size is %d KB\n",
0e8ff41a
MD
308 nfsv3_diskless.swap_nblks);
309 }
310
311 goto out;
312
313bad:
314 error = EBADRPC;
315
316out:
317 m_freem(m);
318 return error;
319}
320
321int
322setfs(struct sockaddr_in *addr, char *path, char *p)
323{
324 unsigned int ip;
325 int val;
326
327 ip = 0;
328 if (((val = getdec(&p)) < 0) || (val > 255))
329 return 0;
330 ip = val << 24;
331 if (*p != '.')
332 return 0;
333 p++;
334 if (((val = getdec(&p)) < 0) || (val > 255))
335 return 0;
336 ip |= (val << 16);
337 if (*p != '.')
338 return 0;
339 p++;
340 if (((val = getdec(&p)) < 0) || (val > 255))
341 return 0;
342 ip |= (val << 8);
343 if (*p != '.')
344 return 0;
345 p++;
346 if (((val = getdec(&p)) < 0) || (val > 255))
347 return 0;
348 ip |= val;
349 if (*p != ':')
350 return 0;
351 p++;
352
353 addr->sin_addr.s_addr = htonl(ip);
354 addr->sin_len = sizeof(struct sockaddr_in);
355 addr->sin_family = AF_INET;
356
357 strncpy(path, p, MNAMELEN - 1);
358 return 1;
359}
360
361static int
362getdec(char **ptr)
363{
364 char *p;
365 int ret;
366
367 p = *ptr;
368 ret = 0;
369 if ((*p < '0') || (*p > '9'))
370 return -1;
371 while ((*p >= '0') && (*p <= '9')) {
372 ret = ret * 10 + (*p - '0');
373 p++;
374 }
375 *ptr = p;
376 return ret;
377}
378
379static char *
380substr(char *a, char *b)
381{
382 char *loc1;
383 char *loc2;
384
385 while (*a != '\0') {
386 loc1 = a;
387 loc2 = b;
388 while (*loc1 == *loc2++) {
389 if (*loc1 == '\0')
390 return 0;
391 loc1++;
392 if (*loc2 == '\0')
393 return loc1;
394 }
395 a++;
396 }
397 return 0;
398}
399
400static int
401xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len)
402{
403 struct mbuf *m;
404 int alignedlen;
405
406 m = *mptr;
407 alignedlen = ( len + 3 ) & ~3;
408
409 if (m->m_len < alignedlen) {
410 m = m_pullup(m, alignedlen);
411 if (m == NULL) {
412 *mptr = NULL;
413 return EBADRPC;
414 }
415 }
416 bcopy(mtod(m, u_char *), buf, len);
417 m_adj(m, alignedlen);
418 *mptr = m;
419 return 0;
420}
421
422static int
423xdr_int_decode(struct mbuf **mptr, int *iptr)
424{
425 u_int32_t i;
426 if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0)
427 return EBADRPC;
428 *iptr = fxdr_unsigned(u_int32_t, i);
429 return 0;
430}
431
432#endif /* BOOTP && NFS_ROOT */
433