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