]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
SNMP: Fix state machine transitions
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 13 Aug 2024 15:50:09 +0000 (17:50 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 13 Aug 2024 15:51:53 +0000 (17:51 +0200)
proto/snmp/snmp.c
proto/snmp/snmp.h
proto/snmp/subagent.c

index 72040aaa0a68c4030ac685fc62d66a3051b5f4fb..0aa17dd337c73f1d8d6adce10d7edb7c000489d6 100644 (file)
@@ -194,7 +194,7 @@ static void
 snmp_tx_skip(sock *sk)
 {
   struct snmp_proto *p = sk->data;
-  proto_notify_state(&p->p, snmp_set_state(p, SNMP_STOP));
+  snmp_set_state(p, SNMP_STOP);
 }
 
 /*
@@ -219,6 +219,7 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
     TRACE(D_EVENTS, "TODO");
     ASSERT(last == SNMP_DOWN);
 
+    proto_notify_state(&p->p, PS_START);
     if (cf->trans_type == SNMP_TRANS_TCP)
     {
       /* We need to lock the IP address */
@@ -288,7 +289,6 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
 
     p->startup_timer->hook = snmp_stop_timeout;
     tm_start(p->startup_timer, 1 S);
-
     return PS_START;
 
   case SNMP_REGISTER:
@@ -306,10 +306,11 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
   case SNMP_CONN:
     TRACE(D_EVENTS, "MIBs registered");
     ASSERT(last == SNMP_REGISTER);
+    proto_notify_state(&p->p, PS_UP);
     return PS_UP;
 
   case SNMP_STOP:
-    if (p->sock && p->state != SNMP_OPEN)
+    if (p->sock && p->state != SNMP_OPEN && !sk_tx_buffer_empty(p->sock))
     {
       TRACE(D_EVENTS, "closing AgentX session");
       if (p->state == SNMP_OPEN || p->state == SNMP_REGISTER ||
@@ -321,6 +322,7 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
 
       p->startup_timer->hook = snmp_stop_timeout;
       tm_start(p->startup_timer, 150 MS);
+      proto_notify_state(&p->p, PS_STOP);
       return PS_STOP;
     }
 
@@ -330,6 +332,7 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
   case SNMP_DOWN:
     TRACE(D_EVENTS, "AgentX session closed");
     snmp_cleanup(p);
+    proto_notify_state(&p->p, PS_DOWN);
     return PS_DOWN;
 
   default:
@@ -426,11 +429,19 @@ snmp_connected(sock *sk)
 int
 snmp_reset(struct snmp_proto *p)
 {
-  int proto_state = snmp_set_state(p, SNMP_STOP);
-  proto_notify_state(&p->p, proto_state);
-  return proto_state;
+  return snmp_set_state(p, SNMP_STOP);
 }
 
+/*
+ * snmp_up - AgentX session has registered all MIBs, protocols is up
+ * @p: SNMP protocol instance
+ */
+void
+snmp_up(struct snmp_proto *p)
+{
+  if (p->state == SNMP_REGISTER)
+    snmp_set_state(p, SNMP_CONN);
+}
 
 /*
  * snmp_sock_err - handle errors on socket by reopenning the socket
@@ -498,7 +509,7 @@ static void
 snmp_stop_timeout(timer *tm)
 {
   struct snmp_proto *p = tm->data;
-  proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
+  snmp_set_state(p, SNMP_DOWN);
 }
 
 /*
index 7e7968416f977932e81c7ac4ee9c30836d3752ce..26dcf2a5185f28453ae1b170cbeee8b7492d0e89 100644 (file)
@@ -170,6 +170,7 @@ void snmp_reconnect(timer *tm);
 int snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state);
 
 int snmp_reset(struct snmp_proto *p);
+void snmp_up(struct snmp_proto *p);
 
 extern const char agentx_master_addr[sizeof(AGENTX_MASTER_ADDR)];
 
index f1a54a7b52f10439dc52697b2134756bd78f5e6c..7e5ebcf098da328294e7b2382f38c42f504a0956 100644 (file)
@@ -872,6 +872,7 @@ do_response(struct snmp_proto *p, byte *pkt)
       break;
 
     case SNMP_STOP:
+    case SNMP_DOWN:
       break;
 
     default:
@@ -1014,7 +1015,7 @@ response_err_ind(struct agentx_response *res, enum agentx_response_errs err, u16
 
 /* agentx-Get-PDU */
 void
-snmp_get_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk)
+snmp_get_pdu(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *walk)
 {
   struct mib_leaf *leaf;
   leaf = snmp_walk_init(p->mib_tree, walk, &c->sr_vb_start->name, c);
@@ -1022,13 +1023,14 @@ snmp_get_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start
   enum snmp_search_res res;
   res = snmp_walk_fill(leaf, walk, c);
 
+  // TODO is this really necessary?
   if (res != SNMP_SEARCH_OK)
     c->sr_vb_start->type = snmp_search_res_to_type(res);
 }
 
 /* agentx-GetNext-PDU */
 int
-snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk)
+snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *walk)
 {
   (void) snmp_walk_init(p->mib_tree, walk, &c->sr_vb_start->name, c);
   struct mib_leaf *leaf = snmp_walk_next(p->mib_tree, walk, c);
@@ -1044,14 +1046,14 @@ snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_
 
 /* agentx-GetBulk-PDU */
 void
-snmp_get_bulk_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk, struct agentx_bulk_state *bulk)
+snmp_get_bulk_pdu(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *walk)
 {
   if (c->index >= bulk->getbulk.non_repeaters)
     bulk->repeaters++;
 
   // store the o_start and o_end
 
-  bulk->has_any |= snmp_get_next_pdu(p, c, o_start, walk);
+  bulk->has_any |= snmp_get_next_pdu(p, c, walk);
 }
 
 int
@@ -1188,15 +1190,15 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
     switch (h->type)
     {
       case AGENTX_GET_PDU:
-       snmp_get_pdu(p, &c, start_rx, &walk);
+       snmp_get_pdu(p, &c, &walk);
        break;
 
       case AGENTX_GET_NEXT_PDU:
-       snmp_get_next_pdu(p, &c, start_rx, &walk);
+       snmp_get_next_pdu(p, &c, &walk);
        break;
 
       case AGENTX_GET_BULK_PDU:
-       snmp_get_bulk_pdu(p, &c, start_rx, &walk, &bulk_state);
+       snmp_get_bulk_pdu(p, &c, &walk);
        break;
 
       default: