Subversion Repositories Kolibri OS

Rev

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