Commit | Line | Data |
---|---|---|
eee3ab16 | 1 | /* tcp_usrreq.c 1.26 81/11/08 */ |
72f24d7d | 2 | |
4eb5d593 | 3 | #include "../h/param.h" |
72f24d7d | 4 | #include "../h/systm.h" |
dad64fdf BJ |
5 | #include "../h/mbuf.h" |
6 | #include "../h/socket.h" | |
eee3ab16 BJ |
7 | #include "../h/socketvar.h" |
8 | #include "../h/protosw.h" | |
9 | #include "../net/inet.h" | |
10 | #include "../net/inet_systm.h" | |
11 | #include "../net/imp.h" | |
12 | #include "../net/ip.h" | |
13 | #include "../net/tcp.h" | |
72f24d7d | 14 | #define TCPFSTAB |
186b5a8a BJ |
15 | #ifdef TCPDEBUG |
16 | #define TCPSTATES | |
17 | #endif | |
eee3ab16 BJ |
18 | #include "../net/tcp_fsm.h" |
19 | #include "../net/tcp_var.h" | |
20 | #include "/usr/include/errno.h" | |
21 | ||
22 | struct tcb *tcp_attach(); | |
23 | ||
24 | /* | |
25 | * Tcp initialization | |
26 | */ | |
27 | tcp_init() | |
28 | { | |
29 | ||
30 | tcp_iss = 1; /* wrong */ | |
31 | tcb.tcb_next = tcb.tcb_prev = (struct tcb *)&tcb; | |
32 | } | |
4eb5d593 | 33 | |
e1506033 BJ |
34 | /* |
35 | * Tcp finite state machine entries for timer and user generated | |
36 | * requests. These routines raise the ipl to that of the network | |
37 | * to prevent reentry. In particluar, this requires that the software | |
38 | * clock interrupt have lower priority than the network so that | |
39 | * we can enter the network from timeout routines without improperly | |
40 | * nesting the interrupt stack. | |
41 | */ | |
42 | ||
43 | /* | |
eee3ab16 | 44 | * Tcp protocol timeout routine called every 500 ms. |
e1506033 BJ |
45 | * Updates the timers in all active tcb's and |
46 | * causes finite state machine actions if timers expire. | |
47 | */ | |
eee3ab16 | 48 | tcp_slowtimo() |
4eb5d593 | 49 | { |
72f24d7d BJ |
50 | register struct tcb *tp; |
51 | int s = splnet(); | |
eee3ab16 | 52 | register short *tmp; |
9c5022e3 | 53 | register int i; |
72f24d7d BJ |
54 | COUNT(TCP_TIMEO); |
55 | ||
56 | /* | |
57 | * Search through tcb's and update active timers. | |
58 | */ | |
eee3ab16 BJ |
59 | tp = tcb.tcb_next; |
60 | for (; tp != (struct tcb *)&tcb; tp = tp->tcb_hd.tcb_next) { | |
9c5022e3 | 61 | tmp = &tp->t_init; |
2e80fb4c | 62 | for (i = 0; i < TNTIMERS; i++) { |
9c5022e3 | 63 | if (*tmp && --*tmp == 0) |
eee3ab16 | 64 | tcp_usrreq(tp->t_socket, PRU_SLOWTIMO, 0, i); |
2e80fb4c BJ |
65 | tmp++; |
66 | } | |
72f24d7d BJ |
67 | tp->t_xmt++; |
68 | } | |
eee3ab16 | 69 | tcp_iss += ISSINCR/2; /* increment iss */ |
72f24d7d | 70 | splx(s); |
4eb5d593 BJ |
71 | } |
72 | ||
e1506033 BJ |
73 | /* |
74 | * Cancel all timers for tcp tp. | |
75 | */ | |
76 | tcp_tcancel(tp) | |
77 | struct tcb *tp; | |
78 | { | |
eee3ab16 | 79 | register short *tmp = &tp->t_init; |
e1506033 BJ |
80 | register int i; |
81 | ||
82 | for (i = 0; i < TNTIMERS; i++) | |
83 | *tmp++ = 0; | |
84 | } | |
85 | ||
9c5022e3 BJ |
86 | /* |
87 | * Process a TCP user request for tcp tb. If this is a send request | |
88 | * then m is the mbuf chain of send data. If this is a timer expiration | |
89 | * (called from the software clock routine), then timertype tells which timer. | |
90 | */ | |
eee3ab16 BJ |
91 | tcp_usrreq(so, req, m, addr) |
92 | struct socket *so; | |
93 | int req; | |
9c5022e3 | 94 | struct mbuf *m; |
eee3ab16 | 95 | caddr_t addr; |
4eb5d593 | 96 | { |
eee3ab16 | 97 | register struct tcb *tp = (struct tcb *)so->so_pcb; |
72f24d7d BJ |
98 | int s = splnet(); |
99 | register int nstate; | |
186b5a8a BJ |
100 | #ifdef TCPDEBUG |
101 | struct tcp_debug tdb; | |
102 | #endif | |
eee3ab16 | 103 | int error = 0; |
72f24d7d BJ |
104 | COUNT(TCP_USRREQ); |
105 | ||
eee3ab16 BJ |
106 | if (tp) { |
107 | nstate = tp->t_state; | |
108 | tp->tc_flags &= ~TC_NET_KEEP; | |
109 | } else | |
110 | if (req != PRU_ATTACH) | |
111 | return (ENOTCONN); | |
9c5022e3 | 112 | #ifdef KPROF |
eee3ab16 | 113 | acounts[nstate][req]++; |
9c5022e3 | 114 | #endif |
186b5a8a | 115 | #ifdef TCPDEBUG |
eee3ab16 BJ |
116 | if (tp && ((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug)) { |
117 | tdb_setup(tp, (struct th *)0, req, &tdb); | |
186b5a8a BJ |
118 | tdb.td_tim = timertype; |
119 | } else | |
120 | tdb.td_tod = 0; | |
121 | #endif | |
eee3ab16 | 122 | switch (req) { |
4eb5d593 | 123 | |
9c5022e3 | 124 | /* |
eee3ab16 BJ |
125 | * Attach a tcp control block to this socket. |
126 | * TCP is not multicast, so this is possible | |
127 | * only if no connection currently exists. | |
9c5022e3 | 128 | */ |
eee3ab16 BJ |
129 | case PRU_ATTACH: |
130 | if (tp) | |
131 | error = EISCONN; | |
132 | else | |
133 | tp = tcp_attach(so, &error); | |
134 | nstate = CLOSED; | |
72f24d7d | 135 | break; |
4eb5d593 | 136 | |
9c5022e3 | 137 | /* |
eee3ab16 BJ |
138 | * Detach the TCP from this socket. This |
139 | * is possible only if a connection currently exists. | |
9c5022e3 | 140 | */ |
eee3ab16 BJ |
141 | case PRU_DETACH: |
142 | so->so_pcb = 0; | |
143 | break; | |
144 | ||
145 | /* | |
146 | * Form connection: send a SYN. | |
147 | */ | |
148 | case PRU_CONNECT: | |
9c5022e3 BJ |
149 | if (nstate != 0 && nstate != CLOSED) |
150 | goto bad; | |
98444525 | 151 | tcp_sndctl(tp); |
72f24d7d BJ |
152 | nstate = SYN_SENT; |
153 | break; | |
4eb5d593 | 154 | |
eee3ab16 BJ |
155 | case PRU_DISCONNECT: |
156 | so->so_pcb = 0; | |
157 | tcp_destroy(tp); | |
158 | break; | |
159 | ||
9c5022e3 | 160 | /* |
eee3ab16 BJ |
161 | * Declare no further transmissions. |
162 | * Can be generated by a user ioctl (half-close), | |
9c5022e3 BJ |
163 | * or when higher level close occurs, if a close hasn't happened |
164 | * already. | |
165 | */ | |
eee3ab16 | 166 | case PRU_SHUTDOWN: |
9c5022e3 | 167 | switch (nstate) { |
4eb5d593 | 168 | |
9c5022e3 BJ |
169 | /* |
170 | * If we are aborting out of a listener or a active | |
171 | * connection which has not yet completed we can just | |
172 | * delete the tcb. | |
173 | */ | |
174 | case LISTEN: | |
e1506033 | 175 | case SYN_SENT: |
72f24d7d | 176 | nstate = CLOSED; |
9c5022e3 | 177 | break; |
4eb5d593 | 178 | |
9c5022e3 BJ |
179 | /* |
180 | * If we have gotten as far as receiving a syn from | |
181 | * our foreign peer, we must be sure to send a FIN. | |
182 | * If we have gotten a FIN from the foreign peer already | |
183 | * (CLOSE_WAIT state), then all that remains is to wait | |
184 | * for his ack of the FIN (LAST_ACK state). If we have | |
185 | * not gotten a FIN from the foreign peer then we need | |
186 | * to either: | |
187 | * 1. rcv ack of our FIN (to FIN_W2) and then | |
188 | * send an ACK (to TIME_WAIT) and timeout at 2*MSL. | |
189 | * or 2. receive hist FIN (to CLOSING), send an ACK | |
190 | * (to TIME_WAIT), and then timeout. | |
191 | * In any case this starts with a transition to FIN_W1 here. | |
192 | */ | |
e1506033 | 193 | case SYN_RCVD: |
9c5022e3 BJ |
194 | case L_SYN_RCVD: |
195 | case ESTAB: | |
e1506033 | 196 | case CLOSE_WAIT: |
9c5022e3 BJ |
197 | tp->tc_flags |= TC_SND_FIN; |
198 | tcp_sndctl(tp); | |
199 | tp->tc_flags |= TC_USR_CLOSED; | |
200 | nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK; | |
201 | break; | |
202 | ||
203 | /* | |
204 | * In these states the user has already closed; | |
205 | * trying to close again is an error. | |
206 | */ | |
207 | case FIN_W1: | |
208 | case FIN_W2: | |
209 | case TIME_WAIT: | |
210 | case CLOSING: | |
211 | case LAST_ACK: | |
212 | case RCV_WAIT: | |
9c5022e3 BJ |
213 | break; |
214 | ||
215 | default: | |
216 | goto bad; | |
217 | } | |
72f24d7d BJ |
218 | break; |
219 | ||
9c5022e3 BJ |
220 | /* |
221 | * User notification of more window availability after | |
222 | * reading out data. This should not happen before a connection | |
223 | * is established or after it is closed. | |
224 | * If the foreign peer has closed and the local entity | |
225 | * has not, inform him of the FIN (give end of file). | |
226 | * If the local entity is in RCV_WAIT state (draining data | |
227 | * out of the TCP buffers after foreign close) and there | |
228 | * is no more data, institute a close. | |
229 | */ | |
eee3ab16 | 230 | case PRU_RCVD: |
9c5022e3 BJ |
231 | if (nstate < ESTAB || nstate == CLOSED) |
232 | goto bad; | |
e1506033 | 233 | tcp_sndwin(tp); |
2a4921ab BJ |
234 | if ((tp->tc_flags&TC_FIN_RCVD) && |
235 | (tp->tc_flags&TC_USR_CLOSED) == 0 && | |
236 | rcv_empty(tp)) | |
eee3ab16 BJ |
237 | tcp_error(tp, ESHUTDOWN); |
238 | if (nstate == RCV_WAIT && rcv_empty(tp)) | |
9c5022e3 | 239 | nstate = CLOSED; |
72f24d7d BJ |
240 | break; |
241 | ||
9c5022e3 BJ |
242 | /* |
243 | * Send request on open connection. | |
244 | * Should not happen if the connection is not yet established. | |
245 | * Allowed only on ESTAB connection and after FIN from | |
246 | * foreign peer. | |
247 | */ | |
eee3ab16 | 248 | case PRU_SEND: |
9c5022e3 BJ |
249 | switch (nstate) { |
250 | ||
251 | case ESTAB: | |
252 | case CLOSE_WAIT: | |
253 | nstate = tcp_usrsend(tp, m); | |
254 | break; | |
255 | ||
256 | default: | |
257 | if (nstate < ESTAB) | |
258 | goto bad; | |
eee3ab16 BJ |
259 | m_freem(m); |
260 | /* tcp_user(tp, UCLSERR); */ | |
9c5022e3 BJ |
261 | break; |
262 | } | |
72f24d7d BJ |
263 | break; |
264 | ||
9c5022e3 BJ |
265 | /* |
266 | * User abort of connection. | |
267 | * If a SYN has been received, but we have not exchanged FINs | |
268 | * then we need to send an RST. In any case we then | |
269 | * enter closed state. | |
270 | */ | |
eee3ab16 | 271 | case PRU_ABORT: |
9c5022e3 BJ |
272 | if (nstate == 0 || nstate == CLOSED) |
273 | break; | |
274 | switch (nstate) { | |
275 | ||
276 | case 0: | |
277 | case CLOSED: | |
278 | break; | |
279 | ||
280 | case SYN_RCVD: | |
281 | case ESTAB: | |
282 | case FIN_W1: | |
283 | case FIN_W2: | |
284 | case CLOSE_WAIT: | |
285 | tp->tc_flags |= TC_SND_RST; | |
286 | tcp_sndnull(tp); | |
287 | /* fall into ... */ | |
288 | ||
289 | default: | |
9c5022e3 BJ |
290 | nstate = CLOSED; |
291 | } | |
72f24d7d BJ |
292 | break; |
293 | ||
9c5022e3 BJ |
294 | /* |
295 | * Network down entry. Discard the tcb and force | |
296 | * the state to be closed, ungracefully. | |
297 | */ | |
eee3ab16 | 298 | case PRU_CLEAR: |
9c5022e3 BJ |
299 | if (nstate == 0 || nstate == CLOSED) |
300 | break; | |
72f24d7d BJ |
301 | nstate = CLOSED; |
302 | break; | |
303 | ||
eee3ab16 BJ |
304 | /* |
305 | * Ioctl on protocols. | |
306 | */ | |
307 | case PRU_CONTROL: | |
308 | break; | |
309 | ||
310 | /* | |
311 | * TCP Timer processing. | |
312 | * Timers should expire only on open connections | |
313 | * not in LISTEN state. | |
314 | */ | |
315 | case PRU_SLOWTIMO: | |
316 | switch (nstate) { | |
317 | ||
318 | case 0: | |
319 | case CLOSED: | |
320 | case LISTEN: | |
321 | goto bad; | |
322 | ||
323 | default: | |
324 | nstate = tcp_timers(tp, (int)addr); | |
325 | } | |
326 | break; | |
327 | ||
9c5022e3 BJ |
328 | default: |
329 | panic("tcp_usrreq"); | |
330 | bad: | |
331 | printf("tcp: bad state: tcb=%x state=%d input=%d\n", | |
eee3ab16 | 332 | tp, tp->t_state, req); |
9c5022e3 | 333 | nstate = EFAILEC; |
72f24d7d BJ |
334 | break; |
335 | } | |
72f24d7d | 336 | #ifdef TCPDEBUG |
8f5a3361 BJ |
337 | if (tdb.td_tod) |
338 | tdb_stuff(&tdb, nstate); | |
72f24d7d BJ |
339 | #endif |
340 | /* YECH */ | |
341 | switch (nstate) { | |
342 | ||
186b5a8a | 343 | case CLOSED: |
72f24d7d BJ |
344 | case SAME: |
345 | break; | |
4eb5d593 | 346 | |
72f24d7d | 347 | case EFAILEC: |
9c5022e3 BJ |
348 | if (m) |
349 | m_freem(dtom(m)); | |
72f24d7d | 350 | break; |
4eb5d593 | 351 | |
72f24d7d BJ |
352 | default: |
353 | tp->t_state = nstate; | |
354 | break; | |
355 | } | |
356 | splx(s); | |
4eb5d593 BJ |
357 | } |
358 | ||
eee3ab16 BJ |
359 | tcp_sense() |
360 | { | |
361 | ||
362 | } | |
363 | ||
a1904ebf BJ |
364 | /* |
365 | * Open routine, called to initialize newly created tcb fields. | |
366 | */ | |
eee3ab16 BJ |
367 | struct tcb * |
368 | tcp_attach(so) | |
369 | register struct socket *so; | |
72f24d7d | 370 | { |
eee3ab16 BJ |
371 | register struct tcb *tp; |
372 | COUNT(TCP_ATTACH); | |
72f24d7d | 373 | |
a1904ebf BJ |
374 | /* |
375 | * Link in tcb queue and make | |
376 | * initialize empty reassembly queue. | |
377 | */ | |
eee3ab16 BJ |
378 | tp->tcb_hd.tcb_next = tcb.tcb_next; |
379 | tcb.tcb_next->tcb_hd.tcb_prev = tp; | |
380 | tp->tcb_hd.tcb_prev = (struct tcb *)&tcb; | |
a1904ebf | 381 | tcb.tcb_next = tp; |
eee3ab16 | 382 | tp->tcb_hd.seg_next = tp->tcb_hd.seg_prev = (struct th *)tp; |
4eb5d593 | 383 | |
a1904ebf BJ |
384 | /* |
385 | * Initialize sequence numbers and | |
386 | * round trip retransmit timer. | |
387 | * (Other fields were init'd to zero when tcb allocated.) | |
388 | */ | |
72f24d7d | 389 | tp->t_xmtime = T_REXMT; |
a1904ebf BJ |
390 | tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = |
391 | tp->iss = tcp_iss; | |
72f24d7d | 392 | tp->snd_off = tp->iss + 1; |
dad64fdf | 393 | tcp_iss += (ISSINCR >> 1) + 1; |
4eb5d593 BJ |
394 | } |
395 | ||
a1904ebf | 396 | /* |
eee3ab16 | 397 | * Destroy a tcb. |
a1904ebf | 398 | */ |
eee3ab16 | 399 | tcp_detach(tp) |
4eb5d593 | 400 | register struct tcb *tp; |
72f24d7d | 401 | { |
eee3ab16 | 402 | register struct socket *so = tp->t_socket; |
72f24d7d BJ |
403 | register struct th *t; |
404 | register struct mbuf *m; | |
eee3ab16 | 405 | COUNT(TCP_DETACH); |
72f24d7d | 406 | |
a1904ebf | 407 | /* |
e1506033 | 408 | * Remove from tcb queue and cancel timers. |
a1904ebf | 409 | */ |
eee3ab16 BJ |
410 | tp->tcb_hd.tcb_prev->tcb_hd.tcb_next = tp->tcb_hd.tcb_next; |
411 | tp->tcb_hd.tcb_next->tcb_hd.tcb_prev = tp->tcb_hd.tcb_prev; | |
e1506033 | 412 | tcp_tcancel(tp); |
72f24d7d | 413 | |
a1904ebf | 414 | /* |
e1506033 | 415 | * Discard all buffers. |
a1904ebf | 416 | */ |
eee3ab16 | 417 | for (t = tp->tcb_hd.seg_next; t != (struct th *)tp; t = t->t_next) |
72f24d7d | 418 | m_freem(dtom(t)); |
eee3ab16 BJ |
419 | if (so->so_rcv.sb_mb) |
420 | { m_freem(so->so_rcv.sb_mb); so->so_rcv.sb_mb = 0; } | |
421 | so->so_rcv.sb_cc = 0; so->so_rcv.sb_mbcnt = 0; | |
422 | if (so->so_snd.sb_mb) | |
423 | { m_freem(so->so_snd.sb_mb); so->so_rcv.sb_mb = 0; } | |
424 | so->so_snd.sb_cc = 0; so->so_snd.sb_mbcnt = 0; | |
425 | ||
426 | for (m = tp->seg_unack; m; m = m->m_act) | |
72f24d7d | 427 | m_freem(m); |
eee3ab16 BJ |
428 | tp->seg_unack = 0; |
429 | ||
430 | /* | |
431 | * Free routing table entry. | |
432 | */ | |
433 | if (tp->t_host) { | |
434 | h_free(tp->t_host); | |
435 | tp->t_host = 0; | |
72f24d7d | 436 | } |
a1904ebf BJ |
437 | |
438 | /* | |
e1506033 | 439 | * Free tcp send template, the tcb itself, |
eee3ab16 | 440 | * and the space we had reserved in the meory pool. |
a1904ebf | 441 | */ |
e1506033 BJ |
442 | if (tp->t_template) { |
443 | m_free(dtom(tp->t_template)); | |
444 | tp->t_template = 0; | |
dad64fdf | 445 | } |
e006f425 | 446 | wmemfree((caddr_t)tp, 1024); |
eee3ab16 | 447 | m_release(so->so_rcv.sb_hiwat + so->so_snd.sb_hiwat + 2 * MSIZE); |
4eb5d593 BJ |
448 | } |
449 | ||
a1904ebf | 450 | /* |
e1506033 | 451 | * Send data queue headed by m0 into the protocol. |
a1904ebf | 452 | */ |
ea727f86 | 453 | tcp_usrsend(tp, m0) |
4eb5d593 | 454 | register struct tcb *tp; |
186b5a8a BJ |
455 | struct mbuf *m0; |
456 | { | |
4eb5d593 | 457 | register struct mbuf *m, *n; |
eee3ab16 | 458 | register struct socket *so = tp->t_socket; |
4eb5d593 | 459 | register off; |
6e8b2eca | 460 | seq_t last; |
a1904ebf | 461 | COUNT(TCP_USRSEND); |
4eb5d593 | 462 | |
4eb5d593 | 463 | last = tp->snd_off; |
186b5a8a | 464 | for (m = n = m0; m != NULL; m = m->m_next) { |
eee3ab16 | 465 | so->so_snd.sb_mbcnt++; |
e71a2b4d | 466 | if (m->m_off > MMAXOFF) |
eee3ab16 | 467 | so->so_snd.sb_mbcnt += NMBPG; |
4eb5d593 BJ |
468 | last += m->m_len; |
469 | } | |
eee3ab16 BJ |
470 | if ((m = so->so_snd.sb_mb) == NULL) |
471 | so->so_snd.sb_mb = n; | |
80de89dc BJ |
472 | else { |
473 | while (m->m_next != NULL) { | |
4eb5d593 BJ |
474 | m = m->m_next; |
475 | last += m->m_len; | |
476 | } | |
e71a2b4d | 477 | if (m->m_off <= MMAXOFF) { |
80de89dc BJ |
478 | last += m->m_len; |
479 | off = m->m_off + m->m_len; | |
e71a2b4d BJ |
480 | while (n && n->m_off <= MMAXOFF && |
481 | (MMAXOFF - off) >= n->m_len) { | |
80de89dc BJ |
482 | bcopy((caddr_t)((int)n + n->m_off), |
483 | (caddr_t)((int)m + off), n->m_len); | |
484 | m->m_len += n->m_len; | |
485 | off += n->m_len; | |
eee3ab16 | 486 | so->so_snd.sb_mbcnt--; |
80de89dc BJ |
487 | n = m_free(n); |
488 | } | |
4eb5d593 BJ |
489 | } |
490 | m->m_next = n; | |
4eb5d593 | 491 | } |
eee3ab16 | 492 | if (tp->t_options & TO_EOL) |
80de89dc | 493 | tp->snd_end = last; |
eee3ab16 | 494 | if (tp->t_options & TO_URG) { |
4eb5d593 | 495 | tp->snd_urp = last+1; |
a3d78bbd | 496 | tp->tc_flags |= TC_SND_URG; |
72f24d7d | 497 | } |
ea727f86 | 498 | tcp_send(tp); |
72f24d7d | 499 | return (SAME); |
4eb5d593 BJ |
500 | } |
501 | ||
a1904ebf BJ |
502 | /* |
503 | * TCP timer went off processing. | |
504 | */ | |
186b5a8a BJ |
505 | tcp_timers(tp, timertype) |
506 | register struct tcb *tp; | |
507 | int timertype; | |
4eb5d593 | 508 | { |
4eb5d593 | 509 | |
72f24d7d | 510 | COUNT(TCP_TIMERS); |
186b5a8a | 511 | switch (timertype) { |
4eb5d593 | 512 | |
72f24d7d | 513 | case TINIT: /* initialization timer */ |
a3d78bbd | 514 | if ((tp->tc_flags&TC_SYN_ACKED) == 0) { /* 35 */ |
eee3ab16 | 515 | /* XXX */ /* tcp_close(tp, UINTIMO); */ |
72f24d7d BJ |
516 | return (CLOSED); |
517 | } | |
518 | return (SAME); | |
519 | ||
520 | case TFINACK: /* fin-ack timer */ | |
521 | switch (tp->t_state) { | |
522 | ||
523 | case TIME_WAIT: | |
524 | /* | |
525 | * We can be sure our ACK of foreign FIN was rcvd, | |
526 | * and can close if no data left for user. | |
527 | */ | |
528 | if (rcv_empty(tp)) { | |
eee3ab16 | 529 | /* XXX */ /* tcp_close(tp, UCLOSED); */ /* 14 */ |
72f24d7d BJ |
530 | return (CLOSED); |
531 | } | |
532 | return (RCV_WAIT); /* 17 */ | |
533 | ||
9c5022e3 | 534 | case CLOSING: |
a3d78bbd | 535 | tp->tc_flags |= TC_WAITED_2_ML; |
72f24d7d BJ |
536 | return (SAME); |
537 | ||
538 | default: | |
539 | return (SAME); | |
540 | } | |
4eb5d593 | 541 | |
72f24d7d BJ |
542 | case TREXMT: /* retransmission timer */ |
543 | if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ | |
544 | /* | |
eee3ab16 | 545 | * Set so for a retransmission, increase rexmt time |
72f24d7d BJ |
546 | * in case of multiple retransmissions. |
547 | */ | |
548 | tp->snd_nxt = tp->snd_una; | |
a3d78bbd | 549 | tp->tc_flags |= TC_REXMT; |
72f24d7d BJ |
550 | tp->t_xmtime = tp->t_xmtime << 1; |
551 | if (tp->t_xmtime > T_REMAX) | |
552 | tp->t_xmtime = T_REMAX; | |
ea727f86 | 553 | tcp_send(tp); |
72f24d7d BJ |
554 | } |
555 | return (SAME); | |
556 | ||
557 | case TREXMTTL: /* retransmit too long */ | |
558 | if (tp->t_rtl_val > tp->snd_una) /* 36 */ | |
eee3ab16 | 559 | /* XXX */ /* to_user(tp->t_socket, URXTIMO); */; |
72f24d7d BJ |
560 | /* |
561 | * If user has already closed, abort the connection. | |
562 | */ | |
a3d78bbd | 563 | if (tp->tc_flags & TC_USR_CLOSED) { |
eee3ab16 | 564 | /* XXX */ /* tcp_close(tp, URXTIMO); */ |
72f24d7d BJ |
565 | return (CLOSED); |
566 | } | |
567 | return (SAME); | |
568 | ||
569 | case TPERSIST: /* persist timer */ | |
570 | /* | |
571 | * Force a byte send through closed window. | |
572 | */ | |
a3d78bbd | 573 | tp->tc_flags |= TC_FORCE_ONE; |
ea727f86 | 574 | tcp_send(tp); |
72f24d7d BJ |
575 | return (SAME); |
576 | } | |
577 | panic("tcp_timers"); | |
4eb5d593 BJ |
578 | } |
579 | ||
eee3ab16 BJ |
580 | tcp_error(so, errno) |
581 | struct socket *so; | |
582 | int errno; | |
4eb5d593 | 583 | { |
72f24d7d | 584 | COUNT(TO_USER); |
4eb5d593 | 585 | |
eee3ab16 BJ |
586 | so->so_error = errno; |
587 | sowakeup(so); | |
4eb5d593 | 588 | } |
186b5a8a BJ |
589 | |
590 | #ifdef TCPDEBUG | |
a1904ebf BJ |
591 | /* |
592 | * TCP debugging utility subroutines. | |
593 | * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID. | |
594 | */ | |
e006f425 BJ |
595 | tdb_setup(tp, n, input, tdp) |
596 | struct tcb *tp; | |
597 | register struct th *n; | |
598 | int input; | |
599 | register struct tcp_debug *tdp; | |
600 | { | |
601 | ||
a1904ebf | 602 | COUNT(TDB_SETUP); |
e006f425 BJ |
603 | tdp->td_tod = time; |
604 | tdp->td_tcb = tp; | |
605 | tdp->td_old = tp->t_state; | |
606 | tdp->td_inp = input; | |
607 | tdp->td_tim = 0; | |
608 | tdp->td_new = -1; | |
609 | if (n) { | |
610 | tdp->td_sno = n->t_seq; | |
611 | tdp->td_ano = n->t_ackno; | |
612 | tdp->td_wno = n->t_win; | |
613 | tdp->td_lno = n->t_len; | |
614 | tdp->td_flg = n->th_flags; | |
615 | } else | |
616 | tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno = | |
617 | tdp->td_flg = 0; | |
618 | } | |
619 | ||
620 | tdb_stuff(tdp, nstate) | |
621 | struct tcp_debug *tdp; | |
622 | int nstate; | |
623 | { | |
a1904ebf | 624 | COUNT(TDB_STUFF); |
e006f425 BJ |
625 | |
626 | tdp->td_new = nstate; | |
627 | tcp_debug[tdbx++ % TDBSIZE] = *tdp; | |
628 | if (tcpconsdebug & 2) | |
629 | tcp_prt(tdp); | |
630 | } | |
a1904ebf | 631 | |
a1904ebf BJ |
632 | tcp_prt(tdp) |
633 | register struct tcp_debug *tdp; | |
634 | { | |
635 | COUNT(TCP_PRT); | |
636 | ||
ddfd844e BJ |
637 | printf("%x ", ((int)tdp->td_tcb)&0xffffff); |
638 | if (tdp->td_inp == INSEND) { | |
639 | printf("SEND #%x", tdp->td_sno); | |
640 | tdp->td_lno = ntohs(tdp->td_lno); | |
641 | tdp->td_wno = ntohs(tdp->td_wno); | |
642 | } else { | |
643 | if (tdp->td_inp == INRECV) | |
644 | printf("RCV #%x ", tdp->td_sno); | |
645 | printf("%s.%s", | |
646 | tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); | |
647 | if (tdp->td_inp == ISTIMER) | |
648 | printf("(%s)", tcptimers[tdp->td_tim]); | |
649 | printf(" -> %s", | |
650 | tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); | |
651 | if (tdp->td_new == -1) | |
652 | printf(" (FAILED)"); | |
a1904ebf | 653 | } |
ddfd844e BJ |
654 | /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ |
655 | if (tdp->td_lno) | |
656 | printf(" len=%d", tdp->td_lno); | |
657 | if (tdp->td_wno) | |
658 | printf(" win=%d", tdp->td_wno); | |
659 | if (tdp->td_flg & TH_FIN) printf(" FIN"); | |
660 | if (tdp->td_flg & TH_SYN) printf(" SYN"); | |
661 | if (tdp->td_flg & TH_RST) printf(" RST"); | |
662 | if (tdp->td_flg & TH_EOL) printf(" EOL"); | |
663 | if (tdp->td_flg & TH_ACK) printf(" ACK %x", tdp->td_ano); | |
664 | if (tdp->td_flg & TH_URG) printf(" URG"); | |
a1904ebf BJ |
665 | printf("\n"); |
666 | } | |
e006f425 | 667 | #endif |