Annotation of researchv9/sys/inet/tcp_output.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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