/***************************************************************************** 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; }
/********************************************************************* * Function: void ANNOUNCE_Task(void) * * Summary: Announce callback task. * * PreCondition: Stack is initialized() * * Input: None * * Output: None * * Side Effects: None * * Overview: Recurring task used to listen for Discovery * messages on the specified ANNOUNCE_PORT. These * messages can be sent using the TCP/IP * Discoverer tool. If one is received, this * function will transmit a reply. * * Note: A UDP socket must be available before this * function is called. It is freed at the end of * the function. UDP_MAX_SOCKETS may need to be * increased if other modules use UDP sockets. ********************************************************************/ void ANNOUNCE_Task(NET_CONFIG * pNetIf) { static enum { DISCOVERY_HOME = 0, DISCOVERY_LISTEN, DISCOVERY_REQUEST_RECEIVED, DISCOVERY_DISABLED } DiscoverySM[TCPIP_NETWORK_INTERFACES] = {DISCOVERY_HOME}; static UDP_SOCKET MySocket[TCPIP_NETWORK_INTERFACES]; uint8_t i; int netIx; UDP_SOCKET s; if(!pNetIf) { return; } else { netIx = _TCPIPStackNetIx(pNetIf); } s = MySocket[netIx]; switch(DiscoverySM[netIx]) { case DISCOVERY_HOME: // Open a UDP socket for inbound and outbound transmission // Since we expect to only receive broadcast packets and // only send unicast packets directly to the node we last // received from, the remote NodeInfo parameter can be anything MySocket[netIx] = UDPOpen(0,UDP_OPEN_SERVER,ANNOUNCE_PORT, ANNOUNCE_PORT); if(MySocket[netIx] == INVALID_UDP_SOCKET) { return; } else { DiscoverySM[netIx]++; UDPSocketSetNet(MySocket[netIx], pNetIf); } break; case DISCOVERY_LISTEN: // Do nothing if no data is waiting if(!UDPIsGetReady(s)) return; // See if this is a discovery query or reply UDPGet(s, &i); UDPDiscard(s); if(i != 'D') return; // We received a discovery request, reply when we can DiscoverySM[netIx]++; // Change the destination to the unicast address of the last received packet TCPIP_IPV4_SetDestAddress(UDPSocketDcpt[s].pTxPkt,remoteNode.IPAddr.Val); memcpy((void*)&UDPSocketDcpt[s].pTxPkt->remoteMACAddr, (const void*)&remoteNode.MACAddr, sizeof(MAC_ADDR)); // No break needed. If we get down here, we are now ready for the DISCOVERY_REQUEST_RECEIVED state case DISCOVERY_REQUEST_RECEIVED: ANNOUNCE_Notify (pNetIf, 0, NULL); // Listen for other discovery requests DiscoverySM[netIx] = DISCOVERY_LISTEN; break; case DISCOVERY_DISABLED: break; } }
/********************************************************************* * Function: void NBNSTask(NET_CONFIG* pConfig) * * PreCondition: None * * Input: pConfig - interface * * Output: None * * Side Effects: None * * Overview: Sends responses to NetBIOS name requests * * Note: None ********************************************************************/ void NBNSTask(NET_CONFIG* pConfig) { uint8_t i; TCPIP_UINT16_VAL Type, Class; NBNS_HEADER NBNSHeader; uint8_t NameString[16]; int netIx; UDP_SOCKET s; netIx = _TCPIPStackNetIx(pConfig); s = MySocket[netIx]; switch(smNBNS[netIx]) { case NBNS_HOME: smNBNS[netIx]++; break; case NBNS_OPEN_SOCKET: MySocket[netIx] = UDPOpen(0,UDP_OPEN_SERVER,NBNS_PORT,NBNS_PORT); if(MySocket[netIx] == INVALID_UDP_SOCKET) break; UDPSocketSetNet(MySocket[netIx], pConfig); smNBNS[netIx]++; case NBNS_LISTEN: if(!UDPIsGetReady(s)) { break; } // Respond only to name requests sent to us from nodes on the same subnet // This prevents us from sending out the wrong IP address information if // we haven't gotten a DHCP lease yet. if((remoteNode.IPAddr.Val & pConfig->MyMask.Val) != (pConfig->MyIPAddr.Val & pConfig->MyMask.Val)) { UDPDiscard(s); break; } // Retrieve the NBNS header and de-big-endian it UDPGet(s, &NBNSHeader.TransactionID.v[1]); UDPGet(s, &NBNSHeader.TransactionID.v[0]); UDPGet(s, &NBNSHeader.Flags.v[1]); UDPGet(s, &NBNSHeader.Flags.v[0]); UDPGet(s, &NBNSHeader.Questions.v[1]); UDPGet(s, &NBNSHeader.Questions.v[0]); UDPGet(s, &NBNSHeader.Answers.v[1]); UDPGet(s, &NBNSHeader.Answers.v[0]); UDPGet(s, &NBNSHeader.AuthoritativeRecords.v[1]); UDPGet(s, &NBNSHeader.AuthoritativeRecords.v[0]); UDPGet(s, &NBNSHeader.AdditionalRecords.v[1]); UDPGet(s, &NBNSHeader.AdditionalRecords.v[0]); // Remove all questions while(NBNSHeader.Questions.Val--) { NBNSGetName(s, NameString); UDPGet(s, &i); // <??> Trailing character on string UDPGet(s, &Type.v[1]); // Question type UDPGet(s, &Type.v[0]); UDPGet(s, &Class.v[1]); // Question class UDPGet(s, &Class.v[0]); if(Type.Val == 0x0020u && Class.Val == 0x0001u && memcmp((void*)NameString, (void*)pConfig->NetBIOSName, sizeof(pConfig->NetBIOSName)) == 0) { if(UDPIsTxPutReady(s, 64)) { NBNSHeader.Flags.Val = 0x8400; UDPPut(s, NBNSHeader.TransactionID.v[1]); UDPPut(s, NBNSHeader.TransactionID.v[0]); UDPPut(s, NBNSHeader.Flags.v[1]); UDPPut(s, NBNSHeader.Flags.v[0]); UDPPut(s, 0x00); // 0x0000 Questions UDPPut(s, 0x00); UDPPut(s, 0x00); // 0x0001 Answers UDPPut(s, 0x01); UDPPut(s, 0x00); // 0x0000 Athoritative records UDPPut(s, 0x00); UDPPut(s, 0x00); // 0x0000 Additional records UDPPut(s, 0x00); NBNSPutName(s, pConfig->NetBIOSName); UDPPut(s, 0x00); // 0x0020 Type: NetBIOS UDPPut(s, 0x20); UDPPut(s, 0x00); // 0x0001 Class: Internet UDPPut(s, 0x01); UDPPut(s, 0x00); // 0x00000000 Time To Live UDPPut(s, 0x00); UDPPut(s, 0x00); UDPPut(s, 0x00); UDPPut(s, 0x00); // 0x0006 Data length UDPPut(s, 0x06); UDPPut(s, 0x60); // 0x6000 Flags: H-node, Unique UDPPut(s, 0x00); UDPPut(s, pConfig->MyIPAddr.v[0]); // Put out IP address UDPPut(s, pConfig->MyIPAddr.v[1]); UDPPut(s, pConfig->MyIPAddr.v[2]); UDPPut(s, pConfig->MyIPAddr.v[3]); // Change the destination address to the unicast address of the last received packet TCPIP_IPV4_SetDestAddress(UDPSocketDcpt[s].pTxPkt,remoteNode.IPAddr.Val); memcpy((void*)&UDPSocketDcpt[s].pTxPkt->remoteMACAddr, (const void*)&remoteNode.MACAddr, sizeof(remoteNode.MACAddr)); UDPFlush(s); } } } UDPDiscard(s); break; } }