Subversion Repositories Kolibri OS

Rev

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