Subversion Repositories Kolibri OS

Rev

Rev 1519 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2010. All rights reserved.    ;;
  4. ;; Distributed under terms of the GNU General Public License       ;;
  5. ;;                                                                 ;;
  6. ;;  TCP.INC                                                        ;;
  7. ;;                                                                 ;;
  8. ;;  Part of the tcp/ip network stack for KolibriOS                 ;;
  9. ;;                                                                 ;;
  10. ;;   Written by hidnplayr@kolibrios.org                            ;;
  11. ;;                                                                 ;;
  12. ;;    Based on the code of 4.4BSD                                  ;;
  13. ;;                                                                 ;;
  14. ;;          GNU GENERAL PUBLIC LICENSE                             ;;
  15. ;;             Version 2, June 1991                                ;;
  16. ;;                                                                 ;;
  17. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  18.  
  19. $Revision: 1529 $
  20.  
  21. ; Socket states
  22. TCB_CLOSED              equ 0
  23. TCB_LISTEN              equ 1
  24. TCB_SYN_SENT            equ 2
  25. TCB_SYN_RECEIVED        equ 3
  26. TCB_ESTABLISHED         equ 4
  27. TCB_CLOSE_WAIT          equ 5
  28. TCB_FIN_WAIT_1          equ 6
  29. TCB_CLOSING             equ 7
  30. TCB_LAST_ACK            equ 8
  31. TCB_FIN_WAIT_2          equ 9
  32. TCB_TIMED_WAIT          equ 10
  33.  
  34. ; Socket Flags
  35. TF_ACKNOW               equ 1 shl 0     ; ack peer immediately
  36. TF_DELACK               equ 1 shl 1     ; ack, but try to delay it
  37. TF_NODELAY              equ 1 shl 2     ; don't delay packets to coalesce
  38. TF_NOOPT                equ 1 shl 3     ; don't use tcp options
  39. TF_SENTFIN              equ 1 shl 4     ; have sent FIN
  40. TF_REQ_SCALE            equ 1 shl 5     ; have/will request window scaling
  41. TF_RCVD_SCALE           equ 1 shl 6     ; other side has requested scaling
  42. TF_REQ_TSTMP            equ 1 shl 7     ; have/will request timestamps
  43. TF_RCVD_TSTMP           equ 1 shl 8     ; a timestamp was received in SYN
  44. TF_SACK_PERMIT          equ 1 shl 9     ; other side said I could SACK
  45.  
  46. ; Segment flags
  47. TH_FIN                  equ 1 shl 0
  48. TH_SYN                  equ 1 shl 1
  49. TH_RST                  equ 1 shl 2
  50. TH_PUSH                 equ 1 shl 3
  51. TH_ACK                  equ 1 shl 4
  52. TH_URG                  equ 1 shl 5
  53.  
  54. ; Segment header options
  55. TCP_OPT_EOL             equ 0           ; End of option list.
  56. TCP_OPT_NOP             equ 1           ; No-Operation.
  57. TCP_OPT_MAXSEG          equ 2           ; Maximum Segment Size.
  58. TCP_OPT_WINDOW          equ 3           ; window scale
  59. TCP_OPT_TIMESTAMP       equ 8
  60.  
  61. ; Fundamental timer values
  62. TCP_time_MSL            equ 47          ; max segment lifetime (30s)
  63. TCP_time_re_min         equ 2           ; min retransmission (1,28s)
  64. TCP_time_re_max         equ 100         ; max retransmission (64s)
  65. TCP_time_pers_min       equ 8           ; min persist (5,12s)
  66. TCP_time_pers_max       equ 94          ; max persist (60,16s)
  67. TCP_time_keep_init      equ 118         ; connectione stablishment (75,52s)
  68. TCP_time_keep_idle      equ 4608        ; idle time before 1st probe (2h)
  69. TCP_time_keep_interval  equ 118         ; between probes when no response (75,52s)
  70. TCP_time_rtt_default    equ 5           ; default Round Trip Time (3,2s)
  71.  
  72. ; timer constants
  73. TCP_max_rxtshift        equ 12          ; max retransmissions waiting for ACK
  74. TCP_max_keepcnt         equ 8           ; max keepalive probes
  75.  
  76. ;
  77. TCP_max_winshift        equ 14
  78. TCP_max_win             equ 65535
  79.  
  80. struct  TCP_segment
  81.         .SourcePort             dw ?
  82.         .DestinationPort        dw ?
  83.         .SequenceNumber         dd ?
  84.         .AckNumber              dd ?
  85.         .DataOffset             db ?    ; DataOffset[0-3 bits] and Reserved[4-7]
  86.         .Flags                  db ?    ; Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN
  87.         .Window                 dw ?
  88.         .Checksum               dw ?
  89.         .UrgentPointer          dw ?
  90.         .Data:                          ; ..or options
  91. ends
  92.  
  93. struct  tcp_in_queue_entry
  94.         .data_ptr       dd ?
  95.         .data_size      dd ?
  96.         .offset         dd ?
  97.         .size:
  98. ends
  99.  
  100. struct  tcp_out_queue_entry
  101.         .data_ptr       dd ?
  102.         .data_size      dd ?
  103.  
  104.         .size:
  105. ends
  106.  
  107. align 4
  108. uglobal
  109.         TCP_segments_tx         rd IP_MAX_INTERFACES
  110.         TCP_segments_rx         rd IP_MAX_INTERFACES
  111.         TCP_bytes_rx            rq IP_MAX_INTERFACES
  112.         TCP_bytes_tx            rq IP_MAX_INTERFACES
  113.         TCP_sequence_num        dd ?
  114. endg
  115.  
  116.  
  117. ;-----------------------------------------------------------------
  118. ;
  119. ; TCP_init
  120. ;
  121. ;  This function resets all TCP variables
  122. ;
  123. ;-----------------------------------------------------------------
  124. macro   TCP_init {
  125.  
  126.         xor     eax, eax
  127.         mov     edi, TCP_segments_tx
  128.         mov     ecx, (6*IP_MAX_INTERFACES)
  129.         rep     stosd
  130.  
  131.         pseudo_random   eax
  132.         mov     [TCP_sequence_num], eax
  133.  
  134. }
  135.  
  136.  
  137. ;----------------------
  138. ;
  139. ;
  140. ;----------------------
  141. macro   TCP_timer_160ms {
  142.  
  143. local   .loop
  144. local   .exit
  145.  
  146.         mov     eax, net_sockets
  147.   .loop:
  148.         mov     eax, [eax + SOCKET.NextPtr]
  149.         or      eax, eax
  150.         jz      .exit
  151.  
  152.         cmp     [eax + SOCKET.Type], IP_PROTO_TCP
  153.         jne     .loop
  154.  
  155.         dec     [eax + TCP_SOCKET.timer_ack]
  156.         jnz     .loop
  157.  
  158.         DEBUGF  1,"TCP ack for socket %x expired, time to piggyback!\n", eax
  159.  
  160.         push    eax
  161.         call    TCP_respond_socket
  162.         pop     eax
  163.  
  164.         jmp     .loop
  165.  
  166.   .exit:
  167.  
  168. }
  169.  
  170.  
  171. ;-----------------------------------------------------------------
  172. ;
  173. ;
  174. ;-----------------------------------------------------------------
  175. macro   TCP_timer_640ms {
  176.  
  177. local   .loop
  178. local   .exit
  179.  
  180. ; Update TCP sequence number
  181.  
  182.         add     [TCP_sequence_num], 64000
  183.  
  184. ; scan through all the active TCP sockets, decrementing ALL timers
  185. ; timers do not have the chance to wrap because of the keepalive timer will kill the socket when it expires
  186.  
  187.         mov     eax, net_sockets
  188.   .loop:
  189.         mov     eax, [eax + SOCKET.NextPtr]
  190.   .check_only:
  191.         or      eax, eax
  192.         jz      .exit
  193.  
  194.         cmp     [eax + SOCKET.Type], IP_PROTO_TCP
  195.         jne     .loop
  196.  
  197.         inc     [eax + TCP_SOCKET.t_idle]
  198.         dec     [eax + TCP_SOCKET.timer_retransmission]
  199.         jnz     .check_more2
  200.  
  201.         DEBUGF  1,"socket %x: Retransmission timer expired\n", eax
  202.  
  203.         push    eax
  204.         call    TCP_output
  205.         pop     eax
  206.  
  207.   .check_more2:
  208.         dec     [eax + TCP_SOCKET.timer_keepalive]
  209.         jnz     .check_more3
  210.  
  211.         DEBUGF  1,"socket %x: Keepalive expired\n", eax
  212.  
  213.         ;;; TODO: check socket state and handle accordingly
  214.  
  215.   .check_more3:
  216.         dec     [eax + TCP_SOCKET.timer_timed_wait]
  217.         jnz     .check_more5
  218.  
  219.         DEBUGF  1,"socket %x: 2MSL timer expired\n", eax
  220.  
  221.   .check_more5:
  222.         dec     [eax + TCP_SOCKET.timer_persist]
  223.         jnz     .loop
  224.  
  225.         DEBUGF  1,"socket %x: persist timer expired\n", eax
  226.  
  227.         jmp     .loop
  228.   .exit:
  229. }
  230.  
  231.  
  232.  
  233.  
  234. macro   TCP_checksum IP1, IP2 {
  235.  
  236. ;-------------
  237. ; Pseudoheader
  238.  
  239.         ; protocol type
  240.         mov     edx, IP_PROTO_TCP
  241.  
  242.         ; source address
  243.         add     dl, byte [IP1+1+4]
  244.         adc     dh, byte [IP1+0+4]
  245.         adc     dl, byte [IP1+3+4]
  246.         adc     dh, byte [IP1+2+4]
  247.  
  248.         ; destination address
  249.         adc     dl, byte [IP2+1+8]
  250.         adc     dh, byte [IP2+0+8]
  251.         adc     dl, byte [IP2+3+8]
  252.         adc     dh, byte [IP2+2+8]
  253.  
  254.         ; size
  255.         adc     dl, cl
  256.         adc     dh, ch
  257.  
  258. ;---------------------
  259. ; Real header and data
  260.  
  261.         push    esi
  262.         call    checksum_1
  263.         call    checksum_2
  264.         pop     esi
  265.  
  266. }       ; returns in dx only
  267.  
  268.  
  269.  
  270. ;-----------------------------------------------------------------
  271. ;
  272. ; TCP_input:
  273. ;
  274. ;  IN:  [esp] = ptr to buffer
  275. ;       [esp+4] = buffer size
  276. ;       ebx = ptr to device struct
  277. ;       ecx = segment size
  278. ;       edx = ptr to TCP segment
  279. ;
  280. ;       esi = ipv4 source address
  281. ;       edi = ipv4 dest   address
  282. ;
  283. ;  OUT: /
  284. ;
  285. ;-----------------------------------------------------------------
  286. align 4
  287. TCP_input:
  288.  
  289.        DEBUGF  1,"TCP_input size=%u\n", ecx
  290. ; Offset must be greater than or equal to the size of the standard TCP header (20) and less than or equal to the TCP length.
  291.  
  292.         movzx   eax, [edx + TCP_segment.DataOffset]
  293.         and     eax, 0xf0
  294.         shr     al, 2
  295.  
  296.         DEBUGF  1,"headersize=%u\n", eax
  297.  
  298.         cmp     eax, 20
  299.         jl      .drop
  300.  
  301. ;-------------------------------
  302. ; Now, re-calculate the checksum
  303.  
  304.         push    eax ecx edx
  305.         pushw   [edx + TCP_segment.Checksum]
  306.         mov     [edx + TCP_segment.Checksum], 0
  307.         push    esi edi
  308.         mov     esi, edx
  309.         TCP_checksum
  310.         pop     esi edi ; yes, swap them (we dont need dest addr)
  311.         pop     cx      ; previous checksum
  312.         cmp     cx, dx
  313.         pop     edx ecx esi
  314.         jnz     .drop
  315.  
  316.         DEBUGF  1,"Checksum is correct\n"
  317.  
  318.         sub     ecx, esi        ; update packet size
  319.         jl      .drop
  320.  
  321. ;-----------------------------------------------------------------------------------------
  322. ; Check if this packet has a timestamp option (We do it here so we can process it quickly)
  323.  
  324.         cmp     esi, 20 + 12                                    ; Timestamp option is 12 bytes
  325.         jl      .no_timestamp
  326.         je      .is_ok
  327.  
  328.         cmp     byte [edx + TCP_segment.Data + 12], TCP_OPT_EOL ; end of option list
  329.         jne     .no_timestamp
  330.  
  331.   .is_ok:
  332.         test    [edx + TCP_segment.Flags], TH_SYN               ; SYN flag must not be set
  333.         jnz     .no_timestamp
  334.  
  335.         cmp     dword [edx + TCP_segment.Data], 0x0101080a      ; Timestamp header
  336.         jne     .no_timestamp
  337.  
  338.         DEBUGF  1,"timestamp ok\n"
  339.  
  340.         ; TODO: Parse the option
  341.         ; TODO: Set a Bit in the TCP to tell all options are parsed
  342.  
  343.   .no_timestamp:
  344.  
  345. ;-------------------------------------------
  346. ; Convert Big-endian values to little endian
  347.  
  348.         ntohld  [edx + TCP_segment.SequenceNumber]
  349.         ntohld  [edx + TCP_segment.AckNumber]
  350.  
  351.         ntohlw  [edx + TCP_segment.Window]
  352.         ntohlw  [edx + TCP_segment.UrgentPointer]
  353.         ntohlw  [edx + TCP_segment.SourcePort]
  354.         ntohlw  [edx + TCP_segment.DestinationPort]
  355.  
  356. ;------------------------------------------------------------
  357. ; Next thing to do is find the TCB (thus, the socket pointer)
  358.  
  359. ; IP Packet TCP Destination Port = local Port
  360. ; (IP Packet SenderAddress = Remote IP)  OR  (Remote IP = 0)
  361. ; (IP Packet TCP Source Port = remote Port)  OR (remote Port = 0)
  362.  
  363.         mov     ebx, net_sockets
  364.  
  365.   .socket_loop:
  366.         mov     ebx, [ebx + SOCKET.NextPtr]
  367.         or      ebx, ebx
  368.         jz      .drop_with_reset
  369.  
  370.         cmp     [ebx + SOCKET.Type], IP_PROTO_TCP
  371.         jne     .socket_loop
  372.  
  373.         mov     ax, [edx + TCP_segment.DestinationPort]
  374.         cmp     [ebx + TCP_SOCKET.LocalPort], ax
  375.         jne     .socket_loop
  376.  
  377.         mov     eax, [ebx + IP_SOCKET.RemoteIP]
  378.         cmp     eax, edi                        ; sender IP
  379.         je      @f
  380.         test    eax, eax
  381.         jnz     .socket_loop
  382.        @@:
  383.  
  384.         mov     ax, [ebx + TCP_SOCKET.RemotePort]
  385.         cmp     [edx + TCP_segment.SourcePort] , ax
  386.         je      .found_socket
  387.         test    ax, ax
  388.         jnz     .socket_loop
  389.   .found_socket:
  390.         DEBUGF  1,"Socket ptr: %x\n", ebx
  391.  
  392. ; ebx now contains the pointer to the socket
  393.  
  394. ;----------------------------
  395. ; Check if socket isnt closed
  396.  
  397.         cmp     [ebx + TCP_SOCKET.t_state], TCB_CLOSED
  398.         je      .drop
  399.  
  400. ;----------------
  401. ; Lock the socket
  402.  
  403. ;;        add     ebx, SOCKET.lock ; TODO: figure out if we should lock now already
  404. ;;        call    wait_mutex
  405. ;;        sub     ebx, SOCKET.lock
  406.  
  407.         DEBUGF  1,"Socket locked\n"
  408.  
  409. ;----------------------------------------------------------------------------------------
  410. ; unscale the window into a 32 bit value (notice that SND_SCALE must be initialised to 0)
  411.  
  412.         movzx   eax, [edx + TCP_segment.Window]
  413.         push    cx
  414.         mov     cl, [ebx + TCP_SOCKET.SND_SCALE]
  415.         shl     eax, cl
  416.         pop     cx
  417.  
  418.         ;;;; do something with eax
  419.  
  420. ;-----------------------------------
  421. ; Is this socket a listening socket?
  422.  
  423. ;        test    [ebx + SOCKET.options], SO_ACCEPTCON
  424. ;        jnz     .listening_socket                       ;;;;; TODO
  425.  
  426. ;-------------------------------------
  427. ; Reset idle timer and keepalive timer
  428.  
  429.         mov     [ebx + TCP_SOCKET.t_idle], 0
  430.         mov     [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval
  431.  
  432. ;--------------------
  433. ; Process TCP options
  434.  
  435.         cmp     esi, 20                         ; esi is headersize
  436.         je      .no_options
  437.  
  438.         DEBUGF  1,"Segment has options\n"
  439.  
  440.         test    [ebx + TCP_SOCKET.t_state], TCB_LISTEN          ; no options when in listen state
  441.         jz      .no_options
  442.  
  443.         lea     edi, [edx + TCP_segment.Data]
  444.         lea     eax, [edx + esi]
  445.  
  446.   .opt_loop:
  447.         cmp     edi, eax
  448.         jge     .no_options
  449.  
  450.         cmp     byte [edi], TCP_OPT_EOL         ; end of option list?
  451.         jz      .no_options
  452.  
  453.         cmp     byte [edi], TCP_OPT_NOP         ; nop ?
  454.         jz      .opt_nop
  455.  
  456.         cmp     byte [edi], TCP_OPT_MAXSEG
  457.         je      .opt_maxseg
  458.  
  459.         cmp     byte [edi], TCP_OPT_WINDOW
  460.         je      .opt_window
  461.  
  462.         cmp     byte [edi], TCP_OPT_TIMESTAMP
  463.         je      .opt_timestamp
  464.  
  465.         jmp     .no_options     ; If we reach here, some unknown options were received, skip them all!
  466.  
  467.   .opt_nop:
  468.         inc     edi
  469.         jmp     .opt_loop
  470.  
  471.   .opt_maxseg:
  472.         cmp     byte [edi+1], 4
  473.         jne     .no_options             ; error occured, ignore all options!
  474.  
  475.         test    [edx + TCP_segment.Flags], TH_SYN
  476.         jz      @f
  477.  
  478.         DEBUGF  1,"Got maxseg option"
  479.  
  480.         ;;;;;
  481.        @@:
  482.         add     edi, 4
  483.         jmp     .opt_loop
  484.  
  485.  
  486.   .opt_window:
  487.         cmp     byte [edi+1], 3
  488.         jne     .no_options
  489.  
  490.         test    [edx + TCP_segment.Flags], TH_SYN
  491.         jz      @f
  492.  
  493.         DEBUGF  1,"Got window option"
  494.  
  495.         ;;;;;
  496.        @@:
  497.         add     edi, 3
  498.         jmp     .opt_loop
  499.  
  500.  
  501.   .opt_timestamp:
  502.         cmp     byte [edi+1], 10
  503.         jne     .no_options
  504.  
  505.         DEBUGF  1,"Got timestamp option"
  506.  
  507.         ;;;;;
  508.  
  509.         add     edi, 10
  510.         jmp     .opt_loop
  511.  
  512.   .no_options:
  513.  
  514. ;-----------------------------------------------------------------------
  515. ; Time to do some header prediction (Original Principle by Van Jacobson)
  516.  
  517. ; There are two common cases for an uni-directional data transfer.
  518. ;
  519. ; General rule: the packets has no control flags, is in-sequence,
  520. ;   window width didnt change and we're not retransmitting.
  521. ;
  522. ; Second rules:
  523. ;  -  If the length is 0 and the ACK moved forward, we're the sender side of the transfer.
  524. ;      In this case we'll free the ACK'ed data and notify higher levels that we have free space in buffer
  525. ;
  526. ;  -  If the length is not 0 and the ACK didn't move, we're the receiver side of the transfer.
  527. ;      If the packets are in order (data queue is empty), add the data to the socket buffer and request a delayed ACK
  528.  
  529.         cmp     [ebx + TCP_SOCKET.t_state], TCB_ESTABLISHED
  530.         jnz     .not_uni_xfer
  531.  
  532.         test    [edx + TCP_segment.Flags], TH_SYN + TH_FIN + TH_RST + TH_URG
  533.         jnz     .not_uni_xfer
  534.  
  535.         test    [edx + TCP_segment.Flags], TH_ACK
  536.         jz      .not_uni_xfer
  537.  
  538.         mov     eax, [edx + TCP_segment.SequenceNumber]
  539.         cmp     eax, [ebx + TCP_SOCKET.RCV_NXT]
  540.         jne     .not_uni_xfer
  541.  
  542.         movzx   eax, [edx + TCP_segment.Window] ;;;;; (should use pre-calculated value isntead: todo: figure out where to store it)
  543.         cmp     eax, [ebx + TCP_SOCKET.SND_WND]
  544.         jne     .not_uni_xfer
  545.  
  546.         mov     eax, [ebx + TCP_SOCKET.SND_NXT]
  547.         cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
  548.         jne     .not_uni_xfer
  549.  
  550. ;---------------------------------------
  551. ; check if we are sender in the uni-xfer
  552.  
  553. ; If the following 4 conditions are all true, this segment is a pure ACK.
  554. ;
  555. ; - The segment contains no data.
  556.         test    ecx, ecx
  557.         jnz     .not_sender
  558.  
  559. ; - The congestion window is greater than or equal to the current send window.
  560. ;     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.
  561.         mov     eax, [ebx + TCP_SOCKET.SND_CWND]
  562.         cmp     eax, [ebx + TCP_SOCKET.SND_WND]
  563.         jl      .not_uni_xfer
  564.  
  565. ; - The acknowledgment field in the segment is less than or equal to the maximum sequence number sent.
  566.         mov     ecx, [edx + TCP_segment.AckNumber]
  567.         cmp     ecx, [ebx + TCP_SOCKET.SND_MAX]
  568.         jg      .not_uni_xfer
  569.  
  570. ; - The acknowledgment field in the segment is greater than the largest unacknowledged sequence number.
  571.         sub     ecx, [ebx + TCP_SOCKET.SND_UNA]
  572.         jle     .not_uni_xfer
  573.  
  574.         DEBUGF  1,"Header prediction: we are sender\n"
  575.  
  576. ;---------------------------------
  577. ; Packet is a pure ACK, process it
  578.  
  579. ; Update RTT estimators
  580.  
  581. ; Delete acknowledged bytes from send buffer
  582. ; notice how ecx already holds number of bytes ack-ed
  583.  
  584.         lea     eax, [ebx + snd]
  585.         call    SOCKET_ring_free
  586.  
  587. ; Stop retransmit timer
  588.         mov     [ebx + TCP_SOCKET.timer_ack], 0
  589.  
  590. ; Awaken waiting processes
  591.         mov     eax, ebx
  592.         call    SOCKET_notify_owner
  593.  
  594. ; Generate more output
  595.         call    TCP_output
  596.  
  597.         jmp     .drop
  598.  
  599. ;-------------------------------------------------
  600. ; maybe we are the receiver in the uni-xfer then..
  601.  
  602.   .not_sender:
  603. ; - The amount of data in the segment is greater than 0 (data count is in ecx)
  604.  
  605. ; - The acknowledgment field equals the largest unacknowledged sequence number. This means no data is acknowledged by this segment.
  606.         mov     eax, [edx + TCP_segment.AckNumber]
  607.         cmp     eax, [ebx + TCP_SOCKET.SND_UNA]
  608.         jne     .not_uni_xfer
  609.  
  610. ; - The reassembly list of out-of-order segments for the connection is empty (seg_next equals tp). ;;;;;;;
  611.  
  612.         jnz     .not_uni_xfer
  613.  
  614. ;-------------------------------------
  615. ; Complete processing of received data
  616.  
  617.         DEBUGF  1,"header prediction: we are receiver\nreceiving %u bytes of data\n", ecx
  618.  
  619.         add     esi, edx
  620.         lea     eax, [ebx + rcv]
  621.         call    SOCKET_ring_add                         ; Add the data to the socket buffer
  622.  
  623.         add     [ebx + TCP_SOCKET.RCV_NXT], ecx         ; Update sequence number with number of bytes we have copied
  624.         or      [ebx + TCP_SOCKET.t_flags], TF_DELACK   ; Set delayed ack flag
  625.  
  626.         jmp     .drop
  627.  
  628. ;----------------------------------------------------
  629. ; Header prediction failed, doing it the slow way..     ;;;;; current implementation of header prediction destroys some regs (ecx) !!
  630.  
  631.   .not_uni_xfer:
  632.  
  633.         DEBUGF  1,"Header prediction failed\n"
  634.  
  635. ;------------------------------
  636. ; Calculate receive window size
  637.  
  638.         ;;;;
  639.  
  640. ;-------------------------
  641. ; TCP slow input procedure
  642.  
  643.         DEBUGF  1,"TCP slow input procedure\n"
  644.  
  645.         cmp     [ebx + TCP_SOCKET.t_state], TCB_LISTEN
  646.         je      .LISTEN
  647.  
  648.         cmp     [ebx + TCP_SOCKET.t_state], TCB_SYN_SENT
  649.         je      .SYN_SENT
  650.  
  651. ;--------------------------------------------
  652. ; Protection Against Wrapped Sequence Numbers
  653.  
  654. ; First, check timestamp if present
  655.  
  656. ;;;; TODO
  657.  
  658. ; Then, check if at least some bytes of data are within window
  659.  
  660. ;;;; TODO
  661.  
  662.         jmp     .trim_then_step6
  663.  
  664. ;-------------
  665. ; Passive Open
  666.  
  667. align 4
  668. .LISTEN:
  669.  
  670.         DEBUGF  1,"TCP state: listen\n"
  671.  
  672.         test    [edx + TCP_segment.Flags], TH_RST
  673.         jnz     .drop
  674.  
  675.         test    [edx + TCP_segment.Flags], TH_ACK
  676.         jnz     .drop_with_reset
  677.  
  678.         test    [edx + TCP_segment.Flags], TH_SYN
  679.         jz      .drop
  680.  
  681.         ; TODO: find sender ip address somewhere!
  682.         ; TODO: check if it's a broadcast or multicast, and drop if so
  683.  
  684.         call    SOCKET_fork
  685.         jz      .drop           ; if we could not open a new connection, drop segment (;;;; should we send RST too?)
  686.  
  687. ;-----------------------
  688. ; Fill in some variables
  689.  
  690.         add     [TCP_sequence_num], 64000
  691.  
  692.         push    [edx + TCP_segment.SourcePort]
  693.         pop     [eax + TCP_SOCKET.RemotePort]
  694.  
  695.         push    [edx + TCP_segment.SequenceNumber]
  696.         pop     [eax + TCP_SOCKET.IRS]
  697.  
  698.         push    [eax + TCP_SOCKET.ISS]
  699.         pop     [eax + TCP_SOCKET.SND_NXT]
  700.  
  701.         mov     [eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
  702.         mov     [eax + TCP_SOCKET.t_flags], TF_ACKNOW
  703.         mov     [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval
  704.  
  705.         mov     ebx, eax
  706.  
  707.         jmp     .trim_then_step6
  708.  
  709.  
  710. ;------------
  711. ; Active Open
  712.  
  713. align 4
  714. .SYN_SENT:
  715.  
  716.         DEBUGF  1,"TCP state: syn_sent\n"
  717.  
  718.         test    [edx + TCP_segment.Flags], TH_ACK
  719.         jz      @f
  720.  
  721.         mov     eax, [edx + TCP_segment.AckNumber]
  722.         cmp     eax, [ebx + TCP_SOCKET.ISS]
  723.         jle     .drop_with_reset
  724.  
  725.         DEBUGF  1,"snd_max = %x\n", [ebx + TCP_SOCKET.SND_MAX]   ;;; TODO: set this, but where?
  726.  
  727. ;        mov     eax, [edx + TCP_segment.AckNumber]
  728. ;;        cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
  729. ;;        jg      .drop_with_reset
  730.        @@:
  731.  
  732.         test    [edx + TCP_segment.Flags], TH_RST
  733.         jz      @f
  734.  
  735.         test    [edx + TCP_segment.Flags], TH_ACK
  736.         jz      .drop
  737.  
  738.         ;tp = tcp_drop(tp, ECONNREFUSED)
  739.  
  740.         jmp     .drop
  741.        @@:
  742.  
  743.         test    [edx + TCP_segment.Flags], TH_SYN
  744.         jz      .drop
  745.  
  746. ; at this point, segment seems to be valid
  747.  
  748.         test    [edx + TCP_segment.Flags], TH_ACK
  749.         jz      .no_syn_ack
  750.  
  751. ; now, process received SYN in response to an active open
  752.  
  753.         mov     eax, [edx + TCP_segment.AckNumber]
  754.         mov     [ebx + TCP_SOCKET.SND_UNA], eax
  755.         cmp     eax, [ebx + TCP_SOCKET.SND_NXT]
  756.         jle     @f
  757.         mov     [ebx + TCP_SOCKET.SND_NXT], eax
  758.        @@:
  759.  
  760.   .no_syn_ack:
  761.  
  762.         mov     [ebx + TCP_SOCKET.timer_retransmission], 0      ; disable retransmission
  763.  
  764.         push    [edx + TCP_segment.SequenceNumber]
  765.         pop     [ebx + TCP_SOCKET.IRS]
  766.  
  767. ;;; TODO: tcp_rcvseqinit
  768.  
  769.         mov     [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
  770.  
  771.         mov     eax, [ebx + TCP_SOCKET.SND_UNA]
  772.         cmp     eax, [ebx + TCP_SOCKET.ISS]
  773.         jle     .simultaneous_open
  774.  
  775.         test    [edx + TCP_segment.Flags], TH_ACK
  776.         jz      .simultaneous_open
  777.  
  778.         DEBUGF  1,"TCP: active open\n"
  779.  
  780. ; TODO: update stats
  781. ; TODO: set socket state to connected
  782.  
  783.         mov     [ebx + TCP_SOCKET.t_state], TCB_ESTABLISHED
  784.  
  785. ; TODO: check if we should scale the connection (567-572)
  786. ; TODO: update RTT estimators
  787.  
  788.         jmp     .trimthenstep6
  789.  
  790.   .simultaneous_open:
  791.  
  792.         DEBUGF  1,"TCP: simultaneous open\n"
  793. ; We have received a syn but no ACK, so we are having a simultaneous open..
  794.         mov     [ebx + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
  795.  
  796. ;-------------------------------------
  797. ; Common processing for receipt of SYN
  798.  
  799.   .trimthenstep6:
  800.  
  801.         inc     [edx + TCP_segment.SequenceNumber]
  802.  
  803.         cmp     cx, [ebx + TCP_SOCKET.RCV_WND]
  804.         jle     @f
  805.  
  806.         movzx   eax, cx
  807.         sub     ax, [ebx + TCP_SOCKET.RCV_WND]
  808.         ; TODO: 592
  809.         mov     cx, [ebx + TCP_SOCKET.RCV_WND]
  810.         ; TODO...
  811.        @@:
  812.         ;;;;;
  813.         jmp     .step6
  814.  
  815.  
  816.  
  817.  
  818.  
  819.   .trim_then_step6:
  820.  
  821.         DEBUGF  1,"Trimming window\n"
  822.  
  823. ;----------------------------
  824. ; trim any data not in window
  825.  
  826.         mov     eax, [ebx + TCP_SOCKET.RCV_NXT]
  827.         sub     eax, [edx + TCP_segment.SequenceNumber]
  828.  
  829.         test    eax, eax
  830.         jz      .no_drop
  831.  
  832.         test    [edx + TCP_segment.Flags], TH_SYN
  833.         jz      .no_drop
  834.  
  835.         and     [edx + TCP_segment.Flags], not (TH_SYN)
  836.         inc     [edx + TCP_segment.SequenceNumber]
  837.  
  838.         cmp     [edx + TCP_segment.UrgentPointer], 1
  839.         jl      @f
  840.  
  841.         dec     [edx + TCP_segment.UrgentPointer]
  842.  
  843.         jmp     .no_drop
  844.        @@:
  845.  
  846.         and     [edx + TCP_segment.Flags], not (TH_URG)
  847.         dec     eax
  848.  
  849.   .no_drop:
  850.  
  851.         DEBUGF  1,"Going to drop %u bytes of data", eax
  852.  
  853. ; eax holds number of bytes to drop
  854.  
  855. ;----------------------------------
  856. ; Check for entire duplicate packet
  857.  
  858.         cmp     eax, ecx
  859.         jge     .duplicate
  860.  
  861.         ;;; TODO: figure 28.30
  862.  
  863. ;------------------------
  864. ; Check for duplicate FIN
  865.  
  866.         test    [edx + TCP_segment.Flags], TH_FIN
  867.         jz      @f
  868.         inc     ecx
  869.         cmp     eax, ecx
  870.         dec     ecx
  871.         jne     @f
  872.  
  873.         mov     eax, ecx
  874.         and     [edx + TCP_segment.Flags], not TH_FIN
  875.         or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
  876.         jmp     .no_duplicate
  877.        @@:
  878.  
  879.         ; Handle the case when a bound socket connects to itself
  880.         ; Allow packets with a SYN and an ACKto continue with the processing
  881.  
  882. ;-------------------------------------
  883. ; Generate duplicate ACK if nescessary
  884.  
  885. ; This code also handles simultaneous half-open or self-connects
  886.  
  887.         test    eax, eax
  888.         jnz     .drop_after_ack
  889.  
  890.         cmp     [edx + TCP_segment.Flags], TH_ACK
  891.         jz      .drop_after_ack
  892.  
  893.   .duplicate:
  894.  
  895.         DEBUGF  1,"Duplicate received"
  896.  
  897. ;----------------------------------------
  898. ; Update statistics for duplicate packets
  899.  
  900.         ;;; TODO
  901.  
  902.         jmp     .drop          ;;; DROP the packet ??
  903.  
  904.   .no_duplicate:
  905.  
  906. ;-----------------------------------------------
  907. ; Remove duplicate data and update urgent offset
  908.  
  909.         add     [edx + TCP_segment.SequenceNumber], eax
  910.  
  911.         ;;; TODO
  912.  
  913.         sub     [edx + TCP_segment.UrgentPointer], ax
  914.         jg      @f
  915.  
  916.         and     [edx + TCP_segment.Flags], not (TH_URG)
  917.         mov     [edx + TCP_segment.UrgentPointer], 0
  918.        @@:
  919.  
  920. ;--------------------------------------------------
  921. ; Handle data that arrives after process terminates
  922.  
  923.         cmp     [ebx + SOCKET.PID], 0
  924.         jge     @f
  925.  
  926.         cmp     [ebx + TCP_SOCKET.t_state], TCB_CLOSE_WAIT
  927.         jle     @f
  928.  
  929.         test    ecx, ecx
  930.         jz      @f
  931.  
  932.         ;;; Close the socket
  933.         ;;; update stats
  934.  
  935.         jmp     .drop_with_reset
  936.  
  937.        @@:
  938.  
  939. ;----------------------------------------
  940. ; Remove data beyond right edge of window
  941.  
  942.         mov     eax, [edx + TCP_segment.SequenceNumber]
  943.         add     eax, ecx
  944.         sub     eax, [ebx + TCP_SOCKET.RCV_NXT]
  945.         sub     ax, [ebx + TCP_SOCKET.RCV_WND]
  946.  
  947.         ; eax now holds the number of bytes to drop
  948.  
  949.         jle     .no_excess_data
  950.  
  951.         ;;; TODO: update stats
  952.  
  953.         cmp     eax, ecx
  954.         jl      .dont_drop_all
  955.  
  956. ;;; TODO 700-736
  957.  
  958.   .dont_drop_all:
  959.  
  960.   .no_excess_data:
  961.  
  962. ;-----------------
  963. ; Record timestamp
  964.  
  965.         ;;; TODO 737-746
  966.  
  967. ;------------------
  968. ; Process RST flags
  969.  
  970.         test    [edx + TCP_segment.Flags], TH_RST
  971.         jz      .rst_skip
  972.  
  973.         DEBUGF  1,"Got an RST flag"
  974.  
  975.         mov     eax, [ebx + TCP_SOCKET.t_state]
  976.         shl     eax, 2
  977.         jmp     dword [eax + .rst_sw_list]
  978.  
  979.   .rst_sw_list:
  980.         dd      .rst_skip       ;TCB_CLOSED
  981.         dd      .rst_skip       ;TCB_LISTEN
  982.         dd      .rst_skip       ;TCB_SYN_SENT
  983.         dd      .econnrefused   ;TCB_SYN_RECEIVED
  984.         dd      .econnreset     ;TCB_ESTABLISHED
  985.         dd      .econnreset     ;TCB_CLOSE_WAIT
  986.         dd      .econnreset     ;TCB_FIN_WAIT_1
  987.         dd      .rst_close      ;TCB_CLOSING
  988.         dd      .rst_close      ;TCB_LAST_ACK
  989.         dd      .econnreset     ;TCB_FIN_WAIT_2
  990.         dd      .rst_close      ;TCB_TIMED_WAIT
  991.  
  992.   .econnrefused:
  993.  
  994.         DEBUGF  1,"Connection refused"
  995.  
  996.         ;;; TODO: debug info
  997.  
  998.         jmp     .close
  999.  
  1000.   .econnreset:
  1001.  
  1002.         DEBUGF  1,"Connection reset"
  1003.  
  1004.         ;;; TODO: debug info
  1005.   .close:
  1006.  
  1007.         DEBUGF  1,"Closing connection"
  1008.  
  1009.         ;;; update stats
  1010.  
  1011.   .rst_close:
  1012.  
  1013.         DEBUGF  1,"Closing with reset"
  1014.  
  1015.         ;;; Close the socket
  1016.         jmp     .drop
  1017.  
  1018.   .rst_skip:
  1019.  
  1020. ;--------------------------------------
  1021. ; handle SYN-full and ACK-less segments
  1022.  
  1023.         test    [edx + TCP_segment.Flags], TH_SYN
  1024.         jz      @f
  1025.  
  1026.         ;;; tcp_drop ( ECONNRESET)
  1027.         jmp     .drop_with_reset
  1028.  
  1029.         test    [edx + TCP_segment.Flags], TH_ACK
  1030.         jz      .drop
  1031.  
  1032. ;----------------
  1033. ; Process the ACK
  1034.  
  1035.         cmp     [ebx + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
  1036.         jg      .ack_dup
  1037.         jl      .ack_nodup
  1038.  
  1039.         ;;;;;
  1040.  
  1041.   .ack_dup:
  1042.  
  1043.         ;;;;
  1044.  
  1045.   .ack_nodup:
  1046.  
  1047.         ;;;; 887
  1048.  
  1049. ;-------------------------------------------------
  1050. ; If the congestion window was inflated to account
  1051. ; for the other side's cached packets, retrace it
  1052.  
  1053.         ;;;; 888 -  902
  1054.  
  1055.  
  1056. ;------------------------------------------
  1057. ; RTT measurements and retransmission timer
  1058.  
  1059.         ;;;;; 903 - 926
  1060.  
  1061.         mov     [ebx + TCP_SOCKET.timer_retransmission], 0
  1062.  
  1063.         mov     eax, [ebx + TCP_SOCKET.SND_MAX]
  1064.         cmp     eax, [edx + TCP_segment.AckNumber]
  1065.         je      .all_outstanding
  1066.         mov     [ebx + TCP_SOCKET.timer_retransmission], 120 ;;;; TODO: correct this value
  1067.   .all_outstanding:
  1068.  
  1069.  
  1070. ;-------------------------------------------
  1071. ; Open congestion window in response to ACKs
  1072.  
  1073.         ;;;;
  1074.  
  1075.  
  1076. ;------------------------------------------
  1077. ; Remove acknowledged data from send buffer
  1078.  
  1079.         lea     eax, [ebx + snd]
  1080.         mov     ecx, ecx                ;;;; 943 - 956
  1081.         call    SOCKET_ring_free
  1082.  
  1083. ;---------------------------------------
  1084. ; Wake up process waiting on send buffer
  1085.  
  1086.         mov     eax, ebx
  1087.         call    SOCKET_notify_owner
  1088.  
  1089.         mov     eax, [ebx + TCP_SOCKET.t_state]
  1090.         shl     eax, 2
  1091.         jmp     dword [eax + .ACK_sw_list]
  1092.  
  1093.   .ACK_sw_list:
  1094.         dd      .step6          ;TCB_CLOSED
  1095.         dd      .step6          ;TCB_LISTEN
  1096.         dd      .step6          ;TCB_SYN_SENT
  1097.         dd      .step6          ;TCB_SYN_RECEIVED
  1098.         dd      .step6          ;TCB_ESTABLISHED
  1099.         dd      .step6          ;TCB_CLOSE_WAIT
  1100.         dd      ._963           ;TCB_FIN_WAIT_1
  1101.         dd      ._958           ;TCB_CLOSING
  1102.         dd      ._999           ;TCB_LAST_ACK
  1103.         dd      .step6          ;TCB_FIN_WAIT_2
  1104.         dd      ._1010          ;TCB_TIMED_WAIT
  1105.  
  1106.  
  1107. ._963:
  1108.  
  1109.  
  1110.         jmp     .step6
  1111.  
  1112.  
  1113. ._958:
  1114.  
  1115.         jmp     .step6
  1116.  
  1117. ._999:
  1118.  
  1119.         jmp     .step6
  1120.  
  1121.  
  1122. ._1010:
  1123.  
  1124.         jmp     .step6
  1125.  
  1126.  
  1127.  
  1128. align 4
  1129. .step6:
  1130.  
  1131.         DEBUGF  1,"step 6\n"
  1132.  
  1133. ;--------------------------
  1134. ; update window information
  1135.  
  1136.         test    [edx + TCP_segment.Flags], TH_ACK
  1137.         jz      .no_window_update
  1138.  
  1139.         mov     eax, [ebx + TCP_SOCKET.SND_WL1]
  1140.         cmp     eax, [edx + TCP_segment.SequenceNumber]
  1141.  
  1142.         ;;;; 1021
  1143.  
  1144. ;----------------------------------
  1145. ; Keep track of pure window updates
  1146.  
  1147.         test    ecx, ecx
  1148.         jz      @f
  1149.  
  1150.         mov     eax, [ebx + TCP_SOCKET.SND_WL2]
  1151.         cmp     eax, [edx + TCP_segment.AckNumber]
  1152.         jne     @f
  1153.  
  1154.         ;; mov eax, tiwin
  1155.         cmp     eax, [ebx + TCP_SOCKET.SND_WND]
  1156.         jle     @f
  1157.  
  1158.         ;;; update stats
  1159.  
  1160.        @@:
  1161.  
  1162.         ;; mov eax, incoming window
  1163.         cmp     eax, [ebx + TCP_SOCKET.max_sndwnd]
  1164.         jle     @f
  1165.         mov     [ebx + TCP_SOCKET.max_sndwnd], eax
  1166.        @@:
  1167.         mov     [ebx + TCP_SOCKET.SND_WND], eax
  1168.  
  1169.         mov     eax, [edx + TCP_segment.SequenceNumber]
  1170.         mov     [ebx + TCP_SOCKET.SND_WL1], eax
  1171.  
  1172.         mov     eax, [edx + TCP_segment.AckNumber]
  1173.         mov     [ebx + TCP_SOCKET.SND_WL2], eax
  1174.  
  1175.         ;;; needoutput = 1
  1176.  
  1177.   .no_window_update:
  1178.  
  1179. ;-----------------
  1180. ; process URG flag
  1181.  
  1182.         test    [edx + TCP_segment.Flags], TH_URG
  1183.         jz      .not_urgent
  1184.  
  1185.         cmp     [edx + TCP_segment.UrgentPointer], 0
  1186.         jz      .not_urgent
  1187.  
  1188.         cmp     [ebx + TCP_SOCKET.t_state], TCB_TIMED_WAIT
  1189.         je      .not_urgent
  1190.  
  1191. ; Ignore bogus urgent offsets
  1192.  
  1193.         ;;; 1040-1050
  1194.  
  1195.         movzx   eax, [edx + TCP_segment.UrgentPointer]
  1196.         add     eax, [ebx + rcv.size]
  1197.         cmp     eax, SOCKET_MAXDATA
  1198.         jle     .not_urgent
  1199.  
  1200.         mov     [edx + TCP_segment.UrgentPointer], 0
  1201.         and     [edx + TCP_segment.Flags], not (TH_URG)
  1202.         jmp     .do_data
  1203.  
  1204.   .not_urgent:
  1205.  
  1206. ;--------------------------------------
  1207. ; processing of received urgent pointer
  1208.  
  1209.         ;;; TODO (1051-1093)
  1210.  
  1211. ;--------------------------------
  1212. ; process the data in the segment
  1213.  
  1214.   .do_data:
  1215.  
  1216.         DEBUGF  1,"TCP: do data:\n"
  1217.  
  1218.         test    [edx + TCP_segment.Flags], TH_FIN
  1219.         jnz     .process_fin
  1220.  
  1221.         test    [ebx + TCP_SOCKET.t_state], TCB_FIN_WAIT_1
  1222.         jge     .dont_do_data
  1223.  
  1224.         DEBUGF  1,"Processing data in segment\n"
  1225.  
  1226.         ;;; NOW, process the data
  1227.  
  1228.         jmp     .final_processing
  1229.  
  1230.  
  1231.   .dont_do_data:
  1232.  
  1233. ;---------------
  1234. ; FIN processing
  1235.  
  1236.   .process_fin:
  1237.  
  1238.         DEBUGF  1,"Processing FIN\n"
  1239.  
  1240.         mov     eax, [ebx + TCP_SOCKET.t_state]
  1241.         shl     eax, 2
  1242.         jmp     dword [eax + .FIN_sw_list]
  1243.  
  1244.   .FIN_sw_list:
  1245.         dd      .no_fin         ;TCB_CLOSED
  1246.         dd      .no_fin         ;TCB_LISTEN
  1247.         dd      .no_fin         ;TCB_SYN_SENT
  1248.         dd      ._1131          ;TCB_SYN_RECEIVED
  1249.         dd      ._1131          ;TCB_ESTABLISHED
  1250.         dd      .no_fin         ;TCB_CLOSE_WAIT
  1251.         dd      ._1139          ;TCB_FIN_WAIT_1
  1252.         dd      .no_fin         ;TCB_CLOSING
  1253.         dd      .no_fin         ;TCB_LAST_ACK
  1254.         dd      ._1147          ;TCB_FIN_WAIT_2
  1255.         dd      ._1156          ;TCB_TIMED_WAIT
  1256.  
  1257.  
  1258.  
  1259.   ._1131:
  1260.  
  1261.   ._1139:
  1262.  
  1263.   ._1147:
  1264.  
  1265.   ._1156:
  1266.  
  1267.  
  1268.   .no_fin:
  1269.  
  1270. ;-----------------
  1271. ; Final processing
  1272.  
  1273.   .final_processing:
  1274.  
  1275.         DEBUGF  1,"Final processing\n"
  1276.  
  1277.         ;;; if debug enabled, output packet
  1278.  
  1279.         ;test    ;;;needoutput = 1
  1280.         ;jnz     .outputnow
  1281.  
  1282.         test    [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
  1283.         jnz     .ack_now
  1284.  
  1285.         mov     [ebx + SOCKET.lock], 0
  1286.         call    kernel_free
  1287.         add     esp, 4
  1288.         ret
  1289.  
  1290.   .ack_now:
  1291.  
  1292.         DEBUGF  1,"ACK now!\n"
  1293.  
  1294.         push    ebx
  1295.         mov     eax, ebx
  1296.         call    TCP_output
  1297.         pop     ebx
  1298.  
  1299.         mov     [ebx + SOCKET.lock], 0
  1300.         call    kernel_free
  1301.         add     esp, 4
  1302.         ret
  1303.  
  1304. ;------------------------------------------
  1305. ; Generate an ACK, droping incoming segment
  1306.  
  1307. align 4
  1308. .drop_after_ack:
  1309.  
  1310.         DEBUGF  1,"Drop after ACK\n"
  1311.  
  1312.         test    [edx + TCP_segment.Flags], TH_RST
  1313.         jnz     .drop
  1314.  
  1315.         and     [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
  1316.  
  1317.         push    ebx
  1318.         mov     eax, ebx
  1319.         call    TCP_output
  1320.         pop     ebx
  1321.  
  1322.         mov     [ebx + SOCKET.lock], 0
  1323.         call    kernel_free
  1324.         add     esp, 4
  1325.         ret
  1326.  
  1327.  
  1328. ;-------------------------------------------
  1329. ; Generate an RST, dropping incoming segment
  1330.  
  1331. align 4
  1332. .drop_with_reset:
  1333.  
  1334.         DEBUGF  1,"Drop with reset\n"
  1335.  
  1336.         test    [edx + TCP_segment.Flags], TH_RST
  1337.         jnz     .drop
  1338.  
  1339.         ;;; if its a multicast/broadcast, also drop
  1340.  
  1341.         test    [edx + TCP_segment.Flags], TH_ACK
  1342.         jnz     .respond_ack
  1343.  
  1344.         test    [edx + TCP_segment.Flags], TH_SYN
  1345.         jnz     .respond_syn
  1346.  
  1347.         mov     [ebx + SOCKET.lock], 0
  1348.         call    kernel_free
  1349.         add     esp, 4
  1350.         ret
  1351.  
  1352.   .respond_ack:
  1353.  
  1354.         ;;;;
  1355.  
  1356.         call    TCP_respond_segment
  1357.  
  1358.         jmp     .destroy_new_socket
  1359.  
  1360.  
  1361.   .respond_syn:
  1362.  
  1363.         ;;;;
  1364.  
  1365.         call    TCP_respond_segment
  1366.  
  1367.         jmp     .destroy_new_socket
  1368.  
  1369. ;-----
  1370. ; Drop
  1371.  
  1372. align 4
  1373. .drop:
  1374.  
  1375.         DEBUGF  1,"Dropping packet\n"
  1376.  
  1377.         ;;;; If debugging options are enabled, output the packet somwhere
  1378.  
  1379.   .destroy_new_socket:
  1380.  
  1381.         ;;;; kill the newly created socket
  1382.  
  1383.         mov     [ebx + SOCKET.lock], 0
  1384.         call    kernel_free
  1385.         add     esp, 4
  1386.         ret
  1387.  
  1388.  
  1389.  
  1390.  
  1391.  
  1392.  
  1393. ;---------------------------
  1394. ;
  1395. ; TCP_pull_out_of_band
  1396. ;
  1397. ; IN:  eax =
  1398. ;      ebx = socket ptr
  1399. ;      edx = tcp packet ptr
  1400. ;
  1401. ; OUT: /
  1402. ;
  1403. ;---------------------------
  1404.  
  1405. align 4
  1406. TCP_pull_out_of_band:
  1407.  
  1408.         DEBUGF  1,"TCP_pull_out_of_band\n"
  1409.  
  1410.         ;;;; 1282-1305
  1411.  
  1412.         ret
  1413.  
  1414.  
  1415.  
  1416. ;-----------------------------------------------------------------
  1417. ;
  1418. ; TCP_output
  1419. ;
  1420. ; IN:  eax = socket pointer
  1421. ;;     esi = ptr to data
  1422. ;;     ecx = number of data bytes
  1423. ;
  1424. ; OUT: /
  1425. ;
  1426. ;-----------------------------------------------------------------
  1427. align 4
  1428. TCP_output:
  1429.  
  1430.         DEBUGF 1,"TCP_output, socket: %x\n", eax
  1431.  
  1432. ; We'll detect the length of the data to be transmitted, and flags to be used
  1433. ; If there is some data, or any critical controls to send (SYN / RST), then transmit
  1434. ; Otherwise, investigate further
  1435.  
  1436.         mov     ebx, [eax + TCP_SOCKET.SND_MAX]
  1437.         cmp     ebx, [eax + TCP_SOCKET.SND_UNA]
  1438.         jne     .not_idle
  1439.  
  1440.         mov     ebx, [eax + TCP_SOCKET.t_idle]
  1441.         cmp     ebx, [eax + TCP_SOCKET.t_rxtcur]
  1442.         jle     .not_idle
  1443.  
  1444. ; We have been idle for a while and no ACKS are expected to clock out any data we send..
  1445. ; Slow start to get ack "clock" running again.
  1446.  
  1447.         mov     ebx, [eax + TCP_SOCKET.t_maxseg]
  1448.         mov     [eax + TCP_SOCKET.SND_CWND], ebx
  1449.  
  1450.   .not_idle:
  1451.   .again:
  1452.         mov     ebx, [eax + TCP_SOCKET.SND_NXT]         ; calculate offset
  1453.         sub     ebx, [eax + TCP_SOCKET.SND_UNA]         ;
  1454.  
  1455.         mov     ecx, [eax + TCP_SOCKET.SND_WND]         ; determine window
  1456.         cmp     ecx, [eax + TCP_SOCKET.SND_CWND]        ;
  1457.         jl      @f                                      ;
  1458.         mov     ecx, [eax + TCP_SOCKET.SND_CWND]        ;
  1459.        @@:                                              ;
  1460.  
  1461.         call    TCP_outflags    ; in dl
  1462.  
  1463. ; If in persist timeout with window of 0, send 1 byte.
  1464. ; Otherwise, if window is small but nonzero, and timer expired,
  1465. ; we will send what we can and go to transmit state
  1466.  
  1467.         test    [eax + TCP_SOCKET.t_force], -1
  1468.         jz      .no_persist_timeout
  1469.  
  1470.         test    ecx, ecx
  1471.         jnz     .no_zero_window
  1472.  
  1473.         cmp     ebx, [eax + snd.size]
  1474.         jge     @f
  1475.  
  1476.         and     dl, not (TH_FIN)          ; clear the FIN flag    ??? how can it be set before?
  1477.  
  1478.        @@:
  1479.         inc     ecx
  1480.         jmp     .no_persist_timeout
  1481.  
  1482.   .no_zero_window:
  1483.  
  1484.         mov     [eax + TCP_SOCKET.timer_persist], 0     ;;;;
  1485.         mov     [eax + TCP_SOCKET.t_rxtshift], 0
  1486.  
  1487.   .no_persist_timeout:
  1488.  
  1489. ;;;106
  1490.  
  1491.         mov     esi, [eax + snd.size]
  1492.         cmp     esi, ecx
  1493.         jl      @f
  1494.         mov     esi, ecx
  1495.        @@:
  1496.         sub     esi, ebx
  1497.  
  1498.         cmp     esi, -1
  1499.         jne     .not_minus_one
  1500.  
  1501. ; If FIN has been set, but not ACKed, and we havent been called to retransmit,
  1502. ; len (esi) will be -1
  1503. ; Otherwise, window shrank after we sent into it.
  1504. ; If window shrank to 0, cancel pending retransmit and pull SND_NXT back to (closed) window
  1505. ; We will enter persist state below.
  1506. ; If window didn't close completely, just wait for an ACK
  1507.  
  1508.         xor     esi, esi
  1509.  
  1510.         test    ecx, ecx
  1511.         jnz     @f
  1512.  
  1513.         mov     [eax + TCP_SOCKET.timer_retransmission], 0   ; cancel retransmit
  1514.  
  1515.         push    [eax + TCP_SOCKET.SND_UNA]
  1516.         pop     [eax + TCP_SOCKET.SND_NXT]
  1517.        @@:
  1518.  
  1519.   .not_minus_one:
  1520.  
  1521. ;;; 124
  1522.  
  1523.         cmp     esi, [eax + TCP_SOCKET.t_maxseg]
  1524.         jle     @f
  1525.  
  1526.         mov     esi, [eax + TCP_SOCKET.t_maxseg]
  1527.         ;sendalot = 1
  1528.  
  1529.        @@:
  1530.  
  1531. ;;; 128
  1532.  
  1533.         mov     edi, [eax + TCP_SOCKET.SND_NXT]
  1534.         add     edi, esi        ; len
  1535.         sub     edi, [eax + TCP_SOCKET.SND_UNA]
  1536.         add     edi, [eax + snd.size]
  1537.         cmp     edi, 0
  1538.         jle     @f
  1539.  
  1540.         and     dl, not (TH_FIN)          ; clear the FIN flag
  1541.  
  1542.        @@:
  1543.  
  1544.  
  1545. ; set ecx to space available in receive buffer
  1546. ; From now on, ecx will be the window we advertise to the other end
  1547.  
  1548.         mov     ecx, SOCKET_MAXDATA
  1549.         sub     ecx, [eax + rcv.size]
  1550.  
  1551. ;------------------------------
  1552. ; Sender silly window avoidance
  1553.  
  1554.         cmp     ecx, [eax + TCP_SOCKET.t_maxseg]
  1555.         je      .send
  1556.  
  1557. ;;; TODO: 144-145
  1558.  
  1559.         test    [eax + TCP_SOCKET.t_force], -1
  1560.         jnz     .send
  1561.  
  1562.         mov     ebx, [eax + TCP_SOCKET.max_sndwnd]
  1563.         shr     ebx, 1
  1564.         cmp     ecx, ebx
  1565.         jge     .send
  1566.  
  1567.         mov     ebx, [eax + TCP_SOCKET.SND_NXT]
  1568.         cmp     ebx, [eax + TCP_SOCKET.SND_MAX]
  1569.         jl      .send
  1570.  
  1571. ;----------------------------------------
  1572. ; Check if a window update should be sent
  1573.  
  1574.         test    ecx, ecx        ; window
  1575.         jz      .no_window
  1576.  
  1577. ;;; TODO 154-172
  1578.  
  1579.   .no_window:
  1580.  
  1581. ;--------------------------
  1582. ; Should a segment be sent?
  1583.  
  1584.         test    [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
  1585.         jnz     .send
  1586.  
  1587.         test    dl, TH_SYN + TH_RST
  1588.         jnz     .send
  1589.  
  1590.         mov     eax, [ebx + TCP_SOCKET.SND_UP]
  1591.         cmp     eax, [ebx + TCP_SOCKET.SND_UNA]
  1592.         jg      .send
  1593.  
  1594.         test    dl, TH_FIN
  1595.         jz      .enter_persist
  1596.  
  1597.         test    [ebx + TCP_SOCKET.t_flags], TF_SENTFIN
  1598.         jnz     .send
  1599.  
  1600.         mov     eax, [ebx + TCP_SOCKET.SND_NXT]
  1601.         cmp     eax, [ebx + TCP_SOCKET.SND_UNA]
  1602.         je      .send
  1603.  
  1604. ;--------------------
  1605. ; Enter persist state
  1606.  
  1607.   .enter_persist:
  1608.  
  1609.         DEBUGF  1,"Entering persist state\n"
  1610.  
  1611. ;--------------------------------------
  1612. ; No reason to send a segment, just ret
  1613.  
  1614.         DEBUGF  1,"No reason to send a segment\n"
  1615.  
  1616.         ret
  1617.  
  1618.  
  1619. ;-----------------------------------------------
  1620. ;
  1621. ; Send a segment
  1622. ;
  1623. ; eax = socket pointer
  1624. ;  dl = flags
  1625. ;
  1626. ;-----------------------------------------------
  1627.  
  1628.   .send:
  1629.  
  1630.         DEBUGF  1,"Preparing to send a segment\n"
  1631.  
  1632.         mov     edi, TCP_segment.Data   ; edi will contain headersize
  1633.  
  1634.         sub     esp, 8                  ; create some space on stack
  1635.         push    eax                     ; save this too..
  1636.  
  1637. ;------------------------------------
  1638. ; Send options with first SYN segment
  1639.  
  1640.         test    dl, TH_SYN
  1641.         jz      .no_options
  1642.  
  1643.         push    [eax + TCP_SOCKET.ISS]
  1644.         pop     [eax + TCP_SOCKET.SND_NXT]
  1645.  
  1646.         test    [eax + TCP_SOCKET.t_flags], TF_NOOPT
  1647.         jnz     .no_options
  1648.  
  1649.         mov     ecx, 1460
  1650.         or      ecx, TCP_OPT_MAXSEG shl 24 + 4 shl 16
  1651.         bswap   ecx
  1652.         push    ecx
  1653.         add     di, 4
  1654.  
  1655.         test    [eax + TCP_SOCKET.t_flags], TF_REQ_SCALE
  1656.         jz      .no_syn
  1657.  
  1658.         test    dl, TH_ACK
  1659.         jnz     .scale_opt
  1660.  
  1661.         test    [eax + TCP_SOCKET.t_flags], TF_RCVD_SCALE
  1662.         jz      .no_syn
  1663.  
  1664.   .scale_opt:
  1665.         movzx   ecx, byte [eax + TCP_SOCKET.request_r_scale]
  1666.         or      ecx, TCP_OPT_WINDOW shl 24 + 4 shl 16 + TCP_OPT_NOP shl 8
  1667.         bswap   ecx
  1668.         pushd   ecx
  1669.         add     di, 4
  1670.  
  1671.   .no_syn:
  1672.  
  1673. ;------------------------------------
  1674. ; Make the timestamp option if needed
  1675.  
  1676.         test    [eax + TCP_SOCKET.t_flags], TF_REQ_TSTMP
  1677.         jz      .no_timestamp
  1678.  
  1679.         test    dl, TH_RST
  1680.         jnz     .no_timestamp
  1681.  
  1682.         test    dl, TH_ACK
  1683.         jz      .timestamp
  1684.  
  1685.         test    [eax + TCP_SOCKET.t_flags], TF_RCVD_TSTMP
  1686.         jz      .no_timestamp
  1687.  
  1688.   .timestamp:
  1689.         mov     esi, [timer_ticks]
  1690.         bswap   esi
  1691.         push    esi
  1692.         pushw   0
  1693.         pushd   TCP_OPT_TIMESTAMP + 10 shl 8 + TCP_OPT_NOP shl 16 + TCP_OPT_NOP shl 24
  1694.         add     di, 10
  1695.  
  1696.   .no_timestamp:
  1697.         ;; TODO: check if we dont exceed the max segment size
  1698.  
  1699.   .no_options:
  1700.         ; eax = socket ptr
  1701.         ; edx = flags
  1702.         ; ecx = data size
  1703.         ; edi = header size
  1704.         ; esi = snd ring buff ptr
  1705.  
  1706.         xor     ecx, ecx        ;;;;;
  1707.         add     ecx, edi        ; total TCP segment size
  1708.  
  1709. ; Start by pushing all TCP header values in reverse order on stack
  1710. ; (essentially, creating the tcp header!)
  1711.  
  1712.         pushw   0       ;        .UrgentPointer          dw ?
  1713.         pushw   0       ;        .Checksum               dw ?
  1714.         pushw   0x00a0  ;        .Window                 dw ?    ;;;;;;;
  1715.         shl     edi, 2  ;        .DataOffset             db ?  only 4 left-most bits
  1716.         shl     dx, 8
  1717.         or      dx, di  ;        .Flags                  db ?
  1718.         pushw   dx
  1719.         shr     edi, 2  ;        .DataOffset             db ? ;;;;
  1720.  
  1721.         push    [eax + TCP_SOCKET.RCV_NXT]      ;        .AckNumber              dd ?
  1722.         ntohld  [esp]
  1723.  
  1724.         push    [eax + TCP_SOCKET.SND_NXT]      ;        .SequenceNumber         dd ?
  1725.         ntohld  [esp]
  1726.  
  1727.         push    [eax + TCP_SOCKET.RemotePort]   ;        .DestinationPort        dw ?
  1728.         ntohlw  [esp]
  1729.  
  1730.         push    [eax + TCP_SOCKET.LocalPort]    ;        .SourcePort             dw ?
  1731.         ntohlw  [esp]
  1732.  
  1733.         push    edi     ; header size
  1734.  
  1735. ; Create the IP packet
  1736.         mov     ebx, [eax + IP_SOCKET.LocalIP]  ; source ip
  1737.         mov     eax, [eax + IP_SOCKET.RemoteIP] ; dest ip
  1738. ;        mov     ecx,                            ; data length
  1739. ;        mov     dx,                             ; fragment id
  1740.         mov     di, IP_PROTO_TCP shl 8 + 128
  1741.         call    IPv4_output
  1742.         jz      .fail
  1743.  
  1744. ;-----------------------------------------
  1745. ; Move TCP header from stack to TCP packet
  1746.  
  1747. ;        pop     ecx                     ; header size
  1748. ;        mov     esi, esp
  1749. ;        add     esp, ecx
  1750. ;        shr     ecx, 2
  1751. ;        rep     movsd
  1752.  
  1753.         mov     ecx, [esp]
  1754.         lea     esi, [esp+4]
  1755.         shr     ecx, 2
  1756.         rep     movsd
  1757.  
  1758.         pop     ecx
  1759.         add     esp, ecx
  1760.  
  1761.         mov     [esp + 3*4+4], edx      ; packet size
  1762.         mov     [esp + 3*4], eax        ; packet ptr
  1763.  
  1764.         mov     edx, edi
  1765.         sub     edx, ecx
  1766.  
  1767. ;--------------
  1768. ; Copy the data
  1769.  
  1770. ; eax = ptr to ring struct
  1771. ; ecx = buffer size
  1772. ; edi = ptr to buffer
  1773.  
  1774.         mov     eax, [esp]              ; socket ptr
  1775.         push    ecx edx
  1776.         add     eax, snd
  1777.         call    SOCKET_ring_read
  1778.         pop     esi ecx
  1779.         pop     eax
  1780.  
  1781. ;-------------------------------------------------------------
  1782. ; Create the checksum  (we have already pushed IPs onto stack)
  1783.  
  1784.         DEBUGF  1,"checksum: ptr=%x size=%u\n", esi, ecx
  1785.         DEBUGF  1,"ip=%x\n", [esp]:8
  1786.         DEBUGF  1,"ip=%x\n", [esp+4]:8
  1787.  
  1788.         TCP_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP)
  1789.         mov     [esi+TCP_segment.Checksum], dx
  1790.  
  1791. ;----------------
  1792. ; Send the packet
  1793.  
  1794.         DEBUGF  1,"Sending TCP Packet to device %x\n", ebx
  1795.         call    [ebx + NET_DEVICE.transmit]
  1796.         ret
  1797.  
  1798.  
  1799.   .fail:
  1800.         pop     ecx
  1801.         add     esp, ecx
  1802.         add     esp, 4+4+8+4
  1803.         DEBUGF 1,"TCP_output: failed\n"
  1804.         ret
  1805.  
  1806.  
  1807.  
  1808. ;-------------------------
  1809. ;
  1810. ; TCP_outflags
  1811. ;
  1812. ;  IN:  eax = socket ptr
  1813. ;
  1814. ;  OUT: edx = flags
  1815. ;
  1816. ;-------------------------
  1817. align 4
  1818. TCP_outflags:
  1819.  
  1820.         mov     edx, [eax + TCP_SOCKET.t_state]
  1821.         movzx   edx, byte [edx + .flaglist]
  1822.  
  1823.         DEBUGF  1,"TCP_outflags, socket: %x, flags: %x\n", eax, dl
  1824.  
  1825.         ret
  1826.  
  1827.   .flaglist:
  1828.  
  1829.         db      TH_RST + TH_ACK         ; TCB_CLOSED
  1830.         db      0                       ; TCB_LISTEN
  1831.         db      TH_SYN                  ; TCB_SYN_SENT
  1832.         db      TH_SYN + TH_ACK         ; TCB_SYN_RECEIVED
  1833.         db               TH_ACK         ; TCB_ESTABLISHED
  1834.         db               TH_ACK         ; TCB_CLOSE_WAIT
  1835.         db      TH_SYN + TH_ACK         ; TCB_FIN_WAIT_1
  1836.         db      TH_SYN + TH_ACK         ; TCB_CLOSING
  1837.         db      TH_SYN + TH_ACK         ; TCB_LAST_ACK
  1838.         db               TH_ACK         ; TCB_FIN_WAIT_2
  1839.         db               TH_ACK         ; TCB_TIMED_WAIT
  1840.  
  1841.  
  1842.  
  1843.  
  1844. ;-------------------------
  1845. ;
  1846. ; TCP_drop
  1847. ;
  1848. ;  IN:  eax = socket ptr
  1849. ;
  1850. ;  OUT: /
  1851. ;
  1852. ;-------------------------
  1853. align 4
  1854. TCP_drop:
  1855.  
  1856.         DEBUGF  1,"TCP_drop\n"
  1857.  
  1858. ;        cmp     [eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
  1859. ;        jl      .no_syn_received
  1860.  
  1861.         mov     [eax + TCP_SOCKET.t_state], TCB_CLOSED
  1862.  
  1863.         call    TCP_output
  1864.  
  1865. ;  .no_syn_received:
  1866.  
  1867.         ret
  1868.  
  1869.  
  1870.  
  1871.  
  1872.  
  1873. ;---------------------------------------
  1874. ;
  1875. ; The easy way to send an ACK/RST/keepalive segment
  1876. ;
  1877. ; TCP_respond_socket:
  1878. ;
  1879. ;  IN:  ebx = socket ptr
  1880. ;        cl = flags
  1881. ;
  1882. ;--------------------------------------
  1883. align 4
  1884. TCP_respond_socket:
  1885.  
  1886.         DEBUGF  1,"TCP_respond_socket\n"
  1887.  
  1888. ;---------------------
  1889. ; Create the IP packet
  1890.  
  1891.         push    cx ebx
  1892.         mov     eax, [ebx + IP_SOCKET.RemoteIP]
  1893.         mov     ebx, [ebx + IP_SOCKET.LocalIP]
  1894.         mov     ecx, TCP_segment.Data
  1895.         mov     di , IP_PROTO_TCP shl 8 + 128
  1896.         call    IPv4_output
  1897.         test    edi, edi
  1898.         jz      .error
  1899.         pop     esi cx
  1900.         push    edx eax
  1901.  
  1902. ;-----------------------------------------------
  1903. ; Fill in the TCP header by using the socket ptr
  1904.  
  1905.         mov     ax, [esi + TCP_SOCKET.LocalPort]
  1906.         rol     ax, 8
  1907.         stosw
  1908.         mov     ax, [esi + TCP_SOCKET.RemotePort]
  1909.         rol     ax, 8
  1910.         stosw
  1911.         mov     eax, [esi + TCP_SOCKET.SND_NXT]
  1912.         bswap   eax
  1913.         stosd
  1914.         mov     eax, [esi + TCP_SOCKET.RCV_NXT]
  1915.         bswap   eax
  1916.         stosd
  1917.         mov     al, 0x50        ; Dataoffset: 20 bytes
  1918.         stosb
  1919.         mov     al, cl
  1920.         stosb
  1921.         mov     ax, [esi + TCP_SOCKET.RCV_WND]
  1922.         rol     ax, 8
  1923.         stosw                   ; window
  1924.         xor     eax, eax
  1925.         stosd                   ; checksum + urgentpointer
  1926.  
  1927. ;---------------------
  1928. ; Fill in the checksum
  1929.  
  1930.   .checksum:
  1931.         sub     edi, TCP_segment.Data
  1932.         mov     ecx, TCP_segment.Data
  1933.         xchg    esi, edi
  1934.         TCP_checksum (edi + IP_SOCKET.LocalIP), (esi + IP_SOCKET.RemoteIP)
  1935.         mov     [esi+TCP_segment.Checksum], dx
  1936.  
  1937. ;--------------------
  1938. ; And send the segment
  1939.  
  1940.         call    [ebx + NET_DEVICE.transmit]
  1941.         ret
  1942.  
  1943.   .error:
  1944.         DEBUGF  1,"TCP_respond failed\n"
  1945.         add     esp, 2+4
  1946.  
  1947.         ret
  1948.  
  1949.  
  1950.  
  1951. ;-------------------------
  1952. ; TCP_respond.segment:
  1953. ;
  1954. ;  IN:  edx = segment ptr (a previously received segment)
  1955. ;        cl = flags
  1956.  
  1957. align 4
  1958. TCP_respond_segment:
  1959.  
  1960.         DEBUGF  1,"TCP_respond_segment\n"
  1961.  
  1962. ;---------------------
  1963. ; Create the IP packet
  1964.  
  1965.         push    cx edx
  1966.         mov     ebx, [edx - 20 + IPv4_Packet.SourceAddress]      ;;;; and what if ip packet had options?!
  1967.         mov     eax, [edx - 20 + IPv4_Packet.DestinationAddress]   ;;;
  1968.         mov     ecx, TCP_segment.Data
  1969.         mov     di , IP_PROTO_TCP shl 8 + 128
  1970.         call    IPv4_output
  1971.         test    edi, edi
  1972.         jz      .error
  1973.  
  1974.         pop     esi cx
  1975.         push    edx eax
  1976.  
  1977. ;---------------------------------------------------
  1978. ; Fill in the TCP header by using a received segment
  1979.  
  1980.         mov     ax, [esi + TCP_segment.DestinationPort]
  1981.         rol     ax, 8
  1982.         stosw
  1983.         mov     ax, [esi + TCP_segment.SourcePort]
  1984.         rol     ax, 8
  1985.         stosw
  1986.         mov     eax, [esi + TCP_segment.AckNumber]
  1987.         bswap   eax
  1988.         stosd
  1989.         xor     eax, eax
  1990.         stosd
  1991.         mov     al, 0x50        ; Dataoffset: 20 bytes
  1992.         stosb
  1993.         mov     al, cl
  1994.         stosb
  1995.         mov     ax, 1280
  1996.         rol     ax, 8
  1997.         stosw                   ; window
  1998.         xor     eax, eax
  1999.         stosd                   ; checksum + urgentpointer
  2000.  
  2001. ;---------------------
  2002. ; Fill in the checksum
  2003.  
  2004.   .checksum:
  2005.         lea     esi, [edi - TCP_segment.Data]
  2006.         mov     ecx, TCP_segment.Data
  2007.         TCP_checksum (esi - 20 + IPv4_Packet.DestinationAddress), (esi - 20 + IPv4_Packet.DestinationAddress)
  2008.         mov     [esi+TCP_segment.Checksum], dx
  2009.  
  2010. ;--------------------
  2011. ; And send the segment
  2012.  
  2013.         call    [ebx + NET_DEVICE.transmit]
  2014.         ret
  2015.  
  2016.   .error:
  2017.         DEBUGF  1,"TCP_respond failed\n"
  2018.         add     esp, 2+4
  2019.  
  2020.         ret
  2021.  
  2022.  
  2023.  
  2024.  
  2025. ;---------------------------------------------------------------------------
  2026. ;
  2027. ; TCP_API
  2028. ;
  2029. ; This function is called by system function 75
  2030. ;
  2031. ; IN:  subfunction number in bl
  2032. ;      device number in bh
  2033. ;      ecx, edx, .. depends on subfunction
  2034. ;
  2035. ; OUT:
  2036. ;
  2037. ;---------------------------------------------------------------------------
  2038. align 4
  2039. TCP_API:
  2040.  
  2041.         movzx   eax, bh
  2042.         shl     eax, 2
  2043.  
  2044.         test    bl, bl
  2045.         jz      .packets_tx     ; 0
  2046.         dec     bl
  2047.         jz      .packets_rx     ; 1
  2048.  
  2049. .error:
  2050.         mov     eax, -1
  2051.         ret
  2052.  
  2053. .packets_tx:
  2054.         add     eax, TCP_segments_tx
  2055.         mov     eax, [eax]
  2056.         ret
  2057.  
  2058. .packets_rx:
  2059.         add     eax, TCP_segments_rx
  2060.         mov     eax, [eax]
  2061.         ret
  2062.