Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
363 johboh 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
}