xref: /csrg-svn/sys/netinet/tcp_output.c (revision 5066)
1 /*	tcp_output.c	4.17	81/11/24	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/mbuf.h"
6 #include "../h/socket.h"
7 #include "../h/socketvar.h"
8 #include "../net/inet.h"
9 #include "../net/inet_pcb.h"
10 #include "../net/inet_systm.h"
11 #include "../net/imp.h"
12 #include "../net/ip.h"
13 #include "../net/ip_var.h"
14 #include "../net/tcp.h"
15 #include "../net/tcp_var.h"
16 #include "../net/tcp_fsm.h"
17 #include "/usr/include/errno.h"
18 
19 /*
20  * Special routines to send control messages.
21  */
22 tcp_sndctl(tp)
23 	struct tcpcb *tp;
24 {
25 COUNT(TCP_SNDCTL);
26 
27         if (tcp_send(tp))
28 		return (1);
29 	tcp_sndnull(tp);
30 	return (0);
31 }
32 
33 tcp_sndwin(tp)
34 	struct tcpcb *tp;
35 {
36 	int ihave, hehas;
37 COUNT(TCP_SNDWIN);
38 
39 	if (tp->rcv_adv) {
40 		register struct socket *so = tp->t_inpcb->inp_socket;
41 
42 		ihave = so->so_rcv.sb_hiwat -
43 		    (so->so_rcv.sb_cc + tp->seqcnt);
44 		hehas = tp->rcv_adv - tp->rcv_nxt;
45 		if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35)
46 			return;
47 	}
48         if (tcp_send(tp))
49 		return;
50 	tcp_sndnull(tp);
51 }
52 
53 tcp_sndnull(tp)
54 	register struct tcpcb *tp;
55 {
56 COUNT(TCP_SNDNULL);
57 
58 	(void) tcp_output(tp, 0, 0, (struct mbuf *)0);
59         tp->tc_flags &= ~TC_ACK_DUE;
60 }
61 
62 /*
63  * Tcp segment output routine.
64  */
65 tcp_send(tp)
66 	register struct tcpcb *tp;
67 {
68 	register unsigned long last, wind;
69 	register struct socket *so = tp->t_inpcb->inp_socket;
70 	struct mbuf *m;
71 	int flags = 0, forced, sent, len;
72 
73 COUNT(TCP_SEND);
74 	tp->snd_lst = tp->snd_nxt;
75 	forced = 0;
76 	m = NULL;
77 	if (tp->snd_nxt == tp->iss) {
78 		flags |= TH_SYN;
79 		tp->snd_lst++;
80 	}
81 	last = tp->snd_off;
82 	for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next)
83 		last += m->m_len;
84 	if (tp->snd_nxt > last) {
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 		}
91 	} else {
92 		if (tp->tc_flags&TC_SYN_ACKED) {
93 			wind = tp->snd_una + tp->snd_wnd;
94 			tp->snd_lst = MIN(last, wind);
95 			if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
96 				tp->snd_lst -= len - 1024;
97 			if (tp->snd_lst >= wind)
98 				tp->t_persist = T_PERS;
99 		}
100 		if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
101 			tp->snd_lst = tp->snd_nxt + 1;
102 			forced = 1;
103 		} else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0)
104 			return (0);
105 		m = m_copy(so->so_snd.sb_mb,
106 		      (int)(MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off),
107 		      (int)(tp->snd_lst - tp->snd_off));
108 		if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
109 			flags |= TH_EOL;
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)) {
113 			flags |= TH_FIN;
114 			tp->seq_fin = tp->snd_lst++;
115 		}
116 	}
117 	if (tp->snd_nxt >= tp->snd_lst)
118 		return (0);
119 	if (tp->tc_flags & TC_SND_URG)
120 		flags |= TH_URG;
121 	sent = tcp_output(tp, flags, (int)(tp->snd_lst - tp->snd_nxt), m);
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;
128 		}
129 	}
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;
136 	}
137 	tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE);
138 	tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi);
139 	return (1);
140 }
141 tcp_output(tp, flags, len, dat)
142 	register struct tcpcb *tp;
143 	register int flags;
144 	int len;
145 	struct mbuf *dat;
146 {
147 	register struct tcpiphdr *t;			/* known to be r9 */
148 	register struct mbuf *m;
149 	struct socket *so = tp->t_inpcb->inp_socket;
150 	register struct ip *ip;
151 COUNT(TCP_OUTPUT);
152 
153 	if ((t = tp->t_template) == 0)
154 		return (0);
155 	MGET(m, 0);
156 	if (m == 0)
157 		return (0);
158 	m->m_off = MMAXOFF - sizeof(struct tcpiphdr);
159 	m->m_len = sizeof (struct tcpiphdr);
160 	m->m_next = dat;
161 	if (flags & TH_SYN)
162 		len--;
163 	if (flags & TH_FIN)
164 		len--;
165 	if (len < 0)
166 		panic("tcp_output");
167 	bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr));
168 	t = mtod(m, struct tcpiphdr *);
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;
175 	t->ti_flags = flags;
176 	if (flags & TH_URG)
177 		t->ti_urp = htons((u_short)tp->snd_urp);	/*XXX */
178 	t->ti_win =
179 	    so->so_rcv.sb_hiwat -
180 		(so->so_rcv.sb_cc + tp->seqcnt);
181 	if (tp->rcv_nxt + t->ti_win > tp->rcv_adv)
182 		tp->rcv_adv = tp->rcv_nxt + t->ti_win;
183 	if (len)
184 		t->ti_len = htons((u_short)(len + sizeof (struct tcphdr)));
185 	t->ti_win = htons(t->ti_win);
186 	t->ti_seq = htonl(tp->snd_nxt);
187 	t->ti_ackno = htonl(tp->rcv_nxt);
188 	t->ti_sum = 0;		/* gratuitous? */
189 	t->ti_sum = inet_cksum(m, sizeof (struct tcpiphdr) + len);
190 	ip = (struct ip *)t;
191 	ip->ip_v = IPVERSION;
192 	ip->ip_hl = 5;
193 	ip->ip_tos = 0;
194 	ip->ip_len = len + sizeof(struct tcpiphdr);
195 	ip->ip_id = ip_id++;
196 	ip->ip_off = 0;
197 	ip->ip_ttl = MAXTTL;
198 	ip_send(ip);
199 	return (1);
200 }
201