/****************************************************************************** * Function: WORD MACCalcRxChecksum(WORD offset, WORD len) * * PreCondition: None * * Input: offset - Number of bytes beyond the beginning of the * Ethernet data (first byte after the type field) * where the checksum should begin * len - Total number of bytes to include in the checksum * * Output: 16-bit checksum as defined by RFC 793. * * Side Effects: None * * Overview: This function performs a checksum calculation in the MAC * buffer itself * * Note: None *****************************************************************************/ WORD MACCalcRxChecksum(WORD offset, WORD len) { WORD temp; WORD RDSave; // Add the offset requested by firmware plus the Ethernet header temp = CurrentPacketLocation.Val + sizeof (ENC_PREAMBLE) + offset; if (temp > RXSTOP) // Adjust value if a wrap is needed { temp -= RXSIZE; } RDSave = ERDPT; ERDPT = temp; temp = CalcIPBufferChecksum(len); ERDPT = RDSave; return temp; }
/********************************************************************* * Function: void ICMPProcess(void) * * PreCondition: MAC buffer contains ICMP type packet. * * Input: *remote: Pointer to a NODE_INFO structure of the * ping requester * len: Count of how many bytes the ping header and * payload are in this IP packet * * Output: Generates an echo reply, if requested * Validates and sets ICMPFlags.bReplyValid if a * correct ping response to one of ours is received. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ void ICMPProcess(NODE_INFO *remote, WORD len) { DWORD_VAL dwVal; // Obtain the ICMP header Type, Code, and Checksum fields MACGetArray((BYTE*)&dwVal, sizeof(dwVal)); // See if this is an ICMP echo (ping) request if(dwVal.w[0] == 0x0008u) { // Validate the checksum using the Microchip MAC's DMA module // The checksum data includes the precomputed checksum in the // header, so a valid packet will always have a checksum of // 0x0000 if the packet is not disturbed. if(MACCalcRxChecksum(0+sizeof(IP_HEADER), len)) return; // Calculate new Type, Code, and Checksum values dwVal.v[0] = 0x00; // Type: 0 (ICMP echo/ping reply) dwVal.v[2] += 8; // Subtract 0x0800 from the checksum if(dwVal.v[2] < 8u) { dwVal.v[3]++; if(dwVal.v[3] == 0u) dwVal.v[2]++; } // Wait for TX hardware to become available (finish transmitting // any previous packet) while(!IPIsTxReady()); // Position the write pointer for the next IPPutHeader operation // NOTE: do not put this before the IPIsTxReady() call for WF compatbility MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Create IP header in TX memory IPPutHeader(remote, IP_PROT_ICMP, len); // Copy ICMP response into the TX memory MACPutArray((BYTE*)&dwVal, sizeof(dwVal)); MACMemCopyAsync(-1, -1, len-4); while(!MACIsMemCopyDone()); // Transmit the echo reply packet MACFlush(); } #if defined(STACK_USE_ICMP_CLIENT) else if(dwVal.w[0] == 0x0000u) // See if this an ICMP Echo reply to our request { // Get the sequence number and identifier fields MACGetArray((BYTE*)&dwVal, sizeof(dwVal)); // See if the identifier matches the one we sent if(dwVal.w[0] != 0xEFBE) return; if(dwVal.w[1] != wICMPSequenceNumber) return; // Validate the ICMP checksum field IPSetRxBuffer(0); if(CalcIPBufferChecksum(sizeof(ICMP_PACKET))) // Two bytes of payload were sent in the echo request return; // Flag that we received the response and stop the timer ticking ICMPFlags.bReplyValid = 1; ICMPTimer = TickGet() - ICMPTimer; } #endif }
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: void UDPFlush(void) Summary: Transmits all pending data in a UDP socket. Description: This function builds a UDP packet with the pending TX data and marks it for transmission over the network interface. Since UDP is a frame-based protocol, this function must be called before returning to the main stack loop whenever any data is written. Precondition: UDPIsPutReady() was previously called to specify the current socket, and data has been written to the socket using the UDPPut family of functions. Parameters: None Returns: None Remarks: Note that unlike TCPFlush, UDPFlush must be called before returning to the main stack loop. There is no auto transmit for UDP segments. ***************************************************************************/ void UDPFlush(void) { UDP_HEADER h; UDP_SOCKET_INFO *p; WORD wUDPLength; p = &UDPSocketInfo[activeUDPSocket]; wUDPLength = UDPTxCount + sizeof(UDP_HEADER); // Generate the correct UDP header h.SourcePort = swaps(p->localPort); h.DestinationPort = swaps(p->remotePort); h.Length = swaps(wUDPLength); h.Checksum = 0x0000; // Calculate IP pseudoheader checksum if we are going to enable // the checksum field #if defined(UDP_USE_TX_CHECKSUM) { PSEUDO_HEADER pseudoHeader; pseudoHeader.SourceAddress = AppConfig.MyIPAddr; pseudoHeader.DestAddress = p->remote.remoteNode.IPAddr; pseudoHeader.Zero = 0x0; pseudoHeader.Protocol = IP_PROT_UDP; pseudoHeader.Length = wUDPLength; SwapPseudoHeader(pseudoHeader); h.Checksum = ~CalcIPChecksum((BYTE*)&pseudoHeader, sizeof(pseudoHeader)); } #endif // Position the hardware write pointer where we will need to // begin writing the IP header MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Write IP header to packet IPPutHeader(&p->remote.remoteNode, IP_PROT_UDP, wUDPLength); // Write UDP header to packet MACPutArray((BYTE*)&h, sizeof(h)); // Calculate the final UDP checksum and write it in, if enabled #if defined(UDP_USE_TX_CHECKSUM) { PTR_BASE wReadPtrSave; WORD wChecksum; wReadPtrSave = MACSetReadPtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER)); wChecksum = CalcIPBufferChecksum(wUDPLength); if(wChecksum == 0x0000u) wChecksum = 0xFFFF; MACSetReadPtr(wReadPtrSave); MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER) + 6); // 6 is the offset to the Checksum field in UDP_HEADER MACPutArray((BYTE*)&wChecksum, sizeof(wChecksum)); } #endif // Transmit the packet MACFlush(); // Reset packet size counter for the next TX operation UDPTxCount = 0; LastPutSocket = INVALID_UDP_SOCKET; }
/***************************************************************************** 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; }
/** * 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; }