Subversion Repositories Kolibri OS

Rev

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