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,

Reply via email to