*/
/**
- * Simple Network Management Protocol State Machine
+ * DOC: Simple Network Management Protocol
+ *
+ * The SNMP protocol is divided into several parts: |snmp.c| which implements
+ * the BIRD intergration, |subagent.c| contains functions for creating and
+ * parsing packets, |bgp_mib.c| takes care of the bgp MIB subtree of standard
+ * BGP4-MIB and |snmp_utils.c| which is collections of helper functions for
+ * working with OIDs, VarBinds.
+ *
+ * Althrough called SNMP the BIRD does not implement SNMP directly but acts as
+ * an AgentX subagent. AgentX subagent connects to AgentX master agent that
+ * processes incomming SNMP requests and passes them down to the correct
+ * subagent. Therefore you need also a running master agent somewhere.
+ * Advantages of this design are that you are capable of doing aggregation of
+ * statuses of multiple BIRDs at the master agent level and much simpler
+ * implementation.
+ *
+ * Before any of the SNMP request could be processed, the SNMP need to
+ * established AgentX session with the master agent and need to register all
+ * subtrees to make them accessible from the master agent. The establishement of
+ * the of session is handled by snmp_start(), snmp_start_locked() and
+ * snmp_start_subagent(). Then we register all MIBs from configuration in
+ * snmp_register_mibs().
+ *
+ * The AgentX request are handled only during MIB subtree registrations and
+ * after then on established session (in states SNMP_REGISTER and SNMP_CONN, see
+ * below). It is also guaranteed that no request is received before MIB subtree
+ * registration because the specific subagent is not authoratitave and also the
+ * master agent has no info about MIB subtree supported by subagent. The AgentX
+ * requests are handled by function snmp_rx() in |subagent.c|.
+ *
+ *
+ *
+ * SNMP State Machine
*
* States with main transitions
*
*/
/**
+ *
+ *
+ *
+ *
* Handling of malformed packet:
- * When we find an error in PDU data, we create and send a response with error
- * defined by the RFC. We await until the packet is send and then we close the
- * communication socket. This also closes the established session. We chose
- * this approach because we cannot easily mark the boundary between packets.
- * When we are reseting the connection, we change the snmp_state to SNMP_RESET.
- * In SNMP_RESET state we skip all received bytes and wait for snmp_tx()
- * to be called. The socket's tx_hook is called when the TX-buffer is empty,
- * meaning our response (agentx-Response-PDU) was send.
*
+ * When we find an error in PDU data, we create and send a response with error
+ * defined by the RFC. We await until the packet is send and then we close the
+ * communication socket. This implicitly closes the established session. We
+ * chose this approach because we cannot easily mark the boundary between packets.
+ * When we are reseting the connection, we change the snmp_state to SNMP_RESET.
+ * In SNMP_RESET state we skip all received bytes and wait for snmp_tx()
+ * to be called. The socket's tx_hook is called when the TX-buffer is empty,
+ * meaning our response (agentx-Response-PDU) was send.
*
- * Partial parsing
- * It may happen that we received only staring part of some PDU from the
- * communication socket. In most cases if we recognize this situation we
- * immediately return, waiting for rest of the PDU to arrive. But for packets
- * like agentx-Get-PDU, agentx-GetNext-PDU and agentx-GetBulk-PDU it could be
- * costly as they could hold many VarBinds. In these cases we process.
+ *
+ * Partial parsing:
+ *
+ * It may happen that we received only staring part of some PDU from the
+ * communication socket. In most cases, if we recognize this situation we
+ * immediately return, waiting for rest of the PDU to arrive. But for packets
+ * like agentx-Get-PDU, agentx-GetNext-PDU and agentx-GetBulk-PDU it could be
+ * costly as they could hold many VarBinds. We don't want to process these
+ * packet twice because it is a lot work. We parse all VarBinds until we hit the
+ * first incomplete one. The logic behind this is to release as much as
+ * possible space from receive buffer. When we hit the first incomplete VarBind,
+ * we store information about the parsing state and move the header inside the
+ * receive buffer.
*
* Transmit packet context
*
{
res = p->last_header;
p->last_header = NULL;
+ p->last_size = 0;
}
else
res = response_header;
STORE_U32(h->payload, pkt_size);
*skip = AGENTX_HEADER_SIZE;
p->last_header = h;
+ p->last_size = c.buffer - sk->tpos;
/* number of bytes parsed from RX-buffer */
ret = pkt - pkt_start;
snmp_pdu_context(&c, sk);
if (c.size < AGENTX_HEADER_SIZE)
- snmp_manage_tbuf(p, &c);
+ return;
+
+ int unused = (sk->tbsize - (sk->tpos - sk->tbuf)) - (p->last_size + AGENTX_HEADER_SIZE);
+ if (p->last_header && unused >= 0)
+ {
+
+ }
+ else if (p->last_header)
+ {
+ }
struct agentx_header *h = (struct agentx_header *) c.buffer;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);