1/* $NetBSD: npf_var.c,v 1.3.2.1 2012/06/26 00:07:20 riz Exp $ */ 2 3/*- 4 * Copyright (c) 2011-2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__RCSID("$NetBSD: npf_var.c,v 1.3.2.1 2012/06/26 00:07:20 riz Exp $"); 34 35#include <stdlib.h> 36#include <string.h> 37#include <unistd.h> 38 39#define _NPFVAR_PRIVATE 40#include "npfctl.h" 41 42typedef struct npf_element { 43 void * e_data; 44 int e_type; 45 struct npf_element *e_next; 46} npf_element_t; 47 48struct npfvar { 49 char * v_key; 50 npf_element_t * v_elements; 51 npf_element_t * v_last; 52 int v_type; 53 size_t v_count; 54 void * v_next; 55}; 56 57static npfvar_t * var_list = NULL; 58static size_t var_num = 0; 59 60npfvar_t * 61npfvar_create(const char *name) 62{ 63 npfvar_t *vp = ecalloc(1, sizeof(*vp)); 64 vp->v_key = estrdup(name); 65 var_num++; 66 return vp; 67} 68 69npfvar_t * 70npfvar_lookup(const char *key) 71{ 72 for (npfvar_t *it = var_list; it != NULL; it = it->v_next) 73 if (strcmp(it->v_key, key) == 0) 74 return it; 75 return NULL; 76} 77 78const char * 79npfvar_type(size_t t) 80{ 81 if (t >= __arraycount(npfvar_types)) { 82 return "unknown"; 83 } 84 return npfvar_types[t]; 85} 86 87void 88npfvar_add(npfvar_t *vp) 89{ 90 vp->v_next = var_list; 91 var_list = vp; 92} 93 94npfvar_t * 95npfvar_add_element(npfvar_t *vp, int type, const void *data, size_t len) 96{ 97 npf_element_t *el; 98 99 if (vp->v_count == 0) { 100 vp->v_type = type; 101 } else if (NPFVAR_TYPE(vp->v_type) != NPFVAR_TYPE(type)) { 102 yyerror("element type '%s' does not match variable type '%s'", 103 npfvar_type(type), npfvar_type(vp->v_type)); 104 return NULL; 105 } 106 vp->v_count++; 107 el = ecalloc(1, sizeof(*el)); 108 el->e_data = ecalloc(1, len); 109 el->e_type = type; 110 memcpy(el->e_data, data, len); 111 112 /* Preserve order of insertion. */ 113 if (vp->v_elements == NULL) { 114 vp->v_elements = el; 115 } else { 116 vp->v_last->e_next = el; 117 } 118 vp->v_last = el; 119 return vp; 120} 121 122npfvar_t * 123npfvar_add_elements(npfvar_t *vp, npfvar_t *vp2) 124{ 125 if (vp2 == NULL) 126 return vp; 127 if (vp == NULL) 128 return vp2; 129 130 if (vp->v_elements == NULL) { 131 if (vp2->v_elements) { 132 vp->v_type = vp2->v_type; 133 vp->v_elements = vp2->v_elements; 134 } 135 } else if (vp2->v_elements) { 136 if (NPFVAR_TYPE(vp->v_type) != NPFVAR_TYPE(vp2->v_type)) { 137 yyerror("variable '%s' type '%s' does not match " 138 "variable '%s' type '%s'", vp->v_key, 139 npfvar_type(vp->v_type), 140 vp2->v_key, npfvar_type(vp2->v_type)); 141 return NULL; 142 } 143 vp->v_last->e_next = vp2->v_elements; 144 } 145 if (vp2->v_elements) { 146 vp->v_last = vp2->v_last; 147 vp->v_count += vp2->v_count; 148 vp2->v_elements = NULL; 149 vp2->v_count = 0; 150 vp2->v_last = NULL; 151 } 152 npfvar_destroy(vp2); 153 return vp; 154} 155 156static void 157npfvar_free_elements(npf_element_t *el) 158{ 159 if (el == NULL) 160 return; 161 npfvar_free_elements(el->e_next); 162 free(el->e_data); 163 free(el); 164} 165 166void 167npfvar_destroy(npfvar_t *vp) 168{ 169 npfvar_free_elements(vp->v_elements); 170 free(vp->v_key); 171 free(vp); 172 var_num--; 173} 174 175char * 176npfvar_expand_string(const npfvar_t *vp) 177{ 178 return npfvar_get_data(vp, NPFVAR_STRING, 0); 179} 180 181size_t 182npfvar_get_count(const npfvar_t *vp) 183{ 184 return vp ? vp->v_count : 0; 185} 186 187static void * 188npfvar_get_data1(const npfvar_t *vp, int type, size_t idx, size_t level) 189{ 190 npf_element_t *el; 191 192 if (level >= var_num) { 193 yyerror("variable loop for '%s'", vp->v_key); 194 return NULL; 195 } 196 197 if (vp == NULL) 198 return NULL; 199 200 if (NPFVAR_TYPE(vp->v_type) != NPFVAR_TYPE(type)) { 201 yyerror("variable '%s' is of type '%s' not '%s'", vp->v_key, 202 npfvar_type(vp->v_type), npfvar_type(type)); 203 return NULL; 204 } 205 206 if (vp->v_count <= idx) { 207 yyerror("variable '%s' has only %zu elements, requested %zu", 208 vp->v_key, vp->v_count, idx); 209 return NULL; 210 } 211 212 el = vp->v_elements; 213 while (idx--) { 214 el = el->e_next; 215 } 216 217 if (vp->v_type == NPFVAR_VAR_ID) { 218 npfvar_t *rvp = npfvar_lookup(el->e_data); 219 return npfvar_get_data1(rvp, type, 0, level + 1); 220 } 221 return el->e_data; 222} 223 224static int 225npfvar_get_type1(const npfvar_t *vp, size_t idx, size_t level) 226{ 227 npf_element_t *el; 228 229 if (level >= var_num) { 230 yyerror("variable loop for '%s'", vp->v_key); 231 return -1; 232 } 233 234 if (vp == NULL) 235 return -1; 236 237 if (vp->v_count <= idx) { 238 yyerror("variable '%s' has only %zu elements, requested %zu", 239 vp->v_key, vp->v_count, idx); 240 return -1; 241 } 242 243 el = vp->v_elements; 244 while (idx--) { 245 el = el->e_next; 246 } 247 248 if (vp->v_type == NPFVAR_VAR_ID) { 249 npfvar_t *rvp = npfvar_lookup(el->e_data); 250 return npfvar_get_type1(rvp, 0, level + 1); 251 } 252 return el->e_type; 253} 254 255int 256npfvar_get_type(const npfvar_t *vp, size_t idx) 257{ 258 return npfvar_get_type1(vp, idx, 0); 259} 260 261void * 262npfvar_get_data(const npfvar_t *vp, int type, size_t idx) 263{ 264 return npfvar_get_data1(vp, type, idx, 0); 265} 266