Subversion Repositories Kolibri OS

Rev

Rev 1318 | Blame | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2009. All rights reserved.    ;;
  4. ;; Distributed under terms of the GNU General Public License       ;;
  5. ;;                                                                 ;;
  6. ;;  TCP.INC                                                        ;;
  7. ;;                                                                 ;;
  8. ;;  Part of the tcp/ip network stack for KolibriOS                 ;;
  9. ;;                                                                 ;;
  10. ;;    Written by hidnplayr@kolibrios.org                           ;;
  11. ;;    Inspired by the TCP code of Mike Hibbit for MenuetOS         ;;
  12. ;;                                                                 ;;
  13. ;;          GNU GENERAL PUBLIC LICENSE                             ;;
  14. ;;             Version 2, June 1991                                ;;
  15. ;;                                                                 ;;
  16. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  17.  
  18.  
  19. $Revision: 1473 $
  20.  
  21. TCP_RETRIES             equ 5           ; Number of times to resend a Packet
  22. TCP_PACKET_TTL          equ 50          ; resend if not replied to in 1/100 s
  23. TCP_SOCKET_TTL          equ 10          ; # of secs to wait before closing socket
  24. TCP_QUEUE_SIZE          equ 16
  25.  
  26. TCP_MAX_ACKS            equ 16
  27.  
  28.  
  29. struct  TCP_Packet
  30.         .SourcePort             dw ?
  31.         .DestinationPort        dw ?
  32.         .SequenceNumber         dd ?
  33.         .AckNumber              dd ?
  34.         .DataOffset             db ?    ; DataOffset[0-3 bits] and Reserved[4-7]
  35.         .Flags                  db ?    ; Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN
  36.         .Window                 dw ?
  37.         .Checksum               dw ?
  38.         .UrgentPointer          dw ?
  39. ;        .Options                rb 3
  40. ;        .Padding                db ?
  41.         .Data:
  42. ends
  43.  
  44. struct  tcp_in_queue_entry
  45.         .data_ptr       dd ?
  46.         .data_size      dd ?
  47.         .offset         dd ?    ; TODO: replace this in code by absolute address isntead of relative offset
  48.         .size:
  49. ends
  50.  
  51. struct  tcp_out_queue_entry
  52.         .data_ptr       dd ?
  53.         .data_size      dd ?
  54.         .ttl            dd ?
  55.         .retries        dd ?
  56.         .owner          dd ?
  57.         .sendproc       dd ?
  58.         .seq_num        dd ?
  59.         .socket         dd ?
  60.         .size:
  61. ends
  62.  
  63. align 4
  64. uglobal
  65.         TCP_PACKETS_TX          rd  MAX_IP
  66.         TCP_PACKETS_RX          rd  MAX_IP
  67.  
  68.         TCP_IN_QUEUE            rd  (tcp_in_queue_entry.size*TCP_QUEUE_SIZE+queue.data)/4
  69.         TCP_OUT_QUEUE           dd  ?, ?
  70.                                 rd  (tcp_out_queue_entry.size*TCP_QUEUE_SIZE)/4
  71.  
  72.         TCP_ACKS                dd  ?
  73.         TCP_ACK_LIST            rd  3*TCP_MAX_ACKS
  74. endg
  75.  
  76. align 4
  77. iglobal
  78. TCPstateHandler:
  79.  
  80.   dd  stateTCB_LISTEN
  81.   dd  stateTCB_SYN_SENT
  82.   dd  stateTCB_SYN_RECEIVED
  83.   dd  stateTCB_ESTABLISHED
  84.   dd  stateTCB_FIN_WAIT_1
  85.   dd  stateTCB_FIN_WAIT_2
  86.   dd  stateTCB_CLOSE_WAIT
  87.   dd  stateTCB_CLOSING
  88.   dd  stateTCB_LAST_ACK
  89.   dd  stateTCB_TIME_WAIT
  90.   dd  stateTCB_CLOSED
  91.  
  92. endg
  93.  
  94.  
  95. ;-----------------------------------------------------------------
  96. ;
  97. ; TCP_init
  98. ;
  99. ;  This function resets all TCP variables
  100. ;
  101. ;  IN:  /
  102. ;  OUT: /
  103. ;
  104. ;-----------------------------------------------------------------
  105. align 4
  106. TCP_init:
  107.  
  108.         xor     eax, eax
  109.         mov     edi, TCP_PACKETS_TX
  110.         mov     ecx, 2*MAX_IP
  111.         rep     stosd
  112.  
  113.         init_queue TCP_IN_QUEUE
  114.  
  115. ; tcp_out_queue is a special type of queue:
  116. ; The first dword is a counter of total packets queued.
  117. ; The remaining bytes are socket 'slots' wich use tcp_out_queue_entry data structure.
  118. ; An empty slot is know by the fact that tcp_out_queue_entry.data_ptr (first dword of the slot) is set to 0
  119. ; There are TCP_OUT_QUEUE_SIZE number of slots
  120.  
  121.         xor     eax, eax
  122.         mov     esi, TCP_OUT_QUEUE
  123.         mov     ecx, TCP_QUEUE_SIZE*tcp_out_queue_entry/4+2+2+3*TCP_MAX_ACKS
  124.         rep     stosd
  125.  
  126.         ret
  127.  
  128.  
  129. ;-----------------------------------------------------------------
  130. ;
  131. ;  TCP_decrease_socket_ttls
  132. ;
  133. ;  IN:  /
  134. ;  OUT: /
  135. ;
  136. ;-----------------------------------------------------------------
  137. align 4
  138. TCP_decrease_socket_ttls:
  139. ; scan through all the sockets, decrementing active timers
  140.  
  141.         mov     ebx, net_sockets
  142.         cmp     [ebx + SOCKET_head.NextPtr], 0
  143.         je      .exit
  144.   .next_socket:
  145.         mov     ebx, [ebx + SOCKET_head.NextPtr]
  146.         or      ebx, ebx
  147.         jz      .exit
  148.  
  149.         cmp     [ebx + SOCKET_head.Type], IP_PROTO_TCP
  150.         jne     .next_socket
  151.  
  152. ;        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.state]
  153.  
  154.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer], 0
  155.         jne     .decrement_tcb
  156.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 0
  157.         jne     .decrement_wnd
  158.         jmp     .next_socket
  159.  
  160.   .decrement_tcb:
  161. ; decrement it, delete socket if TCB timer = 0 & socket in timewait state
  162.         dec     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer]
  163.         jnz     .next_socket
  164.  
  165.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  166.         jne     .next_socket
  167.  
  168.         push    [ebx + SOCKET_head.PrevPtr]
  169.         stdcall net_socket_free, ebx
  170.         pop     ebx
  171.         jmp     .next_socket
  172.  
  173.   .decrement_wnd:
  174.         dec     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer]
  175.         jmp     .next_socket
  176.  
  177.   .exit:
  178.         ret
  179.  
  180.  
  181.  
  182. ;-----------------------------------------------------------------
  183. ;
  184. ; TCP_send_queued:
  185. ;
  186. ;  Decreases 'ttl' of tcp packets queued.
  187. ;  if 'ttl' reaches 0, resend the packet and decrease 'retries'
  188. ;  if 'retries' reaches zero, remove the queued packet
  189. ;
  190. ;  IN:  /
  191. ;  OUT: /
  192. ;
  193. ;-----------------------------------------------------------------
  194. align 4
  195. TCP_send_queued:
  196.  
  197.         cmp     [TCP_OUT_QUEUE], 0
  198.         je      .exit
  199.  
  200.         mov     ebx, TCP_OUT_QUEUE+4
  201.         call    wait_mutex
  202.  
  203.         mov     eax, TCP_QUEUE_SIZE
  204.         mov     ecx, [TCP_OUT_QUEUE]
  205.         mov     esi, TCP_OUT_QUEUE+8
  206.  
  207.   .loop:
  208.         cmp     [esi + tcp_out_queue_entry.data_ptr], 0
  209.         jnz     .found_one
  210.         add     esi, tcp_out_queue_entry.size
  211.         loop    .loop
  212.   .exit:
  213.         mov     [TCP_OUT_QUEUE+4], 0
  214.         ret
  215.  
  216.   .found_one:
  217.         dec     [esi + tcp_out_queue_entry.ttl]
  218.         jz      .send_it
  219.         cmp     [esi + tcp_out_queue_entry.data_ptr], -1
  220.         jz      .is_ack
  221.   .find_next:
  222.         add     esi, tcp_out_queue_entry.size
  223.         dec     eax
  224.         jz      .exit
  225.         test    ecx, ecx
  226.         jnz     .loop
  227.         mov     [TCP_OUT_QUEUE+4], 0
  228.         ret
  229.  
  230.   .send_it:
  231.         pusha
  232.         mov     ebx, [esi + tcp_out_queue_entry.owner]
  233.         pushd   [esi + tcp_out_queue_entry.data_size]
  234.         pushd   [esi + tcp_out_queue_entry.data_ptr]
  235.         DEBUGF 1,"Now sending TCP packet %x, size: %u, owner: %x, sendproc %x\n", [esp], [esp+4], ebx, [esi + tcp_out_queue_entry.sendproc]
  236.         inc     [TCP_PACKETS_TX]
  237.         call    [esi + tcp_out_queue_entry.sendproc]
  238.         add     esp, 8
  239.         popa
  240.  
  241.         dec     [esi + tcp_out_queue_entry.retries]
  242.         jz      .remove_it
  243.  
  244.         mov     [esi + tcp_out_queue_entry.ttl], TCP_PACKET_TTL
  245.         jmp     .find_next
  246.  
  247.   .remove_it:
  248.         push    [esi + tcp_out_queue_entry.data_ptr]
  249.         mov     [esi + tcp_out_queue_entry.data_ptr], 0
  250.         call    kernel_free
  251.         dec     [TCP_OUT_QUEUE]
  252.         jmp     .find_next
  253.  
  254.   .is_ack:
  255.         pusha
  256.         mov     eax, [esi + tcp_out_queue_entry.socket]
  257.         mov     ebx, [esi + tcp_out_queue_entry.owner]
  258.         mov     ecx, [esi + tcp_out_queue_entry.size]
  259.         call    TCP_send_ack
  260.         popa
  261.         mov     [esi + tcp_out_queue_entry.data_ptr], 0
  262.         dec     [TCP_OUT_QUEUE]
  263.         jmp     .find_next
  264.  
  265.  
  266.  
  267. ;-----------------------------------------------------------------
  268. ;
  269. ; TCP_handler:
  270. ;
  271. ;  Called by IPv4_handler,
  272. ;  this procedure will inject the tcp data diagrams in the application sockets.
  273. ;
  274. ;  IN:  Pointer to buffer in [esp]
  275. ;       size of buffer in [esp+4]
  276. ;       pointer to device struct in ebx
  277. ;       TCP Packet size in ecx
  278. ;       pointer to TCP Packet in edx
  279. ;       SourceAddres (IPv4) in esi
  280. ;  OUT: /
  281. ;
  282. ;-----------------------------------------------------------------
  283. align 4
  284. TCP_handler :
  285.  
  286.        DEBUGF 1,"TCP_Handler\n"
  287.  
  288. ; TODO: validate checksum
  289.  
  290. ; Find a matching socket for received packet, all following expressions must be valid:
  291. ;
  292. ; IP Packet TCP Destination Port = local Port
  293. ; (IP Packet SA = Remote IP)  OR  (Remote IP = 0)
  294. ; (IP Packet TCP Source Port = remote Port)  OR (remote Port = 0)
  295.  
  296.         mov     ebx, net_sockets
  297.  
  298.   .socket_loop:
  299.         mov     ebx, [ebx + SOCKET_head.NextPtr]
  300.         or      ebx, ebx
  301.         jz      .dump
  302.  
  303.         mov     ax, [edx + TCP_Packet.DestinationPort]
  304.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], ax
  305.         jne     .socket_loop
  306.  
  307.         mov     eax, [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  308.         cmp     eax, esi
  309.         je      @f
  310.         test    eax, eax
  311.         jne     .socket_loop
  312.        @@:
  313.  
  314.         mov     ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
  315.         cmp     [edx + TCP_Packet.SourcePort] , ax
  316.         je      .found_socket
  317.         test    ax, ax
  318.         jnz     .socket_loop
  319.   .found_socket:
  320.        DEBUGF 1,"Found valid socket for packet\n"
  321.  
  322.         inc     [TCP_PACKETS_RX]
  323.  
  324.         add     ebx, SOCKET_head.lock
  325.         call    wait_mutex
  326.         sub     ebx, SOCKET_head.lock
  327.  
  328. ;-------------------------------
  329. ; ebx is pointer to socket
  330. ; ecx is size of tcp packet
  331. ; edx is pointer to tcp packet
  332.  
  333. ; calculate header length
  334.         movzx   eax, [edx + TCP_Packet.DataOffset]
  335.         and     eax, 11110000b
  336.         shr     eax, 2
  337.        DEBUGF 1,"TCP header size: %u\n", eax
  338.         sub     ecx, eax
  339.  
  340. ;-------------------------------
  341. ; ecx is size of tcp data
  342.  
  343. ; as a Packet has been received, update the TCB timer
  344.  
  345. ; If the received Packet has an ACK bit set, remove any Packets in the resend queue that this received Packet acknowledges
  346.         test    [edx + TCP_Packet.Flags], TH_ACK
  347.         jz      .no_ack                                  ; No ACK, so no data yet
  348.  
  349. ; Calculate ACK number, in intel byte order
  350.         mov     edi, [edx + TCP_Packet.AckNumber]
  351.         bswap   edi
  352.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.last_ack_number], edi
  353.         DEBUGF 1,"Setting last_ack_number to %u\n", edi
  354.  
  355. ; Dequeue all acknowledged packets
  356.         cmp     [TCP_OUT_QUEUE], 0              ; first, check if any packets are queued at all
  357.         je      .no_ack
  358.  
  359.         push    ebx
  360.         mov     ebx, TCP_OUT_QUEUE+4
  361.         call    wait_mutex
  362.         pop     ebx
  363.  
  364.         push    ecx
  365.         DEBUGF 1,"Removing all queued packets with smaller ACK\n"
  366.         mov     ecx, TCP_QUEUE_SIZE
  367.         mov     esi, TCP_OUT_QUEUE+8
  368.   .loop:
  369.         cmp     [esi + tcp_out_queue_entry.data_ptr], 0
  370.         je      .maybe_next
  371.  
  372.         cmp     [esi + tcp_out_queue_entry.socket], ebx
  373.         jne     .maybe_next
  374.  
  375.         cmp     [esi + tcp_out_queue_entry.seq_num], edi
  376.         jg      .maybe_next
  377.  
  378.         DEBUGF 1,"Removing a queued packet\n"
  379.  
  380.         push    [esi + tcp_out_queue_entry.data_ptr]
  381.         mov     [esi + tcp_out_queue_entry.data_ptr], 0
  382.         dec     [TCP_OUT_QUEUE]
  383.         call    kernel_free
  384.  
  385.   .maybe_next:
  386.         add     esi, tcp_out_queue_entry.size
  387.         loop    .loop
  388.  
  389.         mov     [TCP_OUT_QUEUE+4], 0
  390.         pop     ecx
  391.  
  392. ; Now call the correct handler, depending on the socket state
  393.   .no_ack:
  394.         mov     eax, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state]
  395.  
  396.         cmp     eax, TCB_LISTEN
  397.         jb      .dump
  398.         cmp     eax, TCB_CLOSED
  399.         ja      .dump
  400.  
  401.         call    dword [TCPstateHandler+eax*4-4]
  402.  
  403.   .dump:
  404.         DEBUGF 1,"Dumping TCP packet\n"
  405.         call    kernel_free
  406.         add     esp, 4 ; pop (balance stack)
  407.  
  408.         ret
  409.  
  410.  
  411.  
  412. ;-----------------------------------------------------------------
  413. ;
  414. ; TCP_send  (Assumes socket mutex set)
  415. ;
  416. ; IN: eax = socket pointer
  417. ;      bl = flags
  418. ;      ecx = number of bytes to send, may be set to 0  (single ACK)
  419. ;      esi = pointer to data
  420. ;
  421. ;-----------------------------------------------------------------
  422. align 4
  423. TCP_send:
  424.  
  425.         DEBUGF 1,"Creating TCP packet, socket: %x, flags: %x\n",eax, bl
  426.  
  427.         mov     di , IP_PROTO_TCP
  428.         add     ecx, TCP_Packet.Data
  429.  
  430.         push    ecx bx eax esi
  431. ; Create an IPv4 Packet of the correct size
  432.         mov     ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
  433.         mov     eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  434.  
  435.         call    IPv4_create_packet
  436.         cmp     edi, -1
  437.         je      .fail
  438.  
  439. ; If there is any data, copy it first
  440.         pop     esi
  441.         push    edi
  442.         add     edi, TCP_Packet.Data
  443.         sub     ecx, TCP_Packet.Data
  444.  
  445.         shr     ecx, 1
  446.         jnc     .nb
  447.         movsb
  448. .nb:    shr     ecx, 1
  449.         jnc     .nw
  450.         movsw
  451. .nw:    test    ecx, ecx
  452.         jz      .nd
  453.         rep     movsd
  454. .nd:
  455.         pop     edi
  456.  
  457. ; Fill in the TCP header
  458.         pop     esi
  459.  
  460. ; fill in tcp sequence number
  461.         push    [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  462.         pop     [edi + TCP_Packet.SequenceNumber]
  463.  
  464. ; Fill in local and remote ports
  465.         push    dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort]
  466.         pop     dword [edi + TCP_Packet.SourcePort]
  467.  
  468. ; Acknumber
  469.         push    [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  470.         pop     [edi + TCP_Packet.AckNumber]
  471.  
  472. ; Fill  in other tcp options
  473.         pop     cx
  474.         mov     [edi + TCP_Packet.Flags], cl
  475.         mov     [edi + TCP_Packet.Window], 0x0005          ; 1280 bytes
  476.         mov     [edi + TCP_Packet.UrgentPointer], 0
  477.         mov     [edi + TCP_Packet.DataOffset], 0x50
  478.         mov     [edi + TCP_Packet.Checksum], 0
  479.  
  480. ; Get size of total packet back in ecx
  481.         pop     ecx
  482. ; Push pointer to and size of total packet (needed for send procedure)
  483.         push    edx eax
  484. ; push socket number (for TCP_add_to_queue)
  485.         push    esi
  486.  
  487. ; Now, calculate the checksum
  488.         xchg    cl, ch
  489.         pushw   cx
  490.         xchg    cl, ch
  491.         pushw   IP_PROTO_TCP shl 8
  492.         pushd   [edi-4] ; destination address           ; TODO: fix this, IPv4 packet could have options..
  493.         pushd   [edi-8] ; source address
  494.  
  495.         xor     edx, edx
  496.         mov     esi, edi
  497.         call    checksum_1
  498.         mov     ecx, 12
  499.         mov     esi, esp
  500.         call    checksum_1
  501. ; and store it in TCP header
  502.         call    checksum_2
  503.         mov     [edi + TCP_Packet.Checksum], dx
  504.         add     esp, 10                                    ; remove the pseudoheader from stack
  505.  
  506.         DEBUGF 1,"Sending TCP Packet to device %x\n", ebx
  507.         mov     edx, [edi + TCP_Packet.SequenceNumber]
  508.         bswap   edx
  509.         mov     esi, [ebx + ETH_DEVICE.transmit]
  510.  
  511.         pop     cx                                         ; get the length from packet, back from pseudoheader
  512.         pop     edi
  513.  
  514.         cmp     cx, TCP_Packet.Data shl 8                  ; if the packet has no data
  515.         je      .only_one                                  ; send it only once
  516.  
  517.         and     ecx, 0x0000ffff
  518.         xchg    cl, ch
  519.         sub     cx, TCP_Packet.Data
  520.  
  521.         add_INET (edi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT)     ; todo: this should only happen when packet was queued successful
  522.         mov     ecx, TCP_RETRIES
  523.  
  524.         jmp     .go_for_it
  525.  
  526.   .only_one:
  527.         mov     ecx, 1
  528.   .go_for_it:
  529.  
  530.         mov     [edi + SOCKET_head.lock], 0
  531.         jmp     TCP_queue                               ; At last send the packet!
  532.  
  533.   .fail:
  534.         add     esp, 2+4
  535.         or      eax, -1
  536.         ret
  537.  
  538.  
  539. ;-----------------------------------------------------------------
  540. ;
  541. ;  Queue a TCP packet for sending
  542. ;
  543. ;  IN:  [esp] pointer to buffer
  544. ;       [esp + 4] size of buffer
  545. ;       ebx = driver struct
  546. ;       edx = sequence number of this packet in intel byte order
  547. ;       esi = sender proc
  548. ;       edi = socket number
  549.  
  550. ;  OUT: /
  551. ;
  552. ;-----------------------------------------------------------------
  553. align 4
  554. TCP_queue:
  555.  
  556.         DEBUGF 1,"Adding packet to TCP queue, buffer: %x, size: %u, driver: %x, acknum: %u\n", [esp], [esp+4], ebx, edx
  557.  
  558.         cmp     [TCP_OUT_QUEUE], TCP_QUEUE_SIZE
  559.         jge     .full
  560.  
  561.         push    ebx
  562.         mov     ebx, TCP_OUT_QUEUE+4
  563.         call    wait_mutex
  564.         pop     ebx
  565.  
  566.         mov     ecx, TCP_QUEUE_SIZE
  567.         mov     eax, TCP_OUT_QUEUE+8
  568.   .loop:
  569.         cmp     [eax + tcp_out_queue_entry.data_ptr], 0
  570.         je      .found_it
  571.         add     eax, tcp_out_queue_entry.size
  572.         loop    .loop
  573.  
  574.         add     esp, 4
  575.   .full:                        ; silently discard the packet
  576.         DEBUGF 1,"TCP queue is full!\n"
  577.         call    kernel_free
  578.         add     esp, 4
  579.  
  580.         ret
  581.  
  582.   .found_it:                    ; eax points to empty queue entry
  583.  
  584.         mov     [eax + tcp_out_queue_entry.retries], TCP_RETRIES
  585.         pop     [eax + tcp_out_queue_entry.data_ptr]
  586.         pop     [eax + tcp_out_queue_entry.data_size]
  587.         mov     [eax + tcp_out_queue_entry.ttl], 1                      ; send immediately
  588.         mov     [eax + tcp_out_queue_entry.owner], ebx
  589.         mov     [eax + tcp_out_queue_entry.sendproc], esi
  590.         mov     [eax + tcp_out_queue_entry.seq_num], edx
  591.         mov     [eax + tcp_out_queue_entry.socket], edi
  592.  
  593.         inc     [TCP_OUT_QUEUE]
  594.  
  595.         sub     eax, TCP_OUT_QUEUE+8
  596.         shr     eax, 5
  597.         DEBUGF 1,"Added to queue in pos %u, total queued packets: %u\n", eax, [TCP_OUT_QUEUE+8]
  598.  
  599.         mov     [TCP_OUT_QUEUE+4], 0
  600.  
  601.         ret
  602.  
  603.  
  604. ;-----------------------------------------------------------------
  605. ;
  606. ;  IN:  ebx = socket
  607. ;       ecx = ack number
  608. ;
  609. ;  OUT: /
  610. ;
  611. ;-----------------------------------------------------------------
  612. align 4
  613. TCP_queue_ack:
  614.  
  615.         DEBUGF 1,"Adding ACK to TCP queue, socket: %x, acknum: %u\n", ebx, ecx
  616.  
  617.         cmp     [TCP_OUT_QUEUE], TCP_QUEUE_SIZE
  618.         jge     .full
  619.  
  620.         push    ebx ecx
  621.         mov     ebx, TCP_OUT_QUEUE+4
  622.         call    wait_mutex
  623.  
  624.         mov     ecx, TCP_QUEUE_SIZE
  625.         mov     eax, TCP_OUT_QUEUE+8
  626.   .loop:
  627.         cmp     [eax + tcp_out_queue_entry.data_ptr], 0
  628.         je      .found_it
  629.         add     eax, tcp_out_queue_entry.size
  630.         loop    .loop
  631.  
  632.         add     esp, 8
  633.   .full:                        ; silently discard the packet
  634.         DEBUGF 1,"TCP queue is full!\n"
  635.         ret
  636.  
  637.   .found_it:                    ; eax points to empty queue entry
  638.  
  639.         pop     [eax + tcp_out_queue_entry.data_size]                   ; ACK number
  640.         mov     [eax + tcp_out_queue_entry.data_ptr], -1                ; ACK packet
  641.         pop     [eax + tcp_out_queue_entry.socket]
  642.         mov     [eax + tcp_out_queue_entry.retries], 1
  643.         mov     [eax + tcp_out_queue_entry.ttl], 20                     ; 200 ms
  644.  
  645.         inc     [TCP_OUT_QUEUE]
  646.  
  647.         sub     eax, TCP_OUT_QUEUE+8
  648.         shr     eax, 5
  649.         DEBUGF 1,"Added to queue in pos %u, total queued packets: %u\n", eax, [TCP_OUT_QUEUE+8]
  650.  
  651.         mov     [TCP_OUT_QUEUE+4], 0
  652.  
  653.         ret
  654.  
  655.  
  656. ; IN: eax = socket pointer
  657. ;     ebx = device structure
  658. ;     ecx = ack number
  659.  
  660. align 4
  661. TCP_send_ack:
  662.  
  663.         DEBUGF 1,"Creating TCP ACK packet, socket: %x, acknum: %x\n", eax, ecx
  664.  
  665.         push    ecx eax
  666.  
  667.         mov     di , IP_PROTO_TCP
  668.         mov     ecx, TCP_Packet.Data
  669. ; Create an IPv4 Packet of the correct size
  670.         mov     ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
  671.         mov     eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  672.  
  673.         call    IPv4_create_packet
  674.         cmp     edi, -1
  675.         je      .fail
  676.  
  677.         pop     ecx
  678.  
  679. ; fill in tcp sequence number
  680.         push    [ecx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  681.         pop     [edi + TCP_Packet.SequenceNumber]
  682.  
  683. ; Fill in local and remote ports
  684.         push    dword [ecx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort]
  685.         pop     dword [edi + TCP_Packet.SourcePort]
  686.  
  687. ; Acknumber
  688.         pop     [edi + TCP_Packet.AckNumber]
  689.  
  690. ; Fill  in other tcp options
  691.         mov     [edi + TCP_Packet.Flags], TH_ACK
  692.         mov     [edi + TCP_Packet.Window], 0x0005          ; 1280 bytes
  693.         mov     [edi + TCP_Packet.UrgentPointer], 0
  694.         mov     [edi + TCP_Packet.DataOffset], 0x50
  695.         mov     [edi + TCP_Packet.Checksum], 0
  696.  
  697. ; Push pointer to and size of total packet (needed for send procedure)
  698.         push    edx eax esi
  699.  
  700. ; Now, calculate the checksum
  701.         pushw   TCP_Packet.Data shl 8
  702.         pushw   IP_PROTO_TCP shl 8
  703.         pushd   [edi-4] ; destination address           ; TODO: fix this, IPv4 packet could have options..
  704.         pushd   [edi-8] ; source address
  705.  
  706.         xor     edx, edx
  707.         mov     ecx, 12
  708.         mov     esi, esp
  709.         call    checksum_1
  710.         call    checksum_2
  711.         mov     [edi + TCP_Packet.Checksum], dx
  712.         add     esp, 12                                 ; remove the pseudoheader from stack
  713.  
  714.         pop     eax
  715.         call    eax
  716.         call    kernel_free
  717.         add     esp, 4 ; pop (balance stack)
  718.         ret
  719.  
  720.   .fail:
  721.         add     esp, 8
  722.         ret
  723.  
  724.  
  725.  
  726.  
  727. ;-----------------------------------------------------------------
  728. ;
  729. ; Remove all queued TCP packets for a specified socket
  730. ;
  731. ; IN: eax = socket number
  732. ; OUT: /
  733. ;
  734. ; destoys esi and ecx
  735. ;
  736. ;-----------------------------------------------------------------
  737.  
  738. align 4
  739. TCP_remove_socket:
  740.  
  741.         cmp     [TCP_OUT_QUEUE], 0
  742.         je      .skip
  743.  
  744.         mov     ebx, TCP_OUT_QUEUE+4
  745.         call    wait_mutex
  746.  
  747.         mov     eax, TCP_QUEUE_SIZE
  748.         mov     ecx, [TCP_OUT_QUEUE]
  749.         mov     esi, TCP_OUT_QUEUE+8
  750.  
  751.   .loop:
  752.         cmp     [esi + tcp_out_queue_entry.data_ptr], 0
  753.         jz      .maybenext
  754.         cmp     [esi + tcp_out_queue_entry.socket], eax
  755.         jnz     .maybenext
  756.  
  757.         push    [esi + tcp_out_queue_entry.data_ptr]
  758.         mov     [esi + tcp_out_queue_entry.data_ptr], 0
  759.         dec     [TCP_OUT_QUEUE]
  760.         call    kernel_free
  761.  
  762.   .maybenext:
  763.         add     esi, tcp_out_queue_entry.size
  764.         loop    .loop
  765.  
  766.         mov     [TCP_OUT_QUEUE+4], 0
  767.   .skip:
  768.         ret
  769.  
  770.  
  771.  
  772.  
  773.  
  774. ;---------- TCB state handlers start here
  775.  
  776.  
  777.  
  778.  
  779. align 4
  780. stateTCB_LISTEN:
  781.  
  782.         DEBUGF  1,"TCBStateHandler: Listen\n"
  783.  
  784.         test    [edx + TCP_Packet.Flags], TH_SYN        ; SYN packet? => send syn+ack, open new socket and set connection to established
  785.         jz      .exit
  786. ; Exit if backlog queue is full
  787.         mov     ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
  788.         cmp     ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog]
  789.         jae     .exit
  790. ; Allocate new socket
  791.         push    esi edi
  792.         call    net_socket_alloc
  793.         test    eax, eax
  794.         jz      .fail
  795. ; Copy structure from current socket to new, including lock
  796.         lea     esi, [ebx + SOCKET_head.PID]            ; yes, PID must also be copied
  797.         lea     edi, [eax + SOCKET_head.PID]
  798.         mov     ecx, ((SOCKET_head.end - SOCKET_head.PID) + IPv4_SOCKET.end + TCP_SOCKET.end + 3)/4
  799.         rep     movsd
  800.         pop     edi esi
  801. ; Push pointer to new socket to queue
  802.         movzx   ecx, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
  803.         inc     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
  804.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end + ecx*4], eax
  805.  
  806.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], esi ; IP source address
  807.         mov     cx, [edx + TCP_Packet.SourcePort]
  808.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], cx
  809.         mov     ecx, [edx + TCP_Packet.SequenceNumber]
  810.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], ecx
  811.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], ecx
  812.         lea     esi, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  813.         inc_INET esi ; RCV.NXT
  814.         mov     ecx, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS]
  815.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], ecx
  816.  
  817.         mov     [ebx + SOCKET_head.lock], 0
  818.  
  819.         push    eax
  820. ; Now construct the response
  821.         mov     bl, TH_SYN + TH_ACK
  822.         xor     ecx, ecx
  823.         call    TCP_send
  824.         pop     eax
  825.  
  826.         mov     [eax + SOCKET_head.lock], 0
  827.         mov     [eax +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
  828.         call    notify_network_event
  829.         ret
  830.  
  831.   .exit:
  832.         mov     [ebx + SOCKET_head.lock], 0
  833.         ret
  834.  
  835.   .fail:
  836.         add     esp, 8
  837.         mov     [ebx + SOCKET_head.lock], 0
  838.         ret
  839.  
  840.  
  841. align 4
  842. stateTCB_SYN_SENT:
  843.  
  844.         DEBUGF  1,"TCBStateHandler: Syn_Sent\n"
  845.  
  846.         ; We are awaiting an ACK to our SYN, with a SYM
  847.         ; Look at control flags - expecting an ACK
  848.  
  849.         mov     al, [edx + TCP_Packet.Flags]
  850.  
  851.         test    al, TH_RST
  852.         jnz     .reset                  ; jump if RST bit set
  853.  
  854.         push    [edx + TCP_Packet.SequenceNumber]                                    ;;
  855.         pop     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]       ;;
  856.         inc_INET (ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT)      ;;
  857.  
  858.  
  859.         push    [edx + TCP_Packet.AckNumber]                                        ;;;;;;
  860.         pop     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]      ;;;;;;
  861.  
  862.         and     al, TH_SYN + TH_ACK
  863.         jz      .exit                   ; jump if none of the following is set: RST, SYN, ACK
  864.  
  865.         test    al, TH_ACK
  866.         jz     .onlysyn                 ; jump if only SYN bit is set
  867.  
  868.         ; If we arrived here, SYN and ACK are set
  869.  
  870.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
  871.         pushw   TH_ACK
  872.  
  873.   .send:        ; Send an ACK
  874.         mov     eax, ebx
  875.         pop     bx
  876.         push    eax
  877.         xor     ecx, ecx
  878.         call    TCP_send
  879.         pop     ebx
  880.  
  881.   .exit:
  882.         mov     [ebx + SOCKET_head.lock], 0
  883.         ret
  884.  
  885.   .reset:
  886.         ; TODO: ....
  887.  
  888.         ; remove all queued TCP packets for this connection !
  889.  
  890.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSED
  891.         mov     [ebx + SOCKET_head.lock], 0
  892.         ret
  893.  
  894.   .onlysyn:
  895.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
  896.         pushw   TH_SYN + TH_ACK
  897.         jmp     .send
  898.  
  899.  
  900.  
  901. align 4
  902. stateTCB_SYN_RECEIVED:
  903.  
  904.         DEBUGF  1,"TCBStateHandler: Syn_received\n"
  905.  
  906.         test    [edx + TCP_Packet.Flags], TH_RST        ; reset connection? => LISTEN
  907.         jz      .check_ack
  908.  
  909.         push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemotePort]
  910.         pop     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
  911.         push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemoteIP]
  912.         pop     [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  913.  
  914.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LISTEN
  915.         jmp     .exit
  916.  
  917.   .check_ack:
  918.         test    [edx + TCP_Packet.Flags], TH_ACK        ; ACK? => connection established!
  919.         jz      .exit
  920.  
  921.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
  922.         mov     eax, ebx
  923.         call    notify_network_event
  924.  
  925.   .exit:
  926.         mov     [ebx + SOCKET_head.lock], 0
  927.         ret
  928.  
  929.  
  930. if 0
  931.  
  932.  
  933. align 4
  934. stateTCB_ESTABLISHED:
  935.  
  936.         DEBUGF  1,"TCBStateHandler: Established\n"
  937.  
  938.         mov     eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  939.         bswap   eax
  940.         DEBUGF  1,"RCV_NXT is set to:%u\n", eax
  941.         bswap   eax
  942.         cmp     eax, [edx + TCP_Packet.SequenceNumber]
  943.         jne     .exit                                   ;;;;;;
  944.  
  945. ; check if we received an ACK
  946.         test    [edx + TCP_Packet.Flags], TH_ACK
  947.         jz      .no_ack
  948.  
  949.         mov     ax, [edx + TCP_Packet.Window]
  950.         xchg    al, ah
  951.         cmp     ax, 1024
  952.         ja      @f
  953.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1
  954.       @@:
  955.   .no_ack:
  956.  
  957. ; Now, see if we received any data
  958.         test    ecx, ecx
  959.         jz      .nodata
  960.  
  961. ; Calculate next sequencenumber
  962.         add_INET (ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT)
  963.  
  964.         push    edx
  965.         DEBUGF  1,"Got %u bytes data!\n", ecx
  966. ; calculate header length
  967.         movzx   eax, [edx + TCP_Packet.DataOffset]
  968.         and     eax, 11110000b
  969.         shr     eax, 2
  970.         DEBUGF  1,"TCP header size: %u\n", eax
  971.         add     edx, eax        ; now edx points to data
  972.  
  973.         add     esp, 4
  974.         pop     esi             ; pointer to buffer
  975.         add     esp, 4
  976.  
  977.         sub     edx, esi
  978.         mov     edi, edx        ; offset
  979.         mov     eax, ebx        ; socket ptr
  980.  
  981.         call    socket_internal_receiver        ; Place the data from packet into socket
  982.  
  983. ;        lea     ebx, [eax + SOCKET_head.lock]
  984. ;        call    wait_mutex
  985.         mov     ebx, eax
  986.         pop     edx
  987.  
  988.         test    [edx + TCP_Packet.Flags], TH_FIN + TH_RST
  989.         jz      .ack
  990.  
  991.   .nodata:
  992.         test    [edx + TCP_Packet.Flags], TH_FIN + TH_RST
  993.         jz      .exit
  994.  
  995. ; Send an ACK to that fin, and enter closewait state
  996.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSE_WAIT
  997. ; Remove all resend entries from the queue
  998.         mov     eax, ebx
  999.         call    TCP_remove_socket
  1000.  
  1001.   .ack:
  1002.         push    ebx
  1003.         mov     ecx, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  1004.         call    TCP_queue_ack
  1005.         pop     ebx
  1006.  
  1007.   .exit:
  1008.         mov     [ebx + SOCKET_head.lock], 0
  1009.         ret
  1010.  
  1011.  
  1012. end if
  1013.  
  1014.  
  1015. align 4
  1016. stateTCB_ESTABLISHED:
  1017.  
  1018.         DEBUGF  1,"TCBStateHandler: Established\n"
  1019.  
  1020.         mov     eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  1021.         bswap   eax
  1022.         DEBUGF  1,"RCV_NXT is set to:%u\n", eax
  1023.         bswap   eax
  1024.         cmp     eax, [edx + TCP_Packet.SequenceNumber]
  1025.         jne     .exit
  1026.  
  1027. ; Calculate next sequencenumber
  1028.         add_INET (ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT)
  1029.  
  1030.         test    [edx + TCP_Packet.Flags], TH_FIN + TH_RST
  1031.         jnz     .fin
  1032.  
  1033.   .check_ack:
  1034.         test    [edx + TCP_Packet.Flags], TH_ACK
  1035.         jz      .exit
  1036.  
  1037.         DEBUGF  1,"Received ACK\n"
  1038. ; First, look at the incoming window. If this is less than or equal to 1024,
  1039. ; Set the socket window timer to 1. This will stop an additional Packets being queued.
  1040. ; ** I may need to tweak this value, since I do not know how many Packets are already queued
  1041.         push    ecx
  1042.         mov     cx, [edx + TCP_Packet.Window]
  1043.         xchg    cl, ch
  1044.         cmp     cx, 1024
  1045.         ja      @f
  1046.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1
  1047.       @@:
  1048.         pop     ecx
  1049.  
  1050. ; Now, see if we received any data
  1051.         test    ecx, ecx
  1052.         jz      .exit
  1053.  
  1054.         DEBUGF  1,"Got %u bytes data!\n", ecx
  1055. ; calculate header length
  1056.         movzx   eax, [edx + TCP_Packet.DataOffset]
  1057.         and     eax, 11110000b
  1058.         shr     eax, 2
  1059.        DEBUGF 1,"TCP header size: %u\n", eax
  1060.         add     edx, eax        ; now edx points to data
  1061.  
  1062.         add     esp, 4
  1063.         pop     esi             ; pointer to buffer
  1064.         add     esp, 4
  1065.  
  1066.         sub     edx, esi
  1067.         mov     edi, edx        ; offset
  1068.         mov     eax, ebx        ; socket ptr
  1069.  
  1070.         call    socket_internal_receiver        ; Place the data from packet into socket
  1071.  
  1072.         lea     ebx, [eax + SOCKET_head.lock]
  1073.         call    wait_mutex
  1074.         mov     ebx, eax
  1075.  
  1076.   .ack:
  1077.         mov     eax, ebx
  1078.         mov     bl, TH_ACK
  1079.         push    eax
  1080.         xor     ecx, ecx
  1081.         call    TCP_send                    ; send the ack
  1082.         pop     ebx
  1083.   .exit:
  1084.         mov     [ebx + SOCKET_head.lock], 0
  1085.         ret
  1086.  
  1087.   .fin:        ; we received a FIN or RESET
  1088. ; Remove all resend entries from the queue
  1089.         mov     ecx, TCP_QUEUE_SIZE
  1090.         mov     esi, TCP_OUT_QUEUE+4
  1091.  
  1092.   .removeloop:
  1093.         cmp     [esi + tcp_out_queue_entry.data_ptr], 0
  1094.         je      .maybe_next
  1095.  
  1096.         ; TODO: check if the packets belong to the same tcp connection !
  1097.  
  1098.        DEBUGF 1,"Removing a queued packet\n"
  1099.  
  1100.         push    [esi + tcp_out_queue_entry.data_ptr]
  1101.         mov     [esi + tcp_out_queue_entry.data_ptr], 0
  1102.         dec     [TCP_OUT_QUEUE]
  1103.         call    kernel_free
  1104.  
  1105.   .maybe_next:
  1106.         add     esi, tcp_out_queue_entry.size
  1107.         loop    .removeloop
  1108.  
  1109. ; Send an ACK to that fin, and enter closewait state
  1110.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSING
  1111.         jmp     .check_ack
  1112.  
  1113.  
  1114. align 4
  1115. stateTCB_FIN_WAIT_1:
  1116.  
  1117.         DEBUGF  1,"TCBStateHandler: Fin_wait_1\n"
  1118.  
  1119.         ; We can either receive an ACK of a fin, or a fin
  1120.         mov     al, [edx + TCP_Packet.Flags]
  1121.         and     al, TH_FIN + TH_ACK
  1122.  
  1123.         cmp     al, TH_ACK
  1124.         jne     @f
  1125.  
  1126.         ; It was an ACK
  1127.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_FIN_WAIT_2
  1128.         jmp     .exit
  1129.  
  1130.     @@: mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSING
  1131.         cmp     al, TH_FIN
  1132.         je      @f
  1133.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  1134.  
  1135.     @@:
  1136.         ; Send an ACK
  1137.         mov     eax, ebx
  1138.         mov     bl, TH_ACK
  1139.         push    eax
  1140.         xor     ecx, ecx
  1141.         call    TCP_send
  1142.         pop     ebx
  1143.  
  1144.   .exit:
  1145.         mov     [ebx + SOCKET_head.lock], 0
  1146.         ret
  1147.  
  1148.  
  1149.  
  1150. align 4
  1151. stateTCB_FIN_WAIT_2:
  1152.  
  1153.         DEBUGF  1,"TCBStateHandler: Fin_wait_2\n"
  1154.  
  1155.         test    [edx + TCP_Packet.Flags], TH_FIN
  1156.         jz      .exit
  1157.  
  1158.         ; Change state, as we have a fin
  1159.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  1160.  
  1161.         ; Send an ACK
  1162.         mov     eax, ebx
  1163.         mov     bl, TH_ACK
  1164.         push    eax
  1165.         xor     ecx, ecx
  1166.         call    TCP_send
  1167.         pop     ebx
  1168.  
  1169.   .exit:
  1170.         mov     [ebx + SOCKET_head.lock], 0
  1171.         ret
  1172.  
  1173.  
  1174.  
  1175. align 4
  1176. stateTCB_CLOSE_WAIT:
  1177.  
  1178.         DEBUGF  1,"TCBStateHandler: close_wait\n"
  1179.         ; Intentionally left empty
  1180.         ; socket_close_tcp handles this
  1181.  
  1182.         mov     [ebx + SOCKET_head.lock], 0
  1183.         ret
  1184.  
  1185.  
  1186.  
  1187. align 4
  1188. stateTCB_CLOSING:
  1189.  
  1190.         DEBUGF  1,"TCBStateHandler: closingn\n"
  1191.  
  1192.         ; We can either receive an ACK of a fin, or a fin
  1193.         test    [edx + TCP_Packet.Flags], TH_ACK
  1194.         jz      .exit
  1195.  
  1196.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  1197.  
  1198.   .exit:
  1199.  
  1200.         mov     [ebx + SOCKET_head.lock], 0
  1201.         ret
  1202.  
  1203.  
  1204. align 4
  1205. stateTCB_LAST_ACK:
  1206.  
  1207.         DEBUGF  1,"TCBStateHandler: last_ackn\n"
  1208.  
  1209.         ; Look at control flags - expecting an ACK
  1210.         test    [edx + TCP_Packet.Flags], TH_ACK
  1211.         jz      .exit
  1212.  
  1213.         mov     [ebx + SOCKET_head.lock], 0
  1214.  
  1215.         ; delete the socket
  1216.         stdcall net_socket_free, ebx
  1217.  
  1218.   .exit:
  1219.         ret
  1220.  
  1221.  
  1222. align 4
  1223. stateTCB_TIME_WAIT:
  1224.  
  1225.         DEBUGF  1,"TCBStateHandler: time_wait\n"
  1226.  
  1227.         mov     [ebx + SOCKET_head.lock], 0
  1228.  
  1229.         ret
  1230.  
  1231.  
  1232. align 4
  1233. stateTCB_CLOSED:
  1234.  
  1235.         DEBUGF  1,"TCBStateHandler: closed\n"
  1236.  
  1237.         mov     [ebx + SOCKET_head.lock], 0
  1238.  
  1239.         ret
  1240.  
  1241.  
  1242.  
  1243. ;---------------------------------------------------------------------------
  1244. ;
  1245. ; TCP_API
  1246. ;
  1247. ; This function is called by system function 75
  1248. ;
  1249. ; IN:  subfunction number in bl
  1250. ;      device number in bh
  1251. ;      ecx, edx, .. depends on subfunction
  1252. ;
  1253. ; OUT:
  1254. ;
  1255. ;---------------------------------------------------------------------------
  1256. align 4
  1257. TCP_API:
  1258.  
  1259.         movzx   eax, bh
  1260.         shl     eax, 2
  1261.  
  1262.         test    bl, bl
  1263.         jz      .packets_tx     ; 0
  1264.         dec     bl
  1265.         jz      .packets_rx     ; 1
  1266.  
  1267. .error:
  1268.         mov     eax, -1
  1269.         ret
  1270.  
  1271. .packets_tx:
  1272.         add     eax, TCP_PACKETS_TX
  1273.         mov     eax, [eax]
  1274.         ret
  1275.  
  1276. .packets_rx:
  1277.         add     eax, TCP_PACKETS_RX
  1278.         mov     eax, [eax]
  1279.         ret
  1280.