Subversion Repositories Kolibri OS

Rev

Rev 1254 | 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: 1255 $
  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. ;---------- 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.  
  619.         ; We have a SYN. update the socket with this IP Packets details,
  620.         ; And send a response
  621.  
  622.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP], esi ; IP source address
  623.         mov     ax, [edx + TCP_Packet.SourcePort]
  624.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], ax
  625.         mov     eax, [edx + TCP_Packet.SequenceNumber]
  626.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], eax
  627.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax
  628.         lea     esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  629.         inc_INET esi ; RCV.NXT
  630.         mov     eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS]
  631.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], eax
  632.  
  633.         mov     [ebx + SOCKET_head.lock], 0
  634.  
  635.         ; Now construct the response
  636.         mov     bl, TH_SYN + TH_ACK
  637.         call    TCP_send_ack
  638.  
  639.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
  640.  
  641.         ; increment SND.NXT in socket
  642.         lea     esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  643.         inc_INET esi
  644.  
  645.   .exit:
  646.         mov     [ebx + SOCKET_head.lock], 0
  647.         ret
  648.  
  649.  
  650. align 4
  651. stateTCB_SYN_SENT:
  652.  
  653.         DEBUGF  1,"TCBStateHandler: Syn_Sent\n"
  654.  
  655.         ; We are awaiting an ACK to our SYN, with a SYM
  656.         ; Look at control flags - expecting an ACK
  657.  
  658.         mov     al, [edx + TCP_Packet.Flags]
  659.         and     al, TH_SYN + TH_ACK
  660.         cmp     al, TH_SYN + TH_ACK
  661.         je      .syn_ack
  662.  
  663.         test    al, TH_SYN
  664.         jz      .exit
  665.  
  666.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
  667.         pushd   TH_SYN + TH_ACK
  668.         jmp     .send
  669.  
  670.   .syn_ack:
  671.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
  672.         pushd   TH_ACK
  673.  
  674.   .send:
  675.         ; Store the recv.nxt field
  676.         mov     eax, [edx + TCP_Packet.SequenceNumber]
  677.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], eax
  678.         bswap   eax
  679.         inc     eax
  680.         bswap   eax
  681.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax          ; Update our recv.nxt field
  682.         mov     [ebx + SOCKET_head.lock], 0
  683.  
  684.         lea     esi, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  685.         inc_INET esi
  686.  
  687.         ; Send an ACK
  688.         mov     eax, ebx
  689.         pop     ebx
  690.         call    TCP_send_ack
  691.  
  692.   .exit:
  693.         mov     [ebx + SOCKET_head.lock], 0
  694.         ret
  695.  
  696.  
  697.  
  698. align 4
  699. stateTCB_SYN_RECEIVED:
  700.  
  701.         DEBUGF  1,"TCBStateHandler: Syn_received\n"
  702.  
  703.         ; In this case, we are expecting an ACK Packet
  704.         ; For now, if the Packet is an ACK, process it,
  705.         ; If not, ignore it
  706.  
  707.         test    [edx + TCP_Packet.Flags], TH_RST
  708.         jz      .check_ack
  709.  
  710.   ;      push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemotePort]
  711.  ;       pop     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
  712.   ;      push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemoteIP]
  713.  ;       pop     [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  714.  
  715.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LISTEN
  716.         jmp     .exit
  717.  
  718.   .check_ack:
  719.         ; Look at control flags - expecting an ACK
  720.         test    [edx + TCP_Packet.Flags], TH_ACK
  721.         jz      .exit
  722.  
  723.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
  724.  
  725.   .exit:
  726.         mov     [ebx + SOCKET_head.lock], 0
  727.         ret
  728.  
  729.  
  730.  
  731. align 4
  732. stateTCB_ESTABLISHED:
  733.  
  734.  
  735.         DEBUGF  1,"TCBStateHandler: Established\n"
  736.  
  737.         mov     eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  738.         cmp     eax, [edx + TCP_Packet.SequenceNumber]
  739.         jne     .exit
  740.  
  741.         ; Here we are expecting data, or a request to close
  742.         ; OR both...
  743.  
  744.         ; Did we receive a FIN or RST?
  745.         test    [edx + TCP_Packet.Flags], TH_FIN
  746.         jz      .check_ack
  747.  
  748.         ; It was a fin or reset.
  749.  
  750. ;;; TODO: write following code:
  751.         ; Remove resend entries from the queue  - I dont want to send any more data
  752.         ; Send an ACK to that fin, and enter closewait state
  753.  
  754.   .check_ack:
  755.         ; Check that we received an ACK
  756.         test    [edx + TCP_Packet.Flags], TH_ACK
  757.         jz      .exit
  758.  
  759.         DEBUGF  1,"Received ACK\n"
  760.  
  761.         ; First, look at the incoming window. If this is less than or equal to 1024,
  762.         ; Set the socket window timer to 1. This will stop an additional Packets being queued.
  763.         ; ** I may need to tweak this value, since I do not know how many Packets are already queued
  764.         push    ecx
  765.         mov     cx, [edx + TCP_Packet.Window]
  766.         xchg    cl, ch
  767.         cmp     cx, 1024
  768.         ja      @f
  769.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1
  770.       @@:
  771.         pop     ecx
  772.  
  773.         test    ecx, ecx
  774.         jnz     .data                      ; Read data, if any
  775.  
  776.         lea     esi, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  777.         inc_INET esi
  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.              ;;;
  786.         lea     esi, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  787.         add_INET esi
  788.  
  789.         DEBUGF  1,"Got data!\n"
  790.         mov     esi, [esp + 4]
  791.         sub     edx, esi
  792.         mov     edi, edx
  793.         mov     eax, ebx
  794.         call    socket_internal_receiver
  795.  
  796.   .ack:
  797.         mov     [ebx + SOCKET_head.lock], 0
  798.         ; Send an ACK
  799.         mov     eax, ebx
  800.         mov     bl, TH_ACK
  801.         call    TCP_send_ack
  802.   .exit:
  803.  
  804.         mov     [ebx + SOCKET_head.lock], 0
  805.         ret
  806.  
  807.  
  808.  
  809. align 4
  810. stateTCB_FIN_WAIT_1:
  811.  
  812.         DEBUGF  1,"TCBStateHandler: Fin_wait_1\n"
  813.  
  814.         ; We can either receive an ACK of a fin, or a fin
  815.         mov     al, [edx + TCP_Packet.Flags]
  816.         and     al, TH_FIN + TH_ACK
  817.  
  818.         cmp     al, TH_ACK
  819.         jne     @f
  820.  
  821.         ; It was an ACK
  822.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_FIN_WAIT_2
  823.         jmp     .exit
  824.  
  825.     @@: mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSING
  826.         cmp     al, TH_FIN
  827.         je      @f
  828.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  829.  
  830.     @@: lea     esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  831.         inc_INET esi
  832.  
  833.         mov     [ebx + SOCKET_head.lock], 0
  834.         ; Send an ACK
  835.         mov     eax, ebx
  836.         mov     bl, TH_ACK
  837.         call    TCP_send_ack
  838.  
  839.   .exit:
  840.         mov     [ebx + SOCKET_head.lock], 0
  841.         ret
  842.  
  843.  
  844.  
  845. align 4
  846. stateTCB_FIN_WAIT_2:
  847.  
  848.         DEBUGF  1,"TCBStateHandler: Fin_wait_2\n"
  849.  
  850.         test    [edx + TCP_Packet.Flags], TH_FIN
  851.         jz      .exit
  852.  
  853.         ; Change state, as we have a fin
  854.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  855.  
  856.         lea     esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  857.         inc_INET esi
  858.  
  859.         mov     [ebx + SOCKET_head.lock], 0
  860.  
  861.         ; Send an ACK
  862.         mov     eax, ebx
  863.         mov     bl, TH_ACK
  864.         call    TCP_send_ack
  865.  
  866.   .exit:
  867.         mov     [ebx + SOCKET_head.lock], 0
  868.         ret
  869.  
  870.  
  871.  
  872. align 4
  873. stateTCB_CLOSE_WAIT:
  874.  
  875.         DEBUGF  1,"TCBStateHandler: close_wait\n"
  876.         ; Intentionally left empty
  877.         ; socket_close_tcp handles this
  878.  
  879.         mov     [ebx + SOCKET_head.lock], 0
  880.         ret
  881.  
  882.  
  883.  
  884. align 4
  885. stateTCB_CLOSING:
  886.  
  887.         DEBUGF  1,"TCBStateHandler: closingn\n"
  888.  
  889.         ; We can either receive an ACK of a fin, or a fin
  890.         test    [edx + TCP_Packet.Flags], TH_ACK
  891.         jz      .exit
  892.  
  893.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  894.  
  895.   .exit:
  896.  
  897.         mov     [ebx + SOCKET_head.lock], 0
  898.         ret
  899.  
  900.  
  901. align 4
  902. stateTCB_LAST_ACK:
  903.  
  904.         DEBUGF  1,"TCBStateHandler: last_ackn\n"
  905.  
  906.         ; Look at control flags - expecting an ACK
  907.         test    [edx + TCP_Packet.Flags], TH_ACK
  908.         jz      .exit
  909.  
  910.         mov     [ebx + SOCKET_head.lock], 0
  911.  
  912.         ; delete the socket
  913.         stdcall net_socket_free, ebx
  914.  
  915.   .exit:
  916.         ret
  917.  
  918.  
  919. align 4
  920. stateTCB_TIME_WAIT:
  921.  
  922.         DEBUGF  1,"TCBStateHandler: time_wait\n"
  923.  
  924.         mov     [ebx + SOCKET_head.lock], 0
  925.  
  926.         ret
  927.  
  928.  
  929. align 4
  930. stateTCB_CLOSED:
  931.  
  932.         DEBUGF  1,"TCBStateHandler: closed\n"
  933.  
  934.         mov     [ebx + SOCKET_head.lock], 0
  935.  
  936.         ret
  937.  
  938.  
  939.  
  940. ;---------------------------------------------------------------------------
  941. ;
  942. ; TCP_API
  943. ;
  944. ; This function is called by system function 75
  945. ;
  946. ; IN:  subfunction number in bl
  947. ;      device number in bh
  948. ;      ecx, edx, .. depends on subfunction
  949. ;
  950. ; OUT:
  951. ;
  952. ;---------------------------------------------------------------------------
  953.  
  954. align 4
  955. TCP_API:
  956.  
  957.         movzx   eax, bh
  958.         shl     eax, 2
  959.  
  960.         test    bl, bl
  961.         jz      .packets_tx     ; 0
  962.         dec     bl
  963.         jz      .packets_rx     ; 1
  964.  
  965. .error:
  966.         mov     eax, -1
  967.         ret
  968.  
  969. .packets_tx:
  970.         add     eax, TCP_PACKETS_TX
  971.         mov     eax, [eax]
  972.         ret
  973.  
  974. .packets_rx:
  975.         add     eax, TCP_PACKETS_RX
  976.         mov     eax, [eax]
  977.         ret
  978.