Annotation of researchv10no/sys/inet/tcp_output.c, revision 1.1.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.