Subversion Repositories HomeAutomation

Rev

Rev 363 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*********************************************************************
  2.  *
  3.  *                  SNMP Module for Microchip TCP/IP Stack
  4.  *
  5.  *********************************************************************
  6.  * FileName:        SNMP.c
  7.  * Dependencies:    StackTsk.h
  8.  *                  UDP.h
  9.  * Processor:       PIC18
  10.  * Complier:        MCC18 v1.00.50 or higher
  11.  *                  HITECH PICC-18 V8.10PL1 or higher
  12.  * Company:         Microchip Technology, Inc.
  13.  *
  14.  * Software License Agreement
  15.  *
  16.  * The software supplied herewith by Microchip Technology Incorporated
  17.  * (the “Company”) for its PICmicro® Microcontroller is intended and
  18.  * supplied to you, the Company’s customer, for use solely and
  19.  * exclusively on Microchip PICmicro Microcontroller products. The
  20.  * software is owned by the Company and/or its supplier, and is
  21.  * protected under applicable copyright laws. All rights are reserved.
  22.  * Any use in violation of the foregoing restrictions may subject the
  23.  * user to criminal sanctions under applicable laws, as well as to
  24.  * civil liability for the breach of the terms and conditions of this
  25.  * license.
  26.  *
  27.  * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
  28.  * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
  29.  * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  30.  * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
  31.  * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
  32.  * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
  33.  *
  34.  * HiTech PICC18 Compiler Options excluding device selection:
  35.  *                  -FAKELOCAL -G -Zg -E -C
  36.  *
  37.  * Author               Date    Comment
  38.  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  39.  * Nilesh Rajbharti     1/9/03  Original        (Rev 1.0)
  40.  * Dan Cohen            12/11/03  Removed trap support by #define if not
  41.  *                                required to lower code space requirements
  42.  *
  43.  ********************************************************************/
  44. #define THIS_IS_SNMP_SERVER
  45.  
  46. #include <string.h>
  47.  
  48. #include "..\Include\snmp.h"
  49. #include "..\Include\stacktsk.h"
  50. #ifndef _WIN32
  51. #include "..\Include\udp.h"
  52. #include "..\Include\tick.h"
  53. #include "..\Include\arptsk.h"
  54. #endif
  55. #include "..\Include\mpfs.h"
  56.  
  57. #if _WIN32
  58. #include <windows.h>
  59. #endif
  60.  
  61. #if !defined(STACK_USE_SNMP_SERVER)
  62.     #error SNMP module is not enabled.
  63.     #error If you do not want SNMP module, remove this file from your
  64.     #error project to reduce your code size.
  65.     #error If you do want SNMP module, make sure that STACK_USE_SNMP_SERVER
  66.     #error is defined in StackTsk.h file.
  67. #endif
  68.  
  69. #define SNMP_V1                 (0)
  70.  
  71.  
  72. #define STRUCTURE               (0x30)
  73. #define ASN_INT                 (0x02)
  74. #define OCTET_STRING            (0x04)
  75. #define ASN_NULL                (0x05)
  76. #define ASN_OID                 (0x06)
  77.  
  78. // SNMP specific variables
  79. #define SNMP_IP_ADDR            (0x40)
  80. #define SNMP_COUNTER32          (0x41)
  81. #define SNMP_GAUGE32            (0x42)
  82. #define SNMP_TIME_TICKS         (0x43)
  83. #define SNMP_OPAQUE             (0x44)
  84. #define SNMP_NSAP_ADDR          (0x45)
  85.  
  86.  
  87. #define GET_REQUEST             (0xa0)
  88. #define GET_NEXT_REQUEST        (0xa1)
  89. #define GET_RESPONSE            (0xa2)
  90. #define SET_REQUEST             (0xa3)
  91. #define TRAP                    (0xa4)
  92.  
  93. #define IS_STRUCTURE(a)         (a==STRUCTURE)
  94. #define IS_ASN_INT(a)           (a==ASN_INT)
  95. #define IS_OCTET_STRING(a)      (a==OCTET_STRING)
  96. #define IS_OID(a)               (a==ASN_OID)
  97. #define IS_ASN_NULL(a)          (a==ASN_NULL)
  98. #define IS_GET_REQUEST(a)       (a==GET_REQUEST)
  99. #define IS_GET_NEXT_REQUEST(a)  (a==GET_NEXT_REQUEST)
  100. #define IS_GET_RESPONSE(a)      (a==GET_RESPONSE)
  101. #define IS_SET_REQUEST(a)       (a==SET_REQUEST)
  102. #define IS_TRAP(a)              (a==TRAP)
  103. #define IS_AGENT_PDU(a)         (a==GET_REQUEST || \
  104.                                  a==GET_NEXT_REQUEST || \
  105.                                  a==SET_REQUEST)
  106.  
  107. typedef enum _SNMP_ERR_STATUS
  108. {
  109.     SNMP_NO_ERR = 0,
  110.     SNMP_TOO_BIG,
  111.     SNMP_NO_SUCH_NAME,
  112.     SNMP_BAD_VALUE,
  113.     SNMP_READ_ONLY,
  114.     SNMP_GEN_ERR
  115. } SNMP_ERR_STATUS;
  116.  
  117. typedef union _SNMP_STATUS
  118. {
  119.     struct
  120.     {
  121.         unsigned int bIsFileOpen : 1;
  122.     } Flags;
  123.     BYTE Val;
  124. } SNMP_STATUS;
  125.  
  126.  
  127.  
  128. #define SNMP_AGENT_PORT     (161)
  129. #define SNMP_NMS_PORT       (162)
  130. #define AGENT_NOTIFY_PORT   (0xfffe)
  131.  
  132. #ifdef _WIN32
  133.     #define ROM
  134.     extern int _RxIndex;
  135.     extern int _TxIndex;
  136.     extern int _TxLength;
  137.     extern BYTE _TxPacket[1000];
  138.     extern BYTE _RxPacket[1000];
  139.  
  140.     #define INVALID_UDP_SOCKET  (0XFFFF)
  141.  
  142.     #define UDPGet(a)           _UDPGet(a)
  143.     #define UDPFlush()
  144.     #define UDPClose(a)
  145.     #define ARPResolve(a)
  146.     #define ARPIsResolved(a, b) (TRUE)
  147.     static void _UDPGet(BYTE *v)
  148.     {
  149.         *v = _RxPacket[_RxIndex++];
  150.     }
  151.  
  152.     #define UDP_SOCKET              int
  153.     #define BUFFER                  int
  154.  
  155.     #define UDPOpen(a, b, c)            (0)
  156.     #define UDPDiscard()            (_TxLength = 0)
  157.     #define UDPPut(a)               \
  158.     {                               \
  159.         if ( _TxIndex >= _TxLength ) \
  160.             _TxLength = _TxIndex+1; \
  161.         _TxPacket[_TxIndex++] = a;  \
  162.     }
  163.     #define UDPIsGetReady(a)        TRUE
  164.     #define UDPIsPutReady(a)        TRUE
  165.     #define MACGetRxBuffer()        0
  166.     #define MACGetTxBuffer()         0
  167.     #define UDPSetRxBuffer(a)       (_RxIndex = a)
  168.     #define UDPSetTxBuffer(a, b)    (_TxIndex = a+b)
  169.     #define SNMPValidate(a, b)      TRUE
  170. #endif
  171.  
  172. UDP_SOCKET SNMPAgentSocket;
  173.  
  174. typedef struct _SNMP_NOTIFY_INFO
  175. {
  176.     char community[NOTIFY_COMMUNITY_LEN];
  177.     BYTE communityLen;
  178.     SNMP_ID agentIDVar;
  179.     BYTE notificationCode;
  180.     UDP_SOCKET socket;
  181.     DWORD_VAL timestamp;
  182. } SNMP_NOTIFY_INFO;
  183.  
  184. // SNMPNotifyInfo is not required if TRAP is disabled
  185. #if !defined(SNMP_TRAP_DISABED)
  186. static SNMP_NOTIFY_INFO SNMPNotifyInfo;
  187. #endif
  188.  
  189.  
  190. typedef enum _DATA_TYPE
  191. {
  192.     INT8_VAL        = 0x00,
  193.     INT16_VAL       = 0x01,
  194.     INT32_VAL       = 0x02,
  195.     BYTE_ARRAY      = 0x03,
  196.     ASCII_STRING    = 0x04,
  197.     IP_ADDRESS      = 0x05,
  198.     COUNTER32       = 0x06,
  199.     TIME_TICKS_VAL  = 0x07,
  200.     GAUGE32         = 0x08,
  201.     OID_VAL         = 0x09,
  202.  
  203.     DATA_TYPE_UNKNOWN
  204. } DATA_TYPE;
  205.  
  206. typedef union _INDEX_INFO
  207. {
  208.     struct
  209.     {
  210.         unsigned int bIsOID:1;
  211.     } Flags;
  212.     BYTE Val;
  213. } INDEX_INFO;
  214.  
  215.  
  216. typedef struct _DATA_TYPE_INFO
  217. {
  218.     BYTE asnType;
  219.     BYTE asnLen;
  220. } DATA_TYPE_INFO;
  221.  
  222. ROM DATA_TYPE_INFO dataTypeTable[] =
  223. {
  224.     /* INT8_VAL         */ { ASN_INT,           1       },
  225.     /* INT16_VAL        */ { ASN_INT,           2       },
  226.     /* INT32_VAL        */ { ASN_INT,           4       },
  227.     /* BYTE_ARRAY       */ { OCTET_STRING,      0xff    },
  228.     /* ASCII_ARRAY      */ { OCTET_STRING,      0xff    },
  229.     /* IP_ADDRESS       */ { SNMP_IP_ADDR,      4       },
  230.     /* COUNTER32        */ { SNMP_COUNTER32,    4       },
  231.     /* TIME_TICKS_VAL   */ { SNMP_TIME_TICKS,   4       },
  232.     /* GAUTE32          */ { SNMP_GAUGE32,      4       },
  233.     /* OID_VAL          */ { ASN_OID,           0xff    }
  234. };
  235. #define DATA_TYPE_TABLE_SIZE    (sizeof(dataTypeTable)/sizeof(dataTypeTable[0]))
  236.  
  237.  
  238.  
  239. typedef union _MIB_INFO
  240. {
  241.     struct
  242.     {
  243.         unsigned int bIsDistantSibling : 1;
  244.         unsigned int bIsConstant : 1;
  245.         unsigned int bIsSequence : 1;
  246.         unsigned int bIsSibling : 1;
  247.  
  248.         unsigned int bIsParent : 1;
  249.         unsigned int bIsEditable : 1;
  250.         unsigned int bIsAgentID : 1;
  251.         unsigned int bIsIDPresent : 1;
  252.     } Flags;
  253.     BYTE Val;
  254. } MIB_INFO;
  255.  
  256.  
  257. typedef struct _OID_INFO
  258. {
  259.     MPFS            hNode;
  260.  
  261.     BYTE            oid;
  262.     MIB_INFO        nodeInfo;
  263.     DATA_TYPE       dataType;
  264.     SNMP_ID         id;
  265.  
  266.     WORD_VAL        dataLen;
  267.     MPFS            hData;
  268.     MPFS            hSibling;
  269.     MPFS            hChild;
  270.     BYTE            index;
  271.     BYTE            indexLen;
  272. } OID_INFO;
  273.  
  274. static WORD SNMPTxOffset;
  275. static WORD SNMPRxOffset;
  276.  
  277. static BUFFER SNMPRxBuffer;
  278. static BUFFER SNMPTxBuffer;
  279.  
  280. static SNMP_STATUS SNMPStatus;
  281.  
  282. #define _SNMPSetTxOffset(o)     (SNMPTxOffset = o)
  283. #define _SNMPGetTxOffset()      SNMPTxOffset
  284.  
  285.  
  286. static SNMP_ACTION ProcessHeader(char *community, BYTE *len);
  287. static BOOL ProcessGetSetHeader(DWORD *requestID);
  288. static BOOL ProcessVariables(char *community,
  289.                             BYTE len,
  290.                             DWORD_VAL *request,
  291.                             BYTE pduType);
  292.  
  293. static BOOL OIDLookup(BYTE *oid, BYTE oidLen, OID_INFO *rec);
  294. static BOOL IsValidCommunity(char* community, BYTE *len);
  295. static BOOL IsValidInt(DWORD *val);
  296. static BOOL IsValidPDU(SNMP_ACTION *pdu);
  297. static BYTE IsValidLength(WORD *len);
  298. static BOOL IsASNNull(void);
  299. static BOOL IsValidOID(BYTE *oid, BYTE *len);
  300. static BYTE IsValidStructure(WORD *dataLen);
  301. static void _SNMPDuplexInit(UDP_SOCKET socket);
  302. static void _SNMPPut(BYTE v);
  303. static BYTE _SNMPGet(void);
  304. static BOOL GetNextLeaf(OID_INFO *n);
  305. static void ReadMIBRecord(MPFS h, OID_INFO *rec);
  306. static BOOL GetDataTypeInfo(DATA_TYPE dataType, DATA_TYPE_INFO *info);
  307. static BYTE ProcessGetVar(OID_INFO *rec, BOOL bAsOID);
  308. static BYTE ProcessGetNextVar(OID_INFO *rec);
  309. static BOOL GetOIDStringByAddr(OID_INFO *rec, BYTE *oidString, BYTE *len);
  310. static BYTE ProcessSetVar(OID_INFO *rec, SNMP_ERR_STATUS *errorStatus);
  311. static void SetErrorStatus(WORD errorStatusOffset,
  312.                            WORD errorIndexOffset,
  313.                            SNMP_ERR_STATUS errorStatus,
  314.                            BYTE errorIndex);
  315.  
  316. // This function is used only when TRAP is enabled.
  317. #if !defined(SNMP_TRAP_DISABED)
  318. static BOOL GetOIDStringByID(SNMP_ID id, OID_INFO *info, BYTE *oidString, BYTE *len);
  319. #endif
  320.  
  321.  
  322. /*********************************************************************
  323.  * Function:        void SNMPInit(void)
  324.  *
  325.  * PreCondition:    At least one UDP socket must be available.
  326.  *                  UDPInit() is already called.
  327.  *
  328.  * Input:           None
  329.  *
  330.  * Output:          SNMP agent module is initialized.
  331.  *
  332.  * Side Effects:    One UDP socket will be used.
  333.  *
  334.  * Overview:        Initialize SNMP module internals
  335.  *
  336.  * Note:            This function is called only once during lifetime
  337.  *                  of the application.
  338.  ********************************************************************/
  339. void SNMPInit(void)
  340. {
  341.     // Start with no error or flag set.
  342.     SNMPStatus.Val = 0;
  343.  
  344.     SNMPAgentSocket = UDPOpen(SNMP_AGENT_PORT, 0, INVALID_UDP_SOCKET);
  345.     // SNMPAgentSocket must not be INVALID_UDP_SOCKET.
  346.     // If it is, compile time value of UDP Socket numbers must be increased.
  347.  
  348.     return;
  349. }
  350.  
  351.  
  352. /*********************************************************************
  353.  * Function:        BOOL SNMPTask(void)
  354.  *
  355.  * PreCondition:    SNMPInit is already called.
  356.  *
  357.  * Input:           None
  358.  *
  359.  * Output:          TRUE if SNMP module has finished with a state
  360.  *                  FALSE if a state has not been finished.
  361.  *
  362.  *
  363.  * Side Effects:    None
  364.  *
  365.  * Overview:        Handle incoming SNMP requests as well as any
  366.  *                  outgoing SNMP responses and timeout conditions
  367.  *
  368.  * Note:            None.
  369.  ********************************************************************/
  370. BOOL SNMPTask(void)
  371. {
  372.     char community[SNMP_COMMUNITY_MAX_LEN];
  373.     BYTE communityLen;
  374.     DWORD_VAL requestID;
  375.     BYTE pdu;
  376.     MPFS hMIBFile;
  377.     BOOL lbReturn;
  378.  
  379.     char snmpBIBFile[] = SNMP_BIB_FILE_NAME;
  380.  
  381.     // Check to see if there is any packet on SNMP Agent socket.
  382.     if ( !UDPIsGetReady(SNMPAgentSocket) )
  383.         return TRUE;
  384.  
  385.     // As we process SNMP variables, we will prepare response on-the-fly
  386.     // creating full duplex transfer.
  387.     // Current MAC layer does not support full duplex transfer, so
  388.     // SNMP needs to manage its own full duplex connection.
  389.     // Prepare for full duplex transfer.
  390.     _SNMPDuplexInit(SNMPAgentSocket);
  391.  
  392.  
  393.     pdu = ProcessHeader(community, &communityLen);
  394.     if ( pdu == SNMP_ACTION_UNKNOWN )
  395.         goto _SNMPDiscard;
  396.  
  397.     if ( !ProcessGetSetHeader(&requestID.Val) )
  398.         goto _SNMPDiscard;
  399.  
  400.     // Open MIB file.
  401.     SNMPStatus.Flags.bIsFileOpen = FALSE;
  402.     hMIBFile = MPFSOpen((BYTE*)snmpBIBFile);
  403.     if ( hMIBFile != MPFS_INVALID )
  404.     {
  405.         SNMPStatus.Flags.bIsFileOpen = TRUE;
  406.     }
  407.  
  408.     lbReturn = ProcessVariables(community, communityLen, &requestID, pdu);
  409.     if ( SNMPStatus.Flags.bIsFileOpen )
  410.     {
  411.         MPFSClose();
  412.     }
  413.  
  414.     if ( lbReturn == FALSE )
  415.         goto _SNMPDiscard;
  416.  
  417.     UDPFlush();
  418.  
  419.     return TRUE;
  420.  
  421. _SNMPDiscard:
  422.     UDPDiscard();
  423.  
  424.     return TRUE;
  425. }
  426.  
  427.  
  428. #if !defined(SNMP_TRAP_DISABED)
  429. /*********************************************************************
  430.  * Function:        void SNMPNotifyPrepare(IP_ADDR *remoteHost,
  431.  *                                         char *community,
  432.  *                                         BYTE communityLen,
  433.  *                                         SNMP_ID agentIDVar,
  434.  *                                         BYTE notificationCode,
  435.  *                                         DWORD timestamp)
  436.  *
  437.  * PreCondition:    SNMPInit is already called.
  438.  *
  439.  * Input:           remoteHost  - pointer to remote Host IP address
  440.  *                  community   - Community string to use to notify
  441.  *                  communityLen- Community string length
  442.  *                  agentIDVar  - System ID to use identify this agent
  443.  *                  notificaitonCode - Notification Code to use
  444.  *                  timestamp   - Notification timestamp in 100th
  445.  *                                of second.
  446.  *
  447.  * Output:          None
  448.  *
  449.  * Side Effects:    None
  450.  *
  451.  * Overview:        This function prepares SNMP module to send SNMP
  452.  *                  trap (notification) to remote host.
  453.  *
  454.  * Note:            This is first of series of functions to complete
  455.  *                  SNMP notification.
  456.  ********************************************************************/
  457. void SNMPNotifyPrepare(IP_ADDR *remoteHost,
  458.                         char *community,
  459.                         BYTE communityLen,
  460.                         SNMP_ID agentIDVar,
  461.                         BYTE notificationCode,
  462.                         DWORD timestamp )
  463. {
  464.     strcpy(SNMPNotifyInfo.community, community);
  465.     SNMPNotifyInfo.communityLen = communityLen;
  466.  
  467.     SNMPNotifyInfo.agentIDVar = agentIDVar;
  468.     SNMPNotifyInfo.notificationCode = notificationCode;
  469.  
  470.     SNMPNotifyInfo.timestamp.Val = timestamp;
  471.  
  472.     ARPResolve(remoteHost);
  473. }
  474.  
  475.  
  476.  
  477. /*********************************************************************
  478.  * Function:        BOOL SNMPIsNotifyReady(IP_ADDR *remoteHost)
  479.  *
  480.  * PreCondition:    SNMPNotifyPrepare is already called and returned
  481.  *                  TRUE.
  482.  *
  483.  * Input:           remoteHost  - pointer to remote Host IP address
  484.  *
  485.  * Output:          TRUE if remoteHost IP address is resolved and
  486.  *                         SNMPNotify may be called.
  487.  *                  FALSE otherwise.
  488.  *                      This would fail if there were not UDP socket
  489.  *                      to open.
  490.  *
  491.  * Side Effects:    None
  492.  *
  493.  * Overview:        This function resolves given remoteHost IP address
  494.  *                  into MAC address using ARP module.
  495.  *                  If remoteHost is not aviailable, this function
  496.  *                  would never return TRUE.
  497.  *                  Application must implement timeout logic to
  498.  *                  handle "remoteHost not avialable" situation.
  499.  *
  500.  * Note:            None
  501.  ********************************************************************/
  502. BOOL SNMPIsNotifyReady(IP_ADDR *remoteHost)
  503. {
  504.     NODE_INFO remoteNode;
  505.  
  506.     if ( ARPIsResolved(remoteHost, &remoteNode.MACAddr) )
  507.     {
  508.         remoteNode.IPAddr.Val = remoteHost->Val;
  509.  
  510.         SNMPNotifyInfo.socket = UDPOpen(AGENT_NOTIFY_PORT, &remoteNode, SNMP_NMS_PORT);
  511.  
  512.         return (SNMPNotifyInfo.socket != INVALID_UDP_SOCKET);
  513.     }
  514.  
  515.     return FALSE;
  516. }
  517.  
  518.  
  519.  
  520. /*********************************************************************
  521.  * Function:        BOOL SNMPNotify(SNMP_ID var,
  522.  *                                  SNMP_VAL val,
  523.  *                                  SNMP_INDEX index)
  524.  *
  525.  * PreCondition:    SNMPIsNotified is already called and returned
  526.  *                  TRUE.
  527.  *
  528.  * Input:           var     - SNMP var ID that is to be used in
  529.  *                            notification
  530.  *                  val     - Value of var. Only value of
  531.  *                            BYTE, WORD or DWORD can be sent.
  532.  *                  index   - Index of var. If this var is a single,
  533.  *                            index would be 0, or else if this var
  534.  *                            is a sequence, index could be any
  535.  *                            value from 0 to 127.
  536.  *
  537.  * Output:          TRUE if SNMP notification was successful sent.
  538.  *                      This does not guarantee that remoteHost recieved
  539.  *                      it.
  540.  *                  FALSE otherwise.
  541.  *                      This would fail under following contions:
  542.  *                      1) Given SNMP_BIB_FILE does not exist in MPFS
  543.  *                      2) Given var does not exist.
  544.  *                      3) Previously given agentID does not exist
  545.  *                      4) Data type of given var is unknown - only
  546.  *                              possible if MPFS itself was corrupted.
  547.  *
  548.  * Side Effects:    None
  549.  *
  550.  * Overview:        This function creates SNMP trap PDU and sends it
  551.  *                  to previously specified remoteHost.
  552.  *
  553.  * Note:            None
  554.  ********************************************************************/
  555. BOOL SNMPNotify(SNMP_ID var,
  556.                SNMP_VAL val,
  557.                SNMP_INDEX index)
  558. {
  559.     BYTE len;
  560.     BYTE OIDValue[OID_MAX_LEN];
  561.     BYTE OIDLen;
  562.     BYTE agentIDLen;
  563.     BYTE *pOIDValue;
  564.     OID_INFO rec;
  565.     DATA_TYPE_INFO dataTypeInfo;
  566.     WORD packetStructLenOffset;
  567.     WORD pduStructLenOffset;
  568.     WORD varBindStructLenOffset;
  569.     WORD varPairStructLenOffset;
  570.     WORD prevOffset;
  571.     char *pCommunity;
  572.     MPFS hMIBFile;
  573.  
  574.     char snmpBIBFile[] = SNMP_BIB_FILE_NAME;
  575.  
  576.     hMIBFile = MPFSOpen((BYTE*)snmpBIBFile);
  577.     if ( hMIBFile == MPFS_INVALID )
  578.     {
  579.         UDPClose(SNMPNotifyInfo.socket);
  580.         return FALSE;
  581.     }
  582.  
  583.     _SNMPDuplexInit(SNMPNotifyInfo.socket);
  584.  
  585.     len = SNMPNotifyInfo.communityLen;
  586.     pCommunity = SNMPNotifyInfo.community;
  587.  
  588.     _SNMPPut(STRUCTURE);            // First item is packet structure
  589.     packetStructLenOffset = SNMPTxOffset;
  590.     _SNMPPut(0);
  591.  
  592.     // Put SNMP version info - only v1.0 is supported.
  593.     _SNMPPut(ASN_INT);              // Int type.
  594.     _SNMPPut(1);                    // One byte long value.
  595.     _SNMPPut(SNMP_V1);              // v1.0.
  596.  
  597.     //len = strlen(community);  // Save community length for later use.
  598.     _SNMPPut(OCTET_STRING);         // Octet string type.
  599.     _SNMPPut(len);                  // community string length
  600.     while( len-- )                  // Copy entire string.
  601.         _SNMPPut(*(pCommunity++));
  602.  
  603.     // Put PDU type.  SNMP agent's response is always GET RESPONSE
  604.     _SNMPPut(TRAP);
  605.     pduStructLenOffset = SNMPTxOffset;
  606.     _SNMPPut(0);
  607.  
  608.     // Get complete OID string from MPFS.
  609.     if ( !GetOIDStringByID(SNMPNotifyInfo.agentIDVar,
  610.                            &rec, OIDValue, &agentIDLen) )
  611.     {
  612.         MPFSClose();
  613.         UDPClose(SNMPNotifyInfo.socket);
  614.         return FALSE;
  615.     }
  616.  
  617.     if ( !rec.nodeInfo.Flags.bIsAgentID )
  618.     {
  619.         MPFSClose();
  620.         UDPClose(SNMPNotifyInfo.socket);
  621.         return FALSE;
  622.     }
  623.  
  624.     MPFSGetBegin(rec.hData);
  625.  
  626.     _SNMPPut(ASN_OID);
  627.     len = MPFSGet();
  628.     agentIDLen = len;
  629.     _SNMPPut(len);
  630.     while( len-- )
  631.         _SNMPPut(MPFSGet());
  632.  
  633.     MPFSGetEnd();
  634.  
  635.     // This agent's IP address.
  636.     _SNMPPut(SNMP_IP_ADDR);
  637.     _SNMPPut(4);
  638.     _SNMPPut(AppConfig.MyIPAddr.v[0]);
  639.     _SNMPPut(AppConfig.MyIPAddr.v[1]);
  640.     _SNMPPut(AppConfig.MyIPAddr.v[2]);
  641.     _SNMPPut(AppConfig.MyIPAddr.v[3]);
  642.  
  643.     // Trap code
  644.     _SNMPPut(ASN_INT);
  645.     _SNMPPut(1);
  646.     _SNMPPut(6);            // Enterprisespecific trap code
  647.  
  648.     _SNMPPut(ASN_INT);
  649.     _SNMPPut(1);
  650.     _SNMPPut(SNMPNotifyInfo.notificationCode);
  651.  
  652.     // Time stamp
  653.     _SNMPPut(SNMP_TIME_TICKS);
  654.     _SNMPPut(4);
  655.     _SNMPPut(SNMPNotifyInfo.timestamp.v[3]);
  656.     _SNMPPut(SNMPNotifyInfo.timestamp.v[2]);
  657.     _SNMPPut(SNMPNotifyInfo.timestamp.v[1]);
  658.     _SNMPPut(SNMPNotifyInfo.timestamp.v[0]);
  659.  
  660.     // Variable binding structure header
  661.     _SNMPPut(0x30);
  662.     varBindStructLenOffset = SNMPTxOffset;
  663.     _SNMPPut(0);
  664.  
  665.     // Create variable name-pair structure
  666.     _SNMPPut(0x30);
  667.     varPairStructLenOffset = SNMPTxOffset;
  668.     _SNMPPut(0);
  669.  
  670.     // Get complete notification variable OID string.
  671.     if ( !GetOIDStringByID(var, &rec, OIDValue, &OIDLen) )
  672.     {
  673.         MPFSClose();
  674.         UDPClose(SNMPNotifyInfo.socket);
  675.         return FALSE;
  676.     }
  677.  
  678.     // Copy OID string into packet.
  679.     _SNMPPut(ASN_OID);
  680.     _SNMPPut((BYTE)(OIDLen+1));
  681.     len = OIDLen;
  682.     pOIDValue = OIDValue;
  683.     while( len-- )
  684.         _SNMPPut(*pOIDValue++);
  685.     _SNMPPut(index);
  686.  
  687.     // Encode and Copy actual data bytes
  688.     if ( !GetDataTypeInfo(rec.dataType, &dataTypeInfo) )
  689.     {
  690.         MPFSClose();
  691.         UDPClose(SNMPNotifyInfo.socket);
  692.         return FALSE;
  693.     }
  694.  
  695.     _SNMPPut(dataTypeInfo.asnType);
  696.     // In this version, only data type of 4 bytes or less long can be
  697.     // notification variable.
  698.     if ( dataTypeInfo.asnLen == 0xff )
  699.     {
  700.         MPFSClose();
  701.         UDPClose(SNMPNotifyInfo.socket);
  702.         return FALSE;
  703.     }
  704.  
  705.     len = dataTypeInfo.asnLen;
  706.     _SNMPPut(len);
  707.     while( len-- )
  708.         _SNMPPut(val.v[len]);
  709.  
  710.     len = dataTypeInfo.asnLen           // data bytes count
  711.          + 1                            // Length byte
  712.          + 1                            // Data type byte
  713.          + OIDLen                       // OID bytes
  714.          + 2                            // OID header bytes
  715.          + 1;                           // index byte
  716.  
  717.     prevOffset = _SNMPGetTxOffset();
  718.     _SNMPSetTxOffset(varPairStructLenOffset);
  719.     _SNMPPut(len);
  720.  
  721.     len += 2;                           // Variable Binding structure header
  722.     _SNMPSetTxOffset(varBindStructLenOffset);
  723.     _SNMPPut(len);
  724.  
  725.     len = len
  726.         + 2                             // Var bind struct header
  727.         + 6                             // 6 bytes of timestamp
  728.         + 3                             // 3 bytes of trap code
  729.         + 3                             // 3 bytes of notification code
  730.         + 6                             // 6 bytes of agnent IP address
  731.         + agentIDLen                    // Agent ID bytes
  732.         + 2;                                // Agent ID header bytes
  733.     _SNMPSetTxOffset(pduStructLenOffset);
  734.     _SNMPPut(len);
  735.  
  736.     len = len                           // PDU struct length
  737.         + 2                             // PDU header
  738.         + SNMPNotifyInfo.communityLen            // Community string bytes
  739.         + 2                             // Community header bytes
  740.         + 3;                            // SNMP version bytes
  741.     _SNMPSetTxOffset(packetStructLenOffset);
  742.     _SNMPPut(len);
  743.  
  744.     _SNMPSetTxOffset(prevOffset);
  745.  
  746.     MPFSClose();
  747.     UDPFlush();
  748.     UDPClose(SNMPNotifyInfo.socket);
  749.  
  750.     return TRUE;
  751. }
  752. #endif // Code removed when SNMP_TRAP_DISABLED
  753.  
  754. static SNMP_ACTION ProcessHeader(char *community, BYTE *len)
  755. {
  756.     DWORD_VAL tempLen;
  757.     SNMP_ACTION pdu;
  758.  
  759.     // Very first item must be a structure
  760.     if ( !IsValidStructure((WORD*)&tempLen) )
  761.         return SNMP_ACTION_UNKNOWN;
  762.  
  763.     // Only SNMP v1.0 is supported.
  764.     if ( !IsValidInt(&tempLen.Val) )
  765.         return SNMP_ACTION_UNKNOWN;
  766.  
  767.     if ( tempLen.v[0] != SNMP_V1 )
  768.         return SNMP_ACTION_UNKNOWN;
  769.  
  770.     // This function populates response as it processes community string.
  771.     if ( !IsValidCommunity(community, len) )
  772.         return SNMP_ACTION_UNKNOWN;
  773.  
  774.     // Fetch and validate pdu type.  Only "Get" and "Get Next" are expected.
  775.     if ( !IsValidPDU(&pdu) )
  776.         return SNMP_ACTION_UNKNOWN;
  777.  
  778.     // Ask main application to verify community name against requested
  779.     // pdu type.
  780.     if ( !SNMPValidate(pdu, community) )
  781.         return SNMP_ACTION_UNKNOWN;
  782.  
  783.     return pdu;
  784. }
  785.  
  786. static BOOL ProcessGetSetHeader(DWORD *requestID)
  787. {
  788.     DWORD_VAL tempData;
  789.  
  790.     // Fetch and save request ID.
  791.     if ( IsValidInt(&tempData.Val) )
  792.         *requestID = tempData.Val;
  793.     else
  794.         return FALSE;
  795.  
  796.     // Fetch and discard error status
  797.     if ( !IsValidInt(&tempData.Val) )
  798.         return FALSE;
  799.  
  800.     // Fetch and disacard error index
  801.     return IsValidInt(&tempData.Val);
  802. }
  803.  
  804.  
  805. static BOOL ProcessVariables(char *community, BYTE len, DWORD_VAL *request, BYTE pduType)
  806. {
  807.     BYTE temp;
  808.     WORD_VAL varBindingLen;
  809.     WORD_VAL tempLen;
  810.     BYTE errorIndex;
  811.     SNMP_ERR_STATUS errorStatus;
  812.     BYTE varIndex;
  813.     WORD packetStructLenOffset;
  814.     WORD pduLenOffset;
  815.     WORD errorStatusOffset;
  816.     WORD errorIndexOffset;
  817.     WORD varBindStructOffset;
  818.     WORD varStructLenOffset;
  819.     BYTE OIDValue[OID_MAX_LEN];
  820.     BYTE OIDLen;
  821.     BYTE *ptemp;
  822.     OID_INFO OIDInfo;
  823.     WORD_VAL varPairLen;
  824.     WORD_VAL varBindLen;
  825.     BYTE communityLen;
  826.     WORD oidOffset;
  827.     WORD prevOffset;
  828.  
  829.  
  830.     // Before each variables are processed, prepare necessary header.
  831.     _SNMPPut(STRUCTURE);            // First item is packet structure
  832.     // Since we do not know length of structure at this point, use
  833.     // placeholder bytes that will be replaced with actual value.
  834.     _SNMPPut(0x82);
  835.     packetStructLenOffset = SNMPTxOffset;
  836.     _SNMPPut(0);
  837.     _SNMPPut(0);
  838.  
  839.     // Put SNMP version info - only v1.0 is supported.
  840.     _SNMPPut(ASN_INT);              // Int type.
  841.     _SNMPPut(1);                    // One byte long value.
  842.     _SNMPPut(SNMP_V1);              // v1.0.
  843.  
  844.     // Put community string
  845.     communityLen = len;             // Save community length for later use.
  846.     _SNMPPut(OCTET_STRING);         // Octet string type.
  847.     _SNMPPut(len);                  // community string length
  848.     while( len-- )                  // Copy entire string.
  849.         _SNMPPut(*community++);
  850.  
  851.     // Put PDU type.  SNMP agent's response is always GET RESPONSE
  852.     _SNMPPut(GET_RESPONSE);
  853.     // Since we don't know length of this response, use placeholders until
  854.     // we know for sure...
  855.     _SNMPPut(0x82);                    // Be prepared for 2 byte-long length
  856.     pduLenOffset = SNMPTxOffset;
  857.     _SNMPPut(0);
  858.     _SNMPPut(0);
  859.  
  860.     // Put original request back.
  861.     _SNMPPut(ASN_INT);              // Int type.
  862.     _SNMPPut(4);                    // To simplify logic, always use 4 byte long requestID
  863.     _SNMPPut(request->v[3]);         // Start MSB
  864.     _SNMPPut(request->v[2]);
  865.     _SNMPPut(request->v[1]);
  866.     _SNMPPut(request->v[0]);
  867.  
  868.     // Put error status.
  869.     // Since we do not know error status, put place holder until we know it...
  870.     _SNMPPut(ASN_INT);              // Int type
  871.     _SNMPPut(1);                    // One byte long.
  872.     errorStatusOffset = SNMPTxOffset;
  873.     _SNMPPut(0);                    // Placeholder.
  874.  
  875.     // Similarly put error index.
  876.     _SNMPPut(ASN_INT);              // Int type
  877.     _SNMPPut(1);                    // One byte long
  878.     errorIndexOffset = SNMPTxOffset;
  879.     _SNMPPut(0);                    // Placeholder.
  880.  
  881.     varIndex    = 0;
  882.     errorIndex  = 0;
  883.     errorStatus = SNMP_NO_ERR;
  884.  
  885.     // Decode variable binding structure
  886.     if ( !IsValidStructure(&varBindingLen.Val) )
  887.         return FALSE;
  888.  
  889.     // Put variable binding response structure
  890.     _SNMPPut(STRUCTURE);
  891.     _SNMPPut(0x82);
  892.     varBindStructOffset = SNMPTxOffset;
  893.     _SNMPPut(0);
  894.     _SNMPPut(0);
  895.  
  896.     varBindLen.Val = 0;
  897.  
  898.     while( varBindingLen.Val )
  899.     {
  900.         // Need to know what variable we are processing, so that in case
  901.         // if there is problem for that varaible, we can put it in
  902.         // errorIndex location of SNMP packet.
  903.         varIndex++;
  904.  
  905.         // Decode variable length structure
  906.         temp = IsValidStructure(&tempLen.Val);
  907.         if ( !temp )
  908.             return FALSE;
  909.  
  910.         varBindingLen.Val -= tempLen.Val;
  911.         varBindingLen.Val -= temp;
  912.  
  913.  
  914.         // Prepare variable response structure.
  915.         _SNMPPut(STRUCTURE);
  916.         _SNMPPut(0x82);
  917.         varStructLenOffset = SNMPTxOffset;
  918.         _SNMPPut(0);
  919.         _SNMPPut(0);
  920.  
  921.         // Decode next object
  922.         if ( !IsValidOID(OIDValue, &OIDLen) )
  923.             return FALSE;
  924.  
  925.         // For Get & Get-Next, value must be NULL.
  926.         if ( pduType != (BYTE)SET_REQUEST )
  927.         {
  928.             if ( !IsASNNull() )
  929.                 return FALSE;
  930.         }
  931.  
  932.         // Prepare response - original variable
  933.         _SNMPPut(ASN_OID);
  934.         oidOffset = SNMPTxOffset;
  935.         _SNMPPut(OIDLen);
  936.         ptemp = OIDValue;
  937.         temp = OIDLen;
  938.         while( temp-- )
  939.             _SNMPPut(*ptemp++);
  940.  
  941.         // Lookup current OID into our compiled database.
  942.         if ( !OIDLookup(OIDValue, OIDLen, &OIDInfo) )
  943.         {
  944.  
  945.             errorStatus = SNMP_NO_SUCH_NAME;
  946.  
  947.             SetErrorStatus(errorStatusOffset,
  948.                             errorIndexOffset,
  949.                             SNMP_NO_SUCH_NAME,
  950.                             varIndex);
  951.  
  952.             if ( pduType != SNMP_SET )
  953.             {
  954.                 _SNMPPut(ASN_NULL);
  955.                 _SNMPPut(0);
  956.                 varPairLen.Val = OIDLen + 4;
  957.             }
  958.             else
  959.             {
  960.                 // Copy original value as it is and goto next variable.
  961.                 // Copy data type
  962.                 _SNMPPut(_SNMPGet());
  963.  
  964.                 // Get data length.
  965.                 temp = _SNMPGet();
  966.                 _SNMPPut(temp);
  967.  
  968.                 // Start counting total number of bytes in this structure.
  969.                 varPairLen.Val = OIDLen         // OID name bytes
  970.                                 + 2             // OID header bytes
  971.                                 + 2;            // Value header bytes
  972.  
  973.                 // Copy entire data bytes as it is.
  974.                 while( temp-- )
  975.                 {
  976.                     varPairLen.Val++;
  977.                     _SNMPPut(_SNMPGet());
  978.                 }
  979.             }
  980.  
  981.         }
  982.  
  983.         else
  984.         {
  985.             // Now handle specific pduType request...
  986.             if ( pduType == SNMP_GET )
  987.             {
  988.                 // Start counting total number of bytes in this structure.
  989.                 varPairLen.Val = OIDLen + 2;
  990.  
  991.                 prevOffset = _SNMPGetTxOffset();
  992.                 temp = ProcessGetVar(&OIDInfo, FALSE);
  993.                 if ( temp == 0 )
  994.                 {
  995.                     _SNMPSetTxOffset(prevOffset);
  996.                     errorStatus = SNMP_NO_SUCH_NAME;
  997.  
  998.                     SetErrorStatus(errorStatusOffset,
  999.                                    errorIndexOffset,
  1000.                                    SNMP_NO_SUCH_NAME,
  1001.                                    varIndex);
  1002.  
  1003.                     _SNMPPut(ASN_NULL);
  1004.                     _SNMPPut(0);
  1005.                     temp = 2;
  1006.                 }
  1007.                 varPairLen.Val += temp;
  1008.             }
  1009.  
  1010.             else if ( pduType == SNMP_GET_NEXT )
  1011.             {
  1012.                 prevOffset = _SNMPGetTxOffset();
  1013.                 _SNMPSetTxOffset(oidOffset);
  1014.                 temp = ProcessGetNextVar(&OIDInfo);
  1015.                 if ( temp == 0 )
  1016.                 {
  1017.                     _SNMPSetTxOffset(prevOffset);
  1018.  
  1019.                     SetErrorStatus(errorStatusOffset,
  1020.                                    errorIndexOffset,
  1021.                                    SNMP_NO_SUCH_NAME,
  1022.                                    varIndex);
  1023.  
  1024.  
  1025.                     _SNMPPut(ASN_NULL);
  1026.                     _SNMPPut(0);
  1027.  
  1028.                     // Start counting total number of bytes in this structure.
  1029.                     varPairLen.Val = OIDLen             // as put by GetNextVar()
  1030.                                      + 2                // OID header
  1031.                                      + 2;               // ASN_NULL bytes
  1032.  
  1033.                 }
  1034.                 else
  1035.                     varPairLen.Val = (temp + 2);        // + OID headerbytes
  1036.             }
  1037.  
  1038.             else if ( pduType == SNMP_SET )
  1039.             {
  1040.                 temp = ProcessSetVar(&OIDInfo, &errorStatus);
  1041.                 if ( errorStatus != SNMP_NO_ERR )
  1042.                 {
  1043.                     SetErrorStatus(errorStatusOffset,
  1044.                                    errorIndexOffset,
  1045.                                    errorStatus,
  1046.                                    varIndex);
  1047.                 }
  1048.                 varPairLen.Val = OIDLen +2              // OID name + header bytes
  1049.                                 + temp;                 // value bytes as put by SetVar
  1050.             }
  1051.  
  1052.         }
  1053.         prevOffset = _SNMPGetTxOffset();
  1054.  
  1055.         _SNMPSetTxOffset(varStructLenOffset);
  1056.         _SNMPPut(varPairLen.byte.MSB);
  1057.         _SNMPPut(varPairLen.byte.LSB);
  1058.  
  1059.  
  1060.         varBindLen.Val += 4                 // Variable Pair STRUCTURE byte + 1 length byte.
  1061.                         + varPairLen.Val;
  1062.  
  1063.         _SNMPSetTxOffset(prevOffset);
  1064.     }
  1065.  
  1066.  
  1067.     //MACSetTxBuffer(SNMPTxBuffer, varBindStructOffset);
  1068.     _SNMPSetTxOffset(varBindStructOffset);
  1069.     _SNMPPut(varBindLen.byte.MSB);
  1070.     _SNMPPut(varBindLen.byte.LSB);
  1071.  
  1072.     // varBindLen is reused as "pduLen"
  1073.     varBindLen.Val = varBindLen.Val+4           // Variable Binding Strucure length
  1074.                 + 6                         // Request ID bytes
  1075.                 + 3                         // Error status
  1076.                 + 3;                        // Error index
  1077.  
  1078.     //MACSetTxBuffer(SNMPTxBuffer, pduLenOffset);
  1079.     _SNMPSetTxOffset(pduLenOffset);
  1080.     _SNMPPut(varBindLen.byte.MSB);
  1081.     _SNMPPut(varBindLen.byte.LSB);
  1082.  
  1083.     // varBindLen is reused as "packetLen".
  1084.     varBindLen.Val = 3                      // SNMP Version bytes
  1085.                     + 2 + communityLen      // community string bytes
  1086.                     + 4                     // PDU structure header bytes.
  1087.                     + varBindLen.Val;
  1088.  
  1089.     //MACSetTxBuffer(SNMPTxBuffer, packetStructLenOffset);
  1090.     _SNMPSetTxOffset(packetStructLenOffset);
  1091.     _SNMPPut(varBindLen.byte.MSB);
  1092.     _SNMPPut(varBindLen.byte.LSB);
  1093.  
  1094.  
  1095.     return TRUE;
  1096. }
  1097.  
  1098.  
  1099.  
  1100.  
  1101. static BYTE ProcessGetNextVar(OID_INFO *rec)
  1102. {
  1103.     WORD_VAL temp;
  1104.     BYTE putBytes;
  1105.     OID_INFO indexRec;
  1106.     BYTE *pOIDValue;
  1107.     BYTE OIDValue[51];
  1108.     BYTE OIDLen;
  1109.     INDEX_INFO indexInfo;
  1110.     MIB_INFO varNodeInfo;
  1111.     SNMP_ID varID;
  1112.     WORD OIDValOffset;
  1113.     WORD prevOffset;
  1114.     BOOL lbNextLeaf;
  1115.     BYTE ref;
  1116.     SNMP_VAL v;
  1117.     BYTE varDataType;
  1118.     BYTE indexBytes;
  1119.  
  1120.     lbNextLeaf = FALSE;
  1121.     temp.byte.LSB = 0;
  1122.  
  1123.     // Get next leaf only if this OID is a parent or a simple leaf
  1124.     // node.
  1125.     if ( rec->nodeInfo.Flags.bIsParent ||
  1126.         (!rec->nodeInfo.Flags.bIsParent && !rec->nodeInfo.Flags.bIsSequence) )
  1127.     {
  1128. _GetNextLeaf:
  1129.         lbNextLeaf = TRUE;
  1130.         if ( !GetNextLeaf(rec) )
  1131.             return 0;
  1132.     }
  1133.  
  1134.     // Get complete OID string from oid record.
  1135.     if ( !GetOIDStringByAddr(rec, OIDValue, &OIDLen) )
  1136.         return 0;
  1137.  
  1138.     // Copy complete OID string to create response packet.
  1139.     pOIDValue = OIDValue;
  1140.     OIDValOffset = _SNMPGetTxOffset();
  1141.     temp.byte.LSB = OIDLen;
  1142.     _SNMPSetTxOffset(OIDValOffset+1);
  1143.     while( temp.byte.LSB-- )
  1144.         _SNMPPut(*pOIDValue++);
  1145.  
  1146.     // Start counting number of bytes put - OIDLen is already counted.
  1147.     temp.byte.LSB = OIDLen;
  1148.  
  1149.  
  1150.     varDataType = rec->dataType;
  1151.     varID = rec->id;
  1152.  
  1153.  
  1154.     // If this is a simple OID, handle it as a GetVar command.
  1155.     if ( !rec->nodeInfo.Flags.bIsSequence )
  1156.     {
  1157.         // This is an addition to previously copied OID string.
  1158.         // This is index value of '0'.
  1159.         _SNMPPut(0);
  1160.         temp.byte.LSB++;
  1161.  
  1162.         // Since we added one more byte to previously copied OID
  1163.         // string, we need to update OIDLen value.
  1164.         prevOffset = _SNMPGetTxOffset();
  1165.         _SNMPSetTxOffset(OIDValOffset);
  1166.         _SNMPPut(++OIDLen);
  1167.         _SNMPSetTxOffset(prevOffset);
  1168.  
  1169.         // Now do Get on this simple variable.
  1170.         prevOffset = _SNMPGetTxOffset();
  1171.         putBytes = ProcessGetVar(rec, FALSE);
  1172.         if ( putBytes == 0 )
  1173.         {
  1174.             _SNMPSetTxOffset(prevOffset);
  1175.             _SNMPPut(ASN_NULL);
  1176.             _SNMPPut(0);
  1177.             putBytes = 2;
  1178.         }
  1179.  
  1180.         temp.byte.LSB += putBytes; // ProcessGetVar(rec, FALSE);
  1181.  
  1182.         // Return with total number of bytes copied to response packet.
  1183.         return temp.byte.LSB;
  1184.     }
  1185.  
  1186.     // This is a sequence variable.
  1187.  
  1188.     // First of all make sure that there is a next index after this
  1189.     // index.  We also need to make sure that we do not do this foerever.
  1190.     // So make sure that this is not a repeat test.
  1191.     ref = 0;
  1192.     if ( lbNextLeaf == TRUE )
  1193.     {
  1194.         // Let application tell us whether this is a valid index or not.
  1195.         if ( !SNMPGetVar(rec->id, rec->index, &ref, &v) )
  1196.         {
  1197.             // If not, then we need to get next leaf in line.
  1198.             // Remember that we have already did this once, so that we do not
  1199.             // do this forever.
  1200.             //lbNextSequence = TRUE;
  1201.  
  1202.             // Reset the response packet pointer to begining of OID.
  1203.             _SNMPSetTxOffset(OIDValOffset);
  1204.  
  1205.             // Jump to this label within this function - Not a good SW engineering
  1206.             // practice, but this will reuse code at much lower expense.
  1207.             goto _GetNextLeaf;
  1208.         }
  1209.     }
  1210.  
  1211.     // Need to fetch index information from MIB and prepare complete OID+
  1212.     // index response.
  1213.  
  1214.     varNodeInfo.Val = rec->nodeInfo.Val;
  1215.  
  1216.     MPFSGetBegin(MPFSTell());
  1217.  
  1218.     // In this version, only 7-bit index is supported.
  1219.     MPFSGet();
  1220.  
  1221.     indexBytes = 0;
  1222.  
  1223.     indexInfo.Val = MPFSGet();
  1224.  
  1225.     // Fetch index ID.
  1226.     indexRec.id = MPFSGet();
  1227.     // Fetch index data type.
  1228.     indexRec.dataType = MPFSGet();
  1229.  
  1230.     indexRec.index = rec->index;
  1231.  
  1232.     MPFSGetEnd();
  1233.  
  1234.     // Check with application to see if there exists next index
  1235.     // for this index id.
  1236.     if ( !lbNextLeaf && !SNMPGetNextIndex(indexRec.id, &indexRec.index) )
  1237.     {
  1238.         //lbNextSeqeuence = TRUE;
  1239.  
  1240.         // Reset the response packet pointer to begining of OID.
  1241.         _SNMPSetTxOffset(OIDValOffset);
  1242.  
  1243.         // Jump to this label.  Not a good practice, but once-in-a-while
  1244.         // it should be acceptable !
  1245.         goto _GetNextLeaf;
  1246.     }
  1247.  
  1248.     // Index is assumed to be dynamic, and leaf node.
  1249.     // mib2bib has already ensured that this was the case.
  1250.     indexRec.nodeInfo.Flags.bIsConstant = 0;
  1251.     indexRec.nodeInfo.Flags.bIsParent = 0;
  1252.     indexRec.nodeInfo.Flags.bIsSequence = 1;
  1253.  
  1254.     // Now handle this as simple GetVar.
  1255.     // Keep track of number of bytes added to OID.
  1256.     indexBytes += ProcessGetVar(&indexRec, TRUE);
  1257.  
  1258.     rec->index = indexRec.index;
  1259.  
  1260.     // These are the total number of bytes put so far as a result of this function.
  1261.     temp.byte.LSB += indexBytes;
  1262.  
  1263.     // These are the total number of bytes in OID string including index bytes.
  1264.     OIDLen += indexBytes;
  1265.  
  1266.     // Since we added index bytes to previously copied OID
  1267.     // string, we need to update OIDLen value.
  1268.     prevOffset = _SNMPGetTxOffset();
  1269.     _SNMPSetTxOffset(OIDValOffset);
  1270.     _SNMPPut(OIDLen);
  1271.     _SNMPSetTxOffset(prevOffset);
  1272.  
  1273.  
  1274.     // Fetch actual value itself.
  1275.     // Need to restore original OID value.
  1276.     rec->nodeInfo.Val = varNodeInfo.Val;
  1277.     rec->id = varID;
  1278.     rec->dataType = varDataType;
  1279.  
  1280.     temp.byte.LSB += ProcessGetVar(rec, FALSE);
  1281.  
  1282.     return temp.byte.LSB;
  1283. }
  1284.  
  1285.  
  1286.  
  1287.  
  1288. // This is the binary mib format:
  1289. // <oid, nodeInfo, [id], [SiblingOffset], [DistantSibling], [dataType], [dataLen], [data], [{IndexCount, <IndexType>, <Index>, ...>]}, ChildNode
  1290. static BOOL OIDLookup(BYTE *oid, BYTE oidLen, OID_INFO *rec)
  1291. {
  1292.     WORD_VAL tempData;
  1293.     BYTE tempOID;
  1294.     MPFS hNode;
  1295.     BYTE matchedCount;
  1296.  
  1297.     if ( !SNMPStatus.Flags.bIsFileOpen )
  1298.         return FALSE;
  1299.  
  1300.  
  1301.     hNode = MPFSSeek(0);
  1302.     matchedCount = oidLen;
  1303.  
  1304.     // Begin reading the data...
  1305.     //MPFSGetBegin(hNode);
  1306.  
  1307.     while( 1 )
  1308.     {
  1309.         MPFSGetBegin(hNode);
  1310.  
  1311.         // Remember offset of this node so that we can find its sibling
  1312.         // and child data.
  1313.         rec->hNode = MPFSTell(); // hNode;
  1314.  
  1315.         // Read OID byte.
  1316.         tempOID = MPFSGet();
  1317.  
  1318.         // Read Node Info
  1319.         rec->nodeInfo.Val = MPFSGet();
  1320.  
  1321.         // Next byte will be node id, if this is a leaf node with variable data.
  1322.         if ( rec->nodeInfo.Flags.bIsIDPresent )
  1323.             rec->id = MPFSGet();
  1324.  
  1325.         // Read sibling offset, if there is any.
  1326.         if ( rec->nodeInfo.Flags.bIsSibling )
  1327.         {
  1328.             tempData.v[0] = MPFSGet();
  1329.             tempData.v[1] = MPFSGet();
  1330.             rec->hSibling = (MPFS)tempData.Val;
  1331.         }
  1332.  
  1333.         if ( tempOID != *oid )
  1334.         {
  1335.             // If very first OID byte does not match, it may be because it is
  1336.             // 0, 1 or 2.  In that case declare that there is a match.
  1337.             // The command processor would detect OID type and continue or reject
  1338.             // this OID as a valid argument.
  1339.             if ( matchedCount == oidLen )
  1340.                 goto FoundIt;
  1341.  
  1342.             if ( rec->nodeInfo.Flags.bIsSibling )
  1343.             {
  1344.                 MPFSGetEnd();
  1345.                 hNode = MPFSSeek((MPFS)tempData.Val);
  1346.             }
  1347.             else
  1348.                 goto DidNotFindIt;
  1349.         }
  1350.         else
  1351.         {
  1352.             // One more oid byte matched.
  1353.             matchedCount--;
  1354.             oid++;
  1355.  
  1356.             // A node is said to be matched if last matched node is a leaf node
  1357.             // or all but last OID string is matched and last byte of OID is '0'.
  1358.             // i.e. single index.
  1359.             if ( !rec->nodeInfo.Flags.bIsParent )
  1360.             {
  1361.                 // Read and discard Distant Sibling info if there is any.
  1362.                 if ( rec->nodeInfo.Flags.bIsDistantSibling )
  1363.                 {
  1364.                     tempData.v[0] = MPFSGet();
  1365.                     tempData.v[1] = MPFSGet();
  1366.                     rec->hSibling = (MPFS)tempData.Val;
  1367.                 }
  1368.  
  1369.  
  1370.                 rec->dataType = MPFSGet();
  1371.                 rec->hData = MPFSTell();
  1372.  
  1373.                 goto FoundIt;
  1374.             }
  1375.  
  1376.             else if ( matchedCount == 1 && *oid == 0x00 )
  1377.             {
  1378.                 goto FoundIt;
  1379.             }
  1380.  
  1381.             else if ( matchedCount == 0 )
  1382.             {
  1383.                 goto FoundIt;
  1384.             }
  1385.  
  1386.             else
  1387.             {
  1388.                 //hNode = rec->hChild;
  1389.                 hNode = MPFSTell();
  1390.                 MPFSGetEnd();
  1391.                 // Try to match following child node.
  1392.                 continue;
  1393.             }
  1394.         }
  1395.     }
  1396.  
  1397. FoundIt:
  1398.     MPFSGetEnd();
  1399.     // Convert index info from OID to regular value format.
  1400.     tempOID = *oid;
  1401.     rec->index = tempOID;
  1402.  
  1403.     // In this version, we only support 7-bit index.
  1404.     if ( matchedCount == 0 )
  1405.     {
  1406.         rec->index = SNMP_INDEX_INVALID;
  1407.         rec->indexLen = 0;
  1408.     }
  1409.  
  1410.     else if ( matchedCount > 1 || tempOID & 0x80 )
  1411.     {
  1412.         // Current instnace spans across more than 7-bit.
  1413.         rec->indexLen = 0xff;
  1414.         return FALSE;
  1415.     }
  1416.     else
  1417.         rec->indexLen = 1;
  1418.  
  1419.  
  1420.  
  1421.     return TRUE;
  1422.  
  1423. DidNotFindIt:
  1424.     MPFSGetEnd();
  1425.     return FALSE;
  1426. }
  1427.  
  1428.  
  1429. static BOOL GetNextLeaf(OID_INFO *n)
  1430. {
  1431.     WORD_VAL temp;
  1432.  
  1433.     // If current node is leaf, its next sibling (near or distant) is the next leaf.
  1434.     if ( !n->nodeInfo.Flags.bIsParent )
  1435.     {
  1436.         // Since this is a leaf node, it must have at least one distant or near
  1437.         // sibling to get next sibling.
  1438.         if ( n->nodeInfo.Flags.bIsSibling ||
  1439.              n->nodeInfo.Flags.bIsDistantSibling )
  1440.         {
  1441.             // Reposition at sibling.
  1442.             MPFSSeek(n->hSibling);
  1443.  
  1444.             // Fetch node related information
  1445.         }
  1446.         // There is no sibling to this leaf.  This must be the very last node on the tree.
  1447.         else
  1448.         {
  1449.             //--MPFSClose();
  1450.             return FALSE;
  1451.         }
  1452.     }
  1453.  
  1454.     while( 1 )
  1455.     {
  1456.         // Remember current MPFS position for this node.
  1457.         n->hNode = MPFSTell();
  1458.  
  1459.         MPFSGetBegin(n->hNode);
  1460.  
  1461.  
  1462.         // Read OID byte.
  1463.         n->oid = MPFSGet();
  1464.  
  1465.         // Read Node Info
  1466.         n->nodeInfo.Val = MPFSGet();
  1467.  
  1468.         // Next byte will be node id, if this is a leaf node with variable data.
  1469.         if ( n->nodeInfo.Flags.bIsIDPresent )
  1470.             n->id = MPFSGet();
  1471.  
  1472.         // Fetch sibling offset, if there is any.
  1473.         if ( n->nodeInfo.Flags.bIsSibling ||
  1474.              n->nodeInfo.Flags.bIsDistantSibling )
  1475.         {
  1476.             temp.byte.LSB = MPFSGet();
  1477.             temp.byte.MSB = MPFSGet();
  1478.             n->hSibling = temp.Val;
  1479.         }
  1480.  
  1481.         // If we have not reached a leaf yet, continue fetching next child in line.
  1482.         if ( n->nodeInfo.Flags.bIsParent )
  1483.         {
  1484.             MPFSGetEnd();
  1485.             continue;
  1486.         }
  1487.  
  1488.         // Fetch data type.
  1489.         n->dataType = MPFSGet();
  1490.  
  1491.         n->hData = MPFSTell();
  1492.  
  1493.         // Since we just found next leaf in line, it will always have zero index
  1494.         // to it.
  1495.         n->indexLen = 1;
  1496.         n->index = 0;
  1497.  
  1498.         MPFSGetEnd();
  1499.  
  1500.         return TRUE;
  1501.     }
  1502.  
  1503.     return FALSE;
  1504. }
  1505.  
  1506.  
  1507.  
  1508.  
  1509.  
  1510. static BOOL IsValidCommunity(char* community, BYTE *len)
  1511. {
  1512.     BYTE tempData;
  1513.     BYTE tempLen;
  1514.  
  1515.     tempData = _SNMPGet();
  1516.     if ( !IS_OCTET_STRING(tempData) )
  1517.         return FALSE;
  1518.  
  1519.     tempLen = _SNMPGet();
  1520.     *len    = tempLen;
  1521.     if ( tempLen > SNMP_COMMUNITY_MAX_LEN )
  1522.         return FALSE;
  1523.  
  1524.     while( tempLen-- )
  1525.     {
  1526.         tempData = _SNMPGet();
  1527.         *community++ = tempData;
  1528.     }
  1529.     *community = '\0';
  1530.  
  1531.     return TRUE;
  1532. }
  1533.  
  1534.  
  1535. static BOOL IsValidInt(DWORD *val)
  1536. {
  1537.     DWORD_VAL tempData;
  1538.     DWORD_VAL tempLen;
  1539.  
  1540.     tempLen.Val = 0;
  1541.  
  1542.     // Get variable type
  1543.     if ( !IS_ASN_INT(_SNMPGet()) )
  1544.         return FALSE;
  1545.  
  1546.     if ( !IsValidLength(&tempLen.word.LSW) )
  1547.         return FALSE;
  1548.  
  1549.     // Integer length of more than 32-bit is not supported.
  1550.     if ( tempLen.Val > 4 )
  1551.         return FALSE;
  1552.  
  1553.     tempData.Val = 0;
  1554.     while( tempLen.v[0]-- )
  1555.         tempData.v[tempLen.v[0]] = _SNMPGet();
  1556.  
  1557.     *val = tempData.Val;
  1558.  
  1559.     return TRUE;
  1560. }
  1561.  
  1562. static BOOL IsValidPDU(SNMP_ACTION *pdu)
  1563. {
  1564.     BYTE tempData;
  1565.     WORD tempLen;
  1566.  
  1567.  
  1568.     // Fetch pdu data type
  1569.     tempData = _SNMPGet();
  1570.     if ( !IS_AGENT_PDU(tempData) )
  1571.         return FALSE;
  1572.  
  1573.     *pdu = tempData;
  1574.  
  1575.     // Now fetch pdu length.  We don't need to remember pdu length.
  1576.     return IsValidLength(&tempLen);
  1577. }
  1578.  
  1579. // Checks current packet and returns total length value
  1580. // as well as actual length bytes.
  1581. static BYTE IsValidLength(WORD *len)
  1582. {
  1583.     BYTE tempData;
  1584.     WORD_VAL tempLen;
  1585.     BYTE lengthBytes;
  1586.  
  1587.     // Initialize length value.
  1588.     tempLen.Val = 0;
  1589.     lengthBytes = 0;
  1590.  
  1591.     tempData = _SNMPGet();
  1592.     tempLen.v[0] = tempData;
  1593.     if ( tempData & 0x80 )
  1594.     {
  1595.         tempData &= 0x7F;
  1596.  
  1597.         // We do not support any length byte count of more than 2
  1598.         // i.e. total length value must not be more than 16-bit.
  1599.         if ( tempData > 2 )
  1600.             return FALSE;
  1601.  
  1602.         // Total length bytes are 0x80 itself plus tempData.
  1603.         lengthBytes = tempData + 1;
  1604.  
  1605.         // Get upto 2 bytes of length value.
  1606.         while( tempData-- )
  1607.             tempLen.v[tempData] = _SNMPGet();
  1608.     }
  1609.     else
  1610.         lengthBytes = 1;
  1611.  
  1612.     *len = tempLen.Val;
  1613.  
  1614.     return lengthBytes;
  1615. }
  1616.  
  1617. static BOOL IsASNNull(void)
  1618. {
  1619.     // Fetch and verify that this is NULL data type.
  1620.     if ( !IS_ASN_NULL(_SNMPGet()) )
  1621.         return FALSE;
  1622.  
  1623.     // Fetch and verify that length value is zero.
  1624.     return (_SNMPGet() == 0 );
  1625. }
  1626.  
  1627. static BOOL IsValidOID(BYTE *oid, BYTE *len)
  1628. {
  1629.     DWORD_VAL tempLen;
  1630.  
  1631.     // Fetch and verify that this is OID.
  1632.     if ( !IS_OID(_SNMPGet()) )
  1633.         return FALSE;
  1634.  
  1635.     // Retrieve OID length
  1636.     if ( !IsValidLength(&tempLen.word.LSW) )
  1637.         return FALSE;
  1638.  
  1639.     // Make sure that OID length is within our capability.
  1640.     if ( tempLen.word.LSW > OID_MAX_LEN )
  1641.         return FALSE;
  1642.  
  1643.     *len = tempLen.v[0];
  1644.  
  1645.     while( tempLen.v[0]-- )
  1646.         *oid++ = _SNMPGet();
  1647.  
  1648.  
  1649.     return TRUE;
  1650. }
  1651.  
  1652.  
  1653. static BYTE IsValidStructure(WORD *dataLen)
  1654. {
  1655.     DWORD_VAL tempLen;
  1656.     BYTE headerBytes;
  1657.  
  1658.  
  1659.     if ( !IS_STRUCTURE(_SNMPGet()) )
  1660.         return FALSE;
  1661.  
  1662.     // Retrieve structure length
  1663.     headerBytes = IsValidLength(&tempLen.word.LSW);
  1664.     if ( !headerBytes )
  1665.         return FALSE;
  1666.  
  1667.     headerBytes++;
  1668.  
  1669.  
  1670.     // Since we are using UDP as our transport and UDP are not fragmented,
  1671.     // this structure length cannot be more than 1500 bytes.
  1672.     // As a result, we will only use lower WORD of length value.
  1673.     *dataLen = tempLen.word.LSW;
  1674.  
  1675.     return headerBytes;
  1676. }
  1677.  
  1678.  
  1679.  
  1680.  
  1681. static void _SNMPDuplexInit(UDP_SOCKET socket)
  1682. {
  1683.     // In full duplex transfer, transport protocol must be ready to
  1684.     // accept new transmit packet.
  1685.     while( !UDPIsPutReady(socket) ) ;
  1686.  
  1687.     // Fetch and remember current tx and rx buffer id.
  1688.     SNMPRxBuffer = MACGetRxBuffer();
  1689.     SNMPTxBuffer = MACGetTxBuffer();
  1690.  
  1691.     // Initialize buffer offsets.
  1692.     SNMPRxOffset = 0;
  1693.     SNMPTxOffset = 0;
  1694. }
  1695.  
  1696.  
  1697. static void _SNMPPut(BYTE v)
  1698. {
  1699.     UDPSetTxBuffer(SNMPTxBuffer, SNMPTxOffset);
  1700.  
  1701.     UDPPut(v);
  1702.  
  1703.     SNMPTxOffset++;
  1704. }
  1705.  
  1706.  
  1707. static BYTE _SNMPGet(void)
  1708. {
  1709.     BYTE v;
  1710.  
  1711.     UDPSetRxBuffer(SNMPRxOffset++);
  1712.     UDPGet(&v);
  1713.     return v;
  1714. }
  1715.  
  1716.  
  1717. #if !defined(SNMP_TRAP_DISABED)
  1718. static BOOL GetOIDStringByID(SNMP_ID id, OID_INFO *info, BYTE *oidString, BYTE *len)
  1719. {
  1720.     MPFS hCurrent;
  1721.  
  1722.     hCurrent = MPFSSeek(0);
  1723.  
  1724.     while (1)
  1725.     {
  1726.         ReadMIBRecord(hCurrent, info);
  1727.  
  1728.         if ( !info->nodeInfo.Flags.bIsParent )
  1729.         {
  1730.             if ( info->nodeInfo.Flags.bIsIDPresent )
  1731.             {
  1732.                 if ( info->id == id )
  1733.                     return GetOIDStringByAddr(info, oidString, len);
  1734.             }
  1735.  
  1736.             if ( info->nodeInfo.Flags.bIsSibling ||
  1737.                  info->nodeInfo.Flags.bIsDistantSibling )
  1738.                 MPFSSeek(info->hSibling);
  1739.  
  1740.             else
  1741.                 break;
  1742.  
  1743.         }
  1744.         hCurrent = MPFSTell();
  1745.     }
  1746.     return FALSE;
  1747. }
  1748. #endif
  1749.  
  1750.  
  1751.  
  1752.  
  1753. static BOOL GetOIDStringByAddr(OID_INFO *rec, BYTE *oidString, BYTE *len)
  1754. {
  1755.     MPFS hTarget;
  1756.     MPFS hCurrent;
  1757.     MPFS hNext;
  1758.     OID_INFO currentMIB;
  1759.     BYTE index;
  1760.     enum { SM_PROBE_SIBLING, SM_PROBE_CHILD } state;
  1761.  
  1762.     hCurrent = MPFSSeek(0);
  1763.  
  1764.  
  1765.     hTarget = rec->hNode;
  1766.     state = SM_PROBE_SIBLING;
  1767.     index = 0;
  1768.  
  1769.     while( 1 )
  1770.     {
  1771.         ReadMIBRecord(hCurrent, &currentMIB);
  1772.  
  1773.         oidString[index] = currentMIB.oid;
  1774.  
  1775.         if ( hTarget == hCurrent )
  1776.         {
  1777.             *len = ++index;
  1778.  
  1779.             return TRUE;
  1780.         }
  1781.  
  1782.  
  1783.         switch(state)
  1784.         {
  1785.         case SM_PROBE_SIBLING:
  1786.             if ( !currentMIB.nodeInfo.Flags.bIsSibling )
  1787.                 state = SM_PROBE_CHILD;
  1788.  
  1789.             else
  1790.             {
  1791.                 hNext = currentMIB.hSibling;
  1792.                 MPFSSeek(hNext);
  1793.                 hNext = MPFSTell();
  1794.                 if ( hTarget >= hNext )
  1795.                 {
  1796.                     hCurrent = hNext;
  1797.                     break;
  1798.                 }
  1799.                 else
  1800.                     state = SM_PROBE_CHILD;
  1801.             }
  1802.  
  1803.         case SM_PROBE_CHILD:
  1804.             if ( !currentMIB.nodeInfo.Flags.bIsParent )
  1805.                 return FALSE;
  1806.  
  1807.             index++;
  1808.  
  1809.             hCurrent = currentMIB.hChild;
  1810.             state = SM_PROBE_SIBLING;
  1811.             break;
  1812.         }
  1813.     }
  1814.     return FALSE;
  1815. }
  1816.  
  1817. static void ReadMIBRecord(MPFS h, OID_INFO *rec)
  1818. {
  1819.     MIB_INFO nodeInfo;
  1820.     WORD_VAL tempVal;
  1821.  
  1822.     MPFSGetBegin(h);
  1823.  
  1824.     // Remember location of this record.
  1825.     rec->hNode = h;
  1826.  
  1827.     // Read OID
  1828.     rec->oid = MPFSGet();
  1829.  
  1830.     // Read nodeInfo
  1831.     rec->nodeInfo.Val = MPFSGet();
  1832.     nodeInfo = rec->nodeInfo;
  1833.  
  1834.     // Read id, if there is any: Only leaf node with dynamic data will have id.
  1835.     if ( nodeInfo.Flags.bIsIDPresent )
  1836.         rec->id = MPFSGet();
  1837.  
  1838.     // Read Sibling offset if there is any - any node may have sibling
  1839.     if ( nodeInfo.Flags.bIsSibling )
  1840.     {
  1841.         tempVal.byte.LSB = MPFSGet();
  1842.         tempVal.byte.MSB = MPFSGet();
  1843.         rec->hSibling = (MPFS)tempVal.Val;
  1844.     }
  1845.  
  1846.     // All rest of the parameters are applicable to leaf node only.
  1847.     if ( nodeInfo.Flags.bIsParent )
  1848.         rec->hChild = MPFSTell();
  1849.     else
  1850.     {
  1851.         if ( nodeInfo.Flags.bIsDistantSibling )
  1852.         {
  1853.             // Read Distant Sibling if there is any - only leaf node will have distant sibling
  1854.             tempVal.byte.LSB = MPFSGet();
  1855.             tempVal.byte.MSB = MPFSGet();
  1856.             rec->hSibling = (MPFS)tempVal.Val;
  1857.         }
  1858.  
  1859.         // Save data type for this node.
  1860.         rec->dataType = MPFSGet();
  1861.  
  1862.         rec->hData = MPFSTell();
  1863.  
  1864.     }
  1865.  
  1866.     MPFSGetEnd();
  1867. }
  1868.  
  1869.  
  1870. static BOOL GetDataTypeInfo(DATA_TYPE dataType, DATA_TYPE_INFO *info )
  1871. {
  1872.     if ( dataType >= DATA_TYPE_UNKNOWN )
  1873.         return FALSE;
  1874.  
  1875.     info->asnType   = dataTypeTable[dataType].asnType;
  1876.     info->asnLen    = dataTypeTable[dataType].asnLen;
  1877.  
  1878.     return TRUE;
  1879. }
  1880.  
  1881. static BYTE ProcessSetVar(OID_INFO *rec, SNMP_ERR_STATUS *errorStatus)
  1882. {
  1883.     SNMP_ERR_STATUS errorCode;
  1884.     DATA_TYPE_INFO actualDataTypeInfo;
  1885.     BYTE dataType;
  1886.     BYTE dataLen;
  1887.     SNMP_VAL dataValue;
  1888.     BYTE ref;
  1889.     BYTE temp;
  1890.     BYTE copiedBytes;
  1891.  
  1892.     // Start with no error.
  1893.     errorCode = SNMP_NO_ERR;
  1894.     copiedBytes = 0;
  1895.  
  1896.     // Non-leaf, Constant and ReadOnly node cannot be modified
  1897.     if ( rec->nodeInfo.Flags.bIsParent    ||
  1898.          rec->nodeInfo.Flags.bIsConstant  ||
  1899.          !rec->nodeInfo.Flags.bIsEditable )
  1900.         errorCode = SNMP_NO_SUCH_NAME;
  1901.  
  1902.     dataType = _SNMPGet();
  1903.     _SNMPPut(dataType);
  1904.     copiedBytes++;
  1905.  
  1906.     // Get data type for this node.
  1907.     //actualDataType = MPFSGet();
  1908.  
  1909.     if ( !GetDataTypeInfo(rec->dataType, &actualDataTypeInfo) )
  1910.         errorCode = SNMP_BAD_VALUE;
  1911.  
  1912.     // Make sure that received data type is same as what is declared
  1913.     // for this node.
  1914.     if ( dataType != actualDataTypeInfo.asnType )
  1915.         errorCode = SNMP_BAD_VALUE;
  1916.  
  1917.     // Make sure that received data length is within our capability.
  1918.     dataLen = _SNMPGet();
  1919.     _SNMPPut(dataLen);
  1920.     copiedBytes++;
  1921.  
  1922.     // Only max data length of 127 is supported.
  1923.     if ( dataLen > 0x7f )
  1924.         errorCode = SNMP_BAD_VALUE;
  1925.  
  1926.     // If this is a Simple variable and given index is other than '0',
  1927.     // it is considered bad value
  1928.     if ( !rec->nodeInfo.Flags.bIsSequence && rec->index != 0x00 )
  1929.         errorCode = SNMP_NO_SUCH_NAME;
  1930.  
  1931.     dataValue.dword = 0;
  1932.     ref = 0;
  1933.  
  1934.     // If data length is within 4 bytes, fetch all at once and pass it
  1935.     // to application.
  1936.     if ( actualDataTypeInfo.asnLen != 0xff )
  1937.     {
  1938.         // According to mib def., this data length for this data type/
  1939.         // must be less or equal to 4, if not, we don't know what this
  1940.         // is.
  1941.         if ( dataLen <= 4 )
  1942.         {
  1943.             // Now that we have verified data length, fetch them all
  1944.             // at once and save it in correct place.
  1945.             //dataLen--;
  1946.  
  1947.             while( dataLen-- )
  1948.             {
  1949.                 temp = _SNMPGet();
  1950.                 dataValue.v[dataLen] = temp;
  1951.  
  1952.                 // Copy same byte back to create response...
  1953.                 _SNMPPut(temp);
  1954.                 copiedBytes++;
  1955.             }
  1956.  
  1957.  
  1958.             // Pass it to application.
  1959.             if ( errorCode == SNMP_NO_ERR )
  1960.             {
  1961.                 if ( !SNMPSetVar(rec->id, rec->index, ref, dataValue) )
  1962.                     errorCode = SNMP_BAD_VALUE;
  1963.             }
  1964.         }
  1965.         else
  1966.             errorCode = SNMP_BAD_VALUE;
  1967.     }
  1968.     else
  1969.     {
  1970.         // This is a multi-byte Set operation.
  1971.         // Check with application to see if this many bytes can be
  1972.         // written to current variable.
  1973.         if ( !SNMPIsValidSetLen(rec->id, dataLen) )
  1974.             errorCode = SNMP_BAD_VALUE;
  1975.  
  1976.         // Even though there may have been error processing this
  1977.         // variable, we still need to reply with original data
  1978.         // so at least copy those bytes.
  1979.         while( dataLen-- )
  1980.         {
  1981.             dataValue.byte = _SNMPGet();
  1982.  
  1983.             _SNMPPut(dataValue.byte);
  1984.             copiedBytes++;
  1985.  
  1986.             // Ask applicaton to set this variable only if there was
  1987.             // no previous error.
  1988.             if ( errorCode == SNMP_NO_ERR )
  1989.             {
  1990.                 if ( !SNMPSetVar(rec->id, rec->index, ref++, dataValue) )
  1991.                     errorCode = SNMP_BAD_VALUE;
  1992.             }
  1993.         }
  1994.         // Let application know about end of data transfer
  1995.         if ( errorCode == SNMP_NO_ERR )
  1996.             SNMPSetVar(rec->id, rec->index, (WORD)SNMP_END_OF_VAR, dataValue);
  1997.     }
  1998.  
  1999.     *errorStatus = errorCode;
  2000.  
  2001.     return copiedBytes;
  2002. }
  2003.  
  2004.  
  2005.  
  2006.  
  2007. static BYTE ProcessGetVar(OID_INFO *rec, BOOL bAsOID)
  2008. {
  2009.     BYTE ref;
  2010.     BYTE temp;
  2011.     SNMP_VAL v;
  2012.     BYTE varLen;
  2013.     BYTE dataType;
  2014.     DATA_TYPE_INFO dataTypeInfo;
  2015.     WORD offset;
  2016.     WORD prevOffset;
  2017.  
  2018.     v.dword   = 0;
  2019.  
  2020.     // Non-leaf node does not contain any data.
  2021.     if ( rec->nodeInfo.Flags.bIsParent )
  2022.         return 0;
  2023.  
  2024.     // If current OID is Simple variable and index is other than .0
  2025.     // we don't Get this variable.
  2026.     if ( !rec->nodeInfo.Flags.bIsSequence )
  2027.     {
  2028.         // index of other than '0' is not invalid.
  2029.         if ( rec->index > 0 )
  2030.             return 0;
  2031.     }
  2032.  
  2033.     dataType = rec->dataType;
  2034.     if ( !GetDataTypeInfo(dataType, &dataTypeInfo) )
  2035.         return 0;
  2036.  
  2037.     if ( !bAsOID )
  2038.     {
  2039.         _SNMPPut(dataTypeInfo.asnType);
  2040.  
  2041.         offset = SNMPTxOffset;
  2042.         _SNMPPut(dataTypeInfo.asnLen);
  2043.     }
  2044.  
  2045.     if ( rec->nodeInfo.Flags.bIsConstant )
  2046.     {
  2047.         MPFSGetBegin(rec->hData);
  2048.  
  2049.         varLen = MPFSGet();
  2050.         temp = varLen;
  2051.         while( temp-- )
  2052.             _SNMPPut(MPFSGet());
  2053.  
  2054.         MPFSGetEnd();
  2055.     }
  2056.     else
  2057.     {
  2058.         ref = SNMP_START_OF_VAR;
  2059.         v.dword = 0;
  2060.         varLen = 0;
  2061.  
  2062.         do
  2063.         {
  2064.             if ( SNMPGetVar(rec->id, rec->index, &ref, &v) )
  2065.             {
  2066.                 if ( dataTypeInfo.asnLen != 0xff )
  2067.                 {
  2068.                     varLen = dataTypeInfo.asnLen;
  2069.  
  2070.                     while( dataTypeInfo.asnLen )
  2071.                         _SNMPPut(v.v[--dataTypeInfo.asnLen]);
  2072.  
  2073.                     break;
  2074.                 }
  2075.                 else
  2076.                 {
  2077.                     varLen++;
  2078.                     _SNMPPut(v.v[0]);
  2079.                 }
  2080.             }
  2081.             else
  2082.                 return 0;
  2083.  
  2084.         } while( ref != SNMP_END_OF_VAR );
  2085.     }
  2086.  
  2087.     if ( !bAsOID )
  2088.     {
  2089.         prevOffset = _SNMPGetTxOffset();
  2090.  
  2091.         _SNMPSetTxOffset(offset);
  2092.         _SNMPPut(varLen);
  2093.  
  2094.         _SNMPSetTxOffset(prevOffset);
  2095.  
  2096.         varLen++;
  2097.         varLen++;
  2098.     }
  2099.  
  2100.  
  2101.     return varLen;
  2102. }
  2103.  
  2104.  
  2105. static void SetErrorStatus(WORD errorStatusOffset,
  2106.                            WORD errorIndexOffset,
  2107.                            SNMP_ERR_STATUS errorStatus,
  2108.                            BYTE errorIndex)
  2109. {
  2110.     WORD prevOffset;
  2111.  
  2112.     prevOffset = _SNMPGetTxOffset();
  2113.  
  2114.     _SNMPSetTxOffset(errorStatusOffset);
  2115.     _SNMPPut((BYTE)errorStatus);
  2116.  
  2117.     _SNMPSetTxOffset(errorIndexOffset);
  2118.     _SNMPPut(errorIndex);
  2119.  
  2120.     _SNMPSetTxOffset(prevOffset);
  2121. }
  2122.