/********************************************************************* * Function: static void NBNSGetName (UDP_SOCKET s, uint8_t *String) * * PreCondition: None * * Input: String: Pointer to an array into which * a received NetBIOS name should be copied. * * Output: None * * Side Effects: None * * Overview: Reads the NetBIOS name from a UDP socket and * copies it into a user-specified buffer. * * Note: None ********************************************************************/ static void NBNSGetName(UDP_SOCKET s, uint8_t *String) { uint8_t i, j, k; if(String == NULL) { UDPGet(s, &i); while(i--) { UDPGet(s, &j); } } else { UDPGet(s, &i); if(i != 32u) { *String = 0; return; } while(i--) { UDPGet(s, &j); j -= 'A'; k = j<<4; i--; UDPGet(s, &j); j -= 'A'; *String++ = k | j; } } }
static void NBNSGetName(BYTE *String) { BYTE i, j, k; if(String == NULL) { UDPGet(&i); while(i--) { UDPGet(&j); } } else { UDPGet(&i); if(i > 32) { *String = 0; return; } while(i--) { UDPGet(&j); j -= 'A'; k = j<<4; i--; UDPGet(&j); j -= 'A'; *String++ = k | j; } } }
/***************************************************************************** Function: static void DNSDiscardName(UDP_SOCKET s) Summary: Reads a name string or string pointer from the DNS socket and discards it. Description: This function reads a name string from the DNS socket. Each string consists of a series of labels. Each label consists of a length prefix byte, followed by the label bytes. At the end of the string, a zero length label is found as termination. If name compression is used, this function will automatically detect the pointer and discard it. Precondition: UDP socket is obtained and ready for reading a DNS name Parameters: None Returns: None ***************************************************************************/ static void DNSDiscardName(UDP_SOCKET s) { uint8_t i; while(1) { // Get first byte which will tell us if this is a 16-bit pointer or the // length of the first of a series of labels if(!UDPGet(s, &i)) return; // Check if this is a pointer, if so, get the reminaing 8 bits and return if((i & 0xC0u) == 0xC0u) { UDPGet(s, &i); return; } // Exit once we reach a zero length label if(i == 0u) return; // Discard complete label UDPGetArray(DNSSocket, NULL, i); } }
/********************************************************************* * Function: BYTE TFTPGet(void) * * PreCondition: TFTPOpenFile() is called with TFTP_FILE_MODE_READ * and TFTPIsGetReady() = TRUE * * Input: None * * Output: data byte as received from remote server. * * Side Effects: None * * Overview: Fetches next data byte from TFTP socket. * If end of data block is reached, it issues * ack to server so that next data block can be * received. * * Note: Use this function to read file from server. ********************************************************************/ BYTE TFTPGet(void) { BYTE v; // Read byte from UDP UDPGet(&v); // Update block length MutExVar.group2._tftpBlockLength.Val++; // Check to see if entire data block is fetched. // To reduce code, MSB is compared for 0x02 (of 0x200 = 512). if ( MutExVar.group2._tftpBlockLength.byte.MSB == TFTP_BLOCK_SIZE_MSB ) { // Entire block was fetched. Discard everything else. UDPDiscard(); // Remember that we have flushed this block. _tftpFlags.bits.bIsFlushed = TRUE; // Reset block length. MutExVar.group2._tftpBlockLength.Val = 0; // Must send ACK to receive next block. _tftpState = SM_TFTP_SEND_ACK; } return v; }
static void DNSGetString(BYTE *String) { BYTE i; BYTE j; if(String == NULL) { UDPGet(&i); while(i) { while(i--) { UDPGet(&j); } UDPGet(&i); } } else { UDPGet(&i); while(i) { while(i--) { UDPGet(String); String++; } UDPGet(&i); } } }
/***************************************************************************** Function: static void DNSCopyRXNameToTX(void) Summary: Copies a DNS hostname, possibly including name compression, from the RX packet to the TX packet (without name compression in TX case). Description: None Precondition: RX pointer is set to currently point to the DNS name to copy Parameters: None Returns: None ***************************************************************************/ static void DNSCopyRXNameToTX(void) { WORD w; BYTE i; BYTE len; while(1) { // Get first byte which will tell us if this is a 16-bit pointer or the // length of the first of a series of labels if(!UDPGet(&i)) return; // Check if this is a pointer, if so, get the reminaing 8 bits and seek to the pointer value if((i & 0xC0u) == 0xC0u) { ((BYTE*)&w)[1] = i & 0x3F; UDPGet((BYTE*)&w); IPSetRxBuffer(sizeof(UDP_HEADER) + w); continue; } // Write the length byte len = i; UDPPut(len); // Exit if we've reached a zero length label if(len == 0u) return; // Copy all of the bytes in this label while(len--) { UDPGet(&i); UDPPut(i); } } }
/***************************************************************************** Function: static void DNSCopyRXNameToTX(UDP_SOCKET s, NET_CONFIG* pNet) Summary: Copies a DNS hostname, possibly including name compression, from the RX packet to the TX packet (without name compression in TX case). Description: None Precondition: RX pointer is set to currently point to the DNS name to copy Parameters: None Returns: None ***************************************************************************/ static void DNSCopyRXNameToTX(UDP_SOCKET s, NET_CONFIG* pNet) { uint16_t w; uint8_t i; uint8_t len; while(1) { // Get first byte which will tell us if this is a 16-bit pointer or the // length of the first of a series of labels if(!UDPGet(s, &i)) return; // Check if this is a pointer, if so, get the reminaing 8 bits and seek to the pointer value if((i & 0xC0u) == 0xC0u) { ((uint8_t*)&w)[1] = i & 0x3F; UDPGet(s, (uint8_t*)&w); IPSetRxBuffer(pNet, sizeof(UDP_HEADER) + w); continue; } // Write the length byte len = i; UDPPut(s, len); // Exit if we've reached a zero length label if(len == 0u) return; // Copy all of the bytes in this label while(len--) { UDPGet(s, &i); UDPPut(s, i); } } }
/********************************************************************* * Function: TFTP_RESULT TFTPIsGetReady(void) * * PreCondition: TFTPOpenFile() is called with TFTP_FILE_MODE_READ * and TFTPIsFileOpened() returned with TRUE. * * Input: None * * Output: TFTP_OK if it there is more data byte available * to read * * TFTP_TIMEOUT if timeout occurred waiting for * new data. * * TFTP_END_OF_FILE if end of file has reached. * * TFTP_ERROR if remote server returned ERROR. * Actual error code may be read by calling * TFTPGetError() * * TFTP_NOT_READY if still waiting for new data. * * Side Effects: None * * Overview: Waits for data block. If data block does not * arrive within specified timeout, it automatically * sends out ack for previous block to remind * server to send next data block. * If all attempts are exhausted, it returns with * TFTP_TIMEOUT. * * Note: By default, this funciton uses "octet" or binary * mode of file transfer. ********************************************************************/ TFTP_RESULT TFTPIsGetReady(void) { WORD_VAL opCode; WORD_VAL blockNumber; BOOL bTimeOut; // Check to see if timeout has occurred. bTimeOut = FALSE; if ( TickGetDiff(TickGet(), _tftpStartTick) >= TFTP_GET_TIMEOUT_VAL ) { bTimeOut = TRUE; _tftpStartTick = TickGet(); } switch(_tftpState) { case SM_TFTP_WAIT_FOR_DATA: // If timeout occurs in this state, it may be because, we have not // even received very first data block or some in between block. if ( bTimeOut == TRUE ) { bTimeOut = FALSE; if ( _tftpRetries++ > (TFTP_MAX_RETRIES-1) ) { DEBUG(printf("TFTPIsGetReady(): Timeout.\n")); // Forget about all previous attempts. _tftpRetries = 1; return TFTP_TIMEOUT; } // If we have not even received first block, ask application // retry. if ( MutExVar.group2._tftpBlockNumber.Val == 1 ) { DEBUG(printf("TFTPIsGetReady(): TFTPOpen Retry.\n")); return TFTP_RETRY; } else { DEBUG(printf("TFTPIsGetReady(): ACK Retry #%d...,\n", _tftpRetries)); // Block number was already incremented in last ACK attempt, // so decrement it. MutExVar.group2._tftpBlockNumber.Val--; // Do it. _tftpState = SM_TFTP_SEND_ACK; break; } } // For Read operation, server will respond with data block. if ( !UDPIsGetReady(_tftpSocket) ) break; // Get opCode UDPGet(&opCode.byte.MSB); UDPGet(&opCode.byte.LSB); // Get block number. UDPGet(&blockNumber.byte.MSB); UDPGet(&blockNumber.byte.LSB); // In order to read file, this must be data with block number of 0. if ( opCode.Val == TFTP_OPCODE_DATA ) { // Make sure that this is not a duplicate block. if ( MutExVar.group2._tftpBlockNumber.Val == blockNumber.Val ) { // Mark that we have not acked this block. _tftpFlags.bits.bIsAcked = FALSE; // Since we have a packet, forget about previous retry count. _tftpRetries = 1; _tftpState = SM_TFTP_READY; return TFTP_OK; } // If received block has already been received, simply ack it // so that Server can "get over" it and send next block. else if ( MutExVar.group2._tftpBlockNumber.Val > blockNumber.Val ) { DEBUG(printf("TFTPIsGetReady(): "\ "Duplicate block %d received - droping it...\n", \ blockNumber.Val)); MutExVar.group2._tftpDuplicateBlock.Val = blockNumber.Val; _tftpState = SM_TFTP_DUPLICATE_ACK; } #if defined(TFTP_DEBUG) else { DEBUG(printf("TFTPIsGetReady(): "\ "Unexpected block %d received - droping it...\n", \ blockNumber.Val)); } #endif } // Discard all unexpected and error blocks. UDPDiscard(); // If this was an error, remember error code for later delivery. if ( opCode.Val == TFTP_OPCODE_ERROR ) { _tftpError = blockNumber.Val; return TFTP_ERROR; } break; case SM_TFTP_DUPLICATE_ACK: if ( UDPIsPutReady(_tftpSocket) ) { _TFTPSendAck(MutExVar.group2._tftpDuplicateBlock); _tftpState = SM_TFTP_WAIT_FOR_DATA; } break; case SM_TFTP_READY: if ( UDPIsGetReady(_tftpSocket) ) { _tftpStartTick = TickGet(); return TFTP_OK; } // End of file is reached when data block is less than 512 bytes long. // To reduce code, only MSB compared against 0x02 (of 0x200 = 512) to // determine if block is less than 512 bytes long or not. else if ( MutExVar.group2._tftpBlockLength.Val == 0 || MutExVar.group2._tftpBlockLength.byte.MSB < TFTP_BLOCK_SIZE_MSB ) _tftpState = SM_TFTP_SEND_LAST_ACK; else break; case SM_TFTP_SEND_LAST_ACK: case SM_TFTP_SEND_ACK: if ( UDPIsPutReady(_tftpSocket) ) { _TFTPSendAck(MutExVar.group2._tftpBlockNumber); // This is the next block we are expecting. MutExVar.group2._tftpBlockNumber.Val++; // Remember that we have already acked current block. _tftpFlags.bits.bIsAcked = TRUE; if ( _tftpState == SM_TFTP_SEND_LAST_ACK ) return TFTP_END_OF_FILE; _tftpState = SM_TFTP_WAIT_FOR_DATA; } break; } return TFTP_NOT_READY; }
/***************************************************************************** Function: void DHCPServerTask(NET_CONFIG* pConfig) Summary: Performs periodic DHCP server tasks. Description: This function performs any periodic tasks requied by the DHCP server module, such as processing DHCP requests and distributing IP addresses. Precondition: None Parameters: pConfig - interface Returns: None ***************************************************************************/ void DHCPServerTask(NET_CONFIG* pConfig) { uint8_t i; uint8_t Option, Len; BOOTP_HEADER BOOTPHeader; uint32_t dw; bool bAccept; int netIx; UDP_SOCKET s; #if defined(TCPIP_STACK_USE_DHCP_CLIENT) // Make sure we don't clobber anyone else's DHCP server if(DHCPIsServerDetected(pConfig)) return; #endif netIx = _TCPIPStackNetIx(pConfig); if(!bDHCPServerEnabled[netIx]) return; s = MySocket[netIx]; switch(smDHCPServer[netIx]) { case DHCP_OPEN_SOCKET: // Obtain a UDP socket to listen/transmit on MySocket[netIx] = UDPOpen(0,UDP_OPEN_SERVER,DHCP_SERVER_PORT, DHCP_CLIENT_PORT); if(MySocket[netIx] == INVALID_UDP_SOCKET) break; UDPSocketSetNet(MySocket[netIx], pConfig); // Decide which address to lease out // Note that this needs to be changed if we are to // support more than one lease DHCPNextLease[netIx].Val = (pConfig->MyIPAddr.Val & pConfig->MyMask.Val) + 0x02000000; if(DHCPNextLease[netIx].v[3] == 255u) DHCPNextLease[netIx].v[3] += 0x03; if(DHCPNextLease[netIx].v[3] == 0u) DHCPNextLease[netIx].v[3] += 0x02; smDHCPServer[netIx]++; case DHCP_LISTEN: // Check to see if a valid DHCP packet has arrived if(UDPIsGetReady(s) < 241u) break; // Retrieve the BOOTP header UDPGetArray(s, (uint8_t*)&BOOTPHeader, sizeof(BOOTPHeader)); bAccept = (BOOTPHeader.ClientIP.Val == DHCPNextLease[netIx].Val) || (BOOTPHeader.ClientIP.Val == 0x00000000u); // Validate first three fields if(BOOTPHeader.MessageType != 1u) break; if(BOOTPHeader.HardwareType != 1u) break; if(BOOTPHeader.HardwareLen != 6u) break; // Throw away 10 unused bytes of hardware address, // server host name, and boot file name -- unsupported/not needed. for(i = 0; i < 64+128+(16-sizeof(MAC_ADDR)); i++) UDPGet(s, &Option); // Obtain Magic Cookie and verify UDPGetArray(s, (uint8_t*)&dw, sizeof(uint32_t)); if(dw != 0x63538263ul) break; // Obtain options while(1) { // Get option type if(!UDPGet(s, &Option)) break; if(Option == DHCP_END_OPTION) break; // Get option length UDPGet(s, &Len); // Process option switch(Option) { case DHCP_MESSAGE_TYPE: UDPGet(s, &i); switch(i) { case DHCP_DISCOVER_MESSAGE: DHCPReplyToDiscovery(&BOOTPHeader, netIx); break; case DHCP_REQUEST_MESSAGE: // NOTE : This #if section was missing from 5.36 #if defined(TCPIP_STACK_USE_ZEROCONF_LINK_LOCAL) if ( (BOOTPHeader.ClientIP.Val == 0x00000000u) && (bLeaseAvailable[netIx] == false) ) { // Lease available only to the current lease holder break; } #endif DHCPReplyToRequest(&BOOTPHeader, bAccept, netIx); // NOTE : This #if section was missing from 5.36 #if defined(TCPIP_STACK_USE_ZEROCONF_LINK_LOCAL) bLeaseAvailable[netIx] = false; #endif break; // Need to handle these if supporting more than one DHCP lease case DHCP_RELEASE_MESSAGE: case DHCP_DECLINE_MESSAGE: break; } break; case DHCP_PARAM_REQUEST_IP_ADDRESS: if(Len == 4u) { // Get the requested IP address and see if it is the one we have on offer. UDPGetArray(s, (uint8_t*)&dw, 4); Len -= 4; bAccept = (dw == DHCPNextLease[netIx].Val); } break; case DHCP_END_OPTION: UDPDiscard(s); return; } // Remove any unprocessed bytes that we don't care about while(Len--) { UDPGet(s, &i); } } UDPDiscard(s); break; } }
/***************************************************************************** Function: static void DHCPReplyToRequest(BOOTP_HEADER *Header, bool bAccept, int netIx) Summary: Replies to a DHCP Request message. Description: This function replies to a DHCP Request message by sending out a DHCP Acknowledge message. Precondition: None Parameters: Header - the BootP header this is in response to. bAccept - whether or not we've accepted this request netIx - interface index Returns: None Internal: Needs to support more than one simultaneous lease in the future. ***************************************************************************/ static void DHCPReplyToRequest(BOOTP_HEADER *Header, bool bAccept, int netIx) { uint8_t i; NET_CONFIG* pConfig; UDP_SOCKET s; // Set the correct socket to active and ensure that // enough space is available to generate the DHCP response s = MySocket[netIx]; if(UDPIsPutReady(s) < 300u) return; pConfig = UDPSocketGetNet(s); // Search through all remaining options and look for the Requested IP address field // Obtain options while(UDPIsGetReady(s)) { uint8_t Option, Len; uint32_t dw; // Get option type if(!UDPGet(s, &Option)) break; if(Option == DHCP_END_OPTION) break; // Get option length UDPGet(s, &Len); // Process option if((Option == DHCP_PARAM_REQUEST_IP_ADDRESS) && (Len == 4u)) { // Get the requested IP address and see if it is the one we have on offer. If not, we should send back a NAK, but since there could be some other DHCP server offering this address, we'll just silently ignore this request. UDPGetArray(s, (uint8_t*)&dw, 4); Len -= 4; if(dw != DHCPNextLease[netIx].Val) { bAccept = false; } break; } // Remove the unprocessed bytes that we don't care about while(Len--) { UDPGet(s, &i); } } // Begin putting the BOOTP Header and DHCP options UDPPut(s, BOOT_REPLY); // Message Type: 2 (BOOTP Reply) // Reply with the same Hardware Type, Hardware Address Length, Hops, and Transaction ID fields UDPPutArray(s, (uint8_t*)&(Header->HardwareType), 7); UDPPut(s, 0x00); // Seconds Elapsed: 0 (Not used) UDPPut(s, 0x00); // Seconds Elapsed: 0 (Not used) UDPPutArray(s, (uint8_t*)&(Header->BootpFlags), sizeof(Header->BootpFlags)); UDPPutArray(s, (uint8_t*)&(Header->ClientIP), sizeof(IP_ADDR));// Your (client) IP Address: UDPPutArray(s, (uint8_t*)&DHCPNextLease[netIx], sizeof(IP_ADDR)); // Lease IP address to give out UDPPut(s, 0x00); // Next Server IP Address: 0.0.0.0 (not used) UDPPut(s, 0x00); // Next Server IP Address: 0.0.0.0 (not used) UDPPut(s, 0x00); // Next Server IP Address: 0.0.0.0 (not used) UDPPut(s, 0x00); // Next Server IP Address: 0.0.0.0 (not used) UDPPut(s, 0x00); // Relay Agent IP Address: 0.0.0.0 (not used) UDPPut(s, 0x00); // Relay Agent IP Address: 0.0.0.0 (not used) UDPPut(s, 0x00); // Relay Agent IP Address: 0.0.0.0 (not used) UDPPut(s, 0x00); // Relay Agent IP Address: 0.0.0.0 (not used) UDPPutArray(s, (uint8_t*)&(Header->ClientMAC), sizeof(MAC_ADDR)); // Client MAC address: Same as given by client for(i = 0; i < 64+128+(16-sizeof(MAC_ADDR)); i++) // Remaining 10 bytes of client hardware address, server host name: Null string (not used) UDPPut(s, 0x00); // Boot filename: Null string (not used) UDPPut(s, 0x63); // Magic Cookie: 0x63538263 UDPPut(s, 0x82); // Magic Cookie: 0x63538263 UDPPut(s, 0x53); // Magic Cookie: 0x63538263 UDPPut(s, 0x63); // Magic Cookie: 0x63538263 // Options: DHCP lease ACKnowledge if(bAccept) { UDPPut(s, DHCP_OPTION_ACK_MESSAGE); UDPPut(s, 1); UDPPut(s, DHCP_ACK_MESSAGE); } else // Send a NACK { UDPPut(s, DHCP_OPTION_ACK_MESSAGE); UDPPut(s, 1); UDPPut(s, DHCP_NAK_MESSAGE); } // Option: Lease duration UDPPut(s, DHCP_IP_LEASE_TIME); UDPPut(s, 4); UDPPut(s, (DHCP_LEASE_DURATION>>24) & 0xFF); UDPPut(s, (DHCP_LEASE_DURATION>>16) & 0xFF); UDPPut(s, (DHCP_LEASE_DURATION>>8) & 0xFF); UDPPut(s, (DHCP_LEASE_DURATION) & 0xFF); // Option: Server identifier UDPPut(s, DHCP_SERVER_IDENTIFIER); UDPPut(s, sizeof(IP_ADDR)); UDPPutArray(s, (uint8_t*)&pConfig->MyIPAddr, sizeof(IP_ADDR)); // Option: Subnet Mask UDPPut(s, DHCP_SUBNET_MASK); UDPPut(s, sizeof(IP_ADDR)); UDPPutArray(s, (uint8_t*)&pConfig->MyMask, sizeof(IP_ADDR)); // Option: Router/Gateway address UDPPut(s, DHCP_ROUTER); UDPPut(s, sizeof(IP_ADDR)); UDPPutArray(s, (uint8_t*)&pConfig->MyIPAddr, sizeof(IP_ADDR)); // Option: DNS server address UDPPut(s, DHCP_DNS); UDPPut(s, sizeof(IP_ADDR)); UDPPutArray(s, (uint8_t*)&pConfig->MyIPAddr, sizeof(IP_ADDR)); // No more options, mark ending UDPPut(s, DHCP_END_OPTION); // Add zero padding to ensure compatibility with old BOOTP relays that discard small packets (<300 UDP octets) while(UDPGetTxCount(s) < 300u) UDPPut(s, 0); // Force remote destination address to be the broadcast address, regardless // of what the node's source IP address was (to ensure we don't try to // unicast to 0.0.0.0). memset((void*)&UDPSocketDcpt[s].remoteNode, 0xFF, sizeof(NODE_INFO)); // Transmit the packet UDPFlush(s); }
/********************************************************************* * Function: void DiscoveryTask(void) * * Summary: Announce callback task. * * PreCondition: Stack is initialized() * * Input: None * * Output: None * * Side Effects: None * * Overview: Recurring task used to listen for Discovery * messages on the specified ANNOUNCE_PORT. These * messages can be sent using the Microchip Device * Discoverer tool. If one is received, this * function will transmit a reply. * * Note: A UDP socket must be available before this * function is called. It is freed at the end of * the function. MAX_UDP_SOCKETS may need to be * increased if other modules use UDP sockets. ********************************************************************/ void DiscoveryTask(void) { static enum { DISCOVERY_HOME = 0, DISCOVERY_LISTEN, DISCOVERY_REQUEST_RECEIVED, DISCOVERY_DISABLED } DiscoverySM = DISCOVERY_HOME; static UDP_SOCKET MySocket; BYTE i; switch(DiscoverySM) { case DISCOVERY_HOME: // Open a UDP socket for inbound and outbound transmission // Since we expect to only receive broadcast packets and // only send unicast packets directly to the node we last // received from, the remote NodeInfo parameter can be anything MySocket = UDPOpen(ANNOUNCE_PORT, NULL, ANNOUNCE_PORT); if(MySocket == INVALID_UDP_SOCKET) return; else DiscoverySM++; break; case DISCOVERY_LISTEN: // Do nothing if no data is waiting if(!UDPIsGetReady(MySocket)) return; // See if this is a discovery query or reply UDPGet(&i); UDPDiscard(); if(i != 'D') return; // We received a discovery request, reply when we can DiscoverySM++; // Change the destination to the unicast address of the last received packet memcpy((void*)&UDPSocketInfo[MySocket].remoteNode, (const void*)&remoteNode, sizeof(remoteNode)); // No break needed. If we get down here, we are now ready for the DISCOVERY_REQUEST_RECEIVED state case DISCOVERY_REQUEST_RECEIVED: if(!UDPIsPutReady(MySocket)) return; // Begin sending our MAC address in human readable form. // The MAC address theoretically could be obtained from the // packet header when the computer receives our UDP packet, // however, in practice, the OS will abstract away the useful // information and it would be difficult to obtain. It also // would be lost if this broadcast packet were forwarded by a // router to a different portion of the network (note that // broadcasts are normally not forwarded by routers). UDPPutArray((BYTE*)AppConfig.NetBIOSName, sizeof(AppConfig.NetBIOSName)-1); UDPPut('\r'); UDPPut('\n'); // Convert the MAC address bytes to hex (text) and then send it i = 0; while(1) { UDPPut(btohexa_high(AppConfig.MyMACAddr.v[i])); UDPPut(btohexa_low(AppConfig.MyMACAddr.v[i])); if(++i == 6u) break; UDPPut('-'); } UDPPut('\r'); UDPPut('\n'); // Send the packet UDPFlush(); // Listen for other discovery requests DiscoverySM = DISCOVERY_LISTEN; break; case DISCOVERY_DISABLED: break; } }
/********************************************************************* 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) | +---------------------------------------------------------------+ ********************************************************************/ static BYTE _DHCPReceive(void) { BYTE v; BYTE i, j; BYTE type; BOOL lbDone; DWORD_VAL tempServerID; // Assume unknown message until proven otherwise. type = DHCP_UNKNOWN_MESSAGE; UDPGet(&v); // op //Make sure this is BOOT_REPLY. if ( v == BOOT_REPLY ) { //Discard htype, hlen, hops, xid, secs, flags, ciaddr. for ( i = 0; i < 15u; i++ ) UDPGet(&v); // Check to see if this is the first offer if(DHCPState.bits.bOfferReceived) { // Discard offered IP address, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { // Save offered IP address until we know for sure that we have it. UDPGet(&tempIPAddress.v[0]); UDPGet(&tempIPAddress.v[1]); UDPGet(&tempIPAddress.v[2]); UDPGet(&tempIPAddress.v[3]); ValidValues.bits.IPAddress = 1; } //Ignore siaddr, giaddr for ( i = 0; i < 8u; i++ ) UDPGet(&v); //Check to see if chaddr (Client Hardware Address) belongs to us. for ( i = 0; i < 6u; i++ ) { UDPGet(&v); if ( v != AppConfig.MyMACAddr.v[i]) goto UDPInvalid; } //Ignore part of chaddr, sname, file, magic cookie. for ( i = 0; i < 206u; i++ ) UDPGet(&v); 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(DHCPState.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(DHCPState.bits.bOfferReceived) { // Discard offered IP mask, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGet(&tempMask.v[0]); UDPGet(&tempMask.v[1]); UDPGet(&tempMask.v[2]); UDPGet(&tempMask.v[3]); 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(DHCPState.bits.bOfferReceived) { // Discard offered Gateway address, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGet(&tempGateway.v[0]); UDPGet(&tempGateway.v[1]); UDPGet(&tempGateway.v[2]); UDPGet(&tempGateway.v[3]); ValidValues.bits.Gateway = 1; } } else goto UDPInvalid; // Discard any other router addresses. j -= 4; while(j--) UDPGet(&v); break; #if STACK_USE_DNS case DHCP_DNS: UDPGet(&j); // Len must be >= 4. if ( j >= 4u ) { // Check to see if this is the first offer if(DHCPState.bits.bOfferReceived) { // Discard offered DNS server address, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGet(&tempDNS.v[0]); UDPGet(&tempDNS.v[1]); UDPGet(&tempDNS.v[2]); UDPGet(&tempDNS.v[3]); ValidValues.bits.DNS = 1; } } else goto UDPInvalid; // Discard any other DNS server addresses j -= 4; 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(DHCPState.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(&tempServerID.v[3]); // Get the id UDPGet(&tempServerID.v[2]); UDPGet(&tempServerID.v[1]); UDPGet(&tempServerID.v[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(DHCPState.bits.bOfferReceived) { // Discard offered lease time, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGet(&DHCPLeaseTime.v[3]); UDPGet(&DHCPLeaseTime.v[2]); UDPGet(&DHCPLeaseTime.v[1]); UDPGet(&DHCPLeaseTime.v[0]); // Due to possible timing delays, consider actual lease // time less by half hour. if ( DHCPLeaseTime.Val > HALF_HOUR ) DHCPLeaseTime.Val = DHCPLeaseTime.Val - HALF_HOUR; } } else goto UDPInvalid; break; default: // Ignore all unsupport tags. UDPGet(&j); // Get option len while( j-- ) // Ignore option values UDPGet(&v); } } while( !lbDone ); } // If this is an OFFER message, remember current server id. if ( type == DHCP_OFFER_MESSAGE ) { DHCPServerID.Val = tempServerID.Val; DHCPState.bits.bOfferReceived = TRUE; } else { // For other types of messages, make sure that received // server id matches with our previous one. if ( DHCPServerID.Val != tempServerID.Val ) type = DHCP_UNKNOWN_MESSAGE; } UDPDiscard(); // We are done with this packet return type; UDPInvalid: UDPDiscard(); return DHCP_UNKNOWN_MESSAGE; }
/***************************************************************************** Function: BOOL DNSIsResolved(IP_ADDR* HostIP) Summary: Determines if the DNS resolution is complete and provides the IP. Description: Call this function to determine if the DNS resolution of an address has been completed. If so, the resolved address will be provided in HostIP. Precondition: DNSResolve or DNSResolveROM has been called. Parameters: HostIP - A pointer to an IP_ADDR structure in which to store the resolved IP address once resolution is complete. Return Values: TRUE - The DNS client has obtained an IP, or the DNS process has encountered an error. HostIP will be 0.0.0.0 on error. Possible errors include server timeout (i.e. DNS server not available), hostname not in the DNS, or DNS server errors. FALSE - The resolution process is still in progress. ***************************************************************************/ BOOL DNSIsResolved(IP_ADDR* HostIP) { static DWORD StartTime; static WORD_VAL SentTransactionID __attribute__((persistent)); static BYTE vARPAttemptCount; static BYTE vDNSAttemptCount; BYTE i; WORD_VAL w; DNS_HEADER DNSHeader; DNS_ANSWER_HEADER DNSAnswerHeader; switch(smDNS) { case DNS_START: vARPAttemptCount = 0; vDNSAttemptCount = 0; // No break; case DNS_ARP_START_RESOLVE: ARPResolve(&AppConfig.PrimaryDNSServer); vARPAttemptCount++; StartTime = TickGet(); smDNS = DNS_ARP_RESOLVE; break; case DNS_ARP_RESOLVE: if(!ARPIsResolved(&AppConfig.PrimaryDNSServer, &ResolvedInfo.MACAddr)) { if(TickGet() - StartTime > DNS_TIMEOUT) smDNS = (vARPAttemptCount >= 3u) ? DNS_FAIL : DNS_ARP_START_RESOLVE; break; } ResolvedInfo.IPAddr.Val = AppConfig.PrimaryDNSServer.Val; smDNS = DNS_OPEN_SOCKET; // No break: DNS_OPEN_SOCKET is the correct next state case DNS_OPEN_SOCKET: MySocket = UDPOpen(0, &ResolvedInfo, DNS_PORT); if(MySocket == INVALID_UDP_SOCKET) break; smDNS = DNS_QUERY; // No need to break, we can immediately start resolution case DNS_QUERY: if(!UDPIsPutReady(MySocket)) break; // Put DNS query here SentTransactionID.Val++; UDPPut(SentTransactionID.v[1]);// User chosen transaction ID UDPPut(SentTransactionID.v[0]); UDPPut(0x01); // Standard query with recursion UDPPut(0x00); UDPPut(0x00); // 0x0001 questions UDPPut(0x01); UDPPut(0x00); // 0x0000 answers UDPPut(0x00); UDPPut(0x00); // 0x0000 name server resource records UDPPut(0x00); UDPPut(0x00); // 0x0000 additional records UDPPut(0x00); // Put hostname string to resolve if(DNSHostName) DNSPutString(DNSHostName); else DNSPutROMString(DNSHostNameROM); UDPPut(0x00); // Type: DNS_TYPE_A A (host address) or DNS_TYPE_MX for mail exchange UDPPut(RecordType); UDPPut(0x00); // Class: IN (Internet) UDPPut(0x01); UDPFlush(); StartTime = TickGet(); smDNS = DNS_GET_RESULT; break; case DNS_GET_RESULT: if(!UDPIsGetReady(MySocket)) { if(TickGet() - StartTime > DNS_TIMEOUT) smDNS = DNS_FAIL; break; } // Retrieve the DNS header and de-big-endian it UDPGet(&DNSHeader.TransactionID.v[1]); UDPGet(&DNSHeader.TransactionID.v[0]); // Throw this packet away if it isn't in response to our last query if(DNSHeader.TransactionID.Val != SentTransactionID.Val) { UDPDiscard(); break; } UDPGet(&DNSHeader.Flags.v[1]); UDPGet(&DNSHeader.Flags.v[0]); UDPGet(&DNSHeader.Questions.v[1]); UDPGet(&DNSHeader.Questions.v[0]); UDPGet(&DNSHeader.Answers.v[1]); UDPGet(&DNSHeader.Answers.v[0]); UDPGet(&DNSHeader.AuthoritativeRecords.v[1]); UDPGet(&DNSHeader.AuthoritativeRecords.v[0]); UDPGet(&DNSHeader.AdditionalRecords.v[1]); UDPGet(&DNSHeader.AdditionalRecords.v[0]); // Remove all questions (queries) while(DNSHeader.Questions.Val--) { DNSDiscardName(); UDPGet(&w.v[1]); // Question type UDPGet(&w.v[0]); UDPGet(&w.v[1]); // Question class UDPGet(&w.v[0]); } // Scan through answers while(DNSHeader.Answers.Val--) { DNSDiscardName(); // Throw away response name UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(&DNSAnswerHeader.ResponseType.v[0]); UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(&DNSAnswerHeader.ResponseClass.v[0]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(&DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A or MX, class 1 // Check if this is Type A or MX if( DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseClass.Val == 0x0001u && // Internet class DNSAnswerHeader.ResponseLen.Val == 0x0004u) { Flags.bits.AddressValid = TRUE; UDPGet(&ResolvedInfo.IPAddr.v[0]); UDPGet(&ResolvedInfo.IPAddr.v[1]); UDPGet(&ResolvedInfo.IPAddr.v[2]); UDPGet(&ResolvedInfo.IPAddr.v[3]); goto DoneSearchingRecords; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(&i); } } } // Remove all Authoritative Records while(DNSHeader.AuthoritativeRecords.Val--) { DNSDiscardName(); // Throw away response name UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(&DNSAnswerHeader.ResponseType.v[0]); UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(&DNSAnswerHeader.ResponseClass.v[0]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(&DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A or MX, class 1 // Check if this is Type A if( DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseClass.Val == 0x0001u && // Internet class DNSAnswerHeader.ResponseLen.Val == 0x0004u) { Flags.bits.AddressValid = TRUE; UDPGet(&ResolvedInfo.IPAddr.v[0]); UDPGet(&ResolvedInfo.IPAddr.v[1]); UDPGet(&ResolvedInfo.IPAddr.v[2]); UDPGet(&ResolvedInfo.IPAddr.v[3]); goto DoneSearchingRecords; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(&i); } } } // Remove all Additional Records while(DNSHeader.AdditionalRecords.Val--) { DNSDiscardName(); // Throw away response name UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(&DNSAnswerHeader.ResponseType.v[0]); UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(&DNSAnswerHeader.ResponseClass.v[0]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(&DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A or MX, class 1 // Check if this is Type A if( DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseClass.Val == 0x0001u && // Internet class DNSAnswerHeader.ResponseLen.Val == 0x0004u) { Flags.bits.AddressValid = TRUE; UDPGet(&ResolvedInfo.IPAddr.v[0]); UDPGet(&ResolvedInfo.IPAddr.v[1]); UDPGet(&ResolvedInfo.IPAddr.v[2]); UDPGet(&ResolvedInfo.IPAddr.v[3]); goto DoneSearchingRecords; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(&i); } } } DoneSearchingRecords: UDPDiscard(); UDPClose(MySocket); MySocket = INVALID_UDP_SOCKET; smDNS = DNS_DONE; // No break, DNS_DONE is the correct step case DNS_DONE: // Return 0.0.0.0 if DNS resolution failed, otherwise return the // resolved IP address if(!Flags.bits.AddressValid) ResolvedInfo.IPAddr.Val = 0; HostIP->Val = ResolvedInfo.IPAddr.Val; return TRUE; case DNS_FAIL: // If 3 attempts or more, quit if(vDNSAttemptCount >= 2u) { // Return an invalid IP address 0.0.0.0 if we can't finish ARP or DNS query step HostIP->Val = 0x00000000; return TRUE; } vDNSAttemptCount++; // Swap primary and secondary DNS servers if there is a secondary DNS server programmed if(AppConfig.SecondaryDNSServer.Val) { AppConfig.PrimaryDNSServer.Val ^= AppConfig.SecondaryDNSServer.Val; AppConfig.SecondaryDNSServer.Val ^= AppConfig.PrimaryDNSServer.Val; AppConfig.PrimaryDNSServer.Val ^= AppConfig.SecondaryDNSServer.Val; // Start another ARP resolution for the secondary server (now primary) vARPAttemptCount = 0; if(MySocket != INVALID_UDP_SOCKET) { UDPClose(MySocket); MySocket = INVALID_UDP_SOCKET; } smDNS = DNS_ARP_START_RESOLVE; } break; } return FALSE; }
/***************************************************************************** Function: void DNSClientTask(void) Summary: DNS client state machine Description: Process the DNS client state machine Precondition: DNSClientInit has been called. Parameters: None Return Values: None ***************************************************************************/ void DNSClientTask(void) { uint8_t i; TCPIP_UINT16_VAL w; DNS_HEADER DNSHeader; DNS_ANSWER_HEADER DNSAnswerHeader; switch(smDNS) { case DNS_IDLE: break; // nothing to do case DNS_START: smDNS = DNSRetry(DNS_START); stateStartTime = 0; // flag the first Open try break; case DNS_OPEN_SOCKET: DNSSocket = UDPOpenClient(IP_ADDRESS_TYPE_IPV4, DNS_CLIENT_PORT, (IP_MULTI_ADDRESS*)(DNSServers + vDNSServerIx)); if(DNSSocket == INVALID_UDP_SOCKET) { if(stateStartTime == 0) { stateStartTime = SYS_TICK_Get(); } else if(SYS_TICK_Get() - stateStartTime > (DNS_CLIENT_OPEN_TMO * SYS_TICK_TicksPerSecondGet())) { smDNS = DNS_FAIL_OPEN_TMO; } break; } // got a valid UDP socket UDPSocketSetNet(DNSSocket, pDNSNet); stateStartTime = SYS_TICK_Get(); smDNS = DNS_QUERY; // no break, start sending the query; case DNS_QUERY: if(!UDPIsOpened(DNSSocket) || (UDPIsTxPutReady(DNSSocket, 18 + strlen (DNSHostName)) < (18 + strlen (DNSHostName)))) { if(SYS_TICK_Get() - stateStartTime > (DNS_CLIENT_OPEN_TMO * SYS_TICK_TicksPerSecondGet())) { smDNS = DNS_FAIL_OPEN_TMO; } break; // wait some more } // Put DNS query here SentTransactionID.Val = (uint16_t)rand(); UDPPut(DNSSocket, SentTransactionID.v[1]);// User chosen transaction ID UDPPut(DNSSocket, SentTransactionID.v[0]); UDPPut(DNSSocket, 0x01); // Standard query with recursion UDPPut(DNSSocket, 0x00); UDPPut(DNSSocket, 0x00); // 0x0001 questions UDPPut(DNSSocket, 0x01); UDPPut(DNSSocket, 0x00); // 0x0000 answers UDPPut(DNSSocket, 0x00); UDPPut(DNSSocket, 0x00); // 0x0000 name server resource records UDPPut(DNSSocket, 0x00); UDPPut(DNSSocket, 0x00); // 0x0000 additional records UDPPut(DNSSocket, 0x00); // Put hostname string to resolve DNSPutString(DNSSocket, DNSHostName); UDPPut(DNSSocket, 0x00); // Type: DNS_TYPE_A A (host address) or DNS_TYPE_MX for mail exchange UDPPut(DNSSocket, RecordType); UDPPut(DNSSocket, 0x00); // Class: IN (Internet) UDPPut(DNSSocket, 0x01); UDPFlush(DNSSocket); stateStartTime = SYS_TICK_Get(); smDNS = DNS_GET_RESULT; break; case DNS_GET_RESULT: if(!UDPIsGetReady(DNSSocket)) { if(SYS_TICK_Get() - stateStartTime > (DNS_CLIENT_SERVER_TMO * SYS_TICK_TicksPerSecondGet())) { smDNS = DNS_FAIL_SERVER; } break; } // Retrieve the DNS header and de-big-endian it UDPGet(DNSSocket, &DNSHeader.TransactionID.v[1]); UDPGet(DNSSocket, &DNSHeader.TransactionID.v[0]); // Throw this packet away if it isn't in response to our last query if(DNSHeader.TransactionID.Val != SentTransactionID.Val) { UDPDiscard(DNSSocket); break; } UDPGet(DNSSocket, &DNSHeader.Flags.v[1]); UDPGet(DNSSocket, &DNSHeader.Flags.v[0]); UDPGet(DNSSocket, &DNSHeader.Questions.v[1]); UDPGet(DNSSocket, &DNSHeader.Questions.v[0]); UDPGet(DNSSocket, &DNSHeader.Answers.v[1]); UDPGet(DNSSocket, &DNSHeader.Answers.v[0]); UDPGet(DNSSocket, &DNSHeader.AuthoritativeRecords.v[1]); UDPGet(DNSSocket, &DNSHeader.AuthoritativeRecords.v[0]); UDPGet(DNSSocket, &DNSHeader.AdditionalRecords.v[1]); UDPGet(DNSSocket, &DNSHeader.AdditionalRecords.v[0]); // Remove all questions (queries) while(DNSHeader.Questions.Val--) { DNSDiscardName(DNSSocket); UDPGet(DNSSocket, &w.v[1]); // Question type UDPGet(DNSSocket, &w.v[0]); UDPGet(DNSSocket, &w.v[1]); // Question class UDPGet(DNSSocket, &w.v[0]); } // Scan through answers while(DNSHeader.Answers.Val--) { DNSDiscardName(DNSSocket); // Throw away response name UDPGet(DNSSocket, &DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(DNSSocket, &DNSAnswerHeader.ResponseType.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(DNSSocket, &DNSAnswerHeader.ResponseClass.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(DNSSocket, &DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A or MX, class 1 // Check if this is Type A, MX, or AAAA if( DNSAnswerHeader.ResponseClass.Val == 0x0001u) // Internet class { if (DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseLen.Val == 0x0004u) { Flags.bits.AddressValid = true; Flags.bits.AddressType = IP_ADDRESS_TYPE_IPV4; UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[0]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[1]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[2]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[3]); goto DoneSearchingRecords; } else if (DNSAnswerHeader.ResponseType.Val == 0x001Cu && DNSAnswerHeader.ResponseLen.Val == 0x0010u) { if (RecordType != DNS_TYPE_AAAA) { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } break; } Flags.bits.AddressValid = true; Flags.bits.AddressType = IP_ADDRESS_TYPE_IPV6; UDPGetArray (DNSSocket, (void *)&ResolvedAddress.ipv6Address, sizeof (IPV6_ADDR)); goto DoneSearchingRecords; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } } } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } } } // Remove all Authoritative Records while(DNSHeader.AuthoritativeRecords.Val--) { DNSDiscardName(DNSSocket); // Throw away response name UDPGet(DNSSocket, &DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(DNSSocket, &DNSAnswerHeader.ResponseType.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(DNSSocket, &DNSAnswerHeader.ResponseClass.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(DNSSocket, &DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A or MX, class 1 // Check if this is Type A if( DNSAnswerHeader.ResponseClass.Val == 0x0001u) // Internet class { if (DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseLen.Val == 0x0004u) { Flags.bits.AddressValid = true; Flags.bits.AddressType = IP_ADDRESS_TYPE_IPV4; UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[0]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[1]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[2]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[3]); goto DoneSearchingRecords; } else if (DNSAnswerHeader.ResponseType.Val == 0x001Cu && DNSAnswerHeader.ResponseLen.Val == 0x0010u) { if (RecordType != DNS_TYPE_AAAA) { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } break; } Flags.bits.AddressValid = true; Flags.bits.AddressType = IP_ADDRESS_TYPE_IPV6; UDPGetArray (DNSSocket, (void *)&ResolvedAddress.ipv6Address, sizeof (IPV6_ADDR)); goto DoneSearchingRecords; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } } } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } } } // Remove all Additional Records while(DNSHeader.AdditionalRecords.Val--) { DNSDiscardName(DNSSocket); // Throw away response name UDPGet(DNSSocket, &DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(DNSSocket, &DNSAnswerHeader.ResponseType.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(DNSSocket, &DNSAnswerHeader.ResponseClass.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(DNSSocket, &DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A or MX, class 1 // Check if this is Type A if( DNSAnswerHeader.ResponseClass.Val == 0x0001u) // Internet class { if (DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseLen.Val == 0x0004u) { Flags.bits.AddressValid = true; Flags.bits.AddressType = IP_ADDRESS_TYPE_IPV4; UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[0]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[1]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[2]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[3]); goto DoneSearchingRecords; } else if (DNSAnswerHeader.ResponseType.Val == 0x001Cu && DNSAnswerHeader.ResponseLen.Val == 0x0010u) { if (RecordType != DNS_TYPE_AAAA) { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } break; } Flags.bits.AddressValid = true; Flags.bits.AddressType = IP_ADDRESS_TYPE_IPV6; UDPGetArray (DNSSocket, (void *)&ResolvedAddress.ipv6Address, sizeof (IPV6_ADDR)); goto DoneSearchingRecords; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } } } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } } } DoneSearchingRecords: UDPDiscard(DNSSocket); _DNSReleaseSocket(); if(Flags.bits.AddressValid) { smDNS = DNS_DONE; } else { smDNS = DNSRetry(DNS_FAIL_SERVER); } break; // done case DNS_FAIL_ARP: // see if there is other server we may try smDNS = DNSRetry(DNS_FAIL_ARP); break; case DNS_FAIL_SERVER: smDNS = DNSRetry(DNS_FAIL_SERVER); break; default: // DNS_DONE, DNS_FAIL_ARP_TMO, DNS_FAIL_OPEN_TMO, DNS_FAIL_SERVER_TMO // either done or some error state break; } #if DNS_CLIENT_VERSION_NO >= 2 dnsTickPending = 0; #endif // DNS_CLIENT_VERSION_NO >= 2 }
/** * Call DNSIsResolved() until the host is resolved. * You cannot start two DNS resolution proceedures concurrently. * You must not modify *Hostname until DNSIsResolved() returns TRUE. * * @preCondition DNSResolve() was called. * * @param HostIP 4 byte IP address */ BOOL DNSIsResolved(IP_ADDR *HostIP) { static UDP_SOCKET MySocket; static NODE_INFO Remote; static TICK StartTime; BYTE i; WORD_VAL w; DNS_HEADER DNSHeader; DNS_ANSWER_HEADER DNSAnswerHeader; IP_ADDR tmpIpAddr; switch(smDNS) { case DNS_HOME: tmpIpAddr.v[0] = MY_DNS_BYTE1; tmpIpAddr.v[1] = MY_DNS_BYTE2; tmpIpAddr.v[2] = MY_DNS_BYTE3; tmpIpAddr.v[3] = MY_DNS_BYTE4; ARPResolve(&tmpIpAddr); StartTime = TickGet(); smDNS++; break; case DNS_RESOLVE_ARP: if(!ARPIsResolved(&tmpIpAddr, &Remote.MACAddr)) { if(TickGet() - StartTime > DNS_TIMEOUT) { smDNS--; } break; } Remote.IPAddr.Val = tmpIpAddr.Val; smDNS++; // No need to break, we can immediately start resolution case DNS_OPEN_SOCKET: MySocket = UDPOpen(0, &Remote, DNS_PORT); if(MySocket == INVALID_UDP_SOCKET) { #if (DEBUG_DNS >= LOG_ERROR) debugPutMsg(1); //@mxd:1:Could not open UDP socket #endif break; } smDNS++; // No need to break, we can immediately start resolution case DNS_QUERY: if(!UDPIsPutReady(MySocket)) break; // Put DNS query here UDPPut(0x12); // User chosen ID UDPPut(0x34); UDPPut(0x01); // Standard query with recursion UDPPut(0x00); UDPPut(0x00); // 0x0001 questions UDPPut(0x01); UDPPut(0x00); // 0x0000 answers UDPPut(0x00); UDPPut(0x00); // 0x0000 name server resource records UDPPut(0x00); UDPPut(0x00); // 0x0000 additional records UDPPut(0x00); // Put hostname string to resolve DNSPutString(DNSHostName); UDPPut(0x00); // Type: A (host address) UDPPut(0x01); UDPPut(0x00); // Class: IN (Internet) UDPPut(0x01); UDPFlush(); StartTime = TickGet(); smDNS++; break; case DNS_GET_RESULT: if(!UDPIsGetReady(MySocket)) { if(TickGet() - StartTime > DNS_TIMEOUT) { smDNS--; } break; } // Retrieve the DNS header and de-big-endian it UDPGet(&DNSHeader.TransactionID.v[1]); UDPGet(&DNSHeader.TransactionID.v[0]); UDPGet(&DNSHeader.Flags.v[1]); UDPGet(&DNSHeader.Flags.v[0]); UDPGet(&DNSHeader.Questions.v[1]); UDPGet(&DNSHeader.Questions.v[0]); UDPGet(&DNSHeader.Answers.v[1]); UDPGet(&DNSHeader.Answers.v[0]); UDPGet(&DNSHeader.AuthoritativeRecords.v[1]); UDPGet(&DNSHeader.AuthoritativeRecords.v[0]); UDPGet(&DNSHeader.AdditionalRecords.v[1]); UDPGet(&DNSHeader.AdditionalRecords.v[0]); // Remove all questions while(DNSHeader.Questions.Val--) { DNSGetString(NULL); UDPGet(&w.v[1]); // Question type UDPGet(&w.v[0]); UDPGet(&w.v[1]); // Question class UDPGet(&w.v[0]); } // Scan through answers while(DNSHeader.Answers.Val--) { UDPGet(&DNSAnswerHeader.ResponseName.v[1]); // Response name UDPGet(&DNSAnswerHeader.ResponseName.v[0]); UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(&DNSAnswerHeader.ResponseType.v[0]); UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(&DNSAnswerHeader.ResponseClass.v[0]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(&DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A, class 1 // Check if this is Type A if( DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseClass.Val == 0x0001u && // Internet class DNSAnswerHeader.ResponseLen.Val == 0x0004u) { UDPGet(&HostIP->v[0]); UDPGet(&HostIP->v[1]); UDPGet(&HostIP->v[2]); UDPGet(&HostIP->v[3]); break; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(&i); } } } UDPDiscard(); UDPClose(MySocket); MySocket = INVALID_UDP_SOCKET; smDNS++; // No need to break, we are done and need to return TRUE case DNS_DONE: return TRUE; } return FALSE; }
/********************************************************************* * Function: void ANNOUNCE_Task(void) * * Summary: Announce callback task. * * PreCondition: Stack is initialized() * * Input: None * * Output: None * * Side Effects: None * * Overview: Recurring task used to listen for Discovery * messages on the specified ANNOUNCE_PORT. These * messages can be sent using the TCP/IP * Discoverer tool. If one is received, this * function will transmit a reply. * * Note: A UDP socket must be available before this * function is called. It is freed at the end of * the function. UDP_MAX_SOCKETS may need to be * increased if other modules use UDP sockets. ********************************************************************/ void ANNOUNCE_Task(NET_CONFIG * pNetIf) { static enum { DISCOVERY_HOME = 0, DISCOVERY_LISTEN, DISCOVERY_REQUEST_RECEIVED, DISCOVERY_DISABLED } DiscoverySM[TCPIP_NETWORK_INTERFACES] = {DISCOVERY_HOME}; static UDP_SOCKET MySocket[TCPIP_NETWORK_INTERFACES]; uint8_t i; int netIx; UDP_SOCKET s; if(!pNetIf) { return; } else { netIx = _TCPIPStackNetIx(pNetIf); } s = MySocket[netIx]; switch(DiscoverySM[netIx]) { case DISCOVERY_HOME: // Open a UDP socket for inbound and outbound transmission // Since we expect to only receive broadcast packets and // only send unicast packets directly to the node we last // received from, the remote NodeInfo parameter can be anything MySocket[netIx] = UDPOpen(0,UDP_OPEN_SERVER,ANNOUNCE_PORT, ANNOUNCE_PORT); if(MySocket[netIx] == INVALID_UDP_SOCKET) { return; } else { DiscoverySM[netIx]++; UDPSocketSetNet(MySocket[netIx], pNetIf); } break; case DISCOVERY_LISTEN: // Do nothing if no data is waiting if(!UDPIsGetReady(s)) return; // See if this is a discovery query or reply UDPGet(s, &i); UDPDiscard(s); if(i != 'D') return; // We received a discovery request, reply when we can DiscoverySM[netIx]++; // Change the destination to the unicast address of the last received packet TCPIP_IPV4_SetDestAddress(UDPSocketDcpt[s].pTxPkt,remoteNode.IPAddr.Val); memcpy((void*)&UDPSocketDcpt[s].pTxPkt->remoteMACAddr, (const void*)&remoteNode.MACAddr, sizeof(MAC_ADDR)); // No break needed. If we get down here, we are now ready for the DISCOVERY_REQUEST_RECEIVED state case DISCOVERY_REQUEST_RECEIVED: ANNOUNCE_Notify (pNetIf, 0, NULL); // Listen for other discovery requests DiscoverySM[netIx] = DISCOVERY_LISTEN; break; case DISCOVERY_DISABLED: break; } }
/********************************************************************* * Function: void NBNSTask(void) * * PreCondition: None * * Input: None * * Output: Sends responses to NetBIOS name requests * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ void NBNSTask(void) { static UDP_SOCKET MySocket; BYTE i; WORD_VAL Type, Class; NBNS_HEADER NBNSHeader; BYTE NameString[16]; static enum { NBNS_HOME = 0, NBNS_OPEN_SOCKET, NBNS_LISTEN } smNBNS = NBNS_HOME; switch(smNBNS) { case NBNS_HOME: smNBNS++; break; case NBNS_OPEN_SOCKET: MySocket = UDPOpen(NBNS_PORT, NULL, NBNS_PORT); if(MySocket == INVALID_UDP_SOCKET) break; smNBNS++; case NBNS_LISTEN: if(!UDPIsGetReady(MySocket)) break; // Respond only to name requests sent to us from nodes on the same subnet // This prevents us from sending out the wrong IP address information if // we haven't gotten a DHCP lease yet. if((remoteNode.IPAddr.Val & AppConfig.MyMask.Val) != (AppConfig.MyIPAddr.Val & AppConfig.MyMask.Val)) { UDPDiscard(); break; } // Retrieve the NBNS header and de-big-endian it UDPGet(&NBNSHeader.TransactionID.v[1]); UDPGet(&NBNSHeader.TransactionID.v[0]); UDPGet(&NBNSHeader.Flags.v[1]); UDPGet(&NBNSHeader.Flags.v[0]); UDPGet(&NBNSHeader.Questions.v[1]); UDPGet(&NBNSHeader.Questions.v[0]); UDPGet(&NBNSHeader.Answers.v[1]); UDPGet(&NBNSHeader.Answers.v[0]); UDPGet(&NBNSHeader.AuthoritativeRecords.v[1]); UDPGet(&NBNSHeader.AuthoritativeRecords.v[0]); UDPGet(&NBNSHeader.AdditionalRecords.v[1]); UDPGet(&NBNSHeader.AdditionalRecords.v[0]); // Remove all questions while(NBNSHeader.Questions.Val--) { NBNSGetName(NameString); UDPGet(&i); // <??> Trailing character on string UDPGet(&Type.v[1]); // Question type UDPGet(&Type.v[0]); UDPGet(&Class.v[1]); // Question class UDPGet(&Class.v[0]); if(Type.Val == 0x0020u && Class.Val == 0x0001u && strcmp((char*)NameString, (char*)AppConfig.NetBIOSName) == 0) { while(!UDPIsPutReady(MySocket)); NBNSHeader.Flags.Val = 0x8400; UDPPut(NBNSHeader.TransactionID.v[1]); UDPPut(NBNSHeader.TransactionID.v[0]); UDPPut(NBNSHeader.Flags.v[1]); UDPPut(NBNSHeader.Flags.v[0]); UDPPut(0x00); // 0x0000 Questions UDPPut(0x00); UDPPut(0x00); // 0x0001 Answers UDPPut(0x01); UDPPut(0x00); // 0x0000 Athoritative records UDPPut(0x00); UDPPut(0x00); // 0x0000 Additional records UDPPut(0x00); NBNSPutName(AppConfig.NetBIOSName); UDPPut(0x00); // 0x0020 Type: NetBIOS UDPPut(0x20); UDPPut(0x00); // 0x0001 Class: Internet UDPPut(0x01); UDPPut(0x00); // 0x00000000 Time To Live UDPPut(0x00); UDPPut(0x00); UDPPut(0x00); UDPPut(0x00); // 0x0006 Data length UDPPut(0x06); UDPPut(0x60); // 0x6000 Flags: H-node, Unique UDPPut(0x00); UDPPut(AppConfig.MyIPAddr.v[0]); // Put out IP address UDPPut(AppConfig.MyIPAddr.v[1]); UDPPut(AppConfig.MyIPAddr.v[2]); UDPPut(AppConfig.MyIPAddr.v[3]); // Change the destination address to the unicast address of the last received packet memcpy((void*)&UDPSocketInfo[MySocket].remoteNode, (const void*)&remoteNode, sizeof(remoteNode)); UDPFlush(); } } UDPDiscard(); break; } }
/********************************************************************* * Function: void NBNSTask(NET_CONFIG* pConfig) * * PreCondition: None * * Input: pConfig - interface * * Output: None * * Side Effects: None * * Overview: Sends responses to NetBIOS name requests * * Note: None ********************************************************************/ void NBNSTask(NET_CONFIG* pConfig) { uint8_t i; TCPIP_UINT16_VAL Type, Class; NBNS_HEADER NBNSHeader; uint8_t NameString[16]; int netIx; UDP_SOCKET s; netIx = _TCPIPStackNetIx(pConfig); s = MySocket[netIx]; switch(smNBNS[netIx]) { case NBNS_HOME: smNBNS[netIx]++; break; case NBNS_OPEN_SOCKET: MySocket[netIx] = UDPOpen(0,UDP_OPEN_SERVER,NBNS_PORT,NBNS_PORT); if(MySocket[netIx] == INVALID_UDP_SOCKET) break; UDPSocketSetNet(MySocket[netIx], pConfig); smNBNS[netIx]++; case NBNS_LISTEN: if(!UDPIsGetReady(s)) { break; } // Respond only to name requests sent to us from nodes on the same subnet // This prevents us from sending out the wrong IP address information if // we haven't gotten a DHCP lease yet. if((remoteNode.IPAddr.Val & pConfig->MyMask.Val) != (pConfig->MyIPAddr.Val & pConfig->MyMask.Val)) { UDPDiscard(s); break; } // Retrieve the NBNS header and de-big-endian it UDPGet(s, &NBNSHeader.TransactionID.v[1]); UDPGet(s, &NBNSHeader.TransactionID.v[0]); UDPGet(s, &NBNSHeader.Flags.v[1]); UDPGet(s, &NBNSHeader.Flags.v[0]); UDPGet(s, &NBNSHeader.Questions.v[1]); UDPGet(s, &NBNSHeader.Questions.v[0]); UDPGet(s, &NBNSHeader.Answers.v[1]); UDPGet(s, &NBNSHeader.Answers.v[0]); UDPGet(s, &NBNSHeader.AuthoritativeRecords.v[1]); UDPGet(s, &NBNSHeader.AuthoritativeRecords.v[0]); UDPGet(s, &NBNSHeader.AdditionalRecords.v[1]); UDPGet(s, &NBNSHeader.AdditionalRecords.v[0]); // Remove all questions while(NBNSHeader.Questions.Val--) { NBNSGetName(s, NameString); UDPGet(s, &i); // <??> Trailing character on string UDPGet(s, &Type.v[1]); // Question type UDPGet(s, &Type.v[0]); UDPGet(s, &Class.v[1]); // Question class UDPGet(s, &Class.v[0]); if(Type.Val == 0x0020u && Class.Val == 0x0001u && memcmp((void*)NameString, (void*)pConfig->NetBIOSName, sizeof(pConfig->NetBIOSName)) == 0) { if(UDPIsTxPutReady(s, 64)) { NBNSHeader.Flags.Val = 0x8400; UDPPut(s, NBNSHeader.TransactionID.v[1]); UDPPut(s, NBNSHeader.TransactionID.v[0]); UDPPut(s, NBNSHeader.Flags.v[1]); UDPPut(s, NBNSHeader.Flags.v[0]); UDPPut(s, 0x00); // 0x0000 Questions UDPPut(s, 0x00); UDPPut(s, 0x00); // 0x0001 Answers UDPPut(s, 0x01); UDPPut(s, 0x00); // 0x0000 Athoritative records UDPPut(s, 0x00); UDPPut(s, 0x00); // 0x0000 Additional records UDPPut(s, 0x00); NBNSPutName(s, pConfig->NetBIOSName); UDPPut(s, 0x00); // 0x0020 Type: NetBIOS UDPPut(s, 0x20); UDPPut(s, 0x00); // 0x0001 Class: Internet UDPPut(s, 0x01); UDPPut(s, 0x00); // 0x00000000 Time To Live UDPPut(s, 0x00); UDPPut(s, 0x00); UDPPut(s, 0x00); UDPPut(s, 0x00); // 0x0006 Data length UDPPut(s, 0x06); UDPPut(s, 0x60); // 0x6000 Flags: H-node, Unique UDPPut(s, 0x00); UDPPut(s, pConfig->MyIPAddr.v[0]); // Put out IP address UDPPut(s, pConfig->MyIPAddr.v[1]); UDPPut(s, pConfig->MyIPAddr.v[2]); UDPPut(s, pConfig->MyIPAddr.v[3]); // Change the destination address to the unicast address of the last received packet TCPIP_IPV4_SetDestAddress(UDPSocketDcpt[s].pTxPkt,remoteNode.IPAddr.Val); memcpy((void*)&UDPSocketDcpt[s].pTxPkt->remoteMACAddr, (const void*)&remoteNode.MACAddr, sizeof(remoteNode.MACAddr)); UDPFlush(s); } } } UDPDiscard(s); break; } }
/***************************************************************************** Function: static void DHCPReplyToRequest(BOOTP_HEADER *Header, BOOL bAccept) Summary: Replies to a DHCP Request message. Description: This function replies to a DHCP Request message by sending out a DHCP Acknowledge message. Precondition: None Parameters: Header - the BootP header this is in response to. bAccept - whether or not we've accepted this request Returns: None Internal: Needs to support more than one simultaneous lease in the future. ***************************************************************************/ static void DHCPReplyToRequest(BOOTP_HEADER *Header, BOOL bAccept) { BYTE i; // Set the correct socket to active and ensure that // enough space is available to generate the DHCP response if(UDPIsPutReady(MySocket) < 300u) return; // Search through all remaining options and look for the Requested IP address field // Obtain options while(UDPIsGetReady(MySocket)) { BYTE Option, Len; DWORD dw; // Get option type if(!UDPGet(&Option)) break; if(Option == DHCP_END_OPTION) break; // Get option length UDPGet(&Len); // Process option if((Option == DHCP_PARAM_REQUEST_IP_ADDRESS) && (Len == 4u)) { // Get the requested IP address and see if it is the one we have on offer. If not, we should send back a NAK, but since there could be some other DHCP server offering this address, we'll just silently ignore this request. UDPGetArray((BYTE*)&dw, 4); Len -= 4; if(dw != DHCPNextLease.Val) { bAccept = FALSE; } break; } // Remove the unprocessed bytes that we don't care about while(Len--) { UDPGet(&i); } } #if defined(STACK_USE_DHCP_CLIENT) // Someone is using our DHCP server, start using a static // IP address and update the bind count so it displays on // the LCD AppConfig.Flags.bInConfigMode = FALSE; DHCPBindCount++; #endif // Begin putting the BOOTP Header and DHCP options UDPPut(BOOT_REPLY); // Message Type: 2 (BOOTP Reply) // Reply with the same Hardware Type, Hardware Address Length, Hops, and Transaction ID fields UDPPutArray((BYTE*)&(Header->HardwareType), 7); UDPPut(0x00); // Seconds Elapsed: 0 (Not used) UDPPut(0x00); // Seconds Elapsed: 0 (Not used) UDPPutArray((BYTE*)&(Header->BootpFlags), sizeof(Header->BootpFlags)); UDPPutArray((BYTE*)&(Header->ClientIP), sizeof(IP_ADDR));// Your (client) IP Address: UDPPutArray((BYTE*)&DHCPNextLease, sizeof(IP_ADDR)); // Lease IP address to give out UDPPut(0x00); // Next Server IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Next Server IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Next Server IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Next Server IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Relay Agent IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Relay Agent IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Relay Agent IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Relay Agent IP Address: 0.0.0.0 (not used) UDPPutArray((BYTE*)&(Header->ClientMAC), sizeof(MAC_ADDR)); // Client MAC address: Same as given by client for(i = 0; i < 64+128+(16-sizeof(MAC_ADDR)); i++) // Remaining 10 bytes of client hardware address, server host name: Null string (not used) UDPPut(0x00); // Boot filename: Null string (not used) UDPPut(0x63); // Magic Cookie: 0x63538263 UDPPut(0x82); // Magic Cookie: 0x63538263 UDPPut(0x53); // Magic Cookie: 0x63538263 UDPPut(0x63); // Magic Cookie: 0x63538263 // Options: DHCP lease ACKnowledge if(bAccept) { UDPPut(DHCP_OPTION_ACK_MESSAGE); UDPPut(1); UDPPut(DHCP_ACK_MESSAGE); } else // Send a NACK { UDPPut(DHCP_OPTION_ACK_MESSAGE); UDPPut(1); UDPPut(DHCP_NAK_MESSAGE); } // Option: Lease duration UDPPut(DHCP_IP_LEASE_TIME); UDPPut(4); UDPPut((DHCP_LEASE_DURATION>>24) & 0xFF); UDPPut((DHCP_LEASE_DURATION>>16) & 0xFF); UDPPut((DHCP_LEASE_DURATION>>8) & 0xFF); UDPPut((DHCP_LEASE_DURATION) & 0xFF); // Option: Server identifier UDPPut(DHCP_SERVER_IDENTIFIER); UDPPut(sizeof(IP_ADDR)); UDPPutArray((BYTE*)&AppConfig.MyIPAddr, sizeof(IP_ADDR)); // Option: Subnet Mask UDPPut(DHCP_SUBNET_MASK); UDPPut(sizeof(IP_ADDR)); UDPPutArray((BYTE*)&AppConfig.MyMask, sizeof(IP_ADDR)); // Option: Router/Gateway address UDPPut(DHCP_ROUTER); UDPPut(sizeof(IP_ADDR)); UDPPutArray((BYTE*)&AppConfig.MyIPAddr, sizeof(IP_ADDR)); // No more options, mark ending UDPPut(DHCP_END_OPTION); // Add zero padding to ensure compatibility with old BOOTP relays that discard small packets (<300 UDP octets) while(UDPTxCount < 300u) UDPPut(0); // Transmit the packet UDPFlush(); }
/** * Must be called every couple of ms * */ void busTask(void) { BYTE c; BYTE bytesRead; BYTE busId; BYTE linkedMask; ///////////////////////////////////////////////// //UDP 1 //Get bus to link to UDP 1 busId = appcfgGetc(BUSCFG_UDP1_LINK); #if defined(BRD_SBC65EC) //Currently UDP 1 can only be linked to Serial 1, Serial 2 and I2C for SBC65EC if ((busId >= BUSID_SER1) && (busId <= BUSID_I2C1) && (udpBus1 != INVALID_UDP_SOCKET)) { #else //Currently UDP 1 can only be linked to Serial 1 and I2C for SBC68EC if ( ((busId == BUSID_SER1) || (busId == BUSID_I2C1)) && (udpBus1 != INVALID_UDP_SOCKET)) { #endif //Is there any data waiting for us on this UDP port? if (UDPIsGetReady(udpBus1)) { if (busIsEnabled(busId)) { //Read bytes while (UDPGet(&c)) { //Wait until a byte is transmitted by the interrupt routine and buffer has place again. while (busIsTxBufFull(busId)) { busService(busId); FAST_USER_PROCESS(); } //Add byte to TX buffer, and update buffer pointers busPutByteTxBuf(busId, c); } //Initiate transmitting if not already transmitting if (!busIsTxing(busId)) { busService(busId); } } //Discard the socket buffer. UDPDiscard(); } //Is there any data to send on UDP port if(busRxBufHasData(busId)) { if (UDPIsPutReady(udpBus1)) { while(busRxBufHasData(busId)) { //Read and remove byte from buffer c = busPeekByteRxBuf(busId); busRemoveByteRxBuf(busId); UDPPut(c); } // Now transmit it. UDPFlush(); } } } ///////////////////////////////////////////////// //UDP 2 //Get bus to link to UDP 2 busId = appcfgGetc(BUSCFG_UDP2_LINK); #if defined(BRD_SBC65EC) //Currently UDP 1 can only be linked to Serial 1, Serial 2 and I2C for SBC65EC if ((busId >= BUSID_SER1) && (busId <= BUSID_I2C1) && (udpBus1 != INVALID_UDP_SOCKET)) { #else //Currently UDP 1 can only be linked to Serial 1 and I2C for SBC68EC if ( ((busId == BUSID_SER1) || (busId == BUSID_I2C1)) && (udpBus1 != INVALID_UDP_SOCKET)) { #endif //Is there any data waiting for us on this UDP port? if (UDPIsGetReady(udpBus2)) { if (busIsEnabled(busId)) { //Read bytes while (UDPGet(&c)) { //Wait until a byte is transmitted by the interrupt routine and buffer has place again. while (busIsTxBufFull(busId)) { busService(busId); FAST_USER_PROCESS(); } //Add byte to TX buffer, and update buffer pointers busPutByteTxBuf(busId, c); } //Initiate transmitting if not already transmitting if (!busIsTxing(busId)) { busService(busId); } } //Discard the socket buffer. UDPDiscard(); } //Is there any data to send on UDP port if(busRxBufHasData(busId)) { if (UDPIsPutReady(udpBus2)) { while(busRxBufHasData(busId)) { //Read and remove byte from buffer c = busPeekByteRxBuf(busId); busRemoveByteRxBuf(busId); UDPPut(c); } // Now transmit it. UDPFlush(); } } } ///////////////////////////////////////////////// //Service all serial buses for (busId=0; busId<BUS_COUNT; busId++) { busService(busId); } } /** * Service the given bus. If our code has a section where it has to wait for the transmit * buffer of a bus to be empties, it should call this function while waiting. * * @param busId The bus ID of the requested bus. Is a BUSID_XXX variable * */ void busService(BYTE busId) { switch(busId) { case BUSID_SER1: serService(); break; #if defined(BRD_SBC65EC) case BUSID_SER2: ser2Service(); break; #endif case BUSID_I2C1: i2cBusService(); break; case BUSID_SPI1: NOP(); break; } } /** * Gets a byte at the given offset from the Transmit Buffer, without removing it. * The byte is NOT removed from the buffer, and the buffer pointers are NOT updated! * The byte at the given offset it returned. The offset is how deep the byte is in * the buffer. For example, 0 will return first byte in buffer, 5 will return the 6th * byte in the buffer. * * @preCondition Ensure offset parameter is not larger than current number of bytes * contained in buffer. Call busGetTxBufCount() to get current number of bytes in buffer. * * @param busId The bus ID of the requested bus. Is a BUSID_XXX variable * @param offset Offset of byte to return. Is a value from 0-n, where n = (busGetTxBufCount() - 1) * * @return Returns the byte at the given offset in the given bus's Transmit buffer. */ BYTE busPeekByteTxBufAt(BYTE busId, BYTE offset) { BYTE ofst; ofst = busInfo.buf[busId].getTx + offset; //Check if offset wrap around if (ofst >= busInfo.buf[busId].txBufSize) { ofst = ofst - busInfo.buf[busId].txBufSize; } return *(busInfo.buf[busId].txBuf + ofst); } /** * Gets a byte at the given offset from the Receive Buffer, without removing it. * The byte is NOT removed from the buffer, and the buffer pointers are NOT updated! * The byte at the given offset it returned. The offset is how deep the byte is in * the buffer. For example, 0 will return first byte in buffer, 5 will return the 6th * byte in the buffer. * * @preCondition Ensure offset parameter is not larger than current number of bytes * contained in buffer. Call busGetRxBufCount() to get current number of bytes in buffer. * * @param busId The bus ID of the requested bus. Is a BUSID_XXX variable * @param offset Offset of byte to return. Is a value from 0-n, where n = (busGetRxBufCount() - 1) * * @return Returns the byte at the given offset in the given bus's Receive buffer. */ BYTE busPeekByteRxBufAt(BYTE busId, BYTE offset) { BYTE ofst; ofst = busInfo.buf[busId].getRx + offset; //Check if offset wrap around if (ofst >= busInfo.buf[busId].rxBufSize) { ofst = ofst - busInfo.buf[busId].rxBufSize; } return *(busInfo.buf[busId].rxBuf + ofst); }
/********************************************************************* * Function: TFTP_RESULT TFTPIsPutReady(void) * * PreCondition: TFTPOpenFile() is called with TFTP_FILE_MODE_WRITE * and TFTPIsFileOpened() returned with TRUE. * * Input: None * * Output: TFTP_OK if it is okay to write more data byte. * * TFTP_TIMEOUT if timeout occurred waiting for * ack from server * * TFTP_RETRY if all server did not send ack * on time and application needs to resend * last block. * * TFTP_ERROR if remote server returned ERROR. * Actual error code may be read by calling * TFTPGetError() * * TFTP_NOT_READY if still waiting... * * Side Effects: None * * Overview: Waits for ack from server. If ack does not * arrive within specified timeout, it it instructs * application to retry last block by returning * TFTP_RETRY. * * If all attempts are exhausted, it returns with * TFTP_TIMEOUT. * * Note: None ********************************************************************/ TFTP_RESULT TFTPIsPutReady(void) { WORD_VAL opCode; WORD_VAL blockNumber; BOOL bTimeOut; // Check to see if timeout has occurred. bTimeOut = FALSE; if ( TickGetDiff(TickGet(), _tftpStartTick) >= TFTP_GET_TIMEOUT_VAL ) { bTimeOut = TRUE; _tftpStartTick = TickGet(); } switch(_tftpState) { case SM_TFTP_WAIT_FOR_ACK: // When timeout occurs in this state, application must retry. if ( bTimeOut ) { if ( _tftpRetries++ > (TFTP_MAX_RETRIES-1) ) { DEBUG(printf("TFTPIsPutReady(): Timeout.\n")); // Forget about all previous attempts. _tftpRetries = 1; return TFTP_TIMEOUT; } else { DEBUG(printf("TFTPIsPutReady(): Retry.\n")); return TFTP_RETRY; } } // Must wait for ACK from server before we transmit next block. if ( !UDPIsGetReady(_tftpSocket) ) break; // Get opCode. UDPGet(&opCode.byte.MSB); UDPGet(&opCode.byte.LSB); // Get block number. UDPGet(&blockNumber.byte.MSB); UDPGet(&blockNumber.byte.LSB); // Discard everything else. UDPDiscard(); // This must be ACK or else there is a problem. if ( opCode.Val == TFTP_OPCODE_ACK ) { // Also the block number must match with what we are expecting. if ( MutExVar.group2._tftpBlockNumber.Val == blockNumber.Val ) { // Mark that block we sent previously has been ack'ed. _tftpFlags.bits.bIsAcked = TRUE; // Since we have ack, forget about previous retry count. _tftpRetries = 1; // If this file is being closed, this must be last ack. // Declare it as closed. if ( _tftpFlags.bits.bIsClosing ) { _tftpFlags.bits.bIsClosed = TRUE; return TFTP_OK; } // Or else, wait for put to become ready so that caller // can transfer more data blocks. _tftpState = SM_TFTP_WAIT; } else { DEBUG(printf("TFTPIsPutReady(): "\ "Unexpected block %d received - droping it...\n", \ blockNumber.Val)); return TFTP_NOT_READY; } } else if ( opCode.Val == TFTP_OPCODE_ERROR ) { // For error opCode, remember error code so that application // can read it later. _tftpError = blockNumber.Val; // Declare error. return TFTP_ERROR; } else break; case SM_TFTP_WAIT: // Wait for UDP is to be ready to transmit. if ( UDPIsPutReady(_tftpSocket) ) { // Put next block of data. MutExVar.group2._tftpBlockNumber.Val++; UDPPut(0); UDPPut(TFTP_OPCODE_DATA); UDPPut(MutExVar.group2._tftpBlockNumber.byte.MSB); UDPPut(MutExVar.group2._tftpBlockNumber.byte.LSB); // Remember that this block is not yet flushed. _tftpFlags.bits.bIsFlushed = FALSE; // Remember that this block is not acknowledged. _tftpFlags.bits.bIsAcked = FALSE; // Now, TFTP module is ready to put more data. _tftpState = SM_TFTP_READY; return TFTP_OK; } break; case SM_TFTP_READY: // TFTP module is said to be ready only when underlying UDP // is ready to transmit. if ( UDPIsPutReady(_tftpSocket) ) return TFTP_OK; } return TFTP_NOT_READY; }
/***************************************************************************** Function: static void DHCPReplyToRequest(BOOTP_HEADER *Header, BOOL bAccept) Summary: Replies to a DHCP Request message. Description: This function replies to a DHCP Request message by sending out a DHCP Acknowledge message. Precondition: None Parameters: Header - the BootP header this is in response to. bAccept - whether or not we've accepted this request Returns: None Internal: Needs to support more than one simultaneous lease in the future. ***************************************************************************/ static void DHCPReplyToRequest(BOOTP_HEADER *Header, BOOL bAccept, BOOL bRenew) { BYTE i; INT8 indexOfPool = 255; IP_ADDR ipAddr; // Set the correct socket to active and ensure that // enough space is available to generate the DHCP response if(UDPIsPutReady(MySocket) < 300u) return; // Search through all remaining options and look for the Requested IP address field // Obtain options while(UDPIsGetReady(MySocket)) { BYTE Option, Len; DWORD dw; MAC_ADDR tmp_MacAddr; // Get option type if(!UDPGet(&Option)) break; if(Option == DHCP_END_OPTION) break; // Get option length UDPGet(&Len); if(bRenew) { if((Option == DHCP_PARAM_REQUEST_CLIENT_ID) && (Len == 7u)) { // Get the requested IP address and see if it is the one we have on offer. If not, we should send back a NAK, but since there could be some other DHCP server offering this address, we'll just silently ignore this request. UDPGet(&i); UDPGetArray((UINT8*)&tmp_MacAddr, 6); Len -= 7; indexOfPool = getIndexByMacaddr_DhcpPool(&tmp_MacAddr);//(&tmp_MacAddr,(IPV4_ADDR*)&Header->); if(-1 != indexOfPool) { if(GetIPAddrFromIndex_DhcpPool(indexOfPool).Val == Header->ClientIP.Val) postAssign_ToDHCPClient_FromPool(&tmp_MacAddr, &(Header->ClientIP)); else bAccept = FALSE; } else { bAccept = FALSE; } break; } } else { // if((Option == DHCP_PARAM_REQUEST_IP_ADDRESS) && (Len == 4u)) { // Get the requested IP address and see if it is the one we have on offer. If not, we should send back a NAK, but since there could be some other DHCP server offering this address, we'll just silently ignore this request. UDPGetArray((UINT8*)&dw, 4); Len -= 4; indexOfPool = postAssign_ToDHCPClient_FromPool(&(Header->ClientMAC),(IP_ADDR*)&dw); if( -1 == indexOfPool) { bAccept = FALSE; } break; } } // Remove the unprocessed bytes that we don't care about while(Len--) { UDPGet(&i); } } // Begin putting the BOOTP Header and DHCP options UDPPut(BOOT_REPLY); // Message Type: 2 (BOOTP Reply) // Reply with the same Hardware Type, Hardware Address Length, Hops, and Transaction ID fields UDPPutArray((BYTE*)&(Header->HardwareType), 7); UDPPut(0x00); // Seconds Elapsed: 0 (Not used) UDPPut(0x00); // Seconds Elapsed: 0 (Not used) UDPPutArray((BYTE*)&(Header->BootpFlags), sizeof(Header->BootpFlags)); UDPPutArray((BYTE*)&(Header->ClientIP), sizeof(IP_ADDR));// Your (client) IP Address: //UDPPutArray((BYTE*)&DHCPNextLease, sizeof(IP_ADDR)); // Lease IP address to give out if(bAccept) ipAddr = GetIPAddrFromIndex_DhcpPool(indexOfPool); else ipAddr.Val=0u; UDPPutArray((UINT8*)&ipAddr, sizeof(IP_ADDR)); // Lease IP address to give out UDPPut(0x00); // Next Server IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Next Server IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Next Server IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Next Server IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Relay Agent IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Relay Agent IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Relay Agent IP Address: 0.0.0.0 (not used) UDPPut(0x00); // Relay Agent IP Address: 0.0.0.0 (not used) UDPPutArray((BYTE*)&(Header->ClientMAC), sizeof(MAC_ADDR)); // Client MAC address: Same as given by client for(i = 0; i < 64+128+(16-sizeof(MAC_ADDR)); i++) // Remaining 10 bytes of client hardware address, server host name: Null string (not used) UDPPut(0x00); // Boot filename: Null string (not used) UDPPut(0x63); // Magic Cookie: 0x63538263 UDPPut(0x82); // Magic Cookie: 0x63538263 UDPPut(0x53); // Magic Cookie: 0x63538263 UDPPut(0x63); // Magic Cookie: 0x63538263 // Options: DHCP lease ACKnowledge if(bAccept) { UDPPut(DHCP_OPTION_ACK_MESSAGE); UDPPut(1); UDPPut(DHCP_ACK_MESSAGE); } else // Send a NACK { UDPPut(DHCP_OPTION_ACK_MESSAGE); UDPPut(1); UDPPut(DHCP_NAK_MESSAGE); } // Option: Lease duration UDPPut(DHCP_IP_LEASE_TIME); UDPPut(4); UDPPut((DHCP_LEASE_DURATION>>24) & 0xFF); UDPPut((DHCP_LEASE_DURATION>>16) & 0xFF); UDPPut((DHCP_LEASE_DURATION>>8) & 0xFF); UDPPut((DHCP_LEASE_DURATION) & 0xFF); // Option: Server identifier UDPPut(DHCP_SERVER_IDENTIFIER); UDPPut(sizeof(IP_ADDR)); UDPPutArray((BYTE*)&AppConfig.MyIPAddr, sizeof(IP_ADDR)); // Option: Subnet Mask UDPPut(DHCP_SUBNET_MASK); UDPPut(sizeof(IP_ADDR)); UDPPutArray((BYTE*)&AppConfig.MyMask, sizeof(IP_ADDR)); // Option: Router/Gateway address UDPPut(DHCP_ROUTER); UDPPut(sizeof(IP_ADDR)); UDPPutArray((BYTE*)&AppConfig.MyIPAddr, sizeof(IP_ADDR)); // Option: DNS server address UDPPut(DHCP_DNS); UDPPut(sizeof(IP_ADDR)); UDPPutArray((BYTE*)&AppConfig.MyIPAddr, sizeof(IP_ADDR)); // No more options, mark ending UDPPut(DHCP_END_OPTION); // Add zero padding to ensure compatibility with old BOOTP relays that discard small packets (<300 UDP octets) while(UDPTxCount < 300u) UDPPut(0); // Force remote destination address to be the broadcast address, regardless // of what the node's source IP address was (to ensure we don't try to // unicast to 0.0.0.0). memset((void*)&UDPSocketInfo[MySocket].remote.remoteNode, 0xFF, sizeof(NODE_INFO)); // Transmit the packet UDPFlush(); }
/********************************************************************* 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) | +---------------------------------------------------------------+ ********************************************************************/ static BYTE _DHCPReceive(void) { BYTE v; BYTE i; BYTE type; BOOL lbDone; DWORD_VAL tempServerID; // Assume unknown message until proven otherwise. type = DHCP_UNKNOWN_MESSAGE; /* * Assume default IP Lease time of 60 seconds. * This should be minimum possible to make sure that if * server did not specify lease time, we try again after * this minimum time. */ DHCPLeaseTime.Val = 60; UDPGet(&v); // op /* * Make sure this is BOOT_REPLY. */ if ( v == BOOT_REPLY ) { /* * Discard htype, hlen, hops, xid, secs, flags, ciaddr. */ for ( i = 0; i < 15; i++ ) UDPGet(&v); /* * Save offered IP address until we know for sure that * we have it. */ UDPGet(&tempIPAddress.v[0]); UDPGet(&tempIPAddress.v[1]); UDPGet(&tempIPAddress.v[2]); UDPGet(&tempIPAddress.v[3]); /* * Ignore siaddr, giaddr */ for ( i = 0; i < 8; i++ ) UDPGet(&v); /* * Check to see if chaddr (Client Hardware Address) belongs to us. */ for ( i = 0; i < 6; i++ ) { UDPGet(&v); if ( v != AppConfig.MyMACAddr.v[i]) goto UDPInvalid; } /* * Ignore part of chaddr, sname, file, magic cookie. */ for ( i = 0; i < 206; i++ ) UDPGet(&v); lbDone = FALSE; do { UDPGet(&v); switch(v) { case DHCP_MESSAGE_TYPE: UDPGet(&v); // Skip len // Len must be 1. if ( v == 1 ) { UDPGet(&type); // Get type } else goto UDPInvalid; break; case DHCP_SUBNET_MASK: UDPGet(&v); // Skip len // Len must be 4. if ( v == 4 ) { UDPGet(&tempMask.v[0]); UDPGet(&tempMask.v[1]); UDPGet(&tempMask.v[2]); UDPGet(&tempMask.v[3]); } else goto UDPInvalid; break; case DHCP_ROUTER: UDPGet(&v); // Len must be >= 4. if ( v >= 4 ) { UDPGet(&tempGateway.v[0]); UDPGet(&tempGateway.v[1]); UDPGet(&tempGateway.v[2]); UDPGet(&tempGateway.v[3]); } else goto UDPInvalid; /* * Discard any other router addresses. */ v -= 4; while(v--) UDPGet(&i); break; case DHCP_SERVER_IDENTIFIER: UDPGet(&v); // Get len // Len must be 4. if ( v == 4 ) { UDPGet(&UPPER_MSB(tempServerID)); // Get the id UDPGet(&UPPER_LSB(tempServerID)); UDPGet(&LOWER_MSB(tempServerID)); UDPGet(&LOWER_LSB(tempServerID)); } 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 == 4 ) { UDPGet(&UPPER_MSB(DHCPLeaseTime)); UDPGet(&UPPER_LSB(DHCPLeaseTime)); UDPGet(&LOWER_MSB(DHCPLeaseTime)); UDPGet(&LOWER_LSB(DHCPLeaseTime)); /* * Due to possible timing delays, consider actual lease * time less by half hour. */ if ( DHCPLeaseTime.Val > HALF_HOUR ) DHCPLeaseTime.Val = DHCPLeaseTime.Val - HALF_HOUR; } else goto UDPInvalid; break; default: // Ignore all unsupport tags. UDPGet(&v); // Get option len while( v-- ) // Ignore option values UDPGet(&i); } } while( !lbDone ); } /* * If this is an OFFER message, remember current server id. */ if ( type == DHCP_OFFER_MESSAGE ) { DHCPServerID.Val = tempServerID.Val; } else { /* * For other types of messages, make sure that received * server id matches with our previous one. */ if ( DHCPServerID.Val != tempServerID.Val ) type = DHCP_UNKNOWN_MESSAGE; } UDPDiscard(); // We are done with this packet return type; UDPInvalid: UDPDiscard(); return DHCP_UNKNOWN_MESSAGE; }
int8_t vscp_getUDPEvent( PVSCPMSG pmsg ) { int i; BYTE b1, b2; crc remainder = INITIAL_REMAINDER; // Must be something to receive if ( !UDPIsGetReady( vscp_udp_receivesocket ) ) return FALSE; // head if ( !UDPGet( &b1 ) ) return FALSE; crcSlow_bithandler( b1, &remainder ); // CRC calculation pmsg->head = b1; // class if ( !UDPGet( &b1 ) ) return FALSE; crcSlow_bithandler( b1, &remainder ); // CRC calculation if ( !UDPGet( &b2 ) ) return FALSE; crcSlow_bithandler( b2, &remainder ); // CRC calculation pmsg->vscp_class = ( b1 << 8 ) + b2; // type if ( !UDPGet( &b1 ) ) return FALSE; crcSlow_bithandler( b1, &remainder ); // CRC calculation if ( !UDPGet( &b2 ) ) return FALSE; crcSlow_bithandler( b2, &remainder ); // CRC calculation pmsg->vscp_type = ( b1 << 8 ) + b2; // GUID for ( i=0; i<16; i++ ) { if ( !UDPGet( &b1 ) ) return FALSE; crcSlow_bithandler( b1, &remainder ); // CRC calculation pmsg->GUID[ i ] = b1; } // Size if ( !UDPGet( &b1 ) ) return FALSE; crcSlow_bithandler( b1, &remainder ); // CRC calculation if ( !UDPGet( &b2 ) ) return FALSE; crcSlow_bithandler( b2, &remainder ); // CRC calculation pmsg->sizeData = ( b1 << 8 ) + b2; #ifdef VSCP_LEVEL2_LIMITED_DEVICE if ( pmsg->sizeData > LIMITED_DEVICE_DATASIZE ) return FALSE; #else if ( pmsg->sizeData > (512-25) ) return FALSE; #endif // Data for ( i=0; i<pmsg->sizeData; i++ ) { if ( !UDPGet( &b1 ) ) return FALSE; crcSlow_bithandler( b1, &remainder ); // CRC calculation pmsg->data[ i ] = b1; } // crc if ( !UDPGet( &b1 ) ) return FALSE; crcSlow_bithandler( b1, &remainder ); // CRC calculation if ( !UDPGet( &b2 ) ) return FALSE; crcSlow_bithandler( b2, &remainder ); // CRC calculation pmsg->crc = ( b1 << 8 ) + b2; if ( ( remainder ^ FINAL_XOR_VALUE ) ) return FALSE; // we have the information we need UDPDiscard(); return TRUE; }
bool NBNSTask(TCPIP_NET_IF* pNetIf) { uint8_t i; TCPIP_UINT16_VAL Type, Class; NBNS_HEADER NBNSHeader; uint8_t NameString[16]; UDP_SOCKET s; int nbnsRxSize; int nbnsTxSize; s = nbnsDcpt.uSkt; switch(nbnsDcpt.sm) { case NBNS_HOME: nbnsDcpt.sm++; break; case NBNS_OPEN_SOCKET: s = UDPOpenServer(IP_ADDRESS_TYPE_IPV4, NBNS_PORT, 0); if(s == INVALID_UDP_SOCKET) break; if(!UDPRemoteBind(s, IP_ADDRESS_TYPE_IPV4, NBNS_PORT, 0)) { UDPClose(s); break; } nbnsDcpt.uSkt = s; nbnsDcpt.sm++; case NBNS_LISTEN: //if(!UDPIsGetReady(s)) nbnsRxSize = UDPIsGetReady(s); if(!nbnsRxSize) { break; } // Respond only to name requests sent to us from nodes on the same subnet // This prevents us from sending out the wrong IP address information if // we haven't gotten a DHCP lease yet. if((remoteNode.IPAddr.Val & pNetIf->netMask.Val) != (pNetIf->netIPAddr.Val & pNetIf->netMask.Val)) { UDPDiscard(s); break; } #ifdef _NBNS_DEBUG nbnsRxOks++; if(nbnsRxSize > nbnsRxMaxSize) { nbnsRxMaxSize = nbnsRxSize; } #endif // _NBNS_DEBUG // Retrieve the NBNS header and de-big-endian it UDPGet(s, &NBNSHeader.TransactionID.v[1]); UDPGet(s, &NBNSHeader.TransactionID.v[0]); UDPGet(s, &NBNSHeader.Flags.v[1]); UDPGet(s, &NBNSHeader.Flags.v[0]); UDPGet(s, &NBNSHeader.Questions.v[1]); UDPGet(s, &NBNSHeader.Questions.v[0]); UDPGet(s, &NBNSHeader.Answers.v[1]); UDPGet(s, &NBNSHeader.Answers.v[0]); UDPGet(s, &NBNSHeader.AuthoritativeRecords.v[1]); UDPGet(s, &NBNSHeader.AuthoritativeRecords.v[0]); UDPGet(s, &NBNSHeader.AdditionalRecords.v[1]); UDPGet(s, &NBNSHeader.AdditionalRecords.v[0]); // Remove all questions while(NBNSHeader.Questions.Val--) { NBNSGetName(s, NameString); UDPGet(s, &i); // <??> Trailing character on string UDPGet(s, &Type.v[1]); // Question type UDPGet(s, &Type.v[0]); UDPGet(s, &Class.v[1]); // Question class UDPGet(s, &Class.v[0]); if(Type.Val == 0x0020u && Class.Val == 0x0001u) { int nIfs, nIx; TCPIP_NET_IF* pIf; const char* netbName; nIfs = TCPIP_STACK_NetworksNo(); for(nIx = 0; nIx < nIfs; nIx++) { pIf = (TCPIP_NET_IF*)TCPIP_STACK_IxToNet(nIx); netbName = TCPIP_STACK_NetBIOSName(pIf); // this checks the IF is up! if(memcmp((void*)NameString, netbName, sizeof(pIf->NetBIOSName)) == 0) { // one of our interfaces has this name nbnsTxSize = UDPIsTxPutReady(s, 64); if(nbnsTxSize) { #ifdef _NBNS_DEBUG nbnsTxOks++; if(nbnsTxSize > nbnsTxMaxSize) { nbnsTxMaxSize = nbnsTxSize; } #endif // _NBNS_DEBUG NBNSHeader.Flags.Val = 0x8400; UDPPut(s, NBNSHeader.TransactionID.v[1]); UDPPut(s, NBNSHeader.TransactionID.v[0]); UDPPut(s, NBNSHeader.Flags.v[1]); UDPPut(s, NBNSHeader.Flags.v[0]); UDPPut(s, 0x00); // 0x0000 Questions UDPPut(s, 0x00); UDPPut(s, 0x00); // 0x0001 Answers UDPPut(s, 0x01); UDPPut(s, 0x00); // 0x0000 Athoritative records UDPPut(s, 0x00); UDPPut(s, 0x00); // 0x0000 Additional records UDPPut(s, 0x00); NBNSPutName(s, netbName); UDPPut(s, 0x00); // 0x0020 Type: NetBIOS UDPPut(s, 0x20); UDPPut(s, 0x00); // 0x0001 Class: Internet UDPPut(s, 0x01); UDPPut(s, 0x00); // 0x00000000 Time To Live UDPPut(s, 0x00); UDPPut(s, 0x00); UDPPut(s, 0x00); UDPPut(s, 0x00); // 0x0006 Data length UDPPut(s, 0x06); UDPPut(s, 0x60); // 0x6000 Flags: H-node, Unique UDPPut(s, 0x00); UDPPut(s, pIf->netIPAddr.v[0]); // Put out IP address UDPPut(s, pIf->netIPAddr.v[1]); UDPPut(s, pIf->netIPAddr.v[2]); UDPPut(s, pIf->netIPAddr.v[3]); // Change the destination address to the unicast address of the last received packet UDPSetDestinationIPAddress(s, IP_ADDRESS_TYPE_IPV4, (IP_MULTI_ADDRESS*)&remoteNode.IPAddr); memcpy((void*)&((IPV4_PACKET*)UDPSocketDcpt[s].pTxPkt)->remoteMACAddr, (const void*)&remoteNode.MACAddr, sizeof(remoteNode.MACAddr)); UDPFlush(s); } #ifdef _NBNS_DEBUG else { nbnsTxFails++; } #endif // _NBNS_DEBUG break; } } } } UDPDiscard(s); break; } return true; }
/***************************************************************************** Function: void DHCPServerTask(void) Summary: Performs periodic DHCP server tasks. Description: This function performs any periodic tasks requied by the DHCP server module, such as processing DHCP requests and distributing IP addresses. Precondition: None Parameters: None Returns: None ***************************************************************************/ void DHCPServerTask(void) { BYTE i; BYTE Option, Len; BOOTP_HEADER BOOTPHeader; DWORD dw; BOOL bAccept; static enum { DHCP_OPEN_SOCKET, DHCP_LISTEN } smDHCPServer = DHCP_OPEN_SOCKET; #if defined(STACK_USE_DHCP_CLIENT) // Make sure we don't clobber anyone else's DHCP server if(DHCPIsServerDetected(0)) return; #endif if(!bDHCPServerEnabled) return; switch(smDHCPServer) { case DHCP_OPEN_SOCKET: // Obtain a UDP socket to listen/transmit on //MySocket = UDPOpen(DHCP_SERVER_PORT, NULL, DHCP_CLIENT_PORT); MySocket = UDPOpenEx(0,UDP_OPEN_SERVER,DHCP_SERVER_PORT, DHCP_CLIENT_PORT); if(MySocket == INVALID_UDP_SOCKET) break; // Decide which address to lease out // Note that this needs to be changed if we are to // support more than one lease DHCPNextLease.Val = (AppConfig.MyIPAddr.Val & AppConfig.MyMask.Val) + 0x02000000; if(DHCPNextLease.v[3] == 255u) DHCPNextLease.v[3] += 0x03; if(DHCPNextLease.v[3] == 0u) DHCPNextLease.v[3] += 0x02; smDHCPServer++; case DHCP_LISTEN: // Check to see if a valid DHCP packet has arrived if(UDPIsGetReady(MySocket) < 241u) break; // Retrieve the BOOTP header UDPGetArray((BYTE*)&BOOTPHeader, sizeof(BOOTPHeader)); bAccept = (BOOTPHeader.ClientIP.Val == DHCPNextLease.Val) || (BOOTPHeader.ClientIP.Val == 0x00000000u); // Validate first three fields if(BOOTPHeader.MessageType != 1u) break; if(BOOTPHeader.HardwareType != 1u) break; if(BOOTPHeader.HardwareLen != 6u) break; // Throw away 10 unused bytes of hardware address, // server host name, and boot file name -- unsupported/not needed. for(i = 0; i < 64+128+(16-sizeof(MAC_ADDR)); i++) UDPGet(&Option); // Obtain Magic Cookie and verify UDPGetArray((BYTE*)&dw, sizeof(DWORD)); if(dw != 0x63538263ul) break; // Obtain options while(1) { // Get option type if(!UDPGet(&Option)) break; if(Option == DHCP_END_OPTION) break; // Get option length UDPGet(&Len); // Process option switch(Option) { case DHCP_MESSAGE_TYPE: UDPGet(&i); switch(i) { case DHCP_DISCOVER_MESSAGE: DHCPReplyToDiscovery(&BOOTPHeader); break; case DHCP_REQUEST_MESSAGE: DHCPReplyToRequest(&BOOTPHeader, bAccept); break; // Need to handle these if supporting more than one DHCP lease case DHCP_RELEASE_MESSAGE: case DHCP_DECLINE_MESSAGE: break; } break; case DHCP_PARAM_REQUEST_IP_ADDRESS: if(Len == 4u) { // Get the requested IP address and see if it is the one we have on offer. UDPGetArray((BYTE*)&dw, 4); Len -= 4; bAccept = (dw == DHCPNextLease.Val); } break; case DHCP_END_OPTION: UDPDiscard(); return; } // Remove any unprocessed bytes that we don't care about while(Len--) { UDPGet(&i); } } UDPDiscard(); break; } }
/***************************************************************************** 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 ); }
/***************************************************************************** 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_VAL tempServerID; // Assume unknown message until proven otherwise. type = DHCP_UNKNOWN_MESSAGE; UDPGet(&v); // op // Make sure this is BOOT_REPLY. if ( v == BOOT_REPLY ) { // Discard htype, hlen, hops, xid, secs, flags, ciaddr. for ( i = 0; i < 15u; i++ ) UDPGet(&v); // Check to see if this is the first offer if(DHCPFlags.bits.bOfferReceived) { // Discard offered IP address, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { // Save offered IP address until we know for sure that we have it. UDPGetArray((BYTE*)&tempIPAddress, sizeof(tempIPAddress)); ValidValues.bits.IPAddress = 1; } // Ignore siaddr, giaddr for ( i = 0; i < 8u; i++ ) UDPGet(&v); // Check to see if chaddr (Client Hardware Address) belongs to us. for ( i = 0; i < 6u; i++ ) { UDPGet(&v); if ( v != AppConfig.MyMACAddr.v[i]) goto UDPInvalid; } // Ignore part of chaddr, sname, file, magic cookie. for ( i = 0; i < 206u; i++ ) UDPGet(&v); 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(DHCPFlags.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(DHCPFlags.bits.bOfferReceived) { // Discard offered IP mask, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGetArray((BYTE*)&tempMask, sizeof(tempMask)); 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(DHCPFlags.bits.bOfferReceived) { // Discard offered Gateway address, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGetArray((BYTE*)&tempGateway, sizeof(tempGateway)); 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(!DHCPFlags.bits.bOfferReceived) { UDPGetArray((BYTE*)&tempDNS, sizeof(tempDNS)); 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(!DHCPFlags.bits.bOfferReceived) { UDPGetArray((BYTE*)&tempDNS2, sizeof(tempDNS2)); 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(&tempServerID.v[3]); // Get the id UDPGet(&tempServerID.v[2]); UDPGet(&tempServerID.v[1]); UDPGet(&tempServerID.v[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(DHCPFlags.bits.bOfferReceived) { // Discard offered lease time, we already have an offer for ( i = 0; i < 4u; i++ ) UDPGet(&v); } else { UDPGet(&DHCPLeaseTime.v[3]); UDPGet(&DHCPLeaseTime.v[2]); UDPGet(&DHCPLeaseTime.v[1]); UDPGet(&DHCPLeaseTime.v[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 DHCPLeaseTime.Val -= DHCPLeaseTime.Val>>5; } } else goto UDPInvalid; break; default: // Ignore all unsupport tags. UDPGet(&j); // Get option len while( j-- ) // Ignore option values UDPGet(&v); } } while( !lbDone ); } // If this is an OFFER message, remember current server id. if ( type == DHCP_OFFER_MESSAGE ) { DHCPServerID.Val = tempServerID.Val; DHCPFlags.bits.bOfferReceived = TRUE; } else { // For other types of messages, make sure that received // server id matches with our previous one. if ( DHCPServerID.Val != tempServerID.Val ) type = DHCP_UNKNOWN_MESSAGE; } UDPDiscard(); // We are done with this packet return type; UDPInvalid: UDPDiscard(); return DHCP_UNKNOWN_MESSAGE; }