When the DPI packet is parsed, the snmp_dpi_hdr structure will show in
the
packet_type that this is an SNMP_DPI_GET packet. In that
case, the
packet_body contains a pointer to a GET-varBind,
which is represented in an snmp_dpi_get_packet structure:
struct dpi_get_packet {
char *object_p; /* ptr to OIDstring */
char *group_p; /* ptr to sub-tree */
char *instance_p; /* ptr to rest of OID */
struct dpi_get_packet *next_p; /* ptr to next in chain */
};
typedef struct dpi_get_packet snmp_dpi_get_packet;
#define snmp_dpi_get_packet_NULL_p ((snmp_dpi_get_packet *)0)
Assuming you have registered subtree 1.3.6.1.4.1.2.2.1.5
and a GET request comes in for one variable (1.3.6.1.4.1.2.2.1.5.1.0)
that is object 1 instance 0 in the subtree, the fields in the snmp_dpi_get_packet
would have pointers to:
object_p -> "1.3.6.1.4.1.2.2.1.5.1.0"
group_p -> "1.3.6.1.4.1.2.2.1.5."
instance_p -> "1.0"
next_p -> snmp_dpi_get_packet_NULL_p
If
there are multiple varBinds in a GET request, each one is represented
in an snmp_dpi_get_packet structure and all the snmp_dpi_get_packet
structures are chained using the next pointer. If the next pointer
is not the snmp_dpi_get_packet_NULL_p pointer, there are more varBinds
in the list.
Now you can analyze the varBind structure for whatever
checking you want to do. When you are ready to make a response that
contains the value of the variable, you prepare a SET-varBind, which
is represented in an snmp_dpi_set_packet structure:
struct dpi_set_packet {
char *object_p; /* ptr to OIDstring */
char *group_p; /* ptr to sub-tree */
char *instance_p; /* ptr to rest of OID */
unsigned char value_type; /* SNMP_TYPE_xxxx */
unsigned short value_len; /* value length */
char *value_p; /* ptr to value itself */
struct dpi_set_packet *next_p; /* ptr to next in chain */
};
typedef struct dpi_set_packet snmp_dpi_set_packet;
#define snmp_dpi_set_packet_NULL_p ((snmp_dpi_set_packet *)0)
You can use the mkDPIset() function to prepare such a structure.
This function expects the following parameters:
- A pointer to an existing snmp_dpi_set_packet structure if the
new varBind must be added to an existing chain of varBinds. If this
is the first or the only varBind in the chain, pass the snmp_dpi_set_packet_NULL_p
pointer to indicate this.
- A pointer to the subtree that you registered.
- A pointer to the rest of the OID; in other words, the piece that
follows the subtree.
- The value type of the value to be bound to the variable name.
This must be one of the SNMP_TYPE_xxxx values as defined in the
snmp_dpi.h include file.
- The length of the value. For integer type values, this must be
a length of 4. Work with 32-bit signed or unsigned integers except
for the Counter64 type. For the Counter64 type, point to an snmp_dpi_u64
structure and pass the length of that structure.
- A pointer to the value.
Memory for the varBind is dynamically allocated and the
data itself is copied. So upon return you can dispose of our own
pointers and allocated memory as you please. If the call is successful,
a pointer is returned as follows:
- To a new snmp_dpi_set_packet if it is the first or only varBind.
- To the existing snmp_dpi_set_packet that you passed on the call.
In this case, the new packet has been chained to the end of the varBind
list.
If the mkDPIset() call fails, a NULL pointer is returned.
When you have prepared the SET-varBind data, you can create a DPI RESPONSE packet
using the mkDPIresponse() function that expects these parameters:
- A pointer to an snmp_dpi_hdr. You should use the header of the
parsed incoming packet. It is used to copy the packet_id from
the request into the response, such that the agent can correlate the
response to a request.
- A return code which is an SNMP error code. If successful, this
should be SNMP_ERROR_noError (value 0). If failure, it must be one
of the SNMP_ERROR_xxxx values as defined in the snmp_dpi.h include
file.
A request for a nonexisting object or instance is not considered
an error. Instead, you must pass a value type of SNMP_TYPE_noSuchObject
or SNMP_TYPE_noSuchInstance respectively. These two value types have
an implicit value of NULL, so you can pass a 0 length and a NULL pointer
for the value in this case.
- The index of the varBind in error starts counting at 1. Pass
0 if no error occurred, or pass the proper index of the first varBind
for which an error was detected.
- A pointer to a chain of snmp_dpi_set_packets (varBinds) to be
returned as response to the GET request. If an error was detected,
an snmp_dpi_set_packet_NULL_p pointer may be passed.
The following code example returns a response. You assume
that there are no errors in the request, but proper code should do
the checking for that. For instance, you return a noSuchInstance
if the instance is not exactly what you expect and a noSuchObject
if the object instance_ID is greater than 3. However, there might
be no instance_ID at all and you should check for that, too.
static int do_get(snmp_dpi_hdr *hdr_p, snmp_dpi_get_packet *pack_p)
{
unsigned char *packet_p;
int rc;
snmp_dpi_set_packet *varBind_p;
char *i_p;
varBind_p = /* init the varBind chain */
snmp_dpi_set_packet_NULL_p; /* to a NULL pointer */
if (instance_level) {
if (pack_p->instance_p) {
printf("unexpected INSTANCE ptr \n");
return(-1);
}
i_p = pack_p->group_p + strlen(DPI_SIMPLE_MIB);
} else {
i_p = pack_p->instance_p;
}
if (i_p && (strcmp(i_p,"1.0") == 0)) {
varBind_p = mkDPIset( /* Make DPI set packet */
varBind_p, /* ptr to varBind chain */
pack_p->group_p, /* ptr to subtree */
pack_p->instance_p, /* ptr to rest of OID */
SNMP_TYPE_Integer32, /* value type Integer 32 */
sizeof(value1), /* length of value */
value1); /* ptr to value */
} else if (i_p && (strcmp(i_p,"2.0") == 0)) {
varBind_p = mkDPIset( /* Make DPI set packet */
varBind_p, /* ptr to varBind chain */
pack_p->group_p, /* ptr to subtree */
pack_p->instance_p, /* ptr to rest of OID */
SNMP_TYPE_DisplayString,/* value type */
value2_len, /* length of value */
value2_p); /* ptr to value */
} else if (i_p && (strcmp(i_p,"3.0") == 0)) {
varBind_p = mkDPIset( /* Make DPI set packet */
varBind_p, /* ptr to varBind chain */
pack_p->group_p, /* ptr to subtree */
pack_p->instance_p, /* ptr to rest of OID */
SNMP_TYPE_Counter32, /* value type */
sizeof(value3), /* length of value */
value3); /* ptr to value */
#ifndef EXCLUDE_SNMP_SMIv2_SUPPORT
} else if (i_p && (strcmp(i_p,"4.0") == 0)) {
varBind_p = mkDPIset( /* Make DPI set packet */
varBind_p, /* ptr to varBind chain */
pack_p->group_p, /* ptr to subtree */
pack_p->instance_p, /* ptr to rest of OID */
SNMP_TYPE_Counter64, /* value type */
sizeof(value4), /* length of value */
value4); /* ptr to value *Apr23*/
} else if (i_p && (strcmp(i_p,"4") > 0)) {
#else
} else if (i_p && (strcmp(i_p,"3") > 0)) {
#endif /* ndef EXCLUDE_SNMP_SMIv2_SUPPORT */
varBind_p = mkDPIset( /* Make DPI set packet */
varBind_p, /* ptr to varBind chain */
pack_p->group_p, /* ptr to subtree */
pack_p->instance_p, /* ptr to rest of OID */
SNMP_TYPE_noSuchObject, /* value type */
0L, /* length of value */
(unsigned char *)0); /* ptr to value */
} else {
varBind_p = mkDPIset( /* Make DPI set packet */
varBind_p, /* ptr to varBind chain */
pack_p->group_p, /* ptr to subtree */
pack_p->instance_p, /* ptr to rest of OID */
SNMP_TYPE_noSuchInstance,/* value type */
0L, /* length of value */
(unsigned char *)0); /* ptr to value */
} /* endif */
if (!varBind_p) return(-1); /* If it failed, return */
packet_p = mkDPIresponse( /* Make DPIresponse packet */
hdr_p, /* ptr parsed request */
SNMP_ERROR_noError, /* all is OK, no error */
0L, /* index is zero, no error */
varBind_p); /* varBind response data */
if (!packet_p) return(-1); /* If it failed, return */
rc = DPIsend_packet_to_agent( /* send RESPONSE packet */
handle, /* on this connection */
packet_p, /* this is the packet */
DPI_PACKET_LEN(packet_p));/* and this is its length */
return(rc); /* return retcode */
} /* end of do_get() */