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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations) (download)
Thu Apr 19 09:01:15 2007 UTC (17 years, 1 month ago) by hedin
File MIME type: text/plain
File size: 59311 byte(s)
added the TCP/IP stack, source code.
1 /*********************************************************************
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