BOOL MACRxbufGetHdr(MAC_ADDR *remote, BYTE* type) { /* * This marks that all future accesses to MACRxbufGet 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. */ MACRxbufDiscard(); /* * 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; }
/** * Check if the MAC Receive Buffer has any received packets. * Reads the following data from the next available packet in the RX buffer: <ul> * <li> The MAC 4 bytes RX packet header (status, nex receive packet, length) </li> * <li> The 14 byte Ethernet header </li></ul> * Once a data packet is fetched by calling MACRxbufGetHdr, the complete data * packet must be fetched (using MACRxbufGet) and discarded (using MACRxbufDiscard). * Users cannot call MACRxbufGetHdr multiple times to receive multiple packets * and fetch data later on. * * @param[out] remote Pointer to a MAC_ADDR structure. This function will write the MAC address of the * node who sent this packet to this structure * @param[out] type Pointer to byte. This function will write the type of header to this variable. * Can be ETHER_IP, ETHER_ARP or MAC_UNKNOWN * * @return True if RX Buffer contained a packet and it's header was read, False if not * */ BOOL MACRxbufGetHdr(MAC_ADDR *remote, BYTE* type) { NE_PREAMBLE header; BYTE NICWritePtr; BYTE NICReadPtr; WORD_VAL temp; *type = MAC_UNKNOWN; //Read CURR and BNDY registers = RX Buffer's GET and PUT pointers NICPut(CMDR, 0x60); //Set page 1 NICWritePtr = NICGet(CURRP); //Curr is the RX Buffer's PUT pointer NICPut(CMDR, 0x20); //Reset to page 0 NICReadPtr = NICGet(BNRY); //Get BNRY pointer // Reset NIC if overrun has occured. if ( NICGet(ISR) & 0x10 ) { BYTE resend; #if (DEBUG_MAC >= LOG_ERROR) debugPutMsg(3); //@mxd:3:Overrun error! Reseting MAC! #endif // Save TXP bit resend = NICGet(CMDR) & 0x04; //Issue STOP command to NIC and delay 2ms NICPut(CMDR, 0x21); DelayMs(2); //Clear Remote Byte count registers NICPut(RBCR0, 0); NICPut(RBCR1, 0); // TXP bit set? if (resend) // No re-send if Packet Transmitted or Transmit Error bit is set resend = !(NICGet(ISR) & 0x0A); //Put NIC in loopback mode and issue start command NICPut(TCR, 0x02); NICPut(CMDR, 0x22); // HM: Modified, changed to 22 to re-start NIC // Empty ring buffer completely MACCurrRxbuf = NICWritePtr; MACRxbufDiscard(); //Reset ISR by writing FF to it NICPut(ISR, 0xff); //Take NIC out of loopback mode NICPut(TCR, 0x00); //Resend the packet if(resend) NICPut(CMDR, 0x26); return FALSE; } //Is there something in the buffer if ( NICWritePtr != NICReadPtr ) { temp.v[1] = NICReadPtr; //Pointer to RAM page, is MSB of address temp.v[0] = 0; //LSB is 0 NICSetAddr(temp.Val); //Read the following from the current MAC RX Buffer: // - The MAC 4 bytes RX packet header (status, nex receive packet, length) // - The 14 byte Ethernet header MACRxbufGetArray((BYTE*)&header, sizeof(header)); // Validate packet length and status as. if ( header.Status.PRX && (header.ReceivedBytes >= MINFRAMEC) && (header.ReceivedBytes <= MAXFRAMEC) && (header.NextPacketPointer < RXSTOP) && (header.NextPacketPointer >= RXSTART) ) { header.Type.Val = swaps(header.Type.Val); memcpy((void*)remote->v, (void*)header.SourceMACAddr.v, sizeof(*remote)); if ( (header.Type.v[1] == 0x08) && ((header.Type.v[0] == ETHER_IP) || (header.Type.v[0] == ETHER_ARP)) ) *type = header.Type.v[0]; MACCurrRxbuf = NICReadPtr; //Set MACCurrRxbuf with page address of current RX Buffer return TRUE; } //ERROR!!! Invalid packet received! #if (DEBUG_MAC >= LOG_ERROR) debugPutMsg(4); //@mxd:4:Invalid Packet Error! #endif //Ring now contains garbage MACCurrRxbuf = NICWritePtr; // Empty ring buffer completely MACRxbufDiscard(); } return FALSE; }
/** * 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 NODE_INFO remoteNode; 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; lbContinue = TRUE; while( lbContinue ) { lbContinue = FALSE; switch(smStack) { case SM_STACK_IDLE: case SM_STACK_MAC: //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'. if ( !MACRxbufGetHdr(&remoteNode.MACAddr, &type.MACFrameType) ) { //Header was NOT read if MACRxbufGetHdr returned FALSE #if defined(STACK_USE_DHCP) //If DHCP is enabled AND MAC is not linked yet, set our IP to 0 if (STACK_IS_DHCP_ENABLED) { if ( !MACIsLinked() ) { #if (DEBUG_STACKTSK >= LOG_INFO) debugPutMsg(1); //@mxd:1:DHCP Enabled but MAC not linked yet - set IP to 0.0.0.0 #endif //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 break; } 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 { MACRxbufDiscard(); #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_ARP: lbContinue = FALSE; if ( ARPProcess() ) smStack = SM_STACK_IDLE; 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 ) { /* * 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]; #if defined(STACK_USE_DHCP) /* * If DHCP and IP gleaning is enabled at the * same time, we must ensuer that once we have * IP address through IP gleaning, we abort * any pending DHCP requests and do not renew * any new DHCP configuration. */ DHCPAbort(); #endif } } #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 { lbContinue = FALSE; MACRxbufDiscard(); smStack = SM_STACK_IDLE; } } else { MACRxbufDiscard(); smStack = SM_STACK_IDLE; } break; #if defined(STACK_USE_UDP) case SM_STACK_UDP: //tempLocalIP.v[0] = MY_IP_BYTE1; //tempLocalIP.v[1] = MY_IP_BYTE2; //tempLocalIP.v[2] = MY_IP_BYTE3; //tempLocalIP.v[3] = MY_IP_BYTE4; if ( UDPProcess(&remoteNode, &destIP, dataCount) ) smStack = SM_STACK_IDLE; lbContinue = FALSE; break; #endif #if defined(STACK_USE_TCP) case SM_STACK_TCP: //tempLocalIP.v[0] = MY_IP_BYTE1; //tempLocalIP.v[1] = MY_IP_BYTE2; //tempLocalIP.v[2] = MY_IP_BYTE3; //tempLocalIP.v[3] = MY_IP_BYTE4; //Will return TRUE if TCPProcess finished it's task, else FALSE if ( TCPProcess(&remoteNode, &destIP, dataCount) ) smStack = SM_STACK_IDLE; lbContinue = FALSE; break; #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; } else { smStack = SM_STACK_IDLE; } } else { smStack = SM_STACK_IDLE; } } #endif MACRxbufDiscard(); 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 } } #if defined(STACK_USE_TCP) // Perform timed TCP FSM. TCPTick(); #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() ) stackFlags.bits.bInConfigMode = FALSE; #endif //Perform routine MAC tasks MACTask(); }
/** * Only one IP message can be received. Caller may not transmit and receive * a message at the same time. * * @preCondition MACRxbufGetHdr() == TRUE * * @param localIP Local node IP Address (Destination IP Address) as received in current IP header. * If this information is not required caller may pass NULL value. * @param remote Remote node info * @param protocol Current packet protocol * @param len Length of IP data. For example, if TCP is contained in this IP * packet, this will be = TCP Header length + TCP Data Length * * @return TRUE, if valid packet was received <br> * FALSE otherwise */ BOOL IPGetHeader(IP_ADDR *localIP, NODE_INFO *remote, BYTE *protocol, WORD *len) { WORD_VAL ReceivedChecksum; WORD_VAL CalcChecksum; WORD checksums[2]; IP_HEADER header; BYTE optionsLen; #define MAX_OPTIONS_LEN (20) // As per RFC 791. BYTE options[MAX_OPTIONS_LEN]; //Read IP header. The data is read from the current MAC RX Buffer MACRxbufGetArray((BYTE*)&header, sizeof(header)); //Write out ID of received IP header #if (DEBUG_IP >= LOG_DEBUG) debugPutMsg(1); //@mxd:1:Received IP header with ID=0x%x%x //Write HEX WORD value of tmp debugPutByteHex(header.Identification.v[0]); debugPutByteHex(header.Identification.v[1]); #endif // Make sure that this IPv4 packet. if ( (header.VersionIHL & 0xf0) != IP_VERSION ) { goto IPGetHeader_Discard; } /* * Calculate options length in this header, if there is any. * IHL is in terms of numbers of 32-bit DWORDs; i.e. actual * length is 4 times IHL. */ optionsLen = ((header.VersionIHL & 0x0f) << 2) - sizeof(header); /* * If there is any option(s), read it so that we can include them * in checksum calculation. */ if ( optionsLen > MAX_OPTIONS_LEN ) { goto IPGetHeader_Discard; } if ( optionsLen > 0 ) { //Read options data. The data is read from the current MAC RX Buffer MACRxbufGetArray(options, optionsLen); } // Save header checksum; clear it and recalculate it ourselves. ReceivedChecksum.Val = header.HeaderChecksum.Val; header.HeaderChecksum.Val = 0; // Calculate checksum of header including options bytes. checksums[0] = ~CalcIPChecksum((BYTE*)&header, sizeof(header)); // Calculate Options checksum too, if they are present. if ( optionsLen > 0 ) checksums[1] = ~CalcIPChecksum((BYTE*)options, optionsLen); else checksums[1] = 0; CalcChecksum.Val = CalcIPChecksum((BYTE*)checksums, 2 * sizeof(WORD)); // Network to host conversion. SwapIPHeader(&header); // Make sure that checksum is correct and IP version is supported. if ( ReceivedChecksum.Val != CalcChecksum.Val || (header.VersionIHL & 0xf0) != IP_VERSION ) { // Bad/Unknown packet. Discard it. goto IPGetHeader_Discard; } /* * If caller is intrested, return destination IP address * as seen in this IP header. */ if ( localIP ) localIP->Val = header.DestAddress.Val; remote->IPAddr.Val = header.SourceAddress.Val; *protocol = header.Protocol; *len = header.TotalLength.Val - optionsLen - sizeof(header); return TRUE; IPGetHeader_Discard: MACRxbufDiscard(); return FALSE; }