/********************************************************************* * Function: BOOL UDPGet(BYTE *v) * * PreCondition: UDPInit() is already called AND * UDPIsGetReady(s) == TRUE * * Input: v - Buffer to receive UDP data byte * * Output: TRUE if a data byte was read * FALSE if no data byte was read or available * * Side Effects: None * * Overview: None * * Note: This function fetches data from an active UDP * socket as set by UDPIsGetReady() call. ********************************************************************/ BOOL UDPGet(BYTE *v) { // CALLER MUST MAKE SURE THAT THERE IS ENOUGH DATA BYTE IN BUFFER // BEFORE CALLING THIS FUNCTION. // USE UDPIsGetReady() TO CONFIRM. if ( UDPSocketInfo[activeUDPSocket].RxCount == 0 ) return FALSE; // If if this very first read to packet, set MAC Rx Pointer to // beginig of UDP data area. if ( UDPSocketInfo[activeUDPSocket].Flags.bFirstRead ) { UDPSocketInfo[activeUDPSocket].Flags.bFirstRead = FALSE; UDPSetRxBuffer(0); } *v = MACGet(); UDPSocketInfo[activeUDPSocket].RxCount--; if ( UDPSocketInfo[activeUDPSocket].RxCount == 0 ) { MACDiscardRx(); } return TRUE; }
/********************************************************************* * Function: void UDPDiscard(void) * * PreCondition: UDPInit() is already called AND * UDPIsGetReady() == TRUE with desired UDP socket. * * Input: None * * Output: None * * Side Effects: None * * Overview: None * * Note: This function discards an active UDP socket content. ********************************************************************/ void UDPDiscard(void) { if ( UDPSocketInfo[activeUDPSocket].RxCount ) MACDiscardRx(); UDPSocketInfo[activeUDPSocket].RxCount = 0; }
/** * Read the requested number of bytes from the active UDP socket into * the given buffer. * * Note: This function fetches data from an active UDP socket as set by * UDPIsGetReady() call. * * @preCondition UDPInit() is already called AND * UDPIsGetReady(s) == TRUE * * @param[in] buffer Buffer to hold received data. * @param count Buffer length * * @return Number of bytes loaded into buffer. */ WORD UDPGetArray(BYTE *buffer, WORD count) { WORD bytesRead; if ( UDPSocketInfo[activeUDPSocket].RxCount == 0 ) return 0; // If if this very first read to packet, set MAC Rx Pointer to // beginig of UDP data area. if ( UDPSocketInfo[activeUDPSocket].Flags.bFirstRead ) { UDPSocketInfo[activeUDPSocket].Flags.bFirstRead = FALSE; UDPSetRxBuffer(0); } //If more bytes requested then are left in the receive buffer, adjust count if (count > UDPSocketInfo[activeUDPSocket].RxCount) { count = UDPSocketInfo[activeUDPSocket].RxCount; } //Read the requested amount of data from the current MAC receive buffer bytesRead = MACGetArray(buffer, count); UDPSocketInfo[activeUDPSocket].RxCount -= bytesRead; if ( UDPSocketInfo[activeUDPSocket].RxCount == 0 ) { MACDiscardRx(); //Discard the contents of the current RX buffer } return count; }
/********************************************************************* * Function: BOOL UDPProcess(NODE_INFO* remoteNode, * WORD len) * * PreCondition: UDPInit() is already called AND * UDP segment is ready in MAC buffer * * Input: remoteNode - Remote node info * len - Total length of UDP semgent. * * Output: TRUE if this function has completed its task * FALSE otherwise * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ BOOL UDPProcess(NODE_INFO *remoteNode, WORD len) { UDP_HEADER h; UDP_SOCKET s; /* * Retrieve UDP header. */ MACGetArray((BYTE*)&h, sizeof(h)); h.SourcePort = swaps(h.SourcePort); h.DestinationPort = swaps(h.DestinationPort); h.Length = swaps(h.Length) - sizeof(UDP_HEADER);; h.Checksum = swaps(h.Checksum); s = FindMatchingSocket(&h, remoteNode); if ( s == INVALID_UDP_SOCKET ) { /* * If there is no matching socket, There is no one to handle * this data. Discard it. */ MACDiscardRx(); } else { UDPSocketInfo[s].RxCount = h.Length; UDPSocketInfo[s].Flags.bFirstRead = TRUE; } return TRUE; }
/** * This function discards an active UDP socket content. * * @preCondition UDPInit() is already called AND * UDPIsGetReady() == TRUE with desired UDP socket. */ void UDPDiscard(void) { if ( UDPSocketInfo[activeUDPSocket].RxCount ) MACDiscardRx(); //Discard the contents of the current RX buffer UDPSocketInfo[activeUDPSocket].RxCount = 0; }
/****************************************************************************** * Function: BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type) * * PreCondition: None * * Input: *remote: Location to store the Source MAC address of the * received frame. * *type: Location of a BYTE to store the constant * MAC_UNKNOWN, ETHER_IP, or ETHER_ARP, representing * the contents of the Ethernet type field. * * Output: TRUE: If a packet was waiting in the RX buffer. The * remote, and type values are updated. * FALSE: If a packet was not pending. remote and type are * not changed. * * Side Effects: Last packet is discarded if MACDiscardRx() hasn't already * been called. * * Overview: None * * Note: None *****************************************************************************/ BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type) { ENC_PREAMBLE header; // Test if at least one packet has been received and is waiting if (EPKTCNT == 0u) { return FALSE; } // Flag that we have received a packet so that we don't swap the RX polarity // anymore. flags.bits.bRXPolarityValid = 1; // Make absolutely certain that any previous packet was discarded if (flags.bits.bWasDiscarded == 0u) { MACDiscardRx(); return FALSE; } // Save the location of this packet CurrentPacketLocation.Val = NextPacketLocation.Val; // Set the read pointer to the beginning of the next unprocessed packet ERDPT = CurrentPacketLocation.Val; // Obtain the MAC header from the Ethernet buffer MACGetArray((BYTE*) & header, sizeof (header)); // The EtherType field, like most items transmitted on the Ethernet medium // are in big endian. header.Type.Val = swaps(header.Type.Val); // Do a sanity check. There might be a bug in code someplace if this // Reset() ever happens. Check for potential errors in array/pointer writing code. if (header.NextPacketPointer > RXSTOP || ((BYTE_VAL*) (&header.NextPacketPointer))->bits.b0 || header.StatusVector.bits.Zero || header.StatusVector.bits.CRCError || header.StatusVector.bits.ByteCount > 1518u || !header.StatusVector.bits.ReceiveOk) { Reset(); } // Save the location where the hardware will write the next packet to NextPacketLocation.Val = header.NextPacketPointer; // Return the Ethernet frame's Source MAC address field to the caller // This parameter is useful for replying to requests without requiring an // ARP cycle. memcpy((void*) remote->v, (void*) header.SourceMACAddr.v, sizeof (*remote)); // Return a simplified version of the EtherType field to the caller *type = MAC_UNKNOWN; if ((header.Type.v[1] == 0x08u) && ((header.Type.v[0] == ETHER_IP) || (header.Type.v[0] == ETHER_ARP))) { *type = header.Type.v[0]; } // Mark this packet as discardable flags.bits.bWasDiscarded = 0; return TRUE; }
/***************************************************************************** Function: void UDPDiscard(void) Summary: Discards any remaining RX data from a UDP socket. Description: This function discards any remaining received data in the currently active UDP socket. Precondition: UDPIsGetReady() was previously called to select the currently active socket. Parameters: None Returns: None Remarks: It is safe to call this function more than is necessary. If no data is available, this function does nothing. ***************************************************************************/ void UDPDiscard(void) { if(!Flags.bWasDiscarded) { MACDiscardRx(); UDPRxCount = 0; SocketWithRxData = INVALID_UDP_SOCKET; Flags.bWasDiscarded = 1; } }
/********************************************************************* * Function: BOOL ARPGet(NODE_INFO* remote, BYTE* opCode) * * PreCondition: ARP packet is ready in MAC buffer. * * Input: remote - Remote node info * opCode - Buffer to hold ARP op code. * * Output: TRUE if a valid ARP packet was received. * FALSE otherwise. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ int1 ARPGet(NODE_INFO *remote, int8 *opCode) { ARP_PACKET packet; //MACGetArray((int8*)&packet, sizeof(packet)); MACGetArray(&packet, sizeof(ARP_PACKET)); MACDiscardRx(); SwapARPPacket(&packet); debug_arp("\r\nARP: HW:%LX PR:%LX ML:%U PL:%U O:%LX TI:%U.%U.%U.%U FI:%U.%U.%U.%U", packet.HardwareType, packet.Protocol, packet.MACAddrLen, packet.ProtocolLen, packet.Operation, packet.TargetIPAddr.v[0],packet.TargetIPAddr.v[1], packet.TargetIPAddr.v[2],packet.TargetIPAddr.v[3], packet.SenderIPAddr.v[0],packet.SenderIPAddr.v[1],packet.SenderIPAddr.v[2],packet.SenderIPAddr.v[3]); if ( packet.HardwareType != HW_ETHERNET || packet.MACAddrLen != sizeof(MAC_ADDR) || packet.ProtocolLen != sizeof(IP_ADDR) ) return FALSE; if ( packet.Operation == ARP_OPERATION_RESP ) *opCode = ARP_REPLY; else if ( packet.Operation == ARP_OPERATION_REQ ) *opCode = ARP_REQUEST; else { *opCode = ARP_UNKNOWN; return FALSE; } if(packet.TargetIPAddr.Val == AppConfig.MyIPAddr.Val) { remote->MACAddr = packet.SenderMACAddr; remote->IPAddr = packet.SenderIPAddr; return TRUE; } else return FALSE; }
/********************************************************************* * Function: BOOL ARPGet(NODE_INFO* remote, BYTE* opCode) * * PreCondition: ARP packet is ready in MAC buffer. * * Input: remote - Remote node info * opCode - Buffer to hold ARP op code. * * Output: TRUE if a valid ARP packet was received. * FALSE otherwise. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ BOOL ARPGet(NODE_INFO *remote, BYTE *opCode) { ARP_PACKET packet; MACGetArray((BYTE*)&packet, sizeof(packet)); MACDiscardRx(); SwapARPPacket(&packet); if ( packet.HardwareType != HW_ETHERNET || packet.MACAddrLen != sizeof(MAC_ADDR) || packet.ProtocolLen != sizeof(IP_ADDR) ) { return FALSE; } if ( packet.Operation == ARP_OPERATION_RESP ) { *opCode = ARP_REPLY; } else if ( packet.Operation == ARP_OPERATION_REQ ) *opCode = ARP_REQUEST; else { *opCode = ARP_UNKNOWN; return FALSE; } if(packet.TargetIPAddr.Val == AppConfig.MyIPAddr.Val) { remote->MACAddr = packet.SenderMACAddr; remote->IPAddr = packet.SenderIPAddr; return TRUE; } else return FALSE; }
BOOL UDPProcess(NODE_INFO *remoteNode, IP_ADDR *localIP, WORD len) { UDP_HEADER h; UDP_SOCKET s; UDP_PSEUDO_HEADER pseudoHeader; WORD_VAL checksum; /* * Retrieve UDP header. */ //MACGetArray((BYTE*)&h, sizeof(h)); MACGetArray(&h, sizeof(UDP_HEADER)); h.SourcePort = swaps(h.SourcePort); h.DestinationPort = swaps(h.DestinationPort); h.Length = swaps(h.Length) - sizeof(UDP_HEADER); debug_udp("\r\nUDP PROCESS SP=%LX DP=%LX PAYLOAD=%LX ", h.SourcePort, h.DestinationPort, h.Length ); // See if we need to validate the checksum field (0x0000 is disabled) if(h.Checksum) { h.Checksum = swaps(h.Checksum); // Calculate IP pseudoheader checksum. pseudoHeader.SourceAddress = remoteNode->IPAddr; pseudoHeader.DestAddress.v[0] = localIP->v[0]; pseudoHeader.DestAddress.v[1] = localIP->v[1]; pseudoHeader.DestAddress.v[2] = localIP->v[2]; pseudoHeader.DestAddress.v[3] = localIP->v[3]; pseudoHeader.Zero = 0x0; pseudoHeader.Protocol = IP_PROT_UDP; pseudoHeader.Length = len; SwapPseudoHeader(pseudoHeader); checksum.Val = ~CalcIPChecksum(&pseudoHeader, sizeof(pseudoHeader)); // Set UDP packet checksum = pseudo header checksum in MAC RAM. IPSetRxBuffer(6); MACPut(checksum.v[0]); // In case if the end of the RX buffer is reached and a wraparound is needed, set the next address to prevent writing to the wrong address. IPSetRxBuffer(7); MACPut(checksum.v[1]); IPSetRxBuffer(0); // Now calculate UDP packet checksum in NIC RAM - including // pesudo header. checksum.Val = CalcIPBufferChecksum(len); if ( checksum.Val != h.Checksum ) { debug_udp("INVALID-CS "); MACDiscardRx(); return TRUE; } } s = FindMatching_UDP_Socket(&h, remoteNode, localIP); if ( s == INVALID_UDP_SOCKET ) { /* * If there is no matching socket, There is no one to handle * this data. Discard it. */ debug_udp("INVALID-SOCKET "); MACDiscardRx(); } else { UDPSocketInfo[s].RxCount = h.Length; UDPSocketInfo[s].Flags.bFirstRead = TRUE; debug_udp("MATCH AS:%U ", s); /*debug_udp("MAC-%X:%X:%X:%X:%X:%X", remoteNode->MACAddr.v[0], remoteNode->MACAddr.v[1], remoteNode->MACAddr.v[2], remoteNode->MACAddr.v[3], remoteNode->MACAddr.v[4], remoteNode->MACAddr.v[5] );*/ } return TRUE; }
/***************************************************************************** Function: BOOL UDPProcess(NODE_INFO *remoteNode, IP_ADDR *localIP, WORD len) Summary: Handles an incoming UDP segment. Description: This function handles an incoming UDP segment to determine if it is acceptable and should be handed to one of the stack applications for processing. Precondition: UDPInit() has been called an a UDP segment is ready in the MAC buffer. Parameters: remoteNode - The remote node that sent this segment. localIP - The destination IP address for this segment. len - Total length of the UDP segment. Return Values: TRUE - A valid packet is waiting and the stack applications should be called to handle it. FALSE - The packet was discarded. ***************************************************************************/ BOOL UDPProcess(NODE_INFO *remoteNode, IP_ADDR *localIP, WORD len) { UDP_HEADER h; UDP_SOCKET s; PSEUDO_HEADER pseudoHeader; DWORD_VAL checksums; UDPRxCount = 0; // Retrieve UDP header. MACGetArray((BYTE*)&h, sizeof(h)); h.SourcePort = swaps(h.SourcePort); h.DestinationPort = swaps(h.DestinationPort); h.Length = swaps(h.Length) - sizeof(UDP_HEADER); // See if we need to validate the checksum field (0x0000 is disabled) if(h.Checksum) { // Calculate IP pseudoheader checksum. pseudoHeader.SourceAddress = remoteNode->IPAddr; pseudoHeader.DestAddress.Val = localIP->Val; pseudoHeader.Zero = 0x0; pseudoHeader.Protocol = IP_PROT_UDP; pseudoHeader.Length = len; SwapPseudoHeader(pseudoHeader); checksums.w[0] = ~CalcIPChecksum((BYTE*)&pseudoHeader, sizeof(pseudoHeader)); // Now calculate UDP packet checksum in NIC RAM -- should match pseudoHeader IPSetRxBuffer(0); checksums.w[1] = CalcIPBufferChecksum(len); if(checksums.w[0] != checksums.w[1]) { MACDiscardRx(); return FALSE; } } s = FindMatchingSocket(&h, remoteNode, localIP); if(s == INVALID_UDP_SOCKET) { // If there is no matching socket, There is no one to handle // this data. Discard it. MACDiscardRx(); return FALSE; } else { SocketWithRxData = s; UDPRxCount = h.Length; Flags.bFirstRead = 1; Flags.bWasDiscarded = 0; } return TRUE; }
/** * This FSM checks for new incoming packets, and routes it to appropriate * stack components. It also performs timed operations. * * This function must be called periodically called * to make sure that timely response. * * @preCondition StackInit() is already called. * * side affect: Stack FSM is executed. */ void StackTask(void) { static WORD dataCount; #if defined(STACK_USE_ICMP) static BYTE data[MAX_ICMP_DATA_LEN]; static WORD ICMPId; static WORD ICMPSeq; #endif IP_ADDR destIP; //Is filled with the Destination IP address contained in the IP header union { BYTE MACFrameType; BYTE IPFrameType; ICMP_CODE ICMPCode; } type; BOOL lbContinue; do { lbContinue = FALSE; switch(smStack) { case SM_STACK_IDLE: case SM_STACK_MAC: //debugPutGenRomStr(2, (ROM char*)"1"); //@mxd:2:%s //Check if the MAC RX Buffer has any data, and if it does, read the header. //Get the next header from the NIC. The node who sent it's address will be copied to //'remoteNode.MACAddr'. //Header was NOT read if MACGetHeader returned FALSE if ( !MACGetHeader(&remoteNode.MACAddr, &type.MACFrameType) ) { //debugPutGenRomStr(2, (ROM char*)"2"); //@mxd:2:%s //MODIFIED DHCP BEGIN // ADDED #if defined(STACK_USE_DHCP) // Normally, an application would not include DHCP module // if it is not enabled. But in case some one wants to disable // DHCP module at run-time, remember to not clear our IP // address if link is removed. if(STACK_IS_DHCP_ENABLED) { if(!MACIsLinked()) { AppConfig.MyIPAddr.v[0] = MY_DEFAULT_IP_ADDR_BYTE1; AppConfig.MyIPAddr.v[1] = MY_DEFAULT_IP_ADDR_BYTE2; AppConfig.MyIPAddr.v[2] = MY_DEFAULT_IP_ADDR_BYTE3; AppConfig.MyIPAddr.v[3] = MY_DEFAULT_IP_ADDR_BYTE4; AppConfig.MyMask.v[0] = MY_DEFAULT_MASK_BYTE1; AppConfig.MyMask.v[1] = MY_DEFAULT_MASK_BYTE2; AppConfig.MyMask.v[2] = MY_DEFAULT_MASK_BYTE3; AppConfig.MyMask.v[3] = MY_DEFAULT_MASK_BYTE4; DHCPFlags.bits.bDHCPServerDetected = FALSE; stackFlags.bits.bInConfigMode = TRUE; DHCPReset(); } // DHCP must be called all the time even after IP configuration is // discovered. // DHCP has to account lease expiration time and renew the configuration // time. DHCPTask(); if(DHCPIsBound()) stackFlags.bits.bInConfigMode = FALSE; } #endif //MODIFIED DHCP END //MODIFIED DHCP BEGIN // Removed /* #if defined(STACK_USE_DHCP) // Normally, an application would not include DHCP module // if it is not enabled. But in case some one wants to disable // DHCP module at run-time, remember to not clear our IP // address if link is removed. //Set our IP to 0.0.0.0 if all the following are TRUE: // - DHCP is enabled // - MAC is not linked yet (or cable is unplugged) if (STACK_IS_DHCP_ENABLED) { if ( !MACIsLinked() ) { //debugPutGenRomStr(2, (ROM char*)"3"); //@mxd:2:%s #if (DEBUG_STACKTSK >= LOG_INFO) //debugPutMsg(1); //@mxd:1:DHCP Enabled but MAC not linked yet - set IP to 0.0.0.0 #endif //if (stackFlags.bits.bInConfigMode) { //IP address must be 0.0.0.0 before DHCP has obtained a valid IP address MY_IP_BYTE1 = 0; MY_IP_BYTE2 = 0; MY_IP_BYTE3 = 0; MY_IP_BYTE4 = 0; //} stackFlags.bits.bInConfigMode = TRUE; DHCPReset(); } } #endif */ //MODIFIED DHCP END break; //case SM_STACK_IDLE: AND case SM_STACK_MAC: } //debugPutGenRomStr(2, (ROM char*)"4"); //@mxd:2:%s lbContinue = TRUE; if ( type.MACFrameType == MAC_IP ) { smStack = SM_STACK_IP; #if (DEBUG_STACKTSK >= LOG_DEBUG) debugPutMsg(2); //@mxd:2:Reading MAC IP header #endif } else if ( type.MACFrameType == MAC_ARP ) { smStack = SM_STACK_ARP; #if (DEBUG_STACKTSK >= LOG_DEBUG) debugPutMsg(3); //@mxd:3:Reading MAC ARP header #endif } else { MACDiscardRx(); //Discard the contents of the current RX buffer #if (DEBUG_STACKTSK >= LOG_WARN) debugPutMsg(4); //@mxd:4:Unknown MAC header read, MAC Frame Type = 0x%x debugPutByteHex(type.MACFrameType); #endif } break; //case SM_STACK_IDLE: AND case SM_STACK_MAC: case SM_STACK_ARP: if ( ARPProcess() ) smStack = SM_STACK_IDLE; //lbContinue = FALSE; //Removed in latest Microchip TCP/IP stack break; case SM_STACK_IP: if ( IPGetHeader(&destIP, /* Get Destination IP Address as received in IP header */ &remoteNode, &type.IPFrameType, &dataCount) ) { lbContinue = TRUE; if ( type.IPFrameType == IP_PROT_ICMP ) { smStack = SM_STACK_ICMP; #if defined(STACK_USE_IP_GLEANING) if(stackFlags.bits.bInConfigMode && STACK_IS_DHCP_ENABLED) { // Accoriding to "IP Gleaning" procedure, // when we receive an ICMP packet with a valid // IP address while we are still in configuration // mode, accept that address as ours and conclude // configuration mode. if ( destIP.Val != 0xffffffff ) { stackFlags.bits.bInConfigMode = FALSE; MY_IP_BYTE1 = destIP.v[0]; MY_IP_BYTE2 = destIP.v[1]; MY_IP_BYTE3 = destIP.v[2]; MY_IP_BYTE4 = destIP.v[3]; myDHCPBindCount--; } } #endif } #if defined(STACK_USE_TCP) else if ( type.IPFrameType == IP_PROT_TCP ) smStack = SM_STACK_TCP; #endif #if defined(STACK_USE_UDP) else if ( type.IPFrameType == IP_PROT_UDP ) smStack = SM_STACK_UDP; #endif else // Unknown/unsupported higher level protocol { lbContinue = FALSE; MACDiscardRx(); //Discard the contents of the current RX buffer smStack = SM_STACK_IDLE; } } else // Improper IP header version or checksum { MACDiscardRx(); //Discard the contents of the current RX buffer smStack = SM_STACK_IDLE; } break; //case SM_STACK_IP: #if defined(STACK_USE_UDP) case SM_STACK_UDP: if ( UDPProcess(&remoteNode, &destIP, dataCount) ) smStack = SM_STACK_IDLE; //lbContinue = FALSE; //Removed in latest Microchip TCP/IP stack break; //case SM_STACK_UDP: #endif #if defined(STACK_USE_TCP) case SM_STACK_TCP: if ( TCPProcess(&remoteNode, &destIP, dataCount) ) //Will return TRUE if TCPProcess finished it's task, else FALSE smStack = SM_STACK_IDLE; //lbContinue = FALSE; //Removed in latest Microchip TCP/IP stack break; //case SM_STACK_TCP: #endif case SM_STACK_ICMP: smStack = SM_STACK_IDLE; #if defined(STACK_USE_ICMP) if ( dataCount <= (MAX_ICMP_DATA_LEN+9) ) { if ( ICMPGet(&type.ICMPCode, data, (BYTE*)&dataCount, &ICMPId, &ICMPSeq) ) { if ( type.ICMPCode == ICMP_ECHO_REQUEST ) { lbContinue = TRUE; smStack = SM_STACK_ICMP_REPLY; } } } #endif MACDiscardRx(); //Discard the contents of the current RX buffer break; //case SM_STACK_ICMP: #if defined(STACK_USE_ICMP) case SM_STACK_ICMP_REPLY: if ( ICMPIsTxReady() ) { ICMPPut(&remoteNode, ICMP_ECHO_REPLY, data, (BYTE)dataCount, ICMPId, ICMPSeq); smStack = SM_STACK_IDLE; } break; //case SM_STACK_ICMP_REPLY: #endif } //switch(smStack) FAST_USER_PROCESS(); } while(lbContinue); #if defined(STACK_USE_TCP) // Perform timed TCP FSM. TCPTick(); #endif //MODIFIED DHCP BEGIN // Removed this //#if defined(STACK_USE_DHCP) /* * DHCP must be called all the time even after IP configuration is * discovered. * DHCP has to account lease expiration time and renew the configuration * time. */ // DHCPTask(); // if(DHCPIsBound()) // stackFlags.bits.bInConfigMode = FALSE; //#endif //debugPutGenRomStr(2, (ROM char*)"MACTask"); //@mxd:2:%s //Perform routine MAC tasks MACTask(); }
/****************************************************************************** * Function: void StackTask(void) * PreCondition: StackInit() is already called. * Input: None * Output: Stack FSM is executed. * Side Effects: None * Note: This FSM checks for new incoming packets, * and routes it to appropriate stack components. * It also performs timed operations. * This function must be called periodically to * ensure timely responses. ******************************************************************************/ void StackTask(void) { static WORD dataCount; IP_ADDR tempLocalIP; BOOL lbContinue; #if defined(STACK_USE_ICMP) static BYTE data[MAX_ICMP_DATA_LEN]; static WORD ICMPId, ICMPSeq; #endif union { BYTE MACFrameType; BYTE IPFrameType; ICMP_CODE ICMPCode; } type; do { lbContinue = FALSE; switch(smStack) { case SM_STACK_IDLE: case SM_STACK_MAC: if ( !MACGetHeader(&remoteNode.MACAddr, &type.MACFrameType) ) { #if defined(STACK_USE_DHCP) // Normally, an application would not include DHCP module // if it is not enabled. But in case some one wants to disable // DHCP module at run-time, remember to not clear our IP // address if link is removed. if ( AppConfig.Flags.bIsDHCPEnabled ) { if ( !MACIsLinked() ) { AppConfig.MyIPAddr.Val = 0x00000000ul; AppConfig.Flags.bInConfigMode = TRUE; DHCPReset(); } } #endif break; } lbContinue = TRUE; if ( type.MACFrameType == MAC_IP ) smStack = SM_STACK_IP; else if ( type.MACFrameType == MAC_ARP ) smStack = SM_STACK_ARP; else MACDiscardRx(); break; case SM_STACK_ARP: if ( ARPProcess() ) smStack = SM_STACK_IDLE; break; case SM_STACK_IP: if ( IPGetHeader(&tempLocalIP,&remoteNode,&type.IPFrameType,&dataCount) ) { lbContinue = TRUE; if ( type.IPFrameType == IP_PROT_ICMP ) { smStack = SM_STACK_ICMP; #if defined(STACK_USE_IP_GLEANING) if(AppConfig.Flags.bInConfigMode && AppConfig.Flags.bIsDHCPEnabled) { /* * Accoriding to "IP Gleaning" procedure, * when we receive an ICMP packet with a valid * IP address while we are still in configuration * mode, accept that address as ours and conclude * configuration mode. */ if( tempLocalIP.Val != 0xffffffff ) { AppConfig.Flags.bInConfigMode = FALSE; AppConfig.MyIPAddr = tempLocalIP; myDHCPBindCount--; } } #endif } #if defined(STACK_USE_TCP) else if ( type.IPFrameType == IP_PROT_TCP ) smStack = SM_STACK_TCP; #endif #if defined(STACK_USE_UDP) else if ( type.IPFrameType == IP_PROT_UDP ) smStack = SM_STACK_UDP; #endif else // Unknown/unsupported higher level protocol { lbContinue = FALSE; MACDiscardRx(); smStack = SM_STACK_IDLE; } } else // Improper IP header version or checksum { MACDiscardRx(); smStack = SM_STACK_IDLE; } break; #if defined(STACK_USE_UDP) case SM_STACK_UDP: if ( UDPProcess(&remoteNode, &tempLocalIP, dataCount) ) smStack = SM_STACK_IDLE; break; #endif #if defined(STACK_USE_TCP) case SM_STACK_TCP: if ( TCPProcess(&remoteNode, &tempLocalIP, dataCount) ) smStack = SM_STACK_IDLE; break; #endif case SM_STACK_ICMP: smStack = SM_STACK_IDLE; #if defined(STACK_USE_ICMP) if ( dataCount <= (MAX_ICMP_DATA_LEN+8) ) { if ( ICMPGet(&type.ICMPCode,data,(BYTE*)&dataCount,&ICMPId,&ICMPSeq) ) { if ( type.ICMPCode == ICMP_ECHO_REQUEST ) { lbContinue = TRUE; smStack = SM_STACK_ICMP_REPLY; } } } #endif MACDiscardRx(); break; #if defined(STACK_USE_ICMP) case SM_STACK_ICMP_REPLY: if ( ICMPIsTxReady() ) { ICMPPut(&remoteNode,ICMP_ECHO_REPLY,data,(BYTE)dataCount,ICMPId,ICMPSeq); smStack = SM_STACK_IDLE; } break; #endif } } while(lbContinue); #if defined(STACK_USE_TCP) TCPTick(); // Perform timed TCP FSM. #endif #if defined(STACK_USE_DHCP) /* * DHCP must be called all the time even after IP configuration is * discovered. * DHCP has to account lease expiration time and renew the configuration * time. */ DHCPTask(); if(DHCPIsBound()) AppConfig.Flags.bInConfigMode = FALSE; #endif #if defined(STACK_USE_SNTP) SNTPTask(); // Execute SNTP client FSM #endif #if defined(STACK_USE_NBNS) NBNSTask(); // Execute NetBIOS name service task #endif }
/** * Performs UDP related tasks. Must continuesly be called. * * @preCondition UDPInit() is already called AND <br> * UDP segment is ready in MAC buffer * * @param remoteNode Remote node info * @param len Total length of UDP semgent * @param destIP The Destination IP Address of the currently received packet * * @return TRUE if this function has completed its task <br> * FALSE otherwise */ BOOL UDPProcess(NODE_INFO *remoteNode, IP_ADDR *destIP, WORD len) { UDP_HEADER h; UDP_SOCKET s; PSEUDO_HEADER pseudoHeader; WORD_VAL checksum; #if defined(UDP_SPEED_OPTIMIZE) BYTE temp; #endif //Retrieve UDP header. The data is read from the current MAC RX Buffer MACGetArray((BYTE*)&h, sizeof(h)); #if defined(UDP_SPEED_OPTIMIZE) temp = h.SourcePort.v[0]; h.SourcePort.v[0] = h.SourcePort.v[1]; h.SourcePort.v[1] = temp; temp = h.DestinationPort.v[0]; h.DestinationPort.v[0] = h.DestinationPort.v[1]; h.DestinationPort.v[1] = temp; //Will an overflow occur after the subtraction? if ((BYTE)sizeof(UDP_HEADER) > h.Length.v[1]) { temp = h.Length.v[0] - 1; } else { temp = h.Length.v[0]; } h.Length.v[0] = h.Length.v[1] - (BYTE)sizeof(UDP_HEADER); h.Length.v[1] = temp; #else h.SourcePort.Val = swaps(h.SourcePort.Val); h.DestinationPort.Val = swaps(h.DestinationPort.Val); h.Length.Val = swaps(h.Length.Val) - sizeof(UDP_HEADER); #endif // See if we need to validate the checksum field (0x0000 is disabled) if(h.Checksum.Val) { #if defined(UDP_SPEED_OPTIMIZE) temp = h.Checksum.v[0]; h.Checksum.v[0] = h.Checksum.v[1]; h.Checksum.v[1] = temp; #else h.Checksum.Val = swaps(h.Checksum.Val); #endif // Calculate IP pseudoheader checksum. pseudoHeader.SourceAddress = remoteNode->IPAddr; pseudoHeader.DestAddress.v[0] = destIP->v[0]; pseudoHeader.DestAddress.v[1] = destIP->v[1]; pseudoHeader.DestAddress.v[2] = destIP->v[2]; pseudoHeader.DestAddress.v[3] = destIP->v[3]; pseudoHeader.Zero = 0x0; pseudoHeader.Protocol = IP_PROT_UDP; pseudoHeader.Length = len; SwapPseudoHeader(pseudoHeader); checksum.Val = ~CalcIPChecksum((BYTE*)&pseudoHeader, sizeof(pseudoHeader)); // Set UCP packet checksum = pseudo header checksum in MAC RAM. IPSetRxBuffer(6); MACPut(checksum.v[0]); // In case if the end of the RX buffer is reached and a wraparound is needed, set the next address to prevent writing to the wrong address. IPSetRxBuffer(7); MACPut(checksum.v[1]); IPSetRxBuffer(0); //Set current receive buffer access pointer to first byte of IP data = first byte of TCP header // Now calculate UDP packet checksum in NIC RAM - including // pesudo header. checksum.Val = CalcIPBufferChecksum(len); if ( checksum.Val != h.Checksum.Val ) { MACDiscardRx(); //Discard the contents of the current RX buffer return TRUE; } } s = FindMatchingSocket(&h, remoteNode, destIP); if ( s == INVALID_UDP_SOCKET ) { // If there is no matching socket, There is no one to handle // this data. Discard it. MACDiscardRx(); //Discard the contents of the current RX buffer } else { UDPSocketInfo[s].RxCount = h.Length.Val; UDPSocketInfo[s].Flags.bFirstRead = TRUE; } return TRUE; }
/***************************************************************************** Function: bool ARPProcess(void) Summary: Processes an incoming ARP packet. Description: Retrieves an ARP packet from the MAC buffer and determines if it is a response to our request (in which case the ARP is resolved) or if it is a request requiring our response (in which case we transmit one.) Precondition: ARP packet is ready in the MAC buffer. Parameters: None Return Values: true - All processing of this ARP packet is complete. Do not call again until a new ARP packet is waiting in the RX buffer. false - This function must be called again. More time is needed to send an ARP response. ***************************************************************************/ bool ARPProcess(void) { ARP_PACKET packet; static NODE_INFO Target; #if defined(STACK_USE_AUTO_IP) uint8_t i; #endif static enum { SM_ARP_IDLE = 0, SM_ARP_REPLY } smARP = SM_ARP_IDLE; switch(smARP) { case SM_ARP_IDLE: // Obtain the incoming ARP packet MACGetArray((uint8_t*)&packet, sizeof(packet)); MACDiscardRx(); SwapARPPacket(&packet); // Validate the ARP packet if ( packet.HardwareType != HW_ETHERNET || packet.MACAddrLen != sizeof(MAC_ADDR) || packet.ProtocolLen != sizeof(IP_ADDR) ) { return true; } #ifdef STACK_USE_ZEROCONF_LINK_LOCAL ARPProcessRxPkt(&packet); #endif #ifdef STACK_USE_AUTO_IP if (packet.SenderIPAddr.Val == AppConfig.MyIPAddr.Val) { AutoIPConflict(0); return true; } #endif // Handle incoming ARP responses #ifdef STACK_CLIENT_MODE if(packet.Operation == ARP_OPERATION_RESP) { /* #if defined(STACK_USE_AUTO_IP) for (i = 0; i < NETWORK_INTERFACES; i++) if (AutoIPConfigIsInProgress(i)) AutoIPConflict(i); #endif*/ Cache.MACAddr = packet.SenderMACAddr; Cache.IPAddr = packet.SenderIPAddr; //putsUART("ARPProcess: SM_ARP_IDLE: ARP_OPERATION_RESP \r\n"); return true; } #endif // Handle incoming ARP requests for our MAC address if(packet.Operation == ARP_OPERATION_REQ) { if(packet.TargetIPAddr.Val != AppConfig.MyIPAddr.Val) { return true; } #ifdef STACK_USE_ZEROCONF_LINK_LOCAL /* Fix for Loop-Back suppression: * For ZCLL-Claim packets, host should not respond. * Check Sender's MAC-address with own MAC-address and * if it is matched, response will not be sent back. This * was leading to flooding of ARP-answeres */ if(!memcmp (&packet.SenderMACAddr, &AppConfig.MyMACAddr, 6)) { putsUART("Loopback answer suppressed \r\n"); return true; } #endif #if defined(STACK_USE_AUTO_IP) for (i = 0; i < NETWORK_INTERFACES; i++) if (AutoIPConfigIsInProgress(i)) { AutoIPConflict(i); return true; } #endif Target.IPAddr = packet.SenderIPAddr; Target.MACAddr = packet.SenderMACAddr; //putsUART("ARPProcess: SM_ARP_IDLE: ARP_OPERATION_REQ \r\n"); smARP = SM_ARP_REPLY; } // Do not break. If we get down here, we need to send a reply. case SM_ARP_REPLY: packet.Operation = ARP_OPERATION_RESP; #if defined(STACK_USE_AUTO_IP) if (AutoIPIsConfigured(0)) { packet.TargetMACAddr.v[0] = 0xFF; packet.TargetMACAddr.v[1] = 0xFF; packet.TargetMACAddr.v[2] = 0xFF; packet.TargetMACAddr.v[3] = 0xFF; packet.TargetMACAddr.v[4] = 0xFF; packet.TargetMACAddr.v[5] = 0xFF; } else #endif packet.TargetMACAddr = Target.MACAddr; packet.TargetIPAddr = Target.IPAddr; #ifdef STACK_USE_ZEROCONF_LINK_LOCAL packet.SenderIPAddr = AppConfig.MyIPAddr; #endif //putsUART("ARPProcess: SM_ARP_REPLY \r\n"); // Send an ARP response to a previously received request if(!ARPPut(&packet)) { return false; } // Begin listening for ARP requests again smARP = SM_ARP_IDLE; break; } return true; }
int1 MACGetHeader(MAC_ADDR *remote, int8* type) { NE_PREAMBLE header; int8 NICWritePtr; WORD_VAL temp; *type = MAC_UNKNOWN; // Reset NIC if overrun has occured. if ( NICGet(ISR) & 0x10 ) { #if 1 NICPut(CMDR, 0x21); Delay(0xff); NICPut(RBCR0, 0); NICPut(RBCR1, 0); NICPut(TCR, 0x02); NICPut(CMDR, 0x20); MACDiscardRx(); NICPut(ISR, 0xff); NICPut(TCR, 0x00); return FALSE; #else MACInit(); return FALSE; #endif } NICPut(CMDR, 0x60); NICWritePtr = NICGet(CURRP); NICPut(CMDR, 0x20); if ( NICWritePtr != NICReadPtr ) { temp.v[1] = NICReadPtr; temp.v[0] = 0; NICSetAddr(temp.Val); //MACGetArray((int8*)&header, sizeof(header)); debug("\r\n***************************************\r\n"); MACGetArray(&header, sizeof(NE_PREAMBLE)); debug(debug_putc,"\r\n\r\nGOT HDR = ST:%X NPP:%X LEN:%LU", (int8)header.Status,header.NextPacketPointer,header.ReceivedBytes); debug(debug_putc,"\r\n DEST: %X.%X.%X.%X.%X.%X SRC: %X.%X.%X.%X.%X.%X TYPE:%LX", header.DestMACAddr.v[0],header.DestMACAddr.v[1],header.DestMACAddr.v[2], header.DestMACAddr.v[3],header.DestMACAddr.v[4],header.DestMACAddr.v[5], header.SourceMACAddr.v[0],header.SourceMACAddr.v[1],header.SourceMACAddr.v[2], header.SourceMACAddr.v[3],header.SourceMACAddr.v[4],header.SourceMACAddr.v[5], header.Type.Val); // Validate packet length and status. if ( header.Status.PRX && (header.ReceivedBytes >= MINFRAMEC) && (header.ReceivedBytes <= MAXFRAMEC) ) { debug(debug_putc," VALID"); header.Type.Val = swaps(header.Type.Val); //memcpy((char*)remote->v, (char*)header.SourceMACAddr.v, sizeof(*remote)); memcpy(&remote->v[0], &header.SourceMACAddr.v[0], sizeof(MAC_ADDR)); if ( (header.Type.v[1] == 0x08) && ((header.Type.v[0] == ETHER_IP) || (header.Type.v[0] == ETHER_ARP)) ) *type = header.Type.v[0]; } NICCurrentRdPtr = NICReadPtr; NICReadPtr = header.NextPacketPointer; return TRUE; } return FALSE; }
BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type) { /* * This marks that all future accesses to MACGet and MACPut * be applied to Receive buffer. */ bIsRxActive = TRUE; if ( RxBuffer.PacketCount ) { /* * Set up packet access index. */ RxBuffer.CallerAccess = RxBuffer.CurrentPacket; RxBuffer.CallerAccess++; if ( RxBuffer.CallerAccess >= MAX_SLIP_BUFFER_SIZE ) RxBuffer.CallerAccess = 0; /* * Handle modem commands differently. */ if ( RxBuffer.Data[RxBuffer.CallerAccess] == 'A' ) { /* * Once a modem command is detected, we are not interested * in detail. */ MACDiscardRx(); //Discard the contents of the current RX buffer /* * Mark TxBuffer for Modem String. * This will make sure that Transmit ISR does nottransmit END * at the end. */ TxBuffer.Flags.bits.bIsModemString = TRUE; /* * Since this special handling does not follow standard * SLIP buffer logic, we will setup all required variables * manually. */ TxBuffer.Length = 4; TxBuffer.CallerAccess = 0; /* * Remember to use transmit buffer for MACPut */ bIsRxActive = FALSE; /* * Now load modem response. */ MACPut('O'); MACPut('K'); MACPut('\r'); MACPut('\n'); /* * Transmit it. */ MACFlush(); } else { /* * This was not a modem command. * It must be IP packet. Mark it accordingly and return. */ *type = MAC_IP; return TRUE; } } return FALSE; }
/***************************************************************************** Function: ARP_RESULT ARPProcess(NET_CONFIG* pIf) Summary: Processes an incoming ARP packet. Description: Retrieves an ARP packet from the MAC buffer and determines if it is a response to our request (in which case the ARP is resolved) or if it is a request requiring our response (in which case we transmit one.) Precondition: ARP packet is ready in the MAC buffer. Parameters: None Return Values: ARP_RES_OK - processing OK. ARP_RES_error - some error occurred ***************************************************************************/ ARP_RESULT ARPProcess(NET_CONFIG* pIf) { ARP_PACKET packet; MAC_ADDR *dstMAC; OA_HASH_ENTRY *hE; ARP_CACHE_DCPT *pArpDcpt; int netIx; TCPIP_MAC_HANDLE hMac; ARP_RESULT arpReqRes; netIx = _TCPIPStackNetIx(pIf); pArpDcpt = arpCache + netIx; hMac = _TCPIPStackNetToMac(pIf); // Obtain the incoming ARP packet and process MACGetArray(hMac, (uint8_t*)&packet, sizeof(packet)); MACDiscardRx(hMac); SwapARPPacket(&packet); // Validate the ARP packet if ( packet.HardwareType != HW_ETHERNET || packet.MACAddrLen != sizeof(MAC_ADDR) || packet.ProtocolLen != sizeof(IP_ADDR) ) { return ARP_RES_OK; } #ifdef TCPIP_STACK_USE_ZEROCONF_LINK_LOCAL ARPProcessRxPkt(pIf, &packet); #endif arpReqRes = ARP_RES_OK; // Handle incoming ARP packet hE = OAHashLookUp(pArpDcpt->cacheDcpt, &packet.SenderIPAddr.Val); if(hE != 0) { // we already have this sender and we should update it _ARPUpdateEntry(pIf, (ARP_HASH_ENTRY*)hE, &packet.SenderMACAddr); } while(packet.TargetIPAddr.Val == pIf->MyIPAddr.Val) { // we are the target and we should add to cache anyway if(hE == 0) { // not there yet arpReqRes = _ARPAddCompleteEntry(pIf, &packet.SenderIPAddr, &packet.SenderMACAddr); } // Handle incoming ARP operation if(packet.Operation == ARP_OPERATION_REQ) { // ARP packet asking for this host IP address #ifdef TCPIP_STACK_USE_ZEROCONF_LINK_LOCAL /* Fix for Loop-Back suppression: * For ZCLL-Claim packets, host should not respond. * Check Sender's MAC-address with own MAC-address and * if it is matched, response will not be sent back. This * was leading to flooding of ARP-answeres */ if(!memcmp (&packet.SenderMACAddr, &pIf->MyMACAddr, 6)) { SYS_CONSOLE_MESSAGE("Loopback answer suppressed \r\n"); break; } #endif #if defined(TCPIP_STACK_USE_AUTO_IP) if ((packet.SenderIPAddr.Val == pIf->MyIPAddr.Val) || AutoIPConfigIsInProgress(pIf)) { AutoIPConflict(pIf); break; } #endif // Need to send a reply to the requestor #if defined(TCPIP_STACK_USE_AUTO_IP) if (AutoIPIsConfigured(pIf)) { dstMAC = &arpBcastAdd; } else #endif { dstMAC = &packet.SenderMACAddr; } // Send an ARP response to the received request if(!ARP_SendIfPkt(pIf, ARP_OPERATION_RESP, (uint32_t)pIf->MyIPAddr.Val, (uint32_t)packet.SenderIPAddr.Val, dstMAC)) { arpReqRes = ARP_RES_TX_FAILED; } } break; } return arpReqRes; }