/** * 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: BOOL UDPPut(BYTE v) * * PreCondition: UDPIsPutReady() == TRUE with desired UDP socket * that is to be loaded. * * Input: v - Data byte to loaded into transmit buffer * * Output: TRUE if transmit buffer is still ready to accept * more data bytes * * FALSE if transmit buffer can no longer accept * any more data byte. * * Side Effects: None * * Overview: Given data byte is put into UDP transmit buffer * and active UDP socket buffer length is incremented * by one. * If buffer has become full, FALSE is returned. * Or else TRUE is returned. * * Note: This function loads data into an active UDP socket * as determined by previous call to UDPIsPutReady() ********************************************************************/ BOOL UDPPut(BYTE v) { UDP_SOCKET_INFO *p; WORD temp; p = &UDPSocketInfo[activeUDPSocket]; if ( p->TxCount == 0 ) { /* * This is the very first byte that is loaded in UDP buffer. * Remember what transmit buffer we are loading, and * start loading this and next bytes in data area of UDP * packet. */ p->TxBuffer = MACGetTxBuffer(); IPSetTxBuffer(p->TxBuffer, sizeof(UDP_HEADER)); p->TxOffset = 0; } /* * Load it. */ MACPut(v); if ( p->TxOffset++ >= p->TxCount ) p->TxCount++; #if 0 /* * Keep track of number of bytes loaded. * If total bytes fill up buffer, transmit it. */ p->TxCount++; #endif #define SIZEOF_MAC_HEADER (14) /* * Depending on what communication media is used, allowable UDP * data length will vary. */ #if !defined(STACK_USE_SLIP) #define MAX_UDP_DATA (MAC_TX_BUFFER_SIZE - SIZEOF_MAC_HEADER - sizeof(IP_HEADER) - sizeof(UDP_HEADER)) #else #define MAX_UDP_DATA (MAC_TX_BUFFER_SIZE - sizeof(IP_HEADER) - sizeof(UDP_HEADER) ) #endif temp = p->TxCount; if ( temp >= MAX_UDP_DATA ) { UDPFlush(); } #undef MAX_UDP_DATA 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: 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; /* * When using SLIP (USART), packet transmission takes some time * and hence before sending another packet, we must make sure * that, last packet is transmitted. * When using ethernet controller, transmission occurs very fast * and by the time next packet is transmitted, previous is * transmitted and we do not need to check for last packet. */ //while( !IPIsTxReady() ); p = &UDPSocketInfo[activeUDPSocket]; 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 = 0x00; 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(); p->TxBuffer = INVALID_BUFFER; p->TxCount = 0; }
/** * Given data byte is put into the UDP transmit buffer and active UDP socket buffer * length is incremented. The data is NOT sent yet, and the UDPFlush() function must * be called to send all data contained in the transmit buffer. * * If the transmit buffer filled up, the contents of the transmit buffer will be sent, * and this function will return FALSE. In this case, it is VERY IMPORTANT to call the * UDPIsPutReady() function again before calling the UDPPut() or UDPPutArray() functions! * * 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 v - Data byte to loaded into transmit buffer * * @return TRUE if transmit buffer is still ready to accept more data bytes <br> * FALSE if transmit buffer can no longer accept any more data byte.<br> * If FALSE is returned, then UDPIsPutReady() has to be called again before * calling the UDPPut() or UDPPutArray() functions! */ BOOL UDPPut(BYTE v) { UDP_SOCKET_INFO *p; 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 ) { // This is the very first byte that is loaded in UDP buffer. // Remember what transmit buffer we are loading, and // start loading this and next bytes in data area of UDP packet. 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)); udpChecksum = 0; //p->TxOffset = 0; /* TxOffset is not required! */ } //Load it. MACPut(v); if (p->TxCount & 1) { udpChecksum += v; } else { udpChecksum += ((WORD)v << 8); } //Keep track of number of bytes loaded. //If total bytes fill up buffer, transmit it. p->TxCount++; if ( p->TxCount >= UDPGetMaxDataLength() ) { UDPFlush(); udpChecksum = 0; } return TRUE; }
/** * 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: 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; }
/********************************************************************* * Function: BOOL UDPPut(BYTE v) * * PreCondition: UDPIsPutReady() == TRUE with desired UDP socket * that is to be loaded. * * Input: v - Data byte to loaded into transmit buffer * * Output: TRUE if transmit buffer is still ready to accept * more data bytes * * FALSE if transmit buffer can no longer accept * any more data byte. * * Side Effects: None * * Overview: Given data byte is put into UDP transmit buffer * and active UDP socket buffer length is incremented * by one. * If buffer has become full, FALSE is returned. * Or else TRUE is returned. * * Note: This function loads data into an active UDP socket * as determined by previous call to UDPIsPutReady() ********************************************************************/ BOOL UDPPut(BYTE v) { UDP_SOCKET_INFO *p; WORD temp; WORD tempOffset; WORD tempCount; p = &UDPSocketInfo[activeUDPSocket]; tempCount=p->TxCount; if ( tempCount == 0 ) { // This is the very first byte that is loaded in UDP buffer. // Remember what transmit buffer we are loading, and // start loading this and next bytes in data area of UDP packet. p->TxBuffer = MACGetTxBuffer(TRUE); // Make sure that we received a TX buffer if(p->TxBuffer == INVALID_BUFFER) return FALSE; IPSetTxBuffer(p->TxBuffer, sizeof(UDP_HEADER)); p->TxOffset = 0; } tempOffset=p->TxOffset; /*if (v>=0x20) debug_udp("-%c", v); else debug_udp("-0x%X", v);*/ // Load it. MACPut(v); // Keep track of number of bytes loaded. // If total bytes fill up buffer, transmit it. if (tempOffset >= tempCount) { tempCount++; } tempOffset++; /* //broken in ccs? if ( p->TxOffset++ >= p->TxCount ) { p->TxCount++; debug_udp("!"); } */ #define SIZEOF_MAC_HEADER (14) // Depending on what communication media is used, allowable UDP // data length will vary. #if STACK_USE_SLIP #define MAX_UDP_DATA (MAC_TX_BUFFER_SIZE - SIZEOF_MAC_HEADER - sizeof(IP_HEADER) - sizeof(UDP_HEADER)) #else #define MAX_UDP_DATA (MAC_TX_BUFFER_SIZE - sizeof(IP_HEADER) - sizeof(UDP_HEADER) ) #endif p->TxOffset = tempOffset; //temp = p->TxCount; //if ( temp >= MAX_UDP_DATA ) p->TxCount = tempCount; if (tempCount >= MAX_UDP_DATA) { UDPFlush(); } #undef MAX_UDP_DATA return TRUE; }
/***************************************************************************** Function: void UDPSetTxBuffer(WORD wOffset) Summary: Moves the pointer within the TX buffer. Description: This function allows the write location within the TX buffer to be specified. Future calls to UDPPut, UDPPutArray, UDPPutString, etc will write data from the indicated location. Precondition: UDPInit() must have been previously called and a socket is currently active. Parameters: wOffset - Offset from beginning of UDP packet data payload to place the write pointer. Returns: None ***************************************************************************/ void UDPSetTxBuffer(WORD wOffset) { IPSetTxBuffer(wOffset+sizeof(UDP_HEADER)); wPutOffset = wOffset; }
/** * 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; }
/***************************************************************************** Function: void UDPSetTxBuffer(uint16_t wOffset) Summary: Moves the pointer within the TX buffer. Description: This function allows the write location within the TX buffer to be specified. Future calls to UDPPut, UDPPutArray, UDPPutString, etc will write data from the indicated location. Precondition: UDPInit() must have been previously called and a socket is currently active. Parameters: wOffset - Offset from beginning of UDP packet data payload to place the write pointer. Returns: None ***************************************************************************/ void UDPSetTxBuffer(uint16_t wOffset) { IPSetTxBuffer(wOffset+sizeof(UDP_HEADER)); wPutOffset = wOffset; }