Subversion Repositories Kolibri OS

Rev

Rev 1529 | 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: 1530 $
  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]
  244.         adc     dh, byte [IP1+0]
  245.         adc     dl, byte [IP1+3]
  246.         adc     dh, byte [IP1+2]
  247.  
  248.         ; destination address
  249.         adc     dl, byte [IP2+1]
  250.         adc     dh, byte [IP2+0]
  251.         adc     dl, byte [IP2+3]
  252.         adc     dh, byte [IP2+2]
  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 (esp), (esp+4)
  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.         cmp     [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.         movzx   eax, word[edi+2]
  479.         rol     ax, 8
  480.         DEBUGF  1,"Maxseg: %u", ax
  481.  
  482.         mov     [ebx + TCP_SOCKET.t_maxseg], eax
  483.  
  484.        @@:
  485.         add     edi, 4
  486.         jmp     .opt_loop
  487.  
  488.  
  489.   .opt_window:
  490.         cmp     byte [edi+1], 3
  491.         jne     .no_options
  492.  
  493.         test    [edx + TCP_segment.Flags], TH_SYN
  494.         jz      @f
  495.  
  496.         DEBUGF  1,"Got window option"
  497.  
  498.         ;;;;;
  499.        @@:
  500.         add     edi, 3
  501.         jmp     .opt_loop
  502.  
  503.  
  504.   .opt_timestamp:
  505.         cmp     byte [edi+1], 10
  506.         jne     .no_options
  507.  
  508.         DEBUGF  1,"Got timestamp option"
  509.  
  510.         ;;;;;
  511.  
  512.         add     edi, 10
  513.         jmp     .opt_loop
  514.  
  515.   .no_options:
  516.  
  517. ;-----------------------------------------------------------------------
  518. ; Time to do some header prediction (Original Principle by Van Jacobson)
  519.  
  520. ; There are two common cases for an uni-directional data transfer.
  521. ;
  522. ; General rule: the packets has no control flags, is in-sequence,
  523. ;   window width didnt change and we're not retransmitting.
  524. ;
  525. ; Second rules:
  526. ;  -  If the length is 0 and the ACK moved forward, we're the sender side of the transfer.
  527. ;      In this case we'll free the ACK'ed data and notify higher levels that we have free space in buffer
  528. ;
  529. ;  -  If the length is not 0 and the ACK didn't move, we're the receiver side of the transfer.
  530. ;      If the packets are in order (data queue is empty), add the data to the socket buffer and request a delayed ACK
  531.  
  532.         cmp     [ebx + TCP_SOCKET.t_state], TCB_ESTABLISHED
  533.         jnz     .not_uni_xfer
  534.  
  535.         test    [edx + TCP_segment.Flags], TH_SYN + TH_FIN + TH_RST + TH_URG
  536.         jnz     .not_uni_xfer
  537.  
  538.         test    [edx + TCP_segment.Flags], TH_ACK
  539.         jz      .not_uni_xfer
  540.  
  541.         mov     eax, [edx + TCP_segment.SequenceNumber]
  542.         cmp     eax, [ebx + TCP_SOCKET.RCV_NXT]
  543.         jne     .not_uni_xfer
  544.  
  545.         movzx   eax, [edx + TCP_segment.Window] ;;;;; (should use pre-calculated value isntead: todo: figure out where to store it)
  546.         cmp     eax, [ebx + TCP_SOCKET.SND_WND]
  547.         jne     .not_uni_xfer
  548.  
  549.         mov     eax, [ebx + TCP_SOCKET.SND_NXT]
  550.         cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
  551.         jne     .not_uni_xfer
  552.  
  553. ;---------------------------------------
  554. ; check if we are sender in the uni-xfer
  555.  
  556. ; If the following 4 conditions are all true, this segment is a pure ACK.
  557. ;
  558. ; - The segment contains no data.
  559.         test    ecx, ecx
  560.         jnz     .not_sender
  561.  
  562. ; - The congestion window is greater than or equal to the current send window.
  563. ;     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.
  564.         mov     eax, [ebx + TCP_SOCKET.SND_CWND]
  565.         cmp     eax, [ebx + TCP_SOCKET.SND_WND]
  566.         jl      .not_uni_xfer
  567.  
  568. ; - The acknowledgment field in the segment is less than or equal to the maximum sequence number sent.
  569.         mov     ecx, [edx + TCP_segment.AckNumber]
  570.         cmp     ecx, [ebx + TCP_SOCKET.SND_MAX]
  571.         jg      .not_uni_xfer
  572.  
  573. ; - The acknowledgment field in the segment is greater than the largest unacknowledged sequence number.
  574.         sub     ecx, [ebx + TCP_SOCKET.SND_UNA]
  575.         jle     .not_uni_xfer
  576.  
  577.         DEBUGF  1,"Header prediction: we are sender\n"
  578.  
  579. ;---------------------------------
  580. ; Packet is a pure ACK, process it
  581.  
  582. ; Update RTT estimators
  583.  
  584. ; Delete acknowledged bytes from send buffer
  585. ; notice how ecx already holds number of bytes ack-ed
  586.  
  587.         lea     eax, [ebx + snd]
  588.         call    SOCKET_ring_free
  589.  
  590. ; Stop retransmit timer
  591.         mov     [ebx + TCP_SOCKET.timer_ack], 0
  592.  
  593. ; Awaken waiting processes
  594.         mov     eax, ebx
  595.         call    SOCKET_notify_owner
  596.  
  597. ; Generate more output
  598.         call    TCP_output
  599.  
  600.         jmp     .drop
  601.  
  602. ;-------------------------------------------------
  603. ; maybe we are the receiver in the uni-xfer then..
  604.  
  605.   .not_sender:
  606. ; - The amount of data in the segment is greater than 0 (data count is in ecx)
  607.  
  608. ; - The acknowledgment field equals the largest unacknowledged sequence number. This means no data is acknowledged by this segment.
  609.         mov     eax, [edx + TCP_segment.AckNumber]
  610.         cmp     eax, [ebx + TCP_SOCKET.SND_UNA]
  611.         jne     .not_uni_xfer
  612.  
  613. ; - The reassembly list of out-of-order segments for the connection is empty (seg_next equals tp). ;;;;;;;
  614.  
  615.         jnz     .not_uni_xfer
  616.  
  617. ;-------------------------------------
  618. ; Complete processing of received data
  619.  
  620.         DEBUGF  1,"header prediction: we are receiver\nreceiving %u bytes of data\n", ecx
  621.  
  622.         add     esi, edx
  623.         lea     eax, [ebx + rcv]
  624.         call    SOCKET_ring_add                         ; Add the data to the socket buffer
  625.  
  626.         add     [ebx + TCP_SOCKET.RCV_NXT], ecx         ; Update sequence number with number of bytes we have copied
  627.         or      [ebx + TCP_SOCKET.t_flags], TF_DELACK   ; Set delayed ack flag
  628.  
  629.         jmp     .drop
  630.  
  631. ;----------------------------------------------------
  632. ; Header prediction failed, doing it the slow way..     ;;;;; current implementation of header prediction destroys some regs (ecx) !!
  633.  
  634.   .not_uni_xfer:
  635.  
  636.         DEBUGF  1,"Header prediction failed\n"
  637.  
  638. ;------------------------------
  639. ; Calculate receive window size
  640.  
  641.         ;;;;
  642.  
  643. ;-------------------------
  644. ; TCP slow input procedure
  645.  
  646.         DEBUGF  1,"TCP slow input procedure\n"
  647.  
  648.         cmp     [ebx + TCP_SOCKET.t_state], TCB_LISTEN
  649.         je      .LISTEN
  650.  
  651.         cmp     [ebx + TCP_SOCKET.t_state], TCB_SYN_SENT
  652.         je      .SYN_SENT
  653.  
  654. ;--------------------------------------------
  655. ; Protection Against Wrapped Sequence Numbers
  656.  
  657. ; First, check timestamp if present
  658.  
  659. ;;;; TODO
  660.  
  661. ; Then, check if at least some bytes of data are within window
  662.  
  663. ;;;; TODO
  664.  
  665.         jmp     .trim_then_step6
  666.  
  667. ;-------------
  668. ; Passive Open
  669.  
  670. align 4
  671. .LISTEN:
  672.  
  673.         DEBUGF  1,"TCP state: listen\n"
  674.  
  675.         test    [edx + TCP_segment.Flags], TH_RST
  676.         jnz     .drop
  677.  
  678.         test    [edx + TCP_segment.Flags], TH_ACK
  679.         jnz     .drop_with_reset
  680.  
  681.         test    [edx + TCP_segment.Flags], TH_SYN
  682.         jz      .drop
  683.  
  684.         ; TODO: find sender ip address somewhere!
  685.         ; TODO: check if it's a broadcast or multicast, and drop if so
  686.  
  687.         call    SOCKET_fork
  688.         jz      .drop           ; if we could not open a new connection, drop segment (;;;; should we send RST too?)
  689.  
  690. ;-----------------------
  691. ; Fill in some variables
  692.  
  693.         add     [TCP_sequence_num], 64000
  694.  
  695.         push    [edx + TCP_segment.SourcePort]
  696.         pop     [eax + TCP_SOCKET.RemotePort]
  697.  
  698.         push    [edx + TCP_segment.SequenceNumber]
  699.         pop     [eax + TCP_SOCKET.IRS]
  700.  
  701.         push    [eax + TCP_SOCKET.ISS]
  702.         pop     [eax + TCP_SOCKET.SND_NXT]
  703.  
  704.         mov     [eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
  705.         mov     [eax + TCP_SOCKET.t_flags], TF_ACKNOW
  706.         mov     [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval
  707.  
  708.         mov     ebx, eax
  709.  
  710.         jmp     .trim_then_step6
  711.  
  712.  
  713. ;------------
  714. ; Active Open
  715.  
  716. align 4
  717. .SYN_SENT:
  718.  
  719.         DEBUGF  1,"TCP state: syn_sent\n"
  720.  
  721.         test    [edx + TCP_segment.Flags], TH_ACK
  722.         jz      @f
  723.  
  724.         mov     eax, [edx + TCP_segment.AckNumber]
  725.         cmp     eax, [ebx + TCP_SOCKET.ISS]
  726.         jle     .drop_with_reset
  727.  
  728.         DEBUGF  1,"snd_max = %x\n", [ebx + TCP_SOCKET.SND_MAX]   ;;; TODO: set this, but where?
  729.  
  730. ;        mov     eax, [edx + TCP_segment.AckNumber]
  731. ;;        cmp     eax, [ebx + TCP_SOCKET.SND_MAX]
  732. ;;        jg      .drop_with_reset
  733.        @@:
  734.  
  735.         test    [edx + TCP_segment.Flags], TH_RST
  736.         jz      @f
  737.  
  738.         test    [edx + TCP_segment.Flags], TH_ACK
  739.         jz      .drop
  740.  
  741.         ;tp = tcp_drop(tp, ECONNREFUSED)
  742.  
  743.         jmp     .drop
  744.        @@:
  745.  
  746.         test    [edx + TCP_segment.Flags], TH_SYN
  747.         jz      .drop
  748.  
  749. ; at this point, segment seems to be valid
  750.  
  751.         test    [edx + TCP_segment.Flags], TH_ACK
  752.         jz      .no_syn_ack
  753.  
  754. ; now, process received SYN in response to an active open
  755.  
  756.         mov     eax, [edx + TCP_segment.AckNumber]
  757.         mov     [ebx + TCP_SOCKET.SND_UNA], eax
  758.         cmp     eax, [ebx + TCP_SOCKET.SND_NXT]
  759.         jle     @f
  760.         mov     [ebx + TCP_SOCKET.SND_NXT], eax
  761.        @@:
  762.  
  763.   .no_syn_ack:
  764.  
  765.         mov     [ebx + TCP_SOCKET.timer_retransmission], 0      ; disable retransmission
  766.  
  767.         push    [edx + TCP_segment.SequenceNumber]
  768.         pop     [ebx + TCP_SOCKET.IRS]
  769.  
  770. ;;; TODO: tcp_rcvseqinit
  771.  
  772.         mov     [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
  773.  
  774.         mov     eax, [ebx + TCP_SOCKET.SND_UNA]
  775.         cmp     eax, [ebx + TCP_SOCKET.ISS]
  776.         jle     .simultaneous_open
  777.  
  778.         test    [edx + TCP_segment.Flags], TH_ACK
  779.         jz      .simultaneous_open
  780.  
  781.         DEBUGF  1,"TCP: active open\n"
  782.  
  783. ; TODO: update stats
  784. ; TODO: set socket state to connected
  785.  
  786.         mov     [ebx + TCP_SOCKET.t_state], TCB_ESTABLISHED
  787.  
  788. ; TODO: check if we should scale the connection (567-572)
  789. ; TODO: update RTT estimators
  790.  
  791.         jmp     .trimthenstep6
  792.  
  793.   .simultaneous_open:
  794.  
  795.         DEBUGF  1,"TCP: simultaneous open\n"
  796. ; We have received a syn but no ACK, so we are having a simultaneous open..
  797.         mov     [ebx + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
  798.  
  799. ;-------------------------------------
  800. ; Common processing for receipt of SYN
  801.  
  802.   .trimthenstep6:
  803.  
  804.         inc     [edx + TCP_segment.SequenceNumber]
  805.  
  806.         cmp     cx, [ebx + TCP_SOCKET.RCV_WND]
  807.         jle     @f
  808.  
  809.         movzx   eax, cx
  810.         sub     ax, [ebx + TCP_SOCKET.RCV_WND]
  811.         ; TODO: 592
  812.         mov     cx, [ebx + TCP_SOCKET.RCV_WND]
  813.         ; TODO...
  814.        @@:
  815.         ;;;;;
  816.         jmp     .step6
  817.  
  818.  
  819.  
  820.  
  821.  
  822.   .trim_then_step6:
  823.  
  824.         DEBUGF  1,"Trimming window\n"
  825.  
  826. ;----------------------------
  827. ; trim any data not in window
  828.  
  829.         mov     eax, [ebx + TCP_SOCKET.RCV_NXT]
  830.         sub     eax, [edx + TCP_segment.SequenceNumber]
  831.  
  832.         test    eax, eax
  833.         jz      .no_drop
  834.  
  835.         test    [edx + TCP_segment.Flags], TH_SYN
  836.         jz      .no_drop
  837.  
  838.         and     [edx + TCP_segment.Flags], not (TH_SYN)
  839.         inc     [edx + TCP_segment.SequenceNumber]
  840.  
  841.         cmp     [edx + TCP_segment.UrgentPointer], 1
  842.         jl      @f
  843.  
  844.         dec     [edx + TCP_segment.UrgentPointer]
  845.  
  846.         jmp     .no_drop
  847.        @@:
  848.  
  849.         and     [edx + TCP_segment.Flags], not (TH_URG)
  850.         dec     eax
  851.  
  852.   .no_drop:
  853.  
  854.         DEBUGF  1,"Going to drop %u bytes of data", eax
  855.  
  856. ; eax holds number of bytes to drop
  857.  
  858. ;----------------------------------
  859. ; Check for entire duplicate packet
  860.  
  861.         cmp     eax, ecx
  862.         jge     .duplicate
  863.  
  864.         ;;; TODO: figure 28.30
  865.  
  866. ;------------------------
  867. ; Check for duplicate FIN
  868.  
  869.         test    [edx + TCP_segment.Flags], TH_FIN
  870.         jz      @f
  871.         inc     ecx
  872.         cmp     eax, ecx
  873.         dec     ecx
  874.         jne     @f
  875.  
  876.         mov     eax, ecx
  877.         and     [edx + TCP_segment.Flags], not TH_FIN
  878.         or      [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
  879.         jmp     .no_duplicate
  880.        @@:
  881.  
  882.         ; Handle the case when a bound socket connects to itself
  883.         ; Allow packets with a SYN and an ACKto continue with the processing
  884.  
  885. ;-------------------------------------
  886. ; Generate duplicate ACK if nescessary
  887.  
  888. ; This code also handles simultaneous half-open or self-connects
  889.  
  890.         test    eax, eax
  891.         jnz     .drop_after_ack
  892.  
  893.         cmp     [edx + TCP_segment.Flags], TH_ACK
  894.         jz      .drop_after_ack
  895.  
  896.   .duplicate:
  897.  
  898.         DEBUGF  1,"Duplicate received"
  899.  
  900. ;----------------------------------------
  901. ; Update statistics for duplicate packets
  902.  
  903.         ;;; TODO
  904.  
  905.         jmp     .drop          ;;; DROP the packet ??
  906.  
  907.   .no_duplicate:
  908.  
  909. ;-----------------------------------------------
  910. ; Remove duplicate data and update urgent offset
  911.  
  912.         add     [edx + TCP_segment.SequenceNumber], eax
  913.  
  914.         ;;; TODO
  915.  
  916.         sub     [edx + TCP_segment.UrgentPointer], ax
  917.         jg      @f
  918.  
  919.         and     [edx + TCP_segment.Flags], not (TH_URG)
  920.         mov     [edx + TCP_segment.UrgentPointer], 0
  921.        @@:
  922.  
  923. ;--------------------------------------------------
  924. ; Handle data that arrives after process terminates
  925.  
  926.         cmp     [ebx + SOCKET.PID], 0
  927.         jge     @f
  928.  
  929.         cmp     [ebx + TCP_SOCKET.t_state], TCB_CLOSE_WAIT
  930.         jle     @f
  931.  
  932.         test    ecx, ecx
  933.         jz      @f
  934.  
  935.         ;;; Close the socket
  936.         ;;; update stats
  937.  
  938.         jmp     .drop_with_reset
  939.  
  940.        @@:
  941.  
  942. ;----------------------------------------
  943. ; Remove data beyond right edge of window
  944.  
  945.         mov     eax, [edx + TCP_segment.SequenceNumber]
  946.         add     eax, ecx
  947.         sub     eax, [ebx + TCP_SOCKET.RCV_NXT]
  948.         sub     ax, [ebx + TCP_SOCKET.RCV_WND]
  949.  
  950.         ; eax now holds the number of bytes to drop
  951.  
  952.         jle     .no_excess_data
  953.  
  954.         ;;; TODO: update stats
  955.  
  956.         cmp     eax, ecx
  957.         jl      .dont_drop_all
  958.  
  959. ;;; TODO 700-736
  960.  
  961.   .dont_drop_all:
  962.  
  963.   .no_excess_data:
  964.  
  965. ;-----------------
  966. ; Record timestamp
  967.  
  968.         ;;; TODO 737-746
  969.  
  970. ;------------------
  971. ; Process RST flags
  972.  
  973.         test    [edx + TCP_segment.Flags], TH_RST
  974.         jz      .rst_skip
  975.  
  976.         DEBUGF  1,"Got an RST flag"
  977.  
  978.         mov     eax, [ebx + TCP_SOCKET.t_state]
  979.         shl     eax, 2
  980.         jmp     dword [eax + .rst_sw_list]
  981.  
  982.   .rst_sw_list:
  983.         dd      .rst_skip       ;TCB_CLOSED
  984.         dd      .rst_skip       ;TCB_LISTEN
  985.         dd      .rst_skip       ;TCB_SYN_SENT
  986.         dd      .econnrefused   ;TCB_SYN_RECEIVED
  987.         dd      .econnreset     ;TCB_ESTABLISHED
  988.         dd      .econnreset     ;TCB_CLOSE_WAIT
  989.         dd      .econnreset     ;TCB_FIN_WAIT_1
  990.         dd      .rst_close      ;TCB_CLOSING
  991.         dd      .rst_close      ;TCB_LAST_ACK
  992.         dd      .econnreset     ;TCB_FIN_WAIT_2
  993.         dd      .rst_close      ;TCB_TIMED_WAIT
  994.  
  995.   .econnrefused:
  996.  
  997.         DEBUGF  1,"Connection refused"
  998.  
  999.         ;;; TODO: debug info
  1000.  
  1001.         jmp     .close
  1002.  
  1003.   .econnreset:
  1004.  
  1005.         DEBUGF  1,"Connection reset"
  1006.  
  1007.         ;;; TODO: debug info
  1008.   .close:
  1009.  
  1010.         DEBUGF  1,"Closing connection"
  1011.  
  1012.         ;;; update stats
  1013.  
  1014.   .rst_close:
  1015.  
  1016.         DEBUGF  1,"Closing with reset"
  1017.  
  1018.         ;;; Close the socket
  1019.         jmp     .drop
  1020.  
  1021.   .rst_skip:
  1022.  
  1023. ;--------------------------------------
  1024. ; handle SYN-full and ACK-less segments
  1025.  
  1026.         test    [edx + TCP_segment.Flags], TH_SYN
  1027.         jz      @f
  1028.  
  1029.         ;;; tcp_drop ( ECONNRESET)
  1030.         jmp     .drop_with_reset
  1031.  
  1032.         test    [edx + TCP_segment.Flags], TH_ACK
  1033.         jz      .drop
  1034.  
  1035. ;----------------
  1036. ; Process the ACK
  1037.  
  1038.         cmp     [ebx + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
  1039.         jg      .ack_dup
  1040.         jl      .ack_nodup
  1041.  
  1042.         ;;;;;
  1043.  
  1044.   .ack_dup:
  1045.  
  1046.         ;;;;
  1047.  
  1048.   .ack_nodup:
  1049.  
  1050.         ;;;; 887
  1051.  
  1052. ;-------------------------------------------------
  1053. ; If the congestion window was inflated to account
  1054. ; for the other side's cached packets, retrace it
  1055.  
  1056.         ;;;; 888 -  902
  1057.  
  1058.  
  1059. ;------------------------------------------
  1060. ; RTT measurements and retransmission timer
  1061.  
  1062.         ;;;;; 903 - 926
  1063.  
  1064.         mov     [ebx + TCP_SOCKET.timer_retransmission], 0
  1065.  
  1066.         mov     eax, [ebx + TCP_SOCKET.SND_MAX]
  1067.         cmp     eax, [edx + TCP_segment.AckNumber]
  1068.         je      .all_outstanding
  1069.         mov     [ebx + TCP_SOCKET.timer_retransmission], 120 ;;;; TODO: correct this value
  1070.   .all_outstanding:
  1071.  
  1072.  
  1073. ;-------------------------------------------
  1074. ; Open congestion window in response to ACKs
  1075.  
  1076.         ;;;;
  1077.  
  1078.  
  1079. ;------------------------------------------
  1080. ; Remove acknowledged data from send buffer
  1081.  
  1082.         lea     eax, [ebx + snd]
  1083.         mov     ecx, ecx                ;;;; 943 - 956
  1084.         call    SOCKET_ring_free
  1085.  
  1086. ;---------------------------------------
  1087. ; Wake up process waiting on send buffer
  1088.  
  1089.         mov     eax, ebx
  1090.         call    SOCKET_notify_owner
  1091.  
  1092.         mov     eax, [ebx + TCP_SOCKET.t_state]
  1093.         shl     eax, 2
  1094.         jmp     dword [eax + .ACK_sw_list]
  1095.  
  1096.   .ACK_sw_list:
  1097.         dd      .step6          ;TCB_CLOSED
  1098.         dd      .step6          ;TCB_LISTEN
  1099.         dd      .step6          ;TCB_SYN_SENT
  1100.         dd      .step6          ;TCB_SYN_RECEIVED
  1101.         dd      .step6          ;TCB_ESTABLISHED
  1102.         dd      .step6          ;TCB_CLOSE_WAIT
  1103.         dd      ._963           ;TCB_FIN_WAIT_1
  1104.         dd      ._958           ;TCB_CLOSING
  1105.         dd      ._999           ;TCB_LAST_ACK
  1106.         dd      .step6          ;TCB_FIN_WAIT_2
  1107.         dd      ._1010          ;TCB_TIMED_WAIT
  1108.  
  1109.  
  1110. ._963:
  1111.  
  1112.  
  1113.         jmp     .step6
  1114.  
  1115.  
  1116. ._958:
  1117.  
  1118.         jmp     .step6
  1119.  
  1120. ._999:
  1121.  
  1122.         jmp     .step6
  1123.  
  1124.  
  1125. ._1010:
  1126.  
  1127.         jmp     .step6
  1128.  
  1129.  
  1130.  
  1131. align 4
  1132. .step6:
  1133.  
  1134.         DEBUGF  1,"step 6\n"
  1135.  
  1136. ;--------------------------
  1137. ; update window information
  1138.  
  1139.         test    [edx + TCP_segment.Flags], TH_ACK
  1140.         jz      .no_window_update
  1141.  
  1142.         mov     eax, [ebx + TCP_SOCKET.SND_WL1]
  1143.         cmp     eax, [edx + TCP_segment.SequenceNumber]
  1144.  
  1145.         ;;;; 1021
  1146.  
  1147. ;----------------------------------
  1148. ; Keep track of pure window updates
  1149.  
  1150.         test    ecx, ecx
  1151.         jz      @f
  1152.  
  1153.         mov     eax, [ebx + TCP_SOCKET.SND_WL2]
  1154.         cmp     eax, [edx + TCP_segment.AckNumber]
  1155.         jne     @f
  1156.  
  1157.         ;; mov eax, tiwin
  1158.         cmp     eax, [ebx + TCP_SOCKET.SND_WND]
  1159.         jle     @f
  1160.  
  1161.         ;;; update stats
  1162.  
  1163.        @@:
  1164.  
  1165.         ;; mov eax, incoming window
  1166.         cmp     eax, [ebx + TCP_SOCKET.max_sndwnd]
  1167.         jle     @f
  1168.         mov     [ebx + TCP_SOCKET.max_sndwnd], eax
  1169.        @@:
  1170.         mov     [ebx + TCP_SOCKET.SND_WND], eax
  1171.  
  1172.         mov     eax, [edx + TCP_segment.SequenceNumber]
  1173.         mov     [ebx + TCP_SOCKET.SND_WL1], eax
  1174.  
  1175.         mov     eax, [edx + TCP_segment.AckNumber]
  1176.         mov     [ebx + TCP_SOCKET.SND_WL2], eax
  1177.  
  1178.         ;;; needoutput = 1
  1179.  
  1180.   .no_window_update:
  1181.  
  1182. ;-----------------
  1183. ; process URG flag
  1184.  
  1185.         test    [edx + TCP_segment.Flags], TH_URG
  1186.         jz      .not_urgent
  1187.  
  1188.         cmp     [edx + TCP_segment.UrgentPointer], 0
  1189.         jz      .not_urgent
  1190.  
  1191.         cmp     [ebx + TCP_SOCKET.t_state], TCB_TIMED_WAIT
  1192.         je      .not_urgent
  1193.  
  1194. ; Ignore bogus urgent offsets
  1195.  
  1196.         ;;; 1040-1050
  1197.  
  1198.         movzx   eax, [edx + TCP_segment.UrgentPointer]
  1199.         add     eax, [ebx + rcv.size]
  1200.         cmp     eax, SOCKET_MAXDATA
  1201.         jle     .not_urgent
  1202.  
  1203.         mov     [edx + TCP_segment.UrgentPointer], 0
  1204.         and     [edx + TCP_segment.Flags], not (TH_URG)
  1205.         jmp     .do_data
  1206.  
  1207.   .not_urgent:
  1208.  
  1209. ;--------------------------------------
  1210. ; processing of received urgent pointer
  1211.  
  1212.         ;;; TODO (1051-1093)
  1213.  
  1214. ;--------------------------------
  1215. ; process the data in the segment
  1216.  
  1217.   .do_data:
  1218.  
  1219.         DEBUGF  1,"TCP: do data:\n"
  1220.  
  1221.         test    [edx + TCP_segment.Flags], TH_FIN
  1222.         jnz     .process_fin
  1223.  
  1224.         test    [ebx + TCP_SOCKET.t_state], TCB_FIN_WAIT_1
  1225.         jge     .dont_do_data
  1226.  
  1227.         DEBUGF  1,"Processing data in segment\n"
  1228.  
  1229.         ;;; NOW, process the data
  1230.  
  1231.         jmp     .final_processing
  1232.  
  1233.  
  1234.   .dont_do_data:
  1235.  
  1236. ;---------------
  1237. ; FIN processing
  1238.  
  1239.   .process_fin:
  1240.  
  1241.         DEBUGF  1,"Processing FIN\n"
  1242.  
  1243.         mov     eax, [ebx + TCP_SOCKET.t_state]
  1244.         shl     eax, 2
  1245.         jmp     dword [eax + .FIN_sw_list]
  1246.  
  1247.   .FIN_sw_list:
  1248.         dd      .no_fin         ;TCB_CLOSED
  1249.         dd      .no_fin         ;TCB_LISTEN
  1250.         dd      .no_fin         ;TCB_SYN_SENT
  1251.         dd      ._1131          ;TCB_SYN_RECEIVED
  1252.         dd      ._1131          ;TCB_ESTABLISHED
  1253.         dd      .no_fin         ;TCB_CLOSE_WAIT
  1254.         dd      ._1139          ;TCB_FIN_WAIT_1
  1255.         dd      .no_fin         ;TCB_CLOSING
  1256.         dd      .no_fin         ;TCB_LAST_ACK
  1257.         dd      ._1147          ;TCB_FIN_WAIT_2
  1258.         dd      ._1156          ;TCB_TIMED_WAIT
  1259.  
  1260.  
  1261.  
  1262.   ._1131:
  1263.  
  1264.   ._1139:
  1265.  
  1266.   ._1147:
  1267.  
  1268.   ._1156:
  1269.  
  1270.  
  1271.   .no_fin:
  1272.  
  1273. ;-----------------
  1274. ; Final processing
  1275.  
  1276.   .final_processing:
  1277.  
  1278.         DEBUGF  1,"Final processing\n"
  1279.  
  1280.         ;;; if debug enabled, output packet
  1281.  
  1282.         ;test    ;;;needoutput = 1
  1283.         ;jnz     .outputnow
  1284.  
  1285.         test    [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
  1286.         jnz     .ack_now
  1287.  
  1288.         mov     [ebx + SOCKET.lock], 0
  1289.         call    kernel_free
  1290.         add     esp, 4
  1291.         ret
  1292.  
  1293.   .ack_now:
  1294.  
  1295.         DEBUGF  1,"ACK now!\n"
  1296.  
  1297.         push    ebx
  1298.         mov     eax, ebx
  1299.         call    TCP_output
  1300.         pop     ebx
  1301.  
  1302.         mov     [ebx + SOCKET.lock], 0
  1303.         call    kernel_free
  1304.         add     esp, 4
  1305.         ret
  1306.  
  1307. ;------------------------------------------
  1308. ; Generate an ACK, droping incoming segment
  1309.  
  1310. align 4
  1311. .drop_after_ack:
  1312.  
  1313.         DEBUGF  1,"Drop after ACK\n"
  1314.  
  1315.         test    [edx + TCP_segment.Flags], TH_RST
  1316.         jnz     .drop
  1317.  
  1318.         and     [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
  1319.  
  1320.         push    ebx
  1321.         mov     eax, ebx
  1322.         call    TCP_output
  1323.         pop     ebx
  1324.  
  1325.         mov     [ebx + SOCKET.lock], 0
  1326.         call    kernel_free
  1327.         add     esp, 4
  1328.         ret
  1329.  
  1330.  
  1331. ;-------------------------------------------
  1332. ; Generate an RST, dropping incoming segment
  1333.  
  1334. align 4
  1335. .drop_with_reset:
  1336.  
  1337.         DEBUGF  1,"Drop with reset\n"
  1338.  
  1339.         test    [edx + TCP_segment.Flags], TH_RST
  1340.         jnz     .drop
  1341.  
  1342.         ;;; if its a multicast/broadcast, also drop
  1343.  
  1344.         test    [edx + TCP_segment.Flags], TH_ACK
  1345.         jnz     .respond_ack
  1346.  
  1347.         test    [edx + TCP_segment.Flags], TH_SYN
  1348.         jnz     .respond_syn
  1349.  
  1350.         mov     [ebx + SOCKET.lock], 0
  1351.         call    kernel_free
  1352.         add     esp, 4
  1353.         ret
  1354.  
  1355.   .respond_ack:
  1356.  
  1357.         ;;;;
  1358.  
  1359.         call    TCP_respond_segment
  1360.  
  1361.         jmp     .destroy_new_socket
  1362.  
  1363.  
  1364.   .respond_syn:
  1365.  
  1366.         ;;;;
  1367.  
  1368.         call    TCP_respond_segment
  1369.  
  1370.         jmp     .destroy_new_socket
  1371.  
  1372. ;-----
  1373. ; Drop
  1374.  
  1375. align 4
  1376. .drop:
  1377.  
  1378.         DEBUGF  1,"Dropping packet\n"
  1379.  
  1380.         ;;;; If debugging options are enabled, output the packet somwhere
  1381.  
  1382.   .destroy_new_socket:
  1383.  
  1384.         ;;;; kill the newly created socket
  1385.  
  1386.         mov     [ebx + SOCKET.lock], 0
  1387.         call    kernel_free
  1388.         add     esp, 4
  1389.         ret
  1390.  
  1391.  
  1392.  
  1393.  
  1394.  
  1395.  
  1396. ;---------------------------
  1397. ;
  1398. ; TCP_pull_out_of_band
  1399. ;
  1400. ; IN:  eax =
  1401. ;      ebx = socket ptr
  1402. ;      edx = tcp packet ptr
  1403. ;
  1404. ; OUT: /
  1405. ;
  1406. ;---------------------------
  1407.  
  1408. align 4
  1409. TCP_pull_out_of_band:
  1410.  
  1411.         DEBUGF  1,"TCP_pull_out_of_band\n"
  1412.  
  1413.         ;;;; 1282-1305
  1414.  
  1415.         ret
  1416.  
  1417.  
  1418.  
  1419. ;-----------------------------------------------------------------
  1420. ;
  1421. ; TCP_output
  1422. ;
  1423. ; IN:  eax = socket pointer
  1424. ;;     esi = ptr to data
  1425. ;;     ecx = number of data bytes
  1426. ;
  1427. ; OUT: /
  1428. ;
  1429. ;-----------------------------------------------------------------
  1430. align 4
  1431. TCP_output:
  1432.  
  1433.         DEBUGF 1,"TCP_output, socket: %x\n", eax
  1434.  
  1435. ; We'll detect the length of the data to be transmitted, and flags to be used
  1436. ; If there is some data, or any critical controls to send (SYN / RST), then transmit
  1437. ; Otherwise, investigate further
  1438.  
  1439.         mov     ebx, [eax + TCP_SOCKET.SND_MAX]
  1440.         cmp     ebx, [eax + TCP_SOCKET.SND_UNA]
  1441.         jne     .not_idle
  1442.  
  1443.         mov     ebx, [eax + TCP_SOCKET.t_idle]
  1444.         cmp     ebx, [eax + TCP_SOCKET.t_rxtcur]
  1445.         jle     .not_idle
  1446.  
  1447. ; We have been idle for a while and no ACKS are expected to clock out any data we send..
  1448. ; Slow start to get ack "clock" running again.
  1449.  
  1450.         mov     ebx, [eax + TCP_SOCKET.t_maxseg]
  1451.         mov     [eax + TCP_SOCKET.SND_CWND], ebx
  1452.  
  1453.   .not_idle:
  1454.   .again:
  1455.         mov     ebx, [eax + TCP_SOCKET.SND_NXT]         ; calculate offset
  1456.         sub     ebx, [eax + TCP_SOCKET.SND_UNA]         ;
  1457.  
  1458.         mov     ecx, [eax + TCP_SOCKET.SND_WND]         ; determine window
  1459.         cmp     ecx, [eax + TCP_SOCKET.SND_CWND]        ;
  1460.         jl      @f                                      ;
  1461.         mov     ecx, [eax + TCP_SOCKET.SND_CWND]        ;
  1462.        @@:                                              ;
  1463.  
  1464.         call    TCP_outflags    ; in dl
  1465.  
  1466. ; If in persist timeout with window of 0, send 1 byte.
  1467. ; Otherwise, if window is small but nonzero, and timer expired,
  1468. ; we will send what we can and go to transmit state
  1469.  
  1470.         test    [eax + TCP_SOCKET.t_force], -1
  1471.         jz      .no_persist_timeout
  1472.  
  1473.         test    ecx, ecx
  1474.         jnz     .no_zero_window
  1475.  
  1476.         cmp     ebx, [eax + snd.size]
  1477.         jge     @f
  1478.  
  1479.         and     dl, not (TH_FIN)          ; clear the FIN flag    ??? how can it be set before?
  1480.  
  1481.        @@:
  1482.         inc     ecx
  1483.         jmp     .no_persist_timeout
  1484.  
  1485.   .no_zero_window:
  1486.  
  1487.         mov     [eax + TCP_SOCKET.timer_persist], 0     ;;;;
  1488.         mov     [eax + TCP_SOCKET.t_rxtshift], 0
  1489.  
  1490.   .no_persist_timeout:
  1491.  
  1492. ;;;106
  1493.  
  1494.         mov     esi, [eax + snd.size]
  1495.         cmp     esi, ecx
  1496.         jl      @f
  1497.         mov     esi, ecx
  1498.        @@:
  1499.         sub     esi, ebx
  1500.  
  1501.         cmp     esi, -1
  1502.         jne     .not_minus_one
  1503.  
  1504. ; If FIN has been set, but not ACKed, and we havent been called to retransmit,
  1505. ; len (esi) will be -1
  1506. ; Otherwise, window shrank after we sent into it.
  1507. ; If window shrank to 0, cancel pending retransmit and pull SND_NXT back to (closed) window
  1508. ; We will enter persist state below.
  1509. ; If window didn't close completely, just wait for an ACK
  1510.  
  1511.         xor     esi, esi
  1512.  
  1513.         test    ecx, ecx
  1514.         jnz     @f
  1515.  
  1516.         mov     [eax + TCP_SOCKET.timer_retransmission], 0   ; cancel retransmit
  1517.  
  1518.         push    [eax + TCP_SOCKET.SND_UNA]
  1519.         pop     [eax + TCP_SOCKET.SND_NXT]
  1520.        @@:
  1521.  
  1522.   .not_minus_one:
  1523.  
  1524. ;;; 124
  1525.  
  1526.         cmp     esi, [eax + TCP_SOCKET.t_maxseg]
  1527.         jle     @f
  1528.  
  1529.         mov     esi, [eax + TCP_SOCKET.t_maxseg]
  1530.         ;sendalot = 1
  1531.  
  1532.        @@:
  1533.  
  1534. ;;; 128
  1535.  
  1536.         mov     edi, [eax + TCP_SOCKET.SND_NXT]
  1537.         add     edi, esi        ; len
  1538.         sub     edi, [eax + TCP_SOCKET.SND_UNA]
  1539.         add     edi, [eax + snd.size]
  1540.         cmp     edi, 0
  1541.         jle     @f
  1542.  
  1543.         and     dl, not (TH_FIN)          ; clear the FIN flag
  1544.  
  1545.        @@:
  1546.  
  1547.  
  1548. ; set ecx to space available in receive buffer
  1549. ; From now on, ecx will be the window we advertise to the other end
  1550.  
  1551.         mov     ecx, SOCKET_MAXDATA
  1552.         sub     ecx, [eax + rcv.size]
  1553.  
  1554. ;------------------------------
  1555. ; Sender silly window avoidance
  1556.  
  1557.         cmp     ecx, [eax + TCP_SOCKET.t_maxseg]
  1558.         je      .send
  1559.  
  1560. ;;; TODO: 144-145
  1561.  
  1562.         test    [eax + TCP_SOCKET.t_force], -1
  1563.         jnz     .send
  1564.  
  1565.         mov     ebx, [eax + TCP_SOCKET.max_sndwnd]
  1566.         shr     ebx, 1
  1567.         cmp     ecx, ebx
  1568.         jge     .send
  1569.  
  1570.         mov     ebx, [eax + TCP_SOCKET.SND_NXT]
  1571.         cmp     ebx, [eax + TCP_SOCKET.SND_MAX]
  1572.         jl      .send
  1573.  
  1574. ;----------------------------------------
  1575. ; Check if a window update should be sent
  1576.  
  1577.         test    ecx, ecx        ; window
  1578.         jz      .no_window
  1579.  
  1580. ;;; TODO 154-172
  1581.  
  1582.   .no_window:
  1583.  
  1584. ;--------------------------
  1585. ; Should a segment be sent?
  1586.  
  1587.         test    [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
  1588.         jnz     .send
  1589.  
  1590.         test    dl, TH_SYN + TH_RST
  1591.         jnz     .send
  1592.  
  1593.         mov     eax, [ebx + TCP_SOCKET.SND_UP]
  1594.         cmp     eax, [ebx + TCP_SOCKET.SND_UNA]
  1595.         jg      .send
  1596.  
  1597.         test    dl, TH_FIN
  1598.         jz      .enter_persist
  1599.  
  1600.         test    [ebx + TCP_SOCKET.t_flags], TF_SENTFIN
  1601.         jnz     .send
  1602.  
  1603.         mov     eax, [ebx + TCP_SOCKET.SND_NXT]
  1604.         cmp     eax, [ebx + TCP_SOCKET.SND_UNA]
  1605.         je      .send
  1606.  
  1607. ;--------------------
  1608. ; Enter persist state
  1609.  
  1610.   .enter_persist:
  1611.  
  1612.         DEBUGF  1,"Entering persist state\n"
  1613.  
  1614. ;--------------------------------------
  1615. ; No reason to send a segment, just ret
  1616.  
  1617.         DEBUGF  1,"No reason to send a segment\n"
  1618.  
  1619.         ret
  1620.  
  1621.  
  1622. ;-----------------------------------------------
  1623. ;
  1624. ; Send a segment
  1625. ;
  1626. ; eax = socket pointer
  1627. ;  dl = flags
  1628. ;
  1629. ;-----------------------------------------------
  1630.  
  1631.   .send:
  1632.  
  1633.         DEBUGF  1,"Preparing to send a segment\n"
  1634.  
  1635.         mov     edi, TCP_segment.Data   ; edi will contain headersize
  1636.  
  1637.         sub     esp, 8                  ; create some space on stack
  1638.         push    eax                     ; save this too..
  1639.  
  1640. ;------------------------------------
  1641. ; Send options with first SYN segment
  1642.  
  1643.         test    dl, TH_SYN
  1644.         jz      .no_options
  1645.  
  1646.         push    [eax + TCP_SOCKET.ISS]
  1647.         pop     [eax + TCP_SOCKET.SND_NXT]
  1648.  
  1649.         test    [eax + TCP_SOCKET.t_flags], TF_NOOPT
  1650.         jnz     .no_options
  1651.  
  1652.         mov     ecx, 1460
  1653.         or      ecx, TCP_OPT_MAXSEG shl 24 + 4 shl 16
  1654.         bswap   ecx
  1655.         push    ecx
  1656.         add     di, 4
  1657.  
  1658.         test    [eax + TCP_SOCKET.t_flags], TF_REQ_SCALE
  1659.         jz      .no_syn
  1660.  
  1661.         test    dl, TH_ACK
  1662.         jnz     .scale_opt
  1663.  
  1664.         test    [eax + TCP_SOCKET.t_flags], TF_RCVD_SCALE
  1665.         jz      .no_syn
  1666.  
  1667.   .scale_opt:
  1668.         movzx   ecx, byte [eax + TCP_SOCKET.request_r_scale]
  1669.         or      ecx, TCP_OPT_WINDOW shl 24 + 4 shl 16 + TCP_OPT_NOP shl 8
  1670.         bswap   ecx
  1671.         pushd   ecx
  1672.         add     di, 4
  1673.  
  1674.   .no_syn:
  1675.  
  1676. ;------------------------------------
  1677. ; Make the timestamp option if needed
  1678.  
  1679.         test    [eax + TCP_SOCKET.t_flags], TF_REQ_TSTMP
  1680.         jz      .no_timestamp
  1681.  
  1682.         test    dl, TH_RST
  1683.         jnz     .no_timestamp
  1684.  
  1685.         test    dl, TH_ACK
  1686.         jz      .timestamp
  1687.  
  1688.         test    [eax + TCP_SOCKET.t_flags], TF_RCVD_TSTMP
  1689.         jz      .no_timestamp
  1690.  
  1691.   .timestamp:
  1692.         mov     esi, [timer_ticks]
  1693.         bswap   esi
  1694.         push    esi
  1695.         pushw   0
  1696.         pushd   TCP_OPT_TIMESTAMP + 10 shl 8 + TCP_OPT_NOP shl 16 + TCP_OPT_NOP shl 24
  1697.         add     di, 10
  1698.  
  1699.   .no_timestamp:
  1700.         ;; TODO: check if we dont exceed the max segment size
  1701.  
  1702.   .no_options:
  1703.         ; eax = socket ptr
  1704.         ; edx = flags
  1705.         ; ecx = data size
  1706.         ; edi = header size
  1707.         ; esi = snd ring buff ptr
  1708.  
  1709.         xor     ecx, ecx        ;;;;;
  1710.         add     ecx, edi        ; total TCP segment size
  1711.  
  1712. ; Start by pushing all TCP header values in reverse order on stack
  1713. ; (essentially, creating the tcp header!)
  1714.  
  1715.         pushw   0       ;        .UrgentPointer          dw ?
  1716.         pushw   0       ;        .Checksum               dw ?
  1717.         pushw   0x00a0  ;        .Window                 dw ?    ;;;;;;;
  1718.         shl     edi, 2  ;        .DataOffset             db ?  only 4 left-most bits
  1719.         shl     dx, 8
  1720.         or      dx, di  ;        .Flags                  db ?
  1721.         pushw   dx
  1722.         shr     edi, 2  ;        .DataOffset             db ? ;;;;
  1723.  
  1724.         push    [eax + TCP_SOCKET.RCV_NXT]      ;        .AckNumber              dd ?
  1725.         ntohld  [esp]
  1726.  
  1727.         push    [eax + TCP_SOCKET.SND_NXT]      ;        .SequenceNumber         dd ?
  1728.         ntohld  [esp]
  1729.  
  1730.         push    [eax + TCP_SOCKET.RemotePort]   ;        .DestinationPort        dw ?
  1731.         ntohlw  [esp]
  1732.  
  1733.         push    [eax + TCP_SOCKET.LocalPort]    ;        .SourcePort             dw ?
  1734.         ntohlw  [esp]
  1735.  
  1736.         push    edi     ; header size
  1737.  
  1738. ; Create the IP packet
  1739.         mov     ebx, [eax + IP_SOCKET.LocalIP]  ; source ip
  1740.         mov     eax, [eax + IP_SOCKET.RemoteIP] ; dest ip
  1741. ;        mov     ecx,                            ; data length
  1742. ;        mov     dx,                             ; fragment id
  1743.         mov     di, IP_PROTO_TCP shl 8 + 128
  1744.         call    IPv4_output
  1745.         jz      .fail
  1746.  
  1747. ;-----------------------------------------
  1748. ; Move TCP header from stack to TCP packet
  1749.  
  1750. ;        pop     ecx                     ; header size
  1751. ;        mov     esi, esp
  1752. ;        add     esp, ecx
  1753. ;        shr     ecx, 2
  1754. ;        rep     movsd
  1755.  
  1756.         mov     ecx, [esp]
  1757.         lea     esi, [esp+4]
  1758.         shr     ecx, 2
  1759.         rep     movsd
  1760.  
  1761.         pop     ecx
  1762.         add     esp, ecx
  1763.  
  1764.         mov     [esp + 4+4], edx        ; packet size
  1765.         mov     [esp + 4], eax          ; packet ptr
  1766.  
  1767.         mov     edx, edi
  1768.         sub     edx, ecx
  1769.  
  1770. ;--------------
  1771. ; Copy the data
  1772.  
  1773. ; eax = ptr to ring struct
  1774. ; ecx = buffer size
  1775. ; edi = ptr to buffer
  1776.  
  1777.         mov     eax, [esp]              ; socket ptr
  1778.         push    ecx edx
  1779.         add     eax, snd
  1780.         call    SOCKET_ring_read
  1781.         pop     esi ecx
  1782.         pop     eax
  1783.  
  1784. ;-------------------------------------------------------------
  1785. ; Create the checksum  (we have already pushed IPs onto stack)
  1786.  
  1787.         DEBUGF  1,"checksum: ptr=%x size=%u\n", esi, ecx
  1788.  
  1789.         TCP_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP)
  1790.         mov     [esi+TCP_segment.Checksum], dx
  1791.  
  1792. ;----------------
  1793. ; Send the packet
  1794.  
  1795.         DEBUGF  1,"Sending TCP Packet to device %x\n", ebx
  1796.         call    [ebx + NET_DEVICE.transmit]
  1797.         ret
  1798.  
  1799.  
  1800.   .fail:
  1801.         pop     ecx
  1802.         add     esp, ecx
  1803.         add     esp, 4+4+8+4
  1804.         DEBUGF 1,"TCP_output: failed\n"
  1805.         ret
  1806.  
  1807.  
  1808.  
  1809. ;-------------------------
  1810. ;
  1811. ; TCP_outflags
  1812. ;
  1813. ;  IN:  eax = socket ptr
  1814. ;
  1815. ;  OUT: edx = flags
  1816. ;
  1817. ;-------------------------
  1818. align 4
  1819. TCP_outflags:
  1820.  
  1821.         mov     edx, [eax + TCP_SOCKET.t_state]
  1822.         movzx   edx, byte [edx + .flaglist]
  1823.  
  1824.         DEBUGF  1,"TCP_outflags, socket: %x, flags: %x\n", eax, dl
  1825.  
  1826.         ret
  1827.  
  1828.   .flaglist:
  1829.  
  1830.         db      TH_RST + TH_ACK         ; TCB_CLOSED
  1831.         db      0                       ; TCB_LISTEN
  1832.         db      TH_SYN                  ; TCB_SYN_SENT
  1833.         db      TH_SYN + TH_ACK         ; TCB_SYN_RECEIVED
  1834.         db               TH_ACK         ; TCB_ESTABLISHED
  1835.         db               TH_ACK         ; TCB_CLOSE_WAIT
  1836.         db      TH_SYN + TH_ACK         ; TCB_FIN_WAIT_1
  1837.         db      TH_SYN + TH_ACK         ; TCB_CLOSING
  1838.         db      TH_SYN + TH_ACK         ; TCB_LAST_ACK
  1839.         db               TH_ACK         ; TCB_FIN_WAIT_2
  1840.         db               TH_ACK         ; TCB_TIMED_WAIT
  1841.  
  1842.  
  1843.  
  1844.  
  1845. ;-------------------------
  1846. ;
  1847. ; TCP_drop
  1848. ;
  1849. ;  IN:  eax = socket ptr
  1850. ;
  1851. ;  OUT: /
  1852. ;
  1853. ;-------------------------
  1854. align 4
  1855. TCP_drop:
  1856.  
  1857.         DEBUGF  1,"TCP_drop\n"
  1858.  
  1859. ;        cmp     [eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
  1860. ;        jl      .no_syn_received
  1861.  
  1862.         mov     [eax + TCP_SOCKET.t_state], TCB_CLOSED
  1863.  
  1864.         call    TCP_output
  1865.  
  1866. ;  .no_syn_received:
  1867.  
  1868.         ret
  1869.  
  1870.  
  1871.  
  1872.  
  1873.  
  1874. ;---------------------------------------
  1875. ;
  1876. ; The easy way to send an ACK/RST/keepalive segment
  1877. ;
  1878. ; TCP_respond_socket:
  1879. ;
  1880. ;  IN:  ebx = socket ptr
  1881. ;        cl = flags
  1882. ;
  1883. ;--------------------------------------
  1884. align 4
  1885. TCP_respond_socket:
  1886.  
  1887.         DEBUGF  1,"TCP_respond_socket\n"
  1888.  
  1889. ;---------------------
  1890. ; Create the IP packet
  1891.  
  1892.         push    cx ebx
  1893.         mov     eax, [ebx + IP_SOCKET.RemoteIP]
  1894.         mov     ebx, [ebx + IP_SOCKET.LocalIP]
  1895.         mov     ecx, TCP_segment.Data
  1896.         mov     di , IP_PROTO_TCP shl 8 + 128
  1897.         call    IPv4_output
  1898.         test    edi, edi
  1899.         jz      .error
  1900.         pop     esi cx
  1901.         push    edx eax
  1902.  
  1903. ;-----------------------------------------------
  1904. ; Fill in the TCP header by using the socket ptr
  1905.  
  1906.         mov     ax, [esi + TCP_SOCKET.LocalPort]
  1907.         rol     ax, 8
  1908.         stosw
  1909.         mov     ax, [esi + TCP_SOCKET.RemotePort]
  1910.         rol     ax, 8
  1911.         stosw
  1912.         mov     eax, [esi + TCP_SOCKET.SND_NXT]
  1913.         bswap   eax
  1914.         stosd
  1915.         mov     eax, [esi + TCP_SOCKET.RCV_NXT]
  1916.         bswap   eax
  1917.         stosd
  1918.         mov     al, 0x50        ; Dataoffset: 20 bytes
  1919.         stosb
  1920.         mov     al, cl
  1921.         stosb
  1922.         mov     ax, [esi + TCP_SOCKET.RCV_WND]
  1923.         rol     ax, 8
  1924.         stosw                   ; window
  1925.         xor     eax, eax
  1926.         stosd                   ; checksum + urgentpointer
  1927.  
  1928. ;---------------------
  1929. ; Fill in the checksum
  1930.  
  1931.   .checksum:
  1932.         sub     edi, TCP_segment.Data
  1933.         mov     ecx, TCP_segment.Data
  1934.         xchg    esi, edi
  1935.         TCP_checksum (edi + IP_SOCKET.LocalIP), (esi + IP_SOCKET.RemoteIP)
  1936.         mov     [esi+TCP_segment.Checksum], dx
  1937.  
  1938. ;--------------------
  1939. ; And send the segment
  1940.  
  1941.         call    [ebx + NET_DEVICE.transmit]
  1942.         ret
  1943.  
  1944.   .error:
  1945.         DEBUGF  1,"TCP_respond failed\n"
  1946.         add     esp, 2+4
  1947.  
  1948.         ret
  1949.  
  1950.  
  1951.  
  1952. ;-------------------------
  1953. ; TCP_respond.segment:
  1954. ;
  1955. ;  IN:  edx = segment ptr (a previously received segment)
  1956. ;        cl = flags
  1957.  
  1958. align 4
  1959. TCP_respond_segment:
  1960.  
  1961.         DEBUGF  1,"TCP_respond_segment\n"
  1962.  
  1963. ;---------------------
  1964. ; Create the IP packet
  1965.  
  1966.         push    cx edx
  1967.         mov     ebx, [edx - 20 + IPv4_Packet.SourceAddress]      ;;;; and what if ip packet had options?!
  1968.         mov     eax, [edx - 20 + IPv4_Packet.DestinationAddress]   ;;;
  1969.         mov     ecx, TCP_segment.Data
  1970.         mov     di , IP_PROTO_TCP shl 8 + 128
  1971.         call    IPv4_output
  1972.         test    edi, edi
  1973.         jz      .error
  1974.  
  1975.         pop     esi cx
  1976.         push    edx eax
  1977.  
  1978. ;---------------------------------------------------
  1979. ; Fill in the TCP header by using a received segment
  1980.  
  1981.         mov     ax, [esi + TCP_segment.DestinationPort]
  1982.         rol     ax, 8
  1983.         stosw
  1984.         mov     ax, [esi + TCP_segment.SourcePort]
  1985.         rol     ax, 8
  1986.         stosw
  1987.         mov     eax, [esi + TCP_segment.AckNumber]
  1988.         bswap   eax
  1989.         stosd
  1990.         xor     eax, eax
  1991.         stosd
  1992.         mov     al, 0x50        ; Dataoffset: 20 bytes
  1993.         stosb
  1994.         mov     al, cl
  1995.         stosb
  1996.         mov     ax, 1280
  1997.         rol     ax, 8
  1998.         stosw                   ; window
  1999.         xor     eax, eax
  2000.         stosd                   ; checksum + urgentpointer
  2001.  
  2002. ;---------------------
  2003. ; Fill in the checksum
  2004.  
  2005.   .checksum:
  2006.         lea     esi, [edi - TCP_segment.Data]
  2007.         mov     ecx, TCP_segment.Data
  2008.         TCP_checksum (esi - 20 + IPv4_Packet.DestinationAddress), (esi - 20 + IPv4_Packet.DestinationAddress)
  2009.         mov     [esi+TCP_segment.Checksum], dx
  2010.  
  2011. ;--------------------
  2012. ; And send the segment
  2013.  
  2014.         call    [ebx + NET_DEVICE.transmit]
  2015.         ret
  2016.  
  2017.   .error:
  2018.         DEBUGF  1,"TCP_respond failed\n"
  2019.         add     esp, 2+4
  2020.  
  2021.         ret
  2022.  
  2023.  
  2024.  
  2025.  
  2026. ;---------------------------------------------------------------------------
  2027. ;
  2028. ; TCP_API
  2029. ;
  2030. ; This function is called by system function 75
  2031. ;
  2032. ; IN:  subfunction number in bl
  2033. ;      device number in bh
  2034. ;      ecx, edx, .. depends on subfunction
  2035. ;
  2036. ; OUT:
  2037. ;
  2038. ;---------------------------------------------------------------------------
  2039. align 4
  2040. TCP_API:
  2041.  
  2042.         movzx   eax, bh
  2043.         shl     eax, 2
  2044.  
  2045.         test    bl, bl
  2046.         jz      .packets_tx     ; 0
  2047.         dec     bl
  2048.         jz      .packets_rx     ; 1
  2049.  
  2050. .error:
  2051.         mov     eax, -1
  2052.         ret
  2053.  
  2054. .packets_tx:
  2055.         add     eax, TCP_segments_tx
  2056.         mov     eax, [eax]
  2057.         ret
  2058.  
  2059. .packets_rx:
  2060.         add     eax, TCP_segments_rx
  2061.         mov     eax, [eax]
  2062.         ret
  2063.