before carry to arpavax
[unix-history] / usr / src / sys / netinet / tcp_output.c
CommitLineData
a6503abf 1/* tcp_output.c 4.18 81/11/25 */
76ee76df
BJ
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/mbuf.h"
6#include "../h/socket.h"
d52566dd 7#include "../h/socketvar.h"
d52566dd 8#include "../net/inet.h"
53a5409e 9#include "../net/inet_pcb.h"
d52566dd
BJ
10#include "../net/inet_systm.h"
11#include "../net/imp.h"
12#include "../net/ip.h"
eb44bfb2 13#include "../net/ip_var.h"
d52566dd
BJ
14#include "../net/tcp.h"
15#include "../net/tcp_var.h"
16#include "../net/tcp_fsm.h"
17#include "/usr/include/errno.h"
76ee76df 18
ea727f86 19/*
a6503abf
BJ
20 * Tcp output routine: figure out what should be sent
21 * and, if nothing, send a null segment anyways if force is nonzero
22 * (e.g. to be sure to send an ACK).
23 *
24 * This routine can be called only after SYNs have been exchanged.
ea727f86 25 */
a6503abf 26tcp_output(tp)
53a5409e 27 register struct tcpcb *tp;
ea727f86 28{
53a5409e 29 register struct socket *so = tp->t_inpcb->inp_socket;
a6503abf
BJ
30 register int len;
31 struct mbuf *m0;
32 int off, flags;
33 register struct mbuf *m;
34 register struct tcpiphdr *ti;
35 int win;
76ee76df 36
a6503abf 37COUNT(TCP_OUTPUT);
76ee76df 38
a6503abf
BJ
39 /*
40 * Determine length of data that can be transmitted.
41 * If will transmit to end of data and no more data
42 * is coming, then send FIN also.
43 * Make a copy of the data (if any). If no data
44 * and not forced to transmit, just return.
45 */
46 off = tp->snd_nxt - tp->snd_una;
47 len = MIN(so->so_snd.sb_cc, tp->snd_wnd) - off;
48 if (len > tp->mtu)
49 len = tp->mtu;
50 if (len == so->so_snd.sb_cc && (so->so_state & SS_CANTSNDMORE))
51 flags = TH_FIN;
52 else
53 flags = 0;
54 if (len)
55 goto send;
56
57 /*
58 * No data to send: see if something else makes us want to send.
59 * First check if we owe peer and ack or have a unacked FIN to send.
60 */
61 if (tp->t_flags & TF_OWEACK)
62 goto send;
63 if ((so->so_state & SS_CANTSNDMORE) &&
64 TCPS_OURFINISACKED(tp->t_state) == 0)
65 goto send;
66 if (tp->t_state == TCPS_SYN_SENT) {
67 flags = TH_SYN;
68 goto send;
76ee76df 69 }
a6503abf
BJ
70 if (tp->t_state == TCPS_CLOSED) {
71 flags = TH_RST;
72 goto send;
76ee76df 73 }
76ee76df 74
a6503abf
BJ
75 /*
76 * Calculate available window in i, and also amount
77 * of window known to peer (as advertised window less
78 * next expected input.) If this is 35% or more of the
79 * maximum possible window, then want to send a segment to peer.
80 */
81 i = sbspace(&so->so_rcv) - tp->seqcnt;
82 if (i > 0 &&
83 ((100*(i-(tp->rcv_adv-tp->rcv_nxt))/so->so_rcv.sb_hiwat) >= 35))
84 goto send;
85
86 /*
87 * No reason to send a segment, just return.
88 */
89 return;
90
91send:
92 /*
93 * Grab a header mbuf, attaching a copy of data to
94 * be transmitted, and initialize the header from
95 * the template for sends on this connection.
96 */
76ee76df
BJ
97 MGET(m, 0);
98 if (m == 0)
99 return (0);
53a5409e
BJ
100 m->m_off = MMAXOFF - sizeof(struct tcpiphdr);
101 m->m_len = sizeof (struct tcpiphdr);
a6503abf
BJ
102 if (len) {
103 m->m_next = m_copy(so->so_snd.sb_mb, off, len);
104 if (m->m_next == 0)
105 len = 0;
106 }
107 ti = mtod(m, struct tcpiphdr *);
108 if (tp->t_template == 0)
109 panic("tcp_output");
110 bcopy((caddr_t)tp->t_template, ti, sizeof (struct tcpiphdr));
111
112 /*
113 * Fill in fields, remembering maximum advertised
114 * window for use in delaying messages about window sizes.
115 */
116 ti->ti_seq = htonl(tp->snd_nxt);
117 ti->ti_ackno = htonl(tp->rcv_nxt);
118 /* OPTIONS */
76ee76df 119 if (flags & TH_SYN)
a6503abf
BJ
120 ti->ti_flags = flags;
121 else
122 ti->ti_flags = flags | TH_ACK;
123 win = sbspace(&so->so_rcv);
124 if (win > 0)
125 ti->ti_win = htons(win);
126 if (SEQ_GT(tp->snd_urp, tp->snd_nxt))
127 ti->ti_urp = htons((u_short)(tp->snd_urp - tp->snd_nxt));
128 ti->ti_flags |= TH_URG;
129 } else
130 /*
131 * If no urgent pointer to send, then we pull
132 * the urgent pointer to the left edge of the send window
133 * so that it doesn't drift into the send window on sequence
134 * number wraparound.
135 */
136 tp->snd_urp = tp->snd_una; /* drag it along */
137
138 /*
139 * Put TCP length in extended header, and then
140 * checksum extended header and data.
141 */
142 if (len)
143 ti->ti_len = htons((u_short)(len + sizeof (struct tcphdr)));
144 ti->ti_sum = inet_cksum(m, sizeof (struct tcpiphdr) + len);
145
146 /*
147 * Fill in IP length and desired time to live and
148 * send to IP level.
149 */
150 ((struct ip *)ti)->ip_len = len + sizeof (struct tcpiphdr);
151 ((struct ip *)ti)->ip_ttl = TCP_TTL;
152 if (ip_output(m) == 0)
153 return;
154
155 /*
156 * Data sent (as far as we can tell).
157 * If this advertises a larger window than any other segment,
158 * then record its sequence to be used in suppressing messages.
159 * Advance snd_nxt to reflect transmitted sequence space,
160 * drop send for purpose of ACK requirements,
161 * and time transmission if not a retransmit.
162 */
163 if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
164 tp->rcv_adv = tp->rcv_nxt + win;
165 tp->snd_nxt += len;
166 tp->t_flags &= ~(TF_OWEACK|TF_DELACK);
76ee76df 167 if (flags & TH_FIN)
a6503abf
BJ
168 tp->snd_nxt++;
169 if (SEQ_GT(tp->snd_nxt, tp->snd_hi)) {
170 tp->snd_hi = tp->snd_nxt;
171 /* TIME TRANSMIT */
76ee76df 172 }
a6503abf 173 return;
76ee76df 174}