Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
5133 hidnplayr 3
;; Copyright (C) KolibriOS team 2004-2014. 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: 5133 $
3545 hidnplayr 18
 
19
;-----------------------------------------------------------------
20
;
21
; TCP_input:
22
;
23
;       Add a segment to the incoming TCP queue
24
;
25
;  IN:  [esp] = ptr to buffer
26
;       [esp+4] = buffer size (dont care)
27
;       ebx = ptr to device struct
28
;       ecx = segment size
29
;       esi = ptr to TCP segment
30
;       edi = ptr to ipv4 source address, followed by ipv4 dest address
31
;
32
;  OUT: /
33
;
34
;-----------------------------------------------------------------
35
 
36
align 4
37
TCP_input:
38
 
39
; record the current time
40
        mov     eax, [timer_ticks]      ; in 1/100 seconds
41
        mov     [esp + 4], eax
42
 
43
        push    ebx ecx esi edi         ; mind the order
44
        mov     esi, esp
45
 
46
        add_to_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .fail
47
        add     esp, sizeof.TCP_queue_entry
48
 
3644 hidnplayr 49
        call    NET_ptr_to_num4
50
        inc     [TCP_segments_rx + edi]
51
 
3545 hidnplayr 52
        xor     edx, edx
53
        mov     eax, [TCP_input_event]
54
        mov     ebx, [eax + EVENT.id]
55
        xor     esi, esi
56
        call    raise_event
57
 
58
        ret
59
 
60
  .fail:
3556 hidnplayr 61
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP incoming queue is full, discarding packet!\n"
3545 hidnplayr 62
 
3644 hidnplayr 63
        call    NET_ptr_to_num4
64
        inc     [TCP_segments_missed + edi]
3545 hidnplayr 65
 
66
        add     esp, sizeof.TCP_queue_entry - 8
3861 hidnplayr 67
        call    NET_packet_free
3545 hidnplayr 68
        add     esp, 4
69
 
70
        ret
71
 
72
 
73
 
74
 
75
align 4
4339 hidnplayr 76
proc TCP_process_input
3545 hidnplayr 77
 
4339 hidnplayr 78
locals
79
        dataoffset      dd ?
4344 hidnplayr 80
        timestamp       dd ?
4347 hidnplayr 81
        temp_bits       db ?
4339 hidnplayr 82
endl
83
 
3545 hidnplayr 84
        xor     esi, esi
85
        mov     ecx, MANUAL_DESTROY
86
        call    create_event
87
        mov     [TCP_input_event], eax
88
 
89
  .wait:
90
        mov     eax, [TCP_input_event]
91
        mov     ebx, [eax + EVENT.id]
92
        call    wait_event
93
 
94
  .loop:
95
        get_from_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .wait
96
 
97
        push    [esi + TCP_queue_entry.timestamp]
4344 hidnplayr 98
        pop     [timestamp]
3545 hidnplayr 99
        push    [esi + TCP_queue_entry.buffer_ptr]
100
 
101
        mov     ebx, [esi + TCP_queue_entry.device_ptr]
102
        mov     ecx, [esi + TCP_queue_entry.segment_size]
103
        mov     edi, [esi + TCP_queue_entry.ip_ptr]                     ; ptr to ipv4 source address, followed by ipv4 destination address
104
        mov     esi, [esi + TCP_queue_entry.segment_ptr]                ; change esi last
105
 
3556 hidnplayr 106
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: size=%u time=%d\n", ecx, [timer_ticks]
3545 hidnplayr 107
 
108
        mov     edx, esi
109
 
110
        cmp     ebx, LOOPBACK_DEVICE
111
        je      .checksum_ok
112
 
113
; re-calculate the checksum (if not already done by hw)
4388 hidnplayr 114
        test    [ebx + NET_DEVICE.hwacc], NET_HWACC_TCP_IPv4_IN
115
        jnz     .checksum_ok
3545 hidnplayr 116
 
117
        push    ecx esi
118
        pushw   [esi + TCP_header.Checksum]
119
        mov     [esi + TCP_header.Checksum], 0
120
        TCP_checksum (edi), (edi+4)
121
        pop     cx                      ; previous checksum
122
        cmp     cx, dx
123
        pop     edx ecx
124
        jne     .drop_no_socket
125
  .checksum_ok:
126
 
127
; Verify the data offset
4339 hidnplayr 128
        movzx   eax, [edx + TCP_header.DataOffset]
129
        and     al, 0xf0                        ; Calculate TCP segment header size (throwing away unused reserved bits in TCP header)
130
        shr     al, 2
131
        cmp     al, sizeof.TCP_header           ; Now see if it's at least the size of a standard TCP header
132
        jb      .drop_no_socket                 ; If not, drop the packet
133
        mov     [dataoffset], eax
3545 hidnplayr 134
 
135
        sub     ecx, eax                                                ; substract TCP header size from total segment size
136
        jb      .drop_no_socket                                         ; If total segment size is less then the advertised header size, drop packet
3556 hidnplayr 137
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: %u bytes of data\n", ecx
3545 hidnplayr 138
 
139
;-------------------------------------------
140
; Convert Big-endian values to little endian
141
 
142
        ntohd   [edx + TCP_header.SequenceNumber]
143
        ntohd   [edx + TCP_header.AckNumber]
144
 
145
        ntohw   [edx + TCP_header.Window]
146
        ntohw   [edx + TCP_header.UrgentPointer]
147
 
148
;------------------------
149
; Find the socket pointer
150
 
151
; IP Packet TCP Destination Port = local Port
152
; (IP Packet SenderAddress = Remote IP)  OR  (Remote IP = 0)
153
; (IP Packet TCP Source Port = remote Port) OR (remote Port = 0)
154
 
155
  .findpcb:
3647 hidnplayr 156
        pusha
157
        mov     ecx, socket_mutex
158
        call    mutex_lock
159
        popa
160
 
3545 hidnplayr 161
        mov     ebx, net_sockets
162
        mov     si, [edx + TCP_header.DestinationPort]
163
 
164
  .socket_loop:
165
        mov     ebx, [ebx + SOCKET.NextPtr]
166
        or      ebx, ebx
3647 hidnplayr 167
        jz      .no_socket ;respond_seg_reset
3545 hidnplayr 168
 
169
        cmp     [ebx + SOCKET.Domain], AF_INET4
170
        jne     .socket_loop
171
 
172
        cmp     [ebx + SOCKET.Protocol], IP_PROTO_TCP
173
        jne     .socket_loop
174
 
175
        cmp     [ebx + TCP_SOCKET.LocalPort], si
176
        jne     .socket_loop
177
 
178
        mov     eax, [ebx + IP_SOCKET.RemoteIP]
179
        cmp     eax, [edi]                              ; Ipv4 source address
180
        je      @f
181
        test    eax, eax
182
        jnz     .socket_loop
183
       @@:
184
 
185
        mov     ax, [ebx + TCP_SOCKET.RemotePort]
