Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved.    ;;
4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  Part of the TCP/IP network stack for KolibriOS                 ;;
7
;;                                                                 ;;
8
;;   Written by hidnplayr@kolibrios.org                            ;;
9
;;                                                                 ;;
10
;;    Based on the code of 4.4BSD                                  ;;
11
;;                                                                 ;;
12
;;          GNU GENERAL PUBLIC LICENSE                             ;;
13
;;             Version 2, June 1991                                ;;
14
;;                                                                 ;;
15
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
16
 
17
$Revision: 3407 $
18
 
19
;-----------------------------------------------------------------
20
;
21
; TCP_input:
22
;
23
;       Add a segment to the incoming TCP queue
24
;
25
;  IN:  [esp] = ptr to buffer
26
;       [esp+4] = buffer size (dont care)
27
;       ebx = ptr to device struct
28
;       ecx = segment size
29
;       esi = ptr to TCP segment
30
;       edi = ptr to ipv4 source address, followed by ipv4 dest address
31
;
32
;  OUT: /
33
;
34
;-----------------------------------------------------------------
35
 
36
align 4
37
TCP_input:
38
 
39
; record the current time
40
        mov     eax, [timer_ticks]      ; in 1/100 seconds
41
        mov     [esp + 4], eax
42
 
43
        push    ebx ecx esi edi         ; mind the order
44
        mov     esi, esp
45
 
46
        pushf
47
        cli
48
        add_to_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .fail
49
        popf
50
 
51
        add     esp, sizeof.TCP_queue_entry
52
 
53
        xor     edx, edx
54
        mov     eax, [TCP_input_event]
55
        mov     ebx, [eax + EVENT.id]
56
        xor     esi, esi
57
        call    raise_event
58
 
59
        ret
60
 
61
  .fail:
62
        popf
63
        DEBUGF  2, "TCP incoming queue is full, discarding packet!\n"
64
 
65
        inc     [TCP_segments_missed]   ; FIXME: use correct interface
66
 
67
        add     esp, sizeof.TCP_queue_entry - 8
68
        call    kernel_free
69
        add     esp, 4
70
 
71
        ret
72
 
73
 
74
 
75
 
76
align 4
77
TCP_process_input:
78
 
79
        xor     esi, esi
80
        mov     ecx, MANUAL_DESTROY
81
        call    create_event
82
        mov     [TCP_input_event], eax
83
 
84
  .wait:
85
        mov     eax, [TCP_input_event]
86
        mov     ebx, [eax + EVENT.id]
87
        call    wait_event
88
 
89
  .loop:
90
        get_from_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .wait
91
 
92
        push    [esi + TCP_queue_entry.timestamp]
93
        push    [esi + TCP_queue_entry.buffer_ptr]
94
 
95
        mov     ebx, [esi + TCP_queue_entry.device_ptr]
96
        mov     ecx, [esi + TCP_queue_entry.segment_size]
97
        mov     edi, [esi + TCP_queue_entry.ip_ptr]                     ; ptr to ipv4 source address, followed by ipv4 destination address
98
        mov     esi, [esi + TCP_queue_entry.segment_ptr]                ; change esi last
99
 
100
        DEBUGF  1,"TCP_input: size=%u time=%d\n", ecx, [timer_ticks]
101
 
102
        mov     edx, esi
103
 
104
        cmp     ebx, LOOPBACK_DEVICE
105
        je      .checksum_ok
106
 
107
; re-calculate the checksum (if not already done by hw)
108
;        test    [ebx + NET_DEVICE.hwacc], HWACC_TCP_IPv4_IN
109
;        jnz     .checksum_ok
110
 
111
        push    ecx esi
112
        pushw   [esi + TCP_header.Checksum]
113
        mov     [esi + TCP_header.Checksum], 0
114
        TCP_checksum (edi), (edi+4)
115
        pop     cx                      ; previous checksum
116
        cmp     cx, dx
117
        pop     edx ecx
118
        jne     .drop_no_socket
119
  .checksum_ok:
120
 
