/**************************************************************************** Function: bool SendNotification(uint8_t receiverIndex, SNMP_ID var, SNMP_VAL val) Summary: Prepare, validate remote node which will receive trap and send trap pdu. Description: This routine prepares the trap notification pdu, sends ARP and get remote device MAC address to which notification to sent, sends the notification. Notofication state machine is getting updated if there is any ARP resolution failure for a perticular trap destination address. PreCondition: SNMPTrapDemo() is called. parameters: receiverIndex - The index to array where remote ip address is stored. var - SNMP var ID that is to be used in notification val - Value of var. Only value of uint8_t, uint16_t or uint32_t can be sent. Return Values: true - If notification send is successful. false - If send notification failed. Remarks: None. *************************************************************************/ static bool SendNotification(uint8_t receiverIndex, SNMP_ID var, SNMP_VAL val) { static enum { SM_PREPARE, SM_NOTIFY_WAIT } smState = SM_PREPARE; IP_ADDR IPAddress; static uint8_t tempRxIndex; static IP_ADDR tempIpAddress; // Convert local to network order. IPAddress.v[0] = trapInfo.table[receiverIndex].IPAddress.v[3]; IPAddress.v[1] = trapInfo.table[receiverIndex].IPAddress.v[2]; IPAddress.v[2] = trapInfo.table[receiverIndex].IPAddress.v[1]; IPAddress.v[3] = trapInfo.table[receiverIndex].IPAddress.v[0]; switch(smState) { case SM_PREPARE: tempRxIndex=receiverIndex; // Convert local to network order. tempIpAddress.v[0] = trapInfo.table[receiverIndex].IPAddress.v[3]; tempIpAddress.v[1] = trapInfo.table[receiverIndex].IPAddress.v[2]; tempIpAddress.v[2] = trapInfo.table[receiverIndex].IPAddress.v[1]; tempIpAddress.v[3] = trapInfo.table[receiverIndex].IPAddress.v[0]; SNMPNotifyPrepare(&IPAddress, trapInfo.table[receiverIndex].community, trapInfo.table[receiverIndex].communityLen, MICROCHIP, // Agent ID Var gSpecificTrapNotification, // Specifc Trap notification code SNMPGetTimeStamp()); smState = SM_NOTIFY_WAIT; break; case SM_NOTIFY_WAIT: if ( SNMPIsNotifyReady(&IPAddress) ) { smState = SM_PREPARE; SNMPNotify(var, val, 0); return true; } /* if trapInfo table address for a perticular index is different comparing to the SM_PREPARE IP address then change the state to SM_PREPARE*/ if((tempIpAddress.Val != IPAddress.Val) && (tempRxIndex == receiverIndex)) { smState = SM_PREPARE; } /* Change state machine from SM_NOTIFY_WAIT to SM_PREPARE if incoming trap destination index is different from the SM_PREPARE trap destination index*/ if(tempRxIndex != receiverIndex) smState=SM_PREPARE; } return false; }
/************************************************************************** Function: void SNMPSendTrap(void) Summary: Prepare, validate remote node which will receive trap and send trap pdu. Description: This function is used to send trap notification to previously configured ip address if trap notification is enabled. There are different trap notification code. The current implementation sends trap for authentication failure (4). PreCondition: If application defined event occurs to send the trap. parameters: None. Returns: None. Remarks: This is a callback function called by the application on certain predefined events. This routine only implemented to send a authentication failure Notification-type macro with PUSH_BUTTON oid stored in MPFS. If the ARP is no resolved i.e. if SNMPIsNotifyReady() returns false, this routine times out in 5 seconds. This routine should be modified according to event occured and should update corrsponding OID and notification type to the trap pdu. *************************************************************************/ void SNMPSendTrap(void) { static uint8_t timeLock=false; static uint8_t receiverIndex=0; ///is application specific IP_ADDR remHostIPAddress,* remHostIpAddrPtr; SNMP_VAL val; static SYS_TICK TimerRead; static enum { SM_PREPARE, SM_NOTIFY_WAIT } smState = SM_PREPARE; gpSnmpIf = TCPIP_STACK_GetDefaultNet(); if(trapInfo.table[receiverIndex].Flags.bEnabled) { remHostIPAddress.v[0] = trapInfo.table[receiverIndex].IPAddress.v[3]; remHostIPAddress.v[1] = trapInfo.table[receiverIndex].IPAddress.v[2]; remHostIPAddress.v[2] = trapInfo.table[receiverIndex].IPAddress.v[1]; remHostIPAddress.v[3] = trapInfo.table[receiverIndex].IPAddress.v[0]; remHostIpAddrPtr = &remHostIPAddress; if(timeLock==(uint8_t)false) { TimerRead=SYS_TICK_Get(); timeLock=true; } } else { receiverIndex++; if((receiverIndex == (uint8_t)TRAP_TABLE_SIZE)) { receiverIndex=0; timeLock=false; gSendTrapFlag=false; UDPDiscard(s, gpSnmpIf); } return; } switch(smState) { case SM_PREPARE: SNMPNotifyPrepare(remHostIpAddrPtr,trapInfo.table[receiverIndex].community, trapInfo.table[receiverIndex].communityLen, MICROCHIP, // Agent ID Var gSpecificTrapNotification, // Notification code. SNMPGetTimeStamp()); smState++; break; case SM_NOTIFY_WAIT: if(SNMPIsNotifyReady(remHostIpAddrPtr)) { smState = SM_PREPARE; val.byte = 0; receiverIndex++; //application has to decide on which SNMP var OID to send. Ex. PUSH_BUTTON SNMPNotify(gOIDCorrespondingSnmpMibID, val, 0); smState = SM_PREPARE; UDPDiscard(s, gpSnmpIf); break; } } //Try for max 5 seconds to send TRAP, do not get block in while() if((SYS_TICK_Get()-TimerRead)>(5*SYS_TICK_TicksPerSecondGet())|| (receiverIndex == (uint8_t)TRAP_TABLE_SIZE)) { UDPDiscard(s, gpSnmpIf); smState = SM_PREPARE; receiverIndex=0; timeLock=false; gSendTrapFlag=false; return; } }
/************************************************************************** Function: void SNMPV2TrapDemo(void) Summary: Send SNMP V2 notification with multiple varbinds. Description: This routine sends a trap v2 pdu with multiple varbind variables for the predefined ip addresses with the agent. And as per RFC1905 the first two variable bindings in the varbind pdu list of an SNMPv2-Trap-PDU are sysUpTime.0 and snmpTrapOID.0 respectively. To support multiple varbind, user need to call SendNotification() for the first varbind variable and SendNotification() will do the arp resolve and adds sysUpTime.0 and snmpTrapOID.0 variable to the pdu. For the second varbind variable onwards user need to call only SNMPNotify(). In this demo , snmpv2 trap includes ANALOG_POT0,PUSH_BUTTON and LED_D5 variable bindains and this trap can be generated by using portmeter value. and SNMPv2-Trap-PDU will be generated only when pot meter reading exceeds 501. gSetTrapSendFlag Should be set to true when user is trying to send first variable binding and gSetTrapSendFlag should be set to false before sending the last variable binding. * if user is sending only one variable binding then * gSetTrapSendFlag should be set to False. * user can add more variable bindings. PreCondition: Application defined event occurs to send the trap. parameters: None. Returns: None. Remarks: This routine guides how to build a event generated trap notification. *************************************************************************/ void SNMPV2TrapDemo(void) { static SYS_TICK tempTimerRead = 0; static uint8_t trapIndex=0; static SNMP_VAL analogPotVal; static uint8_t potReadLock = false; static uint8_t timeLock = false; static uint8_t maxTryToSendTrap=0; if(timeLock==(uint8_t)false) { tempTimerRead=SYS_TICK_Get(); timeLock=true; } gpSnmpIf = TCPIP_STACK_GetDefaultNet(); for(;trapIndex<TRAP_TABLE_SIZE;trapIndex++) { if(!trapInfo.table[trapIndex].Flags.bEnabled) continue; //Read POT reading once and send trap to all configured recipient if(potReadLock ==(uint8_t)false) { analogPotVal.word= (uint16_t)ADC1BUF0; potReadLock = true; } if(analogPotVal.word >512u) { /* * prepare and send multivarbind pdu using pot meter value. * for SNMP v2 trap sysUpTime.0 and SNMPv2TrapOID.0 are mandatory * apart from these varbinds, push button and potmeter OID are included * to this pdu. */ gSpecificTrapNotification = 1; //expecting 1 should be the specific trap. gGenericTrapNotification = ENTERPRISE_SPECIFIC; gSetTrapSendFlag = true; // insert ANALOG_POT0 OID value and OID to the varbind pdu //set global flag gSetTrapSendFlag to true , it signifies that there are more than one // variable need to be the part of SNMP v2 TRAP. // if there is only varbind variable to be the part of SNMP v2 trap, // then user should set gSetTrapSendFlag to false. //gSetTrapSendFlag = false; if(SendNotification(trapIndex,ANALOG_POT0,analogPotVal) == false) { if(maxTryToSendTrap >= MAX_TRY_TO_SEND_TRAP) { trapIndex++; maxTryToSendTrap = 0; return; } maxTryToSendTrap++; return ; } //prepare PUSH_BUTTON trap .for the next trap varbind we need to use snmp_notify instead of // SendNotification(), because we have already prepared SNMP v2 trap header //and arp has been resolved already. analogPotVal.byte = BUTTON0_IO; SNMPNotify(PUSH_BUTTON,analogPotVal,0); // if this is the last trap variable need to be the part of SNMP v2 Trap, // then we should disable gSetTrapSendFlag to false gSetTrapSendFlag = false; analogPotVal.byte = LED0_IO; SNMPNotify(LED_D5,analogPotVal,0); } } //Try for max 5 seconds to send TRAP, do not get block in while() if((SYS_TICK_Get()-tempTimerRead)>(5*SYS_TICK_TicksPerSecondGet())) { // UDPDiscard(s, gpSnmpIf); potReadLock = false; timeLock = false; trapIndex = 0; analogPotVal.word = 0; return; } }
/************************************************************************** Function: void SNMPSendTrap(void) Summary: Prepare, validate remote node which will receive trap and send trap pdu. Description: This function is used to send trap notification to previously configured ip address if trap notification is enabled. There are different trap notification code. The current implementation sends trap for authentication failure (4). PreCondition: If application defined event occurs to send the trap. parameters: None. Returns: None. Remarks: This is a callback function called by the application on certain predefined events. This routine only implemented to send a authentication failure Notification-type macro with PUSH_BUTTON oid stored in MPFS. If the ARP is no resolved i.e. if SNMPIsNotifyReady() returns FALSE, this routine times out in 5 seconds. This routine should be modified according to event occured and should update corrsponding OID and notification type to the trap pdu. *************************************************************************/ void SNMPSendTrap(void) { static BYTE timeLock=FALSE; static BYTE receiverIndex=0; ///is application specific IP_ADDR remHostIPAddress,* remHostIpAddrPtr; SNMP_VAL val; static DWORD TimerRead; static enum { SM_PREPARE, SM_NOTIFY_WAIT } smState = SM_PREPARE; if(trapInfo.table[receiverIndex].Flags.bEnabled) { remHostIPAddress.v[0] = trapInfo.table[receiverIndex].IPAddress.v[3]; remHostIPAddress.v[1] = trapInfo.table[receiverIndex].IPAddress.v[2]; remHostIPAddress.v[2] = trapInfo.table[receiverIndex].IPAddress.v[1]; remHostIPAddress.v[3] = trapInfo.table[receiverIndex].IPAddress.v[0]; remHostIpAddrPtr = &remHostIPAddress; if(timeLock==(BYTE)FALSE) { TimerRead=TickGet(); timeLock=TRUE; } } else { receiverIndex++; if((receiverIndex == (BYTE)TRAP_TABLE_SIZE)) { receiverIndex=0; timeLock=FALSE; gSendTrapFlag=FALSE; UDPDiscard(); } return; } switch(smState) { case SM_PREPARE: SNMPNotifyPrepare(remHostIpAddrPtr,trapInfo.table[receiverIndex].community, trapInfo.table[receiverIndex].communityLen, MICROCHIP, // Agent ID Var gSpecificTrapNotification, // Notification code. SNMPGetTimeStamp()); smState++; break; case SM_NOTIFY_WAIT: if(SNMPIsNotifyReady(remHostIpAddrPtr)) { smState = SM_PREPARE; val.byte = 0; receiverIndex++; //application has to decide on which SNMP var OID to send. Ex. PUSH_BUTTON SNMPNotify(gOIDCorrespondingSnmpMibID, val, 0); smState = SM_PREPARE; UDPDiscard(); break; } } //Try for max 5 seconds to send TRAP, do not get block in while() if((TickGet()-TimerRead)>(5*TICK_SECOND)|| (receiverIndex == (BYTE)TRAP_TABLE_SIZE)) { UDPDiscard(); smState = SM_PREPARE; receiverIndex=0; timeLock=FALSE; gSendTrapFlag=FALSE; return; } }
/************************************************************************** Function: void SNMPV2TrapDemo(void) Summary: Send SNMP V2 notification with multiple varbinds. Description: This routine sends a trap v2 pdu with multiple varbind variables for the predefined ip addresses with the agent. And as per RFC1905 the first two variable bindings in the varbind pdu list of an SNMPv2-Trap-PDU are sysUpTime.0 and snmpTrapOID.0 respectively. To support multiple varbind, user need to call SendNotification() for the first varbind variable and SendNotification() will do the arp resolve and adds sysUpTime.0 and snmpTrapOID.0 variable to the pdu. For the second varbind variable onwards user need to call only SNMPNotify(). In this demo , snmpv2 trap includes ANALOG_POT0,PUSH_BUTTON and LED_D5 variable bindains and this trap can be generated by using portmeter value. and SNMPv2-Trap-PDU will be generated only when pot meter reading exceeds 501. gSetTrapSendFlag Should be set to TRUE when user is trying to send first variable binding and gSetTrapSendFlag should be set to FALSE before sending the last variable binding. * if user is sending only one variable binding then * gSetTrapSendFlag should be set to False. * user can add more variable bindings. PreCondition: Application defined event occurs to send the trap. parameters: None. Returns: None. Remarks: This routine guides how to build a event generated trap notification. *************************************************************************/ void SNMPV2TrapDemo(void) { static DWORD tempTimerRead = 0; static BYTE trapIndex=0; static SNMP_VAL analogPotVal; static BYTE potReadLock = FALSE; static BYTE timeLock = FALSE; static BYTE maxTryToSendTrap=0; if(timeLock==(BYTE)FALSE) { tempTimerRead=TickGet(); timeLock=TRUE; } for(;trapIndex<TRAP_TABLE_SIZE;trapIndex++) { if(!trapInfo.table[trapIndex].Flags.bEnabled) continue; //Read POT reading once and send trap to all configured recipient if(potReadLock ==(BYTE)FALSE) { #if defined(__18CXX) // Wait until A/D conversion is done ADCON0bits.GO = 1; while(ADCON0bits.GO); // Convert 10-bit value into ASCII string analogPotVal.word= (WORD)ADRES; #else analogPotVal.word= (WORD)ADC1BUF0; #endif potReadLock = TRUE; } if(analogPotVal.word >512u) { /* * prepare and send multivarbind pdu using pot meter value. * for SNMP v2 trap sysUpTime.0 and SNMPv2TrapOID.0 are mandatory * apart from these varbinds, push button and potmeter OID are included * to this pdu. */ gSpecificTrapNotification = 1; //expecting 1 should be the specific trap. gGenericTrapNotification = ENTERPRISE_SPECIFIC; gSetTrapSendFlag = TRUE; // insert ANALOG_POT0 OID value and OID to the varbind pdu //set global flag gSetTrapSendFlag to TRUE , it signifies that there are more than one // variable need to be the part of SNMP v2 TRAP. // if there is only varbind variable to be the part of SNMP v2 trap, // then user should set gSetTrapSendFlag to FALSE. //gSetTrapSendFlag = FALSE; if(SendNotification(trapIndex,ANALOG_POT0,analogPotVal) == FALSE) { if(maxTryToSendTrap >= MAX_TRY_TO_SEND_TRAP) { trapIndex++; maxTryToSendTrap = 0; return; } maxTryToSendTrap++; return ; } //prepare PUSH_BUTTON trap .for the next trap varbind we need to use snmp_notify instead of // SendNotification(), because we have already prepared SNMP v2 trap header //and arp has been resolved already. analogPotVal.byte = BUTTON0_IO; SNMPNotify(PUSH_BUTTON,analogPotVal,0); // if this is the last trap variable need to be the part of SNMP v2 Trap, // then we should disable gSetTrapSendFlag to FALSE gSetTrapSendFlag = FALSE; analogPotVal.byte = LED0_IO; SNMPNotify(LED_D5,analogPotVal,0); } } //Try for max 5 seconds to send TRAP, do not get block in while() if((TickGet()-tempTimerRead)>(5*TICK_SECOND)) { // UDPDiscard(); potReadLock = FALSE; timeLock = FALSE; trapIndex = 0; analogPotVal.word = 0; return; } }