1 /* $NetBSD: npf_var.c,v 1.4 2012/02/26 21:50:05 christos 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.4 2012/02/26 21:50:05 christos Exp $"); 34 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #define _NPFVAR_PRIVATE 40 #include "npfctl.h" 41 42 typedef struct npf_element { 43 void * e_data; 44 int e_type; 45 struct npf_element *e_next; 46 } npf_element_t; 47 48 struct 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 57 static npfvar_t * var_list = NULL; 58 static size_t var_num = 0; 59 60 npfvar_t * 61 npfvar_create(const char *name) 62 { 63 npfvar_t *vp = zalloc(sizeof(*vp)); 64 vp->v_key = xstrdup(name); 65 return vp; 66 } 67 68 npfvar_t * 69 npfvar_lookup(const char *key) 70 { 71 for (npfvar_t *it = var_list; it != NULL; it = it->v_next) 72 if (strcmp(it->v_key, key) == 0) 73 return it; 74 return NULL; 75 } 76 77 const char * 78 npfvar_type(size_t t) 79 { 80 if (t >= __arraycount(npfvar_types)) { 81 return "unknown"; 82 } 83 return npfvar_types[t]; 84 } 85 86 void 87 npfvar_add(npfvar_t *vp) 88 { 89 vp->v_next = var_list; 90 var_list = vp; 91 var_num++; 92 } 93 94 npfvar_t * 95 npfvar_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 = zalloc(sizeof(*el)); 108 el->e_data = zalloc(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 122 npfvar_t * 123 npfvar_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 156 static void 157 npfvar_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 166 void 167 npfvar_destroy(npfvar_t *vp) 168 { 169 npfvar_free_elements(vp->v_elements); 170 free(vp->v_key); 171 free(vp); 172 } 173 174 char * 175 npfvar_expand_string(const npfvar_t *vp) 176 { 177 return npfvar_get_data(vp, NPFVAR_STRING, 0); 178 } 179 180 size_t 181 npfvar_get_count(const npfvar_t *vp) 182 { 183 return vp ? vp->v_count : 0; 184 } 185 186 static void * 187 npfvar_get_data1(const npfvar_t *vp, int type, size_t idx, size_t level) 188 { 189 npf_element_t *el; 190 191 if (level >= var_num) { 192 yyerror("variable loop for '%s'", vp->v_key); 193 return NULL; 194 } 195 196 if (vp == NULL) 197 return NULL; 198 199 if (NPFVAR_TYPE(vp->v_type) != NPFVAR_TYPE(type)) { 200 yyerror("variable '%s' is of type '%s' not '%s'", vp->v_key, 201 npfvar_type(vp->v_type), npfvar_type(type)); 202 return NULL; 203 } 204 205 if (vp->v_count <= idx) { 206 yyerror("variable '%s' has only %zu elements, requested %zu", 207 vp->v_key, vp->v_count, idx); 208 return NULL; 209 } 210 211 el = vp->v_elements; 212 while (idx--) { 213 el = el->e_next; 214 } 215 216 if (vp->v_type == NPFVAR_VAR_ID) { 217 npfvar_t *rvp = npfvar_lookup(el->e_data); 218 return npfvar_get_data1(rvp, type, 0, level + 1); 219 } 220 return el->e_data; 221 } 222 223 static int 224 npfvar_get_type1(const npfvar_t *vp, size_t idx, size_t level) 225 { 226 npf_element_t *el; 227 228 if (level >= var_num) { 229 yyerror("variable loop for '%s'", vp->v_key); 230 return -1; 231 } 232 233 if (vp == NULL) 234 return -1; 235 236 if (vp->v_count <= idx) { 237 yyerror("variable '%s' has only %zu elements, requested %zu", 238 vp->v_key, vp->v_count, idx); 239 return -1; 240 } 241 242 el = vp->v_elements; 243 while (idx--) { 244 el = el->e_next; 245 } 246 247 if (vp->v_type == NPFVAR_VAR_ID) { 248 npfvar_t *rvp = npfvar_lookup(el->e_data); 249 return npfvar_get_type1(rvp, 0, level + 1); 250 } 251 return el->e_type; 252 } 253 254 int 255 npfvar_get_type(const npfvar_t *vp, size_t idx) 256 { 257 return npfvar_get_type1(vp, idx, 0); 258 } 259 260 void * 261 npfvar_get_data(const npfvar_t *vp, int type, size_t idx) 262 { 263 return npfvar_get_data1(vp, type, idx, 0); 264 } 265