121
; Verify the data offset
122
        and     [edx + TCP_header.DataOffset], 0xf0                     ; Calculate TCP segment header size (throwing away unused reserved bits in TCP header)
123
        shr     [edx + TCP_header.DataOffset], 2
124
        cmp     [edx + TCP_header.DataOffset], sizeof.TCP_header        ; Now see if it's at least the size of a standard TCP header
125
        jb      .drop_no_socket                                         ; If not, drop the packet
126
 
127
        movzx   eax, [edx + TCP_header.DataOffset]
128
        sub     ecx, eax                                                ; substract TCP header size from total segment size
129
        jb      .drop_no_socket                                         ; If total segment size is less then the advertised header size, drop packet
130
        DEBUGF  1,"TCP_input: %u bytes of data\n", ecx
131
 
132
;-------------------------------------------
133
; Convert Big-endian values to little endian
134
 
135
        ntohd   [edx + TCP_header.SequenceNumber]
136
        ntohd   [edx + TCP_header.AckNumber]
137
 
138
        ntohw   [edx + TCP_header.Window]
139
        ntohw   [edx + TCP_header.UrgentPointer]
140
 
141
;------------------------
142
; Find the socket pointer
143
 
144
; IP Packet TCP Destination Port = local Port
145
; (IP Packet SenderAddress = Remote IP)  OR  (Remote IP = 0)
146
; (IP Packet TCP Source Port = remote Port) OR (remote Port = 0)
147
 
148
  .findpcb:
149
        mov     ebx, net_sockets
150
        mov     si, [edx + TCP_header.DestinationPort]
151
 
152
  .socket_loop:
153
        mov     ebx, [ebx + SOCKET.NextPtr]
154
        or      ebx, ebx
155
        jz      .respond_seg_reset
156
 
157
        cmp     [ebx + SOCKET.Domain], AF_INET4
158
        jne     .socket_loop
159
 
160
        cmp     [ebx + SOCKET.Protocol], IP_PROTO_TCP
161
        jne     .socket_loop
162
 
163
        cmp     [ebx + TCP_SOCKET.LocalPort], si
164
        jne     .socket_loop
165
 
166
        mov     eax, [ebx + IP_SOCKET.RemoteIP]
167
        cmp     eax, [edi]                              ; Ipv4 source address
168
        je      @f
169
        test    eax, eax
170
        jnz     .socket_loop
171
       @@:
172
 
173
        mov     ax, [ebx + TCP_SOCKET.RemotePort]
174
        cmp     [edx + TCP_header.SourcePort], ax
175
        je      .found_socket
176
        test    ax, ax
177
        jnz     .socket_loop
178
  .found_socket:                                        ; ebx now contains the socketpointer
179
        DEBUGF  1,"TCP_input: socket ptr=%x state=%u flags=%x\n", ebx, [ebx + TCP_SOCKET.t_state], [edx + TCP_header.Flags]:2
180
 
181
;-------------
182
; update stats
183
 
184
        inc     [TCP_segments_rx]                       ; FIXME: correct interface?
185
 
186
;----------------------------
187
; Check if socket isnt closed
188
 
189
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_CLOSED
190
        je      .drop_no_socket
191
 
192
;----------------
193
; Lock the socket
194
 
195
        pusha
196
        lea     ecx, [ebx + SOCKET.mutex]
197
        call    mutex_lock
198
        popa
199
 
200
        DEBUGF  1,"TCP_input: socket locked\n"
201
 
202
;---------------------------
203
; disable all temporary bits
204
 
205
        mov     [ebx + TCP_SOCKET.temp_bits], 0
206
 
207
;---------------------------------------
208
; unscale the window into a 32 bit value
209
 
210
        movzx   eax, [edx + TCP_header.Window]
211
        push    ecx
212
        mov     cl, [ebx + TCP_SOCKET.SND_SCALE]
213
        shl     eax, cl
214
        mov     dword [edx + TCP_header.Window], eax    ; word after window is checksum, we dont need checksum anymore
215
        pop     ecx
216
 
217
;---------------------------------------
218
; Are we accepting incoming connections?
219
 
