Subversion Repositories Kolibri OS

Rev

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

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