I'm currently working on adding SNMPv3 support to traps in snmpd(8). For sending traps we loop over sc_trapreceivers and can send each trap to 0 or more receivers.
I want to high-jack snmpe_response() to do the heavy lifting for doing the snmp/usm encoding, but this interface frees the varbindlist in snmp_msgfree(), which means I need to rebuild the varbindlist for every iteration. To keep this simple I suggest adding ober_dup, which duplicates a full ber_element chain. Sending this prior to any of my snmpd(8) work, since it requires a library version bump. OK? Any additional coordination needed for this diff? martijn@ Index: Symbols.map =================================================================== RCS file: /cvs/src/lib/libutil/Symbols.map,v retrieving revision 1.3 diff -u -p -r1.3 Symbols.map --- Symbols.map 24 Oct 2019 12:39:26 -0000 1.3 +++ Symbols.map 22 Jul 2021 20:18:35 -0000 @@ -65,6 +65,7 @@ ober_add_set; ober_add_string; ober_calc_len; + ober_dup; ober_free; ober_free_element; ober_free_elements; Index: ber.c =================================================================== RCS file: /cvs/src/lib/libutil/ber.c,v retrieving revision 1.21 diff -u -p -r1.21 ber.c --- ber.c 22 Feb 2021 17:15:02 -0000 1.21 +++ ber.c 22 Jul 2021 20:18:35 -0000 @@ -926,6 +926,43 @@ ober_getpos(struct ber_element *elm) return elm->be_offs; } +struct ber_element * +ober_dup(struct ber_element *orig) +{ + struct ber_element *new; + + if ((new = malloc(sizeof(*new))) == NULL) + return NULL; + memcpy(new, orig, sizeof(*new)); + new->be_next = NULL; + new->be_sub = NULL; + + if (orig->be_next != NULL) { + if ((new->be_next = ober_dup(orig->be_next)) == NULL) + goto fail; + } + if (orig->be_encoding == BER_TYPE_SEQUENCE || + orig->be_encoding == BER_TYPE_SET) { + if (orig->be_sub != NULL) { + if ((new->be_sub = ober_dup(orig->be_sub)) == NULL) + goto fail; + } + } else if (orig->be_encoding == BER_TYPE_OCTETSTRING || + orig->be_encoding == BER_TYPE_BITSTRING || + orig->be_encoding == BER_TYPE_OBJECT) { + if (orig->be_val != NULL) { + if ((new->be_val = malloc(orig->be_len)) == NULL) + goto fail; + memcpy(new->be_val, orig->be_val, orig->be_len); + } + } else + new->be_numeric = orig->be_numeric; + return new; + fail: + ober_free_elements(new); + return NULL; +} + void ober_free_element(struct ber_element *root) { Index: ber.h =================================================================== RCS file: /cvs/src/lib/libutil/ber.h,v retrieving revision 1.3 diff -u -p -r1.3 ber.h --- ber.h 31 Dec 2019 10:34:14 -0000 1.3 +++ ber.h 22 Jul 2021 20:18:35 -0000 @@ -137,6 +137,7 @@ ssize_t ober_write_elements(struct be void ober_set_readbuf(struct ber *, void *, size_t); struct ber_element *ober_read_elements(struct ber *, struct ber_element *); off_t ober_getpos(struct ber_element *); +struct ber_element *ober_dup(struct ber_element *); void ober_free_element(struct ber_element *); void ober_free_elements(struct ber_element *); size_t ober_calc_len(struct ber_element *); Index: ober_set_header.3 =================================================================== RCS file: /cvs/src/lib/libutil/ober_set_header.3,v retrieving revision 1.2 diff -u -p -r1.2 ober_set_header.3 --- ober_set_header.3 12 Mar 2021 05:18:01 -0000 1.2 +++ ober_set_header.3 22 Jul 2021 20:18:35 -0000 @@ -23,6 +23,7 @@ .Nm ober_set_writecallback , .Nm ober_link_elements , .Nm ober_replace_elements , +.Nm ober_dup , .Nm ober_unlink_elements , .Nm ober_free_element , .Nm ober_free_elements @@ -45,6 +46,8 @@ .Ft "void" .Fn "ober_replace_elements" "struct ber_element *prev" "struct ber_element *elm" .Ft "struct ber_element *" +.Ft "struct ber_element *" +.Fn "ober_dup" "struct ber_element *orig" .Fn "ober_unlink_elements" "struct ber_element *prev" .Ft "void" .Fn "ober_free_element" "struct ber_element *root" @@ -101,6 +104,9 @@ with and frees any dynamically allocated storage associated with .Fa prev . .Pp +.Fn ober_dup +duplicates an element and all linked elements. +.Pp .Fn ober_unlink_elements unlinks .Fa prev . @@ -116,6 +122,11 @@ returns the total length of a fully popu .Fa root containing one or more .Vt ber_element . +.Pp +.Fn ober_dup +returns a pointer to the duplicated element or +.Dv NULL +on error. .Pp .Fn ober_unlink_elements returns a pointer to Index: shlib_version =================================================================== RCS file: /cvs/src/lib/libutil/shlib_version,v retrieving revision 1.32 diff -u -p -r1.32 shlib_version --- shlib_version 31 Dec 2019 10:34:14 -0000 1.32 +++ shlib_version 22 Jul 2021 20:18:35 -0000 @@ -1,2 +1,2 @@ major=15 -minor=0 +minor=1