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