implement -r
[unix-history] / usr / src / sys / netinet / tcp_output.c
CommitLineData
2ff61f9d 1/* tcp_output.c 4.17 81/11/24 */
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
BJ
19/*
20 * Special routines to send control messages.
21 */
22tcp_sndctl(tp)
53a5409e 23 struct tcpcb *tp;
ea727f86
BJ
24{
25COUNT(TCP_SNDCTL);
26
27 if (tcp_send(tp))
28 return (1);
29 tcp_sndnull(tp);
d52566dd 30 return (0);
ea727f86
BJ
31}
32
33tcp_sndwin(tp)
53a5409e 34 struct tcpcb *tp;
ea727f86
BJ
35{
36 int ihave, hehas;
37COUNT(TCP_SNDWIN);
38
39 if (tp->rcv_adv) {
53a5409e
BJ
40 register struct socket *so = tp->t_inpcb->inp_socket;
41
d52566dd
BJ
42 ihave = so->so_rcv.sb_hiwat -
43 (so->so_rcv.sb_cc + tp->seqcnt);
ea727f86 44 hehas = tp->rcv_adv - tp->rcv_nxt;
d52566dd 45 if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35)
ea727f86
BJ
46 return;
47 }
48 if (tcp_send(tp))
cdad2eb1 49 return;
ea727f86 50 tcp_sndnull(tp);
ea727f86
BJ
51}
52
53tcp_sndnull(tp)
53a5409e 54 register struct tcpcb *tp;
ea727f86
BJ
55{
56COUNT(TCP_SNDNULL);
57
cdad2eb1 58 (void) tcp_output(tp, 0, 0, (struct mbuf *)0);
ea727f86
BJ
59 tp->tc_flags &= ~TC_ACK_DUE;
60}
61
ea727f86
BJ
62/*
63 * Tcp segment output routine.
64 */
65tcp_send(tp)
53a5409e 66 register struct tcpcb *tp;
76ee76df 67{
76ee76df 68 register unsigned long last, wind;
53a5409e 69 register struct socket *so = tp->t_inpcb->inp_socket;
76ee76df 70 struct mbuf *m;
53a5409e 71 int flags = 0, forced, sent, len;
76ee76df 72
ea727f86 73COUNT(TCP_SEND);
76ee76df
BJ
74 tp->snd_lst = tp->snd_nxt;
75 forced = 0;
76 m = NULL;
ea727f86 77 if (tp->snd_nxt == tp->iss) {
76ee76df
BJ
78 flags |= TH_SYN;
79 tp->snd_lst++;
80 }
76ee76df 81 last = tp->snd_off;
d52566dd 82 for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next)
76ee76df 83 last += m->m_len;
76ee76df 84 if (tp->snd_nxt > last) {
76ee76df
BJ
85 if ((tp->tc_flags&TC_SND_FIN) &&
86 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
87
88 flags |= TH_FIN;
89 tp->seq_fin = tp->snd_lst++;
90 }
ea727f86 91 } else {
76ee76df 92 if (tp->tc_flags&TC_SYN_ACKED) {
76ee76df 93 wind = tp->snd_una + tp->snd_wnd;
cdad2eb1 94 tp->snd_lst = MIN(last, wind);
76ee76df
BJ
95 if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
96 tp->snd_lst -= len - 1024;
76ee76df
BJ
97 if (tp->snd_lst >= wind)
98 tp->t_persist = T_PERS;
99 }
76ee76df
BJ
100 if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
101 tp->snd_lst = tp->snd_nxt + 1;
102 forced = 1;
ddfd844e 103 } else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0)
7be5ba08 104 return (0);
4ad99bae 105 m = m_copy(so->so_snd.sb_mb,
cdad2eb1
BJ
106 (int)(MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off),
107 (int)(tp->snd_lst - tp->snd_off));
76ee76df
BJ
108 if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
109 flags |= TH_EOL;
76ee76df
BJ
110 if ((tp->tc_flags&TC_SND_FIN) && !forced &&
111 tp->snd_lst == last &&
112 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
76ee76df
BJ
113 flags |= TH_FIN;
114 tp->seq_fin = tp->snd_lst++;
115 }
116 }
ddfd844e
BJ
117 if (tp->snd_nxt >= tp->snd_lst)
118 return (0);
ea727f86
BJ
119 if (tp->tc_flags & TC_SND_URG)
120 flags |= TH_URG;
cdad2eb1 121 sent = tcp_output(tp, flags, (int)(tp->snd_lst - tp->snd_nxt), m);
ea727f86
BJ
122 if (!forced) {
123 tp->t_rexmt = tp->t_xmtime;
124 tp->t_rexmt_val = tp->snd_lst;
125 if ((tp->tc_flags&TC_REXMT) == 0) {
126 tp->t_rexmttl = T_REXMTTL;
127 tp->t_rtl_val = tp->snd_lst;
76ee76df 128 }
76ee76df 129 }
ea727f86
BJ
130 if (sent)
131 tp->snd_nxt = tp->snd_lst;
132 if ((tp->tc_flags&TC_SYN_ACKED) &&
133 tp->snd_una > tp->t_xmt_val) {
134 tp->t_xmt = 0;
135 tp->t_xmt_val = tp->snd_lst;
76ee76df 136 }
ea727f86 137 tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE);
7be5ba08 138 tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi);
ea727f86 139 return (1);
76ee76df 140}
76ee76df 141tcp_output(tp, flags, len, dat)
53a5409e 142 register struct tcpcb *tp;
76ee76df
BJ
143 register int flags;
144 int len;
145 struct mbuf *dat;
146{
53a5409e 147 register struct tcpiphdr *t; /* known to be r9 */
76ee76df 148 register struct mbuf *m;
53a5409e 149 struct socket *so = tp->t_inpcb->inp_socket;
76ee76df 150 register struct ip *ip;
3552a746 151COUNT(TCP_OUTPUT);
76ee76df 152
e1506033 153 if ((t = tp->t_template) == 0)
76ee76df
BJ
154 return (0);
155 MGET(m, 0);
156 if (m == 0)
157 return (0);
53a5409e
BJ
158 m->m_off = MMAXOFF - sizeof(struct tcpiphdr);
159 m->m_len = sizeof (struct tcpiphdr);
76ee76df
BJ
160 m->m_next = dat;
161 if (flags & TH_SYN)
162 len--;
163 if (flags & TH_FIN)
164 len--;
cdad2eb1
BJ
165 if (len < 0)
166 panic("tcp_output");
53a5409e
BJ
167 bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr));
168 t = mtod(m, struct tcpiphdr *);
76ee76df
BJ
169 if (tp->tc_flags&TC_SND_RST) {
170 flags &= ~TH_SYN;
171 flags |= TH_RST;
172 }
173 if (tp->tc_flags&TC_SYN_RCVD)
174 flags |= TH_ACK;
eb44bfb2 175 t->ti_flags = flags;
76ee76df 176 if (flags & TH_URG)
cdad2eb1 177 t->ti_urp = htons((u_short)tp->snd_urp); /*XXX */
eb44bfb2 178 t->ti_win =
53a5409e
BJ
179 so->so_rcv.sb_hiwat -
180 (so->so_rcv.sb_cc + tp->seqcnt);
eb44bfb2
BJ
181 if (tp->rcv_nxt + t->ti_win > tp->rcv_adv)
182 tp->rcv_adv = tp->rcv_nxt + t->ti_win;
76ee76df 183 if (len)
2ff61f9d 184 t->ti_len = htons((u_short)(len + sizeof (struct tcphdr)));
eb44bfb2 185 t->ti_win = htons(t->ti_win);
eb44bfb2
BJ
186 t->ti_seq = htonl(tp->snd_nxt);
187 t->ti_ackno = htonl(tp->rcv_nxt);
188 t->ti_sum = 0; /* gratuitous? */
2b4b57cd 189 t->ti_sum = inet_cksum(m, sizeof (struct tcpiphdr) + len);
76ee76df
BJ
190 ip = (struct ip *)t;
191 ip->ip_v = IPVERSION;
192 ip->ip_hl = 5;
193 ip->ip_tos = 0;
53a5409e 194 ip->ip_len = len + sizeof(struct tcpiphdr);
76ee76df
BJ
195 ip->ip_id = ip_id++;
196 ip->ip_off = 0;
197 ip->ip_ttl = MAXTTL;
2b4b57cd
BJ
198 ip_send(ip);
199 return (1);
76ee76df 200}