Subversion Repositories Kolibri OS

Rev

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

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