/********************************************************************* * Function: BOOL UDPGet(BYTE *v) * * PreCondition: UDPInit() is already called AND * UDPIsGetReady(s) == TRUE * * Input: v - Buffer to receive UDP data byte * * Output: TRUE if a data byte was read * FALSE if no data byte was read or available * * Side Effects: None * * Overview: None * * Note: This function fetches data from an active UDP * socket as set by UDPIsGetReady() call. ********************************************************************/ BOOL UDPGet(BYTE *v) { // CALLER MUST MAKE SURE THAT THERE IS ENOUGH DATA BYTE IN BUFFER // BEFORE CALLING THIS FUNCTION. // USE UDPIsGetReady() TO CONFIRM. if ( UDPSocketInfo[activeUDPSocket].RxCount == 0 ) return FALSE; // If if this very first read to packet, set MAC Rx Pointer to // beginig of UDP data area. if ( UDPSocketInfo[activeUDPSocket].Flags.bFirstRead ) { UDPSocketInfo[activeUDPSocket].Flags.bFirstRead = FALSE; UDPSetRxBuffer(0); } *v = MACGet(); UDPSocketInfo[activeUDPSocket].RxCount--; if ( UDPSocketInfo[activeUDPSocket].RxCount == 0 ) { MACDiscardRx(); } return TRUE; }
/** * Read the requested number of bytes from the active UDP socket into * the given buffer. * * Note: This function fetches data from an active UDP socket as set by * UDPIsGetReady() call. * * @preCondition UDPInit() is already called AND * UDPIsGetReady(s) == TRUE * * @param[in] buffer Buffer to hold received data. * @param count Buffer length * * @return Number of bytes loaded into buffer. */ WORD UDPGetArray(BYTE *buffer, WORD count) { WORD bytesRead; if ( UDPSocketInfo[activeUDPSocket].RxCount == 0 ) return 0; // If if this very first read to packet, set MAC Rx Pointer to // beginig of UDP data area. if ( UDPSocketInfo[activeUDPSocket].Flags.bFirstRead ) { UDPSocketInfo[activeUDPSocket].Flags.bFirstRead = FALSE; UDPSetRxBuffer(0); } //If more bytes requested then are left in the receive buffer, adjust count if (count > UDPSocketInfo[activeUDPSocket].RxCount) { count = UDPSocketInfo[activeUDPSocket].RxCount; } //Read the requested amount of data from the current MAC receive buffer bytesRead = MACGetArray(buffer, count); UDPSocketInfo[activeUDPSocket].RxCount -= bytesRead; if ( UDPSocketInfo[activeUDPSocket].RxCount == 0 ) { MACDiscardRx(); //Discard the contents of the current RX buffer } return count; }
/***************************************************************************** Function: WORD UDPIsGetReady(UDP_SOCKET s) Summary: Determines how many bytes can be read from the UDP socket. Description: This function determines if bytes can be read from the specified UDP socket. It also prepares the UDP module for reading by setting the indicated socket as the currently active connection. Precondition: UDPInit() must have been previously called. Parameters: s - The socket to be made active (which has already been opened or is listening) Returns: The number of bytes that can be read from this socket. ***************************************************************************/ WORD UDPIsGetReady(UDP_SOCKET s) { activeUDPSocket = s; if(SocketWithRxData != s) return 0; // If this is the very first time we are accessing this packet, // move the read point to the begining of the packet. if(Flags.bFirstRead) { Flags.bFirstRead = 0; UDPSetRxBuffer(0); } return UDPRxCount - wGetOffset; }
/***************************************************************************** Function: void _DHCPReceive(void) Description: Receives and parses a DHCP message. Precondition: A DHCP message is waiting in the UDP buffer. Parameters: None Returns: One of the DCHP_TYPE* contants. ***************************************************************************/ static BYTE _DHCPReceive(void) { /********************************************************************* DHCP PACKET FORMAT AS PER RFC 1541 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | op (1) | htype (1) | hlen (1) | hops (1) | +---------------+---------------+---------------+---------------+ | xid (4) | +-------------------------------+-------------------------------+ | secs (2) | flags (2) | +-------------------------------+-------------------------------+ | ciaddr (4) | +---------------------------------------------------------------+ | yiaddr (4) | +---------------------------------------------------------------+ | siaddr (4) | +---------------------------------------------------------------+ | giaddr (4) | +---------------------------------------------------------------+ | | | chaddr (16) | | | | | +---------------------------------------------------------------+ | | | sname (64) | +---------------------------------------------------------------+ | | | file (128) | +---------------------------------------------------------------+ | | | options (312) | +---------------------------------------------------------------+ ********************************************************************/ BYTE v; BYTE i, j; BYTE type; BOOL lbDone; DWORD tempServerID; // Assume unknown message until proven otherwise. type = DHCP_UNKNOWN_MESSAGE; UDPGet(&v); // op // Make sure this is BOOT_REPLY. if ( v == BOOT_REPLY ) { // Jump to chaddr field (Client Hardware Address -- our MAC address for // Ethernet and WiFi networks) and verify that this message is directed // to us before doing any other processing. UDPSetRxBuffer(28); // chaddr field is at offset 28 in the UDP packet payload -- see DHCP packet format above for ( i = 0; i < 6u; i++ ) { UDPGet(&v); if ( v != AppConfig.MyMACAddr.v[i]) goto UDPInvalid; } // Check to see if this is the first offer. If it is, record its // yiaddr value ("Your (client) IP address") so that we can REQUEST to // use it later. if(!DHCPClient.flags.bits.bOfferReceived) { UDPSetRxBuffer(16); UDPGetArray((BYTE*)&DHCPClient.tempIPAddress, sizeof(DHCPClient.tempIPAddress)); DHCPClient.validValues.bits.IPAddress = 1; } // Jump to DHCP options (ignore htype, hlen, hops, xid, secs, flags, // ciaddr, siaddr, giaddr, padding part of chaddr, sname, file, magic // cookie fields) UDPSetRxBuffer(240); lbDone = FALSE; do { // Get the Option number // Break out eventually in case if this is a malformed // DHCP message, ie: missing DHCP_END_OPTION marker if(!UDPGet(&v)) { lbDone = TRUE; break; } switch(v) { case DHCP_MESSAGE_TYPE: UDPGet(&v); // Skip len // Len must be 1. if ( v == 1u ) { UDPGet(&type); // Get type // Throw away the packet if we know we don't need it (ie: another offer when we already have one) if(DHCPClient.flags.bits.bOfferReceived && (type == DHCP_OFFER_MESSAGE)) { goto UDPInvalid; } } else goto UDPInvalid; break; case DHCP_SUBNET_MASK: UDPGet(&v); // Skip len // Len must be 4. if ( v == 4u ) { // Check to see if this is the first offer if(DHCPClient.flags.bits.bOfferReceived) { // Discard offered IP mask, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGetArray((BYTE*)&DHCPClient.tempMask, sizeof(DHCPClient.tempMask)); DHCPClient.validValues.bits.Mask = 1; } } else goto UDPInvalid; break; case DHCP_ROUTER: UDPGet(&j); // Len must be >= 4. if ( j >= 4u ) { // Check to see if this is the first offer if(DHCPClient.flags.bits.bOfferReceived) { // Discard offered Gateway address, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGetArray((BYTE*)&DHCPClient.tempGateway, sizeof(DHCPClient.tempGateway)); DHCPClient.validValues.bits.Gateway = 1; } } else goto UDPInvalid; // Discard any other router addresses. j -= 4; while(j--) UDPGet(&v); break; #if defined(STACK_USE_DNS) case DHCP_DNS: UDPGet(&j); // Len must be >= 4. if(j < 4u) goto UDPInvalid; // Check to see if this is the first offer if(!DHCPClient.flags.bits.bOfferReceived) { UDPGetArray((BYTE*)&DHCPClient.tempDNS, sizeof(DHCPClient.tempDNS)); DHCPClient.validValues.bits.DNS = 1; j -= 4; } // Len must be >= 4 for a secondary DNS server address if(j >= 4u) { // Check to see if this is the first offer if(!DHCPClient.flags.bits.bOfferReceived) { UDPGetArray((BYTE*)&DHCPClient.tempDNS2, sizeof(DHCPClient.tempDNS2)); DHCPClient.validValues.bits.DNS2 = 1; j -= 4; } } // Discard any other DNS server addresses while(j--) UDPGet(&v); break; #endif // case DHCP_HOST_NAME: // UDPGet(&j); // // Len must be >= 4. // if(j < 1u) // goto UDPInvalid; // // // Check to see if this is the first offer // if(DHCPFlags.bits.bOfferReceived) // { // // Discard offered host name, we already have an offer // while(j--) // UDPGet(&v); // } // else // { // for(i = 0; j, i < sizeof(tempHostName); i++, j--) // { // UDPGet(&tempHostName[i]); // } // while(j--) // { // UDPGet(&v); // } // ValidValues.bits.HostName = 1; // } // // break; case DHCP_SERVER_IDENTIFIER: UDPGet(&v); // Get len // Len must be 4. if ( v == 4u ) { UDPGet(&(((BYTE*)&tempServerID)[3])); // Get the id UDPGet(&(((BYTE*)&tempServerID)[2])); UDPGet(&(((BYTE*)&tempServerID)[1])); UDPGet(&(((BYTE*)&tempServerID)[0])); } else goto UDPInvalid; break; case DHCP_END_OPTION: lbDone = TRUE; break; case DHCP_IP_LEASE_TIME: UDPGet(&v); // Get len // Len must be 4. if ( v == 4u ) { // Check to see if this is the first offer if(DHCPClient.flags.bits.bOfferReceived) { // Discard offered lease time, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGet(&(((BYTE*)(&DHCPClient.dwLeaseTime))[3])); UDPGet(&(((BYTE*)(&DHCPClient.dwLeaseTime))[2])); UDPGet(&(((BYTE*)(&DHCPClient.dwLeaseTime))[1])); UDPGet(&(((BYTE*)(&DHCPClient.dwLeaseTime))[0])); // In case if our clock is not as accurate as the remote // DHCP server's clock, let's treat the lease time as only // 96.875% of the value given DHCPClient.dwLeaseTime -= DHCPClient.dwLeaseTime>>5; } } else goto UDPInvalid; break; default: // Ignore all unsupport tags. UDPGet(&j); // Get option len while( j-- ) // Ignore option values UDPGet(&v); } } while( !lbDone ); }