/********************************************************************* * 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: 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; }
/****************************************************************************** * Function: void MACMemCopyAsync(PTR_BASE destAddr, PTR_BASE sourceAddr, WORD len) * * PreCondition: None * * Input: destAddr: Destination address in the Ethernet memory to * copy to. If (PTR_BASE)-1 is specified, the * current EWRPT value will be used instead. * sourceAddr: Source address to read from. If (PTR_BASE)-1 is * specified, the current ERDPT value will be used * instead. * len: Number of bytes to copy * * Output: None * * Side Effects: None * * Overview: Bytes are asynchrnously transfered within the buffer. Call * MACIsMemCopyDone() to see when the transfer is complete. * * Note: If a prior transfer is already in progress prior to * calling this function, this function will block until it * can start this transfer. *****************************************************************************/ void MACMemCopyAsync(PTR_BASE destAddr, PTR_BASE sourceAddr, WORD len) { WORD_VAL ReadSave, WriteSave; BOOL UpdateWritePointer = FALSE; BOOL UpdateReadPointer = FALSE; if (destAddr == (PTR_BASE) - 1) { UpdateWritePointer = TRUE; destAddr = EWRPT; } if (sourceAddr == (PTR_BASE) - 1) { UpdateReadPointer = TRUE; sourceAddr = ERDPT; } // Handle special conditions where len == 0 or len == 1 // The DMA module is not capable of handling those corner cases if (len <= 1u) { ReadSave.Val = ERDPT; WriteSave.Val = EWRPT; ERDPT = sourceAddr; EWRPT = destAddr; while (len--) MACPut(MACGet()); if (!UpdateReadPointer) { ERDPT = ReadSave.Val; } if (!UpdateWritePointer) { EWRPT = WriteSave.Val; } } else { if (UpdateWritePointer) { WriteSave.Val = destAddr + len; EWRPT = WriteSave.Val; } len += sourceAddr - 1; while (ECON1bits.DMAST); EDMAST = sourceAddr; EDMADST = destAddr; if ((sourceAddr <= RXSTOP) && (len > RXSTOP)) //&& (sourceAddr >= RXSTART)) len -= RXSIZE; EDMAND = len; ECON1bits.CSUMEN = 0; ECON1bits.DMAST = 1; while (ECON1bits.DMAST); // DMA requires that you must not access EDATA while DMA active if (UpdateReadPointer) { len++; if ((sourceAddr <= RXSTOP) && (len > RXSTOP)) //&& (sourceAddr >= RXSTART)) len -= RXSIZE; ERDPT = len; } } }
/****************************************************************************** * 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); }
/** * 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: BOOL UDPPut(BYTE v) Summary: Writes a byte to the currently active socket. Description: This function writes a single byte 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: v - The byte to be loaded into the transmit buffer. Return Values: TRUE - The byte was successfully written to the socket. FALSE - The transmit buffer is already full and so the write failed. ***************************************************************************/ BOOL UDPPut(BYTE v) { // See if we are out of transmit space. if(wPutOffset >= (MAC_TX_BUFFER_SIZE - sizeof(IP_HEADER) - sizeof(UDP_HEADER))) { return FALSE; } // Load application data byte MACPut(v); wPutOffset++; if(wPutOffset > UDPTxCount) UDPTxCount = wPutOffset; return TRUE; }
/***************************************************************************** Function: bool UDPPut(uint8_t v) Summary: Writes a byte to the currently active socket. Description: This function writes a single byte 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: v - The byte to be loaded into the transmit buffer. Return Values: true - The byte was successfully written to the socket. false - The transmit buffer is already full and so the write failed. ***************************************************************************/ bool UDPPut(uint8_t v) { // See if we are out of transmit space. if(wPutOffset >= (MAC_TX_BUFFER_SIZE - sizeof(IP_HEADER) - sizeof(UDP_HEADER))) { return false; } // Load application data byte MACPut(v); wPutOffset++; if(wPutOffset > UDPTxCount) UDPTxCount = wPutOffset; return true; }
/** * 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; }
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]); }
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: 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; }
void MACPutArray(int8 *val, int16 len) { while( len-- ) MACPut(*val++); }
/****************************************************************************** * Function: void MACInit(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: MACInit enables the Ethernet module, waits for the * to become ready, and programs all registers for future * TX/RX operations. * * Note: This function blocks for at least 1ms, waiting for the * hardware to stabilize. *****************************************************************************/ void MACInit(void) { BYTE i; TRISA &= 0xFC; // Clear TRISA0 and TRISA1 to set LED0 and LED1 as outputs for Ethernet module status ECON2bits.ETHEN = 1; // Enable Ethernet! // If Ethernet TPIN+/- RX polarity swap hardware exists, start controlling // it and default it to the non-swapped state. #if defined(ETH_RX_POLARITY_SWAP_TRIS) ETH_RX_POLARITY_SWAP_TRIS = 0; ETH_RX_POLARITY_SWAP_IO = 0; #endif // Wait for PHYRDY to become set. while (!ESTATbits.PHYRDY); // Configure the receive buffer boundary pointers // and the buffer write protect pointer (receive buffer read pointer) flags.v = 0; flags.bits.bWasDiscarded = 1; NextPacketLocation.Val = RXSTART; ERXST = RXSTART; ERXRDPTL = LOW(RXSTOP); // Write low byte first ERXRDPTH = HIGH(RXSTOP); // Write high byte last ERXND = RXSTOP; ETXST = TXSTART; // Write a permanant per packet control byte of 0x00 EWRPT = TXSTART; MACPut(0x00); // Configure Receive Filters // (No need to reconfigure - Unicast OR Broadcast with CRC checking is // acceptable) //ERXFCON = ERXFCON_CRCEN; // Promiscious mode // Configure the MAC // Enable the receive portion of the MAC MACON1 = MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN; Nop(); // Pad packets to 60 bytes, add CRC, and check Type/Length field. #if defined(FULL_DUPLEX) MACON3 = MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX; Nop(); MABBIPG = 0x15; Nop(); #else MACON3 = MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN; Nop(); MABBIPG = 0x12; Nop(); #endif // Allow infinite deferals if the medium is continuously busy // (do not time out a transmission if the half duplex medium is // completely saturated with other people's data) MACON4 = MACON4_DEFER; Nop(); // Set non-back-to-back inter-packet gap to 9.6us. The back-to-back // inter-packet gap (MABBIPG) is set by MACSetDuplex() which is called // later. MAIPGL = 0x12; Nop(); MAIPGH = 0x0C; Nop(); // Set the maximum packet size which the controller will accept MAMXFLL = LOW(6 + 6 + 2 + 1500 + 4); Nop(); MAMXFLH = HIGH(6 + 6 + 2 + 1500 + 4); Nop(); // Initialize physical MAC address registers MAADR1 = 0; //AppConfig.MyMACAddr.v[0]; Nop(); MAADR2 = 0; //AppConfig.MyMACAddr.v[1]; Nop(); MAADR3 = 0; //AppConfig.MyMACAddr.v[2]; Nop(); MAADR4 = 0; //AppConfig.MyMACAddr.v[3]; Nop(); MAADR5 = 0; //AppConfig.MyMACAddr.v[4]; Nop(); MAADR6 = 0; //AppConfig.MyMACAddr.v[5]; Nop(); // Disable half duplex loopback in PHY and set RXAPDIS bit as per errata WritePHYReg(PHCON2, PHCON2_HDLDIS | PHCON2_RXAPDIS); // Configure LEDA to display LINK status, LEDB to display TX/RX activity SetLEDConfig(0x3472); // Set the PHY into the proper duplex state #if defined(FULL_DUPLEX) WritePHYReg(PHCON1, PHCON1_PDPXMD); #else WritePHYReg(PHCON1, 0x0000); #endif // Enable packet reception ECON1bits.RXEN = 1; }//end MACInit
/** * 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; }
BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type) { /* * This marks that all future accesses to MACGet and MACPut * be applied to Receive buffer. */ bIsRxActive = TRUE; if ( RxBuffer.PacketCount ) { /* * Set up packet access index. */ RxBuffer.CallerAccess = RxBuffer.CurrentPacket; RxBuffer.CallerAccess++; if ( RxBuffer.CallerAccess >= MAX_SLIP_BUFFER_SIZE ) RxBuffer.CallerAccess = 0; /* * Handle modem commands differently. */ if ( RxBuffer.Data[RxBuffer.CallerAccess] == 'A' ) { /* * Once a modem command is detected, we are not interested * in detail. */ MACDiscardRx(); //Discard the contents of the current RX buffer /* * Mark TxBuffer for Modem String. * This will make sure that Transmit ISR does nottransmit END * at the end. */ TxBuffer.Flags.bits.bIsModemString = TRUE; /* * Since this special handling does not follow standard * SLIP buffer logic, we will setup all required variables * manually. */ TxBuffer.Length = 4; TxBuffer.CallerAccess = 0; /* * Remember to use transmit buffer for MACPut */ bIsRxActive = FALSE; /* * Now load modem response. */ MACPut('O'); MACPut('K'); MACPut('\r'); MACPut('\n'); /* * Transmit it. */ MACFlush(); } else { /* * This was not a modem command. * It must be IP packet. Mark it accordingly and return. */ *type = MAC_IP; return TRUE; } } return FALSE; }
void MACPutArray(BYTE *val, WORD len) { while( len-- ) MACPut(*val++); }
/** * 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; }