Subversion Repositories Kolibri OS

Rev

Rev 1255 | 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: 1256 $
  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.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.last_ack_number], eax
  364.         ;---------
  365.  
  366.         cmp     [TCP_OUT_QUEUE], 0
  367.         je      .call_handler
  368.         push    ecx
  369.  
  370.        DEBUGF 1,"Removing all queued packets with smaller ACK\n"
  371.  
  372.         mov     ecx, TCP_QUEUE_SIZE
  373.         mov     esi, TCP_OUT_QUEUE+4
  374.  
  375.   .loop:
  376.         cmp     [esi + tcp_out_queue_entry.data_ptr], 0
  377.         je      .maybe_next
  378.         cmp     [esi + tcp_out_queue_entry.seq_num], eax
  379.         jg      .maybe_next
  380.         ; TODO: check if the packets belong to the same tcp connection !
  381.  
  382.        DEBUGF 1,"Removing a queued packet\n"
  383.  
  384.         push    [esi + tcp_out_queue_entry.data_ptr]
  385.         mov     [esi + tcp_out_queue_entry.data_ptr], 0
  386.         dec     [TCP_OUT_QUEUE]
  387.         call    kernel_free
  388.  
  389.   .maybe_next:
  390.         add     esi, tcp_out_queue_entry.size
  391.         loop    .loop
  392.  
  393.         pop     ecx
  394.   .call_handler:
  395.         ; Call handler for given TCB state
  396.         mov     eax, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state]
  397.         DEBUGF 1,"Socket state: %u\n", eax
  398.  
  399.         cmp     eax, TCB_LISTEN
  400.         jb      .dump
  401.         cmp     eax, TCB_CLOSED
  402.         ja      .dump
  403.  
  404.         dec     eax
  405.         shl     eax, 2
  406.         add     eax, stateHandler
  407.  
  408.         call    dword[eax]
  409.  
  410.   .dump:
  411.         DEBUGF 1,"Dumping TCP packet\n"
  412.         call    kernel_free
  413.         add     esp, 4 ; pop (balance stack)
  414.  
  415.         ret
  416.  
  417.  
  418.  
  419. ;-----------------------------------------------------------------
  420. ;
  421. ; TCP_socket_send
  422. ;
  423. ; IN: eax = socket pointer
  424. ;     ecx = number of bytes to send
  425. ;     esi = pointer to data
  426. ;
  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.  
  527. align 4
  528. TCP_send_ack:
  529.  
  530.         DEBUGF 1,"Creating TCP ACK, socket: %x, flags: %x\n",eax, bl
  531.  
  532.         mov     di , IP_PROTO_TCP
  533.         mov     ecx, TCP_Packet.Options
  534.  
  535.         push    bx eax
  536.  
  537. ; Create an IPv4 Packet of the correct size
  538.  
  539.         mov     ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
  540.         mov     eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  541.  
  542.         call    IPv4_create_packet
  543.         cmp     edi, -1
  544.         je      .fail
  545.  
  546. ; Fill in the TCP header
  547.         pop     esi
  548.  
  549.         push    [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  550.         pop     [edi + TCP_Packet.SequenceNumber]
  551.  
  552.         push    dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort] ; both ports at once
  553.         pop     dword [edi + TCP_Packet.SourcePort]
  554.  
  555.         push    [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  556.         pop     [edi + TCP_Packet.AckNumber]
  557.  
  558.         pop     cx
  559.         mov     [edi + TCP_Packet.Flags], cl
  560.         mov     [edi + TCP_Packet.Window], 0x0005          ; 1280 bytes
  561.         mov     [edi + TCP_Packet.UrgentPointer], 0
  562.         mov     [edi + TCP_Packet.DataOffset], 0x50
  563.         mov     [edi + TCP_Packet.Checksum], 0
  564.  
  565.         push    edx eax
  566.  
  567. ;        lea     esi, [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  568. ;        inc_INET esi
  569.  
  570. ; Now, calculate the checksum
  571.         pushw   TCP_Packet.Options shl 8
  572.         pushw   IP_PROTO_TCP shl 8
  573.         pushd   [edi-4] ; destination address
  574.         pushd   [edi-8] ; source address
  575.  
  576.         xor     edx, edx
  577.         mov     ecx, TCP_Packet.Options
  578.         mov     esi, edi
  579.         call    checksum_1
  580.         mov     ecx, 12
  581.         mov     esi, esp
  582.         call    checksum_1
  583.         add     esp, 12                                    ; remove the pseudoheader from stack
  584. ; and store it in TCP header
  585.         call    checksum_2
  586.         mov     [edi + TCP_Packet.Checksum], dx
  587.  
  588. ; And now, send the packet!
  589.         DEBUGF 1,"Sending TCP Packet to device %x\n", ebx
  590.         mov     esi, [ebx + ETH_DEVICE.transmit]
  591.         mov     edx, [edi + TCP_Packet.SequenceNumber]
  592.         jmp     TCP_add_to_queue
  593.  
  594.   .fail:
  595.         add     esp, 2+4
  596.         ret
  597.  
  598.  
  599.  
  600.  
  601.  
  602. ;---------- TCB state handlers start here
  603.  
  604.  
  605.  
  606.  
  607. align 4
  608. stateTCB_LISTEN:
  609.  
  610.         DEBUGF  1,"TCBStateHandler: Listen\n"
  611.  
  612.         ; In this case, we are expecting a SYN Packet
  613.         ; For now, if the Packet is a SYN, process it, and send a response
  614.         ; If not, ignore it
  615.  
  616.         ; Look at control flags
  617.         test    [edx + TCP_Packet.Flags], TH_SYN
  618.         jz      .exit
  619.         ; Exit if backlog queue is full
  620.         mov     ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
  621.         cmp     ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog]
  622.         jae     .exit
  623.         ; Allocate new socket
  624.         push    esi
  625.         call    net_socket_alloc
  626.         pop     esi
  627.         test    eax, eax
  628.         jz      .exit
  629.         ; Copy structure from current socket to new, including lock
  630.         push    esi edi
  631.         lea     esi, [ebx + SOCKET_head.PID]    ; yes, PID must also be copied
  632.         lea     edi, [eax + SOCKET_head.PID]
  633.         mov     ecx, ((SOCKET_head.end - SOCKET_head.PID) + IPv4_SOCKET.end + TCP_SOCKET.end + 3)/4
  634.         rep     movsd
  635.         pop     edi esi
  636.         ; Push pointer to new socket to queue
  637.         movzx   ecx, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
  638.         inc     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
  639.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end + ecx*4], eax
  640.  
  641.         ; We have a SYN. update the socket with this IP Packets details,
  642.         ; And send a response
  643.  
  644.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], esi ; IP source address
  645.         mov     cx, [edx + TCP_Packet.SourcePort]
  646.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], cx
  647.         mov     ecx, [edx + TCP_Packet.SequenceNumber]
  648.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], ecx
  649.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], ecx
  650.         lea     esi, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  651.         inc_INET esi ; RCV.NXT
  652.         mov     ecx, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS]
  653.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], ecx
  654.  
  655.         mov     [eax + SOCKET_head.lock], 0
  656.         mov     [ebx + SOCKET_head.lock], 0
  657.  
  658.         push    eax
  659.         ; Now construct the response
  660.         mov     bl, TH_SYN + TH_ACK
  661.         call    TCP_send_ack
  662.         pop     eax
  663.  
  664.         mov     [eax +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
  665.         call    notify_network_event
  666.  
  667.         ; increment SND.NXT in socket
  668.         lea     esi, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  669.         inc_INET esi
  670.         ret
  671.  
  672.   .exit:
  673.         mov     [ebx + SOCKET_head.lock], 0
  674.         ret
  675.  
  676.  
  677. align 4
  678. stateTCB_SYN_SENT:
  679.  
  680.         DEBUGF  1,"TCBStateHandler: Syn_Sent\n"
  681.  
  682.         ; We are awaiting an ACK to our SYN, with a SYM
  683.         ; Look at control flags - expecting an ACK
  684.  
  685.         mov     al, [edx + TCP_Packet.Flags]
  686.         and     al, TH_SYN + TH_ACK
  687.         cmp     al, TH_SYN + TH_ACK
  688.         je      .syn_ack
  689.  
  690.         test    al, TH_SYN
  691.         jz      .exit
  692.  
  693.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
  694.         pushd   TH_SYN + TH_ACK
  695.         jmp     .send
  696.  
  697.   .syn_ack:
  698.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
  699.         pushd   TH_ACK
  700.  
  701.   .send:
  702.         ; Store the recv.nxt field
  703.         mov     eax, [edx + TCP_Packet.SequenceNumber]
  704.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], eax
  705.         bswap   eax
  706.         inc     eax
  707.         bswap   eax
  708.         mov     [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax          ; Update our recv.nxt field
  709.         mov     [ebx + SOCKET_head.lock], 0
  710.  
  711.         lea     esi, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  712.         inc_INET esi
  713.  
  714.         ; Send an ACK
  715.         mov     eax, ebx
  716.         pop     ebx
  717.         call    TCP_send_ack
  718.  
  719.   .exit:
  720.         mov     [ebx + SOCKET_head.lock], 0
  721.         ret
  722.  
  723.  
  724.  
  725. align 4
  726. stateTCB_SYN_RECEIVED:
  727.  
  728.         DEBUGF  1,"TCBStateHandler: Syn_received\n"
  729.  
  730.         ; In this case, we are expecting an ACK Packet
  731.         ; For now, if the Packet is an ACK, process it,
  732.         ; If not, ignore it
  733.  
  734.         test    [edx + TCP_Packet.Flags], TH_RST
  735.         jz      .check_ack
  736.  
  737.   ;      push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemotePort]
  738.  ;       pop     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
  739.   ;      push    [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemoteIP]
  740.  ;       pop     [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
  741.  
  742.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LISTEN
  743.         jmp     .exit
  744.  
  745.   .check_ack:
  746.         ; Look at control flags - expecting an ACK
  747.         test    [edx + TCP_Packet.Flags], TH_ACK
  748.         jz      .exit
  749.  
  750.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
  751.         mov     eax, ebx
  752.         call    notify_network_event
  753.  
  754.   .exit:
  755.         mov     [ebx + SOCKET_head.lock], 0
  756.         ret
  757.  
  758.  
  759.  
  760. align 4
  761. stateTCB_ESTABLISHED:
  762.  
  763.  
  764.         DEBUGF  1,"TCBStateHandler: Established\n"
  765.  
  766.         mov     eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  767.         cmp     eax, [edx + TCP_Packet.SequenceNumber]
  768.         jne     .exit
  769.  
  770.         ; Here we are expecting data, or a request to close
  771.         ; OR both...
  772.  
  773.         ; Did we receive a FIN or RST?
  774.         test    [edx + TCP_Packet.Flags], TH_FIN
  775.         jz      .check_ack
  776.  
  777.         ; It was a fin or reset.
  778.  
  779. ;;; TODO: write following code:
  780.         ; Remove resend entries from the queue  - I dont want to send any more data
  781.         ; Send an ACK to that fin, and enter closewait state
  782.  
  783.   .check_ack:
  784.         ; Check that we received an ACK
  785.         test    [edx + TCP_Packet.Flags], TH_ACK
  786.         jz      .exit
  787.  
  788.         DEBUGF  1,"Received ACK\n"
  789.  
  790.         ; First, look at the incoming window. If this is less than or equal to 1024,
  791.         ; Set the socket window timer to 1. This will stop an additional Packets being queued.
  792.         ; ** I may need to tweak this value, since I do not know how many Packets are already queued
  793.         push    ecx
  794.         mov     cx, [edx + TCP_Packet.Window]
  795.         xchg    cl, ch
  796.         cmp     cx, 1024
  797.         ja      @f
  798.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1
  799.       @@:
  800.         pop     ecx
  801.  
  802.         test    ecx, ecx
  803.         jnz     .data                      ; Read data, if any
  804.  
  805.         lea     esi, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  806.         inc_INET esi
  807.  
  808.         ; If we had received a fin, we need to ACK it.
  809.         cmp     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSE_WAIT
  810.         je      .ack
  811.         jmp     .exit
  812.  
  813.   .data:
  814.              ;;;
  815.         lea     esi, [ebx +  SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
  816.         add_INET esi
  817.  
  818.         DEBUGF  1,"Got data!\n"
  819.         mov     esi, [esp + 4]
  820.         sub     edx, esi
  821.         mov     edi, edx
  822.         mov     eax, ebx
  823.         call    socket_internal_receiver
  824.  
  825.   .ack:
  826.         mov     [ebx + SOCKET_head.lock], 0
  827.         ; Send an ACK
  828.         mov     eax, ebx
  829.         mov     bl, TH_ACK
  830.         call    TCP_send_ack
  831.   .exit:
  832.  
  833.         mov     [ebx + SOCKET_head.lock], 0
  834.         ret
  835.  
  836.  
  837.  
  838. align 4
  839. stateTCB_FIN_WAIT_1:
  840.  
  841.         DEBUGF  1,"TCBStateHandler: Fin_wait_1\n"
  842.  
  843.         ; We can either receive an ACK of a fin, or a fin
  844.         mov     al, [edx + TCP_Packet.Flags]
  845.         and     al, TH_FIN + TH_ACK
  846.  
  847.         cmp     al, TH_ACK
  848.         jne     @f
  849.  
  850.         ; It was an ACK
  851.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_FIN_WAIT_2
  852.         jmp     .exit
  853.  
  854.     @@: mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSING
  855.         cmp     al, TH_FIN
  856.         je      @f
  857.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  858.  
  859.     @@: lea     esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  860.         inc_INET esi
  861.  
  862.         mov     [ebx + SOCKET_head.lock], 0
  863.         ; Send an ACK
  864.         mov     eax, ebx
  865.         mov     bl, TH_ACK
  866.         call    TCP_send_ack
  867.  
  868.   .exit:
  869.         mov     [ebx + SOCKET_head.lock], 0
  870.         ret
  871.  
  872.  
  873.  
  874. align 4
  875. stateTCB_FIN_WAIT_2:
  876.  
  877.         DEBUGF  1,"TCBStateHandler: Fin_wait_2\n"
  878.  
  879.         test    [edx + TCP_Packet.Flags], TH_FIN
  880.         jz      .exit
  881.  
  882.         ; Change state, as we have a fin
  883.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  884.  
  885.         lea     esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
  886.         inc_INET esi
  887.  
  888.         mov     [ebx + SOCKET_head.lock], 0
  889.  
  890.         ; Send an ACK
  891.         mov     eax, ebx
  892.         mov     bl, TH_ACK
  893.         call    TCP_send_ack
  894.  
  895.   .exit:
  896.         mov     [ebx + SOCKET_head.lock], 0
  897.         ret
  898.  
  899.  
  900.  
  901. align 4
  902. stateTCB_CLOSE_WAIT:
  903.  
  904.         DEBUGF  1,"TCBStateHandler: close_wait\n"
  905.         ; Intentionally left empty
  906.         ; socket_close_tcp handles this
  907.  
  908.         mov     [ebx + SOCKET_head.lock], 0
  909.         ret
  910.  
  911.  
  912.  
  913. align 4
  914. stateTCB_CLOSING:
  915.  
  916.         DEBUGF  1,"TCBStateHandler: closingn\n"
  917.  
  918.         ; We can either receive an ACK of a fin, or a fin
  919.         test    [edx + TCP_Packet.Flags], TH_ACK
  920.         jz      .exit
  921.  
  922.         mov     [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_TIMED_WAIT
  923.  
  924.   .exit:
  925.  
  926.         mov     [ebx + SOCKET_head.lock], 0
  927.         ret
  928.  
  929.  
  930. align 4
  931. stateTCB_LAST_ACK:
  932.  
  933.         DEBUGF  1,"TCBStateHandler: last_ackn\n"
  934.  
  935.         ; Look at control flags - expecting an ACK
  936.         test    [edx + TCP_Packet.Flags], TH_ACK
  937.         jz      .exit
  938.  
  939.         mov     [ebx + SOCKET_head.lock], 0
  940.  
  941.         ; delete the socket
  942.         stdcall net_socket_free, ebx
  943.  
  944.   .exit:
  945.         ret
  946.  
  947.  
  948. align 4
  949. stateTCB_TIME_WAIT:
  950.  
  951.         DEBUGF  1,"TCBStateHandler: time_wait\n"
  952.  
  953.         mov     [ebx + SOCKET_head.lock], 0
  954.  
  955.         ret
  956.  
  957.  
  958. align 4
  959. stateTCB_CLOSED:
  960.  
  961.         DEBUGF  1,"TCBStateHandler: closed\n"
  962.  
  963.         mov     [ebx + SOCKET_head.lock], 0
  964.  
  965.         ret
  966.  
  967.  
  968.  
  969. ;---------------------------------------------------------------------------
  970. ;
  971. ; TCP_API
  972. ;
  973. ; This function is called by system function 75
  974. ;
  975. ; IN:  subfunction number in bl
  976. ;      device number in bh
  977. ;      ecx, edx, .. depends on subfunction
  978. ;
  979. ; OUT:
  980. ;
  981. ;---------------------------------------------------------------------------
  982.  
  983. align 4
  984. TCP_API:
  985.  
  986.         movzx   eax, bh
  987.         shl     eax, 2
  988.  
  989.         test    bl, bl
  990.         jz      .packets_tx     ; 0
  991.         dec     bl
  992.         jz      .packets_rx     ; 1
  993.  
  994. .error:
  995.         mov     eax, -1
  996.         ret
  997.  
  998. .packets_tx:
  999.         add     eax, TCP_PACKETS_TX
  1000.         mov     eax, [eax]
  1001.         ret
  1002.  
  1003. .packets_rx:
  1004.         add     eax, TCP_PACKETS_RX
  1005.         mov     eax, [eax]
  1006.         ret
  1007.