1 /* Dynamic db (proposal, transforms, attributes) handling.
2 * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * RCSID $Id: db_ops.c,v 1.4 2005/04/07 20:13:44 as Exp $
18 * The stratedy is to have (full contained) struct db_prop in db_context
19 * pointing to ONE dynamically sizable transform vector (trans0).
20 * Each transform stores attrib. in ONE dyn. sizable attribute vector (attrs0)
21 * in a "serialized" way (attributes storage is used in linear sequence for
22 * subsecuent transforms).
24 * Resizing for both trans0 and attrs0 is supported:
25 * - For trans0: quite simple, just allocate and copy trans. vector content
26 * also update trans_cur (by offset)
27 * - For attrs0: after allocating and copying attrs, I must rewrite each
28 * trans->attrs present in trans0; to achieve this, calculate
29 * attrs pointer offset (new minus old) and iterate over
30 * each transform "adding" this difference.
31 * also update attrs_cur (by offset)
33 * db_context structure:
34 * +---------------------+
39 * +---------------------+ <-+
40 * | trans0 | ----> { trans#1 | ... | trans#i | ... }
41 * +---------------------+ ^
42 * | trans_cur | ----------------------' current transf.
43 * +---------------------+
44 * | attrs0 | ----> { attr#1 | ... | attr#j | ... }
45 * +---------------------+ ^
46 * | attrs_cur | ---------------------' current attr.
47 * +---------------------+
48 * | max_trans,max_attrs | max_trans/attrs: number of elem. of each vector
49 * +---------------------+
51 * See testing examples at end for interface usage.
57 #include <sys/types.h>
61 #include "constants.h"
74 #define passert(x) assert(x)
75 extern int debug
; /* eg: spi.c */
76 #define DBG(cond, action) { if (debug) { action ; } }
77 #define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
78 #define alloc_thing(thing, name) alloc_bytes(sizeof (thing), name)
79 void * alloc_bytes(size_t size
, const char *name
) {
82 fprintf(stderr
, "unable to malloc %lu bytes for %s",
83 (unsigned long) size
, name
);
84 memset(p
, '\0', size
);
87 #define pfreeany(ptr) free(ptr)
94 * Because of the single-threaded nature of pluto/spdb.c,
95 * alloc()/free() is exercised many times with very small
97 * Just caching last object (currently it will select the
98 * largest) will avoid this allocation mas^Wperturbations
101 struct db_ops_alloc_cache
{
107 #ifndef NO_DB_OPS_STATS
109 * stats: do account for allocations
110 * displayed in db_ops_show_status()
112 struct db_ops_stats
{
113 int st_curr_cnt
; /* current number of allocations */
114 int st_total_cnt
; /* total allocations so far */
115 size_t st_maxsz
; /* max. size requested */
117 #define DB_OPS_ZERO { 0, 0, 0};
118 #define DB_OPS_STATS_DESC "{curr_cnt, total_cnt, maxsz}"
119 #define DB_OPS_STATS_STR(name) name "={%d,%d,%d} "
120 #define DB_OPS_STATS_F(st) (st).st_curr_cnt, (st).st_total_cnt, (int)(st).st_maxsz
121 static struct db_ops_stats db_context_st
= DB_OPS_ZERO
;
122 static struct db_ops_stats db_trans_st
= DB_OPS_ZERO
;
123 static struct db_ops_stats db_attrs_st
= DB_OPS_ZERO
;
124 static __inline__
void * alloc_bytes_st (size_t size
, const char *str
, struct db_ops_stats
*st
)
126 void *ptr
= alloc_bytes(size
, str
);
130 if (size
> st
->st_maxsz
) st
->st_maxsz
=size
;
134 #define ALLOC_BYTES_ST(z,s,st) alloc_bytes_st(z, s, &st);
135 #define PFREE_ST(p,st) do { st.st_curr_cnt--; pfree(p); } while (0);
139 #define ALLOC_BYTES_ST(z,s,n) alloc_bytes(z, s);
140 #define PFREE_ST(p,n) pfree(p);
142 #endif /* NO_DB_OPS_STATS */
143 /* Initialize db object
144 * max_trans and max_attrs can be 0, will be dynamically expanded
145 * as a result of "add" operations
148 db_prop_init(struct db_context
*ctx
, u_int8_t protoid
, int max_trans
, int max_attrs
)
155 if (max_trans
> 0) { /* quite silly if not */
156 ctx
->trans0
= ALLOC_BYTES_ST ( sizeof (struct db_trans
) * max_trans
,
157 "db_context->trans", db_trans_st
);
158 if (!ctx
->trans0
) goto out
;
161 if (max_attrs
> 0) { /* quite silly if not */
162 ctx
->attrs0
= ALLOC_BYTES_ST (sizeof (struct db_attr
) * max_attrs
,
163 "db_context->attrs", db_attrs_st
);
164 if (!ctx
->attrs0
) goto out
;
168 if (ret
< 0 && ctx
->trans0
) {
169 PFREE_ST(ctx
->trans0
, db_trans_st
);
172 ctx
->max_trans
= max_trans
;
173 ctx
->max_attrs
= max_attrs
;
174 ctx
->trans_cur
= ctx
->trans0
;
175 ctx
->attrs_cur
= ctx
->attrs0
;
176 ctx
->prop
.protoid
= protoid
;
177 ctx
->prop
.trans
= ctx
->trans0
;
178 ctx
->prop
.trans_cnt
= 0;
182 /* Expand storage for transforms by number delta_trans */
184 db_trans_expand(struct db_context
*ctx
, int delta_trans
)
187 struct db_trans
*new_trans
, *old_trans
;
188 int max_trans
= ctx
->max_trans
+ delta_trans
;
191 old_trans
= ctx
->trans0
;
192 new_trans
= ALLOC_BYTES_ST ( sizeof (struct db_trans
) * max_trans
,
193 "db_context->trans (expand)", db_trans_st
);
196 memcpy(new_trans
, old_trans
, ctx
->max_trans
* sizeof(struct db_trans
));
198 /* update trans0 (obviously) */
199 ctx
->trans0
= ctx
->prop
.trans
= new_trans
;
200 /* update trans_cur (by offset) */
201 offset
= (char *)(new_trans
) - (char *)(old_trans
);
204 char *cctx
= (char *)(ctx
->trans_cur
);
207 ctx
->trans_cur
= (struct db_trans
*)cctx
;
209 /* update elem count */
210 ctx
->max_trans
= max_trans
;
211 PFREE_ST(old_trans
, db_trans_st
);
217 * Expand storage for attributes by delta_attrs number AND
218 * rewrite trans->attr pointers
221 db_attrs_expand(struct db_context
*ctx
, int delta_attrs
)
224 struct db_attr
*new_attrs
, *old_attrs
;
227 int max_attrs
= ctx
->max_attrs
+ delta_attrs
;
230 old_attrs
= ctx
->attrs0
;
231 new_attrs
= ALLOC_BYTES_ST ( sizeof (struct db_attr
) * max_attrs
,
232 "db_context->attrs (expand)", db_attrs_st
);
236 memcpy(new_attrs
, old_attrs
, ctx
->max_attrs
* sizeof(struct db_attr
));
238 /* update attrs0 and attrs_cur (obviously) */
239 offset
= (char *)(new_attrs
) - (char *)(old_attrs
);
242 char *actx
= (char *)(ctx
->attrs0
);
245 ctx
->attrs0
= (struct db_attr
*)actx
;
247 actx
= (char *)ctx
->attrs_cur
;
249 ctx
->attrs_cur
= (struct db_attr
*)actx
;
252 /* for each transform, rewrite attrs pointer by offsetting it */
253 for (t
=ctx
->prop
.trans
, ti
=0; ti
< ctx
->prop
.trans_cnt
; t
++, ti
++) {
254 char *actx
= (char *)(t
->attrs
);
257 t
->attrs
= (struct db_attr
*)actx
;
259 /* update elem count */
260 ctx
->max_attrs
= max_attrs
;
261 PFREE_ST(old_attrs
, db_attrs_st
);
266 /* Allocate a new db object */
268 db_prop_new(u_int8_t protoid
, int max_trans
, int max_attrs
)
270 struct db_context
*ctx
;
271 ctx
= ALLOC_BYTES_ST ( sizeof (struct db_context
), "db_context", db_context_st
);
274 if (db_prop_init(ctx
, protoid
, max_trans
, max_attrs
) < 0) {
275 PFREE_ST(ctx
, db_context_st
);
281 /* Free a db object */
283 db_destroy(struct db_context
*ctx
)
285 if (ctx
->trans0
) PFREE_ST(ctx
->trans0
, db_trans_st
);
286 if (ctx
->attrs0
) PFREE_ST(ctx
->attrs0
, db_attrs_st
);
287 PFREE_ST(ctx
, db_context_st
);
289 /* Start a new transform, expand trans0 is needed */
291 db_trans_add(struct db_context
*ctx
, u_int8_t transid
)
293 /* skip incrementing current trans pointer the 1st time*/
294 if (ctx
->trans_cur
&& ctx
->trans_cur
->attr_cnt
)
297 * Strategy: if more space is needed, expand by
298 * <current_size>/2 + 1
300 * This happens to produce a "reasonable" sequence
301 * after few allocations, eg.:
302 * 0,1,2,4,8,13,20,31,47
304 if ((ctx
->trans_cur
- ctx
->trans0
) >= ctx
->max_trans
) {
305 /* XXX:jjo if fails should shout and flag it */
306 if (db_trans_expand(ctx
, ctx
->max_trans
/2 + 1)<0)
309 ctx
->trans_cur
->transid
= transid
;
310 ctx
->trans_cur
->attrs
=ctx
->attrs_cur
;
311 ctx
->trans_cur
->attr_cnt
= 0;
312 ctx
->prop
.trans_cnt
++;
315 /* Add attr copy to current transform, expanding attrs0 if needed */
317 db_attr_add(struct db_context
*ctx
, const struct db_attr
*a
)
320 * Strategy: if more space is needed, expand by
321 * <current_size>/2 + 1
323 if ((ctx
->attrs_cur
- ctx
->attrs0
) >= ctx
->max_attrs
) {
324 /* XXX:jjo if fails should shout and flag it */
325 if (db_attrs_expand(ctx
, ctx
->max_attrs
/2 + 1) < 0)
328 *ctx
->attrs_cur
++=*a
;
329 ctx
->trans_cur
->attr_cnt
++;
332 /* Add attr copy (by value) to current transform,
333 * expanding attrs0 if needed, just calls db_attr_add().
336 db_attr_add_values(struct db_context
*ctx
, u_int16_t type
, u_int16_t val
)
341 return db_attr_add (ctx
, &attr
);
343 #ifndef NO_DB_OPS_STATS
345 db_ops_show_status(void)
347 whack_log(RC_COMMENT
, "stats " __FILE__
": "
348 DB_OPS_STATS_DESC
" :"
349 DB_OPS_STATS_STR("context")
350 DB_OPS_STATS_STR("trans")
351 DB_OPS_STATS_STR("attrs"),
352 DB_OPS_STATS_F(db_context_st
),
353 DB_OPS_STATS_F(db_trans_st
),
354 DB_OPS_STATS_F(db_attrs_st
)
358 #endif /* NO_DB_OPS_STATS */
360 * From below to end just testing stuff ....
363 static void db_prop_print(struct db_prop
*p
)
368 enum_names
*n
, *n_at
, *n_av
;
369 printf("protoid=\"%s\"\n", enum_name(&protocol_names
, p
->protoid
));
370 for (ti
=0, t
=p
->trans
; ti
< p
->trans_cnt
; ti
++, t
++) {
371 switch( t
->transid
) {
373 n
=&isakmp_transformid_names
;break;
374 case PROTO_IPSEC_ESP
:
375 n
=&esp_transformid_names
;break;
379 printf(" transid=\"%s\"\n",
380 enum_name(n
, t
->transid
));
381 for (ai
=0, a
=t
->attrs
; ai
< t
->attr_cnt
; ai
++, a
++) {
383 switch( t
->transid
) {
385 n_at
=&oakley_attr_names
;
386 i
=a
->type
|ISAKMP_ATTR_AF_TV
;
387 n_av
=oakley_attr_val_descs
[(i
)&ISAKMP_ATTR_RTYPE_MASK
];
389 case PROTO_IPSEC_ESP
:
390 n_at
=&ipsec_attr_names
;
391 i
=a
->type
|ISAKMP_ATTR_AF_TV
;
392 n_av
=ipsec_attr_val_descs
[(i
)&ISAKMP_ATTR_RTYPE_MASK
];
397 printf(" type=\"%s\" value=\"%s\"\n",
399 enum_name(n_av
, a
->val
));
404 static void db_print(struct db_context
*ctx
)
406 printf("trans_cur diff=%d, attrs_cur diff=%d\n",
407 ctx
->trans_cur
- ctx
->trans0
,
408 ctx
->attrs_cur
- ctx
->attrs0
);
409 db_prop_print(&ctx
->prop
);
413 passert_fail(const char *pred_str
, const char *file_str
, unsigned long line_no
);
416 passert_fail(const char *pred_str
, const char *file_str
, unsigned long line_no
)
418 fprintf(stderr
, "ASSERTION FAILED at %s:%lu: %s", file_str
, line_no
, pred_str
);
419 abort(); /* exiting correctly doesn't always work */
422 struct db_context
*ctx
=db_prop_new(PROTO_ISAKMP
, 0, 0);
423 db_trans_add(ctx
, KEY_IKE
);
424 db_attr_add_values(ctx
, OAKLEY_ENCRYPTION_ALGORITHM
, OAKLEY_3DES_CBC
);
425 db_attr_add_values(ctx
, OAKLEY_HASH_ALGORITHM
, OAKLEY_MD5
);
426 db_attr_add_values(ctx
, OAKLEY_AUTHENTICATION_METHOD
, OAKLEY_RSA_SIG
);
427 db_attr_add_values(ctx
, OAKLEY_GROUP_DESCRIPTION
, OAKLEY_GROUP_MODP1024
);
428 db_trans_add(ctx
, KEY_IKE
);
429 db_attr_add_values(ctx
, OAKLEY_ENCRYPTION_ALGORITHM
, OAKLEY_AES_CBC
);
430 db_attr_add_values(ctx
, OAKLEY_HASH_ALGORITHM
, OAKLEY_MD5
);
431 db_attr_add_values(ctx
, OAKLEY_AUTHENTICATION_METHOD
, OAKLEY_PRESHARED_KEY
);
432 db_attr_add_values(ctx
, OAKLEY_GROUP_DESCRIPTION
, OAKLEY_GROUP_MODP1536
);
433 db_trans_add(ctx
, ESP_3DES
);
434 db_attr_add_values(ctx
, AUTH_ALGORITHM
, AUTH_ALGORITHM_HMAC_SHA1
);