Subversion Repositories Kolibri OS

Rev

Rev 3674 | Rev 3756 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved.    ;;
4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  Part of the TCP/IP network stack for KolibriOS                 ;;
7
;;                                                                 ;;
8
;;   Written by hidnplayr@kolibrios.org                            ;;
9
;;                                                                 ;;
10
;;    Based on the code of 4.4BSD                                  ;;
11
;;                                                                 ;;
12
;;          GNU GENERAL PUBLIC LICENSE                             ;;
13
;;             Version 2, June 1991                                ;;
14
;;                                                                 ;;
15
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
16
 
17
$Revision: 3407 $
18
 
19
;-----------------------------------------------------------------
20
;
21
; TCP_input:
22
;
23
;       Add a segment to the incoming TCP queue
24
;
25
;  IN:  [esp] = ptr to buffer
26
;       [esp+4] = buffer size (dont care)
27
;       ebx = ptr to device struct
28
;       ecx = segment size
29
;       esi = ptr to TCP segment
30
;       edi = ptr to ipv4 source address, followed by ipv4 dest address
31
;
32
;  OUT: /
33
;
34
;-----------------------------------------------------------------
35
 
36
align 4
37
TCP_input:
38
 
39
; record the current time
40
        mov     eax, [timer_ticks]      ; in 1/100 seconds
41
        mov     [esp + 4], eax
42
 
43
        push    ebx ecx esi edi         ; mind the order
44
        mov     esi, esp
45
 
46
        pushf
47
        cli
48
        add_to_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .fail
49
        popf
50
 
51
        add     esp, sizeof.TCP_queue_entry
52
 
3644 hidnplayr 53
        call    NET_ptr_to_num4
54
        inc     [TCP_segments_rx + edi]
55
 
3545 hidnplayr 56
        xor     edx, edx
57
        mov     eax, [TCP_input_event]
58
        mov     ebx, [eax + EVENT.id]
59
        xor     esi, esi
60
        call    raise_event
61
 
62
        ret
63
 
64
  .fail:
65
        popf
3556 hidnplayr 66
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP incoming queue is full, discarding packet!\n"
3545 hidnplayr 67
 
3644 hidnplayr 68
        call    NET_ptr_to_num4
69
        inc     [TCP_segments_missed + edi]
3545 hidnplayr 70
 
71
        add     esp, sizeof.TCP_queue_entry - 8
72
        call    kernel_free
73
        add     esp, 4
74
 
75
        ret
76
 
77
 
78
 
79
 
80
align 4
81
TCP_process_input:
82
 
83
        xor     esi, esi
84
        mov     ecx, MANUAL_DESTROY
85
        call    create_event
86
        mov     [TCP_input_event], eax
87
 
88
  .wait:
89
        mov     eax, [TCP_input_event]
90
        mov     ebx, [eax + EVENT.id]
91
        call    wait_event
92
 
93
  .loop:
94
        get_from_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .wait
95
 
96
        push    [esi + TCP_queue_entry.timestamp]
97
        push    [esi + TCP_queue_entry.buffer_ptr]
98
 
99
        mov     ebx, [esi + TCP_queue_entry.device_ptr]
100
        mov     ecx, [esi + TCP_queue_entry.segment_size]
101
        mov     edi, [esi + TCP_queue_entry.ip_ptr]                     ; ptr to ipv4 source address, followed by ipv4 destination address
102
        mov     esi, [esi + TCP_queue_entry.segment_ptr]                ; change esi last
103
 
3556 hidnplayr 104
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: size=%u time=%d\n", ecx, [timer_ticks]
3545 hidnplayr 105
 
106
        mov     edx, esi
107
 
108
        cmp     ebx, LOOPBACK_DEVICE
109
        je      .checksum_ok
110
 
111
; re-calculate the checksum (if not already done by hw)
112
;        test    [ebx + NET_DEVICE.hwacc], HWACC_TCP_IPv4_IN
113
;        jnz     .checksum_ok
114
 
115
        push    ecx esi
116
        pushw   [esi + TCP_header.Checksum]
117
        mov     [esi + TCP_header.Checksum], 0
118
        TCP_checksum (edi), (edi+4)
119
        pop     cx                      ; previous checksum
120
        cmp     cx, dx
121
        pop     edx ecx
122
        jne     .drop_no_socket
123
  .checksum_ok:
124
 
125
; Verify the data offset
126
        and     [edx + TCP_header.DataOffset], 0xf0                     ; Calculate TCP segment header size (throwing away unused reserved bits in TCP header)
127
        shr     [edx + TCP_header.DataOffset], 2
128
        cmp     [edx + TCP_header.DataOffset], sizeof.TCP_header        ; Now see if it's at least the size of a standard TCP header
129
        jb      .drop_no_socket                                         ; If not, drop the packet
130
 
131
        movzx   eax, [edx + TCP_header.DataOffset]
132
        sub     ecx, eax                                                ; substract TCP header size from total segment size
133
        jb      .drop_no_socket                                         ; If total segment size is less then the advertised header size, drop packet
3556 hidnplayr 134
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: %u bytes of data\n", ecx
3545 hidnplayr 135
 
136
;-------------------------------------------
137
; Convert Big-endian values to little endian
138
 
139
        ntohd   [edx + TCP_header.SequenceNumber]
140
        ntohd   [edx + TCP_header.AckNumber]
141
 
142
        ntohw   [edx + TCP_header.Window]
143
        ntohw   [edx + TCP_header.UrgentPointer]
144
 
145
;------------------------
146
; Find the socket pointer
147
 
148
; IP Packet TCP Destination Port = local Port
149
; (IP Packet SenderAddress = Remote IP)  OR  (Remote IP = 0)
150
; (IP Packet TCP Source Port = remote Port) OR (remote Port = 0)
151
 
152
  .findpcb:
3647 hidnplayr 153
        pusha
154
        mov     ecx, socket_mutex
155
        call    mutex_lock
156
        popa
157
 
3545 hidnplayr 158
        mov     ebx, net_sockets
159
        mov     si, [edx + TCP_header.DestinationPort]
160
 
161
  .socket_loop:
162
        mov     ebx, [ebx + SOCKET.NextPtr]
163
        or      ebx, ebx
3647 hidnplayr 164
        jz      .no_socket ;respond_seg_reset
3545 hidnplayr 165
 
166
        cmp     [ebx + SOCKET.Domain], AF_INET4
167
        jne     .socket_loop
168
 
169
        cmp     [ebx + SOCKET.Protocol], IP_PROTO_TCP
170
        jne     .socket_loop
171
 
172
        cmp     [ebx + TCP_SOCKET.LocalPort], si
173
        jne     .socket_loop
174
 
175
        mov     eax, [ebx + IP_SOCKET.RemoteIP]
176
        cmp     eax, [edi]                              ; Ipv4 source address
177
        je      @f
178
        test    eax, eax
179
        jnz     .socket_loop
180
       @@:
181
 
182
        mov     ax, [ebx + TCP_SOCKET.RemotePort]
183
        cmp     [edx + TCP_header.SourcePort], ax
184
        je      .found_socket
185
        test    ax, ax
186
        jnz     .socket_loop
187
  .found_socket:                                        ; ebx now contains the socketpointer
3647 hidnplayr 188
        pusha
189
        mov     ecx, socket_mutex
190
        call    mutex_unlock
191
        popa
192
 
3556 hidnplayr 193
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: socket ptr=%x state=%u flags=%x\n", ebx, [ebx + TCP_SOCKET.t_state], [edx + TCP_header.Flags]:2
3545 hidnplayr 194
 
195
;----------------------------
196
; Check if socket isnt closed
197
 
198
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_CLOSED
199
        je      .drop_no_socket
200
 
201
;----------------
202
; Lock the socket
203
 
204
        pusha
205
        lea     ecx, [ebx + SOCKET.mutex]
206
        call    mutex_lock
207
        popa
208
 
3556 hidnplayr 209
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: socket locked\n"
3545 hidnplayr 210
 
211
;---------------------------
212
; disable all temporary bits
213
 
214
        mov     [ebx + TCP_SOCKET.temp_bits], 0
215
 
216
;---------------------------------------
217
; unscale the window into a 32 bit value
218
 
219
        movzx   eax, [edx + TCP_header.Window]
220
        push    ecx
221
        mov     cl, [ebx + TCP_SOCKET.SND_SCALE]
