⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nettcp.c

📁 uC/IP Release Notes These release notes for uC/IP are divided into the following sections
💻 C
📖 第 1 页 / 共 5 页
字号:
    NTOHL(tcpHdr->ack);
    NTOHS(tcpHdr->win);
    NTOHS(tcpHdr->urgent);

    segLen = ipHdr->ip_len - sizeof(IPHdr) - tcpHeadLen;

    /* Find the connection if any. */   
    conn.localIPAddr = ipHdr->ip_dst.s_addr;
    conn.localPort = tcpHdr->dstPort;
    conn.remoteIPAddr = ipHdr->ip_src.s_addr;
    conn.remotePort = tcpHdr->srcPort;
    if((tcb = tcbLookup(&conn)) == NULL) {
        TCPCB *ntcb;
        
        if(!(tcpHdr->flags & TH_SYN)) {
            /* No open TCB for this connection so reject */
            tcpReset(inBuf, ipHdr, tcpHdr, segLen);
            return;
        }
        
        /*
         * Check for a LISTEN on this connection request.
         */
        conn.remoteIPAddr = 0;
        conn.remotePort = 0;
        if((tcb = tcbLookup(&conn)) == NULL) {
            /*
             * Could be a LISTEN with a null local address.
             */
            conn.localIPAddr = 0;
            if((tcb = tcbLookup(&conn)) == NULL) {
                /* No unspecified LISTEN so reject */
                tcpReset(inBuf, ipHdr, tcpHdr, segLen);
                return;
            }
        }
        /* We've found a server listen socket, so clone the TCB */
        if(tcb->flags & CLONE) {
            OS_EVENT *connectSem;   /* Semaphore for connections. */
            OS_EVENT *readSem;      /* Semaphore for read function. */
            OS_EVENT *writeSem;     /* Semaphore for write function. */
            OS_EVENT *mutex;        /* Semaphore for mutex. */
            
            /*
             * If no room in the listen queue, we have to reject the connection. 
             */
            if (tcb->listenQOpen < listenQLen(tcb)) {
                tcpReset(inBuf, ipHdr, tcpHdr, segLen);
                return;
            }
        
            /* Get a free TCB. */
            OS_ENTER_CRITICAL();
            if ((ntcb = topTcpCB) == NULL) {
                OS_EXIT_CRITICAL();
                
                /* This may fail, but we should at least try */
                tcpReset(inBuf, ipHdr, tcpHdr, segLen);
                return;
            } else {
                topTcpCB = topTcpCB->next;
                ntcb->next = ntcb;  /* Next -> self => neither free nor linked. */
                ntcb->prev = NULL;  /* Always NULL when neither free nor linked. */
                STATS(if (--tcpStats.curFree.val < tcpStats.minFree.val)
                        tcpStats.minFree.val = tcpStats.curFree.val;)
                OS_EXIT_CRITICAL();
            }
            
            /* Duplicate the TCB but must preserve the semaphores. */
            connectSem = ntcb->connectSem;
            readSem = ntcb->readSem;
            writeSem = ntcb->writeSem;
            mutex = ntcb->mutex;
            memcpy(ntcb, tcb, sizeof(TCPCB));
            ntcb->connectSem = connectSem;
            ntcb->readSem = readSem;
            ntcb->writeSem = writeSem;
            ntcb->mutex = mutex;
#define TCP_SEM_FIX
#ifdef TCP_SEM_FIX
            /* Grab semaphores if they don't already exist. */
            if (!ntcb->connectSem)
                if ((ntcb->connectSem = OSSemCreate(0)) == NULL)
                    panic("TCPERR_ALLOC");
            if (!ntcb->readSem)
                if ((ntcb->readSem = OSSemCreate(0)) == NULL)
                    panic("TCPERR_ALLOC");
            if (!ntcb->writeSem)
                if ((ntcb->writeSem = OSSemCreate(0)) == NULL)
                    panic("TCPERR_ALLOC");
            if (!ntcb->mutex)
                if ((ntcb->mutex = OSSemCreate(1)) == NULL)
                    panic("TCPERR_ALLOC");
#endif
            /* 
             * Put this on the parent's accept queue.
             */
            listenQPush(tcb, ntcb);
            
            tcb = ntcb;
            
        /* Otherwise we use the original TCB. */
        } else {
            tcbUnlink(tcb); /* It'll be put back on later */
        }

        /* Load the local address and remote address and port into the TCB. */
        tcb->ipSrcAddr = tcb->conn.localIPAddr = ipHdr->ip_dst.s_addr;
        tcb->ipDstAddr = tcb->conn.remoteIPAddr = ipHdr->ip_src.s_addr;
        tcb->tcpDstPort = tcb->conn.remotePort = tcpHdr->srcPort;

        /* Initialize connection parameters. */     
        tcb->rcv.wnd = TCP_DEFWND;
        tcb->mss = ipMTU(tcb->ipDstAddr) - sizeof(IPHdr) - sizeof(TCPHdr);
        tcb->mss = MAX(tcb->mss, TCP_MINMSS);
        tcb->minFreeBufs = ((tcb->mss + NBUFSZ) / NBUFSZ);

        /* NOW put it on the right hash chain */
        tcbLink(tcb);
    }
    
    TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpInput[%d]: %s:%u->%s:%u %d@%lu",
                (int)(tcb - & tcbs[0]),
                ip_ntoa2(ipHdr->ip_src.s_addr), ntohs(tcpHdr->srcPort),
                ip_ntoa(ipHdr->ip_dst.s_addr), ntohs(tcpHdr->dstPort),
                segLen, tcpHdr->seq));
    TCPDEBUG((tcb->traceLevel, TL_TCP, "               %s %lu win %u",
                tcpFlagLabel[tcpHdr->flags & TCPFLAGLABELMASK],
                tcpHdr->ack, tcpHdr->win));
    TCPDEBUG((tcb->traceLevel + 2, TL_TCP, "          IP: %.*H", 
                ipHeadLen * 2, (char *)ipHdr));
    TCPDEBUG((tcb->traceLevel + 2, TL_TCP, "         TCP: %.*H", 
                tcpHeadLen * 2, (char *)tcpHdr));
    if (segLen > 0) {
        if (tcpHeadLen + sizeof(IPHdr) < inBuf->len) {
            TCPDEBUG((tcb->traceLevel, TL_TCP, "        DATA: %.*H",
                        MIN(segLen, 20) * 2, (char *)tcpHdr + tcpHeadLen));
        } else if (inBuf->nextBuf) {
            NBuf *n0 = inBuf->nextBuf;
            TCPDEBUG((tcb->traceLevel, TL_TCP, "        DATA: %.*H",
                        MIN(segLen, 20) * 2, nBUFTOPTR(n0, char *)));
        }
    }
                
    /*
     * If we're doing keep alive, update the keep alive timer.
     */
    if (tcb->keepAlive) {
        tcb->keepTime = OSTimeGet() + tcb->keepAlive;
        tcb->keepProbes = 0;
        TCPDEBUG((tcb->traceLevel + 1, TL_TCP, "tcpInput: Keepalive set for %lu", 
                    (int)(tcb - & tcbs[0]),
                    tcb->keepTime - OSTimeGet()));
        timeoutJiffy(
                &tcb->keepTimer, 
                tcb->keepTime, 
                keepTimeout, 
                tcb);
    }
    
    
    /* Do unsynchronized-state processing (p. 64-68) */
    switch(tcb->state){
    case CLOSED:
        if(tcpHdr->flags & TH_RST) {
            TCPDEBUG((tcb->traceLevel - 1, TL_TCP, "tcpInput[%d]: Dropping RESET on CLOSED",
                    (int)(tcb - & tcbs[0])));
            STATS(tcpStats.resetIn.val++;)
            nFreeChain(inBuf);
        } else
            tcpReset(inBuf, ipHdr, tcpHdr, segLen);
        return;
    case LISTEN:
        if(tcpHdr->flags & TH_RST) {
            /*
             * XXX - What would it mean if we got a reset on a listening
             * connection?  After all, we shouldn't have sent anything!
             */
            TCPDEBUG((tcb->traceLevel - 1, TL_TCP, "tcpInput[%d]: Dropping RESET on LISTEN",
                    (int)(tcb - & tcbs[0])));
            STATS(tcpStats.resetIn.val++;)
            nFreeChain(inBuf);
            return;
        }
        if(tcpHdr->flags & TH_ACK){
            tcpReset(inBuf, ipHdr, tcpHdr, segLen);
            return;
        }
        if(tcpHdr->flags & TH_SYN){
            /* 
             * Security check (RFC 793 pg 65) skipped here.
             *
             * Check incoming precedence (RFC 793 pg 66) and if it's
             * greater than ours, upgrade ours.  In fact we actually
             * adopt it's entire TOS.
             */
            if(IPTOS_PREC(ipHdr->ip_tos) > IPTOS_PREC(tcb->ipTOS)) {
                TCPDEBUG((tcb->traceLevel - 1, TL_TCP, 
                    "tcpInput[%d]: Changing TOS from %d to %d",
                    (int)(tcb - & tcbs[0]), tcb->ipTOS, ipHdr->ip_tos));
                tcb->ipTOS = ipHdr->ip_tos;
            }
    
            STATS(tcpStats.conin.val++;)
            procSyn(tcb, tcpHdr);
            sendSyn(tcb);
            setState(tcb, SYN_RECEIVED);        
            /* If the segment contains no data then we're done. */
            if(segLen == 0 && !(tcpHdr->flags & TH_FIN)) {
                nFreeChain(inBuf);
                tcpOutput(tcb);
                return;
            }
        } else {
            TCPDEBUG((tcb->traceLevel - 1, TL_TCP, "tcpInput[%d]: Dropping non-SYN in LISTEN",
                (int)(tcb - & tcbs[0])));
            nFreeChain(inBuf);
            return;
        }
        /* At this point the segment contains data - continue processing. */
        break;
    case SYN_SENT:
        if(tcpHdr->flags & TH_ACK){
            if(!seqWithin(tcpHdr->ack, tcb->iss + 1, tcb->snd.nxt)) {
                tcpReset(inBuf, ipHdr, tcpHdr, segLen);
                return;
            }
        }
        if(tcpHdr->flags & TH_RST){ /* p 67 */
            if(tcpHdr->flags & TH_ACK){
                /*
                 * The ack must be acceptable since we just checked it.
                 * This is how the remote side refuses connect requests.
                 */
                closeSelf(tcb, TCPERR_RESET);
            }
            TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpInput[%d]: Dropping RESET on SYN-SENT",
                (int)(tcb - & tcbs[0])));
            STATS(tcpStats.resetIn.val++;)
            nFreeChain(inBuf);
            return;
        }
        
        /* (Security check skipped here) */
        
        /* Check incoming precedence; it must match if there's an ACK */
        if(tcpHdr->flags & TH_ACK) {
            if(IPTOS_PREC(ipHdr->ip_tos) != IPTOS_PREC(tcb->ipTOS)) {
                TCPDEBUG((LOG_WARNING, TL_TCP, "tcpInput[%d]: in TOS PREC %u != our PREC %u",
                        (int)(tcb - &tcbs[0]),
                        IPTOS_PREC(ipHdr->ip_tos), 
                        IPTOS_PREC(tcb->ipTOS)));
                tcpReset(inBuf, ipHdr, tcpHdr, segLen);
                return;
            }
        } else {
            if(IPTOS_PREC(ipHdr->ip_tos) > IPTOS_PREC(tcb->ipTOS)) {
                TCPDEBUG((tcb->traceLevel - 1, TL_TCP, 
                    "tcpInput[%d]: Changing TOS from %d to %d",
                    (int)(tcb - & tcbs[0]), tcb->ipTOS, ipHdr->ip_tos));
                tcb->ipTOS = ipHdr->ip_tos;
            }
        }
        
        if(tcpHdr->flags & TH_SYN){
            procSyn(tcb, tcpHdr);
            if(tcpHdr->flags & TH_ACK){
                /*
                 * Our SYN has been acked, otherwise the ACK
                 * wouldn't have been valid.
                 */
                tcbUpdate(tcb, tcpHdr);
                setState(tcb,ESTABLISHED);
            } else {
                setState(tcb,SYN_RECEIVED);
            }
            /* If no data then we're done. */
            if(segLen == 0 && !(tcpHdr->flags & TH_FIN)) {
                nFreeChain(inBuf);  
                tcpOutput(tcb);
                return;
            }
            
        /* Ignore segment if neither SYN or RST is set */
        } else {
            TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpInput[%d]: Dropping non-SYN in SYN-SENT",
                (int)(tcb - & tcbs[0])));
            STATS(tcpStats.resetIn.val++;)
            nFreeChain(inBuf);  
            return;
        }
        
        /* At this point there is valid data in the segment so continue processing. */
        break;
    }
    
    /*
     * We reach this point directly in any synchronized state. Note that
     * if we fell through from LISTEN or SYN_SENT processing because of a
     * data-bearing SYN, then window trimming and sequence testing "cannot
     * fail".
     */

    /*
     * Trim segment to fit receive window.  If none of the segment is 
     * acceptable, then if the segment isn't a reset, resend the last
     * sent ACK. 
     */
    if ((segLen = trimSeg(tcb, tcpHdr, inBuf, ipHeadLen + tcpHeadLen, segLen)) < 0) {
        if(!(tcpHdr->flags & TH_RST)){
            tcb->flags |= FORCE;
            tcpOutput(tcb);
        }
        TCPDEBUG((tcb->traceLevel - 1, TL_TCP, "tcpInput[%d]: Dropping unacceptable segment in %s", 
                    (int)(tcb - & tcbs[0]),
                    tcbStates[tcb->state]));
        STATS(tcpStats.resetIn.val++;)
        nFreeChain(inBuf);
        return;
    }
    
    /*
     * Check the segment's flags and if OK and the ACK field is set, process
     * the acknowledgement field here.  RFC 793 specifies that this is to
     * be done when the segment begins with the next expected octet
     * (i.e. at the top of the loop below) but we do it here so that we
     * clear what we can from the output queue BEFORE we drop this due
     * to a shortage of buffers or queue it in the resequencing queue.
     */
    switch(procInFlags(tcb, tcpHdr, ipHdr)) {
    case ACKCLOSE:
        closeSelf(tcb, 0);
        /*** Fall through... ***/
    case ACKDROP:
        nFreeChain(inBuf);
        return;
        
    case ACKRESET:
        tcpReset(inBuf, ipHdr, tcpHdr, segLen);
        return;
    }
    
    /*
     * Before continuing, check that there are enough free buffers for normal
     * operation.  If not, we'll drop something.  If this is the next
     * data expected, drop chains from the resequencing queue until we've
     * cleared sufficient space.  If we're still short of buffers, drop this
     * segment.
     */
    if (nBUFSFREE() < tcb->minFreeBufs) {
        if(tcpHdr->seq == tcb->rcv.nxt) {
            while(nQHEAD(tcb->reseq) && nBUFSFREE() < tcb->minFreeBufs) {
                NBuf *segBuf;
                
                nDEQUEUE(tcb->reseq, segBuf);
                TCPDEBUG((tcb->traceLevel - 1, TL_TCP, 
                            "tcpInput[%d]: Clearing reseq queue",
                            (int)(

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -