fixed bug making 2dd screw up on vt100's with "set number".
[unix-history] / usr / src / sys / netinet / tcp_output.c
CommitLineData
cdad2eb1 1/* tcp_output.c 4.13 81/11/16 */
76ee76df
BJ
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/mbuf.h"
6#include "../h/socket.h"
d52566dd
BJ
7#include "../h/socketvar.h"
8#include "../net/inet_cksum.h"
9#include "../net/inet.h"
10#include "../net/inet_host.h"
53a5409e 11#include "../net/inet_pcb.h"
d52566dd
BJ
12#include "../net/inet_systm.h"
13#include "../net/imp.h"
14#include "../net/ip.h"
eb44bfb2 15#include "../net/ip_var.h"
d52566dd
BJ
16#include "../net/tcp.h"
17#include "../net/tcp_var.h"
18#include "../net/tcp_fsm.h"
19#include "/usr/include/errno.h"
76ee76df 20
ea727f86
BJ
21/*
22 * Special routines to send control messages.
23 */
24tcp_sndctl(tp)
53a5409e 25 struct tcpcb *tp;
ea727f86
BJ
26{
27COUNT(TCP_SNDCTL);
28
29 if (tcp_send(tp))
30 return (1);
31 tcp_sndnull(tp);
d52566dd 32 return (0);
ea727f86
BJ
33}
34
35tcp_sndwin(tp)
53a5409e 36 struct tcpcb *tp;
ea727f86
BJ
37{
38 int ihave, hehas;
39COUNT(TCP_SNDWIN);
40
41 if (tp->rcv_adv) {
53a5409e
BJ
42 register struct socket *so = tp->t_inpcb->inp_socket;
43
d52566dd
BJ
44 ihave = so->so_rcv.sb_hiwat -
45 (so->so_rcv.sb_cc + tp->seqcnt);
ea727f86 46 hehas = tp->rcv_adv - tp->rcv_nxt;
d52566dd 47 if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35)
ea727f86
BJ
48 return;
49 }
50 if (tcp_send(tp))
cdad2eb1 51 return;
ea727f86 52 tcp_sndnull(tp);
ea727f86
BJ
53}
54
55tcp_sndnull(tp)
53a5409e 56 register struct tcpcb *tp;
ea727f86
BJ
57{
58COUNT(TCP_SNDNULL);
59
cdad2eb1 60 (void) tcp_output(tp, 0, 0, (struct mbuf *)0);
ea727f86
BJ
61 tp->tc_flags &= ~TC_ACK_DUE;
62}
63
64tcp_sndrst(tp, n)
53a5409e
BJ
65 register struct tcpcb *tp;
66 register struct tcpiphdr *n;
ea727f86
BJ
67{
68COUNT(TCP_SNDRST);
69
70 /* don't send a reset in response to a reset */
eb44bfb2 71 if (n->ti_flags&TH_RST)
ea727f86
BJ
72 return;
73 tp->tc_flags |= TC_SND_RST;
eb44bfb2
BJ
74 if (n->ti_flags&TH_ACK)
75 tp->snd_nxt = n->ti_ackno;
ea727f86
BJ
76 tp->tc_flags &= ~TC_SYN_RCVD;
77 tcp_sndnull(tp);
78 tp->tc_flags &= ~TC_SND_RST;
79}
80
81/*
82 * Tcp segment output routine.
83 */
84tcp_send(tp)
53a5409e 85 register struct tcpcb *tp;
76ee76df 86{
76ee76df 87 register unsigned long last, wind;
53a5409e 88 register struct socket *so = tp->t_inpcb->inp_socket;
76ee76df 89 struct mbuf *m;
53a5409e 90 int flags = 0, forced, sent, len;
76ee76df 91
ea727f86 92COUNT(TCP_SEND);
76ee76df
BJ
93 tp->snd_lst = tp->snd_nxt;
94 forced = 0;
95 m = NULL;
ea727f86 96 if (tp->snd_nxt == tp->iss) {
76ee76df
BJ
97 flags |= TH_SYN;
98 tp->snd_lst++;
99 }
76ee76df 100 last = tp->snd_off;
d52566dd 101 for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next)
76ee76df 102 last += m->m_len;
76ee76df 103 if (tp->snd_nxt > last) {
76ee76df
BJ
104 if ((tp->tc_flags&TC_SND_FIN) &&
105 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
106
107 flags |= TH_FIN;
108 tp->seq_fin = tp->snd_lst++;
109 }
ea727f86 110 } else {
76ee76df 111 if (tp->tc_flags&TC_SYN_ACKED) {
76ee76df 112 wind = tp->snd_una + tp->snd_wnd;
cdad2eb1 113 tp->snd_lst = MIN(last, wind);
76ee76df
BJ
114 if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
115 tp->snd_lst -= len - 1024;
76ee76df
BJ
116 if (tp->snd_lst >= wind)
117 tp->t_persist = T_PERS;
118 }
76ee76df
BJ
119 if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
120 tp->snd_lst = tp->snd_nxt + 1;
121 forced = 1;
ddfd844e 122 } else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0)
7be5ba08 123 return (0);
cdad2eb1
BJ
124 m = sbcopy(&so->so_snd,
125 (int)(MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off),
126 (int)(tp->snd_lst - tp->snd_off));
76ee76df
BJ
127 if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
128 flags |= TH_EOL;
76ee76df
BJ
129 if ((tp->tc_flags&TC_SND_FIN) && !forced &&
130 tp->snd_lst == last &&
131 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
76ee76df
BJ
132 flags |= TH_FIN;
133 tp->seq_fin = tp->snd_lst++;
134 }
135 }
ddfd844e
BJ
136 if (tp->snd_nxt >= tp->snd_lst)
137 return (0);
ea727f86
BJ
138 if (tp->tc_flags & TC_SND_URG)
139 flags |= TH_URG;
cdad2eb1 140 sent = tcp_output(tp, flags, (int)(tp->snd_lst - tp->snd_nxt), m);
ea727f86
BJ
141 if (!forced) {
142 tp->t_rexmt = tp->t_xmtime;
143 tp->t_rexmt_val = tp->snd_lst;
144 if ((tp->tc_flags&TC_REXMT) == 0) {
145 tp->t_rexmttl = T_REXMTTL;
146 tp->t_rtl_val = tp->snd_lst;
76ee76df 147 }
76ee76df 148 }
ea727f86
BJ
149 if (sent)
150 tp->snd_nxt = tp->snd_lst;
151 if ((tp->tc_flags&TC_SYN_ACKED) &&
152 tp->snd_una > tp->t_xmt_val) {
153 tp->t_xmt = 0;
154 tp->t_xmt_val = tp->snd_lst;
76ee76df 155 }
ea727f86 156 tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE);
7be5ba08 157 tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi);
ea727f86 158 return (1);
76ee76df
BJ
159}
160
161/*
162 * Create template to be used to send tcp packets on a connection.
163 * Call after host entry created, allocates an mbuf and fills
164 * in a skeletal tcp/ip header, minimizing the amount of work
165 * necessary when the connection is used.
166 */
53a5409e 167struct tcpiphdr *
76ee76df 168tcp_template(tp)
53a5409e 169 struct tcpcb *tp;
76ee76df 170{
53a5409e
BJ
171 register struct inpcb *inp = tp->t_inpcb;
172 register struct in_host *h = inp->inp_fhost;
76ee76df 173 register struct mbuf *m;
53a5409e 174 register struct tcpiphdr *n;
76ee76df
BJ
175
176 if (h == 0)
177 return (0);
178 m = m_get(1);
179 if (m == 0)
180 return (0);
53a5409e
BJ
181 m->m_off = MMAXOFF - sizeof (struct tcpiphdr);
182 m->m_len = sizeof (struct tcpiphdr);
183 n = mtod(m, struct tcpiphdr *);
eb44bfb2
BJ
184 n->ti_next = n->ti_prev = 0;
185 n->ti_x1 = 0;
186 n->ti_pr = IPPROTO_TCP;
187 n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
188 n->ti_src.s_addr = n_lhost.s_addr;
189 n->ti_dst.s_addr = h->h_addr.s_addr;
190 n->ti_sport = htons(inp->inp_lport);
191 n->ti_dport = htons(inp->inp_fport);
192 n->ti_seq = 0;
193 n->ti_ackno = 0;
194 n->ti_x2 = 0;
195 n->ti_off = 5;
196 n->ti_flags = 0;
197 n->ti_win = 0;
198 n->ti_sum = 0;
199 n->ti_urp = 0;
76ee76df
BJ
200 return (n);
201}
202
203tcp_output(tp, flags, len, dat)
53a5409e 204 register struct tcpcb *tp;
76ee76df
BJ
205 register int flags;
206 int len;
207 struct mbuf *dat;
208{
53a5409e 209 register struct tcpiphdr *t; /* known to be r9 */
76ee76df 210 register struct mbuf *m;
53a5409e 211 struct socket *so = tp->t_inpcb->inp_socket;
76ee76df
BJ
212 register struct ip *ip;
213 int i;
214#ifdef TCPDEBUG
215 struct tcp_debug tdb;
216#endif
3552a746 217COUNT(TCP_OUTPUT);
76ee76df 218
e1506033 219 if ((t = tp->t_template) == 0)
76ee76df
BJ
220 return (0);
221 MGET(m, 0);
222 if (m == 0)
223 return (0);
53a5409e
BJ
224 m->m_off = MMAXOFF - sizeof(struct tcpiphdr);
225 m->m_len = sizeof (struct tcpiphdr);
76ee76df
BJ
226 m->m_next = dat;
227 if (flags & TH_SYN)
228 len--;
229 if (flags & TH_FIN)
230 len--;
cdad2eb1
BJ
231 if (len < 0)
232 panic("tcp_output");
53a5409e
BJ
233 bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr));
234 t = mtod(m, struct tcpiphdr *);
76ee76df
BJ
235 if (tp->tc_flags&TC_SND_RST) {
236 flags &= ~TH_SYN;
237 flags |= TH_RST;
238 }
239 if (tp->tc_flags&TC_SYN_RCVD)
240 flags |= TH_ACK;
eb44bfb2 241 t->ti_flags = flags;
76ee76df 242 if (flags & TH_URG)
cdad2eb1 243 t->ti_urp = htons((u_short)tp->snd_urp); /*XXX */
eb44bfb2 244 t->ti_win =
53a5409e
BJ
245 so->so_rcv.sb_hiwat -
246 (so->so_rcv.sb_cc + tp->seqcnt);
eb44bfb2
BJ
247 if (tp->rcv_nxt + t->ti_win > tp->rcv_adv)
248 tp->rcv_adv = tp->rcv_nxt + t->ti_win;
76ee76df 249 if (len)
cdad2eb1 250 t->ti_len = htons((u_short)(len + TCPSIZE));
eb44bfb2 251 t->ti_win = htons(t->ti_win);
76ee76df 252#ifdef TCPDEBUG
53a5409e 253 if ((so->so_options & SO_DEBUG) || tcpconsdebug) {
eb44bfb2
BJ
254 t->ti_seq = tp->snd_nxt;
255 t->ti_ackno = tp->rcv_nxt;
76ee76df
BJ
256 tdb_setup(tp, t, INSEND, &tdb);
257 tdb_stuff(&tdb, -2);
258 }
259#endif
eb44bfb2
BJ
260 t->ti_seq = htonl(tp->snd_nxt);
261 t->ti_ackno = htonl(tp->rcv_nxt);
262 t->ti_sum = 0; /* gratuitous? */
53a5409e 263 CKSUM_TCPSET(m, t, r9, sizeof (struct tcpiphdr) + len);
76ee76df
BJ
264 ip = (struct ip *)t;
265 ip->ip_v = IPVERSION;
266 ip->ip_hl = 5;
267 ip->ip_tos = 0;
53a5409e 268 ip->ip_len = len + sizeof(struct tcpiphdr);
76ee76df
BJ
269 ip->ip_id = ip_id++;
270 ip->ip_off = 0;
271 ip->ip_ttl = MAXTTL;
272 i = ip_send(ip);
d52566dd 273 return (i);
76ee76df
BJ
274}
275
d52566dd
BJ
276tcp_fasttimo()
277{
278
279}