/***************************************************************************** Function: static void DHCPReplyToDiscovery(BOOTP_HEADER *Header, int netIx) Summary: Replies to a DHCP Discover message. Description: This function replies to a DHCP Discover message by sending out a DHCP Offer message. Precondition: None Parameters: Header - the BootP header this is in response to. netIx - interface index Returns: None ***************************************************************************/ static void DHCPReplyToDiscovery(BOOTP_HEADER *Header, 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); // 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)); UDPPut(s, 0x00); // Your (client) IP Address: 0.0.0.0 (none yet assigned) UDPPut(s, 0x00); // Your (client) IP Address: 0.0.0.0 (none yet assigned) UDPPut(s, 0x00); // Your (client) IP Address: 0.0.0.0 (none yet assigned) UDPPut(s, 0x00); // Your (client) IP Address: 0.0.0.0 (none yet assigned) 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 Offer UDPPut(s, DHCP_MESSAGE_TYPE); UDPPut(s, 1); UDPPut(s, DHCP_OFFER_MESSAGE); // Option: Subnet Mask UDPPut(s, DHCP_SUBNET_MASK); UDPPut(s, sizeof(IP_ADDR)); UDPPutArray(s, (uint8_t*)&pConfig->MyMask, sizeof(IP_ADDR)); // 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: 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: 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: int sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen) Summary: This function used to send the data for both connection oriented and connection-less sockets. Description: The sendto function is used to send outgoing data on a socket. The destination address is given by to and tolen. Both Datagram and stream sockets are supported. Precondition: socket function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. buf - application data buffer containing data to transmit. len - length of data in bytes. flags - message flags. Currently this field is not supported. to - Optional pointer to the the sockaddr structure containing the destination address. If NULL, the currently bound remote port and IP address are used as the destination. tolen - length of the sockaddr structure. Returns: On success, sendto returns number of bytes sent. In case of error returns SOCKET_ERROR (and errno set accordingly). Remarks: None. ***************************************************************************/ int sendto( SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen ) { struct BSDSocket *socket; UDP_SOCKET_DCPT* udpSkt; int size = SOCKET_ERROR; NODE_INFO remoteInfo; uint16_t wRemotePort; struct sockaddr_in local; if( s >= BSD_SOCKET_COUNT ) { errno = EBADF; return SOCKET_ERROR; } socket = &BSDSocketArray[s]; if(socket->bsdState == SKT_CLOSED) { errno = EBADF; return SOCKET_ERROR; } if(socket->SocketType == SOCK_DGRAM) //UDP { // Decide the destination IP address and port remoteInfo.IPAddr.Val = socket->remoteIP; wRemotePort = socket->remotePort; if(to) { if((unsigned int)tolen != sizeof(struct sockaddr_in)) { errno = EFAULT; return SOCKET_ERROR; } wRemotePort = ((struct sockaddr_in*)to)->sin_port; remoteInfo.IPAddr.Val = ((struct sockaddr_in*)to)->sin_addr.s_addr; // Implicitly bind the socket if it isn't already if(socket->bsdState == SKT_CREATED) { memset(&local, 0x00, sizeof(local)); if(bind(s, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR) return SOCKET_ERROR; } } if(remoteInfo.IPAddr.Val == IP_ADDR_ANY) remoteInfo.IPAddr.Val = 0xFFFFFFFFu; // Set the remote IP and MAC address if it is different from what we already have stored in the UDP socket udpSkt = UDPSocketDcpt + socket->SocketID; if(TCPIP_IPV4_GetDestAddress(udpSkt->pTxPkt).Val != remoteInfo.IPAddr.Val) { TCPIP_IPV4_SetDestAddress(udpSkt->pTxPkt, remoteInfo.IPAddr.Val); if(!ARPIsResolved(UDPSocketGetNet(socket->SocketID), &remoteInfo.IPAddr, &((IPV4_PACKET*)udpSkt->pTxPkt)->remoteMACAddr)) { errno = EINPROGRESS; return SOCKET_ERROR; } } // Select the UDP socket and see if we can write to it if(UDPIsTxPutReady(socket->SocketID, len)) { // Set the proper remote port udpSkt->remotePort = wRemotePort; // Write data and send UDP datagram size = UDPPutArray(socket->SocketID, (uint8_t*)buf, len); UDPFlush(socket->SocketID); return size; } } else if(socket->SocketType == SOCK_STREAM) //TCP will only send to the already established socket. { if(socket->bsdState != SKT_EST) { errno = ENOTCONN; return SOCKET_ERROR; } if(HandlePossibleTCPDisconnection(s)) { errno = ECONNRESET; return SOCKET_ERROR; } // Handle special case were 0 return value is okay if(len == 0) return 0; // Write data to the socket. If one or more bytes were written, then // return this value. Otherwise, fail and return SOCKET_ERROR. size = TCPPutArray(socket->SocketID, (uint8_t*)buf, len); if(size) return size; } errno = EWOULDBLOCK; return SOCKET_ERROR; }