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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (show annotations) (download)
Tue May 1 08:17:39 2007 UTC (17 years, 1 month 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 /*********************************************************************
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