220
        test    [ebx + SOCKET.options], SO_ACCEPTCON
221
        jz      .no_accept
222
 
223
        DEBUGF  1,"TCP_input: Accepting new connection\n"
224
 
225
        pusha
226
        lea     ecx, [ebx + SOCKET.mutex]
227
        call    mutex_unlock
228
        popa
229
 
230
        push    ecx edx esi edi         ;;;
231
        call    SOCKET_fork
232
        pop     edi esi edx ecx
233
 
234
        test    eax, eax
235
        jz      .drop_no_socket
236
 
237
        mov     ebx, eax
238
 
239
        mov     [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET        ;;; FIXME: should we take over bits from previous socket?
240
 
241
        push    dword [edi + 4]                         ; Ipv4 destination addres
242
        pop     [ebx + IP_SOCKET.LocalIP]
243
 
244
        push    [edx + TCP_header.DestinationPort]
245
        pop     [ebx + TCP_SOCKET.LocalPort]
246
 
247
        mov     [ebx + TCP_SOCKET.t_state], TCPS_LISTEN
248
  .no_accept:
249
 
250
 
251
;-------------------------------------
252
; Reset idle timer and keepalive timer
253
 
254
        mov     [ebx + TCP_SOCKET.t_idle], 0
255
        mov     [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_idle
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
 
266
        DEBUGF  1,"TCP_input: Segment has options\n"
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
293
        DEBUGF  1,"TCP_input: unknown option:%u\n", al
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
306
        DEBUGF  1,"TCP_input: Maxseg=%u\n", ax
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
 
320
        DEBUGF  1,"TCP_input: Got window scale option\n"
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
 
339
        DEBUGF  1,"TCP_input: Selective Acknowledgement permitted\n"
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
 
351
        DEBUGF  1,"TCP_input: Got timestamp option\n"
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
 
375
        DEBUGF  1,"TCP_input: PAWS: detected an old segment\n"
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
 
453
        DEBUGF  1,"TCP_input: Header prediction: we are sender\n"
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
491
        mov     [ebx + TCP_SOCKET.timer_retransmission], 0
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
 
527
        DEBUGF  1,"TCP_input: Header prediction: we are receiving %u bytes\n", ecx
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
 
548
        DEBUGF  1,"TCP_input: Header prediction failed\n"
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
       @@:
561
        DEBUGF  1,"Receive window size=%d\n", eax
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
 
582
        DEBUGF  1,"TCP_input: %u bytes duplicate data!\n", eax
583
 
584
        test    [edx + TCP_header.Flags], TH_SYN
585
        jz      .no_dup_syn
586
 
587
        DEBUGF  1,"TCP_input: got duplicate syn\n"
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
616
        DEBUGF  1, "616\n"
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
 
661
        DEBUGF  1,"%d bytes beyond right edge of window\n", eax
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
 
690
        DEBUGF  1, "690\n"
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
 
718
        DEBUGF  1,"Recording timestamp\n"
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
 
732
        DEBUGF  1,"TCP_input: Got an RST flag\n"
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:
752
        DEBUGF  1,"TCP_input: Connection refused\n"
753
 
754
        mov     [ebx + SOCKET.errorcode], ECONNREFUSED
755
        jmp     .close
756
 
757
  .econnreset:
758
        DEBUGF  1,"TCP_input: Connection reset\n"
759
 
760
        mov     [ebx + SOCKET.errorcode], ECONNRESET
761
 
762
  .close:
763
        DEBUGF  1,"TCP_input: Closing connection\n"
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:
772
        DEBUGF  1,"TCP_input: Closing with reset\n"
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
 
802
        DEBUGF  1,"TCP_input: state=syn_received\n"
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
 
849
        DEBUGF  1,"TCP_input: Processing duplicate ACK\n"
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
 
855
        cmp     [ebx + TCP_SOCKET.timer_retransmission], 0 ;;;;  FIXME
856
        jg      @f
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
 
889
        mov     [ebx + TCP_SOCKET.timer_retransmission], 0      ; turn off retransmission timer
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
 
930
        DEBUGF  1,"TCP_input: Increasing congestion window\n"
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
 
983
        DEBUGF  1,"TCP_input: acceptable ACK for %u bytes\n", edi
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
1020
        mov     [ebx + TCP_SOCKET.timer_retransmission], 0
1021
        or      [ebx + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT
1022
        jmp     .no_restart
1023
  .more_data:
1024
        cmp     [ebx + TCP_SOCKET.timer_persist], 0
1025
        jne     .no_restart
1026
 
1027
        mov     eax, [ebx + TCP_SOCKET.t_rxtcur]
1028
        mov     [ebx + TCP_SOCKET.timer_retransmission], eax
1029
 
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
 
1076
        DEBUGF  1,"TCP_input: our FIN is acked\n"
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
 
1091
        DEBUGF  1,"TCP_input: our FIN is not acked\n"
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
1143
       @@:
1144
        mov     [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_2
1145
        jmp     .ack_processed
1146
 
1147
  .ack_c:
1148
        jnc     .ack_processed
1149
 
1150
        mov     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1151
        mov     eax, ebx
1152
        call    TCP_cancel_timers
1153
        mov     [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
1154
        mov     eax, ebx
1155
        call    SOCKET_is_disconnected
1156
        jmp     .ack_processed
1157
 
1158
  .ack_la:
1159
        jnc     .ack_processed
1160
 
1161
        mov     eax, ebx
1162
        call    TCP_disconnect
1163
        jmp     .drop
1164
 
1165
  .ack_tw:
1166
        mov     [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
1167
        jmp     .drop_after_ack
1168
 
1169
  .reset_dupacks:               ; We got a new ACK, reset duplicate ACK counter
1170
        mov     [ebx + TCP_SOCKET.t_dupacks], 0
1171
        jmp     .ack_processed
1172
 
1173
;-------
1174
; LISTEN
1175
 
1176
align 4
1177
  .LISTEN:
1178
 
1179
        DEBUGF  1,"TCP_input: state=listen\n"
1180
 
1181
        test    [edx + TCP_header.Flags], TH_RST
1182
        jnz     .drop
1183
 
1184
        test    [edx + TCP_header.Flags], TH_ACK
1185
        jnz     .drop_with_reset
1186
 
1187
        test    [edx + TCP_header.Flags], TH_SYN
1188
        jz      .drop
1189
 
1190
;;; TODO: check if it's a broadcast or multicast, and drop if so
1191
 
1192
        push    dword [edi]                             ; Ipv4 source addres
1193
        pop     [ebx + IP_SOCKET.RemoteIP]
1194
 
1195
        push    [edx + TCP_header.SourcePort]
1196
        pop     [ebx + TCP_SOCKET.RemotePort]
1197
 
1198
        push    [edx + TCP_header.SequenceNumber]
1199
        pop     [ebx + TCP_SOCKET.IRS]
1200
 
1201
        mov     eax, [TCP_sequence_num]
1202
        add     [TCP_sequence_num], 64000 / 2
1203
        mov     [ebx + TCP_SOCKET.ISS], eax
1204
        mov     [ebx + TCP_SOCKET.SND_NXT], eax
1205
 
1206
        TCP_sendseqinit ebx
1207
        TCP_rcvseqinit ebx
1208
 
1209
        mov     [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
1210
        mov     [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1211
        mov     [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval  ;;;; macro
1212
 
1213
        lea     eax, [ebx + STREAM_SOCKET.snd]
1214
        call    SOCKET_ring_create
1215
 
1216
        lea     eax, [ebx + STREAM_SOCKET.rcv]
1217
        call    SOCKET_ring_create
1218
 
1219
        and     [ebx + TCP_SOCKET.temp_bits], not TCP_BIT_DROPSOCKET
1220
 
1221
;;;        call    SOCKET_notify_owner
1222
 
1223
        jmp     .trim_then_step6
1224
 
1225
;------------
1226
; Active Open
1227
 
1228
align 4
1229
  .SYN_SENT:
1230
 
1231
        DEBUGF  1,"TCP_input: state=syn_sent\n"
1232
 
1233
        test    [edx + TCP_header.Flags], TH_ACK
1234
        jz      @f
1235
 
1236
        mov     eax, [edx + TCP_header.AckNumber]
1237
        cmp     eax, [ebx + TCP_SOCKET.ISS]
1238
        jbe     .drop_with_reset
1239
 
1240
        cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
1241
        ja      .drop_with_reset
1242
       @@:
1243
 
1244
        test    [edx + TCP_header.Flags], TH_RST
1245
        jz      @f
1246
 
1247
        test    [edx + TCP_header.Flags], TH_ACK
1248
        jz      .drop
1249
 
1250
        mov     eax, ebx
1251
        mov     ebx, ECONNREFUSED
1252
        call    TCP_drop
1253
 
1254
        jmp     .drop
1255
       @@:
1256
 
1257
        test    [edx + TCP_header.Flags], TH_SYN
1258
        jz      .drop
1259
 
1260
; at this point, segment seems to be valid
1261
 
1262
        test    [edx + TCP_header.Flags], TH_ACK
1263
        jz      .no_syn_ack
1264
 
1265
; now, process received SYN in response to an active open
1266
 
1267
        mov     eax, [edx + TCP_header.AckNumber]
1268
        mov     [ebx + TCP_SOCKET.SND_UNA], eax
1269
        cmp     eax, [ebx + TCP_SOCKET.SND_NXT]
1270
        jbe     @f
1271
        mov     [ebx + TCP_SOCKET.SND_NXT], eax
1272
       @@:
1273
 
1274
  .no_syn_ack:
1275
        mov     [ebx + TCP_SOCKET.timer_retransmission], 0      ; disable retransmission
1276
 
1277
        push    [edx + TCP_header.SequenceNumber]
1278
        pop     [ebx + TCP_SOCKET.IRS]
1279
 
1280
        TCP_rcvseqinit ebx
1281
 
1282
        or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1283
 
1284
        mov     eax, [ebx + TCP_SOCKET.SND_UNA]
1285
        cmp     eax, [ebx + TCP_SOCKET.ISS]
1286
        jbe     .simultaneous_open
1287
 
1288
        test    [edx + TCP_header.Flags], TH_ACK
1289
        jz      .simultaneous_open
1290
 
1291
        DEBUGF  1,"TCP_input: active open\n"
1292
 
1293
;;; TODO: update stats
1294
 
1295
; set socket state to connected
1296
        mov     [ebx + SOCKET.state], SS_ISCONNECTED
1297
        mov     [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
1298
 
1299
; Do window scaling on this connection ?
1300
        mov     eax, [ebx + TCP_SOCKET.t_flags]
1301
        and     eax, TF_REQ_SCALE or TF_RCVD_SCALE
1302
        cmp     eax, TF_REQ_SCALE or TF_RCVD_SCALE
1303
        jne     .no_scaling
1304
 
1305
        mov     ax, word [ebx + TCP_SOCKET.requested_s_scale]
1306
        mov     word [ebx + TCP_SOCKET.SND_SCALE], ax
1307
  .no_scaling:
1308
 
1309
;;; TODO: reassemble packets queue
1310
 
1311
        mov     eax, [ebx + TCP_SOCKET.t_rtt]
1312
        test    eax, eax
1313
        je      .trim_then_step6
1314
        call    TCP_xmit_timer
1315
        jmp     .trim_then_step6
1316
 
1317
  .simultaneous_open:
1318
 
1319
        DEBUGF  1,"TCP_input: simultaneous open\n"
1320
; We have received a syn but no ACK, so we are having a simultaneous open..
1321
        mov     [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
1322
 
1323
;-------------------------------------
1324
; Common processing for receipt of SYN
1325
 
1326
  .trim_then_step6:
1327
 
1328
        inc     [edx + TCP_header.SequenceNumber]
1329
 
1330
;;; TODO: Drop any received data that follows receive window (590)
1331
 
1332
        mov     eax, [edx + TCP_header.SequenceNumber]
1333
        mov     [ebx + TCP_SOCKET.RCV_UP], eax
1334
        dec     eax
1335
        mov     [ebx + TCP_SOCKET.SND_WL1], eax
1336
 
1337
;-------
1338
; step 6
1339
 
1340
  .ack_processed:
1341
 
1342
        DEBUGF  1,"TCP_input: ACK processed\n"
1343
 
1344
;----------------------------------------------
1345
; check if we need to update window information
1346
 
1347
        test    [edx + TCP_header.Flags], TH_ACK
1348
        jz      .no_window_update
1349
 
1350
        mov     eax, [ebx + TCP_SOCKET.SND_WL1]
1351
        cmp     eax, [edx + TCP_header.SequenceNumber]
1352
        jb      .update_window
1353
        ja      @f
1354
 
1355
        mov     eax, [ebx + TCP_SOCKET.SND_WL2]
1356
        cmp     eax, [edx + TCP_header.AckNumber]
1357
        jb      .update_window
1358
        ja      .no_window_update
1359
       @@:
1360
 
1361
        mov     eax, dword [edx + TCP_header.Window]
1362
        cmp     eax, [ebx + TCP_SOCKET.SND_WND]
1363
        jbe     .no_window_update
1364
 
1365
  .update_window:
1366
 
1367
;;; TODO: update stats (Keep track of pure window updates)
1368
 
1369
        mov     eax, dword [edx + TCP_header.Window]
1370
        cmp     eax, [ebx + TCP_SOCKET.max_sndwnd]
1371
        jbe     @f
1372
        mov     [ebx + TCP_SOCKET.max_sndwnd], eax
1373
       @@:
1374
        mov     [ebx + TCP_SOCKET.SND_WND], eax
1375
 
1376
        DEBUGF  1,"TCP_input: Updating window to %u\n", eax
1377
 
1378
        push    [edx + TCP_header.SequenceNumber]
1379
        pop     [ebx + TCP_SOCKET.SND_WL1]
1380
 
1381
        push    [edx + TCP_header.AckNumber]
1382
        pop     [ebx + TCP_SOCKET.SND_WL2]
1383
 
1384
        or      [ebx + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT
1385
 
1386
  .no_window_update:
1387
 
1388
;-----------------
1389
; process URG flag
1390
 
1391
        test    [edx + TCP_header.Flags], TH_URG
1392
        jz      .not_urgent
1393
 
1394
        cmp     [edx + TCP_header.UrgentPointer], 0
1395
        jz      .not_urgent
1396
 
1397
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1398
        je      .not_urgent
1399
 
1400
; Ignore bogus urgent offsets
1401
 
1402
        movzx   eax, [edx + TCP_header.UrgentPointer]
1403
        add     eax, [ebx + STREAM_SOCKET.rcv.size]
1404
        cmp     eax, SOCKET_MAXDATA
1405
        jbe     .not_urgent
1406
 
1407
        mov     [edx + TCP_header.UrgentPointer], 0
1408
        and     [edx + TCP_header.Flags], not (TH_URG)
1409
        jmp     .do_data
1410
 
1411
  .not_urgent:
1412
 
1413
; processing of received urgent pointer
1414
 
1415
        ;;; TODO (1051-1093)
1416
 
1417
 
1418
;---------------------------------------
1419
; process the data in the segment (1094)
1420
 
1421
  .do_data:
1422
 
1423
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1424
        jae     .final_processing
1425
 
1426
        test    [edx + TCP_header.Flags], TH_FIN
1427
        jnz     @f
1428
 
1429
        test    ecx, ecx
1430
        jnz     .final_processing
1431
       @@:
1432
 
1433
 
1434
; The segment is in order?
1435
        mov     eax, [edx + TCP_header.SequenceNumber]
1436
        cmp     eax, [ebx + TCP_SOCKET.RCV_NXT]
1437
        jne     .out_of_order
1438
 
1439
; The reassembly queue is empty?
1440
        cmp     [ebx + TCP_SOCKET.seg_next], 0
1441
        jne     .out_of_order
1442
 
1443
; The connection is established?
1444
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
1445
        jne     .out_of_order
1446
 
1447
; Ok, lets do this..  Set delayed ACK flag and copy data into socket buffer
1448
        or      [ebx + TCP_SOCKET.t_flags], TF_DELACK
1449
 
1450
        pusha
1451
        movzx   esi, [edx + TCP_header.DataOffset]
1452
        add     esi, edx
1453
        lea     eax, [ebx + STREAM_SOCKET.rcv]
1454
        call    SOCKET_ring_write                       ; Add the data to the socket buffer
1455
        add     [ebx + TCP_SOCKET.RCV_NXT], ecx         ; Update sequence number with number of bytes we have copied
1456
        popa
1457
 
1458
; Wake up the sleeping process
1459
        mov     eax, ebx
1460
        call    SOCKET_notify
1461
 
1462
        jmp     .data_done
1463
 
1464
  .out_of_order:
1465
 
1466
; Uh-oh, some data is out of order, lets call TCP reassemble for help
1467
 
1468
        call    TCP_reassemble
1469
 
1470
        DEBUGF  1, "1470\n"
1471
        or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1472
 
1473
  .data_done:
1474
 
1475
;---------------
1476
; FIN processing
1477
 
1478
        test    [edx + TCP_header.Flags], TH_FIN
1479
        jz      .final_processing
1480
 
1481
        DEBUGF  1,"TCP_input: Processing FIN\n"
1482
 
1483
        cmp     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1484
        jae     .not_first_fin
1485
 
1486
        DEBUGF  1,"TCP_input: First FIN for this connection\n"
1487
 
1488
        mov     eax, ebx
1489
        call    SOCKET_cant_recv_more
1490
 
1491
        mov     [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
1492
        inc     [ebx + TCP_SOCKET.RCV_NXT]
1493
 
1494
  .not_first_fin:
1495
        mov     eax, [ebx + TCP_SOCKET.t_state]
1496
        shl     eax, 2
1497
        jmp     dword [eax + .FIN_sw_list]
1498
 
1499
  .FIN_sw_list:
1500
        dd      .final_processing       ; TCPS_CLOSED
1501
        dd      .final_processing       ; TCPS_LISTEN
1502
        dd      .final_processing       ; TCPS_SYN_SENT
1503
        dd      .fin_syn_est            ; TCPS_SYN_RECEIVED
1504
        dd      .fin_syn_est            ; TCPS_ESTABLISHED
1505
        dd      .final_processing       ; TCPS_CLOSE_WAIT
1506
        dd      .fin_wait1              ; TCPS_FIN_WAIT_1
1507
        dd      .final_processing       ; TCPS_CLOSING
1508
        dd      .final_processing       ; TCPS_LAST_ACK
1509
        dd      .fin_wait2              ; TCPS_FIN_WAIT_2
1510
        dd      .fin_timed              ; TCPS_TIMED_WAIT
1511
 
1512
  .fin_syn_est:
1513
 
1514
        mov     [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
1515
        jmp     .final_processing
1516
 
1517
  .fin_wait1:
1518
 
1519
        mov     [ebx + TCP_SOCKET.t_state], TCPS_CLOSING
1520
        jmp     .final_processing
1521
 
1522
  .fin_wait2:
1523
 
1524
        mov     [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
1525
        mov     eax, ebx
1526
        call    TCP_cancel_timers
1527
        mov     [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
1528
        call    SOCKET_is_disconnected
1529
        jmp     .final_processing
1530
 
1531
  .fin_timed:
1532
        mov     [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
1533
        jmp     .final_processing
1534
 
1535
 
1536
  .drop_after_ack:
1537
        DEBUGF  1,"TCP_input: Drop after ACK\n"
1538
 
1539
        push    edx ebx
1540
        lea     ecx, [ebx + SOCKET.mutex]
1541
        call    mutex_unlock
1542
        pop     eax edx
1543
 
1544
        test    [edx + TCP_header.Flags], TH_RST
1545
        jnz     .dumpit
1546
 
1547
        or      [eax + TCP_SOCKET.t_flags], TF_ACKNOW
1548
        jmp     .need_output
1549
 
1550
  .drop_with_reset:
1551
        DEBUGF  1,"TCP_input: Drop with reset\n"
1552
 
1553
        push    ebx edx
1554
        lea     ecx, [ebx + SOCKET.mutex]
1555
        call    mutex_unlock
1556
        pop     edx ebx
1557
 
1558
        test    [edx + TCP_header.Flags], TH_RST
1559
        jnz     .dumpit
1560
 
1561
        ;;; if its a multicast/broadcast, also drop
1562
 
1563
        test    [edx + TCP_header.Flags], TH_ACK
1564
        jnz     .respond_ack
1565
 
1566
        test    [edx + TCP_header.Flags], TH_SYN
1567
        jnz     .respond_syn
1568
        jmp     .dumpit
1569
 
1570
;-----------------
1571
; Final processing
1572
 
1573
  .final_processing:
1574
        DEBUGF  1,"TCP_input: Final processing\n"
1575
 
1576
        push    ebx
1577
        lea     ecx, [ebx + SOCKET.mutex]
1578
        call    mutex_unlock
1579
        pop     eax
1580
 
1581
        test    [eax + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT
1582
        jnz     .need_output
1583
 
1584
        test    [eax + TCP_SOCKET.t_flags], TF_ACKNOW
1585
        jz      .dumpit
1586
        DEBUGF  1,"TCP_input: ACK now!\n"
1587
 
1588
  .need_output:
1589
        DEBUGF  1,"TCP_input: need output\n"
1590
        call    TCP_output
1591
 
1592
  .dumpit:
1593
        DEBUGF  1,"TCP_input: dumping\n"
1594
 
1595
        call    kernel_free
1596
        add     esp, 4
1597
        jmp     .loop
1598
 
1599
;---------
1600
; Respond
1601
 
1602
  .respond_ack:
1603
        push    ebx
1604
        mov     cl, TH_RST
1605
        call    TCP_respond
1606
        pop     ebx
1607
        jmp     .destroy_new_socket
1608
 
1609
  .respond_syn:
1610
        push    ebx
1611
        mov     cl, TH_RST + TH_ACK
1612
        call    TCP_respond
1613
        pop     ebx
1614
        jmp     .destroy_new_socket
1615
 
1616
  .respond_seg_reset:
1617
        test    [edx + TCP_header.Flags], TH_RST
1618
        jnz     .drop_no_socket
1619
 
1620
        ;;; TODO: if its a multicast/broadcast, also drop
1621
 
1622
        test    [edx + TCP_header.Flags], TH_ACK
1623
        jnz     .respond_seg_ack
1624
 
1625
        test    [edx + TCP_header.Flags], TH_SYN
1626
        jnz     .respond_seg_syn
1627
 
1628
        jmp     .drop_no_socket
1629
 
1630
  .respond_seg_ack:
1631
        mov     cl, TH_RST
1632
        call    TCP_respond_segment
1633
        jmp     .drop_no_socket
1634
 
1635
  .respond_seg_syn:
1636
        mov     cl, TH_RST + TH_ACK
1637
        call    TCP_respond_segment
1638
        jmp     .drop_no_socket
1639
 
1640
;-----
1641
; Drop
1642
 
1643
  .drop:
1644
        DEBUGF  1,"TCP_input: Dropping segment\n"
1645
 
1646
        pusha
1647
        lea     ecx, [ebx + SOCKET.mutex]
1648
        call    mutex_unlock
1649
        popa
1650
 
1651
  .destroy_new_socket:
1652
        test    [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET
1653
        jz      .drop_no_socket
1654
 
1655
        mov     eax, ebx
1656
        call    SOCKET_free
1657
 
1658
  .drop_no_socket:
1659
        DEBUGF  1,"TCP_input: Drop (no socket)\n"
1660
 
1661
        call    kernel_free
1662
        add     esp, 4
1663
        jmp     .loop