Subversion Repositories Kolibri OS

Rev

Rev 2434 | Rev 3555 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2011. 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: 2465 $
  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         20              ; 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.         push    eax ecx
  223.         mov     ecx, IPBUFFSIZE
  224.         mul     ecx
  225.         add     eax, IPbuffs
  226.  
  227.         ; we have the buffer address in eax
  228.         mov     edi, eax
  229.         pop     ecx
  230.         ; Now get buffer location, and copy buffer across. argh! more copying,,
  231.         imul    esi, ecx, IPBUFFSIZE
  232.         add     esi, resendBuffer
  233.  
  234.         ; we have resend buffer location in esi
  235.         mov     ecx, IPBUFFSIZE
  236.  
  237.         ; copy data across
  238.         push    edi
  239.         cld
  240.         rep movsb
  241.         pop     edi
  242.  
  243.         ; queue packet
  244.         mov     eax, NET1OUT_QUEUE
  245.         mov     edx, [stack_ip]
  246.         cmp     edx, [edi + IP_PACKET.DestinationAddress]
  247.         jne     .not_local
  248.         mov     eax, IPIN_QUEUE
  249.  
  250.   .not_local:
  251.         pop     ebx
  252.         call    queue
  253.  
  254.   .tth005:
  255.         popad
  256.  
  257.         inc     ecx
  258.         add     esi, 8
  259.         jmp     .next_resendq
  260.  
  261.   .exit:
  262.         ret
  263. endp
  264.  
  265.  
  266. ;***************************************************************************
  267. ;   Function
  268. ;      tcp_rx
  269. ;
  270. ;   Description
  271. ;       TCP protocol handler
  272. ;       This is a kernel function, called by ip_rx
  273. ;       IP buffer address given in edx
  274. ;          IP buffer number in eax
  275. ;          Free up (or re-use) IP buffer when finished
  276. ;
  277. ;***************************************************************************
  278.  
  279. proc tcp_rx stdcall uses ebx
  280.         ; The process is as follows.
  281.         ; Look for a socket with matching remote IP, remote port, local port
  282.         ; if not found, then
  283.         ; look for remote IP + local port match ( where sockets remote port = 0)
  284.         ; if not found, then
  285.         ; look for a socket where local socket port == IP packets remote port
  286.         ; where sockets remote port, remote IP = 0
  287.         ; discard if not found
  288.         ; Call sockets tcbStateMachine, with pointer to packet.
  289.         ; the state machine will not delete the packet, so do that here.
  290.  
  291.         push    eax
  292.  
  293.         ; Look for a socket where
  294.         ; IP Packet TCP Destination Port = local Port
  295.         ; IP Packet SA = Remote IP
  296.         ; IP Packet TCP Source Port = remote Port
  297.  
  298.         mov     ebx, net_sockets
  299.  
  300.   .next_socket.1:
  301.         mov     ebx, [ebx + SOCKET.NextPtr]
  302.         or      ebx, ebx
  303.         jz      .next_socket.1.exit
  304.  
  305. ;        DEBUGF  1, "K : tcp_rx - 1.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
  306.  
  307.         mov     ax, [edx + 20 + TCP_PACKET.DestinationPort]  ; get the dest. port from the TCP hdr
  308.         cmp     [ebx + SOCKET.LocalPort], ax            ; get the dest. port from the TCP hdr
  309.         jne     .next_socket.1                          ; different - try next socket
  310.  
  311. ;        DEBUGF  1, "K : tcp_rx - 1.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP]
  312.  
  313.         mov     eax, [edx + IP_PACKET.SourceAddress]    ; get the source IP Addr from the IP hdr
  314.         cmp     [ebx + SOCKET.RemoteIP], eax            ; compare with socket's remote IP
  315.         jne     .next_socket.1                          ; different - try next socket
  316.  
  317. ;        DEBUGF  1, "K : tcp_rx - 1.sport: %x - %x\n", [edx + 20 + TCP_PACKET.SourcePort]:4, [ebx + SOCKET.RemotePort]:4
  318.  
  319.         mov     ax, [edx + 20 + TCP_PACKET.SourcePort]  ; get the source port from the TCP hdr
  320.         cmp     [ebx + SOCKET.RemotePort], ax           ; compare with socket's remote port
  321.         jne     .next_socket.1                          ; different - try next socket
  322.  
  323.         ; We have a complete match - use this socket
  324.         jmp     .change_state
  325.  
  326.   .next_socket.1.exit:
  327.  
  328.         ; If we got here, there was no match
  329.         ; Look for a socket where
  330.         ; IP Packet TCP Destination Port = local Port
  331.         ; IP Packet SA = Remote IP
  332.         ; socket remote Port = 0
  333.  
  334.         mov     ebx, net_sockets
  335.  
  336.   .next_socket.2:
  337.         mov     ebx, [ebx + SOCKET.NextPtr]
  338.         or      ebx, ebx
  339.         jz      .next_socket.2.exit
  340.  
  341. ;        DEBUGF  1, "K : tcp_rx - 2.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
  342.  
  343.         mov     ax, [edx + 20 + TCP_PACKET.DestinationPort]  ; get the dest. port from the TCP hdr
  344.         cmp     [ebx + SOCKET.LocalPort], ax            ; compare with socket's local port
  345.         jne     .next_socket.2                          ; different - try next socket
  346.  
  347. ;        DEBUGF  1, "K : tcp_rx - 2.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP]
  348.  
  349.         mov     eax, [edx + IP_PACKET.SourceAddress]    ; get the source IP Addr from the IP hdr
  350.         cmp     [ebx + SOCKET.RemoteIP], eax            ; compare with socket's remote IP
  351.         jne     .next_socket.2                          ; different - try next socket
  352.  
  353. ;        DEBUGF  1, "K : tcp_rx - 2.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
  354.  
  355.         cmp     [ebx + SOCKET.RemotePort], 0            ; only match a remote socket of 0
  356.         jne     .next_socket.2                          ; different - try next socket
  357.  
  358.         ; We have a complete match - use this socket
  359.         jmp     .change_state
  360.  
  361.   .next_socket.2.exit:
  362.  
  363.         ; If we got here, there was no match
  364.         ; Look for a socket where
  365.         ; IP Packet TCP Destination Port = local Port
  366.         ; socket Remote IP = 0
  367.         ; socket remote Port = 0
  368.  
  369.         mov     ebx, net_sockets
  370.  
  371.   .next_socket.3:
  372.         mov     ebx, [ebx + SOCKET.NextPtr]
  373.         or      ebx, ebx
  374.         jz      .next_socket.3.exit
  375.  
  376. ;        DEBUGF  1, "K : tcp_rx - 3.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
  377.  
  378.         mov     ax, [edx + 20 + TCP_PACKET.DestinationPort]  ; get destination port from the TCP hdr
  379.         cmp     [ebx + SOCKET.LocalPort], ax            ; compare with socket's local port
  380.         jne     .next_socket.3                          ; different - try next socket
  381.  
  382. ;        DEBUGF  1, "K : tcp_rx - 3.addr: 00000000 - %x\n", [ebx + SOCKET.RemoteIP]
  383.  
  384.         cmp     [ebx + SOCKET.RemoteIP], 0              ; only match a socket remote IP of 0
  385.         jne     .next_socket.3                          ; different - try next socket
  386.  
  387. ;        DEBUGF  1, "K : tcp_rx - 3.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
  388.  
  389.         cmp     [ebx + SOCKET.RemotePort], 0            ; only match a remote socket of 0
  390.         jne     .next_socket.3                          ; different - try next socket
  391.  
  392.         ; We have a complete match - use this socket
  393.         jmp     .change_state
  394.  
  395.   .next_socket.3.exit:
  396.  
  397.         ; If we got here, we need to reject the packet
  398.  
  399.         DEBUGF  1, "K : tcp_rx - dumped\n"
  400.         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
  401.  
  402.         inc     [dumped_rx_count]
  403.         jmp     .exit
  404.  
  405.   .change_state:
  406.  
  407.         ; We have a valid socket/TCB, so call the TCB State Machine for that skt.
  408.         ; socket is pointed to by ebx
  409.         ; IP packet is pointed to by edx
  410.         ; IP buffer number is on stack ( it will be popped at the end)
  411.  
  412.         stdcall tcpStateMachine, ebx
  413.  
  414.   .exit:
  415.         pop     eax
  416.         call    freeBuff
  417.         ret
  418. endp
  419.  
  420.  
  421. ;***************************************************************************
  422. ;   Function
  423. ;      buildTCPPacket
  424. ;
  425. ;   Description
  426. ;       builds an IP Packet with TCP data fully populated for transmission
  427. ;       You may destroy any and all registers
  428. ;          TCP control flags specified in bl
  429. ;          This TCB is in [sktAddr]
  430. ;          User data pointed to by esi
  431. ;       Data length in ecx
  432. ;          Transmit buffer number in eax
  433. ;
  434. ;***************************************************************************
  435.  
  436. proc build_tcp_packet stdcall, sockAddr:DWORD
  437.         push    ecx                        ; Save data length
  438.  
  439.         ; convert buffer pointer eax to the absolute address
  440.         mov     ecx, IPBUFFSIZE
  441.         mul     ecx
  442.         add     eax, IPbuffs
  443.  
  444.         mov     edx, eax
  445.  
  446.         mov     [edx + 20 + TCP_PACKET.Flags], bl               ; TCP flags
  447.  
  448.         mov     ebx, [sockAddr]
  449.  
  450.         ; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
  451.  
  452.         ; Fill in the IP header ( some data is in the socket descriptor)
  453.         mov     eax, [ebx + SOCKET.LocalIP]
  454.         mov     [edx + IP_PACKET.SourceAddress], eax
  455.         mov     eax, [ebx + SOCKET.RemoteIP]
  456.         mov     [edx + IP_PACKET.DestinationAddress], eax
  457.  
  458.         mov     [edx + IP_PACKET.VersionAndIHL], 0x45
  459.         mov     [edx + IP_PACKET.TypeOfService], 0
  460.  
  461.         pop     eax                   ; Get the TCP data length
  462.         push    eax
  463.  
  464.         add     eax, 20 + 20           ; add IP header and TCP header lengths
  465.         rol     ax, 8
  466.         mov     [edx + IP_PACKET.TotalLength], ax
  467.         mov     [edx + IP_PACKET.Identification], 0
  468.         mov     [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040
  469.         mov     [edx + IP_PACKET.TimeToLive], 0x20
  470.         mov     [edx + IP_PACKET.Protocol], PROTOCOL_TCP
  471.  
  472.         ; Checksum left unfilled
  473.         mov     [edx + IP_PACKET.HeaderChecksum], 0
  474.  
  475.         ; Fill in the TCP header (some data is in the socket descriptor)
  476.         mov     ax, [ebx + SOCKET.LocalPort]
  477.         mov     [edx + 20 + TCP_PACKET.SourcePort], ax          ; Local Port
  478.  
  479.         mov     ax, [ebx + SOCKET.RemotePort]
  480.         mov     [edx + 20 + TCP_PACKET.DestinationPort], ax     ; desitination Port
  481.  
  482.         ; Checksum left unfilled
  483.         mov     [edx + 20 + TCP_PACKET.Checksum], 0
  484.  
  485.         ; sequence number
  486.         mov     eax, [ebx + SOCKET.SND_NXT]
  487.         mov     [edx + 20 + TCP_PACKET.SequenceNumber], eax
  488.  
  489.         ; ack number
  490.         mov     eax, [ebx + SOCKET.RCV_NXT]
  491.         mov     [edx + 20 + TCP_PACKET.AckNumber], eax
  492.  
  493.         ; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size)
  494.         ; 768 bytes seems better
  495.         mov     [edx + 20 + TCP_PACKET.Window], 0x0003
  496.  
  497.         ; Urgent pointer (0)
  498.         mov     [edx + 20 + TCP_PACKET.UrgentPointer], 0
  499.  
  500.         ; data offset ( 0x50 )
  501.         mov     [edx + 20 + TCP_PACKET.DataOffset], 0x50
  502.  
  503.         pop     ecx                  ; count of bytes to send
  504.         mov     ebx, ecx            ; need the length later
  505.  
  506.         cmp     ebx, 0
  507.         jz      @f
  508.  
  509.         mov     edi, edx
  510.         add     edi, 40
  511.         cld
  512.         rep movsb                   ; copy the data across
  513.  
  514.     @@: ; we have edx as IPbuffer ptr.
  515.         ; Fill in the TCP checksum
  516.         ; First, fill in pseudoheader
  517.         mov     eax, [edx + IP_PACKET.SourceAddress]
  518.         mov     [pseudoHeader], eax
  519.         mov     eax, [edx + IP_PACKET.DestinationAddress]
  520.         mov     [pseudoHeader + 4], eax
  521.         mov     word[pseudoHeader + 8], PROTOCOL_TCP shl 8 + 0
  522.         add     ebx, 20
  523.         mov     [pseudoHeader + 10], bh
  524.         mov     [pseudoHeader + 11], bl
  525.  
  526.         mov     eax, pseudoHeader
  527.         mov     [checkAdd1], eax
  528.         mov     word[checkSize1], 12
  529.         mov     eax, edx
  530.         add     eax, 20
  531.         mov     [checkAdd2], eax
  532.         mov     eax, ebx
  533.         mov     [checkSize2], ax
  534.  
  535.         call    checksum
  536.  
  537.         ; store it in the TCP checksum ( in the correct order! )
  538.         mov     ax, [checkResult]
  539.         rol     ax, 8
  540.         mov     [edx + 20 + TCP_PACKET.Checksum], ax
  541.  
  542.         ; Fill in the IP header checksum
  543.         GET_IHL eax, edx               ; get IP-Header length
  544.         stdcall checksum_jb, edx, eax  ; buf_ptr, buf_size
  545.         rol     ax, 8
  546.         mov     [edx + IP_PACKET.HeaderChecksum], ax
  547.  
  548.         ret
  549. endp
  550.  
  551.  
  552. ; Increments the 32 bit value pointed to by esi in internet order
  553. proc inc_inet_esi stdcall
  554.         push    eax
  555.         mov     eax, [esi]
  556.         bswap   eax
  557.         inc     eax
  558.         bswap   eax
  559.         mov     [esi], eax
  560.         pop     eax
  561.         ret
  562. endp
  563.  
  564.  
  565. ; Increments the 32 bit value pointed to by esi in internet order
  566. ; by the value in ecx
  567. proc add_inet_esi stdcall
  568.         push    eax
  569.         mov     eax, [esi]
  570.         bswap   eax
  571.         add     eax, ecx
  572.         bswap   eax
  573.         mov     [esi], eax
  574.         pop     eax
  575.         ret
  576. endp
  577.  
  578.  
  579. iglobal
  580.   TCBStateHandler dd \
  581.     stateTCB_LISTEN, \
  582.     stateTCB_SYN_SENT, \
  583.     stateTCB_SYN_RECEIVED, \
  584.     stateTCB_ESTABLISHED, \
  585.     stateTCB_FIN_WAIT_1, \
  586.     stateTCB_FIN_WAIT_2, \
  587.     stateTCB_CLOSE_WAIT, \
  588.     stateTCB_CLOSING, \
  589.     stateTCB_LAST_ACK, \
  590.     stateTCB_TIME_WAIT, \
  591.     stateTCB_CLOSED
  592. endg
  593.  
  594.  
  595. ;***************************************************************************
  596. ;   Function
  597. ;      tcpStateMachine
  598. ;
  599. ;   Description
  600. ;       TCP state machine
  601. ;       This is a kernel function, called by tcp_rx
  602. ;
  603. ;       IP buffer address given in edx
  604. ;          Socket/TCB address in ebx
  605. ;
  606. ;       The IP buffer will be released by the caller
  607. ;***************************************************************************
  608.  
  609. proc tcpStateMachine stdcall, sockAddr:DWORD
  610.         ; as a packet has been received, update the TCB timer
  611.         mov     [ebx + SOCKET.TCBTimer], TWOMSL
  612.  
  613.         ; If the received packet has an ACK bit set,
  614.         ; remove any packets in the resend queue that this
  615.         ; received packet acknowledges
  616.         pushad
  617.         test    [edx + 20 + TCP_PACKET.Flags], TH_ACK
  618.         jz      .call_handler                                   ; No ACK, so no data yet
  619.  
  620.         ; get skt number in eax
  621.         stdcall net_socket_addr_to_num, ebx
  622.  
  623.         ; The ack number is in [edx + 28], inet format
  624.         ; skt in eax
  625.  
  626.         mov     esi, resendQ
  627.         xor     ecx, ecx
  628.  
  629.   .next_resendq:
  630.         cmp     ecx, NUMRESENDENTRIES
  631.         je      .call_handler     ; None left
  632.         cmp     [esi + 4], eax
  633.         je      @f                ; found one
  634.         inc     ecx
  635.         add     esi, 8
  636.         jmp     .next_resendq
  637.  
  638.     @@:                   ; Can we delete this buffer?
  639.  
  640.                           ; If yes, goto @@. No, goto .next_resendq
  641.         ; Get packet data address
  642.  
  643.         push    ecx
  644.         ; Now get buffer location, and copy buffer across. argh! more copying,,
  645.         imul    edi, ecx, IPBUFFSIZE
  646.         add     edi, resendBuffer
  647.  
  648.         ; we have dest buffer location in edi. incoming packet in edx.
  649.         ; Get this packets sequence number
  650.         ; preserve al, ecx, esi, edx
  651.         mov     ecx, [edi + 20 + TCP_PACKET.SequenceNumber]
  652.         bswap   ecx
  653.         movzx   ebx, word[edi + 2]
  654.         xchg    bl, bh
  655.         sub     ebx, 40
  656.         add     ecx, ebx          ; ecx is now seq# of last byte +1, intel format
  657.  
  658.         ; get recievd ack #, in intel format
  659.         mov     ebx, [edx + 20 + TCP_PACKET.AckNumber]
  660.         bswap   ebx
  661.  
  662.         cmp     ebx, ecx        ; Finally. ecx = rx'ed ack. ebx = last byte in que
  663.                                 ; DANGER! need to handle case that we have just
  664.                                 ; passed the 2**32, and wrapped round!
  665.         pop     ecx
  666.         jae     @f              ; if rx > old, delete old
  667.  
  668.         inc     ecx
  669.         add     esi, 8
  670.         jmp     .next_resendq
  671.  
  672.     @@:
  673.         mov     dword[esi + 4], 0
  674.         inc     ecx
  675.         add     esi, 8
  676.         jmp     .next_resendq
  677.  
  678.   .call_handler:
  679.         popad
  680.  
  681.         ; Call handler for given TCB state
  682.  
  683.         mov     eax, [ebx + SOCKET.TCBState]
  684.         cmp     eax, TCB_LISTEN
  685.         jb      .exit
  686.         cmp     eax, TCB_CLOSED
  687.         ja      .exit
  688.  
  689.         stdcall [TCBStateHandler + (eax - 1) * 4], [sockAddr]
  690.  
  691.   .exit:
  692.         ret
  693. endp
  694.  
  695. ;***************************************************************************
  696. ;   Function
  697. ;      signal_network_event
  698. ;
  699. ;   Description
  700. ;       Signals about network event to socket owner
  701. ;       This is a kernel function, called from TCP handler
  702. ;
  703. ;          Socket/TCB address in ebx
  704. ;***************************************************************************
  705. proc signal_network_event
  706.         push    ecx esi eax
  707.         mov     eax, [ebx + SOCKET.PID]
  708.         mov     ecx, 1
  709.         mov     esi, TASK_DATA + TASKDATA.pid
  710.  
  711.   .next_pid:
  712.         cmp     [esi], eax
  713.         je      .found_pid
  714.         inc     ecx
  715.         add     esi, 0x20
  716.         cmp     ecx, [TASK_COUNT]
  717.         jbe     .next_pid
  718.  
  719.   .found_pid:
  720.         shl     ecx, 8
  721.         or      [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
  722.         pop     eax esi ecx
  723.         ret
  724. endp
  725.  
  726. proc stateTCB_LISTEN stdcall, sockAddr:DWORD
  727.         ; In this case, we are expecting a SYN packet
  728.         ; For now, if the packet is a SYN, process it, and send a response
  729.         ; If not, ignore it
  730.  
  731.         ; Look at control flags
  732.         test    [edx + 20 + TCP_PACKET.Flags], TH_SYN
  733.         jz      .exit
  734.  
  735.         ; We have a SYN. update the socket with this IP packets details,
  736.         ; And send a response
  737.  
  738.         mov     eax, [edx + IP_PACKET.SourceAddress]
  739.         mov     [ebx + SOCKET.RemoteIP], eax
  740.         mov     ax, [edx + 20 + TCP_PACKET.SourcePort]
  741.         mov     [ebx + SOCKET.RemotePort], ax
  742.         mov     eax, [edx + 20 + TCP_PACKET.SequenceNumber]
  743.         mov     [ebx + SOCKET.IRS], eax
  744.         mov     [ebx + SOCKET.RCV_NXT], eax
  745.         lea     esi, [ebx + SOCKET.RCV_NXT]
  746.         call    inc_inet_esi ; RCV.NXT
  747.         mov     eax, [ebx + SOCKET.ISS]
  748.         mov     [ebx + SOCKET.SND_NXT], eax
  749.  
  750.         ; Now construct the response, and queue for sending by IP
  751.         mov     eax, EMPTY_QUEUE
  752.         call    dequeue
  753.         cmp     ax, NO_BUFFER
  754.         je      .exit
  755.  
  756.         push    ebx
  757.         push    eax
  758.         mov     bl, TH_SYN + TH_ACK
  759.         xor     ecx, ecx
  760.         xor     esi, esi
  761.         stdcall build_tcp_packet, [sockAddr]
  762.  
  763.         mov     eax, NET1OUT_QUEUE
  764.         mov     edx, [stack_ip]
  765.         mov     ecx, [sockAddr]
  766.         cmp     edx, [ecx + SOCKET.RemoteIP]
  767.         jne     .not_local
  768.         mov     eax, IPIN_QUEUE
  769.  
  770.   .not_local:
  771.         ; Send it.
  772.         pop     ebx
  773.         call    queue
  774.  
  775.         pop     ebx
  776.         mov     esi, [sockAddr]
  777.         mov     [esi + SOCKET.TCBState], TCB_SYN_RECEIVED
  778.         call    signal_network_event
  779.  
  780.         ; increment SND.NXT in socket
  781.         add     esi, SOCKET.SND_NXT
  782.         call    inc_inet_esi
  783.  
  784.   .exit:
  785.         ret
  786. endp
  787.  
  788.  
  789. proc stateTCB_SYN_SENT stdcall, sockAddr:DWORD
  790.         ; We are awaiting an ACK to our SYN, with a SYM
  791.         ; Look at control flags - expecting an ACK
  792.  
  793.         mov     al, [edx + 20 + TCP_PACKET.Flags]
  794.         and     al, TH_SYN + TH_ACK
  795.         cmp     al, TH_SYN + TH_ACK
  796.         je      .syn_ack
  797.  
  798.         test    al, TH_SYN
  799.         jz      .exit
  800.  
  801.         mov     [ebx + SOCKET.TCBState], TCB_SYN_RECEIVED
  802.         push    TH_SYN + TH_ACK
  803.         jmp     .send
  804.  
  805.   .syn_ack:
  806.         mov     [ebx + SOCKET.TCBState], TCB_ESTABLISHED
  807.         push    TH_ACK
  808.  
  809.   .send:
  810.         call    signal_network_event
  811.         ; Store the recv.nxt field
  812.         mov     eax, [edx + 20 + TCP_PACKET.SequenceNumber]
  813.  
  814.         ; Update our recv.nxt field
  815.         mov     [ebx + SOCKET.RCV_NXT], eax
  816.         lea     esi, [ebx + SOCKET.RCV_NXT]
  817.         call    inc_inet_esi
  818.  
  819.         ; Send an ACK
  820.         ; Now construct the response, and queue for sending by IP
  821.         mov     eax, EMPTY_QUEUE
  822.         call    dequeue
  823.         cmp     ax, NO_BUFFER
  824.         pop     ebx
  825.         je      .exit
  826.  
  827.         push    eax
  828.  
  829.         xor     ecx, ecx
  830.         xor     esi, esi
  831.         stdcall build_tcp_packet, [sockAddr]
  832.  
  833.         mov     eax, NET1OUT_QUEUE
  834.         mov     edx, [stack_ip]
  835.         mov     ecx, [sockAddr]
  836.         cmp     edx, [ecx + SOCKET.RemoteIP]
  837.         jne     .not_local
  838.         mov     eax, IPIN_QUEUE
  839.  
  840.   .not_local:
  841.         ; Send it.
  842.         pop     ebx
  843.         call    queue
  844.  
  845.   .exit:
  846.         ret
  847. endp
  848.  
  849.  
  850. proc stateTCB_SYN_RECEIVED stdcall, sockAddr:DWORD
  851.         ; In this case, we are expecting an ACK packet
  852.         ; For now, if the packet is an ACK, process it,
  853.         ; If not, ignore it
  854.  
  855.         test    [edx + 20 + TCP_PACKET.Flags], TH_RST
  856.         jz      .check_ack
  857.  
  858.         push    [ebx + SOCKET.OrigRemotePort] [ebx + SOCKET.OrigRemoteIP]
  859.         pop     [ebx + SOCKET.RemoteIP] [ebx + SOCKET.RemotePort]
  860.  
  861.         mov     [ebx + SOCKET.TCBState], TCB_LISTEN
  862.         jmp     .signal
  863.  
  864.   .check_ack:
  865.         ; Look at control flags - expecting an ACK
  866.         test    [edx + 20 + TCP_PACKET.Flags], TH_ACK
  867.         jz      .exit
  868.  
  869.         mov     [ebx + SOCKET.TCBState], TCB_ESTABLISHED
  870.   .signal:
  871.         call    signal_network_event
  872.  
  873.   .exit:
  874.         ret
  875. endp
  876.  
  877.  
  878. proc stateTCB_ESTABLISHED stdcall, sockAddr:DWORD
  879.         ; Here we are expecting data, or a request to close
  880.         ; OR both...
  881.  
  882.         ; Ignore all packets with sequnce number other than next expected
  883.  
  884.         ; recv.nxt is in dword [edx+24], in inet format
  885.         ; recv seq is in [sktAddr]+56, in inet format
  886.         ; just do a comparision
  887.         mov     eax, [ebx + SOCKET.RCV_NXT]
  888.         cmp     eax, [edx + 20 + TCP_PACKET.SequenceNumber]
  889.         jne     .exit
  890.  
  891.         ; Did we receive a FIN or RST?
  892.         test    [edx + 20 + TCP_PACKET.Flags], TH_FIN+TH_RST
  893.         jz      .check_ack
  894.  
  895.         ; It was a fin or reset.
  896.  
  897.         ; Remove resend entries from the queue  - I dont want to send any more data
  898.         pushad
  899.  
  900.         ; get skt #
  901.         stdcall net_socket_addr_to_num, ebx
  902.  
  903.         mov     esi, resendQ
  904.         mov     ecx, 0
  905.  
  906.   .next_resendq:
  907.         cmp     ecx, NUMRESENDENTRIES
  908.         je      .last_resendq       ; None left
  909.         cmp     [esi + 4], eax
  910.         je      @f                  ; found one
  911.         inc     ecx
  912.         add     esi, 8
  913.         jmp     .next_resendq
  914.  
  915.     @@:
  916.         mov     dword[esi + 4], 0
  917.         inc     ecx
  918.         add     esi, 8
  919.         jmp     .next_resendq
  920.  
  921.   .last_resendq:
  922.         popad
  923.  
  924.     @@: ; Send an ACK to that fin, and enter closewait state
  925.  
  926.         mov     [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
  927.         test    [edx + 20 + TCP_PACKET.Flags], TH_RST
  928.         je      @f
  929.         mov     [ebx + SOCKET.TCBState], TCB_CLOSED
  930.     @@:
  931.         call    signal_network_event
  932.         lea     esi, [ebx + SOCKET.RCV_NXT]
  933.         mov     eax, [esi]              ; save original
  934.         call    inc_inet_esi
  935.         ;; jmp    ste_ack - NO, there may be data
  936.  
  937.   .check_ack:
  938.         ; Check that we received an ACK
  939.         test    [edx + 20 + TCP_PACKET.Flags], TH_ACK
  940.         jz      .exit
  941.  
  942.         ; TODO - done, I think!
  943.         ; First, look at the incoming window. If this is less than or equal to 1024,
  944.         ; Set the socket window timer to 1. This will stop an additional packets being queued.
  945.         ; ** I may need to tweak this value, since I do not know how many packets are already queued
  946.         mov     cx, [edx + 20 + TCP_PACKET.Window]
  947.         xchg    cl, ch
  948.         cmp     cx, 1024
  949.         ja      @f
  950.  
  951.         mov     [ebx + SOCKET.wndsizeTimer], 1
  952.  
  953.     @@: ; OK, here is the deal
  954.  
  955.  
  956.         ; Read the data bytes, store in socket buffer
  957.         movzx   ecx, [edx + IP_PACKET.TotalLength]
  958.         xchg    cl, ch
  959.         sub     ecx, 40                    ; Discard 40 bytes of header
  960.         ja      .data                      ; Read data, if any
  961.  
  962.         ; If we had received a fin, we need to ACK it.
  963.         cmp     [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
  964.         je      .ack
  965.         jmp     .exit
  966.  
  967.   .data:
  968.         push    ecx
  969.         push    ecx edx
  970.         lea     ecx, [ebx+SOCKET.mutex]
  971.         call    mutex_lock
  972.         pop     edx ecx
  973.  
  974.         push    ebx
  975.         mov     eax, [ebx + SOCKET.rxDataCount]
  976.         add     eax, ecx
  977.         cmp     eax, SOCKETBUFFSIZE - SOCKETHEADERSIZE
  978.         ja      .overflow
  979.  
  980.         mov     [ebx + SOCKET.rxDataCount], eax      ; increment the count of bytes in buffer
  981.  
  982.         ; point to the location to store the data
  983.         lea     edi, [ebx + eax + SOCKETHEADERSIZE]
  984.         sub     edi, ecx
  985.  
  986.         add     edx, 40        ; edx now points to the data
  987.         mov     esi, edx
  988.  
  989.         cld
  990.         rep movsb              ; copy the data across
  991.  
  992.         lea     ecx, [ebx + SOCKET.mutex]
  993.         call    mutex_unlock
  994.  
  995.         ; flag an event to the application
  996.         pop     ebx
  997.         call    signal_network_event
  998.  
  999.         pop     ecx
  1000.  
  1001.         ; Update our recv.nxt field
  1002.         lea     esi, [ebx + SOCKET.RCV_NXT]
  1003.         call    add_inet_esi
  1004.  
  1005.   .ack:
  1006.         ; Send an ACK
  1007.         ; Now construct the response, and queue for sending by IP
  1008.         mov     eax, EMPTY_QUEUE
  1009.         call    dequeue
  1010.         cmp     ax, NO_BUFFER
  1011.         je      .exit
  1012.  
  1013.         push    eax
  1014.  
  1015.         mov     bl, TH_ACK
  1016.         xor     ecx, ecx
  1017.         xor     esi, esi
  1018.         stdcall build_tcp_packet, [sockAddr]
  1019.  
  1020.         mov     eax, NET1OUT_QUEUE
  1021.  
  1022.         mov     edx, [stack_ip]
  1023.         mov     ecx, [sockAddr]
  1024.         cmp     edx, [ecx + SOCKET.RemoteIP]
  1025.         jne     .not_local
  1026.         mov     eax, IPIN_QUEUE
  1027.  
  1028.   .not_local:
  1029.         ; Send it.
  1030.         pop     ebx
  1031.         call    queue
  1032.  
  1033.   .exit:
  1034.         ret
  1035.   .overflow:
  1036.         ; no place in buffer
  1037.         ; so simply restore stack and exit
  1038.         lea     ecx, [ebx + SOCKET.mutex]
  1039.         call    mutex_unlock
  1040.         pop     eax ecx
  1041.         ret
  1042. endp
  1043.  
  1044.  
  1045. proc stateTCB_FIN_WAIT_1 stdcall, sockAddr:DWORD
  1046.         ; We can either receive an ACK of a fin, or a fin
  1047.         mov     al, [edx + 20 + TCP_PACKET.Flags]
  1048.         and     al, TH_FIN + TH_ACK
  1049.  
  1050.         cmp     al, TH_ACK
  1051.         jne     @f
  1052.  
  1053.         ; It was an ACK
  1054.         mov     [ebx + SOCKET.TCBState], TCB_FIN_WAIT_2
  1055.         jmp     .exit
  1056.  
  1057.     @@:
  1058.         mov     [ebx + SOCKET.TCBState], TCB_CLOSING
  1059.         cmp     al, TH_FIN
  1060.         je      @f
  1061.         mov     [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
  1062.  
  1063.     @@:
  1064.         lea     esi, [ebx + SOCKET.RCV_NXT]
  1065.         call    inc_inet_esi
  1066.  
  1067.         ; Send an ACK
  1068.         mov     eax, EMPTY_QUEUE
  1069.         call    dequeue
  1070.         cmp     ax, NO_BUFFER
  1071.         je      .exit
  1072.  
  1073.         push    eax
  1074.  
  1075.         mov     bl, TH_ACK
  1076.         xor     ecx, ecx
  1077.         xor     esi, esi
  1078.         stdcall build_tcp_packet, [sockAddr]
  1079.  
  1080.         mov     eax, NET1OUT_QUEUE
  1081.         mov     edx, [stack_ip]
  1082.         mov     ecx, [sockAddr]
  1083.         cmp     edx, [ecx + SOCKET.RemoteIP]
  1084.         jne     .not_local
  1085.         mov     eax, IPIN_QUEUE
  1086.  
  1087.   .not_local:
  1088.         ; Send it.
  1089.         pop     ebx
  1090.         call    queue
  1091.  
  1092.   .exit:
  1093.         ret
  1094. endp
  1095.  
  1096.  
  1097. proc stateTCB_FIN_WAIT_2 stdcall, sockAddr:DWORD
  1098.         test    [edx + 20 + TCP_PACKET.Flags], TH_FIN
  1099.         jz      .exit
  1100.  
  1101.         ; Change state, as we have a fin
  1102.         mov     [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
  1103.  
  1104.         lea     esi, [ebx + SOCKET.RCV_NXT]
  1105.         call    inc_inet_esi
  1106.  
  1107.         ; Send an ACK
  1108.         mov     eax, EMPTY_QUEUE
  1109.         call    dequeue
  1110.         cmp     ax, NO_BUFFER
  1111.         je      .exit
  1112.  
  1113.         push    eax
  1114.  
  1115.         mov     bl, TH_ACK
  1116.         xor     ecx, ecx
  1117.         xor     esi, esi
  1118.         stdcall build_tcp_packet, [sockAddr]
  1119.  
  1120.         mov     eax, NET1OUT_QUEUE
  1121.         mov     edx, [stack_ip]
  1122.         mov     ecx, [sockAddr]
  1123.         cmp     edx, [ecx + SOCKET.RemoteIP]
  1124.         jne     .not_local
  1125.         mov     eax, IPIN_QUEUE
  1126.  
  1127.   .not_local:
  1128.         ; Send it.
  1129.         pop     ebx
  1130.         call    queue
  1131.  
  1132.   .exit:
  1133.         ret
  1134. endp
  1135.  
  1136.  
  1137. proc stateTCB_CLOSE_WAIT stdcall, sockAddr:DWORD
  1138.         ; Intentionally left empty
  1139.         ; socket_close_tcp handles this
  1140.         ret
  1141. endp
  1142.  
  1143.  
  1144. proc stateTCB_CLOSING stdcall, sockAddr:DWORD
  1145.         ; We can either receive an ACK of a fin, or a fin
  1146.         test    [edx + 20 + TCP_PACKET.Flags], TH_ACK
  1147.         jz      .exit
  1148.  
  1149.         mov     [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
  1150.  
  1151.   .exit:
  1152.         ret
  1153. endp
  1154.  
  1155.  
  1156. proc stateTCB_LAST_ACK stdcall, sockAddr:DWORD
  1157.         ; Look at control flags - expecting an ACK
  1158.         test    [edx + 20 + TCP_PACKET.Flags], TH_ACK
  1159.         jz      .exit
  1160.  
  1161.         ; delete the socket
  1162.         stdcall net_socket_free, ebx
  1163.  
  1164.   .exit:
  1165.         ret
  1166. endp
  1167.  
  1168.  
  1169. proc stateTCB_TIME_WAIT stdcall, sockAddr:DWORD
  1170.         ret
  1171. endp
  1172.  
  1173.  
  1174. proc stateTCB_CLOSED stdcall, sockAddr:DWORD
  1175.         ret
  1176. endp
  1177.