Annotation of researchv10no/sys/inet/tcp_output.c, revision 1.1

1.1     ! root        1: /*     tcp_output.c    6.1     83/07/29        */
        !             2: 
        !             3: #include "sys/param.h"
        !             4: #include "sys/stream.h"
        !             5: #include "sys/inet/in.h"
        !             6: #include "sys/inet/ip.h"
        !             7: #include "sys/inet/ip_var.h"
        !             8: #include "sys/inet/tcp.h"
        !             9: #define        TCPOUTFLAGS
        !            10: #include "sys/inet/tcp_fsm.h"
        !            11: #include "sys/inet/tcp_seq.h"
        !            12: #include "sys/inet/tcp_timer.h"
        !            13: #include "sys/inet/tcp_var.h"
        !            14: #include "sys/inet/tcpip.h"
        !            15: 
        !            16: int tcp_busy;  /* set/unset by tcp_output callers, to keep out timer */
        !            17: 
        !            18: /*
        !            19:  * Initial options.
        !            20:  */
        !            21: u_char tcp_initopt[4] = { TCPOPT_MAXSEG, 4, 0x0, 0x0, };
        !            22: extern tcpprintfs;
        !            23: 
        !            24: /*
        !            25:  *  Settable maximum tcp segment size.
        !            26:  */
        !            27: extern int tcp_maxseg;
        !            28: 
        !            29: /*
        !            30:  * Tcp output routine: figure out what should be sent and send it.
        !            31:  */
        !            32: tcp_output(tp)
        !            33:        register struct tcpcb *tp;
        !            34: {
        !            35:        register int len;
        !            36:        struct block *bp0;
        !            37:        int off, flags, win, error;
        !            38:        register struct block *bp;
        !            39:        register struct tcpiphdr *ti;
        !            40:        u_char *opt;
        !            41:        unsigned optlen = 0;
        !            42:        int sendalot;
        !            43: 
        !            44:        /*
        !            45:         *  don't output if the template has been removed
        !            46:         */
        !            47:        if (tp->t_template == 0)
        !            48:                return (0);
        !            49: 
        !            50:        if(tcp_busy != 1)
        !            51:                panic("tcp_busy");
        !            52: 
        !            53:        /*
        !            54:         * Determine length of data that should be transmitted,
        !            55:         * and flags that will be used.
        !            56:         * If there is some data or critical controls (SYN, RST)
        !            57:         * to send, then transmit; otherwise, investigate further.
        !            58:         */
        !            59: again:
        !            60:        sendalot = 0;
        !            61:        off = tp->snd_nxt - tp->snd_una;
        !            62:        len = MIN(sosndcc(tp), tp->snd_wnd+tp->t_force) - off;
        !            63:        if (len < 0)
        !            64:                return (0);     /* ??? */       /* past FIN */
        !            65:        if (len > tp->t_maxseg) {
        !            66:                len = tp->t_maxseg;
        !            67:                sendalot = 1;
        !            68:        }
        !            69: 
        !            70:        flags = tcp_outflags[tp->t_state];
        !            71:        if (tp->snd_nxt + len < tp->snd_una + sosndcc(tp))
        !            72:                flags &= ~TH_FIN;
        !            73:        if (flags & (TH_SYN|TH_RST|TH_FIN))
        !            74:                goto send;
        !            75:        if (SEQ_GT(tp->snd_up, tp->snd_una))
        !            76:                goto send;
        !            77: 
        !            78:        /*
        !            79:         * Sender silly window avoidance.  If can send all data,
        !            80:         * a maximum segment, at least 1/4 of window do it,
        !            81:         * or are forced, do it; otherwise don't bother.
        !            82:         */
        !            83:        if (len) {
        !            84:                if (len == tp->t_maxseg || off+len >= sosndcc(tp))
        !            85:                        goto send;
        !            86:                if (len * 4 >= tp->snd_wnd)             /* a lot */
        !            87:                        goto send;
        !            88:                if (tp->t_force)
        !            89:                        goto send;
        !            90:        }
        !            91: 
        !            92:        /*
        !            93:         * Send if we owe peer an ACK.
        !            94:         */
        !            95:        if (tp->t_flags&TF_ACKNOW)
        !            96:                goto send;
        !            97: 
        !            98: 
        !            99:        /*
        !           100:         * Calculate available window in i, and also amount
        !           101:         * of window known to peer (as advertised window less
        !           102:         * next expected input.)  If this is 35% or more of the
        !           103:         * maximum possible window, then want to send a segment to peer.
        !           104:         */
        !           105:        win = sbrcvspace(tp);
        !           106:        if (win > 0 &&
        !           107:            ((100*(win-(tp->rcv_adv-tp->rcv_nxt))/sorcvhiwat(tp)) >= 35))
        !           108:                goto send;
        !           109: 
        !           110:        /*
        !           111:         * TCP window updates are not reliable, rather a polling protocol
        !           112:         * using ``persist'' packets is used to insure receipt of window
        !           113:         * updates.  The three ``states'' for the output side are:
        !           114:         *      idle                    not doing retransmits or persists
        !           115:         *      persisting              to move a zero window
        !           116:         *      (re)transmitting        and thereby not persisting
        !           117:         *
        !           118:         * tp->t_timer[TCPT_PERSIST]
        !           119:         *      is set when we are in persist state.
        !           120:         * tp->t_force
        !           121:         *      is set when we are called to send a persist packet.
        !           122:         * tp->t_timer[TCPT_REXMT]
        !           123:         *      is set when we are retransmitting
        !           124:         * The output side is idle when both timers are zero.
        !           125:         *
        !           126:         * If send window is closed, there is data to transmit, and no
        !           127:         * retransmit or persist is pending, then go to persist state,
        !           128:         * arranging to force out a byte to get more current window information
        !           129:         * if nothing happens soon.
        !           130:         */
        !           131:        if (tp->snd_wnd == 0 && sosndcc(tp) &&
        !           132:            tp->t_timer[TCPT_REXMT] == 0 && tp->t_timer[TCPT_PERSIST] == 0) {
        !           133:                tp->t_rxtshift = 0;
        !           134:                tcp_setpersist(tp);
        !           135:        }
        !           136: 
        !           137:        /*
        !           138:         * No reason to send a segment, just return.
        !           139:         */
        !           140:        return (0);
        !           141: 
        !           142: send:
        !           143:        /*
        !           144:         * Grab a header block, attaching a copy of data to
        !           145:         * be transmitted, and initialize the header from
        !           146:         * the template for sends on this connection.
        !           147:         */
        !           148:        bp = bp_get();
        !           149:        if (bp == NULL)
        !           150:                return (1);
        !           151:        bp->next = 0;
        !           152:        bp->wptr += sizeof (struct tcpiphdr);
        !           153:        if (len) {
        !           154:                bp->next = bp_copy(tp->so_wq->first, off, len);
        !           155:                if (bp->next == 0)
        !           156:                        len = 0;
        !           157:        }
        !           158:        ti = (struct tcpiphdr *)bp->rptr;
        !           159:        if (tp->t_template == 0)
        !           160:                panic("tcp_output");
        !           161:        bcopy((caddr_t)tp->t_template->rptr,(caddr_t)ti, sizeof (struct tcpiphdr));
        !           162: 
        !           163:        /*
        !           164:         * Fill in fields, remembering maximum advertised
        !           165:         * window for use in delaying messages about window sizes.
        !           166:         */
        !           167:        ti->ti_seq = tp->snd_nxt;
        !           168:        ti->ti_ack = tp->rcv_nxt;
        !           169:        ti->ti_seq = htonl(ti->ti_seq);
        !           170:        ti->ti_ack = htonl(ti->ti_ack);
        !           171:        /*
        !           172:         * Before ESTABLISHED, force sending of initial options
        !           173:         * unless TCP set to not do any options.
        !           174:         */
        !           175:        if (tp->t_state < TCPS_ESTABLISHED) {
        !           176:                short maxseg;
        !           177: 
        !           178:                if (tp->t_flags&TF_NOOPT)
        !           179:                        goto noopt;
        !           180:                if (in_netof(ti->ti_src) != in_netof(ti->ti_dst))
        !           181:                        goto noopt;
        !           182:                opt = tcp_initopt;
        !           183:                optlen = sizeof (tcp_initopt);
        !           184:                maxseg = tcp_maxseg;
        !           185:                *(u_short *)(opt + 2) = htons(maxseg);
        !           186:        } else {
        !           187:                if (tp->t_tcpopt == 0)
        !           188:                        goto noopt;
        !           189:                opt = (u_char *)tp->t_tcpopt->rptr;
        !           190:                optlen = BLEN(tp->t_tcpopt);
        !           191:        }
        !           192:        if (opt) {
        !           193:                bp0 = bp->next;
        !           194:                bp->next = bp_get();
        !           195:                if (bp->next == 0) {
        !           196:                        freeb(bp);
        !           197:                        bp_free(bp0);
        !           198:                        return (1);
        !           199:                }
        !           200:                bp->next->next = bp0;
        !           201:                bp0 = bp->next;
        !           202:                bp0->wptr += optlen;
        !           203:                bcopy((caddr_t)opt, (caddr_t)bp0->rptr, optlen);
        !           204:                opt = (u_char *)((caddr_t)bp0->rptr + optlen);
        !           205:                while (BLEN(bp0) & 0x3) {
        !           206:                        bp0->wptr++;
        !           207:                        *opt++ = TCPOPT_EOL;
        !           208:                }
        !           209:                optlen = BLEN(bp0);
        !           210:                ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2;
        !           211:        }
        !           212: noopt:
        !           213:        ti->ti_flags = flags;
        !           214:        win = sbrcvspace(tp);
        !           215:        if (win < sorcvhiwat(tp) / 4) {
        !           216:                /*
        !           217:                 *  avoid wastefully small packets caused by small windows
        !           218:                 */
        !           219:                win = 0;
        !           220:        }
        !           221:        if ((tp->so_state & SS_OPEN)==0 && tp->t_state > TCPS_CLOSE_WAIT) {
        !           222:                /*
        !           223:                 *  if the local process has disappeared, then open up
        !           224:                 *  the window to get the remote process to send something
        !           225:                 *  rather than hang waiting to send
        !           226:                 */
        !           227:                win = 1;
        !           228:        }
        !           229:        if (win > 0)
        !           230:                ti->ti_win = htons((u_short)win);
        !           231:        if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
        !           232:                ti->ti_urp = tp->snd_up - tp->snd_nxt;
        !           233:                ti->ti_urp = htons(ti->ti_urp);
        !           234:                ti->ti_flags |= TH_URG;
        !           235:        } else
        !           236:                /*
        !           237:                 * If no urgent pointer to send, then we pull
        !           238:                 * the urgent pointer to the left edge of the send window
        !           239:                 * so that it doesn't drift into the send window on sequence
        !           240:                 * number wraparound.
        !           241:                 */
        !           242:                tp->snd_up = tp->snd_una;               /* drag it along */
        !           243:        /*
        !           244:         * If anything to send and we can send it all, set PUSH.
        !           245:         * (This will keep happy those implementations which only
        !           246:         * give data to the user when a buffer fills or a PUSH comes in.)
        !           247:         */
        !           248:        if (len && off+len == sosndcc(tp))
        !           249:                ti->ti_flags |= TH_PUSH;
        !           250: 
        !           251:        /*
        !           252:         * Put TCP length in extended header, and then
        !           253:         * checksum extended header and data.
        !           254:         */
        !           255:        if (len + optlen) {
        !           256:                ti->ti_len = sizeof (struct tcphdr) + optlen + len;
        !           257:                ti->ti_len = htons((u_short)ti->ti_len);
        !           258:        }
        !           259:        ti->ti_src = htonl(ti->ti_src);
        !           260:        ti->ti_dst = htonl(ti->ti_dst);
        !           261:        ti->ti_sport = htons(ti->ti_sport);
        !           262:        ti->ti_dport = htons(ti->ti_dport);
        !           263:        ti->ti_sum = in_cksum(bp, sizeof (struct tcpiphdr) + (int)optlen + len);
        !           264:        tcp_debug(ti, 1);
        !           265:        ti->ti_src = ntohl(ti->ti_src);
        !           266:        ti->ti_dst = ntohl(ti->ti_dst);
        !           267: 
        !           268:        /*
        !           269:         * In transmit state, time the transmission and arrange for
        !           270:         * the retransmit.  In persist state, reset persist time for
        !           271:         * next persist.
        !           272:         */
        !           273:        if (tp->t_force == 0) {
        !           274:                /*
        !           275:                 * Advance snd_nxt over sequence space of this segment.
        !           276:                 */
        !           277:                if (flags & (TH_SYN|TH_FIN))
        !           278:                        tp->snd_nxt++;
        !           279:                tp->snd_nxt += len;
        !           280:                if (SEQ_GT(tp->snd_nxt, tp->snd_max))
        !           281:                        tp->snd_max = tp->snd_nxt;
        !           282: 
        !           283:                /*
        !           284:                 * Time this transmission if not a retransmission and
        !           285:                 * not currently timing anything.
        !           286:                 */
        !           287:                if (SEQ_GT(tp->snd_nxt, tp->snd_max) && tp->t_rtt == 0) {
        !           288:                        tp->t_rtt = 1;
        !           289:                        tp->t_rtseq = tp->snd_nxt - len;
        !           290:                }
        !           291: 
        !           292:                /*
        !           293:                 * Set retransmit timer if not currently set.
        !           294:                 * Initial value for retransmit timer to tcp_beta*tp->t_srtt.
        !           295:                 * Initialize shift counter which is used for exponential
        !           296:                 * backoff of retransmit time.
        !           297:                 */
        !           298:                if (tp->t_timer[TCPT_REXMT] == 0 &&
        !           299:                    tp->snd_nxt != tp->snd_una) {
        !           300:                        TCPT_RANGESET(tp->t_timer[TCPT_REXMT],
        !           301:                            tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX);
        !           302:                        tp->t_rtt = 0;
        !           303:                        tp->t_rxtshift = 0;
        !           304:                }
        !           305:                tp->t_timer[TCPT_PERSIST] = 0;
        !           306:        } else {
        !           307:                if (SEQ_GT(tp->snd_una+1, tp->snd_max))
        !           308:                        tp->snd_max = tp->snd_una+1;
        !           309:        }
        !           310: 
        !           311:        /*
        !           312:         * Fill in IP length and desired time to live and
        !           313:         * send to IP level.
        !           314:         */
        !           315:        ((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + optlen + len;
        !           316:        ((struct ip *)ti)->ip_ttl = TCP_TTL;
        !           317:        error = tcp_ldout(bp);
        !           318:        if (error)
        !           319:                return (error);
        !           320: 
        !           321: 
        !           322:        /*
        !           323:         * Data sent (as far as we can tell).
        !           324:         * If this advertises a larger window than any other segment,
        !           325:         * then remember the size of the advertised window.
        !           326:         * Drop send for purpose of ACK requirements.
        !           327:         */
        !           328:        if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
        !           329:                tp->rcv_adv = tp->rcv_nxt + win;
        !           330:        tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);
        !           331:        if (sendalot && tp->t_force == 0)
        !           332:                goto again;
        !           333:        return (0);
        !           334: }
        !           335: 
        !           336: tcp_setpersist(tp)
        !           337:        register struct tcpcb *tp;
        !           338: {
        !           339: 
        !           340:        if (tp->t_timer[TCPT_REXMT])
        !           341:                panic("tcp_output REXMT");
        !           342:        /*
        !           343:         * Start/restart persistance timer.
        !           344:         */
        !           345:        TCPT_RANGESET(tp->t_timer[TCPT_PERSIST],
        !           346:            ((int)(tcp_beta * tp->t_srtt)) << tp->t_rxtshift,
        !           347:            TCPTV_PERSMIN, TCPTV_MAX);
        !           348:        tp->t_rxtshift++;
        !           349:        if (tp->t_rxtshift >= TCP_MAXRXTSHIFT)
        !           350:                tp->t_rxtshift = 0;
        !           351: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.