/********************************************************************* * Function: LONG ICMPGetReply(void) * * PreCondition: ICMPBeginUsage() returned TRUE and ICMPSendPing() * was called * * Input: None * * Output: -2: No response received yet * -1: Operation timed out (longer than ICMP_TIMEOUT) * has elapsed. * >=0: Number of TICKs that elapsed between * initial ICMP transmission and reception of * a valid echo. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ LONG ICMPGetReply(void) { switch(ICMPState) { case SM_ARP_RESOLVE: // See if the ARP reponse was successfully received if(ARPIsResolved(&ICMPRemote.IPAddr, &ICMPRemote.MACAddr)) { // Position the write pointer for the next IPPutHeader operation MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Wait for TX hardware to become available (finish transmitting // any previous packet) while(!IPIsTxReady()); // Create IP header in TX memory IPPutHeader(&ICMPRemote, IP_PROT_ICMP, sizeof(ICMP_HEADER) + 2); MACPutArray((BYTE*)&ICMPHeader, sizeof(ICMPHeader)); MACPut(0x00); // Send two dummy bytes as ping payload MACPut(0x00); // (needed for compatibility with some buggy NAT routers) MACFlush(); // MAC Address resolved and echo sent, advance state ICMPState = SM_GET_ECHO; return -2; } // See if the ARP/echo request timed out if(TickGet() - ICMPTimer > ICMP_TIMEOUT) { ICMPState = SM_IDLE; return -1; } // No ARP response back yet return -2; case SM_GET_ECHO: // See if the echo was successfully received if(ICMPFlags.bReplyValid) { return (LONG)ICMPTimer; } // See if the ARP/echo request timed out if(TickGet() - ICMPTimer > ICMP_TIMEOUT) { ICMPState = SM_IDLE; return -1; } // No echo response back yet return -2; // SM_IDLE or illegal/impossible state: default: return -1; } }
/********************************************************************* * Function: SHORT ICMPGetReply(void) * * PreCondition: ICMPBeginUsage() returned TRUE and ICMPSendPing() * was called * * Input: None * * Output: -2: No response received yet * -1: Operation timed out (longer than ICMP_TIMEOUT) * has elapsed. * >=0: Number of TICKs that elapsed between * initial ICMP transmission and reception of * a valid echo. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ SHORT ICMPGetReply(void) { switch(ICMPState) { case SM_IDLE: return -1; case SM_ARP_RESOLVE: // See if the ARP reponse was successfully received if(ARPIsResolved(&ICMPRemote.IPAddr, &ICMPRemote.MACAddr)) { // Position the write pointer for the next IPPutHeader operation MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Wait for TX hardware to become available (finish transmitting // any previous packet) while(!IPIsTxReady()); // Create IP header in TX memory IPPutHeader(&ICMPRemote, IP_PROT_ICMP, sizeof(ICMP_HEADER)); MACPutArray((BYTE*)&ICMPHeader, sizeof(ICMPHeader)); MACFlush(); // MAC Address resolved and echo sent, advance state ICMPState = SM_GET_ECHO; return -2; } // See if the ARP/echo request timed out if((WORD)TickGet() - ICMPTimer > ICMP_TIMEOUT) { ICMPState = SM_IDLE; return -1; } // No ARP response back yet return -2; case SM_GET_ECHO: // See if the echo was successfully received if(ICMPFlags.bReplyValid) { return (SHORT)ICMPTimer; } // See if the ARP/echo request timed out if((WORD)TickGet() - ICMPTimer > ICMP_TIMEOUT) { ICMPState = SM_IDLE; return -1; } // No echo response back yet return -2; } }
/** * This function transmit all data from the active UDP socket. * * @preCondition UDPPut() is already called and desired UDP socket * is set as an active socket by calling * UDPIsPutReady(). * * @return All and any data associated with active UDP socket * buffer is marked as ready for transmission. * */ void UDPFlush(void) { UDP_HEADER h; UDP_SOCKET_INFO *p; // Wait for TX hardware to become available (finish transmitting // any previous packet) while( !IPIsTxReady(TRUE) ) FAST_USER_PROCESS(); p = &UDPSocketInfo[activeUDPSocket]; h.SourcePort.Val = swaps(p->localPort); h.DestinationPort.Val = swaps(p->remotePort); h.Length.Val = (WORD)((WORD)p->TxCount + (WORD)sizeof(UDP_HEADER)); // Do not swap h.Length yet. It is needed in IPPutHeader. h.Checksum.Val = 0x00; //Makes the given TX Buffer active, and set's the pointer to the first byte after the IP //header. This is the first byte of the UDP header. The UDP header follows the IP header. IPSetTxBuffer(p->TxBuffer, 0); //Load IP header. IPPutHeader( &p->remoteNode, IP_PROT_UDP, h.Length.Val ); //Now swap h.Length.Val h.Length.Val = swaps(h.Length.Val); //Now load UDP header. IPPutArray((BYTE*)&h, sizeof(h)); //Update checksum. !!!!!!!!!!!!!!! TO BE IMPLEMENTED !!!!!!!!!!!!!!!!!!! //Send data contained in TX Buffer via MAC MACFlush(); // The buffer was reserved with AutoFree, so we can immediately // discard it. The MAC layer will free it after transmission. p->TxBuffer = INVALID_BUFFER; p->TxCount = 0; }
/********************************************************************* * Function: LONG ICMPGetReply(void) * * PreCondition: ICMPBeginUsage() returned TRUE and ICMPSendPing() * was called * * Input: None * * Output: -3: Could not resolve hostname (DNS timeout or * hostname invalid) * -2: No response received yet * -1: Operation timed out (longer than ICMP_TIMEOUT) * has elapsed. * >=0: Number of TICKs that elapsed between * initial ICMP transmission and reception of * a valid echo. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ LONG ICMPGetReply(void) { ICMP_PACKET ICMPPacket; switch(ICMPState) { #if defined(STACK_USE_DNS) case SM_DNS_SEND_QUERY: // Obtain DNS module ownership if(!DNSBeginUsage()) break; // Send DNS query if(ICMPFlags.bRemoteHostIsROM) DNSResolveROM(StaticVars.RemoteHost.szROM, DNS_TYPE_A); else DNSResolve(StaticVars.RemoteHost.szRAM, DNS_TYPE_A); ICMPState = SM_DNS_GET_RESPONSE; break; case SM_DNS_GET_RESPONSE: // See if DNS is done, and if so, get the remote IP address if(!DNSIsResolved(&StaticVars.ICMPRemote.IPAddr)) break; // Free the DNS module DNSEndUsage(); // Return error code if the DNS query failed if(StaticVars.ICMPRemote.IPAddr.Val == 0x00000000ul) { ICMPState = SM_IDLE; return -3; } ICMPState = SM_ARP_SEND_QUERY; // No break; #endif case SM_ARP_SEND_QUERY: ARPResolve(&StaticVars.ICMPRemote.IPAddr); ICMPState = SM_ARP_GET_RESPONSE; break; case SM_ARP_GET_RESPONSE: // See if the ARP reponse was successfully received if(!ARPIsResolved(&StaticVars.ICMPRemote.IPAddr, &StaticVars.ICMPRemote.MACAddr)) break; ICMPState = SM_ICMP_SEND_ECHO_REQUEST; // No break; case SM_ICMP_SEND_ECHO_REQUEST: if(!IPIsTxReady()) break; // Set up the ping packet ICMPPacket.vType = 0x08; // 0x08: Echo (ping) request ICMPPacket.vCode = 0x00; ICMPPacket.wChecksum = 0x0000; ICMPPacket.wIdentifier = 0xEFBE; wICMPSequenceNumber++; ICMPPacket.wSequenceNumber = wICMPSequenceNumber; ICMPPacket.wData = 0x2860; ICMPPacket.wChecksum = CalcIPChecksum((BYTE*)&ICMPPacket, sizeof(ICMPPacket)); // Record the current time. This will be used as a basis for // finding the echo response time, which exludes the ARP and DNS // steps ICMPTimer = TickGet(); // Position the write pointer for the next IPPutHeader operation MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Create IP header in TX memory IPPutHeader(&StaticVars.ICMPRemote, IP_PROT_ICMP, sizeof(ICMPPacket)); MACPutArray((BYTE*)&ICMPPacket, sizeof(ICMPPacket)); MACFlush(); // Echo sent, advance state ICMPState = SM_ICMP_GET_ECHO_RESPONSE; break; case SM_ICMP_GET_ECHO_RESPONSE: // See if the echo was successfully received if(ICMPFlags.bReplyValid) return (LONG)ICMPTimer; break; // SM_IDLE or illegal/impossible state: default: return -1; } // See if the DNS/ARP/echo request timed out if(TickGet() - ICMPTimer > ICMP_TIMEOUT) { // Free DNS module if we have it in use #if defined(STACK_USE_DNS) if(ICMPState == SM_DNS_GET_RESPONSE) DNSEndUsage(); #endif // Stop ICMP echo test and return error to caller ICMPState = SM_IDLE; return -1; } // Still working. No response to report yet. return -2; }
/********************************************************************* * 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 }
/********************************************************************* * Function: BOOL UDPFlush(void) * * PreCondition: UDPPut() is already called and desired UDP socket * is set as an active socket by calling * UDPIsPutReady(). * * Input: None * * Output: All and any data associated with active UDP socket * buffer is marked as ready for transmission. * * Side Effects: None * * Overview: None * * Note: This function transmit all data from * an active UDP socket. ********************************************************************/ void UDPFlush(void) { UDP_HEADER h; UDP_SOCKET_INFO *p; // Wait for TX hardware to become available (finish transmitting // any previous packet) while( !IPIsTxReady(TRUE) ); p = &UDPSocketInfo[activeUDPSocket]; debug_udp("\r\nUDP FLUSH - Sok:%U TxC:%LU SP:%LU DP:%LU ", activeUDPSocket, p->TxCount, p->localPort, p->remotePort ); debug_udp("MAC-%X:%X:%X:%X:%X:%X", p->remoteNode.MACAddr.v[0], p->remoteNode.MACAddr.v[1], p->remoteNode.MACAddr.v[2], p->remoteNode.MACAddr.v[3], p->remoteNode.MACAddr.v[4], p->remoteNode.MACAddr.v[5] ); h.SourcePort = swaps(p->localPort); h.DestinationPort = swaps(p->remotePort); h.Length = (WORD)((WORD)p->TxCount + (WORD)sizeof(UDP_HEADER)); // Do not swap h.Length yet. It is needed in IPPutHeader. h.Checksum = 0x0000; IPSetTxBuffer(p->TxBuffer, 0); /* * Load IP header. */ IPPutHeader( &p->remoteNode, IP_PROT_UDP, h.Length ); // Now swap h.Length. h.Length = swaps(h.Length); // Now load UDP header. IPPutArray((BYTE*)&h, sizeof(h)); // Update checksum. // TO BE IMPLEMENTED MACFlush(); // The buffer was reserved with AutoFree, so we can immediately // discard it. The MAC layer will free it after transmission. p->TxBuffer = INVALID_BUFFER; p->TxCount = 0; }
/** * This function transmit all data from the active UDP socket. * * @preCondition UDPPut() is already called and desired UDP socket * is set as an active socket by calling * UDPIsPutReady(). * * @return All and any data associated with active UDP socket * buffer is marked as ready for transmission. * */ void UDPFlush(void) { UDP_HEADER h; UDP_SOCKET_INFO *p; WORD csLength; DWORD_VAL csChecksum; // Wait for TX hardware to become available (finish transmitting // any previous packet) while( !IPIsTxReady(TRUE) ) FAST_USER_PROCESS(); p = &UDPSocketInfo[activeUDPSocket]; h.SourcePort.Val = swaps(p->localPort); h.DestinationPort.Val = swaps(p->remotePort); h.Length.Val = (WORD)((WORD)p->TxCount + (WORD)sizeof(UDP_HEADER)); // Do not swap h.Length yet. It is needed in IPPutHeader. h.Checksum.Val = 0x00; //Makes the given TX Buffer active, and set's the pointer to the first byte after the IP //header. This is the first byte of the UDP header. The UDP header follows the IP header. IPSetTxBuffer(p->TxBuffer, 0); //Load IP header. IPPutHeader( &p->remoteNode, IP_PROT_UDP, h.Length.Val ); // save length before swap for checksum calculation csLength = p->TxCount; //Now swap h.Length.Val h.Length.Val = swaps(h.Length.Val); //Now load UDP header. IPPutArray((BYTE*)&h, sizeof(h)); //Update checksum. !!!!!!!!!!!!!!! TO BE IMPLEMENTED !!!!!!!!!!!!!!!!!!! // Update checksum. // start the checksum with value for UDP protocol & length from pseudo header (and in the actual packet) csChecksum.Val = (WORD)IP_PROT_UDP + (WORD)csLength + sizeof(UDP_HEADER); // add in my address and the remoteNode address csChecksum.Val += ((WORD)MY_IP_BYTE1 << 8) + MY_IP_BYTE2; csChecksum.Val += ((WORD)MY_IP_BYTE3 << 8) + MY_IP_BYTE4; csChecksum.Val += ((WORD)p->remoteNode.IPAddr.v[0] << 8) + ((WORD)p->remoteNode.IPAddr.v[1] ) + ((WORD)p->remoteNode.IPAddr.v[2] << 8) + ((WORD)p->remoteNode.IPAddr.v[3] ); // set mac pointer to the ip_addr of the source, so all of pseudo header but length is included. // length of pseudo header is already included in previous instruction. //MACSetRxBuffer( sizeof(IP_HEADER)+sizeof(UDP_HEADER) ); csChecksum.Val += (WORD)p->localPort; csChecksum.Val += (WORD)p->remotePort; csChecksum.Val += (WORD)csLength + sizeof(UDP_HEADER); //IPSetRxBuffer(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER) - ( sizeof(IP_ADDR) * 2 ) ); // handled in UdpPut routines csChecksum.Val += udpChecksum; // add any carry over to the last word while((DWORD)csChecksum.word.MSW) { csChecksum.Val = (DWORD)csChecksum.word.LSW + (DWORD)csChecksum.word.MSW; } // add any carry over from adding the carry over //csChecksum.Val = (DWORD)csChecksum.word.LSW + (DWORD)csChecksum.word.MSW; // invert csChecksum.Val = ~csChecksum.Val; // set write pointer to location of checksum in packet //MACSetWritePtr( sizeof(ETHER_HEADER) + sizeof(IP_HEADER) + sizeof(UDP_HEADER) - 2 ); IPSetTxBuffer(p->TxBuffer, sizeof(UDP_HEADER) - 2); // write the swapped checksum to the packet //MACPut( csChecksum.v[1] ); //MACPut( csChecksum.v[0] ); MACPut(0); MACPut(0); //Send data contained in TX Buffer via MAC MACFlush(); // The buffer was reserved with AutoFree, so we can immediately // discard it. The MAC layer will free it after transmission. p->TxBuffer = INVALID_BUFFER; p->TxCount = 0; }