/***************************************************************************** Function: static bool ARPPut(ARP_PACKET* packet) Description: Writes an ARP packet to the MAC. Precondition: None Parameters: packet - A pointer to an ARP_PACKET structure with correct operation and target preconfigured. Return Values: true - The ARP packet was generated properly false - Not a possible return value ***************************************************************************/ static bool ARPPut(ARP_PACKET* packet) { while(!MACIsTxReady()); MACSetWritePtr(BASE_TX_ADDR); packet->HardwareType = HW_ETHERNET; packet->Protocol = ARP_IP; packet->MACAddrLen = sizeof(MAC_ADDR); packet->ProtocolLen = sizeof(IP_ADDR); // packet->SenderMACAddr = AppConfig.MyMACAddr; // HI-TECH PICC-18 compiler can't handle this statement, use memcpy() as a workaround memcpy(&packet->SenderMACAddr, (void*)&AppConfig.MyMACAddr, sizeof(packet->SenderMACAddr)); #ifdef STACK_USE_ZEROCONF_LINK_LOCAL //packet->SenderIPAddr = AppConfig.MyIPAddr; /* Removed for ZCLL, SenderIPAddr should be filled in */ #else packet->SenderIPAddr = AppConfig.MyIPAddr; #endif SwapARPPacket(packet); MACPutHeader(&packet->TargetMACAddr, MAC_ARP, sizeof(*packet)); MACPutArray((uint8_t*)packet, sizeof(*packet)); MACFlush(); return true; }
/***************************************************************************** Function: static bool ARP_SendIfPkt(NET_CONFIG* pIf, uint16_t oper, uint32_t srcIP, uint32_t dstIP, MAC_ADDR* dstMAC) Description: Writes an ARP packet to the MAC using the interface pointer for src IP and MAC address. Precondition: None Parameters: Return Values: true - The ARP packet was generated properly false - otherwise ***************************************************************************/ static bool ARP_SendIfPkt(NET_CONFIG* pIf, uint16_t oper, uint32_t srcIP, uint32_t dstIP, MAC_ADDR* dstMAC) { ARP_PACKET packet; TCPIP_MAC_HANDLE hMac; packet.HardwareType = HW_ETHERNET; packet.Protocol = ARP_IP; packet.MACAddrLen = sizeof(MAC_ADDR); packet.ProtocolLen = sizeof(IP_ADDR); packet.Operation = oper; packet.SenderMACAddr = pIf->MyMACAddr; packet.SenderIPAddr.Val = srcIP; packet.TargetMACAddr = *dstMAC; packet.TargetIPAddr.Val = dstIP; SwapARPPacket(&packet); hMac = _TCPIPStackNetToMac(pIf); if(!MACIsTxReady(hMac)) { return false; } MACSetWritePtr(hMac, MACGetTxBaseAddr(hMac)); MACPutHeader(hMac, &packet.TargetMACAddr, ETHERTYPE_ARP, sizeof(packet)); MACPutArray(hMac, (uint8_t*)&packet, sizeof(packet)); MACFlush(hMac); return true; }
/********************************************************************* * 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; }
/********************************************************************* * 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: void ARPPut(NODE_INFO* more, BYTE opCode) * * PreCondition: None * * Input: remote - Remote node info * opCode - ARP op code to send * * Output: TRUE - The ARP packet was generated properly * FALSE - Unable to allocate a TX buffer * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ BOOL ARPPut(NODE_INFO *remote, BYTE opCode) { ARP_PACKET packet; BUFFER MyTxBuffer; MyTxBuffer = MACGetTxBuffer(TRUE); // Do not respond if there is no room to generate the ARP reply if(MyTxBuffer == INVALID_BUFFER) return FALSE; MACSetTxBuffer(MyTxBuffer, 0); packet.HardwareType = HW_ETHERNET; packet.Protocol = ARP_IP; packet.MACAddrLen = sizeof(MAC_ADDR); packet.ProtocolLen = sizeof(IP_ADDR); if ( opCode == ARP_REQUEST ) { packet.Operation = ARP_OPERATION_REQ; 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 { packet.Operation = ARP_OPERATION_RESP; packet.TargetMACAddr = remote->MACAddr; } packet.SenderMACAddr = AppConfig.MyMACAddr; packet.SenderIPAddr = AppConfig.MyIPAddr; // Check to see if target is on same subnet, if not, find Gateway MAC. // Once we get Gateway MAC, all access to remote host will go through Gateway. if((packet.SenderIPAddr.Val ^ remote->IPAddr.Val) & AppConfig.MyMask.Val) { packet.TargetIPAddr = AppConfig.MyGateway; } else packet.TargetIPAddr = remote->IPAddr; SwapARPPacket(&packet); MACPutHeader(&packet.TargetMACAddr, MAC_ARP, sizeof(packet)); //MACPutArray((int8*)&packet, sizeof(packet)); MACPutArray(&packet, sizeof(ARP_PACKET)); MACFlush(); return TRUE; }
/** * Given number of data bytes from the given array are put into the UDP transmit buffer * and active UDP socket buffer length is incremented by number of bytes. The data is * NOT sent yet, and the UDPFlush() function must be called to send all data contained * in the transmit buffer. * * If there is not enough space in the transmit buffer for all the data, the contents of * the transmit buffer will be sent, and this function will return the actual amount of * bytes that were sent. In this case, it is VERY IMPORTANT to call the UDPIsPutReady() * function again before calling the UDPPut() or UDPPutArray() functions! This will however * only happen if the transmit buffer fills up. The transmit buffer for UDP data is * = (MAC_TX_BUFFER_SIZE - 42), which is usually 982 bytes. If writing less then this to * the transmit buffer before calling UDPFlush(), then this function will always return the * requested number of bytes! * * Note: This function loads data into an active UDP socket as determined by previous * call to UDPIsPutReady(). * * @preCondition UDPIsPutReady() == TRUE with desired UDP socket * that is to be loaded. * * @param[in] buffer Buffer containing data that has to be sent. * @param count Number of bytes to send * * @return Number of bytes added to the transmit buffer.<br> * !!!!! IMPORTANT !!!!!<br> * If this value is less then the number of bytes we requested to send, then * UDPIsPutReady() must be called again before calling the UDPPut() or * UDPPutArray() functions! */ WORD UDPPutArray(BYTE *buffer, WORD count) { UDP_SOCKET_INFO *p; WORD temp; WORD ckCount = 0; p = &UDPSocketInfo[activeUDPSocket]; //This UDP Socket does not contain any unsent data, and currently does not own a TX Buffer! //Assign it the next available TX Buffer if ( p->TxCount == 0 ) { //Get handle to next available TX Buffer. The UDPIsPutReady() function that has to be called //prior to this function will determine if there is an available TX Buffer. p->TxBuffer = MACGetTxBuffer(TRUE); // Make sure that we received a TX buffer if(p->TxBuffer == INVALID_BUFFER) return FALSE; //This sets the current TX Buffer pointer to the given offset after the IP header. //We give the size of the UDP header here as a parameter. This causes the current //write pointer to be set to firt byte after the UDP header, which is the UDP data //area. IPSetTxBuffer(p->TxBuffer, sizeof(UDP_HEADER)); } //This function request more bytes to be written to the TX Buffer then there is space if ((p->TxCount + count) > UDPGetMaxDataLength()) { //Update count with maximum number of bytes that there is place for in the TX Buffer count = UDPGetMaxDataLength() - p->TxCount; } //Write buffer MACPutArray(buffer, count); while (ckCount <= count) { if (p->TxCount+ckCount & 1) { udpChecksum += *(buffer+ckCount); } else { udpChecksum += ((WORD)*(buffer+ckCount) << 8); } ckCount++; } //Keep track of number of bytes loaded. //If total bytes fill up buffer, transmit it. p->TxCount += count; if ( p->TxCount >= UDPGetMaxDataLength() ) { UDPFlush(); } return count; //Return actual number of bytes sent }
/********************************************************************* * 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; } }
/** * A ICMP packet is created and put on MAC. * * @preCondition ICMPIsTxReady() == TRUE * * @param remote Remote node info * @param code ICMP_ECHO_REPLY or ICMP_ECHO_REQUEST * @param data Data bytes * @param len Number of bytes to send * @param id ICMP identifier * @param seq ICMP sequence number */ void ICMPPut(NODE_INFO *remote, ICMP_CODE code, BYTE *data, BYTE len, WORD id, WORD seq) { ICMP_PACKET packet; WORD ICMPLen; BUFFER MyTxBuffer; MyTxBuffer = MACGetTxBuffer(TRUE); // Abort if there is no where in the Ethernet controller to // store this packet. if(MyTxBuffer == INVALID_BUFFER) return; IPSetTxBuffer(MyTxBuffer, 0); ICMPLen = ICMP_HEADER_SIZE + (WORD)len; packet.Code = 0; packet.Type = code; packet.Checksum = 0; packet.Identifier = id; packet.SequenceNumber = seq; memcpy((void*)packet.Data, (void*)data, len); SwapICMPPacket(&packet); #if defined(NON_MCHP_MAC) //This is NOT a Microchip MAC packet.Checksum = CalcIPChecksum((BYTE*)&packet, ICMPLen); #endif IPPutHeader(remote, IP_PROT_ICMP, (WORD)(ICMP_HEADER_SIZE + len)); IPPutArray((BYTE*)&packet, ICMPLen); #if !defined(NON_MCHP_MAC) //This is a Microchip MAC // Calculate and write the ICMP checksum using the Microchip MAC's DMA packet.Checksum = MACCalcTxChecksum(sizeof(IP_HEADER), ICMPLen); IPSetTxBuffer(MyTxBuffer, 2); MACPutArray((BYTE*)&packet.Checksum, 2); #endif MACFlush(); }
/****************************************************************************** * Function: void MACPutHeader(MAC_ADDR *remote, BYTE type, WORD dataLen) * * PreCondition: MACIsTxReady() must return TRUE. * * Input: *remote: Pointer to memory which contains the destination * MAC address (6 bytes) * type: The constant ETHER_ARP or ETHER_IP, defining which * value to write into the Ethernet header's type field. * dataLen: Length of the Ethernet data payload * * Output: None * * Side Effects: None * * Overview: None * * Note: Because of the dataLen parameter, it is probably * advantagous to call this function immediately before * transmitting a packet rather than initially when the * packet is first created. The order in which the packet * is constructed (header first or data first) is not * important. *****************************************************************************/ void MACPutHeader(MAC_ADDR *remote, BYTE type, WORD dataLen) { // Set the write pointer to the beginning of the transmit buffer EWRPT = TXSTART + 1; // Calculate where to put the TXND pointer dataLen += (WORD)sizeof (ETHER_HEADER) + TXSTART; // Write the TXND pointer into the registers, given the dataLen given ETXND = dataLen; // Set the per-packet control byte and write the Ethernet destination // address MACPutArray((BYTE*) remote, sizeof (*remote)); // Write our MAC address in the Ethernet source field MACPutArray((BYTE*) & AppConfig.MyMACAddr, sizeof (AppConfig.MyMACAddr)); // Write the appropriate Ethernet Type WORD for the protocol being used MACPut(0x08); MACPut((type == MAC_IP) ? ETHER_IP : ETHER_ARP); }
/********************************************************************* * 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; }
/** * This function writes the MAC header (Ethernet header) part of a packet that * has to be transmitted to the current TX buffer (page in NIC RAM). * After this function, the data must still be written to the TX buffer. * After both header and data has been written, bits are set to instruct * NIC to transmit transmit buffer. This function does 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 to the current TX Buffer </li> * <li> Set the NIC Remote DMA byte count to the given len. This configures the * Remote DMA to receive the given number of bytes. </li></ul> * * @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 type Type of header. Can be ETHER_IP, ETHER_ARP or MAC_UNKNOWN * @param dataLen Size of the Data of this Ethernet packet. A Ethernet packet consists of: <br> * - 6 Bytes = Desitination MAC address <br> * - 6 Bytes = Source MAC address <br> * - 2 Bytes = Type field, currently only IP or ARP <br> * - n Bytes = Data. Minimum length of 46 bytes <br><br> * The data will be written to the TX buffer following this command. * * @return True if header was read, False if not */ void MACPutHeader(MAC_ADDR *remote, BYTE type, WORD dataLen) { WORD_VAL mytemp; BYTE etherType; NICPut(ISR, 0x0a); //Set the address of the current Remote DMA. This is the address that all future MACPut() //functions will write data to in the current TX Buffer. This address is set to the start //address of the current MAC TX Buffer. The current TX Buffer will thus point to the first //byte in the packet that will be transmitted = first byte of Ethernet header mytemp.v[1] = TxBuffers[MACCurrTxbuf].Index; mytemp.v[0] = 0; NICSetAddr(mytemp.Val); ///////////////////////////////////////////////// //Write Ethernet header part (MAC header) = Dest MAC Adrr, Source MAC Adr, Type MACPutArray((BYTE*)remote, sizeof(*remote)); MACPut(MY_MAC_BYTE1); MACPut(MY_MAC_BYTE2); MACPut(MY_MAC_BYTE3); MACPut(MY_MAC_BYTE4); MACPut(MY_MAC_BYTE5); MACPut(MY_MAC_BYTE6); if ( type == MAC_IP ) etherType = ETHER_IP; else etherType = ETHER_ARP; MACPut(0x08); MACPut(etherType); dataLen += (WORD)sizeof(ETHER_HEADER); //If datalength smaller than minimum Ethernet packet (not including CRC), pad till minimum size if ( dataLen < MINFRAME ) dataLen = MINFRAME; mytemp.Val = dataLen; NICPut(TBCR0, mytemp.v[0]); NICPut(TBCR1, mytemp.v[1]); }
/***************************************************************************** Function: WORD UDPPutArray(BYTE *cData, WORD wDataLen) Summary: Writes an array of bytes to the currently active socket. Description: This function writes an array of bytes to the currently active UDP socket, while incrementing the buffer length. UDPIsPutReady should be used before calling this function to specify the currently active socket. Precondition: UDPIsPutReady() was previously called to specify the current socket. Parameters: cData - The array to write to the socket. wDateLen - Number of bytes from cData to be written. Returns: The number of bytes successfully placed in the UDP transmit buffer. If this value is less than wDataLen, then the buffer became full and the input was truncated. ***************************************************************************/ WORD UDPPutArray(BYTE *cData, WORD wDataLen) { WORD wTemp; wTemp = (MAC_TX_BUFFER_SIZE - sizeof(IP_HEADER) - sizeof(UDP_HEADER)) - wPutOffset; if(wTemp < wDataLen) wDataLen = wTemp; wPutOffset += wDataLen; if(wPutOffset > UDPTxCount) UDPTxCount = wPutOffset; // Load application data bytes MACPutArray(cData, wDataLen); return wDataLen; }
void MACPutHeader(MAC_ADDR *remote, int8 type, int16 dataLen) { WORD_VAL mytemp; int8 etherType; NICPut(ISR, 0x0a); mytemp.v[1] = TxBuffers[NICCurrentTxBuffer].Index; mytemp.v[0] = 0; NICSetAddr(mytemp.Val); // MACPutArray((int8*)remote, sizeof(*remote)); MACPutArray(remote, sizeof(MAC_ADDR)); debug(debug_putc,"\r\n\r\nMACPUTHEADER: DA:%X.%X.%X.%X.%X.%X T=%X L=%LX", remote->v[0],remote->v[1],remote->v[2],remote->v[3],remote->v[4],remote->v[5],type,datalen); MACPut(MY_MAC_BYTE1); MACPut(MY_MAC_BYTE2); MACPut(MY_MAC_BYTE3); MACPut(MY_MAC_BYTE4); MACPut(MY_MAC_BYTE5); MACPut(MY_MAC_BYTE6); if ( type == MAC_IP ) etherType = ETHER_IP; else etherType = ETHER_ARP; MACPut(0x08); MACPut(etherType); dataLen += (int16)sizeof(ETHER_HEADER); if ( dataLen < MINFRAME ) // 64 ) // NKR 4/23/02 dataLen = 64; // MINFRAME; mytemp.Val = dataLen; NICPut(TBCR0, mytemp.v[0]); NICPut(TBCR1, mytemp.v[1]); }
/********************************************************************* * Function: void HTTPInit(void) * * PreCondition: TCP must already be initialized. * * Input: None * * Output: None * * Side Effects: None * * Overview: Sets all HTTP sockets to listening state. * Initialize state machine for each connection. * * Note: This function is called only one during lifetime * of the application. ********************************************************************/ void HTTPInit(void) { WORD oldPtr; // Make sure the file handles are invalidated curHTTP.file = MPFS_INVALID_HANDLE; curHTTP.offsets = MPFS_INVALID_HANDLE; for(curHTTPID = 0; curHTTPID < MAX_HTTP_CONNECTIONS; curHTTPID++) { smHTTP = SM_HTTP_IDLE; sktHTTP = TCPListen(HTTP_PORT); // Save the default record (just invalid file handles) oldPtr = MACSetWritePtr(BASE_HTTPB_ADDR + curHTTPID*sizeof(HTTP_CONN)); MACPutArray((BYTE*)&curHTTP, sizeof(HTTP_CONN)); MACSetWritePtr(oldPtr); } }
/** * 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: static void HTTPLoadConn(BYTE connID) * * PreCondition: None * * Input: connID the connection ID to load * * Output: curHTTP has a new connection loaded * * Side Effects: None * * Overview: Loads the current HTTP connection out of Ethernet * buffer RAM and into local RAM for processing. * * Note: None ********************************************************************/ static void HTTPLoadConn(BYTE connID) { WORD oldPtr; // Return if already loaded if(connID == curHTTPID) return; // Save the old one oldPtr = MACSetWritePtr(BASE_HTTPB_ADDR + curHTTPID*sizeof(HTTP_CONN)); MACPutArray((BYTE*)&curHTTP, sizeof(HTTP_CONN)); MACSetWritePtr(oldPtr); // Load the new one oldPtr = MACSetReadPtr(BASE_HTTPB_ADDR + connID*sizeof(HTTP_CONN)); MACGetArray((BYTE*)&curHTTP, sizeof(HTTP_CONN)); MACSetReadPtr(oldPtr); // Remember which one is loaded curHTTPID = connID; }
/********************************************************************* * 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: 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; }
void AutoIPTasks(void) { BYTE i; for (i = 0; i < NETWORK_INTERFACES; i++) { LoadState (i); AutoIPClient.flags.bits.bCurrentLinkState = MACIsLinked(); if(AutoIPClient.flags.bits.bCurrentLinkState != AutoIPClient.flags.bits.bLastLinkState) { AutoIPClient.flags.bits.bLastLinkState = AutoIPClient.flags.bits.bCurrentLinkState; if(!AutoIPClient.flags.bits.bCurrentLinkState) { AutoIPClient.flags.bits.bConfigureAutoIP = FALSE; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; AppConfig.MyIPAddr.Val = AppConfig.DefaultIPAddr.Val; AppConfig.MyMask.Val = AppConfig.DefaultMask.Val; } else { AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG; } } #if defined (STACK_USE_DHCP_CLIENT) if (DHCPIsBound(i)) { AutoIPClient.flags.bits.bConfigureAutoIP = FALSE; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; AutoIPClient.flags.bits.bLastDHCPState = TRUE; } else { if (AutoIPClient.flags.bits.bLastDHCPState == TRUE) { if (AutoIPClient.flags.bits.bCurrentLinkState) AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG; } AutoIPClient.flags.bits.bLastDHCPState = FALSE; } #endif if (AutoIPClient.flags.bits.gDisableAutoIP == TRUE) { AutoIPClient.flags.bits.bConfigureAutoIP = FALSE; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; } switch (AutoIPClient.smAUTOIPState) { // Default no-AutoIP case case SM_AUTOIP_DISABLED: break; // Initializes the random number generator with a seed based on the MAC address case SM_AUTOIP_INIT_RNG: AutoIPRandSeed (((DWORD)AppConfig.MyMACAddr.v[0] + ((DWORD)AppConfig.MyMACAddr.v[1] << 8) + \ ((DWORD)AppConfig.MyMACAddr.v[2] << 16) + ((DWORD)AppConfig.MyMACAddr.v[3] << 24) + \ ((DWORD)AppConfig.MyMACAddr.v[4]) + ((DWORD)AppConfig.MyMACAddr.v[5] << 8)), i); AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS; // Check the address to see if it's in use before we write it into AppConfig case SM_AUTOIP_CHECK_ADDRESS: if (AutoIPClient.flags.bits.checkAddress == FALSE) { AutoIPClient.flags.bits.checkAddress = TRUE; AppConfig.MyMask.Val = 0x00000000; // Generate a random IP address (based on the MAC address) to try and claim. // Dynamic link-local addresses can fall within the range: // 169.254.1.0 - 169.254.254.255 AutoIPClient.packet.TargetIPAddr.byte.MB = AutoIPRand(i) % 256; AutoIPClient.packet.TargetIPAddr.byte.UB = (AutoIPRand(i) % 254) + 1; AutoIPClient.packet.TargetIPAddr.word.LW = 0xFEA9; ARPResolve (&AutoIPClient.packet.TargetIPAddr); AutoIPClient.eventTime = TickGet(); } if (!ARPIsResolved (&AutoIPClient.packet.TargetIPAddr, &AutoIPClient.packet.TargetMACAddr)) { if (TickGet() - AutoIPClient.eventTime > TICK_SECOND) { AutoIPClient.smAUTOIPState = SM_AUTOIP_SETUP_MESSAGE; } } else { AutoIPClient.flags.bits.checkAddress = FALSE; } break; // Set up an ARP packet case SM_AUTOIP_SETUP_MESSAGE: AutoIPClient.flags.bits.checkAddress = FALSE; // Set the bConfigureAutoIP flag- This flag will cause an AutoIP conflict // if a response packet is received from the address we're trying to claim. AutoIPClient.flags.bits.bConfigureAutoIP = TRUE; // Configure the fields for a gratuitous ARP packet AutoIPClient.packet.Operation = ARP_OPERATION_REQ; AutoIPClient.packet.TargetMACAddr.v[0] = 0xff; AutoIPClient.packet.TargetMACAddr.v[1] = 0xff; AutoIPClient.packet.TargetMACAddr.v[2] = 0xff; AutoIPClient.packet.TargetMACAddr.v[3] = 0xff; AutoIPClient.packet.TargetMACAddr.v[4] = 0xff; AutoIPClient.packet.TargetMACAddr.v[5] = 0xff; AppConfig.MyIPAddr = AutoIPClient.packet.TargetIPAddr; AppConfig.MyMask.Val = 0x0000FFFF; memcpy(&AutoIPClient.packet.SenderMACAddr, (void*)&AppConfig.MyMACAddr, sizeof(AutoIPClient.packet.SenderMACAddr)); AutoIPClient.packet.HardwareType = HW_ETHERNET; AutoIPClient.packet.Protocol = ARP_IP; AutoIPClient.packet.MACAddrLen = sizeof(MAC_ADDR); AutoIPClient.packet.ProtocolLen = sizeof(IP_ADDR); AutoIPClient.packet.SenderIPAddr.Val = AutoIPClient.packet.TargetIPAddr.Val; SwapARPPacket(&AutoIPClient.packet); // Generate a random delay between 0 and 1 second AutoIPClient.randomDelay = ((rand() % 20) * TICK_SECOND) / 20; // Store the current time AutoIPClient.eventTime = TickGet(); // Set the state to send the ARP packet AutoIPClient.smAUTOIPState = SM_AUTOIP_GRATUITOUS_ARP1; break; // Send a gratuitous ARP packet to try and claim our address case SM_AUTOIP_GRATUITOUS_ARP1: case SM_AUTOIP_GRATUITOUS_ARP2: case SM_AUTOIP_GRATUITOUS_ARP3: // Check to ensure we've passed the delay time if (TickGet() - AutoIPClient.eventTime > AutoIPClient.randomDelay) { // Store the new event time AutoIPClient.eventTime = TickGet(); // Generate a new random delay between 1 and 2 seconds AutoIPClient.randomDelay = TICK_SECOND + (((rand() % 20) * TICK_SECOND) / 20); // Transmit the packet while(!MACIsTxReady()); MACSetWritePtr(BASE_TX_ADDR); MACPutHeader(&AutoIPClient.packet.TargetMACAddr, MAC_ARP, sizeof(AutoIPClient.packet)); MACPutArray((BYTE*)&AutoIPClient.packet, sizeof(AutoIPClient.packet)); MACFlush(); // Increment the probe iteration or increment to the delay state AutoIPClient.smAUTOIPState++; } break; // Delay for 1-2 seconds after sending the third ARP request before // entering the configured state case SM_AUTOIP_DELAY: if (TickGet() - AutoIPClient.eventTime > AutoIPClient.randomDelay) AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED; break; // Configure the module to limit the rate at which packets are sent case SM_AUTOIP_RATE_LIMIT_SET: AutoIPClient.eventTime = TickGet(); 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; AutoIPClient.smAUTOIPState = SM_AUTOIP_RATE_LIMIT_WAIT; break; // Ensure that we don't try more than one address every 60 seconds case SM_AUTOIP_RATE_LIMIT_WAIT: if (TickGet() - AutoIPClient.eventTime > TICK_SECOND * 60) AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS; break; // Configured state case SM_AUTOIP_CONFIGURED: AutoIPClient.flags.bits.bConfigureAutoIP = FALSE; break; // Address defense state case SM_AUTOIP_DEFEND: // Prepare and send an ARP response AutoIPClient.packet.Operation = ARP_OPERATION_RESP; AutoIPClient.packet.HardwareType = HW_ETHERNET; AutoIPClient.packet.Protocol = ARP_IP; SwapARPPacket(&AutoIPClient.packet); while(!MACIsTxReady()); MACSetWritePtr(BASE_TX_ADDR); MACPutHeader(&AutoIPClient.packet.TargetMACAddr, MAC_ARP, sizeof(AutoIPClient.packet)); MACPutArray((BYTE*)&AutoIPClient.packet, sizeof(AutoIPClient.packet)); MACFlush(); AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED; break; } } }
void AutoIPTasks(NET_CONFIG* pConfig) { // uint8_t i; TCPIP_MAC_HANDLE hMac; // for (i = 0; i < NETWORK_INTERFACES; i++) { LoadState(_TCPIPStackNetIx(pConfig)); hMac = _TCPIPStackNetToMac(pConfig); AutoIPClient.flags.bits.bCurrentLinkState = MACIsLinked(hMac); if(AutoIPClient.flags.bits.bCurrentLinkState != AutoIPClient.flags.bits.bLastLinkState) { AutoIPClient.flags.bits.bLastLinkState = AutoIPClient.flags.bits.bCurrentLinkState; if(!AutoIPClient.flags.bits.bCurrentLinkState) { AutoIPClient.flags.bits.bConfigureAutoIP = false; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; pConfig->MyIPAddr.Val = pConfig->DefaultIPAddr.Val; pConfig->MyMask.Val = pConfig->DefaultMask.Val; } else { AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG; } } #if defined (TCPIP_STACK_USE_DHCP_CLIENT) if (DHCPIsBound(pConfig)) { AutoIPClient.flags.bits.bConfigureAutoIP = false; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; AutoIPClient.flags.bits.bLastDHCPState = true; } else { if (AutoIPClient.flags.bits.bLastDHCPState == true) { if (AutoIPClient.flags.bits.bCurrentLinkState) AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG; } AutoIPClient.flags.bits.bLastDHCPState = false; } #endif if (AutoIPClient.flags.bits.gDisableAutoIP == true) { AutoIPClient.flags.bits.bConfigureAutoIP = false; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; } switch (AutoIPClient.smAUTOIPState) { // Default no-AutoIP case case SM_AUTOIP_DISABLED: break; // Initializes the random number generator with a seed based on the MAC address case SM_AUTOIP_INIT_RNG: AutoIPRandSeed (((uint32_t)pConfig->MyMACAddr.v[0] + ((uint32_t)pConfig->MyMACAddr.v[1] << 8) + \ ((uint32_t)pConfig->MyMACAddr.v[2] << 16) + ((uint32_t)pConfig->MyMACAddr.v[3] << 24) + \ ((uint32_t)pConfig->MyMACAddr.v[4]) + ((uint32_t)pConfig->MyMACAddr.v[5] << 8)), pConfig); AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS; // Check the address to see if it's in use before we write it into NetConfig case SM_AUTOIP_CHECK_ADDRESS: if (AutoIPClient.flags.bits.checkAddress == false) { AutoIPClient.flags.bits.checkAddress = true; pConfig->MyMask.Val = 0x00000000; // Generate a random IP address (based on the MAC address) to try and claim. // Dynamic link-local addresses can fall within the range: // 169.254.1.0 - 169.254.254.255 AutoIPClient.packet.TargetIPAddr.byte.MB = AutoIPRand(pConfig) % 256; AutoIPClient.packet.TargetIPAddr.byte.UB = (AutoIPRand(pConfig) % 254) + 1; AutoIPClient.packet.TargetIPAddr.word.LW = 0xFEA9; ARPResolve (pConfig, &AutoIPClient.packet.TargetIPAddr); AutoIPClient.eventTime = SYS_TICK_Get(); } if (!ARPIsResolved (pConfig, &AutoIPClient.packet.TargetIPAddr, &AutoIPClient.packet.TargetMACAddr)) { if (SYS_TICK_Get() - AutoIPClient.eventTime > SYS_TICK_TicksPerSecondGet()) { AutoIPClient.smAUTOIPState = SM_AUTOIP_SETUP_MESSAGE; } } else { AutoIPClient.flags.bits.checkAddress = false; } break; // Set up an ARP packet case SM_AUTOIP_SETUP_MESSAGE: AutoIPClient.flags.bits.checkAddress = false; // Set the bConfigureAutoIP flag- This flag will cause an AutoIP conflict // if a response packet is received from the address we're trying to claim. AutoIPClient.flags.bits.bConfigureAutoIP = true; // Configure the fields for a gratuitous ARP packet AutoIPClient.packet.Operation = ARP_OPERATION_REQ; AutoIPClient.packet.TargetMACAddr.v[0] = 0xff; AutoIPClient.packet.TargetMACAddr.v[1] = 0xff; AutoIPClient.packet.TargetMACAddr.v[2] = 0xff; AutoIPClient.packet.TargetMACAddr.v[3] = 0xff; AutoIPClient.packet.TargetMACAddr.v[4] = 0xff; AutoIPClient.packet.TargetMACAddr.v[5] = 0xff; pConfig->MyIPAddr = AutoIPClient.packet.TargetIPAddr; pConfig->MyMask.Val = 0x0000FFFF; memcpy(&AutoIPClient.packet.SenderMACAddr, (void*)&pConfig->MyMACAddr, sizeof(AutoIPClient.packet.SenderMACAddr)); AutoIPClient.packet.HardwareType = HW_ETHERNET; AutoIPClient.packet.Protocol = ARP_IP; AutoIPClient.packet.MACAddrLen = sizeof(MAC_ADDR); AutoIPClient.packet.ProtocolLen = sizeof(IP_ADDR); AutoIPClient.packet.SenderIPAddr.Val = AutoIPClient.packet.TargetIPAddr.Val; SwapARPPacket(&AutoIPClient.packet); // Generate a random delay between 0 and 1 second AutoIPClient.randomDelay = ((LFSRRand() % 20) * SYS_TICK_TicksPerSecondGet()) / 20; // Store the current time AutoIPClient.eventTime = SYS_TICK_Get(); // Set the state to send the ARP packet AutoIPClient.smAUTOIPState = SM_AUTOIP_GRATUITOUS_ARP1; break; // Send a gratuitous ARP packet to try and claim our address case SM_AUTOIP_GRATUITOUS_ARP1: case SM_AUTOIP_GRATUITOUS_ARP2: case SM_AUTOIP_GRATUITOUS_ARP3: // Check to ensure we've passed the delay time if (SYS_TICK_Get() - AutoIPClient.eventTime > AutoIPClient.randomDelay) { if(!MACIsTxReady(hMac)) { break; } // Store the new event time AutoIPClient.eventTime = SYS_TICK_Get(); // Generate a new random delay between 1 and 2 seconds AutoIPClient.randomDelay = SYS_TICK_TicksPerSecondGet() + (((LFSRRand() % 20) * SYS_TICK_TicksPerSecondGet()) / 20); // Transmit the packet MACSetWritePtr(hMac, MACGetTxBaseAddr(hMac)); MACPutHeader(hMac, &AutoIPClient.packet.TargetMACAddr, ETHERTYPE_ARP, sizeof(AutoIPClient.packet)); MACPutArray(hMac, (uint8_t*)&AutoIPClient.packet, sizeof(AutoIPClient.packet)); MACFlush(hMac); // Increment the probe iteration or increment to the delay state AutoIPClient.smAUTOIPState++; } break; // Delay for 1-2 seconds after sending the third ARP request before // entering the configured state case SM_AUTOIP_DELAY: if (SYS_TICK_Get() - AutoIPClient.eventTime > AutoIPClient.randomDelay) AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED; break; // Configure the module to limit the rate at which packets are sent case SM_AUTOIP_RATE_LIMIT_SET: AutoIPClient.eventTime = SYS_TICK_Get(); pConfig->MyIPAddr.Val = pConfig->DefaultIPAddr.Val; AutoIPClient.smAUTOIPState = SM_AUTOIP_RATE_LIMIT_WAIT; break; // Ensure that we don't try more than one address every 60 seconds case SM_AUTOIP_RATE_LIMIT_WAIT: if (SYS_TICK_Get() - AutoIPClient.eventTime > SYS_TICK_TicksPerSecondGet() * 60) AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS; break; // Configured state case SM_AUTOIP_CONFIGURED: AutoIPClient.flags.bits.bConfigureAutoIP = false; break; // Address defense state case SM_AUTOIP_DEFEND: // Prepare and send an ARP response if(!MACIsTxReady(hMac)) { break; } AutoIPClient.packet.Operation = ARP_OPERATION_RESP; AutoIPClient.packet.HardwareType = HW_ETHERNET; AutoIPClient.packet.Protocol = ARP_IP; SwapARPPacket(&AutoIPClient.packet); MACSetWritePtr(hMac, MACGetTxBaseAddr(hMac)); MACPutHeader(hMac, &AutoIPClient.packet.TargetMACAddr, ETHERTYPE_ARP, sizeof(AutoIPClient.packet)); MACPutArray(hMac, (uint8_t*)&AutoIPClient.packet, sizeof(AutoIPClient.packet)); MACFlush(hMac); AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED; break; } } }
/********************************************************************* * Function: void ARPPut(NODE_INFO* more, BYTE opCode) * * PreCondition: MACIsTxReady() == TRUE * * Input: remote - Remote node info * opCode - ARP op code to send * * Output: None * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ void ARPPut(NODE_INFO *remote, BYTE opCode) { ARP_PACKET packet; packet.HardwareType = HW_ETHERNET; packet.Protocol = ARP_IP; packet.MACAddrLen = sizeof(MAC_ADDR); packet.ProtocolLen = sizeof(IP_ADDR); if ( opCode == ARP_REQUEST ) { packet.Operation = ARP_OPERATION_REQ; 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 { packet.Operation = ARP_OPERATION_RESP; packet.TargetMACAddr = remote->MACAddr; } packet.SenderMACAddr.v[0] = MY_MAC_BYTE1; packet.SenderMACAddr.v[1] = MY_MAC_BYTE2; packet.SenderMACAddr.v[2] = MY_MAC_BYTE3; packet.SenderMACAddr.v[3] = MY_MAC_BYTE4; packet.SenderMACAddr.v[4] = MY_MAC_BYTE5; packet.SenderMACAddr.v[5] = MY_MAC_BYTE6; packet.SenderIPAddr.v[0] = MY_IP_BYTE1; packet.SenderIPAddr.v[1] = MY_IP_BYTE2; packet.SenderIPAddr.v[2] = MY_IP_BYTE3; packet.SenderIPAddr.v[3] = MY_IP_BYTE4; /* * Check to see if target is on same subnet, if not, find * Gateway MAC. * Once we get Gateway MAC, all access to remote host will * go through Gateway. */ if (((packet.SenderIPAddr.v[0] ^ remote->IPAddr.v[0]) & MY_MASK_BYTE1) || ((packet.SenderIPAddr.v[1] ^ remote->IPAddr.v[1]) & MY_MASK_BYTE2) || ((packet.SenderIPAddr.v[2] ^ remote->IPAddr.v[2]) & MY_MASK_BYTE3) || ((packet.SenderIPAddr.v[3] ^ remote->IPAddr.v[3]) & MY_MASK_BYTE4) ) { packet.TargetIPAddr.v[0] = MY_GATE_BYTE1; packet.TargetIPAddr.v[1] = MY_GATE_BYTE2; packet.TargetIPAddr.v[2] = MY_GATE_BYTE3; packet.TargetIPAddr.v[3] = MY_GATE_BYTE4; } else packet.TargetIPAddr = remote->IPAddr; SwapARPPacket(&packet); MACPutHeader(&packet.TargetMACAddr, MAC_ARP, sizeof(packet)); MACPutArray((BYTE*)&packet, sizeof(packet)); MACFlush(); }