222
        shl     eax, cl
223
        mov     dword [edx + TCP_header.Window], eax    ; word after window is checksum, we dont need checksum anymore
224
        pop     ecx
225
 
226
;---------------------------------------
227
; Are we accepting incoming connections?
228
 
229
        test    [ebx + SOCKET.options], SO_ACCEPTCON
230
        jz      .no_accept
231
 
3556 hidnplayr 232
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Accepting new connection\n"
3545 hidnplayr 233
 
234
        pusha
235
        lea     ecx, [ebx + SOCKET.mutex]
236
        call    mutex_unlock
237
        popa
238
 
239
        push    ecx edx esi edi         ;;;
240
        call    SOCKET_fork
241
        pop     edi esi edx ecx
242
 
243
        test    eax, eax
244
        jz      .drop_no_socket
245
 
246
        mov     ebx, eax
247
 
248
        mov     [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET        ;;; FIXME: should we take over bits from previous socket?
249
 
250
        push    dword [edi + 4]                         ; Ipv4 destination addres
251
        pop     [ebx + IP_SOCKET.LocalIP]
252
 
253
        push    [edx + TCP_header.DestinationPort]
254
        pop     [ebx + TCP_SOCKET.LocalPort]
255
 
256
        mov     [ebx + TCP_SOCKET.t_state], TCPS_LISTEN
257
  .no_accept:
258
 
259
 
260
;-------------------------------------
261
; Reset idle timer and keepalive timer
262
 
263
        mov     [ebx + TCP_SOCKET.t_idle], 0
264
        mov     [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_idle
3600 hidnplayr 265
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_keepalive
3545 hidnplayr 266
 
267
;--------------------
268
; Process TCP options
269
 
270
        push    ecx
271
 
272
        movzx   ecx, [edx + TCP_header.DataOffset]
273
        cmp     ecx, sizeof.TCP_header                  ; Does header contain any options?
274
        je      .no_options
275
 
3556 hidnplayr 276
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Segment has options\n"
3545 hidnplayr 277
 
278
;;; FIXME: for LISTEN, options should be called after we determined route, we need it for MSS
279
;;;        cmp     [ebx + TCP_SOCKET.t_state], TCPS_LISTEN ; no options when in listen state
280
;;;        jz      .not_uni_xfer                           ; also no header prediction
281
 
282
        add     ecx, edx
283
        lea     esi, [edx + sizeof.TCP_header]
284
 
285
  .opt_loop:
286
        cmp     esi, ecx                        ; are we scanning outside of header?
287
        jae     .no_options
288
        lodsb
289
        cmp     al, TCP_OPT_EOL                 ; end of option list?
290
        je      .no_options
291
        cmp     al, TCP_OPT_NOP
292
        je      .opt_loop
293
        cmp     al, TCP_OPT_MAXSEG
294
        je      .opt_maxseg
295
        cmp     al, TCP_OPT_WINDOW
296
        je      .opt_window
297
        cmp     al, TCP_OPT_SACK_PERMIT
298
        je      .opt_sack_permit
299
;        cmp     al, TCP_OPT_SACK
300
;        je      .opt_sack
301
        cmp     al, TCP_OPT_TIMESTAMP
302
        je      .opt_timestamp
3556 hidnplayr 303
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: unknown option:%u\n", al
3545 hidnplayr 304
        jmp     .no_options                     ; If we reach here, some unknown options were received, skip them all!
305
 
306
  .opt_maxseg:
307
        lodsb
308
        cmp     al, 4
309
        jne     .no_options                     ; error occured, ignore all options!
310
 
311
        test    [edx + TCP_header.Flags], TH_SYN
312
        jz      @f
313
 
314
        lodsw
315
        rol     ax, 8
3556 hidnplayr 316
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Maxseg=%u\n", ax
3545 hidnplayr 317
        call    TCP_mss
318
       @@:
319
        jmp     .opt_loop
320
 
321
 
322
  .opt_window:
323
        lodsb
324
        cmp     al, 3
325
        jne     .no_options
326
 
327
        test    [edx + TCP_header.Flags], TH_SYN
328
        jz      @f
329
 
3556 hidnplayr 330
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Got window scale option\n"
3545 hidnplayr 331
        or      [ebx + TCP_SOCKET.t_flags], TF_RCVD_SCALE
332
 
333
        lodsb
334
        mov     [ebx + TCP_SOCKET.SND_SCALE], al
335
        ;;;;; TODO
336
 
337
       @@:
338
        jmp     .opt_loop
339
 
340
 
341
  .opt_sack_permit:
342
        lodsb
343
        cmp     al, 2
344
        jne     .no_options
345
 
346
        test    [edx + TCP_header.Flags], TH_SYN
347
        jz      @f
348
 
3556 hidnplayr 349
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Selective Acknowledgement permitted\n"
3545 hidnplayr 350
        or      [ebx + TCP_SOCKET.t_flags], TF_SACK_PERMIT
351
 
352
       @@:
353
        jmp     .opt_loop
354
 
355
 
356
  .opt_timestamp:
357
        lodsb
358
        cmp     al, 10                          ; length must be 10
359
        jne     .no_options
360
 
3556 hidnplayr 361
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Got timestamp option\n"
3545 hidnplayr 362
 
363
        test    [edx + TCP_header.Flags], TH_SYN
364
        jz      @f
365
        or      [ebx + TCP_SOCKET.t_flags], TF_RCVD_TSTMP
366
       @@:
367
 
368
        lodsd
369
        mov     [ebx + TCP_SOCKET.ts_val], eax
370
        lodsd                                   ; timestamp echo reply
371
        mov     [ebx + TCP_SOCKET.ts_ecr], eax
372
        or      [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP
373
 
374
        ; Since we have a timestamp, lets do the paws test right away!
375
 
376
        test    [edx + TCP_header.Flags], TH_RST
377
        jnz     .no_paws
378
 
379
        mov     eax, [ebx + TCP_SOCKET.ts_recent]
380
        test    eax, eax
381
        jz      .no_paws
382
        cmp     eax, [ebx + TCP_SOCKET.ts_val]
383
        jge     .no_paws
384
 
3556 hidnplayr 385
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: PAWS: detected an old segment\n"
3545 hidnplayr 386
 
387
        mov     eax, [esp+4+4]                          ; tcp_now
388
        sub     eax, [ebx + TCP_SOCKET.ts_recent_age]
389
 
390
        pop     ecx
391
        cmp     eax, TCP_PAWS_IDLE
392
        jle     .drop_after_ack                         ; TODO: update stats
393
        push    ecx
394
 
395
        mov     [ebx + TCP_SOCKET.ts_recent], 0         ; timestamp was invalid, fix it.
396
  .no_paws:
397
        jmp     .opt_loop
398
 
399
  .no_options:
400
 
401
        pop     ecx
402
 
403
;-----------------------------------------------------------------------
404
; Time to do some header prediction (Original Principle by Van Jacobson)
405
 
406
; There are two common cases for an uni-directional data transfer.
407
;
408
; General rule: the packets has no control flags, is in-sequence,
409
;   window width didnt change and we're not retransmitting.
410
;
411
; Second rules:
412
;  -  If the length is 0 and the ACK moved forward, we're the sender side of the transfer.
413
;      In this case we'll free the ACK'ed data and notify higher levels that we have free space in buffer
414
;
415
;  -  If the length is not 0 and the ACK didn't move, we're the receiver side of the transfer.
416
;      If the packets are in order (data queue is empty), add the data to the socket buffer and request a delayed ACK
417
 
418
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
419
        jnz     .not_uni_xfer
420
 
421
        test    [edx + TCP_header.Flags], TH_SYN + TH_FIN + TH_RST + TH_URG
422
        jnz     .not_uni_xfer
423
 
424
        test    [edx + TCP_header.Flags], TH_ACK
425
        jz      .not_uni_xfer
426
 
427
        mov     eax, [edx + TCP_header.SequenceNumber]
428
        cmp     eax, [ebx + TCP_SOCKET.RCV_NXT]
429
        jne     .not_uni_xfer
430
 
431
        mov     eax, dword [edx + TCP_header.Window]
432
        cmp     eax, [ebx + TCP_SOCKET.SND_WND]
433
        jne     .not_uni_xfer
434
 
435
        mov     eax, [ebx + TCP_SOCKET.SND_NXT]
436
        cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
437
        jne     .not_uni_xfer
438
 
439
;---------------------------------------
440
; check if we are sender in the uni-xfer
441
 
442
; If the following 4 conditions are all true, this segment is a pure ACK.
443
;
444
; - The segment contains no data.
445
        test    ecx, ecx
446
        jnz     .not_sender
447
 
448
; - The congestion window is greater than or equal to the current send window.
449
;     This test is true only if the window is fully open, that is, the connection is not in the middle of slow start or congestion avoidance.
450
        mov     eax, [ebx + TCP_SOCKET.SND_CWND]
451
        cmp     eax, [ebx + TCP_SOCKET.SND_WND]
452
        jb      .not_uni_xfer
453
 
454
; - The acknowledgment field in the segment is less than or equal to the maximum sequence number sent.
455
        mov     eax, [edx + TCP_header.AckNumber]
456
        cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
457
        ja      .not_uni_xfer
458
 
459
; - The acknowledgment field in the segment is greater than the largest unacknowledged sequence number.
460
        sub     eax, [ebx + TCP_SOCKET.SND_UNA]
461
        jbe     .not_uni_xfer
462
 
3556 hidnplayr 463
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction: we are sender\n"
3545 hidnplayr 464
 
465
;---------------------------------
466
; Packet is a pure ACK, process it
467
 
468
; Delete acknowledged bytes from send buffer
469
        pusha
470
        mov     ecx, eax
471
        lea     eax, [ebx + STREAM_SOCKET.snd]
472
        call    SOCKET_ring_free
473
        popa
474
 
475
; Update RTT estimators
476
 
477
        test    [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP
478
        jz      .no_timestamp_rtt
479
        mov     eax, [esp + 4]                          ; timestamp when this segment was received
480
        sub     eax, [ebx + TCP_SOCKET.ts_ecr]
481
        inc     eax
482
        call    TCP_xmit_timer
483
        jmp     .rtt_done
484
 
485
  .no_timestamp_rtt:
486
        cmp     [ebx + TCP_SOCKET.t_rtt], 0
487
        je      .rtt_done
488
        mov     eax, [edx + TCP_header.AckNumber]
489
        cmp     eax, [ebx + TCP_SOCKET.t_rtseq]
490
        jbe     .rtt_done
491
        mov     eax, [ebx + TCP_SOCKET.t_rtt]
492
        call    TCP_xmit_timer
493
 
494
  .rtt_done:
495
 
496
; update window pointers
497
        mov     eax, [edx + TCP_header.AckNumber]
498
        mov     [ebx + TCP_SOCKET.SND_UNA], eax
499
 
500
; Stop retransmit timer
3600 hidnplayr 501
        and     [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission
3545 hidnplayr 502
 
503
; Unlock the socket
504
        pusha
505
        lea     ecx, [ebx + SOCKET.mutex]
506
        call    mutex_unlock
507
        popa
508
 
509
; Awaken waiting processes
510
        mov     eax, ebx
511
        call    SOCKET_notify
512
 
513
; Generate more output
514
        call    TCP_output
515
 
516
        jmp     .drop_no_socket
517
 
518
;-------------------------------------------------
519
; maybe we are the receiver in the uni-xfer then..
520
 
521
  .not_sender:
522
; - The amount of data in the segment is greater than 0 (data count is in ecx)
523
 
524
; - The acknowledgment field equals the largest unacknowledged sequence number. This means no data is acknowledged by this segment.
525
        mov     eax, [edx + TCP_header.AckNumber]
526
        cmp     eax, [ebx + TCP_SOCKET.SND_UNA]
527
        jne     .not_uni_xfer
528
 
529
; - The reassembly list of out-of-order segments for the connection is empty (seg_next equals tp).
530
 
531
;;; TODO
532
 
533
;       jnz     .not_uni_xfer
534
 
535
; Complete processing of received data
536
 
3556 hidnplayr 537
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction: we are receiving %u bytes\n", ecx
3545 hidnplayr 538
 
539
        add     [ebx + TCP_SOCKET.RCV_NXT], ecx         ; Update sequence number with number of bytes we have copied
540
 
541
        movzx   esi, [edx + TCP_header.DataOffset]
542
        add     esi, edx
543
        lea     eax, [ebx + STREAM_SOCKET.rcv]
544
        call    SOCKET_ring_write                       ; Add the data to the socket buffer
545
 
546
        mov     eax, ebx
547
        call    SOCKET_notify
548
 
549
        or      [ebx + TCP_SOCKET.t_flags], TF_DELACK   ; Set delayed ack flag
550
 
551
        jmp     .drop
552
 
553
;--------------------------------------------------
554
; Header prediction failed, do it the slow way
555
 
556
  .not_uni_xfer:
557
 
3556 hidnplayr 558
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction failed\n"
3545 hidnplayr 559
 
560
; Calculate receive window size
561
 
562
        push    edx
563
        mov     eax, SOCKETBUFFSIZE
564
        sub     eax, [ebx + STREAM_SOCKET.rcv.size]
565
        mov     edx, [ebx + TCP_SOCKET.RCV_ADV]
566
        sub     edx, [ebx + TCP_SOCKET.RCV_NXT]
567
        cmp     eax, edx
568
        jg      @f
569
        mov     eax, edx
570
       @@:
3556 hidnplayr 571
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Receive window size=%d\n", eax
3545 hidnplayr 572
        mov     [ebx + TCP_SOCKET.RCV_WND], eax
573
        pop     edx
574
 
575
; If we are in listen or syn_sent state, go to that specific code right away
576
 
577
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_LISTEN
578
        je      .LISTEN
579
 
580
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_SYN_SENT
581
        je      .SYN_SENT
582
 
583
;----------------------------
584
; trim any data not in window
585
 
586
; check for duplicate data at beginning of segment (635)
587
 
588
        mov     eax, [ebx + TCP_SOCKET.RCV_NXT]
589
        sub     eax, [edx + TCP_header.SequenceNumber]
590
        jle     .no_duplicate
591
 
3556 hidnplayr 592
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: %u bytes duplicate data!\n", eax
3545 hidnplayr 593
 
594
        test    [edx + TCP_header.Flags], TH_SYN
595
        jz      .no_dup_syn
596
 
3556 hidnplayr 597
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: got duplicate syn\n"
3545 hidnplayr 598
 
599
        and     [edx + TCP_header.Flags], not (TH_SYN)
600
        inc     [edx + TCP_header.SequenceNumber]
601
 
602
        cmp     [edx + TCP_header.UrgentPointer], 1
603
        jbe     @f
604
        dec     [edx + TCP_header.UrgentPointer]
605
        jmp     .dup_syn
606
       @@:
607
        and     [edx + TCP_header.Flags], not (TH_URG)
608
  .dup_syn:
609
        dec     eax
610
  .no_dup_syn:
611
 
612
; Check for entire duplicate segment (646)
613
        cmp     eax, ecx                ; eax holds number of bytes to drop, ecx is data size
614
        jb      .duplicate
615
        jnz     @f
616
        test    [edx + TCP_header.Flags], TH_FIN
617
        jnz     .duplicate
618
       @@:
619
 
620
; Any valid FIN must be to the left of the window.
621
; At this point the FIN must be out of sequence or a duplicate, drop it
622
        and     [edx + TCP_header.Flags], not TH_FIN
623
 
624
; send an ACK and resynchronize and drop any data.
625
; But keep on processing for RST or ACK
3556 hidnplayr 626
        DEBUGF  DEBUG_NETWORK_VERBOSE,  "616\n"
3545 hidnplayr 627
        or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
628
        mov     eax, ecx
629
;TODO: update stats
630
 
631
;-----------------------------------------------
632
; Remove duplicate data and update urgent offset
633
 
634
  .duplicate:
635
;;; TODO: 677
636
        add     [edx + TCP_header.SequenceNumber], eax
637
        sub     ecx, eax
638
 
639
        sub     [edx + TCP_header.UrgentPointer], ax
640
        jg      @f
641
        and     [edx + TCP_header.Flags], not (TH_URG)
642
        mov     [edx + TCP_header.UrgentPointer], 0
643
       @@:
644
 
645
;--------------------------------------------------
646
; Handle data that arrives after process terminates (687)
647
 
648
  .no_duplicate:
649
        cmp     [ebx + SOCKET.PID], 0
650
        jne     .not_terminated
651
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
652
        jbe     .not_terminated
653
        test    ecx, ecx
654
        jz      .not_terminated
655
 
656
        mov     eax, ebx
657
        call    TCP_close
658
;;;TODO: update stats
659
        jmp     .respond_seg_reset
660
 
661
;----------------------------------------
662
; Remove data beyond right edge of window (700-736)
663
 
664
  .not_terminated:
665
        mov     eax, [edx + TCP_header.SequenceNumber]
666
        add     eax, ecx
667
        sub     eax, [ebx + TCP_SOCKET.RCV_NXT]
668
        sub     eax, [ebx + TCP_SOCKET.RCV_WND]         ; eax now holds the number of bytes to drop
669
        jle     .no_excess_data
670
 
3556 hidnplayr 671
        DEBUGF  DEBUG_NETWORK_VERBOSE, "%d bytes beyond right edge of window\n", eax
3545 hidnplayr 672
 
673
;;; TODO: update stats
674
        cmp     eax, ecx
675
        jl      .dont_drop_all
676
; If a new connection request is received while in TIME_WAIT, drop the old connection and start over,
677
; if the sequence numbers are above the previous ones
678
 
679
        test    [edx + TCP_header.Flags], TH_SYN
680
        jz      .no_new_request
681
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
682
        jne     .no_new_request
683
;        mov     edx, [ebx + TCP_SOCKET.RCV_NXT]
684
;        cmp     edx, [edx + TCP_header.SequenceNumber]
685
;        add     edx, 64000      ; TCP_ISSINCR   FIXME
686
        mov     eax, ebx
687
        call    TCP_close
688
        jmp     .findpcb        ; FIXME: skip code for unscaling window, ...
689
  .no_new_request:
690
 
691
; If window is closed can only take segments at window edge, and have to drop data and PUSH from
692
; incoming segments. Continue processing, but remember to ACK. Otherwise drop segment and ACK
693
 
694
        cmp     [ebx + TCP_SOCKET.RCV_WND], 0
695
        jne     .drop_after_ack
696
        mov     eax, [edx + TCP_header.SequenceNumber]
697
        cmp     eax, [ebx + TCP_SOCKET.RCV_NXT]
698
        jne     .drop_after_ack
699
 
3556 hidnplayr 700
        DEBUGF  DEBUG_NETWORK_VERBOSE,  "690\n"
3545 hidnplayr 701
        or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
702
;;; TODO: update stats
703
        jmp     .no_excess_data
704
  .dont_drop_all:
705
;;; TODO: update stats
706
;;; TODO: 733
707
 
708
        sub     ecx, eax
709
        and     [ebx + TCP_SOCKET.t_flags], not (TH_PUSH or TH_FIN)
710
  .no_excess_data:
711
 
712
;-----------------
713
; Record timestamp (737-746)
714
 
715
; If last ACK falls within this segments sequence numbers, record its timestamp
716
        test    [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP
717
        jz      .no_timestamp
718
        mov     eax, [ebx + TCP_SOCKET.last_ack_sent]
719
        sub     eax, [edx + TCP_header.SequenceNumber]
720
        jb      .no_timestamp
721
        test    [ebx + TCP_header.Flags], TH_SYN or TH_FIN      ; syn and fin occupy one byte
722
        jz      @f
723
        dec     eax
724
       @@:
725
        sub     eax, ecx
726
        jae     .no_timestamp
727
 
3556 hidnplayr 728
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Recording timestamp\n"
3545 hidnplayr 729
 
730
        mov     eax, [esp + 4]                                  ; tcp_now
731
        mov     [ebx + TCP_SOCKET.ts_recent_age], eax
732
        mov     eax, [ebx + TCP_SOCKET.ts_val]
733
        mov     [ebx + TCP_SOCKET.ts_recent], eax
734
  .no_timestamp:
735
 
736
;------------------
737
; Process RST flags
738
 
739
        test    [edx + TCP_header.Flags], TH_RST
740
        jz      .no_rst
741
 
3556 hidnplayr 742
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Got an RST flag\n"
3545 hidnplayr 743
 
744
        mov     eax, [ebx + TCP_SOCKET.t_state]
745
        shl     eax, 2
746
        jmp     dword [eax + .rst_sw_list]
747
 
748
  .rst_sw_list:
749
        dd      .no_rst         ; TCPS_CLOSED
750
        dd      .no_rst         ; TCPS_LISTEN
751
        dd      .no_rst         ; TCPS_SYN_SENT
752
        dd      .econnrefused   ; TCPS_SYN_RECEIVED
753
        dd      .econnreset     ; TCPS_ESTABLISHED
754
        dd      .econnreset     ; TCPS_CLOSE_WAIT
755
        dd      .econnreset     ; TCPS_FIN_WAIT_1
756
        dd      .rst_close      ; TCPS_CLOSING
757
        dd      .rst_close      ; TCPS_LAST_ACK
758
        dd      .econnreset     ; TCPS_FIN_WAIT_2
759
        dd      .rst_close      ; TCPS_TIMED_WAIT
760
 
761
  .econnrefused:
3556 hidnplayr 762
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Connection refused\n"
3545 hidnplayr 763
 
764
        mov     [ebx + SOCKET.errorcode], ECONNREFUSED
765
        jmp     .close
766
 
767
  .econnreset:
3556 hidnplayr 768
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Connection reset\n"
3545 hidnplayr 769
 
770
        mov     [ebx + SOCKET.errorcode], ECONNRESET
771
 
772
  .close:
3556 hidnplayr 773
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Closing connection\n"
3545 hidnplayr 774
 
775
        mov     [ebx + TCP_SOCKET.t_state], TCPS_CLOSED
776
;;; TODO: update stats (tcp drops)
777
        mov     eax, ebx
778
        call    TCP_close
779
        jmp     .drop_no_socket
780
 
781
  .rst_close:
3556 hidnplayr 782
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Closing with reset\n"
3545 hidnplayr 783
 
784
        mov     eax, ebx
785
        call    TCP_close
786
        jmp     .drop_no_socket
787
 
788
  .no_rst:
789
 
790
;--------------------------------------
791
; handle SYN-full and ACK-less segments
792
 
793
        test    [edx + TCP_header.Flags], TH_SYN
794
        jz      .not_syn_full
795
 
796
        mov     eax, ebx
797
        mov     ebx, ECONNRESET
798
        call    TCP_drop
799
        jmp     .drop_with_reset
800
  .not_syn_full:
801
 
802
;---------------
803
; ACK processing
804
 
805
        test    [edx + TCP_header.Flags], TH_ACK
806
        jz      .drop
807
 
808
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
809
        jb      .ack_processed                                  ; states: closed, listen, syn_sent
810
        ja      .no_syn_rcv                                     ; established, fin_wait_1, fin_wait_2, close_wait, closing, last_ack, time_wait
811
 
3556 hidnplayr 812
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: state=syn_received\n"
3545 hidnplayr 813
 
814
        mov     eax, [edx + TCP_header.AckNumber]
815
        cmp     [ebx + TCP_SOCKET.SND_UNA], eax
816
        ja      .drop_with_reset
817
        cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
818
        ja      .drop_with_reset
819
 
820
;;; TODO: update stats
821
 
822
        mov     eax, ebx
823
        call    SOCKET_is_connected
824
        mov     [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
825
 
826
; Do window scaling?
827
 
828
        test    [ebx + TCP_SOCKET.t_flags], TF_RCVD_SCALE
829
        jz      @f
830
        test    [ebx + TCP_SOCKET.t_flags], TF_REQ_SCALE
831
        jz      @f
832
 
833
        push    word [ebx + TCP_SOCKET.requested_s_scale]       ; Set send and receive scale factors to the received values
834
        pop     word [ebx + TCP_SOCKET.SND_SCALE]
835
       @@:
836
 
837
;;; TODO: call TCP_reassemble
838
 
839
        mov     eax, [edx + TCP_header.SequenceNumber]
840
        dec     eax
841
        mov     [ebx + TCP_SOCKET.SND_WL1], eax
842
 
843
  .no_syn_rcv:
844
 
845
;-------------------------
846
; check for duplicate ACKs
847
 
848
        mov     eax, [edx + TCP_header.AckNumber]
849
        cmp     eax, [ebx + TCP_SOCKET.SND_UNA]
850
        ja      .not_dup_ack
851
 
852
        test    ecx, ecx
853
        jnz     .reset_dupacks
854
 
855
        mov     eax, dword [edx + TCP_header.Window]
856
        cmp     eax, [ebx + TCP_SOCKET.SND_WND]
857
        jne     .reset_dupacks
858
 
3556 hidnplayr 859
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Processing duplicate ACK\n"
3545 hidnplayr 860
 
861
; If we have outstanding data, other than a window probe, this is a completely duplicate ACK
862
; (window info didnt change) The ACK is the biggest we've seen and we've seen exactly our rexmt threshold of them,
863
; assume a packet has been dropped and retransmit it. Kludge snd_nxt & the congestion window so we send only this one packet.
864
 
3600 hidnplayr 865
        test    [ebx + TCP_SOCKET.timer_flags], timer_flag_retransmission
866
        jz      @f
3545 hidnplayr 867
 
868
        mov     eax, [edx + TCP_header.AckNumber]
869
        cmp     eax, [ebx + TCP_SOCKET.SND_UNA]
870
        je      .dup_ack
871
 
872
       @@:
873
        mov     [ebx + TCP_SOCKET.t_dupacks], 0
874
        jmp     .not_dup_ack
875
 
876
  .dup_ack:
877
        inc     [ebx + TCP_SOCKET.t_dupacks]
878
        cmp     [ebx + TCP_SOCKET.t_dupacks], TCP_re_xmit_thresh
879
        jne     .no_re_xmit
880
 
881
        push    [ebx + TCP_SOCKET.SND_NXT]              ; >>>>
882
 
883
        mov     eax, [ebx + TCP_SOCKET.SND_WND]
884
        cmp     eax, [ebx + TCP_SOCKET.SND_CWND]
885
        cmova   eax, [ebx + TCP_SOCKET.SND_CWND]
886
        shr     eax, 1
887
        push    edx
888
        xor     edx, edx
889
        div     [ebx + TCP_SOCKET.t_maxseg]
890
        cmp     eax, 2
891
        ja      @f
892
        xor     eax, eax
893
        mov     al, 2
894
       @@:
895
        mul     [ebx + TCP_SOCKET.t_maxseg]
896
        pop     edx
897
        mov     [ebx + TCP_SOCKET.SND_SSTHRESH], eax
898
 
3600 hidnplayr 899
        and     [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission   ; turn off retransmission timer
3545 hidnplayr 900
        mov     [ebx + TCP_SOCKET.t_rtt], 0
901
        mov     eax, [edx + TCP_header.AckNumber]
902
        mov     [ebx + TCP_SOCKET.SND_NXT], eax
903
        mov     eax, [ebx + TCP_SOCKET.t_maxseg]
904
        mov     [ebx + TCP_SOCKET.SND_CWND], eax
905
 
906
; Unlock the socket
907
        push    ebx
908
        lea     ecx, [ebx + SOCKET.mutex]
909
        call    mutex_unlock
910
 
911
; retransmit missing segment
912
        mov     eax, [esp]
913
        call    TCP_output
914
 
915
; Lock the socket again
916
        mov     ecx, [esp]
917
        add     ecx, SOCKET.mutex
918
        call    mutex_lock
3711 clevermous 919
        pop     ebx
3545 hidnplayr 920
 
921
; Continue processing
922
        xor     edx, edx
923
        mov     eax, [ebx + TCP_SOCKET.t_maxseg]
924
        mul     [ebx + TCP_SOCKET.t_dupacks]
925
        add     eax, [ebx + TCP_SOCKET.SND_SSTHRESH]
926
        mov     [ebx + TCP_SOCKET.SND_CWND], eax
927
 
928
        pop     eax                                     ; <<<<
929
        cmp     eax, [ebx + TCP_SOCKET.SND_NXT]
930
        jb      @f
931
        mov     [ebx + TCP_SOCKET.SND_NXT], eax
932
       @@:
933
 
934
        jmp     .drop
935
 
936
 
937
  .no_re_xmit:
938
        jbe     .not_dup_ack
939
 
3556 hidnplayr 940
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Increasing congestion window\n"
3545 hidnplayr 941
 
942
        mov     eax, [ebx + TCP_SOCKET.t_maxseg]
943
        add     [ebx + TCP_SOCKET.SND_CWND], eax
944
 
945
; Unlock the socket
946
        push    ebx
947
        lea     ecx, [ebx + SOCKET.mutex]
948
        call    mutex_unlock
949
 
950
; retransmit missing segment
951
        mov     eax, [esp]
952
        call    TCP_output
953
 
954
; Lock the socket again
955
        mov     ecx, [esp]
956
        add     ecx, SOCKET.mutex
957
        call    mutex_lock
958
        pop     ebx
959
 
960
        jmp     .drop
961
 
962
 
963
  .not_dup_ack:
964
 
965
;-------------------------------------------------
966
; If the congestion window was inflated to account
967
; for the other side's cached packets, retract it
968
 
969
        mov     eax, [ebx + TCP_SOCKET.SND_SSTHRESH]
970
        cmp     eax, [ebx + TCP_SOCKET.SND_CWND]
971
        ja      @f
972
        cmp     [ebx + TCP_SOCKET.t_dupacks], TCP_re_xmit_thresh
973
        jbe     @f
974
        mov     [ebx + TCP_SOCKET.SND_CWND], eax
975
       @@:
976
 
977
        mov     [ebx + TCP_SOCKET.t_dupacks], 0
978
 
979
        mov     eax, [edx + TCP_header.AckNumber]
980
        cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
981
        jbe     @f
982
 
983
        ;;; TODO: update stats
984
        jmp     .drop_after_ack
985
 
986
       @@:
987
 
988
        mov     edi, [edx + TCP_header.AckNumber]
989
        sub     edi, [ebx + TCP_SOCKET.SND_UNA]         ; now we got the number of acked bytes in edi
990
 
991
        ;;; TODO: update stats
992
 
3556 hidnplayr 993
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: acceptable ACK for %u bytes\n", edi
3545 hidnplayr 994
 
995
;------------------------------------------
996
; RTT measurements and retransmission timer  (912-926)
997
 
998
; If we have a timestamp, update smoothed RTT
999
 
1000
        test    [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP
1001
        jz      .timestamp_not_present
1002
        mov     eax, [esp+4]
1003
        sub     eax, [ebx + TCP_SOCKET.ts_ecr]
1004
        inc     eax
1005
        call    TCP_xmit_timer
1006
        jmp     .rtt_done_
1007
 
1008
; If no timestamp but transmit timer is running and timed sequence number was acked,
1009
; update smoothed RTT. Since we now have an RTT measurement, cancel the timer backoff
1010
; (Phil Karn's retransmit algo)
1011
; Recompute the initial retransmit timer
1012
 
1013
  .timestamp_not_present:
1014
        mov     eax, [edx + TCP_header.AckNumber]
1015
        cmp     eax, [ebx + TCP_SOCKET.t_rtseq]
1016
        jbe     .rtt_done_
1017
        mov     eax, [ebx + TCP_SOCKET.t_rtt]
1018
        test    eax, eax
1019
        jz      .rtt_done_
1020
        call    TCP_xmit_timer
1021
 
1022
  .rtt_done_:
1023
 
1024
; If all outstanding data is acked, stop retransmit timer and remember to restart (more output or persist)
1025
; If there is more data to be acked, restart retransmit timer, using current (possible backed-off) value.
1026
 
1027
        mov     eax, [ebx + TCP_SOCKET.SND_MAX]
1028
        cmp     eax, [edx + TCP_header.AckNumber]
1029
        jne     .more_data
3600 hidnplayr 1030
        and     [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission
3545 hidnplayr 1031
        or      [ebx + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT
1032
        jmp     .no_restart
1033
  .more_data:
3600 hidnplayr 1034
        test    [ebx + TCP_SOCKET.timer_flags], timer_flag_persist
1035
        jnz     .no_restart
3545 hidnplayr 1036
 
1037
        mov     eax, [ebx + TCP_SOCKET.t_rxtcur]
1038
        mov     [ebx + TCP_SOCKET.timer_retransmission], eax
3600 hidnplayr 1039
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_retransmission
3545 hidnplayr 1040
  .no_restart:
1041
 
1042
 
1043
;-------------------------------------------
1044
; Open congestion window in response to ACKs
1045
 
1046
        mov     esi, [ebx + TCP_SOCKET.SND_CWND]
1047
        mov     eax, [ebx + TCP_SOCKET.t_maxseg]
1048
 
1049
        cmp     esi, [ebx + TCP_SOCKET.SND_SSTHRESH]
1050
        jbe     @f
1051
        push    edx
1052
        push    eax
1053
        mul     eax
1054
        div     esi
1055
        pop     edx
1056
        shr     edx, 3
1057
        add     eax, edx
1058
        pop     edx
1059
       @@:
1060
 
1061
        add     esi, eax
1062
 
1063
        push    ecx
1064
        mov     cl, [ebx + TCP_SOCKET.SND_SCALE]
1065
        mov     eax, TCP_max_win
1066
        shl     eax, cl
1067
        pop     ecx
1068
 
1069
        cmp     esi, eax
1070
        cmova   esi, eax
1071
        mov     [ebx + TCP_SOCKET.SND_CWND], esi
1072
 
1073
;------------------------------------------
1074
; Remove acknowledged data from send buffer
1075
 
1076
        cmp     edi, [ebx + STREAM_SOCKET.snd.size]
1077
        jbe     .finiacked
1078
 
1079
        push    ecx edx ebx
1080
        mov     ecx, [ebx + STREAM_SOCKET.snd.size]
1081
        lea     eax, [ebx + STREAM_SOCKET.snd]
1082
        sub     [ebx + TCP_SOCKET.SND_WND], ecx
1083
        call    SOCKET_ring_free
1084
        pop     ebx edx ecx
1085
 
3556 hidnplayr 1086
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: our FIN is acked\n"
3545 hidnplayr 1087
        stc
1088
 
1089
        jmp     .wakeup
1090
 
1091
  .finiacked:
1092
 
1093
        push    ecx edx ebx
1094
        mov     ecx, edi
1095
        lea     eax, [ebx + STREAM_SOCKET.snd]
1096
        call    SOCKET_ring_free
1097
        pop     ebx
1098
        sub     [ebx + TCP_SOCKET.SND_WND], ecx
1099
        pop     edx ecx
1100
 
3556 hidnplayr 1101
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: our FIN is not acked\n"
3545 hidnplayr 1102
        clc
1103
 
1104
;----------------------------------------
1105
; Wake up process waiting on send buffer
1106
 
1107
  .wakeup:
1108
 
1109
        pushf                   ; Keep the flags (Carry flag)
1110
        mov     eax, ebx
1111
        call    SOCKET_notify
1112
 
1113
; Update TCPS
1114
 
1115
        mov     eax, [edx + TCP_header.AckNumber]
1116
        mov     [ebx + TCP_SOCKET.SND_UNA], eax
1117
        cmp     eax, [ebx + TCP_SOCKET.SND_NXT]
1118
        jb      @f
1119
        mov     [ebx + TCP_SOCKET.SND_NXT], eax
1120
       @@:
1121
 
1122
        popf
1123
 
1124
; General ACK handling complete
1125
; Now do the state-specific ones
1126
; Carry flag is set when our FIN is acked
1127
 
1128
        mov     eax, [ebx + TCP_SOCKET.t_state]
1129
        jmp     dword [eax*4 + .ACK_sw_list]
1130
 
1131
  .ACK_sw_list:
1132
        dd      .ack_processed  ; TCPS_CLOSED
1133
        dd      .ack_processed  ; TCPS_LISTEN
1134
        dd      .ack_processed  ; TCPS_SYN_SENT
1135
        dd      .ack_processed  ; TCPS_SYN_RECEIVED
1136
        dd      .ack_processed  ; TCPS_ESTABLISHED
1137
        dd      .ack_processed  ; TCPS_CLOSE_WAIT
1138
        dd      .ack_fw1        ; TCPS_FIN_WAIT_1
1139
        dd      .ack_c          ; TCPS_CLOSING
1140
        dd      .ack_la         ; TCPS_LAST_ACK
1141
        dd      .ack_processed  ; TCPS_FIN_WAIT_2
1142
        dd      .ack_tw         ; TCPS_TIMED_WAIT
1143
 
1144
 
1145
  .ack_fw1:
1146
        jnc     .ack_processed
1147
 
1148
        test    [ebx + SOCKET.state], SS_CANTRCVMORE
1149
        jnz     @f
1150
        mov     eax, ebx
1151
        call    SOCKET_is_disconnected
1152
        mov     [ebx + TCP_SOCKET.timer_timed_wait], TCP_time_max_idle
3600 hidnplayr 1153
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
3545 hidnplayr 1154
       @@:
1155
        mov     [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_2
1156
        jmp     .ack_processed
1157
 
1158
  .ack_c:
1159
        jnc     .ack_processed
1160
 
1161
        mov     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1162
        mov     eax, ebx
1163
        call    TCP_cancel_timers
1164
        mov     [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
3600 hidnplayr 1165
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
3545 hidnplayr 1166
        mov     eax, ebx
1167
        call    SOCKET_is_disconnected
1168
        jmp     .ack_processed
1169
 
1170
  .ack_la:
1171
        jnc     .ack_processed
1172
 
3652 hidnplayr 1173
        push    ebx
1174
        lea     ecx, [ebx + SOCKET.mutex]
1175
        call    mutex_unlock
1176
        pop     ebx
1177
 
1178
        push    ebx
3545 hidnplayr 1179
        mov     eax, ebx
1180
        call    TCP_disconnect
3652 hidnplayr 1181
        pop     ebx
3545 hidnplayr 1182
 
3652 hidnplayr 1183
        jmp     .destroy_new_socket
1184
 
3545 hidnplayr 1185
  .ack_tw:
1186
        mov     [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
3600 hidnplayr 1187
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
3545 hidnplayr 1188
        jmp     .drop_after_ack
1189
 
1190
  .reset_dupacks:               ; We got a new ACK, reset duplicate ACK counter
1191
        mov     [ebx + TCP_SOCKET.t_dupacks], 0
1192
        jmp     .ack_processed
1193
 
1194
;-------
1195
; LISTEN
1196
 
1197
align 4
1198
  .LISTEN:
1199
 
3556 hidnplayr 1200
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: state=listen\n"
3545 hidnplayr 1201
 
1202
        test    [edx + TCP_header.Flags], TH_RST
1203
        jnz     .drop
1204
 
1205
        test    [edx + TCP_header.Flags], TH_ACK
1206
        jnz     .drop_with_reset
1207
 
1208
        test    [edx + TCP_header.Flags], TH_SYN
1209
        jz      .drop
1210
 
1211
;;; TODO: check if it's a broadcast or multicast, and drop if so
1212
 
1213
        push    dword [edi]                             ; Ipv4 source addres
1214
        pop     [ebx + IP_SOCKET.RemoteIP]
1215
 
1216
        push    [edx + TCP_header.SourcePort]
1217
        pop     [ebx + TCP_SOCKET.RemotePort]
1218
 
1219
        push    [edx + TCP_header.SequenceNumber]
1220
        pop     [ebx + TCP_SOCKET.IRS]
1221
 
1222
        mov     eax, [TCP_sequence_num]
1223
        add     [TCP_sequence_num], 64000 / 2
1224
        mov     [ebx + TCP_SOCKET.ISS], eax
1225
        mov     [ebx + TCP_SOCKET.SND_NXT], eax
1226
 
1227
        TCP_sendseqinit ebx
1228
        TCP_rcvseqinit ebx
1229
 
1230
        mov     [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
1231
        mov     [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1232
        mov     [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval  ;;;; macro
3600 hidnplayr 1233
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_keepalive
3545 hidnplayr 1234
 
1235
        lea     eax, [ebx + STREAM_SOCKET.snd]
1236
        call    SOCKET_ring_create
1237
 
1238
        lea     eax, [ebx + STREAM_SOCKET.rcv]
1239
        call    SOCKET_ring_create
1240
 
1241
        and     [ebx + TCP_SOCKET.temp_bits], not TCP_BIT_DROPSOCKET
1242
 
3674 hidnplayr 1243
        pusha
1244
        mov     eax, ebx
1245
        call    SOCKET_notify
1246
        popa
3545 hidnplayr 1247
 
1248
        jmp     .trim_then_step6
1249
 
1250
;------------
1251
; Active Open
1252
 
1253
align 4
1254
  .SYN_SENT:
1255
 
3556 hidnplayr 1256
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: state=syn_sent\n"
3545 hidnplayr 1257
 
1258
        test    [edx + TCP_header.Flags], TH_ACK
1259
        jz      @f
1260
 
1261
        mov     eax, [edx + TCP_header.AckNumber]
1262
        cmp     eax, [ebx + TCP_SOCKET.ISS]
1263
        jbe     .drop_with_reset
1264
 
1265
        cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
1266
        ja      .drop_with_reset
1267
       @@:
1268
 
1269
        test    [edx + TCP_header.Flags], TH_RST
1270
        jz      @f
1271
 
1272
        test    [edx + TCP_header.Flags], TH_ACK
1273
        jz      .drop
1274
 
1275
        mov     eax, ebx
1276
        mov     ebx, ECONNREFUSED
1277
        call    TCP_drop
1278
 
1279
        jmp     .drop
1280
       @@:
1281
 
1282
        test    [edx + TCP_header.Flags], TH_SYN
1283
        jz      .drop
1284
 
1285
; at this point, segment seems to be valid
1286
 
1287
        test    [edx + TCP_header.Flags], TH_ACK
1288
        jz      .no_syn_ack
1289
 
1290
; now, process received SYN in response to an active open
1291
 
1292
        mov     eax, [edx + TCP_header.AckNumber]
1293
        mov     [ebx + TCP_SOCKET.SND_UNA], eax
1294
        cmp     eax, [ebx + TCP_SOCKET.SND_NXT]
1295
        jbe     @f
1296
        mov     [ebx + TCP_SOCKET.SND_NXT], eax
1297
       @@:
1298
 
1299
  .no_syn_ack:
3600 hidnplayr 1300
        and     [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission   ; disable retransmission timer
3545 hidnplayr 1301
 
1302
        push    [edx + TCP_header.SequenceNumber]
1303
        pop     [ebx + TCP_SOCKET.IRS]
1304
 
1305
        TCP_rcvseqinit ebx
1306
 
1307
        or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1308
 
1309
        mov     eax, [ebx + TCP_SOCKET.SND_UNA]
1310
        cmp     eax, [ebx + TCP_SOCKET.ISS]
1311
        jbe     .simultaneous_open
1312
 
1313
        test    [edx + TCP_header.Flags], TH_ACK
1314
        jz      .simultaneous_open
1315
 
3556 hidnplayr 1316
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: active open\n"
3545 hidnplayr 1317
 
1318
;;; TODO: update stats
1319
 
1320
; set socket state to connected
3674 hidnplayr 1321
        push    eax
1322
        mov     eax, ebx
1323
        call    SOCKET_is_connected
1324
        pop     eax
3545 hidnplayr 1325
        mov     [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
1326
 
1327
; Do window scaling on this connection ?
1328
        mov     eax, [ebx + TCP_SOCKET.t_flags]
1329
        and     eax, TF_REQ_SCALE or TF_RCVD_SCALE
1330
        cmp     eax, TF_REQ_SCALE or TF_RCVD_SCALE
1331
        jne     .no_scaling
1332
 
1333
        mov     ax, word [ebx + TCP_SOCKET.requested_s_scale]
1334
        mov     word [ebx + TCP_SOCKET.SND_SCALE], ax
1335
  .no_scaling:
1336
 
1337
;;; TODO: reassemble packets queue
1338
 
1339
        mov     eax, [ebx + TCP_SOCKET.t_rtt]
1340
        test    eax, eax
1341
        je      .trim_then_step6
1342
        call    TCP_xmit_timer
1343
        jmp     .trim_then_step6
1344
 
1345
  .simultaneous_open:
1346
 
3556 hidnplayr 1347
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: simultaneous open\n"
3545 hidnplayr 1348
; We have received a syn but no ACK, so we are having a simultaneous open..
1349
        mov     [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
1350
 
1351
;-------------------------------------
1352
; Common processing for receipt of SYN
1353
 
1354
  .trim_then_step6:
1355
 
1356
        inc     [edx + TCP_header.SequenceNumber]
1357
 
1358
;;; TODO: Drop any received data that follows receive window (590)
1359
 
1360
        mov     eax, [edx + TCP_header.SequenceNumber]
1361
        mov     [ebx + TCP_SOCKET.RCV_UP], eax
1362
        dec     eax
1363
        mov     [ebx + TCP_SOCKET.SND_WL1], eax
1364
 
1365
;-------
1366
; step 6
1367
 
1368
  .ack_processed:
1369
 
3556 hidnplayr 1370
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: ACK processed\n"
3545 hidnplayr 1371
 
1372
;----------------------------------------------
1373
; check if we need to update window information
1374
 
1375
        test    [edx + TCP_header.Flags], TH_ACK
1376
        jz      .no_window_update
1377
 
1378
        mov     eax, [ebx + TCP_SOCKET.SND_WL1]
1379
        cmp     eax, [edx + TCP_header.SequenceNumber]
1380
        jb      .update_window
1381
        ja      @f
1382
 
1383
        mov     eax, [ebx + TCP_SOCKET.SND_WL2]
1384
        cmp     eax, [edx + TCP_header.AckNumber]
1385
        jb      .update_window
1386
        ja      .no_window_update
1387
       @@:
1388
 
1389
        mov     eax, dword [edx + TCP_header.Window]
1390
        cmp     eax, [ebx + TCP_SOCKET.SND_WND]
1391
        jbe     .no_window_update
1392
 
1393
  .update_window:
1394
 
1395
;;; TODO: update stats (Keep track of pure window updates)
1396
 
1397
        mov     eax, dword [edx + TCP_header.Window]
1398
        cmp     eax, [ebx + TCP_SOCKET.max_sndwnd]
1399
        jbe     @f
1400
        mov     [ebx + TCP_SOCKET.max_sndwnd], eax
1401
       @@:
1402
        mov     [ebx + TCP_SOCKET.SND_WND], eax
1403
 
3556 hidnplayr 1404
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Updating window to %u\n", eax
3545 hidnplayr 1405
 
1406
        push    [edx + TCP_header.SequenceNumber]
1407
        pop     [ebx + TCP_SOCKET.SND_WL1]
1408
 
1409
        push    [edx + TCP_header.AckNumber]
1410
        pop     [ebx + TCP_SOCKET.SND_WL2]
1411
 
1412
        or      [ebx + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT
1413
 
1414
  .no_window_update:
1415
 
1416
;-----------------
1417
; process URG flag
1418
 
1419
        test    [edx + TCP_header.Flags], TH_URG
1420
        jz      .not_urgent
1421
 
1422
        cmp     [edx + TCP_header.UrgentPointer], 0
1423
        jz      .not_urgent
1424
 
1425
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1426
        je      .not_urgent
1427
 
1428
; Ignore bogus urgent offsets
1429
 
1430
        movzx   eax, [edx + TCP_header.UrgentPointer]
1431
        add     eax, [ebx + STREAM_SOCKET.rcv.size]
1432
        cmp     eax, SOCKET_MAXDATA
1433
        jbe     .not_urgent
1434
 
1435
        mov     [edx + TCP_header.UrgentPointer], 0
1436
        and     [edx + TCP_header.Flags], not (TH_URG)
1437
        jmp     .do_data
1438
 
1439
  .not_urgent:
1440
 
1441
; processing of received urgent pointer
1442
 
1443
        ;;; TODO (1051-1093)
1444
 
1445
 
1446
;---------------------------------------
1447
; process the data in the segment (1094)
1448
 
1449
  .do_data:
1450
 
1451
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1452
        jae     .final_processing
1453
 
1454
        test    [edx + TCP_header.Flags], TH_FIN
1455
        jnz     @f
1456
 
1457
        test    ecx, ecx
1458
        jnz     .final_processing
1459
       @@:
1460
 
1461
 
1462
; The segment is in order?
1463
        mov     eax, [edx + TCP_header.SequenceNumber]
1464
        cmp     eax, [ebx + TCP_SOCKET.RCV_NXT]
1465
        jne     .out_of_order
1466
 
1467
; The reassembly queue is empty?
1468
        cmp     [ebx + TCP_SOCKET.seg_next], 0
1469
        jne     .out_of_order
1470
 
1471
; The connection is established?
1472
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
1473
        jne     .out_of_order
1474
 
1475
; Ok, lets do this..  Set delayed ACK flag and copy data into socket buffer
1476
        or      [ebx + TCP_SOCKET.t_flags], TF_DELACK
1477
 
1478
        pusha
1479
        movzx   esi, [edx + TCP_header.DataOffset]
1480
        add     esi, edx
1481
        lea     eax, [ebx + STREAM_SOCKET.rcv]
1482
        call    SOCKET_ring_write                       ; Add the data to the socket buffer
1483
        add     [ebx + TCP_SOCKET.RCV_NXT], ecx         ; Update sequence number with number of bytes we have copied
1484
        popa
1485
 
1486
; Wake up the sleeping process
1487
        mov     eax, ebx
1488
        call    SOCKET_notify
1489
 
1490
        jmp     .data_done
1491
 
1492
  .out_of_order:
1493
 
1494
; Uh-oh, some data is out of order, lets call TCP reassemble for help
1495
 
1496
        call    TCP_reassemble
1497
 
3556 hidnplayr 1498
        DEBUGF  DEBUG_NETWORK_VERBOSE,  "1470\n"
3545 hidnplayr 1499
        or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1500
 
1501
  .data_done:
1502
 
1503
;---------------
1504
; FIN processing
1505
 
1506
        test    [edx + TCP_header.Flags], TH_FIN
1507
        jz      .final_processing
1508
 
3556 hidnplayr 1509
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Processing FIN\n"
3545 hidnplayr 1510
 
1511
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1512
        jae     .not_first_fin
1513
 
3556 hidnplayr 1514
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: First FIN for this connection\n"
3545 hidnplayr 1515
 
1516
        mov     eax, ebx
1517
        call    SOCKET_cant_recv_more
1518
 
1519
        mov     [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1520
        inc     [ebx + TCP_SOCKET.RCV_NXT]
1521
 
1522
  .not_first_fin:
1523
        mov     eax, [ebx + TCP_SOCKET.t_state]
1524
        shl     eax, 2
1525
        jmp     dword [eax + .FIN_sw_list]
1526
 
1527
  .FIN_sw_list:
1528
        dd      .final_processing       ; TCPS_CLOSED
1529
        dd      .final_processing       ; TCPS_LISTEN
1530
        dd      .final_processing       ; TCPS_SYN_SENT
1531
        dd      .fin_syn_est            ; TCPS_SYN_RECEIVED
1532
        dd      .fin_syn_est            ; TCPS_ESTABLISHED
1533
        dd      .final_processing       ; TCPS_CLOSE_WAIT
1534
        dd      .fin_wait1              ; TCPS_FIN_WAIT_1
1535
        dd      .final_processing       ; TCPS_CLOSING
1536
        dd      .final_processing       ; TCPS_LAST_ACK
1537
        dd      .fin_wait2              ; TCPS_FIN_WAIT_2
1538
        dd      .fin_timed              ; TCPS_TIMED_WAIT
1539
 
1540
  .fin_syn_est:
1541
 
1542
        mov     [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
1543
        jmp     .final_processing
1544
 
1545
  .fin_wait1:
1546
 
1547
        mov     [ebx + TCP_SOCKET.t_state], TCPS_CLOSING
1548
        jmp     .final_processing
1549
 
1550
  .fin_wait2:
1551
 
1552
        mov     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1553
        mov     eax, ebx
1554
        call    TCP_cancel_timers
1555
        mov     [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
3600 hidnplayr 1556
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
3545 hidnplayr 1557
        call    SOCKET_is_disconnected
1558
        jmp     .final_processing
1559
 
1560
  .fin_timed:
1561
        mov     [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
3600 hidnplayr 1562
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
3545 hidnplayr 1563
        jmp     .final_processing
1564
 
1565
 
1566
  .drop_after_ack:
3556 hidnplayr 1567
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Drop after ACK\n"
3545 hidnplayr 1568
 
1569
        push    edx ebx
1570
        lea     ecx, [ebx + SOCKET.mutex]
1571
        call    mutex_unlock
1572
        pop     eax edx
1573
 
1574
        test    [edx + TCP_header.Flags], TH_RST
1575
        jnz     .dumpit
1576
 
1577
        or      [eax + TCP_SOCKET.t_flags], TF_ACKNOW
1578
        jmp     .need_output
1579
 
1580
  .drop_with_reset:
3556 hidnplayr 1581
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Drop with reset\n"
3545 hidnplayr 1582
 
1583
        push    ebx edx
1584
        lea     ecx, [ebx + SOCKET.mutex]
1585
        call    mutex_unlock
1586
        pop     edx ebx
1587
 
1588
        test    [edx + TCP_header.Flags], TH_RST
1589
        jnz     .dumpit
1590
 
1591
        ;;; if its a multicast/broadcast, also drop
1592
 
1593
        test    [edx + TCP_header.Flags], TH_ACK
1594
        jnz     .respond_ack
1595
 
1596
        test    [edx + TCP_header.Flags], TH_SYN
1597
        jnz     .respond_syn
1598
        jmp     .dumpit
1599
 
1600
;-----------------
1601
; Final processing
1602
 
1603
  .final_processing:
3556 hidnplayr 1604
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Final processing\n"
3545 hidnplayr 1605
 
1606
        push    ebx
1607
        lea     ecx, [ebx + SOCKET.mutex]
1608
        call    mutex_unlock
1609
        pop     eax
1610
 
1611
        test    [eax + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT
1612
        jnz     .need_output
1613
 
1614
        test    [eax + TCP_SOCKET.t_flags], TF_ACKNOW
1615
        jz      .dumpit
3556 hidnplayr 1616
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: ACK now!\n"
3545 hidnplayr 1617
 
1618
  .need_output:
3556 hidnplayr 1619
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: need output\n"
3545 hidnplayr 1620
        call    TCP_output
1621
 
1622
  .dumpit:
3556 hidnplayr 1623
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: dumping\n"
3545 hidnplayr 1624
 
1625
        call    kernel_free
1626
        add     esp, 4
1627
        jmp     .loop
1628
 
1629
;---------
1630
; Respond
1631
 
1632
  .respond_ack:
1633
        push    ebx
1634
        mov     cl, TH_RST
1635
        call    TCP_respond
1636
        pop     ebx
1637
        jmp     .destroy_new_socket
1638
 
1639
  .respond_syn:
1640
        push    ebx
1641
        mov     cl, TH_RST + TH_ACK
1642
        call    TCP_respond
1643
        pop     ebx
1644
        jmp     .destroy_new_socket
1645
 
3647 hidnplayr 1646
  .no_socket:
1647
 
1648
        pusha
1649
        mov     ecx, socket_mutex
1650
        call    mutex_unlock
1651
        popa
1652
 
3545 hidnplayr 1653
  .respond_seg_reset:
1654
        test    [edx + TCP_header.Flags], TH_RST
1655
        jnz     .drop_no_socket
1656
 
1657
        ;;; TODO: if its a multicast/broadcast, also drop
1658
 
1659
        test    [edx + TCP_header.Flags], TH_ACK
1660
        jnz     .respond_seg_ack
1661
 
1662
        test    [edx + TCP_header.Flags], TH_SYN
1663
        jnz     .respond_seg_syn
1664
 
1665
        jmp     .drop_no_socket
1666
 
1667
  .respond_seg_ack:
1668
        mov     cl, TH_RST
1669
        call    TCP_respond_segment
1670
        jmp     .drop_no_socket
1671
 
1672
  .respond_seg_syn:
1673
        mov     cl, TH_RST + TH_ACK
1674
        call    TCP_respond_segment
1675
        jmp     .drop_no_socket
1676
 
1677
;-----
1678
; Drop
1679
 
1680
  .drop:
3556 hidnplayr 1681
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Dropping segment\n"
3545 hidnplayr 1682
 
1683
        pusha
1684
        lea     ecx, [ebx + SOCKET.mutex]
1685
        call    mutex_unlock
1686
        popa
1687
 
1688
  .destroy_new_socket:
1689
        test    [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET
1690
        jz      .drop_no_socket
1691
 
1692
        mov     eax, ebx
1693
        call    SOCKET_free
1694
 
1695
  .drop_no_socket:
3556 hidnplayr 1696
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Drop (no socket)\n"
3545 hidnplayr 1697
 
1698
        call    kernel_free
1699
        add     esp, 4
1700
        jmp     .loop