1 1.1 rmind /*- 2 1.15 joe * Copyright (c) 2011-2025 The NetBSD Foundation, Inc. 3 1.1 rmind * All rights reserved. 4 1.1 rmind * 5 1.1 rmind * This code is derived from software contributed to The NetBSD Foundation 6 1.1 rmind * by Christos Zoulas. 7 1.1 rmind * 8 1.1 rmind * Redistribution and use in source and binary forms, with or without 9 1.1 rmind * modification, are permitted provided that the following conditions 10 1.1 rmind * are met: 11 1.1 rmind * 1. Redistributions of source code must retain the above copyright 12 1.1 rmind * notice, this list of conditions and the following disclaimer. 13 1.1 rmind * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 rmind * notice, this list of conditions and the following disclaimer in the 15 1.1 rmind * documentation and/or other materials provided with the distribution. 16 1.1 rmind * 17 1.1 rmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 1.1 rmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 1.1 rmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 1.1 rmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 1.1 rmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 1.1 rmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 1.1 rmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 1.1 rmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 1.1 rmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 1.1 rmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 1.1 rmind * POSSIBILITY OF SUCH DAMAGE. 28 1.1 rmind */ 29 1.1 rmind 30 1.13 rmind /* 31 1.13 rmind * NPF variables are used to build the intermediate representation (IR) 32 1.13 rmind * of the configuration grammar. They represent primitive types (strings, 33 1.13 rmind * numbers, etc) as well as complex types (address and mask, table, etc). 34 1.13 rmind */ 35 1.13 rmind 36 1.1 rmind #include <sys/cdefs.h> 37 1.16 joe __RCSID("$NetBSD: npf_var.c,v 1.16 2025/08/20 11:03:59 joe Exp $"); 38 1.1 rmind 39 1.1 rmind #include <stdlib.h> 40 1.1 rmind #include <string.h> 41 1.1 rmind #include <unistd.h> 42 1.1 rmind 43 1.1 rmind #define _NPFVAR_PRIVATE 44 1.1 rmind #include "npfctl.h" 45 1.1 rmind 46 1.1 rmind typedef struct npf_element { 47 1.1 rmind void * e_data; 48 1.13 rmind unsigned e_type; 49 1.1 rmind struct npf_element *e_next; 50 1.1 rmind } npf_element_t; 51 1.1 rmind 52 1.1 rmind struct npfvar { 53 1.1 rmind char * v_key; 54 1.1 rmind npf_element_t * v_elements; 55 1.1 rmind npf_element_t * v_last; 56 1.1 rmind size_t v_count; 57 1.1 rmind void * v_next; 58 1.1 rmind }; 59 1.1 rmind 60 1.1 rmind static npfvar_t * var_list = NULL; 61 1.2 christos static size_t var_num = 0; 62 1.1 rmind 63 1.1 rmind npfvar_t * 64 1.8 rmind npfvar_create(void) 65 1.1 rmind { 66 1.7 rmind npfvar_t *vp = ecalloc(1, sizeof(*vp)); 67 1.5 rmind var_num++; 68 1.1 rmind return vp; 69 1.1 rmind } 70 1.1 rmind 71 1.1 rmind npfvar_t * 72 1.1 rmind npfvar_lookup(const char *key) 73 1.1 rmind { 74 1.1 rmind for (npfvar_t *it = var_list; it != NULL; it = it->v_next) 75 1.1 rmind if (strcmp(it->v_key, key) == 0) 76 1.1 rmind return it; 77 1.1 rmind return NULL; 78 1.1 rmind } 79 1.1 rmind 80 1.1 rmind const char * 81 1.1 rmind npfvar_type(size_t t) 82 1.1 rmind { 83 1.1 rmind if (t >= __arraycount(npfvar_types)) { 84 1.1 rmind return "unknown"; 85 1.1 rmind } 86 1.1 rmind return npfvar_types[t]; 87 1.1 rmind } 88 1.1 rmind 89 1.1 rmind void 90 1.8 rmind npfvar_add(npfvar_t *vp, const char *name) 91 1.1 rmind { 92 1.8 rmind vp->v_key = estrdup(name); 93 1.1 rmind vp->v_next = var_list; 94 1.1 rmind var_list = vp; 95 1.1 rmind } 96 1.1 rmind 97 1.1 rmind npfvar_t * 98 1.13 rmind npfvar_create_element(unsigned type, const void *data, size_t len) 99 1.8 rmind { 100 1.8 rmind npfvar_t *vp = npfvar_create(); 101 1.8 rmind return npfvar_add_element(vp, type, data, len); 102 1.8 rmind } 103 1.8 rmind 104 1.8 rmind npfvar_t * 105 1.13 rmind npfvar_create_from_string(unsigned type, const char *string) 106 1.8 rmind { 107 1.8 rmind return npfvar_create_element(type, string, strlen(string) + 1); 108 1.8 rmind } 109 1.8 rmind 110 1.8 rmind npfvar_t * 111 1.13 rmind npfvar_add_element(npfvar_t *vp, unsigned type, const void *data, size_t len) 112 1.1 rmind { 113 1.1 rmind npf_element_t *el; 114 1.1 rmind 115 1.7 rmind el = ecalloc(1, sizeof(*el)); 116 1.7 rmind el->e_data = ecalloc(1, len); 117 1.4 christos el->e_type = type; 118 1.1 rmind memcpy(el->e_data, data, len); 119 1.1 rmind 120 1.13 rmind /* Preserve the order of insertion. */ 121 1.1 rmind if (vp->v_elements == NULL) { 122 1.1 rmind vp->v_elements = el; 123 1.1 rmind } else { 124 1.1 rmind vp->v_last->e_next = el; 125 1.1 rmind } 126 1.1 rmind vp->v_last = el; 127 1.13 rmind vp->v_count++; 128 1.1 rmind return vp; 129 1.1 rmind } 130 1.1 rmind 131 1.1 rmind npfvar_t * 132 1.1 rmind npfvar_add_elements(npfvar_t *vp, npfvar_t *vp2) 133 1.1 rmind { 134 1.1 rmind if (vp2 == NULL) 135 1.1 rmind return vp; 136 1.1 rmind if (vp == NULL) 137 1.1 rmind return vp2; 138 1.1 rmind 139 1.1 rmind if (vp->v_elements == NULL) { 140 1.1 rmind if (vp2->v_elements) { 141 1.1 rmind vp->v_elements = vp2->v_elements; 142 1.1 rmind } 143 1.1 rmind } else if (vp2->v_elements) { 144 1.1 rmind vp->v_last->e_next = vp2->v_elements; 145 1.1 rmind } 146 1.1 rmind if (vp2->v_elements) { 147 1.1 rmind vp->v_last = vp2->v_last; 148 1.1 rmind vp->v_count += vp2->v_count; 149 1.1 rmind vp2->v_elements = NULL; 150 1.1 rmind vp2->v_count = 0; 151 1.1 rmind vp2->v_last = NULL; 152 1.1 rmind } 153 1.1 rmind npfvar_destroy(vp2); 154 1.1 rmind return vp; 155 1.1 rmind } 156 1.1 rmind 157 1.1 rmind static void 158 1.1 rmind npfvar_free_elements(npf_element_t *el) 159 1.1 rmind { 160 1.1 rmind if (el == NULL) 161 1.1 rmind return; 162 1.1 rmind npfvar_free_elements(el->e_next); 163 1.1 rmind free(el->e_data); 164 1.1 rmind free(el); 165 1.1 rmind } 166 1.1 rmind 167 1.1 rmind void 168 1.1 rmind npfvar_destroy(npfvar_t *vp) 169 1.1 rmind { 170 1.1 rmind npfvar_free_elements(vp->v_elements); 171 1.1 rmind free(vp->v_key); 172 1.1 rmind free(vp); 173 1.5 rmind var_num--; 174 1.1 rmind } 175 1.1 rmind 176 1.1 rmind char * 177 1.1 rmind npfvar_expand_string(const npfvar_t *vp) 178 1.1 rmind { 179 1.12 rmind if (npfvar_get_count(vp) != 1) { 180 1.13 rmind yyerror("variable '%s' has multiple elements", vp->v_key); 181 1.13 rmind return NULL; 182 1.12 rmind } 183 1.1 rmind return npfvar_get_data(vp, NPFVAR_STRING, 0); 184 1.1 rmind } 185 1.1 rmind 186 1.14 joe uint32_t 187 1.14 joe npfvar_expand_number(const npfvar_t *vp) 188 1.14 joe { 189 1.14 joe uint32_t *number; 190 1.14 joe if (npfvar_get_count(vp) != 1) { 191 1.14 joe yyerror("variable '%s' has multiple elements", vp->v_key); 192 1.14 joe } 193 1.14 joe number = (uint32_t *)npfvar_get_data(vp, NPFVAR_NUM, 0); 194 1.14 joe return *number; 195 1.14 joe } 196 1.14 joe 197 1.14 joe void 198 1.14 joe npf_var_rid(char *var_id, rid_parser parser, uint32_t *rid, const char *ridt) 199 1.14 joe { 200 1.14 joe npfvar_t *vp = npfvar_lookup(var_id); 201 1.14 joe int type = npfvar_get_type(vp, 0); 202 1.14 joe char *rid_type; 203 1.14 joe 204 1.14 joe switch (type) { 205 1.14 joe case NPFVAR_IDENTIFIER: 206 1.14 joe case NPFVAR_STRING: 207 1.14 joe rid_type = npfvar_expand_string(vp); 208 1.14 joe if (parser(rid_type, rid) == -1) { 209 1.14 joe yyerror("unknown %s %s", var_id, ridt); 210 1.14 joe } 211 1.14 joe break; 212 1.14 joe case NPFVAR_NUM: 213 1.14 joe *rid = npfvar_expand_number(vp); 214 1.14 joe break; 215 1.14 joe case -1: 216 1.14 joe yyerror("undefined variable '%s'", var_id); 217 1.14 joe break; 218 1.14 joe default: 219 1.14 joe yyerror("wrong variable '%s' type '%s' for %s id", 220 1.14 joe var_id, npfvar_type(type), ridt); 221 1.14 joe break; 222 1.14 joe } 223 1.14 joe } 224 1.14 joe 225 1.1 rmind size_t 226 1.1 rmind npfvar_get_count(const npfvar_t *vp) 227 1.1 rmind { 228 1.1 rmind return vp ? vp->v_count : 0; 229 1.1 rmind } 230 1.1 rmind 231 1.13 rmind static npf_element_t * 232 1.13 rmind npfvar_get_element(const npfvar_t *vp, size_t idx, size_t level) 233 1.1 rmind { 234 1.1 rmind npf_element_t *el; 235 1.1 rmind 236 1.13 rmind /* 237 1.13 rmind * Verify the parameters. 238 1.13 rmind */ 239 1.13 rmind if (vp == NULL) { 240 1.2 christos return NULL; 241 1.2 christos } 242 1.13 rmind if (level >= var_num) { 243 1.13 rmind yyerror("circular dependency for variable '%s'", vp->v_key); 244 1.1 rmind return NULL; 245 1.1 rmind } 246 1.1 rmind if (vp->v_count <= idx) { 247 1.1 rmind yyerror("variable '%s' has only %zu elements, requested %zu", 248 1.1 rmind vp->v_key, vp->v_count, idx); 249 1.1 rmind return NULL; 250 1.1 rmind } 251 1.1 rmind 252 1.13 rmind /* 253 1.13 rmind * Get the element at the given index. 254 1.13 rmind */ 255 1.1 rmind el = vp->v_elements; 256 1.1 rmind while (idx--) { 257 1.1 rmind el = el->e_next; 258 1.1 rmind } 259 1.2 christos 260 1.16 joe return el; 261 1.16 joe } 262 1.16 joe 263 1.16 joe /* 264 1.16 joe * now we can return a VAR_ID to be fully resolved 265 1.16 joe * and fleshed out in filter rules in both type and data 266 1.16 joe */ 267 1.16 joe void * 268 1.16 joe npfvar_getfilt_data(const npfvar_t *vp, unsigned type, size_t idx) 269 1.16 joe { 270 1.16 joe npf_element_t *el = npfvar_get_element(vp, idx, 0); 271 1.16 joe 272 1.16 joe if (!el) 273 1.16 joe return NULL; 274 1.16 joe 275 1.16 joe if (el && NPFVAR_TYPE(el->e_type) != NPFVAR_TYPE(type)) { 276 1.16 joe yyerror("variable '%s' element %zu " 277 1.16 joe "is of type '%s' rather than '%s'", vp->v_key, 278 1.16 joe idx, npfvar_type(el->e_type), npfvar_type(type)); 279 1.16 joe return NULL; 280 1.4 christos } 281 1.16 joe return el->e_data; 282 1.16 joe } 283 1.16 joe 284 1.16 joe int 285 1.16 joe npfvar_getfilt_type(const npfvar_t *vp, size_t idx) 286 1.16 joe { 287 1.16 joe npf_element_t *el = npfvar_get_element(vp, idx, 0); 288 1.16 joe return el ? (int)el->e_type : -1; 289 1.4 christos } 290 1.4 christos 291 1.4 christos int 292 1.4 christos npfvar_get_type(const npfvar_t *vp, size_t idx) 293 1.4 christos { 294 1.13 rmind npf_element_t *el = npfvar_get_element(vp, idx, 0); 295 1.16 joe 296 1.16 joe if (!el) 297 1.16 joe return -1; 298 1.16 joe 299 1.16 joe /* 300 1.16 joe * Resolve if it is a reference to another variable. 301 1.16 joe */ 302 1.16 joe if (el->e_type == NPFVAR_VAR_ID) { 303 1.16 joe const npfvar_t *rvp = npfvar_lookup(el->e_data); 304 1.16 joe if (rvp == NULL) 305 1.16 joe yyerror("variable not found"); 306 1.16 joe 307 1.16 joe return npfvar_get_type(rvp, idx); 308 1.16 joe } 309 1.16 joe return (int)el->e_type; 310 1.4 christos } 311 1.4 christos 312 1.2 christos void * 313 1.13 rmind npfvar_get_data(const npfvar_t *vp, unsigned type, size_t idx) 314 1.2 christos { 315 1.13 rmind npf_element_t *el = npfvar_get_element(vp, idx, 0); 316 1.13 rmind 317 1.16 joe if (!el) 318 1.16 joe return NULL; 319 1.16 joe 320 1.16 joe /* 321 1.16 joe * Resolve if it is a reference to another variable. 322 1.16 joe */ 323 1.16 joe if (el->e_type == NPFVAR_VAR_ID) { 324 1.16 joe const npfvar_t *rvp = npfvar_lookup(el->e_data); 325 1.16 joe if (rvp == NULL) 326 1.16 joe yyerror("variable not found"); 327 1.16 joe 328 1.16 joe return npfvar_get_data(rvp, type, idx); 329 1.16 joe } 330 1.16 joe 331 1.13 rmind if (el && NPFVAR_TYPE(el->e_type) != NPFVAR_TYPE(type)) { 332 1.13 rmind yyerror("variable '%s' element %zu " 333 1.13 rmind "is of type '%s' rather than '%s'", vp->v_key, 334 1.13 rmind idx, npfvar_type(el->e_type), npfvar_type(type)); 335 1.13 rmind return NULL; 336 1.13 rmind } 337 1.13 rmind return el->e_data; 338 1.2 christos } 339