Commit | Line | Data |
---|---|---|
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 | */ | |
24 | tcp_sndctl(tp) | |
53a5409e | 25 | struct tcpcb *tp; |
ea727f86 BJ |
26 | { |
27 | COUNT(TCP_SNDCTL); | |
28 | ||
29 | if (tcp_send(tp)) | |
30 | return (1); | |
31 | tcp_sndnull(tp); | |
d52566dd | 32 | return (0); |
ea727f86 BJ |
33 | } |
34 | ||
35 | tcp_sndwin(tp) | |
53a5409e | 36 | struct tcpcb *tp; |
ea727f86 BJ |
37 | { |
38 | int ihave, hehas; | |
39 | COUNT(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 | ||
55 | tcp_sndnull(tp) | |
53a5409e | 56 | register struct tcpcb *tp; |
ea727f86 BJ |
57 | { |
58 | COUNT(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 | ||
64 | tcp_sndrst(tp, n) | |
53a5409e BJ |
65 | register struct tcpcb *tp; |
66 | register struct tcpiphdr *n; | |
ea727f86 BJ |
67 | { |
68 | COUNT(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 | */ | |
84 | tcp_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 | 92 | COUNT(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 | 167 | struct tcpiphdr * |
76ee76df | 168 | tcp_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 | ||
203 | tcp_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 | 217 | COUNT(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 |
276 | tcp_fasttimo() |
277 | { | |
278 | ||
279 | } |