xref: /freebsd/sys/netgraph/ng_parse.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 
2 /*
3  * ng_parse.c
4  *
5  * Copyright (c) 1999 Whistle Communications, Inc.
6  * All rights reserved.
7  *
8  * Subject to the following obligations and disclaimer of warranty, use and
9  * redistribution of this software, in source or object code forms, with or
10  * without modifications are expressly permitted by Whistle Communications;
11  * provided, however, that:
12  * 1. Any and all reproductions of the source or object code must include the
13  *    copyright notice above and the following disclaimer of warranties; and
14  * 2. No rights are granted, in any manner or form, to use Whistle
15  *    Communications, Inc. trademarks, including the mark "WHISTLE
16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17  *    such appears in the above copyright notice or in the software.
18  *
19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35  * OF SUCH DAMAGE.
36  *
37  * Author: Archie Cobbs <archie@whistle.com>
38  *
39  * $Whistle: ng_parse.c,v 1.3 1999/11/29 01:43:48 archie Exp $
40  * $FreeBSD$
41  */
42 
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/errno.h>
47 #include <sys/malloc.h>
48 #include <sys/ctype.h>
49 
50 #include <netinet/in.h>
51 
52 #include <netgraph/ng_message.h>
53 #include <netgraph/netgraph.h>
54 #include <netgraph/ng_parse.h>
55 
56 /* Compute alignment for primitive integral types */
57 struct int16_temp {
58 	char	x;
59 	int16_t	y;
60 };
61 
62 struct int32_temp {
63 	char	x;
64 	int32_t	y;
65 };
66 
67 struct int64_temp {
68 	char	x;
69 	int64_t	y;
70 };
71 
72 #define INT8_ALIGNMENT		1
73 #define INT16_ALIGNMENT		((int)&((struct int16_temp *)0)->y)
74 #define INT32_ALIGNMENT		((int)&((struct int32_temp *)0)->y)
75 #define INT64_ALIGNMENT		((int)&((struct int64_temp *)0)->y)
76 
77 /* Type of composite object: struct, array, or fixedarray */
78 enum comptype {
79 	CT_STRUCT,
80 	CT_ARRAY,
81 	CT_FIXEDARRAY,
82 };
83 
84 /* Composite types helper functions */
85 static int	ng_parse_composite(const struct ng_parse_type *type,
86 			const char *s, int *off, const u_char *start,
87 			u_char *const buf, int *buflen, enum comptype ctype);
88 static int	ng_unparse_composite(const struct ng_parse_type *type,
89 			const u_char *data, int *off, char *cbuf, int cbuflen,
90 			enum comptype ctype);
91 static int	ng_get_composite_elem_default(const struct ng_parse_type *type,
92 			int index, const u_char *start, u_char *buf,
93 			int *buflen, enum comptype ctype);
94 static int	ng_get_composite_len(const struct ng_parse_type *type,
95 			const u_char *start, const u_char *buf,
96 			enum comptype ctype);
97 static const	struct ng_parse_type *ng_get_composite_etype(const struct
98 			ng_parse_type *type, int index, enum comptype ctype);
99 static int	ng_parse_get_elem_pad(const struct ng_parse_type *type,
100 			int index, enum comptype ctype, int posn);
101 
102 /* Parsing helper functions */
103 static int	ng_parse_skip_value(const char *s, int off, int *lenp);
104 
105 /* Poor man's virtual method calls */
106 #define METHOD(t,m)	(ng_get_ ## m ## _method(t))
107 #define INVOKE(t,m)	(*METHOD(t,m))
108 
109 static ng_parse_t	*ng_get_parse_method(const struct ng_parse_type *t);
110 static ng_unparse_t	*ng_get_unparse_method(const struct ng_parse_type *t);
111 static ng_getDefault_t	*ng_get_getDefault_method(const
112 				struct ng_parse_type *t);
113 static ng_getAlign_t	*ng_get_getAlign_method(const struct ng_parse_type *t);
114 
115 #define ALIGNMENT(t)	(METHOD(t, getAlign) == NULL ? \
116 				0 : INVOKE(t, getAlign)(t))
117 
118 /* For converting binary to string */
119 #define NG_PARSE_APPEND(fmt, args...)				\
120 		do {						\
121 			int len;				\
122 								\
123 			len = snprintf((cbuf), (cbuflen),	\
124 				fmt , ## args);			\
125 			if (len >= (cbuflen))			\
126 				return (ERANGE);		\
127 			(cbuf) += len;				\
128 			(cbuflen) -= len;			\
129 		} while (0)
130 
131 /************************************************************************
132 			PUBLIC FUNCTIONS
133  ************************************************************************/
134 
135 /*
136  * Convert an ASCII string to binary according to the supplied type descriptor
137  */
138 int
139 ng_parse(const struct ng_parse_type *type,
140 	const char *string, int *off, u_char *buf, int *buflen)
141 {
142 	return INVOKE(type, parse)(type, string, off, buf, buf, buflen);
143 }
144 
145 /*
146  * Convert binary to an ASCII string according to the supplied type descriptor
147  */
148 int
149 ng_unparse(const struct ng_parse_type *type,
150 	const u_char *data, char *cbuf, int cbuflen)
151 {
152 	int off = 0;
153 
154 	return INVOKE(type, unparse)(type, data, &off, cbuf, cbuflen);
155 }
156 
157 /*
158  * Fill in the default value according to the supplied type descriptor
159  */
160 int
161 ng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen)
162 {
163 	ng_getDefault_t *const func = METHOD(type, getDefault);
164 
165 	if (func == NULL)
166 		return (EOPNOTSUPP);
167 	return (*func)(type, buf, buf, buflen);
168 }
169 
170 
171 /************************************************************************
172 			STRUCTURE TYPE
173  ************************************************************************/
174 
175 static int
176 ng_struct_parse(const struct ng_parse_type *type,
177 	const char *s, int *off, const u_char *const start,
178 	u_char *const buf, int *buflen)
179 {
180 	return ng_parse_composite(type, s, off, start, buf, buflen, CT_STRUCT);
181 }
182 
183 static int
184 ng_struct_unparse(const struct ng_parse_type *type,
185 	const u_char *data, int *off, char *cbuf, int cbuflen)
186 {
187 	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_STRUCT);
188 }
189 
190 static int
191 ng_struct_getDefault(const struct ng_parse_type *type,
192 	const u_char *const start, u_char *buf, int *buflen)
193 {
194 	int off = 0;
195 
196 	return ng_parse_composite(type,
197 	    "{}", &off, start, buf, buflen, CT_STRUCT);
198 }
199 
200 static int
201 ng_struct_getAlign(const struct ng_parse_type *type)
202 {
203 	const struct ng_parse_struct_info *si = type->info;
204 	const struct ng_parse_struct_field *field;
205 	int align = 0;
206 
207 	for (field = si->fields; field->name != NULL; field++) {
208 		int falign = ALIGNMENT(field->type);
209 
210 		if (falign > align)
211 			align = falign;
212 	}
213 	return align;
214 }
215 
216 const struct ng_parse_type ng_parse_struct_type = {
217 	NULL,
218 	NULL,
219 	NULL,
220 	ng_struct_parse,
221 	ng_struct_unparse,
222 	ng_struct_getDefault,
223 	ng_struct_getAlign
224 };
225 
226 /************************************************************************
227 			FIXED LENGTH ARRAY TYPE
228  ************************************************************************/
229 
230 static int
231 ng_fixedarray_parse(const struct ng_parse_type *type,
232 	const char *s, int *off, const u_char *const start,
233 	u_char *const buf, int *buflen)
234 {
235 	return ng_parse_composite(type,
236 	    s, off, start, buf, buflen, CT_FIXEDARRAY);
237 }
238 
239 static int
240 ng_fixedarray_unparse(const struct ng_parse_type *type,
241 	const u_char *data, int *off, char *cbuf, int cbuflen)
242 {
243 	return ng_unparse_composite(type,
244 		data, off, cbuf, cbuflen, CT_FIXEDARRAY);
245 }
246 
247 static int
248 ng_fixedarray_getDefault(const struct ng_parse_type *type,
249 	const u_char *const start, u_char *buf, int *buflen)
250 {
251 	int off = 0;
252 
253 	return ng_parse_composite(type,
254 	    "[]", &off, start, buf, buflen, CT_FIXEDARRAY);
255 }
256 
257 static int
258 ng_fixedarray_getAlign(const struct ng_parse_type *type)
259 {
260 	const struct ng_parse_fixedarray_info *fi = type->info;
261 
262 	return ALIGNMENT(fi->elementType);
263 }
264 
265 const struct ng_parse_type ng_parse_fixedarray_type = {
266 	NULL,
267 	NULL,
268 	NULL,
269 	ng_fixedarray_parse,
270 	ng_fixedarray_unparse,
271 	ng_fixedarray_getDefault,
272 	ng_fixedarray_getAlign
273 };
274 
275 /************************************************************************
276 			VARIABLE LENGTH ARRAY TYPE
277  ************************************************************************/
278 
279 static int
280 ng_array_parse(const struct ng_parse_type *type,
281 	const char *s, int *off, const u_char *const start,
282 	u_char *const buf, int *buflen)
283 {
284 	return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY);
285 }
286 
287 static int
288 ng_array_unparse(const struct ng_parse_type *type,
289 	const u_char *data, int *off, char *cbuf, int cbuflen)
290 {
291 	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY);
292 }
293 
294 static int
295 ng_array_getDefault(const struct ng_parse_type *type,
296 	const u_char *const start, u_char *buf, int *buflen)
297 {
298 	int off = 0;
299 
300 	return ng_parse_composite(type,
301 	    "[]", &off, start, buf, buflen, CT_ARRAY);
302 }
303 
304 static int
305 ng_array_getAlign(const struct ng_parse_type *type)
306 {
307 	const struct ng_parse_array_info *ai = type->info;
308 
309 	return ALIGNMENT(ai->elementType);
310 }
311 
312 const struct ng_parse_type ng_parse_array_type = {
313 	NULL,
314 	NULL,
315 	NULL,
316 	ng_array_parse,
317 	ng_array_unparse,
318 	ng_array_getDefault,
319 	ng_array_getAlign
320 };
321 
322 /************************************************************************
323 				INT8 TYPE
324  ************************************************************************/
325 
326 static int
327 ng_int8_parse(const struct ng_parse_type *type,
328 	const char *s, int *off, const u_char *const start,
329 	u_char *const buf, int *buflen)
330 {
331 	long val;
332 	int8_t val8;
333 	char *eptr;
334 
335 	val = strtol(s + *off, &eptr, 0);
336 	if (val < -0x80 || val > 0xff || eptr == s + *off)
337 		return (EINVAL);
338 	*off = eptr - s;
339 	val8 = (int8_t)val;
340 	bcopy(&val8, buf, sizeof(int8_t));
341 	*buflen = sizeof(int8_t);
342 	return (0);
343 }
344 
345 static int
346 ng_int8_unparse(const struct ng_parse_type *type,
347 	const u_char *data, int *off, char *cbuf, int cbuflen)
348 {
349 	int8_t val;
350 
351 	bcopy(data + *off, &val, sizeof(int8_t));
352 	NG_PARSE_APPEND("%d", (int)val);
353 	*off += sizeof(int8_t);
354 	return (0);
355 }
356 
357 static int
358 ng_int8_getDefault(const struct ng_parse_type *type,
359 	const u_char *const start, u_char *buf, int *buflen)
360 {
361 	int8_t val;
362 
363 	if (*buflen < sizeof(int8_t))
364 		return (ERANGE);
365 	val = 0;
366 	bcopy(&val, buf, sizeof(int8_t));
367 	*buflen = sizeof(int8_t);
368 	return (0);
369 }
370 
371 static int
372 ng_int8_getAlign(const struct ng_parse_type *type)
373 {
374 	return INT8_ALIGNMENT;
375 }
376 
377 const struct ng_parse_type ng_parse_int8_type = {
378 	NULL,
379 	NULL,
380 	NULL,
381 	ng_int8_parse,
382 	ng_int8_unparse,
383 	ng_int8_getDefault,
384 	ng_int8_getAlign
385 };
386 
387 /************************************************************************
388 				INT16 TYPE
389  ************************************************************************/
390 
391 static int
392 ng_int16_parse(const struct ng_parse_type *type,
393 	const char *s, int *off, const u_char *const start,
394 	u_char *const buf, int *buflen)
395 {
396 	long val;
397 	int16_t val16;
398 	char *eptr;
399 
400 	val = strtol(s + *off, &eptr, 0);
401 	if (val < -0x8000 || val > 0xffff || eptr == s + *off)
402 		return (EINVAL);
403 	*off = eptr - s;
404 	val16 = (int16_t)val;
405 	bcopy(&val16, buf, sizeof(int16_t));
406 	*buflen = sizeof(int16_t);
407 	return (0);
408 }
409 
410 static int
411 ng_int16_unparse(const struct ng_parse_type *type,
412 	const u_char *data, int *off, char *cbuf, int cbuflen)
413 {
414 	int16_t val;
415 
416 	bcopy(data + *off, &val, sizeof(int16_t));
417 	NG_PARSE_APPEND("%d", (int)val);
418 	*off += sizeof(int16_t);
419 	return (0);
420 }
421 
422 static int
423 ng_int16_getDefault(const struct ng_parse_type *type,
424 	const u_char *const start, u_char *buf, int *buflen)
425 {
426 	int16_t val;
427 
428 	if (*buflen < sizeof(int16_t))
429 		return (ERANGE);
430 	val = 0;
431 	bcopy(&val, buf, sizeof(int16_t));
432 	*buflen = sizeof(int16_t);
433 	return (0);
434 }
435 
436 static int
437 ng_int16_getAlign(const struct ng_parse_type *type)
438 {
439 	return INT16_ALIGNMENT;
440 }
441 
442 const struct ng_parse_type ng_parse_int16_type = {
443 	NULL,
444 	NULL,
445 	NULL,
446 	ng_int16_parse,
447 	ng_int16_unparse,
448 	ng_int16_getDefault,
449 	ng_int16_getAlign
450 };
451 
452 /************************************************************************
453 				INT32 TYPE
454  ************************************************************************/
455 
456 static int
457 ng_int32_parse(const struct ng_parse_type *type,
458 	const char *s, int *off, const u_char *const start,
459 	u_char *const buf, int *buflen)
460 {
461 	long val;			/* assumes long is at least 32 bits */
462 	int32_t val32;
463 	char *eptr;
464 
465 	val = strtol(s + *off, &eptr, 0);
466 	if (val < (long)-0x80000000
467 	    || val > (u_long)0xffffffff || eptr == s + *off)
468 		return (EINVAL);
469 	*off = eptr - s;
470 	val32 = (int32_t)val;
471 	bcopy(&val32, buf, sizeof(int32_t));
472 	*buflen = sizeof(int32_t);
473 	return (0);
474 }
475 
476 static int
477 ng_int32_unparse(const struct ng_parse_type *type,
478 	const u_char *data, int *off, char *cbuf, int cbuflen)
479 {
480 	int32_t val;
481 
482 	bcopy(data + *off, &val, sizeof(int32_t));
483 	NG_PARSE_APPEND("%ld", (long)val);
484 	*off += sizeof(int32_t);
485 	return (0);
486 }
487 
488 static int
489 ng_int32_getDefault(const struct ng_parse_type *type,
490 	const u_char *const start, u_char *buf, int *buflen)
491 {
492 	int32_t val;
493 
494 	if (*buflen < sizeof(int32_t))
495 		return (ERANGE);
496 	val = 0;
497 	bcopy(&val, buf, sizeof(int32_t));
498 	*buflen = sizeof(int32_t);
499 	return (0);
500 }
501 
502 static int
503 ng_int32_getAlign(const struct ng_parse_type *type)
504 {
505 	return INT32_ALIGNMENT;
506 }
507 
508 const struct ng_parse_type ng_parse_int32_type = {
509 	NULL,
510 	NULL,
511 	NULL,
512 	ng_int32_parse,
513 	ng_int32_unparse,
514 	ng_int32_getDefault,
515 	ng_int32_getAlign
516 };
517 
518 /************************************************************************
519 				INT64 TYPE
520  ************************************************************************/
521 
522 static int
523 ng_int64_parse(const struct ng_parse_type *type,
524 	const char *s, int *off, const u_char *const start,
525 	u_char *const buf, int *buflen)
526 {
527 	quad_t val;
528 	int64_t val64;
529 	char *eptr;
530 
531 	val = strtoq(s + *off, &eptr, 0);
532 	if (eptr == s + *off)
533 		return (EINVAL);
534 	*off = eptr - s;
535 	val64 = (int64_t)val;
536 	bcopy(&val64, buf, sizeof(int64_t));
537 	*buflen = sizeof(int64_t);
538 	return (0);
539 }
540 
541 static int
542 ng_int64_unparse(const struct ng_parse_type *type,
543 	const u_char *data, int *off, char *cbuf, int cbuflen)
544 {
545 	int64_t val;
546 
547 	bcopy(data + *off, &val, sizeof(int64_t));
548 	NG_PARSE_APPEND("%lld", (long long)val);
549 	*off += sizeof(int64_t);
550 	return (0);
551 }
552 
553 static int
554 ng_int64_getDefault(const struct ng_parse_type *type,
555 	const u_char *const start, u_char *buf, int *buflen)
556 {
557 	int64_t val;
558 
559 	if (*buflen < sizeof(int64_t))
560 		return (ERANGE);
561 	val = 0;
562 	bcopy(&val, buf, sizeof(int64_t));
563 	*buflen = sizeof(int64_t);
564 	return (0);
565 }
566 
567 static int
568 ng_int64_getAlign(const struct ng_parse_type *type)
569 {
570 	return INT64_ALIGNMENT;
571 }
572 
573 const struct ng_parse_type ng_parse_int64_type = {
574 	NULL,
575 	NULL,
576 	NULL,
577 	ng_int64_parse,
578 	ng_int64_unparse,
579 	ng_int64_getDefault,
580 	ng_int64_getAlign
581 };
582 
583 /************************************************************************
584 				STRING TYPE
585  ************************************************************************/
586 
587 static int
588 ng_string_parse(const struct ng_parse_type *type,
589 	const char *s, int *off, const u_char *const start,
590 	u_char *const buf, int *buflen)
591 {
592 	char *sval;
593 	int len;
594 
595 	if ((sval = ng_get_string_token(s, off, &len)) == NULL)
596 		return (EINVAL);
597 	*off += len;
598 	len = strlen(sval) + 1;
599 	bcopy(sval, buf, len);
600 	FREE(sval, M_NETGRAPH);
601 	*buflen = len;
602 	return (0);
603 }
604 
605 static int
606 ng_string_unparse(const struct ng_parse_type *type,
607 	const u_char *data, int *off, char *cbuf, int cbuflen)
608 {
609 	const char *const raw = (const char *)data + *off;
610 	char *const s = ng_encode_string(raw);
611 
612 	if (s == NULL)
613 		return (ENOMEM);
614 	NG_PARSE_APPEND("%s", s);
615 	*off += strlen(raw) + 1;
616 	FREE(s, M_NETGRAPH);
617 	return (0);
618 }
619 
620 static int
621 ng_string_getDefault(const struct ng_parse_type *type,
622 	const u_char *const start, u_char *buf, int *buflen)
623 {
624 
625 	if (*buflen < 1)
626 		return (ERANGE);
627 	buf[0] = (u_char)'\0';
628 	*buflen = 1;
629 	return (0);
630 }
631 
632 const struct ng_parse_type ng_parse_string_type = {
633 	NULL,
634 	NULL,
635 	NULL,
636 	ng_string_parse,
637 	ng_string_unparse,
638 	ng_string_getDefault,
639 	NULL
640 };
641 
642 /************************************************************************
643 			FIXED BUFFER STRING TYPE
644  ************************************************************************/
645 
646 static int
647 ng_fixedstring_parse(const struct ng_parse_type *type,
648 	const char *s, int *off, const u_char *const start,
649 	u_char *const buf, int *buflen)
650 {
651 	const struct ng_parse_fixedsstring_info *const fi = type->info;
652 	char *sval;
653 	int len;
654 
655 	if ((sval = ng_get_string_token(s, off, &len)) == NULL)
656 		return (EINVAL);
657 	if (strlen(sval) + 1 > fi->bufSize)
658 		return (E2BIG);
659 	*off += len;
660 	len = strlen(sval) + 1;
661 	bcopy(sval, buf, len);
662 	FREE(sval, M_NETGRAPH);
663 	bzero(buf + len, fi->bufSize - len);
664 	*buflen = fi->bufSize;
665 	return (0);
666 }
667 
668 static int
669 ng_fixedstring_unparse(const struct ng_parse_type *type,
670 	const u_char *data, int *off, char *cbuf, int cbuflen)
671 {
672 	const struct ng_parse_fixedsstring_info *const fi = type->info;
673 	int error, temp = *off;
674 
675 	if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0)
676 		return (error);
677 	*off += fi->bufSize;
678 	return (0);
679 }
680 
681 static int
682 ng_fixedstring_getDefault(const struct ng_parse_type *type,
683 	const u_char *const start, u_char *buf, int *buflen)
684 {
685 	const struct ng_parse_fixedsstring_info *const fi = type->info;
686 
687 	if (*buflen < fi->bufSize)
688 		return (ERANGE);
689 	bzero(buf, fi->bufSize);
690 	*buflen = fi->bufSize;
691 	return (0);
692 }
693 
694 const struct ng_parse_type ng_parse_fixedstring_type = {
695 	NULL,
696 	NULL,
697 	NULL,
698 	ng_fixedstring_parse,
699 	ng_fixedstring_unparse,
700 	ng_fixedstring_getDefault,
701 	NULL
702 };
703 
704 const struct ng_parse_fixedsstring_info ng_parse_nodebuf_info = {
705 	NG_NODELEN + 1
706 };
707 const struct ng_parse_type ng_parse_nodebuf_type = {
708 	&ng_parse_fixedstring_type,
709 	&ng_parse_nodebuf_info
710 };
711 
712 const struct ng_parse_fixedsstring_info ng_parse_hookbuf_info = {
713 	NG_HOOKLEN + 1
714 };
715 const struct ng_parse_type ng_parse_hookbuf_type = {
716 	&ng_parse_fixedstring_type,
717 	&ng_parse_hookbuf_info
718 };
719 
720 const struct ng_parse_fixedsstring_info ng_parse_pathbuf_info = {
721 	NG_PATHLEN + 1
722 };
723 const struct ng_parse_type ng_parse_pathbuf_type = {
724 	&ng_parse_fixedstring_type,
725 	&ng_parse_pathbuf_info
726 };
727 
728 const struct ng_parse_fixedsstring_info ng_parse_typebuf_info = {
729 	NG_TYPELEN + 1
730 };
731 const struct ng_parse_type ng_parse_typebuf_type = {
732 	&ng_parse_fixedstring_type,
733 	&ng_parse_typebuf_info
734 };
735 
736 const struct ng_parse_fixedsstring_info ng_parse_cmdbuf_info = {
737 	NG_CMDSTRLEN + 1
738 };
739 const struct ng_parse_type ng_parse_cmdbuf_type = {
740 	&ng_parse_fixedstring_type,
741 	&ng_parse_cmdbuf_info
742 };
743 
744 /************************************************************************
745 			IP ADDRESS TYPE
746  ************************************************************************/
747 
748 static int
749 ng_ipaddr_parse(const struct ng_parse_type *type,
750 	const char *s, int *off, const u_char *const start,
751 	u_char *const buf, int *buflen)
752 {
753 	int i, error;
754 
755 	for (i = 0; i < 4; i++) {
756 		if ((error = ng_int8_parse(&ng_parse_int8_type,
757 		    s, off, start, buf + i, buflen)) != 0)
758 			return (error);
759 		if (i < 3 && s[*off] != '.')
760 			return (EINVAL);
761 		(*off)++;
762 	}
763 	*buflen = 4;
764 	return (0);
765 }
766 
767 static int
768 ng_ipaddr_unparse(const struct ng_parse_type *type,
769 	const u_char *data, int *off, char *cbuf, int cbuflen)
770 {
771 	struct in_addr ip;
772 
773 	bcopy(data + *off, &ip, sizeof(ip));
774 	NG_PARSE_APPEND("%d.%d.%d.%d", ((u_char *)&ip)[0],
775 	    ((u_char *)&ip)[1], ((u_char *)&ip)[2], ((u_char *)&ip)[3]);
776 	*off += sizeof(ip);
777 	return (0);
778 }
779 
780 static int
781 ng_ipaddr_getDefault(const struct ng_parse_type *type,
782 	const u_char *const start, u_char *buf, int *buflen)
783 {
784 	struct in_addr ip = { 0 };
785 
786 	if (*buflen < sizeof(ip))
787 		return (ERANGE);
788 	bcopy(&ip, buf, sizeof(ip));
789 	*buflen = sizeof(ip);
790 	return (0);
791 }
792 
793 const struct ng_parse_type ng_parse_ipaddr_type = {
794 	NULL,
795 	NULL,
796 	NULL,
797 	ng_ipaddr_parse,
798 	ng_ipaddr_unparse,
799 	ng_ipaddr_getDefault,
800 	ng_int32_getAlign
801 };
802 
803 /************************************************************************
804 			BYTE ARRAY TYPE
805  ************************************************************************/
806 
807 /* Get the length of a byte array */
808 static int
809 ng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type,
810 	const u_char *start, const u_char *buf)
811 {
812 	ng_parse_array_getLength_t *const getLength = type->private;
813 
814 	return (*getLength)(type, start, buf);
815 }
816 
817 static int
818 ng_bytearray_elem_unparse(const struct ng_parse_type *type,
819 	const u_char *data, int *off, char *cbuf, int cbuflen)
820 {
821 	int8_t val;
822 
823 	bcopy(data + *off, &val, sizeof(int8_t));
824 	NG_PARSE_APPEND("0x%02x", (int)val & 0xff);	/* always hex format */
825 	*off += sizeof(int8_t);
826 	return (0);
827 }
828 
829 /* Byte array element type is int8, but always output in hex format */
830 const struct ng_parse_type ng_parse_bytearray_elem_type = {
831 	&ng_parse_int8_type,
832 	NULL,
833 	NULL,
834 	NULL,
835 	ng_bytearray_elem_unparse,
836 	NULL,
837 	NULL
838 };
839 
840 static const struct ng_parse_array_info ng_parse_bytearray_subtype_info = {
841 	&ng_parse_bytearray_elem_type,
842 	&ng_parse_bytearray_subtype_getLength,
843 	NULL
844 };
845 static const struct ng_parse_type ng_parse_bytearray_subtype = {
846 	&ng_parse_array_type,
847 	&ng_parse_bytearray_subtype_info
848 };
849 
850 static int
851 ng_bytearray_parse(const struct ng_parse_type *type,
852 	const char *s, int *off, const u_char *const start,
853 	u_char *const buf, int *buflen)
854 {
855 	char *str;
856 	int toklen;
857 
858 	/* We accept either an array of bytes or a string constant */
859 	if ((str = ng_get_string_token(s, off, &toklen)) != NULL) {
860 		ng_parse_array_getLength_t *const getLength = type->info;
861 		int arraylen, slen;
862 
863 		arraylen = (*getLength)(type, start, buf);
864 		if (arraylen > *buflen) {
865 			FREE(str, M_NETGRAPH);
866 			return (ERANGE);
867 		}
868 		slen = strlen(str) + 1;
869 		if (slen > arraylen) {
870 			FREE(str, M_NETGRAPH);
871 			return (E2BIG);
872 		}
873 		bcopy(str, buf, slen);
874 		bzero(buf + slen, arraylen - slen);
875 		FREE(str, M_NETGRAPH);
876 		*off += toklen;
877 		*buflen = arraylen;
878 		return (0);
879 	} else {
880 		struct ng_parse_type subtype;
881 
882 		subtype = ng_parse_bytearray_subtype;
883 		(const void *)subtype.private = type->info;
884 		return ng_array_parse(&subtype, s, off, start, buf, buflen);
885 	}
886 }
887 
888 static int
889 ng_bytearray_unparse(const struct ng_parse_type *type,
890 	const u_char *data, int *off, char *cbuf, int cbuflen)
891 {
892 	struct ng_parse_type subtype;
893 
894 	subtype = ng_parse_bytearray_subtype;
895 	(const void *)subtype.private = type->info;
896 	return ng_array_unparse(&subtype, data, off, cbuf, cbuflen);
897 }
898 
899 static int
900 ng_bytearray_getDefault(const struct ng_parse_type *type,
901 	const u_char *const start, u_char *buf, int *buflen)
902 {
903 	struct ng_parse_type subtype;
904 
905 	subtype = ng_parse_bytearray_subtype;
906 	(const void *)subtype.private = type->info;
907 	return ng_array_getDefault(&subtype, start, buf, buflen);
908 }
909 
910 const struct ng_parse_type ng_parse_bytearray_type = {
911 	NULL,
912 	NULL,
913 	NULL,
914 	ng_bytearray_parse,
915 	ng_bytearray_unparse,
916 	ng_bytearray_getDefault,
917 	NULL
918 };
919 
920 /************************************************************************
921 			STRUCT NG_MESG TYPE
922  ************************************************************************/
923 
924 /* Get msg->header.arglen when "buf" is pointing to msg->data */
925 static int
926 ng_parse_ng_mesg_getLength(const struct ng_parse_type *type,
927 	const u_char *start, const u_char *buf)
928 {
929 	const struct ng_mesg *msg;
930 
931 	msg = (const struct ng_mesg *)(buf - sizeof(*msg));
932 	return msg->header.arglen;
933 }
934 
935 /* Type for the variable length data portion of a struct ng_mesg */
936 static const struct ng_parse_type ng_msg_data_type = {
937 	&ng_parse_bytearray_type,
938 	&ng_parse_ng_mesg_getLength
939 };
940 
941 /* Type for the entire struct ng_mesg header with data section */
942 static const struct ng_parse_struct_info
943 	ng_parse_ng_mesg_type_info = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type);
944 const struct ng_parse_type ng_parse_ng_mesg_type = {
945 	&ng_parse_struct_type,
946 	&ng_parse_ng_mesg_type_info,
947 };
948 
949 /************************************************************************
950 			COMPOSITE HELPER ROUTINES
951  ************************************************************************/
952 
953 /*
954  * Convert a structure or array from ASCII to binary
955  */
956 static int
957 ng_parse_composite(const struct ng_parse_type *type, const char *s,
958 	int *off, const u_char *const start, u_char *const buf, int *buflen,
959 	const enum comptype ctype)
960 {
961 	const int num = ng_get_composite_len(type, start, buf, ctype);
962 	int nextIndex = 0;		/* next implicit array index */
963 	u_int index;			/* field or element index */
964 	int *foff;			/* field value offsets in string */
965 	int align, len, blen, error = 0;
966 
967 	/* Initialize */
968 	MALLOC(foff, int *, num * sizeof(*foff), M_NETGRAPH, M_NOWAIT);
969 	if (foff == NULL) {
970 		error = ENOMEM;
971 		goto done;
972 	}
973 	bzero(foff, num * sizeof(*foff));
974 
975 	/* Get opening brace/bracket */
976 	if (ng_parse_get_token(s, off, &len)
977 	    != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) {
978 		error = EINVAL;
979 		goto done;
980 	}
981 	*off += len;
982 
983 	/* Get individual element value positions in the string */
984 	for (;;) {
985 		enum ng_parse_token tok;
986 
987 		/* Check for closing brace/bracket */
988 		tok = ng_parse_get_token(s, off, &len);
989 		if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) {
990 			*off += len;
991 			break;
992 		}
993 
994 		/* For arrays, the 'name' (ie, index) is optional, so
995 		   distinguish name from values by seeing if the next
996 		   token is an equals sign */
997 		if (ctype != CT_STRUCT) {
998 			int len2, off2;
999 			char *eptr;
1000 
1001 			/* If an opening brace/bracket, index is implied */
1002 			if (tok == T_LBRACE || tok == T_LBRACKET) {
1003 				index = nextIndex++;
1004 				goto gotIndex;
1005 			}
1006 
1007 			/* Might be an index, might be a value, either way... */
1008 			if (tok != T_WORD) {
1009 				error = EINVAL;
1010 				goto done;
1011 			}
1012 
1013 			/* If no equals sign follows, index is implied */
1014 			off2 = *off + len;
1015 			if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
1016 				index = nextIndex++;
1017 				goto gotIndex;
1018 			}
1019 
1020 			/* Index was specified explicitly; parse it */
1021 			index = (u_int)strtoul(s + *off, &eptr, 0);
1022 			if (index < 0 || eptr - (s + *off) != len) {
1023 				error = EINVAL;
1024 				goto done;
1025 			}
1026 			nextIndex = index + 1;
1027 			*off += len + len2;
1028 gotIndex:
1029 		} else {			/* a structure field */
1030 			const struct ng_parse_struct_field *field = NULL;
1031 			const struct ng_parse_struct_info *si = type->info;
1032 
1033 			/* Find the field by name (required) in field list */
1034 			if (tok != T_WORD) {
1035 				error = EINVAL;
1036 				goto done;
1037 			}
1038 			for (index = 0; index < num; index++) {
1039 				field = &si->fields[index];
1040 				if (strncmp(&s[*off], field->name, len) == 0
1041 				    && field->name[len] == '\0')
1042 					break;
1043 			}
1044 			if (index == num) {
1045 				error = ENOENT;
1046 				goto done;
1047 			}
1048 			*off += len;
1049 
1050 			/* Get equals sign */
1051 			if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
1052 				error = EINVAL;
1053 				goto done;
1054 			}
1055 			*off += len;
1056 		}
1057 
1058 		/* Check array index */
1059 		if (index >= num) {
1060 			error = E2BIG;
1061 			goto done;
1062 		}
1063 
1064 		/* Save value's position and skip over it for now */
1065 		if (foff[index] != 0) {
1066 			error = EALREADY;		/* duplicate */
1067 			goto done;
1068 		}
1069 		while (isspace(s[*off]))
1070 			(*off)++;
1071 		foff[index] = *off;
1072 		if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
1073 			goto done;
1074 		*off += len;
1075 	}
1076 
1077 	/* Now build binary structure from supplied values and defaults */
1078 	for (blen = index = 0; index < num; index++) {
1079 		const struct ng_parse_type *const
1080 		    etype = ng_get_composite_etype(type, index, ctype);
1081 		int k, pad, vlen;
1082 
1083 		/* Zero-pad any alignment bytes */
1084 		pad = ng_parse_get_elem_pad(type, index, ctype, blen);
1085 		for (k = 0; k < pad; k++) {
1086 			if (blen >= *buflen) {
1087 				error = ERANGE;
1088 				goto done;
1089 			}
1090 			buf[blen++] = 0;
1091 		}
1092 
1093 		/* Get value */
1094 		vlen = *buflen - blen;
1095 		if (foff[index] == 0) {		/* use default value */
1096 			error = ng_get_composite_elem_default(type, index,
1097 			    start, buf + blen, &vlen, ctype);
1098 		} else {			/* parse given value */
1099 			*off = foff[index];
1100 			error = INVOKE(etype, parse)(etype,
1101 			    s, off, start, buf + blen, &vlen);
1102 		}
1103 		if (error != 0)
1104 			goto done;
1105 		blen += vlen;
1106 	}
1107 
1108 	/* Make total composite structure size a multiple of its alignment */
1109 	if ((align = ALIGNMENT(type)) != 0) {
1110 		while (blen % align != 0) {
1111 			if (blen >= *buflen) {
1112 				error = ERANGE;
1113 				goto done;
1114 			}
1115 			buf[blen++] = 0;
1116 		}
1117 	}
1118 
1119 	/* Done */
1120 	*buflen = blen;
1121 done:
1122 	FREE(foff, M_NETGRAPH);
1123 	return (error);
1124 }
1125 
1126 /*
1127  * Convert an array or structure from binary to ASCII
1128  */
1129 static int
1130 ng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
1131 	int *off, char *cbuf, int cbuflen, const enum comptype ctype)
1132 {
1133 	const int num = ng_get_composite_len(type, data, data + *off, ctype);
1134 	int nextIndex = 0, didOne = 0;
1135 	int error, index;
1136 
1137 	/* Opening brace/bracket */
1138 	NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '[');
1139 
1140 	/* Do each item */
1141 	for (index = 0; index < num; index++) {
1142 		const struct ng_parse_type *const
1143 		    etype = ng_get_composite_etype(type, index, ctype);
1144 		u_char temp[1024];
1145 
1146 		/* Skip any alignment pad bytes */
1147 		*off += ng_parse_get_elem_pad(type, index, ctype, *off);
1148 
1149 		/* See if element is equal to its default value; skip if so */
1150 		if (*off < sizeof(temp)) {
1151 			int tempsize = sizeof(temp) - *off;
1152 
1153 			bcopy(data, temp, *off);
1154 			if (ng_get_composite_elem_default(type, index, temp,
1155 			      temp + *off, &tempsize, ctype) == 0
1156 			    && bcmp(temp + *off, data + *off, tempsize) == 0) {
1157 				*off += tempsize;
1158 				continue;
1159 			}
1160 		}
1161 
1162 		/* Print name= */
1163 		NG_PARSE_APPEND(" ");
1164 		if (ctype != CT_STRUCT) {
1165 			if (index != nextIndex) {
1166 				nextIndex = index;
1167 				NG_PARSE_APPEND("%d=", index);
1168 			}
1169 			nextIndex++;
1170 		} else {
1171 			const struct ng_parse_struct_info *si = type->info;
1172 
1173 			NG_PARSE_APPEND("%s=", si->fields[index].name);
1174 		}
1175 
1176 		/* Print value */
1177 		if ((error = INVOKE(etype, unparse)
1178 		    (etype, data, off, cbuf, cbuflen)) != 0)
1179 			return (error);
1180 		cbuflen -= strlen(cbuf);
1181 		cbuf += strlen(cbuf);
1182 		didOne = 1;
1183 	}
1184 
1185 	/* Closing brace/bracket */
1186 	NG_PARSE_APPEND("%s%c",
1187 	    didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
1188 	return (0);
1189 }
1190 
1191 /*
1192  * Generate the default value for an element of an array or structure
1193  * Returns EOPNOTSUPP if default value is unspecified.
1194  */
1195 static int
1196 ng_get_composite_elem_default(const struct ng_parse_type *type,
1197 	int index, const u_char *const start, u_char *buf, int *buflen,
1198 	const enum comptype ctype)
1199 {
1200 	const struct ng_parse_type *etype;
1201 	ng_getDefault_t *func;
1202 
1203 	switch (ctype) {
1204 	case CT_STRUCT:
1205 		break;
1206 	case CT_ARRAY:
1207 	    {
1208 		const struct ng_parse_array_info *const ai = type->info;
1209 
1210 		if (ai->getDefault != NULL) {
1211 			return (*ai->getDefault)(type,
1212 			    index, start, buf, buflen);
1213 		}
1214 		break;
1215 	    }
1216 	case CT_FIXEDARRAY:
1217 	    {
1218 		const struct ng_parse_fixedarray_info *const fi = type->info;
1219 
1220 		if (*fi->getDefault != NULL) {
1221 			return (*fi->getDefault)(type,
1222 			    index, start, buf, buflen);
1223 		}
1224 		break;
1225 	    }
1226 	default:
1227 	    panic("%s", __FUNCTION__);
1228 	}
1229 
1230 	/* Default to element type default */
1231 	etype = ng_get_composite_etype(type, index, ctype);
1232 	func = METHOD(etype, getDefault);
1233 	if (func == NULL)
1234 		return (EOPNOTSUPP);
1235 	return (*func)(etype, start, buf, buflen);
1236 }
1237 
1238 /*
1239  * Get the number of elements in a struct, variable or fixed array.
1240  */
1241 static int
1242 ng_get_composite_len(const struct ng_parse_type *type,
1243 	const u_char *const start, const u_char *buf,
1244 	const enum comptype ctype)
1245 {
1246 	switch (ctype) {
1247 	case CT_STRUCT:
1248 	    {
1249 		const struct ng_parse_struct_info *const si = type->info;
1250 		int numFields = 0;
1251 
1252 		for (numFields = 0; ; numFields++) {
1253 			const struct ng_parse_struct_field *const
1254 				fi = &si->fields[numFields];
1255 
1256 			if (fi->name == NULL)
1257 				break;
1258 		}
1259 		return (numFields);
1260 	    }
1261 	case CT_ARRAY:
1262 	    {
1263 		const struct ng_parse_array_info *const ai = type->info;
1264 
1265 		return (*ai->getLength)(type, start, buf);
1266 	    }
1267 	case CT_FIXEDARRAY:
1268 	    {
1269 		const struct ng_parse_fixedarray_info *const fi = type->info;
1270 
1271 		return fi->length;
1272 	    }
1273 	default:
1274 	    panic("%s", __FUNCTION__);
1275 	}
1276 	return (0);
1277 }
1278 
1279 /*
1280  * Return the type of the index'th element of a composite structure
1281  */
1282 static const struct ng_parse_type *
1283 ng_get_composite_etype(const struct ng_parse_type *type,
1284 	int index, const enum comptype ctype)
1285 {
1286 	const struct ng_parse_type *etype = NULL;
1287 
1288 	switch (ctype) {
1289 	case CT_STRUCT:
1290 	    {
1291 		const struct ng_parse_struct_info *const si = type->info;
1292 
1293 		etype = si->fields[index].type;
1294 		break;
1295 	    }
1296 	case CT_ARRAY:
1297 	    {
1298 		const struct ng_parse_array_info *const ai = type->info;
1299 
1300 		etype = ai->elementType;
1301 		break;
1302 	    }
1303 	case CT_FIXEDARRAY:
1304 	    {
1305 		const struct ng_parse_fixedarray_info *const fi = type->info;
1306 
1307 		etype = fi->elementType;
1308 		break;
1309 	    }
1310 	default:
1311 	    panic("%s", __FUNCTION__);
1312 	}
1313 	return (etype);
1314 }
1315 
1316 /*
1317  * Get the number of bytes to skip to align for the next
1318  * element in a composite structure.
1319  */
1320 static int
1321 ng_parse_get_elem_pad(const struct ng_parse_type *type,
1322 	int index, enum comptype ctype, int posn)
1323 {
1324 	const struct ng_parse_type *const
1325 	    etype = ng_get_composite_etype(type, index, ctype);
1326 	int align;
1327 
1328 	/* Get element's alignment, and possibly override */
1329 	align = ALIGNMENT(etype);
1330 	if (ctype == CT_STRUCT) {
1331 		const struct ng_parse_struct_info *si = type->info;
1332 
1333 		if (si->fields[index].alignment != 0)
1334 			align = si->fields[index].alignment;
1335 	}
1336 
1337 	/* Return number of bytes to skip to align */
1338 	return (align ? (align - (posn % align)) % align : 0);
1339 }
1340 
1341 /************************************************************************
1342 			PARSING HELPER ROUTINES
1343  ************************************************************************/
1344 
1345 /*
1346  * Skip over a value
1347  */
1348 static int
1349 ng_parse_skip_value(const char *s, int off0, int *lenp)
1350 {
1351 	int len, nbracket, nbrace;
1352 	int off = off0;
1353 
1354 	len = nbracket = nbrace = 0;
1355 	do {
1356 		switch (ng_parse_get_token(s, &off, &len)) {
1357 		case T_LBRACKET:
1358 			nbracket++;
1359 			break;
1360 		case T_LBRACE:
1361 			nbrace++;
1362 			break;
1363 		case T_RBRACKET:
1364 			if (nbracket-- == 0)
1365 				return (EINVAL);
1366 			break;
1367 		case T_RBRACE:
1368 			if (nbrace-- == 0)
1369 				return (EINVAL);
1370 			break;
1371 		case T_EOF:
1372 			return (EINVAL);
1373 		default:
1374 			break;
1375 		}
1376 		off += len;
1377 	} while (nbracket > 0 || nbrace > 0);
1378 	*lenp = off - off0;
1379 	return (0);
1380 }
1381 
1382 /*
1383  * Find the next token in the string, starting at offset *startp.
1384  * Returns the token type, with *startp pointing to the first char
1385  * and *lenp the length.
1386  */
1387 enum ng_parse_token
1388 ng_parse_get_token(const char *s, int *startp, int *lenp)
1389 {
1390 	char *t;
1391 	int i;
1392 
1393 	while (isspace(s[*startp]))
1394 		(*startp)++;
1395 	switch (s[*startp]) {
1396 	case '\0':
1397 		*lenp = 0;
1398 		return T_EOF;
1399 	case '{':
1400 		*lenp = 1;
1401 		return T_LBRACE;
1402 	case '}':
1403 		*lenp = 1;
1404 		return T_RBRACE;
1405 	case '[':
1406 		*lenp = 1;
1407 		return T_LBRACKET;
1408 	case ']':
1409 		*lenp = 1;
1410 		return T_RBRACKET;
1411 	case '=':
1412 		*lenp = 1;
1413 		return T_EQUALS;
1414 	case '"':
1415 		if ((t = ng_get_string_token(s, startp, lenp)) == NULL)
1416 			return T_ERROR;
1417 		FREE(t, M_NETGRAPH);
1418 		return T_STRING;
1419 	default:
1420 		for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
1421 		    && s[i] != '{' && s[i] != '}' && s[i] != '['
1422 		    && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
1423 			;
1424 		*lenp = i - *startp;
1425 		return T_WORD;
1426 	}
1427 }
1428 
1429 /*
1430  * Get a string token, which must be enclosed in double quotes.
1431  * The normal C backslash escapes are recognized.
1432  */
1433 char *
1434 ng_get_string_token(const char *s, int *startp, int *lenp)
1435 {
1436 	char *cbuf, *p;
1437 	int start, off;
1438 
1439 	while (isspace(s[*startp]))
1440 		(*startp)++;
1441 	start = *startp;
1442 	if (s[*startp] != '"')
1443 		return (NULL);
1444 	MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH, M_NOWAIT);
1445 	if (cbuf == NULL)
1446 		return (NULL);
1447 	strcpy(cbuf, s + start + 1);
1448 	for (off = 1, p = cbuf; *p != '\0'; off++, p++) {
1449 		if (*p == '"') {
1450 			*p = '\0';
1451 			*lenp = off + 1;
1452 			return (cbuf);
1453 		} else if (p[0] == '\\' && p[1] != '\0') {
1454 			int x, k;
1455 			char *v;
1456 
1457 			strcpy(p, p + 1);
1458 			v = p;
1459 			switch (*p) {
1460 			case 't':
1461 				*v = '\t';
1462 				off++;
1463 				continue;
1464 			case 'n':
1465 				*v = '\n';
1466 				off++;
1467 				continue;
1468 			case 'r':
1469 				*v = '\r';
1470 				off++;
1471 				continue;
1472 			case 'v':
1473 				*v =  '\v';
1474 				off++;
1475 				continue;
1476 			case 'f':
1477 				*v =  '\f';
1478 				off++;
1479 				continue;
1480 			case '"':
1481 				*v =  '"';
1482 				off++;
1483 				continue;
1484 			case '0': case '1': case '2': case '3':
1485 			case '4': case '5': case '6': case '7':
1486 				for (x = k = 0;
1487 				    k < 3 && *v >= '0' && *v <= '7'; v++) {
1488 					x = (x << 3) + (*v - '0');
1489 					off++;
1490 				}
1491 				*--v = (char)x;
1492 				break;
1493 			case 'x':
1494 				for (v++, x = k = 0;
1495 				    k < 2 && isxdigit(*v); v++) {
1496 					x = (x << 4) + (isdigit(*v) ?
1497 					      (*v - '0') :
1498 					      (tolower(*v) - 'a' + 10));
1499 					off++;
1500 				}
1501 				*--v = (char)x;
1502 				break;
1503 			default:
1504 				continue;
1505 			}
1506 			strcpy(p, v);
1507 		}
1508 	}
1509 	return (NULL);		/* no closing quote */
1510 }
1511 
1512 /*
1513  * Encode a string so it can be safely put in double quotes.
1514  * Caller must free the result.
1515  */
1516 char *
1517 ng_encode_string(const char *raw)
1518 {
1519 	char *cbuf;
1520 	int off = 0;
1521 
1522 	MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH, M_NOWAIT);
1523 	if (cbuf == NULL)
1524 		return (NULL);
1525 	cbuf[off++] = '"';
1526 	for ( ; *raw != '\0'; raw++) {
1527 		switch (*raw) {
1528 		case '\t':
1529 			cbuf[off++] = '\\';
1530 			cbuf[off++] = 't';
1531 			break;
1532 		case '\f':
1533 			cbuf[off++] = '\\';
1534 			cbuf[off++] = 'f';
1535 			break;
1536 		case '\n':
1537 			cbuf[off++] = '\\';
1538 			cbuf[off++] = 'n';
1539 			break;
1540 		case '\r':
1541 			cbuf[off++] = '\\';
1542 			cbuf[off++] = 'r';
1543 			break;
1544 		case '\v':
1545 			cbuf[off++] = '\\';
1546 			cbuf[off++] = 'v';
1547 			break;
1548 		case '"':
1549 		case '\\':
1550 			cbuf[off++] = '\\';
1551 			cbuf[off++] = *raw;
1552 			break;
1553 		default:
1554 			if (*raw < 0x20 || *raw > 0x7e) {
1555 				off += sprintf(cbuf + off,
1556 				    "\\x%02x", (u_char)*raw);
1557 				break;
1558 			}
1559 			cbuf[off++] = *raw;
1560 			break;
1561 		}
1562 	}
1563 	cbuf[off++] = '"';
1564 	cbuf[off] = '\0';
1565 	return (cbuf);
1566 }
1567 
1568 /************************************************************************
1569 			VIRTUAL METHOD LOOKUP
1570  ************************************************************************/
1571 
1572 static ng_parse_t *
1573 ng_get_parse_method(const struct ng_parse_type *t)
1574 {
1575 	while (t != NULL && t->parse == NULL)
1576 		t = t->supertype;
1577 	return (t ? t->parse : NULL);
1578 }
1579 
1580 static ng_unparse_t *
1581 ng_get_unparse_method(const struct ng_parse_type *t)
1582 {
1583 	while (t != NULL && t->unparse == NULL)
1584 		t = t->supertype;
1585 	return (t ? t->unparse : NULL);
1586 }
1587 
1588 static ng_getDefault_t *
1589 ng_get_getDefault_method(const struct ng_parse_type *t)
1590 {
1591 	while (t != NULL && t->getDefault == NULL)
1592 		t = t->supertype;
1593 	return (t ? t->getDefault : NULL);
1594 }
1595 
1596 static ng_getAlign_t *
1597 ng_get_getAlign_method(const struct ng_parse_type *t)
1598 {
1599 	while (t != NULL && t->getAlign == NULL)
1600 		t = t->supertype;
1601 	return (t ? t->getAlign : NULL);
1602 }
1603 
1604