/********************************************************************* * Function: WORD IPPutHeader(NODE_INFO *remote, * BYTE protocol, * WORD len) * * PreCondition: IPIsTxReady() == TRUE * * Input: *remote - Destination node address * protocol - Current packet protocol * len - Current packet data length * * Output: (WORD)0 * * Side Effects: None * * Note: Only one IP message can be transmitted at any * time. ********************************************************************/ WORD IPPutHeader(NODE_INFO *remote, BYTE protocol, WORD len) { IP_HEADER header; IPHeaderLen = sizeof(IP_HEADER); header.VersionIHL = IP_VERSION | IP_IHL; header.TypeOfService = IP_SERVICE; header.TotalLength = sizeof(header) + len; header.Identification = ++_Identifier; header.FragmentInfo = 0; header.TimeToLive = MY_IP_TTL; header.Protocol = protocol; header.HeaderChecksum = 0; header.SourceAddress = AppConfig.MyIPAddr; header.DestAddress.Val = remote->IPAddr.Val; SwapIPHeader(&header); header.HeaderChecksum = CalcIPChecksum((BYTE*)&header, sizeof(header)); MACPutHeader(&remote->MACAddr, MAC_IP, (sizeof(header)+len)); MACPutArray((BYTE*)&header, sizeof(header)); return 0x0000; }
/** * Write the Ethernet Header (MAC Header) and IP Header to the current TX buffer. * The last parameter (len) is the length of the data to follow. * This function will do the following: <ul> * <li> Reset the NIC Remote DMA write pointer to the first byte of the current TX Buffer </li> * <li> Write the given header </li> * <li> Set the NIC Remote DMA byte count to the given len. This configures the Remote DMA * to send the given number of bytes. Only one IP message can be transmitted at any time. * Caller may not transmit and receive a message at the same time.</li></ul> * * @preCondition IPIsTxReady() == TRUE * * @param remote Destination node address * @param protocol Protocol of data to follow, for example IP_PROT_ICMP, IP_PROT_TCP.... * @param len Total length of IP data bytes to follow, excluding IP header. This * is the length of the bytes to follow. * * @return Handle to current packet - For use by IPSendByte() function. * */ WORD IPPutHeader(NODE_INFO *remote, BYTE protocol, WORD len) { IP_HEADER header; header.VersionIHL = IP_VERSION | IP_IHL; header.TypeOfService = IP_SERVICE; header.TotalLength.Val = sizeof(header) + len; header.Identification.Val = ++_Identifier; /** Set the Don't fragment flag for all IP message we sent. We do NOT want to get fragmented data! */ header.FragmentInfo.Val = IP_FLAG_MASK_DF; header.TimeToLive = MY_IP_TTL; header.Protocol = protocol; header.HeaderChecksum.Val = 0; header.SourceAddress.v[0] = MY_IP_BYTE1; header.SourceAddress.v[1] = MY_IP_BYTE2; header.SourceAddress.v[2] = MY_IP_BYTE3; header.SourceAddress.v[3] = MY_IP_BYTE4; header.DestAddress.Val = remote->IPAddr.Val; SwapIPHeader(&header); header.HeaderChecksum.Val = CalcIPChecksum((BYTE*)&header, sizeof(header)); //Write the Ethernet Header to the current TX buffer. The last parameter (dataLen) is the length //of the data to follow. This function will do the following: // - Reset the NIC Remote DMA write pointer to the first byte of the current TX Buffer // - Write the given header // - Set the NIC Remote DMA byte count to the given len. This configures the Remote DMA to // receive the given number of bytes MACPutHeader(&remote->MACAddr, MAC_IP, (sizeof(header)+len)); //Write the IP header to the MAC's TX buffer. MACPutArray((BYTE*)&header, sizeof(header)); return 0x0; }
/********************************************************************* * Function: WORD IPPutHeader(NODE_INFO *remote, * BYTE protocol, * WORD len) * * PreCondition: IPIsTxReady() == TRUE * * Input: *remote - Destination node address * protocol - Current packet protocol * len - Current packet data length * * Output: (WORD)0 * * Side Effects: None * * Note: Only one IP message can be transmitted at any * time. ********************************************************************/ WORD IPPutHeader(NODE_INFO *remote, BYTE protocol, WORD len) { IP_HEADER header; IPHeaderLen = sizeof(IP_HEADER); header.VersionIHL = IP_VERSION | IP_IHL; header.TypeOfService = IP_SERVICE; header.TotalLength = sizeof(header) + len; header.Identification = ++_Identifier; header.FragmentInfo = 0; header.TimeToLive = MY_IP_TTL; header.Protocol = protocol; header.HeaderChecksum = 0; header.SourceAddress = AppConfig.MyIPAddr; header.DestAddress.Val = remote->IPAddr.Val; SwapIPHeader(&header); #if defined(NON_MCHP_MAC) header.HeaderChecksum = CalcIPChecksum((BYTE*)&header, sizeof(header)); #endif MACPutHeader(&remote->MACAddr, MAC_IP, (sizeof(header)+len)); MACPutArray((BYTE*)&header, sizeof(header)); #if !defined(NON_MCHP_MAC) header.HeaderChecksum = MACCalcTxChecksum(0, sizeof(header)); MACSetTxBuffer(CurrentTxBuffer, 10); // 10 is the offset in header to the HeaderChecksum member MACPutArray((BYTE*)&header.HeaderChecksum, 2); MACSetTxBuffer(CurrentTxBuffer, sizeof(header)); // Seek back to the end of the packet #endif return 0x0; }
/********************************************************************* * Function: BOOL IPGetHeader( IP_ADDR *localIP, * NODE_INFO *remote, * BYTE *Protocol, * WORD *len) * * PreCondition: MACGetHeader() == TRUE * * Input: localIP - Local node IP Address as received * in current IP header. * If this information is not required * caller may pass NULL value. * remote - Remote node info * Protocol - Current packet protocol * len - Current packet data length * * Output: TRUE, if valid packet was received * FALSE otherwise * * Side Effects: None * * Note: Only one IP message can be received. * Caller may not transmit and receive a message * at the same time. * ********************************************************************/ BOOL IPGetHeader(IP_ADDR *localIP, NODE_INFO *remote, BYTE *protocol, WORD *len) { WORD_VAL CalcChecksum; IP_HEADER header; #if defined(NON_MCHP_MAC) WORD_VAL ReceivedChecksum; WORD checksums[2]; BYTE optionsLen; #define MAX_OPTIONS_LEN (40u) // As per RFC 791. BYTE options[MAX_OPTIONS_LEN]; #endif // Read IP header. MACGetArray((BYTE*)&header, sizeof(header)); // Make sure that this is an IPv4 packet. if((header.VersionIHL & 0xf0) != IP_VERSION) return FALSE; // Throw this packet away if it is a fragment. // We don't have enough RAM for IP fragment reconstruction. if(header.FragmentInfo & 0xFF1F) return FALSE; IPHeaderLen = (header.VersionIHL & 0x0f) << 2; #if !defined(NON_MCHP_MAC) // Validate the IP header. If it is correct, the checksum // will come out to 0x0000 (because the header contains a // precomputed checksum). A corrupt header will have a // nonzero checksum. CalcChecksum.Val = MACCalcRxChecksum(0, IPHeaderLen); // Seek to the end of the IP header MACSetReadPtrInRx(IPHeaderLen); if(CalcChecksum.Val) #else // 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 = IPHeaderLen - sizeof(header); // If there is any option(s), read it so that we can include them // in checksum calculation. if ( optionsLen > MAX_OPTIONS_LEN ) return FALSE; if ( optionsLen > 0u ) MACGetArray(options, optionsLen); // Save header checksum; clear it and recalculate it ourselves. ReceivedChecksum.Val = header.HeaderChecksum; header.HeaderChecksum = 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 > 0u ) checksums[1] = ~CalcIPChecksum((BYTE*)options, optionsLen); else checksums[1] = 0; CalcChecksum.Val = CalcIPChecksum((BYTE*)checksums, 2 * sizeof(WORD)); // Make sure that checksum is correct if ( ReceivedChecksum.Val != CalcChecksum.Val ) #endif { // Bad packet. The function caller will be notified by means of the FALSE // return value and it should discard the packet. return FALSE; } // Network to host conversion. SwapIPHeader(&header); // 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 - IPHeaderLen; return TRUE; }
/** * 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; }