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 */
103typedef enum xdrbuf_type {
104 XDRBUF_NONE = 0,
105 XDRBUF_BUFFER = 1,
106} xdrbuf_type;
107
108struct 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
129void xb_init(struct xdrbuf *, xdrbuf_type);
130void xb_init_buffer(struct xdrbuf *, char *, size_t);
131void xb_cleanup(struct xdrbuf *);
132void *xb_malloc(size_t) __attribute__((alloc_size(1)));
133void *xb_realloc(void *, size_t, size_t) __attribute__((alloc_size(3)));
134void xb_free(void *);
135void xb_free_size(void *, size_t);
136int xb_grow(struct xdrbuf *);
137void xb_set_cur_buf_len(struct xdrbuf *);
138char *xb_buffer_base(struct xdrbuf *);
139int xb_advance(struct xdrbuf *, size_t);
140size_t xb_offset(struct xdrbuf *);
141int xb_seek(struct xdrbuf *, size_t);
142int xb_add_bytes(struct xdrbuf *, const char *, size_t, int);
143int 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 */
150void
151xb_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 */
161void
162xb_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 */
179char *
180xb_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 */
188void
189xb_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 */
210void
211xb_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 */
225int
226xb_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 */
247size_t
248xb_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 */
266int
267xb_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 */
284void *
285xb_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
297void *
298xb_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 */
314void
315xb_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 */
328void
329xb_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 */
341int
342xb_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 */
376int
377xb_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 */
422int
423xb_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