Subversion Repositories Kolibri OS

Rev

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