186
        cmp     [edx + TCP_header.SourcePort], ax
187
        je      .found_socket
188
        test    ax, ax
189
        jnz     .socket_loop
190
  .found_socket:                                        ; ebx now contains the socketpointer
3647 hidnplayr 191
        pusha
192
        mov     ecx, socket_mutex
193
        call    mutex_unlock
194
        popa
195
 
3556 hidnplayr 196
        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 197
 
198
;----------------------------
199
; Check if socket isnt closed
200
 
201
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_CLOSED
202
        je      .drop_no_socket
203
 
204
;----------------
205
; Lock the socket
206
 
207
        pusha
208
        lea     ecx, [ebx + SOCKET.mutex]
209
        call    mutex_lock
210
        popa
211
 
3556 hidnplayr 212
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: socket locked\n"
3545 hidnplayr 213
 
214
;---------------------------
215
; disable all temporary bits
216
 
4347 hidnplayr 217
        mov     [temp_bits], 0
3545 hidnplayr 218
 
219
;---------------------------------------
220
; unscale the window into a 32 bit value
221
 
222
        movzx   eax, [edx + TCP_header.Window]
223
        push    ecx
224
        mov     cl, [ebx + TCP_SOCKET.SND_SCALE]
225
        shl     eax, cl
226
        mov     dword [edx + TCP_header.Window], eax    ; word after window is checksum, we dont need checksum anymore
227
        pop     ecx
228
 
229
;---------------------------------------
230
; Are we accepting incoming connections?
231
 
232
        test    [ebx + SOCKET.options], SO_ACCEPTCON
233
        jz      .no_accept
234
 
3556 hidnplayr 235
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Accepting new connection\n"
3545 hidnplayr 236
 
237
        pusha
238
        lea     ecx, [ebx + SOCKET.mutex]
239
        call    mutex_unlock
240
        popa
241
 
242
        push    ecx edx esi edi         ;;;
243
        call    SOCKET_fork
244
        pop     edi esi edx ecx
245
 
246
        test    eax, eax
247
        jz      .drop_no_socket
248
 
249
        mov     ebx, eax
250
 
4347 hidnplayr 251
        mov     [temp_bits], TCP_BIT_DROPSOCKET
3545 hidnplayr 252
 
253
        push    dword [edi + 4]                         ; Ipv4 destination addres
254
        pop     [ebx + IP_SOCKET.LocalIP]
255
 
256
        push    [edx + TCP_header.DestinationPort]
257
        pop     [ebx + TCP_SOCKET.LocalPort]
258
 
259
        mov     [ebx + TCP_SOCKET.t_state], TCPS_LISTEN
260
  .no_accept:
261
 
262
 
263
;-------------------------------------
264
; Reset idle timer and keepalive timer
265
 
266
        mov     [ebx + TCP_SOCKET.t_idle], 0
