1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
|
/*
* Dynamic db (proposal, transforms, attributes) handling.
* Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/*
* The strategy is to have (full contained) struct db_prop in db_context
* pointing to ONE dynamically sizable transform vector (trans0).
* Each transform stores attrib. in ONE dyn. sizable attribute vector (attrs0)
* in a "serialized" way (attributes storage is used in linear sequence for
* subsequent transforms).
*
* Resizing for both trans0 and attrs0 is supported:
* - For trans0: quite simple, just allocate and copy trans. vector content
* also update trans_cur (by offset)
* - For attrs0: after allocating and copying attrs, I must rewrite each
* trans->attrs present in trans0; to achieve this, calculate
* attrs pointer offset (new minus old) and iterate over
* each transform "adding" this difference.
* also update attrs_cur (by offset)
*
* db_context structure:
* +---------------------+
* | prop |
* | .protoid |
* | .trans | --+
* | .trans_cnt | |
* +---------------------+ <-+
* | trans0 | ----> { trans#1 | ... | trans#i | ... }
* +---------------------+ ^
* | trans_cur | ----------------------' current transf.
* +---------------------+
* | attrs0 | ----> { attr#1 | ... | attr#j | ... }
* +---------------------+ ^
* | attrs_cur | ---------------------' current attr.
* +---------------------+
* | max_trans,max_attrs | max_trans/attrs: number of elem. of each vector
* +---------------------+
*
* See testing examples at end for interface usage.
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <assert.h>
#include "sysdep.h"
#include "constants.h"
#include "defs.h"
#include "state.h"
#include "log.h"
#include "whack.h"
#include "ikev1_db_ops.h"
#include "show.h"
/*
* stats: do accounting for allocations displayed in db_ops_show_status()
*/
struct db_ops_stats {
int st_curr_cnt; /* current number of allocations */
int st_total_cnt; /* total allocations so far */
size_t st_maxsz; /* max. size requested */
};
#define DB_OPS_ZERO { 0, 0, 0 };
#define DB_OPS_STATS_DESC "{curr_cnt, total_cnt, maxsz}"
#define DB_OPS_STATS_STR(name) name "={%d,%d,%d} "
#define DB_OPS_STATS_F(st) (st).st_curr_cnt, (st).st_total_cnt, \
(int)(st).st_maxsz
static struct db_ops_stats db_context_st = DB_OPS_ZERO;
static struct db_ops_stats db_trans_st = DB_OPS_ZERO;
static struct db_ops_stats db_attrs_st = DB_OPS_ZERO;
static void * alloc_bytes_st(size_t size, const char *str,
struct db_ops_stats *st)
{
void *ptr = alloc_bytes(size, str);
st->st_curr_cnt++;
st->st_total_cnt++;
if (size > st->st_maxsz)
st->st_maxsz = size;
return ptr;
}
#define ALLOC_BYTES_ST(z, s, st) alloc_bytes_st(z, s, &(st));
#define PFREE_ST(p, st) { st.st_curr_cnt--; pfree(p); }
/*
* Initialize db object
*
* max_trans and max_attrs can be 0, will be dynamically expanded
* as a result of "add" operations
*/
static void db_prop_init(struct db_context *ctx, uint8_t protoid, int max_trans,
int max_attrs)
{
ctx->trans0 = NULL;
ctx->attrs0 = NULL;
if (max_trans > 0) {
ctx->trans0 = ALLOC_BYTES_ST(
sizeof(struct db_trans) * max_trans,
"db_context->trans",
db_trans_st);
}
if (max_attrs > 0) {
ctx->attrs0 = ALLOC_BYTES_ST(
sizeof(struct db_attr) * max_attrs,
"db_context->attrs", db_attrs_st);
}
ctx->max_trans = max_trans;
ctx->max_attrs = max_attrs;
ctx->trans_cur = ctx->trans0;
ctx->attrs_cur = ctx->attrs0;
ctx->prop.protoid = protoid;
ctx->prop.trans = ctx->trans0;
ctx->prop.trans_cnt = 0;
}
/* Expand storage for transforms by number delta_trans */
static void db_trans_expand(struct db_context *ctx, int delta_trans)
{
int max_trans = ctx->max_trans + delta_trans;
struct db_trans *const old_trans = ctx->trans0;
struct db_trans *const new_trans = ALLOC_BYTES_ST(sizeof(struct db_trans) * max_trans,
"db_context->trans (expand)", db_trans_st);
memcpy(new_trans, old_trans, ctx->max_trans * sizeof(struct db_trans));
/* update trans0 (obviously) */
ctx->trans0 = ctx->prop.trans = new_trans;
/* update trans_cur (by offset) */
ctx->trans_cur = ctx->trans_cur - old_trans + new_trans;
/* update elem count */
ctx->max_trans = max_trans;
if (old_trans != NULL)
PFREE_ST(old_trans, db_trans_st);
}
/*
* Expand storage for attributes by delta_attrs number AND
* adjust pointers into trans->attr
*/
static void db_attrs_expand(struct db_context *ctx, int delta_attrs)
{
unsigned int ti;
int max_attrs = ctx->max_attrs + delta_attrs;
struct db_attr *const old_attrs = ctx->attrs0;
struct db_attr *const new_attrs = ALLOC_BYTES_ST(sizeof(struct db_attr) * max_attrs,
"db_context->attrs (expand)", db_attrs_st);
memcpy(new_attrs, old_attrs, ctx->max_attrs * sizeof(struct db_attr));
/*
* Relocate pointers into ctx->attrs.
* Note: C addition is NOT associative (due to scaling)
*/
ctx->attrs0 = ctx->attrs0 - old_attrs + new_attrs;
ctx->attrs_cur = ctx->attrs_cur - old_attrs + new_attrs;
for (ti = 0; ti < ctx->prop.trans_cnt; ti++)
ctx->prop.trans[ti].attrs = ctx->prop.trans[ti].attrs - old_attrs + new_attrs;
/* update elem count */
ctx->max_attrs = max_attrs;
if (old_attrs != NULL)
PFREE_ST(old_attrs, db_attrs_st);
}
/* Allocate a new db object */
struct db_context *db_prop_new(uint8_t protoid, int max_trans, int max_attrs)
{
struct db_context *ctx = ALLOC_BYTES_ST(sizeof(struct db_context), "db_context",
db_context_st);
db_prop_init(ctx, protoid, max_trans, max_attrs);
return ctx;
}
/* Free a db object */
void db_destroy(struct db_context *ctx)
{
if (ctx->trans0 != NULL)
PFREE_ST(ctx->trans0, db_trans_st);
if (ctx->attrs0 != NULL)
PFREE_ST(ctx->attrs0, db_attrs_st);
PFREE_ST(ctx, db_context_st);
}
/* Start a new transform, expand trans0 is needed */
void db_trans_add(struct db_context *ctx, uint8_t transid)
{
passert(ctx->trans_cur != NULL);
/* skip incrementing current trans pointer the 1st time*/
if (ctx->trans_cur->attr_cnt != 0)
ctx->trans_cur++;
/*
* Strategy: if more space is needed, expand by
* <current_size>/2 + 1
*
* This happens to produce a "reasonable" sequence
* after few allocations, eg.:
* 0,1,2,4,8,13,20,31,47
*/
if ((ctx->trans_cur - ctx->trans0) >= ctx->max_trans) {
db_trans_expand(ctx, ctx->max_trans / 2 + 1);
}
ctx->trans_cur->transid = transid;
ctx->trans_cur->attrs = ctx->attrs_cur;
ctx->trans_cur->attr_cnt = 0;
ctx->prop.trans_cnt++;
}
/* Add attr copy to current transform, expanding attrs0 if needed */
static void db_attr_add(struct db_context *ctx, const struct db_attr *a)
{
/*
* Strategy: if more space is needed, expand by
* <current_size>/2 + 1
*/
if ((ctx->attrs_cur - ctx->attrs0) >= ctx->max_attrs) {
db_attrs_expand(ctx, ctx->max_attrs / 2 + 1);
}
*ctx->attrs_cur++ = *a;
ctx->trans_cur->attr_cnt++;
}
/*
* Add attr copy (by value) to current transform,
* expanding attrs0 if needed, just calls db_attr_add().
*/
void db_attr_add_values(struct db_context *ctx, enum ikev1_ipsec_attr type, uint16_t val)
{
struct db_attr attr;
/* ??? is this always an Oakley (IKEv1 Phase 1) attribute? */
attr.type.ipsec = type;
attr.val = val;
db_attr_add(ctx, &attr);
}
struct db_prop *db_prop_get(struct db_context *ctx)
{
return &ctx->prop;
}
void show_db_ops_status(struct show *s)
{
show_separator(s);
show(s, "stats db_ops: "
DB_OPS_STATS_DESC " :"
DB_OPS_STATS_STR("context")
DB_OPS_STATS_STR("trans")
DB_OPS_STATS_STR("attrs"),
DB_OPS_STATS_F(db_context_st),
DB_OPS_STATS_F(db_trans_st),
DB_OPS_STATS_F(db_attrs_st));
}
|