/***************************************************************************** Function: int recv( SOCKET s, char* buf, int len, int flags ) Summary: The recv() function is used to receive incoming data that has been queued for a socket. Description: The recv() function is used to receive incoming data that has been queued for a socket. This function can be used with both datagram and stream socket. If the available data is too large to fit in the supplied application buffer buf, excess bytes are discarded in case of SOCK_DGRAM type sockets. For SOCK_STREAM types, the data is buffered internally so the application can retreive all data by multiple calls of recvfrom. Precondition: connect function should be called for TCP and UDP sockets. Server side, accept function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. buf - application data receive buffer. len - buffer length in bytes. flags - no significance in this implementation Returns: If recv is successful, the number of bytes copied to application buffer buf is returned. A value of zero indicates no data available. A return value of SOCKET_ERROR (-1) indicates an error condition. A return value of SOCKET_DISCONNECTED indicates the connection no longer exists. Remarks: None. ***************************************************************************/ int recv( SOCKET s, char* buf, int len, int flags ) { struct BSDSocket *socket; if( s >= BSD_SOCKET_COUNT ) return SOCKET_ERROR; socket = &BSDSocketArray[s]; if(socket->SocketType == SOCK_STREAM) //TCP { if(socket->bsdState != SKT_EST) return SOCKET_ERROR; if(HandlePossibleTCPDisconnection(s)) return SOCKET_ERROR; return TCPGetArray(socket->SocketID, (BYTE*)buf, len); } else if(socket->SocketType == SOCK_DGRAM) //UDP { if(socket->bsdState != SKT_BOUND) return SOCKET_ERROR; if(UDPIsGetReady(socket->SocketID)) return UDPGetArray((BYTE*)buf, len); } return 0; }
ssize_t microchip_udp_read(UDP_SOCKET socket, uint8_t* buf, size_t len, uint32_t* addr, uint16_t* port) { ssize_t rlen; #if NABTO_LOG_CHECK(NABTO_LOG_SEVERITY_TRACE) UDP_SOCKET_INFO* debug; uint32_t sourceIp; #endif if (UDPIsGetReady(socket)) { #if NABTO_LOG_CHECK(NABTO_LOG_SEVERITY_TRACE) debug = &UDPSocketInfo[socket]; READ_U32(sourceIp, &debug->remote.remoteNode.IPAddr.Val); #endif unabto_microchip_arp_add_resolved(&(UDPSocketInfo[socket].remote.remoteNode)); // *addr = ntohl(UDPSocketInfo[socket].remote.remoteNode.IPAddr.Val); WRITE_U32(addr, UDPSocketInfo[socket].remote.remoteNode.IPAddr.Val); *port = UDPSocketInfo[socket].remotePort; rlen = (ssize_t) UDPGetArray(buf, len); NABTO_LOG_TRACE(("UDP read length: %i, %" PRIu16 " <- " PRIip ":%" PRIu16, rlen, debug->localPort, MAKE_IP_PRINTABLE(sourceIp), debug->remotePort)); NABTO_LOG_BUFFER(NABTO_LOG_SEVERITY_TRACE, ("UDP in datagram"), buf, rlen); return rlen; } return 0; }
/**************************************************************************** Function: WORD UDPSBWrite(UDPSB * pUDPSB, WORD cbWrite) Description: Write data from the UDP socket buffers into the UDP socket cache Preconditions: UDPIsGetReady must have already been called so that UDPGetArray will retrieve data from the correct socket. Parameters: pUDPSB - a point to the parallel socket cache data structure. cbWrite - The number of bytes to read from the socket Returns: The number of bytes actually written to the socket cache. Remarks: If more data is written to the socket cache than free space is available then the earlier data in the cache is overwritten. The available bytes will be set to the maximum size of the of the cache; which is RXMAX, or typically 1536 (0x600) bytes. ***************************************************************************/ static WORD UDPSBWrite(UDPSB * pUDPSB, WORD cbWrite) { WORD cbCopy = 0; WORD iWrite = 0; while(cbWrite > 0) { cbCopy = sizeof(pUDPSB->rgbBuffer) - pUDPSB->iEnd; cbCopy = cbCopy < cbWrite ? cbCopy : cbWrite; cbCopy = UDPGetArray(&pUDPSB->rgbBuffer[pUDPSB->iEnd], cbCopy); iWrite += cbCopy; pUDPSB->iEnd += cbCopy; cbWrite -= cbCopy; // run to the front of the bufer if we used it all up if(pUDPSB->iEnd == sizeof(pUDPSB->rgbBuffer)) { pUDPSB->iEnd = 0; } } // if we have a buffer overrun, then set the available count // to the max size of the buffer. pUDPSB->cbAvailable += iWrite; if(pUDPSB->cbAvailable > sizeof(pUDPSB->rgbBuffer)) { pUDPSB->cbAvailable = sizeof(pUDPSB->rgbBuffer); } return(iWrite); }
/***************************************************************************** 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: int recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen) Summary: The recvfrom() function is used to receive incoming data that has been queued for a socket. Description: The recvfrom() function is used to receive incoming data that has been queued for a socket. This function can be used with both datagram and stream type sockets. If the available data is too large to fit in the supplied application buffer buf, excess bytes are discarded in case of SOCK_DGRAM type sockets. For SOCK_STREAM types, the data is buffered internally so the application can retreive all data by multiple calls of recvfrom. Precondition: socket function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. buf - application data receive buffer. len - buffer length in bytes. flags - message flags. Currently this is not supported. from - pointer to the sockaddr structure that will be filled in with the destination address. fromlen - size of buffer pointed by from. Returns: If recvfrom is successful, the number of bytes copied to application buffer buf is returned. A value of zero indicates no data available. A return value of SOCKET_ERROR (-1) indicates an error condition. Remarks: None. ***************************************************************************/ int recvfrom( SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen ) { struct BSDSocket *socket; struct sockaddr_in *rem_addr; SOCKET_INFO *remoteSockInfo; socket = &BSDSocketArray[s]; rem_addr = (struct sockaddr_in *)from; if(socket->SocketType == SOCK_DGRAM) //UDP { // If this BSD socket doesn't have a Microchip UDP socket associated // with it yet, then no data can be received and we must not use the // socket->SocketID parameter, which isn't set yet. if(socket->bsdState != SKT_BOUND) return 0; if(UDPIsGetReady(socket->SocketID)) { // Capture sender information (can change packet to packet) if(from && fromlen) { if((unsigned int)*fromlen >= sizeof(struct sockaddr_in)) { remoteSockInfo = TCPGetRemoteInfo(socket->SocketID); rem_addr->sin_addr.S_un.S_addr = remoteSockInfo->remote.IPAddr.Val; rem_addr->sin_port = remoteSockInfo->remotePort.Val; *fromlen = sizeof(struct sockaddr_in); } } return UDPGetArray((BYTE*)buf, len); } } else //TCP recieve from already connected socket. { if(from && fromlen) { // Capture sender information (will always match socket connection information) if((unsigned int)*fromlen >= sizeof(struct sockaddr_in)) { remoteSockInfo = TCPGetRemoteInfo(socket->SocketID); rem_addr->sin_addr.S_un.S_addr = remoteSockInfo->remote.IPAddr.Val; rem_addr->sin_port = remoteSockInfo->remotePort.Val; *fromlen = sizeof(struct sockaddr_in); } } return recv(s, buf, len, 0); } return 0; }
/***************************************************************************** Function: int recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen) Summary: The recvfrom() function is used to receive incoming data that has been queued for a socket. Description: The recvfrom() function is used to receive incoming data that has been queued for a socket. This function can be used with both datagram and stream type sockets. If the available data is too large to fit in the supplied application buffer buf, excess bytes are discarded in case of SOCK_DGRAM type sockets. For SOCK_STREAM types, the data is buffered internally so the application can retreive all data by multiple calls of recvfrom. Precondition: socket function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. buf - application data receive buffer. len - buffer length in bytes. flags - message flags. Currently this is not supported. from - pointer to the sockaddr structure that will be filled in with the destination address. fromlen - size of buffer pointed by from. Returns: If recvfrom is successful, the number of bytes copied to application buffer buf is returned. A value of zero indicates no data available. A return value of SOCKET_ERROR (-1) indicates an error condition. Remarks: None. ***************************************************************************/ int recvfrom( SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen ) { struct BSDSocket *socket; struct sockaddr_in *rem_addr; SOCKET_INFO *remoteSockInfo; socket = &BSDSocketArray[s]; rem_addr = (struct sockaddr_in *)from; if(socket->SocketType == SOCK_DGRAM) //UDP { if(socket->bsdState != SKT_EST) { socket->SocketID = UDPOpen(socket->localPort, NULL, socket->localPort); //recieve on the same port. socket->bsdState = SKT_EST; } if(socket->bsdState == SKT_EST) { if(UDPIsGetReady(socket->SocketID) > 0) { return UDPGetArray((BYTE*)buf, len); } } } else //TCP recieve from already connected socket. { if(from && fromlen && ((unsigned int)*fromlen >= sizeof(struct sockaddr_in))) { remoteSockInfo = TCPGetRemoteInfo(socket->SocketID); rem_addr->sin_addr.S_un.S_addr = remoteSockInfo->remote.IPAddr.Val; rem_addr->sin_port = remoteSockInfo->remotePort.Val; *fromlen = sizeof(struct sockaddr_in); } return recv(s, buf, len, 0); } return 0; }
void CmdCheck() { #if MAX_UDP_SOCKETS_FREERTOS>0 //UDP Stack activeUdpSocket=0; while (activeUdpSocket < MAX_UDP_SOCKETS_FREERTOS) { //Ring Buffer if(udpSocket[activeUdpSocket] != INVALID_UDP_SOCKET) { //reads udp data and adds in ring buffer udpRxLen[activeUdpSocket] = UDPIsGetReady(udpSocket[activeUdpSocket]); if (udpRxLen[activeUdpSocket] > BUFFER_UDP_LEN[activeUdpSocket]) //overflow { datadiscard = udpRxLen[activeUdpSocket]; // Old debug string UARTWrite(1,"Overflow: "); while (datadiscard > BUFFER_UDP_LEN[activeUdpSocket]) { datadiscard -= BUFFER_UDP_LEN[activeUdpSocket]; if ( datadiscard > BUFFER_UDP_LEN[activeUdpSocket]) UDPGetArray(udpBuffer[activeUdpSocket], BUFFER_UDP_LEN[activeUdpSocket]); else UDPGetArray(udpBuffer[activeUdpSocket], datadiscard); // Old debug string UARTWrite(1,"Overflow While: "); } UDPoverflow = 1; UDPoverflowFlag[activeUdpSocket] = 1; udpRxLen[activeUdpSocket] = BUFFER_UDP_LEN[activeUdpSocket]; } else UDPoverflow = 0; if (udpRxLen[activeUdpSocket] > 0) { if( (p_udp_wifiram[activeUdpSocket]+udpRxLen[activeUdpSocket]) <= (udpBuffer[activeUdpSocket]+BUFFER_UDP_LEN[activeUdpSocket]) ) //append to buffer { UDPGetArray(p_udp_wifiram[activeUdpSocket], udpRxLen[activeUdpSocket]); //data p_udp_wifiram[activeUdpSocket] += udpRxLen[activeUdpSocket]; } else //append to buffer near end, or add to buffer from start { tmp_len[activeUdpSocket] = ((udpBuffer[activeUdpSocket]+BUFFER_UDP_LEN[activeUdpSocket]) - p_udp_wifiram[activeUdpSocket]); //free space on ring buffer if(tmp_len[activeUdpSocket] > 0) //fill buffer and add data from start { UDPGetArray(p_udp_wifiram[activeUdpSocket], tmp_len[activeUdpSocket]); p_udp_wifiram[activeUdpSocket] = udpBuffer[activeUdpSocket]; UDPGetArray(p_udp_wifiram[activeUdpSocket], udpRxLen[activeUdpSocket] - tmp_len[activeUdpSocket] ); p_udp_wifiram[activeUdpSocket] += (udpRxLen[activeUdpSocket] - tmp_len[activeUdpSocket]); } else //add data to buffer from start { p_udp_wifiram[activeUdpSocket] = udpBuffer[activeUdpSocket]; UDPGetArray(p_udp_wifiram[activeUdpSocket], udpRxLen[activeUdpSocket]); p_udp_wifiram[activeUdpSocket] += udpRxLen[activeUdpSocket]; } } udpRxLenGlobal[activeUdpSocket] += udpRxLen[activeUdpSocket]; /* udpBuffer1[50] = '\0'; UARTWrite(1, udpBuffer1); */ } //end ring buffer } activeUdpSocket++; } #endif //UDP STACK if (Cmd != 0) { int fresult = 0; while (xSemaphoreTake(xSemFrontEnd,0) != pdTRUE); if (xFrontEndStat == 1) { fresult = FP[Cmd](); xFrontEndStat = xFrontEndStatRet; xSemaphoreGive(xSemFrontEnd); Cmd = 0; taskYIELD(); } } }
// // Main application entry point. // int main(void) { #if defined(HOST_CM_TEST) DWORD t1 = 0; char st[80]; BOOL host_scan = FALSE; UINT16 scan_count = 0; #endif static IPV4_ADDR dwLastIP[sizeof (TCPIP_HOSTS_CONFIGURATION) / sizeof (*TCPIP_HOSTS_CONFIGURATION)]; int i, nNets; #if defined(SYS_USERIO_ENABLE) static SYS_TICK startTick = 0; int32_t LEDstate=SYS_USERIO_LED_DEASSERTED; #endif // defined(SYS_USERIO_ENABLE) TCPIP_NET_HANDLE netH; const char *netName=0; const char *netBiosName; #if defined (TCPIP_STACK_USE_ZEROCONF_MDNS_SD) char mDNSServiceName[] = "MyWebServiceNameX "; // base name of the service Must not exceed 16 bytes long // the last digit will be incremented by interface #endif // defined (TCPIP_STACK_USE_ZEROCONF_MDNS_SD) // perform system initialization if(!SYS_Initialize()) { return 0; } SYS_CONSOLE_MESSAGE("\r\n\n\n --- TCPIP Demo Starts! --- \r\n"); SYS_OUT_MESSAGE("TCPIPStack " TCPIP_STACK_VERSION " "" "); // Initialize the TCPIP stack if (!TCPIP_STACK_Init(TCPIP_HOSTS_CONFIGURATION, sizeof (TCPIP_HOSTS_CONFIGURATION) / sizeof (*TCPIP_HOSTS_CONFIGURATION), TCPIP_STACK_MODULE_CONFIG_TBL, sizeof (TCPIP_STACK_MODULE_CONFIG_TBL) / sizeof (*TCPIP_STACK_MODULE_CONFIG_TBL))) { return 0; } // Display the names associated with each interface // Perform mDNS registration if mDNS is enabled nNets = TCPIP_STACK_NetworksNo(); for(i = 0; i < nNets; i++) { netH = TCPIP_STACK_IxToNet(i); netName = TCPIP_STACK_NetName(netH); netBiosName = TCPIP_STACK_NetBIOSName(netH); #if defined(TCPIP_STACK_USE_NBNS) SYS_CONSOLE_PRINT(" Interface %s on host %s - NBNS enabled\r\n", netName, netBiosName); #else SYS_CONSOLE_PRINT(" Interface %s on host %s - NBNS disabled\r\n", netName, netBiosName); #endif // defined(TCPIP_STACK_USE_NBNS) #if defined (TCPIP_STACK_USE_ZEROCONF_MDNS_SD) mDNSServiceName[sizeof(mDNSServiceName) - 2] = '1' + i; mDNSServiceRegister( netH , mDNSServiceName // name of the service ,"_http._tcp.local" // type of the service ,80 // TCP or UDP port, at which this service is available ,((const BYTE *)"path=/index.htm") // TXT info ,1 // auto rename the service when if needed ,NULL // no callback function ,NULL); // no application context #endif //TCPIP_STACK_USE_ZEROCONF_MDNS_SD } #if defined (TCPIP_STACK_USE_IPV6) TCPIP_ICMPV6_RegisterCallback(ICMPv6Callback); #endif #if defined(TCPIP_STACK_USE_ICMP_CLIENT) ICMPRegisterCallback(PingProcessIPv4); #endif #if defined(TCPIP_STACK_USE_EVENT_NOTIFICATION) TCPIP_NET_HANDLE hWiFi = TCPIP_STACK_NetHandle("MRF24W"); if (hWiFi) { TCPIP_STACK_RegisterHandler(hWiFi, TCPIP_EV_RX_ALL | TCPIP_EV_TX_ALL | TCPIP_EV_RXTX_ERRORS, StackNotification, 0); } #endif // defined(TCPIP_STACK_USE_EVENT_NOTIFICATION) #if defined(WF_UPDATE_FIRMWARE_UART_24G) extern bool WF_FirmwareUpdate_Uart_24G(void); WF_FirmwareUpdate_Uart_24G(); #endif // Now that all items are initialized, begin the co-operative // multitasking loop. This infinite loop will continuously // execute all stack-related tasks, as well as your own // application's functions. Custom functions should be added // at the end of this loop. // Note that this is a "co-operative mult-tasking" mechanism // where every task performs its tasks (whether all in one shot // or part of it) and returns so that other tasks can do their // job. // If a task needs very long time to do its job, it must be broken // down into smaller pieces so that other tasks can have CPU time. while (1) { SYS_Tasks(); #if defined(SYS_USERIO_ENABLE) // Blink LED0 (right most one) every second. if (SYS_TICK_Get() - startTick >= SYS_TICK_TicksPerSecondGet() / 2ul) { startTick = SYS_TICK_Get(); LEDstate ^= SYS_USERIO_LED_ASSERTED; SYS_USERIO_SetLED(SYS_USERIO_LED_0, LEDstate); } #endif // defined(SYS_USERIO_ENABLE) // This task performs normal stack task including checking // for incoming packet, type of packet and calling // appropriate stack entity to process it. TCPIP_STACK_Task(); // Process application specific tasks here. // For this demo app, this will include the Generic TCP // client and servers, and the SNMP, Ping, and SNMP Trap // demos. Following that, we will process any IO from // the inputs on the board itself. // Any custom modules or processing you need to do should // go here. #if defined(TCPIP_STACK_USE_TCP) && defined(APP_USE_FTP_CLIENT_DEMO) FTPClient(); #endif #if defined(TCPIP_STACK_USE_TCP) && defined(APP_USE_GENERIC_TCP_CLIENT_DEMO) GenericTCPClient(); #endif #if defined(TCPIP_STACK_USE_TCP) && defined(APP_USE_GENERIC_TCP_SERVER_DEMO) GenericTCPServer(); #endif #if defined(TCPIP_STACK_USE_SMTP_CLIENT) && defined(APP_USE_SMTP_CLIENT_DEMO) SMTPDemo(); #endif #if (defined(TCPIP_STACK_USE_ICMP_CLIENT) || defined (TCPIP_STACK_USE_IPV6)) && defined(APP_USE_PING_DEMO) // use ping on the default interface PingDemoTask(); #endif #if defined(TCPIP_STACK_USE_SNMP_SERVER) && !defined(SNMP_TRAP_DISABLED) // User should use one of the following SNMP demo // This routine demonstrates V1 or V2 trap formats with one variable binding. //SNMPTrapDemo(); //This function sends the both SNMP trap version1 and 2 type of notifications #if defined(SNMP_STACK_USE_V2_TRAP) || defined(SNMP_V1_V2_TRAP_WITH_SNMPV3) //This routine provides V2 format notifications with multiple (3) variable bindings //User should modify this routine to send v2 trap format notifications with the required varbinds. SNMPV2TrapDemo(); //This function sends the SNMP trap version 2 type of notifications #endif /* SNMPSendTrap() is used to send trap notification to previously configured ip address if trap notification is enabled. There are different trap notification code. The current implementation sends trap for authentication failure (4). PreCondition: If application defined event occurs to send the trap. Declare a notification flag and update as the event occurs. Uncomment the below function if the application requires. if(notification flag is updated by the application as a predefined event occured) { SNMPSendTrap(); } */ #endif #if defined(TCPIP_STACK_USE_BERKELEY_API) && defined(APP_USE_BERKELEY_API_DEMO) BerkeleyTCPClientDemo(); BerkeleyTCPServerDemo(); BerkeleyUDPClientDemo(0); #endif // If the local IP address has changed (ex: due to DHCP lease change) // write the new IP address to the console display, UART, and Announce // service // We use the default interface for (i = 0; i < sizeof (TCPIP_HOSTS_CONFIGURATION) / sizeof (*TCPIP_HOSTS_CONFIGURATION); i++) { netH = TCPIP_STACK_NetHandle(TCPIP_HOSTS_CONFIGURATION[i].interface); if ((uint32_t) dwLastIP[i].Val != TCPIP_STACK_NetAddress(netH)) { dwLastIP[i].Val = TCPIP_STACK_NetAddress(netH); SYS_CONSOLE_PRINT("Interface Name is: %s\r\n", TCPIP_HOSTS_CONFIGURATION[i].interface); SYS_CONSOLE_MESSAGE("New IP Address is: "); DisplayIPValue(dwLastIP[i]); SYS_CONSOLE_MESSAGE("\r\n"); } } #if defined(TCPIP_STACK_USE_EVENT_NOTIFICATION) if (stackNotifyCnt) { stackNotifyCnt = 0; ProcessNotification(stackNotifyHandle); } #endif // defined(TCPIP_STACK_USE_EVENT_NOTIFICATION) #if defined(WF_UPDATE_FIRMWARE_TCPCLIENT_24G) void WF_FirmwareUpdate_TcpClient_24G(void); WF_FirmwareUpdate_TcpClient_24G(); #endif //defined(WF_UPDATE_FIRMWARE_TCPCLIENT_24G) #if defined(HOST_CM_TEST) switch (g_event) { case WF_EVENT_CONNECTION_PERMANENTLY_LOST: case WF_EVENT_CONNECTION_FAILED: g_event = 0xff; // clear current event // if host scan is active, it can be forced inactive by connection/re-connection process // so just reset host scan state to inactive. host_scan = FALSE; // host scan inactive SYS_CONSOLE_MESSAGE("Reconnecting....\r\n"); WF_Connect(); break; case WF_EVENT_CONNECTION_SUCCESSFUL: g_event = 0xff; // clear current event // if host scan is active, it can be forced inactive by connection/re-connection process // so just reset host scan state to inactive. host_scan = FALSE; // host scan inactive break; case WF_EVENT_SCAN_RESULTS_READY: g_event = 0xff; // clear current event host_scan = FALSE; // host scan inactive // Scan results are valid - OK to retrieve if (SCANCXT.numScanResults > 0) { SCAN_SET_DISPLAY(SCANCXT.scanState); SCANCXT.displayIdx = 0; while (IS_SCAN_STATE_DISPLAY(SCANCXT.scanState)) WFDisplayScanMgr(); } break; case WF_EVENT_CONNECTION_TEMPORARILY_LOST: // This event can happened when CM in module is enabled. g_event = 0xff; // clear current event // if host scan is active, it can be forced inactive by connection/re-connection process // so just reset host scan state to inactive. host_scan = FALSE; // host scan inactive break; default: //sprintf(st,"skip event = %d\r\n",g_event); //SYS_CONSOLE_MESSAGE(st); break; } if (g_DhcpSuccessful) { /* Send and Receive UDP packets */ if(UDPIsOpened(socket1)) { // UDP TX every 10 msec if(SYS_TICK_Get() - timeudp >= SYS_TICK_TicksPerSecondGet() / 100) { timeudp = SYS_TICK_Get(); tx_number++; LED0_IO ^= 1; sprintf(str,"rem=%12lu",tx_number); for(cntstr=16;cntstr<999;cntstr++) str[cntstr]=cntstr; str[999]=0; // Send tx_number (formatted in a string) if(UDPIsTxPutReady(socket1,1000)!=0) { UDPPutString(socket1,(BYTE *)str); UDPFlush(socket1); SYS_CONSOLE_MESSAGE("."); } } // UDP RX tx_number of remote board if(UDPIsGetReady(socket1)!=0) { LED1_IO ^= 1; UDPGetArray(socket1,(BYTE *)str,1000); str[16]=0; //sprintf((char*)LCDText,"%sloc=%12lu",str,tx_number); // Write on EXP16 LCD local and remote TX number //strcpypgm2ram(LCDText,str); //LCDUpdate(); SYS_CONSOLE_MESSAGE("Rx"); } } // Do host scan if((SYS_TICK_Get() - t1) >= SYS_TICK_TicksPerSecondGet() * 20) { t1 = SYS_TICK_Get(); if (!host_scan) // allow host scan if currently inactive { sprintf(st,"%d Scanning ..... event = %d\r\n",++scan_count, g_event); SYS_CONSOLE_MESSAGE(st); host_scan = TRUE; // host scan active WF_Scan(0xff); // scan on all channels } } } // DHCP status #endif //HOST_CM_TEST } }
/***************************************************************************** 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 DNSServerTask(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: Sends dummy responses that point to ourself for DNS requests * * Note: None ********************************************************************/ void DNSServerTask(void) { static UDP_SOCKET MySocket = INVALID_UDP_SOCKET; struct { WORD wTransactionID; WORD wFlags; WORD wQuestions; WORD wAnswerRRs; WORD wAuthorityRRs; WORD wAdditionalRRs; } DNSHeader; // Create a socket to listen on if this is the first time calling this function if(MySocket == INVALID_UDP_SOCKET) { //MySocket = UDPOpen(DNS_PORT, NULL, 0); MySocket = UDPOpenEx(0,UDP_OPEN_SERVER,DNS_PORT,0); return; } // See if a DNS query packet has arrived if(UDPIsGetReady(MySocket) < sizeof(DNSHeader)) return; // Read DNS header UDPGetArray((BYTE*)&DNSHeader, sizeof(DNSHeader)); // Ignore this packet if it isn't a query if((DNSHeader.wFlags & 0x8000) == 0x8000u) return; // Ignore this packet if there are no questions in it if(DNSHeader.wQuestions == 0u) return; // Block until we can transmit a DNS response packet while(!UDPIsPutReady(MySocket)); // Write DNS response packet UDPPutArray((BYTE*)&DNSHeader.wTransactionID, 2); // 2 byte Transaction ID if(DNSHeader.wFlags & 0x0100) UDPPut(0x81); // Message is a response with recursion desired else UDPPut(0x80); // Message is a response without recursion desired flag set UDPPut(0x80); // Recursion available UDPPut(0x00); // 0x0000 Questions UDPPut(0x00); UDPPut(0x00); // 0x0001 Answers RRs UDPPut(0x01); UDPPut(0x00); // 0x0000 Authority RRs UDPPut(0x00); UDPPut(0x00); // 0x0000 Additional RRs UDPPut(0x00); DNSCopyRXNameToTX(); // Copy hostname of first question over to TX packet UDPPut(0x00); // Type A Host address UDPPut(0x01); UDPPut(0x00); // Class INternet UDPPut(0x01); UDPPut(0x00); // Time to Live 10 seconds UDPPut(0x00); UDPPut(0x00); UDPPut(0x0A); UDPPut(0x00); // Data Length 4 bytes UDPPut(0x04); UDPPutArray((BYTE*)&AppConfig.MyIPAddr.Val, 4); // Our IP address #warning tim had added extra code here UDPFlush(); }
/** * Must be called every couple of ms. */ void evtTask(void) { static TICK8 tEvt = 0; static BYTE heartbeat = 20; //Buffer char buf[64]; BYTE buf2Tx; ///////////////////////////////////////////////// //Events switch(smEvt) { //UDP Event port has not been initialized yet, still waiting for MAC and IP address of remote host case SM_EVT_INIT: //Is there any data waiting for us on the "UDP Event port"? //Because of the design of the Modtronix TCP/IP stack we have to consume all data sent to us //as soon as we detect it. Store all data to a buffer as soon as it is detected if (UDPIsGetReady(udpSocketEvt)) { UDPGetArray((BYTE *)buf, 2); //Read first 2 bytes from UDP message, indicates what event ports are active. Bit0=UDP Event Port UDPDiscard(); //Not using receive, so discart msg if (hextob( (char *)buf, &activeEventPorts) == 0) { activeEventPorts = 0; //If error, disable all event ports } smEvt = SM_EVT_INIT_MSG; } break; case SM_EVT_INIT_MSG: //UDP Event port is active if ( ((activeEventPorts & EVT_PORT_UDP)!=0) && UDPIsPutReady(udpSocketEvt) ) { strcpypgm2ram(buf, (ROM char*)"l40=1;"); UDPPutArray((BYTE *)buf, strlen(buf)); // Now transmit it. UDPFlush(); smEvt = SM_EVT_IDLE; } break; case SM_EVT_IDLE: buf2Tx = 0; //Is there any data waiting for us on the "UDP Event port"? //Because of the design of the Modtronix TCP/IP stack we have to consume all data sent to us //as soon as we detect it. Store all data to a buffer as soon as it is detected if (UDPIsGetReady(udpSocketEvt)) { UDPGetArray((BYTE *)buf, 2); //Read first 2 bytes from UDP message, indicates what event ports are active. Bit0=UDP Event Port UDPDiscard(); //Not using receive, so discart msg if (hextob( (char *)buf, &activeEventPorts) == 0) { activeEventPorts = 0; //If error, disable all event ports } break; //Have to break, so stack task can be called, and UDPDiscart is executed } //Enter every 50ms if ( TickGetDiff8bit(tEvt) >= ((TICK8)TICKS_PER_SECOND / (TICK8)20) ) { tEvt = TickGet8bit(); //Every second if (--heartbeat == 0) { heartbeat = 20; //UDP Event port is active if ( ((activeEventPorts & EVT_PORT_UDP)!=0) && UDPIsPutReady(udpSocketEvt) ) { strcpypgm2ram(buf, (ROM char*)"l40=2;"); UDPPutArray((BYTE *)buf, strlen(buf)); buf2Tx |= EVT_PORT_UDP; //Indicate that data was added to UDP event port, and it must be TXed } } //Check LCD display every 50ms buf2Tx |= chkLCD(); //Check Expansion Board every 50ms buf2Tx |= chkXboard(); } //Was anything added to UDP event port if (buf2Tx & EVT_PORT_UDP) { UDPFlush(); //Transmit contents of UDP buffer } break; } }
/***************************************************************************** Function: int recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen) Summary: The recvfrom() function is used to receive incoming data that has been queued for a socket. Description: The recvfrom() function is used to receive incoming data that has been queued for a socket. This function can be used with both datagram and stream type sockets. If the available data is too large to fit in the supplied application buffer buf, excess bytes are discarded in case of SOCK_DGRAM type sockets. For SOCK_STREAM types, the data is buffered internally so the application can retreive all data by multiple calls of recvfrom. Precondition: socket function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. buf - application data receive buffer. len - buffer length in bytes. flags - message flags. Currently this is not supported. from - pointer to the sockaddr structure that will be filled in with the destination address. fromlen - size of buffer pointed by from. Returns: If recvfrom is successful, the number of bytes copied to application buffer buf is returned. A return value of SOCKET_ERROR (-1) indicates an error condition (and errno set accordingly). A value of zero indicates socket has been shutdown by the peer. Remarks: None. ***************************************************************************/ int recvfrom( SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen ) { struct BSDSocket *socket; struct sockaddr_in *rem_addr; TCP_SOCKET_INFO remoteSockInfo; int nBytes; if( s >= BSD_SOCKET_COUNT ) { errno = EBADF; return SOCKET_ERROR; } socket = &BSDSocketArray[s]; rem_addr = (struct sockaddr_in *)from; if(socket->SocketType == SOCK_DGRAM) //UDP { // If this BSD socket doesn't have a Microchip UDP socket associated // with it yet, then no data can be received and we must not use the // socket->SocketID parameter, which isn't set yet. if(socket->bsdState != SKT_BOUND) { errno = EINVAL; return SOCKET_ERROR; } if(UDPIsGetReady(socket->SocketID)) { // Capture sender information (can change packet to packet) if(from && fromlen) { if((unsigned int)*fromlen >= sizeof(struct sockaddr_in)) { rem_addr->sin_addr.S_un.S_addr = TCPIP_IPV4_GetDestAddress(UDPSocketDcpt[socket->SocketID].pTxPkt).Val; rem_addr->sin_port = UDPSocketDcpt[socket->SocketID].remotePort; *fromlen = sizeof(struct sockaddr_in); } } nBytes = UDPGetArray(socket->SocketID, (uint8_t*)buf, len); } else { nBytes = 0; } if(nBytes) { return nBytes; } errno = EWOULDBLOCK; return SOCKET_ERROR; } else //TCP recieve from already connected socket. { if(from && fromlen) { // Capture sender information (will always match socket connection information) if((unsigned int)*fromlen >= sizeof(struct sockaddr_in)) { TCPGetSocketInfo(socket->SocketID, &remoteSockInfo); rem_addr->sin_addr.S_un.S_addr = remoteSockInfo.remoteIPaddress.v4Add.Val; rem_addr->sin_port = remoteSockInfo.remotePort; *fromlen = sizeof(struct sockaddr_in); } } return recv(s, buf, len, 0); } return 0; }
/********************************************************************* * Function: void DNSServerTask(NET_CONFIG* pNet) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: Sends dummy responses that point to ourself for DNS requests * * Note: None ********************************************************************/ void DNSServerTask(NET_CONFIG* pNet) { static UDP_SOCKET MySocket = INVALID_UDP_SOCKET; static struct { uint16_t wTransactionID; uint16_t wFlags; uint16_t wQuestions; uint16_t wAnswerRRs; uint16_t wAuthorityRRs; uint16_t wAdditionalRRs; } DNSHeader; switch(dnssState) { case DNSS_STATE_START: // Create a socket to listen on if this is the first time calling this function if(MySocket == INVALID_UDP_SOCKET) { MySocket = UDPOpen(0,UDP_OPEN_SERVER,DNS_PORT,0); if(MySocket == INVALID_UDP_SOCKET) break; } UDPSocketSetNet(MySocket, pNet); dnssState = DNSS_STATE_WAIT_REQUEST; break; case DNSS_STATE_WAIT_REQUEST: // See if a DNS query packet has arrived if(UDPIsGetReady(MySocket) < sizeof(DNSHeader)) break; // Read DNS header UDPGetArray(MySocket, (uint8_t*)&DNSHeader, sizeof(DNSHeader)); // Ignore this packet if it isn't a query if((DNSHeader.wFlags & 0x8000) == 0x8000u) break; // Ignore this packet if there are no questions in it if(DNSHeader.wQuestions == 0u) break; dnssState = DNSS_STATE_PUT_REQUEST; break; case DNSS_STATE_PUT_REQUEST: // check that we can transmit a DNS response packet if(!UDPIsPutReady(MySocket)) { break; } // Write DNS response packet UDPPutArray(MySocket, (uint8_t*)&DNSHeader.wTransactionID, 2); // 2 byte Transaction ID if(DNSHeader.wFlags & 0x0100) UDPPut(MySocket, 0x81); // Message is a response with recursion desired else UDPPut(MySocket, 0x80); // Message is a response without recursion desired flag set UDPPut(MySocket, 0x80); // Recursion available UDPPut(MySocket, 0x00); // 0x0000 Questions UDPPut(MySocket, 0x00); UDPPut(MySocket, 0x00); // 0x0001 Answers RRs UDPPut(MySocket, 0x01); UDPPut(MySocket, 0x00); // 0x0000 Authority RRs UDPPut(MySocket, 0x00); UDPPut(MySocket, 0x00); // 0x0000 Additional RRs UDPPut(MySocket, 0x00); DNSCopyRXNameToTX(MySocket, pNet); // Copy hostname of first question over to TX packet UDPPut(MySocket, 0x00); // Type A Host address UDPPut(MySocket, 0x01); UDPPut(MySocket, 0x00); // Class INternet UDPPut(MySocket, 0x01); UDPPut(MySocket, 0x00); // Time to Live 10 seconds UDPPut(MySocket, 0x00); UDPPut(MySocket, 0x00); UDPPut(MySocket, 0x0A); UDPPut(MySocket, 0x00); // Data Length 4 bytes UDPPut(MySocket, 0x04); UDPPutArray(MySocket, (uint8_t*)&pNet->MyIPAddr.Val, 4); // Our IP address UDPFlush(MySocket); dnssState = DNSS_STATE_DONE; break; case DNSS_STATE_DONE: break; } }
void Command() { switch (Cmd_Read_Switch) { case 0 : if(UDPIsGetReady(socket2)) { SuccesFull_Read = UDPGetArray(Cmd, 0x3); if (Cmd[0] == Enter || Cmd[0] == 0 || SuccesFull_Read < 3) { Cmd_Read_Switch = 0; Cmd[0] = 0; break; } else if (Cmd[2] == Enter) { Cmd_Read_Switch = 0; Command_Exe(Cmd); } Cmd_Read_Switch = 0; Cmd[0] = 0; Cmd[1] = 0; Cmd[2] = 0; break; } break; case 20 : if(!MACIsLinked()) { return; } #if defined(STACK_USE_DHCP_CLIENT) { static DWORD dwTimer = 0; // Wait until DHCP module is finished if(!DHCPIsBound(0)) { dwTimer = TickGet(); return; } // Wait an additional half second after DHCP is finished to let the announce module and any other stack state machines to reach normal operation if(TickGet() - dwTimer < TICK_SECOND/2) return; } #endif Cmd_Read_Switch = 21; break; case 21 : socket2 = UDPOpen(0x6FFF, NULL, 0x6FFF); //open the socket if(socket2 == 0xFF) //Invalid socket { break; } else{Cmd_Read_Switch = 0;} Led1=1; Output_Enable = 1; break; default : break; } }
/***************************************************************************** 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 }
void EthernetRun(void (*ProcessData)(BYTE *data, WORD dataLen)) { // Now that all items are initialized, begin the co-operative // multitasking loop. This infinite loop will continuously // execute all stack-related tasks, as well as your own // application's functions. Custom functions should be added // at the end of this loop. // Note that this is a "co-operative mult-tasking" mechanism // where every task performs its tasks (whether all in one shot // or part of it) and returns so that other tasks can do their // job. // If a task needs very long time to do its job, it must be broken // down into smaller pieces so that other tasks can have CPU time. // First prepare all UDP stuff. UDPTask(); WORD dataCount; IP_ADDR tempLocalIP; BYTE cFrameType; BYTE cIPFrameType; // And then process incoming data ending this loop once a valid packet is received. int cont = 1; while (cont) { // Before fetching new data, be sure all old UDP data is discarded. UDPDiscard(); // Fetch a packet. We stop receiving data if no data is waiting. if (!MACGetHeader(&remoteNode.MACAddr, &cFrameType)) { break; } // And now process the packet. switch(cFrameType) { // Process any ARP packets. These are used for determining a MAC-to-IP mapping. case MAC_ARP: ARPProcess(); break; // Process any IP packets (of which UDP is a type). case MAC_IP: // If the received packet is not a valid IP packet, ignore it. if (!IPGetHeader(&tempLocalIP, &remoteNode, &cIPFrameType, &dataCount)) { break; } // Now if we've found a valid UDP packet, quit processing data. if (cIPFrameType == IP_PROT_UDP) { // Stop processing data if we came upon a complete UDP packet. if (UDPProcess(&remoteNode, &tempLocalIP, dataCount)) { cont = 0; } } break; } } // Send new UDP data to processing function. if (ProcessData) { WORD dataLen = 0; if ((dataLen = UDPIsGetReady(localServerSocket))) { BYTE data[dataLen]; if (UDPGetArray(data, dataLen) == dataLen) { ProcessData(data, dataLen); } } } // Now run the DHCP server task. This needs to be run continuously as there's no way to tell // if any clients are connected to perform the lease once post-init. The default lease time // is also super short, 60s, so the server needs to be able to process new DHCP stuff. DHCPServerTask(); }
/***************************************************************************** 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(); }
/***************************************************************************** Function: int recv( SOCKET s, char* buf, int len, int flags ) Summary: The recv() function is used to receive incoming data that has been queued for a socket. Description: The recv() function is used to receive incoming data that has been queued for a socket. This function can be used with both datagram and stream socket. If the available data is too large to fit in the supplied application buffer buf, excess bytes are discarded in case of SOCK_DGRAM type sockets. For SOCK_STREAM types, the data is buffered internally so the application can retreive all data by multiple calls of recvfrom. Precondition: connect function should be called for TCP and UDP sockets. Server side, accept function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. buf - application data receive buffer. len - buffer length in bytes. flags - no significance in this implementation Returns: If recv is successful, the number of bytes copied to application buffer buf is returned. A return value of SOCKET_ERROR (-1) indicates an error condition (and errno set accordingly). A value of zero indicates socket has been shutdown by the peer. Remarks: None. ***************************************************************************/ int recv( SOCKET s, char* buf, int len, int flags ) { struct BSDSocket *socket; int nBytes; if( s >= BSD_SOCKET_COUNT ) { errno = EBADF; return SOCKET_ERROR; } socket = &BSDSocketArray[s]; if(socket->SocketType == SOCK_STREAM) //TCP { if(socket->bsdState != SKT_EST) { errno = ENOTCONN; return SOCKET_ERROR; } if(HandlePossibleTCPDisconnection(s)) { errno = ECONNRESET; return SOCKET_ERROR; } nBytes = TCPGetArray(socket->SocketID, (uint8_t*)buf, len); if(nBytes) { return nBytes; } errno = EWOULDBLOCK; return SOCKET_ERROR; } else if(socket->SocketType == SOCK_DGRAM) //UDP { if(socket->bsdState != SKT_BOUND) { errno = EINVAL; return SOCKET_ERROR; } if(UDPIsGetReady(socket->SocketID)) { nBytes = UDPGetArray(socket->SocketID, (uint8_t*)buf, len); } else { nBytes = 0; } if(nBytes) { return nBytes; } errno = EWOULDBLOCK; return SOCKET_ERROR; } return 0; }
void NTPTask(void) { NTP_PACKET pkt; WORD w; switch(NTPState) { case NTP_HOME: debug_ntp(debug_putc, "\r\n\nRefreshing Time\r\n"); // Obtain ownership of the DNS resolution module if(!DNSBeginUsage()) break; // Obtain the IP address associated with the server name DNSResolveROM((ROM BYTE*)NTP_SERVER, DNS_TYPE_A); rtcTimer = time(NULL); NTPState = NTP_NAME_RESOLVE; break; case NTP_NAME_RESOLVE: // Wait for DNS resolution to complete if(!DNSIsResolved(&Server.IPAddr)) { if((time(NULL) - rtcTimer) >= NTP_RESOLVE_TIMEOUT) { DNSEndUsage(); rtcTimer = time(NULL); NTPState = NTP_SHORT_WAIT; } break; } // Obtain DNS resolution result if(!DNSEndUsage()) { // No valid IP address was returned from the DNS // server. Quit and fail for a while if host is not valid. rtcTimer = time(NULL); NTPState = NTP_SHORT_WAIT; break; } NTPState = NTP_ARP_START_RESOLVE; // No need to break case NTP_ARP_START_RESOLVE: case NTP_ARP_START_RESOLVE2: case NTP_ARP_START_RESOLVE3: // Obtain the MAC address associated with the server's IP address ARPResolve(&Server.IPAddr); rtcTimer = time(NULL); NTPState++; break; case NTP_ARP_RESOLVE: case NTP_ARP_RESOLVE2: case NTP_ARP_RESOLVE3: // Wait for the MAC address to finish being obtained if(!ARPIsResolved(&Server.IPAddr, &Server.MACAddr)) { // Time out if too much time is spent in this state if(time(NULL) - rtcTimer >= NTP_ARP_TIMEOUT) { // Retransmit ARP request by going to next SM_ARP_START_RESOLVE state or fail by going to SM_ARP_RESOLVE_FAIL state. NTPState++; } break; } NTPState = NTP_UDP_SEND; break; case NTP_ARP_RESOLVE_FAIL: // ARP failed after 3 tries, abort and wait for next time query rtcTimer = time(NULL); NTPState = NTP_SHORT_WAIT; break; case NTP_UDP_SEND: // Open up the sending UDP socket MySocket = UDPOpen(NTP_LOCAL_PORT, &Server, NTP_SERVER_PORT); if(MySocket == INVALID_UDP_SOCKET) break; // Make certain the socket can be written to if(!UDPIsPutReady(MySocket)) { UDPClose(MySocket); break; } // Transmit a time request packet memset(&pkt, 0, sizeof(pkt)); pkt.flags.versionNumber = 3; // NTP Version 3 pkt.flags.mode = 3; // NTP Client pkt.orig_ts_secs = swapl(NTP_EPOCH); UDPPutArray((BYTE*) &pkt, sizeof(pkt)); UDPFlush(); //dwTimer = TickGet(); rtcTimer = time(NULL); NTPState = NTP_UDP_RECV; break; case NTP_UDP_RECV: // Look for a response time packet if(!UDPIsGetReady(MySocket)) { if((time(NULL)) - rtcTimer >= NTP_REPLY_TIMEOUT) { // Abort the request and wait until the next timeout period UDPClose(MySocket); rtcTimer = time(NULL); NTPState = NTP_SHORT_WAIT; break; } break; } // Get the response time packet w = UDPGetArray((BYTE*) &pkt, sizeof(pkt)); UDPClose(MySocket); rtcTimer = time(NULL); // Validate packet size if(w != sizeof(pkt)) { NTPState = NTP_SHORT_WAIT; break; } g_NTPOk = TRUE; NTPState = NTP_WAIT; // Set out local time to match the returned time NTPLastUpdate = swapl(pkt.tx_ts_secs) - NTP_EPOCH; // Do rounding. If the partial seconds is > 0.5 then add 1 to the seconds count. if(((BYTE*)&pkt.tx_ts_fraq)[0] & 0x80) NTPLastUpdate++; SetTimeSec(NTPLastUpdate); break; case NTP_SHORT_WAIT: // Attempt to requery the NTP server after a specified NTP_FAST_QUERY_INTERVAL time (ex: 8 seconds) has elapsed. g_NTPOk = FALSE; if(time(NULL) - rtcTimer >= NTP_WAIT_INTERVAL) NTPState = NTP_HOME; break; case NTP_WAIT: // Requery the NTP server after a specified NTP_QUERY_INTERVAL time (ex: 10 minutes) has elapsed. if(time(NULL) - NTPLastUpdate >= NTP_QUERY_INTERVAL) NTPState = NTP_HOME; break; } }
/***************************************************************************** Function: int recv( SOCKET s, char* buf, int len, int flags ) Summary: The recv() function is used to receive incoming data that has been queued for a socket. Description: The recv() function is used to receive incoming data that has been queued for a socket. This function can be used with both datagram and stream socket. If the available data is too large to fit in the supplied application buffer buf, the data is buffered internally so the application can retreive all data by multiple calls of recv. Precondition: connect function should be called for TCP and UDP sockets. Server side, accept function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. buf - application data receive buffer. len - buffer length in bytes. flags - no significance in this implementation Returns: If recv is successful, the number of bytes copied to application buffer buf is returned. A value of zero indicates no data available. A return value of SOCKET_ERROR (-1) indicates an error condition. A return value of SOCKET_DISCONNECTED indicates the connection no longer exists. Remarks: None. ***************************************************************************/ int recv( SOCKET s, char* buf, int len, int flags ) { struct BSDSocket *socket; NODE_INFO remoteInfo; static DWORD startTick; if( s >= BSD_SOCKET_COUNT ) return SOCKET_ERROR; socket = &BSDSocketArray[s]; if( socket->bsdState < SKT_BOUND ) return SOCKET_ERROR; if(socket->SocketType == SOCK_STREAM) //TCP { if(!TCPIsConnected(socket->SocketID)) { return SOCKET_DISCONNECTED; } if(TCPIsGetReady(socket->SocketID)) { return TCPGetArray(socket->SocketID, (BYTE*)buf, len); } } else if(socket->SocketType == SOCK_DGRAM) //UDP { if((socket->bsdState >= SKT_READY) && (socket->bsdState != SKT_EST))//making sure that connect function is called { if(socket->bsdState != SKT_ARP_VERIFY) { remoteInfo.IPAddr.Val = socket->remoteIP; ARPResolve(&remoteInfo.IPAddr); startTick = TickGet(); socket->bsdState = SKT_ARP_VERIFY; } else if(socket->bsdState == SKT_ARP_VERIFY) { // Wait for the MAC address to finish being obtained remoteInfo.IPAddr.Val = socket->remoteIP; if(!ARPIsResolved(&remoteInfo.IPAddr, &remoteInfo.MACAddr)) { // Time out if too much time is spent in this state if(TickGet()- startTick > 1*TICK_SECOND) { // Retransmit ARP request socket->bsdState = SKT_ARP_RESOLVE; } } socket->SocketID = UDPOpen(socket->localPort, &remoteInfo, socket->remotePort); socket->bsdState = SKT_EST; } } if(socket->bsdState == SKT_EST) { if(UDPIsGetReady(socket->SocketID) > 0) { return UDPGetArray((BYTE*)buf, len); } } } return 0; }
/***************************************************************************** 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: 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(); }
/***************************************************************************** Function: void SNTPClient(void) Summary: Periodically checks the current time from a pool of servers. Description: This function periodically checks a pool of time servers to obtain the current date/time. Precondition: UDP is initialized. Parameters: None Returns: None Remarks: This function requires once available UDP socket while processing, but frees that socket when the SNTP module is idle. ***************************************************************************/ void SNTPClient(void) { NTP_PACKET pkt; WORD w; // static NODE_INFO Server; static DWORD dwTimer; static UDP_SOCKET MySocket = INVALID_UDP_SOCKET; static enum { SM_HOME = 0, SM_UDP_IS_OPENED, //SM_NAME_RESOLVE, //SM_ARP_START_RESOLVE, //SM_ARP_RESOLVE, //SM_ARP_START_RESOLVE2, //SM_ARP_RESOLVE2, //SM_ARP_START_RESOLVE3, //SM_ARP_RESOLVE3, //SM_ARP_RESOLVE_FAIL, SM_UDP_SEND, SM_UDP_RECV, SM_SHORT_WAIT, SM_WAIT } SNTPState = SM_HOME; switch(SNTPState) { case SM_HOME: if(MySocket == INVALID_UDP_SOCKET) MySocket = UDPOpenEx((DWORD)(PTR_BASE)NTP_SERVER,UDP_OPEN_ROM_HOST,0,NTP_SERVER_PORT); SNTPState++; break; case SM_UDP_IS_OPENED: if(UDPIsOpened(MySocket) == TRUE) { SNTPState = SM_UDP_SEND; } /* else { UDPClose(MySocket); SNTPState = SM_HOME; MySocket = INVALID_UDP_SOCKET; } */ break; #if 0 // Obtain ownership of the DNS resolution module if(!DNSBeginUsage()) break; // Obtain the IP address associated with the server name DNSResolveROM((ROM BYTE*)NTP_SERVER, DNS_TYPE_A); dwTimer = TickGet(); SNTPState = SM_NAME_RESOLVE; break; case SM_NAME_RESOLVE: // Wait for DNS resolution to complete if(!DNSIsResolved(&Server.IPAddr)) { if((TickGet() - dwTimer) > (5 * TICK_SECOND)) { DNSEndUsage(); dwTimer = TickGetDiv64K(); SNTPState = SM_SHORT_WAIT; } break; } // Obtain DNS resolution result if(!DNSEndUsage()) { // No valid IP address was returned from the DNS // server. Quit and fail for a while if host is not valid. dwTimer = TickGetDiv64K(); SNTPState = SM_SHORT_WAIT; break; } SNTPState = SM_ARP_START_RESOLVE; // No need to break case SM_ARP_START_RESOLVE: case SM_ARP_START_RESOLVE2: case SM_ARP_START_RESOLVE3: // Obtain the MAC address associated with the server's IP address ARPResolve(&Server.IPAddr); dwTimer = TickGet(); SNTPState++; break; case SM_ARP_RESOLVE: case SM_ARP_RESOLVE2: case SM_ARP_RESOLVE3: // Wait for the MAC address to finish being obtained if(!ARPIsResolved(&Server.IPAddr, &Server.MACAddr)) { // Time out if too much time is spent in this state if(TickGet() - dwTimer > 1*TICK_SECOND) { // Retransmit ARP request by going to next SM_ARP_START_RESOLVE state or fail by going to SM_ARP_RESOLVE_FAIL state. SNTPState++; } break; } SNTPState = SM_UDP_SEND; break; case SM_ARP_RESOLVE_FAIL: // ARP failed after 3 tries, abort and wait for next time query dwTimer = TickGetDiv64K(); SNTPState = SM_SHORT_WAIT; break; #endif // case SM_UDP_IS_OPENED: case SM_UDP_SEND: // Open up the sending UDP socket //MySocket = UDPOpen(0, &Server, NTP_SERVER_PORT); #if 0 MySocket = UDPOpenEx(NTP_SERVER,UDP_OPEN_ROM_HOST,0,NTP_SERVER_PORT); if(MySocket == INVALID_UDP_SOCKET) break; #endif // Make certain the socket can be written to if(!UDPIsPutReady(MySocket)) { UDPClose(MySocket); SNTPState = SM_HOME; MySocket = INVALID_UDP_SOCKET; break; } // Transmit a time request packet memset(&pkt, 0, sizeof(pkt)); pkt.flags.versionNumber = 3; // NTP Version 3 pkt.flags.mode = 3; // NTP Client pkt.orig_ts_secs = swapl(NTP_EPOCH); UDPPutArray((BYTE*) &pkt, sizeof(pkt)); UDPFlush(); dwTimer = TickGet(); SNTPState = SM_UDP_RECV; break; case SM_UDP_RECV: // Look for a response time packet if(!UDPIsGetReady(MySocket)) { if((TickGet()) - dwTimer > NTP_REPLY_TIMEOUT) { // Abort the request and wait until the next timeout period UDPClose(MySocket); //dwTimer = TickGetDiv64K(); //SNTPState = SM_SHORT_WAIT; SNTPState = SM_HOME; MySocket = INVALID_UDP_SOCKET; break; } break; } // Get the response time packet w = UDPGetArray((BYTE*) &pkt, sizeof(pkt)); UDPClose(MySocket); dwTimer = TickGetDiv64K(); SNTPState = SM_WAIT; MySocket = INVALID_UDP_SOCKET; // Validate packet size if(w != sizeof(pkt)) { break; } // Set out local time to match the returned time dwLastUpdateTick = TickGet(); dwSNTPSeconds = swapl(pkt.tx_ts_secs) - NTP_EPOCH; // Do rounding. If the partial seconds is > 0.5 then add 1 to the seconds count. if(((BYTE*)&pkt.tx_ts_fraq)[0] & 0x80) dwSNTPSeconds++; #ifdef WIFI_NET_TEST wifi_net_test_print("SNTP: current time", dwSNTPSeconds); #endif break; case SM_SHORT_WAIT: // Attempt to requery the NTP server after a specified NTP_FAST_QUERY_INTERVAL time (ex: 8 seconds) has elapsed. if(TickGetDiv64K() - dwTimer > (NTP_FAST_QUERY_INTERVAL/65536ull)) { SNTPState = SM_HOME; MySocket = INVALID_UDP_SOCKET; } break; case SM_WAIT: // Requery the NTP server after a specified NTP_QUERY_INTERVAL time (ex: 10 minutes) has elapsed. if(TickGetDiv64K() - dwTimer > (NTP_QUERY_INTERVAL/65536ull)) { SNTPState = SM_HOME; MySocket = INVALID_UDP_SOCKET; } 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_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; }
/***************************************************************************** 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 ); }
void CmdCheck() { #if MAX_UDP_SOCKETS_FREERTOS>0 //UDP Stack activeUdpSocket=0; while (activeUdpSocket < MAX_UDP_SOCKETS_FREERTOS) { //Ring Buffer if(udpSocket[activeUdpSocket] != INVALID_UDP_SOCKET) { //reads udp data and adds in ring buffer udpRxLen[activeUdpSocket] = UDPIsGetReady(udpSocket[activeUdpSocket]); if(udpRxLen[activeUdpSocket] > (BUFFER_UDP_LEN[activeUdpSocket] - udpRxLenGlobal[activeUdpSocket])) { // Since there is not enough space to store the packet, // discard all the transceiver RAM content related to UDP datadiscard = udpRxLen[activeUdpSocket]; // Set the Overflow Flags UDPoverflow = 1; UDPoverflowFlag[activeUdpSocket] = 1; // Now discard all remaining data in Udp Rx: // Create a dummy array BYTE removeArray[BUFFER_UDP_FIXED_LEN]; // update the datadiscard value while(datadiscard > 0) { datadiscard -= UDPGetArray(removeArray, BUFFER_UDP_FIXED_LEN); } } if (udpRxLen[activeUdpSocket] > 0) { if( (p_udp_wifiram[activeUdpSocket]+udpRxLen[activeUdpSocket]) <= (udpBuffer[activeUdpSocket]+BUFFER_UDP_LEN[activeUdpSocket]) ) //append to buffer { UDPGetArray(p_udp_wifiram[activeUdpSocket], udpRxLen[activeUdpSocket]); //data p_udp_wifiram[activeUdpSocket] += udpRxLen[activeUdpSocket]; } else //append to buffer near end, or add to buffer from start { tmp_len[activeUdpSocket] = ((udpBuffer[activeUdpSocket]+BUFFER_UDP_LEN[activeUdpSocket]) - p_udp_wifiram[activeUdpSocket]); //free space on ring buffer if(tmp_len[activeUdpSocket] > 0) //fill buffer and add data from start { UDPGetArray(p_udp_wifiram[activeUdpSocket], tmp_len[activeUdpSocket]); p_udp_wifiram[activeUdpSocket] = udpBuffer[activeUdpSocket]; UDPGetArray(p_udp_wifiram[activeUdpSocket], udpRxLen[activeUdpSocket] - tmp_len[activeUdpSocket] ); p_udp_wifiram[activeUdpSocket] += (udpRxLen[activeUdpSocket] - tmp_len[activeUdpSocket]); } else //add data to buffer from start { p_udp_wifiram[activeUdpSocket] = udpBuffer[activeUdpSocket]; UDPGetArray(p_udp_wifiram[activeUdpSocket], udpRxLen[activeUdpSocket]); p_udp_wifiram[activeUdpSocket] += udpRxLen[activeUdpSocket]; } } udpRxLenGlobal[activeUdpSocket] += udpRxLen[activeUdpSocket]; } //end ring buffer } activeUdpSocket++; } #endif //UDP STACK if (Cmd != 0) { int fresult = 0; while (xSemaphoreTake(xSemFrontEnd,0) != pdTRUE); if (xFrontEndStat == 1) { fresult = FP[Cmd](); xFrontEndStat = xFrontEndStatRet; xSemaphoreGive(xSemFrontEnd); Cmd = 0; taskYIELD(); } } }