This diff I'm least convinced about, but I do want to put it out there. As far as I'm aware RFC2741 places no restrictions on direct mapping of unregistrations on registrations. Meaning that if I register 1.3.6.1.2.[1-10] and I just unregister 1.3.6.1.2.5 this should leave 1.3.6.1.2.[1-4] and 1.3.6.1.2.[6-10] and this is what currently is implemented (assuming previous (un)register diffs).
However, RFC2742 specifies AgentxRegistrationEntry, which presents the the data as presented in the agentx-register-pdu. This implies that an unregister is expected to be an exact counterpart to agentx-register-pdu, because else an AgentxRegistrationEntry would need to be split up, which would be a horror-show. Do we want to add this restriction and keep the road open to AGENTX-MIB support? Since range support is currently broken anyway this won't cause any problems. Thoughts? OK? martijn@ diff --git a/application_agentx.c b/application_agentx.c index 79900d6..60dc4df 100644 --- a/application_agentx.c +++ b/application_agentx.c @@ -70,11 +70,28 @@ struct appl_agentx_session { struct ax_oid sess_oid; struct ax_ostring sess_descr; struct appl_backend sess_backend; + TAILQ_HEAD(, appl_agentx_registration) sess_registrations; RB_ENTRY(appl_agentx_session) sess_entry; TAILQ_ENTRY(appl_agentx_session) sess_conn_entry; }; +/* RFC2742: AGENTX-MIB:AgentxRegistrationEntry */ +struct appl_agentx_registration { + uint32_t reg_index; + char reg_context[APPL_CONTEXTNAME_MAX + 1]; + struct ax_oid reg_start; + uint8_t reg_rangesubid; + uint32_t reg_upperbound; + uint8_t reg_priority; + uint8_t reg_timeout; + uint8_t reg_instance; + + struct appl_agentx_session *reg_session; + + TAILQ_ENTRY(appl_agentx_registration) reg_entry; +}; + void appl_agentx_listen(struct agentx_master *); void appl_agentx_accept(int, short, void *); void appl_agentx_free(struct appl_agentx_connection *, enum appl_close_reason); @@ -106,6 +123,7 @@ struct appl_backend_functions appl_agentx_functions = { .ab_getnext = appl_agentx_getnext, .ab_getbulk = NULL, /* not properly supported in application.c and libagentx */ }; +static uint32_t appl_agentx_reg_index = 1; RB_HEAD(appl_agentx_conns, appl_agentx_connection) appl_agentx_conns = RB_INITIALIZER(&appl_agentx_conns); @@ -477,6 +495,7 @@ appl_agentx_open(struct appl_agentx_connection *conn, struct ax_pdu *pdu) goto fail; } session->sess_descr.aos_string = NULL; + TAILQ_INIT(&(session->sess_registrations)); session->sess_conn = conn; if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER) @@ -624,6 +643,12 @@ void appl_agentx_session_free(struct appl_agentx_session *session) { struct appl_agentx_connection *conn = session->sess_conn; + struct appl_agentx_registration *reg; + + while ((reg = TAILQ_FIRST(&(session->sess_registrations))) != NULL) { + TAILQ_REMOVE(&(session->sess_registrations), reg, reg_entry); + free(reg); + } appl_close(&(session->sess_backend)); @@ -642,6 +667,7 @@ appl_agentx_register(struct appl_agentx_session *session, struct ax_pdu *pdu) struct ber_oid oid; enum appl_error error; int subtree = 0; + struct appl_agentx_registration *reg; timeout = pdu->ap_payload.ap_register.ap_timeout; timeout = timeout != 0 ? timeout : session->sess_timeout != 0 ? @@ -660,6 +686,13 @@ appl_agentx_register(struct appl_agentx_session *session, struct ax_pdu *pdu) goto fail; } + if ((reg = malloc(sizeof(*reg))) == NULL) { + log_warn("%s: Failed to register", + session->sess_backend.ab_name); + error = APPL_ERROR_PROCESSINGERROR; + goto fail; + } + error = appl_register(pdu->ap_context.aos_string, timeout, pdu->ap_payload.ap_register.ap_priority, &oid, pdu->ap_header.aph_flags & AX_PDU_FLAG_INSTANCE_REGISTRATION, @@ -667,6 +700,26 @@ appl_agentx_register(struct appl_agentx_session *session, struct ax_pdu *pdu) pdu->ap_payload.ap_register.ap_upper_bound, &(session->sess_backend)); + if (error == APPL_ERROR_NOERROR) { + reg->reg_index = appl_agentx_reg_index++; + (void)strlcpy(reg->reg_context, pdu->ap_context.aos_slen == 0 ? + "" : (const char *)pdu->ap_context.aos_string, + sizeof(reg->reg_context)); + reg->reg_start = pdu->ap_payload.ap_register.ap_subtree; + reg->reg_rangesubid = + pdu->ap_payload.ap_register.ap_range_subid; + reg->reg_upperbound = + pdu->ap_payload.ap_register.ap_upper_bound; + reg->reg_priority = pdu->ap_payload.ap_register.ap_priority; + reg->reg_timeout = pdu->ap_payload.ap_register.ap_timeout; + reg->reg_instance = pdu->ap_header.aph_flags & + AX_PDU_FLAG_INSTANCE_REGISTRATION; + reg->reg_session = session; + TAILQ_INSERT_TAIL(&(session->sess_registrations), + reg, reg_entry); + } else + free(reg); + fail: ax_response(session->sess_conn->conn_ax, session->sess_id, pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid, @@ -679,6 +732,11 @@ appl_agentx_unregister(struct appl_agentx_session *session, struct ax_pdu *pdu) { struct ber_oid oid; enum appl_error error; + const char *context; + char oidbuf[1024], subidbuf[11]; + struct appl_agentx_registration *reg; + struct ax_pdu_unregister *payload = &(pdu->ap_payload.ap_unregister); + size_t i; if (appl_agentx_oid2ber_oid( &(pdu->ap_payload.ap_unregister.ap_subtree), &oid) == NULL) { @@ -688,12 +746,58 @@ appl_agentx_unregister(struct appl_agentx_session *session, struct ax_pdu *pdu) goto fail; } + /* + * Special case to keep RFC2742: AGENTX-MIB:AgentxRegistrationEntry + * consistent. Duplicate log warnings from appl_unregister(), while we + * can't enter that function. + */ + context = pdu->ap_context.aos_slen == 0 ? + "" : (const char *)pdu->ap_context.aos_string; + TAILQ_FOREACH(reg, &(session->sess_registrations), reg_entry) { + if (strcmp(reg->reg_context, context) == 0 && + ax_oid_cmp(&(reg->reg_start), + &(payload->ap_subtree)) == 0 && + reg->reg_rangesubid == payload->ap_range_subid && + reg->reg_upperbound == payload->ap_upper_bound && + reg->reg_priority == payload->ap_priority) + break; + } + if (reg == NULL) { + oidbuf[0] = '\0'; + for (i = 0; i < oid.bo_n; i++) { + snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32, + oid.bo_id[i]); + if (i != 0) + strlcat(oidbuf, ".", sizeof(oidbuf)); + if (payload->ap_range_subid == i + 1) { + strlcat(oidbuf, "[", sizeof(oidbuf)); + strlcat(oidbuf, subidbuf, sizeof(oidbuf)); + strlcat(oidbuf, "-", sizeof(oidbuf)); + snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32, + payload->ap_upper_bound); + strlcat(oidbuf, subidbuf, sizeof(oidbuf)); + strlcat(oidbuf, "]", sizeof(oidbuf)); + } else + strlcat(oidbuf, subidbuf, sizeof(oidbuf)); + } + log_info("%s: Unregistering %s context(%s) priority(%"PRIu8")", + session->sess_backend.ab_name, oidbuf, context, + payload->ap_priority); + log_warnx("%s: Can't unregister %s: region not found", + session->sess_backend.ab_name, oidbuf); + + error = APPL_ERROR_UNKNOWNREGISTRATION; + goto fail; + } + error = appl_unregister(pdu->ap_context.aos_string, - pdu->ap_payload.ap_unregister.ap_priority, &oid, - pdu->ap_payload.ap_unregister.ap_range_subid, - pdu->ap_payload.ap_unregister.ap_upper_bound, - &(session->sess_backend)); + payload->ap_priority, &oid, payload->ap_range_subid, + payload->ap_upper_bound, &(session->sess_backend)); + if (error == APPL_ERROR_NOERROR) { + TAILQ_REMOVE(&(session->sess_registrations), reg, reg_entry); + free(reg); + } fail: ax_response(session->sess_conn->conn_ax, session->sess_id, pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,