Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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