Put your short description here; used for first paragraph
and abstract.
When a DPI packet is parsed, the snmp_dpi_hdr structure shows in the
packet_type that this is an SNMP_DPI_GETNEXT packet, and so the packet_body
contains a pointer to a GETNEXT-varBind, which is represented in an
snmp_dpi_next_packet structure:
struct dpi_next_packet {
char *object_p; /* ptr to OIDstring */
char *group_p; /* ptr to sub-tree */
char *instance_p; /* ptr to rest of OID */
struct dpi_next_packet *next_p; /* ptr to next in chain*/
};
typedef struct dpi_next_packet snmp_dpi_next_packet;
#define snmp_dpi_next_packet_NULL_p ((snmp_dpi_next_packet *)0)
Assuming you have registered subtree dpiSimpleMIB and a
GETNEXT arrives for one variable (dpiSimpleInteger.0) that is object
1 instance 0 in the subtree, the fields in the snmp_dpi_get_packet
structure 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_next_packet_NULL_p
If
there are multiple varBinds in a GETNEXT request, each one is represented
in an snmp_dpi_next_packet structure and all the snmp_dpi_next_packet
structures are chained by the next pointer. If the next pointer is
not the snmp_dpi_next_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. You must find out which OID is the one that
lexicographically follows the one in the request. It is that OID
with its value that you must return as a response. Therefore, you
must now also set the proper OID in the response. When you are ready
to make a response that contains the new OID and the value of that
variable, you must prepare a SET-varBind which is represented in an
snmp_dpi_set_packet:
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 only varBind in the chain, pass the snmp_dpi_set_packet_NULL_p
pointer to indicate this.
- A pointer to the desired subtree.
- 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 Counter 64 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. Upon return, you can dispose of your own pointers
and allocated memory as you please. If the call is successful, a
pointer is returned as follows:
- A new snmp_dpi_set_packet if it is the first or only varBind.
- 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, create a DPI RESPONSE packet
using the mkDPIresponse() function, which expects these parameters:
- A pointer to an snmp_dpi_hdr. 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 that 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, pass the OID and value of the first OID that lexicographically
follows the nonexisting object or instance.
Reaching the end
of the subtree is not considered an error. For example, if there
is no NEXT OID, this is not an error. In this situation, return the
original OID as received in the request and a value_type of SNMP_TYPE_endOfMibView.
This value_type has an implicit value of NULL, so you can pass a
0 length and a NULL pointer for the value.
- The index of the first 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 GETNEXT request. If an error was detected,
an snmp_dpi_set_packet_NULL_p pointer may be passed.
The following code example returns a response. It is
assumed that there are no errors in the request, but proper code should
do the checking for that. Proper checking is done for lexicographic
next object, but no checking is done for ULONG_MAX, or making sure
that the instance ID is indeed valid (digits and periods). If the
code gets to the end of our dpiSimpleMIB, an endOfMibView is returned
as defined by the SNMP Version 2 rules.
static int do_next(snmp_dpi_hdr *hdr_p, snmp_dpi_next_packet *pack_p)
{
unsigned char *packet_p;
int rc;
unsigned long subid; /* subid is unsigned */
unsigned long instance; /* same with instance */
char *cp;
snmp_dpi_set_packet *varBind_p;
varBind_p = /* init the varBind chain */
snmp_dpi_set_packet_NULL_p; /* to a NULL pointer */
/* If we have done instance level registration, then we should */
/* never get a getNext. Anyway, if we do, then we skip this and */
/* return an endOfMibView. */
if (instance_level) {
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_endOfMibView, /* value type */
0L, /* length of value */
(unsigned char *)0); /* ptr to value */
} else {
if (pack_p->instance_p) { /* we have an instance ID */
cp = pack_p->instance_p; /* pick up ptr */
subid = strtoul(cp, cp, 10); /* convert subid (object) */
if (*cp == '.') { /* followed by a dot ? */
cp++; /* point after it if yes */
instance=strtoul(cp,cp,10); /* convert real instance */
/* not that we need it, we */
subid++; /* only have instance 0, */
/* so NEXT is next object */
instance = 0; /* and always instance 0 */
} else { /* no real instance passed */
instance = 0; /* so we can use 0 */
if (subid == 0) subid++; /* if object 0, start at 1 */
} /* endif */
} else { /* no instance ID passed */
subid = 1; /* so do first object */
instance = 0; /* instance 0 (all we have)*/
} /* endif */
/* we have set subid and instance such that we can basically */
/* process the request as a GET now. Actually, we don't even */
/* need instance, because all out object instances are zero. */
if (instance != 0) printf("Strange instance: %lu\n",instance);
switch (subid) {
case 1:
varBind_p = mkDPIset( /* Make DPI set packet */
varBind_p, /* ptr to varBind chain */
pack_p->group_p, /* ptr to subtree */
DPI_SIMPLE_INTEGER, /* ptr to rest of OID */
SNMP_TYPE_Integer32, /* value type Integer 32 */
sizeof(value1), /* length of value */
value1); /* ptr to value */
break;
case 2:
varBind_p = mkDPIset( /* Make DPI set packet */
varBind_p, /* ptr to varBind chain */
pack_p->group_p, /* ptr to subtree */
DPI_SIMPLE_STRING, /* ptr to rest of OID */
SNMP_TYPE_DisplayString,/* value type */
value2_len, /* length of value */
value2_p); /* ptr to value */
break;
case 3:
varBind_p = mkDPIset( /* Make DPI set packet */
varBind_p, /* ptr to varBind chain */
pack_p->group_p, /* ptr to subtree */
DPI_SIMPLE_COUNTER32, /* ptr to rest of OID */
SNMP_TYPE_Counter32, /* value type */
sizeof(value3), /* length of value */
value3); /* ptr to value */
break;
#ifndef EXCLUDE_SNMP_SMIv2_SUPPORT
case 4: /* *Apr23*/
varBind_p = mkDPIset( /* Make DPI set packet */
varBind_p, /* ptr to varBind chain */
pack_p->group_p, /* ptr to subtree */
DPI_SIMPLE_COUNTER64, /* ptr to rest of OID */
SNMP_TYPE_Counter64, /* value type */
sizeof(value4), /* length of value */
value4); /* ptr to value */
break; /* *Apr23*/
#endif /* ndef EXCLUDE_SNMP_SMIv2_SUPPORT */
default:
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_endOfMibView, /* value type */
0L, /* length of value */
(unsigned char *)0); /* ptr to value */
break;
} /* endswitch */
} /* 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_next() */