diff --git a/proto/snmp/bgp_mib.c b/proto/snmp/bgp_mib.c index c55af290..d97a0de4 100644 --- a/proto/snmp/bgp_mib.c +++ b/proto/snmp/bgp_mib.c @@ -13,13 +13,6 @@ #include "subagent.h" #include "bgp_mib.h" -STATIC_ASSERT(BGP_MIB_IDLE == BS_IDLE + 1); -STATIC_ASSERT(BGP_MIB_CONNECT == BS_CONNECT + 1); -STATIC_ASSERT(BGP_MIB_ACTIVE == BS_ACTIVE + 1); -STATIC_ASSERT(BGP_MIB_OPENSENT == BS_OPENSENT + 1); -STATIC_ASSERT(BGP_MIB_OPENCONFIRM == BS_OPENCONFIRM + 1); -STATIC_ASSERT(BGP_MIB_ESTABLISHED == BS_ESTABLISHED + 1); - /* hash table macros */ #define SNMP_HASH_KEY(n) n->peer_ip #define SNMP_HASH_NEXT(n) n->next @@ -58,30 +51,30 @@ static u8 bgp_get_candidate(u32 field) { const u8 translation_table[] = { - [SNMP_BGP_PEER_IDENTIFIER] = BGP_INTERNAL_PEER_IDENTIFIER, - [SNMP_BGP_STATE] = BGP_INTERNAL_STATE, - [SNMP_BGP_ADMIN_STATUS] = BGP_INTERNAL_ADMIN_STATUS, - [SNMP_BGP_NEGOTIATED_VERSION] = BGP_INTERNAL_NEGOTIATED_VERSION, - [SNMP_BGP_LOCAL_ADDR] = BGP_INTERNAL_LOCAL_ADDR, - [SNMP_BGP_LOCAL_PORT] = BGP_INTERNAL_LOCAL_PORT, - [SNMP_BGP_REMOTE_ADDR] = BGP_INTERNAL_REMOTE_ADDR, - [SNMP_BGP_REMOTE_PORT] = BGP_INTERNAL_REMOTE_PORT, - [SNMP_BGP_REMOTE_AS] = BGP_INTERNAL_REMOTE_AS, - [SNMP_BGP_RX_UPDATES] = BGP_INTERNAL_RX_UPDATES, - [SNMP_BGP_TX_UPDATES] = BGP_INTERNAL_TX_UPDATES, - [SNMP_BGP_RX_MESSAGES] = BGP_INTERNAL_RX_MESSAGES, - [SNMP_BGP_TX_MESSAGES] = BGP_INTERNAL_TX_MESSAGES, - [SNMP_BGP_LAST_ERROR] = BGP_INTERNAL_LAST_ERROR, - [SNMP_BGP_FSM_TRANSITIONS] = BGP_INTERNAL_FSM_TRANSITIONS, - [SNMP_BGP_FSM_ESTABLISHED_TIME] = BGP_INTERNAL_FSM_ESTABLISHED_TIME, - [SNMP_BGP_RETRY_INTERVAL] = BGP_INTERNAL_RETRY_INTERVAL, - [SNMP_BGP_HOLD_TIME] = BGP_INTERNAL_HOLD_TIME, - [SNMP_BGP_KEEPALIVE] = BGP_INTERNAL_KEEPALIVE, - [SNMP_BGP_HOLD_TIME_CONFIGURED] = BGP_INTERNAL_HOLD_TIME_CONFIGURED, - [SNMP_BGP_KEEPALIVE_CONFIGURED] = BGP_INTERNAL_KEEPALIVE_CONFIGURED, - [SNMP_BGP_ORIGINATION_INTERVAL] = BGP_INTERNAL_ORIGINATION_INTERVAL, - [SNMP_BGP_MIN_ROUTE_ADVERTISEMENT] = BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT, - [SNMP_BGP_IN_UPDATE_ELAPSED_TIME] = BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME, + [BGP4_MIB_PEER_IDENTIFIER] = BGP4_MIB_S_PEER_IDENTIFIER, + [BGP4_MIB_STATE] = BGP4_MIB_S_STATE, + [BGP4_MIB_ADMIN_STATUS] = BGP4_MIB_S_ADMIN_STATUS, + [BGP4_MIB_NEGOTIATED_VERSION] = BGP4_MIB_S_NEGOTIATED_VERSION, + [BGP4_MIB_LOCAL_ADDR] = BGP4_MIB_S_LOCAL_ADDR, + [BGP4_MIB_LOCAL_PORT] = BGP4_MIB_S_LOCAL_PORT, + [BGP4_MIB_REMOTE_ADDR] = BGP4_MIB_S_REMOTE_ADDR, + [BGP4_MIB_REMOTE_PORT] = BGP4_MIB_S_REMOTE_PORT, + [BGP4_MIB_REMOTE_AS] = BGP4_MIB_S_REMOTE_AS, + [BGP4_MIB_RX_UPDATES] = BGP4_MIB_S_RX_UPDATES, + [BGP4_MIB_TX_UPDATES] = BGP4_MIB_S_TX_UPDATES, + [BGP4_MIB_RX_MESSAGES] = BGP4_MIB_S_RX_MESSAGES, + [BGP4_MIB_TX_MESSAGES] = BGP4_MIB_S_TX_MESSAGES, + [BGP4_MIB_LAST_ERROR] = BGP4_MIB_S_LAST_ERROR, + [BGP4_MIB_FSM_TRANSITIONS] = BGP4_MIB_S_FSM_TRANSITIONS, + [BGP4_MIB_FSM_ESTABLISHED_TIME] = BGP4_MIB_S_FSM_ESTABLISHED_TIME, + [BGP4_MIB_RETRY_INTERVAL] = BGP4_MIB_S_RETRY_INTERVAL, + [BGP4_MIB_HOLD_TIME] = BGP4_MIB_S_HOLD_TIME, + [BGP4_MIB_KEEPALIVE] = BGP4_MIB_S_KEEPALIVE, + [BGP4_MIB_HOLD_TIME_CONFIGURED] = BGP4_MIB_S_HOLD_TIME_CONFIGURED, + [BGP4_MIB_KEEPALIVE_CONFIGURED] = BGP4_MIB_S_KEEPALIVE_CONFIGURED, + [BGP4_MIB_ORIGINATION_INTERVAL] = BGP4_MIB_S_ORIGINATION_INTERVAL, + [BGP4_MIB_MIN_ROUTE_ADVERTISEMENT] = BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT, + [BGP4_MIB_IN_UPDATE_ELAPSED_TIME] = BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME, }; /* @@ -90,10 +83,10 @@ bgp_get_candidate(u32 field) */ if (field > 0 && field <= ARRAY_SIZE(translation_table)- 1) return translation_table[field]; - if (field == 0) - return BGP_INTERNAL_PEER_ENTRY; + else if (field == 0) + return BGP4_MIB_S_PEER_ENTRY; else - return BGP_INTERNAL_PEER_TABLE_END; + return BGP4_MIB_S_PEER_TABLE_END; } /** @@ -114,9 +107,9 @@ snmp_bgp_state(const struct oid *oid) */ if (snmp_is_oid_empty(oid)) - return BGP_INTERNAL_END; + return BGP4_MIB_S_END; - u8 state = BGP_INTERNAL_NO_VALUE; + u8 state = BGP4_MIB_S_NO_VALUE; u8 candidate; switch (oid->n_subid) @@ -124,7 +117,7 @@ snmp_bgp_state(const struct oid *oid) default: if (oid->n_subid < 2) { - state = BGP_INTERNAL_INVALID; + state = BGP4_MIB_S_INVALID; break; } @@ -145,11 +138,11 @@ snmp_bgp_state(const struct oid *oid) /* fall through */ case 4: - if (oid->ids[3] == SNMP_BGP_PEER_ENTRY) - state = (state == BGP_INTERNAL_NO_VALUE) ? - BGP_INTERNAL_PEER_ENTRY : state; + if (oid->ids[3] == BGP4_MIB_PEER_ENTRY) + state = (state == BGP4_MIB_S_NO_VALUE) ? + BGP4_MIB_S_PEER_ENTRY : state; else - state = BGP_INTERNAL_NO_VALUE; + state = BGP4_MIB_S_NO_VALUE; /* fall through */ @@ -158,39 +151,39 @@ snmp_bgp_state(const struct oid *oid) switch (oid->ids[2]) { - case SNMP_BGP_VERSION: - state = BGP_INTERNAL_VERSION; + case BGP4_MIB_VERSION: + state = BGP4_MIB_S_VERSION; break; - case SNMP_BGP_LOCAL_AS: - state = BGP_INTERNAL_LOCAL_AS; + case BGP4_MIB_LOCAL_AS: + state = BGP4_MIB_S_LOCAL_AS; break; - case SNMP_BGP_PEER_TABLE: + case BGP4_MIB_PEER_TABLE: /* We use candidate to avoid overriding more specific state */ - candidate = BGP_INTERNAL_PEER_TABLE; + candidate = BGP4_MIB_S_PEER_TABLE; break; - case SNMP_BGP_IDENTIFIER: - state = BGP_INTERNAL_IDENTIFIER; + case BGP4_MIB_IDENTIFIER: + state = BGP4_MIB_S_IDENTIFIER; break; default: /* test fails */ /* We force state invalidation */ - if (oid->ids[2] < SNMP_BGP_VERSION) + if (oid->ids[2] < BGP4_MIB_VERSION) { - state = BGP_INTERNAL_NO_VALUE; - candidate = BGP_INTERNAL_NO_VALUE; + state = BGP4_MIB_S_NO_VALUE; + candidate = BGP4_MIB_S_NO_VALUE; } - else /* oid->ids[2] > SNMP_BGP_PEER_TABLE */ - state = BGP_INTERNAL_END; + else /* oid->ids[2] > BGP4_MIB_PEER_TABLE */ + state = BGP4_MIB_S_END; } - state = (state == BGP_INTERNAL_NO_VALUE) ? + state = (state == BGP4_MIB_S_NO_VALUE) ? candidate : state; /* fall through */ case 2: /* We found bare BGP4-MIB::bgp ObjectId */ - if (state == BGP_INTERNAL_NO_VALUE || - state == BGP_INTERNAL_INVALID) - state = BGP_INTERNAL_BGP; + if (state == BGP4_MIB_S_NO_VALUE || + state == BGP4_MIB_S_INVALID) + state = BGP4_MIB_S_BGP; } return state; @@ -216,73 +209,103 @@ snmp_bgp_reg_failed(struct snmp_proto *p, struct agentx_response UNUSED *r, stru /* * snmp_bgp_notify_common - common functionaly for BGP4-MIB notifications * @p: SNMP protocol instance - * @type - * + * @type: type of notification send - either established or backward transition + * @ip4: IPv4 remote addr + * @last_error: 2 bytes of BGP last error + * @state_val: BGP peer state as defined in MIB */ static void snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_error[], uint state_val) { -#define SNMP_OID_SIZE_FROM_LEN(x) (sizeof(struct oid) + (x) * sizeof(u32)) - - /* OIDs, VB type headers, octet string, ip4 address, integer */ - uint sz = 3 * SNMP_OID_SIZE_FROM_LEN(9) + 3 * 4 + 8 + 8 + 4; - - /* trap OID bgpEstablishedNotification (.1.3.6.1.2.1.0.1) */ - struct oid *head = mb_alloc(p->pool, SNMP_OID_SIZE_FROM_LEN(3)) + sz; - head->n_subid = 3; - head->prefix = 2; - head->include = head->pad = 0; + uint sz = (uint) (snmp_varbind_size_from_len(9, AGENTX_IP_ADDRESS, 0) + + snmp_varbind_size_from_len(9, AGENTX_OCTET_STRING, 2) + + snmp_varbind_size_from_len(9, AGENTX_INTEGER, 0)); u32 trap_ids[] = { 1, 0, type }; - for (uint i = 0; i < head->n_subid; i++) - head->ids[i] = trap_ids[i]; + STATIC_ASSERT(ARRAY_SIZE(trap_ids) == 3); + /* additional size for trap identification, here either + * bgpEstablishedNotification or bgpBackwardTransNotification (see below) */ + void *data = tmp_alloc(snmp_oid_size_from_len(ARRAY_SIZE(trap_ids)) + sz); + struct oid *head = data; + { /* trap id BGP4-MIB::bgpEstablishedNotification (.1.3.6.1.2.15.0.1) + * or BGP4-MIB::bgpBackwardTransNotification (.1.3.6.1.2.15.0.2) */ + head->n_subid = ARRAY_SIZE(trap_ids); + head->prefix = SNMP_MGMT; + head->include = head->reserved = 0; - void *data = (void *) head + sz; + for (uint i = 0; i < head->n_subid; i++) + head->ids[i] = trap_ids[i]; + } + data += sz; struct agentx_varbind *addr_vb = data; - // TODO remove magic constants; use measuring functions instead - /* +4 for varbind header, +8 for octet string */ - struct agentx_varbind *error_vb = data + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8; - struct agentx_varbind *state_vb = (void *) error_vb + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8; - - addr_vb->pad = error_vb->pad = state_vb->pad = 0; - - struct oid *addr = &addr_vb->name; - struct oid *error = &error_vb->name; - struct oid *state = &state_vb->name; - - addr->n_subid = error->n_subid = state->n_subid = 9; - addr->prefix = error->prefix = state->prefix = 2; - addr->include = error->include = state->include = 0; - addr->pad = error->pad = state->pad = 0; + struct agentx_varbind *error_vb = \ + data + snmp_varbind_size_from_len(9, AGENTX_IP_ADDRESS, 0); + struct agentx_varbind *state_vb = \ + (void *) error_vb + snmp_varbind_size_from_len(9, AGENTX_OCTET_STRING, 2); u32 oid_ids[] = { - SNMP_MIB_2, SNMP_BGP4_MIB, SNMP_BGP_PEER_TABLE, SNMP_BGP_PEER_ENTRY + SNMP_MIB_2, BGP4_MIB, BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY }; - for (uint i = 0; i < sizeof(oid_ids) / sizeof(oid_ids[0]); i++) - addr->ids[i] = error->ids[i] = state->ids[i] = oid_ids[i]; + /* + * The n_subid is 9 in all cases because all are rows entries of + * BGP4-MIB::bgpPeerTable + * BGP4-MIB::bgpPeerRemoteAddr = .1.3.6.1.[2].1.15.3.1.7.a.b.c.d + * where .1.3.6.1 is internet prefix, .[2] is SNMP_MGMT, + * .1.15.3.1.7.a.b.c.d has 9 elements (a.b.c.d are IP addr bytes) + * Here subidentifier 7 is entry type bgpPeerRemoteAddr. + */ + #define PEER_TABLE_ENTRY 9 + #define ENTRY_TYPE 4 - addr->ids[4] = SNMP_BGP_REMOTE_ADDR; - error->ids[4] = SNMP_BGP_LAST_ERROR; - state->ids[4] = SNMP_BGP_STATE; + { /* BGP4-MIB::bgpPeerRemoteAddr */ + struct oid *addr = &addr_vb->name; + *addr = (struct oid) { + .n_subid = PEER_TABLE_ENTRY, .prefix = SNMP_MGMT, .include = 0, + .reserved = 0, + }; + for (uint i = 0; i < ARRAY_SIZE(oid_ids); i++) + addr->ids[i] = oid_ids[i]; + addr->ids[ENTRY_TYPE] = BGP4_MIB_REMOTE_ADDR; + ip4_to_oid(addr, ip4); + } + /* We have enough space inside the TX-buffer prepared */ + #define UNLIMITED 100 + snmp_varbind_ip4(addr_vb, UNLIMITED, ip4); - for (uint i = 0; i < 4; i++) - addr->ids[5 + i] = error->ids[5 + i] = state->ids[5 + i] \ - = (ip4_to_u32(ip4) >> (8 * (3-i))) & 0xFF; + { /* BGP4-MIB::bgpPeerLastError */ + struct oid *error = &error_vb->name; + *error = (struct oid) { + .n_subid = PEER_TABLE_ENTRY, .prefix = SNMP_MGMT, .include = 0, + .reserved = 0, + }; + for (uint i = 0; i < ARRAY_SIZE(oid_ids); i++) + error->ids[i] = oid_ids[i]; + error->ids[ENTRY_TYPE] = BGP4_MIB_LAST_ERROR; + ip4_to_oid(error, ip4); + } + snmp_varbind_nstr(error_vb, UNLIMITED, last_error, 2); - snmp_varbind_ip4(addr_vb, 100, ip4); - - snmp_varbind_nstr(error_vb, 100, last_error, 2); - - snmp_varbind_int(state_vb, 100, state_val); + { /* BGP4-MIB::bgpPeerState */ + struct oid *state = &state_vb->name; + *state = (struct oid) { + .n_subid = PEER_TABLE_ENTRY, .prefix = SNMP_MGMT, .include = 0, + .reserved = 0, + }; + for (uint i = 0; i < ARRAY_SIZE(oid_ids); i++) + state->ids[i] = oid_ids[i]; + state->ids[ENTRY_TYPE] = BGP4_MIB_STATE; + ip4_to_oid(state, ip4); + } + snmp_varbind_int(state_vb, UNLIMITED, state_val); + /* We do not send the systemUpTime.0 */ snmp_notify_pdu(p, head, data, sz, 0); - mb_free(head); - mb_free(data); -#undef SNMP_OID_SIZE_FROM_LEN + #undef OID_N_SUBID + #undef UNLIMITED } /* @@ -303,17 +326,17 @@ snmp_bgp_fsm_state(const struct bgp_proto *bgp_proto) if (MAX(bgp_in->state, bgp_out->state) == BS_CLOSE && MIN(bgp_in->state, bgp_out->state) != BS_CLOSE) - return MIN(bgp_in->state, bgp_out->state); + return MIN(bgp_in->state, bgp_out->state) + 1; if (MIN(bgp_in->state, bgp_out->state) == BS_CLOSE) return BS_IDLE; - - return MAX(bgp_in->state, bgp_out->state); + + return MAX(bgp_in->state, bgp_out->state) + 1; } static void snmp_bgp_notify_wrapper(struct snmp_proto *p, struct bgp_proto *bgp, uint type) { - // possibly dangerous + /* possibly incorrect cast */ ip4_addr ip4 = ipa_to_ip4(bgp->remote_ip); char last_error[2]; snmp_bgp_last_error(bgp, last_error); @@ -324,30 +347,27 @@ snmp_bgp_notify_wrapper(struct snmp_proto *p, struct bgp_proto *bgp, uint type) void snmp_bgp_notify_established(struct snmp_proto *p, struct bgp_proto *bgp) { - /* .1.3.6.1.2.15.0.>1< i.e. BGP4-MIB::bgpEstablishedNotification */ - snmp_bgp_notify_wrapper(p, bgp, 1); + snmp_bgp_notify_wrapper(p, bgp, BGP4_MIB_ESTABLISHED_NOTIFICATION); } void snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp) { - /* .1.3.6.1.2.15.0.>2< i.e. BGP4-MIB::bgpBackwardTransNotification */ - snmp_bgp_notify_wrapper(p, bgp, 2); + snmp_bgp_notify_wrapper(p, bgp, BGP4_MIB_BACKWARD_TRANS_NOTIFICATION); } void snmp_bgp_register(struct snmp_proto *p) { - //u32 bgp_mib_prefix[] = {1, 15, 1}; u32 bgp_mib_prefix[] = { 1, 15 }; { /* Register the whole BGP4-MIB::bgp root tree node */ struct snmp_registration *reg; - reg = snmp_registration_create(p, SNMP_BGP4_MIB); + reg = snmp_registration_create(p, BGP4_MIB); - struct oid *oid = mb_alloc(p->pool, - snmp_oid_sizeof(ARRAY_SIZE(bgp_mib_prefix))); + struct oid *oid = mb_allocz(p->pool, + snmp_oid_size_from_len(ARRAY_SIZE(bgp_mib_prefix))); STORE_U8(oid->n_subid, ARRAY_SIZE(bgp_mib_prefix)); STORE_U8(oid->prefix, SNMP_MGMT); @@ -434,7 +454,7 @@ print_bgp_record(const struct bgp_proto *bgp_proto) DBG(" incoming_conn state: %u", bgp_proto->incoming_conn.state + 1); } -static void +static void UNUSED print_bgp_record_all(struct snmp_proto *p) { DBG("dumping watched bgp status"); @@ -448,29 +468,43 @@ print_bgp_record_all(struct snmp_proto *p) +/* + * is_dynamic - is state dependent on runtime BGP peer state + * @state: tested bgp4_mib state + * + * Used to distinguish states that depend on runtime BGP peer states. + * + * Return nonzero for states with value that may change at runtime. + */ static inline int is_dynamic(u8 state) { - return (state >= BGP_INTERNAL_PEER_IDENTIFIER && - state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME); + return (state >= BGP4_MIB_S_PEER_IDENTIFIER && + state <= BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME); } +/* + * is_static - logical inverse of is_dynamic() for states with value + * @state: tested bgp4_mib state + * + * Return nonzero for states with value that do not change at runtime. + */ static inline int is_static(u8 state) { - return (state == BGP_INTERNAL_VERSION || - state == BGP_INTERNAL_LOCAL_AS || - state == BGP_INTERNAL_IDENTIFIER); + return (state == BGP4_MIB_S_VERSION || + state == BGP4_MIB_S_LOCAL_AS || + state == BGP4_MIB_S_IDENTIFIER); } static inline int snmp_bgp_has_value(u8 state) { - if (state <= BGP_INTERNAL_BGP || - state == BGP_INTERNAL_PEER_TABLE || - state == BGP_INTERNAL_PEER_ENTRY || - state == BGP_INTERNAL_PEER_TABLE_END || - state >= BGP_INTERNAL_END) + if (state <= BGP4_MIB_S_BGP || + state == BGP4_MIB_S_PEER_TABLE || + state == BGP4_MIB_S_PEER_ENTRY || + state == BGP4_MIB_S_PEER_TABLE_END || + state >= BGP4_MIB_S_END) return 0; else return 1; @@ -486,12 +520,12 @@ snmp_bgp_has_value(u8 state) u8 snmp_bgp_get_valid(u8 state) { - if (state == BGP_INTERNAL_INVALID || - state == BGP_INTERNAL_BGP || - state == BGP_INTERNAL_PEER_TABLE || - state == BGP_INTERNAL_PEER_ENTRY || - state == BGP_INTERNAL_PEER_TABLE_END || - state >= BGP_INTERNAL_END) + if (state == BGP4_MIB_S_INVALID || + state == BGP4_MIB_S_BGP || + state == BGP4_MIB_S_PEER_TABLE || + state == BGP4_MIB_S_PEER_ENTRY || + state == BGP4_MIB_S_PEER_TABLE_END || + state >= BGP4_MIB_S_END) return 0; else return state; @@ -509,58 +543,37 @@ snmp_bgp_next_state(u8 state) { switch (state) { - case BGP_INTERNAL_LOCAL_AS: - case BGP_INTERNAL_PEER_TABLE: - case BGP_INTERNAL_PEER_ENTRY: - return BGP_INTERNAL_PEER_IDENTIFIER; + case BGP4_MIB_S_LOCAL_AS: + case BGP4_MIB_S_PEER_TABLE: + case BGP4_MIB_S_PEER_ENTRY: + return BGP4_MIB_S_PEER_IDENTIFIER; - case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME: - case BGP_INTERNAL_PEER_TABLE_END: - return BGP_INTERNAL_IDENTIFIER; + case BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME: + case BGP4_MIB_S_PEER_TABLE_END: + return BGP4_MIB_S_IDENTIFIER; - case BGP_INTERNAL_IDENTIFIER: - case BGP_INTERNAL_END: - return BGP_INTERNAL_END; + case BGP4_MIB_S_IDENTIFIER: + case BGP4_MIB_S_END: + return BGP4_MIB_S_END; default: return state + 1; } } -int -snmp_bgp_is_supported(struct oid *o) -{ - if (o->prefix == 2 && o->n_subid > 0 && o->ids[0] == 1) - { - if (o->n_subid == 2 && (o->ids[1] == SNMP_BGP4_MIB || - o->ids[1] == SNMP_BGP_LOCAL_AS)) - return 1; - else if (o->n_subid > 2 && o->ids[1] == SNMP_BGP_PEER_TABLE && - o->ids[2] == SNMP_BGP_PEER_ENTRY) - { - if (o->n_subid == 3) - return 1; - if (o->n_subid == 8 && o->ids[3] > 0) - return 1; - } - return 0; - } - return 0; -} - static int oid_state_compare(const struct oid *oid, u8 state) { ASSUME(oid != NULL); - if (state >= BGP_INTERNAL_PEER_IDENTIFIER && - state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME) + if (state >= BGP4_MIB_S_PEER_IDENTIFIER && + state <= BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME) return (oid->n_subid > 9) - (oid->n_subid < 9); - if ((state >= BGP_INTERNAL_VERSION && state <= BGP_INTERNAL_PEER_TABLE) || - (state == BGP_INTERNAL_IDENTIFIER)) + if ((state >= BGP4_MIB_S_VERSION && state <= BGP4_MIB_S_PEER_TABLE) || + (state == BGP4_MIB_S_IDENTIFIER)) return (oid->n_subid > 3) - (oid->n_subid < 3); - if (state == BGP_INTERNAL_PEER_ENTRY) + if (state == BGP4_MIB_S_PEER_ENTRY) return (oid->n_subid > 4) - (oid->n_subid < 4); - if (state == BGP_INTERNAL_BGP) + if (state == BGP4_MIB_S_BGP) return (oid->n_subid > 2) - (oid->n_subid < 2); return -1; @@ -569,58 +582,58 @@ oid_state_compare(const struct oid *oid, u8 state) static struct oid * update_bgp_oid(struct oid *oid, u8 state) { - if (state == BGP_INTERNAL_END || state == BGP_INTERNAL_INVALID || - state == BGP_INTERNAL_NO_VALUE) + if (state == BGP4_MIB_S_END || state == BGP4_MIB_S_INVALID || + state == BGP4_MIB_S_NO_VALUE) return oid; /* No need to reallocate anything if the OID has same lin. state */ if (snmp_bgp_state(oid) == state) { - if (state >= BGP_INTERNAL_PEER_IDENTIFIER && - state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME && + if (state >= BGP4_MIB_S_PEER_IDENTIFIER && + state <= BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME && oid->n_subid == 9) return oid; - if (state >= BGP_INTERNAL_VERSION && - state <= BGP_INTERNAL_PEER_TABLE && oid->n_subid == 3) + if (state >= BGP4_MIB_S_VERSION && + state <= BGP4_MIB_S_PEER_TABLE && oid->n_subid == 3) return oid; - if (state == BGP_INTERNAL_PEER_ENTRY && oid->n_subid == 4) + if (state == BGP4_MIB_S_PEER_ENTRY && oid->n_subid == 4) return oid; - if (state == BGP_INTERNAL_BGP && oid->n_subid == 2) + if (state == BGP4_MIB_S_BGP && oid->n_subid == 2) return oid; } switch (state) { - case BGP_INTERNAL_BGP: + case BGP4_MIB_S_BGP: /* This could potentially destroy same old data */ if (oid->n_subid != 2) - oid = mb_realloc(oid, snmp_oid_sizeof(2)); + oid = mb_realloc(oid, snmp_oid_size_from_len(2)); oid->n_subid = 2; oid->ids[0] = SNMP_MIB_2; - oid->ids[1] = SNMP_BGP4_MIB; + oid->ids[1] = BGP4_MIB; break; - case BGP_INTERNAL_VERSION: + case BGP4_MIB_S_VERSION: if (oid->n_subid != 3) - oid = mb_realloc(oid, snmp_oid_sizeof(3)); + oid = mb_realloc(oid, snmp_oid_size_from_len(3)); oid->n_subid = 3; - oid->ids[2] = SNMP_BGP_VERSION; + oid->ids[2] = BGP4_MIB_VERSION; break; - case BGP_INTERNAL_LOCAL_AS: + case BGP4_MIB_S_LOCAL_AS: if (oid->n_subid != 3) - oid = mb_realloc(oid, snmp_oid_sizeof(3)); + oid = mb_realloc(oid, snmp_oid_size_from_len(3)); oid->n_subid = 3; - oid->ids[2] = SNMP_BGP_LOCAL_AS; + oid->ids[2] = BGP4_MIB_LOCAL_AS; break; - case BGP_INTERNAL_PEER_IDENTIFIER: + case BGP4_MIB_S_PEER_IDENTIFIER: if (oid->n_subid != 9) { - oid = mb_realloc(oid, snmp_oid_sizeof(9)); + oid = mb_realloc(oid, snmp_oid_size_from_len(9)); if (oid->n_subid < 6) oid->ids[5] = 0; @@ -632,10 +645,10 @@ update_bgp_oid(struct oid *oid, u8 state) oid->ids[8] = 0; } - oid->ids[2] = SNMP_BGP_PEER_TABLE; - oid->ids[3] = SNMP_BGP_PEER_ENTRY; + oid->ids[2] = BGP4_MIB_PEER_TABLE; + oid->ids[3] = BGP4_MIB_PEER_ENTRY; - oid->ids[4] = SNMP_BGP_PEER_IDENTIFIER; + oid->ids[4] = BGP4_MIB_PEER_IDENTIFIER; oid->n_subid = 9; break; @@ -643,7 +656,7 @@ update_bgp_oid(struct oid *oid, u8 state) case num: \ if (oid->n_subid != 9) \ { \ - oid = mb_realloc(oid, snmp_oid_sizeof(9)); \ + oid = mb_realloc(oid, snmp_oid_size_from_len(9)); \ \ if (oid->n_subid < 6) \ oid->ids[5] = 0; \ @@ -658,55 +671,55 @@ update_bgp_oid(struct oid *oid, u8 state) oid->ids[4] = update; \ break; - SNMP_UPDATE_CASE(BGP_INTERNAL_STATE, SNMP_BGP_STATE) + SNMP_UPDATE_CASE(BGP4_MIB_S_STATE, BGP4_MIB_STATE) - SNMP_UPDATE_CASE(BGP_INTERNAL_ADMIN_STATUS, SNMP_BGP_ADMIN_STATUS) + SNMP_UPDATE_CASE(BGP4_MIB_S_ADMIN_STATUS, BGP4_MIB_ADMIN_STATUS) - SNMP_UPDATE_CASE(BGP_INTERNAL_NEGOTIATED_VERSION, SNMP_BGP_NEGOTIATED_VERSION) + SNMP_UPDATE_CASE(BGP4_MIB_S_NEGOTIATED_VERSION, BGP4_MIB_NEGOTIATED_VERSION) - SNMP_UPDATE_CASE(BGP_INTERNAL_LOCAL_ADDR, SNMP_BGP_LOCAL_ADDR) + SNMP_UPDATE_CASE(BGP4_MIB_S_LOCAL_ADDR, BGP4_MIB_LOCAL_ADDR) - SNMP_UPDATE_CASE(BGP_INTERNAL_LOCAL_PORT, SNMP_BGP_LOCAL_PORT) + SNMP_UPDATE_CASE(BGP4_MIB_S_LOCAL_PORT, BGP4_MIB_LOCAL_PORT) - SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_ADDR, SNMP_BGP_REMOTE_ADDR) + SNMP_UPDATE_CASE(BGP4_MIB_S_REMOTE_ADDR, BGP4_MIB_REMOTE_ADDR) - SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_PORT, SNMP_BGP_REMOTE_PORT) + SNMP_UPDATE_CASE(BGP4_MIB_S_REMOTE_PORT, BGP4_MIB_REMOTE_PORT) - SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_AS, SNMP_BGP_REMOTE_AS) + SNMP_UPDATE_CASE(BGP4_MIB_S_REMOTE_AS, BGP4_MIB_REMOTE_AS) - SNMP_UPDATE_CASE(BGP_INTERNAL_RX_UPDATES, SNMP_BGP_RX_UPDATES) + SNMP_UPDATE_CASE(BGP4_MIB_S_RX_UPDATES, BGP4_MIB_RX_UPDATES) - SNMP_UPDATE_CASE(BGP_INTERNAL_TX_UPDATES, SNMP_BGP_TX_UPDATES) + SNMP_UPDATE_CASE(BGP4_MIB_S_TX_UPDATES, BGP4_MIB_TX_UPDATES) - SNMP_UPDATE_CASE(BGP_INTERNAL_RX_MESSAGES, SNMP_BGP_RX_MESSAGES) + SNMP_UPDATE_CASE(BGP4_MIB_S_RX_MESSAGES, BGP4_MIB_RX_MESSAGES) - SNMP_UPDATE_CASE(BGP_INTERNAL_TX_MESSAGES, SNMP_BGP_TX_MESSAGES) + SNMP_UPDATE_CASE(BGP4_MIB_S_TX_MESSAGES, BGP4_MIB_TX_MESSAGES) - SNMP_UPDATE_CASE(BGP_INTERNAL_LAST_ERROR, SNMP_BGP_LAST_ERROR) + SNMP_UPDATE_CASE(BGP4_MIB_S_LAST_ERROR, BGP4_MIB_LAST_ERROR) - SNMP_UPDATE_CASE(BGP_INTERNAL_FSM_TRANSITIONS, SNMP_BGP_FSM_TRANSITIONS) + SNMP_UPDATE_CASE(BGP4_MIB_S_FSM_TRANSITIONS, BGP4_MIB_FSM_TRANSITIONS) - SNMP_UPDATE_CASE(BGP_INTERNAL_FSM_ESTABLISHED_TIME, SNMP_BGP_FSM_ESTABLISHED_TIME) + SNMP_UPDATE_CASE(BGP4_MIB_S_FSM_ESTABLISHED_TIME, BGP4_MIB_FSM_ESTABLISHED_TIME) - SNMP_UPDATE_CASE(BGP_INTERNAL_RETRY_INTERVAL, SNMP_BGP_RETRY_INTERVAL) + SNMP_UPDATE_CASE(BGP4_MIB_S_RETRY_INTERVAL, BGP4_MIB_RETRY_INTERVAL) - SNMP_UPDATE_CASE(BGP_INTERNAL_HOLD_TIME, SNMP_BGP_HOLD_TIME) + SNMP_UPDATE_CASE(BGP4_MIB_S_HOLD_TIME, BGP4_MIB_HOLD_TIME) - SNMP_UPDATE_CASE(BGP_INTERNAL_KEEPALIVE, SNMP_BGP_KEEPALIVE) + SNMP_UPDATE_CASE(BGP4_MIB_S_KEEPALIVE, BGP4_MIB_KEEPALIVE) - SNMP_UPDATE_CASE(BGP_INTERNAL_HOLD_TIME_CONFIGURED, SNMP_BGP_HOLD_TIME_CONFIGURED) + SNMP_UPDATE_CASE(BGP4_MIB_S_HOLD_TIME_CONFIGURED, BGP4_MIB_HOLD_TIME_CONFIGURED) - SNMP_UPDATE_CASE(BGP_INTERNAL_KEEPALIVE_CONFIGURED, SNMP_BGP_KEEPALIVE_CONFIGURED) + SNMP_UPDATE_CASE(BGP4_MIB_S_KEEPALIVE_CONFIGURED, BGP4_MIB_KEEPALIVE_CONFIGURED) - SNMP_UPDATE_CASE(BGP_INTERNAL_ORIGINATION_INTERVAL, SNMP_BGP_ORIGINATION_INTERVAL) + SNMP_UPDATE_CASE(BGP4_MIB_S_ORIGINATION_INTERVAL, BGP4_MIB_ORIGINATION_INTERVAL) - SNMP_UPDATE_CASE(BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT, SNMP_BGP_MIN_ROUTE_ADVERTISEMENT) + SNMP_UPDATE_CASE(BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT, BGP4_MIB_MIN_ROUTE_ADVERTISEMENT) - SNMP_UPDATE_CASE(BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME, SNMP_BGP_IN_UPDATE_ELAPSED_TIME) + SNMP_UPDATE_CASE(BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME, BGP4_MIB_IN_UPDATE_ELAPSED_TIME) - case BGP_INTERNAL_IDENTIFIER: + case BGP4_MIB_S_IDENTIFIER: if (oid->n_subid != 3) - oid = mb_realloc(oid, snmp_oid_sizeof(3)); + oid = mb_realloc(oid, snmp_oid_size_from_len(3)); oid->n_subid = 3; oid->ids[2] = 4; @@ -715,81 +728,12 @@ update_bgp_oid(struct oid *oid, u8 state) default: /* intentionally left blank */ break; - //die("update unavailable"); } return oid; #undef SNMP_UPDATE_CASE } -static struct oid * -bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, const struct oid *o_end, u8 start_state) -{ - ASSUME(o_start != NULL); - ASSUME(o_end != NULL); - - ip4_addr ip4 = ip4_from_oid(o_start); - ip4_addr dest; - - if (o_start->n_subid < 9) - o_start->include = 1; - - int check_dest = snmp_is_oid_empty(o_end); - if (check_dest) - { - u8 end_state = snmp_bgp_state(o_end); - dest = (start_state == end_state && o_end->n_subid > 5) ? - ip4_from_oid(o_end) : - ip4_from_u32(UINT32_MAX); - } - - net_addr net; - net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH); - - struct f_trie_walk_state ws; - - trie_walk_init(&ws, p->bgp_trie, NULL, 0); - - if (!trie_walk_next(&ws, &net)) - return NULL; - - /* - * If the o_end is empty, then there are no conditions on the ip4 address. - */ - int cmp = ip4_compare(net4_prefix(&net), dest); - if (cmp < 0 || (cmp == 0 && snmp_is_oid_empty(o_end))) - { - // TODO repair - struct oid *o = snmp_oid_duplicate(p->pool, o_start); - snmp_oid_ip4_index(o, 5, net4_prefix(&net)); - - return o; - } - - return NULL; -} - -static struct oid * -search_bgp_dynamic(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid -UNUSED, u8 next_state) -{ - struct oid *o_copy = o_start; - do - { - o_start = o_copy = update_bgp_oid(o_copy, next_state); - - o_start = bgp_find_dynamic_oid(p, o_start, o_end, next_state); - - next_state = snmp_bgp_next_state(next_state); - /* The search in next state is done from beginning. */ - o_start->ids[5] = o_start->ids[6] = o_start->ids[7] = o_start->ids[8] = 0; - o_start->include = 1; - - } while (o_start == NULL && next_state < BGP_INTERNAL_END); - - return o_start; -} - /** * snmp_bgp_find_next_oid - walk bgp peer addresses and update @o_start oid * @@ -801,7 +745,6 @@ static int snmp_bgp_find_next_oid(struct snmp_proto *p, struct oid *oid, uint UNUSED contid) { ip4_addr ip4 = ip4_from_oid(oid); - //ip_add4 dest = ip4_from_u32(0xFFFFFFFF); net_addr net; net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH); @@ -823,13 +766,9 @@ snmp_bgp_find_next_oid(struct snmp_proto *p, struct oid *oid, uint UNUSED contid if (trie_walk_next(&ws, &net)) { - u32 res = ipa_to_u32(net_prefix(&net)); - ASSUME(oid->n_subid == 9); - oid->ids[5] = (res & 0xFF000000) >> 24; - oid->ids[6] = (res & 0x00FF0000) >> 16; - oid->ids[7] = (res & 0x0000FF00) >> 8; - oid->ids[8] = (res & 0x000000FF) >> 0; + ip4_addr res = ipa_to_ip4(net_prefix(&net)); + ip4_to_oid(oid, res); return 1; } @@ -840,9 +779,9 @@ static enum snmp_search_res snmp_bgp_search_dynamic(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint UNUSED contid, u8 next_state) { struct oid *oid = *searched; - u8 end_state = MIN(snmp_bgp_state(o_end), BGP_INTERNAL_PEER_TABLE_END); + u8 end_state = MIN(snmp_bgp_state(o_end), BGP4_MIB_S_PEER_TABLE_END); - ASSUME(end_state <= BGP_INTERNAL_END); + ASSUME(end_state <= BGP4_MIB_S_END); ASSUME(oid != NULL); oid = update_bgp_oid(oid, next_state); @@ -851,14 +790,14 @@ snmp_bgp_search_dynamic(struct snmp_proto *p, struct oid **searched, const struc while (!(found = snmp_bgp_find_next_oid(p, oid, contid)) && next_state <= end_state) { next_state = snmp_bgp_next_state(next_state); - if (next_state == BGP_INTERNAL_IDENTIFIER) + if (next_state == BGP4_MIB_S_IDENTIFIER) break; oid = update_bgp_oid(oid, next_state); /* In case of search for next bgp state, we want to start from beginning. */ oid->ids[5] = oid->ids[6] = oid->ids[7] = oid->ids[8] = 0; } - if (next_state < BGP_INTERNAL_PEER_TABLE_END && next_state <= end_state) + if (next_state < BGP4_MIB_S_PEER_TABLE_END && next_state <= end_state) { *searched = oid; return SNMP_SEARCH_OK; @@ -868,13 +807,13 @@ snmp_bgp_search_dynamic(struct snmp_proto *p, struct oid **searched, const struc } enum snmp_search_res -snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid) +snmp_bgp_search(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid) { enum snmp_search_res r = SNMP_SEARCH_END_OF_VIEW; u8 bgp_state = snmp_bgp_state(*searched); u8 state; - if (bgp_state == BGP_INTERNAL_END) + if (bgp_state == BGP4_MIB_S_END) { return SNMP_SEARCH_NO_OBJECT; } @@ -909,7 +848,7 @@ snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid * } state = snmp_bgp_next_state(bgp_state); - if (state <= BGP_INTERNAL_IDENTIFIER) + if (state <= BGP4_MIB_S_IDENTIFIER) { *searched = update_bgp_oid(*searched, state); return SNMP_SEARCH_OK; @@ -921,40 +860,6 @@ snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid * return SNMP_SEARCH_END_OF_VIEW; } -struct oid * -snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid UNUSED) -{ - u8 start_state = snmp_bgp_state(o_start); - - // print debugging information - print_bgp_record_all(p); - - if (o_start->include && snmp_bgp_has_value(start_state) && - !is_dynamic(start_state) && o_start->n_subid == 3) - { - /* We disable including for next time searching. */ - o_start->include = 0; - return o_start; - } - else if (o_start->include && snmp_bgp_has_value(start_state) && - is_dynamic(start_state)) - return search_bgp_dynamic(p, o_start, o_end, contid, start_state); - - /* o_start is not inclusive */ - - u8 next_state = snmp_bgp_next_state(start_state); - // TODO more checks ?!? - if (!is_dynamic(next_state)) - { - o_start = update_bgp_oid(o_start, next_state); - return o_start; - } - - /* is_dynamic(next_state) == 1 */ - - return search_bgp_dynamic(p, o_start, o_end, 0, next_state); -} - static byte * bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb, struct snmp_pdu *c, u8 state) @@ -1011,18 +916,18 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb, snmp_bgp_last_error(bgp_proto, last_error); switch (state) { - case BGP_INTERNAL_PEER_IDENTIFIER: - if (fsm_state == BGP_MIB_OPENCONFIRM || fsm_state == BGP_MIB_ESTABLISHED) + case BGP4_MIB_S_PEER_IDENTIFIER: + if (fsm_state == BGP4_MIB_OPENCONFIRM || fsm_state == BGP4_MIB_ESTABLISHED) pkt = snmp_varbind_ip4(vb, size, ip4_from_u32(bgp_proto->remote_id)); else pkt = snmp_varbind_ip4(vb, size, IP4_NONE); break; - case BGP_INTERNAL_STATE: + case BGP4_MIB_S_STATE: pkt = snmp_varbind_int(vb, size, fsm_state); break; - case BGP_INTERNAL_ADMIN_STATUS: + case BGP4_MIB_S_ADMIN_STATUS: if (bgp_proto->p.disabled) pkt = snmp_varbind_int(vb, size, AGENTX_ADMIN_STOP); else @@ -1030,79 +935,73 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb, break; - case BGP_INTERNAL_NEGOTIATED_VERSION: - if (fsm_state == BGP_MIB_ESTABLISHED || fsm_state == BGP_MIB_ESTABLISHED) - pkt = snmp_varbind_int(vb, size, SNMP_BGP_NEGOTIATED_VER_VALUE); + case BGP4_MIB_S_NEGOTIATED_VERSION: + if (fsm_state == BGP4_MIB_ESTABLISHED || fsm_state == BGP4_MIB_ESTABLISHED) + pkt = snmp_varbind_int(vb, size, BGP4_MIB_NEGOTIATED_VER_VALUE); else - pkt = snmp_varbind_int(vb, size, SNMP_BGP_NEGOTIATED_VER_NO_VALUE); + pkt = snmp_varbind_int(vb, size, BGP4_MIB_NEGOTIATED_VER_NO_VALUE); break; - case BGP_INTERNAL_LOCAL_ADDR: + case BGP4_MIB_S_LOCAL_ADDR: pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->local_ip)); break; - case BGP_INTERNAL_LOCAL_PORT: + case BGP4_MIB_S_LOCAL_PORT: pkt = snmp_varbind_int(vb, size, bgp_conf->local_port); break; - case BGP_INTERNAL_REMOTE_ADDR: + case BGP4_MIB_S_REMOTE_ADDR: pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->remote_ip)); break; - case BGP_INTERNAL_REMOTE_PORT: + case BGP4_MIB_S_REMOTE_PORT: pkt = snmp_varbind_int(vb, size, bgp_conf->remote_port); break; - case BGP_INTERNAL_REMOTE_AS: + case BGP4_MIB_S_REMOTE_AS: pkt = snmp_varbind_int(vb, size, bgp_proto->remote_as); break; - /* IN UPDATES */ - case BGP_INTERNAL_RX_UPDATES: + case BGP4_MIB_S_RX_UPDATES: /* bgpPeerInUpdates */ pkt = snmp_varbind_counter32(vb, size, bgp_stats->rx_updates); break; - /* OUT UPDATES */ - case BGP_INTERNAL_TX_UPDATES: + case BGP4_MIB_S_TX_UPDATES: /* bgpPeerOutUpdate */ pkt = snmp_varbind_counter32(vb, size, bgp_stats->tx_updates); break; - /* IN MESSAGES */ - case BGP_INTERNAL_RX_MESSAGES: + case BGP4_MIB_S_RX_MESSAGES: /* bgpPeerInTotalMessages */ pkt = snmp_varbind_counter32(vb, size, bgp_stats->rx_messages); break; - /* OUT MESSAGES */ - case BGP_INTERNAL_TX_MESSAGES: + case BGP4_MIB_S_TX_MESSAGES: /* bgpPeerOutTotalMessages */ pkt = snmp_varbind_counter32(vb, size, bgp_stats->tx_messages); break; - case BGP_INTERNAL_LAST_ERROR: + case BGP4_MIB_S_LAST_ERROR: pkt = snmp_varbind_nstr(vb, size, last_error, 2); break; - case BGP_INTERNAL_FSM_TRANSITIONS: + case BGP4_MIB_S_FSM_TRANSITIONS: pkt = snmp_varbind_counter32(vb, size, bgp_stats->fsm_established_transitions); break; - case BGP_INTERNAL_FSM_ESTABLISHED_TIME: + case BGP4_MIB_S_FSM_ESTABLISHED_TIME: pkt = snmp_varbind_gauge32(vb, size, (current_time() - bgp_proto->last_established) TO_S); break; - case BGP_INTERNAL_RETRY_INTERVAL: - // retry interval != 0 + case BGP4_MIB_S_RETRY_INTERVAL: /* retry inverval value should be != 0 */ pkt = snmp_varbind_int(vb, size, bgp_conf->connect_retry_time); break; - case BGP_INTERNAL_HOLD_TIME: - // (0, 3..65535) + case BGP4_MIB_S_HOLD_TIME: /* hold time should be == 0 or in 3..65535 */ pkt = snmp_varbind_int(vb, size, (bgp_conn) ? bgp_conn->hold_time : 0); break; - case BGP_INTERNAL_KEEPALIVE: + case BGP4_MIB_S_KEEPALIVE: if (!bgp_conf->hold_time) pkt = snmp_varbind_int(vb, size, 0); else @@ -1110,11 +1009,11 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb, (bgp_conn) ? bgp_conn->keepalive_time : 0); break; - case BGP_INTERNAL_HOLD_TIME_CONFIGURED: + case BGP4_MIB_S_HOLD_TIME_CONFIGURED: pkt = snmp_varbind_int(vb, size, bgp_conf->hold_time); break; - case BGP_INTERNAL_KEEPALIVE_CONFIGURED: + case BGP4_MIB_S_KEEPALIVE_CONFIGURED: if (!bgp_conf->keepalive_time) pkt = snmp_varbind_int(vb, size, 0); else @@ -1122,35 +1021,35 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb, (bgp_conn) ? bgp_conn->keepalive_time : 0); break; - case BGP_INTERNAL_ORIGINATION_INTERVAL: - // (1..65535) but is not supported + case BGP4_MIB_S_ORIGINATION_INTERVAL: + /* value should be in 1..65535 but is not supported by bird */ pkt = snmp_varbind_int(vb, size, 0); break; - case BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT: - // (1..65535) but is not supported + case BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT: + /* value should be in 1..65535 but is not supported by bird */ pkt = snmp_varbind_int(vb, size, 0); break; - case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME: + case BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME: pkt = snmp_varbind_gauge32(vb, size, (current_time() - bgp_proto->last_rx_update) TO_S ); break; - case BGP_INTERNAL_END: + case BGP4_MIB_S_END: break; - case BGP_INTERNAL_INVALID: + case BGP4_MIB_S_INVALID: break; - case BGP_INTERNAL_BGP: + case BGP4_MIB_S_BGP: break; - case BGP_INTERNAL_PEER_TABLE: + case BGP4_MIB_S_PEER_TABLE: break; - case BGP_INTERNAL_PEER_ENTRY: + case BGP4_MIB_S_PEER_ENTRY: break; - case BGP_INTERNAL_NO_VALUE: + case BGP4_MIB_S_NO_VALUE: break; } @@ -1176,7 +1075,7 @@ UNUSED, uint contid UNUSED, u8 state) * snmp_bgp_state() check only prefix. To be sure on OID equivalence we need to * compare the oid->n_subid length. All BGP static fields have same n_subid. */ - if (oid_state_compare(oid, state) < 0 || state == BGP_INTERNAL_END) + if (oid_state_compare(oid, state) < 0 || state == BGP4_MIB_S_END) { vb->type = AGENTX_NO_SUCH_OBJECT; return pkt + snmp_varbind_header_size(vb); @@ -1189,15 +1088,15 @@ UNUSED, uint contid UNUSED, u8 state) switch (state) { - case BGP_INTERNAL_VERSION: + case BGP4_MIB_S_VERSION: pkt = snmp_varbind_nstr(vb, size, BGP4_VERSIONS, 1); break; - case BGP_INTERNAL_LOCAL_AS: + case BGP4_MIB_S_LOCAL_AS: pkt = snmp_varbind_int(vb, size, p->bgp_local_as); break; - case BGP_INTERNAL_IDENTIFIER: + case BGP4_MIB_S_IDENTIFIER: pkt = snmp_varbind_ip4(vb, size, p->bgp_local_id); break; @@ -1231,19 +1130,10 @@ snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, return; } - vb->type = AGENTX_NO_SUCH_OBJECT; // TODO + vb->type = AGENTX_NO_SUCH_OBJECT; ADVANCE(c->buffer, c->size, snmp_varbind_header_size(vb)); } -#if 0 -int -snmp_bgp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, void *tr, struct oid *oid, uint pkt_size) -{ - // TODO: check the type of varbind vb and it's value correctness, don't overflow the pkt_size - return 0; -} -#endif - /* * snmp_bgp_start - prepare BGP4-MIB * @p - SNMP protocol instance holding memory pool @@ -1261,9 +1151,6 @@ snmp_bgp_start(struct snmp_proto *p) WALK_LIST(b, cf->bgp_entries) { const struct bgp_config *bgp_config = (struct bgp_config *) b->config; - if (ipa_zero(bgp_config->remote_ip)) - die("unsupported dynamic BGP"); - const struct bgp_proto *bgp = SKIP_BACK(struct bgp_proto, p, bgp_config->c.proto); diff --git a/proto/snmp/bgp_mib.h b/proto/snmp/bgp_mib.h index 4fcd96ae..c044c0ef 100644 --- a/proto/snmp/bgp_mib.h +++ b/proto/snmp/bgp_mib.h @@ -4,39 +4,41 @@ #include "snmp.h" #include "subagent.h" +#define BGP4_MIB 15 + /* peers attributes */ -enum BGP4_MIB_PEER_TABLE { - SNMP_BGP_PEER_IDENTIFIER = 1, - SNMP_BGP_STATE = 2, - SNMP_BGP_ADMIN_STATUS = 3, /* in read-only mode */ - SNMP_BGP_NEGOTIATED_VERSION = 4, - SNMP_BGP_LOCAL_ADDR = 5, - SNMP_BGP_LOCAL_PORT = 6, - SNMP_BGP_REMOTE_ADDR = 7, - SNMP_BGP_REMOTE_PORT = 8, - SNMP_BGP_REMOTE_AS = 9, - SNMP_BGP_RX_UPDATES = 10, /* in updates */ - SNMP_BGP_TX_UPDATES = 11, /* out updates */ - SNMP_BGP_RX_MESSAGES = 12, /* in total messages */ - SNMP_BGP_TX_MESSAGES = 13, /* out total messages */ - SNMP_BGP_LAST_ERROR = 14, - SNMP_BGP_FSM_TRANSITIONS = 15, /* FSM established transitions */ - SNMP_BGP_FSM_ESTABLISHED_TIME = 16, - SNMP_BGP_RETRY_INTERVAL = 17, - SNMP_BGP_HOLD_TIME = 18, - SNMP_BGP_KEEPALIVE = 19, - SNMP_BGP_HOLD_TIME_CONFIGURED = 20, - SNMP_BGP_KEEPALIVE_CONFIGURED = 21, - SNMP_BGP_ORIGINATION_INTERVAL = 22, /* UNSUPPORTED - 0 */ - SNMP_BGP_MIN_ROUTE_ADVERTISEMENT = 23, /* UNSUPPORTED - 0 */ - SNMP_BGP_IN_UPDATE_ELAPSED_TIME = 24, +enum bgp4_mib_peer_entry_row { + BGP4_MIB_PEER_IDENTIFIER = 1, + BGP4_MIB_STATE = 2, + BGP4_MIB_ADMIN_STATUS = 3, /* in read-only mode */ + BGP4_MIB_NEGOTIATED_VERSION = 4, + BGP4_MIB_LOCAL_ADDR = 5, + BGP4_MIB_LOCAL_PORT = 6, + BGP4_MIB_REMOTE_ADDR = 7, + BGP4_MIB_REMOTE_PORT = 8, + BGP4_MIB_REMOTE_AS = 9, + BGP4_MIB_RX_UPDATES = 10, /* in updates */ + BGP4_MIB_TX_UPDATES = 11, /* out updates */ + BGP4_MIB_RX_MESSAGES = 12, /* in total messages */ + BGP4_MIB_TX_MESSAGES = 13, /* out total messages */ + BGP4_MIB_LAST_ERROR = 14, + BGP4_MIB_FSM_TRANSITIONS = 15, /* FSM established transitions */ + BGP4_MIB_FSM_ESTABLISHED_TIME = 16, + BGP4_MIB_RETRY_INTERVAL = 17, + BGP4_MIB_HOLD_TIME = 18, + BGP4_MIB_KEEPALIVE = 19, + BGP4_MIB_HOLD_TIME_CONFIGURED = 20, + BGP4_MIB_KEEPALIVE_CONFIGURED = 21, + BGP4_MIB_ORIGINATION_INTERVAL = 22, /* UNSUPPORTED - 0 */ + BGP4_MIB_MIN_ROUTE_ADVERTISEMENT = 23, /* UNSUPPORTED - 0 */ + BGP4_MIB_IN_UPDATE_ELAPSED_TIME = 24, } PACKED; /* version of BGP, here BGP-4 */ #define BGP4_VERSIONS ((char[]) { 0x10 }) /* OID bgp.bgpVersion */ /* for OID bgp.bgpPeerTable.bgpPeerEntry.bgpPeerNegotiatedVersion */ -#define SNMP_BGP_NEGOTIATED_VER_VALUE 4 -#define SNMP_BGP_NEGOTIATED_VER_NO_VALUE 0 +#define BGP4_MIB_NEGOTIATED_VER_VALUE 4 +#define BGP4_MIB_NEGOTIATED_VER_NO_VALUE 0 void snmp_bgp_register(struct snmp_proto *p); @@ -46,66 +48,81 @@ void snmp_bgp_reg_failed(struct snmp_proto *p, struct agentx_response *r, struct u8 snmp_bgp_get_valid(u8 state); u8 snmp_bgp_getnext_valid(u8 state); -struct oid *snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid); -enum snmp_search_res snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid); +enum snmp_search_res snmp_bgp_search(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid); void snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, struct snmp_pdu *c); //int snmp_bgp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, void* tr, struct oid *oid, uint pkt_type); void snmp_bgp_notify_established(struct snmp_proto *p, struct bgp_proto *bgp); void snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp); -#define SNMP_BGP_VERSION 1 -#define SNMP_BGP_LOCAL_AS 2 -#define SNMP_BGP_PEER_TABLE 3 -#define SNMP_BGP_PEER_ENTRY 1 -#define SNMP_BGP_IDENTIFIER 4 /* BGP4-MIB::bgpIdentifier local router id */ - -/* BGP linearized state */ -enum BGP_INTERNAL_STATES { - BGP_INTERNAL_INVALID = 0, - BGP_INTERNAL_START = 1, - BGP_INTERNAL_BGP, - BGP_INTERNAL_VERSION, - BGP_INTERNAL_LOCAL_AS, - BGP_INTERNAL_PEER_TABLE, - BGP_INTERNAL_PEER_ENTRY, - BGP_INTERNAL_PEER_IDENTIFIER, - BGP_INTERNAL_STATE, - BGP_INTERNAL_ADMIN_STATUS, - BGP_INTERNAL_NEGOTIATED_VERSION, - BGP_INTERNAL_LOCAL_ADDR, - BGP_INTERNAL_LOCAL_PORT, - BGP_INTERNAL_REMOTE_ADDR, - BGP_INTERNAL_REMOTE_PORT, - BGP_INTERNAL_REMOTE_AS, - BGP_INTERNAL_RX_UPDATES, - BGP_INTERNAL_TX_UPDATES, - BGP_INTERNAL_RX_MESSAGES, - BGP_INTERNAL_TX_MESSAGES, - BGP_INTERNAL_LAST_ERROR, - BGP_INTERNAL_FSM_TRANSITIONS, - BGP_INTERNAL_FSM_ESTABLISHED_TIME, - BGP_INTERNAL_RETRY_INTERVAL, - BGP_INTERNAL_HOLD_TIME, - BGP_INTERNAL_KEEPALIVE, - BGP_INTERNAL_HOLD_TIME_CONFIGURED, - BGP_INTERNAL_KEEPALIVE_CONFIGURED, - BGP_INTERNAL_ORIGINATION_INTERVAL, - BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT, - BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME, - BGP_INTERNAL_PEER_TABLE_END, - BGP_INTERNAL_IDENTIFIER, /* local identification */ - BGP_INTERNAL_END, - BGP_INTERNAL_NO_VALUE = 255, -} PACKED; - -enum bgp4_mib_bgp_states { - BGP_MIB_IDLE = 1, - BGP_MIB_CONNECT = 2, - BGP_MIB_ACTIVE = 3, - BGP_MIB_OPENSENT = 4, - BGP_MIB_OPENCONFIRM = 5, - BGP_MIB_ESTABLISHED = 6, +enum bgp4_mib_rows { + BGP4_MIB_VERSION = 1, + BGP4_MIB_LOCAL_AS = 2, + BGP4_MIB_PEER_TABLE = 3, /* subtable */ + BGP4_MIB_IDENTIFIER = 4, /* BGP4-MIB::bgpIdentifier local router id */ }; +enum bgp4_mib_peer_table_rows { + BGP4_MIB_PEER_ENTRY = 1, +}; + +enum bgp4_mib_linearized_states { + BGP4_MIB_S_INVALID = 0, /* state invalid */ + BGP4_MIB_S_START = 1, + BGP4_MIB_S_BGP, + BGP4_MIB_S_VERSION, + BGP4_MIB_S_LOCAL_AS, + BGP4_MIB_S_PEER_TABLE, + BGP4_MIB_S_PEER_ENTRY, + BGP4_MIB_S_PEER_IDENTIFIER, + BGP4_MIB_S_STATE, + BGP4_MIB_S_ADMIN_STATUS, + BGP4_MIB_S_NEGOTIATED_VERSION, + BGP4_MIB_S_LOCAL_ADDR, + BGP4_MIB_S_LOCAL_PORT, + BGP4_MIB_S_REMOTE_ADDR, + BGP4_MIB_S_REMOTE_PORT, + BGP4_MIB_S_REMOTE_AS, + BGP4_MIB_S_RX_UPDATES, + BGP4_MIB_S_TX_UPDATES, + BGP4_MIB_S_RX_MESSAGES, + BGP4_MIB_S_TX_MESSAGES, + BGP4_MIB_S_LAST_ERROR, + BGP4_MIB_S_FSM_TRANSITIONS, + BGP4_MIB_S_FSM_ESTABLISHED_TIME, + BGP4_MIB_S_RETRY_INTERVAL, + BGP4_MIB_S_HOLD_TIME, + BGP4_MIB_S_KEEPALIVE, + BGP4_MIB_S_HOLD_TIME_CONFIGURED, + BGP4_MIB_S_KEEPALIVE_CONFIGURED, + BGP4_MIB_S_ORIGINATION_INTERVAL, + BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT, + BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME, + BGP4_MIB_S_PEER_TABLE_END, + BGP4_MIB_S_IDENTIFIER, /* state local identification */ + BGP4_MIB_S_END, + BGP4_MIB_S_NO_VALUE = 255, +} PACKED; + +/* valid values for BGP4_MIB_STATE */ +enum bgp4_mib_bgp_states { + BGP4_MIB_IDLE = 1, + BGP4_MIB_CONNECT = 2, + BGP4_MIB_ACTIVE = 3, + BGP4_MIB_OPENSENT = 4, + BGP4_MIB_OPENCONFIRM = 5, + BGP4_MIB_ESTABLISHED = 6, +}; + +STATIC_ASSERT(BGP4_MIB_IDLE == BS_IDLE + 1); +STATIC_ASSERT(BGP4_MIB_CONNECT == BS_CONNECT + 1); +STATIC_ASSERT(BGP4_MIB_ACTIVE == BS_ACTIVE + 1); +STATIC_ASSERT(BGP4_MIB_OPENSENT == BS_OPENSENT + 1); +STATIC_ASSERT(BGP4_MIB_OPENCONFIRM == BS_OPENCONFIRM + 1); +STATIC_ASSERT(BGP4_MIB_ESTABLISHED == BS_ESTABLISHED + 1); + +/* Traps OID sub-identifiers */ +#define BGP4_MIB_ESTABLISHED_NOTIFICATION 1 +#define BGP4_MIB_BACKWARD_TRANS_NOTIFICATION 2 + #endif diff --git a/proto/snmp/snmp.c b/proto/snmp/snmp.c index fbff7270..fe7e8f5f 100644 --- a/proto/snmp/snmp.c +++ b/proto/snmp/snmp.c @@ -1,5 +1,4 @@ -/* - * BIRD -- Simple Network Management Protocol (SNMP) * +/** BIRD -- Simple Network Management Protocol (SNMP) * * (c) 2022 Vojtech Vilimek * (c) 2022 CZ.NIC z.s.p.o. * @@ -134,7 +133,6 @@ static void snmp_cleanup(struct snmp_proto *p); static int snmp_rx_skip(sock UNUSED *sk, uint UNUSED size) { - log(L_INFO "snmp_rx_skip with size %u", size); return 1; } @@ -144,29 +142,38 @@ snmp_rx_skip(sock UNUSED *sk, uint UNUSED size) * * The socket tx_hook is called when the TX-buffer is empty, i.e. all data was * send. This function is used only when we found malformed PDU and we are - * resetting the established session. If called we direcly reset the session. + * resetting the established session. If called, we are reseting the session. */ static void snmp_tx_skip(sock *sk) { - log(L_INFO "snmp_tx_skip()"); struct snmp_proto *p = sk->data; - snmp_set_state(p, SNMP_DOWN); + proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN)); } /* * snmp_set_state - change state with associated actions * @p - SNMP protocol instance * @state - new SNMP protocol state + * + * This function does not notify the bird about protocol state. It is therefore + * a responsibility of the caller to use the returned value appropriately. + * + * Return current protocol state. */ -void +int snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state) { enum snmp_proto_state last = p->state; TRACE(D_EVENTS, "SNMP changing state to %u", state); - p->state = state; + if (state == SNMP_DOWN && (last == SNMP_REGISTER || last == SNMP_CONN)) + { + /* We have a connection established (at least send out agentx-Open-PDU) */ + state = SNMP_STOP; + } + /* else - We did not send any packet, we perform protocol cleanup only. */ if (last == SNMP_RESET) { @@ -174,10 +181,12 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state) p->sock = NULL; } + p->state = state; + switch (state) { case SNMP_INIT: - debug("snmp -> SNMP_INIT\n"); + DBG("snmp -> SNMP_INIT\n"); ASSERT(last == SNMP_DOWN); struct object_lock *lock; lock = p->lock = olock_new(p->pool); @@ -192,12 +201,11 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state) lock->hook = snmp_start_locked; lock->data = p; olock_acquire(lock); - break; + return PS_START; case SNMP_LOCKED: - debug("snmp -> SNMP_LOCKED\n"); + DBG("snmp -> SNMP_LOCKED\n"); ASSERT(last == SNMP_INIT || SNMP_RESET); - snmp_unset_header(p); sock *s = sk_new(p->pool); s->type = SK_TCP_ACTIVE; s->saddr = ipa_from_ip4(p->local_ip); @@ -220,60 +228,56 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state) p->sock = NULL; tm_start(p->startup_timer, p->timeout); } - break; + return PS_START; case SNMP_OPEN: - debug("snmp -> SNMP_OPEN\n"); + DBG("snmp -> SNMP_OPEN\n"); ASSERT(last == SNMP_LOCKED); p->sock->rx_hook = snmp_rx; p->sock->tx_hook = NULL; - log(L_WARN " Staring subagent %u %u %u %u", p->header_offset, p->last_index, p->last_size, p->last_pkt_id); snmp_start_subagent(p); // handle no response (for long time) - break; + return PS_START; case SNMP_REGISTER: - debug("snmp -> SNMP_REGISTER\n"); + DBG("snmp -> SNMP_REGISTER\n"); ASSERT(last == SNMP_OPEN); snmp_register_mibs(p); - break; + return PS_START; case SNMP_CONN: - debug("snmp -> SNMP_CONN\n"); + DBG("snmp -> SNMP_CONN\n"); ASSERT(last == SNMP_REGISTER); - proto_notify_state(&p->p, PS_UP); - break; + return PS_UP; case SNMP_STOP: - debug("snmp -> SNMP_STOP\n"); + DBG("snmp -> SNMP_STOP\n"); ASSUME(last == SNMP_REGISTER || last == SNMP_CONN); snmp_stop_subagent(p); p->sock->rx_hook = snmp_rx_skip; p->sock->tx_hook = snmp_tx_skip; p->startup_timer->hook = snmp_stop_timeout; tm_start(p->startup_timer, p->timeout); - proto_notify_state(&p->p, PS_STOP); - break; + return PS_STOP; case SNMP_DOWN: - debug("snmp -> SNMP_DOWN\n"); - //ASSUME(last == SNMP_STOP || SNMP_INIT || SNMP_LOCKED || SNMP_OPEN); + DBG("snmp -> SNMP_DOWN\n"); snmp_cleanup(p); // FIXME: handle the state in which we call proto_notify_state and // immediately return PS_DOWN from snmp_shutdown() - proto_notify_state(&p->p, PS_DOWN); - break; + return PS_DOWN; case SNMP_RESET: - debug("snmp -> SNMP_RESET\n"); + DBG("snmp -> SNMP_RESET\n"); ASSUME(last == SNMP_REGISTER || last == SNMP_CONN); ASSUME(p->sock); p->sock->rx_hook = snmp_rx_skip; p->sock->tx_hook = snmp_tx_skip; - break; + return PS_STOP; default: - die("unknown state transition"); + die("unknown snmp state transition"); + return PS_DOWN; } } @@ -281,7 +285,7 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state) * snmp_init - preinitialize SNMP instance * @CF - SNMP configuration generic handle * - * Return value is generic handle pointing to preinitialized SNMP procotol + * Returns a generic handle pointing to preinitialized SNMP procotol * instance. */ static struct proto * @@ -344,24 +348,8 @@ snmp_cleanup(struct snmp_proto *p) p->bgp_trie = NULL; } -#if 0 /* - * snmp_down - stop the SNMP protocol and free resources - * @p - SNMP protocol instance - * - * AgentX session is destroyed by closing underlying socket and all resources - * are freed. Afterwards, the PS_DOWN protocol state is announced. - */ -void -snmp_down(struct snmp_proto *p) -{ - snmp_cleanup(p); - proto_notify_state(&p->p, PS_DOWN); -} -#endif - -/* - * snmp_connected - start AgentX session on established channel + * snmp_connected - start AgentX session on created socket * @sk - socket owned by SNMP protocol instance * * Starts the AgentX communication by sending an agentx-Open-PDU. @@ -375,32 +363,18 @@ snmp_connected(sock *sk) } /* - * snmp_sock_disconnect - end or reset socket connection + * snmp_reset - end the communication on AgentX session * @p - SNMP protocol instance * - * If the @reconnect flags is set, we close the socket and then reestablish - * the AgentX session by reentering the start procedure as from the - * snmp_start_locked() function. - * Otherwise we simply shutdown the SNMP protocol if the flag is clear. + * End the communication on AgentX session by downing the whole procotol. This + * causes socket closure that implies AgentX session disconnection. * This function is internal and shouldn't be used outside the SNMP module. */ void -snmp_sock_disconnect(struct snmp_proto *p, int reconnect) +snmp_reset(struct snmp_proto *p) { tm_stop(p->ping_timer); - - if (!reconnect) - { - snmp_set_state(p, SNMP_DOWN); - return; - } - - // TODO - wouldn't be better to use inter jump state RESET (soft reset) ? - snmp_set_state(p, SNMP_DOWN); - - /* We try to reconnect after a short delay */ - //p->startup_timer->hook = snmp_startup_timeout; - //tm_start(p->startup_timer, 4); // TODO make me configurable + proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN)); } /* @@ -414,7 +388,7 @@ snmp_sock_err(sock *sk, int UNUSED err) struct snmp_proto *p = sk->data; TRACE(D_EVENTS, "SNMP socket error %d", err); - snmp_sock_disconnect(p, 1); + snmp_reset(p); } /* @@ -444,80 +418,17 @@ snmp_start_locked(struct object_lock *lock) * snmp_reconnect - helper restarting the AgentX session on packet errors * @tm - the startup_timer holding the SNMP protocol instance * - * Rerun the SNMP module start procedure. Used in situations when the master - * agent returns an agentx-Response-PDU with 'Not Opened' error. We do not close - * the socket if have one. + * Try to recover from an error by reseting the SNMP protocol. It is a simple + * snmp_reset() wrapper for timers. */ void snmp_reconnect(timer *tm) { struct snmp_proto *p = tm->data; - // TODO - snmp_set_state(p, SNMP_DOWN); + snmp_reset(p); return; - /* reset the connection */ - snmp_sock_disconnect(p, 1); - // TODO better snmp_set_state(SNMP_DOWM); ?? - if (p->state == SNMP_STOP || - p->state == SNMP_DOWN) - return; - - // TO-DO is SNMP_RESET really needed ? - if (p->state == SNMP_INIT || - p->state == SNMP_RESET) - //snmp_startup(p); - {} - - if (!p->sock) - snmp_start_locked(p->lock); - else - snmp_connected(p->sock); } -#if 0 -/* - * snmp_startup - start initialized SNMP protocol - * @p - SNMP protocol to start - * - * Starting of SNMP protocols begins with address acqusition through object - * lock. Next step is handled by snmp_start_locked() function. - * This function is internal and shouldn't be used outside the SNMP - * module. - */ -void -snmp_startup(struct snmp_proto *p) -{ - // TODO inline to snmp_start() - if (p->state == SNMP_OPEN || - p->state == SNMP_REGISTER || - p->state == SNMP_CONN) - { - return; - } - - if (p->lock) - { - snmp_start_locked(p->lock); - return; - } - - p->state = SNMP_INIT; - - struct object_lock *lock; - lock = p->lock = olock_new(p->pool); - - // lock->addr - // lock->port - // lock->iface - // lock->vrf - lock->type = OBJLOCK_TCP; - lock->hook = snmp_start_locked; - lock->data = p; - - olock_acquire(lock); -} -#endif - /* * snmp_startup_timeout - start the initiliazed SNMP protocol * @tm - the startup_timer holding the SNMP protocol instance. @@ -547,14 +458,15 @@ static void snmp_stop_timeout(timer *tm) { struct snmp_proto *p = tm->data; - snmp_set_state(p, SNMP_DOWN); + proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN)); } /* * snmp_ping_timeout - send a agentx-Ping-PDU * @tm - the ping_timer holding the SNMP protocol instance. * - * Send an agentx-Ping-PDU and reset the timer for next ping. + * Send an agentx-Ping-PDU. This function is periodically called by ping + * timer. */ static void snmp_ping_timeout(timer *tm) @@ -568,7 +480,7 @@ snmp_ping_timeout(timer *tm) * @P - SNMP protocol generic handle * * The first step in AgentX subagent startup is protocol initialition. - * We must prepare lists, find BGP peers and finally asynchornously open + * We must prepare lists, find BGP peers and finally asynchronously open * a AgentX subagent session through snmp_startup() function call. */ static int @@ -584,7 +496,7 @@ snmp_start(struct proto *P) p->bgp_local_as = cf->bgp_local_as; p->bgp_local_id = cf->bgp_local_id; p->timeout = cf->timeout; - // add default value for startup_delay inside bison .Y file + // TODO add default value for startup_delay inside bison .Y file p->startup_delay = cf->startup_delay; p->pool = p->p.pool; @@ -602,11 +514,7 @@ snmp_start(struct proto *P) snmp_bgp_start(p); - snmp_unset_header(p); - - snmp_set_state(p, SNMP_INIT); - - return PS_START; + return snmp_set_state(p, SNMP_INIT); } static inline int @@ -647,23 +555,23 @@ skip: * @CF - SNMP protocol configuration generic handle carring new values * * We accept the reconfiguration if the new configuration @CF is identical with - * the currently deployed. Otherwise we deny reconfiguration because + * the currently deployed configuration. Otherwise we deny reconfiguration because * the implementation would be cumbersome. */ static int snmp_reconfigure(struct proto *P, struct proto_config *CF) { - // remove lost bonds, add newly created struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P); const struct snmp_config *new = SKIP_BACK(struct snmp_config, cf, CF); + /* We are searching for configuration changes */ int retval = snmp_reconfigure_logic(p, new); - if (retval) { + if (retval) + { /* Reinitialize the hash after snmp_shutdown() */ HASH_INIT(p->bgp_hash, p->pool, 10); snmp_bgp_start(p); - snmp_unset_header(p); } return retval; @@ -683,7 +591,6 @@ snmp_show_proto_info(struct proto *P) // TODO move me into the bgp_mib.c cli_msg(-1006, " BGP4-MIB"); - // TODO enabled cli_msg(-1006, " Local AS %u", p->bgp_local_as); cli_msg(-1006, " Local router id %R", p->bgp_local_id); cli_msg(-1006, " BGP peers"); @@ -726,20 +633,7 @@ static int snmp_shutdown(struct proto *P) { struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P); - - if (p->state == SNMP_REGISTER || - p->state == SNMP_CONN) - { - /* We have a connection established (at leased send out Open-PDU). */ - snmp_set_state(p, SNMP_STOP); - return PS_STOP; - } - else - { - /* We did not create a connection, we clean the lock and other stuff. */ - snmp_set_state(p, SNMP_DOWN); - return PS_DOWN; - } + return snmp_set_state(p, SNMP_DOWN); } diff --git a/proto/snmp/snmp.h b/proto/snmp/snmp.h index 35f7817d..cb80cdf4 100644 --- a/proto/snmp/snmp.h +++ b/proto/snmp/snmp.h @@ -29,6 +29,7 @@ #define SNMP_RX_BUFFER_SIZE 8192 #define SNMP_TX_BUFFER_SIZE 8192 +#define SNMP_PKT_SIZE_MAX 8192 enum snmp_proto_state { SNMP_DOWN = 0, @@ -60,11 +61,15 @@ struct snmp_config { btime timeout; btime startup_delay; u8 priority; - //struct iface *iface; + //struct iface *iface; TODO u32 bonds; - const char *description; - list bgp_entries; - // TODO add support for subagent oid identification + const char *description; /* The order of fields is not arbitrary */ + list bgp_entries; /* We want dynamically allocated fields to be + * at the end of the config struct. + * We use this fact to check differences of + * nonallocated parts of configs with memcpy + */ + //const struct oid *oid_identifier; TODO }; #define SNMP_BGP_P_REGISTERING 0x01 @@ -109,13 +114,6 @@ struct snmp_proto { sock *sock; - /* Partial packet processing */ - uint header_offset; /* offset of PDU header in TX-buffer during - * partial parsing */ - uint last_index; /* stores last index during partial parsing */ - uint last_size; /* number of bytes used inside TX-buffer */ - uint last_pkt_id; /* stores packetId to use for partial packet */ - btime timeout; /* timeout is part of MIB registration. It specifies how long should the master @@ -147,8 +145,8 @@ void snmp_startup(struct snmp_proto *p); void snmp_connected(sock *sk); void snmp_startup_timeout(timer *tm); void snmp_reconnect(timer *tm); -void snmp_sock_disconnect(struct snmp_proto *p, int reconnect); -void snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state); +int snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state); +void snmp_reset(struct snmp_proto *p); #endif diff --git a/proto/snmp/snmp_utils.c b/proto/snmp/snmp_utils.c index cc78f85e..5e706dbb 100644 --- a/proto/snmp/snmp_utils.c +++ b/proto/snmp/snmp_utils.c @@ -11,29 +11,25 @@ #include "snmp_utils.h" inline void -snmp_pdu_context(const struct snmp_proto *p, struct snmp_pdu *pdu, sock *sk) +snmp_pdu_context(struct snmp_pdu *pdu, sock *sk) { pdu->error = AGENTX_RES_NO_ERROR; - if (!snmp_is_partial(p)) - { - pdu->buffer = sk->tpos; - pdu->size = sk->tbuf + sk->tbsize - sk->tpos; - pdu->index = 0; - return; - } - - pdu->buffer = sk->tbuf + p->header_offset + p->last_size; - pdu->size = sk->tbuf + sk->tbsize - pdu->buffer; - pdu->index = p->last_index; + pdu->buffer = sk->tpos; + pdu->size = sk->tbuf + sk->tbsize - sk->tpos; + pdu->index = 0; } +/** + * snmp_session - store packet ids from protocol to header + * @p: source SNMP protocol instance + * @h: dest PDU header + */ inline void snmp_session(const struct snmp_proto *p, struct agentx_header *h) { STORE_U32(h->session_id, p->session_id); STORE_U32(h->transaction_id, p->transaction_id); STORE_U32(h->packet_id, p->packet_id); - //log(L_INFO "storing packet id %u into the header %p", p->packet_id, h); } inline int @@ -42,17 +38,6 @@ snmp_has_context(const struct agentx_header *h) return h->flags & AGENTX_NON_DEFAULT_CONTEXT; } -inline byte * -snmp_add_context(struct snmp_proto *p, struct agentx_header *h, uint contid) -{ - u8 flags = LOAD_U8(h->flags); - STORE_U8(h->flags, flags | AGENTX_NON_DEFAULT_CONTEXT); - // TODO append the context after the header - (void)p; - (void)contid; - return (void *)h + AGENTX_HEADER_SIZE; -} - inline void * snmp_varbind_data(const struct agentx_varbind *vb) { @@ -64,11 +49,12 @@ snmp_varbind_data(const struct agentx_varbind *vb) * snmp_is_oid_empty - check if oid is null-valued * @oid: object identifier to check * - * Test if the oid header is full of zeroes. For @oid NULL returns 0. + * Test if the oid header is full of zeroes. For NULL-pointer @oid returns 0. */ int snmp_is_oid_empty(const struct oid *oid) { + /* We intentionaly ignore padding that should be zeroed */ if (oid != NULL) return LOAD_U8(oid->n_subid) == 0 && LOAD_U8(oid->prefix) == 0 && LOAD_U8(oid->include) == 0; @@ -96,9 +82,9 @@ void snmp_oid_copy(struct oid *dest, const struct oid *src) { STORE_U8(dest->n_subid, src->n_subid); - STORE_U8(dest->prefix, src->prefix); + STORE_U8(dest->prefix, src->prefix); STORE_U8(dest->include, src->include ? 1 : 0); - STORE_U8(dest->pad, 0); + STORE_U8(dest->reserved, 0); for (int i = 0; i < LOAD_U8(src->n_subid); i++) STORE_U32(dest->ids[i], src->ids[i]); @@ -118,7 +104,7 @@ snmp_oid_duplicate(pool *pool, const struct oid *oid) } /** - * create new null oid (blank) + * snmp_oid_blank - create new null oid (blank) * @p: pool hodling snmp_proto structure */ struct oid * @@ -128,10 +114,10 @@ snmp_oid_blank(struct snmp_proto *p) } /** - * snmp_str_size_from_len - return in-buffer octet-string size + * snmp_str_size_from_len - return in-buffer octet string size * @len: length of C-string, returned from strlen() */ -size_t +inline size_t snmp_str_size_from_len(uint len) { return 4 + BIRD_ALIGN(len, 4); @@ -157,7 +143,7 @@ snmp_str_size(const char *str) uint snmp_oid_size(const struct oid *o) { - return 4 + (o->n_subid * 4); + return 4 + (LOAD_U8(o->n_subid) * 4); } /** @@ -165,7 +151,7 @@ snmp_oid_size(const struct oid *o) * @n_subid: number of ids in oid */ inline size_t -snmp_oid_sizeof(uint n_subid) +snmp_oid_size_from_len(uint n_subid) { return sizeof(struct oid) + n_subid * sizeof(u32); } @@ -319,6 +305,32 @@ snmp_varbind_size(const struct agentx_varbind *vb, uint limit) } } +/** + * snmp_varbind_size_from_len - get size in-buffer VarBind for known OID and data + * @n_subid: number of subidentifiers of the VarBind's OID name + * @type: type of VarBind + * @len: length of variably long data + * + * For types with fixed size the @len is not used. For types such as Octet + * String, or OID the @len is used directly. + * + * Return number of bytes used by VarBind in specified form. + */ +inline size_t +snmp_varbind_size_from_len(uint n_subid, enum agentx_type type, uint len) +{ + size_t sz = snmp_oid_size_from_len(n_subid) + + sizeof(struct agentx_varbind) - sizeof(struct oid); + + int data_sz = agentx_type_size(type); + if (data_sz < 0) + sz += len; + else + sz += data_sz; + + return sz; +} + /* * snmp_test_varbind - test validity of VarBind's type * @vb: VarBind to test @@ -369,7 +381,7 @@ struct agentx_varbind * snmp_create_varbind(byte *buf, struct oid *oid) { struct agentx_varbind *vb = (void *) buf; - STORE_U16(vb->pad, 0); + STORE_U16(vb->reserved, 0); snmp_oid_copy(&vb->name, oid); return vb; } @@ -391,7 +403,7 @@ snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new) int snmp_valid_ip4_index(const struct oid *o, uint start) { - if (start + 3 < o->n_subid) + if (start + 3 < LOAD_U8(o->n_subid)) return snmp_valid_ip4_index_unsafe(o, start); else return 0; @@ -409,7 +421,7 @@ int snmp_valid_ip4_index_unsafe(const struct oid *o, uint start) { for (int i = 0; i < 4; i++) - if (o->ids[start + i] >= 256) + if (LOAD_U32(o->ids[start + i]) >= 256) return 0; return 1; @@ -501,6 +513,14 @@ snmp_put_fbyte(byte *buf, u8 data) return buf + 3; } +/* + * snmp_oid_ip4_index - OID append IPv4 index + * @o: OID to use + * @start: index of IP addr's MSB + * @addr: IPv4 address to use + * + * The indices from start to (inclusive) start+3 are overwritten by @addr bytes. + */ void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr) { @@ -511,37 +531,6 @@ snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr) STORE_U32(o->ids[start + 3], temp & 0xFF); } -void UNUSED -snmp_oid_dump(const struct oid *oid) -{ - log(L_WARN "OID DUMP ========"); - - if (oid == NULL) - { - log(L_WARN "is eqaul to NULL"); - log(L_WARN "OID DUMP END ===="); - log(L_WARN "."); - return; - } - - else if (snmp_is_oid_empty(oid)) - { - log(L_WARN "is empty"); - log(L_WARN "OID DUMP END ===="); - log(L_WARN "."); - return; - } - - log(L_WARN " #ids: %4u prefix %3u include: %5s", - oid->n_subid, oid->prefix, (oid->include)? "true" : "false"); - log(L_WARN "IDS -------------"); - - for (int i = 0; i < oid->n_subid; i++) - log(L_WARN " %2u: %11u ~ 0x%08X", i, oid->ids[i], oid->ids[i]); - - log(L_WARN "OID DUMP END ===="); - log(L_WARN); -} /** snmp_oid_compare - find the lexicographical order relation between @left and @right * both @left and @right has to be non-blank. @@ -665,11 +654,13 @@ agentx_type_size(enum agentx_type type) type == AGENTX_INTEGER) return 4; - /* AGENTX_COUNTER_64 */ if (type == AGENTX_COUNTER_64) return 8; - /* AGENTX_OBJECT_ID, AGENTX_OCTET_STRING, AGENTX_IP_ADDRESS, AGENTX_OPAQUE */ + if (AGENTX_IP_ADDRESS) + return snmp_str_size_from_len(4); + + /* AGENTX_OBJECT_ID, AGENTX_OCTET_STRING, AGENTX_OPAQUE */ else return -1; } @@ -759,78 +750,39 @@ snmp_test_close_reason(byte value) return 0; } -inline struct agentx_header * -snmp_create_tx_header(struct snmp_proto *p, byte *tbuf) -{ - /* the response is created always in TX-buffer */ - p->header_offset = tbuf - p->sock->tbuf; - ASSERT(p->header_offset < p->sock->tbsize); - return (struct agentx_header *) tbuf; -} /* - * Partial header manipulation functions + * Debugging */ -/* - * snmp_is_partial - check if we have a partially parted packet in TX-buffer - * @p: SNMP protocol instance - */ -inline int -snmp_is_partial(const struct snmp_proto *p) +void UNUSED +snmp_oid_dump(const struct oid *oid) { - return p->last_size > 0; -} + log(L_WARN "OID DUMP ========"); -/* - * snmp_get_header - restore partial packet's header from TX-buffer - * @p: SNMP protocol instance - */ -inline struct agentx_header * -snmp_get_header(const struct snmp_proto *p) -{ - /* Nonzero last size indicates existence of partial packet */ - ASSERT(p->last_size && p->header_offset < p->sock->tbsize); - return (struct agentx_header *) (p->sock->tbuf + p->header_offset); -} + if (oid == NULL) + { + log(L_WARN "is eqaul to NULL"); + log(L_WARN "OID DUMP END ===="); + log(L_WARN "."); + return; + } -/* - * snmp_set_header - store partial packet's header into protocol - * @p: SNMP protocol instance - * @h: header of the currently parsed PDU - * @c: SNMP PDU context - * - * Store the needed values regarding later partial PDU processing. - */ -inline void -snmp_set_header(struct snmp_proto *p, struct agentx_header *h, struct snmp_pdu *c) -{ - sock *sk = p->sock; - // TODO agentx_headier in last_size or not? - ASSERT(c->buffer - sk->tpos >= AGENTX_HEADER_SIZE); - p->last_size = c->buffer - sk->tpos + p->last_size; - p->header_offset = (((byte *) h) - sk->tbuf); - p->last_index = c->index; - log(L_INFO "using p->packet_id %u as a p->last_pkt_id %u", p->packet_id, p->last_pkt_id); - p->last_pkt_id = p->packet_id; - log(L_INFO "snmp_set_header() tbuf %p tpos %p buffer %p header %p header2 %p offset %u last_size %u last_index %u last_pkt_id %u", - sk->tbuf, sk->tpos, c->buffer,h,(byte*)h, p->header_offset, p->last_size, - p->last_index, p->last_pkt_id); -} + else if (snmp_is_oid_empty(oid)) + { + log(L_WARN "is empty"); + log(L_WARN "OID DUMP END ===="); + log(L_WARN "."); + return; + } -/* - * snmp_unset_header - clean partial packet's header - * @p: SNMP protocol instance - * - * Clean the partial packet processing fields of protocol when the packet is - * fully processed. - */ -inline void -snmp_unset_header(struct snmp_proto *p) -{ - p->last_size = 0; - p->header_offset = 0; - p->last_index = 0; - p->last_pkt_id = 0; -} + log(L_WARN " #ids: %4u prefix %3u include: %5s", + oid->n_subid, oid->prefix, (oid->include)? "true" : "false"); + log(L_WARN "IDS -------------"); + for (int i = 0; i < oid->n_subid; i++) + log(L_WARN " %2u: %11u ~ 0x%08X", i, oid->ids[i], oid->ids[i]); + + log(L_WARN "OID DUMP END ===="); + log(L_WARN); +} diff --git a/proto/snmp/snmp_utils.h b/proto/snmp/snmp_utils.h index 52ba1478..3026f77a 100644 --- a/proto/snmp/snmp_utils.h +++ b/proto/snmp/snmp_utils.h @@ -4,59 +4,65 @@ #include "subagent.h" uint snmp_pkt_len(const byte *start, const byte *end); + +/* + * + * AgentX Variable Biding (VarBind) utils + * + */ + +/* + * AgentX - Variable Binding (VarBind) type utils + */ +void snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t); +enum agentx_type snmp_get_varbind_type(const struct agentx_varbind *vb); +int agentx_type_size(enum agentx_type t); + +/* type Octet String */ size_t snmp_str_size_from_len(uint len); size_t snmp_str_size(const char *str); + +/* type OID - Object Identifier */ int snmp_is_oid_empty(const struct oid *oid); +uint snmp_oid_size(const struct oid *o); +size_t snmp_oid_size_from_len(uint n_subid); +void snmp_oid_copy(struct oid *dest, const struct oid *src); +int snmp_oid_compare(const struct oid *first, const struct oid *second); + +/* type IPv4 */ int snmp_valid_ip4_index(const struct oid *o, uint start); int snmp_valid_ip4_index_unsafe(const struct oid *o, uint start); -uint snmp_oid_size(const struct oid *o); -size_t snmp_oid_sizeof(uint n_subid); +void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr); + +/* + * AgentX - Variable Binding (VarBind) manupulation + */ uint snmp_varbind_hdr_size_from_oid(const struct oid *oid); uint snmp_varbind_header_size(const struct agentx_varbind *vb); uint snmp_varbind_size(const struct agentx_varbind *vb, uint limit); uint snmp_varbind_size_unsafe(const struct agentx_varbind *vb); +size_t snmp_varbind_size_from_len(uint n_subid, enum agentx_type t, uint len); int snmp_test_varbind(const struct agentx_varbind *vb); +void *snmp_varbind_data(const struct agentx_varbind *vb); + +/* + * AgentX - PDU headers, types, contexts + */ void snmp_session(const struct snmp_proto *p, struct agentx_header *h); int snmp_has_context(const struct agentx_header *h); -void snmp_pdu_context(const struct snmp_proto *p, struct snmp_pdu *pdu, sock *sk); - -void snmp_oid_copy(struct oid *dest, const struct oid *src); - +void snmp_pdu_context(struct snmp_pdu *pdu, sock *sk); struct oid *snmp_oid_duplicate(pool *pool, const struct oid *oid); struct oid *snmp_oid_blank(struct snmp_proto *p); -void *snmp_varbind_data(const struct agentx_varbind *vb); -struct agentx_varbind *snmp_create_varbind(byte *buf, struct oid *oid); -struct agentx_varbind *snmp_create_varbind_null(byte *buf); -byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new); +int snmp_test_close_reason(byte value); -int snmp_oid_compare(const struct oid *first, const struct oid *second); - -byte *snmp_no_such_object(byte *buf, struct agentx_varbind *vb, struct oid *oid); -byte *snmp_no_such_instance(byte *buf, struct agentx_varbind *vb, struct oid *oid); - -byte *snmp_put_str(byte *buf, const char *str); -byte *snmp_put_nstr(byte *buf, const char *str, uint len); -byte *snmp_put_blank(byte *buf); -byte *snmp_put_oid(byte *buf, struct oid *oid); - -byte *snmp_put_ip4(byte *buf, ip4_addr ip4); - -byte *snmp_put_fbyte(byte *buf, u8 data); - -void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr); - -void snmp_oid_dump(const struct oid *oid); - -void snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t); -enum agentx_type snmp_get_varbind_type(const struct agentx_varbind *vb); - -//struct oid *snmp_prefixize(struct snmp_proto *p, struct oid *o); - -struct snmp_registration *snmp_registration_create(struct snmp_proto *p, u8 mib_class); -int snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, u8 class); +/* + * AgentX - TX buffer manipulation + */ /* Functions filling buffer a typed value */ +struct agentx_varbind *snmp_create_varbind(byte *buf, struct oid *oid); +struct agentx_varbind *snmp_create_varbind_null(byte *buf); byte *snmp_varbind_int(struct agentx_varbind *vb, uint size, u32 val); byte *snmp_varbind_counter32(struct agentx_varbind *vb, uint size, u32 val); byte *snmp_varbind_gauge32(struct agentx_varbind *vb, uint size, s64 val); @@ -64,18 +70,28 @@ byte *snmp_varbind_ticks(struct agentx_varbind *vb, uint size, u32 val); byte *snmp_varbind_ip4(struct agentx_varbind *vb, uint size, ip4_addr addr); byte *snmp_varbind_nstr(struct agentx_varbind *vb, uint size, const char *str, uint len); +/* Raw */ +byte *snmp_no_such_object(byte *buf, struct agentx_varbind *vb, struct oid *oid); +byte *snmp_no_such_instance(byte *buf, struct agentx_varbind *vb, struct oid *oid); +byte *snmp_put_str(byte *buf, const char *str); +byte *snmp_put_nstr(byte *buf, const char *str, uint len); +byte *snmp_put_blank(byte *buf); +byte *snmp_put_oid(byte *buf, struct oid *oid); +byte *snmp_put_ip4(byte *buf, ip4_addr ip4); +byte *snmp_put_fbyte(byte *buf, u8 data); + + +/* + * + * Helpers, Misc, Debugging + * + */ +struct snmp_registration *snmp_registration_create(struct snmp_proto *p, u8 mib_class); +int snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, u8 class); + void snmp_dump_packet(byte *pkt, uint size); +void snmp_oid_dump(const struct oid *oid); enum agentx_type snmp_search_res_to_type(enum snmp_search_res res); -int agentx_type_size(enum agentx_type t); - -int snmp_test_close_reason(byte value); - -struct agentx_header *snmp_create_tx_header(struct snmp_proto *p, byte *rbuf); -int snmp_is_partial(const struct snmp_proto *p); -struct agentx_header *snmp_get_header(const struct snmp_proto *p); -void snmp_set_header(struct snmp_proto *p, struct agentx_header *h, struct snmp_pdu *c); -void snmp_unset_header(struct snmp_proto *p); - #endif diff --git a/proto/snmp/splitter.py b/proto/snmp/splitter.py new file mode 100755 index 00000000..ebd4f342 --- /dev/null +++ b/proto/snmp/splitter.py @@ -0,0 +1,92 @@ +#! /bin/env python3 + +""" +A very simple script used to test that BIRD does not segfaults on randomly split +AgentX PDUs. +""" + +import socket +import random +import time +import math + +ADDRESS = "127.0.0.1" +PORT = 5000 +AGENTX_MASTER_PORT = 705 + +def chunks(lst, n): + l = len(lst) + for i in range(0, l, n): + yield lst[i: min(i+n, l)] + +def print_msg(header, msg, total): + print(header, "{}/{}".format(len(msg), total)) + for line in chunks(msg, 16): + print(" ", end="") + for char in line: + print("0x{:02x} ".format(char), end="") + + print() + +def create_listen(): + tun = socket.socket() + print(f"Binding to port {PORT} on {ADDRESS}") + tun.bind((ADDRESS, PORT)) + print(f"Listening on {ADDRESS} port {PORT}") + tun.listen(2) + + return tun + +def io_loop(rx, tx): + while True: + try: + to_master = rx.recv(8192) + except BlockingIOError: + to_master = None + + try: + to_subagent = tx.recv(8192) + except BlockingIOError: + to_subagent = None + + if to_master is not None and len(to_master) > 0: + print_msg("S=>M: ", to_master, len(to_master)) + tx.send(to_master) + + if to_subagent is not None and len(to_subagent) > 0: + limit = 5 * len(to_subagent) / 100 + part_len = random.randint(math.ceil(limit), + math.floor(len(to_subagent) - limit)) + + print(f"M->S: {len(to_subagent[:part_len])}/{len(to_subagent)}") + rx.send(to_subagent[:part_len]) + time.sleep(0.4) + print_msg("M=>S: ", to_subagent, len(to_subagent)) + rx.send(to_subagent[part_len:]) + + time.sleep(0.02) + +def safe_io_loop(tun): + while True: + try: + rx, addr = tun.accept() + print("Subagent connected") + + tx = socket.socket() + tx.connect((ADDRESS, AGENTX_MASTER_PORT)) + print("Connected to master agent") + + rx.setblocking(False) + tx.setblocking(False) + + io_loop(rx, tx) + except BrokenPipeError: + rx.close() + tx.close() + +def main(): + with create_listen() as listening: + safe_io_loop(listening) + +if __name__ == '__main__': + main() diff --git a/proto/snmp/subagent.c b/proto/snmp/subagent.c index 5da01baf..c25155b5 100644 --- a/proto/snmp/subagent.c +++ b/proto/snmp/subagent.c @@ -62,12 +62,12 @@ */ static void snmp_mib_fill2(struct snmp_proto *p, struct oid *oid, struct snmp_pdu *c); -static uint parse_response(struct snmp_proto *p, byte *buf, uint size); -static void do_response(struct snmp_proto *p, byte *buf, uint size); -static uint parse_gets2_pdu(struct snmp_proto *p, byte *buf, uint size, uint *skip); +static uint parse_response(struct snmp_proto *p, byte *buf); +static void do_response(struct snmp_proto *p, byte *buf); +static uint parse_gets_pdu(struct snmp_proto *p, byte *pkt); static struct agentx_response *prepare_response(struct snmp_proto *p, struct snmp_pdu *c); static void response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_response_errs err, u16 ind); -static uint update_packet_size(struct snmp_proto *p, struct agentx_header *start, byte *end); +static uint update_packet_size(struct agentx_header *start, byte *end); static struct oid *search_mib(struct snmp_proto *p, const struct oid *o_start, const struct oid *o_end, struct oid *o_curr, struct snmp_pdu *c, enum snmp_search_res *result); u32 snmp_internet[] = { SNMP_ISO, SNMP_ORG, SNMP_DOD, SNMP_INTERNET }; @@ -80,20 +80,36 @@ snmp_is_active(struct snmp_proto *p) p->state == SNMP_CONN; } +/* + * snmp_header - store packet information into buffer + * @h: pointer to created packet header in TX-buffer + * @type: created PDU type + * @flags: set flags + * + * Payload length is set to zero legth. Padding is also zeroed. Real stored + * flags are dependent on compile-time message byte-order configuration. + */ static inline void snmp_header(struct agentx_header *h, enum agentx_pdu_types type, u8 flags) { STORE_U8(h->version, AGENTX_VERSION); - STORE_U8(h->type, (u8) type); + STORE_U8(h->type, type); STORE_U8(h->flags, flags | SNMP_ORDER); - STORE_U8(h->pad, 0); + STORE_U8(h->reserved, 0); STORE_U32(h->payload, 0); } +/* + * snmp_blank_header - create header with no flags except default + * @h: pointer to created header in TX-buffer + * @type: create PDU type + * + * Only flag possibly set may be packet byte order configuration. + */ static inline void snmp_blank_header(struct agentx_header *h, enum agentx_pdu_types type) { - snmp_header(h, type, 0); + snmp_header(h, type, (u8) 0); } /* @@ -109,7 +125,7 @@ snmp_blank_header(struct agentx_header *h, enum agentx_pdu_types type) static void snmp_register_ok(struct snmp_proto *p, struct agentx_response *res, struct oid *oid, u8 UNUSED class) { - // TODO switch based on oid type + // todo switch based on oid type snmp_bgp_reg_ok(p, res, oid); } @@ -120,21 +136,21 @@ snmp_register_ok(struct snmp_proto *p, struct agentx_response *res, struct oid * * @oid: OID whose registration failed * @class: MIB subtree of @oid * - * Send a notification to MIB (selected by @class) about @oid registraion + * Send a notification to MIB (selected by @class) about @oid registration * failure. */ static void snmp_register_failed(struct snmp_proto *p, struct agentx_response *res, struct oid *oid, u8 UNUSED class) { - // TODO switch based on oid type + // todo switch based on oid type snmp_bgp_reg_failed(p, res, oid); } /* - * snmp_register_ack - handle registration -- response to agentx-Register-PDU + * snmp_register_ack - handle registration response * @p: SNMP protocol instance * @res: header of agentx-Response-PDU - * @class: MIB subtree associated with agentx-Register-PDU + * @class: MIB subtree associated with agentx-Register-PDU */ void snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class) @@ -142,7 +158,7 @@ snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class) struct snmp_registration *reg; WALK_LIST(reg, p->registration_queue) { - // TODO add support for more mib trees (other than BGP) + // todo add support for more mib trees (other than BGP4-MIB) if (snmp_registration_match(reg, &res->h, class)) { struct snmp_registered_oid *ro = \ @@ -179,14 +195,15 @@ snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class) static inline void snmp_error(struct snmp_proto *p) { - snmp_set_state(p, SNMP_RESET); + snmp_reset(p); + //snmp_set_state(p, SNMP_RESET); } /* * snmp_simple_response - send an agentx-Response-PDU with no data payload * @p: SNMP protocol instance - * @error: PDU error fields value - * @index: PDU error index field value + * @error: response PDU error fields value + * @index: response PDU error index field value * * This function assumes that the buffer has enough space to fill in the AgentX * Response PDU. So it is the responsibility of the caller to provide that. @@ -196,7 +213,7 @@ snmp_simple_response(struct snmp_proto *p, enum agentx_response_errs error, u16 { sock *sk = p->sock; struct snmp_pdu c; - snmp_pdu_context(p, &c, sk); + snmp_pdu_context(&c, sk); ASSUME(c.size >= sizeof(struct agentx_response)); @@ -220,14 +237,16 @@ open_pdu(struct snmp_proto *p, struct oid *oid) sock *sk = p->sock; struct snmp_pdu c; - snmp_pdu_context(p, &c, sk); + snmp_pdu_context(&c, sk); -#define TIMEOUT_SIZE 4 /* 1B timeout, 3B zero padding */ +#define TIMEOUT_SIZE sizeof(u32) /* 1B timeout, 3B zero padding */ + + /* Make sure that we have enough space in TX-buffer */ if (c.size < AGENTX_HEADER_SIZE + TIMEOUT_SIZE + snmp_oid_size(oid) + + snmp_str_size(cf->description)) snmp_manage_tbuf(p, &c); - struct agentx_header *h = snmp_create_tx_header(p, c.buffer); + struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); snmp_blank_header(h, AGENTX_OPEN_PDU); @@ -250,7 +269,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid) c.buffer = snmp_put_oid(c.buffer, oid); c.buffer = snmp_put_str(c.buffer, cf->description); - uint s = update_packet_size(p, h, c.buffer); + uint s = update_packet_size(h, c.buffer); sk_send(sk, s); #undef TIMEOUT_SIZE } @@ -269,7 +288,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in sock *sk = p->sock; struct snmp_pdu c; - snmp_pdu_context(p, &c, sk); + snmp_pdu_context(&c, sk); #define UPTIME_SIZE \ (6 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[4] } ) */ @@ -282,14 +301,14 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in if (include_uptime) sz += UPTIME_SIZE; + /* Make sure that we have enough space in TX-buffer */ if (c.size < sz) snmp_manage_tbuf(p, &c); - struct agentx_header *h = snmp_create_tx_header(p, c.buffer); + struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); snmp_blank_header(h, AGENTX_NOTIFY_PDU); - p->packet_id++; - log(L_INFO "incrementing packet_id to %u (notify)", p->packet_id); + p->packet_id++; /* New packet id */ snmp_session(p, h); if (include_uptime) @@ -299,7 +318,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in .n_subid = 4, .prefix = SNMP_MGMT, .include = 0, - .pad = 0, + .reserved = 0, }; /* {mgmt}.mib-2.system.sysUpTime.sysUpTimeInstance (0) */ u32 uptime_ids[] = { 1, 1, 3, 0 }; @@ -308,7 +327,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in for (uint i = 0; i < uptime_oid.n_subid; i++) STORE_U32(vb->name.ids[i], uptime_ids[i]); - /* TODO: use time from last reconfiguration instead? [config->load_time] */ + /* TODO use time from last reconfiguration instead? [config->load_time] */ btime uptime = current_time() - boot_time; snmp_varbind_ticks(vb, c.size, (uptime TO_S) / 100); ASSUME(snmp_test_varbind(vb)); @@ -320,7 +339,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in .n_subid = 6, .prefix = 6, /* snmpV2 */ .include = 0, - .pad = 0, + .reserved = 0, }; /* {snmpV2}.snmpModules.snmpAlarmNextIndex.snmpMIBObjects.snmpTrap.snmpTrapIOD.0 */ u32 trap0_ids[] = { 3, 1, 1, 4, 1, 0 }; @@ -335,7 +354,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in memcpy(c.buffer, data, size); ADVANCE(c.buffer, c.size, size); - uint s = update_packet_size(p, h, c.buffer); + uint s = update_packet_size(h, c.buffer); sk_send(sk, s); #undef TRAP0_HEADER_SIZE @@ -365,27 +384,27 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in * see snmp_register() and snmp_unregister() functions. */ static void -un_register_pdu(struct snmp_proto *p, struct oid *oid, uint bound, uint index, enum agentx_pdu_types type, u8 is_instance, uint UNUSED contid) +un_register_pdu(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, enum agentx_pdu_types type, u8 is_instance, uint UNUSED contid) { /* used for agentx-Register-PDU and agentx-Unregister-PDU */ const struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf); sock *sk = p->sock; struct snmp_pdu c; - snmp_pdu_context(p, &c, sk); + snmp_pdu_context(&c, sk); +#define BOUND_SIZE sizeof(u32) /* conditional +4 for upper-bound (optinal field) */ - uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) + ((bound > 1) ? 4 : 0); + uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) + + ((bound > 1) ? BOUND_SIZE : 0); if (c.size < sz) snmp_manage_tbuf(p, &c); - struct agentx_header *h = snmp_create_tx_header(p, c.buffer); + struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); snmp_header(h, type, is_instance ? AGENTX_FLAG_INSTANCE_REGISTRATION : 0); p->packet_id++; - log(L_INFO "incementing the packet_id to %u (%s)", p->packet_id, type == - AGENTX_REGISTER_PDU ? "register" : "unregister"); snmp_session(p, h); struct agentx_un_register_hdr *ur = (struct agentx_un_register_hdr *) c.buffer; @@ -395,7 +414,7 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint bound, uint index, e /* use selected priority */ STORE_U8(ur->priority, cf->priority); STORE_U8(ur->range_subid, (bound > 1) ? index : 0); - STORE_U8(ur->pad, 0); + STORE_U8(ur->reserved, 0); ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_hdr)); snmp_put_oid(c.buffer, oid); @@ -405,12 +424,13 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint bound, uint index, e if (bound > 1) { STORE_PTR(c.buffer, bound); - ADVANCE(c.buffer, c.size, 4); + ADVANCE(c.buffer, c.size, BOUND_SIZE); } - uint s = update_packet_size(p, h, c.buffer); + uint s = update_packet_size(h, c.buffer); sk_send(sk, s); +#undef BOUND_SIZE } /* @@ -425,9 +445,8 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint bound, uint index, e * For more detailed description see un_register_pdu() function. */ void -snmp_register(struct snmp_proto *p, struct oid *oid, uint bound, uint index, u8 is_instance, uint contid) +snmp_register(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, u8 is_instance, uint contid) { - log(L_INFO "performing a registration"); un_register_pdu(p, oid, bound, index, AGENTX_REGISTER_PDU, is_instance, contid); } @@ -442,9 +461,9 @@ snmp_register(struct snmp_proto *p, struct oid *oid, uint bound, uint index, u8 * For more detailed description see un_register_pdu() function. */ void UNUSED -snmp_unregister(struct snmp_proto *p, struct oid *oid, uint len, uint index, uint contid) +snmp_unregister(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, uint contid) { - un_register_pdu(p, oid, len, index, AGENTX_UNREGISTER_PDU, 0, contid); + un_register_pdu(p, oid, bound, index, AGENTX_UNREGISTER_PDU, 0, contid); } /* @@ -452,28 +471,27 @@ snmp_unregister(struct snmp_proto *p, struct oid *oid, uint len, uint index, uin * @p: SNMP protocol instance * @reason: reason for closure */ -static void +static void UNUSED close_pdu(struct snmp_proto *p, enum agentx_close_reasons reason) { sock *sk = p->sock; struct snmp_pdu c; - snmp_pdu_context(p, &c, sk); + snmp_pdu_context(&c, sk); -#define REASON_SIZE 4 +#define REASON_SIZE sizeof(u32) if (c.size < AGENTX_HEADER_SIZE + REASON_SIZE) snmp_manage_tbuf(p, &c); - struct agentx_header *h = snmp_create_tx_header(p, c.buffer); + struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); snmp_blank_header(h, AGENTX_CLOSE_PDU); p->packet_id++; - log(L_INFO "incrementing packet_id %u (close)", p->packet_id); snmp_session(p, h); snmp_put_fbyte(c.buffer, (u8) reason); ADVANCE(c.buffer, c.size, 4); - uint s = update_packet_size(p, h, c.buffer); + uint s = update_packet_size(h, c.buffer); sk_send(sk, s); #undef REASON_SIZE } @@ -482,40 +500,40 @@ close_pdu(struct snmp_proto *p, enum agentx_close_reasons reason) * parse_close_pdu - parse an agentx-Close-PDU * @p: SNMP protocol instance * @pkt_start: pointer to first byte of PDU - * @size: number of bytes received from a socket * * Return number of bytes parsed from RX-buffer. */ static uint -parse_close_pdu(struct snmp_proto *p, byte * const pkt_start, uint size) +parse_close_pdu(struct snmp_proto *p, byte * const pkt_start) { TRACE(D_PACKETS, "SNMP received agentx-Close-PDU"); byte *pkt = pkt_start; - if (size < sizeof(struct agentx_close_pdu)) + struct agentx_close_pdu *pdu = (void *) pkt; + pkt += sizeof(struct agentx_close_pdu); + uint pkt_size = pdu->h.payload; + + if (pkt_size != sizeof(struct agentx_close_pdu)) { TRACE(D_PACKETS, "SNMP malformed agentx-Close-PDU, closing anyway"); snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0); snmp_set_state(p, SNMP_RESET); - return size; + return MIN(pkt_size + AGENTX_HEADER_SIZE, sizeof(struct agentx_close_pdu)); } - struct agentx_close_pdu *pdu = (void *) pkt; - ADVANCE(pkt, size, sizeof(struct agentx_close_pdu)); - if (!snmp_test_close_reason(pdu->reason)) { - TRACE(D_PACKETS, "SNMP invalid close reason"); + TRACE(D_PACKETS, "SNMP invalid close reason %u", pdu->reason); snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0); snmp_set_state(p, SNMP_RESET); - return sizeof(struct agentx_close_pdu); + return pkt_size + AGENTX_HEADER_SIZE; } enum agentx_close_reasons reason = (enum agentx_close_reasons) pdu->reason; TRACE(D_PACKETS, "SNMP close reason %u", reason); snmp_simple_response(p, AGENTX_RES_NO_ERROR, 0); snmp_set_state(p, SNMP_RESET); - return sizeof(struct agentx_close_pdu); + return pkt_size + AGENTX_HEADER_SIZE; } @@ -540,7 +558,8 @@ snmp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, struct oid * { /* Hard-coded no support for writing */ (void)p;(void)vb;(void)oid;(void)pkt_size; - return 0; + snmp_simple_response(p, AGENTX_RES_NOT_WRITABLE, 1); + return pkt_size + AGENTX_HEADER_SIZE; #if 0 if (!oid) return 0; @@ -565,7 +584,6 @@ refresh_ids(struct snmp_proto *p, struct agentx_header *h) { p->transaction_id = LOAD_U32(h->transaction_id); p->packet_id = LOAD_U32(h->packet_id); - //log(L_INFO "loading packet_id %u from header %p", p->packet_id, h); } /* @@ -576,8 +594,8 @@ refresh_ids(struct snmp_proto *p, struct agentx_header *h) * * Return number of bytes parsed from RX-buffer. */ -static uint -parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size) +static inline uint +parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start) { TRACE(D_PACKETS, "SNMP received agentx-TestSet-PDU"); byte *pkt = pkt_start; /* pointer to agentx-TestSet-PDU in RX-buffer */ @@ -585,15 +603,12 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size) struct agentx_response *res; /* pointer to reponse in TX-buffer */ struct agentx_header *h = (void *) pkt; - ADVANCE(pkt, size, AGENTX_HEADER_SIZE); - uint pkt_size = LOAD_U32(h->payload); - - if (pkt_size < size) - return 0; + pkt += AGENTX_HEADER_SIZE; + //uint pkt_size = LOAD_U32(h->payload); sock *sk = p->sock; struct snmp_pdu c; - snmp_pdu_context(p, &c, sk); + snmp_pdu_context(&c, sk); if (c.size < AGENTX_HEADER_SIZE) snmp_manage_tbuf(p, &c); @@ -618,10 +633,6 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size) vb = (void *) pkt; sz = snmp_varbind_size(vb, size); - if (sz > size) - /* wait for more data to arive */ - return 0; - if (sz > pkt_size) { c.error = AGENTX_RES_PARSE_ERROR; @@ -646,7 +657,7 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size) } mb_free(tr); #endif - s = update_packet_size(p, h, c.buffer); + s = update_packet_size(h, c.buffer); if (c.error != AGENTX_RES_NO_ERROR) { @@ -673,46 +684,38 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size) * parse_sets_pdu - common functionality for commit set and undo set PDUs * @p: SNMP protocol instance * @pkt_start: pointer to first byte of on of set related PDU - * @size: number of bytes received from a socket * @error: error status to use * * Return number of bytes parsed from RX-buffer. */ static uint -parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, enum agentx_response_errs err) +parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, enum agentx_response_errs err) { byte *pkt = pkt_start; struct agentx_header *h = (void *) pkt; - ADVANCE(pkt, size, AGENTX_HEADER_SIZE); + pkt += AGENTX_HEADER_SIZE; uint pkt_size = LOAD_U32(h->payload); if (pkt_size != 0) { TRACE(D_PACKETS, "SNMP received malformed set PDU (size)"); snmp_simple_response(p, AGENTX_RES_PARSE_ERROR, 0); - // TODO: best solution for possibly malicious pkt_size - return MIN(size, pkt_size + AGENTX_HEADER_SIZE); + // TODO best solution for possibly malicious pkt_size + return AGENTX_HEADER_SIZE; // use varbind_list_size()?? } struct snmp_pdu c; - snmp_pdu_context(p, &c, p->sock); + snmp_pdu_context(&c, p->sock); if (c.size < sizeof(struct agentx_response)) snmp_manage_tbuf(p, &c); struct agentx_response *r = prepare_response(p, &c); - if (size < pkt_size) - { - c.error = AGENTX_RES_PARSE_ERROR; - } - else - { - // TODO: free resource allocated by parse_test_set_pdu() - // TODO: do something meaningful - //mb_free(tr); - c.error = err; - } + // TODO free resource allocated by parse_test_set_pdu() + // TODO do something meaningful + //mb_free(tr); + c.error = err; TRACE(D_PACKETS, "SNMP received set PDU with error %u", c.error); response_err_ind(p, r, c.error, 0); @@ -729,51 +732,47 @@ parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, enum age * parse_commit_set_pdu - parse an agentx-CommitSet-PDU * @p: SNMP protocol instance * @pkt: pointer to first byte of PDU inside RX-buffer - * @size: number of bytes received from a socket * * Return number of bytes parsed from RX-buffer. */ -static uint -parse_commit_set_pdu(struct snmp_proto *p, byte *pkt, uint size) +static inline uint +parse_commit_set_pdu(struct snmp_proto *p, byte *pkt) { // don't forget to free resoures allocated by parse_test_set_pdu() //mb_free(tr); TRACE(D_PACKETS, "SNMP received agentx-CommitSet-PDU"); - return parse_sets_pdu(p, pkt, size, AGENTX_RES_COMMIT_FAILED); + return parse_sets_pdu(p, pkt, AGENTX_RES_COMMIT_FAILED); } /* * parse_undo_set_pdu - parse an agentx-UndoSet-PDU * @p: SNMP protocol instance * @pkt: pointer to first byte of PDU inside RX-buffer - * @size: number of bytes received from a socket * * Return number of bytes parsed from buffer. */ -static uint -parse_undo_set_pdu(struct snmp_proto *p, byte *pkt, uint size) +static inline uint +parse_undo_set_pdu(struct snmp_proto *p, byte *pkt) { // don't forget to free resources allocated by parse_test_set_pdu() //mb_free(tr); TRACE(D_PACKETS, "SNMP received agentx-UndoSet-PDU"); - return parse_sets_pdu(p, pkt, size, AGENTX_RES_UNDO_FAILED); + return parse_sets_pdu(p, pkt, AGENTX_RES_UNDO_FAILED); } /* * parse_cleanup_set_pdu - parse an agentx-CleanupSet-PDU * @p: SNMP protocol instance * @pkt_start: pointer to first byte of PDU inside RX-buffer - * @size: number of bytes received from a socket * * Return number of bytes parsed from RX-buffer. */ static uint -parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size) +parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start) { TRACE(D_PACKETS, "SNMP received agentx-CleanupSet-PDU"); (void)p; - //TODO: - // don't forget to free resources allocated by parse_test_set_pdu() + // TODO don't forget to free resources allocated by parse_test_set_pdu() //mb_free(p->tr); byte *pkt = pkt_start; @@ -784,7 +783,7 @@ parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size) if (pkt_size != 0) { // TODO should we free even for malformed packets ?? - return MIN(size, pkt_size + AGENTX_HEADER_SIZE); + return AGENTX_HEADER_SIZE; } /* No agentx-Response-PDU is sent in response to agentx-CleanupSet-PDU */ @@ -812,12 +811,11 @@ space_for_response(const sock *sk) * @p: SNMP protocol instance * @pkt: first byte of PDU inside RX-buffer * @size: number of bytes received from a socket - * @skip: length of header that stays still in partial processing * * Return number of bytes parsed from RX-buffer. */ static uint -parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip) +parse_pkt(struct snmp_proto *p, byte *pkt, uint size) { /* TX-buffer free space */ ASSERT(snmp_is_active(p)); @@ -831,21 +829,29 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip) struct agentx_header *h = (void *) pkt; uint pkt_size = LOAD_U32(h->payload); + /* RX side checks - too big packet */ if (pkt_size > SNMP_PKT_SIZE_MAX) - return simple_response(p, AGENTX_RES_GEN_ERR, 0); + { + snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0); + snmp_reset(p); + return 0; // TODO return size?? + } + + /* This guarantees that we have the full packet already received */ + if (size < pkt_size + AGENTX_HEADER_SIZE) + return 0; /* no bytes parsed */ /* We need to see the responses for PDU such as * agentx-Open-PDU, agentx-Register-PDU, ... * even when we are outside the SNMP_CONNECTED state */ if (h->type == AGENTX_RESPONSE_PDU) - return parse_response(p, pkt, size); + return parse_response(p, pkt); ASSERT(snmp_is_active(p)); if (p->state != SNMP_CONN || p->session_id != LOAD_U32(h->session_id)) { - // TODO: resolve issues connected to partial processed packets struct agentx_header copy = { .session_id = p->session_id, .transaction_id = p->transaction_id, @@ -864,14 +870,14 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip) * After unexpected state, we simply reset the session * only sending the agentx-Response-PDU. */ - snmp_set_state(p, SNMP_RESET); - return 0; + snmp_reset(p); + return 0; // return size?? } ASSERT(snmp_is_active(p)); if (h->flags & AGENTX_NON_DEFAULT_CONTEXT) { - // TODO: add non-default context support + // TODO add non-default context support TRACE(D_PACKETS, "SNMP received PDU with unexpected byte order"); snmp_simple_response(p, AGENTX_RES_UNSUPPORTED_CONTEXT, 0); /* We always accept the packet length as correct, up to set limit */ @@ -885,22 +891,22 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip) case AGENTX_GET_PDU: case AGENTX_GET_NEXT_PDU: case AGENTX_GET_BULK_PDU: - return parse_gets2_pdu(p, pkt, size, skip); + return parse_gets_pdu(p, pkt); case AGENTX_CLOSE_PDU: - return parse_close_pdu(p, pkt, size); + return parse_close_pdu(p, pkt); case AGENTX_TEST_SET_PDU: - return parse_test_set_pdu(p, pkt, size); + return parse_test_set_pdu(p, pkt); case AGENTX_COMMIT_SET_PDU: - return parse_commit_set_pdu(p, pkt, size); + return parse_commit_set_pdu(p, pkt); case AGENTX_UNDO_SET_PDU: - return parse_undo_set_pdu(p, pkt, size); + return parse_undo_set_pdu(p, pkt); case AGENTX_CLEANUP_SET_PDU: - return parse_cleanup_set_pdu(p, pkt, size); + return parse_cleanup_set_pdu(p, pkt); default: /* We reset the connection for malformed packet (Unknown packet type) */ @@ -915,39 +921,34 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip) * parse_response - parse an agentx-Response-PDU * @p: SNMP protocol instance * @res: pointer of agentx-Response-PDU header in RX-buffer - * @size: number of bytes received from a socket * * Return number of bytes parsed from RX-buffer. */ static uint -parse_response(struct snmp_proto *p, byte *res, uint size) +parse_response(struct snmp_proto *p, byte *res) { - log(L_WARN "parse response"); - if (size < sizeof(struct agentx_response)) - return 0; - struct agentx_response *r = (void *) res; struct agentx_header *h = (void *) r; // todo reject not compiled byte order uint pkt_size = LOAD_U32(h->payload); - if (size < pkt_size + AGENTX_HEADER_SIZE) - return 0; switch (r->error) { case AGENTX_RES_NO_ERROR: TRACE(D_PACKETS, "SNMP received agetnx-Response-PDU"); - do_response(p, res, size); + do_response(p, res); break; /* Registration errors */ case AGENTX_RES_DUPLICATE_REGISTER: case AGENTX_RES_REQUEST_DENIED: case AGENTX_RES_UNKNOWN_REGISTER: - // TODO: more direct path to mib-specifiec code + // TODO more direct path to mib-specific code TRACE(D_PACKETS, "SNMP received agentx-Response-PDU with error %u", r->error); - snmp_register_ack(p, r, size); + byte *pkt = res + sizeof(struct agentx_response); + struct oid *failed = (void *) pkt; + snmp_register_ack(p, r, snmp_get_mib_class(failed)); break; /* @@ -984,15 +985,14 @@ snmp_register_mibs(struct snmp_proto *p) /* * do_response - act on agentx-Response-PDU and protocol state * @p: SNMP protocol instance - * @buf: RX-buffer with PDU bytes - * @size: number of bytes received from a socket + * @pkt: RX-buffer with PDU bytes * * Return number of bytes parsed from RX-buffer. */ static void -do_response(struct snmp_proto *p, byte *buf, uint size) +do_response(struct snmp_proto *p, byte *pkt) { - struct agentx_response *r = (void *) buf; + struct agentx_response *r = (void *) pkt; struct agentx_header *h = (void *) r; /* TODO make it asynchronous for better speed */ @@ -1017,8 +1017,7 @@ do_response(struct snmp_proto *p, byte *buf, uint size) break; case SNMP_REGISTER:; - byte *pkt = buf; - ADVANCE(pkt, size, AGENTX_HEADER_SIZE); + pkt += AGENTX_HEADER_SIZE; const struct oid *oid = (void *) pkt; @@ -1205,14 +1204,13 @@ snmp_get_bulk2(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, /* * update_packet_size - set PDU size - * @p - SNMP protocol instance * @start - pointer to PDU data start (excluding header size) * @end - pointer after the last PDU byte * * Return number of bytes in TX-buffer (including header size). */ static inline uint -update_packet_size(struct snmp_proto *p, struct agentx_header *start, byte *end) +update_packet_size(struct agentx_header *start, byte *end) { uint s = snmp_pkt_len((byte *) start, end); STORE_U32(start->payload, s); @@ -1254,32 +1252,40 @@ response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_ STORE_U32(res->index, 0); } +static uint +parse_gets_error(struct snmp_proto *p, struct snmp_pdu *c, uint len) +{ + TRACE(D_PACKETS, "SNMP error %u while parsing gets PDU", c->error); + if (c->index > UINT16_MAX) + snmp_simple_response(p, AGENTX_RES_GEN_ERROR, UINT16_MAX); + else + snmp_simple_response(p, AGENTX_RES_GEN_ERROR, c->index); + + return len + AGENTX_HEADER_SIZE; +} /* * parse_gets_pdu - parse received gets PDUs * @p: SNMP protocol instance * @pkt_start: pointer to first byte of received PDU - * @size: number of bytes received from a socket - * @skip: length of header that stays still in partial processing * * Gets PDUs are agentx-Get-PDU, agentx-GetNext-PDU, agentx-GetBulk-PDU. * * Return number of bytes parsed from RX-buffer */ static uint -parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *skip) +parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start) { // TODO checks for c.size underflow - uint ret = 0; struct oid *o_start = NULL, *o_end = NULL; byte *pkt = pkt_start; struct agentx_header *h = (void *) pkt; - ADVANCE(pkt, size, AGENTX_HEADER_SIZE); + pkt += AGENTX_HEADER_SIZE; uint pkt_size = LOAD_U32(h->payload); sock *sk = p->sock; struct snmp_pdu c; - snmp_pdu_context(p, &c, sk); + snmp_pdu_context(&c, sk); /* * Get-Bulk processing stops if all the varbind have type END_OF_MIB_VIEW @@ -1289,15 +1295,11 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s struct agentx_bulk_state bulk_state = { }; if (h->type == AGENTX_GET_BULK_PDU) { - if (size < sizeof(struct agentx_getbulk)) - goto wait; - if (pkt_size < sizeof(struct agentx_getbulk)) { c.error = AGENTX_RES_PARSE_ERROR; c.index = 0; - ret = pkt_size + AGENTX_HEADER_SIZE; - goto error; + return parse_gets_error(p, &c, pkt_size); } struct agentx_getbulk *bulk_info = (void *) pkt; @@ -1316,38 +1318,19 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s struct agentx_response *response_header = prepare_response(p, &c); - while (c.error == AGENTX_RES_NO_ERROR && size > 0 && pkt_size > 0) + while (c.error == AGENTX_RES_NO_ERROR && pkt_size > 0) { - if (size < snmp_oid_sizeof(0)) - goto partial; - /* We load search range start OID */ const struct oid *o_start_b = (void *) pkt; uint sz; if ((sz = snmp_oid_size(o_start_b)) > pkt_size) { c.error = AGENTX_RES_PARSE_ERROR; - ret = MIN(size, pkt_size + AGENTX_HEADER_SIZE); - goto error; - } - - /* - * If we already have written same relevant data to the TX buffer, then - * we send processed part, otherwise we don't have anything to send and - * need to wait for more data to be received. - */ - if (sz > size && c.index > 0) - { - goto partial; - } - else if (sz > size) - { - goto wait; + return parse_gets_error(p, &c, pkt_size); } /* Update buffer pointer and remaining size counters. */ ADVANCE(pkt, pkt_size, sz); - size -= sz; /* * We load search range end OID @@ -1358,24 +1341,12 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s if ((sz = snmp_oid_size(o_end_b)) > pkt_size) { c.error = AGENTX_RES_PARSE_ERROR; - ret = MIN(size, pkt_size + AGENTX_HEADER_SIZE); - goto error; - } - - if (sz > size && c.index > 0) - { - size += snmp_oid_size(o_start_b); - goto partial; - } - else if (sz > size) - { - goto wait; + return parse_gets_error(p, &c, pkt_size); } ADVANCE(pkt, pkt_size, sz); - size -= sz; - // TODO check for oversized OIDs before any allocation (in prefixize()) + /* We don't too to check for oversided OID because the PDU has 8k size limit */ /* We create copy of OIDs outside of rx-buffer and also prefixize them */ o_start = snmp_prefixize(p, o_start_b); @@ -1387,11 +1358,12 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s if (!snmp_is_oid_empty(o_end) && snmp_oid_compare(o_start, o_end) > 0) { c.error = AGENTX_RES_GEN_ERROR; - ret = MIN(size, pkt_size + AGENTX_HEADER_SIZE); - goto error; + mb_free(o_start); + mb_free(o_end); + return parse_gets_error(p, &c, pkt_size); } - /* TODO find mib_class, check if type is GET of GET_NEXT, act acordingly */ + /* TODO find mib_class, check if type is GET of GET_NEXT, act accordingly */ switch (h->type) { case AGENTX_GET_PDU: @@ -1441,61 +1413,18 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s } } - /* send the constructed packet */ - struct agentx_response *res; - if (snmp_is_partial(p)) - { - snmp_log("snmp_is_partial() packet_id %u last_pkt_id %u [proto packet_id] %u", LOAD_U32(res->h.packet_id), p->last_pkt_id, p->packet_id); - res = SKIP_BACK(struct agentx_response, h, snmp_get_header(p)); - ASSERT(LOAD_U32(res->h.packet_id) == p->last_pkt_id); - STORE_U32(res->h.packet_id, p->last_pkt_id); - snmp_unset_header(p); - } - else - res = response_header; - /* We update the error, index pair on the beginning of the packet. */ - response_err_ind(p, res, c.error, c.index + 1); - uint s = update_packet_size(p, &res->h, c.buffer); + response_err_ind(p, response_header, c.error, c.index + 1); + uint s = update_packet_size(&response_header->h, c.buffer); /* We send the message in TX-buffer. */ - snmp_unset_header(p); sk_send(sk, s); // TODO think through the error state /* number of bytes parsed from RX-buffer */ - ret = pkt - pkt_start; - goto free; - -partial: - /* need to tweak RX buffer packet size */ - //STORE_U32(h->payload, pkt_size); - *skip = AGENTX_HEADER_SIZE; - snmp_set_header(p, &response_header->h, &c); - - /* number of bytes parsed from RX-buffer */ - ret = pkt - pkt_start; - /* update the packet length such that the used bytes are not included */ - STORE_U32(h->payload, LOAD_U32(h->payload) - ret + AGENTX_HEADER_SIZE); - goto free; - -wait: - p->packet_id--; /* we did not use the packetID */ - log(L_INFO "decrementing back the packet_id to %u", p->packet_id); - ret = 0; - goto free; - -error: - TRACE(D_PACKETS, "SNMP error %u while parsing gets PDU", c.error); - if (c.index > UINT16_MAX) - snmp_simple_response(p, AGENTX_RES_GEN_ERROR, UINT16_MAX); - else - snmp_simple_response(p, c.error, c.index); - -free: mb_free(o_start); mb_free(o_end); - return ret; + return pkt - pkt_start; } /* @@ -1526,7 +1455,8 @@ void snmp_stop_subagent(struct snmp_proto *p) { tm_stop(p->ping_timer); - close_pdu(p, AGENTX_CLOSE_SHUTDOWN); + /* This cause problems with net-snmp daemon witch halts afterwards */ + //close_pdu(p, AGENTX_CLOSE_SHUTDOWN); } /* @@ -1542,38 +1472,25 @@ snmp_rx(sock *sk, uint size) byte *pkt_start = sk->rbuf; byte *end = pkt_start + size; - byte *last_pkt = pkt_start; - - /* - * In some cases we want to save the header for future parsing, skip is number - * of bytes that should not be overriden by memmove() - */ - uint skip = 0; - - while (snmp_is_active(p) && end >= pkt_start + AGENTX_HEADER_SIZE && skip == 0) + while (snmp_is_active(p) && end >= pkt_start + AGENTX_HEADER_SIZE) { - uint parsed_len = parse_pkt(p, pkt_start, size, &skip); + uint parsed_len = parse_pkt(p, pkt_start, size); if (parsed_len == 0) break; - last_pkt = pkt_start; pkt_start += parsed_len; size -= parsed_len; } - if (!snmp_is_active(p)) - return 1; + /* We flush the RX-buffer on errors */ + if (!snmp_is_active(p) || pkt_start == end) + return 1; /* The whole RX-buffer was consumed */ - if (skip != 0 || pkt_start != end) - { - memmove(sk->rbuf, last_pkt, skip); /* maybe no op */ - memmove(sk->rbuf + skip, pkt_start, size); - sk->rpos = sk->rbuf + size + skip; - return 0; - } - - return 1; + /* Incomplete packet parsing */ + memmove(sk->rbuf, pkt_start, size); + sk->rpos = sk->rbuf + size; + return 0; } /* @@ -1611,35 +1528,25 @@ snmp_ping(struct snmp_proto *p) sock *sk = p->sock; struct snmp_pdu c; - snmp_pdu_context(p, &c, sk); + snmp_pdu_context(&c, sk); if (c.size < AGENTX_HEADER_SIZE) return; int unused = sk->tbuf + sk->tbsize - c.buffer; - if (snmp_is_partial(p) && unused >= AGENTX_HEADER_SIZE) - { - /* We use the start of unsent TX-buffer to fit in the agentx-Ping-PDU */ - memmove(sk->tpos + AGENTX_HEADER_SIZE, sk->tpos, p->last_size); - p->header_offset += AGENTX_HEADER_SIZE; - } - else if (snmp_is_partial(p)) - /* Not enough space inside the buffer */ + if (unused < AGENTX_HEADER_SIZE) return; - /* we do not use the snmp_create_tx_header() because of side effects */ - struct agentx_header *h = (void *) sk->tpos; + //struct agentx_header *h = (void *) sk->tpos; + struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); snmp_blank_header(h, AGENTX_PING_PDU); p->packet_id++; log(L_INFO "incrementing packet_id to %u (ping)", p->packet_id); snmp_session(p, h); - - if (snmp_is_partial(p)) // TODO remove me - snmp_log("snmp_ping() packet_id %u last_pkt_id %u [proto packet_id] ))%u", LOAD_U32(h->packet), p->last_pkt_id, p->packet_id); /* sending only header */ - uint s = update_packet_size(p, h, (byte *) h + AGENTX_HEADER_SIZE); + uint s = update_packet_size(h, (byte *) h + AGENTX_HEADER_SIZE); sk_send(sk, s); } @@ -1714,7 +1621,7 @@ search_mib(struct snmp_proto *p, const struct oid *o_start, const struct oid *o_ switch (o_curr->ids[1]) { case SNMP_BGP4_MIB: - r = snmp_bgp_search2(p, &o_curr, o_end, 0); + r = snmp_bgp_search(p, &o_curr, o_end, 0); if (r == SNMP_SEARCH_OK) { @@ -1863,11 +1770,8 @@ snmp_manage_tbuf(struct snmp_proto UNUSED *p, struct snmp_pdu *c) static struct agentx_response * prepare_response(struct snmp_proto *p, struct snmp_pdu *c) { - if (snmp_is_partial(p)) - return (struct agentx_response *) snmp_get_header(p); - struct agentx_response *r = (void *) c->buffer; - struct agentx_header *h = snmp_create_tx_header(p, (byte *) r); + struct agentx_header *h = &r->h; snmp_blank_header(h, AGENTX_RESPONSE_PDU); snmp_session(p, h); diff --git a/proto/snmp/subagent.h b/proto/snmp/subagent.h index c91206ea..b08519ff 100644 --- a/proto/snmp/subagent.h +++ b/proto/snmp/subagent.h @@ -151,7 +151,7 @@ struct agentx_header { u8 version; u8 type; u8 flags; - u8 pad; + u8 reserved; /* always zero filled */ u32 session_id; /* AgentX sessionID established by Open-PDU */ u32 transaction_id; /* last transactionID seen/used */ u32 packet_id; /* last packetID seen/used */ @@ -165,13 +165,13 @@ struct oid { u8 n_subid; u8 prefix; u8 include; - u8 pad; + u8 reserved; /* always zero filled */ u32 ids[]; }; struct agentx_varbind { u16 type; - u16 pad; + u16 reserved; /* always zero filled */ /* oid part */ struct oid name; /* AgentX variable binding data optionaly here */ @@ -205,15 +205,15 @@ STATIC_ASSERT(4 + 2 + 2 + AGENTX_HEADER_SIZE == sizeof(struct agentx_response)); struct agentx_close_pdu { struct agentx_header h; u8 reason; - u8 pad1; - u16 pad2; + u8 reserved1; /* reserved u24 */ + u16 reserved2; /* whole u24 is always zero filled */ }; struct agentx_un_register_hdr { u8 timeout; u8 priority; u8 range_subid; - u8 pad; + u8 reserved; /* always zero filled */ }; struct agentx_bulk_state {