Watt-32 tcp/ip  2.2 dev-rel.10
tcp_fsm.c
Go to the documentation of this file.
1 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <limits.h>
11 
12 #include "copyrigh.h"
13 #include "wattcp.h"
14 #include "chksum.h"
15 #include "strings.h"
16 #include "misc.h"
17 #include "timer.h"
18 #include "sock_ini.h"
19 #include "language.h"
20 #include "rs232.h"
21 #include "pcconfig.h"
22 #include "pcqueue.h"
23 #include "pcsed.h"
24 #include "pcpkt.h"
25 #include "ip4_out.h"
26 #include "ip6_out.h"
27 #include "ip6_in.h"
28 #include "split.h"
29 #include "pcdbug.h"
30 #include "pcstat.h"
31 #include "pctcp.h"
32 
33 #if !defined(USE_UDP_ONLY)
34 
35 #define flag_SYN_ACK (tcp_FlagSYN | tcp_FlagACK)
36 #define flag_FIN_ACK (tcp_FlagFIN | tcp_FlagACK)
37 
38 #if 1
39  #define TCP_TRACE TCP_TRACE_MSG
40 #else
41  #define TCP_TRACE ((void)0)
42 #endif
43 
44 typedef int (*tcp_StateProc) (_tcp_Socket**, /* in/out: TCP socket, can change on output */
45  const in_Header*, /* in: IP header */
46  tcp_Header*, /* in: TCP header */
47  int); /* in: TCP flags */
48 
49 static int tcp_listen_state (_tcp_Socket**, const in_Header*, tcp_Header*, int);
50 static int tcp_resolve_state (_tcp_Socket**, const in_Header*, tcp_Header*, int);
51 static int tcp_synsent_state (_tcp_Socket**, const in_Header*, tcp_Header*, int);
52 static int tcp_synrec_state (_tcp_Socket**, const in_Header*, tcp_Header*, int);
53 static int tcp_estab_state (_tcp_Socket**, const in_Header*, tcp_Header*, int);
54 static int tcp_estcl_state (_tcp_Socket**, const in_Header*, tcp_Header*, int);
55 static int tcp_finwt1_state (_tcp_Socket**, const in_Header*, tcp_Header*, int);
56 static int tcp_finwt2_state (_tcp_Socket**, const in_Header*, tcp_Header*, int);
57 static int tcp_closewt_state (_tcp_Socket**, const in_Header*, tcp_Header*, int);
58 static int tcp_closing_state (_tcp_Socket**, const in_Header*, tcp_Header*, int);
59 static int tcp_lastack_state (_tcp_Socket**, const in_Header*, tcp_Header*, int);
60 static int tcp_timewt_state (_tcp_Socket**, const in_Header*, tcp_Header*, int);
61 
62 static int tcp_process_data (_tcp_Socket *s, const tcp_Header *tcp, int len, int *flags);
63 static void tcp_set_window (_tcp_Socket *s, const tcp_Header *tcp);
64 static int tcp_process_ACK (_tcp_Socket *s, long *unack);
65 
66 static tcp_StateProc tcp_state_tab [] = {
67  tcp_listen_state, /* tcp_StateLISTEN : listening for connection */
68  tcp_resolve_state, /* tcp_StateRESOLVE : resolving IP, waiting on ARP reply */
69  tcp_synsent_state, /* tcp_StateSYNSENT : SYN sent, active open */
70  tcp_synrec_state, /* tcp_StateSYNREC : SYN received, SYN+ACK sent (listen TCB) */
71  tcp_estab_state, /* tcp_StateESTAB : established */
72  tcp_estcl_state, /* tcp_StateESTCL : established, but will FIN */
73  tcp_finwt1_state, /* tcp_StateFINWT1 : sent FIN */
74  tcp_finwt2_state, /* tcp_StateFINWT2 : sent FIN, received FIN+ACK */
75  tcp_closewt_state, /* tcp_StateCLOSWT : received FIN waiting for close */
76  tcp_closing_state, /* tcp_StateCLOSING : sent FIN, received FIN (waiting for FIN+ACK) */
77  tcp_lastack_state, /* tcp_StateLASTACK : FIN received, ACK+FIN sent */
78  tcp_timewt_state, /* tcp_StateTIMEWT : dally after sending final FIN+ACK */
79  };
80 
81 static BOOL is_ip4; /* TRUE: input packet is IPv4, else IPv6 */
82 static DWORD acknum, seqnum; /* ACK/SEQ of current segment */
83 
84 #if defined(USE_NEW_TCP_REASM) /* not yet */
85 
86 #define MAX_REASM_SEG 10
87 
88 static int tcp_reassemble (_tcp_Socket *s, const tcp_Header *tcp,
89  UINT len, int flags);
90 struct tcp_reasm {
91  struct {
92  DWORD left;
93  DWORD right;
94  } edge [MAX_REASM_SEG];
95  int idx;
96  };
97 #endif
98 
99 
100 /*
101  * _tcp_fsm - Our TCP-input state-machine.
102  *
103  * Returns 1 to tcp_handler() if a retransmission is required
104  * immediately or when RTO expires.
105  */
106 int _tcp_fsm (_tcp_Socket **sp, const in_Header *ip)
107 {
108  tcp_Header *tcp;
109  _tcp_Socket *s = *sp;
110  BYTE flags;
111  int rc;
112  UINT in_state = s->state;
113 
114  if (s->state >= tcp_StateCLOSED)
115  return (0);
116 
117  is_ip4 = (ip->ver == 4);
118 
119 #if defined(NEED_SPLIT)
120  tcp = (tcp_Header*) pkt_get_type_in (TYPE_TCP_HEAD)->data;
121 #else
122  tcp = (tcp_Header*) ((BYTE*)ip + in_GetHdrLen (ip));
123  is_ip4 = TRUE; /* assume IPv4 */
124 #endif
125 
126  acknum = intel (tcp->acknum);
127  seqnum = intel (tcp->seqnum);
128 
129  flags = tcp->flags & tcp_FlagMASK;
130  rc = (*tcp_state_tab[s->state]) (sp, ip, tcp, flags);
131  s = *sp;
132 
133 #if defined(USE_DEBUG)
134  if (debug_on >= 3 && in_state != s->state)
135  {
136  const char *st_in = tcpStateName (in_state);
137  const char *st_out = tcpStateName (s->state);
138 
139  SIO_TRACE (("tcp-state: %s -> %s ", st_in, st_out));
140  TCP_CONSOLE_MSG (3, ("tcp-state: %s -> %s\n", st_in, st_out));
141  }
142 #endif
143 
144 #if defined(USE_BSD_API)
145  if (_bsd_socket_hook)
146  (*_bsd_socket_hook) (BSO_DEBUG, s, in_state, s->state);
147 #endif
148 
149  ARGSUSED (in_state);
150  return (rc);
151 }
152 
153 /*
154  * LISTEN state
155  */
156 static int tcp_listen_state (_tcp_Socket **sp, const in_Header *ip,
157  tcp_Header *tcp, int flags)
158 {
159  _tcp_Socket *s = *sp;
160 
161  SET_PEER_MAC_ADDR (s, ip); /* save his ethernet address */
162 
163  if ((flags & tcp_FlagSYN) == tcp_FlagSYN)
164  {
165 #if defined(USE_BSD_API)
166  /*
167  * Append the TCB `s' to the listen-queue. The new TCB on output
168  * from `_bsd_socket_hook' is the clone of `s' on input unless the
169  * listen-queue is full.
170  */
171  if (_bsd_socket_hook && !(*_bsd_socket_hook)(BSO_SYN_CALLBACK,&s))
172  {
173  /* Append failed due to queue full or (temporary) memory shortage.
174  * Silently discard SYN. TCB `s' is unchanged.
175  */
176  CLR_PEER_MAC_ADDR (s);
177  return (0);
178  }
179 #endif
180 
181  if (is_ip4 && ip->tos > s->tos)
182  s->tos = ip->tos;
183 
184  s->recv_next = seqnum + 1;
185  s->flags = flag_SYN_ACK;
186  s->state = tcp_StateSYNREC;
187  s->unhappy = TRUE;
188  TCP_SEND (s); /* respond immediately */
189 
190  s->timeout = set_timeout (tcp_TIMEOUT);
191  STAT (tcpstats.tcps_accepts++);
192  }
193  else
194  {
195  TCP_SEND_RESET (s, ip, tcp);
196  STAT (tcpstats.tcps_conndrops++);
197  CLR_PEER_MAC_ADDR (s);
198  }
199  return (0);
200 }
201 
202 /*
203  * RESOLVE state, GvB 2002-09 'inserted'
204  * Nothing done here, the action is in pctcp.c / tcp_Retransmitter()
205  */
206 static int tcp_resolve_state (_tcp_Socket **sp, const in_Header *ip,
207  tcp_Header *tcp, int flags)
208 {
209  ARGSUSED (sp);
210  ARGSUSED (ip);
211  ARGSUSED (tcp);
212  ARGSUSED (flags);
213  return (1);
214 }
215 
216 /*
217  * SYNSENT state
218  */
219 static int tcp_synsent_state (_tcp_Socket **sp, const in_Header *ip,
220  tcp_Header *tcp, int flags)
221 {
222  _tcp_Socket *s = *sp;
223 
224  if (flags & tcp_FlagSYN)
225  {
226  if (is_ip4 && ip->tos > s->tos)
227  s->tos = ip->tos;
228 
229  s->flags = tcp_FlagACK;
230  s->timeout = set_timeout (tcp_TIMEOUT);
231 
232  /* SYN+ACK means connection established, else SYNREC
233  */
234  if (flags & tcp_FlagACK)
235  {
236  /* Check the ACK value
237  */
238  if (acknum == s->send_next + 1)
239  {
240  const in6_Header *ip6 = (const in6_Header*) ip;
241  int len;
242 
243  if (is_ip4)
244  len = intel16 (ip->length) - in_GetHdrLen (ip);
245  else len = intel16 (ip6->len);
246 
247  s->state = tcp_StateESTAB;
248  s->send_next++;
249  s->recv_next = seqnum + 1;
250 
251  /* Should be no data in SYN+ACK, but..
252  */
253  tcp_process_data (s, tcp, len, &flags);
254 
255  /* Prevent retrans on no tx-data
256  */
257  s->unhappy = s->tx_datalen > 0 ? TRUE : FALSE;
258 
259  /* !! Maybe use TCP_SENDSOON() to merge application data into ACK
260  */
261  TCP_SEND (s);
262  }
263  else
264  {
265  /* Wrong ACK, force a RST and resend SYN now
266  */
267  s->flags = tcp_FlagRST;
268  s->unhappy = TRUE;
269  TCP_SEND (s);
270 
271  s->send_next = INIT_SEQ(); /* !! should we set a new seq-num? */
272  s->flags = tcp_FlagSYN;
273 
274 #if defined(USE_DEBUG)
275  s->last_seqnum[0] = 0UL;
276  s->last_seqnum[1] = 0UL;
277 #endif
278  TCP_SENDSOON (s);
279  }
280 
283  }
284  else
285  {
286  s->recv_next++;
287  s->state = tcp_StateSYNREC; /* resend SYN in tcp_Retransmitter() */
288  return (1);
289  }
290  }
291  else /* didn't get a SYN back. Reset it */
292  {
293  TCP_SEND_RESET (s, ip, tcp);
294  return (0);
295  }
296  return (1);
297 }
298 
299 /*
300  * SYNREC state (intermediate state for LISTEN to ESTABLISHED state).
301  */
302 static int tcp_synrec_state (_tcp_Socket **sp, const in_Header *ip,
303  tcp_Header *tcp, int flags)
304 {
305  _tcp_Socket *s = *sp;
306 
307  if (flags & tcp_FlagSYN) /* retransmitted SYN */
308  {
309  s->flags = flag_SYN_ACK;
310  s->unhappy = TRUE;
311  TCP_SEND (s);
312  s->timeout = set_timeout (tcp_TIMEOUT);
313  return (0);
314  }
315 
316  if ((flags & tcp_FlagACK) && acknum == (s->send_next + 1))
317  {
318  tcp_set_window (s, tcp); /* Allocate Tx-buffer based on peer's window */
319  STAT (tcpstats.tcps_connects++);
320  s->send_next++;
321  s->flags = tcp_FlagACK;
322  s->state = tcp_StateESTAB;
323  s->timeout = 0UL; /* never timeout now */
324  s->unhappy = FALSE;
325  return (0);
326  }
327  ARGSUSED (ip);
328  return (1);
329 }
330 
331 /*
332  * ESTABLISHED state
333  */
334 static int tcp_estab_state (_tcp_Socket **sp, const in_Header *ip,
335  tcp_Header *tcp, int flags)
336 {
337  const in6_Header *ip6 = (const in6_Header*) ip;
338  _tcp_Socket *s = *sp;
339  int len;
340  long ldiff; /* how much still ACK'ed */
341  BOOL did_tx;
342 
343  /* handle lost SYN
344  */
345  if ((flags & tcp_FlagSYN) && (flags & tcp_FlagACK))
346  {
347  /* !! should check if data and process it */
348  TCP_SEND (s);
349  return (0);
350  }
351 
352  if (!(flags & tcp_FlagACK)) /* must ACK something */
353  return (0);
354 
355  s->timeout = 0UL; /* we do not timeout at this point */
356 
357  if (!tcp_process_ACK(s,&ldiff))
358  {
359  TCP_CONSOLE_MSG (2, ("_tcp_fsm() confused so set unacked "
360  "back to 0 from %ld\n", s->send_una));
361  STAT (tcpstats.tcps_persistdrop++); /* !! a better counter? */
362  s->send_una = 0;
363  }
364 
365  if (s->send_una < 0)
366  s->send_una = 0;
367 
368  s->flags = tcp_FlagACK;
369 
370  if (is_ip4)
371  len = intel16 (ip->length) - in_GetHdrLen (ip);
372  else len = intel16 (ip6->len);
373 
374  if (tcp_process_data (s, tcp, len, &flags) < 0)
375  {
376  TCP_SEND (s); /* An out-of-order or missing segment; do fast ACK */
377  return (1);
378  }
379 
380  did_tx = FALSE;
381 
382  if (s->state != tcp_StateCLOSWT &&
383  (flags & tcp_FlagFIN) &&
384  SEQ_GEQ(s->recv_next,seqnum) &&
385  SEQ_LT(s->recv_next,seqnum+s->adv_win))
386  {
387  if (s->missed_seq[0] == s->missed_seq[1])
388  {
389  s->recv_next++;
390  SET_ERR_MSG (s, _LANG("Connection closed by peer"));
391 
392  /* Implied CLOSE-WAIT -> LAST-ACK transition here
393  */
394  TCP_SEND (s);
395  did_tx = TRUE;
396 
397  TCP_CONSOLE_MSG (2, ("tcp_estab_state(): got FIN\n"));
398 
399  s->locflags |= LF_GOT_FIN;
400  s->flags |= tcp_FlagFIN; /* for tcp_Retransmitter() */
401  s->unhappy = TRUE;
402  s->timeout = set_timeout (tcp_LASTACK_TIME); /* Added AGW 6 Jan 2001 */
403  s->state = tcp_StateLASTACK;
404  }
405  else
406  {
407  s->unhappy = TRUE;
408  TCP_SEND (s); /* force a retransmit, no state change */
409  did_tx = TRUE;
410  }
411  }
412 
413  /*
414  * Eliminate the spurious ACK messages bug.
415  * For the window update, the length should be the
416  * data length only, so exclude the TCP header size
417  * -- Joe <jdhagen@itis.com>
418  */
419  len -= (tcp->offset << 2);
420  if ((ldiff > 0 && s->tx_datalen > 0) || len > 0)
421  {
422  /* Need to ACK and update window, but how urgent ??
423  * We need a better criteria for doing Fast-ACK.
424  */
425  if (ldiff > 0 || s->adv_win < s->max_seg)
426  {
427  TCP_TRACE (("tcp_estab_state (%u): FastACK: ldiff %ld, "
428  "UNA %ld, MS-right %ld\n",
429  __LINE__, ldiff, s->send_una,
430  s->missed_seq[0] != s->missed_seq[1] ?
431  s->missed_seq[0] - s->recv_next : 0));
432  s->karn_count = 0;
433  s->flags |= tcp_FlagPUSH;
434  TCP_SEND (s);
435  did_tx = TRUE;
436 
437  if (s->adv_win == 0) /* need to open closed window in retransmitter */
438  {
439  s->locflags |= LF_WINUPDATE;
440  s->unhappy = TRUE;
441  }
442  }
443  else
444  {
445  TCP_SENDSOON (s); /* delayed ACK */
446  did_tx = TRUE;
447  }
448  }
449 
450  /* Check if we need to reply to keep-alive segment
451  */
452  if (!did_tx && (len == 0) && (seqnum == s->recv_next-1) &&
453  ((flags & tcp_FlagACK) == tcp_FlagACK) && /* ACK only */
454  (s->state == tcp_StateESTAB))
455  {
456  s->locflags |= LF_KEEPALIVE;
457  TCP_TRACE (("tcp_process_ACK(): Got keepalive ACK\n"));
458  TCP_SEND (s);
459  }
460  return (0);
461 }
462 
463 /*
464  * ESTAB_CLOSE state
465  */
466 static int tcp_estcl_state (_tcp_Socket **sp, const in_Header *ip,
467  tcp_Header *tcp, int flags)
468 {
469  tcp_estab_state (sp, ip, tcp, flags);
470  _tcp_close (*sp);
471  return (0);
472 }
473 
474 /*
475  * CLOSE_WAIT state
476  */
477 static int tcp_closewt_state (_tcp_Socket **sp, const in_Header *ip,
478  tcp_Header *tcp, int flags)
479 {
480  return tcp_estab_state (sp, ip, tcp, flags);
481 }
482 
483 /*
484  * FIN_WAIT1 state
485  */
486 static int tcp_finwt1_state (_tcp_Socket **sp, const in_Header *ip,
487  tcp_Header *tcp, int flags)
488 {
489  const in6_Header *ip6 = (const in6_Header*) ip;
490  _tcp_Socket *s = *sp;
491  long ldiff;
492  int len;
493 
494  if (is_ip4)
495  len = intel16 (ip->length) - in_GetHdrLen (ip);
496  else len = intel16 (ip6->len);
497 
498  /* Peer may not have read all the data yet, we
499  * must still supply it as requested
500  */
501  if (tcp_process_ACK(s,&ldiff))
502  {
503  if (ldiff == 0 || s->send_una < 0)
504  s->send_una = 0;
505  }
506 
507  /* They may still be transmitting data, we must read it
508  */
509  tcp_process_data (s, tcp, len, &flags);
510 
511  /* Check if peer TCP has ACK'ed all sent data and
512  * is ready to change states. No missing segment and got FIN+ACK.
513  */
514  if (s->missed_seq[0] == s->missed_seq[1] &&
515  (flags & flag_FIN_ACK) == flag_FIN_ACK)
516  {
517  if (seqnum == s->recv_next)
518  {
519  s->recv_next++; /* we must ACK their FIN! */
520 
521  if (SEQ_GEQ(acknum, s->send_next+1))
522  {
523  /* Not simultaneous close (they've ACKed our FIN)
524  * We need to ACK their FIN and move to TIME_WAIT
525  */
526  s->send_next++;
527  s->timeout = set_timeout (tcp_TIMEWT_TO);
528  s->state = tcp_StateTIMEWT;
529  }
530  else
531  {
532  /* Simultaneous close (haven't ACKed our FIN yet)
533  * We need to ACK their FIN and move to CLOSING
534  */
535  s->timeout = set_timeout (tcp_TIMEOUT); /* !! S. Lawson, added 12.Nov 1999 */
536  s->state = tcp_StateCLOSING;
537  }
538  s->flags = tcp_FlagACK;
539  s->unhappy = FALSE;
540  TCP_SEND (s);
541  }
542  }
543  else if (flags & tcp_FlagACK)
544  {
545  /* other side is legitimately ACKing our FIN
546  */
547  if ((acknum == s->send_next + 1) &&
548  (seqnum == s->recv_next) &&
549  (s->tx_datalen == 0))
550  {
551  if (!(s->locflags & LF_LINGER))
552  {
553  _tcp_unthread (s, TRUE); /* enters tcp_StateCLOSED */
554  return (0);
555  }
556  s->send_next++;
557  s->state = tcp_StateFINWT2;
558  s->unhappy = FALSE; /* we don't send anything */
559  s->timeout = set_timeout (tcp_TIMEOUT);
560  }
561  else if ((acknum == s->send_next + 1) && (seqnum == s->recv_next + 1))
562  {
563  /* !! added 30-Aug 1999 GV
564  * Try to stop that annoying retransmission bug/feature(?)
565  * from FreeBSD 4.x which increments both SEQ and ACK.
566  */
567  s->send_next++;
568  s->recv_next++;
569  s->flags = tcp_FlagRST;
570  s->unhappy = FALSE;
571  s->karn_count = 0;
572  s->tx_datalen = 0;
573  TCP_SEND (s);
574  _tcp_unthread (s, TRUE);
575  return (0);
576  }
577  }
578  return (1);
579 }
580 
581 /*
582  * FIN_WAIT2 state
583  */
584 static int tcp_finwt2_state (_tcp_Socket **sp, const in_Header *ip,
585  tcp_Header *tcp, int flags)
586 {
587  const in6_Header *ip6 = (const in6_Header*) ip;
588  _tcp_Socket *s = *sp;
589  int len;
590 
591  if (is_ip4)
592  len = intel16 (ip->length) - in_GetHdrLen (ip);
593  else len = intel16 (ip6->len);
594 
595  /* They may still be transmitting data, we must read it
596  */
597  tcp_process_data (s, tcp, len, &flags);
598 
599  if (s->missed_seq[0] != s->missed_seq[1])
600  {
601  /* peer must retransmit to get all data */
602  return (1);
603  }
604 
605  if (flags & tcp_FlagFIN)
606  {
607  TCP_CONSOLE_MSG (2, ("tcp_finwt2_state(): got FIN\n"));
608  s->locflags |= LF_GOT_FIN;
609  }
610 
611  if ((flags & tcp_FlagACK) &&
612  acknum == s->send_next &&
613  seqnum == s->recv_next)
614  {
615  s->recv_next++;
616  s->flags = tcp_FlagACK;
617  s->unhappy = FALSE;
618  s->state = tcp_StateTIMEWT;
619  s->timeout = set_timeout (tcp_TIMEWT_TO);
620  TCP_SEND (s);
621  return (0);
622  }
623  return (1);
624 }
625 
626 
627 /*
628  * CLOSING state
629  */
630 static int tcp_closing_state (_tcp_Socket **sp, const in_Header *ip,
631  tcp_Header *tcp, int flags)
632 {
633  _tcp_Socket *s = *sp;
634 
635  if ((flags & (tcp_FlagACK|tcp_FlagFIN)) == tcp_FlagACK) /* ACK, no FIN */
636  {
637  /* Per FINWT1 above, acknum should be 's->send_next+1',
638  * which should cause us to bump 's->send_next' to match.
639  */
640  if (SEQ_GT(acknum,s->send_next) && /* AGW - 6th Jan 2001 */
641  seqnum == s->recv_next)
642  {
643  s->send_next++;
644  s->state = tcp_StateTIMEWT;
645  s->unhappy = FALSE;
646  s->timeout = set_timeout (tcp_TIMEWT_TO);
647  }
648  }
649  ARGSUSED (ip);
650  ARGSUSED (tcp);
651  return (1);
652 }
653 
654 /*
655  * LASTACK state
656  */
657 static int tcp_lastack_state (_tcp_Socket **sp, const in_Header *ip,
658  tcp_Header *tcp, int flags)
659 {
660  _tcp_Socket *s = *sp;
661 
662  if (flags & tcp_FlagFIN)
663  {
664  /* they lost our two packets, back up
665  */
666  TCP_CONSOLE_MSG (2, ("tcp_lastack_state(): got FIN\n"));
667 
668  s->locflags |= LF_GOT_FIN;
669  s->flags = flag_FIN_ACK;
670  TCP_SEND (s);
671  s->unhappy = TRUE;
672  return (0);
673  }
674 
675  if (SEQ_GT(acknum,s->send_next) && /* AGW allow for any later acks 6th Jan 2001 */
676  seqnum == s->recv_next)
677  {
678  s->state = tcp_StateCLOSED; /* no 2*MSL necessary */
679  s->unhappy = FALSE; /* we're done */
680  return (0);
681  }
682  ARGSUSED (ip);
683  ARGSUSED (tcp);
684  return (1);
685 }
686 
687 /*
688  * TIMEWAIT state
689  */
690 static int tcp_timewt_state (_tcp_Socket **sp, const in_Header *ip,
691  tcp_Header *tcp, int flags)
692 {
693  _tcp_Socket *s = *sp;
694 
695  if (flags & tcp_FlagACK)
696  {
697  /* our peer needs an FIN-ACK which is sent by tcp_Retransmitter().
698  */
699  s->flags = tcp_FlagACK;
700  s->unhappy = FALSE;
701  s->state = tcp_StateCLOSED; /* support 2 MSL in RST code */
702  TCP_SEND (s);
703  }
704  ARGSUSED (ip);
705  ARGSUSED (tcp);
706  return (1);
707 }
708 
709 
713 static void tcp_process_options (_tcp_Socket *s, const tcp_Header *tcp,
714  const BYTE *tcp_data, int flags)
715 {
716  const BYTE *opt = (const BYTE*)(tcp+1);
717  WORD max_seg;
718  int num = 0;
719 
720  /* Default to not sending timestamp
721  */
722  s->locflags &= ~LF_USE_TSTAMP;
723 
724  /* Clamp # of options to prevent DoS-attack from 0-sized
725  * unknown options.
726  */
727  while (opt < tcp_data && num++ < 10)
728  {
729  switch (*opt)
730  {
731  case TCPOPT_EOL:
732  return;
733 
734  case TCPOPT_NOP:
735  opt++;
736  break;
737 
738  case TCPOPT_MAXSEG: /* we are very liberal on MSS stuff */
739  if (flags & tcp_FlagSYN)
740  {
741  max_seg = intel16 (*(WORD*)(opt+2));
742  if (!s->max_seg || max_seg < s->max_seg)
743  {
744  TCP_CONSOLE_MSG (2, ("Setting MSS %u\n", max_seg));
745  s->max_seg = max_seg;
746  }
747  }
748  opt += 4;
749  break;
750 
751  case TCPOPT_TIMESTAMP:
752  /* Use TS values only if SEQ is for new data.
753  */
754  if ((flags & tcp_FlagSYN) ||
755  ((flags & tcp_FlagACK) &&
756  (long)(seqnum - s->recv_next)))
757  {
758  s->ts_recent = intel (*(DWORD*)(opt+2)); /* echo this back */
759  s->ts_echo = intel (*(DWORD*)(opt+6)); /* use in RTT calc */
760  s->locflags |= LF_USE_TSTAMP; /* peer has this */
761  }
762  opt += 10;
763  break;
764 
765  case TCPOPT_WINDOW:
766  if (flags & tcp_FlagSYN)
767  {
768  s->rx_wscale = min (TCP_MAX_WINSHIFT, *(opt+2));
769  s->locflags |= LF_RCVD_SCALE;
770  }
771  opt += 3;
772  break;
773 
774  case TCPOPT_SACK_PERM:
775  if (flags & tcp_FlagSYN)
776  s->locflags |= LF_SACK_PERMIT; /* no effect yet */
777  opt += 2;
778  break;
779 
780  case TCPOPT_CHKSUM_REQ:
781  opt += 3;
782  break;
783 
784  case TCPOPT_CHKSUM_DAT:
785  opt += *(opt+1);
786  break;
787 
788  default: /* unknown options; type,length,... */
789  opt += *(opt+1);
790  break;
791  }
792  }
793 }
794 
795 
796 /*
797  * TCP segment processsing:
798  *
799  * In the tcp_Socket structure:
800  *
801  * - rx_datalen is the index in the receive buffer where the next
802  * in-order data should be written.
803  * - recv_next is the TCP sequence number of the start of the next
804  * in-order data.
805  * - missed_seq[0] is the TCP sequence number of the first octet of
806  * the buffered out-of-order data.
807  * - missed_seq[1] is the TCP sequence number of the first octet
808  * following the buffered out-of-order data. If missed_seq[0] and
809  * missed_seq[1] are equal, there is no buffered out-of-order data.
810  *
811  * ldiff is the difference between the received sequence number and
812  * the expected sequence number. If ldiff is zero or positive, and
813  * ldiff is less than the length of the packet, data can be appended
814  * to the receive buffer. If ldiff is negative, data may be prepended
815  * and/or appended to the buffered out-of-order data.
816  *
817  * Packets are discarded without processing if the _end_ of the packet
818  * is before recv_next, in which case we've already processed the
819  * data, or after the advertised receive window.
820  *
821  * For ldiff >= 0, there are four cases to handle:
822  * 1) No out-of-order buffer: append the packet data and add the
823  * length to recv_next.
824  * 2) No overlap with out-of-order buffer: same as (1).
825  * 3) New data reaches but doesn't extend out-of-order buffer:
826  * copy up to buffer, set recv_next to missed_seq[1], and
827  * clear missed_seq[0] and missed_seq[1].
828  * 4) New data extends past out-of-order buffer: same as (1),
829  * also clearing missed_seq[0] and missed_seq[1].
830  *
831  * For ldiff < 0, there are four further cases to handle:
832  * 5) No out-of-order buffer: copy the packet data and set
833  * missed_seq[0] and missed_seq[1].
834  * 6) Data starts at missed_seq[1]: append to out-of-order buffer
835  * and update missed_seq[1].
836  * 7) Data extends start: copy new data and update missed_seq[0].
837  * 8) Data extends end: copy new data and updated missed_seq[1].
838  * Case 7 and case 8 are not exclusive.
839  *
840  * When an out-of-order packet is received, -1 is returned so that a
841  * duplicate acknowledgement will be sent immediately, signalling the
842  * peer to use fast retransmit to resend the missing data.
843  */
844 
845 /*
846  * Add data at rx_datalen, updating rx_datalen and recv_next.
847  */
848 static void
849 copy_in_order (_tcp_Socket *s, const BYTE *data, unsigned len)
850 {
851  TCP_TRACE (("copy_in_order (%u): Append %u bytes at %u-%u\n",
852  __LINE__, len, s->rx_datalen, s->rx_datalen + len));
853  memcpy (s->rx_data + s->rx_datalen, data, len);
854  s->recv_next += len;
855  s->rx_datalen += len;
856 }
857 
858 /*
859  * Handle any new data that increments the 'recv_next' index.
860  * 'ldiff >= 0'.
861  */
862 static void
863 data_in_order (_tcp_Socket *s, const BYTE *data, unsigned len, unsigned diff)
864 {
865  /* Skip data before recv_next. We must be left with some data or
866  * we wouldn't have been called.
867  */
868  data += diff;
869  len -= diff;
870 
871  if (s->protoHandler)
872  {
873  s->recv_next += (*s->protoHandler) (s, data, len, NULL, NULL);
874  }
875  else if (s->missed_seq[0] == s->missed_seq[1] ||
876  s->recv_next + len < s->missed_seq[0])
877  {
878  /* (1) Normal case: just copy all the data to the buffer.
879  * (2) Received in-order doesn't catch up to buffered out-of-order.
880  */
881  copy_in_order (s, data, len);
882  }
883  else
884  {
885  /* (3) Received data catches up to saved out-of-order data.
886  * (4) Received data extends beyond saved out-of-order data.
887  */
888  unsigned ms_end = s->missed_seq[1] - s->recv_next;
889 
890  copy_in_order (s, data, s->missed_seq[0] - s->recv_next);
891 
892  /* Update offset and length to incorporate out-of-order data.
893  */
894  TCP_TRACE (("data_in_order (%u): Use %lu out-of-order bytes\n",
895  __LINE__, s->missed_seq[1] - s->missed_seq[0]));
896  s->rx_datalen += (s->missed_seq[1] - s->missed_seq[0]);
897  s->recv_next = s->missed_seq[1];
898  s->missed_seq[0] = s->missed_seq[1] = 0;
899 
900  if (len > ms_end)
901  {
902  /* (4) Extend out-of-order data, if received past end. */
903  copy_in_order (s, data + ms_end, len - ms_end);
904  }
905  }
906 
907  TCP_TRACE (("data_in_order (%u): edges %lu/%lu, recv.next %lu\n",
908  __LINE__, s->missed_seq[0], s->missed_seq[1],
909  s->recv_next));
910 
911  TCP_TRACE (("data_in_order (%u): new data now ends at %u\n",
912  __LINE__, s->rx_datalen));
913 }
914 
915 /*
916  * Add data before missed_seq[0], updating its value.
917  */
918 static void
919 prepend_out_of_order (_tcp_Socket *s, const BYTE *data, unsigned len)
920 {
921  unsigned start = s->missed_seq[0] - s->recv_next + s->rx_datalen - len;
922 
923  TCP_TRACE (("prepend_out_of_order (%u): Prepend %u bytes at %u-%u\n",
924  __LINE__, len, start, start + len));
925  memcpy (s->rx_data + start, data, len);
926  s->missed_seq[0] -= len;
927 }
928 
929 /*
930  * Add data after missed_seq[1], updating its value.
931  */
932 static void
933 append_out_of_order (_tcp_Socket *s, const BYTE *data, unsigned len)
934 {
935  unsigned start = s->missed_seq[1] - s->recv_next + s->rx_datalen;
936 
937  TCP_TRACE (("append_out_of_order (%u): Append %u bytes at %u-%u\n",
938  __LINE__, len, start, start + len));
939  memcpy (s->rx_data + start, data, len);
940  s->missed_seq[1] += len;
941 }
942 
943 /*
944  * Handle one out-of-segment packet (ldiff < 0)
945  */
946 static void
947 data_out_of_order (_tcp_Socket *s, const BYTE *data, unsigned len, unsigned diff)
948 {
949  if (s->missed_seq[0] == s->missed_seq[1])
950  {
951  /* (5) First out-of-order data. */
952  s->missed_seq[0] = s->missed_seq[1] = seqnum;
953  append_out_of_order (s, data, len);
954  }
955  else if (seqnum == s->missed_seq[1])
956  {
957  /* (6) Common case: immediately following last out-of-order packet. */
958  append_out_of_order (s, data, len);
959  }
960  else
961  {
962  /* Offsets from recv_next:
963  * - diff is offset to start of received data;
964  * - diff + len is offset to after received data;
965  * - left is offset to start of saved out-of-order data;
966  * - right is offset to after saved out-of-order data.
967  */
968  unsigned left = s->missed_seq[0] - s->recv_next;
969  unsigned right = s->missed_seq[1] - s->recv_next;
970 
971  if (diff < left && left <= diff + len)
972  {
973  /* (7) Data extending start. */
974  prepend_out_of_order (s, data, left - diff);
975  }
976 
977  if (diff <= right && right < diff + len)
978  {
979  /* (8) Data extending end. */
980  append_out_of_order (s, data - diff + right, diff + len - right);
981  }
982  }
983 
984  TCP_TRACE (("data_out_of_order (%u): edges %lu/%lu, recv.next %lu\n",
985  __LINE__, s->missed_seq[0], s->missed_seq[1], s->recv_next));
986 }
987 
993 static int tcp_process_data (_tcp_Socket *s, const tcp_Header *tcp,
994  int len, int *flags)
995 {
996  long ldiff;
997  int data_ofs;
998  const BYTE *data;
999 
1000  if (s->stress > 0)
1001  s->stress--;
1002 
1003  tcp_set_window (s, tcp); /* this one should be redundant */
1004 
1005  ldiff = (long) (s->recv_next - seqnum);
1006 
1007  if (*flags & tcp_FlagSYN)
1008  ldiff--; /* back up to 0 */
1009 
1010  /* find the data portion
1011  */
1012  data_ofs = tcp->offset << 2; /* dword to byte offset */
1013  data = (const BYTE*)tcp + data_ofs;
1014 
1015  if (data_ofs - sizeof(*tcp) > 0)
1016  tcp_process_options (s, tcp, data, *flags);
1017 
1018  if (len - data_ofs < 0)
1019  {
1020  STAT (tcpstats.tcps_rcvbadoff++);
1021  len = 0;
1022  }
1023  else
1024  len -= data_ofs; /* remove the header length */
1025 
1026  TCP_TRACE (("tcp_process_data (%u): len %u, ldiff %ld\n",
1027  __LINE__, len, ldiff));
1028 
1031 #if 0
1032  if ((*flags & tcp_FlagURG) && tcp->urgent && intel16(tcp->urgent) < len)
1033  {
1034  intel16 (tcp->urgent) + seq;
1035  }
1036 #endif
1037 
1038  /*
1039  * SYN/RST segments shouldn't carry any data.
1040  * But SYN-ACK can (?)
1041  */
1042  if (*flags & (tcp_FlagSYN|tcp_FlagRST))
1043  return (0);
1044 
1045  if (ldiff) /* Out-of-Sequence data */
1046  {
1047  STAT (tcpstats.tcps_rcvoopack++);
1048  STAT (tcpstats.tcps_rcvoobyte += len);
1049  }
1050  else
1051  {
1052  STAT (tcpstats.tcps_rcvpack++);
1053  STAT (tcpstats.tcps_rcvbyte += len);
1054  }
1055 
1056  /* No TCP data, so nothing more to do
1057  */
1058  if (len == 0)
1059  return (0);
1060 
1061  /* Check that _end_ of packet is valid, i.e. will fit in advertised window.
1062  * If it's before recv_next, we've seen it all before; if it's after
1063  * then the peer (or someone else) sent more than we said we could take.
1064  */
1065  if ((unsigned)len - ldiff > s->adv_win)
1066  {
1067  TCP_TRACE (("tcp_ProcessData (%u): packet ends outside %lu/%lu\n",
1068  __LINE__, s->recv_next, s->recv_next + s->adv_win));
1069  return (0);
1070  }
1071 
1072  /* Handle any new data that increments the 'recv_next' index
1073  */
1074 
1075  if (ldiff >= 0)
1076  {
1077  data_in_order (s, data, len, ldiff);
1078  s->unhappy = (s->tx_datalen > 0);
1079  return (0);
1080  }
1081 
1082  STAT (tcpstats.tcps_rcvduppack++); /* increment dup-ACK count */
1083  STAT (tcpstats.tcps_rcvdupbyte += len);
1084 
1085  /* No out-of-sequence processing of FIN flag - S. Lawson
1086  */
1087  if (*flags & tcp_FlagFIN)
1088  {
1089  TCP_TRACE (("tcp_process_data (%u): clearing FIN\n", __LINE__));
1090  *flags &= ~tcp_FlagFIN;
1091  }
1092 
1093  data_out_of_order (s, data, len, -ldiff);
1094  s->unhappy = TRUE;
1095  return (-1);
1096 }
1097 
1098 
1099 /*
1100  * Process the ACK value in received packet, but only if it falls within
1101  * current window. Discard queued Tx-data that has been acknowledged.
1102  */
1103 static int tcp_process_ACK (_tcp_Socket *s, long *unacked)
1104 {
1105  long ldiff = (long) (acknum - s->send_next);
1106  int diff = (int) ldiff;
1107 
1108  if (unacked)
1109  *unacked = ldiff;
1110 
1111 #if 0
1112  if (ldiff > s->window) /* peer ACK'd data not sent yet */
1113  {
1114  TCP_SEND (s);
1115  STAT (tcpstats.tcps_rcvacktoomuch++);
1116  return (1);
1117  }
1118 #endif
1119 
1120  if (ldiff >= 0 && (unsigned)diff <= s->tx_datalen)
1121  {
1122  if (s->tx_queuelen)
1123  {
1124  s->tx_queue += diff;
1125  s->tx_queuelen -= diff;
1126  }
1127  else if ((unsigned)diff < s->tx_datalen && diff > 0)
1128  {
1129  memmove (s->tx_data, s->tx_data+diff, s->tx_datalen-diff);
1130  }
1131 
1132  diff = min (diff, (long)s->tx_datalen); /* protect against "nastygrams" */
1133  s->tx_datalen -= diff;
1134  s->send_una -= diff;
1135  s->send_next += ldiff;
1136 
1137  /* If peer ACK'ed everything and all queued data sent,
1138  * stop RTT-timer
1139  */
1140  if (s->send_una == 0 && s->tx_datalen == 0)
1141  s->rtt_time = 0UL;
1142 
1143  STAT (tcpstats.tcps_rcvackpack++);
1144  STAT (tcpstats.tcps_rcvackbyte += ldiff);
1145  return (1);
1146  }
1147  return (0);
1148 }
1149 
1155 static void tcp_set_window (_tcp_Socket *s, const tcp_Header *tcp)
1156 {
1157  s->window = intel16 (tcp->window);
1158  if (s->window > MAX_WINDOW)
1159  s->window = MAX_WINDOW;
1160 
1161 #if 0
1162  if (s->send_ssthresh == 0)
1163  s->send_ssthresh = s->window;
1164 #endif
1165 
1166  if (s->tx_data == &s->tx_buf[0] && /* Tx-data in _tcp_Socket */
1167  s->window > s->max_tx_data) /* His window > our Tx-size */
1168  {
1169  WORD window = s->window;
1170  size_t size;
1171  BYTE *buf;
1172 
1173 #if defined(__MSDOS__)
1174  if (_eth_ndis3pkt) /* limit NDIS3PKT's in-transit bytes */
1175  window = min (window, 6*_mss);
1176 #endif
1177 
1178  size = window + 8; /* add size for markers */
1179  buf = malloc (size);
1180 
1181  TCP_TRACE (("tcp_set_window (%u): buf %p, size %lu, datalen %u\n",
1182  __LINE__, buf, (DWORD)size, s->tx_datalen));
1183  if (!buf)
1184  return;
1185 
1186  *(DWORD*)buf = SAFETY_TCP;
1187  *(DWORD*)(buf+size-4) = SAFETY_TCP;
1188  if (s->tx_datalen)
1189  memcpy (buf+4, s->tx_data, s->tx_datalen); /* copy to new buf */
1190  s->tx_data = buf + 4;
1191  s->max_tx_data = window - 1;
1192  }
1193 }
1194 
1199 #if defined(USE_NEW_TCP_REASM)
1200 
1201 static int tcp_reassemble (_tcp_Socket *s, const tcp_Header *tcp,
1202  const BYTE *data, UINT len, int *flags)
1203 {
1204  DWORD left_edge, right_edge;
1205  long size, ofs;
1206 
1207  if (len == 0)
1208  return (0);
1209 
1210  if (SEQ_EQ(seqnum, s->recv_next))
1211  {
1212  /* normal enqueue */
1213  return (0);
1214  }
1215 
1216  left_edge = s->recv_next - s->rx_datalen;
1217  right_edge = s->recv_next + s->adv_win;
1218 
1219  /* segment is left of expected recv-window
1220  */
1221  if (SEQ_LEQ(seqnum, left_edge) &&
1222  SEQ_LEQ(seqnum + len, left_edge))
1223  {
1224  return (0);
1225  }
1226 
1227  /* Some of the segment is left of expected recv-window
1228  */
1229  if (SEQ_LEQ(seqnum, left_edge) &&
1230  SEQ_BETWEEN(seqnum + len, left_edge+1, right_edge))
1231  {
1232  size = seqnum + len - left_edge;
1233  ofs = left_edge - seqnum;
1234  memcpy (s->rx_data + s->rx_datalen, data + ofs, size);
1235  return (0);
1236  }
1237 
1238  /* The normal case
1239  */
1240  if (SEQ_BETWEEN(seqnum,left_edge,right_edge-1) &&
1241  SEQ_GT(seqnum+len,right_edge))
1242  {
1243  size = len;
1244  ofs = seqnum - left_edge;
1245  memcpy (s->rx_data + s->rx_datalen + ofs, data, size);
1246  s->rx_datalen += len;
1247  s->recv_next = seqnum + len;
1248  return (0);
1249  }
1250 
1251  if (SEQ_GT(seqnum,right_edge))
1252  {
1253  return (0);
1254  }
1255  return (-1); /* unexpected case */
1256 }
1257 #endif /* USE_NEW_TCP_REASM */
1258 
1259 #endif /* !USE_UDP_ONLY */
1260 
BYTE karn_count
count of packets
Definition: wattcp.h:647
BYTE tos
TOS from IP-header.
Definition: wattcp.h:648
static int tcp_synsent_state(_tcp_Socket **, const in_Header *, tcp_Header *, int)
Definition: tcp_fsm.c:219
WORD flags
TCP flags used in next Tx.
Definition: wattcp.h:634
DWORD rtt_time
Round Trip Time value.
Definition: wattcp.h:651
void _tcp_close(_tcp_Socket *s)
Close a TCP connection.
Definition: pctcp.c:455
BYTE * tx_data
Tx data buffer (default tx_buf[])
Definition: wattcp.h:682
static void tcp_set_window(_tcp_Socket *s, const tcp_Header *tcp)
Allocate a Tx-buffer based on peer's advertised window.
Definition: tcp_fsm.c:1155
DWORD ts_echo
last TimeStamp echo received
Definition: wattcp.h:656
UINT max_tx_data
Last index for tx_data[].
Definition: wattcp.h:681
BOOL _eth_ndis3pkt
for DOS-programs only
Definition: pcsed.c:57
UINT tx_datalen
number of bytes of data to send
Definition: wattcp.h:680
long send_una
unacked send data, must be signed
Definition: wattcp.h:625
Core definitions.
static int tcp_process_data(_tcp_Socket *s, const tcp_Header *tcp, int len, int *flags)
Process the data in an incoming segment.
Definition: tcp_fsm.c:993
DWORD W32_CALL set_timeout(DWORD msec)
Return time for when given timeout (msec) expires.
Definition: timer.c:503
static int tcp_reassemble(_tcp_Socket *s, const tcp_Header *tcp, const BYTE *data, UINT len, int *flags)
Definition: tcp_fsm.c:1201
static void tcp_process_options(_tcp_Socket *s, const tcp_Header *tcp, const BYTE *tcp_data, int flags)
Process TCP options in segment.
Definition: tcp_fsm.c:713
BYTE tx_buf[tcp_MaxTxBufSize+1]
data for transmission
Definition: wattcp.h:683
Definition: ip.h:67
BYTE unhappy
flag, indicates retransmitting segt's
Definition: wattcp.h:632
_tcp_Socket * _tcp_unthread(_tcp_Socket *ds, BOOL free_tx)
Unthread a socket from the tcp socket list, if it's there.
Definition: pctcp.c:596
UINT window
other guy's window
Definition: wattcp.h:636
void *MS_CDECL * _bsd_socket_hook(enum BSD_SOCKET_OPS op,...)
This hook is to prevent the BSD-socket API being linked in by default.
DWORD missed_seq[2]
S.
Definition: wattcp.h:665
UINT tx_queuelen
optional Tx queue length
Definition: wattcp.h:677
UINT adv_win
our last advertised window
Definition: wattcp.h:637
UINT max_seg
MSS for this connection.
Definition: wattcp.h:658
DWORD last_seqnum[2]
increments
Definition: wattcp.h:629
DWORD recv_next
SEQ number we expect to receive.
Definition: wattcp.h:623
DWORD ts_recent
last TimeStamp value received
Definition: wattcp.h:655
DWORD send_next
SEQ we send but not ACK-ed by peer.
Definition: wattcp.h:624
DWORD timeout
timer for retrans etc.
Definition: wattcp.h:631
UINT state
tcp connection state
Definition: wattcp.h:622