267
        mov     [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_idle
3600 hidnplayr 268
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_keepalive
3545 hidnplayr 269
 
270
;--------------------
271
; Process TCP options
272
 
4339 hidnplayr 273
;;; FIXME: for LISTEN, options should be called after we determined route, we need it for MSS
274
;;;        cmp     [ebx + TCP_SOCKET.t_state], TCPS_LISTEN ; no options when in listen state
275
;;;        jz      .not_uni_xfer                           ; also no header prediction
276
 
3545 hidnplayr 277
        push    ecx
278
 
4339 hidnplayr 279
        mov     ecx, [dataoffset]
3545 hidnplayr 280
        cmp     ecx, sizeof.TCP_header                  ; Does header contain any options?
281
        je      .no_options
282
 
3556 hidnplayr 283
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Segment has options\n"
3545 hidnplayr 284
 
285
        add     ecx, edx
286
        lea     esi, [edx + sizeof.TCP_header]
287
 
288
  .opt_loop:
289
        cmp     esi, ecx                        ; are we scanning outside of header?
290
        jae     .no_options
291
        lodsb
292
        cmp     al, TCP_OPT_EOL                 ; end of option list?
293
        je      .no_options
294
        cmp     al, TCP_OPT_NOP
295
        je      .opt_loop
296
        cmp     al, TCP_OPT_MAXSEG
297
        je      .opt_maxseg
298
        cmp     al, TCP_OPT_WINDOW
299
        je      .opt_window
300
        cmp     al, TCP_OPT_SACK_PERMIT
301
        je      .opt_sack_permit
302
;        cmp     al, TCP_OPT_SACK
303
;        je      .opt_sack
304
        cmp     al, TCP_OPT_TIMESTAMP
305
        je      .opt_timestamp
3556 hidnplayr 306
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: unknown option:%u\n", al
3545 hidnplayr 307
        jmp     .no_options                     ; If we reach here, some unknown options were received, skip them all!
308
 
309
  .opt_maxseg:
310
        lodsb
311
        cmp     al, 4
312
        jne     .no_options                     ; error occured, ignore all options!
313
 
314
        test    [edx + TCP_header.Flags], TH_SYN
315
        jz      @f
316
 
4339 hidnplayr 317
        xor     eax, eax
3545 hidnplayr 318
        lodsw
319
        rol     ax, 8
4339 hidnplayr 320
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Maxseg=%u\n", eax
3545 hidnplayr 321
        call    TCP_mss
322
       @@:
323
        jmp     .opt_loop
324
 
325
 
326
  .opt_window:
327
        lodsb
328
        cmp     al, 3
329
        jne     .no_options
330
 
331
        test    [edx + TCP_header.Flags], TH_SYN
332
        jz      @f
333
 
3556 hidnplayr 334
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Got window scale option\n"
3545 hidnplayr 335
        or      [ebx + TCP_SOCKET.t_flags], TF_RCVD_SCALE
336
 
337
        lodsb
338
        mov     [ebx + TCP_SOCKET.SND_SCALE], al
339
        ;;;;; TODO
340
 
341
       @@:
342
        jmp     .opt_loop
343
 
344
 
345
  .opt_sack_permit:
346
        lodsb
347
        cmp     al, 2
348
        jne     .no_options
349
 
350
        test    [edx + TCP_header.Flags], TH_SYN
351
        jz      @f
352
 
3556 hidnplayr 353
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Selective Acknowledgement permitted\n"
3545 hidnplayr 354
        or      [ebx + TCP_SOCKET.t_flags], TF_SACK_PERMIT
355
 
356
       @@:
357
        jmp     .opt_loop
358
 
359
 
360
  .opt_timestamp:
361
        lodsb
362
        cmp     al, 10                          ; length must be 10
363
        jne     .no_options
364
 
3556 hidnplayr 365
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Got timestamp option\n"
3545 hidnplayr 366
 
367
        test    [edx + TCP_header.Flags], TH_SYN
368
        jz      @f
369
        or      [ebx + TCP_SOCKET.t_flags], TF_RCVD_TSTMP
370
       @@:
371
 
372
        lodsd
4344 hidnplayr 373
        bswap   eax
3545 hidnplayr 374
        mov     [ebx + TCP_SOCKET.ts_val], eax
375
        lodsd                                   ; timestamp echo reply
376
        mov     [ebx + TCP_SOCKET.ts_ecr], eax
4347 hidnplayr 377
        or      [temp_bits], TCP_BIT_TIMESTAMP
3545 hidnplayr 378
 
379
        ; Since we have a timestamp, lets do the paws test right away!
380
 
381
        test    [edx + TCP_header.Flags], TH_RST
382
        jnz     .no_paws
383
 
384
        mov     eax, [ebx + TCP_SOCKET.ts_recent]
385
        test    eax, eax
386
        jz      .no_paws
387
        cmp     eax, [ebx + TCP_SOCKET.ts_val]
4344 hidnplayr 388
        jbe     .no_paws
3545 hidnplayr 389
 
3556 hidnplayr 390
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: PAWS: detected an old segment\n"
3545 hidnplayr 391
 
4344 hidnplayr 392
        mov     eax, [timestamp]
3545 hidnplayr 393
        sub     eax, [ebx + TCP_SOCKET.ts_recent_age]
394
 
395
        pop     ecx
396
        cmp     eax, TCP_PAWS_IDLE
397
        jle     .drop_after_ack                         ; TODO: update stats
398
        push    ecx
399
 
400
        mov     [ebx + TCP_SOCKET.ts_recent], 0         ; timestamp was invalid, fix it.
401
  .no_paws:
402
        jmp     .opt_loop
403
 
404
  .no_options:
405
 
406
        pop     ecx
407
 
408
;-----------------------------------------------------------------------
409
; Time to do some header prediction (Original Principle by Van Jacobson)
410
 
411
; There are two common cases for an uni-directional data transfer.
412
;
413
; General rule: the packets has no control flags, is in-sequence,
414
;   window width didnt change and we're not retransmitting.
415
;
416
; Second rules:
417
;  -  If the length is 0 and the ACK moved forward, we're the sender side of the transfer.
418
;      In this case we'll free the ACK'ed data and notify higher levels that we have free space in buffer
419
;
420
;  -  If the length is not 0 and the ACK didn't move, we're the receiver side of the transfer.
421
;      If the packets are in order (data queue is empty), add the data to the socket buffer and request a delayed ACK
422
 
423
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
424
        jnz     .not_uni_xfer
425
 
426
        test    [edx + TCP_header.Flags], TH_SYN + TH_FIN + TH_RST + TH_URG
427
        jnz     .not_uni_xfer
428
 
429
        test    [edx + TCP_header.Flags], TH_ACK
430
        jz      .not_uni_xfer
431
 
432
        mov     eax, [edx + TCP_header.SequenceNumber]
433
        cmp     eax, [ebx + TCP_SOCKET.RCV_NXT]
434
        jne     .not_uni_xfer
435
 
436
        mov     eax, dword [edx + TCP_header.Window]
437
        cmp     eax, [ebx + TCP_SOCKET.SND_WND]
438
        jne     .not_uni_xfer
439
 
440
        mov     eax, [ebx + TCP_SOCKET.SND_NXT]
441
        cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
442
        jne     .not_uni_xfer
443
 
444
;---------------------------------------
445
; check if we are sender in the uni-xfer
446
 
447
; If the following 4 conditions are all true, this segment is a pure ACK.
448
;
449
; - The segment contains no data.
450
        test    ecx, ecx
451
        jnz     .not_sender
452
 
453
; - The congestion window is greater than or equal to the current send window.
454
;     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.
455
        mov     eax, [ebx + TCP_SOCKET.SND_CWND]
456
        cmp     eax, [ebx + TCP_SOCKET.SND_WND]
457
        jb      .not_uni_xfer
458
 
459
; - The acknowledgment field in the segment is less than or equal to the maximum sequence number sent.
460
        mov     eax, [edx + TCP_header.AckNumber]
461
        cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
462
        ja      .not_uni_xfer
463
 
464
; - The acknowledgment field in the segment is greater than the largest unacknowledged sequence number.
465
        sub     eax, [ebx + TCP_SOCKET.SND_UNA]
466
        jbe     .not_uni_xfer
467
 
3556 hidnplayr 468
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction: we are sender\n"
3545 hidnplayr 469
 
470
;---------------------------------
471
; Packet is a pure ACK, process it
472
 
473
; Delete acknowledged bytes from send buffer
474
        pusha
475
        mov     ecx, eax
476
        lea     eax, [ebx + STREAM_SOCKET.snd]
477
        call    SOCKET_ring_free
478
        popa
479
 
480
; Update RTT estimators
481
 
4347 hidnplayr 482
        test    [temp_bits], TCP_BIT_TIMESTAMP
3545 hidnplayr 483
        jz      .no_timestamp_rtt
4344 hidnplayr 484
        mov     eax, [timestamp]
3545 hidnplayr 485
        sub     eax, [ebx + TCP_SOCKET.ts_ecr]
486
        inc     eax
487
        call    TCP_xmit_timer
488
        jmp     .rtt_done
489
 
490
  .no_timestamp_rtt:
491
        cmp     [ebx + TCP_SOCKET.t_rtt], 0
492
        je      .rtt_done
493
        mov     eax, [edx + TCP_header.AckNumber]
494
        cmp     eax, [ebx + TCP_SOCKET.t_rtseq]
495
        jbe     .rtt_done
496
        mov     eax, [ebx + TCP_SOCKET.t_rtt]
497
        call    TCP_xmit_timer
498
 
499
  .rtt_done:
500
 
501
; update window pointers
502
        mov     eax, [edx + TCP_header.AckNumber]
503
        mov     [ebx + TCP_SOCKET.SND_UNA], eax
504
 
505
; Stop retransmit timer
3600 hidnplayr 506
        and     [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission
3545 hidnplayr 507
 
508
; Unlock the socket
509
        pusha
510
        lea     ecx, [ebx + SOCKET.mutex]
511
        call    mutex_unlock
512
        popa
513
 
514
; Awaken waiting processes
515
        mov     eax, ebx
516
        call    SOCKET_notify
517
 
518
; Generate more output
519
        call    TCP_output
520
 
521
        jmp     .drop_no_socket
522
 
523
;-------------------------------------------------
524
; maybe we are the receiver in the uni-xfer then..
525
 
526
  .not_sender:
527
; - The amount of data in the segment is greater than 0 (data count is in ecx)
528
 
529
; - The acknowledgment field equals the largest unacknowledged sequence number. This means no data is acknowledged by this segment.
530
        mov     eax, [edx + TCP_header.AckNumber]
531
        cmp     eax, [ebx + TCP_SOCKET.SND_UNA]
532
        jne     .not_uni_xfer
533
 
5133 hidnplayr 534
; - The reassembly list of out-of-order segments for the connection is empty.
535
        cmp     [ebx + TCP_SOCKET.seg_next], 0
536
        jne     .not_uni_xfer
3545 hidnplayr 537
 
538
; Complete processing of received data
539
 
3556 hidnplayr 540
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction: we are receiving %u bytes\n", ecx
3545 hidnplayr 541
 
4339 hidnplayr 542
        mov     esi, [dataoffset]
3545 hidnplayr 543
        add     esi, edx
544
        lea     eax, [ebx + STREAM_SOCKET.rcv]
545
        call    SOCKET_ring_write                       ; Add the data to the socket buffer
4344 hidnplayr 546
        add     [ebx + TCP_SOCKET.RCV_NXT], ecx         ; Update sequence number with number of bytes we have copied
3545 hidnplayr 547
 
548
        mov     eax, ebx
549
        call    SOCKET_notify
550
 
551
        or      [ebx + TCP_SOCKET.t_flags], TF_DELACK   ; Set delayed ack flag
552
 
553
        jmp     .drop
554
 
555
;--------------------------------------------------
556
; Header prediction failed, do it the slow way
557
 
558
  .not_uni_xfer:
559
 
3556 hidnplayr 560
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction failed\n"
3545 hidnplayr 561
 
562
; Calculate receive window size
563
        push    edx
4366 hidnplayr 564
        mov     eax, SOCKET_MAXDATA
3545 hidnplayr 565
        sub     eax, [ebx + STREAM_SOCKET.rcv.size]
4366 hidnplayr 566
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Space in receive buffer=%d\n", eax
3545 hidnplayr 567
        mov     edx, [ebx + TCP_SOCKET.RCV_ADV]
568
        sub     edx, [ebx + TCP_SOCKET.RCV_NXT]
4366 hidnplayr 569
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Current advertised window=%d\n", edx
3545 hidnplayr 570
        cmp     eax, edx
571
        jg      @f
572
        mov     eax, edx
573
       @@:
3556 hidnplayr 574
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Receive window size=%d\n", eax
3545 hidnplayr 575
        mov     [ebx + TCP_SOCKET.RCV_WND], eax
576
        pop     edx
577
 
578
; If we are in listen or syn_sent state, go to that specific code right away
579
 
580
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_LISTEN
581
        je      .LISTEN
582
 
583
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_SYN_SENT
584
        je      .SYN_SENT
585
 
586
;----------------------------
587
; trim any data not in window
588
 
4339 hidnplayr 589
; 1. Check for duplicate data at beginning of segment
3545 hidnplayr 590
 
4339 hidnplayr 591
; Calculate number of bytes we need to drop
3545 hidnplayr 592
        mov     eax, [ebx + TCP_SOCKET.RCV_NXT]
593
        sub     eax, [edx + TCP_header.SequenceNumber]
594
        jle     .no_duplicate
595
 
3556 hidnplayr 596
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: %u bytes duplicate data!\n", eax
3545 hidnplayr 597
 
598
        test    [edx + TCP_header.Flags], TH_SYN
599
        jz      .no_dup_syn
600
 
3556 hidnplayr 601
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: got duplicate syn\n"
3545 hidnplayr 602
 
603
        and     [edx + TCP_header.Flags], not (TH_SYN)
604
        inc     [edx + TCP_header.SequenceNumber]
605
 
606
        cmp     [edx + TCP_header.UrgentPointer], 1
607
        jbe     @f
608
        dec     [edx + TCP_header.UrgentPointer]
609
        jmp     .dup_syn
610
       @@:
611
        and     [edx + TCP_header.Flags], not (TH_URG)
612
  .dup_syn:
613
        dec     eax
614
  .no_dup_syn:
615
 
4339 hidnplayr 616
; 2. Check for entire duplicate segment
3545 hidnplayr 617
        cmp     eax, ecx                ; eax holds number of bytes to drop, ecx is data size
618
        jb      .duplicate
619
        jnz     @f
620
        test    [edx + TCP_header.Flags], TH_FIN
621
        jnz     .duplicate
622
       @@:
623
 
624
; Any valid FIN must be to the left of the window.
625
; At this point the FIN must be out of sequence or a duplicate, drop it
626
        and     [edx + TCP_header.Flags], not TH_FIN
627
 
628
; send an ACK and resynchronize and drop any data.
629
; But keep on processing for RST or ACK
630
        or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
631
        mov     eax, ecx
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
664
        call    TCP_close
4339 hidnplayr 665
;;; TODO: update stats
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
694
        call    TCP_close
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
782
        call    TCP_close
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
789
        call    TCP_close
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
802
        call    TCP_drop
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
827
        call    SOCKET_is_connected
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
 
5133 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]
919
        call    TCP_output
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]
958
        call    TCP_output
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
988
 
