2 * Dynamic db (proposal, transforms, attributes) handling.
3 * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
5 * $Id: db_ops.c,v 1.3 2006-03-23 01:19:17 steveb Exp $
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * The stratedy is to have (full contained) struct db_prop in db_context
20 * pointing to ONE dynamically sizable transform vector (trans0).
21 * Each transform stores attrib. in ONE dyn. sizable attribute vector (attrs0)
22 * in a "serialized" way (attributes storage is used in linear sequence for
23 * subsecuent transforms).
25 * Resizing for both trans0 and attrs0 is supported:
26 * - For trans0: quite simple, just allocate and copy trans. vector content
27 * also update trans_cur (by offset)
28 * - For attrs0: after allocating and copying attrs, I must rewrite each
29 * trans->attrs present in trans0; to achieve this, calculate
30 * attrs pointer offset (new minus old) and iterate over
31 * each transform "adding" this difference.
32 * also update attrs_cur (by offset)
34 * db_context structure:
35 * +---------------------+
40 * +---------------------+ <-+
41 * | trans0 | ----> { trans#1 | ... | trans#i | ... }
42 * +---------------------+ ^
43 * | trans_cur | ----------------------' current transf.
44 * +---------------------+
45 * | attrs0 | ----> { attr#1 | ... | attr#j | ... }
46 * +---------------------+ ^
47 * | attrs_cur | ---------------------' current attr.
48 * +---------------------+
49 * | max_trans,max_attrs | max_trans/attrs: number of elem. of each vector
50 * +---------------------+
52 * See testing examples at end for interface usage.
58 #include <sys/types.h>
62 #include "constants.h"
75 #define passert(x) assert(x)
76 extern int debug; /* eg: spi.c */
77 #define DBG(cond, action) { if (debug) { action ; } }
78 #define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
79 #define alloc_thing(thing, name) alloc_bytes(sizeof (thing), name)
80 void * alloc_bytes(size_t size, const char *name) {
83 fprintf(stderr, "unable to malloc %lu bytes for %s",
84 (unsigned long) size, name);
85 memset(p, '\0', size);
88 #define pfreeany(ptr) free(ptr)
95 * Because of the single-threaded nature of pluto/spdb.c,
96 * alloc()/free() is exercised many times with very small
98 * Just caching last object (currently it will select the
99 * largest) will avoid this allocation mas^Wperturbations
102 struct db_ops_alloc_cache {
108 #ifndef NO_DB_OPS_STATS
110 * stats: do account for allocations
111 * displayed in db_ops_show_status()
113 struct db_ops_stats {
114 int st_curr_cnt; /* current number of allocations */
115 int st_total_cnt; /* total allocations so far */
116 size_t st_maxsz; /* max. size requested */
118 #define DB_OPS_ZERO { 0, 0, 0};
119 #define DB_OPS_STATS_DESC "{curr_cnt, total_cnt, maxsz}"
120 #define DB_OPS_STATS_STR(name) name "={%d,%d,%d} "
121 #define DB_OPS_STATS_F(st) (st).st_curr_cnt, (st).st_total_cnt, (st).st_maxsz
122 static struct db_ops_stats db_context_st = DB_OPS_ZERO;
123 static struct db_ops_stats db_trans_st = DB_OPS_ZERO;
124 static struct db_ops_stats db_attrs_st = DB_OPS_ZERO;
125 static __inline__ void * alloc_bytes_st (size_t size, const char *str, struct db_ops_stats *st)
127 void *ptr = alloc_bytes(size, str);
131 if (size > st->st_maxsz) st->st_maxsz=size;
135 #define ALLOC_BYTES_ST(z,s,st) alloc_bytes_st(z, s, &st);
136 #define PFREE_ST(p,st) do { st.st_curr_cnt--; pfree(p); } while (0);
140 #define ALLOC_BYTES_ST(z,s,n) alloc_bytes(z, s);
141 #define PFREE_ST(p,n) pfree(p);
143 #endif /* NO_DB_OPS_STATS */
144 /* Initialize db object
145 * max_trans and max_attrs can be 0, will be dynamically expanded
146 * as a result of "add" operations
149 db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs)
156 if (max_trans > 0) { /* quite silly if not */
157 ctx->trans0 = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans,
158 "db_context->trans", db_trans_st);
159 if (!ctx->trans0) goto out;
162 if (max_attrs > 0) { /* quite silly if not */
163 ctx->attrs0 = ALLOC_BYTES_ST (sizeof (struct db_attr) * max_attrs,
164 "db_context->attrs", db_attrs_st);
165 if (!ctx->attrs0) goto out;
169 if (ret < 0 && ctx->trans0) {
170 PFREE_ST(ctx->trans0, db_trans_st);
173 ctx->max_trans = max_trans;
174 ctx->max_attrs = max_attrs;
175 ctx->trans_cur = ctx->trans0;
176 ctx->attrs_cur = ctx->attrs0;
177 ctx->prop.protoid = protoid;
178 ctx->prop.trans = ctx->trans0;
179 ctx->prop.trans_cnt = 0;
183 #define INCR_POINTER(PT, OFF) PT = (void *)((char *)PT + OFF)
185 /* Expand storage for transforms by number delta_trans */
187 db_trans_expand(struct db_context *ctx, int delta_trans)
190 struct db_trans *new_trans, *old_trans;
191 int max_trans = ctx->max_trans + delta_trans;
194 old_trans = ctx->trans0;
195 new_trans = alloc_bytes ( sizeof (struct db_trans) * max_trans,
196 "db_context->trans (expand)");
199 memcpy(new_trans, old_trans, ctx->max_trans * sizeof(struct db_trans));
201 /* update trans0 (obviously) */
202 ctx->trans0 = ctx->prop.trans = new_trans;
203 /* update trans_cur (by offset) */
204 offset = (char *)(new_trans) - (char *)(old_trans);
205 INCR_POINTER(ctx->trans_cur, offset);
206 /* update elem count */
207 ctx->max_trans = max_trans;
215 * Expand storage for attributes by delta_attrs number AND
216 * rewrite trans->attr pointers
219 db_attrs_expand(struct db_context *ctx, int delta_attrs)
222 struct db_attr *new_attrs, *old_attrs;
225 int max_attrs = ctx->max_attrs + delta_attrs;
228 old_attrs = ctx->attrs0;
229 new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs,
230 "db_context->attrs (expand)", db_attrs_st);
234 memcpy(new_attrs, old_attrs, ctx->max_attrs * sizeof(struct db_attr));
236 /* update attrs0 and attrs_cur (obviously) */
237 offset = (char *)(new_attrs) - (char *)(old_attrs);
238 INCR_POINTER(ctx->attrs0, offset);
239 INCR_POINTER(ctx->attrs_cur, offset);
240 /* for each transform, rewrite attrs pointer by offsetting it */
241 for (t=ctx->prop.trans, ti=0; ti < ctx->prop.trans_cnt; t++, ti++) {
242 INCR_POINTER(t->attrs, offset);
244 /* update elem count */
245 ctx->max_attrs = max_attrs;
246 PFREE_ST(old_attrs, db_attrs_st);
251 /* Allocate a new db object */
253 db_prop_new(u_int8_t protoid, int max_trans, int max_attrs)
255 struct db_context *ctx;
256 ctx = ALLOC_BYTES_ST ( sizeof (struct db_context), "db_context", db_context_st);
259 if (db_prop_init(ctx, protoid, max_trans, max_attrs) < 0) {
260 PFREE_ST(ctx, db_context_st);
266 /* Free a db object */
268 db_destroy(struct db_context *ctx)
270 PFREE_ST(ctx->trans0, db_trans_st);
271 PFREE_ST(ctx->attrs0, db_attrs_st);
272 PFREE_ST(ctx, db_context_st);
274 /* Start a new transform, expand trans0 is needed */
276 db_trans_add(struct db_context *ctx, u_int8_t transid)
278 /* skip incrementing current trans pointer the 1st time*/
279 if (ctx->trans_cur && ctx->trans_cur->attr_cnt)
282 * Strategy: if more space is needed, expand by
283 * <current_size>/2 + 1
285 * This happens to produce a "reasonable" sequence
286 * after few allocations, eg.:
287 * 0,1,2,4,8,13,20,31,47
289 if ((ctx->trans_cur - ctx->trans0) >= ctx->max_trans) {
290 /* XXX:jjo if fails should shout and flag it */
291 if (db_trans_expand(ctx, ctx->max_trans/2 + 1)<0)
294 ctx->trans_cur->transid = transid;
295 ctx->trans_cur->attrs=ctx->attrs_cur;
296 ctx->trans_cur->attr_cnt = 0;
297 ctx->prop.trans_cnt++;
300 /* Add attr copy to current transform, expanding attrs0 if needed */
302 db_attr_add(struct db_context *ctx, const struct db_attr *a)
305 * Strategy: if more space is needed, expand by
306 * <current_size>/2 + 1
308 if ((ctx->attrs_cur - ctx->attrs0) >= ctx->max_attrs) {
309 /* XXX:jjo if fails should shout and flag it */
310 if (db_attrs_expand(ctx, ctx->max_attrs/2 + 1) < 0)
313 *ctx->attrs_cur++=*a;
314 ctx->trans_cur->attr_cnt++;
317 /* Add attr copy (by value) to current transform,
318 * expanding attrs0 if needed, just calls db_attr_add().
321 db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val)
326 return db_attr_add (ctx, &attr);
329 * From below to end just testing stuff ....
331 #ifndef NO_DB_OPS_STATS
333 db_ops_show_status(void)
335 whack_log(RC_COMMENT, "stats : "
336 DB_OPS_STATS_DESC " :"
337 DB_OPS_STATS_STR("context")
338 DB_OPS_STATS_STR("trans")
339 DB_OPS_STATS_STR("attrs"),
340 DB_OPS_STATS_F(db_context_st),
341 DB_OPS_STATS_F(db_trans_st),
342 DB_OPS_STATS_F(db_attrs_st)
346 #endif /* NO_DB_OPS_STATS */
348 static void db_prop_print(struct db_prop *p)
353 enum_names *n, *n_at, *n_av;
354 printf("protoid=\"%s\"\n", enum_name(&protocol_names, p->protoid));
355 for (ti=0, t=p->trans; ti< p->trans_cnt; ti++, t++) {
356 switch( t->transid) {
358 n=&isakmp_transformid_names;break;
359 case PROTO_IPSEC_ESP:
360 n=&esp_transformid_names;break;
364 printf(" transid=\"%s\"\n",
365 enum_name(n, t->transid));
366 for (ai=0, a=t->attrs; ai < t->attr_cnt; ai++, a++) {
368 switch( t->transid) {
370 n_at=&oakley_attr_names;
371 i=a->type|ISAKMP_ATTR_AF_TV;
372 n_av=oakley_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
374 case PROTO_IPSEC_ESP:
375 n_at=&ipsec_attr_names;
376 i=a->type|ISAKMP_ATTR_AF_TV;
377 n_av=ipsec_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
382 printf(" type=\"%s\" value=\"%s\"\n",
384 enum_name(n_av, a->val));
389 static void db_print(struct db_context *ctx)
391 printf("trans_cur diff=%d, attrs_cur diff=%d\n",
392 ctx->trans_cur - ctx->trans0,
393 ctx->attrs_cur - ctx->attrs0);
394 db_prop_print(&ctx->prop);
398 passert_fail(const char *pred_str, const char *file_str, unsigned long line_no);
401 passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
403 fprintf(stderr, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
404 abort(); /* exiting correctly doesn't always work */
407 struct db_context *ctx=db_prop_new(PROTO_ISAKMP, 0, 0);
408 db_trans_add(ctx, KEY_IKE);
409 db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_DES_CBC);
410 db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
411 db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
412 db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024);
413 db_trans_add(ctx, KEY_IKE);
414 db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC);
415 db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
416 db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
417 db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024);
418 db_trans_add(ctx, KEY_IKE);
419 db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_AES_CBC);
420 db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
421 db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY);
422 db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536);
423 db_trans_add(ctx, ESP_3DES);
424 db_attr_add_values(ctx, AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1);
425 db_trans_add(ctx, ESP_DES);
426 db_attr_add_values(ctx, AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1);