Subversion Repositories Kolibri OS

Rev

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

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