Subversion Repositories Kolibri OS

Rev

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

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