Subversion Repositories Kolibri OS

Rev

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