/[H8]/trunk/docs/MCHPStack2.20/Source/SNMP.c
ViewVC logotype

Annotation of /trunk/docs/MCHPStack2.20/Source/SNMP.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue May 1 08:17:39 2007 UTC (17 years, 2 months ago) by hedin
File MIME type: text/plain
File size: 60624 byte(s)
Removed tcpip stack 4.02 and added tcpip stack 2.20.
1 hedin 62 /*********************************************************************
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     *
41     ********************************************************************/
42     #define THIS_IS_SNMP_SERVER
43    
44     #include <string.h>
45    
46     #include "snmp.h"
47     #include "stacktsk.h"
48     #ifndef _WIN32
49     #include "udp.h"
50     #include "tick.h"
51     #include "arptsk.h"
52     #endif
53     #include "mpfs.h"
54    
55     #if _WIN32
56     #include <windows.h>
57     #endif
58    
59     #if !defined(STACK_USE_SNMP_SERVER)
60     #error SNMP module is not enabled.
61     #error If you do not want SNMP module, remove this file from your
62     #error project to reduce your code size.
63     #error If you do want SNMP module, make sure that STACK_USE_SNMP_SERVER
64     #error is defined in StackTsk.h file.
65     #endif
66    
67     #define SNMP_V1 (0)
68    
69    
70     #define STRUCTURE (0x30)
71     #define ASN_INT (0x02)
72     #define OCTET_STRING (0x04)
73     #define ASN_NULL (0x05)
74     #define ASN_OID (0x06)
75    
76     // SNMP specific variables
77     #define SNMP_IP_ADDR (0x40)
78     #define SNMP_COUNTER32 (0x41)
79     #define SNMP_GAUGE32 (0x42)
80     #define SNMP_TIME_TICKS (0x43)
81     #define SNMP_OPAQUE (0x44)
82     #define SNMP_NSAP_ADDR (0x45)
83    
84    
85     #define GET_REQUEST (0xa0)
86     #define GET_NEXT_REQUEST (0xa1)
87     #define GET_RESPONSE (0xa2)
88     #define SET_REQUEST (0xa3)
89     #define TRAP (0xa4)
90    
91     #define IS_STRUCTURE(a) (a==STRUCTURE)
92     #define IS_ASN_INT(a) (a==ASN_INT)
93     #define IS_OCTET_STRING(a) (a==OCTET_STRING)
94     #define IS_OID(a) (a==ASN_OID)
95     #define IS_ASN_NULL(a) (a==ASN_NULL)
96     #define IS_GET_REQUEST(a) (a==GET_REQUEST)
97     #define IS_GET_NEXT_REQUEST(a) (a==GET_NEXT_REQUEST)
98     #define IS_GET_RESPONSE(a) (a==GET_RESPONSE)
99     #define IS_SET_REQUEST(a) (a==SET_REQUEST)
100     #define IS_TRAP(a) (a==TRAP)
101     #define IS_AGENT_PDU(a) (a==GET_REQUEST || \
102     a==GET_NEXT_REQUEST || \
103     a==SET_REQUEST)
104    
105     typedef enum _SNMP_ERR_STATUS
106     {
107     SNMP_NO_ERR = 0,
108     SNMP_TOO_BIG,
109     SNMP_NO_SUCH_NAME,
110     SNMP_BAD_VALUE,
111     SNMP_READ_ONLY,
112     SNMP_GEN_ERR
113     } SNMP_ERR_STATUS;
114    
115     typedef union _SNMP_STATUS
116     {
117     struct
118     {
119     unsigned int bIsFileOpen : 1;
120     } Flags;
121     BYTE Val;
122     } SNMP_STATUS;
123    
124    
125    
126     #define SNMP_AGENT_PORT (161)
127     #define SNMP_NMS_PORT (162)
128     #define AGENT_NOTIFY_PORT (0xfffe)
129    
130     #ifdef _WIN32
131     #define ROM
132     extern int _RxIndex;
133     extern int _TxIndex;
134     extern int _TxLength;
135     extern BYTE _TxPacket[1000];
136     extern BYTE _RxPacket[1000];
137    
138     #define INVALID_UDP_SOCKET (0XFFFF)
139    
140     #define UDPGet(a) _UDPGet(a)
141     #define UDPFlush()
142     #define UDPClose(a)
143     #define ARPResolve(a)
144     #define ARPIsResolved(a, b) (TRUE)
145     static void _UDPGet(BYTE *v)
146     {
147     *v = _RxPacket[_RxIndex++];
148     }
149    
150     #define UDP_SOCKET int
151     #define BUFFER int
152    
153     #define UDPOpen(a, b, c) (0)
154     #define UDPDiscard() (_TxLength = 0)
155     #define UDPPut(a) \
156     { \
157     if ( _TxIndex >= _TxLength ) \
158     _TxLength = _TxIndex+1; \
159     _TxPacket[_TxIndex++] = a; \
160     }
161     #define UDPIsGetReady(a) TRUE
162     #define UDPIsPutReady(a) TRUE
163     #define MACGetRxBuffer() 0
164     #define MACGetTxBuffer() 0
165     #define UDPSetRxBuffer(a) (_RxIndex = a)
166     #define UDPSetTxBuffer(a, b) (_TxIndex = a+b)
167     #define SNMPValidate(a, b) TRUE
168    
169     #undef MY_IP_BYTE1
170     #undef MY_IP_BYTE2
171     #undef MY_IP_BYTE3
172     #undef MY_IP_BYTE4
173     #define MY_IP_BYTE1 (10)
174     #define MY_IP_BYTE2 (10)
175     #define MY_IP_BYTE3 (5)
176     #define MY_IP_BYTE4 (15)
177    
178     #endif
179    
180     UDP_SOCKET SNMPAgentSocket;
181    
182     typedef struct _SNMP_NOTIFY_INFO
183     {
184     char community[NOTIFY_COMMUNITY_LEN];
185     BYTE communityLen;
186     SNMP_ID agentIDVar;
187     BYTE notificationCode;
188     UDP_SOCKET socket;
189     DWORD_VAL timestamp;
190     } SNMP_NOTIFY_INFO;
191    
192     static SNMP_NOTIFY_INFO SNMPNotifyInfo;
193    
194    
195     typedef enum _DATA_TYPE
196     {
197     INT8_VAL = 0x00,
198     INT16_VAL = 0x01,
199     INT32_VAL = 0x02,
200     BYTE_ARRAY = 0x03,
201     ASCII_STRING = 0x04,
202     IP_ADDRESS = 0x05,
203     COUNTER32 = 0x06,
204     TIME_TICKS_VAL = 0x07,
205     GAUGE32 = 0x08,
206     OID_VAL = 0x09,
207    
208     DATA_TYPE_UNKNOWN
209     } DATA_TYPE;
210    
211     typedef union _INDEX_INFO
212     {
213     struct
214     {
215     unsigned int bIsOID:1;
216     } Flags;
217     BYTE Val;
218     } INDEX_INFO;
219    
220    
221     typedef struct _DATA_TYPE_INFO
222     {
223     BYTE asnType;
224     BYTE asnLen;
225     } DATA_TYPE_INFO;
226    
227     ROM DATA_TYPE_INFO dataTypeTable[] =
228     {
229     /* INT8_VAL */ { ASN_INT, 1 },
230     /* INT16_VAL */ { ASN_INT, 2 },
231     /* INT32_VAL */ { ASN_INT, 4 },
232     /* BYTE_ARRAY */ { OCTET_STRING, 0xff },
233     /* ASCII_ARRAY */ { OCTET_STRING, 0xff },
234     /* IP_ADDRESS */ { SNMP_IP_ADDR, 4 },
235     /* COUNTER32 */ { SNMP_COUNTER32, 4 },
236     /* TIME_TICKS_VAL */ { SNMP_TIME_TICKS, 4 },
237     /* GAUTE32 */ { SNMP_GAUGE32, 4 },
238     /* OID_VAL */ { ASN_OID, 0xff }
239     };
240     #define DATA_TYPE_TABLE_SIZE (sizeof(dataTypeTable)/sizeof(dataTypeTable[0]))
241    
242    
243    
244     typedef union _MIB_INFO
245     {
246     struct
247     {
248     unsigned int bIsDistantSibling : 1;
249     unsigned int bIsConstant : 1;
250     unsigned int bIsSequence : 1;
251     unsigned int bIsSibling : 1;
252    
253     unsigned int bIsParent : 1;
254     unsigned int bIsEditable : 1;
255     unsigned int bIsAgentID : 1;
256     unsigned int bIsIDPresent : 1;
257     } Flags;
258     BYTE Val;
259     } MIB_INFO;
260    
261    
262     typedef struct _OID_INFO
263     {
264     MPFS hNode;
265    
266     BYTE oid;
267     MIB_INFO nodeInfo;
268     DATA_TYPE dataType;
269     SNMP_ID id;
270    
271     WORD_VAL dataLen;
272     MPFS hData;
273     MPFS hSibling;
274     MPFS hChild;
275     BYTE index;
276     BYTE indexLen;
277     } OID_INFO;
278    
279     static WORD SNMPTxOffset;
280     static WORD SNMPRxOffset;
281    
282     static BUFFER SNMPRxBuffer;
283     static BUFFER SNMPTxBuffer;
284    
285     static SNMP_STATUS SNMPStatus;
286    
287     #define _SNMPSetTxOffset(o) (SNMPTxOffset = o)
288     #define _SNMPGetTxOffset() SNMPTxOffset
289    
290    
291     static SNMP_ACTION ProcessHeader(char *community, BYTE *len);
292     static BOOL ProcessGetSetHeader(DWORD *requestID);
293     static BOOL ProcessVariables(char *community,
294     BYTE len,
295     DWORD_VAL *request,
296     BYTE pduType);
297    
298     static BOOL OIDLookup(BYTE *oid, BYTE oidLen, OID_INFO *rec);
299     static BOOL IsValidCommunity(char* community, BYTE *len);
300     static BOOL IsValidInt(DWORD *val);
301     static BOOL IsValidPDU(SNMP_ACTION *pdu);
302     static BYTE IsValidLength(WORD *len);
303     static BOOL IsASNNull(void);
304     static BOOL IsValidOID(BYTE *oid, BYTE *len);
305     static BYTE IsValidStructure(WORD *dataLen);
306     static void _SNMPDuplexInit(UDP_SOCKET socket);
307     static void _SNMPPut(BYTE v);
308     static BYTE _SNMPGet(void);
309     static BOOL GetNextLeaf(OID_INFO *n);
310     static void ReadMIBRecord(MPFS h, OID_INFO *rec);
311     static BOOL GetDataTypeInfo(DATA_TYPE dataType, DATA_TYPE_INFO *info);
312     static BYTE ProcessGetVar(OID_INFO *rec, BOOL bAsOID);
313     static BYTE ProcessGetNextVar(OID_INFO *rec);
314     static BOOL GetOIDStringByAddr(OID_INFO *rec, BYTE *oidString, BYTE *len);
315     static BYTE ProcessSetVar(OID_INFO *rec, SNMP_ERR_STATUS *errorStatus);
316     static void SetErrorStatus(WORD errorStatusOffset,
317     WORD errorIndexOffset,
318     SNMP_ERR_STATUS errorStatus,
319     BYTE errorIndex);
320     static BOOL GetOIDStringByID(SNMP_ID id, OID_INFO *info, BYTE *oidString, BYTE *len);
321    
322    
323     /*********************************************************************
324     * Function: void SNMPInit(void)
325     *
326     * PreCondition: At least one UDP socket must be available.
327     * UDPInit() is already called.
328     *
329     * Input: None
330     *
331     * Output: SNMP agent module is initialized.
332     *
333     * Side Effects: One UDP socket will be used.
334     *
335     * Overview: Initialize SNMP module internals
336     *
337     * Note: This function is called only once during lifetime
338     * of the application.
339     ********************************************************************/
340     void SNMPInit(void)
341     {
342     // Start with no error or flag set.
343     SNMPStatus.Val = 0;
344    
345     SNMPAgentSocket = UDPOpen(SNMP_AGENT_PORT, 0, INVALID_UDP_SOCKET);
346     // SNMPAgentSocket must not be INVALID_UDP_SOCKET.
347     // If it is, compile time value of UDP Socket numbers must be increased.
348    
349     return;
350     }
351    
352    
353     /*********************************************************************
354     * Function: BOOL SNMPTask(void)
355     *
356     * PreCondition: SNMPInit is already called.
357     *
358     * Input: None
359     *
360     * Output: TRUE if SNMP module has finished with a state
361     * FALSE if a state has not been finished.
362     *
363     *
364     * Side Effects: None
365     *
366     * Overview: Handle incoming SNMP requests as well as any
367     * outgoing SNMP responses and timeout conditions
368     *
369     * Note: None.
370     ********************************************************************/
371     BOOL SNMPTask(void)
372     {
373     char community[SNMP_COMMUNITY_MAX_LEN];
374     BYTE communityLen;
375     DWORD_VAL requestID;
376     BYTE pdu;
377     MPFS hMIBFile;
378     BOOL lbReturn;
379    
380     char snmpBIBFile[] = SNMP_BIB_FILE_NAME;
381    
382     // Check to see if there is any packet on SNMP Agent socket.
383     if ( !UDPIsGetReady(SNMPAgentSocket) )
384     return TRUE;
385    
386     // As we process SNMP variables, we will prepare response on-the-fly
387     // creating full duplex transfer.
388     // Current MAC layer does not support full duplex transfer, so
389     // SNMP needs to manage its own full duplex connection.
390     // Prepare for full duplex transfer.
391     _SNMPDuplexInit(SNMPAgentSocket);
392    
393    
394     pdu = ProcessHeader(community, &communityLen);
395     if ( pdu == SNMP_ACTION_UNKNOWN )
396     goto _SNMPDiscard;
397    
398     if ( !ProcessGetSetHeader(&requestID.Val) )
399     goto _SNMPDiscard;
400    
401     // Open MIB file.
402     SNMPStatus.Flags.bIsFileOpen = FALSE;
403     hMIBFile = MPFSOpen((BYTE*)snmpBIBFile);
404     if ( hMIBFile != MPFS_INVALID )
405     {
406     SNMPStatus.Flags.bIsFileOpen = TRUE;
407     }
408    
409     lbReturn = ProcessVariables(community, communityLen, &requestID, pdu);
410     if ( SNMPStatus.Flags.bIsFileOpen )
411     {
412     MPFSClose();
413     }
414    
415     if ( lbReturn == FALSE )
416     goto _SNMPDiscard;
417    
418     UDPFlush();
419    
420     return TRUE;
421    
422     _SNMPDiscard:
423     UDPDiscard();
424    
425     return TRUE;
426     }
427    
428    
429    
430     /*********************************************************************
431     * Function: void SNMPNotifyPrepare(IP_ADDR *remoteHost,
432     * char *community,
433     * BYTE communityLen,
434     * SNMP_ID agentIDVar,
435     * BYTE notificationCode,
436     * DWORD timestamp)
437     *
438     * PreCondition: SNMPInit is already called.
439     *
440     * Input: remoteHost - pointer to remote Host IP address
441     * community - Community string to use to notify
442     * communityLen- Community string length
443     * agentIDVar - System ID to use identify this agent
444     * notificaitonCode - Notification Code to use
445     * timestamp - Notification timestamp in 100th
446     * of second.
447     *
448     * Output: None
449     *
450     * Side Effects: None
451     *
452     * Overview: This function prepares SNMP module to send SNMP
453     * trap (notification) to remote host.
454     *
455     * Note: This is first of series of functions to complete
456     * SNMP notification.
457     ********************************************************************/
458     void SNMPNotifyPrepare(IP_ADDR *remoteHost,
459     char *community,
460     BYTE communityLen,
461     SNMP_ID agentIDVar,
462     BYTE notificationCode,
463     DWORD timestamp )
464     {
465     strcpy(SNMPNotifyInfo.community, community);
466     SNMPNotifyInfo.communityLen = communityLen;
467    
468     SNMPNotifyInfo.agentIDVar = agentIDVar;
469     SNMPNotifyInfo.notificationCode = notificationCode;
470    
471     SNMPNotifyInfo.timestamp.Val = timestamp;
472    
473     ARPResolve(remoteHost);
474     }
475    
476    
477    
478     /*********************************************************************
479     * Function: BOOL SNMPIsNotifyReady(IP_ADDR *remoteHost)
480     *
481     * PreCondition: SNMPNotifyPrepare is already called and returned
482     * TRUE.
483     *
484     * Input: remoteHost - pointer to remote Host IP address
485     *
486     * Output: TRUE if remoteHost IP address is resolved and
487     * SNMPNotify may be called.
488     * FALSE otherwise.
489     * This would fail if there were not UDP socket
490     * to open.
491     *
492     * Side Effects: None
493     *
494     * Overview: This function resolves given remoteHost IP address
495     * into MAC address using ARP module.
496     * If remoteHost is not aviailable, this function
497     * would never return TRUE.
498     * Application must implement timeout logic to
499     * handle "remoteHost not avialable" situation.
500     *
501     * Note: None
502     ********************************************************************/
503     BOOL SNMPIsNotifyReady(IP_ADDR *remoteHost)
504     {
505     NODE_INFO remoteNode;
506    
507     if ( ARPIsResolved(remoteHost, &remoteNode.MACAddr) )
508     {
509     remoteNode.IPAddr.Val = remoteHost->Val;
510    
511     SNMPNotifyInfo.socket = UDPOpen(AGENT_NOTIFY_PORT, &remoteNode, SNMP_NMS_PORT);
512    
513     return (SNMPNotifyInfo.socket != INVALID_UDP_SOCKET);
514     }
515    
516     return FALSE;
517     }
518    
519    
520    
521     /*********************************************************************
522     * Function: BOOL SNMPNotify(SNMP_ID var,
523     * SNMP_VAL val,
524     * SNMP_INDEX index)
525     *
526     * PreCondition: SNMPIsNotified is already called and returned
527     * TRUE.
528     *
529     * Input: var - SNMP var ID that is to be used in
530     * notification
531     * val - Value of var. Only value of
532     * BYTE, WORD or DWORD can be sent.
533     * index - Index of var. If this var is a single,
534     * index would be 0, or else if this var
535     * is a sequence, index could be any
536     * value from 0 to 127.
537     *
538     * Output: TRUE if SNMP notification was successful sent.
539     * This does not guarantee that remoteHost recieved
540     * it.
541     * FALSE otherwise.
542     * This would fail under following contions:
543     * 1) Given SNMP_BIB_FILE does not exist in MPFS
544     * 2) Given var does not exist.
545     * 3) Previously given agentID does not exist
546     * 4) Data type of given var is unknown - only
547     * possible if MPFS itself was corrupted.
548     *
549     * Side Effects: None
550     *
551     * Overview: This function creates SNMP trap PDU and sends it
552     * to previously specified remoteHost.
553     *
554     * Note: None
555     ********************************************************************/
556     BOOL SNMPNotify(SNMP_ID var,
557     SNMP_VAL val,
558     SNMP_INDEX index)
559     {
560     BYTE len;
561     BYTE OIDValue[OID_MAX_LEN];
562     BYTE OIDLen;
563     BYTE agentIDLen;
564     BYTE *pOIDValue;
565     OID_INFO rec;
566     DATA_TYPE_INFO dataTypeInfo;
567     WORD packetStructLenOffset;
568     WORD pduStructLenOffset;
569     WORD varBindStructLenOffset;
570     WORD varPairStructLenOffset;
571     WORD prevOffset;
572     char *pCommunity;
573     MPFS hMIBFile;
574    
575     char snmpBIBFile[] = SNMP_BIB_FILE_NAME;
576    
577     hMIBFile = MPFSOpen((BYTE*)snmpBIBFile);
578     if ( hMIBFile == MPFS_INVALID )
579     {
580     UDPClose(SNMPNotifyInfo.socket);
581     return FALSE;
582     }
583    
584     _SNMPDuplexInit(SNMPNotifyInfo.socket);
585    
586     len = SNMPNotifyInfo.communityLen;
587     pCommunity = SNMPNotifyInfo.community;
588    
589     _SNMPPut(STRUCTURE); // First item is packet structure
590     packetStructLenOffset = SNMPTxOffset;
591     _SNMPPut(0);
592    
593     // Put SNMP version info - only v1.0 is supported.
594     _SNMPPut(ASN_INT); // Int type.
595     _SNMPPut(1); // One byte long value.
596     _SNMPPut(SNMP_V1); // v1.0.
597    
598     //len = strlen(community); // Save community length for later use.
599     _SNMPPut(OCTET_STRING); // Octet string type.
600     _SNMPPut(len); // community string length
601     while( len-- ) // Copy entire string.
602     _SNMPPut(*(pCommunity++));
603    
604     // Put PDU type. SNMP agent's response is always GET RESPONSE
605     _SNMPPut(TRAP);
606     pduStructLenOffset = SNMPTxOffset;
607     _SNMPPut(0);
608    
609     // Get complete OID string from MPFS.
610     if ( !GetOIDStringByID(SNMPNotifyInfo.agentIDVar,
611     &rec, OIDValue, &agentIDLen) )
612     {
613     MPFSClose();
614     UDPClose(SNMPNotifyInfo.socket);
615     return FALSE;
616     }
617    
618     if ( !rec.nodeInfo.Flags.bIsAgentID )
619     {
620     MPFSClose();
621     UDPClose(SNMPNotifyInfo.socket);
622     return FALSE;
623     }
624    
625     MPFSGetBegin(rec.hData);
626    
627     _SNMPPut(ASN_OID);
628     len = MPFSGet();
629     agentIDLen = len;
630     _SNMPPut(len);
631     while( len-- )
632     _SNMPPut(MPFSGet());
633    
634     MPFSGetEnd();
635    
636     // This agent's IP address.
637     _SNMPPut(SNMP_IP_ADDR);
638     _SNMPPut(4);
639     _SNMPPut(MY_IP_BYTE1);
640     _SNMPPut(MY_IP_BYTE2);
641     _SNMPPut(MY_IP_BYTE3);
642     _SNMPPut(MY_IP_BYTE4);
643    
644     // Trap code
645     _SNMPPut(ASN_INT);
646     _SNMPPut(1);
647     _SNMPPut(6); // Enterprisespecific trap code
648    
649     _SNMPPut(ASN_INT);
650     _SNMPPut(1);
651     _SNMPPut(SNMPNotifyInfo.notificationCode);
652    
653     // Time stamp
654     _SNMPPut(SNMP_TIME_TICKS);
655     _SNMPPut(4);
656     _SNMPPut(SNMPNotifyInfo.timestamp.v[3]);
657     _SNMPPut(SNMPNotifyInfo.timestamp.v[2]);
658     _SNMPPut(SNMPNotifyInfo.timestamp.v[1]);
659     _SNMPPut(SNMPNotifyInfo.timestamp.v[0]);
660    
661     // Variable binding structure header
662     _SNMPPut(0x30);
663     varBindStructLenOffset = SNMPTxOffset;
664     _SNMPPut(0);
665    
666     // Create variable name-pair structure
667     _SNMPPut(0x30);
668     varPairStructLenOffset = SNMPTxOffset;
669     _SNMPPut(0);
670    
671     // Get complete notification variable OID string.
672     if ( !GetOIDStringByID(var, &rec, OIDValue, &OIDLen) )
673     {
674     MPFSClose();
675     UDPClose(SNMPNotifyInfo.socket);
676     return FALSE;
677     }
678    
679     // Copy OID string into packet.
680     _SNMPPut(ASN_OID);
681     _SNMPPut((BYTE)(OIDLen+1));
682     len = OIDLen;
683     pOIDValue = OIDValue;
684     while( len-- )
685     _SNMPPut(*pOIDValue++);
686     _SNMPPut(index);
687    
688     // Encode and Copy actual data bytes
689     if ( !GetDataTypeInfo(rec.dataType, &dataTypeInfo) )
690     {
691     MPFSClose();
692     UDPClose(SNMPNotifyInfo.socket);
693     return FALSE;
694     }
695    
696     _SNMPPut(dataTypeInfo.asnType);
697     // In this version, only data type of 4 bytes or less long can be
698     // notification variable.
699     if ( dataTypeInfo.asnLen == 0xff )
700     {
701     MPFSClose();
702     UDPClose(SNMPNotifyInfo.socket);
703     return FALSE;
704     }
705    
706     len = dataTypeInfo.asnLen;
707     _SNMPPut(len);
708     while( len-- )
709     _SNMPPut(val.v[len]);
710    
711     len = dataTypeInfo.asnLen // data bytes count
712     + 1 // Length byte
713     + 1 // Data type byte
714     + OIDLen // OID bytes
715     + 2 // OID header bytes
716     + 1; // index byte
717    
718     prevOffset = _SNMPGetTxOffset();
719     _SNMPSetTxOffset(varPairStructLenOffset);
720     _SNMPPut(len);
721    
722     len += 2; // Variable Binding structure header
723     _SNMPSetTxOffset(varBindStructLenOffset);
724     _SNMPPut(len);
725    
726     len = len
727     + 2 // Var bind struct header
728     + 6 // 6 bytes of timestamp
729     + 3 // 3 bytes of trap code
730     + 3 // 3 bytes of notification code
731     + 6 // 6 bytes of agnent IP address
732     + agentIDLen // Agent ID bytes
733     + 2; // Agent ID header bytes
734     _SNMPSetTxOffset(pduStructLenOffset);
735     _SNMPPut(len);
736    
737     len = len // PDU struct length
738     + 2 // PDU header
739     + SNMPNotifyInfo.communityLen // Community string bytes
740     + 2 // Community header bytes
741     + 3; // SNMP version bytes
742     _SNMPSetTxOffset(packetStructLenOffset);
743     _SNMPPut(len);
744    
745     _SNMPSetTxOffset(prevOffset);
746    
747     MPFSClose();
748     UDPFlush();
749     UDPClose(SNMPNotifyInfo.socket);
750    
751     return TRUE;
752     }
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 = 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 = 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     static BOOL GetOIDStringByID(SNMP_ID id, OID_INFO *info, BYTE *oidString, BYTE *len)
1718     {
1719     MPFS hCurrent;
1720    
1721     hCurrent = MPFSSeek(0);
1722    
1723     while (1)
1724     {
1725     ReadMIBRecord(hCurrent, info);
1726    
1727     if ( !info->nodeInfo.Flags.bIsParent )
1728     {
1729     if ( info->nodeInfo.Flags.bIsIDPresent )
1730     {
1731     if ( info->id == id )
1732     return GetOIDStringByAddr(info, oidString, len);
1733     }
1734    
1735     if ( info->nodeInfo.Flags.bIsSibling ||
1736     info->nodeInfo.Flags.bIsDistantSibling )
1737     MPFSSeek(info->hSibling);
1738    
1739     else
1740     break;
1741    
1742     }
1743     hCurrent = MPFSTell();
1744     }
1745     return FALSE;
1746     }
1747    
1748    
1749    
1750    
1751    
1752     static BOOL GetOIDStringByAddr(OID_INFO *rec, BYTE *oidString, BYTE *len)
1753     {
1754     MPFS hTarget;
1755     MPFS hCurrent;
1756     MPFS hNext;
1757     OID_INFO currentMIB;
1758     BYTE index;
1759     enum { SM_PROBE_SIBLING, SM_PROBE_CHILD } state;
1760    
1761     hCurrent = MPFSSeek(0);
1762    
1763    
1764     hTarget = rec->hNode;
1765     state = SM_PROBE_SIBLING;
1766     index = 0;
1767    
1768     while( 1 )
1769     {
1770     ReadMIBRecord(hCurrent, &currentMIB);
1771    
1772     oidString[index] = currentMIB.oid;
1773    
1774     if ( hTarget == hCurrent )
1775     {
1776     *len = ++index;
1777    
1778     return TRUE;
1779     }
1780    
1781    
1782     switch(state)
1783     {
1784     case SM_PROBE_SIBLING:
1785     if ( !currentMIB.nodeInfo.Flags.bIsSibling )
1786     state = SM_PROBE_CHILD;
1787    
1788     else
1789     {
1790     hNext = currentMIB.hSibling;
1791     MPFSSeek(hNext);
1792     hNext = MPFSTell();
1793     if ( hTarget >= hNext )
1794     {
1795     hCurrent = hNext;
1796     break;
1797     }
1798     else
1799     state = SM_PROBE_CHILD;
1800     }
1801    
1802     case SM_PROBE_CHILD:
1803     if ( !currentMIB.nodeInfo.Flags.bIsParent )
1804     return FALSE;
1805    
1806     index++;
1807    
1808     hCurrent = currentMIB.hChild;
1809     state = SM_PROBE_SIBLING;
1810     break;
1811     }
1812     }
1813     return FALSE;
1814     }
1815    
1816     static void ReadMIBRecord(MPFS h, OID_INFO *rec)
1817     {
1818     MIB_INFO nodeInfo;
1819     WORD_VAL tempVal;
1820    
1821     MPFSGetBegin(h);
1822    
1823     // Remember location of this record.
1824     rec->hNode = h;
1825    
1826     // Read OID
1827     rec->oid = MPFSGet();
1828    
1829     // Read nodeInfo
1830     rec->nodeInfo.Val = MPFSGet();
1831     nodeInfo = rec->nodeInfo;
1832    
1833     // Read id, if there is any: Only leaf node with dynamic data will have id.
1834     if ( nodeInfo.Flags.bIsIDPresent )
1835     rec->id = MPFSGet();
1836    
1837     // Read Sibling offset if there is any - any node may have sibling
1838     if ( nodeInfo.Flags.bIsSibling )
1839     {
1840     tempVal.byte.LSB = MPFSGet();
1841     tempVal.byte.MSB = MPFSGet();
1842     rec->hSibling = tempVal.Val;
1843     }
1844    
1845     // All rest of the parameters are applicable to leaf node only.
1846     if ( nodeInfo.Flags.bIsParent )
1847     rec->hChild = MPFSTell();
1848     else
1849     {
1850     if ( nodeInfo.Flags.bIsDistantSibling )
1851     {
1852     // Read Distant Sibling if there is any - only leaf node will have distant sibling
1853     tempVal.byte.LSB = MPFSGet();
1854     tempVal.byte.MSB = MPFSGet();
1855     rec->hSibling = tempVal.Val;
1856     }
1857    
1858     // Save data type for this node.
1859     rec->dataType = MPFSGet();
1860    
1861     rec->hData = MPFSTell();
1862    
1863     }
1864    
1865     MPFSGetEnd();
1866     }
1867    
1868    
1869     static BOOL GetDataTypeInfo(DATA_TYPE dataType, DATA_TYPE_INFO *info )
1870     {
1871     if ( dataType >= DATA_TYPE_UNKNOWN )
1872     return FALSE;
1873    
1874     info->asnType = dataTypeTable[dataType].asnType;
1875     info->asnLen = dataTypeTable[dataType].asnLen;
1876    
1877     return TRUE;
1878     }
1879    
1880     static BYTE ProcessSetVar(OID_INFO *rec, SNMP_ERR_STATUS *errorStatus)
1881     {
1882     SNMP_ERR_STATUS errorCode;
1883     DATA_TYPE_INFO actualDataTypeInfo;
1884     BYTE dataType;
1885     BYTE dataLen;
1886     SNMP_VAL dataValue;
1887     BYTE ref;
1888     BYTE temp;
1889     BYTE copiedBytes;
1890    
1891     // Start with no error.
1892     errorCode = SNMP_NO_ERR;
1893     copiedBytes = 0;
1894    
1895     // Non-leaf, Constant and ReadOnly node cannot be modified
1896     if ( rec->nodeInfo.Flags.bIsParent ||
1897     rec->nodeInfo.Flags.bIsConstant ||
1898     !rec->nodeInfo.Flags.bIsEditable )
1899     errorCode = SNMP_NO_SUCH_NAME;
1900    
1901     dataType = _SNMPGet();
1902     _SNMPPut(dataType);
1903     copiedBytes++;
1904    
1905     // Get data type for this node.
1906     //actualDataType = MPFSGet();
1907    
1908     if ( !GetDataTypeInfo(rec->dataType, &actualDataTypeInfo) )
1909     errorCode = SNMP_BAD_VALUE;
1910    
1911     // Make sure that received data type is same as what is declared
1912     // for this node.
1913     if ( dataType != actualDataTypeInfo.asnType )
1914     errorCode = SNMP_BAD_VALUE;
1915    
1916     // Make sure that received data length is within our capability.
1917     dataLen = _SNMPGet();
1918     _SNMPPut(dataLen);
1919     copiedBytes++;
1920    
1921     // Only max data length of 127 is supported.
1922     if ( dataLen > 0x7f )
1923     errorCode = SNMP_BAD_VALUE;
1924    
1925     // If this is a Simple variable and given index is other than '0',
1926     // it is considered bad value
1927     if ( !rec->nodeInfo.Flags.bIsSequence && rec->index != 0x00 )
1928     errorCode = SNMP_NO_SUCH_NAME;
1929    
1930     dataValue.dword = 0;
1931     ref = 0;
1932    
1933     // If data length is within 4 bytes, fetch all at once and pass it
1934     // to application.
1935     if ( actualDataTypeInfo.asnLen != 0xff )
1936     {
1937     // According to mib def., this data length for this data type/
1938     // must be less or equal to 4, if not, we don't know what this
1939     // is.
1940     if ( dataLen <= 4 )
1941     {
1942     // Now that we have verified data length, fetch them all
1943     // at once and save it in correct place.
1944     //dataLen--;
1945    
1946     while( dataLen-- )
1947     {
1948     temp = _SNMPGet();
1949     dataValue.v[dataLen] = temp;
1950    
1951     // Copy same byte back to create response...
1952     _SNMPPut(temp);
1953     copiedBytes++;
1954     }
1955    
1956    
1957     // Pass it to application.
1958     if ( errorCode == SNMP_NO_ERR )
1959     {
1960     if ( !SNMPSetVar(rec->id, rec->index, ref, dataValue) )
1961     errorCode = SNMP_BAD_VALUE;
1962     }
1963     }
1964     else
1965     errorCode = SNMP_BAD_VALUE;
1966     }
1967     else
1968     {
1969     // This is a multi-byte Set operation.
1970     // Check with application to see if this many bytes can be
1971     // written to current variable.
1972     if ( !SNMPIsValidSetLen(rec->id, dataLen) )
1973     errorCode = SNMP_BAD_VALUE;
1974    
1975     // Even though there may have been error processing this
1976     // variable, we still need to reply with original data
1977     // so at least copy those bytes.
1978     while( dataLen-- )
1979     {
1980     dataValue.byte = _SNMPGet();
1981    
1982     _SNMPPut(dataValue.byte);
1983     copiedBytes++;
1984    
1985     // Ask applicaton to set this variable only if there was
1986     // no previous error.
1987     if ( errorCode == SNMP_NO_ERR )
1988     {
1989     if ( !SNMPSetVar(rec->id, rec->index, ref++, dataValue) )
1990     errorCode = SNMP_BAD_VALUE;
1991     }
1992     }
1993     // Let application know about end of data transfer
1994     if ( errorCode == SNMP_NO_ERR )
1995     SNMPSetVar(rec->id, rec->index, (WORD)SNMP_END_OF_VAR, dataValue);
1996     }
1997    
1998     *errorStatus = errorCode;
1999    
2000     return copiedBytes;
2001     }
2002    
2003    
2004    
2005    
2006     static BYTE ProcessGetVar(OID_INFO *rec, BOOL bAsOID)
2007     {
2008     BYTE ref;
2009     BYTE temp;
2010     SNMP_VAL v;
2011     BYTE varLen;
2012     BYTE dataType;
2013     DATA_TYPE_INFO dataTypeInfo;
2014     WORD offset;
2015     WORD prevOffset;
2016    
2017     v.dword = 0;
2018    
2019     // Non-leaf node does not contain any data.
2020     if ( rec->nodeInfo.Flags.bIsParent )
2021     return 0;
2022    
2023     // If current OID is Simple variable and index is other than .0
2024     // we don't Get this variable.
2025     if ( !rec->nodeInfo.Flags.bIsSequence )
2026     {
2027     // index of other than '0' is not invalid.
2028     if ( rec->index > 0 )
2029     return 0;
2030     }
2031    
2032     dataType = rec->dataType;
2033     if ( !GetDataTypeInfo(dataType, &dataTypeInfo) )
2034     return 0;
2035    
2036     if ( !bAsOID )
2037     {
2038     _SNMPPut(dataTypeInfo.asnType);
2039    
2040     offset = SNMPTxOffset;
2041     _SNMPPut(dataTypeInfo.asnLen);
2042     }
2043    
2044     if ( rec->nodeInfo.Flags.bIsConstant )
2045     {
2046     MPFSGetBegin(rec->hData);
2047    
2048     varLen = MPFSGet();
2049     temp = varLen;
2050     while( temp-- )
2051     _SNMPPut(MPFSGet());
2052    
2053     MPFSGetEnd();
2054     }
2055     else
2056     {
2057     ref = SNMP_START_OF_VAR;
2058     v.dword = 0;
2059     varLen = 0;
2060    
2061     do
2062     {
2063     if ( SNMPGetVar(rec->id, rec->index, &ref, &v) )
2064     {
2065     if ( dataTypeInfo.asnLen != 0xff )
2066     {
2067     varLen = dataTypeInfo.asnLen;
2068    
2069     while( dataTypeInfo.asnLen )
2070     _SNMPPut(v.v[--dataTypeInfo.asnLen]);
2071    
2072     break;
2073     }
2074     else
2075     {
2076     varLen++;
2077     _SNMPPut(v.v[0]);
2078     }
2079     }
2080     else
2081     return 0;
2082    
2083     } while( ref != SNMP_END_OF_VAR );
2084     }
2085    
2086     if ( !bAsOID )
2087     {
2088     prevOffset = _SNMPGetTxOffset();
2089    
2090     _SNMPSetTxOffset(offset);
2091     _SNMPPut(varLen);
2092    
2093     _SNMPSetTxOffset(prevOffset);
2094    
2095     varLen++;
2096     varLen++;
2097     }
2098    
2099    
2100     return varLen;
2101     }
2102    
2103    
2104     static void SetErrorStatus(WORD errorStatusOffset,
2105     WORD errorIndexOffset,
2106     SNMP_ERR_STATUS errorStatus,
2107     BYTE errorIndex)
2108     {
2109     WORD prevOffset;
2110    
2111     prevOffset = _SNMPGetTxOffset();
2112    
2113     _SNMPSetTxOffset(errorStatusOffset);
2114     _SNMPPut((BYTE)errorStatus);
2115    
2116     _SNMPSetTxOffset(errorIndexOffset);
2117     _SNMPPut(errorIndex);
2118    
2119     _SNMPSetTxOffset(prevOffset);
2120     }

  ViewVC Help
Powered by ViewVC 1.1.20