Subversion Repositories Kolibri OS

Rev

Rev 1256 | 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: 1257 $
  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. TCP_QUEUE_SIZE          equ 16
  24.  
  25.  
  26. struct  TCP_Packet
  27.         .SourcePort             dw ?
  28.         .DestinationPort        dw ?
  29.         .SequenceNumber         dd ?
  30.         .AckNumber              dd ?
  31.         .DataOffset             db ?    ; DataOffset[0-3 bits] and Reserved[4-7]
  32.         .Flags                  db ?    ; Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN
  33.         .Window                 dw ?
  34.         .Checksum               dw ?
  35.         .UrgentPointer          dw ?
  36.         .Options                rb 3
  37.         .Padding                db ?
  38.         .Data:
  39. ends
  40.  
  41. align 4
  42. uglobal
  43.         TCP_PACKETS_TX          rd  MAX_IP
  44.         TCP_PACKETS_RX          rd  MAX_IP
  45.  
  46.         TCP_IN_QUEUE            rd  (tcp_in_queue_entry.size*TCP_QUEUE_SIZE+queue.data)/4
  47.         TCP_OUT_QUEUE           dd  ?
  48.                                 rd  (tcp_out_queue_entry.size*TCP_QUEUE_SIZE)/4
  49. endg
  50.  
  51. align 4
  52. iglobal
  53. stateHandler:
  54.  
  55.   dd  stateTCB_LISTEN
  56.   dd  stateTCB_SYN_SENT
  57.   dd  stateTCB_SYN_RECEIVED
  58.   dd  stateTCB_ESTABLISHED
  59.   dd  stateTCB_FIN_WAIT_1
  60.   dd  stateTCB_FIN_WAIT_2
  61.   dd  stateTCB_CLOSE_WAIT
  62.   dd  stateTCB_CLOSING
  63.   dd  stateTCB_LAST_ACK
  64.   dd  stateTCB_TIME_WAIT
  65.   dd  stateTCB_CLOSED
  66.  
  67. endg
  68.  
  69.  
  70. ;-----------------------------------------------------------------
  71. ;
  72. ; TCP_init
  73. ;
  74. ;  This function resets all TCP variables
  75. ;
  76. ;  IN:  /
  77. ;  OUT: /
  78. ;
  79. ;-----------------------------------------------------------------
  80. align 4
  81. TCP_init:
  82.  
  83.         xor     eax, eax
  84.         mov     edi, TCP_PACKETS_TX
  85.         mov     ecx, 2*MAX_IP
  86.         rep     stosd
  87.  
  88.         init_queue TCP_IN_QUEUE
  89.  
  90.         ; tcp_out_queue is a special type of queue:
  91.         ; The first dword is a counter of total packets queued.
  92.         ; The remaining bytes are socket 'slots' wich use tcp_out_queue_entry data structure.
  93.         ; An empty slot is know by the fact that tcp_out_queue_entry.data_ptr (first dword of the slot) is set to 0
  94.         ; There are TCP_OUT_QUEUE_SIZE number of slots
  95.  
  96.         xor     eax, eax
  97.         mov     esi, TCP_OUT_QUEUE
  98.         mov     ecx, TCP_QUEUE_SIZE*tcp_out_queue_entry/4+1
  99.         rep     stosd
  100.  
  101.         ret
  102.  
  103.  
  104. ;-----------------------------------------------------------------
  105. ;
  106. ;  TCP_decrease_socket_ttls
  107. ;
  108. ;  IN:  /
  109. ;  OUT: /
  110. ;
  111. ;-----------------------------------------------------------------
  112. align 4
  113. TCP_decrease_socket_ttls:
  114.         ; scan through all the sockets, decrementing active timers
  115.  
  116.         mov     ebx, net_sockets
  117.  
  118.         cmp     [ebx + SOCKET_head.NextPtr], 0
  119.         je      .exit
  120.  
  121.   .next_socket:
  122.         mov     ebx, [ebx + SOCKET_head.NextPtr]
  123.         or      ebx, ebx
  124.         jz      .exit
  125.  
  126.         cmp     [ebx + SOCKET_head.Type], IP_PROTO_TCP
  127.         jne     .next_socket
  128.  
  129. ;        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]
  130.  
  131.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer], 0
  132.         jne     .decrement_tcb
  133.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 0
  134.         jne     .decrement_wnd
  135.         jmp     .next_socket
  136.  
  137.   .decrement_tcb:
  138.         ; decrement it, delete socket if TCB timer = 0 & socket in timewait state
  139.         dec     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer]
  140.         jnz     .next_socket
  141.  
  142.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  143.         jne     .next_socket
  144.  
  145.         push    [ebx + SOCKET_head.PrevPtr]
  146.         stdcall net_socket_free, ebx
  147.         pop     ebx
  148.         jmp     .next_socket
  149.  
  150.   .decrement_wnd:
  151.         ; TODO - prove it works!
  152.         dec     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer]
  153.         jmp     .next_socket
  154.  
  155.   .exit:
  156.         ret
  157.  
  158.  
  159.  
  160. ;-----------------------------------------------------------------
  161. ;
  162. ; TCP_send_queued:
  163. ;
  164. ;  Decreases 'ttl' of tcp packets queued.
  165. ;  if 'ttl' reaches 0, resend the packet and decrease 'retries'
  166. ;  if 'retries' reaches zero, remove the queued packet
  167. ;
  168. ;  IN:  /
  169. ;  OUT: /
  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.         inc     [TCP_PACKETS_TX]
  209.         call    [esi + tcp_out_queue_entry.sendproc]
  210.         add     esp, 8
  211.         pop     esi ecx eax
  212.  
  213.         dec     [esi + tcp_out_queue_entry.retries]
  214.         jz      .remove_it
  215.  
  216.         mov     [esi + tcp_out_queue_entry.ttl], TCP_PACKET_TTL
  217.         jmp     .find_next
  218.  
  219.   .remove_it:
  220.         push    [esi + tcp_out_queue_entry.data_ptr]
  221.         mov     [esi + tcp_out_queue_entry.data_ptr], 0
  222.         call    kernel_free
  223.         jmp     .find_next
  224.  
  225.  
  226.  
  227. ;-----------------------------------------------------------------
  228. ;
  229. ; TCP_add_to_queue:
  230. ;
  231. ;  Queue a TCP packet for sending
  232. ;
  233. ;  IN:  [esp] pointer to buffer
  234. ;       [esp + 4] size of buffer
  235. ;       ebx = driver struct
  236. ;       esi = sender proc
  237. ;       edx = acknum
  238. ;  OUT: /
  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. align 4
  302. TCP_handler :
  303.  
  304.        DEBUGF 1,"TCP_Handler\n"
  305.  
  306.         ; TODO: validate checksum
  307.  
  308.         ; IP Packet TCP Destination Port = local Port
  309.         ; IP Packet SA = Remote IP  OR = 0
  310.         ; IP Packet TCP Source Port = remote Port  OR = 0
  311.  
  312.         mov     ebx, net_sockets
  313.  
  314.   .socket_loop:
  315.         mov     ebx, [ebx + SOCKET_head.NextPtr]
  316.         or      ebx, ebx
  317.         jz      .dump
  318.  
  319.         mov     ax, [edx + TCP_Packet.DestinationPort]
  320.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], ax
  321.         jne     .socket_loop
  322.  
  323.         mov     eax, [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  324.         cmp     eax, esi
  325.         je      @f
  326.         test    eax, eax
  327.         jne     .socket_loop
  328.        @@:
  329.  
  330.         mov     ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
  331.         cmp     [edx + TCP_Packet.SourcePort] , ax
  332.         je      .change_state
  333.         test    ax, ax
  334.         jnz     .socket_loop
  335.  
  336.   .change_state:
  337.  
  338.        DEBUGF 1,"Found valid socket for packet\n"
  339.  
  340.         inc     [TCP_PACKETS_RX]
  341.  
  342.         push    ebx
  343.         lea     ebx, [ebx + SOCKET_head.lock]
  344.         call    wait_mutex
  345.         pop     ebx
  346.  
  347. ;----------------------------------
  348. ; ebx is pointer to socket
  349. ; ecx is size of tcp packet
  350. ; edx is pointer to tcp packet
  351.  
  352.         ; as a Packet has been received, update the TCB timer
  353.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.timer], TCP_SOCKET_TTL
  354.  
  355.         ; If the received Packet has an ACK bit set, remove any Packets in the resend queue that this received Packet acknowledges
  356.         test    [edx + TCP_Packet.Flags], TH_ACK
  357.         jz      .call_handler                                   ; No ACK, so no data yet
  358.  
  359. ;        mov     eax, [edx + TCP_Packet.SequenceNumber]          ; Calculate sequencenumber in eax
  360. ;        bswap   eax                                             ;
  361. ;        add     eax, ecx                                        ;
  362.  
  363.         mov     eax, [edx + TCP_Packet.AckNumber]
  364.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.last_ack_number], eax
  365.         ;---------
  366.  
  367.         cmp     [TCP_OUT_QUEUE], 0
  368.         je      .call_handler
  369.         push    ecx
  370.  
  371.        DEBUGF 1,"Removing all queued packets with smaller ACK\n"
  372.  
  373.         mov     ecx, TCP_QUEUE_SIZE
  374.         mov     esi, TCP_OUT_QUEUE+4
  375.  
  376.   .loop:
  377.         cmp     [esi + tcp_out_queue_entry.data_ptr], 0
  378.         je      .maybe_next
  379.         cmp     [esi + tcp_out_queue_entry.seq_num], eax
  380.         jg      .maybe_next
  381.         ; TODO: check if the packets belong to the same tcp connection !
  382.  
  383.        DEBUGF 1,"Removing a queued packet\n"
  384.  
  385.         push    [esi + tcp_out_queue_entry.data_ptr]
  386.         mov     [esi + tcp_out_queue_entry.data_ptr], 0
  387.         dec     [TCP_OUT_QUEUE]
  388.         call    kernel_free
  389.  
  390.   .maybe_next:
  391.         add     esi, tcp_out_queue_entry.size
  392.         loop    .loop
  393.  
  394.         pop     ecx
  395.   .call_handler:
  396.         ; Call handler for given TCB state
  397.         mov     eax, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state]
  398.         DEBUGF 1,"Socket state: %u\n", eax
  399.  
  400.         cmp     eax, TCB_LISTEN
  401.         jb      .dump
  402.         cmp     eax, TCB_CLOSED
  403.         ja      .dump
  404.  
  405.         dec     eax
  406.         shl     eax, 2
  407.         add     eax, stateHandler
  408.  
  409.         call    dword[eax]
  410.  
  411.   .dump:
  412.         DEBUGF 1,"Dumping TCP packet\n"
  413.         call    kernel_free
  414.         add     esp, 4 ; pop (balance stack)
  415.  
  416.         ret
  417.  
  418.  
  419.  
  420. ;-----------------------------------------------------------------
  421. ;
  422. ; TCP_socket_send
  423. ;
  424. ; IN: eax = socket pointer
  425. ;     ecx = number of bytes to send
  426. ;     esi = pointer to data
  427. ;
  428. ;-----------------------------------------------------------------
  429. align 4
  430. TCP_socket_send:
  431.  
  432.         DEBUGF 1,"Creating TCP Packet\n"
  433.  
  434.         mov     di , IP_PROTO_TCP
  435.  
  436. ; Create an IPv4 Packet of the correct size
  437.         push    eax
  438.         mov     ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
  439.         mov     eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  440.  
  441. ; meanwhile, create the pseudoheader in stack,
  442. ; (now that we still have all the variables that are needed.)
  443.         push    cx
  444.         push    di
  445.         push    eax
  446.         push    ebx
  447.  
  448.  
  449.         push    ecx esi eax             ; save some variables for later
  450.         add     ecx, TCP_Packet.Options
  451.         call    IPv4_create_packet
  452.         cmp     edi, -1
  453.         je      .fail
  454.  
  455.         pop     esi
  456.  
  457. ; Now add the TCP header to the IPv4 packet
  458.  
  459.         push    [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  460.         pop     [edi + TCP_Packet.SequenceNumber]
  461.  
  462.         push    dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort]
  463.         pop     dword [edi + TCP_Packet.SourcePort]
  464.  
  465.  
  466.         push    [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  467.         pop     [edi + TCP_Packet.AckNumber]
  468.  
  469.         mov     al, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.flags]
  470.         mov     [edi + TCP_Packet.Flags], al
  471.  
  472.         mov     [edi + TCP_Packet.Window], 0x0005          ; 1280 bytes
  473.         mov     [edi + TCP_Packet.UrgentPointer], 0
  474.         mov     [edi + TCP_Packet.DataOffset], 0x50
  475.         mov     [edi + TCP_Packet.Checksum], 0
  476.  
  477. ; Copy the data
  478.         mov     esi, [esp]
  479.         mov     ecx, [esp+4]
  480.         add     edi, TCP_Packet.Options
  481.  
  482.         shr     ecx, 1
  483.         jnc     .nb
  484.         movsb
  485. .nb:    shr     ecx, 1
  486.         jnc     .nw
  487.         movsw
  488. .nw:    rep movsd
  489.  
  490. ; Now, calculate the checksum for pseudoheader
  491.         xor     edx, edx
  492.         mov     ecx, 12
  493.         mov     esi, esp
  494.         call    checksum_1
  495.         add     esp, 12                                    ; remove the pseudoheader from stack
  496. ; And that of the data
  497.         pop     esi
  498.         pop     ecx
  499.         call    checksum_1
  500. ; Now create the final checksum and store it in TCP header
  501.         call    checksum_2
  502.         mov     [edi + TCP_Packet.Checksum], dx
  503.  
  504. ; And now, send it!
  505.         DEBUGF 1,"Sending TCP Packet to device %x\n", ebx
  506.         lea     esi, [ebx+ETH_DEVICE.transmit]
  507.         mov     edx, [edi + TCP_Packet.AckNumber]
  508.         jmp     TCP_add_to_queue
  509.  
  510.   .fail:
  511.         add     esp, 12+12+4
  512.         ret
  513.  
  514.  
  515.  
  516.  
  517.  
  518. ;-----------------------------------------------------------------
  519. ;
  520. ; TCP_send_ack
  521. ;
  522. ; IN: eax = socket pointer
  523. ;      bl = flags
  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  ; TODO: fix this, IPv4 packet could have options..
  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. ;---------- TCB state handlers start here
  602.  
  603.  
  604.  
  605.  
  606. align 4
  607. stateTCB_LISTEN:
  608.  
  609.         DEBUGF  1,"TCBStateHandler: Listen\n"
  610.  
  611.         ; In this case, we are expecting a SYN Packet
  612.         ; For now, if the Packet is a SYN, process it, and send a response
  613.         ; If not, ignore it
  614.  
  615.         ; Look at control flags
  616.         test    [edx + TCP_Packet.Flags], TH_SYN
  617.         jz      .exit
  618.         ; Exit if backlog queue is full
  619.         mov     ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
  620.         cmp     ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog]
  621.         jae     .exit
  622.         ; Allocate new socket
  623.         push    esi
  624.         call    net_socket_alloc
  625.         pop     esi
  626.         test    eax, eax
  627.         jz      .exit
  628.         ; Copy structure from current socket to new, including lock
  629.         push    esi edi
  630.         lea     esi, [ebx + SOCKET_head.PID]    ; yes, PID must also be copied
  631.         lea     edi, [eax + SOCKET_head.PID]
  632.         mov     ecx, ((SOCKET_head.end - SOCKET_head.PID) + IPv4_SOCKET.end + TCP_SOCKET.end + 3)/4
  633.         rep     movsd
  634.         pop     edi esi
  635.         ; Push pointer to new socket to queue
  636.         movzx   ecx, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
  637.         inc     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
  638.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end + ecx*4], eax
  639.  
  640.         ; We have a SYN. update the socket with this IP Packets details,
  641.         ; And send a response
  642.  
  643.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], esi ; IP source address
  644.         mov     cx, [edx + TCP_Packet.SourcePort]
  645.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], cx
  646.         mov     ecx, [edx + TCP_Packet.SequenceNumber]
  647.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], ecx
  648.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], ecx
  649.         lea     esi, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  650.         inc_INET esi ; RCV.NXT
  651.         mov     ecx, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS]
  652.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], ecx
  653.  
  654.         mov     [eax + SOCKET_head.lock], 0
  655.         mov     [ebx + SOCKET_head.lock], 0
  656.  
  657.         push    eax
  658.         ; Now construct the response
  659.         mov     bl, TH_SYN + TH_ACK
  660.         call    TCP_send_ack
  661.         pop     eax
  662.  
  663.         mov     [eax +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
  664.         call    notify_network_event
  665.  
  666.         ; increment SND.NXT in socket
  667.         lea     esi, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  668.         inc_INET esi
  669.         ret
  670.  
  671.   .exit:
  672.         mov     [ebx + SOCKET_head.lock], 0
  673.         ret
  674.  
  675.  
  676. align 4
  677. stateTCB_SYN_SENT:
  678.  
  679.         DEBUGF  1,"TCBStateHandler: Syn_Sent\n"
  680.  
  681.         ; We are awaiting an ACK to our SYN, with a SYM
  682.         ; Look at control flags - expecting an ACK
  683.  
  684.         mov     al, [edx + TCP_Packet.Flags]
  685.         and     al, TH_SYN + TH_ACK
  686.         cmp     al, TH_SYN + TH_ACK
  687.         je      .syn_ack
  688.  
  689.         test    al, TH_SYN
  690.         jz      .exit
  691.  
  692.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
  693.         pushd   TH_SYN + TH_ACK
  694.         jmp     .send
  695.  
  696.   .syn_ack:
  697.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
  698.         pushd   TH_ACK
  699.  
  700.   .send:
  701.         ; Store the recv.nxt field
  702.         mov     eax, [edx + TCP_Packet.SequenceNumber]
  703.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], eax
  704.         bswap   eax
  705.         inc     eax
  706.         bswap   eax
  707.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax          ; Update our recv.nxt field
  708.         mov     [ebx + SOCKET_head.lock], 0
  709.  
  710.         lea     esi, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  711.         inc_INET esi
  712.  
  713.         ; Send an ACK
  714.         mov     eax, ebx
  715.         pop     ebx
  716.         call    TCP_send_ack
  717.  
  718.   .exit:
  719.         mov     [ebx + SOCKET_head.lock], 0
  720.         ret
  721.  
  722.  
  723.  
  724. align 4
  725. stateTCB_SYN_RECEIVED:
  726.  
  727.         DEBUGF  1,"TCBStateHandler: Syn_received\n"
  728.  
  729.         ; In this case, we are expecting an ACK Packet
  730.         ; For now, if the Packet is an ACK, process it,
  731.         ; If not, ignore it
  732.  
  733.         test    [edx + TCP_Packet.Flags], TH_RST
  734.         jz      .check_ack
  735.  
  736.   ;      push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemotePort]
  737.  ;       pop     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
  738.   ;      push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemoteIP]
  739.  ;       pop     [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  740.  
  741.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LISTEN
  742.         jmp     .exit
  743.  
  744.   .check_ack:
  745.         ; Look at control flags - expecting an ACK
  746.         test    [edx + TCP_Packet.Flags], TH_ACK
  747.         jz      .exit
  748.  
  749.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
  750.         mov     eax, ebx
  751.         call    notify_network_event
  752.  
  753.   .exit:
  754.         mov     [ebx + SOCKET_head.lock], 0
  755.         ret
  756.  
  757.  
  758.  
  759. align 4
  760. stateTCB_ESTABLISHED:
  761.  
  762.  
  763.         DEBUGF  1,"TCBStateHandler: Established\n"
  764.  
  765.         mov     eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  766.         cmp     eax, [edx + TCP_Packet.SequenceNumber]
  767.         jne     .exit
  768.  
  769.         ; Here we are expecting data, or a request to close
  770.         ; OR both...
  771.  
  772.         ; Did we receive a FIN or RST?
  773.         test    [edx + TCP_Packet.Flags], TH_FIN
  774.         jz      .check_ack
  775.  
  776.         ; It was a fin or reset.
  777.  
  778. ;;; TODO: write following code:
  779.         ; Remove resend entries from the queue  - I dont want to send any more data
  780.         ; Send an ACK to that fin, and enter closewait state
  781.  
  782.   .check_ack:
  783.         ; Check that we received an ACK
  784.         test    [edx + TCP_Packet.Flags], TH_ACK
  785.         jz      .exit
  786.  
  787.         DEBUGF  1,"Received ACK\n"
  788.  
  789.         ; First, look at the incoming window. If this is less than or equal to 1024,
  790.         ; Set the socket window timer to 1. This will stop an additional Packets being queued.
  791.         ; ** I may need to tweak this value, since I do not know how many Packets are already queued
  792.         push    ecx
  793.         mov     cx, [edx + TCP_Packet.Window]
  794.         xchg    cl, ch
  795.         cmp     cx, 1024
  796.         ja      @f
  797.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1
  798.       @@:
  799.         pop     ecx
  800.  
  801.         test    ecx, ecx
  802.         jnz     .data                      ; Read data, if any
  803.  
  804.         lea     esi, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  805.         inc_INET esi
  806.  
  807.         ; If we had received a fin, we need to ACK it.
  808.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSE_WAIT
  809.         je      .ack
  810.         jmp     .exit
  811.  
  812.   .data:
  813.              ;;;
  814.         lea     esi, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  815.         add_INET esi
  816.  
  817.         DEBUGF  1,"Got data!\n"
  818.         mov     esi, [esp + 4]
  819.         sub     edx, esi
  820.         mov     edi, edx
  821.         mov     eax, ebx
  822.         call    socket_internal_receiver
  823.  
  824.   .ack:
  825.         mov     [ebx + SOCKET_head.lock], 0
  826.         ; Send an ACK
  827.         mov     eax, ebx
  828.         mov     bl, TH_ACK
  829.         call    TCP_send_ack
  830.   .exit:
  831.  
  832.         mov     [ebx + SOCKET_head.lock], 0
  833.         ret
  834.  
  835.  
  836.  
  837. align 4
  838. stateTCB_FIN_WAIT_1:
  839.  
  840.         DEBUGF  1,"TCBStateHandler: Fin_wait_1\n"
  841.  
  842.         ; We can either receive an ACK of a fin, or a fin
  843.         mov     al, [edx + TCP_Packet.Flags]
  844.         and     al, TH_FIN + TH_ACK
  845.  
  846.         cmp     al, TH_ACK
  847.         jne     @f
  848.  
  849.         ; It was an ACK
  850.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_FIN_WAIT_2
  851.         jmp     .exit
  852.  
  853.     @@: mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSING
  854.         cmp     al, TH_FIN
  855.         je      @f
  856.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  857.  
  858.     @@: lea     esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  859.         inc_INET esi
  860.  
  861.         mov     [ebx + SOCKET_head.lock], 0
  862.         ; Send an ACK
  863.         mov     eax, ebx
  864.         mov     bl, TH_ACK
  865.         call    TCP_send_ack
  866.  
  867.   .exit:
  868.         mov     [ebx + SOCKET_head.lock], 0
  869.         ret
  870.  
  871.  
  872.  
  873. align 4
  874. stateTCB_FIN_WAIT_2:
  875.  
  876.         DEBUGF  1,"TCBStateHandler: Fin_wait_2\n"
  877.  
  878.         test    [edx + TCP_Packet.Flags], TH_FIN
  879.         jz      .exit
  880.  
  881.         ; Change state, as we have a fin
  882.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  883.  
  884.         lea     esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  885.         inc_INET esi
  886.  
  887.         mov     [ebx + SOCKET_head.lock], 0
  888.  
  889.         ; Send an ACK
  890.         mov     eax, ebx
  891.         mov     bl, TH_ACK
  892.         call    TCP_send_ack
  893.  
  894.   .exit:
  895.         mov     [ebx + SOCKET_head.lock], 0
  896.         ret
  897.  
  898.  
  899.  
  900. align 4
  901. stateTCB_CLOSE_WAIT:
  902.  
  903.         DEBUGF  1,"TCBStateHandler: close_wait\n"
  904.         ; Intentionally left empty
  905.         ; socket_close_tcp handles this
  906.  
  907.         mov     [ebx + SOCKET_head.lock], 0
  908.         ret
  909.  
  910.  
  911.  
  912. align 4
  913. stateTCB_CLOSING:
  914.  
  915.         DEBUGF  1,"TCBStateHandler: closingn\n"
  916.  
  917.         ; We can either receive an ACK of a fin, or a fin
  918.         test    [edx + TCP_Packet.Flags], TH_ACK
  919.         jz      .exit
  920.  
  921.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  922.  
  923.   .exit:
  924.  
  925.         mov     [ebx + SOCKET_head.lock], 0
  926.         ret
  927.  
  928.  
  929. align 4
  930. stateTCB_LAST_ACK:
  931.  
  932.         DEBUGF  1,"TCBStateHandler: last_ackn\n"
  933.  
  934.         ; Look at control flags - expecting an ACK
  935.         test    [edx + TCP_Packet.Flags], TH_ACK
  936.         jz      .exit
  937.  
  938.         mov     [ebx + SOCKET_head.lock], 0
  939.  
  940.         ; delete the socket
  941.         stdcall net_socket_free, ebx
  942.  
  943.   .exit:
  944.         ret
  945.  
  946.  
  947. align 4
  948. stateTCB_TIME_WAIT:
  949.  
  950.         DEBUGF  1,"TCBStateHandler: time_wait\n"
  951.  
  952.         mov     [ebx + SOCKET_head.lock], 0
  953.  
  954.         ret
  955.  
  956.  
  957. align 4
  958. stateTCB_CLOSED:
  959.  
  960.         DEBUGF  1,"TCBStateHandler: closed\n"
  961.  
  962.         mov     [ebx + SOCKET_head.lock], 0
  963.  
  964.         ret
  965.  
  966.  
  967.  
  968. ;---------------------------------------------------------------------------
  969. ;
  970. ; TCP_API
  971. ;
  972. ; This function is called by system function 75
  973. ;
  974. ; IN:  subfunction number in bl
  975. ;      device number in bh
  976. ;      ecx, edx, .. depends on subfunction
  977. ;
  978. ; OUT:
  979. ;
  980. ;---------------------------------------------------------------------------
  981. align 4
  982. TCP_API:
  983.  
  984.         movzx   eax, bh
  985.         shl     eax, 2
  986.  
  987.         test    bl, bl
  988.         jz      .packets_tx     ; 0
  989.         dec     bl
  990.         jz      .packets_rx     ; 1
  991.  
  992. .error:
  993.         mov     eax, -1
  994.         ret
  995.  
  996. .packets_tx:
  997.         add     eax, TCP_PACKETS_TX
  998.         mov     eax, [eax]
  999.         ret
  1000.  
  1001. .packets_rx:
  1002.         add     eax, TCP_PACKETS_RX
  1003.         mov     eax, [eax]
  1004.         ret
  1005.