Hi, there's a bug in snmpd that breaks GETBULK requests for multiple OIDs.
Example: # OID1=1.3.6.1.2.1.1.1 # OID2=1.3.6.1.2.1.31.1.1.1.1 # snmpbulkget -Cr3 -c public -v2c localhost $OID1 SNMPv2-MIB::sysDescr.0 = STRING: OpenBSD null 5.7 GENERIC#123 i386 SNMPv2-MIB::sysObjectID.0 = OID: OPENBSD-BASE-MIB::openBSDDefaultObjectID SNMPv2-MIB::sysUpTime.0 = Timeticks: (68096) 0:11:20.96 # snmpbulkget -Cr3 -c public -v2c localhost $OID2 IF-MIB::ifName.1 = STRING: em0 IF-MIB::ifName.2 = STRING: iwi0 IF-MIB::ifName.3 = STRING: enc0 # snmpbulkget -Cr3 -c public -v2c localhost $OID1 $OID2 SNMPv2-MIB::sysDescr.0 = STRING: OpenBSD null 5.7 GENERIC#123 i386 IF-MIB::ifName.1 = STRING: em0 IF-MIB::ifName.2 = STRING: iwi0 IF-MIB::ifName.3 = STRING: enc0 Each query for a single OID delivers three repetitions (as requested by "-Cr3"). But the query for two OIDs skips the repetitions for the first one. If we add more OIDs, only the last OID of the query will have repetitions in the reply. The reason is that we must link the result of each mps_getbulkreq() to the end of the previous list and not the start of it. With the patch below, we get the desired result: # snmpbulkget -Cr3 -c public -v2c localhost $OID1 $OID2 SNMPv2-MIB::sysDescr.0 = STRING: OpenBSD null 5.7 GENERIC#123 i386 SNMPv2-MIB::sysObjectID.0 = OID: OPENBSD-BASE-MIB::openBSDDefaultObjectID SNMPv2-MIB::sysUpTime.0 = Timeticks: (239) 0:00:02.39 IF-MIB::ifName.1 = STRING: em0 IF-MIB::ifName.2 = STRING: iwi0 IF-MIB::ifName.3 = STRING: enc0 Gerhard Index: mps.c =================================================================== RCS file: /cvs/src/usr.sbin/snmpd/mps.c,v retrieving revision 1.20 diff -u -p -u -p -r1.20 mps.c --- mps.c 16 Jan 2015 00:05:13 -0000 1.20 +++ mps.c 3 Jun 2015 08:48:42 -0000 @@ -289,7 +289,7 @@ mps_getnextreq(struct snmp_message *msg, int mps_getbulkreq(struct snmp_message *msg, struct ber_element **root, - struct ber_oid *o, int max) + struct ber_element **end, struct ber_oid *o, int max) { struct ber_element *c, *d, *e; size_t len; @@ -297,14 +297,17 @@ mps_getbulkreq(struct snmp_message *msg, j = max; c = *root; + *end = NULL; for (d = NULL, len = 0; j > 0; j--) { e = ber_add_sequence(NULL); if (c == NULL) c = e; ret = mps_getnextreq(msg, e, o); - if (ret == 1) + if (ret == 1) { + *root = c; return (1); + } if (ret == -1) { ber_free_elements(e); if (d == NULL) @@ -319,6 +322,7 @@ mps_getbulkreq(struct snmp_message *msg, if (d != NULL) ber_link_elements(d, e); d = e; + *end = d; } *root = c; Index: snmpd.h =================================================================== RCS file: /cvs/src/usr.sbin/snmpd/snmpd.h,v retrieving revision 1.59 diff -u -p -u -p -r1.59 snmpd.h --- snmpd.h 16 Jan 2015 00:05:13 -0000 1.59 +++ snmpd.h 3 Jun 2015 09:02:38 -0000 @@ -396,6 +396,7 @@ struct snmp_message { struct ber_element *sm_c; struct ber_element *sm_next; struct ber_element *sm_last; + struct ber_element *sm_end; u_int8_t sm_data[READ_BUF_SIZE]; size_t sm_datalen; @@ -638,7 +639,7 @@ int mps_getreq(struct snmp_message *, int mps_getnextreq(struct snmp_message *, struct ber_element *, struct ber_oid *); int mps_getbulkreq(struct snmp_message *, struct ber_element **, - struct ber_oid *, int); + struct ber_element **, struct ber_oid *, int); int mps_setreq(struct snmp_message *, struct ber_element *, struct ber_oid *); int mps_set(struct ber_oid *, void *, long long); Index: snmpe.c =================================================================== RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v retrieving revision 1.40 diff -u -p -u -p -r1.40 snmpe.c --- snmpe.c 16 Jan 2015 00:05:13 -0000 1.40 +++ snmpe.c 3 Jun 2015 09:06:31 -0000 @@ -374,6 +374,7 @@ snmpe_parsevarbinds(struct snmp_message break; case 1: msg->sm_c = NULL; + msg->sm_end = NULL; switch (msg->sm_context) { @@ -409,7 +410,8 @@ snmpe_parsevarbinds(struct snmp_message case SNMP_C_GETBULKREQ: ret = mps_getbulkreq(msg, &msg->sm_c, - &o, msg->sm_maxrepetitions); + &msg->sm_end, &o, + msg->sm_maxrepetitions); if (ret == 0 || ret == 1) break; msg->sm_error = SNMP_ERROR_NOSUCHNAME; @@ -420,11 +422,13 @@ snmpe_parsevarbinds(struct snmp_message } if (msg->sm_c == NULL) break; + if (msg->sm_end == NULL) + msg->sm_end = msg->sm_c; if (msg->sm_last == NULL) msg->sm_varbindresp = msg->sm_c; else ber_link_elements(msg->sm_last, msg->sm_c); - msg->sm_last = msg->sm_c; + msg->sm_last = msg->sm_end; break; } } Index: mps.c =================================================================== RCS file: /cvs/src/usr.sbin/snmpd/mps.c,v retrieving revision 1.20 diff -u -p -u -p -r1.20 mps.c --- mps.c 16 Jan 2015 00:05:13 -0000 1.20 +++ mps.c 3 Jun 2015 08:48:42 -0000 @@ -289,7 +289,7 @@ mps_getnextreq(struct snmp_message *msg, int mps_getbulkreq(struct snmp_message *msg, struct ber_element **root, - struct ber_oid *o, int max) + struct ber_element **end, struct ber_oid *o, int max) { struct ber_element *c, *d, *e; size_t len; @@ -297,14 +297,17 @@ mps_getbulkreq(struct snmp_message *msg, j = max; c = *root; + *end = NULL; for (d = NULL, len = 0; j > 0; j--) { e = ber_add_sequence(NULL); if (c == NULL) c = e; ret = mps_getnextreq(msg, e, o); - if (ret == 1) + if (ret == 1) { + *root = c; return (1); + } if (ret == -1) { ber_free_elements(e); if (d == NULL) @@ -319,6 +322,7 @@ mps_getbulkreq(struct snmp_message *msg, if (d != NULL) ber_link_elements(d, e); d = e; + *end = d; } *root = c; Index: snmpd.h =================================================================== RCS file: /cvs/src/usr.sbin/snmpd/snmpd.h,v retrieving revision 1.59 diff -u -p -u -p -r1.59 snmpd.h --- snmpd.h 16 Jan 2015 00:05:13 -0000 1.59 +++ snmpd.h 3 Jun 2015 09:02:38 -0000 @@ -396,6 +396,7 @@ struct snmp_message { struct ber_element *sm_c; struct ber_element *sm_next; struct ber_element *sm_last; + struct ber_element *sm_end; u_int8_t sm_data[READ_BUF_SIZE]; size_t sm_datalen; @@ -638,7 +639,7 @@ int mps_getreq(struct snmp_message *, int mps_getnextreq(struct snmp_message *, struct ber_element *, struct ber_oid *); int mps_getbulkreq(struct snmp_message *, struct ber_element **, - struct ber_oid *, int); + struct ber_element **, struct ber_oid *, int); int mps_setreq(struct snmp_message *, struct ber_element *, struct ber_oid *); int mps_set(struct ber_oid *, void *, long long); Index: snmpe.c =================================================================== RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v retrieving revision 1.40 diff -u -p -u -p -r1.40 snmpe.c --- snmpe.c 16 Jan 2015 00:05:13 -0000 1.40 +++ snmpe.c 3 Jun 2015 09:06:31 -0000 @@ -374,6 +374,7 @@ snmpe_parsevarbinds(struct snmp_message break; case 1: msg->sm_c = NULL; + msg->sm_end = NULL; switch (msg->sm_context) { @@ -409,7 +410,8 @@ snmpe_parsevarbinds(struct snmp_message case SNMP_C_GETBULKREQ: ret = mps_getbulkreq(msg, &msg->sm_c, - &o, msg->sm_maxrepetitions); + &msg->sm_end, &o, + msg->sm_maxrepetitions); if (ret == 0 || ret == 1) break; msg->sm_error = SNMP_ERROR_NOSUCHNAME; @@ -420,11 +422,13 @@ snmpe_parsevarbinds(struct snmp_message } if (msg->sm_c == NULL) break; + if (msg->sm_end == NULL) + msg->sm_end = msg->sm_c; if (msg->sm_last == NULL) msg->sm_varbindresp = msg->sm_c; else ber_link_elements(msg->sm_last, msg->sm_c); - msg->sm_last = msg->sm_c; + msg->sm_last = msg->sm_end; break; } }