989
        ;;; TODO: update stats
990
        jmp     .drop_after_ack
991
 
992
       @@:
993
 
994
        mov     edi, [edx + TCP_header.AckNumber]
995
        sub     edi, [ebx + TCP_SOCKET.SND_UNA]         ; now we got the number of acked bytes in edi
996
 
997
        ;;; TODO: update stats
998
 
3556 hidnplayr 999
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: acceptable ACK for %u bytes\n", edi
3545 hidnplayr 1000
 
1001
;------------------------------------------
4347 hidnplayr 1002
; RTT measurements and retransmission timer
3545 hidnplayr 1003
 
1004
; If we have a timestamp, update smoothed RTT
1005
 
4347 hidnplayr 1006
        test    [temp_bits], TCP_BIT_TIMESTAMP
3545 hidnplayr 1007
        jz      .timestamp_not_present
4344 hidnplayr 1008
        mov     eax, [timestamp]
3545 hidnplayr 1009
        sub     eax, [ebx + TCP_SOCKET.ts_ecr]
1010
        inc     eax
1011
        call    TCP_xmit_timer
1012
        jmp     .rtt_done_
1013
 
1014
; If no timestamp but transmit timer is running and timed sequence number was acked,
1015
; update smoothed RTT. Since we now have an RTT measurement, cancel the timer backoff
1016
; (Phil Karn's retransmit algo)
1017
; Recompute the initial retransmit timer
1018
 
1019
  .timestamp_not_present:
1020
        mov     eax, [edx + TCP_header.AckNumber]
1021
        cmp     eax, [ebx + TCP_SOCKET.t_rtseq]
1022
        jbe     .rtt_done_
1023
        mov     eax, [ebx + TCP_SOCKET.t_rtt]
1024
        test    eax, eax
1025
        jz      .rtt_done_
1026
        call    TCP_xmit_timer
1027
 
1028
  .rtt_done_:
1029
 
1030
; If all outstanding data is acked, stop retransmit timer and remember to restart (more output or persist)
1031
; If there is more data to be acked, restart retransmit timer, using current (possible backed-off) value.
1032
 
1033
        mov     eax, [ebx + TCP_SOCKET.SND_MAX]
1034
        cmp     eax, [edx + TCP_header.AckNumber]
1035
        jne     .more_data
3600 hidnplayr 1036
        and     [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission
4347 hidnplayr 1037
        or      [temp_bits], TCP_BIT_NEEDOUTPUT
3545 hidnplayr 1038
        jmp     .no_restart
1039
  .more_data:
3600 hidnplayr 1040
        test    [ebx + TCP_SOCKET.timer_flags], timer_flag_persist
1041
        jnz     .no_restart
3545 hidnplayr 1042
 
1043
        mov     eax, [ebx + TCP_SOCKET.t_rxtcur]
1044
        mov     [ebx + TCP_SOCKET.timer_retransmission], eax
3600 hidnplayr 1045
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_retransmission
3545 hidnplayr 1046
  .no_restart:
1047
 
1048
 
1049
;-------------------------------------------
1050
; Open congestion window in response to ACKs
1051
 
1052
        mov     esi, [ebx + TCP_SOCKET.SND_CWND]
1053
        mov     eax, [ebx + TCP_SOCKET.t_maxseg]
1054
 
1055
        cmp     esi, [ebx + TCP_SOCKET.SND_SSTHRESH]
1056
        jbe     @f
1057
        push    edx
1058
        push    eax
1059
        mul     eax
1060
        div     esi
1061
        pop     edx
1062
        shr     edx, 3
1063
        add     eax, edx
1064
        pop     edx
1065
       @@:
1066
 
1067
        add     esi, eax
1068
 
1069
        push    ecx
1070
        mov     cl, [ebx + TCP_SOCKET.SND_SCALE]
1071
        mov     eax, TCP_max_win
1072
        shl     eax, cl
1073
        pop     ecx
1074
 
1075
        cmp     esi, eax
4296 hidnplayr 1076
        jbe     @f
1077
        mov     esi, eax
1078
  @@:
3545 hidnplayr 1079
        mov     [ebx + TCP_SOCKET.SND_CWND], esi
1080
 
1081
;------------------------------------------
1082
; Remove acknowledged data from send buffer
1083
 
1084
        cmp     edi, [ebx + STREAM_SOCKET.snd.size]
1085
        jbe     .finiacked
1086
 
1087
        push    ecx edx ebx
1088
        mov     ecx, [ebx + STREAM_SOCKET.snd.size]
1089
        lea     eax, [ebx + STREAM_SOCKET.snd]
1090
        sub     [ebx + TCP_SOCKET.SND_WND], ecx
1091
        call    SOCKET_ring_free
1092
        pop     ebx edx ecx
1093
 
3556 hidnplayr 1094
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: our FIN is acked\n"
5133 hidnplayr 1095
        or      [temp_bits], TCP_BIT_FIN_IS_ACKED
3545 hidnplayr 1096
        jmp     .wakeup
1097
 
1098
  .finiacked:
1099
 
1100
        push    ecx edx ebx
1101
        mov     ecx, edi
1102
        lea     eax, [ebx + STREAM_SOCKET.snd]
1103
        call    SOCKET_ring_free
1104
        pop     ebx
1105
        sub     [ebx + TCP_SOCKET.SND_WND], ecx
1106
        pop     edx ecx
1107
 
3556 hidnplayr 1108
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: our FIN is not acked\n"
3545 hidnplayr 1109
 
1110
;----------------------------------------
1111
; Wake up process waiting on send buffer
1112
 
1113
  .wakeup:
1114
        mov     eax, ebx
1115
        call    SOCKET_notify
1116
 
1117
; Update TCPS
1118
        mov     eax, [edx + TCP_header.AckNumber]
1119
        mov     [ebx + TCP_SOCKET.SND_UNA], eax
1120
        cmp     eax, [ebx + TCP_SOCKET.SND_NXT]
1121
        jb      @f
1122
        mov     [ebx + TCP_SOCKET.SND_NXT], eax
1123
       @@:
1124
 
1125
; General ACK handling complete
1126
; Now do the state-specific ones
1127
; Carry flag is set when our FIN is acked
1128
 
1129
        mov     eax, [ebx + TCP_SOCKET.t_state]
1130
        jmp     dword [eax*4 + .ACK_sw_list]
1131
 
1132
  .ACK_sw_list:
1133
        dd      .ack_processed  ; TCPS_CLOSED
1134
        dd      .ack_processed  ; TCPS_LISTEN
1135
        dd      .ack_processed  ; TCPS_SYN_SENT
1136
        dd      .ack_processed  ; TCPS_SYN_RECEIVED
1137
        dd      .ack_processed  ; TCPS_ESTABLISHED
1138
        dd      .ack_processed  ; TCPS_CLOSE_WAIT
1139
        dd      .ack_fw1        ; TCPS_FIN_WAIT_1
1140
        dd      .ack_c          ; TCPS_CLOSING
1141
        dd      .ack_la         ; TCPS_LAST_ACK
1142
        dd      .ack_processed  ; TCPS_FIN_WAIT_2
1143
        dd      .ack_tw         ; TCPS_TIMED_WAIT
1144
 
1145
 
1146
  .ack_fw1:
5133 hidnplayr 1147
        test    [temp_bits], TCP_BIT_FIN_IS_ACKED
1148
        jz      .ack_processed
3545 hidnplayr 1149
 
1150
        test    [ebx + SOCKET.state], SS_CANTRCVMORE
1151
        jnz     @f
1152
        mov     eax, ebx
1153
        call    SOCKET_is_disconnected
1154
        mov     [ebx + TCP_SOCKET.timer_timed_wait], TCP_time_max_idle
3600 hidnplayr 1155
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
3545 hidnplayr 1156
       @@:
1157
        mov     [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_2
1158
        jmp     .ack_processed
1159
 
1160
  .ack_c:
5133 hidnplayr 1161
        test    [temp_bits], TCP_BIT_FIN_IS_ACKED
1162
        jz      .ack_processed
3545 hidnplayr 1163
 
1164
        mov     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1165
        mov     eax, ebx
1166
        call    TCP_cancel_timers
1167
        mov     [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
3600 hidnplayr 1168
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
3545 hidnplayr 1169
        mov     eax, ebx
1170
        call    SOCKET_is_disconnected
1171
        jmp     .ack_processed
1172
 
1173
  .ack_la:
5133 hidnplayr 1174
        test    [temp_bits], TCP_BIT_FIN_IS_ACKED
1175
        jz      .ack_processed
3545 hidnplayr 1176
 
3652 hidnplayr 1177
        push    ebx
1178
        lea     ecx, [ebx + SOCKET.mutex]
1179
        call    mutex_unlock
1180
        pop     ebx
1181
 
3545 hidnplayr 1182
        mov     eax, ebx
4366 hidnplayr 1183
        call    TCP_close
1184
        jmp     .drop_no_socket
3545 hidnplayr 1185
 
1186
  .ack_tw:
1187
        mov     [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
3600 hidnplayr 1188
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
3545 hidnplayr 1189
        jmp     .drop_after_ack
1190
 
1191
  .reset_dupacks:               ; We got a new ACK, reset duplicate ACK counter
1192
        mov     [ebx + TCP_SOCKET.t_dupacks], 0
1193
        jmp     .ack_processed
1194
 
1195
;-------
1196
; LISTEN
1197
 
1198
align 4
1199
  .LISTEN:
1200
 
3556 hidnplayr 1201
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: state=listen\n"
3545 hidnplayr 1202
 
1203
        test    [edx + TCP_header.Flags], TH_RST
1204
        jnz     .drop
1205
 
1206
        test    [edx + TCP_header.Flags], TH_ACK
1207
        jnz     .drop_with_reset
1208
 
1209
        test    [edx + TCP_header.Flags], TH_SYN
1210
        jz      .drop
1211
 
1212
;;; TODO: check if it's a broadcast or multicast, and drop if so
1213
 
1214
        push    dword [edi]                             ; Ipv4 source addres
1215
        pop     [ebx + IP_SOCKET.RemoteIP]
1216
 
1217
        push    [edx + TCP_header.SourcePort]
1218
        pop     [ebx + TCP_SOCKET.RemotePort]
1219
 
1220
        push    [edx + TCP_header.SequenceNumber]
1221
        pop     [ebx + TCP_SOCKET.IRS]
1222
 
1223
        mov     eax, [TCP_sequence_num]
1224
        add     [TCP_sequence_num], 64000 / 2
1225
        mov     [ebx + TCP_SOCKET.ISS], eax
1226
        mov     [ebx + TCP_SOCKET.SND_NXT], eax
1227
 
1228
        TCP_sendseqinit ebx
1229
        TCP_rcvseqinit ebx
1230
 
1231
        mov     [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
4347 hidnplayr 1232
        or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
3545 hidnplayr 1233
        mov     [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval  ;;;; macro
3600 hidnplayr 1234
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_keepalive
3545 hidnplayr 1235
 
1236
        lea     eax, [ebx + STREAM_SOCKET.snd]
1237
        call    SOCKET_ring_create
1238
 
1239
        lea     eax, [ebx + STREAM_SOCKET.rcv]
1240
        call    SOCKET_ring_create
1241
 
4347 hidnplayr 1242
        and     [temp_bits], not TCP_BIT_DROPSOCKET
3545 hidnplayr 1243
 
3674 hidnplayr 1244
        pusha
1245
        mov     eax, ebx
1246
        call    SOCKET_notify
1247
        popa
3545 hidnplayr 1248
 
5133 hidnplayr 1249
        jmp     .trim
3545 hidnplayr 1250
 
1251
;------------
1252
; Active Open
1253
 
1254
align 4
1255
  .SYN_SENT:
1256
 
3556 hidnplayr 1257
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: state=syn_sent\n"
3545 hidnplayr 1258
 
1259
        test    [edx + TCP_header.Flags], TH_ACK
1260
        jz      @f
1261
 
1262
        mov     eax, [edx + TCP_header.AckNumber]
1263
        cmp     eax, [ebx + TCP_SOCKET.ISS]
1264
        jbe     .drop_with_reset
1265
 
1266
        cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
1267
        ja      .drop_with_reset
1268
       @@:
1269
 
1270
        test    [edx + TCP_header.Flags], TH_RST
1271
        jz      @f
1272
 
1273
        test    [edx + TCP_header.Flags], TH_ACK
1274
        jz      .drop
1275
 
1276
        mov     eax, ebx
1277
        mov     ebx, ECONNREFUSED
1278
        call    TCP_drop
1279
 
1280
        jmp     .drop
1281
       @@:
1282
 
1283
        test    [edx + TCP_header.Flags], TH_SYN
1284
        jz      .drop
1285
 
1286
; at this point, segment seems to be valid
1287
 
1288
        test    [edx + TCP_header.Flags], TH_ACK
1289
        jz      .no_syn_ack
1290
 
1291
; now, process received SYN in response to an active open
1292
 
1293
        mov     eax, [edx + TCP_header.AckNumber]
1294
        mov     [ebx + TCP_SOCKET.SND_UNA], eax
1295
        cmp     eax, [ebx + TCP_SOCKET.SND_NXT]
1296
        jbe     @f
1297
        mov     [ebx + TCP_SOCKET.SND_NXT], eax
1298
       @@:
1299
 
1300
  .no_syn_ack:
3600 hidnplayr 1301
        and     [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission   ; disable retransmission timer
3545 hidnplayr 1302
 
1303
        push    [edx + TCP_header.SequenceNumber]
1304
        pop     [ebx + TCP_SOCKET.IRS]
1305
 
1306
        TCP_rcvseqinit ebx
1307
 
1308
        or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1309
 
1310
        mov     eax, [ebx + TCP_SOCKET.SND_UNA]
1311
        cmp     eax, [ebx + TCP_SOCKET.ISS]
1312
        jbe     .simultaneous_open
1313
 
1314
        test    [edx + TCP_header.Flags], TH_ACK
1315
        jz      .simultaneous_open
1316
 
3556 hidnplayr 1317
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: active open\n"
3545 hidnplayr 1318
 
1319
;;; TODO: update stats
1320
 
1321
; set socket state to connected
3674 hidnplayr 1322
        push    eax
1323
        mov     eax, ebx
1324
        call    SOCKET_is_connected
1325
        pop     eax
3545 hidnplayr 1326
        mov     [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
1327
 
1328
; Do window scaling on this connection ?
1329
        mov     eax, [ebx + TCP_SOCKET.t_flags]
1330
        and     eax, TF_REQ_SCALE or TF_RCVD_SCALE
1331
        cmp     eax, TF_REQ_SCALE or TF_RCVD_SCALE
1332
        jne     .no_scaling
1333
 
1334
        mov     ax, word [ebx + TCP_SOCKET.requested_s_scale]
1335
        mov     word [ebx + TCP_SOCKET.SND_SCALE], ax
1336
  .no_scaling:
1337
 
1338
;;; TODO: reassemble packets queue
1339
 
1340
        mov     eax, [ebx + TCP_SOCKET.t_rtt]
1341
        test    eax, eax
5133 hidnplayr 1342
        je      .trim
3545 hidnplayr 1343
        call    TCP_xmit_timer
5133 hidnplayr 1344
        jmp     .trim
3545 hidnplayr 1345
 
1346
  .simultaneous_open:
1347
 
3556 hidnplayr 1348
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: simultaneous open\n"
3545 hidnplayr 1349
; We have received a syn but no ACK, so we are having a simultaneous open..
1350
        mov     [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
1351
 
1352
;-------------------------------------
1353
; Common processing for receipt of SYN
1354
 
5133 hidnplayr 1355
  .trim:
3545 hidnplayr 1356
        inc     [edx + TCP_header.SequenceNumber]
1357
 
4339 hidnplayr 1358
; Drop any received data that doesnt fit in the receive window.
1359
        cmp     ecx, [ebx + TCP_SOCKET.RCV_WND]
1360
        jbe     .dont_trim
3545 hidnplayr 1361
 
4339 hidnplayr 1362
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: received data does not fit in window, trimming %u bytes\n", eax
1363
        mov     ecx, [ebx + TCP_SOCKET.RCV_WND]
1364
        and     [edx + TCP_header.Flags], not (TH_FIN)
1365
;;; TODO: update stats
1366
 
1367
  .dont_trim:
3545 hidnplayr 1368
        mov     eax, [edx + TCP_header.SequenceNumber]
1369
        mov     [ebx + TCP_SOCKET.RCV_UP], eax
1370
        dec     eax
1371
        mov     [ebx + TCP_SOCKET.SND_WL1], eax
1372
 
1373
  .ack_processed:
3556 hidnplayr 1374
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: ACK processed\n"
3545 hidnplayr 1375
 
1376
;----------------------------------------------
1377
; check if we need to update window information
1378
 
1379
        test    [edx + TCP_header.Flags], TH_ACK
1380
        jz      .no_window_update
1381
 
1382
        mov     eax, [ebx + TCP_SOCKET.SND_WL1]
1383
        cmp     eax, [edx + TCP_header.SequenceNumber]
1384
        jb      .update_window
1385
        ja      @f
1386
 
1387
        mov     eax, [ebx + TCP_SOCKET.SND_WL2]
1388
        cmp     eax, [edx + TCP_header.AckNumber]
1389
        jb      .update_window
1390
        ja      .no_window_update
1391
       @@:
1392
 
1393
        mov     eax, dword [edx + TCP_header.Window]
1394
        cmp     eax, [ebx + TCP_SOCKET.SND_WND]
1395
        jbe     .no_window_update
1396
 
1397
  .update_window:
1398
 
1399
;;; TODO: update stats (Keep track of pure window updates)
1400
 
1401
        mov     eax, dword [edx + TCP_header.Window]
1402
        cmp     eax, [ebx + TCP_SOCKET.max_sndwnd]
1403
        jbe     @f
1404
        mov     [ebx + TCP_SOCKET.max_sndwnd], eax
1405
       @@:
1406
        mov     [ebx + TCP_SOCKET.SND_WND], eax
1407
 
3556 hidnplayr 1408
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Updating window to %u\n", eax
3545 hidnplayr 1409
 
1410
        push    [edx + TCP_header.SequenceNumber]
1411
        pop     [ebx + TCP_SOCKET.SND_WL1]
1412
 
1413
        push    [edx + TCP_header.AckNumber]
1414
        pop     [ebx + TCP_SOCKET.SND_WL2]
1415
 
4347 hidnplayr 1416
        or      [temp_bits], TCP_BIT_NEEDOUTPUT
3545 hidnplayr 1417
 
1418
  .no_window_update:
1419
 
1420
;-----------------
1421
; process URG flag
1422
 
1423
        test    [edx + TCP_header.Flags], TH_URG
1424
        jz      .not_urgent
1425
 
1426
        cmp     [edx + TCP_header.UrgentPointer], 0
1427
        jz      .not_urgent
1428
 
1429
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1430
        je      .not_urgent
1431
 
1432
; Ignore bogus urgent offsets
1433
 
1434
        movzx   eax, [edx + TCP_header.UrgentPointer]
1435
        add     eax, [ebx + STREAM_SOCKET.rcv.size]
1436
        cmp     eax, SOCKET_MAXDATA
1437
        jbe     .not_urgent
1438
 
1439
        mov     [edx + TCP_header.UrgentPointer], 0
1440
        and     [edx + TCP_header.Flags], not (TH_URG)
1441
        jmp     .do_data
1442
 
1443
  .not_urgent:
1444
 
1445
; processing of received urgent pointer
1446
 
1447
        ;;; TODO (1051-1093)
1448
 
1449
 
1450
;---------------------------------------
1451
; process the data in the segment (1094)
1452
 
1453
  .do_data:
1454
 
1455
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1456
        jae     .final_processing
1457
 
1458
        test    [edx + TCP_header.Flags], TH_FIN
1459
        jnz     @f
1460
 
1461
        test    ecx, ecx
3756 hidnplayr 1462
        jz      .final_processing
3545 hidnplayr 1463
       @@:
1464
 
1465
; The segment is in order?
1466
        mov     eax, [edx + TCP_header.SequenceNumber]
1467
        cmp     eax, [ebx + TCP_SOCKET.RCV_NXT]
1468
        jne     .out_of_order
1469
 
1470
; The reassembly queue is empty?
1471
        cmp     [ebx + TCP_SOCKET.seg_next], 0
1472
        jne     .out_of_order
1473
 
1474
; The connection is established?
1475
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
1476
        jne     .out_of_order
1477
 
1478
; Ok, lets do this..  Set delayed ACK flag and copy data into socket buffer
1479
        or      [ebx + TCP_SOCKET.t_flags], TF_DELACK
1480
 
1481
        pusha
4339 hidnplayr 1482
        mov     esi, [dataoffset]
3545 hidnplayr 1483
        add     esi, edx
1484
        lea     eax, [ebx + STREAM_SOCKET.rcv]
1485
        call    SOCKET_ring_write                       ; Add the data to the socket buffer
1486
        add     [ebx + TCP_SOCKET.RCV_NXT], ecx         ; Update sequence number with number of bytes we have copied
1487
        popa
1488
 
1489
; Wake up the sleeping process
1490
        mov     eax, ebx
1491
        call    SOCKET_notify
1492
 
1493
        jmp     .data_done
1494
 
1495
  .out_of_order:
4339 hidnplayr 1496
        DEBUGF  DEBUG_NETWORK_VERBOSE,  "TCP data is out of order!\nSequencenumber is %u, we expected %u.\n", \
1497
        [edx + TCP_header.SequenceNumber], [ebx + TCP_SOCKET.RCV_NXT]
3545 hidnplayr 1498
 
1499
; Uh-oh, some data is out of order, lets call TCP reassemble for help
1500
 
1501
        call    TCP_reassemble
1502
 
4339 hidnplayr 1503
; Generate ACK immediately, to let the other end know that a segment was received out of order,
1504
; and to tell it what sequence number is expected. This aids the fast-retransmit algorithm.
3545 hidnplayr 1505
        or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1506
  .data_done:
1507
 
1508
;---------------
1509
; FIN processing
1510
 
1511
        test    [edx + TCP_header.Flags], TH_FIN
1512
        jz      .final_processing
1513
 
3556 hidnplayr 1514
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Processing FIN\n"
3545 hidnplayr 1515
 
1516
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1517
        jae     .not_first_fin
1518
 
3556 hidnplayr 1519
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: First FIN for this connection\n"
3545 hidnplayr 1520
 
1521
        mov     eax, ebx
1522
        call    SOCKET_cant_recv_more
1523
 
4347 hidnplayr 1524
        or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
3545 hidnplayr 1525
        inc     [ebx + TCP_SOCKET.RCV_NXT]
1526
 
1527
  .not_first_fin:
1528
        mov     eax, [ebx + TCP_SOCKET.t_state]
1529
        shl     eax, 2
1530
        jmp     dword [eax + .FIN_sw_list]
1531
 
1532
  .FIN_sw_list:
1533
        dd      .final_processing       ; TCPS_CLOSED
1534
        dd      .final_processing       ; TCPS_LISTEN
1535
        dd      .final_processing       ; TCPS_SYN_SENT
1536
        dd      .fin_syn_est            ; TCPS_SYN_RECEIVED
1537
        dd      .fin_syn_est            ; TCPS_ESTABLISHED
1538
        dd      .final_processing       ; TCPS_CLOSE_WAIT
1539
        dd      .fin_wait1              ; TCPS_FIN_WAIT_1
1540
        dd      .final_processing       ; TCPS_CLOSING
1541
        dd      .final_processing       ; TCPS_LAST_ACK
1542
        dd      .fin_wait2              ; TCPS_FIN_WAIT_2
1543
        dd      .fin_timed              ; TCPS_TIMED_WAIT
1544
 
1545
  .fin_syn_est:
1546
        mov     [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
1547
        jmp     .final_processing
1548
 
1549
  .fin_wait1:
1550
        mov     [ebx + TCP_SOCKET.t_state], TCPS_CLOSING
1551
        jmp     .final_processing
1552
 
1553
  .fin_wait2:
1554
        mov     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1555
        mov     eax, ebx
1556
        call    TCP_cancel_timers
1557
        call    SOCKET_is_disconnected
1558
 
1559
  .fin_timed:
1560
        mov     [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
3600 hidnplayr 1561
        or      [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
3545 hidnplayr 1562
 
4347 hidnplayr 1563
;-----------------
1564
; Final processing
3545 hidnplayr 1565
 
4347 hidnplayr 1566
  .final_processing:
1567
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Final processing\n"
1568
 
1569
        push    ebx
1570
        lea     ecx, [ebx + SOCKET.mutex]
1571
        call    mutex_unlock
1572
        pop     eax
1573
 
1574
        test    [temp_bits], TCP_BIT_NEEDOUTPUT
1575
        jnz     .need_output
1576
 
1577
        test    [eax + TCP_SOCKET.t_flags], TF_ACKNOW
5133 hidnplayr 1578
        jz      .done
4347 hidnplayr 1579
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: ACK now!\n"
1580
 
1581
  .need_output:
1582
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: need output\n"
1583
        call    TCP_output
1584
 
5133 hidnplayr 1585
  .done:
4347 hidnplayr 1586
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: dumping\n"
1587
 
1588
        call    NET_packet_free
1589
        jmp     .loop
1590
 
1591
 
1592
;-----------------
1593
; Drop the segment
1594
 
1595
 
3545 hidnplayr 1596
  .drop_after_ack:
3556 hidnplayr 1597
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Drop after ACK\n"
3545 hidnplayr 1598
 
1599
        push    edx ebx
1600
        lea     ecx, [ebx + SOCKET.mutex]
1601
        call    mutex_unlock
1602
        pop     eax edx
1603
 
1604
        test    [edx + TCP_header.Flags], TH_RST
5133 hidnplayr 1605
        jnz     .done
3545 hidnplayr 1606
 
1607
        or      [eax + TCP_SOCKET.t_flags], TF_ACKNOW
1608
        jmp     .need_output
1609
 
1610
  .drop_with_reset:
3556 hidnplayr 1611
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Drop with reset\n"
3545 hidnplayr 1612
 
1613
        push    ebx edx
1614
        lea     ecx, [ebx + SOCKET.mutex]
1615
        call    mutex_unlock
1616
        pop     edx ebx
1617
 
1618
        test    [edx + TCP_header.Flags], TH_RST
5133 hidnplayr 1619
        jnz     .done
3545 hidnplayr 1620
 
1621
        ;;; if its a multicast/broadcast, also drop
1622
 
1623
        test    [edx + TCP_header.Flags], TH_ACK
1624
        jnz     .respond_ack
1625
 
1626
        test    [edx + TCP_header.Flags], TH_SYN
1627
        jnz     .respond_syn
5133 hidnplayr 1628
        jmp     .done
3545 hidnplayr 1629
 
1630
;---------
1631
; Respond
1632
 
1633
  .respond_ack:
1634
        push    ebx
1635
        mov     cl, TH_RST
1636
        call    TCP_respond
1637
        pop     ebx
1638
        jmp     .destroy_new_socket
1639
 
1640
  .respond_syn:
1641
        push    ebx
1642
        mov     cl, TH_RST + TH_ACK
1643
        call    TCP_respond
1644
        pop     ebx
1645
        jmp     .destroy_new_socket
1646
 
5133 hidnplayr 1647
;-----------------------------------------
1648
; The connection has no associated socket
1649
 
3647 hidnplayr 1650
  .no_socket:
1651
        pusha
1652
        mov     ecx, socket_mutex
1653
        call    mutex_unlock
1654
        popa
1655
 
3545 hidnplayr 1656
  .respond_seg_reset:
1657
        test    [edx + TCP_header.Flags], TH_RST
1658
        jnz     .drop_no_socket
1659
 
1660
        ;;; TODO: if its a multicast/broadcast, also drop
1661
 
1662
        test    [edx + TCP_header.Flags], TH_ACK
1663
        jnz     .respond_seg_ack
1664
 
1665
        test    [edx + TCP_header.Flags], TH_SYN
1666
        jnz     .respond_seg_syn
1667
 
1668
        jmp     .drop_no_socket
1669
 
1670
  .respond_seg_ack:
1671
        mov     cl, TH_RST
1672
        call    TCP_respond_segment
1673
        jmp     .drop_no_socket
1674
 
1675
  .respond_seg_syn:
1676
        mov     cl, TH_RST + TH_ACK
1677
        call    TCP_respond_segment
1678
        jmp     .drop_no_socket
1679
 
5133 hidnplayr 1680
;------------------------------------------------
1681
; Unlock socket mutex and prepare to drop segment
3545 hidnplayr 1682
 
1683
  .drop:
3556 hidnplayr 1684
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Dropping segment\n"
3545 hidnplayr 1685
 
1686
        pusha
1687
        lea     ecx, [ebx + SOCKET.mutex]
1688
        call    mutex_unlock
1689
        popa
1690
 
5133 hidnplayr 1691
;--------------------------------------------
1692
; Destroy the newly created socket if needed
1693
 
3545 hidnplayr 1694
  .destroy_new_socket:
4347 hidnplayr 1695
        test    [temp_bits], TCP_BIT_DROPSOCKET
3545 hidnplayr 1696
        jz      .drop_no_socket
1697
 
1698
        mov     eax, ebx
1699
        call    SOCKET_free
1700
 
5133 hidnplayr 1701
;------------------
1702
; Drop the segment
1703
 
3545 hidnplayr 1704
  .drop_no_socket:
3556 hidnplayr 1705
        DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_input: Drop (no socket)\n"
3545 hidnplayr 1706
 
3861 hidnplayr 1707
        call    NET_packet_free
3545 hidnplayr 1708
        jmp     .loop
4339 hidnplayr 1709
 
1710
endp