xref: /xnu-10002.41.9/bsd/nfs/xdr_subs.h (revision 699cd48037512bf4380799317ca44ca453c82f57)
1 /*
2  * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29 /*
30  * Copyright (c) 1989, 1993
31  *     The Regents of the University of California.  All rights reserved.
32  *
33  * This code is derived from software contributed to Berkeley by
34  * Rick Macklem at The University of Guelph.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *     This product includes software developed by the University of
47  *     California, Berkeley and its contributors.
48  * 4. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  *
64  *     @(#)xdr_subs.h  8.3 (Berkeley) 3/30/95
65  * FreeBSD-Id: xdr_subs.h,v 1.9 1997/02/22 09:42:53 peter Exp $
66  */
67 
68 #ifndef _NFS_XDR_SUBS_H_
69 #define _NFS_XDR_SUBS_H_
70 
71 #include <sys/appleapiopts.h>
72 
73 #ifdef __APPLE_API_PRIVATE
74 /*
75  * Macros used for conversion to/from xdr representation by nfs...
76  * These use the MACHINE DEPENDENT routines ntohl, htonl
77  * As defined by "XDR: External Data Representation Standard" RFC1014
78  *
79  * To simplify the implementation, we use ntohl/htonl even on big-endian
80  * machines, and count on them being `#define'd away.  Some of these
81  * might be slightly more efficient as quad_t copies on a big-endian,
82  * but we cannot count on their alignment anyway.
83  */
84 
85 #define fxdr_unsigned(t, v)     ((t)ntohl((uint32_t)(v)))
86 #define txdr_unsigned(v)        (htonl((uint32_t)(v)))
87 
88 #define fxdr_hyper(f, t) { \
89 	((uint32_t *)(t))[_QUAD_HIGHWORD] = ntohl(((uint32_t *)(f))[0]); \
90 	((uint32_t *)(t))[_QUAD_LOWWORD] = ntohl(((uint32_t *)(f))[1]); \
91 }
92 #define txdr_hyper(f, t) { \
93 	((uint32_t *)(t))[0] = htonl(((uint32_t *)(f))[_QUAD_HIGHWORD]); \
94 	((uint32_t *)(t))[1] = htonl(((uint32_t *)(f))[_QUAD_LOWWORD]); \
95 }
96 
97 
98 /*
99  * xdrbuf
100  *
101  * generalized functionality for managing the building/dissecting of XDR data
102  */
103 typedef enum xdrbuf_type {
104 	XDRBUF_NONE   = 0,
105 	XDRBUF_BUFFER = 1,
106 } xdrbuf_type;
107 
108 struct xdrbuf {
109 	union {
110 		struct {
111 			char *                  xbb_base;       /* base address of buffer */
112 			size_t                  xbb_size;       /* size of buffer */
113 			size_t                  xbb_len;        /* length of data in buffer */
114 		} xb_buffer;
115 	} xb_u;
116 	char *          xb_ptr;         /* pointer to current position */
117 	size_t          xb_left;        /* bytes remaining in current buffer */
118 	size_t          xb_growsize;    /* bytes to allocate when growing */
119 	xdrbuf_type     xb_type;        /* type of xdr buffer */
120 	uint32_t        xb_flags;       /* XB_* (see below) */
121 };
122 
123 #define XB_CLEANUP      0x0001  /* needs cleanup */
124 
125 #define XDRWORD         4       /* the basic XDR building block is a 4 byte (32 bit) word */
126 #define xdr_rndup(a)    (((a)+3)&(~0x3))        /* round up to XDRWORD size */
127 #define xdr_pad(a)      (xdr_rndup(a) - (a))    /* calculate round up padding */
128 
129 void xb_init(struct xdrbuf *, xdrbuf_type);
130 void xb_init_buffer(struct xdrbuf *, char *, size_t);
131 void xb_cleanup(struct xdrbuf *);
132 void *xb_malloc(size_t) __attribute__((alloc_size(1)));
133 void *xb_realloc(void *, size_t, size_t)  __attribute__((alloc_size(3)));
134 void xb_free(void *);
135 void xb_free_size(void *, size_t);
136 int xb_grow(struct xdrbuf *);
137 void xb_set_cur_buf_len(struct xdrbuf *);
138 char *xb_buffer_base(struct xdrbuf *);
139 int xb_advance(struct xdrbuf *, size_t);
140 size_t xb_offset(struct xdrbuf *);
141 int xb_seek(struct xdrbuf *, size_t);
142 int xb_add_bytes(struct xdrbuf *, const char *, size_t, int);
143 int xb_get_bytes(struct xdrbuf *, char *, uint32_t, int);
144 
145 #ifdef _NFS_XDR_SUBS_FUNCS_
146 
147 /*
148  * basic initialization of xdrbuf structure
149  */
150 void
xb_init(struct xdrbuf * xbp,xdrbuf_type type)151 xb_init(struct xdrbuf *xbp, xdrbuf_type type)
152 {
153 	bzero(xbp, sizeof(*xbp));
154 	xbp->xb_type = type;
155 	xbp->xb_flags |= XB_CLEANUP;
156 }
157 
158 /*
159  * initialize a single-buffer xdrbuf
160  */
161 void
xb_init_buffer(struct xdrbuf * xbp,char * buf,size_t buflen)162 xb_init_buffer(struct xdrbuf *xbp, char *buf, size_t buflen)
163 {
164 	xb_init(xbp, XDRBUF_BUFFER);
165 	xbp->xb_u.xb_buffer.xbb_base = buf;
166 	xbp->xb_u.xb_buffer.xbb_size = buflen;
167 	xbp->xb_u.xb_buffer.xbb_len = buflen;
168 	xbp->xb_growsize = 512;
169 	xbp->xb_ptr = buf;
170 	xbp->xb_left = buflen;
171 	if (buf) { /* when using an existing buffer, xb code should skip cleanup */
172 		xbp->xb_flags &= ~XB_CLEANUP;
173 	}
174 }
175 
176 /*
177  * get the pointer to the single-buffer xdrbuf's buffer
178  */
179 char *
xb_buffer_base(struct xdrbuf * xbp)180 xb_buffer_base(struct xdrbuf *xbp)
181 {
182 	return xbp->xb_u.xb_buffer.xbb_base;
183 }
184 
185 /*
186  * clean up any resources held by an xdrbuf
187  */
188 void
xb_cleanup(struct xdrbuf * xbp)189 xb_cleanup(struct xdrbuf *xbp)
190 {
191 	if (!(xbp->xb_flags & XB_CLEANUP)) {
192 		return;
193 	}
194 	switch (xbp->xb_type) {
195 	case XDRBUF_BUFFER:
196 		if (xbp->xb_u.xb_buffer.xbb_base) {
197 			xb_free(xbp->xb_u.xb_buffer.xbb_base);
198 		}
199 		break;
200 	default:
201 		break;
202 	}
203 	xbp->xb_flags &= ~XB_CLEANUP;
204 }
205 
206 /*
207  * set the length of valid data in the current buffer to
208  * be up to the current location within the buffer
209  */
210 void
xb_set_cur_buf_len(struct xdrbuf * xbp)211 xb_set_cur_buf_len(struct xdrbuf *xbp)
212 {
213 	switch (xbp->xb_type) {
214 	case XDRBUF_BUFFER:
215 		xbp->xb_u.xb_buffer.xbb_len = xbp->xb_ptr - xbp->xb_u.xb_buffer.xbb_base;
216 		break;
217 	default:
218 		break;
219 	}
220 }
221 
222 /*
223  * advance forward through existing data in xdrbuf
224  */
225 int
xb_advance(struct xdrbuf * xbp,size_t len)226 xb_advance(struct xdrbuf *xbp, size_t len)
227 {
228 	size_t tlen;
229 
230 	while (len) {
231 		if (xbp->xb_left <= 0) {
232 			return EBADRPC;
233 		}
234 		tlen = MIN(xbp->xb_left, len);
235 		if (tlen) {
236 			xbp->xb_ptr += tlen;
237 			xbp->xb_left -= tlen;
238 			len -= tlen;
239 		}
240 	}
241 	return 0;
242 }
243 
244 /*
245  * Calculate the current offset in the XDR buffer.
246  */
247 size_t
xb_offset(struct xdrbuf * xbp)248 xb_offset(struct xdrbuf *xbp)
249 {
250 	size_t offset = 0;
251 
252 	switch (xbp->xb_type) {
253 	case XDRBUF_BUFFER:
254 		offset = xbp->xb_ptr - xbp->xb_u.xb_buffer.xbb_base;
255 		break;
256 	default:
257 		break;
258 	}
259 
260 	return offset;
261 }
262 
263 /*
264  * Seek to the given offset in the existing data in the XDR buffer.
265  */
266 int
xb_seek(struct xdrbuf * xbp,size_t offset)267 xb_seek(struct xdrbuf *xbp, size_t offset)
268 {
269 	switch (xbp->xb_type) {
270 	case XDRBUF_BUFFER:
271 		xbp->xb_ptr = xbp->xb_u.xb_buffer.xbb_base + offset;
272 		xbp->xb_left = xbp->xb_u.xb_buffer.xbb_len - offset;
273 		break;
274 	default:
275 		break;
276 	}
277 
278 	return 0;
279 }
280 
281 /*
282  * allocate memory
283  */
284 void *
xb_malloc(size_t size)285 xb_malloc(size_t size)
286 {
287 	void *buf = NULL;
288 
289 #ifdef KERNEL
290 	buf = kalloc_data(size, Z_WAITOK);
291 #else
292 	buf = malloc(size);
293 #endif
294 	return buf;
295 }
296 
297 void *
xb_realloc(void * oldbuf,size_t old_size,size_t new_size)298 xb_realloc(void *oldbuf, size_t old_size, size_t new_size)
299 {
300 	void *buf = NULL;
301 
302 #ifdef KERNEL
303 	buf = krealloc_data(oldbuf, old_size, new_size, Z_WAITOK);
304 #else
305 	(void)old_size;
306 	buf = realloc(oldbuf, new_size);
307 #endif
308 	return buf;
309 }
310 
311 /*
312  * free a chunk of memory allocated with xb_malloc()
313  */
314 void
xb_free_size(void * buf,size_t len)315 xb_free_size(void *buf, size_t len)
316 {
317 #ifdef KERNEL
318 	kfree_data(buf, len);
319 #else
320 	(void)len;
321 	free(buf);
322 #endif
323 }
324 
325 /*
326  * free a chunk of memory allocated with xb_malloc()
327  */
328 void
xb_free(void * buf)329 xb_free(void *buf)
330 {
331 #ifdef KERNEL
332 	kfree_data_addr(buf);
333 #else
334 	free(buf);
335 #endif
336 }
337 
338 /*
339  * Increase space available for new data in XDR buffer.
340  */
341 int
xb_grow(struct xdrbuf * xbp)342 xb_grow(struct xdrbuf *xbp)
343 {
344 	char *newbuf, *oldbuf;
345 	size_t newsize, oldsize;
346 
347 	switch (xbp->xb_type) {
348 	case XDRBUF_BUFFER:
349 		oldsize = xbp->xb_u.xb_buffer.xbb_size;
350 		oldbuf = xbp->xb_u.xb_buffer.xbb_base;
351 		newsize = oldsize + xbp->xb_growsize;
352 		if (newsize < oldsize) {
353 			return ENOMEM;
354 		}
355 		newbuf = xb_realloc(oldbuf, oldsize, newsize);
356 		if (newbuf == NULL) {
357 			return ENOMEM;
358 		}
359 		xbp->xb_u.xb_buffer.xbb_base = newbuf;
360 		xbp->xb_u.xb_buffer.xbb_size = newsize;
361 		xbp->xb_ptr = newbuf + oldsize;
362 		xbp->xb_left = xbp->xb_growsize;
363 		break;
364 	default:
365 		break;
366 	}
367 
368 	return 0;
369 }
370 
371 /*
372  * xb_add_bytes()
373  *
374  * Add "count" bytes of opaque data pointed to by "buf" to the given XDR buffer.
375  */
376 int
xb_add_bytes(struct xdrbuf * xbp,const char * buf,size_t count,int nopad)377 xb_add_bytes(struct xdrbuf *xbp, const char *buf, size_t count, int nopad)
378 {
379 	size_t len, tlen;
380 	int error;
381 
382 	len = nopad ? count : xdr_rndup(count);
383 
384 	/* copy in "count" bytes and zero out any pad bytes */
385 	while (len) {
386 		if (xbp->xb_left <= 0) {
387 			/* need more space */
388 			if ((error = xb_grow(xbp))) {
389 				return error;
390 			}
391 			if (xbp->xb_left <= 0) {
392 				return ENOMEM;
393 			}
394 		}
395 		tlen = MIN(xbp->xb_left, len);
396 		if (tlen) {
397 			if (count) {
398 				if (tlen > count) {
399 					tlen = count;
400 				}
401 				bcopy(buf, xbp->xb_ptr, tlen);
402 			} else {
403 				bzero(xbp->xb_ptr, tlen);
404 			}
405 			xbp->xb_ptr += tlen;
406 			xbp->xb_left -= tlen;
407 			len -= tlen;
408 			if (count) {
409 				buf += tlen;
410 				count -= tlen;
411 			}
412 		}
413 	}
414 	return 0;
415 }
416 
417 /*
418  * xb_get_bytes()
419  *
420  * Get "count" bytes of opaque data from the given XDR buffer.
421  */
422 int
xb_get_bytes(struct xdrbuf * xbp,char * buf,uint32_t count,int nopad)423 xb_get_bytes(struct xdrbuf *xbp, char *buf, uint32_t count, int nopad)
424 {
425 	size_t len, tlen;
426 
427 	len = nopad ? count : xdr_rndup(count);
428 
429 	/* copy in "count" bytes and zero out any pad bytes */
430 	while (len) {
431 		if (xbp->xb_left <= 0) {
432 			return ENOMEM;
433 		}
434 		tlen = MIN(xbp->xb_left, len);
435 		if (tlen) {
436 			if (count) {
437 				if (tlen > count) {
438 					tlen = count;
439 				}
440 				bcopy(xbp->xb_ptr, buf, tlen);
441 			}
442 			xbp->xb_ptr += tlen;
443 			xbp->xb_left -= tlen;
444 			len -= tlen;
445 			if (count) {
446 				buf += tlen;
447 				count -= tlen;
448 			}
449 		}
450 	}
451 	return 0;
452 }
453 
454 #endif /* _NFS_XDR_SUBS_FUNCS_ */
455 
456 
457 /*
458  * macros for building XDR data
459  */
460 
461 /* finalize the data that has been added to the buffer */
462 #define xb_build_done(E, XB) \
463 	do { \
464 	        if (E) break; \
465 	        xb_set_cur_buf_len(XB); \
466 	} while (0)
467 
468 /* add a 32-bit value */
469 #define xb_add_32(E, XB, VAL) \
470 	do { \
471 	        uint32_t __tmp; \
472 	        if (E) break; \
473 	        __tmp = txdr_unsigned(VAL); \
474 	        (E) = xb_add_bytes((XB), (void*)&__tmp, XDRWORD, 0); \
475 	} while (0)
476 
477 /* add a 64-bit value */
478 #define xb_add_64(E, XB, VAL) \
479 	do { \
480 	        uint64_t __tmp1, __tmp2; \
481 	        if (E) break; \
482 	        __tmp1 = (VAL); \
483 	        txdr_hyper(&__tmp1, &__tmp2); \
484 	        (E) = xb_add_bytes((XB), (char*)&__tmp2, 2 * XDRWORD, 0); \
485 	} while (0)
486 
487 /* add an array of XDR words */
488 #define xb_add_word_array(E, XB, A, LEN) \
489 	do { \
490 	        uint32_t __i; \
491 	        xb_add_32((E), (XB), (LEN)); \
492 	        for (__i=0; __i < (uint32_t)(LEN); __i++) \
493 	                xb_add_32((E), (XB), (A)[__i]); \
494 	} while (0)
495 #define xb_add_bitmap(E, XB, B, LEN)    xb_add_word_array((E), (XB), (B), (LEN))
496 
497 /* add a file handle */
498 #define xb_add_fh(E, XB, FHP, FHLEN) \
499 	do { \
500 	        xb_add_32((E), (XB), (FHLEN)); \
501 	        if (E) break; \
502 	        (E) = xb_add_bytes((XB), (char*)(FHP), (FHLEN), 0); \
503 	} while (0)
504 
505 /* add a string */
506 #define xb_add_string(E, XB, S, LEN) \
507 	do { \
508 	        xb_add_32((E), (XB), (LEN)); \
509 	        if (E) break; \
510 	        (E) = xb_add_bytes((XB), (const char*)(S), (LEN), 0); \
511 	} while (0)
512 
513 
514 /*
515  * macros for decoding XDR data
516  */
517 
518 /* skip past data in the buffer */
519 #define xb_skip(E, XB, LEN) \
520 	do { \
521 	        if (E) break; \
522 	        (E) = xb_advance((XB), (LEN)); \
523 	} while (0)
524 
525 /* get a 32-bit value */
526 #define xb_get_32(E, XB, LVAL) \
527 	do { \
528 	        uint32_t __tmp; \
529 	        (LVAL) = (typeof((LVAL))) 0; \
530 	        if (E) break; \
531 	        (E) = xb_get_bytes((XB), (char*)&__tmp, XDRWORD, 0); \
532 	        if (E) break; \
533 	        (LVAL) = fxdr_unsigned(uint32_t, __tmp); \
534 	} while (0)
535 
536 /* get a 64-bit value */
537 #define xb_get_64(E, XB, LVAL) \
538 	do { \
539 	        uint64_t __tmp; \
540 	        (LVAL) = 0; \
541 	        if (E) break; \
542 	        (E) = xb_get_bytes((XB), (char*)&__tmp, 2 * XDRWORD, 0); \
543 	        if (E) break; \
544 	        fxdr_hyper(&__tmp, &(LVAL)); \
545 	} while (0)
546 
547 /* get an array of XDR words (of a given expected/maximum length) */
548 #define xb_get_word_array(E, XB, A, LEN) \
549 	do { \
550 	        uint32_t __len = 0, __i; \
551 	        xb_get_32((E), (XB), __len); \
552 	        if (E) break; \
553 	        for (__i=0; __i < MIN(__len, (uint32_t)(LEN)); __i++) \
554 	                xb_get_32((E), (XB), (A)[__i]); \
555 	        if (E) break; \
556 	        for (; __i < __len; __i++) \
557 	                xb_skip((E), (XB), XDRWORD); \
558 	        for (; __i < (uint32_t)(LEN); __i++) \
559 	                (A)[__i] = 0; \
560 	        (LEN) = __len; \
561 	} while (0)
562 #define xb_get_bitmap(E, XB, B, LEN)    xb_get_word_array((E), (XB), (B), (LEN))
563 
564 #endif /* __APPLE_API_PRIVATE */
565 #endif /* _NFS_XDR_SUBS_H_ */
566