Merge remote-tracking branch 'origin/vendor/BINUTILS227'
[dragonfly.git] / sys / vfs / nfs / nfs_mountrpc.c
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