Subversion Repositories Kolibri OS

Rev

Rev 914 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;  TCP.INC                                                     ;;
  7. ;;                                                              ;;
  8. ;;  TCP Processes for Menuet OS  TCP/IP stack                   ;;
  9. ;;                                                              ;;
  10. ;;  Copyright 2002 Mike Hibbett, mikeh@oceanfree.net            ;;
  11. ;;                                                              ;;
  12. ;;  See file COPYING for details                                ;;
  13. ;;  v0.6 : Added reset handling in the established state        ;;
  14. ;;         Added a timer per socket to allow delays when        ;;
  15. ;;         rx window gets below 1KB                             ;;
  16. ;;                                                              ;;
  17. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  18.  
  19. $Revision: 2971 $
  20.  
  21.  
  22. ; TCP TCB states
  23. TCB_LISTEN         equ        1
  24. TCB_SYN_SENT       equ        2
  25. TCB_SYN_RECEIVED   equ        3
  26. TCB_ESTABLISHED    equ        4
  27. TCB_FIN_WAIT_1     equ        5
  28. TCB_FIN_WAIT_2     equ        6
  29. TCB_CLOSE_WAIT     equ        7
  30. TCB_CLOSING        equ        8
  31. TCB_LAST_ACK       equ        9
  32. TCB_TIMED_WAIT     equ        10
  33. TCB_CLOSED         equ        11
  34.  
  35. TH_FIN  = 0x01
  36. TH_SYN  = 0x02
  37. TH_RST  = 0x04
  38. TH_PUSH = 0x08
  39. TH_ACK  = 0x10
  40. TH_URG  = 0x20
  41.  
  42. TWOMSL              equ     10      ; # of secs to wait before closing socket
  43.  
  44. TCP_RETRIES         equ         5               ; Number of times to resend a packet
  45. TCP_TIMEOUT         equ         10              ; resend if not replied to in x hs
  46.  
  47. ;*******************************************************************
  48. ;   Interface
  49. ;
  50. ;       tcp_tx_handler      Handles the TCP transmit queue
  51. ;       tcp_rx              The protocol handler for received data
  52. ;       buildTCPPacket      fills in the packet headers and data
  53. ;       tcpStateMachine     Main state machine for received TCP packets
  54. ;       tcp_tcb_handler     1s timer, to erase tcb's in TIME_WAIT state
  55. ;
  56. ;*******************************************************************
  57.  
  58.  
  59. ;   TCP Payload ( Data field in IP datagram )
  60. ;
  61. ;    0                   1                   2                   3
  62. ;    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  63. ;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  64. ;20 |          Source Port          |       Destination Port        |
  65. ;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  66. ;24 |                        Sequence Number                        |
  67. ;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  68. ;28 |                    Acknowledgment Number                      |
  69. ;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  70. ;32 |  Data |           |U|A|P|R|S|F|                               |
  71. ;   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
  72. ;   |       |           |G|K|H|T|N|N|                               |
  73. ;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  74. ;36 |           Checksum            |         Urgent Pointer        |
  75. ;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  76. ;40 |                    Options                    |    Padding    |
  77. ;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  78. ;   |                             data
  79.  
  80.  
  81. struc TCP_PACKET
  82. {  .SourcePort       dw  ?  ;+00
  83.    .DestinationPort  dw  ?  ;+02
  84.    .SequenceNumber   dd  ?  ;+04
  85.    .AckNumber        dd  ?  ;+08
  86.    .DataOffset       db  ?  ;+12 - DataOffset[0-3 bits] and Reserved[4-7]
  87.    .Flags            db  ?  ;+13 - Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN
  88.    .Window           dw  ?  ;+14
  89.    .Checksum         dw  ?  ;+16
  90.    .UrgentPointer    dw  ?  ;+18
  91.    .Options          rb  3  ;+20
  92.    .Padding          db  ?  ;+23
  93.    .Data             db  ?  ;+24
  94. }
  95.  
  96. virtual at 0
  97.   TCP_PACKET TCP_PACKET
  98. end virtual
  99.  
  100.  
  101.  
  102. ;***************************************************************************
  103. ;   Function
  104. ;      tcp_tcb_handler
  105. ;
  106. ;   Description
  107. ;       Handles sockets in the timewait state, closing them
  108. ;       when the TCB timer expires
  109. ;
  110. ;***************************************************************************
  111.  
  112. proc tcp_tcb_handler stdcall uses ebx
  113.     ; scan through all the sockets, decrementing active timers
  114.  
  115.         mov     ebx, net_sockets
  116.  
  117.         cmp     [ebx + SOCKET.NextPtr], 0
  118.         je      .exit
  119.         ;DEBUGF 1, "K : sockets:\n"
  120.  
  121.   .next_socket:
  122.         mov     ebx, [ebx + SOCKET.NextPtr]
  123.         or      ebx, ebx
  124.         jz      .exit
  125.  
  126.         ;DEBUGF 1, "K :   %x-%x: %x-%x-%x-%u\n", [ebx + SOCKET.PID]:2, [ebx + SOCKET.Number]:2, [ebx + SOCKET.LocalPort]:4, [ebx + SOCKET.RemoteIP], [ebx + SOCKET.RemotePort]:4, [ebx + SOCKET.TCBState]
  127.  
  128.         cmp     [ebx + SOCKET.TCBTimer], 0
  129.         jne     .decrement_tcb
  130.         cmp     [ebx + SOCKET.wndsizeTimer], 0
  131.         jne     .decrement_wnd
  132.         jmp     .next_socket
  133.  
  134.   .decrement_tcb:
  135.     ; decrement it, delete socket if TCB timer = 0 & socket in timewait state
  136.         dec     [ebx + SOCKET.TCBTimer]
  137.         jnz     .next_socket
  138.  
  139.         cmp     [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
  140.         jne     .next_socket
  141.  
  142.         push    [ebx + SOCKET.PrevPtr]
  143.         stdcall net_socket_free, ebx
  144.         pop     ebx
  145.         jmp     .next_socket
  146.  
  147.   .decrement_wnd:
  148.     ; TODO - prove it works!
  149.         dec     [ebx + SOCKET.wndsizeTimer]
  150.         jmp     .next_socket
  151.  
  152.   .exit:
  153.     ret
  154. endp
  155.  
  156.  
  157. ;***************************************************************************
  158. ;   Function
  159. ;      tcp_tx_handler
  160. ;
  161. ;   Description
  162. ;       Handles queued TCP data
  163. ;       This is a kernel function, called by stack_handler
  164. ;
  165. ;***************************************************************************
  166.  
  167. proc tcp_tx_handler stdcall
  168.     ; decrement all resend buffers timers. If they
  169.     ; expire, queue them for sending, and restart the timer.
  170.     ; If the retries counter reach 0, delete the entry
  171.  
  172.     mov     esi, resendQ
  173.     mov     ecx, 0
  174.  
  175.   .next_resendq:
  176.     cmp     ecx, NUMRESENDENTRIES
  177.         je      .exit               ; None left
  178.         cmp     dword[esi + 4], 0
  179.         jne     @f                   ; found one
  180.     inc     ecx
  181.         add     esi, 8
  182.         jmp     .next_resendq
  183.  
  184.     @@: ; we have one. decrement it's timer by 1
  185.         dec     word[esi + 2]
  186.         jz      @f
  187.     inc     ecx
  188.         add     esi, 8
  189.         jmp     .next_resendq       ; Timer not zero, so move on
  190.  
  191.     @@:
  192.         xor     ebx, ebx
  193.     ; restart timer, and decrement retries
  194.     ; After the first resend, back of on next, by a factor of 5
  195.         mov     [esi + 2], word TCP_TIMEOUT * 5
  196.         dec     byte[esi + 1]
  197.         jnz     @f
  198.  
  199.     ; retries now 0, so delete from queue
  200.         xchg     [esi + 4], ebx
  201.  
  202.     @@: ; resend packet
  203.         pushad
  204.  
  205.     mov     eax, EMPTY_QUEUE
  206.     call    dequeue
  207.     cmp     ax, NO_BUFFER
  208.         jne     .tth004z
  209.  
  210.     ; TODO - try again in 10ms.
  211.         test    ebx, ebx
  212.         jnz     @f
  213.         mov     [esi + 4], ebx
  214.  
  215.     @@: ; Mark it to expire in 10ms - 1 tick
  216.         mov     byte[esi + 1], 1
  217.         mov     word[esi + 2], 1
  218.         jmp     .tth005
  219.  
  220.   .tth004z:
  221.     ; we have a buffer # in ax
  222.  
  223.         push    eax ecx
  224.     mov     ecx, IPBUFFSIZE
  225.     mul     ecx
  226.     add     eax, IPbuffs
  227.  
  228.     ; we have the buffer address in eax
  229.     mov     edi, eax
  230.     pop     ecx
  231.     ; Now get buffer location, and copy buffer across. argh! more copying,,
  232.         mov     esi, resendBuffer
  233.     @@: add     esi, IPBUFFSIZE
  234.         loop    @b
  235.  
  236.     ; we have resend buffer location in esi
  237.     mov     ecx, IPBUFFSIZE
  238.  
  239.     ; copy data across
  240.         push    edi
  241.     cld
  242.     rep     movsb
  243.         pop     edi
  244.  
  245.     ; queue packet
  246.  
  247.  
  248.  
  249.     mov     eax, NET1OUT_QUEUE
  250.  
  251.     mov     edx, [stack_ip]
  252.         cmp     edx, [edi + IP_PACKET.DestinationAddress]
  253.         jne     .not_local
  254.     mov     eax, IPIN_QUEUE
  255.  
  256.   .not_local:
  257.     pop     ebx
  258.  
  259.     call    queue
  260.  
  261.   .tth005:
  262.         popad
  263.  
  264.     inc     ecx
  265.         add     esi, 8
  266.         jmp     .next_resendq
  267.  
  268.   .exit:
  269.     ret
  270. endp
  271.  
  272.  
  273. ;***************************************************************************
  274. ;   Function
  275. ;      tcp_rx
  276. ;
  277. ;   Description
  278. ;       TCP protocol handler
  279. ;       This is a kernel function, called by ip_rx
  280. ;       IP buffer address given in edx
  281. ;          IP buffer number in eax
  282. ;          Free up (or re-use) IP buffer when finished
  283. ;
  284. ;***************************************************************************
  285.  
  286. proc tcp_rx stdcall uses ebx
  287.     ; The process is as follows.
  288.     ; Look for a socket with matching remote IP, remote port, local port
  289.     ; if not found, then
  290.     ; look for remote IP + local port match ( where sockets remote port = 0)
  291.     ; if not found, then
  292.     ; look for a socket where local socket port == IP packets remote port
  293.     ; where sockets remote port, remote IP = 0
  294.     ; discard if not found
  295.     ; Call sockets tcbStateMachine, with pointer to packet.
  296.     ; the state machine will not delete the packet, so do that here.
  297.  
  298.     push        eax
  299.  
  300.     ; Look for a socket where
  301.     ; IP Packet TCP Destination Port = local Port
  302.     ; IP Packet SA = Remote IP
  303.     ; IP Packet TCP Source Port = remote Port
  304.  
  305.         mov     ebx, net_sockets
  306.  
  307.   .next_socket.1:
  308.         mov     ebx, [ebx + SOCKET.NextPtr]
  309.         or      ebx, ebx
  310.         jz      .next_socket.1.exit
  311.  
  312. ;        DEBUGF  1, "K : tcp_rx - 1.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
  313.  
  314.         mov     ax, [edx + 20 + TCP_PACKET.DestinationPort]  ; get the dest. port from the TCP hdr
  315.         cmp     [ebx + SOCKET.LocalPort], ax            ; get the dest. port from the TCP hdr
  316.         jne     .next_socket.1                          ; different - try next socket
  317.  
  318. ;        DEBUGF  1, "K : tcp_rx - 1.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP]
  319.  
  320.         mov     eax, [edx + IP_PACKET.SourceAddress]    ; get the source IP Addr from the IP hdr
  321.         cmp     [ebx + SOCKET.RemoteIP], eax            ; compare with socket's remote IP
  322.         jne     .next_socket.1                          ; different - try next socket
  323.  
  324. ;        DEBUGF  1, "K : tcp_rx - 1.sport: %x - %x\n", [edx + 20 + TCP_PACKET.SourcePort]:4, [ebx + SOCKET.RemotePort]:4
  325.  
  326.         mov     ax, [edx + 20 + TCP_PACKET.SourcePort]  ; get the source port from the TCP hdr
  327.         cmp     [ebx + SOCKET.RemotePort], ax           ; compare with socket's remote port
  328.         jne     .next_socket.1                          ; different - try next socket
  329.  
  330.     ; We have a complete match - use this socket
  331.         jmp     .change_state
  332.  
  333.   .next_socket.1.exit:
  334.  
  335.     ; If we got here, there was no match
  336.     ; Look for a socket where
  337.     ; IP Packet TCP Destination Port = local Port
  338.     ; IP Packet SA = Remote IP
  339.     ; socket remote Port = 0
  340.  
  341.         mov     ebx, net_sockets
  342.  
  343.   .next_socket.2:
  344.         mov     ebx, [ebx + SOCKET.NextPtr]
  345.         or      ebx, ebx
  346.         jz      .next_socket.2.exit
  347.  
  348. ;        DEBUGF  1, "K : tcp_rx - 2.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
  349.  
  350.         mov     ax, [edx + 20 + TCP_PACKET.DestinationPort]  ; get the dest. port from the TCP hdr
  351.         cmp     [ebx + SOCKET.LocalPort], ax            ; compare with socket's local port
  352.         jne     .next_socket.2                          ; different - try next socket
  353.  
  354. ;        DEBUGF  1, "K : tcp_rx - 2.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP]
  355.  
  356.         mov     eax, [edx + IP_PACKET.SourceAddress]    ; get the source IP Addr from the IP hdr
  357.         cmp     [ebx + SOCKET.RemoteIP], eax            ; compare with socket's remote IP
  358.         jne     .next_socket.2                          ; different - try next socket
  359.  
  360. ;        DEBUGF  1, "K : tcp_rx - 2.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
  361.  
  362.         cmp     [ebx + SOCKET.RemotePort], 0            ; only match a remote socket of 0
  363.         jne     .next_socket.2                          ; different - try next socket
  364.  
  365.     ; We have a complete match - use this socket
  366.         jmp     .change_state
  367.  
  368.   .next_socket.2.exit:
  369.  
  370.     ; If we got here, there was no match
  371.     ; Look for a socket where
  372.     ; IP Packet TCP Destination Port = local Port
  373.     ; socket Remote IP = 0
  374.     ; socket remote Port = 0
  375.  
  376.         mov     ebx, net_sockets
  377.  
  378.   .next_socket.3:
  379.         mov     ebx, [ebx + SOCKET.NextPtr]
  380.         or      ebx, ebx
  381.         jz      .next_socket.3.exit
  382.  
  383. ;        DEBUGF  1, "K : tcp_rx - 3.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
  384.  
  385.         mov     ax, [edx + 20 + TCP_PACKET.DestinationPort]  ; get destination port from the TCP hdr
  386.         cmp     [ebx + SOCKET.LocalPort], ax            ; compare with socket's local port
  387.         jne     .next_socket.3                          ; different - try next socket
  388.  
  389. ;        DEBUGF  1, "K : tcp_rx - 3.addr: 00000000 - %x\n", [ebx + SOCKET.RemoteIP]
  390.  
  391.         cmp     [ebx + SOCKET.RemoteIP], 0              ; only match a socket remote IP of 0
  392.         jne     .next_socket.3                          ; different - try next socket
  393.  
  394. ;        DEBUGF  1, "K : tcp_rx - 3.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
  395.  
  396.         cmp     [ebx + SOCKET.RemotePort], 0            ; only match a remote socket of 0
  397.         jne     .next_socket.3                          ; different - try next socket
  398.  
  399.     ; We have a complete match - use this socket
  400.         jmp     .change_state
  401.  
  402.   .next_socket.3.exit:
  403.  
  404.     ; If we got here, we need to reject the packet
  405.  
  406.         DEBUGF  1, "K : tcp_rx - dumped\n"
  407.         DEBUGF  1, "K :   --------: %x-%x-%x (flags: %x)\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [edx + IP_PACKET.SourceAddress], [edx + 20 + TCP_PACKET.SourcePort]:4, [edx + 20 + TCP_PACKET.Flags]:2
  408.  
  409.         inc     [dumped_rx_count]
  410.         jmp     .exit
  411.  
  412.   .change_state:
  413.  
  414.     ; We have a valid socket/TCB, so call the TCB State Machine for that skt.
  415.         ; socket is pointed to by ebx
  416.         ; IP packet is pointed to by edx
  417.     ; IP buffer number is on stack ( it will be popped at the end)
  418.  
  419.         stdcall tcpStateMachine, ebx
  420.  
  421.   .exit:
  422.     pop     eax
  423.     call    freeBuff
  424.  
  425.     ret
  426. endp
  427.  
  428.  
  429. ;***************************************************************************
  430. ;   Function
  431. ;      buildTCPPacket
  432. ;
  433. ;   Description
  434. ;       builds an IP Packet with TCP data fully populated for transmission
  435. ;       You may destroy any and all registers
  436. ;          TCP control flags specified in bl
  437. ;          This TCB is in [sktAddr]
  438. ;          User data pointed to by esi
  439. ;       Data length in ecx
  440. ;          Transmit buffer number in eax
  441. ;
  442. ;***************************************************************************
  443.  
  444. proc build_tcp_packet stdcall, sockAddr:DWORD
  445.     push    ecx                        ; Save data length
  446.  
  447.     ; convert buffer pointer eax to the absolute address
  448.     mov     ecx, IPBUFFSIZE
  449.     mul     ecx
  450.     add     eax, IPbuffs
  451.  
  452.     mov     edx, eax
  453.  
  454.         mov     [edx + 20 + TCP_PACKET.Flags], bl               ; TCP flags
  455.  
  456.         mov     ebx, [sockAddr]
  457.  
  458.     ; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
  459.  
  460.     ; Fill in the IP header ( some data is in the socket descriptor)
  461.         mov     eax, [ebx + SOCKET.LocalIP]
  462.         mov     [edx + IP_PACKET.SourceAddress], eax
  463.         mov     eax, [ebx + SOCKET.RemoteIP]
  464.         mov     [edx + IP_PACKET.DestinationAddress], eax
  465.  
  466.         mov     [edx + IP_PACKET.VersionAndIHL], 0x45
  467.         mov     [edx + IP_PACKET.TypeOfService], 0
  468.  
  469.     pop     eax                   ; Get the TCP data length
  470.     push    eax
  471.  
  472.     add     eax, 20 + 20           ; add IP header and TCP header lengths
  473.         rol     ax, 8
  474.         mov     [edx + IP_PACKET.TotalLength], ax
  475.         mov     [edx + IP_PACKET.Identification], 0
  476.         mov     [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040
  477.         mov     [edx + IP_PACKET.TimeToLive], 0x20
  478.         mov     [edx + IP_PACKET.Protocol], PROTOCOL_TCP
  479.  
  480.     ; Checksum left unfilled
  481.         mov     [edx + IP_PACKET.HeaderChecksum], 0
  482.  
  483.         ; Fill in the TCP header (some data is in the socket descriptor)
  484.         mov     ax, [ebx + SOCKET.LocalPort]
  485.         mov     [edx + 20 + TCP_PACKET.SourcePort], ax          ; Local Port
  486.  
  487.         mov     ax, [ebx + SOCKET.RemotePort]
  488.         mov     [edx + 20 + TCP_PACKET.DestinationPort], ax     ; desitination Port
  489.  
  490.     ; Checksum left unfilled
  491.         mov     [edx + 20 + TCP_PACKET.Checksum], 0
  492.  
  493.     ; sequence number
  494.         mov     eax, [ebx + SOCKET.SND_NXT]
  495.         mov     [edx + 20 + TCP_PACKET.SequenceNumber], eax
  496.  
  497.     ; ack number
  498.         mov     eax, [ebx + SOCKET.RCV_NXT]
  499.         mov     [edx + 20 + TCP_PACKET.AckNumber], eax
  500.  
  501.     ; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size)
  502.     ; 768 bytes seems better
  503.         mov     [edx + 20 + TCP_PACKET.Window], 0x0003
  504.  
  505.     ; Urgent pointer (0)
  506.         mov     [edx + 20 + TCP_PACKET.UrgentPointer], 0
  507.  
  508.     ; data offset ( 0x50 )
  509.         mov     [edx + 20 + TCP_PACKET.DataOffset], 0x50
  510.  
  511.     pop     ecx                  ; count of bytes to send
  512.     mov     ebx, ecx            ; need the length later
  513.  
  514.     cmp     ebx, 0
  515.         jz      @f
  516.  
  517.     mov     edi, edx
  518.     add     edi, 40
  519.     cld
  520.     rep     movsb               ; copy the data across
  521.  
  522.     @@: ; we have edx as IPbuffer ptr.
  523.     ; Fill in the TCP checksum
  524.     ; First, fill in pseudoheader
  525.         mov     eax, [edx + IP_PACKET.SourceAddress]
  526.     mov     [pseudoHeader], eax
  527.         mov     eax, [edx + IP_PACKET.DestinationAddress]
  528.         mov     [pseudoHeader + 4], eax
  529.         mov     word[pseudoHeader + 8], PROTOCOL_TCP shl 8 + 0
  530.     add     ebx, 20
  531.         mov     [pseudoHeader + 10], bh
  532.         mov     [pseudoHeader + 11], bl
  533.  
  534.     mov     eax, pseudoHeader
  535.     mov     [checkAdd1], eax
  536.         mov     word[checkSize1], 12
  537.     mov     eax, edx
  538.     add     eax, 20
  539.     mov     [checkAdd2], eax
  540.     mov     eax, ebx
  541.     mov     [checkSize2], ax
  542.  
  543.     call    checksum
  544.  
  545.     ; store it in the TCP checksum ( in the correct order! )
  546.     mov     ax, [checkResult]
  547.         rol     ax, 8
  548.         mov     [edx + 20 + TCP_PACKET.Checksum], ax
  549.  
  550.     ; Fill in the IP header checksum
  551.         GET_IHL eax, edx               ; get IP-Header length
  552.         stdcall checksum_jb, edx, eax  ; buf_ptr, buf_size
  553.         rol     ax, 8
  554.         mov     [edx + IP_PACKET.HeaderChecksum], ax
  555.  
  556.     ret
  557. endp
  558.  
  559.  
  560. ; Increments the 32 bit value pointed to by esi in internet order
  561. proc inc_inet_esi stdcall
  562.     push    eax
  563.         mov     eax, [esi]
  564.         bswap   eax
  565.         inc     eax
  566.         bswap   eax
  567.         mov     [esi], eax
  568.     pop     eax
  569.     ret
  570. endp
  571.  
  572.  
  573. ; Increments the 32 bit value pointed to by esi in internet order
  574. ; by the value in ecx
  575. proc add_inet_esi stdcall
  576.     push    eax
  577.         mov     eax, [esi]
  578.         bswap   eax
  579.     add     eax, ecx
  580.         bswap   eax
  581.         mov     [esi], eax
  582.     pop     eax
  583.     ret
  584. endp
  585.  
  586.  
  587. iglobal
  588.   TCBStateHandler dd \
  589.     stateTCB_LISTEN, \
  590.     stateTCB_SYN_SENT, \
  591.     stateTCB_SYN_RECEIVED, \
  592.     stateTCB_ESTABLISHED, \
  593.     stateTCB_FIN_WAIT_1, \
  594.     stateTCB_FIN_WAIT_2, \
  595.     stateTCB_CLOSE_WAIT, \
  596.     stateTCB_CLOSING, \
  597.     stateTCB_LAST_ACK, \
  598.     stateTCB_TIME_WAIT, \
  599.     stateTCB_CLOSED
  600. endg
  601.  
  602. ;***************************************************************************
  603. ;   Function
  604. ;      tcpStateMachine
  605. ;
  606. ;   Description
  607. ;       TCP state machine
  608. ;       This is a kernel function, called by tcp_rx
  609. ;
  610. ;       IP buffer address given in edx
  611. ;          Socket/TCB address in ebx
  612. ;
  613. ;       The IP buffer will be released by the caller
  614. ;***************************************************************************
  615.  
  616. proc tcpStateMachine stdcall, sockAddr:DWORD
  617.     ; as a packet has been received, update the TCB timer
  618.         mov     [ebx + SOCKET.TCBTimer], TWOMSL
  619.  
  620.     ; If the received packet has an ACK bit set,
  621.     ; remove any packets in the resend queue that this
  622.     ; received packet acknowledges
  623.         pushad
  624.         test    [edx + 20 + TCP_PACKET.Flags], TH_ACK
  625.         jz      .call_handler                                   ; No ACK, so no data yet
  626.  
  627.         ; get skt number in eax
  628.         stdcall net_socket_addr_to_num, ebx
  629.  
  630.     ; The ack number is in [edx + 28], inet format
  631.         ; skt in eax
  632.  
  633.     mov     esi, resendQ
  634.         xor     ecx, ecx
  635.  
  636.   .next_resendq:
  637.     cmp     ecx, NUMRESENDENTRIES
  638.         je      .call_handler     ; None left
  639.         cmp     [esi + 4], eax
  640.         je      @f                ; found one
  641.     inc     ecx
  642.         add     esi, 8
  643.         jmp     .next_resendq
  644.  
  645.     @@:                   ; Can we delete this buffer?
  646.  
  647.                           ; If yes, goto @@. No, goto .next_resendq
  648.     ; Get packet data address
  649.  
  650.     push    ecx
  651.     ; Now get buffer location, and copy buffer across. argh! more copying,,
  652.         imul    edi, ecx, IPBUFFSIZE
  653.         add     edi, resendBuffer
  654.  
  655.     ; we have dest buffer location in edi. incoming packet in edx.
  656.     ; Get this packets sequence number
  657.     ; preserve al, ecx, esi, edx
  658.         mov     ecx, [edi + 20 + TCP_PACKET.SequenceNumber]
  659.         bswap   ecx
  660.         movzx   ebx, word[edi + 2]
  661.         xchg    bl, bh
  662.     sub     ebx, 40
  663.     add     ecx, ebx          ; ecx is now seq# of last byte +1, intel format
  664.  
  665.     ; get recievd ack #, in intel format
  666.         mov     ebx, [edx + 20 + TCP_PACKET.AckNumber]
  667.         bswap   ebx
  668.  
  669.     cmp     ebx, ecx        ; Finally. ecx = rx'ed ack. ebx = last byte in que
  670.                             ; DANGER! need to handle case that we have just
  671.                             ; passed the 2**32, and wrapped round!
  672.     pop     ecx
  673.         jae     @f              ; if rx > old, delete old
  674.  
  675.     inc     ecx
  676.         add     esi, 8
  677.         jmp     .next_resendq
  678.  
  679.     @@: mov     dword[esi + 4], 0
  680.     inc     ecx
  681.         add     esi, 8
  682.         jmp     .next_resendq
  683.  
  684.   .call_handler:
  685.         popad
  686.  
  687.     ; Call handler for given TCB state
  688.  
  689.         mov     eax, [ebx + SOCKET.TCBState]
  690.         cmp     eax, TCB_LISTEN
  691.         jb      .exit
  692.         cmp     eax, TCB_CLOSED
  693.         ja      .exit
  694.  
  695.         stdcall [TCBStateHandler + (eax - 1) * 4], [sockAddr]
  696.  
  697.   .exit:
  698.     ret
  699. endp
  700.  
  701.  
  702. proc stateTCB_LISTEN stdcall, sockAddr:DWORD
  703.     ; In this case, we are expecting a SYN packet
  704.     ; For now, if the packet is a SYN, process it, and send a response
  705.     ; If not, ignore it
  706.  
  707.     ; Look at control flags
  708.         test    [edx + 20 + TCP_PACKET.Flags], TH_SYN
  709.         jz      .exit
  710.  
  711.     ; We have a SYN. update the socket with this IP packets details,
  712.     ; And send a response
  713.  
  714.         mov     eax, [edx + IP_PACKET.SourceAddress]
  715.         mov     [ebx + SOCKET.RemoteIP], eax
  716.         mov     ax, [edx + 20 + TCP_PACKET.SourcePort]
  717.         mov     [ebx + SOCKET.RemotePort], ax
  718.         mov     eax, [edx + 20 + TCP_PACKET.SequenceNumber]
  719.         mov     [ebx + SOCKET.IRS], eax
  720.         mov     [ebx + SOCKET.RCV_NXT], eax
  721.         lea     esi, [ebx + SOCKET.RCV_NXT]
  722.     call    inc_inet_esi ; RCV.NXT
  723.         mov     eax, [ebx + SOCKET.ISS]
  724.         mov     [ebx + SOCKET.SND_NXT], eax
  725.  
  726.     ; Now construct the response, and queue for sending by IP
  727.     mov     eax, EMPTY_QUEUE
  728.     call    dequeue
  729.     cmp     ax, NO_BUFFER
  730.         je      .exit
  731.  
  732.     push    eax
  733.         mov     bl, TH_SYN + TH_ACK
  734.         xor     ecx, ecx
  735.         xor     esi, esi
  736.         stdcall build_tcp_packet, [sockAddr]
  737.  
  738.     mov     eax, NET1OUT_QUEUE
  739.     mov     edx, [stack_ip]
  740.         mov     ecx, [sockAddr]
  741.         cmp     edx, [ecx + SOCKET.RemoteIP]
  742.         jne     .not_local
  743.     mov     eax, IPIN_QUEUE
  744.  
  745.   .not_local:
  746.        ; Send it.
  747.     pop     ebx
  748.     call    queue
  749.  
  750.         mov     esi, [sockAddr]
  751.         mov     [esi + SOCKET.TCBState], TCB_SYN_RECEIVED
  752.  
  753.         ; increment SND.NXT in socket
  754.         add     esi, SOCKET.SND_NXT
  755.     call    inc_inet_esi
  756.  
  757.   .exit:
  758.     ret
  759. endp
  760.  
  761.  
  762. proc stateTCB_SYN_SENT stdcall, sockAddr:DWORD
  763.     ; We are awaiting an ACK to our SYN, with a SYM
  764.     ; Look at control flags - expecting an ACK
  765.  
  766.         mov     al, [edx + 20 + TCP_PACKET.Flags]
  767.         and     al, TH_SYN + TH_ACK
  768.         cmp     al, TH_SYN + TH_ACK
  769.         je      .syn_ack
  770.  
  771.         test    al, TH_SYN
  772.         jz      .exit
  773.  
  774.         mov     [ebx + SOCKET.TCBState], TCB_SYN_RECEIVED
  775.         push    TH_SYN + TH_ACK
  776.         jmp     .send
  777.  
  778.   .syn_ack:
  779.         mov     [ebx + SOCKET.TCBState], TCB_ESTABLISHED
  780.         push    TH_ACK
  781.  
  782.   .send:
  783.     ; Store the recv.nxt field
  784.         mov     eax, [edx + 20 + TCP_PACKET.SequenceNumber]
  785.  
  786.     ; Update our recv.nxt field
  787.         mov     [ebx + SOCKET.RCV_NXT], eax
  788.         lea     esi, [ebx + SOCKET.RCV_NXT]
  789.     call    inc_inet_esi
  790.  
  791.     ; Send an ACK
  792.     ; Now construct the response, and queue for sending by IP
  793.     mov     eax, EMPTY_QUEUE
  794.     call    dequeue
  795.     cmp     ax, NO_BUFFER
  796.         pop     ebx
  797.         je      .exit
  798.  
  799.     push    eax
  800.  
  801.         xor     ecx, ecx
  802.         xor     esi, esi
  803.         stdcall build_tcp_packet, [sockAddr]
  804.  
  805.     mov     eax, NET1OUT_QUEUE
  806.  
  807.     mov     edx, [stack_ip]
  808.         mov     ecx, [sockAddr]
  809.         cmp     edx, [ecx + SOCKET.RemoteIP]
  810.         jne     .not_local
  811.     mov     eax, IPIN_QUEUE
  812.  
  813.   .not_local:
  814.        ; Send it.
  815.     pop     ebx
  816.     call    queue
  817.  
  818.   .exit:
  819.     ret
  820. endp
  821.  
  822.  
  823. proc stateTCB_SYN_RECEIVED stdcall, sockAddr:DWORD
  824.     ; In this case, we are expecting an ACK packet
  825.     ; For now, if the packet is an ACK, process it,
  826.     ; If not, ignore it
  827.  
  828.         test    [edx + 20 + TCP_PACKET.Flags], TH_RST
  829.         jz      .check_ack
  830.  
  831.         push    [ebx + SOCKET.OrigRemotePort] [ebx + SOCKET.OrigRemoteIP]
  832.         pop     [ebx + SOCKET.RemoteIP] [ebx + SOCKET.RemotePort]
  833.  
  834.         mov     [ebx + SOCKET.TCBState], TCB_LISTEN
  835.         jmp     .exit
  836.  
  837.   .check_ack:
  838.     ; Look at control flags - expecting an ACK
  839.         test    [edx + 20 + TCP_PACKET.Flags], TH_ACK
  840.         jz      .exit
  841.  
  842.         mov     [ebx + SOCKET.TCBState], TCB_ESTABLISHED
  843.  
  844.   .exit:
  845.     ret
  846. endp
  847.  
  848.  
  849. proc stateTCB_ESTABLISHED stdcall, sockAddr:DWORD
  850.     ; Here we are expecting data, or a request to close
  851.     ; OR both...
  852.  
  853.     ; Did we receive a FIN or RST?
  854.         test    [edx + 20 + TCP_PACKET.Flags], TH_FIN
  855.         jz      .check_ack
  856.  
  857.     ; It was a fin or reset.
  858.  
  859.     ; Remove resend entries from the queue  - I dont want to send any more data
  860.         pushad
  861.  
  862.         ; get skt #
  863.         stdcall net_socket_addr_to_num, ebx
  864.  
  865.     mov     esi, resendQ
  866.     mov     ecx, 0
  867.  
  868.   .next_resendq:
  869.     cmp     ecx, NUMRESENDENTRIES
  870.         je      .last_resendq       ; None left
  871.         cmp     [esi + 4], eax
  872.         je      @f                  ; found one
  873.         inc     ecx
  874.         add     esi, 8
  875.         jmp     .next_resendq
  876.  
  877.     @@: mov     dword[esi + 4], 0
  878.     inc     ecx
  879.         add     esi, 8
  880.         jmp     .next_resendq
  881.  
  882.   .last_resendq:
  883.         popad
  884.  
  885.     @@: ; Send an ACK to that fin, and enter closewait state
  886.  
  887.         mov     [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
  888.         lea     esi, [ebx + SOCKET.RCV_NXT]
  889.     mov     eax, [esi]              ; save original
  890.     call    inc_inet_esi
  891.     ;; jmp    ste_ack - NO, there may be data
  892.  
  893.   .check_ack:
  894.     ; Check that we received an ACK
  895.         test    [edx + 20 + TCP_PACKET.Flags], TH_ACK
  896.         jz      .exit
  897.  
  898.     ; TODO - done, I think!
  899.     ; First, look at the incoming window. If this is less than or equal to 1024,
  900.         ; Set the socket window timer to 1. This will stop an additional packets being queued.
  901.     ; ** I may need to tweak this value, since I do not know how many packets are already queued
  902.         mov     cx, [edx + 20 + TCP_PACKET.Window]
  903.         xchg    cl, ch
  904.     cmp     cx, 1024
  905.         ja      @f
  906.  
  907.         mov     [ebx + SOCKET.wndsizeTimer], 1
  908.  
  909.     @@: ; OK, here is the deal
  910.     ; My recv.nct field holds the seq of the expected next rec byte
  911.     ; if the recevied sequence number is not equal to this, do not
  912.     ; increment the recv.nxt field, do not copy data - just send a
  913.     ; repeat ack.
  914.  
  915.         ; recv.nxt is in dword [edx+24], in inet format
  916.     ; recv seq is in [sktAddr]+56, in inet format
  917.     ; just do a comparision
  918.         mov     ecx, [ebx + SOCKET.RCV_NXT]
  919.         cmp     [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
  920.         jne     @f
  921.     mov     ecx, eax
  922.  
  923.     @@: cmp     ecx, [edx + 20 + TCP_PACKET.SequenceNumber]
  924.         jne     .ack
  925.  
  926.  
  927.     ; Read the data bytes, store in socket buffer
  928.         movzx   ecx, [edx + IP_PACKET.TotalLength]
  929.         xchg    cl, ch
  930.     sub     ecx, 40                    ; Discard 40 bytes of header
  931.         ja      .data                      ; Read data, if any
  932.  
  933.     ; If we had received a fin, we need to ACK it.
  934.         cmp     [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
  935.         je      .ack
  936.         jmp     .exit
  937.  
  938.   .data:
  939.         push    ebx
  940.         add     ebx, SOCKET.lock
  941.         call    wait_mutex
  942.         pop     ebx
  943.  
  944.         push    ecx
  945.         push    [ebx + SOCKET.PID]      ; get socket owner PID
  946.         mov     eax, [ebx + SOCKET.rxDataCount]
  947.         add     eax, ecx
  948.         cmp     eax, SOCKETBUFFSIZE - SOCKETHEADERSIZE
  949.         ja      .overflow
  950.  
  951.         mov     [ebx + SOCKET.rxDataCount], eax      ; increment the count of bytes in buffer
  952.  
  953.     ; point to the location to store the data
  954.         lea     edi, [ebx + eax + SOCKETHEADERSIZE]
  955.         sub     edi, ecx
  956.  
  957.     add     edx, 40        ; edx now points to the data
  958.     mov     esi, edx
  959.  
  960.     cld
  961.     rep     movsb          ; copy the data across
  962.         mov     [ebx + SOCKET.lock], 0  ; release mutex
  963.  
  964.     ; flag an event to the application
  965.     pop     eax
  966.         mov     ecx, 1
  967.         mov     esi, TASK_DATA + TASKDATA.pid
  968.  
  969.   .next_pid:
  970.         cmp     [esi], eax
  971.         je      .found_pid
  972.     inc     ecx
  973.         add     esi, 0x20
  974.         cmp     ecx, [TASK_COUNT]
  975.         jbe     .next_pid
  976.  
  977.   .found_pid:
  978.         shl     ecx, 8
  979.         or      [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
  980.  
  981.     pop     ecx
  982.  
  983.     ; Update our recv.nxt field
  984.         lea     esi, [ebx + SOCKET.RCV_NXT]
  985.     call    add_inet_esi
  986.  
  987.   .ack:
  988.     ; Send an ACK
  989.     ; Now construct the response, and queue for sending by IP
  990.     mov     eax, EMPTY_QUEUE
  991.     call    dequeue
  992.     cmp     ax, NO_BUFFER
  993.         je      .exit
  994.  
  995.     push    eax
  996.  
  997.         mov     bl, TH_ACK
  998.         xor     ecx, ecx
  999.         xor     esi, esi
  1000.         stdcall build_tcp_packet, [sockAddr]
  1001.  
  1002.     mov     eax, NET1OUT_QUEUE
  1003.  
  1004.     mov     edx, [stack_ip]
  1005.         mov     ecx, [sockAddr]
  1006.         cmp     edx, [ecx + SOCKET.RemoteIP]
  1007.         jne     .not_local
  1008.     mov     eax, IPIN_QUEUE
  1009.  
  1010.   .not_local:
  1011.        ; Send it.
  1012.     pop     ebx
  1013.     call    queue
  1014.  
  1015.   .exit:
  1016.     ret
  1017.   .overflow:
  1018.         ; no place in buffer
  1019.         ; so simply restore stack and exit
  1020.         pop     eax ecx
  1021.         mov     [ebx + SOCKET.lock], 0
  1022.         ret
  1023. endp
  1024.  
  1025.  
  1026. proc stateTCB_FIN_WAIT_1 stdcall, sockAddr:DWORD
  1027.     ; We can either receive an ACK of a fin, or a fin
  1028.         mov     al, [edx + 20 + TCP_PACKET.Flags]
  1029.         and     al, TH_FIN + TH_ACK
  1030.  
  1031.         cmp     al, TH_ACK
  1032.         jne     @f
  1033.  
  1034.     ; It was an ACK
  1035.         mov     [ebx + SOCKET.TCBState], TCB_FIN_WAIT_2
  1036.         jmp     .exit
  1037.  
  1038.     @@: mov     [ebx + SOCKET.TCBState], TCB_CLOSING
  1039.         cmp     al, TH_FIN
  1040.         je      @f
  1041.         mov     [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
  1042.  
  1043.     @@: lea     esi, [ebx + SOCKET.RCV_NXT]
  1044.     call    inc_inet_esi
  1045.  
  1046.     ; Send an ACK
  1047.     mov     eax, EMPTY_QUEUE
  1048.     call    dequeue
  1049.     cmp     ax, NO_BUFFER
  1050.         je      .exit
  1051.  
  1052.     push    eax
  1053.  
  1054.         mov     bl, TH_ACK
  1055.         xor     ecx, ecx
  1056.         xor     esi, esi
  1057.         stdcall build_tcp_packet, [sockAddr]
  1058.  
  1059.     mov     eax, NET1OUT_QUEUE
  1060.  
  1061.     mov     edx, [stack_ip]
  1062.         mov     ecx, [sockAddr]
  1063.         cmp     edx, [ecx + SOCKET.RemoteIP]
  1064.         jne     .not_local
  1065.     mov     eax, IPIN_QUEUE
  1066.  
  1067.   .not_local:
  1068.     ; Send it.
  1069.     pop     ebx
  1070.     call    queue
  1071.  
  1072.   .exit:
  1073.     ret
  1074. endp
  1075.  
  1076.  
  1077. proc stateTCB_FIN_WAIT_2 stdcall, sockAddr:DWORD
  1078.         test    [edx + 20 + TCP_PACKET.Flags], TH_FIN
  1079.         jz      .exit
  1080.  
  1081.     ; Change state, as we have a fin
  1082.         mov     [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
  1083.  
  1084.         lea     esi, [ebx + SOCKET.RCV_NXT]
  1085.         call    inc_inet_esi
  1086.  
  1087.     ; Send an ACK
  1088.     mov     eax, EMPTY_QUEUE
  1089.     call    dequeue
  1090.     cmp     ax, NO_BUFFER
  1091.         je      .exit
  1092.  
  1093.     push    eax
  1094.  
  1095.         mov     bl, TH_ACK
  1096.         xor     ecx, ecx
  1097.         xor     esi, esi
  1098.         stdcall build_tcp_packet, [sockAddr]
  1099.  
  1100.     mov     eax, NET1OUT_QUEUE
  1101.  
  1102.     mov     edx, [stack_ip]
  1103.         mov     ecx, [sockAddr]
  1104.         cmp     edx, [ecx + SOCKET.RemoteIP]
  1105.         jne     .not_local
  1106.     mov     eax, IPIN_QUEUE
  1107.  
  1108.   .not_local:
  1109.        ; Send it.
  1110.     pop     ebx
  1111.     call    queue
  1112.  
  1113.   .exit:
  1114.     ret
  1115. endp
  1116.  
  1117.  
  1118. proc stateTCB_CLOSE_WAIT stdcall, sockAddr:DWORD
  1119.     ; Intentionally left empty
  1120.     ; socket_close_tcp handles this
  1121.     ret
  1122. endp
  1123.  
  1124.  
  1125. proc stateTCB_CLOSING stdcall, sockAddr:DWORD
  1126.     ; We can either receive an ACK of a fin, or a fin
  1127.         test    [edx + 20 + TCP_PACKET.Flags], TH_ACK
  1128.         jz      .exit
  1129.  
  1130.         mov     [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
  1131.  
  1132.   .exit:
  1133.     ret
  1134. endp
  1135.  
  1136.  
  1137. proc stateTCB_LAST_ACK stdcall, sockAddr:DWORD
  1138.     ; Look at control flags - expecting an ACK
  1139.         test    [edx + 20 + TCP_PACKET.Flags], TH_ACK
  1140.         jz      .exit
  1141.  
  1142.     ; delete the socket
  1143.         stdcall net_socket_free, ebx
  1144.  
  1145.   .exit:
  1146.     ret
  1147. endp
  1148.  
  1149.  
  1150. proc stateTCB_TIME_WAIT stdcall, sockAddr:DWORD
  1151.     ret
  1152. endp
  1153.  
  1154.  
  1155. proc stateTCB_CLOSED stdcall, sockAddr:DWORD
  1156.     ret
  1157. endp
  1158.