Exemplo n.º 1
0
Arquivo: tftp.c Projeto: ryenus/vbox
DECLINLINE(int) tftpSendError(PNATState pData,
                              PTFTPSESSION pTftpSession,
                              uint16_t errorcode,
                              const char *msg,
                              PCTFTPIPHDR pcTftpIpHeaderRecv)
{
    struct mbuf *m = NULL;
    PTFTPIPHDR pTftpIpHeader = NULL;

    LogFlowFunc(("ENTER: errorcode: %RX16, msg: %s\n", errorcode, msg));
    m = slirpTftpMbufAlloc(pData);
    if (!m)
    {
        LogFlowFunc(("LEAVE: Can't allocate mbuf\n"));
        return -1;
    }

    m->m_data += if_maxlinkhdr;
    m->m_len = sizeof(TFTPIPHDR)
             + strlen(msg) + 1; /* ending zero */
    m->m_pkthdr.header = mtod(m, void *);
    pTftpIpHeader = mtod(m, PTFTPIPHDR);

    pTftpIpHeader->u16TftpOpType = RT_H2N_U16_C(TFTP_ERROR);
    pTftpIpHeader->Core.u16TftpOpCode = RT_H2N_U16(errorcode);

    m_copyback(pData, m, sizeof(TFTPIPHDR), strlen(msg) + 1 /* copy ending zerro*/, (c_caddr_t)msg);

    tftpSend(pData, pTftpSession, m, pcTftpIpHeaderRecv);

    tftpSessionTerminate(pTftpSession);

    LogFlowFuncLeave();
    return 0;
}
Exemplo n.º 2
0
Arquivo: tftp.c Projeto: ryenus/vbox
static int tftpSendData(PNATState pData,
                          PTFTPSESSION pTftpSession,
                          uint16_t u16Block,
                          PCTFTPIPHDR pcTftpIpHeaderRecv)
{
    struct mbuf *m;
    PTFTPIPHDR pTftpIpHeader;
    int cbRead = 0;
    int rc = VINF_SUCCESS;

    if (u16Block == pTftpSession->cTftpAck)
        pTftpSession->cTftpAck++;
    else
    {
        tftpSendError(pData, pTftpSession, 6, "ACK is wrong", pcTftpIpHeaderRecv);
        tftpSessionTerminate(pTftpSession);
        return -1;
    }

    m = slirpTftpMbufAlloc(pData);
    if (!m)
        return -1;

    m->m_data += if_maxlinkhdr;
    m->m_pkthdr.header = mtod(m, void *);
    pTftpIpHeader = mtod(m, PTFTPIPHDR);
    m->m_len = sizeof(TFTPIPHDR);

    pTftpIpHeader->u16TftpOpType = RT_H2N_U16_C(TFTP_DATA);
    pTftpIpHeader->Core.u16TftpOpCode = RT_H2N_U16(pTftpSession->cTftpAck);

    rc = tftpReadDataBlock(pData, pTftpSession, (uint8_t *)&pTftpIpHeader->Core.u16TftpOpCode + sizeof(uint16_t), &cbRead);

    if (RT_SUCCESS(rc))
    {
        pTftpSession->cbTransfered += cbRead;
        m->m_len += cbRead;
        tftpSend(pData, pTftpSession, m, pcTftpIpHeaderRecv);
        if (cbRead > 0)
            tftpSessionUpdate(pData, pTftpSession);
        else
            tftpSessionTerminate(pTftpSession);
    }
    else
    {
        m_freem(pData, m);
        tftpSendError(pData, pTftpSession, 1, "File not found", pcTftpIpHeaderRecv);
        /* send "file not found" error back */
        return -1;
    }

    return 0;
}
Exemplo n.º 3
0
// tftpReSync()
//
// Attempt to ReSync a failed transfer
//
int tftpReSyncLocal( TFTP *pTftp, int dir )
{
    int rc = 0;
    //printf("in resynch, returning\n");
    //return 0;
    
    // Fluch pending input packets
    tftpFlushPackets( pTftp );

    // Abort if too many Sync errors
    pTftp->MaxSyncError--;
    if( pTftp->MaxSyncError == 0 )
    {
        rc = TFTPERROR_FAILED;
        goto ABORT;   // Too Many Sync Errors
    }

    // Back up expected block
    if (dir==0) pTftp->NextBlock--;

    // Resend last packet - if we're on block ZERO, resend the initial
    // request.
    if( !pTftp->NextBlock )
        tftpXRQBuild( pTftp, dir );
    else if (dir==0)
        tftpACKBuild( pTftp );
    else
		/* was last block of file ack'd ?*/
        if( pTftp->BufferUsed <0 ) // last packet did not make it there
            //tftpDATABuild(pTftp, &pTftp->Buffer[(pTftp->NextBlock-1)*SEGSIZE], pTftp->Length+SEGSIZE);
            tftpDATABuild(pTftp, &pTftp->Buffer[pTftp->BufferSize-pTftp->BufferUsed-SEGSIZE], pTftp->Length+SEGSIZE);
        else
            //tftpDATABuild(pTftp, &pTftp->Buffer[(pTftp->NextBlock-1)*SEGSIZE], SEGSIZE );
            tftpDATABuild(pTftp, &pTftp->Buffer[pTftp->BufferSize-pTftp->BufferUsed-SEGSIZE], SEGSIZE );
           	  
    // Send the packet
    rc = tftpSend( pTftp );
    if( rc < 0 )
        goto ABORT;

    if (dir==0) pTftp->NextBlock++;  //  Increment next expected BLOCK
    //pTftp->NextBlock++;  //  Increment next expected BLOCK

ABORT:
    return(rc);
}
Exemplo n.º 4
0
//
// tftpPutFile()
//
// Called to sent a file using TFTP. Called with TFTP parameter
// structure initialized.
//
// Returns:
//      1 - If file was sucessfully transferred
//     
//     <0 - Error
//
static int tftpPutFile( TFTP *pTftp )
{
    int rc = 0;

    // Build the request packet
    tftpXRQBuild( pTftp , 1 /* 1==write */);

    // Send the request packet
    rc = tftpSend( pTftp );
    if( rc < 0 )
       goto ABORT;

    //
    // Now look for ACKs and then send data 
    //
    pTftp->MaxSyncError   = MAX_SYNC_TRIES;  // set sync error counter
    pTftp->NextBlock      = 0;               // first ACK block expected is "0"

    for(;;)
    {
    	//printf("tftpPutFile() - reading response\n");
        // Try and get a reply packet
        rc = tftpReadPacket( pTftp );
        if( rc < 0 )
        {
            printf("tftpPutFile: abort from readPacket\n");
            goto ABORT;
        }
        // Process the reply packet
        //printf("tftpPutFile: processing rcv pkt\n");
        rc = tftpProcessPacket( pTftp, 1 );
        if( rc < 0 ){
            printf(" .. abort from tftpProcessPkt\n");
            goto ABORT;
        }    
        // If done, break out of loop
        if( rc == 1 )
            break;
    }

    rc = 1;

ABORT:
    return(rc);
}
Exemplo n.º 5
0
//
// tftpGetFile()
//
// Called to receive a file using TFTP. Called with TFTP parameter
// structure initialized.
//
// Returns:
//      1 - If file was sucessfully transferred
//      0 - If the file was transferred but too large for the buffer
//     <0 - Error
//
static int tftpGetFile( TFTP *pTftp )
{
    int rc = 0;

    // Build the request packet
    tftpXRQBuild( pTftp, 0 );

    // Send the request packet
    rc = tftpSend( pTftp );
    if( rc < 0 )
       goto ABORT;

    //
    // Now look for response packets
    //
    pTftp->MaxSyncError   = MAX_SYNC_TRIES;  // set sync error counter
    pTftp->NextBlock      = 1;               // first block expected is "1"

    for(;;)
    {
        // Try and get a reply packet
        rc = tftpReadPacket( pTftp );
        if( rc < 0 )
            goto ABORT;

        // Process the reply packet
        rc = tftpProcessPacket( pTftp, 0 );
        if( rc < 0 )
            goto ABORT;

        // If done, break out of loop
        if( rc == 1 )
            break;
    }

    // If the receive buffer was too small, return 0, else return 1
    if( pTftp->BufferUsed < pTftp->FileSize )
       rc = 0;
    else
       rc = 1;

ABORT:
    return(rc);
}
Exemplo n.º 6
0
Arquivo: tftp.c Projeto: ryenus/vbox
DECLINLINE(int) tftpSendOACK(PNATState pData,
                          PTFTPSESSION pTftpSession,
                          PCTFTPIPHDR pcTftpIpHeaderRecv)
{
    struct mbuf *m;
    PTFTPIPHDR pTftpIpHeader;
    int rc = VINF_SUCCESS;

    rc = tftpSessionEvaluateOptions(pData, pTftpSession);
    if (RT_FAILURE(rc))
    {
        tftpSendError(pData, pTftpSession, 2, "Internal Error (blksize evaluation)", pcTftpIpHeaderRecv);
        LogFlowFuncLeave();
        return -1;
    }

    m = slirpTftpMbufAlloc(pData);
    if (!m)
        return -1;



    m->m_data += if_maxlinkhdr;
    m->m_pkthdr.header = mtod(m, void *);
    pTftpIpHeader = mtod(m, PTFTPIPHDR);
    m->m_len = sizeof(TFTPIPHDR) - sizeof(uint16_t); /* no u16TftpOpCode */

    pTftpIpHeader->u16TftpOpType = RT_H2N_U16_C(TFTP_OACK);

    if (pTftpSession->OptionBlkSize.fRequested)
    {
        if (pTftpSession->OptionBlkSize.u64Value > UINT16_MAX)
            rc = VERR_INVALID_PARAMETER;
        else
            rc = tftpAddOptionToOACK(pData, m, "blksize", pTftpSession->OptionBlkSize.u64Value);
    }
    if (   RT_SUCCESS(rc)
        && pTftpSession->OptionTSize.fRequested)
        rc = tftpAddOptionToOACK(pData, m, "tsize", pTftpSession->OptionTSize.u64Value);

    rc = tftpSend(pData, pTftpSession, m, pcTftpIpHeaderRecv);
    return RT_SUCCESS(rc) ? 0 : -1;
}
Exemplo n.º 7
0
// tftpProcessPacket()
//
// Processes a data packet obtained from ReadPacket()
//
// Returns:
//      1 - Operation Complete
//      0 - Operation Progressing
//     <0 - Error Condition
//
static int tftpProcessPacket( TFTP *pTftp, int dir /* 0= reading, 1=writing */ )
{
    int    rc = 0, done = 0;
    UINT16 OpCode;
    UINT16 ServerBlock;
    UINT32 CopySize;
    struct tftphdr *ReadBuffer;
	char * dataPtr;

    ReadBuffer = (struct tftphdr *)pTftp->PacketBuffer;

    // Check for a bad packet - resynch on error
    if( !pTftp->Length )
        return( tftpReSyncLocal( pTftp, dir ) );

    OpCode = (UINT16) ntohs(ReadBuffer->opcode);
    //printf("processpacket = opcode = %d\n",OpCode);
    switch (OpCode)
    {
    case ERROR :
        // Copy the error code
        pTftp->ErrorCode = (UINT16) ntohs(ReadBuffer->block);

        // If the buffer is large enough, copy the error message
        pTftp->Length -= TFTP_HEADER;          // Get payload length

        // Copy file data if room left in buffer is large enough
        if( pTftp->BufferSize >= pTftp->Length )
        {
            bcopy( ReadBuffer->data, pTftp->Buffer, (int)pTftp->Length );
            pTftp->BufferUsed = pTftp->Length;
        }
        else
            pTftp->BufferUsed = 0;

        rc = TFTPERROR_ERRORREPLY;
        break;

   	case ACK:
		ServerBlock = (UINT16) ntohs(ReadBuffer->block);
		//printf("** ACK %d recv\n",ServerBlock);
		if (pTftp->NextBlock != ServerBlock)
        {
			//printf("write resynch error %d %d\n",pTftp->NextBlock, ServerBlock);
            rc = tftpReSyncLocal( pTftp, 1 );
            //pTftp->Length = 0;
            break;
        }
    
	     // If this is the first block, reset our port number.??
        if( pTftp->NextBlock == 0)
        {
            pTftp->peeraddr.sin_port = pTftp->tmpaddr.sin_port;  // Update TID
            //printf(" new dest port = %d %x\n", pTftp->tmpaddr.sin_port,pTftp->tmpaddr.sin_port);
        }

        //  ACK matches what we sent
        pTftp->MaxSyncError = MAX_SYNC_TRIES;  // reset Sync Counter
			 
		/* was last block of file ack'd ?*/
        if( pTftp->BufferUsed <0 )
        //if( pTftp->BufferUsed <=0 )
		{
            done = 1;
            //printf("** done = 1, should be exiting\n");
		    break;
		}


		dataPtr = &pTftp->Buffer[pTftp->BufferSize-pTftp->BufferUsed];
		/*not last block,  see where we are in file to send */
        pTftp->Length = SEGSIZE;     
		if (pTftp->BufferUsed<  SEGSIZE)
		{
			pTftp->Length = pTftp->BufferUsed;  
			pTftp->BufferUsed-=SEGSIZE;
			//pTftp->BufferUsed = 0;
		}
		else
		{
			pTftp->BufferUsed-=pTftp->Length;
		}
		//dataPtr = &pTftp->Buffer[pTftp->NextBlock*SEGSIZE];
	    CopySize = pTftp->Length;
		 //  Increment next BLOCK
        pTftp->NextBlock++;
        //printf("** sending next block: len=%d, bu=%d, dp=%x, CS=%d, blk=%d\n", pTftp->Length, pTftp->BufferUsed, dataPtr, CopySize,
        //                                                                       pTftp->NextBlock);
        //send data block
        tftpDATABuild( pTftp ,dataPtr, CopySize);
        rc = tftpSend( pTftp );
        if( rc < 0 )   { /*printf("process ack, rc<0 from tftpSend (data)\n");*/ break;}

        // Our done flag is the return code on success
        rc = done;
       	break;
	case DATA :
        // Received Data, verify BLOCK correct
        ServerBlock = (UINT16) ntohs(ReadBuffer->block);

        // If this is not the block we're expecting, resync
        if (pTftp->NextBlock != ServerBlock)
        {
           rc = tftpReSyncLocal( pTftp , 0);
            pTftp->Length = 0;
            break;
        }

        // If this is the first block, reset our port number.
        if( pTftp->NextBlock == 1 )
            pTftp->peeraddr.sin_port = pTftp->tmpaddr.sin_port;  // Update TID

        //  Block is for me!
        pTftp->MaxSyncError = MAX_SYNC_TRIES;  // reset Sync Counter
        pTftp->Length -= TFTP_HEADER;          // Get payload length
        CopySize = pTftp->Length;              // Copy length
        pTftp->FileSize += CopySize;           // Track the file length

        // Copy file data if room left in buffer is large enough
        if( pTftp->BufferSize > pTftp->BufferUsed )
        {
            if( (pTftp->BufferSize - pTftp->BufferUsed) < CopySize)
               CopySize = pTftp->BufferSize - pTftp->BufferUsed;

            if( CopySize )
            {
                // Add it to our receive buffer
                bcopy( ReadBuffer->data, (pTftp->Buffer+pTftp->BufferUsed),
                       (int)CopySize );

                // Track the number of bytes used
                pTftp->BufferUsed += CopySize;
            }
        }

        // If we received a partial block, we're done
        if( pTftp->Length < SEGSIZE )
            done = 1;

        // Need to acknowledge this block
        tftpACKBuild( pTftp );
        rc = tftpSend( pTftp );
        if( rc < 0 )
            break;

        //  Increment next expected BLOCK
        pTftp->NextBlock++;

        // Our done flag is the return code on success
        rc = done;
        break;

    default:
        rc = TFTPERROR_FAILED;
        break;
    }

    return(done==1 ?  1: rc);
}