/*++ Copyright (c) 1992-1996 Microsoft Corporation Module Name: pduapi.c Abstract: Performs all functions to encode/decode a RFC 1157 PDU and trap. Environment: User Mode - Win32 Revision History: 10-May-1996 DonRyan Removed banner from Technology Dynamics, Inc. --*/ //--------------------------- WINDOWS DEPENDENCIES -------------------------- //--------------------------- STANDARD DEPENDENCIES -- #include ---- #include //--------------------------- MODULE DEPENDENCIES -- #include"xxxxx.h" ------ #include #include #include "berapi.h" //--------------------------- SELF-DEPENDENCY -- ONE #include"module.h" ----- #include "pduapi.h" //--------------------------- PUBLIC VARIABLES --(same as in module.h file)-- //--------------------------- PRIVATE CONSTANTS ----------------------------- #define PDU_ERRORSTATUS_LAST SNMP_ERRORSTATUS_GENERR #define PDU_GENERICTRAP_LAST SNMP_GENERICTRAP_ENTERSPECIFIC //--------------------------- PRIVATE STRUCTS ------------------------------- //--------------------------- PRIVATE VARIABLES ----------------------------- //--------------------------- PRIVATE PROTOTYPES ---------------------------- void PDU_ReleasePDU( RFC1157Pdu *pdu // PDU to release ); void PDU_ReleaseTrap( RFC1157TrapPdu *pdu // Trap to release ); //--------------------------- PRIVATE PROCEDURES ---------------------------- //--------------------------- PUBLIC PROCEDURES ----------------------------- // // SnmpPduEncodePdu: // Encode a RFC1157 PDU. // // Notes: // The encoded PDU is left in reverse order so the rest of the message // information can be appended to the buffer, and then reversed. // // The buffer information must be initialized prior to calling this routine. // // If an error occurs, the entire buffer is freed, and set to NULL. // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_PDUAPI_INVALID_ES // SNMPAPI SnmpPduEncodePdu( IN BYTE nType, // Type of RFC 1157 PDU to encode IN RFC1157Pdu *pdu, // RFC 1157 PDU to encode into stream buffer IN OUT BYTE **pBuffer, // Stream buffer to accept encoding IN OUT UINT *nLength // Length of stream buffer ) { SNMPAPI nResult; UINT nBufStart; int I; // Check for valid error status if ( pdu->errorStatus > PDU_ERRORSTATUS_LAST ) { SetLastError( SNMP_PDUAPI_INVALID_ES ); nResult = SNMPAPI_ERROR; goto Exit; } // Save start position of buffer nBufStart = *nLength; // Encode var binds for ( I=pdu->varBinds.len-1;I >= 0;I-- ) { UINT nSeqStart; // Save starting point of sequence nSeqStart = *nLength; // Encode variable value if ( SNMPAPI_ERROR == SnmpBerEncodeAsnAny(&pdu->varBinds.list[I].value, pBuffer, nLength) ) { goto Exit; } // Encode variable name if ( SNMPAPI_ERROR == SnmpBerEncodeAsnObjectId(ASN_OBJECTIDENTIFIER, &pdu->varBinds.list[I].name, pBuffer, nLength) ) { goto Exit; } // Encode the entire variable info. as a sequence if ( SNMPAPI_ERROR == SnmpBerEncodeAsnSequence(*nLength - nSeqStart, pBuffer, nLength) ) { goto Exit; } } // Encode the var bind list as a sequence of 'sequence's if ( SNMPAPI_ERROR == SnmpBerEncodeAsnImplicitSeq(ASN_SEQUENCEOF, *nLength - nBufStart, pBuffer, nLength) ) { goto Exit; } // Encode error-index if ( SNMPAPI_ERROR == (nResult = SnmpBerEncodeAsnInteger(ASN_INTEGER, pdu->errorIndex, pBuffer, nLength)) ) { goto Exit; } // Encode error-status if ( SNMPAPI_ERROR == (nResult = SnmpBerEncodeAsnInteger(ASN_INTEGER, pdu->errorStatus, pBuffer, nLength)) ) { goto Exit; } // Encode request-id if ( SNMPAPI_ERROR == (nResult = SnmpBerEncodeAsnInteger(ASN_INTEGER, pdu->requestId, pBuffer, nLength)) ) { goto Exit; } // Encode entire pdu as Implicit Sequence if ( SNMPAPI_ERROR == (nResult = SnmpBerEncodeAsnImplicitSeq(nType, *nLength - nBufStart, pBuffer, nLength)) ) { goto Exit; } Exit: if ( nResult == SNMPAPI_ERROR ) { SnmpUtilMemFree( *pBuffer ); *pBuffer = NULL; *nLength = 0; } return nResult; } // SnmpPduEncodePdu // // SnmpPduDecodePdu // Decode a PDU. // // Notes: // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_MEM_ALLOC_ERROR // SNMP_PDUAPI_INVALID_ES // SNMPAPI SnmpPduDecodePdu( IN BYTE nType, // Type of RFC 1157 PDU to decode OUT RFC1157Pdu *pdu, // RFC 1157 PDU to accept decoding IN OUT BYTE **pBuffer, // Stream buffer to decode IN OUT UINT *nLength // Length of stream buffer ) { UINT BufLen; BYTE *BufPtr; AsnAny pResult; SNMPAPI nResult; // Initialize variable bindings' list pdu->varBinds.list = NULL; pdu->varBinds.len = 0; // process the sequence encapsuling the PDU if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(nType, pBuffer, nLength, &pResult)) ) { goto Exit; } // Make copy of sequence information BufPtr = pResult.asnValue.sequence.stream; BufLen = pResult.asnValue.sequence.length; // Decode request-id if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_INTEGER, &BufPtr, &BufLen, &pResult)) ) { goto Exit; } // Save request-id pdu->requestId = pResult.asnValue.number; // Decode error-status if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_INTEGER, &BufPtr, &BufLen, &pResult)) ) { goto Exit; } // Save error-status pdu->errorStatus = pResult.asnValue.number; // Check for valid error status if ( pdu->errorStatus > PDU_ERRORSTATUS_LAST ) { SetLastError( SNMP_PDUAPI_INVALID_ES ); nResult = SNMPAPI_ERROR; goto Exit; } // Decode error-index if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_INTEGER, &BufPtr, &BufLen, &pResult)) ) { goto Exit; } // Save error-status pdu->errorIndex = pResult.asnValue.number; // Decode variable-bindings' sequence if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_SEQUENCEOF, &BufPtr, &BufLen, &pResult)) ) { goto Exit; } // Make temps of sequence data BufLen = pResult.asnValue.sequence.length; BufPtr = pResult.asnValue.sequence.stream; // Gather variables and save in pdu list while ( BufLen ) { BYTE *VarBufPtr; UINT VarBufLen; // Alloc space for variable binding pdu->varBinds.list = (RFC1157VarBind *) SnmpUtilMemReAlloc( pdu->varBinds.list, ((pdu->varBinds.len+1)*sizeof(RFC1157VarBind)) ); // Check for errors on alloc if ( pdu->varBinds.list == NULL ) { SetLastError( SNMP_MEM_ALLOC_ERROR ); nResult = SNMPAPI_ERROR; goto Exit; } // Decode sequence of info if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_SEQUENCE, &BufPtr, &BufLen, &pResult)) ) { goto Exit; } // Setup variable bindings' buffer VarBufPtr = pResult.asnValue.sequence.stream; VarBufLen = pResult.asnValue.sequence.length; // Decode name if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_OBJECTIDENTIFIER, &VarBufPtr, &VarBufLen, &pResult)) ) { goto Exit; } // Save name of variable // This is a non-standard copy - MS C specific pdu->varBinds.list[pdu->varBinds.len].name = pResult.asnValue.object; // Get ASN Type if ( SNMPAPI_ERROR == (nResult = SnmpBerQueryAsnType(VarBufPtr, VarBufLen)) ) { goto Exit; } // Decode value if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream( (BYTE)nResult, &VarBufPtr, &VarBufLen, &pdu->varBinds.list[pdu->varBinds.len++].value)) ) { goto Exit; } } Exit: if ( nResult == SNMPAPI_ERROR ) { PDU_ReleasePDU( pdu ); } return nResult; } // SnmpPduDecodePdu // // SnmpPduEncodeTrap: // The encoded TRAP is left in reverse order so the rest of the message // information can be appended to the buffer, and then reversed. // // Notes: // The buffer information must be initialized prior to calling this routine. // // If an error occurs, the entire buffer is freed and set to NULL. // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_PDUAPI_INVALID_GT // SNMPAPI SnmpPduEncodeTrap( IN BYTE nType, // Type of RFC 1157 TRAP to encode IN RFC1157TrapPdu *pdu, // RFC 1157 Trap to encode into stream buffer IN OUT BYTE **pBuffer, // Stream buffer to accept encoding IN OUT UINT *nLength // Length of stream buffer ) { SNMPAPI nResult; UINT nBufStart; int I; // Check for valid generic trap if ( pdu->genericTrap > PDU_GENERICTRAP_LAST ) { SetLastError( SNMP_PDUAPI_INVALID_GT ); nResult = SNMPAPI_ERROR; goto Exit; } // Save start position of buffer nBufStart = *nLength; // Encode var binds for( I=pdu->varBinds.len-1;I >= 0;I-- ) { UINT nSeqStart; // Save starting point of sequence nSeqStart = *nLength; // Encode variable value if ( SNMPAPI_ERROR == SnmpBerEncodeAsnAny(&pdu->varBinds.list[I].value, pBuffer, nLength) ) { goto Exit; } // Encode variable name if ( SNMPAPI_ERROR == SnmpBerEncodeAsnObjectId(ASN_OBJECTIDENTIFIER, &pdu->varBinds.list[I].name, pBuffer, nLength) ) { goto Exit; } // Encode the entire variable info. as a sequence if ( SNMPAPI_ERROR == SnmpBerEncodeAsnSequence(*nLength - nSeqStart, pBuffer, nLength) ) { goto Exit; } } // Encode the var bind list as a sequence of 'sequence's if ( SNMPAPI_ERROR == SnmpBerEncodeAsnImplicitSeq(ASN_SEQUENCEOF, *nLength - nBufStart, pBuffer, nLength) ) { goto Exit; } // Encode time-stamp if ( SNMPAPI_ERROR == (nResult = SnmpBerEncodeAsnInteger(ASN_RFC1155_TIMETICKS, pdu->timeStamp, pBuffer, nLength)) ) { goto Exit; } // Encode specific-trap if ( SNMPAPI_ERROR == (nResult = SnmpBerEncodeAsnInteger(ASN_INTEGER, pdu->specificTrap, pBuffer, nLength)) ) { goto Exit; } // Encode generic-trap if ( SNMPAPI_ERROR == (nResult = SnmpBerEncodeAsnInteger(ASN_INTEGER, pdu->genericTrap, pBuffer, nLength)) ) { goto Exit; } // Encode agent-addr if ( SNMPAPI_ERROR == (nResult = SnmpBerEncodeAsnOctetStr(ASN_RFC1155_IPADDRESS, &pdu->agentAddr, pBuffer, nLength)) ) { goto Exit; } // Encode enterprise if ( SNMPAPI_ERROR == (nResult = SnmpBerEncodeAsnObjectId(ASN_OBJECTIDENTIFIER, &pdu->enterprise, pBuffer, nLength)) ) { goto Exit; } // Encode entire pdu as Implicit Sequence if ( SNMPAPI_ERROR == (nResult = SnmpBerEncodeAsnImplicitSeq(nType, *nLength - nBufStart, pBuffer, nLength)) ) { goto Exit; } Exit: if ( nResult == SNMPAPI_ERROR ) { SnmpUtilMemFree( *pBuffer ); *pBuffer = NULL; *nLength = 0; } return nResult; } // SnmpPduEncodeTrap // // SnmpPduDecodeTrap: // Decode a TRAP. // // Notes: // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_MEM_ALLOC_ERROR // SNMP_PDUAPI_INVALID_GT // SNMPAPI SnmpPduDecodeTrap( IN BYTE nType, // Type of RFC 1157 TRAP to decode OUT RFC1157TrapPdu *pdu, // RFC 1157 Trap to accept decoding IN OUT BYTE **pBuffer, // Stream buffer to decode IN OUT UINT *nLength // Length of stream buffer ) { UINT BufLen; BYTE *BufPtr; AsnAny pResult; SNMPAPI nResult; // Initialize variable bindings' list pdu->enterprise.ids = NULL; pdu->varBinds.list = NULL; pdu->varBinds.len = 0; // process the sequence encapsuling the PDU if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(nType, pBuffer, nLength, &pResult)) ) { goto Exit; } // Make copy of sequence information BufPtr = pResult.asnValue.sequence.stream; BufLen = pResult.asnValue.sequence.length; // Decode enterprise if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_OBJECTIDENTIFIER, &BufPtr, &BufLen, &pResult)) ) { goto Exit; } // This is a non-standard structure copy pdu->enterprise = pResult.asnValue.object; // Decode agent-addr if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_RFC1155_IPADDRESS, &BufPtr, &BufLen, &pResult)) ) { goto Exit; } // This is a non-standard structure copy pdu->agentAddr = pResult.asnValue.string; // Decode generic-trap if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_INTEGER, &BufPtr, &BufLen, &pResult)) ) { goto Exit; } pdu->genericTrap = pResult.asnValue.number; // Check for valid generic trap if ( pdu->genericTrap > PDU_GENERICTRAP_LAST ) { SetLastError( SNMP_PDUAPI_INVALID_GT ); nResult = SNMPAPI_ERROR; goto Exit; } // Decode specific-trap if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_INTEGER, &BufPtr, &BufLen, &pResult)) ) { goto Exit; } pdu->specificTrap = pResult.asnValue.number; // Decode time-stamp if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_RFC1155_TIMETICKS, &BufPtr, &BufLen, &pResult)) ) { goto Exit; } pdu->timeStamp = pResult.asnValue.number; // Decode variable-bindings' sequence if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_SEQUENCEOF, &BufPtr, &BufLen, &pResult)) ) { goto Exit; } // Make temps of sequence data BufLen = pResult.asnValue.sequence.length; BufPtr = pResult.asnValue.sequence.stream; // Gather variables and save in pdu list while ( BufLen ) { BYTE *VarBufPtr; UINT VarBufLen; // Alloc space for variable binding pdu->varBinds.list = (RFC1157VarBind *) SnmpUtilMemReAlloc( pdu->varBinds.list, ((pdu->varBinds.len+1)*sizeof(RFC1157VarBind)) ); // Check for errors on alloc if ( pdu->varBinds.list == NULL ) { SetLastError( SNMP_MEM_ALLOC_ERROR ); nResult = SNMPAPI_ERROR; goto Exit; } // Decode sequence of info if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_SEQUENCE, &BufPtr, &BufLen, &pResult)) ) { goto Exit; } // Setup variable bindings' buffer VarBufPtr = pResult.asnValue.sequence.stream; VarBufLen = pResult.asnValue.sequence.length; // Decode name if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream(ASN_OBJECTIDENTIFIER, &VarBufPtr, &VarBufLen, &pResult)) ) { goto Exit; } // Save name of variable // This is a non-standard copy - MS C specific pdu->varBinds.list[pdu->varBinds.len].name = pResult.asnValue.object; // Decode value if ( SNMPAPI_ERROR == (nResult = SnmpBerDecodeAsnStream( (BYTE)SnmpBerQueryAsnType(VarBufPtr, VarBufLen), &VarBufPtr, &VarBufLen, &pdu->varBinds.list[pdu->varBinds.len++].value)) ) { goto Exit; } } Exit: if ( nResult == SNMPAPI_ERROR ) { PDU_ReleaseTrap( pdu ); } return nResult; } // SnmpPduDecodePdu // // SnmpPduEncodeAnyPdu // Determines the type of PDU to encode (PDU or TRAP) and calls the // appropriate routine to do it. // // Notes: // If the pdu type is unrecognized, this is an error and the buffer info. // is freed. // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_PDUAPI_UNRECOGNIZED_PDU // SNMPAPI SnmpPduEncodeAnyPdu( RFC1157Pdus *pdu, // PDU/TRAP to Encode IN OUT BYTE **pBuffer, // Buffer to accept encoding IN OUT UINT *nLength // Length of buffer ) { SNMPAPI nResult; // Encode PDU/TRAP switch ( pdu->pduType ) { case ASN_RFC1157_GETREQUEST: case ASN_RFC1157_GETNEXTREQUEST: case ASN_RFC1157_GETRESPONSE: case ASN_RFC1157_SETREQUEST: nResult = SnmpPduEncodePdu( pdu->pduType, &pdu->pduValue.pdu, pBuffer, nLength ); break; case ASN_RFC1157_TRAP: nResult = SnmpPduEncodeTrap( pdu->pduType, &pdu->pduValue.trap, pBuffer, nLength ); break; default: SetLastError( SNMP_PDUAPI_UNRECOGNIZED_PDU ); nResult = SNMPAPI_ERROR; } if ( nResult == SNMPAPI_ERROR ) { SnmpUtilMemFree( *pBuffer ); *pBuffer = NULL; *nLength = 0; } return nResult; } // SnmpPduEncodeAnyPdu // // SnmpPduDecodeAnyPdu // Determines and sets the type of PDU to decode (PDU or TRAP) and calls the // appropriate routine to do it. // // Notes: // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_PDUAPI_UNRECOGNIZED_PDU // SNMPAPI SnmpPduDecodeAnyPdu( OUT RFC1157Pdus *pdu, // Will accept PDU or TRAP as result IN OUT BYTE **pBuffer, // Stream buffer to decode IN OUT UINT *nLength // Length of stream buffer ) { SNMPAPI nResult; // Get pdu type if ( SNMPAPI_ERROR == (pdu->pduType = (BYTE)(nResult = SnmpBerQueryAsnType(*pBuffer, *nLength))) ) { goto Exit; } switch ( nResult ) { case ASN_RFC1157_GETREQUEST: case ASN_RFC1157_GETNEXTREQUEST: case ASN_RFC1157_GETRESPONSE: case ASN_RFC1157_SETREQUEST: nResult = SnmpPduDecodePdu( pdu->pduType, &pdu->pduValue.pdu, pBuffer, nLength ); break; case ASN_RFC1157_TRAP: nResult = SnmpPduDecodeTrap( pdu->pduType, &pdu->pduValue.trap, pBuffer, nLength ); break; default: SetLastError( SNMP_PDUAPI_UNRECOGNIZED_PDU ); nResult = SNMPAPI_ERROR; } Exit: return nResult; } // SnmpPduDecodeAnyPdu // // PDU_ReleasePDU // Frees all memory associated with a pdu, including a call to // SnmpUtilVarBindListFree to free the var binds list. // // Notes: // The dynamic memory associated with a pdu must be set before calling // this routine. // // Return Codes: // None. // // Error Codes: // None. // void PDU_ReleasePDU( RFC1157Pdu *pdu // PDU to release ) { SnmpUtilVarBindListFree( &pdu->varBinds ); } // PDU_ReleasePDU // // PDU_ReleaseTrap // Frees all memory associated with a trap, including a call to // SnmpUtilVarBindListFree to free the var binds list. // // Notes: // The dynamic memory associated with a trap pdu must be set before calling // this routine. // // Return Codes: // None. // // Error Codes: // None. // void PDU_ReleaseTrap( RFC1157TrapPdu *pdu // Trap to release ) { SnmpUtilOidFree( &pdu->enterprise ); // Free network address if dynamic if ( pdu->agentAddr.dynamic ) { SnmpUtilMemFree( pdu->agentAddr.stream ); } SnmpUtilVarBindListFree( &pdu->varBinds ); } // PDU_ReleaseTrap // // PDU_ReleaseAnyPdu // Determines what type of PDU it is and calls the appropriate routine // to release it. // // Notes: // // Return Codes: // SNMPAPI_NOERROR // SNMPAPI_ERROR // // Error Codes: // SNMP_PDUAPI_UNRECOGNIZED_PDU // SNMPAPI PDU_ReleaseAnyPDU( IN OUT RFC1157Pdus *Pdu ) { SNMPAPI nResult; // Encode PDU/TRAP switch ( Pdu->pduType ) { case ASN_RFC1157_GETREQUEST: case ASN_RFC1157_GETNEXTREQUEST: case ASN_RFC1157_GETRESPONSE: case ASN_RFC1157_SETREQUEST: PDU_ReleasePDU( &Pdu->pduValue.pdu ); break; case ASN_RFC1157_TRAP: PDU_ReleaseTrap( &Pdu->pduValue.trap ); break; default: SetLastError( SNMP_PDUAPI_UNRECOGNIZED_PDU ); nResult = SNMPAPI_ERROR; goto Exit; } nResult = SNMPAPI_NOERROR; Exit: return nResult; } // PDU_ReleaseAnyPDU //-------------------------------- END --------------------------------------