Subversion Repositories Kolibri OS

Rev

Rev 1249 | 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. ;;                                                                 ;;
  12. ;;          GNU GENERAL PUBLIC LICENSE                             ;;
  13. ;;             Version 2, June 1991                                ;;
  14. ;;                                                                 ;;
  15. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  16.  
  17.  
  18. $Revision: 1254 $
  19.  
  20. TCP_RETRIES             equ 5           ; Number of times to resend a Packet
  21. TCP_PACKET_TTL          equ 50          ; resend if not replied to in 1/100 s
  22. TCP_SOCKET_TTL          equ 10          ; # of secs to wait before closing socket
  23.  
  24. TCP_QUEUE_SIZE          equ 16
  25.  
  26.  
  27. struct  TCP_Packet
  28.         .SourcePort             dw ?
  29.         .DestinationPort        dw ?
  30.         .SequenceNumber         dd ?
  31.         .AckNumber              dd ?
  32.         .DataOffset             db ?    ; DataOffset[0-3 bits] and Reserved[4-7]
  33.         .Flags                  db ?    ; Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN
  34.         .Window                 dw ?
  35.         .Checksum               dw ?
  36.         .UrgentPointer          dw ?
  37.         .Options                rb 3
  38.         .Padding                db ?
  39.         .Data:
  40. ends
  41.  
  42. align 4
  43. uglobal
  44.         TCP_PACKETS_TX          rd  MAX_IP
  45.         TCP_PACKETS_RX          rd  MAX_IP
  46.  
  47.         TCP_IN_QUEUE            rd  (tcp_in_queue_entry.size*TCP_QUEUE_SIZE+queue.data)/4
  48.         TCP_OUT_QUEUE           dd  ?
  49.                                 rd  (tcp_out_queue_entry.size*TCP_QUEUE_SIZE)/4
  50. endg
  51.  
  52. align 4
  53. iglobal
  54.  
  55. stateHandler:
  56.  
  57.   dd  stateTCB_LISTEN
  58.   dd  stateTCB_SYN_SENT
  59.   dd  stateTCB_SYN_RECEIVED
  60.   dd  stateTCB_ESTABLISHED
  61.   dd  stateTCB_FIN_WAIT_1
  62.   dd  stateTCB_FIN_WAIT_2
  63.   dd  stateTCB_CLOSE_WAIT
  64.   dd  stateTCB_CLOSING
  65.   dd  stateTCB_LAST_ACK
  66.   dd  stateTCB_TIME_WAIT
  67.   dd  stateTCB_CLOSED
  68.  
  69. endg
  70.  
  71.  
  72. ;-----------------------------------------------------------------
  73. ;
  74. ; TCP_init
  75. ;
  76. ;  This function resets all TCP variables
  77. ;
  78. ;  IN:  /
  79. ;  OUT: /
  80. ;
  81. ;-----------------------------------------------------------------
  82.  
  83. align 4
  84. TCP_init:
  85.  
  86.         xor     eax, eax
  87.         mov     edi, TCP_PACKETS_TX
  88.         mov     ecx, 2*MAX_IP
  89.         rep     stosd
  90.  
  91.         init_queue TCP_IN_QUEUE
  92.  
  93.         ; tcp_out_queue is a special type of queue
  94.         xor     eax, eax
  95.         mov     esi, TCP_OUT_QUEUE
  96.         mov     ecx, TCP_QUEUE_SIZE*tcp_out_queue_entry/4+1
  97.         rep     stosd
  98.  
  99.         ret
  100.  
  101.  
  102. ;-----------------------------------------------------------------
  103. ;
  104. ;  TCP_decrease_socket_ttls
  105. ;
  106. ;  IN:  /
  107. ;  OUT: /
  108. ;
  109. ;-----------------------------------------------------------------
  110.  
  111. align 4
  112. TCP_decrease_socket_ttls:
  113.         ; scan through all the sockets, decrementing active timers
  114.  
  115.         mov     ebx, net_sockets
  116.  
  117.         cmp     [ebx + SOCKET_head.NextPtr], 0
  118.         je      .exit
  119.  
  120.   .next_socket:
  121.         mov     ebx, [ebx + SOCKET_head.NextPtr]
  122.         or      ebx, ebx
  123.         jz      .exit
  124.  
  125.         cmp     [ebx + SOCKET_head.Type], IP_PROTO_TCP
  126.         jne     .next_socket
  127.  
  128. ;        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]
  129.  
  130.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer], 0
  131.         jne     .decrement_tcb
  132.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 0
  133.         jne     .decrement_wnd
  134.         jmp     .next_socket
  135.  
  136.   .decrement_tcb:
  137.         ; decrement it, delete socket if TCB timer = 0 & socket in timewait state
  138.         dec     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer]
  139.         jnz     .next_socket
  140.  
  141.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  142.         jne     .next_socket
  143.  
  144.         push    [ebx + SOCKET_head.PrevPtr]
  145.         stdcall net_socket_free, ebx
  146.         pop     ebx
  147.         jmp     .next_socket
  148.  
  149.   .decrement_wnd:
  150.         ; TODO - prove it works!
  151.         dec     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer]
  152.         jmp     .next_socket
  153.  
  154.   .exit:
  155.         ret
  156.  
  157.  
  158.  
  159. ;-----------------------------------------------------------------
  160. ;
  161. ; TCP_send_queued:
  162. ;
  163. ;  Decreases 'ttl' of tcp packets queued.
  164. ;  if 'ttl' reaches 0, resend the packet and decrease 'retries'
  165. ;  if 'retries' reaches zero, remove the queued packet
  166. ;
  167. ;  IN:  /
  168. ;  OUT: /
  169. ;
  170. ;-----------------------------------------------------------------
  171.  
  172. align 4
  173. TCP_send_queued:
  174.  
  175.         cmp     [TCP_OUT_QUEUE], 0
  176.         je      .exit
  177.  
  178.         mov     eax, TCP_QUEUE_SIZE
  179.         mov     ecx, [TCP_OUT_QUEUE]
  180.         mov     esi, TCP_OUT_QUEUE+4
  181.  
  182.   .loop:
  183.         cmp     [esi + tcp_out_queue_entry.data_ptr], 0
  184.         jnz     .found_one
  185.         add     esi, tcp_out_queue_entry.size
  186.         loop    .loop
  187.   .exit:
  188.         ret
  189.  
  190.   .found_one:
  191.         dec     [esi + tcp_out_queue_entry.ttl]
  192.         jz      .send_it
  193.   .find_next:
  194.         add     esi, tcp_out_queue_entry.size
  195.         dec     eax
  196.         jz      .exit
  197.         test    ecx, ecx
  198.         jnz     .loop
  199.         ret
  200.  
  201.   .send_it:
  202.         push    eax ecx esi
  203.  
  204.         mov     ebx, [esi + tcp_out_queue_entry.owner]
  205.         push    [esi + tcp_out_queue_entry.data_size]
  206.         push    [esi + tcp_out_queue_entry.data_ptr]
  207.         DEBUGF 1,"Now sending TCP packet %x, size: %u, owner: %x, sendproc %x\n", [esp], [esp+4], ebx, [esi + tcp_out_queue_entry.sendproc]
  208.         call    [esi + tcp_out_queue_entry.sendproc]
  209.         add     esp, 8
  210.         pop     esi ecx eax
  211.  
  212.         dec     [esi + tcp_out_queue_entry.retries]
  213.         jz      .remove_it
  214.  
  215.         mov     [esi + tcp_out_queue_entry.ttl], TCP_PACKET_TTL
  216.         jmp     .find_next
  217.  
  218.   .remove_it:
  219.         push    [esi + tcp_out_queue_entry.data_ptr]
  220.         mov     [esi + tcp_out_queue_entry.data_ptr], 0
  221.         call    kernel_free
  222.         jmp     .find_next
  223.  
  224.  
  225.  
  226. ;-----------------------------------------------------------------
  227. ;
  228. ; TCP_add_to_queue:
  229. ;
  230. ;  Queue a TCP packet for sending
  231. ;
  232. ;  IN:  [esp] pointer to buffer
  233. ;       [esp + 4] size of buffer
  234. ;       ebx = driver struct
  235. ;       esi = sender proc
  236. ;       edx = acknum
  237. ;  OUT: /
  238. ;
  239. ;-----------------------------------------------------------------
  240.  
  241. align 4
  242. TCP_add_to_queue:
  243.  
  244.         DEBUGF 1,"Adding packet to TCP queue, buffer: %x, size: %u, driver: %x, acknum: %x\n", [esp], [esp+4], ebx, edx
  245.  
  246.         cmp     [TCP_OUT_QUEUE], TCP_QUEUE_SIZE
  247.         jge     .full
  248.  
  249.         mov     ecx, TCP_QUEUE_SIZE
  250.         mov     eax, TCP_OUT_QUEUE+4
  251.  
  252.   .loop:
  253.         cmp     [eax + tcp_out_queue_entry.data_ptr], 0
  254.         je      .found_it
  255.         add     eax, tcp_out_queue_entry.size
  256.         loop    .loop
  257.  
  258.   .full:                        ; silently discard the packet
  259.  
  260.         DEBUGF 1,"TCP queue is full!\n"
  261.  
  262.         call    kernel_free
  263.         add     esp, 4
  264.  
  265.         ret
  266.  
  267.   .found_it:                    ; eax point to empty queue entry
  268.  
  269.         pop     [eax + tcp_out_queue_entry.data_ptr]
  270.         pop     [eax + tcp_out_queue_entry.data_size]
  271.         mov     [eax + tcp_out_queue_entry.ttl], 1                      ; send immediately
  272.         mov     [eax + tcp_out_queue_entry.retries], TCP_RETRIES
  273.         mov     [eax + tcp_out_queue_entry.owner], ebx
  274.         mov     [eax + tcp_out_queue_entry.sendproc], esi
  275.         mov     [eax + tcp_out_queue_entry.seq_num], edx
  276.  
  277.         inc     [TCP_OUT_QUEUE]
  278.  
  279.         sub     eax, TCP_OUT_QUEUE+4
  280.         DEBUGF 1,"Added to queue in pos %u\n", eax
  281.  
  282.         ret
  283.  
  284.  
  285. ;-----------------------------------------------------------------
  286. ;
  287. ; TCP_handler:
  288. ;
  289. ;  Called by IPv4_handler,
  290. ;  this procedure will inject the tcp data diagrams in the application sockets.
  291. ;
  292. ;  IN:  Pointer to buffer in [esp]
  293. ;       size of buffer in [esp+4]
  294. ;       pointer to device struct in ebx
  295. ;       TCP Packet size in ecx
  296. ;       pointer to TCP Packet data in edx
  297. ;       SourceAddres in esi
  298. ;  OUT: /
  299. ;
  300. ;-----------------------------------------------------------------
  301.  
  302. align 4
  303. TCP_handler :
  304.  
  305.        DEBUGF 1,"TCP_Handler\n"
  306.  
  307.         ; TODO: validate checksum
  308.  
  309.         ; IP Packet TCP Destination Port = local Port
  310.         ; IP Packet SA = Remote IP  OR = 0
  311.         ; IP Packet TCP Source Port = remote Port  OR = 0
  312.  
  313.         mov     ebx, net_sockets
  314.  
  315.   .socket_loop:
  316.         mov     ebx, [ebx + SOCKET_head.NextPtr]
  317.         or      ebx, ebx
  318.         jz      .dump
  319.  
  320.         mov     ax, [edx + TCP_Packet.DestinationPort]
  321.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], ax
  322.         jne     .socket_loop
  323.  
  324.         mov     eax, [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  325.         cmp     eax, esi
  326.         je      @f
  327.         test    eax, eax
  328.         jne     .socket_loop
  329.        @@:
  330.  
  331.         mov     ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
  332.         cmp     [edx + TCP_Packet.SourcePort] , ax
  333.         je      .change_state
  334.         test    ax, ax
  335.         jnz     .socket_loop
  336.  
  337.   .change_state:
  338.  
  339.        DEBUGF 1,"Found valid socket for packet\n"
  340.  
  341.         push    ebx
  342.         lea     ebx, [ebx + SOCKET_head.lock]
  343.         call    wait_mutex
  344.         pop     ebx
  345.  
  346. ;----------------------------------
  347. ; ebx is pointer to socket
  348. ; ecx is size of tcp packet
  349. ; edx is pointer to tcp packet
  350.  
  351.         ; as a Packet has been received, update the TCB timer
  352.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer], TCP_SOCKET_TTL
  353.  
  354.         ; If the received Packet has an ACK bit set, remove any Packets in the resend queue that this received Packet acknowledges
  355.         test    [edx + TCP_Packet.Flags], TH_ACK
  356.         jz      .call_handler                                   ; No ACK, so no data yet
  357.  
  358. ;        mov     eax, [edx + TCP_Packet.SequenceNumber]          ; Calculate sequencenumber in eax
  359. ;        bswap   eax                                             ;
  360. ;        add     eax, ecx                                        ;
  361.  
  362.         mov     eax, [edx + TCP_Packet.AckNumber]
  363.         ;---------
  364.  
  365.         cmp     [TCP_OUT_QUEUE], 0
  366.         je      .call_handler
  367.         push    ecx
  368.  
  369.        DEBUGF 1,"Removing all queued packets with smaller ACK\n"
  370.  
  371.         mov     ecx, TCP_QUEUE_SIZE
  372.         mov     esi, TCP_OUT_QUEUE+4
  373.  
  374.   .loop:
  375.         cmp     [esi + tcp_out_queue_entry.data_ptr], 0
  376.         je      .maybe_next
  377.         cmp     [esi + tcp_out_queue_entry.seq_num], eax
  378.         jg      .maybe_next
  379.         ; TODO: check if the packets belong to the same tcp connection !
  380.  
  381.        DEBUGF 1,"Removing a queued packet\n"
  382.  
  383.         push    [esi + tcp_out_queue_entry.data_ptr]
  384.         mov     [esi + tcp_out_queue_entry.data_ptr], 0
  385.         dec     [TCP_OUT_QUEUE]
  386.         call    kernel_free
  387.  
  388.   .maybe_next:
  389.         add     esi, tcp_out_queue_entry.size
  390.         loop    .loop
  391.  
  392.         pop     ecx
  393.   .call_handler:
  394.         ; Call handler for given TCB state
  395.         mov     eax, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state]
  396.         DEBUGF 1,"Socket state: %u\n", eax
  397.  
  398.         cmp     eax, TCB_LISTEN
  399.         jb      .dump
  400.         cmp     eax, TCB_CLOSED
  401.         ja      .dump
  402.  
  403.         dec     eax
  404.         shl     eax, 2
  405.         add     eax, stateHandler
  406.  
  407.         call    dword[eax]
  408.  
  409.   .dump:
  410.         DEBUGF 1,"Dumping TCP packet\n"
  411.         call    kernel_free
  412.         add     esp, 4 ; pop (balance stack)
  413.  
  414.         ret
  415.  
  416.  
  417.  
  418. ;-----------------------------------------------------------------
  419. ;
  420. ; TCP_socket_send
  421. ;
  422. ; IN: eax = socket pointer
  423. ;     ecx = number of bytes to send
  424. ;     esi = pointer to data
  425. ;
  426. ;-----------------------------------------------------------------
  427.  
  428. align 4
  429. TCP_socket_send:
  430.  
  431.         DEBUGF 1,"Creating TCP Packet\n"
  432.  
  433.         mov     di , IP_PROTO_TCP
  434.  
  435. ; Create an IPv4 Packet of the correct size
  436.         push    eax
  437.         mov     ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
  438.         mov     eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  439.  
  440. ; meanwhile, create the pseudoheader in stack,
  441. ; (now that we still have all the variables that are needed.)
  442.         push    cx
  443.         push    di
  444.         push    eax
  445.         push    ebx
  446.  
  447.  
  448.         push    ecx esi eax             ; save some variables for later
  449.         add     ecx, TCP_Packet.Options
  450.         call    IPv4_create_packet
  451.         cmp     edi, -1
  452.         je      .fail
  453.  
  454.         pop     esi
  455.  
  456. ; Now add the TCP header to the IPv4 packet
  457.  
  458.         push    [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  459.         pop     [edi + TCP_Packet.SequenceNumber]
  460.  
  461.         push    dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort]
  462.         pop     dword [edi + TCP_Packet.SourcePort]
  463.  
  464.  
  465.         push    [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  466.         pop     [edi + TCP_Packet.AckNumber]
  467.  
  468.         mov     al, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.flags]
  469.         mov     [edi + TCP_Packet.Flags], al
  470.  
  471.         mov     [edi + TCP_Packet.Window], 0x0005          ; 1280 bytes
  472.         mov     [edi + TCP_Packet.UrgentPointer], 0
  473.         mov     [edi + TCP_Packet.DataOffset], 0x50
  474.         mov     [edi + TCP_Packet.Checksum], 0
  475.  
  476. ; Copy the data
  477.         mov     esi, [esp]
  478.         mov     ecx, [esp+4]
  479.         add     edi, TCP_Packet.Options
  480.  
  481.         shr     ecx, 1
  482.         jnc     .nb
  483.         movsb
  484. .nb:    shr     ecx, 1
  485.         jnc     .nw
  486.         movsw
  487. .nw:    rep movsd
  488.  
  489. ; Now, calculate the checksum for pseudoheader
  490.         xor     edx, edx
  491.         mov     ecx, 12
  492.         mov     esi, esp
  493.         call    checksum_1
  494.         add     esp, 12                                    ; remove the pseudoheader from stack
  495. ; And that of the data
  496.         pop     esi
  497.         pop     ecx
  498.         call    checksum_1
  499. ; Now create the final checksum and store it in TCP header
  500.         call    checksum_2
  501.         mov     [edi + TCP_Packet.Checksum], dx
  502.  
  503. ; And now, send it!
  504.         DEBUGF 1,"Sending TCP Packet to device %x\n", ebx
  505.         lea     esi, [ebx+ETH_DEVICE.transmit]
  506.         mov     edx, [edi + TCP_Packet.AckNumber]
  507.         jmp     TCP_add_to_queue
  508.  
  509.   .fail:
  510.         add     esp, 12+12+4
  511.         ret
  512.  
  513.  
  514.  
  515.  
  516.  
  517. ;-----------------------------------------------------------------
  518. ;
  519. ; TCP_send_ack
  520. ;
  521. ; IN: eax = socket pointer
  522. ;      bl = flags
  523. ;
  524. ;-----------------------------------------------------------------
  525.  
  526. align 4
  527. TCP_send_ack:
  528.  
  529.         DEBUGF 1,"Creating TCP ACK, socket: %x, flags: %x\n",eax, bl
  530.  
  531.         mov     di , IP_PROTO_TCP
  532.         mov     ecx, TCP_Packet.Options
  533.  
  534.         push    bx eax
  535.  
  536. ; Create an IPv4 Packet of the correct size
  537.  
  538.         mov     ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
  539.         mov     eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  540.  
  541.         call    IPv4_create_packet
  542.         cmp     edi, -1
  543.         je      .fail
  544.  
  545. ; Fill in the TCP header
  546.         pop     esi
  547.  
  548.         push    [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  549.         pop     [edi + TCP_Packet.SequenceNumber]
  550.  
  551.         push    dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort] ; both ports at once
  552.         pop     dword [edi + TCP_Packet.SourcePort]
  553.  
  554.         push    [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  555.         pop     [edi + TCP_Packet.AckNumber]
  556.  
  557.         pop     cx
  558.         mov     [edi + TCP_Packet.Flags], cl
  559.         mov     [edi + TCP_Packet.Window], 0x0005          ; 1280 bytes
  560.         mov     [edi + TCP_Packet.UrgentPointer], 0
  561.         mov     [edi + TCP_Packet.DataOffset], 0x50
  562.         mov     [edi + TCP_Packet.Checksum], 0
  563.  
  564.         push    edx eax
  565.  
  566.         lea     esi, [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  567.         inc_INET esi
  568.  
  569. ; Now, calculate the checksum
  570.         pushw   TCP_Packet.Options shl 8
  571.         pushw   IP_PROTO_TCP shl 8
  572.         pushd   [edi-4] ; destination address
  573.         pushd   [edi-8] ; source address
  574.  
  575.         xor     edx, edx
  576.         mov     ecx, TCP_Packet.Options
  577.         mov     esi, edi
  578.         call    checksum_1
  579.         mov     ecx, 12
  580.         mov     esi, esp
  581.         call    checksum_1
  582.         add     esp, 12                                    ; remove the pseudoheader from stack
  583. ; and store it in TCP header
  584.         call    checksum_2
  585.         mov     [edi + TCP_Packet.Checksum], dx
  586.  
  587. ; And now, send the packet!
  588.         DEBUGF 1,"Sending TCP Packet to device %x\n", ebx
  589.         mov     esi, [ebx + ETH_DEVICE.transmit]
  590.         mov     edx, [edi + TCP_Packet.SequenceNumber]
  591.         jmp     TCP_add_to_queue
  592.  
  593.   .fail:
  594.         add     esp, 2+4
  595.         ret
  596.  
  597.  
  598.  
  599.  
  600.  
  601. align 4
  602. stateTCB_LISTEN:
  603.  
  604.         DEBUGF  1,"TCBStateHandler: Listen\n"
  605.  
  606.         ; In this case, we are expecting a SYN Packet
  607.         ; For now, if the Packet is a SYN, process it, and send a response
  608.         ; If not, ignore it
  609.  
  610.         ; Look at control flags
  611.         test    [edx + TCP_Packet.Flags], TH_SYN
  612.         jz      .exit
  613.  
  614.         ; We have a SYN. update the socket with this IP Packets details,
  615.         ; And send a response
  616.  
  617.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP], esi ; IP source address
  618.         mov     ax, [edx + TCP_Packet.SourcePort]
  619.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], ax
  620.         mov     eax, [edx + TCP_Packet.SequenceNumber]
  621.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], eax
  622.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax
  623.         lea     esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  624.         inc_INET esi ; RCV.NXT
  625.         mov     eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS]
  626.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], eax
  627.  
  628.         mov     [ebx + SOCKET_head.lock], 0
  629.  
  630.         ; Now construct the response
  631.         mov     bl, TH_SYN + TH_ACK
  632.         call    TCP_send_ack
  633.  
  634.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
  635.  
  636.         ; increment SND.NXT in socket
  637.         lea     esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  638.         inc_INET esi
  639.  
  640.   .exit:
  641.         mov     [ebx + SOCKET_head.lock], 0
  642.         ret
  643.  
  644.  
  645. align 4
  646. stateTCB_SYN_SENT:
  647.  
  648.         DEBUGF  1,"TCBStateHandler: Syn_Sent\n"
  649.  
  650.         ; We are awaiting an ACK to our SYN, with a SYM
  651.         ; Look at control flags - expecting an ACK
  652.  
  653.         mov     al, [edx + TCP_Packet.Flags]
  654.         and     al, TH_SYN + TH_ACK
  655.         cmp     al, TH_SYN + TH_ACK
  656.         je      .syn_ack
  657.  
  658.         test    al, TH_SYN
  659.         jz      .exit
  660.  
  661.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
  662.         pushd   TH_SYN + TH_ACK
  663.         jmp     .send
  664.  
  665.   .syn_ack:
  666.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
  667.         pushd   TH_ACK
  668.  
  669.   .send:
  670.         ; Store the recv.nxt field
  671.         mov     eax, [edx + TCP_Packet.SequenceNumber]
  672.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], eax
  673.         bswap   eax
  674.         inc     eax
  675.         bswap   eax
  676.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax          ; Update our recv.nxt field
  677.         mov     [ebx + SOCKET_head.lock], 0
  678.  
  679.         ; Send an ACK
  680.         mov     eax, ebx
  681.         pop     ebx
  682.         call    TCP_send_ack
  683.  
  684.   .exit:
  685.         mov     [ebx + SOCKET_head.lock], 0
  686.         ret
  687.  
  688.  
  689.  
  690. align 4
  691. stateTCB_SYN_RECEIVED:
  692.  
  693.         DEBUGF  1,"TCBStateHandler: Syn_received\n"
  694.  
  695.         ; In this case, we are expecting an ACK Packet
  696.         ; For now, if the Packet is an ACK, process it,
  697.         ; If not, ignore it
  698.  
  699.         test    [edx + TCP_Packet.Flags], TH_RST
  700.         jz      .check_ack
  701.  
  702.   ;      push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemotePort]
  703.  ;       pop     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
  704.   ;      push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemoteIP]
  705.  ;       pop     [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  706.  
  707.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LISTEN
  708.         jmp     .exit
  709.  
  710.   .check_ack:
  711.         ; Look at control flags - expecting an ACK
  712.         test    [edx + TCP_Packet.Flags], TH_ACK
  713.         jz      .exit
  714.  
  715.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
  716.  
  717.   .exit:
  718.         mov     [ebx + SOCKET_head.lock], 0
  719.         ret
  720.  
  721.  
  722.  
  723. align 4
  724. stateTCB_ESTABLISHED:
  725.  
  726.  
  727.         DEBUGF  1,"TCBStateHandler: Established\n"
  728.  
  729.         ; Here we are expecting data, or a request to close
  730.         ; OR both...
  731.  
  732.         ; Did we receive a FIN or RST?
  733.         test    [edx + TCP_Packet.Flags], TH_FIN
  734.         jz      .check_ack
  735.  
  736.         ; It was a fin or reset.
  737.  
  738. ;;; TODO: write following code:
  739.         ; Remove resend entries from the queue  - I dont want to send any more data
  740.         ; Send an ACK to that fin, and enter closewait state
  741.  
  742.   .check_ack:
  743.         ; Check that we received an ACK
  744.         test    [edx + TCP_Packet.Flags], TH_ACK
  745.         jz      .exit
  746.  
  747.         DEBUGF  1,"Received ACK\n"
  748.  
  749.         ; First, look at the incoming window. If this is less than or equal to 1024,
  750.         ; Set the socket window timer to 1. This will stop an additional Packets being queued.
  751.         ; ** I may need to tweak this value, since I do not know how many Packets are already queued
  752.         mov     cx, [edx + TCP_Packet.Window]
  753.         xchg    cl, ch
  754.         cmp     cx, 1024
  755.         ja      @f
  756.  
  757.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1
  758.  
  759.     @@: ; OK, here is the deal
  760.         ; My recv.nct field holds the seq of the expected next rec byte
  761.         ; if the recevied sequence number is not equal to this, do not
  762.         ; increment the recv.nxt field, do not copy data - just send a
  763.         ; repeat ack.
  764.  
  765.         ; recv.nxt is in dword [edx+24], in inet format
  766.         ; recv seq is in [sktAddr]+56, in inet format
  767.         ; just do a comparision
  768.         mov     ecx, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  769.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSE_WAIT
  770.         jne     @f
  771.         mov     ecx, eax
  772.  
  773.     @@: cmp     ecx, [edx + TCP_Packet.SequenceNumber]
  774.         jne     .ack
  775.  
  776.         test    ecx, ecx
  777.         jnz     .data
  778.  
  779.         ; If we had received a fin, we need to ACK it.
  780.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSE_WAIT
  781.         je      .ack
  782.         jmp     .exit
  783.  
  784.   .data:
  785.         DEBUGF  1,"Got data!\n"
  786.         mov     esi, [esp + 4]
  787.         sub     edx, esi
  788.         mov     edi, edx
  789.         call    socket_internal_receiver
  790.  
  791.   .ack:
  792.         mov     [ebx + SOCKET_head.lock], 0
  793.         ; Send an ACK
  794.         mov     eax, ebx
  795.         mov     bl, TH_ACK
  796.         call    TCP_send_ack
  797.   .exit:
  798.  
  799.         mov     [ebx + SOCKET_head.lock], 0
  800.         ret
  801.  
  802.  
  803.  
  804. align 4
  805. stateTCB_FIN_WAIT_1:
  806.  
  807.         DEBUGF  1,"TCBStateHandler: Fin_wait_1\n"
  808.  
  809.         ; We can either receive an ACK of a fin, or a fin
  810.         mov     al, [edx + TCP_Packet.Flags]
  811.         and     al, TH_FIN + TH_ACK
  812.  
  813.         cmp     al, TH_ACK
  814.         jne     @f
  815.  
  816.         ; It was an ACK
  817.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_FIN_WAIT_2
  818.         jmp     .exit
  819.  
  820.     @@: mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSING
  821.         cmp     al, TH_FIN
  822.         je      @f
  823.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  824.  
  825.     @@: lea     esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  826.         inc_INET esi
  827.  
  828.         mov     [ebx + SOCKET_head.lock], 0
  829.         ; Send an ACK
  830.         mov     eax, ebx
  831.         mov     bl, TH_ACK
  832.         call    TCP_send_ack
  833.  
  834.   .exit:
  835.         mov     [ebx + SOCKET_head.lock], 0
  836.         ret
  837.  
  838.  
  839.  
  840. align 4
  841. stateTCB_FIN_WAIT_2:
  842.  
  843.         DEBUGF  1,"TCBStateHandler: Fin_wait_2\n"
  844.  
  845.         test    [edx + TCP_Packet.Flags], TH_FIN
  846.         jz      .exit
  847.  
  848.         ; Change state, as we have a fin
  849.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  850.  
  851.         lea     esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  852.         inc_INET esi
  853.  
  854.         mov     [ebx + SOCKET_head.lock], 0
  855.  
  856.         ; Send an ACK
  857.         mov     eax, ebx
  858.         mov     bl, TH_ACK
  859.         call    TCP_send_ack
  860.  
  861.   .exit:
  862.         mov     [ebx + SOCKET_head.lock], 0
  863.         ret
  864.  
  865.  
  866.  
  867. align 4
  868. stateTCB_CLOSE_WAIT:
  869.  
  870.         DEBUGF  1,"TCBStateHandler: close_wait\n"
  871.         ; Intentionally left empty
  872.         ; socket_close_tcp handles this
  873.  
  874.         mov     [ebx + SOCKET_head.lock], 0
  875.         ret
  876.  
  877.  
  878.  
  879. align 4
  880. stateTCB_CLOSING:
  881.  
  882.         DEBUGF  1,"TCBStateHandler: closingn\n"
  883.  
  884.         ; We can either receive an ACK of a fin, or a fin
  885.         test    [edx + TCP_Packet.Flags], TH_ACK
  886.         jz      .exit
  887.  
  888.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  889.  
  890.   .exit:
  891.  
  892.         mov     [ebx + SOCKET_head.lock], 0
  893.         ret
  894.  
  895.  
  896. align 4
  897. stateTCB_LAST_ACK:
  898.  
  899.         DEBUGF  1,"TCBStateHandler: last_ackn\n"
  900.  
  901.         ; Look at control flags - expecting an ACK
  902.         test    [edx + TCP_Packet.Flags], TH_ACK
  903.         jz      .exit
  904.  
  905.         mov     [ebx + SOCKET_head.lock], 0
  906.  
  907.         ; delete the socket
  908.         stdcall net_socket_free, ebx
  909.  
  910.   .exit:
  911.         ret
  912.  
  913.  
  914. align 4
  915. stateTCB_TIME_WAIT:
  916.  
  917.         DEBUGF  1,"TCBStateHandler: time_wait\n"
  918.  
  919.         mov     [ebx + SOCKET_head.lock], 0
  920.  
  921.         ret
  922.  
  923.  
  924. align 4
  925. stateTCB_CLOSED:
  926.  
  927.         DEBUGF  1,"TCBStateHandler: closed\n"
  928.  
  929.         mov     [ebx + SOCKET_head.lock], 0
  930.  
  931.         ret
  932.  
  933.  
  934.  
  935. ;---------------------------------------------------------------------------
  936. ;
  937. ; TCP_API
  938. ;
  939. ; This function is called by system function 75
  940. ;
  941. ; IN:  subfunction number in bl
  942. ;      device number in bh
  943. ;      ecx, edx, .. depends on subfunction
  944. ;
  945. ; OUT:
  946. ;
  947. ;---------------------------------------------------------------------------
  948.  
  949. align 4
  950. TCP_API:
  951.  
  952.         movzx   eax, bh
  953.         shl     eax, 2
  954.  
  955.         test    bl, bl
  956.         jz      .packets_tx     ; 0
  957.         dec     bl
  958.         jz      .packets_rx     ; 1
  959.  
  960. .error:
  961.         mov     eax, -1
  962.         ret
  963.  
  964. .packets_tx:
  965.         add     eax, TCP_PACKETS_TX
  966.         mov     eax, [eax]
  967.         ret
  968.  
  969. .packets_rx:
  970.         add     eax, TCP_PACKETS_RX
  971.         mov     eax, [eax]
  972.         ret
  973.