@(#)40 1.1 src/tcpip/usr/samples/snmpd/dpi2/dpi20ref.txt, snmp, tcpip720 11/19/96 16:34:24 # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # tcpip720 src/tcpip/usr/samples/snmpd/dpi2/dpi20ref.txt 1.1 # # Licensed Materials - Property of IBM # # Restricted Materials of IBM # # COPYRIGHT International Business Machines Corp. 1996 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG DPI VERSION 2.0 API - PROGRAMMERS REFERENCE Wijnen [Page i] SNMP-DPI API Version 2.0 January 1994 Table of contents 1.0 INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . 2 1.1 Copyright and Disclaimer . . . . . . . . . . . . . . . . . 2 1.2 Who Should Read This Manual . . . . . . . . . . . . . . . 2 1.3 Freely Available Implementation . . . . . . . . . . . . . 4 1.4 Multiple Levels of the SNMP DPI API . . . . . . . . . . . 6 2.0 SNMP DPI API (VERSION 2.0) . . . . . . . . . . . . . . . . 7 2.1 API Audience . . . . . . . . . . . . . . . . . . . . . . . 7 2.1.1 API for Sub-agent Programmer . . . . . . . . . . . . . . 9 2.1.2 API for Agent Programmer . . . . . . . . . . . . . . . 11 2.2 Transport Related DPI API Functions . . . . . . . . . . 13 2.2.1 The DPIawait_packet_from_agent() Function . . . . . . 14 2.2.2 The DPIconnect_to_agent_NMQ() Function . . . . . . . . 16 2.2.3 The DPIconnect_to_agent_TCP() Function . . . . . . . . 18 2.2.4 The DPIconnect_to_agent_UDP() Function . . . . . . . . 20 2.2.5 The DPIdisconnect_from_agent() Function . . . . . . . 22 2.2.6 The DPIsend_packet_to_agent() Function . . . . . . . . 24 2.2.7 The lookup_host() Function . . . . . . . . . . . . . . 26 2.2.8 The query_DPI_port() Function . . . . . . . . . . . . 28 2.3 Basic DPI API Functions . . . . . . . . . . . . . . . . 31 2.3.1 The DPIdebug() Function . . . . . . . . . . . . . . . 32 2.3.2 The DPI_PACKET_LEN() macro . . . . . . . . . . . . . . 33 2.3.3 The fDPIparse() Function . . . . . . . . . . . . . . . 34 2.3.4 The fDPIset() Function . . . . . . . . . . . . . . . . 36 2.3.5 The mkDPIAreYouThere() Function . . . . . . . . . . . 38 2.3.6 The mkDPIbulk() Function . . . . . . . . . . . . . . . 40 2.3.7 The mkDPIclose() Function . . . . . . . . . . . . . . 43 2.3.8 The mkDPIget() Function . . . . . . . . . . . . . . . 45 2.3.9 The mkDPIhdr() Function . . . . . . . . . . . . . . . 47 2.3.10 The mkDPIhdr_version() Function . . . . . . . . . . . 49 2.3.11 The mkDPInext() Function . . . . . . . . . . . . . . 52 2.3.12 The mkDPIopen() Function . . . . . . . . . . . . . . 54 2.3.13 The mkDPIpacket() Function . . . . . . . . . . . . . 57 2.3.14 The mkDPIregister() Function . . . . . . . . . . . . 59 2.3.15 The mkDPIresponse() Function . . . . . . . . . . . . 62 2.3.16 The mkDPIset() Function . . . . . . . . . . . . . . . 65 2.3.17 The mkDPItrap() Function . . . . . . . . . . . . . . 71 2.3.18 The mkDPIunregister() Function . . . . . . . . . . . 73 2.3.19 The pDPIpacket() Function . . . . . . . . . . . . . . 75 2.4 DPI Structures . . . . . . . . . . . . . . . . . . . . . 77 2.4.1 The snmp_dpi_bulk_packet structure . . . . . . . . . . 78 2.4.2 The snmp_dpi_close_packet structure . . . . . . . . . 80 2.4.3 The snmp_dpi_get_packet structure . . . . . . . . . . 81 2.4.4 The snmp_dpi_next_packet structure . . . . . . . . . . 83 2.4.5 The snmp_dpi_hdr structure . . . . . . . . . . . . . . 85 2.4.6 The snmp_dpi_open_packet structure . . . . . . . . . . 88 2.4.7 The snmp_dpi_reg_packet structure . . . . . . . . . . 90 2.4.8 The snmp_dpi_resp_packet structure . . . . . . . . . . 92 2.4.9 The snmp_dpi_set_packet structure . . . . . . . . . . 94 2.4.10 The snmp_dpi_trap_packet structure . . . . . . . . . 96 Wijnen [Page ii] SNMP-DPI API Version 2.0 January 1994 2.4.11 The snmp_dpi_ureg_packet structure . . . . . . . . . 98 2.4.12 The snmp_dpi_u64 structure . . . . . . . . . . . . . 100 2.5 Character Set Selection . . . . . . . . . . . . . . . . 101 2.6 Constants and Values . . . . . . . . . . . . . . . . . . 103 2.6.1 DPI CLOSE Reason Codes . . . . . . . . . . . . . . . . 103 2.6.2 DPI Packet Types . . . . . . . . . . . . . . . . . . . 104 2.6.3 DPI RESPONSE Error Codes . . . . . . . . . . . . . . . 105 2.6.4 DPI UNREGISTER Reason Codes . . . . . . . . . . . . . 107 2.6.5 DPI SNMP Value Types . . . . . . . . . . . . . . . . . 108 2.6.6 Value Representation . . . . . . . . . . . . . . . . . 109 2.6.7 Return Codes from DPI Transport Related Functions . . 110 2.7 The snmp_dpi.h Include File . . . . . . . . . . . . . . 111 3.0 SNMP DPI 1.1 API . . . . . . . . . . . . . . . . . . . . 113 4.0 HOW TO CHANGE YOUR DPI SUB-AGENT TO DPI 2.0 . . . . . . 116 5.0 A SIMPLE SAMPLE DPI SUB-AGENT . . . . . . . . . . . . . 118 5.1 Overview of Sub-agent Processing . . . . . . . . . . . . 118 5.1.1 Connecting to the agent . . . . . . . . . . . . . . . 120 5.2 Registering a sub-tree with the agent . . . . . . . . . 123 5.3 Processing requests from the agent . . . . . . . . . . . 125 5.3.1 Processing a GET request . . . . . . . . . . . . . . . 127 5.3.2 Processing a GETNEXT request . . . . . . . . . . . . . 131 5.3.3 Processing a SET/COMMIT/UNDO request . . . . . . . . . 135 5.3.4 Processing an UNREGISTER request . . . . . . . . . . . 139 5.3.5 Processing a CLOSE request . . . . . . . . . . . . . . 139 5.4 Generating a TRAP . . . . . . . . . . . . . . . . . . . 140 Wijnen [Page iii] SNMP-DPI API Version 2.0 January 1994 (C) COPYRIGHT International Business Machines Corp. 1994 Permission to use, copy, modify, and distribute this software and its documentation for any lawful purpose and without fee is hereby granted, provided that this notice be retained unaltered, and that the names of IBM and all other contributors shall not be used in advertising or publicity pertaining to distribution of the software without specific written prior permission. No contributor makes any representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. IBM AND ALL OTHER CONTRIBUTORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT. IN NO EVENT SHALL IBM OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT, TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH, THE USE OR PERFORMANCE OF THIS SOFTWARE. Wijnen [Page 1] SNMP-DPI API Version 2.0 January 1994 1.0 INTRODUCTION 1.1 COPYRIGHT AND DISCLAIMER (C) COPYRIGHT International Business Machines Corp. 1994 Permission to use, copy, modify, and distribute this software and its documentation for any lawful purpose and without fee is hereby granted, provided that this notice be retained unaltered, and that the names of IBM and all other contributors shall not be used in advertising or publicity pertaining to distribution of the software without specific written prior permission. No contributor makes any representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. IBM AND ALL OTHER CONTRIBUTORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT. IN NO EVENT SHALL IBM OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT, TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH, THE USE OR PERFORMANCE OF THIS SOFTWARE. 1.2 WHO SHOULD READ THIS MANUAL This document describes an API on top of the SNMP DPI Version 2.0. The API has been implemented and is in use by several products. Some people consider it a low level API, and samples of a higher level API do exist. This API has two types of audiences: o The DPI sub-agent programmer o The programmer(s) who implement a DPI capable SNMP agent Some of the functions described in this document are used by both types of audiences. Other functions are (normally) only used by one type of programmer. In each function description, we have included a statement about the intended audience or user, so that you can quickly decide if the information is relevant to the type of work you are doing. The reader may also want to obtain a copy of the relevant RFCs. Wijnen [Page 2] SNMP-DPI API Version 2.0 January 1994 o RFC1228 is the SNMP DPI 1.0 RFC o RFC15xx is the SNMP DPI 2.0 RFC o RFC1440 through RFC1452 are the SNMPv2 RFCs. Wijnen [Page 3] SNMP-DPI API Version 2.0 January 1994 1.3 FREELY AVAILABLE IMPLEMENTATION DPI 2.0 has been implemented by IBM Research and the source code is freely available under the terms listed in 1.1, "Copyright and Disclaimer" on page 2. You can obtain the code and documentation by anonymous FTP from: software.watson.ibm.com (129.34.139.5) To obtain the source, perform the following steps: ftp software.watson.ibm.com user: anonymous password: your_e-mail_address cd /public/dpi get README binary get dpi_api.tar (or compressed dpi_api.tar.Z) quit The code consists of the following source files: snmp_dpi.h The public SNMP DPI 2.0 API as provided to the DPI sub-agent programmer. The DPI sub-agent code must include this file. snmp_mDPI.c The base DPI 2.0 encode/decode functions. This is system and platform independent code, ANSI C compliant. This piece of the code is used both at the agent and at the sub-agent side. snmp_dpi1.h To be included (done by by snmp_dpi.h) if the DPI sub-agent programmer wants DPI version 1.x compatibility. It will be included if the programmer defines: SNMP_DPI_VERSION=1 SNMP_DPI_RELEASE=1 snmp_qDPI.c System independent portion of the code for the query_DPI_port() function. snmp_lDPI.c Sample of system specific code for the DPI API. The SNMP DPI 2.0 API defines functions like: Wijnen [Page 4] SNMP-DPI API Version 2.0 January 1994 query_DPI_port() lookup_host() DPIconnect_to_agent_TCP() DPIconnect_to_agent_UDP() DPIconnect_to_agent_NMQ() DPIdisconnect_from_agent() DPIsend_packet_from_agent() DPIawait_packet_from_agent() Those functions cannot be implemented in a system independent manner because unfortunately, the BSD socket implementation is not 100% compatible on all systems. However, with some #ifdef logic, it is possible to make them work on several platforms. The sample provided currently compiles and works on: OS/2 2.x with TCP/IP 2.0 for OS/2 AIX 3.2 and up /* TODO: need to test */ AIX/ESA x.x and up /* TODO: need to test */ AIX 1.3 for PS/2 /* TODO: need to test */ snmp_lDPI.h Defines function prototypes, message texts and such for use within the DPI internal code. dpi_sample.c A very basic sample SNMP DPI sub-agent to explain and show how to use the SNMP DPI API. dpiSimple.mib The dpiSimple MIB that goes with the dpi_sample.c source. This code can be used by people who want to implement the SNMP DPI version 2.0 API and/or an SNMP DPI 2.0 capable agent on their own platform. The DPI sub-agent programmer can use the snmp_dpi.h include file and the dpi_sample.c file as a sample on how to use the DPI API. Wijnen [Page 5] SNMP-DPI API Version 2.0 January 1994 1.4 MULTIPLE LEVELS OF THE SNMP DPI API The primary objective of this guide is to describe the SNMP DPI 2.0 API. Some functions are implemented as macros. This is because the older DPI version 1.x had the same function names with different arguments. So the new implementation uses a new function name. It is thus possible to provide either the DPI 1.x or the DPI 2.x API by properly defining the macros. By default, when you include the snmp_dpi.h include file, you will be exposed to the DPI 2.0 API. This is the recommended use of the SNMP DPI API, for which you will find the reference material in 2.0, "SNMP DPI API (Version 2.0)" on page 7. When you link-edit your object code into an executable file, you must then use the new DPI functions as provided in the snmp_mDPI.c, snmp_qDPI.c and snmp_lDPI.c source files. If you have DPI 1.x based code, then you may opt to keep using the old DPI 1.x snmp_dpi.h include file and the old DPI 1.x functions as provided in DPILIB (mkDPI.c and get_DPI.c). You will be able to communicate with an SNMP agent which implements DPI 2.0 based on the DPI 2.0 implementation by IBM Research. For instance, the IBM Research new Platform Independent SNMP stack includes support for DPI 1.x sub-agents. However, you may want to recompile your DPI 1.x based code against the new snmp_dpi.h include file. If you choose for DPI 1.x compatibility, you must also use DPI 1.x version of the snmp_mDPI.c code (e.g. compiled with these flags). In 3.0, "SNMP DPI 1.1 API" on page 113 we have a short discussion of the items to be considered if you want to use the DPI 1.x compatibility mode. In 4.0, "How to change your DPI sub-agent to DPI 2.0" on page 116 we discuss what kind of changes you must make to your source to migrate it to the SNMP DPI 2.0 API. If you take a few minutes to look at it, you will see that this is not too big a task. Wijnen [Page 6] SNMP-DPI API Version 2.0 January 1994 2.0 SNMP DPI API (VERSION 2.0) Some functions of the DPI API for version 2.0 are implemented as macros. This is because the older DPI version 1 had the same function names, but with different arguments. The new implementation has a new function names which are not always the most intuitive. By defining the macros with the more natural names for the functions (macros have same names as the functions were named in DPI version 1) we hide the non-intuitive names and at the same time we allow that by providing a different set of macros we can give DPI version 1 compatibility. The basic DPI functions are provided by platform independent code that is ANSI C compliant. However, once a DPI packet needs to be sent to an agent or sub-agent, then it depends on the platform and the chosen transport protocol how that is exactly implemented. Waiting for a DPI packet is also depends on those things, but besides that, some sub-agents want to control sending of and waiting for packets themselves, because they may need to be driven by other interrupts as well. So, there is a set of DPI transport related functions that may are implemented on all platforms to hide the platform dependent issues for those sub-agents that do not need detailed control about the transport themselves. 2.1 API AUDIENCE There are basically two types of audiences for the DPI API. 1. The Sub-agent Programmer who writes code to implement a DPI sub-agent. 2. The Agent Programmer who wants to implement DPI support in an SNMP agent. First we have an overview of the functions and data structures normally used by a Sub-agent programmer. Then we have an overview of the functions and data structures normally used by a Agent programmer. Wijnen [Page 7] SNMP-DPI API Version 2.0 January 1994 Then we have description of all the functions and data structures and each description also lists the intended audience, so that you can quickly decide if you need to worry about a certain function. Wijnen [Page 8] SNMP-DPI API Version 2.0 January 1994 2.1.1 API FOR SUB-AGENT PROGRAMMER AUDIENCE DPI sub-agent programmer. Basic DPI functions normally used by the programmer who implements a DPI sub-agent: 2.3.1, "The DPIdebug() Function" on page 32 2.3.2, "The DPI_PACKET_LEN() macro" on page 33 2.3.3, "The fDPIparse() Function" on page 34 2.3.4, "The fDPIset() Function" on page 36 2.3.5, "The mkDPIAreYouThere() Function" on page 38 2.3.7, "The mkDPIclose() Function" on page 43 2.3.12, "The mkDPIopen() Function" on page 54 2.3.14, "The mkDPIregister() Function" on page 59 2.3.15, "The mkDPIresponse() Function" on page 62 2.3.16, "The mkDPIset() Function" on page 65 2.3.17, "The mkDPItrap() Function" on page 71 2.3.18, "The mkDPIunregister() Function" on page 73 2.3.19, "The pDPIpacket() Function" on page 75 DPI transport related functions normally used by the programmer who implements a DPI sub-agent: 2.2.1, "The DPIawait_packet_from_agent() Function" on page 14 2.2.2, "The DPIconnect_to_agent_NMQ() Function" on page 16 2.2.3, "The DPIconnect_to_agent_TCP() Function" on page 18 2.2.4, "The DPIconnect_to_agent_UDP() Function" on page 20 2.2.5, "The DPIdisconnect_from_agent() Function" on page 22 2.2.6, "The DPIsend_packet_to_agent() Function" on page 24 2.2.7, "The lookup_host() Function" on page 26 2.2.8, "The query_DPI_port() Function" on page 28 Data structures normally used by the programmer who implements a DPI sub-agent: 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.4.2, "The snmp_dpi_close_packet structure" on page 80 2.4.3, "The snmp_dpi_get_packet structure" on page 81 2.4.4, "The snmp_dpi_next_packet structure" on page 83 2.4.1, "The snmp_dpi_bulk_packet structure" on page 78 2.4.8, "The snmp_dpi_resp_packet structure" on page 92 2.4.9, "The snmp_dpi_set_packet structure" on page 94 2.4.11, "The snmp_dpi_ureg_packet structure" on page 98 2.4.12, "The snmp_dpi_u64 structure" on page 100 Constants an values normally of interest to the programmer who implements a DPI sub-agent: Wijnen [Page 9] SNMP-DPI API Version 2.0 January 1994 2.6.1, "DPI CLOSE Reason Codes" on page 103 2.6.2, "DPI Packet Types" on page 104 2.6.3, "DPI RESPONSE Error Codes" on page 105 2.6.4, "DPI UNREGISTER Reason Codes" on page 107 2.6.5, "DPI SNMP Value Types" on page 108 2.6.6, "Value Representation" on page 109 2.5, "Character Set Selection" on page 101 See also 2.7, "The snmp_dpi.h Include File" on page 111. Wijnen [Page 10] SNMP-DPI API Version 2.0 January 1994 2.1.2 API FOR AGENT PROGRAMMER AUDIENCE DPI agent programmer. Functions normally used by the programmer who implements a DPI capable SNMP agent: 2.3.1, "The DPIdebug() Function" on page 32 2.3.2, "The DPI_PACKET_LEN() macro" on page 33 2.3.3, "The fDPIparse() Function" on page 34 2.3.4, "The fDPIset() Function" on page 36 2.3.7, "The mkDPIclose() Function" on page 43 2.3.8, "The mkDPIget() Function" on page 45 2.3.9, "The mkDPIhdr() Function" on page 47 2.3.10, "The mkDPIhdr_version() Function" on page 49 2.3.11, "The mkDPInext() Function" on page 52 2.3.6, "The mkDPIbulk() Function" on page 40 2.3.13, "The mkDPIpacket() Function" on page 57 2.3.15, "The mkDPIresponse() Function" on page 62 2.3.16, "The mkDPIset() Function" on page 65 2.3.18, "The mkDPIunregister() Function" on page 73 2.3.19, "The pDPIpacket() Function" on page 75 Data structures normally used by the programmer who implements a DPI capable SNMP agent: 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.4.2, "The snmp_dpi_close_packet structure" on page 80 2.4.3, "The snmp_dpi_get_packet structure" on page 81 2.4.4, "The snmp_dpi_next_packet structure" on page 83 2.4.1, "The snmp_dpi_bulk_packet structure" on page 78 2.4.6, "The snmp_dpi_open_packet structure" on page 88 2.4.7, "The snmp_dpi_reg_packet structure" on page 90 2.4.8, "The snmp_dpi_resp_packet structure" on page 92 2.4.9, "The snmp_dpi_set_packet structure" on page 94 2.4.10, "The snmp_dpi_trap_packet structure" on page 96 2.4.11, "The snmp_dpi_ureg_packet structure" on page 98 2.4.12, "The snmp_dpi_u64 structure" on page 100 Constants an values normally of interest to the programmer who implements a DPI capable SNMP agent: 2.6.1, "DPI CLOSE Reason Codes" on page 103 2.6.2, "DPI Packet Types" on page 104 2.6.3, "DPI RESPONSE Error Codes" on page 105 2.6.4, "DPI UNREGISTER Reason Codes" on page 107 2.6.5, "DPI SNMP Value Types" on page 108 2.6.6, "Value Representation" on page 109 Wijnen [Page 11] SNMP-DPI API Version 2.0 January 1994 2.5, "Character Set Selection" on page 101 See also 2.7, "The snmp_dpi.h Include File" on page 111. Wijnen [Page 12] SNMP-DPI API Version 2.0 January 1994 2.2 TRANSPORT RELATED DPI API FUNCTIONS This section contains a description of each DPI transport related function that is available to the DPI sub-agent programmer. These functions try to hide any platform specific issues for the DPI sub-agent programmer so that the sub-agent can be made as portable as possible. If you need detailed control for sending and awaiting DPI packets, then you may have to do some of the transport related code yourself. As you can see, we recognize different types of transport. Our functions are basically the same for any platform, except for the initial call to setup a connection. Not all the transport types may be supported on your platform. Please check with your platform DPI provider which ones are supported. RELATED INFORMATION 2.2.1, "The DPIawait_packet_from_agent() Function" on page 14 2.2.2, "The DPIconnect_to_agent_NMQ() Function" on page 16 2.2.3, "The DPIconnect_to_agent_TCP() Function" on page 18 2.2.4, "The DPIconnect_to_agent_UDP() Function" on page 20 2.2.5, "The DPIdisconnect_from_agent() Function" on page 22 2.2.7, "The lookup_host() Function" on page 26 2.2.8, "The query_DPI_port() Function" on page 28 2.2.6, "The DPIsend_packet_to_agent() Function" on page 24 Wijnen [Page 13] SNMP-DPI API Version 2.0 January 1994 2.2.1 THE DPIAWAIT_PACKET_FROM_AGENT() FUNCTION AUDIENCE DPI sub-agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | int DPIawait_packet_from_agent( /* await a DPI packet */| | int handle, /* on this connection */| | int timeout, /* timeout in seconds. */| | unsigned char **message_p, /* receives ptr to data */| | unsigned long *length); /* receives length of data */| | | +-------------------------------------------------------------------+ PARAMETER(S) handle A handle as obtained with a DPIconnect_to_agent_xxxx() call. timeout A timeout value in seconds. There are two special values: -1 causes the function to wait forever until a packet arrives 0 Means that the function will only check if a packet is waiting. If not an immediate return is made. If there is a packet that will be returned. message_p The address of a ptr that will receive the address of a static DPI packet buffer or, if there is no packet, a NULL pointer. length The address of an (unsigned long) integer that will receive the length of the received DPI packet or, if there is no packet, a zero value. RETURN VALUE If success, then a zero (DPI_RC_noError) is returned. The callers buffer ptr and length will be set to point to the received DPI packet and to the length of that packet. If failure, then a negative integer is returned. It indicates what kind of error occurred. See 2.6.7, "Return Codes from DPI Wijnen [Page 14] SNMP-DPI API Version 2.0 January 1994 Transport Related Functions" on page 110 for a list of possible error codes. DESCRIPTION The DPIawait_packet_from_agent() function is used at the sub-agent side to await a DPI packet from the DPI capable SNMP agent. The programmer can specify how long to wait. EXAMPLE #include int handle; unsigned char *pack_p; unsigned long length; handle = DPIconnect_to_agent_TCP("localhost", "public"); if (handle < 0) printf("Error %d from connect\n",handle); exit(1); } /* endif */ /* do useful stuff */ rc = DPIawait_packet_from_agent(handle, -1, &pack_p, &length); if (rc) { printf("Error %d from await packet\n"); exit(1); } /* endif */ /* handle the packet */ RELATED INFORMATION 2.2.3, "The DPIconnect_to_agent_TCP() Function" on page 18 Wijnen [Page 15] SNMP-DPI API Version 2.0 January 1994 2.2.2 THE DPICONNECT_TO_AGENT_NMQ() FUNCTION AUDIENCE DPI sub-agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | int DPIconnect_to_agent_NMQ( /* Connect to DPI Named Queue */| | char *t_qname_p, /* target (agent) queue name */| | char *s_qname_p); /* source (sub-agent) q name */| | | +-------------------------------------------------------------------+ PARAMETER(S) t_qname_p A pointer to a NULL terminated character string representing the target Queue Name where the DPI capable SNMP agent is expecting DPI packets. s_qname_p A pointer to a NULL terminated character string representing the source Queue Name from which the sub-agent will be sending DPI packets and where it expects DPI packets as input. RETURN VALUE If success, an positive integer that represents the connection. It is to be used as a handle in subsequent calls to DPI transport related functions. If failure, then a negative integer is returned. It indicates what kind of error occurred. See 2.6.7, "Return Codes from DPI Transport Related Functions" on page 110 for a list of possible error codes. DESCRIPTION The DPIconnect_to_agent_NMQ() function is used at the sub-agent side to setup an NMQ (named queue) connection to the DPI capable SNMP agent. Wijnen [Page 16] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include int handle; handle = DPIconnect_to_agent_NMQ("DPIqueue", "MYqueue"); if (handle < 0) printf("Error %d from connect\n",handle); exit(1); } /* endif */ RELATED INFORMATION 2.6.7, "Return Codes from DPI Transport Related Functions" on page 110 Wijnen [Page 17] SNMP-DPI API Version 2.0 January 1994 2.2.3 THE DPICONNECT_TO_AGENT_TCP() FUNCTION AUDIENCE DPI sub-agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | int DPIconnect_to_agent_TCP( /* Connect to DPI TCP port */| | char *hostname_p, /* target hostname/IP address */| | char *community_p); /* community name */| | | +-------------------------------------------------------------------+ PARAMETER(S) hostname_p A pointer to a NULL terminated character string representing the hostname (or IP address in dot notation) of the host where the DPI capable SNMP agent is running. community_p A pointer to a NULL terminated character string representing the community name that is required to obtain the dpiPort from the SNMP agent via an SNMP GET request. RETURN VALUE If success, an positive integer that represents the connection. It is to be used as a handle in subsequent calls to DPI transport related functions. If failure, then a negative integer is returned. It indicates what kind of error occurred. See 2.6.7, "Return Codes from DPI Transport Related Functions" on page 110 for a list of possible error codes. DESCRIPTION The DPIconnect_to_agent_TCP() function is used at the sub-agent side to setup a TCP connection to the DPI capable SNMP agent. Wijnen [Page 18] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include int handle; handle = DPIconnect_to_agent_TCP("localhost", "loopback"); if (handle < 0) printf("Error %d from connect\n",handle); exit(1); } /* endif */ RELATED INFORMATION 2.6.7, "Return Codes from DPI Transport Related Functions" on page 110 Wijnen [Page 19] SNMP-DPI API Version 2.0 January 1994 2.2.4 THE DPICONNECT_TO_AGENT_UDP() FUNCTION AUDIENCE DPI sub-agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | int DPIconnect_to_agent_UDP( /* Connect to DPI UDP port */| | char *hostname_p, /* target hostname/IP address */| | char *community_p); /* community name */| | | +-------------------------------------------------------------------+ PARAMETER(S) hostname_p A pointer to a NULL terminated character string representing the hostname (or IP address in dot notation) of the host where the DPI capable SNMP agent is running. community_p A pointer to a NULL terminated character string representing the community name that is required to obtain the dpiPort from the SNMP agent via an SNMP GET request. RETURN VALUE If success, an positive integer that represents the connection. It is to be used as a handle in subsequent calls to DPI transport related functions. If failure, then a negative integer is returned. It indicates what kind of error occurred. See 2.6.7, "Return Codes from DPI Transport Related Functions" on page 110 for a list of possible error codes. DESCRIPTION The DPIconnect_to_agent_UDP() function is used at the sub-agent side to setup a UDP connection to the DPI capable SNMP agent. Wijnen [Page 20] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include int handle; handle = DPIconnect_to_agent_UDP("localhost", "loopback"); if (handle < 0) printf("Error %d from connect\n",handle); exit(1); } /* endif */ RELATED INFORMATION 2.6.7, "Return Codes from DPI Transport Related Functions" on page 110 Wijnen [Page 21] SNMP-DPI API Version 2.0 January 1994 2.2.5 THE DPIDISCONNECT_FROM_AGENT() FUNCTION AUDIENCE DPI sub-agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | void DPIdisconnect_from_agent( /* disconnect from DPI (agent)*/| | int handle); /* close this connection */| | | +-------------------------------------------------------------------+ PARAMETER(S) handle A handle as obtained with a DPIconnect_to_agent_xxxx() call. RETURN VALUE If success, an positive integer that represents the connection. It is to be used as a handle in subsequent calls to DPI transport related functions. If failure, then a negative integer is returned. It indicates what kind of error occurred. See 2.6.7, "Return Codes from DPI Transport Related Functions" on page 110 for a list of possible error codes. DESCRIPTION The DPIdisconnect_from_agent() function is used at the sub-agent side to terminate a connection to the DPI capable SNMP agent. EXAMPLE #include int handle; handle = DPIconnect_to_agent_TCP("localhost", "loopback"); if (handle < 0) printf("Error %d from connect\n",handle); exit(1); } /* endif */ /* do useful stuff */ DPIdisconnect_from_agent(handle); Wijnen [Page 22] SNMP-DPI API Version 2.0 January 1994 RELATED INFORMATION 2.2.3, "The DPIconnect_to_agent_TCP() Function" on page 18 Wijnen [Page 23] SNMP-DPI API Version 2.0 January 1994 2.2.6 THE DPISEND_PACKET_TO_AGENT() FUNCTION AUDIENCE DPI sub-agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | int DPIsend_packet_to_agent( /* send a DPI packet */| | int handle, /* on this connection */| | unsigned char *message_p, /* ptr to the packet data */| | unsigned long length); /* length of the packet */| | | +-------------------------------------------------------------------+ PARAMETER(S) handle A handle as obtained with a DPIconnect_to_agent_xxxx() call. message_p A ptr to the buffer containing the DPI packet to be sent. length The length of the DPI packet to be sent. The DPI_PACKET_LEN macro is a useful macro to calculate the length. RETURN VALUE If success, then a zero (DPI_RC_noError) is returned. If failure, then a negative integer is returned. It indicates what kind of error occurred. See 2.6.7, "Return Codes from DPI Transport Related Functions" on page 110 for a list of possible error codes. DESCRIPTION The DPIsend_packet_to_agent() function is used at the sub-agent side to send a DPI packet to the DPI capable SNMP agent. EXAMPLE #include int handle; unsigned char *pack_p; Wijnen [Page 24] SNMP-DPI API Version 2.0 January 1994 handle = DPIconnect_to_agent_TCP("localhost", "loopback"); if (handle < 0) printf("Error %d from connect\n",handle); exit(1); } /* endif */ pack_p = mkDPIopen("1.3.6.1.2.3.4.5", "Sample DPI sub-agent" 0L,2L,,DPI_NATIVE_CSET, 0,(char *)0); if (pack_p) { rc = DPIsend_packet_to_agent(handle,pack_p, DPI_PACKET_LEN(pack_p)); if (rc) { printf("Error %d from await packet\n"); exit(1); } /* endif */ } else { printf("Can't make DPI OPEN packet\n"); exit(1); } /* endif */ /* await the response */ RELATED INFORMATION 2.2.3, "The DPIconnect_to_agent_TCP() Function" on page 18 2.3.2, "The DPI_PACKET_LEN() macro" on page 33 2.3.12, "The mkDPIopen() Function" on page 54 Wijnen [Page 25] SNMP-DPI API Version 2.0 January 1994 2.2.7 THE LOOKUP_HOST() FUNCTION AUDIENCE DPI sub-agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | unsigned long lookup_host( /* find IP address in network */| | char *hostname_p); /* byte order for this host */| | | +-------------------------------------------------------------------+ PARAMETER(S) hostname_p A pointer to a NULL terminated character string representing the hostname (or IP address in dot notation) of the host where the DPI capable SNMP agent is running. RETURN VALUE If success, then the IP address for is returned in network byte order, so ready to be used in a sockaddr_in structure. If failure, then a value of 0 is returned. DESCRIPTION The lookup_host() function is used to obtain the IP address (in network byte order) of a host (or IP address in dot notation). The DPI sub-agent programmer only needs to use this function if to code the connection setup and send or await the packet. The programmer then obtains the DPI port number, finds the IP address of the agent with 2.2.7, "The lookup_host() Function" and then sets up a socket for communication. This function is implicitly executed by the DPIconnect_to_agent_TCP() and DPIconnect_to_agent_UDP() functions. It is this DPIconnect_to_agent_xxxx() function that the DPI sub-agent programmer would normally use. Wijnen [Page 26] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include #include /* other include files for BSD sockets and such */ int handle; unsigned char *pack_p; long int dpi_port; int fd; struct sockaddr_in s,t; /* source and target */ dpi_port = query_DPI_port("localhost", /* get DPI port number */ "public", /* for TCP, local host */ dpiPortForTCP); if (dpi_port < 0) exit(1); /* error if negative */ host_addr = lookup_host("localhost"); /* find target IP addr */ if (host_addr == 0) exit(1); /* unknown, that's it */ fd = socket(AF_INET,SOCK_STREAM,0); /* create a TCP socket */ if (fd < 0) exit(1); /* failure to do so */ memset(&s,0,sizeof(s)); s.sin_family = AF_INET; /* set AF_INET family */ s.sin_port = 0; /* give us any port, */ s.sin_addr.s_addr = htonl(INADDR_ANY); /* any local IPaddress */ rc = bind(fd,(struct sockaddr *)s, /* bind our socket(fd) */ sizeof(s_sock)); /* defined in s socket */ if (rc < 0) exit(1); /* failure, so exit */ memset(&d,0,sizeof(d)); d.sin_family = AF_INET; /* set AF_INET family */ d.sin_port = htons(dpi_port); /* set requested port */ d.sin_addr.s_addr = host_addr; /* destination IP addr */ /* network byte order */ rc = connect(fd,(struct sockaddr *)d, /* connect to target */ sizeof(d)); /* based on d sock */ if (rc < 0) exit(1); /* failed, exit */ /* now we have a socket on which to send/receive DPI packets */ RELATED INFORMATION 2.2.8, "The query_DPI_port() Function" on page 28 2.2.3, "The DPIconnect_to_agent_TCP() Function" on page 18 2.2.4, "The DPIconnect_to_agent_UDP() Function" on page 20 Wijnen [Page 27] SNMP-DPI API Version 2.0 January 1994 2.2.8 THE QUERY_DPI_PORT() FUNCTION AUDIENCE DPI sub-agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | long int query_DPI_port( /* Query (GET) SNMP_DPI port */| | char *hostname_p, /* target hostname/IPaddress */| | char *community_p, /* communityname for GET */| | int porttype); /* port type, one of: */| | /* dpiPortForTCP */| | /* dpiPortForUDP */| | | +-------------------------------------------------------------------+ PARAMETER(S) hostname_p A pointer to a NULL terminated character string representing the hostname (or IP address in dot notation) of the host where the DPI capable SNMP agent is running. community_p A pointer to a NULL terminated character string representing the community name that is required to obtain the dpiPort from the SNMP agent via an SNMP GET request. porttype The dpiPort object for a specific port type that you want to obtain. Currently there are two types, one for a TCP port and one for a UDP port. The snmp_dpi.h include file has two #define statements for these DPI port types: #define dpiPortForTCP 1 #define dpiPortForUDP 2 RETURN VALUE If success, then the DPI port number for the specified protocol (TCP or UDP) is returned. If failure, then a value of -1 is returned. DESCRIPTION Wijnen [Page 28] SNMP-DPI API Version 2.0 January 1994 The query_DPI_port function is used to obtain the port number on which the DPI capable SNMP agent at the specified host is listening for connections (TCP) or packets (UDP). The DPI sub-agent programmer only needs to use this function if to code the connection setup and send or await the packet. The programmer then obtains the DPI port number, finds the IP address of the agent with 2.2.7, "The lookup_host() Function" on page 26 and then sets up a socket for communication. This function is implicitly executed by the DPIconnect_to_agent_TCP() and DPIconnect_to_agent_UDP() functions. It is this DPIconnect_to_agent_xxxx() function that the DPI sub-agent programmer would normally use. Wijnen [Page 29] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include #include /* other include files for BSD sockets and such */ int handle; unsigned char *pack_p; long int dpi_port; int fd; struct sockaddr_in s,t; /* source and target */ dpi_port = query_DPI_port("localhost", /* get DPI port number */ "public", /* for TCP, local host */ dpiPortForTCP); if (dpi_port < 0) exit(1); /* error if negative */ host_addr = lookup_host("localhost"); /* find target IP addr */ if (host_addr == 0) exit(1); /* unknown, that's it */ fd = socket(AF_INET,SOCK_STREAM,0); /* create a TCP socket */ if (fd < 0) exit(1); /* failure to do so */ memset(&s,0,sizeof(s)); s.sin_family = AF_INET; /* set AF_INET family */ s.sin_port = 0; /* give us any port, */ s.sin_addr.s_addr = htonl(INADDR_ANY); /* any local IPaddress */ rc = bind(fd,(struct sockaddr *)s, /* bind our socket(fd) */ sizeof(s_sock)); /* defined in s socket */ if (rc < 0) exit(1); /* failure, so exit */ memset(&d,0,sizeof(d)); d.sin_family = AF_INET; /* set AF_INET family */ d.sin_port = htons(dpi_port); /* set requested port */ d.sin_addr.s_addr = host_addr; /* destination IP addr */ /* network byte order */ rc = connect(fd,(struct sockaddr *)d, /* connect to target */ sizeof(d)); /* based on d sock */ if (rc < 0) exit(1); /* failed, exit */ /* now we have a socket on which to send/receive DPI packets */ RELATED INFORMATION 2.2.7, "The lookup_host() Function" on page 26 2.2.3, "The DPIconnect_to_agent_TCP() Function" on page 18 2.2.4, "The DPIconnect_to_agent_UDP() Function" on page 20 Wijnen [Page 30] SNMP-DPI API Version 2.0 January 1994 2.3 BASIC DPI API FUNCTIONS This section contains a description of each DPI function that is available to the DPI sub-agent programmer. It also includes a description of DPI functions that are normally not used by the DPI sub-agent programmer, but rather by the person who implements a DPI capable SNMP agent. Each description contains an AUDIENCE statement so that you can quickly see if it relates to the type of work you are doing. See 2.1.2, "API for Agent Programmer" on page 11 or 2.1.1, "API for Sub-agent Programmer" on page 9 for a specific list of functions and definitions per audience. Wijnen [Page 31] SNMP-DPI API Version 2.0 January 1994 2.3.1 THE DPIDEBUG() FUNCTION AUDIENCE DPI sub-agent programmer. DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | void DPIdebug(int level); | | | +-------------------------------------------------------------------+ PARAMETER(S) level If this value is zero, then tracing is turned off. If it has any other value, then tracing is turned on at the specified level. The higher the value, the more detail. A higher level includes all lower levels of tracing. Currently there are two levels of detail: 1 display packet creation and parsing. 2 display hex dump of incoming and outgoing DPI packets. DESCRIPTION The DPIdebug() function turns DPI internal debugging/tracing on or off. EXAMPLE #include DPIdebug(2); RELATED INFORMATION 2.7, "The snmp_dpi.h Include File" on page 111 Wijnen [Page 32] SNMP-DPI API Version 2.0 January 1994 2.3.2 THE DPI_PACKET_LEN() MACRO AUDIENCE DPI sub-agent programmer. DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | int DPI_PACKET_LEN(unsigned char *packet_p) | | | +-------------------------------------------------------------------+ PARAMETER(S). packet_p A pointer to a (serialized) DPI packet. RETURN VALUE An integer representing the total DPI packet length. DESCRIPTION The DPI_PACKET_LEN macro generates C-code that returns an integer representing the length of a DPI packet. It uses the first two octets (in network byte order) of the packet to calculate the length. EXAMPLE #include unsigned char *pack_p; int length; pack_p = mkDPIclose(SNMP_CLOSE_goingDown); if (pack_p) { length = DPI_PACKET_LEN(pack_p); /* send packet to agent or sub-agent */ } /* endif */ Wijnen [Page 33] SNMP-DPI API Version 2.0 January 1994 2.3.3 THE FDPIPARSE() FUNCTION AUDIENCE DPI sub-agent programmer. DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | void fDPIparse(snmp_dpi_hdr *hdr_p); | | | +-------------------------------------------------------------------+ PARAMETER(S) hdr_p A pointer to the parse tree. The parse tree is represented by an snmp_dpi_hdr structure. DESCRIPTION The fDPIparse() function frees a parse tree that was previously created by a call to pDPIpacket(). The parse tree may have been created in other ways too. After calling fDPIparse(), no further references to the parse tree can be made. You must also realize that a (complete or partial) DPI parse tree is also implicitly freed by call to a DPI function that serializes a parse tree into a DPI packet. The section that describes each function tells you if this is the case. An example of such a function is mkDPIresponse(). EXAMPLE #include snmp_dpi_hdr *hdr_p; unsigned char *pack_p; /* assume pack_p points to */ /* incoming DPI packet */ hdr_p = pDPIpacket(pack_p); /* handle the packet and when done do the following */ if (hdr_p) fDPIparse(hdr_p); RELATED INFORMATION 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.3.19, "The pDPIpacket() Function" on page 75 Wijnen [Page 34] SNMP-DPI API Version 2.0 January 1994 2.7, "The snmp_dpi.h Include File" on page 111 Wijnen [Page 35] SNMP-DPI API Version 2.0 January 1994 2.3.4 THE FDPISET() FUNCTION AUDIENCE DPI sub-agent programmer. DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | void fDPIset(snmp_dpi_set_packet *packet_p); | | | +-------------------------------------------------------------------+ PARAMETER(S) packet_p A pointer to the first snmp_dpi_set_packet structure in a chain of such structures. DESCRIPTION The fDPIset() function is typically used if you must free a chain of one or more snmp_dpi_set_packet structures. This may be the case if you are in the middle of preparing a chain of such structures for a DPI RESPONSE packet, but then run into an error before you can actually make the response. If you get to the point where you make a DPI response packet that you pass the chain of snmp_dpi_set_packet structures to, then the mkDPIresponse() function will free the chain of snmp_dpi_set_packet structures. Wijnen [Page 36] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; snmp_dpi_set_packet *set_p, *first_p; long int num1 = 0, num2 = 0; hdr_p = pDPIpacket(pack_p); /* assume pack_p */ /* analyze packet and assume all OK */ /* points to the */ /* now prepare response; 2 varBinds */ /* incoming packet */ set_p = mkDPIset(snmp_dpi_NULL_p, /* create first one */ "1.3.6.1.2.3.4.5.","1.0", /* OID=1, instance=0 */ SNMP_TYPE_Integer32, sizeof(num1), &num1); if (set_p) { /* if success, then */ first_p = set_p; /* save ptr to first */ set_p = mkDPIset(set_p, /* chain next one */ "1.3.6.1.2.3.4.5.","1.1", /* OID=1, instance=1 */ SNMP_TYPE_Integer32, sizeof(num2), &num2); if (set_p) { /* success 2nd one */ pack_p = mkDPIresponse(hdr_p, /* make response */ SNMP_ERROR_noError, /* It will also free */ 0L, first_p); /* the set_p tree */ /* send DPI response to agent */ } else { /* 2nd mkDPIset fail */ fDPIset(first_p); /* must free chain */ } /* endif */ } /* endif */ RELATED INFORMATION 2.3.3, "The fDPIparse() Function" on page 34 2.4.9, "The snmp_dpi_set_packet structure" on page 94 2.3.15, "The mkDPIresponse() Function" on page 62 Wijnen [Page 37] SNMP-DPI API Version 2.0 January 1994 2.3.5 THE MKDPIAREYOUTHERE() FUNCTION AUDIENCE DPI sub-agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | unsigned char *mkDPIAreYouThere(void); | | | +-------------------------------------------------------------------+ PARAMETER(S) none RETURN VALUE If success, then a pointer to a static DPI packet buffer is returned. The first two bytes of the buffer (in network byte order) contain the length of the remaining packet. The macro DPI_PACKET_LEN can be used to calculate the total length of the DPI packet. If failure, then a NULL pointer is returned. Be aware that the static buffer for the DPI packet is shared by other mkDPIxxxx() function that create a serialized DPI packet. DESCRIPTION The mkDPIAreYouThere() function creates a serialized DPI ARE_YOU_THERE packet that can then be sent to the DPI peer (normally the agent). A sub-agent connected via TCP probably does not need this function, because normally when the agent breaks the "connection" you will receive an EOF on the file descriptor. For unreliable "connections", like over UDP, this function may be useful to periodically poll the agent and verify that it still knows about the sub-agent. If your "connection" to the agent is still healthy, the agent will send a DPI RESPONSE with SNMP_ERROR_DPI_noError in the error code field and zero in the error index field. The RESPONSE will have no varBind data. If your "connection" is not healthy, the agent may Wijnen [Page 38] SNMP-DPI API Version 2.0 January 1994 send a response with an error indication, or may just not send a response at all. EXAMPLE #include unsigned char *pack_p; pack_p = mkDPIAreYouThere(); if (pack_p) { /* send the packet to the agent */ } /* endif */ /* wait for response with DPIawait_packet_from_agent() */ /* normally the response should come back pretty quickly, */ /* but it depends on the load of the agent */ RELATED INFORMATION 2.4.8, "The snmp_dpi_resp_packet structure" on page 92 2.2.1, "The DPIawait_packet_from_agent() Function" on page 14 Wijnen [Page 39] SNMP-DPI API Version 2.0 January 1994 2.3.6 THE MKDPIBULK() FUNCTION AUDIENCE DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | unsigned char *mkDPIbulk( /* Make DPIbulk packet tree*/| | long int non-repeaters, /* count of non-repeaters */| | long int max-repetitions, /* max repetitions */| | snmp_dpi_next_packet *packet_p, /* ptr to chain of NEXTs */| | /* containing the varBinds */| | | +-------------------------------------------------------------------+ PARAMETER(S) non_repeaters The number of varBinds (objects) in the chain of snmp_dpi_next_packet structures for which you only want one next object to be retrieved. max_repetitions The maximum number of next objects that you want for each of the rest of the varBinds in the chain of snmp_dpi_next_packet structures. packet_p A pointer to a chain of snmp_dpi_next_packet structures. You must pass a valid pointer to an existing chain. RETURN VALUE If success, then a pointer to a static DPI packet buffer is returned. The first two bytes of the buffer (in network byte order) contain the length of the remaining packet. The macro DPI_PACKET_LEN can be used to calculate the total length of the DPI packet. If failure, then a NULL pointer is returned. Be aware that the static buffer for the DPI packet is shared by other mkDPIxxxx() function that create a serialized DPI packet. DESCRIPTION The mkDPIbulk() function creates a serialized DPI GETBULK packet that can then be sent to the DPI peer (sub-agent). Wijnen [Page 40] SNMP-DPI API Version 2.0 January 1994 In the following example let us assume that we want to obtain a table in which we expect 20 rows with the objects 1, 2, 3, 4 in each column. We also want to obtain the one other object, that is the counter that represents the number of rows in the table. (Normally the request would have come in via an SNMP PDU, here we just show how to use the mkDPIbulk() function). EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; snmp_dpi_next_packet *first_p, nxt_p; long int num = 0; int i; nxt_p = snmp_dpi_next_packet_NULL_p; first_p = mkDPInext("1.3.6.1.2.3.4.5.", /* sub-tree to look at */ "1", /* 1.0 is entryCount */ SNMP_TYPE_NULL, sizeof(num), &num); if (first_p) { nxt_p = first_p; for (i=1; i<5; i++) { char instance[8]; sprintf(instance, "2.1.%d", i); /* next table object */ nxt_p = mkDPInext(nxt_p, "1.3.6.1.2.3.4.5.", instance, SNMP_TYPE_NULL, sizeof(num), &num); if (nxt_p) continue; /* all ok, iterate for loop */ else if (first_p) { /* failed to mkDPInext */ hdr_p = mkDPIhdr(SNMP_DPI_GETNEXT); /* trick to free*/ if (hdr_p) { /* allocated */ hdr_p->data_u.next_p = first_p; /* memory via */ fDPIparse(hdr_p); /* fDPIparse */ first_p = snmp_dpi_next_packet_NULL_p;/* reset */ hdr_p = snmp_hdr_NULL_p; /* ptrs */ } /* endif */ } /* endfor */ } /* endif */ if (first_p) { pack_p = mkDPIbulk(1,20,first_p); /* make DPI BULK packet */ if (pack_p) /* send packet to sub-agent */ } /* endif */ } /* endif */ RELATED INFORMATION Wijnen [Page 41] SNMP-DPI API Version 2.0 January 1994 2.3.9, "The mkDPIhdr() Function" on page 47 2.3.11, "The mkDPInext() Function" on page 52 2.3.3, "The fDPIparse() Function" on page 34 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.4.4, "The snmp_dpi_next_packet structure" on page 83 2.4.1, "The snmp_dpi_bulk_packet structure" on page 78 Wijnen [Page 42] SNMP-DPI API Version 2.0 January 1994 2.3.7 THE MKDPICLOSE() FUNCTION AUDIENCE DPI sub-agent programmer. DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | unsigned char *mkDPIclose(char reason_code); | | | +-------------------------------------------------------------------+ PARAMETER(S) reason_code The reason for closing the DPI connection. See 2.6.1, "DPI CLOSE Reason Codes" on page 103 for a list of valid reason codes. RETURN VALUE If success, then a pointer to a static DPI packet buffer is returned. The first two bytes of the buffer (in network byte order) contain the length of the remaining packet. The macro DPI_PACKET_LEN can be used to calculate the total length of the DPI packet. If failure, then a NULL pointer is returned. Be aware that the static buffer for the DPI packet is shared by other mkDPIxxxx() function that create a serialized DPI packet. DESCRIPTION The mkDPIclose() function creates a serialized DPI CLOSE packet that can then be sent to the DPI peer. As a result of sending the packet, the DPI connection will be closed. Sending a DPI CLOSE packet to the agent implies an automatic DPI UNREGISTER for all registered sub-trees on the connection being closed. Wijnen [Page 43] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include unsigned char *pack_p; pack_p = mkDPIclose(SNMP_CLOSE_goingDown); if (pack_p) { /* send the packet to the agent */ } /* endif */ RELATED INFORMATION 2.4.2, "The snmp_dpi_close_packet structure" on page 80 2.6.1, "DPI CLOSE Reason Codes" on page 103 Wijnen [Page 44] SNMP-DPI API Version 2.0 January 1994 2.3.8 THE MKDPIGET() FUNCTION AUDIENCE DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | snmp_dpi_get_packet *mkDPIget( /* Make DPI get packet tree */| | snmp_dpi_get_packet *packet_p, /* ptr to GET structure */| | char *group_p, /* ptr to group ID (sub-tree)*/| | char *instance_p); /* ptr to instance OID string*/| | | +-------------------------------------------------------------------+ PARAMETER(S) packet_p A pointer to a chain of snmp_dpi_get_packet structures. Pass a NULL pointer if this is the first structure to be created. group_p A pointer to a NULL terminated character string that represents the registered sub-tree that caused this GET request to be passed to this DPI sub-agent. The sub-tree must have a trailing dot. instance_p A pointer to a NULL terminated character string that represents the rest (the piece following the sub-tree part) of the OBJECT IDENTIFIER of the variable instance being accessed. Use of the term instance_p here should not be confused with an OBJECT instance, because this string may consist of a piece of the OBJECT IDENTIFIER plus the INSTANCE IDENTIFIER. RETURN VALUE If success, and a chain of one or more packets was passed in the packet_p argument, then the same pointer as passed in packet_p is returned. A new dynamically allocated structure has then been added to the end of that chain of snmp_dpi_get_packet structures. If success, and a NULL pointer was passed in the packet_p argument, then a pointer to a new dynamically allocated structure is returned. If failure, then a NULL pointer is returned. Wijnen [Page 45] SNMP-DPI API Version 2.0 January 1994 DESCRIPTION The mkDPIget() function is used at the agent side to prepare a chain of one or more snmp_dpi_get_packet structures. This chain is normally anchored in an snmp_dpi_hdr structure that has its packet_type field set to SNMP_DPI_GET. When all varBinds have been prepared into snmp_dpi_get_packet structures, a call can be made to mkDPIpacket() which will then serialize the DPI parse tree into a DPI packet that can be sent to the DPI peer (normally a sub-agent). EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; hdr_p = mkDPIhdr(SNMP_DPI_GET); if (hdr_p) { hdr_p->data_u.get_p = mkDPIget(snmp_dpi_get_packet_NULL_p, "1.3.6.1.2.3.4.5.", "1.0"); if (hdr_p->data_u.get_p) { pack_p = mkDPIpacket(hdr_p); if (pack_p) { /* send packet to sub-agent */ } /* endif */ } /* endif */ } /* endif */ RELATED INFORMATION 2.3.9, "The mkDPIhdr() Function" on page 47 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.4.3, "The snmp_dpi_get_packet structure" on page 81 Wijnen [Page 46] SNMP-DPI API Version 2.0 January 1994 2.3.9 THE MKDPIHDR() FUNCTION AUDIENCE DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | snmp_dpi_hdr *mkDPIhdr( /* Make DPI hdr for parse tree*/ | | int type); /* packet type; SNMP_DPI_xxxx */ | | | +-------------------------------------------------------------------+ PARAMETER(S) type Specifies what kind of DPI packet will be represented by the parse tree. See 2.6.2, "DPI Packet Types" on page 104 for a list of currently defined DPI packet types RETURN VALUE If success, a pointer to a dynamically allocated snmp_dpi_hdr structure is returned. If failure, then a NULL pointer is returned. DESCRIPTION The mkDPIhdr() function is used at the agent side to prepare any type of DPI parse tree. The parse tree needs to be completed afterwards for the specific DPI packet type. Once that is done, a call to mkDPIpacket will serialize the parse tree into a DPI packet that can be sent to the DPI peer (normally a sub-agent). Wijnen [Page 47] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; hdr_p = mkDPIhdr(SNMP_DPI_GET); if (hdr_p) { hdr_p->data_u.get_p = mkDPIget(snmp_dpi_get_packet_NULL_p, "1.3.6.1.2.3.4.5.", "1.0"); if (hdr_p->data_u.get_p) { pack_p = mkDPIpacket(hdr_p); if (pack_p) { /* send packet to sub-agent */ } /* endif */ } /* endif */ } /* endif */ RELATED INFORMATION 2.3.8, "The mkDPIget() Function" on page 45 2.3.13, "The mkDPIpacket() Function" on page 57 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.4.3, "The snmp_dpi_get_packet structure" on page 81 Wijnen [Page 48] SNMP-DPI API Version 2.0 January 1994 2.3.10 THE MKDPIHDR_VERSION() FUNCTION AUDIENCE DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | snmp_dpi_hdr *mkDPIhdr_version( /* Make a DPI hdr (parse tree)*/| | int type, /* packet type; SNMP_DPI_xxxx */| | char version, /* for this specific version */| | char release); /* for this specific release */| | | +-------------------------------------------------------------------+ PARAMETER(S) type Specifies what kind of DPI packet will be represented by the parse tree. See 2.6.2, "DPI Packet Types" on page 104 for a list of currently defined DPI packet types version DPI version of DPI packet to be created. release DPI release of DPI packet to be created. RETURN VALUE If success, a pointer to a dynamically allocated snmp_dpi_hdr structure is returned. If failure, then a NULL pointer is returned. DESCRIPTION The mkDPIhdr_version() function is used at the agent side to prepare any type of DPI parse tree for a specific DPI version and release. Specifically it is used if you want to support back level DPI sub-agents. In that case you must send DPI packets of a form that was defined for the DPI version and release that the sub-agent is using. The parse tree needs to be completed afterwards for the specific DPI packet type. Once that is done, a call to mkDPIpacket will serialize the parse tree into a DPI packet that can be sent to the DPI peer (normally a sub-agent). Wijnen [Page 49] SNMP-DPI API Version 2.0 January 1994 It is the programmers responsibility to correctly use the version and release specification in such a way that the packets to be created are valid for the specified version and release. For instance, a DPI OPEN is not valid for versions prior to DPI version 2. EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; hdr_p = mkDPIhdr_version(SNMP_DPI_GET, 1, 1); if (hdr_p) { hdr_p->data_u.get_p = mkDPIget(snmp_dpi_get_packet_NULL_p, "1.3.6.1.2.3.4.5.", "1.0"); if (hdr_p->data_u.get_p) { pack_p = mkDPIpacket(hdr_p); if (pack_p) { /* send packet to sub-agent */ } /* endif */ } /* endif */ } /* endif */ Wijnen [Page 50] SNMP-DPI API Version 2.0 January 1994 RELATED INFORMATION 2.3.8, "The mkDPIget() Function" on page 45 2.3.13, "The mkDPIpacket() Function" on page 57 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.4.3, "The snmp_dpi_get_packet structure" on page 81 Wijnen [Page 51] SNMP-DPI API Version 2.0 January 1994 2.3.11 THE MKDPINEXT() FUNCTION AUDIENCE DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | snmp_dpi_next_packet *mkDPInext( /* Make DPI next packet tree */| | snmp_dpi_next_packet *packet_p,/* ptr to NEXT structure */| | char *group_p, /* ptr to group ID (sub-tree)*/| | char *instance_p);/* ptr to instance OID string*/| | | +-------------------------------------------------------------------+ PARAMETER(S) packet_p A pointer to a chain of snmp_dpi_next_packet structures. Pass a NULL pointer if this is the first structure to be created. group_p A pointer to a NULL terminated character string that represents the registered sub-tree that caused this GET request to be passed to this DPI sub-agent. The sub-tree must have a trailing dot. instance_p A pointer to a NULL terminated character string that represents the rest (the piece following the sub-tree part) of the OBJECT IDENTIFIER of the variable instance being accessed. Use of the term instance_p here should not be confused with an OBJECT instance, because this string may consist of a piece of the OBJECT IDENTIFIER plus the INSTANCE IDENTIFIER. RETURN VALUE If success, and a chain of one or more packets was passed in the packet_p argument, then the same pointer as passed in packet_p is returned. A new dynamically allocated structure has then been added to the end of that chain of snmp_dpi_next_packet structures. If success, and a NULL pointer was passed in the packet_p argument, then a pointer to a new dynamically allocated structure is returned. If failure, then a NULL pointer is returned. Wijnen [Page 52] SNMP-DPI API Version 2.0 January 1994 DESCRIPTION The mkDPInext() function is used at the agent side to prepare a chain of one or more snmp_dpi_next_packet structures. This chain is normally anchored in an snmp_dpi_hdr structure that has its packet_type field set to SNMP_DPI_GETNEXT. When all varBinds have been prepared into snmp_dpi_next_packet structures, a call can be made to mkDPIpacket() which will then serialize the DPI parse tree into a DPI packet that can be sent to the DPI peer (normally a sub-agent). EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; hdr_p = mkDPIhdr(SNMP_DPI_GET); if (hdr_p) { hdr_p->data_u.next_p = mkDPInext(snmp_dpi_next_packet_NULL_p, "1.3.6.1.2.3.4.5.", "1.0"); if (hdr_p->data_u.next_p) { pack_p = mkDPIpacket(hdr_p); if (pack_p) { /* send packet to sub-agent */ } /* endif */ } /* endif */ } /* endif */ RELATED INFORMATION 2.3.9, "The mkDPIhdr() Function" on page 47 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.4.4, "The snmp_dpi_next_packet structure" on page 83 Wijnen [Page 53] SNMP-DPI API Version 2.0 January 1994 2.3.12 THE MKDPIOPEN() FUNCTION AUDIENCE DPI sub-agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | unsigned char *mkDPIopen( /* Make a DPI open packet */| | char *oid_p, /* sub-agent Identifier (OID) */| | char *description_p, /* sub-agent descriptive name */| | unsigned long timeout, /* requested default timeout */| | unsigned long max_varBinds, /* max varBinds per DPI ndle */| | char character_set, /* selected character set */| | #define DPI_NATIVE_CSET 0 /* 0 = native character set */| | #define DPI_ASCII_CSET 1 /* 1 = ASCII character set */| | | | unsigned long password_len, /* length of password (if any)*/| | unsigned char *password_p); /* ptr to password (if any) */| | | +-------------------------------------------------------------------+ PARAMETER(S) oid_p A pointer to a NULL terminated character string representing the OBJECT IDENTIFIER which uniquely identifies the sub-agent. description_p A pointer to a NULL terminated character string, which is a descriptive name for the sub-agent. This can be any DisplayString, which basically is an octet string containing only characters from the ASCII NVT set. timeout The requested timeout for this sub-agent. An agent often has a limit for this value and it will use that limit if this value is larger. A timeout of zero has a special meaning in the sense that the agent will then use its own default timeout value. max_varBinds The maximum number of varBinds per DPI packet that the sub-agent is prepared to handle. It must be a positive number greater than zero. If a value greater than 1 is specified, then the agent will try to combine as many varBinds (belonging to the same Wijnen [Page 54] SNMP-DPI API Version 2.0 January 1994 sub-tree) per DPI packet as possible (up to this value). character_set The character set that you want to use for string-based data fields in the DPI packets and structures. The choices are: DPI_NATIVE_CSET specifies that you want to use the native character set of the platform on which the agent that you connect to is running. DPI_ASCII_CSET specifies that you want to use the ASCII character set. The agent will translate between ASCII and the native character set as required. See 2.5, "Character Set Selection" on page 101 for more information on character set selection. password_len The length (in octets) of an optional password. It depends on the agent implementation if a password is needed. If not, then a zero length may be specified. password_p A pointer to an octet string representing the password for this sub-agent. A password may include any character value, including the NULL character. If the password_len is zero, then this can be a NULL pointer. RETURN VALUE If success, then a pointer to a static DPI packet buffer is returned. The first two bytes of the buffer (in network byte order) contain the length of the remaining packet. The macro DPI_PACKET_LEN can be used to calculate the total length of the DPI packet. If failure, then a NULL pointer is returned. Be aware that the static buffer for the DPI packet is shared by other mkDPIxxxx() functions that create a serialized DPI packet. DESCRIPTION The mkDPIopen() function creates a serialized DPI OPEN packet that can then be sent to the DPI peer (a DPI capable SNMP agent). Normally you will want to use the native character set. That makes it the easiest for the sub-agent developer. However, if the agent and sub-agent each run on their own platform and those platforms use different native character sets then you must select the ASCII Wijnen [Page 55] SNMP-DPI API Version 2.0 January 1994 character set, so that you both know exactly how to represent string-based data that is being send back and forth. EXAMPLE #include unsigned char *pack_p; pack_p = mkDPIopen("1.3.6.1.2.3.4.5", "Sample DPI sub-agent" 0L,2L, DPI_NATIVE_CSET, 0,(char *)0); if (pack_p) { /* send packet to the agent */ } /* endif */ RELATED INFORMATION 2.4.6, "The snmp_dpi_open_packet structure" on page 88 2.5, "Character Set Selection" on page 101 Wijnen [Page 56] SNMP-DPI API Version 2.0 January 1994 2.3.13 THE MKDPIPACKET() FUNCTION AUDIENCE DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | unsigned char *mkDPIpacket( /* Make a DPI packet */ | | snmp_dpi_hdr *hdr_p); /* ptr to a parse tree */ | | | +-------------------------------------------------------------------+ PARAMETER(S) hdr_p A pointer to a DPI parse tree. RETURN VALUE If success, then a pointer to a static DPI packet buffer is returned. The first two bytes of the buffer (in network byte order) contain the length of the remaining packet. The macro DPI_PACKET_LEN can be used to calculate the total length of the DPI packet. If failure, then a NULL pointer is returned. Be aware that the static buffer for the DPI packet is shared by other mkDPIxxxx() functions that create a serialized DPI packet. DESCRIPTION The mkDPIpacket() function creates a serialized DPI packet that can then be sent to the DPI peer (normally a sub-agent). Wijnen [Page 57] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; hdr_p = mkDPIhdr(SNMP_DPI_GET); if (hdr_p) { hdr_p->data_u.next_p = mkDPInext(snmp_dpi_next_packet_NULL_p, "1.3.6.1.2.3.4.5.", "1.0"); if (hdr_p->data_u.next_p) { pack_p = mkDPIpacket(hdr_p); if (pack_p) { /* send packet to sub-agent */ } /* endif */ } /* endif */ } /* endif */ RELATED INFORMATION 2.3.9, "The mkDPIhdr() Function" on page 47 2.3.11, "The mkDPInext() Function" on page 52 2.4.4, "The snmp_dpi_next_packet structure" on page 83 2.4.5, "The snmp_dpi_hdr structure" on page 85 Wijnen [Page 58] SNMP-DPI API Version 2.0 January 1994 2.3.14 THE MKDPIREGISTER() FUNCTION AUDIENCE DPI sub-agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | unsigned char *mkDPIregister( /* Make a DPI register packet */| | unsigned short timeout, /* in seconds (16-bit) */| | long int priority, /* requested priority */| | char *group_p, /* ptr to group ID (sub-tree) */| | char bulk_select);/* Bulk selection (GETBULK) */| | #define DPI_BULK_NO 0 /* map GETBULK into GETNEXTs */| | #define DPI_BULK_YES 1 /* pass GETBULK to sub-agent */| | | +-------------------------------------------------------------------+ PARAMETER(S) timeout The requested timeout in seconds. An agent often has a limit for this value and it will use that limit if this value is larger. The value zero has special meaning in the sense that it tells the agent to use the timeout value that was specified in the DPI OPEN packet. priority The requested priority. This field may contain any of these values: -1 Requests the best available priority. 0 Requests a better priority than the highest priority currently registered. Use this value to obtain the SNMP DPI version 1 behavior. nnn Any other positive value. You will receive that priority if available, otherwise the next best priority that is available. group_p A pointer to a NULL terminated character string that represents the sub-tree to be registered. This group ID must have a trailing dot. bulk_select Specifies if you want the agent to pass GETBULK on to the sub-agent or to map them into multiple GETNEXT requests. The choices are: Wijnen [Page 59] SNMP-DPI API Version 2.0 January 1994 DPI_BULK_NO Do not pass any GETBULK requests, but instead map a GETBULK request into multiple GETNEXT requests. DPI_BULK_YES Do pass a GETBULK request to the sub-agent. RETURN VALUE If success, then a pointer to a static DPI packet buffer is returned. The first two bytes of the buffer (in network byte order) contain the length of the remaining packet. The macro DPI_PACKET_LEN can be used to calculate the total length of the DPI packet. If failure, then a NULL pointer is returned. Be aware that the static buffer for the DPI packet is shared by other mkDPIxxxx() functions that create a serialized DPI packet. DESCRIPTION The mkDPIregister() function creates a serialized DPI REGISTER packet that can then be sent to the DPI peer (a DPI capable SNMP agent). The bulk_selection can be used to ask the agent to map an SNMP GETBULK request into multiple GETNEXT requests. This makes it easier for the DPI sub-agent programmer because GETBULK processing doesn't need implementing. At the other hand, if one expects that a single GETBULK might improve the performance a lot then one can tell the agent to pass such requests. This might be the case if one expects a GETBULK to arrive (often) for a table for which one needs to do a kernel dive. Using GETBULK one might be able to do just one dive instead of many (although one could anticipate the dive with a GETNEXT also and so obtain and cache the table upon the first GETNEXT request). Be aware that according to the DPI 2.0 RFC, not all agents need to support DPI_BULK_YES; they will return an appropriate error code in the DPI RESPONSE though if such is the case. Normally the SNMP agent sends a DPI RESPONSE packet back, which details if the register was successful or not. Wijnen [Page 60] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include unsigned char *pack_p; pack_p = mkDPIregister(0,0L,"1.3.6.1.2.3.4.5." DPI_BULK_NO); if (pack_p) { /* send packet to agent and await response */ } /* endif */ RELATED INFORMATION 2.4.7, "The snmp_dpi_reg_packet structure" on page 90 2.4.8, "The snmp_dpi_resp_packet structure" on page 92 Wijnen [Page 61] SNMP-DPI API Version 2.0 January 1994 2.3.15 THE MKDPIRESPONSE() FUNCTION AUDIENCE DPI sub-agent programmer. DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | unsigned char *mkDPIresponse( /* Make a DPI response packet*/| | snmp_dpi_hdr *hdr_p, /* ptr to packet to respnd to*/| | long int error_code, /* error code: SNMP_ERROR_xxx*/| | long int error_index, /* index to varBind in error */| | snmp_dpi_set_packet *packet_p);/* ptr to varBinds, a chain */| | /* of dpi_set_packets */| | | +-------------------------------------------------------------------+ PARAMETER(S) hdr_p A pointer to the parse tree of the DPI request to which this DPI packet will be the response. The function uses this parse tree to copy the packet_id and the DPI version and release, so that the DPI packet is correctly formatted as a response. error_code The error code. See 2.6.3, "DPI RESPONSE Error Codes" on page 105 for a list of valid codes. error_index Specifies the first varBind in error. Counting starts at 1 for the first varBind. This field should be zero if there is no error. packet_p A pointer to a chain of snmp_dpi_set_packet structures. This partial parse tree will be freed by the mkDPIresponse() function. So upon return you cannot reference it anymore. Pass a NULL pointer if there are no varBinds to be returned. RETURN VALUE If success, then a pointer to a static DPI packet buffer is returned. The first two bytes of the buffer (in network byte order) contain the length of the remaining packet. The macro Wijnen [Page 62] SNMP-DPI API Version 2.0 January 1994 DPI_PACKET_LEN can be used to calculate the total length of the DPI packet. If failure, then a NULL pointer is returned. Be aware that the static buffer for the DPI packet is shared by other mkDPIxxxx() functions that create a serialized DPI packet. DESCRIPTION The mkDPIresponse() function is used at the sub-agent side to prepare a DPI RESPONSE packet to a GET, GETNEXT, GETBULK, SET, COMMIT or UNDO request. The resulting packet can be sent to the DPI peer (normally a DPI capable SNMP agent). EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; snmp_dpi_set_packet *set_p; long int num; hdr_p = pDPIpacket(pack_p); /* parse incoming packet */ /* assume it's in pack_p */ if (hdr_p) { /* analyze packet, assume GET, no error */ set_p = mkDPIset(snmp_dpi_set_packet_NULL_p, "1.3.6.1.2.3.4.5.", "1.0", SNMP_TYPE_Integer32, sizeof(num), &num); if (set_p) { pack_p = mkDPIresponse(hdr_p, SNMP_ERROR_noError, 0L, set_p); if (pack_p) { /* send packet to sub-agent */ } /* endif */ } /* endif */ } /* endif */ The mkDPIresponse() function is used at the agent side to prepare a DPI RESPONSE packet to an OPEN, REGISTER or UNREGISTER request. In the case of a RESPONSE to a REGISTER request and if there is no error, then the actually assigned priority must be passed in the error_index argument. The resulting packet can be sent to the DPI peer (normally a sub-agent). Wijnen [Page 63] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; long int priority; hdr_p = pDPIpacket(pack_p); /* parse incoming packet */ /* assume it's in pack_p */ if (hdr_p) { /* analyze packet, assume REGISTER and OK */ pack_p = mkDPIresponse(hdr_p, SNMP_ERROR_DPI_noError, priority, snmp_dpi_set_packet_NULL_p); if (pack_p) { /* send packet to sub-agent */ } /* endif */ } /* endif */ RELATED INFORMATION 2.3.9, "The mkDPIhdr() Function" on page 47 2.3.19, "The pDPIpacket() Function" on page 75 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.4.4, "The snmp_dpi_next_packet structure" on page 83 Wijnen [Page 64] SNMP-DPI API Version 2.0 January 1994 2.3.16 THE MKDPISET() FUNCTION AUDIENCE DPI sub-agent programmer. DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | snmp_dpi_set_packet *mkDPIset( /* Make DPI set packet tree */| | snmp_dpi_set_packet *packet_p, /* ptr to SET structure */| | char *group_p, /* ptr to group ID(sub-tree)*/| | char *instance_p,/* ptr to instance OIDstring*/| | int value_type,/* value type: SNMP_TYPE_xxx*/| | int value_len, /* length of value */| | void *value_p); /* ptr to value */| | | +-------------------------------------------------------------------+ PARAMETER(S) packet_p A pointer to a chain of snmp_dpi_set_packet structures. Pass a NULL pointer if this is the first structure to be created. group_p A pointer to a NULL terminated character string that represents the registered sub-tree that caused this GET request to be passed to this DPI sub-agent. The sub-tree must have a trailing dot. instance_p A pointer to a NULL terminated character string that represents the rest (the piece following the sub-tree part) of the OBJECT IDENTIFIER of the variable instance being accessed. Use of the term instance_p here should not be confused with an OBJECT instance, because this string may consist of a piece of the OBJECT IDENTIFIER plus the INSTANCE IDENTIFIER. value_type The type of the value. See 2.6.5, "DPI SNMP Value Types" on page 108 for a list of currently defined value types. value_len This is an unsigned 16-bit integer that specifies the length (in octets) of the value pointed to by the value field. The length may be zero if the value if of type SNMP_TYPE_NULL. Wijnen [Page 65] SNMP-DPI API Version 2.0 January 1994 value_p A pointer to the actual value. This field may contain a NULL pointer if the value is of (implicit or explicit) type SNMP_TYPE_NULL. RETURN VALUE If success, and a chain of one or more packets was passed in the packet_p argument, then the same pointer as passed in packet_p is returned. A new dynamically allocated structure has then been added to the end of that chain of snmp_dpi_get_packet structures. If success, and a NULL pointer was passed in the packet_p argument, then a pointer to a new dynamically allocated structure is returned. If failure, then a NULL pointer is returned. DESCRIPTION The mkDPIset() function is used at the sub-agent side to prepare a chain of one or more snmp_dpi_set_packet structures. This chain is then later used to create a DPI RESPONSE packet by a call to mkDPIresponse() which can then be sent to the DPI peer (normally a DPI capable SNMP agent). The chain of snmp_dpi_set_packet structures can also be used to create a DPI TRAP packet that includes varBinds as explained in 2.3.17, "The mkDPItrap() Function" on page 71. Wijnen [Page 66] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; snmp_dpi_set_packet *set_p; long int num; hdr_p = pDPIpacket(pack_p) /* parse incoming packet */ /* assume it's in pack_p */ if (hdr_p) { /* analyze packet, assume GET, no error */ set_p = mkDPIset(snmp_dpi_set_packet_NULL_p, "1.3.6.1.2.3.4.5.", "1.0", SNMP_TYPE_Integer32, sizeof(num), &num); if (set_p) { pack_p = mkDPIresponse(hdr_p, SNMP_ERROR_noError, 0L, set_p); if (pack_p) /* send packet to sub-agent */ } /* endif */ } /* endif */ } /* endif */ The mkDPIset() function is used at the agent side to prepare a chain of one or more snmp_dpi_set_packet structures. This chain is normally anchored in an snmp_dpi_hdr structure that has its packet_type field set to SNMP_DPI_SET, SNMP_DPI_COMMIT or SNMP_DPI_UNDO. When all varBinds have been prepared into snmp_dpi_set_packet structures, a call can be made to mkDPIpacket() which will then serialize the DPI parse tree into a DPI packet that can be sent to the DPI peer (normally a sub-agent). Wijnen [Page 67] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; long int num; hdr_p = mkDPIhdr(SNMP_DPI_SET); if (hdr_p) { hdr_p->data_u.set_p = mkDPIset(snmp_dpi_set_packet_NULL_p, "1.3.6.1.2.3.4.5.", "1.0", SNMP_TYPE_Integer32, sizeof(num), &num); if (hdr_p->data_u.set_p) { pack_p = mkDPIpacket(hdr_p); if (pack_p) /* send packet to sub-agent */ } /* endif */ } /* endif */ } /* endif */ If you must chain many snmp_dpi_set_packet structures, you should realize that the packets are chained only by forward pointers. So it might be wise to use the last structure in the existing chain as the pack_p argument. Then, the underlying code does not have to scan through a possibly long chain of structures in order to chain the new structure at the end. In the next example let's assume we want to chain 20 snmp_dpi_set_packet structures as a response to a GETBULK. Wijnen [Page 68] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; snmp_dpi_set_packet *first_p; snmp_dpi_set_packet *set_p; long int num[20]; int i; hdr_p = pDPIpacket(pack_p); /* parse incoming packet */ /* assume it's in pack_p */ if (hdr_p) { /* analyze packet, assume GETBULK, no error. In this */ /* example we do not check max_repetitions as we should */ set_p = snmp_dpi_set_packet_NULL_p; first_p = snmp_dpi_set_packet_NULL_p; for (i=0; i<20; i++) { char instance[5]; sprintf(instance, "%1.%d", i+1); set_p = mkDPIset(set_p, "1.3.6.1.2.3.4.5.", instance, SNMP_TYPE_Integer32, sizeof(num), &num[i]); if (set_p) { if (first_p) continue; /* OK, iterate for loop */ first_p = set_p; /* remember first one */ } else if (first_p) { /* failed to mkDPIset */ fDPIset(first_p) /* free allocated memory */ first_p = snmp_dpi_set_packet_NULL_p; /* reset */ } /* endif */ } /* endfor */ if (first_p) { pack_p = mkDPIresponse(hdr_p, SNMP_ERROR_noError, 0L, first_p); if (pack_p) /* send packet to sub-agent */ } /* endif */ } /* endif */ } /* endif */ RELATED INFORMATION 2.3.9, "The mkDPIhdr() Function" on page 47 2.3.19, "The pDPIpacket() Function" on page 75 2.3.15, "The mkDPIresponse() Function" on page 62 2.3.17, "The mkDPItrap() Function" on page 71 2.4.5, "The snmp_dpi_hdr structure" on page 85 Wijnen [Page 69] SNMP-DPI API Version 2.0 January 1994 2.4.9, "The snmp_dpi_set_packet structure" on page 94 2.6.5, "DPI SNMP Value Types" on page 108 2.6.6, "Value Representation" on page 109 Wijnen [Page 70] SNMP-DPI API Version 2.0 January 1994 2.3.17 THE MKDPITRAP() FUNCTION AUDIENCE DPI sub-agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | unsigned char *mkDPItrap( /* Make a DPI trap packet */| | long int generic, /* generic traptype (32 bit)*/| | long int specific, /* specific traptype (32 bit)*/| | snmp_dpi_set_packet *packet_p, /* ptr to varBinds, a chain */| | /* of dpi_set_packets */| | char *enterprise_p); /* ptr to enterprise OID */| | | +-------------------------------------------------------------------+ PARAMETER(S) generic The generic trap type. The range of this value is 0-6, where 6 (enterpriseSpecific) is the type that is probably used most by DPI sub-agent programmers. The values 0-5 are well defined standard SNMP traps. specific The (enterprise) specific trap type. This can be any value that is valid for the MIB sub-trees that the sub-agent implements. packet_p A pointer to a chain of snmp_dpi_set_structures, representing the varBinds to be passed with the trap. This partial parse tree will freed by the mkDPItrap() function so you cannot reference it anymore upon completion of the call. A NULL pointer means that there are no varBinds to be included in the trap. enterprise_p A pointer to a NULL terminated character string representing the enterprise ID (OBJECT IDENTIFIER) for which this trap is defined. A NULL pointer can be used. In this case, the sub-agent Identifier as passed in the DPI OPEN packet will be used when the agent receives the DPI TRAP packet. RETURN VALUE If success, then a pointer to a static DPI packet buffer is returned. The first two bytes of the buffer (in network byte Wijnen [Page 71] SNMP-DPI API Version 2.0 January 1994 order) contain the length of the remaining packet. The macro DPI_PACKET_LEN can be used to calculate the total length of the DPI packet. If failure, then a NULL pointer is returned. Be aware that the static buffer for the DPI packet is shared by other mkDPIxxxx() functions that create a serialized DPI packet. DESCRIPTION The mkDPItrap() function is used at the sub-agent side to prepare a DPI TRAP packet. The resulting packet can be sent to the DPI peer (normally a DPI capable SNMP agent). EXAMPLE #include unsigned char *pack_p; snmp_dpi_set_packet *set_p; long int num; set_p = mkDPIset(snmp_dpi_set_packet_NULL_p, "1.3.6.1.2.3.4.5.", "1.0", SNMP_TYPE_Integer32, sizeof(num), &num); if (set_p) { pack_p = mkDPItrap(6,1,set_p, (char *)0); if (pack_p) { /* send packet to sub-agent */ } /* endif */ } /* endif */ RELATED INFORMATION 2.3.17, "The mkDPItrap() Function" on page 71 2.4.10, "The snmp_dpi_trap_packet structure" on page 96 Wijnen [Page 72] SNMP-DPI API Version 2.0 January 1994 2.3.18 THE MKDPIUNREGISTER() FUNCTION AUDIENCE DPI sub-agent programmer. DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | unsigned char *mkDPIunregister( /* Make DPI unregister packet */| | char reason_code; /* unregister reason code */| | char *group_p); /* ptr to group ID (sub-tree) */| | | +-------------------------------------------------------------------+ PARAMETER(S) reason_code The reason for the unregister. See 2.6.4, "DPI UNREGISTER Reason Codes" on page 107 for a list of the currently defined reason codes. group_p A pointer to a NULL terminated character string that represents the sub-tree to be unregistered. The sub-tree must have a trailing dot. RETURN VALUE If success, then a pointer to a static DPI packet buffer is returned. The first two bytes of the buffer (in network byte order) contain the length of the remaining packet. The macro DPI_PACKET_LEN can be used to calculate the total length of the DPI packet. If failure, then a NULL pointer is returned. Be aware that the static buffer for the DPI packet is shared by other mkDPIxxxx() functions that create a serialized DPI packet. DESCRIPTION The mkDPIunregister() function creates a serialized DPI UNREGISTER packet that can then be sent to the DPI peer (a DPI capable SNMP agent or sub-agent). Normally the SNMP peer then sends a DPI RESPONSE packet back, which details if the unregister was successful or not. Wijnen [Page 73] SNMP-DPI API Version 2.0 January 1994 EXAMPLE #include unsigned char *pack_p; pack_p = mkDPIunregister( SNMP_UNREGISTER_goingDown, "1.3.6.1.2.3.4.5."); if (pack_p) { /* send packet to agent or sub-agent and await response */ } /* endif */ RELATED INFORMATION 2.4.11, "The snmp_dpi_ureg_packet structure" on page 98 Wijnen [Page 74] SNMP-DPI API Version 2.0 January 1994 2.3.19 THE PDPIPACKET() FUNCTION AUDIENCE DPI sub-agent programmer. DPI agent programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | | snmp_dpi_hdr *pDPIpacket(unsigned char *packet_p); | | | +-------------------------------------------------------------------+ PARAMETER(S). packet_p A pointer to a (serialized) DPI packet. RETURN VALUE If success, a pointer to a DPI parse tree (snmp_dpi_hdr) is returned. Memory for the parse tree has been dynamically allocated, and it is the callers responsibility to free it when no longer needed. You can use the fDPIparse() function to free the parse tree. If failure, a NULL pointer is returned. DESCRIPTION The pDPIpacket() function parses the buffer pointed to by the packet_p argument. It ensures that the buffer contains a valid DPI packet and that the packet is for a DPI version and release that is supported by the DPI functions in use. EXAMPLE #include unsigned char *pack_p; snmp_dpi_hdr *hdr_p; hdr_p = pDPIpacket(pack_p); /* parse incoming packet */ /* assume it's in pack_p */ if (hdr_p) { /* analyze packet, and handle it */ } Wijnen [Page 75] SNMP-DPI API Version 2.0 January 1994 RELATED INFORMATION 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.7, "The snmp_dpi.h Include File" on page 111 2.3.3, "The fDPIparse() Function" on page 34 Wijnen [Page 76] SNMP-DPI API Version 2.0 January 1994 2.4 DPI STRUCTURES This section contains a description of each structure that is used in the SNMP DPI API. It also includes structures that are normally not used by the DPI sub-agent programmer, but rather by the person who implements a DPI capable SNMP agent. Each description of structure clearly states the intended audience. Wijnen [Page 77] SNMP-DPI API Version 2.0 January 1994 2.4.1 THE SNMP_DPI_BULK_PACKET STRUCTURE AUDIENCE DPI sub-agent programmer. DPI agent programmer. STRUCTURE DEFINITION +-------------------------------------------------------------------+ | | | struct dpi_bulk_packet { | | long int non_repeaters; /* count of non-repeaters*/| | long int max_repetitions; /* max repeaters */| | struct dpi_next_packet *varBind_p; /* ptr to varBinds, chain*/| | /* of dpi_next_packets */| | }; | | typedef struct dpi_bulk_packet snmp_dpi_bulk_packet; | | #define snmp_dpi_bulk_packet_NULL_p ((snmp_dpi_bulk_packet *)0)| | | +-------------------------------------------------------------------+ STRUCTURE MEMBERS non_repeaters The number of varBinds in the chain of dpi_next_packet structures that are to be treated as a single GETNEXT. max_repetitions The max number of repetitions for the remaining set of varBinds in dpi_next_packet structures treated as a single GETNEXT. varBind_p The pointer to the first varBind in the chain of dpi_next_packet structures. DESCRIPTION The snmp_dpi_bulk_packet structure represents a parse tree for a DPI GETBULK packet. At the sub-agent side, the snmp_dpi_bulk_packet structure is normally created as a result of a call to pDPIpacket(). This is the case if the DPI packet is of type SNMP_DPI_GETBULK. The snmp_dpi_hdr structure then contains a pointer to an snmp_dpi_bulk_packet structure, which in turn has a pointer to a chain of one or more snmp_dpi_next_packet structures. The DPI sub-agent programmer uses this structure to find out which variables instances are to be returned in a DPI RESPONSE. Wijnen [Page 78] SNMP-DPI API Version 2.0 January 1994 At the agent side, this structure is normally created with a call to the mkDPIbulk() function. The programmer here normally does not inspect the structure itself. RELATED INFORMATION 2.3.19, "The pDPIpacket() Function" on page 75 2.3.6, "The mkDPIbulk() Function" on page 40 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.4.4, "The snmp_dpi_next_packet structure" on page 83 Wijnen [Page 79] SNMP-DPI API Version 2.0 January 1994 2.4.2 THE SNMP_DPI_CLOSE_PACKET STRUCTURE AUDIENCE DPI sub-agent programmer. DPI agent programmer. STRUCTURE DEFINITION +-------------------------------------------------------------------+ | | | struct dpi_close_packet { | | char reason_code; /* reason for closing */| | }; | | typedef struct dpi_close_packet snmp_dpi_close_packet; | | #define snmp_dpi_close_packet_NULL_p ((snmp_dpi_close_packet*)0)| | | +-------------------------------------------------------------------+ STRUCTURE MEMBERS reason_code The reason for the close. See 2.6.1, "DPI CLOSE Reason Codes" on page 103 for a list of valid reason codes. DESCRIPTION The snmp_dpi_close_packet structure represents a parse tree for a DPI CLOSE packet. The snmp_dpi_close_packet structure may be created as a result of a call to pDPIpacket(). This is the case if the DPI packet is of type SNMP_DPI_CLOSE. The snmp_dpi_hdr structure then contains a pointer to a snmp_dpi_close_packet structure. An snmp_dpi_close_packet_structure is also created as a result of a mkDPIclose() call, but then the programmer never sees the structure since mkDPIclose() immediately creates a serialized DPI packet from it and then frees the structure. It is recommended that DPI programmer (both at the agent and at the sub-agent side) uses mkDPIclose() to create a DPI CLOSE packet. RELATED INFORMATION 2.3.19, "The pDPIpacket() Function" on page 75 2.3.7, "The mkDPIclose() Function" on page 43 2.4.5, "The snmp_dpi_hdr structure" on page 85 Wijnen [Page 80] SNMP-DPI API Version 2.0 January 1994 2.4.3 THE SNMP_DPI_GET_PACKET STRUCTURE AUDIENCE DPI sub-agent programmer. DPI agent programmer. STRUCTURE DEFINITION +-------------------------------------------------------------------+ | | | struct dpi_get_packet { | | char *object_p; /* ptr to OID string */| | char *group_p; /* ptr to sub-tree(group)*/| | 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) | | | +-------------------------------------------------------------------+ STRUCTURE MEMBERS object_p A pointer to a NULL terminated character string that represents the full OBJECT IDENTIFIER of the variable instance that is being accessed. It basically is a concatenation of the fields group_p and instance_p. Using this field is not recommended because it is only included for DPI version 1 compatibility and it maybe withdrawn in a later version. group_p A pointer to a NULL terminated character string that represents the registered sub-tree that caused this GET request to be passed to this DPI sub-agent. The sub-tree must have a trailing dot. instance_p A pointer to a NULL terminated character string that represents the rest (the piece following the sub-tree part) of the OBJECT IDENTIFIER of the variable instance being accessed. Use of the term instance_p here should not be confused with an OBJECT instance, because this string may consist of a piece of the OBJECT IDENTIFIER plus the INSTANCE IDENTIFIER. next_p A pointer to a possible next snmp_dpi_get_packet structure. If this next field contains the NULL ptr, then this is the end of the chain. DESCRIPTION Wijnen [Page 81] SNMP-DPI API Version 2.0 January 1994 The snmp_dpi_get_packet structure represents a parse tree for a DPI GET packet. At the sub-agent side, the snmp_dpi_get_packet structure is normally created as a result of a call to pDPIpacket(). This is the case if the DPI packet is of type SNMP_DPI_GET. The snmp_dpi_hdr structure then contains a pointer to a chain of one or more snmp_dpi_get_packet structures. The DPI sub-agent programmer uses this structure to find out which variables instances are to be returned in a DPI RESPONSE. At the agent side, this structure is normally created with a call to the mkDPIget() function. The programmer here normally does not inspect the structure itself. RELATED INFORMATION 2.3.19, "The pDPIpacket() Function" on page 75 2.3.8, "The mkDPIget() Function" on page 45 2.4.5, "The snmp_dpi_hdr structure" on page 85 Wijnen [Page 82] SNMP-DPI API Version 2.0 January 1994 2.4.4 THE SNMP_DPI_NEXT_PACKET STRUCTURE AUDIENCE DPI sub-agent programmer. DPI agent programmer. STRUCTURE DEFINITION +-------------------------------------------------------------------+ | | | struct dpi_next_packet { | | char *object_p; /* ptr to OID (string) */| | char *group_p; /* ptr to sub-tree(group)*/| | 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)| | | +-------------------------------------------------------------------+ STRUCTURE MEMBERS object_p A pointer to a NULL terminated character string that represents the full OBJECT IDENTIFIER of the variable instance that is being accessed. It basically is a concatenation of the fields group_p and instance_p. Using this field is not recommended because it is only included for DPI version 1 compatibility and it maybe withdrawn in a later version. group_p A pointer to a NULL terminated character string that represents the registered sub-tree that caused this GETNEXT request to be passed to this DPI sub-agent. This sub-tree must have a trailing dot. instance_p A pointer to a NULL terminated character string that represents the rest (the piece following the sub-tree part) of the OBJECT IDENTIFIER of the variable instance being accessed. Use of the term instance_p here should not be confused with an OBJECT instance, because this string may consist of a piece of the OBJECT IDENTIFIER plus the INSTANCE IDENTIFIER. In this case of GETNEXT, the instance_p may be the NULL pointer which means that the request is for the first variable instance in the registered sub-tree. Wijnen [Page 83] SNMP-DPI API Version 2.0 January 1994 next_p A pointer to a possible next snmp_dpi_get_packet structure. If this next field contains the NULL ptr, then this is the end of the chain. DESCRIPTION The snmp_dpi_next_packet structure represents a parse tree for a DPI GETNEXT packet. At the sub-agent side, the snmp_dpi_next_packet structure is normally created as a result of a call to pDPIpacket(). This is the case if the DPI packet is of type SNMP_DPI_GETNEXT. The snmp_dpi_hdr structure then contains a pointer to a chain of one or more snmp_dpi_next_packet structures. The DPI sub-agent programmer uses this structure to find out which variables instances are to be returned in a DPI RESPONSE. At the agent side, this structure is normally created with a call to the mkDPInext() function. The programmer here normally does not inspect the structure itself. RELATED INFORMATION 2.3.19, "The pDPIpacket() Function" on page 75 2.3.11, "The mkDPInext() Function" on page 52 2.4.5, "The snmp_dpi_hdr structure" on page 85 Wijnen [Page 84] SNMP-DPI API Version 2.0 January 1994 2.4.5 THE SNMP_DPI_HDR STRUCTURE AUDIENCE DPI sub-agent programmer. DPI agent programmer. STRUCTURE DEFINITION +-------------------------------------------------------------------+ | | | struct snmp_dpi_hdr { | | unsigned char proto_major; /* always 2: SNMP_DPI_PROTOCOL*/| | unsigned char proto_version; /* DPI version */| | unsigned char proto_release; /* DPI release */| | unsigned short packet_id; /* 16-bit, DPI packet ID */| | unsigned char packet_type; /* DPI packet type */| | union { | | snmp_dpi_reg_packet *reg_p; | | snmp_dpi_ureg_packet *ureg_p; | | snmp_dpi_get_packet *get_p; | | snmp_dpi_next_packet *next_p; | | snmp_dpi_next_packet *bulk_p; | | snmp_dpi_set_packet *set_p; | | snmp_dpi_resp_packet *resp_p; | | snmp_dpi_trap_packet *trap_p; | | snmp_dpi_open_packet *open_p; | | snmp_dpi_close_packet *close_p; | | unsigned char *any_p; | | } data_u; | | }; | | typedef struct snmp_dpi_hdr snmp_dpi_hdr; | | #define snmp_dpi_hdr_NULL_p ((snmp_dpi_hdr *)0) | | | +-------------------------------------------------------------------+ STRUCTURE MEMBERS proto_major This defines the major protocol, and for SNMP DPI it is always 2. proto_version This defines the DPI version. proto_release This defines the DPI release. packet_id This field contains the packet ID of the DPI packet. When you create a response to a request, the packet ID must be the same as that of the request. This is taken care of if you use the mkDPIresponse() function. Wijnen [Page 85] SNMP-DPI API Version 2.0 January 1994 packet_type Specifies what kind of DPI packet (parse tree) we are dealing with. See 2.6.2, "DPI Packet Types" on page 104 for a list of currently defined DPI packet types data_u This is a union of pointers to the different types of data structures that are created based on the packet_type field. The pointers themselves have names that are self_explanatory. The fields proto_major, proto_version, proto_release and packet_id are basically for DPI internal use. So the DPI programmer normally needs not be concerned about them. If you work with an unreliable DPI "connection" (like UDP), then you may want to use the packet_id field to ensure you are handling the correct packet. DESCRIPTION The snmp_dpi_hdr structure is the anchor of a DPI parse tree. At the sub-agent side, the snmp_dpi_hdr structure is normally created as a result of a call to pDPIpacket(). The DPI sub-agent programmer uses this structure to interrogate packets. Depending on the packet_type, the pointer to the chain of one or more packet_type specific structures that contain the actual packet data can be picked. At the agent side, for creating an out-going packet, this structure is normally created with a call to the mkDPIhdr() or the mkDPIhdr_version() function. After that the structure is completed by setting a proper pointer to the a chain of one ore more packet type specific data structures. At the agent side, for an incoming packet, this structure is normally created with a Depending on the packet_type, you can pick up the pointer to the chain of one or more packet_type specific structures that contain the actual packet data. In the case of an incoming SNMP DPI ARE_YOU_THERE packet, there is just the snmp_dpi_hdr without any packet specific data. The storage for a DPI parse tree is always dynamically allocated and it is then the callers responsibility to free this parse tree when it is no longer needed. You can use the fDPIparse() function to do that. Be aware that some mkDPIxxxx functions do free the parse tree that is passed to them. An example is the mkDPIpacket() function. RELATED INFORMATION Wijnen [Page 86] SNMP-DPI API Version 2.0 January 1994 2.3.19, "The pDPIpacket() Function" on page 75 2.3.3, "The fDPIparse() Function" on page 34 2.3.9, "The mkDPIhdr() Function" on page 47 2.3.10, "The mkDPIhdr_version() Function" on page 49 2.4.2, "The snmp_dpi_close_packet structure" on page 80 2.4.3, "The snmp_dpi_get_packet structure" on page 81 2.4.4, "The snmp_dpi_next_packet structure" on page 83 2.4.1, "The snmp_dpi_bulk_packet structure" on page 78 2.4.6, "The snmp_dpi_open_packet structure" on page 88 2.4.7, "The snmp_dpi_reg_packet structure" on page 90 2.4.8, "The snmp_dpi_resp_packet structure" on page 92 2.4.9, "The snmp_dpi_set_packet structure" on page 94 2.4.10, "The snmp_dpi_trap_packet structure" on page 96 2.4.11, "The snmp_dpi_ureg_packet structure" on page 98 Wijnen [Page 87] SNMP-DPI API Version 2.0 January 1994 2.4.6 THE SNMP_DPI_OPEN_PACKET STRUCTURE AUDIENCE DPI agent programmer. STRUCTURE DEFINITION +-------------------------------------------------------------------+ | | | struct dpi_open_packet { | | char *oid_p; /* sub-agent ID, OID string */| | char *description_p; /* sub-agent descriptive name*/| | unsigned short timeout; /* requested timeout,seconds */| | unsigned short max_varBinds; /* max varBinds I can handle */| | char character_set; /* character set selection */| | unsigned short password_len; /* length of password */| | unsigned char *password_p; /* ptr to password itself */| | }; | | typedef struct dpi_open_packet snmp_dpi_open_packet; | | #define snmp_dpi_open_packet_NULL_p ((snmp_dpi_open_packet *)0) | | | +-------------------------------------------------------------------+ STRUCTURE MEMBERS oid_p A pointer to a NULL terminated character string representing the OBJECT IDENTIFIER which uniquely identifies the sub-agent. description_p A pointer to a NULL terminated character string which is a descriptive name for the sub-agent. This can be any DisplayString, which basically is an octet string containing only characters from the ASCII NVT set. timeout The requested timeout for this sub-agent. An agent often has a limit for this value and it will use that limit if this value is larger. max_varBinds The maximum number of varBinds per DPI packet that the sub-agent is prepared to handle. It must be a positive number greater than zero. If a value greater than 1 is specified, then the agent will try to combine as many varBinds (belonging to the same sub-tree) per DPI packet as possible (up to this value). character_set The selected character set for string based data: Wijnen [Page 88] SNMP-DPI API Version 2.0 January 1994 DPI_NATIVE_CSET specifies that you want to use the native character set of the platform on which the agent that you connect to is running. DPI_ASCII_CSET specifies that you want to use the ASCII character set. The agent will translate between ASCII and the native character set as required. See 2.5, "Character Set Selection" on page 101 for more information on character set selection. password_len The length (in octets) of an optional password. It depends on the agent implementation if a password is needed. If not, then a zero length may be specified. password_p A pointer to an octet string representing the password for this sub-agent. A password may include any character value, including the NULL character. If the password_len is zero, then this can be a NULL pointer. DESCRIPTION The snmp_dpi_open_packet structure represents a parse tree for a DPI OPEN packet. The snmp_dpi_open_packet structure is normally created as a result of a call to pDPIpacket(). This is the case if the DPI packet is of type SNMP_DPI_OPEN. The snmp_dpi_hdr structure then contains a pointer to a snmp_dpi_open_packet structure. Normally this will only happen at the agent side. So the DPI sub-agent programmer need not be concerned with this structure. The mkDPIopen() function can be used to create a DPI OPEN packet. RELATED INFORMATION 2.3.19, "The pDPIpacket() Function" on page 75 2.3.3, "The fDPIparse() Function" on page 34 2.3.12, "The mkDPIopen() Function" on page 54 2.5, "Character Set Selection" on page 101 2.4.5, "The snmp_dpi_hdr structure" on page 85 Wijnen [Page 89] SNMP-DPI API Version 2.0 January 1994 2.4.7 THE SNMP_DPI_REG_PACKET STRUCTURE AUDIENCE DPI agent programmer. STRUCTURE DEFINITION +-------------------------------------------------------------------+ | | | struct dpi_reg_packet { | | unsigned short timeout; /* requested timout; seconds*/| | long int priority;/* requested priority */| | char *group_p; /* ptr to sub-tree (group) */| | struct dpi_reg_packet *next_p; /* ptr to next in chain */| | char bulk; /* GETBULK selection yes/no */| | }; | | typedef struct dpi_reg_packet snmp_dpi_reg_packet; | | #define snmp_dpi_reg_packet_NULL_p ((snmp_dpi_reg_packet *)0) | | | +-------------------------------------------------------------------+ STRUCTURE MEMBERS timeout The requested timeout in seconds. An agent often has a limit for this value and it will use that limit if this value is larger. priority The requested priority. This field may contain any of these values: -1 Requests the best available priority. 0 Requests a better priority than the highest priority currently registered. Use this value to obtain the SNMP DPI version 1 behavior. nnn Any other positive value. You will receive that priority if available or the next best priority that is available. group_p A pointer to a NULL terminated character string that represents the sub-tree to be registered. This sub-tree must have a trailing dot. next_p A pointer to a possible next snmp_dpi_reg_packet structure. If this next field contains the NULL ptr, then this is the end of the chain. Currently, we do not support multiple registrations in one DPI packet, so this field should always be zero. Wijnen [Page 90] SNMP-DPI API Version 2.0 January 1994 bulk The GETBULK selection. The field may contain one of these values: DPI_BULK_NO Do not pass any GETBULK requests; instead map a GETBULK request into multiple GETNEXT requests. DPI_BULK_YES Do pass a GETBULK request to the sub-agent. DESCRIPTION The snmp_dpi_reg_packet structure represents a parse tree for a DPI REGISTER packet. The snmp_dpi_reg_packet structure is normally created as a result of a call to pDPIpacket(). This is the case if the DPI packet is of type SNMP_DPI_REGISTER. The snmp_dpi_hdr structure then contains a pointer to a snmp_dpi_reg_packet structure. Normally, this will only happen at the agent side, so the DPI sub-agent programmer need not be concerned with this structure. To create a DPI REGISTER pactket, the programmer is advised to use the mkDPIregister() function. RELATED INFORMATION 2.3.19, "The pDPIpacket() Function" on page 75 2.3.14, "The mkDPIregister() Function" on page 59 2.5, "Character Set Selection" on page 101 2.4.5, "The snmp_dpi_hdr structure" on page 85 Wijnen [Page 91] SNMP-DPI API Version 2.0 January 1994 2.4.8 THE SNMP_DPI_RESP_PACKET STRUCTURE AUDIENCE DPI sub-agent programmer. DPI agent programmer. STRUCTURE DEFINITION +-------------------------------------------------------------------+ | | | struct dpi_resp_packet { | | char error_code; /* like: SNMP_ERROR_xxx */| | unsigned long int error_index;/* 1st varBind in error */| | #define resp_priority error_index /* if respons to register*/| | struct dpi_set_packet *varBind_p; /* ptr to varBind, chain */| | /* of dpi_set_packets */| | }; | | typedef struct dpi_resp_packet snmp_dpi_resp_packet; | | #define snmp_dpi_resp_packet_NULL_p ((snmp_dpi_resp_packet *)0)| | | +-------------------------------------------------------------------+ STRUCTURE MEMBERS error_code The return code or the error code. See 2.6.3, "DPI RESPONSE Error Codes" on page 105 for a list of valid codes. error_index Specifies the first varBind is in error. Counting starts at 1 for the first varBind. This field should be zero (SNMP_ERROR_noError) if there is no error. resp_priority This is a redefinition of the error_index field. If the response it to a DPI REGISTER request and the error_code is equal to SNMP_ERROR_DPI_noError, then this field contains the priority that was actually assigned. varBind_p A pointer to the a chain of one ore more snmp_dpi_set_structures, representing varBinds of the response. This field contains a NULL pointer if there are no varBinds in the response. DESCRIPTION The snmp_dpi_resp_packet structure represents a parse tree for a DPI RESPONSE packet. Wijnen [Page 92] SNMP-DPI API Version 2.0 January 1994 The snmp_dpi_resp_packet structure is normally created as a result of a call to pDPIpacket(). This is the case if the DPI packet is of type SNMP_DPI_RESPONSE. The snmp_dpi_hdr structure then contains a pointer to a snmp_dpi_resp_packet structure. Most of the time this only happens at the agent side. At the DPI sub-agent side, a DPI RESPONSE should only be expected at initialization and termination time when the sub-agent has issued a DPI OPEN, DPI REGISTER or DPI UNREGISTER request. The DPI programmer is advised to use the mkDPIresponse() function to prepare a DPI RESPONSE packet. RELATED INFORMATION 2.3.19, "The pDPIpacket() Function" on page 75 2.3.15, "The mkDPIresponse() Function" on page 62 2.4.9, "The snmp_dpi_set_packet structure" on page 94 2.4.5, "The snmp_dpi_hdr structure" on page 85 Wijnen [Page 93] SNMP-DPI API Version 2.0 January 1994 2.4.9 THE SNMP_DPI_SET_PACKET STRUCTURE AUDIENCE DPI sub-agent programmer. DPI agent programmer. STRUCTURE DEFINITION +-------------------------------------------------------------------+ | | | struct dpi_set_packet { | | char *object_p; /* ptr to Object ID (string) */| | char *group_p; /* ptr to sub-tree (group) */| | char *instance_p; /* ptr to rest of OID */| | unsigned char value_type; /* value type: SNMP_TYPE_xxx */| | unsigned short value_len; /* value length */| | char *value_p; /* ptr to the 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) | | | +-------------------------------------------------------------------+ STRUCTURE MEMBERS object_p A pointer to a NULL terminated character string that represents the full OBJECT IDENTIFIER of the variable instance that is being accessed. It basically is a concatenation of the fields group_p and instance_p. Using this field is not recommended because it is only included for DPI version 1 compatibility and it maybe withdrawn in a later version. group_p A pointer to a NULL terminated character string that represents the registered sub-tree that caused this SET, COMMIT or UNDO request to be passed to this DPI sub-agent. The sub-tree must have a trailing dot. instance_p A pointer to a NULL terminated character string that represents the rest (the piece following the sub-tree part) of the OBJECT IDENTIFIER of the variable instance being accessed. Use of the term instance_p here should not be confused with an OBJECT instance because this string may consist of a piece of the OBJECT IDENTIFIER plus the INSTANCE IDENTIFIER. Wijnen [Page 94] SNMP-DPI API Version 2.0 January 1994 value_type The type of the value. See 2.6.5, "DPI SNMP Value Types" on page 108 for a list of currently defined value types. value_len This is an unsigned 16-bit integer that specifies the length (in octets) of the value pointed to by the value field. The length may be zero if the value if of type SNMP_TYPE_NULL. value_p A pointer to the actual value. This field may contain a NULL pointer if the value if of type SNMP_TYPE_NULL. See 2.6.6, "Value Representation" on page 109 for information on how the data is represented for the various value types. next_p A pointer to a possible next snmp_dpi_set_packet structure. If this next field contains the NULL pointer, then this is the end of the chain. DESCRIPTION The snmp_dpi_set_packet structure represents a parse tree for a DPI SET request. The snmp_dpi_set_packet structure may be created as a result of a call to pDPIpacket(). This is the case if the DPI packet is of type SNMP_DPI_SET, SNMP_DPI_COMMIT or SNMP_DPI_UNDO. The snmp_dpi_hdr structure then contains a pointer to a chain of one ore more snmp_dpi_set_packet structures. This structure can also be created with a mkDPIset() call, which is typically used when preparing varBinds for a DPI RESPONSE packet. RELATED INFORMATION 2.3.19, "The pDPIpacket() Function" on page 75 2.3.16, "The mkDPIset() Function" on page 65 2.6.5, "DPI SNMP Value Types" on page 108 2.6.6, "Value Representation" on page 109 2.4.5, "The snmp_dpi_hdr structure" on page 85 Wijnen [Page 95] SNMP-DPI API Version 2.0 January 1994 2.4.10 THE SNMP_DPI_TRAP_PACKET STRUCTURE AUDIENCE DPI agent programmer. STRUCTURE DEFINITION +-------------------------------------------------------------------+ | | | struct dpi_trap_packet { | | long int generic; /* generic trap type */| | long int specific; /* specific trap type */| | struct dpi_set_packet *varBind_p; /* ptr to varBind chain */| | char *enterprise_p;/* ptr to enterpriseID */| | }; | | typedef struct dpi_trap_packet snmp_dpi_trap_packet; | | #define snmp_dpi_trap_packet_NULL_p ((snmp_dpi_trap_packet *)0)| | | +-------------------------------------------------------------------+ STRUCTURE MEMBERS generic The generic trap type. The range of this value is 0-6, where 6 (enterpriseSpecific) is the type that is probably used most by DPI sub-agent programmers. The values 0-5 are well defined standard SNMP traps. specific The (enterprise) specific trap type. This can be any value that is valid for the MIB sub-trees that the sub-agent implements. varBind_p A pointer to a chain of one or more snmp_dpi_set_packet structures, representing the varBind(s) to be included in the trap. A NULL pointer means that there are no varBinds included in the trap. enterprise_p A pointer to a NULL terminated character string representing the enterprise ID (OBJECT IDENTIFIER) for which this trap is defined. A NULL pointer can be used. In this case, the sub-agent Identifier as passed in the DPI OPEN packet will be used when the agent receives this packet. DESCRIPTION The snmp_dpi_trap_packet structure represents a parse tree for a DPI TRAP packet. Wijnen [Page 96] SNMP-DPI API Version 2.0 January 1994 At the agent side, the snmp_dpi_trap_packet structure is normally created as a result of a call to pDPIpacket(). This is the case if the DPI packet is of type SNMP_DPI_TRAP. The snmp_dpi_hdr structure then contains a pointer to a snmp_dpi_trap_packet structure. The DPI sub-agent programmer should not be concerned with this structure. A programmer is advised to prepare a DPI TRAP packet using the mkDPItrap() function. In that case the structure isn't seen. RELATED INFORMATION 2.3.19, "The pDPIpacket() Function" on page 75 2.3.17, "The mkDPItrap() Function" on page 71 2.4.9, "The snmp_dpi_set_packet structure" on page 94 2.4.5, "The snmp_dpi_hdr structure" on page 85 Wijnen [Page 97] SNMP-DPI API Version 2.0 January 1994 2.4.11 THE SNMP_DPI_UREG_PACKET STRUCTURE AUDIENCE DPI sub-agent programmer. DPI agent programmer. STRUCTURE DEFINITION +-------------------------------------------------------------------+ | | | struct dpi_ureg_packet { | | char reason_code;/* reason for unregister */| | char *group_p; /* ptr to sub-tree(group)*/| | struct dpi_reg_packet *next_p; /* ptr to next in chain */| | }; | | typedef struct dpi_ureg_packet snmp_dpi_ureg_packet; | | #define snmp_dpi_ureg_packet_NULL_p ((snmp_dpi_ureg_packet *)0)| | | +-------------------------------------------------------------------+ STRUCTURE MEMBERS reason_code The reason for the unregister. See 2.6.4, "DPI UNREGISTER Reason Codes" on page 107 for a list of the currently defined reason codes. group_p A pointer to a NULL terminated character string that represents the sub-tree to be unregistered. This sub-tree must have a trailing dot. next_p A pointer to a possible next snmp_dpi_ureg_packet structure. If this next field contains the NULL ptr, then this is the end of the chain. Currently we do not support multiple unregister requests in one DPI packet, so this field should always be zero. DESCRIPTION The snmp_dpi_ureg_packet structure represents a parse tree for a DPI UNREGISTER request. The snmp_dpi_ureg_packet structure is normally created as a result of a call to pDPIpacket(). This is the case if the DPI packet is of type SNMP_DPI_UNREGISTER. The snmp_dpi_hdr structure then contains a pointer to a snmp_dpi_ureg_packet structure. The DPI programmer is advised to use the mkDPIunregister() function to create a DPI UNREGISTER packet. Wijnen [Page 98] SNMP-DPI API Version 2.0 January 1994 RELATED INFORMATION 2.3.19, "The pDPIpacket() Function" on page 75 2.3.18, "The mkDPIunregister() Function" on page 73 2.4.5, "The snmp_dpi_hdr structure" on page 85 Wijnen [Page 99] SNMP-DPI API Version 2.0 January 1994 2.4.12 THE SNMP_DPI_U64 STRUCTURE AUDIENCE DPI sub-agent programmer. DPI agent programmer. STRUCTURE DEFINITION +-------------------------------------------------------------------+ | | | struct snmp_dpi_u64 { /* for unsigned 64-bit int */ | | unsigned long high; /* - high order 32 bits */ | | unsigned long low; /* - low order 32 bits */ | | }; | | typedef struct snmp_dpi_u64 snmp_dpi_u64; | | | +-------------------------------------------------------------------+ STRUCTURE MEMBERS high The high order (most significant) 32 bits low The low order (least significant) 32 bits DESCRIPTION The snmp_dpi_u64 structure represents an unsigned 64-bit integer as need for values with a type of SNMP_TYPE_Counter64. The snmp_dpi_u64 structure may be created as a result of a call to pDPIpacket(). This is the case if the DPI packet is of type SNMP_DPI_SET and one of the values has a type of SNMP_TYPE_Counter64. The value_p pointer of the snmp_dpi_set_packet structure will then point to an snmp_dpi_u64 structure. The DPI programmer must also use an snmp_dpi_u64 structure as the argument to a mkDPIset() call if he wants to create a value of type SNMP_TYPE_Counter64. RELATED INFORMATION 2.3.19, "The pDPIpacket() Function" on page 75 2.4.9, "The snmp_dpi_set_packet structure" on page 94 2.6.5, "DPI SNMP Value Types" on page 108 2.6.6, "Value Representation" on page 109 Wijnen [Page 100] SNMP-DPI API Version 2.0 January 1994 2.5 CHARACTER SET SELECTION AUDIENCE DPI sub-agent programmer. DPI agent programmer. Base on the character set used on the platform where agent and sub-agent are running, there are basically three scenarios that you may be faced with: 1. Both run on an ASCII based platform. In reality a lot of platforms use the ASCII character set, and for those platforms, the character set selection is kind of a moot point. Just use the native character set in that case, which is then ASCII anyway. 2. The both run on the same non-ASCII based platform. It is expected that the agent and the sub-agent normally run on the same machine or at least on the same platform. In that case, it is easiest to use the native character set for data that is represented as strings. If such native character set is not the ASCII character set, then the agent must translate from ASCII to the native character set (and vice versa) as needed. 3. One runs on ASCII based platform, the other on a non-ASCII based platform. If the agent and sub-agent each run on their own platform and those platforms use different native character sets (like IBM PS/2 OS/2 uses ASCII and IBM Mainframe MVS uses EBCDIC) then you must select the ASCII character set, so that you both know exactly how to represent string-based data that is being send back and forth. The entity that is not ASCII based must do the translation from ASCII to the native character set (and vice versa) as needed. When the DPI sub-agent sends a DPI OPEN packet, it must specify the character set it wants to use. The sub-agent here needs to know or figure out in an implementation dependent manner if the agent is running on a system with the same character set as the sub-agent (if you connect to the agent loopback or localhost, you might assume that you are using the same character set). The sub-agent has two choices: Wijnen [Page 101] SNMP-DPI API Version 2.0 January 1994 DPI_NATIVE_CSET specifies that you want to use the native character set of the platform on which the agent that you connect to is running. DPI_ASCII_CSET specifies that you want to use the ASCII character set. The agent will translate between ASCII and the native character set as required. If the sub-agent is on a non-ASCII based platform, it may have to translate also. The DPI packets have a number of fields that are represented as strings. The fields that will/must be represented in the selected character set are: o The null terminated string pointed to by the description_p, enterprise_p, group_p, instance_p, and oid_p arguments in the various mkDPIxxxx(...) functions. o The string pointed to by the value_p argument in the mkDPIset(...) function, that is if the value_type argument specifies that the value is a SNMP_TYPE_DisplayString or a SNMP_TYPE_OBJECT_IDENTIFIER. o The null terminated string pointed to by the description_p, enterprise_p, group_p, instance_p, and oid_p pointers in the various snmp_dpi_xxxx_packet structures. o The string pointed to by the value_P pointer in the snmp_dpi_set_packet structure, that is if the value_type field specifies that the value is a SNMP_TYPE_DisplayString or a SNMP_TYPE_OBJECT_IDENTIFIER. RELATED INFORMATION 2.3.12, "The mkDPIopen() Function" on page 54 2.4.6, "The snmp_dpi_open_packet structure" on page 88 Wijnen [Page 102] SNMP-DPI API Version 2.0 January 1994 2.6 CONSTANTS AND VALUES This section describes all the constants and names for values as they are defined in the snmp_dpi.h include file. 2.6.1 DPI CLOSE REASON CODES AUDIENCE DPI sub-agent programmer. DPI agent programmer. These are the currently defined DPI CLOSE reason codes as defined in the snmp_dpi.h include file: #define SNMP_CLOSE_otherReason 1 #define SNMP_CLOSE_goingDown 2 #define SNMP_CLOSE_unsupportedVersion 3 #define SNMP_CLOSE_protocolError 4 #define SNMP_CLOSE_authenticationFailure 5 #define SNMP_CLOSE_byManager 6 #define SNMP_CLOSE_timeout 7 #define SNMP_CLOSE_openError 8 These codes are used in the reason_code argument for the mkDPIclose() function and in the reason_code field in the snmp_dpi_close_packet structure. RELATED INFORMATION 2.4.2, "The snmp_dpi_close_packet structure" on page 80 2.3.7, "The mkDPIclose() Function" on page 43 Wijnen [Page 103] SNMP-DPI API Version 2.0 January 1994 2.6.2 DPI PACKET TYPES AUDIENCE DPI sub-agent programmer. DPI agent programmer. These are the currently defined DPI packet types as defined in the snmp_dpi.h include file: #define SNMP_DPI_GET 1 #define SNMP_DPI_GET_NEXT 2 /* old DPI 1.x style */ #define SNMP_DPI_GETNEXT 2 #define SNMP_DPI_SET 3 #define SNMP_DPI_TRAP 4 #define SNMP_DPI_RESPONSE 5 #define SNMP_DPI_REGISTER 6 #define SNMP_DPI_UNREGISTER 7 #define SNMP_DPI_OPEN 8 #define SNMP_DPI_CLOSE 9 #define SNMP_DPI_COMMIT 10 #define SNMP_DPI_UNDO 11 #define SNMP_DPI_GETBULK 12 #define SNMP_DPI_TRAPV2 13 /* reserved, not .... */ #define SNMP_DPI_INFORM 14 /* reserved, implemented */ #define SNMP_DPI_ARE_YOU_THERE 15 These packet types are used in the type argument for the mkDPIhdr() function and in the packet_type field in the snmp_dpi_hdr structure. RELATED INFORMATION 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.3.9, "The mkDPIhdr() Function" on page 47 Wijnen [Page 104] SNMP-DPI API Version 2.0 January 1994 2.6.3 DPI RESPONSE ERROR CODES AUDIENCE DPI sub-agent programmer. DPI agent programmer. In case of an error on an SNMP request like GET, GETNEXT, GETBULK, SET, COMMIT, UNDO the RESPONSE can have one of these currently defined error codes. They are define in the snmp_dpi.h include file: #define SNMP_ERROR_noError 0 #define SNMP_ERROR_tooBig 1 #define SNMP_ERROR_noSuchName 2 #define SNMP_ERROR_badValue 3 #define SNMP_ERROR_readOnly 4 #define SNMP_ERROR_genErr 5 #define SNMP_ERROR_noAccess 6 #define SNMP_ERROR_wrongType 7 #define SNMP_ERROR_wrongLength 8 #define SNMP_ERROR_wrongEncoding 9 #define SNMP_ERROR_wrongValue 10 #define SNMP_ERROR_noCreation 11 #define SNMP_ERROR_inconsistentValue 12 #define SNMP_ERROR_resourceUnavailable 13 #define SNMP_ERROR_commitFailed 14 #define SNMP_ERROR_undoFailed 15 #define SNMP_ERROR_authorizationError 16 #define SNMP_ERROR_notWritable 17 #define SNMP_ERROR_inconsistentName 18 In case of an error on a DPI only request (OPEN, REGISTER, UNREGISTER, ARE_YOU_THERE) the RESPONSE can have one of these currently defined error codes. They are define in the snmp_dpi.h include file: #define SNMP_ERROR_DPI_noError 0 #define SNMP_ERROR_DPI_otherError 101 #define SNMP_ERROR_DPI_notFound 102 #define SNMP_ERROR_DPI_alreadyRegistered 103 #define SNMP_ERROR_DPI_higherPriorityRegistered 104 #define SNMP_ERROR_DPI_mustOpenFirst 105 #define SNMP_ERROR_DPI_notAuthorized 106 #define SNMP_ERROR_DPI_viewSelectionNotSupported 107 #define SNMP_ERROR_DPI_getBulkSelectionNotSupported 108 #define SNMP_ERROR_DPI_duplicateSubAgentIdentifier 109 #define SNMP_ERROR_DPI_invalidDisplayString 110 #define SNMP_ERROR_DPI_characterSetSelectionNotSupported 111 Wijnen [Page 105] SNMP-DPI API Version 2.0 January 1994 These codes are used in the error_code argument for the mkDPIresponse() function and in the error_code field in the snmp_dpi_resp_packet structure. RELATED INFORMATION 2.4.8, "The snmp_dpi_resp_packet structure" on page 92 2.3.15, "The mkDPIresponse() Function" on page 62 Wijnen [Page 106] SNMP-DPI API Version 2.0 January 1994 2.6.4 DPI UNREGISTER REASON CODES AUDIENCE DPI sub-agent programmer. DPI agent programmer. These are the currently defined DPI UNREGISTER reason codes. They are define in the snmp_dpi.h include file: #define SNMP_UNREGISTER_otherReason 1 #define SNMP_UNREGISTER_goingDown 2 #define SNMP_UNREGISTER_justUnregister 3 #define SNMP_UNREGISTER_newRegistration 4 #define SNMP_UNREGISTER_higherPriorityRegistered 5 #define SNMP_UNREGISTER_byManager 6 #define SNMP_UNREGISTER_timeout 7 These codes are used in the reason_code argument for the mkDPIunregister() function and in the reason_code field in the snmp_dpi_ureg_packet structure. RELATED INFORMATION 2.4.11, "The snmp_dpi_ureg_packet structure" on page 98 2.3.18, "The mkDPIunregister() Function" on page 73 Wijnen [Page 107] SNMP-DPI API Version 2.0 January 1994 2.6.5 DPI SNMP VALUE TYPES AUDIENCE DPI sub-agent programmer. DPI agent programmer. These are the currently defined value types as as defined in the snmp_dpi.h include file: #define SNMP_TYPE_MASK 0x7f /* mask to isolate type*/ #define SNMP_TYPE_Integer32 (128|1) /* 32-bit INTEGER */ #define SNMP_TYPE_OCTET_STRING 2 /* OCTET STRING */ #define SNMP_TYPE_OBJECT_IDENTIFIER 3 /* OBJECT IDENTIFIER */ #define SNMP_TYPE_NULL 4 /* NULL, no value */ #define SNMP_TYPE_IpAddress 5 /* IMPLICIT OCTETSTRING*/ #define SNMP_TYPE_Counter32 (128|6) /* 32-bit Counter */ #define SNMP_TYPE_Gauge32 (128|7) /* 32-bit Gauge */ #define SNMP_TYPE_TimeTicks (128|8) /* 32-bit TimeTicks in */ /* hundredths of a sec */ #define SNMP_TYPE_DisplayString 9 /* DisplayString (TC) */ #define SNMP_TYPE_BIT_STRING 10 /* BIT STRING */ #define SNMP_TYPE_NsapAddress 11 /* IMPLICIT OCTETSTRING*/ #define SNMP_TYPE_UInteger32 (128|12)/* 32-bit INTEGER */ #define SNMP_TYPE_Counter64 13 /* 64-bit Counter */ #define SNMP_TYPE_Opaque 14 /* IMPLICIT OCTETSTRING*/ #define SNMP_TYPE_noSuchObject 15 /* IMPLICIT NULL */ #define SNMP_TYPE_noSuchInstance 16 /* IMPLICIT NULL */ #define SNMP_TYPE_endOfMibView 17 /* IMPLICIT NULL */ These value types are used in the value_type argument for the mkDPIset() function and in the value_type field in the snmp_dpi_set_packet structure. RELATED INFORMATION 2.4.9, "The snmp_dpi_set_packet structure" on page 94 2.3.16, "The mkDPIset() Function" on page 65 2.6.6, "Value Representation" on page 109 Wijnen [Page 108] SNMP-DPI API Version 2.0 January 1994 2.6.6 VALUE REPRESENTATION Values in the snmp_dpi_set_packet structure are represented as follows: o 32-bit integers are defined as long int or unsigned long int (we assume that a long int is 4 bytes). o 64-bit integers are represented as an snmp_dpi_u64 (so-far we only deal with unsigned 64 bit integers in SNMP) structure that has two fields, the high order piece and the low order piece, each of type unsigned long int (we assume these are 4-bytes). o Object Identifiers are NULL terminated strings in the selected character set, representing the OID in ASN.1 dotted notation. The length includes the terminating NULL. Example ASCII: '312e332e362e312e322e312e312e312e3000'h represents "1.3.6.1.2.1.1.1.0" which is sysDescr.0. Example EBCDIC: 'f14bf34bf64bf14bf24bf14bf14bf14bf000'h represents "1.3.6.1.2.1.1.1.0" which is sysDescr.0. o DisplayStrings are in the selected character set. The length specifies the length of the string. Example ASCII: '6162630d0a'h represents "abc\r\n", no NULL. Example EBCDIC: '8182830d25'h represents "abc\r\n", no NULL. o IpAddress, NsapAddress and Opaque are implicit OCTET_STRING, so they are a sequence of octets/bytes. This means for instance that the IP address is in network byte order. o NULL has a zero length for the value, no value data, so a NULL pointer in the value_p field. o noSuchObject, noSuchInstance and endOfMibView are implicit NULL and represented as such. o BIT_STRING is an OCTET_STRING of the form uubbbb...bb, where the first octet (uu) is 0x00-0x07 and indicates the number of unused bits in the last octet (bb). The bb octets represent the bit string itself, where bit zero (0) comes first and so on. Wijnen [Page 109] SNMP-DPI API Version 2.0 January 1994 2.6.7 RETURN CODES FROM DPI TRANSPORT RELATED FUNCTIONS AUDIENCE DPI sub-agent programmer. These are the currently defined values for the return codes from DPI transport related functions. They are defined in the snmp_dpi.h include file: #define DPI_RC_OK 0 /* all OK, no error */ #define DPI_RC_NOK -1 /* some other error */ #define DPI_RC_NO_PORT -2 /* can't figure out DPIport */ #define DPI_RC_NO_CONNECTION -3 /* no connection to DPIagent*/ #define DPI_RC_EOF -4 /* EOF receivd on connection*/ #define DPI_RC_IO_ERROR -5 /* Some I/O error on connect*/ #define DPI_RC_INVALID_HANDLE -6 /* unknown/invalid handle */ #define DPI_RC_TIMEOUT -7 /* timeout occurred */ #define DPI_RC_PACKET_TOO_LARGE -8 /* packed too large, dropped*/ These values are used as return codes for the transport related DPI functions. RELATED INFORMATION 2.2.3, "The DPIconnect_to_agent_TCP() Function" on page 18 2.2.4, "The DPIconnect_to_agent_UDP() Function" on page 20 2.2.2, "The DPIconnect_to_agent_NMQ() Function" on page 16 2.2.1, "The DPIawait_packet_from_agent() Function" on page 14 2.2.6, "The DPIsend_packet_to_agent() Function" on page 24 Wijnen [Page 110] SNMP-DPI API Version 2.0 January 1994 2.7 THE SNMP_DPI.H INCLUDE FILE AUDIENCE DPI sub-agent programmer. DPI agent programmer. The snmp_dpi.h include file defines the SNMP DPI API to the DPI programmer. SYNTAX +-------------------------------------------------------------------+ | | | #include | | | +-------------------------------------------------------------------+ PARAMETER(S) None DESCRIPTION The snmp_dpi.h include file defines the SNMP DPI API to the DPI programmer. It has all the function proto-type statements, and it also has the definitions for the snmp_dpi structures. RELATED INFORMATION Macros, functions, structures, constants and values defined in the snmp_dpi.h include file: 2.2.1, "The DPIawait_packet_from_agent() Function" on page 14 2.2.3, "The DPIconnect_to_agent_TCP() Function" on page 18 2.2.4, "The DPIconnect_to_agent_UDP() Function" on page 20 2.2.2, "The DPIconnect_to_agent_NMQ() Function" on page 16 2.3.1, "The DPIdebug() Function" on page 32 2.2.5, "The DPIdisconnect_from_agent() Function" on page 22 2.3.2, "The DPI_PACKET_LEN() macro" on page 33 2.2.6, "The DPIsend_packet_to_agent() Function" on page 24 2.3.3, "The fDPIparse() Function" on page 34 2.3.4, "The fDPIset() Function" on page 36 2.3.5, "The mkDPIAreYouThere() Function" on page 38 2.3.7, "The mkDPIclose() Function" on page 43 2.3.8, "The mkDPIget() Function" on page 45 2.3.9, "The mkDPIhdr() Function" on page 47 2.3.10, "The mkDPIhdr_version() Function" on page 49 2.3.11, "The mkDPInext() Function" on page 52 2.3.12, "The mkDPIopen() Function" on page 54 Wijnen [Page 111] SNMP-DPI API Version 2.0 January 1994 2.3.6, "The mkDPIbulk() Function" on page 40 2.3.13, "The mkDPIpacket() Function" on page 57 2.3.14, "The mkDPIregister() Function" on page 59 2.3.15, "The mkDPIresponse() Function" on page 62 2.3.16, "The mkDPIset() Function" on page 65 2.3.17, "The mkDPItrap() Function" on page 71 2.3.18, "The mkDPIunregister() Function" on page 73 2.3.19, "The pDPIpacket() Function" on page 75 2.4.2, "The snmp_dpi_close_packet structure" on page 80 2.4.3, "The snmp_dpi_get_packet structure" on page 81 2.4.4, "The snmp_dpi_next_packet structure" on page 83 2.4.1, "The snmp_dpi_bulk_packet structure" on page 78 2.4.5, "The snmp_dpi_hdr structure" on page 85 2.2.7, "The lookup_host() Function" on page 26 2.4.6, "The snmp_dpi_open_packet structure" on page 88 2.2.8, "The query_DPI_port() Function" on page 28 2.4.7, "The snmp_dpi_reg_packet structure" on page 90 2.4.8, "The snmp_dpi_resp_packet structure" on page 92 2.4.9, "The snmp_dpi_set_packet structure" on page 94 2.4.10, "The snmp_dpi_trap_packet structure" on page 96 2.4.11, "The snmp_dpi_ureg_packet structure" on page 98 2.6.1, "DPI CLOSE Reason Codes" on page 103 2.6.2, "DPI Packet Types" on page 104 2.6.3, "DPI RESPONSE Error Codes" on page 105 2.6.4, "DPI UNREGISTER Reason Codes" on page 107 2.6.5, "DPI SNMP Value Types" on page 108 2.5, "Character Set Selection" on page 101 Wijnen [Page 112] SNMP-DPI API Version 2.0 January 1994 3.0 SNMP DPI 1.1 API The DPI API for SNMP DPI version 1.1 is reasonably well documented (at least for the sub-agent programmer) in the latest Programmers Reference manuals for the IBM TCP/IP products for OS/2, VM and MVS. You can keep your existing DPI 1.1 sub-agent and communicate with a DPI capable agent that supports DPI 1.1 in addition to DPI 2.0. For example, the IBM Research new Platform Independent SNMP stack provides support for multiple versions of DPI, namely version 1.0, version 1.1 and version 2.0. Normally you would compile your DPI 1.1 sub-agent with the DPI 1.1 snmp_dpi.h include file and link-edit it with the provided DPILIB at the DPI 1.1 level. You can continue to do this until you are ready to migrate to DPI version 2.0. You can also compile your DPI API 1.1 based sub-agents with the new include files and then link them with the new object files. You do this by requesting DPI version 1.1 compatibility via a few -D compiler flags. What happens in this case is that the DPI 1.1 functions are mapped onto the DPI 2.0 function via a set of macro definitions, which are defined in the snmp_dpi1.h include file. This include file is automatically include if you ask for DPI 1.1 compatibility. However, a number of field names in the snmp_dpi_xxxx_packet structures have changed so that the names are now more consistent throughout the DPI code. The new names also comply with POSIX such that you can see from the name if the value is a pointer or a union. The names that have changed and that affect the sub-agent code are listed in Table 1 on page 114. There is no clean approach to make this change transparent, you probably will have to change the names in your code. You may want to try a simple set of defines like: #define packet_body data_u #define dpi_get get_p #define dpi_set set_p #define dpi_next next_p #define dpi_response resp_p #define dpi_trap trap_p #define group_id group_p #define object_id object_p #define value value_p #define type value_type #define next next_p #define enterprise enterprise_p But they may conflict with other definitions that you have, in which case you must change your code. Wijnen [Page 113] SNMP-DPI API Version 2.0 January 1994 +-----------------------------------------------------------------+ | Table 1. Changed field names in snmp_dpi_xxxx_packet | | structures. | +---------------+----------------+--------------------------------+ | OLD NAME | NEW NAME | DATA STRUCTURE (XXXX) | +---------------+----------------+--------------------------------+ | group_id | group_p | getnext | +---------------+----------------+--------------------------------+ | object_id | object_p | get, getnext, set | +---------------+----------------+--------------------------------+ | value | value_p | set | +---------------+----------------+--------------------------------+ | type | value_type | set | +---------------+----------------+--------------------------------+ | next | next_p | set | +---------------+----------------+--------------------------------+ | enterprise | enterprise_p | trap | +---------------+----------------+--------------------------------+ | packet_body | data_u | dpi_hdr | +---------------+----------------+--------------------------------+ | dpi_get | get_p | hdr (packet_body) | +---------------+----------------+--------------------------------+ | dpi_getnext | next_p | hdr (packet_body) | +---------------+----------------+--------------------------------+ | dpi_set | set_p | hdr (packet_body) | +---------------+----------------+--------------------------------+ | dpi_trap | trap_p | hdr (packet_body) | +---------------+----------------+--------------------------------+ The advantage of using recompiling with the new include files and using the new DPI code is that this new DPI code has a more extensive error detection capability. You must however use object files of the new DPI code that also have been compiled with the DPI 1.1 compatibility. To create your DPI 1.1 based sub-agent with the new code, perform the following steps: o compile -DSNMP_DPI_VERSION=1 -DSNMP_DPI_RELEASE=1 yourcode.c o compile -DSNMP_DPI_VERSION=1 -DSNMP_DPI_RELEASE=1 snmp_mDPI.c o compile -DSNMP_DPI_VERSION=1 -DSNMP_DPI_RELEASE=1 snmp_qDPI.c o compile -DSNMP_DPI_VERSION=1 -DSNMP_DPI_RELEASE=1 snmp_lDPI.c o linkedit yourcode.obj snmp_mDPI.obj snmp_qDPI.obj snmp_lDPI.obj The new executable should now be able to communicate as a DPI 1.1 sub-agent with an agent that support DPI 1.1. Instead of using the compile flag options: -DSNMP_DPI_VERSION=1 -DSNMP_DPI_RELEASE=0 -DSNMP_DPI_VERSION=1 -DSNMP_DPI_RELEASE=1 Wijnen [Page 114] SNMP-DPI API Version 2.0 January 1994 you can also use a preprocessor #define directive to specify that you want DPI 1.1 compatibility: #define SNMP_DPI_VERSION 1 #define SNMP_DPI_RELEASE 1 /* 1 or 0 is valid */ #include The #define directives must precede the #include , because it is in that include file that the level of the SNMP DPI API is defined. If you specify DPI 1.x compatibility, it also includes an additional include file. If you want to convert to DPI 2.0 (which prepares you also for SNMPv2), then you must make changes to your code. See 4.0, "How to change your DPI sub-agent to DPI 2.0" on page 116 for more information. Wijnen [Page 115] SNMP-DPI API Version 2.0 January 1994 4.0 HOW TO CHANGE YOUR DPI SUB-AGENT TO DPI 2.0 When you want to change your DPI 1.x based sub-agent code to the DPI 2.0 level, then you may use these guidelines of steps to do: o Things you MUST do: - Add a mkDPIopen() call and send the created packet to the agent. This opens your "DPI connection" with the agent. Wait for the response and ensure that the open is accepted. You need to pass a sub-agent ID (Object Identifier) which must be a unique ASN.1 OID. See 2.3.12, "The mkDPIopen() Function" on page 54 for more information. - Change your mkDPIregister() calls and pass the arguments according to the new function prototype. You must also expect a RESPONSE to the REGISTER request. See 2.3.14, "The mkDPIregister() Function" on page 59 for more information. - Change mkDPIset() and/or mkDPIlist() calls to the new mkDPIset() call. Basically all mkDPIset() calls are now of the DPI 1.1 mkDPIlist() form. See 2.3.16, "The mkDPIset() Function" on page 65 for more information. - Change mkDPItrap() and mkDPItrape() calls to the new mkDPItrap() call. Basically all mkDPItrap() calls are now of the DPI 1.1 mkDPItrape() form. See 2.3.17, "The mkDPItrap() Function" on page 71 for more information. - Add code to recognize DPI RESPONSE packets (they should be expected as a result of OPEN, REGISTER, UNREGISTER requests). - Add code to unregister your sub-tree(s) and close the "DPI connection" when you want to terminate the sub-agent. See 2.3.18, "The mkDPIunregister() Function" on page 73 and 2.3.7, "The mkDPIclose() Function" on page 43 for more information. - Change your code to use the new SNMPv2 error codes as defined in the snmp_dpi.h include file. - Change your code that handles a GET request. It should return a varBind with SNMP_TYPE_noSuchObject or SNMP_TYPE_noSuchInstance instead of an error SNMP_ERROR_noSuchName if the object or the instance do not exist. This is not considered an error any more, and so you should return an SNMP_ERROR_noError with an error index of zero. - Change your code that handles a GETNEXT request. It should return a varBind with SNMP_TYPE_endOfMibView instead of an error SNMP_ERROR_noSuchName if you reach the end of your MIB or sub-tree. This is not considered an error any more, and so you should return an SNMP_ERROR_noError with an error index of zero. Wijnen [Page 116] SNMP-DPI API Version 2.0 January 1994 o Things you might want to consider, but are not mandatory. - Do not reference the object ID pointer (object_p) in the snmp_dpi_xxxx_packet structures anymore. Instead start using the group_p and instance_p pointers. The object_p pointer may be removed in a future version of the DPI API. - Check 2.2, "Transport Related DPI API Functions" on page 13 to see if you want to use those functions instead of using your own code for those functions. - Consider using more than 1 varBind per DPI packet. You can specify this on the REGISTER request. You must then be prepared to handle multiple varBinds per DPI packet. The varBinds are chained via the various snmp_dpi_xxxx_packet structures. See 2.3.14, "The mkDPIregister() Function" on page 59 for more information. Wijnen [Page 117] SNMP-DPI API Version 2.0 January 1994 5.0 A SIMPLE SAMPLE DPI SUB-AGENT In this chapter we will discuss the implementation of a very basic and simple sample DPI sub-agent. The code "dpi_sample.c" is included with the freely available code package. 5.1 OVERVIEW OF SUB-AGENT PROCESSING This overview assumes that the sub-agent communicates with the agent over a TCP connection. Other connection implementations are possible, and in that case, the processing approach may be a bit different. We also take the most simplistic sample in the sense that we will request the agent to send us at most one varBind per DPI packet, so we do not need to loop through a list of varBinds. Potentially, you may gain performance improvements if you allow for multiple varBinds per DPI packet (on GET, GETNEXT, SET requests), but to do so, your code will have to loop through the varBind list and so it becomes somewhat more complicated. We assume that the DPI sub-agent programmer can handle that once he or she understands the basics of the DPI API. For our simple sub-agent we have defined a dpiSimple mib as follows DPISimple-MIB DEFINITIONS ::= BEGIN IMPORTS MODULE-IDENTITY, OBJECT-TYPE, snmpModules, enterprises FROM SNMPv2-SMI DisplayString FROM SNMPv2-TC ibm OBJECT IDENTIFIER ::= { enterprises 2 } ibmDPI OBJECT IDENTIFIER ::= { ibm 2 } dpi20MIB OBJECT IDENTIFIER ::= { ibmDPI 1 } -- dpiSimpleMIB MODULE-IDENTITY -- LAST-UPDATED "9401310000Z" -- ORGANIZATION "IBM Research - T.J. Watson Research Center" -- CONTACT-INFO " Bert Wijnen -- Postal: IBM International Operations -- Watsonweg 2 -- 1423 ND Uithoorn -- The Netherlands -- Tel: +31 2975 53316 Wijnen [Page 118] SNMP-DPI API Version 2.0 January 1994 -- Fax: +31 2975 62468 -- E-mail: wijnen@vnet.ibm.com -- (IBM internal: wijnen at nlvm1)" -- DESCRIPTION -- "The MIB module describing DPI Simple Objects for -- the dpi_sample.c program" -- ::= { snmpModules x } dpiSimpleMIB OBJECT IDENTIFIER ::= { dpi20MIB 5 } dpiSimpleInteger OBJECT-TYPE SYNTAX INTEGER ACCESS read-only STATUS mandatory DESCRIPTION "A sample integer32 value" ::= { dpiSimpleMIB 1 } dpiSimpleString OBJECT-TYPE SYNTAX DisplayString ACCESS read-write STATUS mandatory DESCRIPTION "A sample Display String" ::= { dpiSimpleMIB 2 } dpiSimpleCounter32 OBJECT-TYPE SYNTAX Counter -- Counter32 is SNMPv2 ACCESS read-only STATUS mandatory DESCRIPTION "A sample 32-bit counter" ::= { dpiSimpleMIB 3 } dpiSimpleCounter64 OBJECT-TYPE SYNTAX Counter -- Counter64 is SNMPv2, -- No SMI support for it yet ACCESS read-only STATUS mandatory DESCRIPTION "A sample 64-bit counter" ::= { dpiSimpleMIB 4 } END To make things more readable, we have defined the following names in our dpi_sample.c source file. Wijnen [Page 119] SNMP-DPI API Version 2.0 January 1994 #define DPI_SIMPLE_SUBAGENT "1.3.6.1.4.1.2.2.1.5" #define DPI_SIMPLE_MIB "1.3.6.1.4.1.2.2.1.5." #define DPI_SIMPLE_INTEGER "1.0" /* dpiSimpleInteger.0 */ #define DPI_SIMPLE_STRING "2.0" /* dpiSimpleInteger.0 */ #define DPI_SIMPLE_COUNTER32 "3.0" /* dpiSimpleCounter32.0 */ #define DPI_SIMPLE_COUNTER64 "4.0" /* dpiSimpleCounter64.0 */ In addition, we have defined the following variables as global variable in our dpi_sample.c source file. static long int value1 = 5; /* readOnly */ #define value2_p cur_val_p /* readWrite */ static char *cur_val_p = (char *)0; static char *new_val_p = (char *)0; static char *old_val_p = (char *)0; static unsigned long value3 = 1; /* readOnly */ static snmp_dpi_u64 value4 = {1L,1L}; /* readOnly */ 5.1.1 CONNECTING TO THE AGENT Before a sub-agent can receive or send any DPI packets from/to the SNMP DPI capable agent, it must "connect" to the agent and then identify itself to the agent. Setting up the connection is one simple call to the the function DPIconnect_to_agent_TCP(). It expects two arguments: o a hostname (name or IpAdress in dot notation) that specifies where the agent is running. Often, the name "loopback" or "localhost" can be used if the sub-agent runs on the same system as the agent. o a community name which is used to obtain the dpi TCP port from the agent. Internally that is done by sending a regular SNMP GET request to the agent. In an open environment, we probably can use the well know community name "public". The function returns an negative error code if an error occurs. If the connection setup is successful, then it returns a handle which represents the connection, and which we must use on subsequent calls to send or await DPI packets. The second step is to identify the sub-agent to the agent. This is done by making a DPI-OPEN packet, sending it to the agent and then awaiting the response from the agent. The agent may accept or deny the OPEN request. Making a DPI-OPEN packet is done by calling mkDPIopen() which expects seven arguments: o A unique sub-agent identification (an Object Identifier). o A description. Might be the NULL string ("") Wijnen [Page 120] SNMP-DPI API Version 2.0 January 1994 o Overall sub-agent timeout in seconds. The agent uses this value as a timeout value for a response when it sends a request to the sub-agent. Note that the agent may have a maximum value for this timeout that will be used if you exceed it. o The maximum number of varBinds per DPI packet that the sub-agent is willing (or is able) to handle. o The character set we want to use. In most cases you want to use the native character set. o Length of a password (zero means no password) o Ptr to the password (or NULL if no password) It depends on the agent if sub-agents must specify a password to open up a connection. The function returns a ptr to a static buffer holding the DPI packet if success. If it fails, it returns a NULL ptr. Once the DPI-OPEN packet has been created, you must send it to the agent. You can use the DPIsend_packet_to_agent() function which expects three arguments: o The handle of a connection (from DPIconnect_to_agent_TCP) o A ptr to the DPI packet (from mkDPIopen) o The length of the packet. The snmp_dpi.h include file provides a macro DPI_PACKET_LEN that calculates the packet length of a DPI packet. This function returns DPI_RC_OK (value zero) if success, otherwise an appropriate DPI_RC_xxxx error code as defined in snmp_dpi.h. Now we must wait for a response to the DPI-OPEN. To await such a response, you call the DPIawait_packet_from_agent() function, which expects four arguments: o The handle of a connection (from DPIconnect_to_agent_TCP) o A timeout in seconds (max time to wait for response) o A ptr to a ptr, which will receive a ptr to a static buffer containing the awaited DPI packet. If the system fails to receive a packet, then a NULL ptr will be stored. o A ptr to a long integer (32-bit) which will receive the length of the awaited packet. On a failure it will be set to zero. This function returns DPI_RC_OK (value zero) if success, otherwise an appropriate DPI_RC_xxxx error code as defined in snmp_dpi.h. The last step is to ensure that we indeed got a DPI-RESPONSE back from the agent, and if we did then we must ensure that the agent indeed accepted us as a valid sub-agent. This will be shown by the error_code field in the DPI response packet. Wijnen [Page 121] SNMP-DPI API Version 2.0 January 1994 The following code sample demonstrates how to setup a connection and then "open" it by identifying yourself to the agent. #include /* DPI 2.0 API definitions */ static int handle; /* handle has global scope */ static void do_connect_and_open(void) { unsigned char *packet_p; int rc; unsigned long length; snmp_dpi_hdr *hdr_p; handle = DPIconnect_to_agent_TCP( /* (TCP) connect to agent*/ "loopback", /* on this host */ "public"); /* snmp community name */ if (handle < 0) exit(1); /* If it failed, exit */ packet_p = mkDPIopen( /* Make DPI-OPEN packet */ DPI_SIMPLE_SUBAGENT, /* Our identification */ "Simple DPI subAgent",/* description */ 5L, /* Our overall timeout */ 1L, /* max varBinds/packet */ DPI_NATIVE_CSET, /* native character set */ 0L, /* password length */ (unsigned char *)0); /* ptr to password */ if (!packet_p) exit(1); /* If it failed, exit */ rc = DPIsend_packet_to_agent( /* send OPEN packet */ handle, /* on this connection */ packet_p, /* this is the packet */ DPI_PACKET_LEN(packet_p)); /* this is its length */ if (rc != DPI_RC_OK) exit(1); /* If it failed, exit */ rc = DPIawait_packet_from_agent( /* wait for response */ handle, /* on this connection */ 3, /* timeout in seconds */ &packet_p, /* receives ptr to packet*/ &length); /* receives packet length*/ if (rc != DPI_RC_OK) exit(1); /* If it failed, exit */ hdr_p = pDPIpacket(packet_p); /* parse DPI packet */ if (hdr_p == snmp_dpi_hdr_NULL_p) /* If we fail to parse it*/ exit(1); /* then exit */ if (hdr_p->packet_type != SNMP_DPI_RESPONSE) exit(1); Wijnen [Page 122] SNMP-DPI API Version 2.0 January 1994 rc = hdr_p->data_u.resp_p->error_code; if (rc != SNMP_ERROR_DPI_noError) exit(1); } /* end of do_connect_and_open() */ 5.2 REGISTERING A SUB-TREE WITH THE AGENT After we have setup a connection to the agent and after we have identified ourselves, we must register one or more MIB sub-trees for which we want to be responsible (handle all SNMP requests). To do so, the sub-agent must create a DPI-REGISTER packet and send it to the agent. The agent will then send a response to indicate success or failure of the register request. To create a DPI-REGISTER packet, the sub-agent uses a call to the mkDPIregister() function, which expects these arguments: o A timeout value (in seconds) for this sub-tree. If you specify zero, then your overall timeout value (specified in DPI-OPEN) is used. Here you can specify a different value if you expect longer processing time for a specific sub-tree. o A requested priority. Multiple sub-agents may register the same sub-tree at different priorities (0 is better than 1 and so on). The agent considers the sub-agent with the best priority to be the active sub-agent for the sub-tree. If you specify -1, then you ask for the best priority available. If you specify 0, then you ask for a better priority than any existing sub-agent may already have. o The MIB sub-tree which you want to control. You must specify this one with a trailing dot. o Your choice of GETBULK processing. You can ask the agent to map a GETBULK into multiple GETNEXT packets or to pass the GETBULK to you. The function returns a ptr to a static buffer holding the DPI packet if success. If it fails, it returns a NULL ptr. Now we must send this DPI-REGISTER packet to the agent. We use the DPIsend_packet_to_agent() function to do so, in a similar way as we did send the DPI_OPEN packet. Then we wait for a response from the agent. Again, we use the DPIawait_packet_from_agent() function in the same way as we awaited a response on the DPI-OPEN request. Once we have received the response, we must check the return code to ensure that registration was successful. The following code sample demonstrates how to register one MIB sub-tree with the agent. Wijnen [Page 123] SNMP-DPI API Version 2.0 January 1994 #include /* DPI 2.0 API definitions */ static int handle; /* handle has global scope */ static void do_register(void) { unsigned char *packet_p; int rc; unsigned long length; snmp_dpi_hdr *hdr_p; packet_p = mkDPIregister( /* Make DPI register */ 3, /* timeout in seconds */ 0, /* requested priority */ DPI_SIMPLE_MIB, /* ptr to the sub-tree */ DPI_BULK_NO); /* GetBulk into GetNext */ if (!packet_p) exit(1); /* If it failed, exit */ rc = DPIsend_packet_to_agent( /* send OPEN packet */ handle, /* on this connection */ packet_p, /* this is the packet */ DPI_PACKET_LEN(packet_p));/* this is its length */ if (rc != DPI_RC_OK) exit(1); /* If it failed, exit */ rc = DPIawait_packet_from_agent( /* wait for response */ handle, /* on this connection */ 3, /* timeout in seconds */ &packet_p, /* gets ptr to packet */ &length); /* gets packet length */ if (rc != DPI_RC_OK) exit(1); /* If it failed, exit */ hdr_p = pDPIpacket(packet_p); /* parse DPI packet */ if (hdr_p == snmp_dpi_hdr_NULL_p) /* Failed to parse it */ exit(1); /* so exit */ if (hdr_p->packet_type != SNMP_DPI_RESPONSE) exit(1); rc = hdr_p->data_u.resp_p->error_code; if (rc != SNMP_ERROR_DPI_noError) exit(1); } /* end of do_register() */ Wijnen [Page 124] SNMP-DPI API Version 2.0 January 1994 5.3 PROCESSING REQUESTS FROM THE AGENT After we have registered our sample MIB sub-tree with the agent, we must expect that SNMP requests for that sub-tree will be passed for processing by the us. The requests will arrive in the form of DPI packets on the connection that the we have established. So we go into a while loop to await DPI packets from the agent. The sub-agent cannot know in advance which kind of packet arrives from the agent. So we await a DPI packet (forever), then we parse the packet, check the packet type and process the request based on the DPI packet type. A call to pDPIpacket (which expects as argument a ptr to the encoded/serialized DPI packet) returns us a ptr to a DPI parse tree. The ptr points to a snmp_dpi_hdr structure which looks as follows: struct snmp_dpi_hdr { unsigned char proto_major; unsigned char proto_version; unsigned char proto_release; unsigned short packet_id; unsigned char packet_type; union { snmp_dpi_reg_packet *reg_p; snmp_dpi_ureg_packet *ureg_p; snmp_dpi_get_packet *get_p; snmp_dpi_next_packet *next_p; snmp_dpi_next_packet *bulk_p; snmp_dpi_set_packet *set_p; snmp_dpi_resp_packet *resp_p; snmp_dpi_trap_packet *trap_p; snmp_dpi_open_packet *open_p; snmp_dpi_close_packet *close_p; unsigned char *any_p; } data_u; }; typedef struct snmp_dpi_hdr snmp_dpi_hdr; #define snmp_dpi_hdr_NULL_p ((snmp_dpi_hdr *)0) Given the DPI parse tree we decide how to process the DPI packet. The following code sample demonstrates the high level process of a DPI sub-agent. #include /* DPI 2.0 API definitions */ static int handle; /* handle has global scope */ main(int argc, char *argv[], char *envp[]) { unsigned char *packet_p; int rc = 0; Wijnen [Page 125] SNMP-DPI API Version 2.0 January 1994 unsigned long length; snmp_dpi_hdr *hdr_p; if (argc>1) { /* if use passed one parm */ if (strcmp(argv[1],"-d")==0) /* being -d, then we */ DPIdebug(2); /* turn on DPI debugging */ } /* endif */ /* which shows us things */ do_connect_and_open(); /* connect and DPI-OPEN */ do_register(); /* register our sub-tree */ while (rc == 0) { /* do forever */ rc = DPIawait_packet_from_agent( /* wait for a DPI packet */ handle, /* on this connection */ -1, /* wait forever */ &packet_p, /* receives ptr to packet */ &length); /* receives packet length */ if (rc != DPI_RC_OK) exit(1); /* If it failed, exit */ hdr_p = pDPIpacket(packet_p); /* parse DPI packet */ if (hdr_p == snmp_dpi_hdr_NULL_p)/* If we fail to parse it */ exit(1); /* then exit */ switch(hdr_p->packet_type) { /* handle by DPI type */ case SNMP_DPI_GET: rc = do_get(hdr_p, hdr_p->data_u.get_p); break; case SNMP_DPI_GETNEXT: rc = do_next(hdr_p, hdr_p->data_u.next_p); break; case SNMP_DPI_SET: case SNMP_DPI_COMMIT: case SNMP_DPI_UNDO: rc = do_set(hdr_p, hdr_p->data_u.set_p); break; case SNMP_DPI_CLOSE: rc = do_close(hdr_p, hdr_p->data_u.close_p); break; case SNMP_DPI_UNREGISTER: rc = do_unreg(hdr_p, hdr_p->data_u.ureg_p); break; default: printf("Unexpected DPI packet type %d\n", Wijnen [Page 126] SNMP-DPI API Version 2.0 January 1994 hdr_p->packet_type); rc = -1; } /* endswitch */ if (rc) exit(1); } /* endwhile */ return(0); } /* end of main() */ 5.3.1 PROCESSING A GET REQUEST A get request is pretty easy to process. When the DPI packet is parsed, the snmp_dpi_hdr structure will show in the packet_type that this is a SNMP_DPI_GET packet. In that case, the packet_body contains a ptr 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) So, assuming we have registered example sub-tree 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 (so that is object 1 instance 0 in our sub-tree), then the fields in the snmp_dpi_get_packet would have ptrs that point 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, then each one is represented in a snmp_dpi_get_packet structure and all the snmp_dpi_get_packet structures are chained via the next ptr. As long as the next ptr is not the snmp_dpi_get_packet_NULL_p pointer then there are more varBinds in the list. Now we can analyze the varBind structure for whatever checking we want to do. Once we are ready to make a response that contains the value of the variable, then we first prepare a SET-varBind which is represented in an snmp_dpi_set_packet structure: Wijnen [Page 127] SNMP-DPI API Version 2.0 January 1994 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) We can use the mkDPIset() function to prepare such a structure. This function expects the following arguments: o a ptr 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, then pass the snmp_dpi_set_packet_NULL_p ptr to indicate this. o a ptr to the sub-tree that we registered. o a ptr to the rest of the OID, in other words the piece that follows the sub-tree. o the value type of the value to be bound to the variable name. This is must be one of the SNMP_TYPE_xxxx values as defined in the snmp_dpi.h include file. o the length of the value (for integer type values this must be a length of 4. So we always work with 32-bit signed or unsigned integers (except of course for the Counter64 type, for those we must point to a snmp_dpi_u64 structure and pass the length of that structure). o a ptr to the value. Memory for the varBind is dynamically allocated and the data itself is copied. So upon return we can dispose of our own ptrs and allocated memory as we please. If the call is successful, then a ptr is returned: o to a new snmp_dpi_set_packet if it is the first/only varBind o to the existing snmp_dpi_set_packet that we passed on the call. In this case, the new packed has been chained to the end of the varBind list. If the mkDPIset() call fails, a NULL ptr is returned. Once we have prepared the SET-varBind data, we can create a DPI RESPONSE packet using the mkDPIresponse() function which expects these arguments: o a ptr to an snmp_dpi_hdr. We should use the hdr of the parsed incoming packet. It is used to copy the packet_id from the Wijnen [Page 128] SNMP-DPI API Version 2.0 January 1994 request into the response, such that the agent can correlate the response to a request. o a return code (snmp error code). If success, this should be SNMP_ERROR_noError (value zero). If failure, it must be one of the SNMP_ERROR_xxxx values as defined in the snmp_dpi.h include file. Note that a request for a non-existing object or instance is not considered an error. Instead, we 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 we can pass a zero length and a NULL ptr for the value in this case. o The index of the varBind in error (starts counting at 1). Pass zero if no error occurred, else pass the proper index of the first varBind for which an error was detected. o a ptr to a (chain of) snmp_dpi_set_packets (varBinds) to be returned as response to the GET request. If an error was detected, then an snmp_dpi_set_packet_NULL_p ptr may be passed. The following code sample returns a response. We assume that there are no errors in the request, but proper code should do the checking for that. For instance, we return a noSuchInstance if the instance is not exactly what we expect and a noSuchObject if the object instance_ID is greater than 3 (like 4.0). But there might be no instance_ID at all and we 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; varBind_p = /* init the varBind chain*/ snmp_dpi_set_packet_NULL_p; /* to a NULL pointer */ if (pack_p->instance_p && (strcmp(pack_p->instance_p,"1.0") == 0)) { varBind_p = mkDPIset( /* Make DPI set packet */ varBind_p, /* ptr to varBind chain */ pack_p->group_p, /* ptr to sub-tree */ 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 (pack_p->instance_p && Wijnen [Page 129] SNMP-DPI API Version 2.0 January 1994 (strcmp(pack_p->instance_p,"2.0") == 0)) { varBind_p = mkDPIset( /* Make DPI set packet*/ varBind_p, /* ptr to varBindchain*/ pack_p->group_p, /* ptr to sub-tree */ pack_p->instance_p, /* ptr to rest of OID */ SNMP_TYPE_DisplayString,/* value type */ strlen(value2_p), /* length of value */ value2_p); /* ptr to value */ } else if (pack_p->instance_p && (strcmp(pack_p->instance_p,"3.0") == 0)) { varBind_p = mkDPIset( /* Make DPI set packet*/ varBind_p, /* ptr to varBindchain*/ pack_p->group_p, /* ptr to sub-tree */ pack_p->instance_p, /* ptr to rest of OID */ SNMP_TYPE_Counter32, /* value type */ sizeof(value3), /* length of value */ &value3); /* ptr to value */ } else if (pack_p->instance_p && (strcmp(pack_p->instance_p,"3")>0)) { varBind_p = mkDPIset( /* Make DPI set packet*/ varBind_p, /* ptr to varBindchain*/ pack_p->group_p, /* ptr to sub-tree */ 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 varBindchain*/ pack_p->group_p, /* ptr to sub-tree */ 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 pack */ hdr_p, /* ptr parsed request */ SNMP_ERROR_noError, /* all is OK, no error */ 0L, /* index zero, no error */ varBind_p); /* varBind response data */ if (!packet_p) return(-1); /* If it failed, return */ rc = DPIsend_packet_to_agent( /* send OPEN packet */ Wijnen [Page 130] SNMP-DPI API Version 2.0 January 1994 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() */ 5.3.2 PROCESSING A GETNEXT REQUEST A getnext request is more difficult to process. When a DPI packet is parsed, the snmp_dpi_hdr structure shows in the packet_type that this is a SNMP_DPI_GETNEXT packet, and so the packet_body contains a ptr 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) So, assuming we have registered example sub-tree dpiSimpleMIB and a GETNEXT arrives for one variable dpiSimpleInteger.0 (so that is object 1 instance 0 in our sub-tree), then the fields in the snmp_dpi_get_packet structure would have ptrs pointing 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, then each one is represented in a snmp_dpi_get_packet structure and all the snmp_dpi_get_packet structures are chained via the next ptr. As long as the next ptr is not the snmp_dpi_next_packet_NULL_p pointer then there are more varBinds in the list. Now we can analyze the varBind structure for whatever checking we want to do. Then we must find out which OID is the one that lexicographically follows the one in the request. And it is that OID with its value that we must return as a response. So we must now also set the proper OID in the response. Once we are ready to make a response that contains the new OID and the value of that variable we must then prepare a SET-varBind which is represented in an snmp_dpi_set_packet: Wijnen [Page 131] SNMP-DPI API Version 2.0 January 1994 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) We can use the mkDPIset() function to prepare such a structure. This function expects the following arguments: o A ptr 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, then we pass the snmp_dpi_set_packet_NULL_p ptr to indicate this. o a ptr to the sub-tree that we registered. a ptr to the rest of the OID, in other words the piece that follows the sub-tree. o the value type of the value to be bound to the variable name. This is must be one of the SNMP_TYPE_xxxx values as defined in the snmp_dpi.h include file. o the length of the value (for integer type values this must be a length of 4. So we always work with 32-bit signed or unsigned integers (except of course for the Counter64 type, for those we must point to a snmp_dpi_u64 structure and pass the length of that structure). o a ptr to the value. Memory for the varBind is dynamically allocated and the data itself is copied. Upon return we can dispose of our own ptrs and allocated memory as we please. If the call is successful, then a ptr is returned: o to a new snmp_dpi_set_packet if it is the first/only varBind o to the existing snmp_dpi_set_packet that we passed on the call. In this case, the new packed has been chained to the end of the varBind list. If the mkDPIset() call fails, a NULL ptr is returned. Once we have prepared the SET-varBind data, we can create a DPI RESPONSE packet using the mkDPIresponse() function, which expects these arguments: o a ptr to an snmp_dpi_hdr. We should use the hdr of the parsed incoming packet. It is used to copy the packet_id from the Wijnen [Page 132] SNMP-DPI API Version 2.0 January 1994 request into the response, such that the agent can correlate the response to a request. o a return code (snmp error code). If success, this should be SNMP_ERROR_noError (value zero). If failure, it must be one of the SNMP_ERROR_xxxx values as defined in the snmp_dpi.h include file. Note that a request for a non-existing object or instance is not considered an error. Instead, we must pass the OID and value of the first OID that lexicographically follows the non-existing object and/or instance. Also, reaching the end of our sub-tree (there is no NEXT OID) is not considered an error. In this situation we must return the original OID (as received in request) and a value_type of SNMP_TYPE_endOfMibView. This value_type has an implicit value of NULL, so we can pass a zero length and a NULL ptr for the value. o The index of the first varBind in error (start counting at 1). Pass zero if no error occurred, else pass the proper index of the first varBind for which an error was detected. o a ptr to a (chain of) snmp_dpi_set_packet(s) (varBinds) to be returned as response to the GETNEXT request. If an error was detected, then an snmp_dpi_set_packet_NULL_p ptr may be passed. The following code sample returns a response. We assume that there are no errors in the request, but proper code should do the checking for that. We do proper checking for lexicographic next object, but we do no checking for ULONG_MAX, or making sure that the instance ID is indeed valid (digits and dots). If we get to the end of our dpiSimpleMIB then we must return an endOfMibView, as defined by the SNMPv2 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 (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 */ Wijnen [Page 133] SNMP-DPI API Version 2.0 January 1994 /* 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 */ instance = 0; /* passed, so we use 0 */ if (subid == 0) subid++; /* if object 0, subid 1 */ } /* endif */ } else { /* no instance ID passed */ subid = 1; /* so do first object */ instance = 0; /* 0 is 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 sub-tree */ 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 varBindchain*/ pack_p->group_p, /* ptr to sub-tree */ DPI_SIMPLE_STRING, /* ptr to rest of OID */ SNMP_TYPE_DisplayString,/* value type */ strlen(value2_p), /* length of value */ value2_p); /* ptr to value */ break; case 3: varBind_p = mkDPIset( /* Make DPI set packet*/ varBind_p, /* ptr to varBindchain*/ pack_p->group_p, /* ptr to sub-tree */ DPI_SIMPLE_COUNTER32, /* ptr to rest of OID */ SNMP_TYPE_Counter32, /* value type */ sizeof(value3), /* length of value */ &value3); /* ptr to value */ break; default: varBind_p = mkDPIset( /* Make DPI set packet*/ varBind_p, /* ptr to varBindchain*/ Wijnen [Page 134] SNMP-DPI API Version 2.0 January 1994 pack_p->group_p, /* ptr to sub-tree */ 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 */ if (!varBind_p) return(-1); /* If it failed, return */ packet_p = mkDPIresponse( /* Make DPIresponse pack */ hdr_p, /* ptr parsed request */ SNMP_ERROR_noError, /* all is OK, no error */ 0L, /* index zero, no error */ varBind_p); /* varBind response data */ if (!packet_p) return(-1); /* If it failed, return */ rc = DPIsend_packet_to_agent( /* send OPEN 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() */ 5.3.3 PROCESSING A SET/COMMIT/UNDO REQUEST These three requests can come in one of these sequences: o SET, COMMIT o SET, UNDO o SET, COMMIT, UNDO Normal sequence is SET and then COMMIT. When we receive a SET request, we must make preparations to accept the new value like check that it is for an existing object and instance, check the value type and contents to be valid, allocate memory etc), but we must not yet effectuate the change. If all goes well, the next request we receive will be a COMMIT request. It is then that we must effectuate the change, but we must then also keep enough information such that we can UNDO the change later if we get a subsequent UNDO request. The latter may happen if the agent discovers any errors with other sub-agents while processing requests that belong to the same original SNMP SET packet (all the varBinds in the same SNMP request PDU must be processed "as if atomic"). Wijnen [Page 135] SNMP-DPI API Version 2.0 January 1994 When the DPI packet is parsed, the snmp_dpi_hdr structure shows in the packet_type that this is an SNMP_DPI_SET, SNMP_DPI_COMMIT SNMP_DPI_UNDO packet. In that case, the packet_body contains a ptr to a SET-varBind, represented in an snmp_dpi_get_packet structure (COMMIT and UNDO have same varBind data as SET upon which they follow): 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) So, assuming we have registered example sub-tree dpiSimpleMIB and a GET request comes in for one variable dpiSimpleString.0 (so that is object 1 instance 0 in our sub-tree), and also assuming that the agent knows about our compiled dpiSimpleMIB so that it knows this is a DisplayString as opposed to just an arbitrary OCTET_STRING, then the ptrs in the snmp_dpi_set_packet structure would have ptrs and values like: object_p -> "1.3.6.1.4.1.2.2.1.5.2.0" group_p -> "1.3.6.1.4.1.2.2.1.5" instance_p -> "2.0" value_type -> SNMP_TYPE_DisplayString value_len -> 8 value_p -> ptr to the value to be set. next_p -> snmp_dpi_get_packet_NULL_p If there are multiple varBinds in a SET request, then each one is represented in a snmp_dpi_set_packet structure and all the snmp_dpi_set_packet structures are chained via the next ptr. As long as the next ptr is not the snmp_dpi_set_packet_NULL_p pointer then there are more varBinds in the list. Now we can analyze the varBind structure for whatever checking we want to do. Once we are ready to make a response that contains the value of the variable, we may prepare a new SET-varBind. However, by definition, the response to a successful SET is exactly the same as the SET request. So there is no need to return any varBinds. A simple response with SNMP_ERROR_noError and an index of zero will do. In case that there is an error, then a simple response with the SNMP_ERROR_xxxx error code and an index pointing to the varBind in error (counting starts at 1) will do. Wijnen [Page 136] SNMP-DPI API Version 2.0 January 1994 The following code sample returns a response. We assume that there are no errors in the request, but proper code should do the checking for that. We also do not check if the varBind in the COMMIT and/or UNDO is the same as that in the SET request. A proper agent would make sure that that is the case, but a proper sub-agent may want to verify that for itself. We only do one simple check that this is dpiSimpleString.0, and if it is not, we return a noCreation. This may not be correct, the mainline does not even return a response. static int do_set(snmp_dpi_hdr *hdr_p, snmp_dpi_set_packet *pack_p) { unsigned char *packet_p; int rc; int index = 0; int error = SNMP_ERROR_noError; snmp_dpi_set_packet *varBind_p; varBind_p = /* init the varBind chain*/ snmp_dpi_set_packet_NULL_p; /* to a NULL pointer */ if (!pack_p->instance_p || (strcmp(pack_p->instance_p,"2.0") != 0)) { if (pack_p->instance_p && (strncmp(pack_p->instance_p,"1.",2) == 0)) { error = SNMP_ERROR_notWritable; } else if (pack_p->instance_p && (strncmp(pack_p->instance_p,"2.",2) == 0)) { error = SNMP_ERROR_noCreation; } else if (pack_p->instance_p && (strncmp(pack_p->instance_p,"3.",2) == 0)) { error = SNMP_ERROR_notWritable; } else { error = SNMP_ERROR_noCreation; } /* endif */ packet_p = mkDPIresponse( /* Make DPIresponse pack */ hdr_p, /* ptr parsed request */ error, /* all is OK, no error */ 1, /* index 1, 1st varBind */ varBind_p); /* varBind response data */ if (!packet_p) return(-1); /* If it failed, return */ Wijnen [Page 137] SNMP-DPI API Version 2.0 January 1994 rc = DPIsend_packet_to_agent( /* send OPEN 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 */ } switch (hdr_p->packet_type) { case SNMP_DPI_SET: if ((pack_p->value_type != SNMP_TYPE_DisplayString) && (pack_p->value_type != SNMP_TYPE_OCTET_STRING)) { /* check octet string in case agent has no compiled MIB*/ error = SNMP_ERROR_wrongType; break; /* from switch */ } /* endif */ if (new_val_p) free(new_val_p); /* free allocated memory */ if (old_val_p) free(old_val_p); /* if we allocated any */ new_val_p = /* allocate memory for */ malloc(pack_p->value_len); /* new value to set */ if (new_val_p) { /* If success, then also */ memcpy(new_val_p, /* copy new value to our */ pack_p->value_p, /* own + newly allocated */ pack_p->value_len); /* memory area. */ } else { /* Else failed to malloc,*/ error = SNMP_ERROR_genErr; /* so that is a genErr */ index = 1; /* at first varBind */ } /* endif */ break; case SNMP_DPI_COMMIT: old_val_p = cur_val_p; /* save old one for undo */ cur_val_p = new_val_p; /* make new value current*/ new_val_p = (char *)0; /* keep only 1 ptr around*/ /* may need to convert from ASCII to native if OCTET_STRING */ break; case SNMP_DPI_UNDO: if (new_val_p) free(new_val_p); /* free allocated memory */ cur_val_p = old_val_p; /* reset to old value */ break; } /* endswitch */ packet_p = mkDPIresponse( /* Make DPIresponse pack */ hdr_p, /* ptr parsed request */ error, /* all is OK, no error */ index, /* index zero, no error */ varBind_p); /* varBind response data */ if (!packet_p) return(-1); /* If it failed, return */ Wijnen [Page 138] SNMP-DPI API Version 2.0 January 1994 rc = DPIsend_packet_to_agent( /* send OPEN packet */ handle, /* on this connection */ packet_p, /* this is the packet */ DPI_PACKET_LEN(packet_p));/* this is its length */ return(rc); /* return retcode */ } /* end of do_set() */ 5.3.4 PROCESSING AN UNREGISTER REQUEST An agent can send an UNREGISTER packet if some other sub-agent does a register for the same sub-tree at a higher priority. An agent can also send an UNREGISTER if for instance an SNMP manager tells it to "invalidate" the sub-agent connection or the registered sub-tree. Here is a very simple sample piece of code to handle such a packet. #include /* DPI 2.0 API definitions */ static int do_unreg(snmp_dpi_hdr *hdr_p, snmp_dpi_ureg_packet *pack_p) { printf("DPI UNREGISTER received from agent, reason=%d\n", pack_p->reason_code); printf(" sub-tree=%s\n",pack_p->group_p); DPIdisconnect_from_agent(handle); return(-1); /* causes exit in main loop */ } /* end of do_unreg() */ 5.3.5 PROCESSING A CLOSE REQUEST An agent can send a CLOSE packet if it encounters an error or for some other reason. It can also do so if an SNMP MANAGER tells it to "invalidate" the sub-agent connection. Here is a very simple sample piece of code to handle such a packet. #include /* DPI 2.0 API definitions */ static int do_close(snmp_dpi_hdr *hdr_p, snmp_dpi_close_packet *pack_p) { printf("DPI CLOSE received from agent, reason=%d\n", pack_p->reason_code); DPIdisconnect_from_agent(handle); return(-1); /* causes exit in main loop */ } /* end of do_close() */ Wijnen [Page 139] SNMP-DPI API Version 2.0 January 1994 5.4 GENERATING A TRAP A trap can be issued at any time. To do so, you must create a trap packet and send it to the agent. With the TRAP, you can pass all sorts of varBinds if you want. In this sample, we pass two varBinds one with integer data and one with an octet string. You can also pass an Enterprise ID, but with DPI 2.0, the agent will use your sub-agent ID as the enterprise ID if you do not pass one with the trap. In most cases that will probably be fine. So we must first prepare a varBind list (chain) that contains the two variables that we want to pass along with the trap. To do so we must prepare a chain of two snmp_dpi_set_packet structures, which looks like: 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) p. We can use the mkDPIset() function to prepare such a structure. This function expects the following arguments: o A ptr 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, then pass the snmp_dpi_set_packet_NULL_p ptr to indicate this. o a ptr to the sub-tree that we registered. o a ptr to the rest of the OID, in other words the piece that follows the sub-tree. o the value type of the value to be bound to the variable name. This is must be one of the SNMP_TYPE_xxxx values as defined in the snmp_dpi.h include file. o the length of the value (for integer type values this must be a length of 4. So we always work with 32-bit signed or unsigned integers (except of course for the Counter64 type, for those we must point to a snmp_dpi_u64 structure and pass the length of that structure). o a ptr to the value. Memory for the varBind is dynamically allocated and the data itself is copied. So upon return we can dispose of our own ptrs and Wijnen [Page 140] SNMP-DPI API Version 2.0 January 1994 allocated memory as we please. If the call is successful, then a ptr is returned: o to a new snmp_dpi_set_packet if it is the first/only varBind o to the existing snmp_dpi_set_packet that we passed on the call. In this case, the new packed has been chained to the end of the varBind list. If the mkDPIset() call fails, a NULL ptr is returned. Once we have prepared the SET-varBind data, we can create a DPI TRAP packet. To do so we can use the mkDPItrap() function which expects these arguments: o the generic trap code, use 6 for enterpriseSpecific trap type. o the specific trap type. This is a type that is defined by the MIB which we are implementing. So in our sample we just use a 1. o a ptr to a chain of varBinds or the NULL ptr if no varBinds need to be passed with the trap o a ptr to the enterprise OID if we want to use a different enterprise ID than the OID we used to identify ourselves as a sub-agent at DPI-OPEN time. The following code sample creates an enterpriseSpecific trap with specific type 1, and passes two varBinds, the first one with our object 1, instance 0, Integer32 value; the second one with our object 2, instance 0, Octet String. We pass no enterprise ID. static int do_trap(void) { unsigned char *packet_p; int rc; snmp_dpi_set_packet *varBind_p; varBind_p = /* init the varBindchain */ snmp_dpi_set_packet_NULL_p, /* to a NULL pointer */ varBind_p = mkDPIset( /* Make DPI set packet */ varBind_p, /* ptr to varBind chain */ DPI_SIMPLE_MIB, /* ptr to sub-tree */ DPI_SIMPLE_INTEGER, /* ptr to rest of OID */ SNMP_TYPE_Integer32, /* value type Integer 32 */ sizeof(value1), /* length of value */ &value1); /* ptr to value */ if (!varBind_p) return(-1); /* If it failed, return */ varBind_p = mkDPIset( /* Make DPI set packet*/ varBind_p, /* ptr to varBindchain*/ Wijnen [Page 141] SNMP-DPI API Version 2.0 January 1994 DPI_SIMPLE_MIB, /* ptr to sub-tree */ DPI_SIMPLE_STRING, /* ptr to rest of OID */ SNMP_TYPE_DisplayString,/* value type */ strlen(value2_p), /* length of value */ value2_p); /* ptr to value */ if (!varBind_p) return(-1); /* If it failed, return */ varBind_p = mkDPIset( /* Make DPI set packet*/ varBind_p, /* ptr to varBindchain*/ DPI_SIMPLE_MIB, /* ptr to sub-tree */ DPI_SIMPLE_COUNTER32, /* ptr to rest of OID */ SNMP_TYPE_Counter32, /* value type */ sizeof(value3), /* length of value */ &value3); /* ptr to value */ if (!varBind_p) return(-1); /* If it failed, return */ packet_p = mkDPItrap( /* Make DPItrap packet */ 6, /* enterpriseSpecific */ 1, /* specific type = 1 */ varBind_p, /* varBind data, and use */ (char *)0); /* default enterpriseID */ if (!packet_p) return(-1); /* If it failed, return */ rc = DPIsend_packet_to_agent( /* send OPEN 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_trap() */  Wijnen [Page 142]