/[H8]/trunk/docs/Microchip TCP_IP stack/TCPIP Stack/SNMP.c
ViewVC logotype

Annotation of /trunk/docs/Microchip TCP_IP stack/TCPIP Stack/SNMP.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20