so_addr
[unix-history] / usr / src / sys / netinet / tcp_output.c
CommitLineData
4ad99bae 1/* tcp_output.c 4.15 81/11/20 */
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
62tcp_sndrst(tp, n)
53a5409e
BJ
63 register struct tcpcb *tp;
64 register struct tcpiphdr *n;
ea727f86
BJ
65{
66COUNT(TCP_SNDRST);
67
68 /* don't send a reset in response to a reset */
eb44bfb2 69 if (n->ti_flags&TH_RST)
ea727f86
BJ
70 return;
71 tp->tc_flags |= TC_SND_RST;
eb44bfb2
BJ
72 if (n->ti_flags&TH_ACK)
73 tp->snd_nxt = n->ti_ackno;
ea727f86
BJ
74 tp->tc_flags &= ~TC_SYN_RCVD;
75 tcp_sndnull(tp);
76 tp->tc_flags &= ~TC_SND_RST;
77}
78
79/*
80 * Tcp segment output routine.
81 */
82tcp_send(tp)
53a5409e 83 register struct tcpcb *tp;
76ee76df 84{
76ee76df 85 register unsigned long last, wind;
53a5409e 86 register struct socket *so = tp->t_inpcb->inp_socket;
76ee76df 87 struct mbuf *m;
53a5409e 88 int flags = 0, forced, sent, len;
76ee76df 89
ea727f86 90COUNT(TCP_SEND);
76ee76df
BJ
91 tp->snd_lst = tp->snd_nxt;
92 forced = 0;
93 m = NULL;
ea727f86 94 if (tp->snd_nxt == tp->iss) {
76ee76df
BJ
95 flags |= TH_SYN;
96 tp->snd_lst++;
97 }
76ee76df 98 last = tp->snd_off;
d52566dd 99 for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next)
76ee76df 100 last += m->m_len;
76ee76df 101 if (tp->snd_nxt > last) {
76ee76df
BJ
102 if ((tp->tc_flags&TC_SND_FIN) &&
103 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
104
105 flags |= TH_FIN;
106 tp->seq_fin = tp->snd_lst++;
107 }
ea727f86 108 } else {
76ee76df 109 if (tp->tc_flags&TC_SYN_ACKED) {
76ee76df 110 wind = tp->snd_una + tp->snd_wnd;
cdad2eb1 111 tp->snd_lst = MIN(last, wind);
76ee76df
BJ
112 if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
113 tp->snd_lst -= len - 1024;
76ee76df
BJ
114 if (tp->snd_lst >= wind)
115 tp->t_persist = T_PERS;
116 }
76ee76df
BJ
117 if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
118 tp->snd_lst = tp->snd_nxt + 1;
119 forced = 1;
ddfd844e 120 } else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0)
7be5ba08 121 return (0);
4ad99bae 122 m = m_copy(so->so_snd.sb_mb,
cdad2eb1
BJ
123 (int)(MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off),
124 (int)(tp->snd_lst - tp->snd_off));
76ee76df
BJ
125 if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
126 flags |= TH_EOL;
76ee76df
BJ
127 if ((tp->tc_flags&TC_SND_FIN) && !forced &&
128 tp->snd_lst == last &&
129 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
76ee76df
BJ
130 flags |= TH_FIN;
131 tp->seq_fin = tp->snd_lst++;
132 }
133 }
ddfd844e
BJ
134 if (tp->snd_nxt >= tp->snd_lst)
135 return (0);
ea727f86
BJ
136 if (tp->tc_flags & TC_SND_URG)
137 flags |= TH_URG;
cdad2eb1 138 sent = tcp_output(tp, flags, (int)(tp->snd_lst - tp->snd_nxt), m);
ea727f86
BJ
139 if (!forced) {
140 tp->t_rexmt = tp->t_xmtime;
141 tp->t_rexmt_val = tp->snd_lst;
142 if ((tp->tc_flags&TC_REXMT) == 0) {
143 tp->t_rexmttl = T_REXMTTL;
144 tp->t_rtl_val = tp->snd_lst;
76ee76df 145 }
76ee76df 146 }
ea727f86
BJ
147 if (sent)
148 tp->snd_nxt = tp->snd_lst;
149 if ((tp->tc_flags&TC_SYN_ACKED) &&
150 tp->snd_una > tp->t_xmt_val) {
151 tp->t_xmt = 0;
152 tp->t_xmt_val = tp->snd_lst;
76ee76df 153 }
ea727f86 154 tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE);
7be5ba08 155 tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi);
ea727f86 156 return (1);
76ee76df
BJ
157}
158
159/*
160 * Create template to be used to send tcp packets on a connection.
161 * Call after host entry created, allocates an mbuf and fills
162 * in a skeletal tcp/ip header, minimizing the amount of work
163 * necessary when the connection is used.
164 */
53a5409e 165struct tcpiphdr *
76ee76df 166tcp_template(tp)
53a5409e 167 struct tcpcb *tp;
76ee76df 168{
53a5409e 169 register struct inpcb *inp = tp->t_inpcb;
76ee76df 170 register struct mbuf *m;
53a5409e 171 register struct tcpiphdr *n;
76ee76df 172
4ad99bae 173COUNT(TCP_TEMPLATE);
76ee76df
BJ
174 m = m_get(1);
175 if (m == 0)
176 return (0);
53a5409e
BJ
177 m->m_off = MMAXOFF - sizeof (struct tcpiphdr);
178 m->m_len = sizeof (struct tcpiphdr);
179 n = mtod(m, struct tcpiphdr *);
eb44bfb2
BJ
180 n->ti_next = n->ti_prev = 0;
181 n->ti_x1 = 0;
182 n->ti_pr = IPPROTO_TCP;
183 n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
4ad99bae
BJ
184 n->ti_src = inp->inp_laddr;
185 n->ti_dst = inp->inp_faddr;
eb44bfb2
BJ
186 n->ti_sport = htons(inp->inp_lport);
187 n->ti_dport = htons(inp->inp_fport);
188 n->ti_seq = 0;
189 n->ti_ackno = 0;
190 n->ti_x2 = 0;
191 n->ti_off = 5;
192 n->ti_flags = 0;
193 n->ti_win = 0;
194 n->ti_sum = 0;
195 n->ti_urp = 0;
76ee76df
BJ
196 return (n);
197}
198
199tcp_output(tp, flags, len, dat)
53a5409e 200 register struct tcpcb *tp;
76ee76df
BJ
201 register int flags;
202 int len;
203 struct mbuf *dat;
204{
53a5409e 205 register struct tcpiphdr *t; /* known to be r9 */
76ee76df 206 register struct mbuf *m;
53a5409e 207 struct socket *so = tp->t_inpcb->inp_socket;
76ee76df 208 register struct ip *ip;
76ee76df
BJ
209#ifdef TCPDEBUG
210 struct tcp_debug tdb;
211#endif
3552a746 212COUNT(TCP_OUTPUT);
76ee76df 213
e1506033 214 if ((t = tp->t_template) == 0)
76ee76df
BJ
215 return (0);
216 MGET(m, 0);
217 if (m == 0)
218 return (0);
53a5409e
BJ
219 m->m_off = MMAXOFF - sizeof(struct tcpiphdr);
220 m->m_len = sizeof (struct tcpiphdr);
76ee76df
BJ
221 m->m_next = dat;
222 if (flags & TH_SYN)
223 len--;
224 if (flags & TH_FIN)
225 len--;
cdad2eb1
BJ
226 if (len < 0)
227 panic("tcp_output");
53a5409e
BJ
228 bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr));
229 t = mtod(m, struct tcpiphdr *);
76ee76df
BJ
230 if (tp->tc_flags&TC_SND_RST) {
231 flags &= ~TH_SYN;
232 flags |= TH_RST;
233 }
234 if (tp->tc_flags&TC_SYN_RCVD)
235 flags |= TH_ACK;
eb44bfb2 236 t->ti_flags = flags;
76ee76df 237 if (flags & TH_URG)
cdad2eb1 238 t->ti_urp = htons((u_short)tp->snd_urp); /*XXX */
eb44bfb2 239 t->ti_win =
53a5409e
BJ
240 so->so_rcv.sb_hiwat -
241 (so->so_rcv.sb_cc + tp->seqcnt);
eb44bfb2
BJ
242 if (tp->rcv_nxt + t->ti_win > tp->rcv_adv)
243 tp->rcv_adv = tp->rcv_nxt + t->ti_win;
76ee76df 244 if (len)
cdad2eb1 245 t->ti_len = htons((u_short)(len + TCPSIZE));
eb44bfb2 246 t->ti_win = htons(t->ti_win);
76ee76df 247#ifdef TCPDEBUG
53a5409e 248 if ((so->so_options & SO_DEBUG) || tcpconsdebug) {
eb44bfb2
BJ
249 t->ti_seq = tp->snd_nxt;
250 t->ti_ackno = tp->rcv_nxt;
76ee76df
BJ
251 tdb_setup(tp, t, INSEND, &tdb);
252 tdb_stuff(&tdb, -2);
253 }
254#endif
eb44bfb2
BJ
255 t->ti_seq = htonl(tp->snd_nxt);
256 t->ti_ackno = htonl(tp->rcv_nxt);
257 t->ti_sum = 0; /* gratuitous? */
2b4b57cd 258 t->ti_sum = inet_cksum(m, sizeof (struct tcpiphdr) + len);
76ee76df
BJ
259 ip = (struct ip *)t;
260 ip->ip_v = IPVERSION;
261 ip->ip_hl = 5;
262 ip->ip_tos = 0;
53a5409e 263 ip->ip_len = len + sizeof(struct tcpiphdr);
76ee76df
BJ
264 ip->ip_id = ip_id++;
265 ip->ip_off = 0;
266 ip->ip_ttl = MAXTTL;
2b4b57cd
BJ
267 ip_send(ip);
268 return (1);
76ee76df
BJ
269}
270
d52566dd
BJ
271tcp_fasttimo()
272{
273
4ad99bae
BJ
274COUNT(TCP_FASTTIMO);
275 /* someday do delayed ack processing here */
d52566dd 276}