Пример #1
0
/*****************************************************************************
  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;
}
Пример #2
0
/*********************************************************************
 * 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;
	}	

}
Пример #3
0
/*********************************************************************
 * 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;
	}
}