;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; TCP.INC ;; ;; ;; ;; TCP Processes for Menuet OS TCP/IP stack ;; ;; ;; ;; Version 0.6 4th July 2004 ;; ;; ;; ;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;; ;; ;; ;; See file COPYING for details ;; ;; v0.6 : Added reset handling in the established state ;; ;; Added a timer per socket to allow delays when rx window ;; ;; gets below 1KB ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; TCP TCB states TCB_LISTEN equ 1 TCB_SYN_SENT equ 2 TCB_SYN_RECEIVED equ 3 TCB_ESTABLISHED equ 4 TCB_FIN_WAIT_1 equ 5 TCB_FIN_WAIT_2 equ 6 TCB_CLOSE_WAIT equ 7 TCB_CLOSING equ 8 TCB_LAST_ACK equ 9 TCB_TIME_WAIT equ 10 TCB_CLOSED equ 11 TWOMSL equ 10 ; # of secs to wait before closing socket TCP_RETRIES equ 5 ; Number of times to resend a packet TCP_TIMEOUT equ 10 ; resend if not replied to in x hs ;******************************************************************* ; Interface ; ; tcp_tx_handler Handles the TCP transmit queue ; tcp_rx The protocol handler for received data ; buildTCPPacket fills in the packet headers and data ; tcpStateMachine Main state machine for received TCP packets ; tcp_tcb_handler 1s timer, to erase tcb's in TIME_WAIT state ; ;******************************************************************* ; TCP Payload ( Data field in IP datagram ) ; ; 0 1 2 3 ; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ;20 | Source Port | Destination Port | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ;24 | Sequence Number | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ;28 | Acknowledgment Number | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ;32 | Data | |U|A|P|R|S|F| | ; | Offset| Reserved |R|C|S|S|Y|I| Window | ; | | |G|K|H|T|N|N| | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ;36 | Checksum | Urgent Pointer | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ;40 | Options | Padding | ; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ; | data struc TCP_PACKET { .SourcePort dw ? ;+00 .DestinationPort dw ? ;+02 .SequenceNumber dd ? ;+04 .AckNumber dd ? ;+08 .DataOffset db ? ;+12 - DataOffset[0-3 bits] and Reserved[4-7] .Flags db ? ;+13 - Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN .Window dw ? ;+14 .Checksum dw ? ;+16 .UrgentPointer dw ? ;+18 .Options rb 3 ;+20 .Padding db ? ;+23 .Data db ? ;+24 } virtual at 0 TCP_PACKET TCP_PACKET end virtual ;*************************************************************************** ; Function ; tcp_tcb_handler ; ; Description ; Handles sockets in the timewait state, closing them ; when the TCB timer expires ; ;*************************************************************************** tcp_tcb_handler: ; scan through all the sockets, decrementing active timers mov eax, SOCKETBUFFSIZE * NUM_SOCKETS mov ecx, NUM_SOCKETS tth1: sub eax, SOCKETBUFFSIZE cmp [eax + sockets + 32], dword 0 jne tth2 tth1a: cmp [eax + sockets + 72], dword 0 jne tth4 loop tth1 ret tth2: ; decrement it, delete socket if TCB timer = 0 & socket in timewait state pusha dec dword [eax + sockets + 32] cmp [eax + sockets + 32], dword 0 jne tth3 cmp [eax + sockets + 28], dword TCB_TIME_WAIT jne tth3 ; OK, delete socket mov edi, eax add edi, sockets xor eax, eax mov ecx, SOCKETHEADERSIZE cld rep stosb tth3: popa jmp tth1a loop tth1 ret ; TODO - prove it works! tth4: dec dword [eax + sockets + 72] loop tth1 ret tth_exit: ret ;*************************************************************************** ; Function ; tcp_tx_handler ; ; Description ; Handles queued TCP data ; This is a kernel function, called by stack_handler ; ;*************************************************************************** tcp_tx_handler: ; decrement all resend buffers timers. If they ; expire, queue them for sending, and restart the timer. ; If the retries counter reach 0, delete the entry mov esi, resendQ mov ecx, 0 tth001: cmp ecx, NUMRESENDENTRIES je tth003 ; None left cmp [esi], byte 0xFF jne tth002 ; found one inc ecx add esi, 4 jmp tth001 tth002: ; we have one. decrement it's timer by 1 dec word [esi+2] mov ax, [esi+2] cmp ax, 0 je tth002a inc ecx add esi, 4 jmp tth001 ; Timer not zero, so move on tth002a: mov bl, 0xff ; restart timer, and decrement retries ; After the first resend, back of on next, by a factor of 5 mov [esi+2], word TCP_TIMEOUT * 5 dec byte [esi+1] mov al, [esi+1] cmp al, 0 jne tth004 ; retries now 0, so delete from queue xchg [esi], bl tth004: ; resend packet pusha mov eax, EMPTY_QUEUE call dequeue cmp ax, NO_BUFFER jne tth004z ; TODO - try again in 10ms. cmp bl, 0xff jne tth004za mov [esi], bl tth004za: ; Mark it to expire in 10ms - 1 tick mov [esi+1], byte 1 mov [esi+2], word 1 jmp tth005 tth004z: ; we have a buffer # in ax push eax push ecx mov ecx, IPBUFFSIZE mul ecx add eax, IPbuffs ; we have the buffer address in eax mov edi, eax pop ecx ; get resend data address inc ecx ; Now get buffer location, and copy buffer across. argh! more copying,, mov esi, resendBuffer - IPBUFFSIZE tth004a: add esi, IPBUFFSIZE loop tth004a ; we have resend buffer location in esi mov ecx, IPBUFFSIZE ; copy data across cld rep movsb ; queue packet mov eax, NET1OUT_QUEUE mov edx, [stack_ip] mov ecx, [ edi + 16 ] cmp edx, ecx jne tth004b mov eax, IPIN_QUEUE tth004b: pop ebx call queue tth005: popa inc ecx add esi, 4 jmp tth001 tth003: ret ;*************************************************************************** ; Function ; tcp_rx ; ; Description ; TCP protocol handler ; This is a kernel function, called by ip_rx ; IP buffer address given in edx ; IP buffer number in eax ; Free up (or re-use) IP buffer when finished ; ;*************************************************************************** tcp_rx: ; The process is as follows. ; Look for a socket with matching remote IP, remote port, local port ; if not found, then ; look for remote IP + local port match ( where sockets remote port = 0) ; if not found, then ; look for a socket where local socket port == IP packets remote port ; where sockets remote port, remote IP = 0 ; discard if not found ; Call sockets tcbStateMachine, with pointer to packet. ; the state machine will not delete the packet, so do that here. push eax ; Look for a socket where ; IP Packet TCP Destination Port = local Port ; IP Packet SA = Remote IP ; IP Packet TCP Source Port = remote Port mov eax, SOCKETBUFFSIZE * NUM_SOCKETS mov ecx, NUM_SOCKETS ss1: sub eax, SOCKETBUFFSIZE movzx ebx, word [edx + 22] ; get the dest. port from the TCP hdr cmp [eax + sockets + 12], bx ; compare with socket's local port jnz nxttst1 ; different - try next socket movzx ebx, word [edx + 20] ; get the source port from the TCP hdr cmp [eax + sockets + 20], bx ; compare with socket's remote port jnz nxttst1 ; different - try next socket mov ebx, [edx + 12] ; get the source IP Addr from the IP hdr cmp [eax + sockets + 16], ebx ; compare with socket's remote IP jnz nxttst1 ; different - try next socket ; We have a complete match - use this socket jmp tcprx_001 nxttst1: loop ss1 ; Return back if no match ; If we got here, there was no match ; Look for a socket where ; IP Packet TCP Destination Port = local Port ; IP Packet SA = Remote IP ; socket remote Port = 0 mov eax, SOCKETBUFFSIZE * NUM_SOCKETS mov ecx, NUM_SOCKETS ss2: sub eax, SOCKETBUFFSIZE movzx ebx, word [edx + 22] ; get the dest. port from the TCP hdr cmp [eax + sockets + 12], bx ; compare with socket's local port jnz nxttst2 ; different - try next socket mov ebx, [edx + 12] ; get the source IP Addr from the IP hdr cmp [eax + sockets + 16], ebx ; compare with socket's remote IP jnz nxttst2 ; different - try next socket mov ebx, 0 cmp [eax + sockets + 20], bx ; only match a remote socket of 0 jnz nxttst2 ; different - try next socket ; We have a complete match - use this socket jmp tcprx_001 nxttst2: loop ss2 ; Return back if no match ; If we got here, there was no match ; Look for a socket where ; IP Packet TCP Destination Port = local Port ; socket Remote IP = 0 ; socket remote Port = 0 mov eax, SOCKETBUFFSIZE * NUM_SOCKETS mov ecx, NUM_SOCKETS ss3: sub eax, SOCKETBUFFSIZE movzx ebx, word [edx + 22] ; get destination port from the TCP hdr cmp [eax + sockets + 12], bx ; compare with socket's local port jnz nxttst3 ; different - try next socket mov ebx, 0 cmp [eax + sockets + 20], bx ; only match a remote socket of 0 jnz nxttst3 ; different - try next socket mov ebx, 0 cmp [eax + sockets + 16], ebx ; only match a socket remote IP of 0 jnz nxttst3 ; different - try next socket ; We have a complete match - use this socket jmp tcprx_001 nxttst3: loop ss3 ; Return back if no match ; If we got here, we need to reject the packet inc dword [dumped_rx_count] jmp tcprx_exit tcprx_001: ; We have a valid socket/TCB, so call the TCB State Machine for that skt. ; socket is pointed to by [eax + sockets] ; IP packet is pointed to by [edx] ; IP buffer number is on stack ( it will be popped at the end) call tcpStateMachine tcprx_exit: pop eax call freeBuff ret ;*************************************************************************** ; Function ; buildTCPPacket ; ; Description ; builds an IP Packet with TCP data fully populated for transmission ; You may destroy any and all registers ; TCP control flags specified in bl ; This TCB is in [sktAddr] ; User data pointed to by esi ; Data length in ecx ; Transmit buffer number in eax ; ;*************************************************************************** buildTCPPacket: push ecx ; Save data length ; convert buffer pointer eax to the absolute address mov ecx, IPBUFFSIZE mul ecx add eax, IPbuffs mov edx, eax mov [edx + 33], bl ; TCP flags mov ebx, [sktAddr] ; So, ebx holds the socket ptr, edx holds the IPbuffer ptr ; Fill in the IP header ( some data is in the socket descriptor) mov eax, [ebx + 8] mov [edx + 12], eax ; source IP mov eax, [ebx + 16] mov [edx + 16], eax ; Destination IP mov al, 0x45 mov [edx], al ; Version, IHL xor al, al mov [edx + 1], al ; Type of service pop eax ; Get the TCP data length push eax add eax, 20 + 20 ; add IP header and TCP header lengths mov [edx + 2], ah mov [edx + 3], al xor al, al mov [edx + 4], al mov [edx + 5], al mov al, 0x40 mov [edx + 6], al xor al, al mov [edx + 7], al mov al, 0x20 mov [edx + 8], al mov al, 6 ; TCP protocol mov [edx + 9], al ; Checksum left unfilled xor ax, ax mov [edx + 10], ax ; Fill in the TCP header ( some data is in the socket descriptor) mov ax, [ebx + 12] mov [edx + 20], ax ; Local Port mov ax, [ebx + 20] mov [edx + 20 + 2], ax ; desitination Port ; Checksum left unfilled xor ax, ax mov [edx + 20 + 16], ax ; sequence number mov eax, [ebx + 48] mov [edx + 20 + 4], eax ; ack number mov eax, [ebx + 56] mov [edx + 20 + 8], eax ; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size) ; 768 bytes seems better mov ax, 0x0003 mov [edx + 20 + 14], ax ; Urgent pointer (0) mov ax, 0 mov [edx + 20 + 18], ax ; data offset ( 0x50 ) mov al, 0x50 mov [edx + 20 + 12], al pop ecx ; count of bytes to send mov ebx, ecx ; need the length later cmp ebx, 0 jz btp_001 mov edi, edx add edi, 40 cld rep movsb ; copy the data across btp_001: ; we have edx as IPbuffer ptr. ; Fill in the TCP checksum ; First, fill in pseudoheader mov eax, [edx + 12] mov [pseudoHeader], eax mov eax, [edx + 16] mov [pseudoHeader+4], eax mov ax, 0x0600 ; 0 + protocol mov [pseudoHeader+8], ax add ebx, 20 mov eax, ebx mov [pseudoHeader+10], ah mov [pseudoHeader+11], al mov eax, pseudoHeader mov [checkAdd1], eax mov [checkSize1], word 12 mov eax, edx add eax, 20 mov [checkAdd2], eax mov eax, ebx mov [checkSize2], ax call checksum ; store it in the TCP checksum ( in the correct order! ) mov ax, [checkResult] mov [edx + 20 + 16], ah mov [edx + 20 + 17], al ; Fill in the IP header checksum GET_IHL eax,edx ; get IP-Header length stdcall checksum_jb,edx,eax ; buf_ptr, buf_size mov [edx + 10], ah mov [edx + 11], al ret ; Increments the 32 bit value pointed to by esi in internet order inc_inet_esi: push eax add esi, 3 mov al, byte[esi] inc al mov byte[esi], al cmp al, 0 jnz iie_exit dec esi mov al, byte[esi] inc al mov byte[esi], al cmp al, 0 jnz iie_exit dec esi mov al, byte[esi] inc al mov byte[esi], al cmp al, 0 jnz iie_exit dec esi mov al, byte[esi] inc al mov byte[esi], al iie_exit: pop eax ret ; Increments the 32 bit value pointed to by esi in internet order ; by the value in ecx add_inet_esi: push eax mov al, [esi] shl eax, 8 inc esi mov al, [esi] shl eax, 8 inc esi mov al, [esi] shl eax, 8 inc esi mov al, [esi] add eax, ecx mov [esi], al dec esi shr eax, 8 mov [esi], al dec esi shr eax, 8 mov [esi], al dec esi shr eax, 8 mov [esi], al pop eax ret iglobal TCBStateHandler: dd stateTCB_LISTEN dd stateTCB_SYN_SENT dd stateTCB_SYN_RECEIVED dd stateTCB_ESTABLISHED dd stateTCB_FIN_WAIT_1 dd stateTCB_FIN_WAIT_2 dd stateTCB_CLOSE_WAIT dd stateTCB_CLOSING dd stateTCB_LAST_ACK dd stateTCB_TIME_WAIT dd stateTCB_CLOSED endg ;*************************************************************************** ; Function ; tcpStateMachine ; ; Description ; TCP state machine ; This is a kernel function, called by tcp_rx ; ; IP buffer address given in edx ; Socket/TCB address in [eax + sockets] ; ; The IP buffer will be released by the caller ;*************************************************************************** tcpStateMachine: mov ebx, sockets add ebx, eax mov [sktAddr], ebx ; as a packet has been received, update the TCB timer mov ecx, TWOMSL mov [ebx + 32], ecx ; If the received packet has an ACK bit set, ; remove any packets in the resend queue that this ; received packet acknowledges pusha mov cl, [edx + 33] and cl, 0x10 cmp cl, 0x10 jne tsm001 ; No ACK, so no data yet ; get skt number in al shr eax, 12 ; The ack number is in [edx + 28], inet format ; skt in al mov esi, resendQ mov ecx, 0 t001: cmp ecx, NUMRESENDENTRIES je t003 ; None left cmp [esi], al je t002 ; found one inc ecx add esi, 4 jmp t001 t002: ; Can we delete this buffer? ; If yes, goto t004. No, goto t001 ; Get packet data address push ecx inc ecx ; Now get buffer location, and copy buffer across. argh! more copying,, mov edi, resendBuffer - IPBUFFSIZE t002a: add edi, IPBUFFSIZE loop t002a ; we have dest buffer location in edi. incoming packet in edx. ; Get this packets sequence number ; preserve al, ecx, esi, edx mov cl, [edi + 24] shl ecx, 8 mov cl, [edi + 25] shl ecx, 8 mov cl, [edi + 26] shl ecx, 8 mov cl, [edi + 27] movzx ebx, byte [edi + 3] mov bh, [edi + 2] sub ebx, 40 add ecx, ebx ; ecx is now seq# of last byte +1, intel format ; get recievd ack #, in intel format mov bl, [edx + 28] shl ebx, 8 mov bl, [edx + 29] shl ebx, 8 mov bl, [edx + 30] shl ebx, 8 mov bl, [edx + 31] cmp ebx, ecx ; Finally. ecx = rx'ed ack. ebx = last byte in que ; DANGER! need to handle case that we have just ; passed the 2**32, and wrapped round! pop ecx jae t004 ; if rx > old, delete old inc ecx add esi, 4 jmp t001 t004: dec dword [arp_rx_count] ; ************ TEST ONLY! mov [esi], byte 0xFF inc ecx add esi, 4 jmp t001 t003: tsm001: popa ; Call handler for given TCB state mov ebx, [eax + sockets+28] cmp ebx, TCB_LISTEN jb tsm_exit cmp ebx, TCB_CLOSED ja tsm_exit dec ebx call dword [TCBStateHandler+ebx*4] tsm_exit: ret stateTCB_LISTEN: ; In this case, we are expecting a SYN packet ; For now, if the packet is a SYN, process it, and send a response ; If not, ignore it ; Look at control flags mov bl, [edx + 33] and bl, 0x02 cmp bl, 0x02 jnz stl_exit ; We have a SYN. update the socket with this IP packets details, ; And send a response mov ebx, [edx + 12] ; IP source address mov [eax + sockets + 16], ebx mov bx, [edx + 20] ; IP source port mov [eax + sockets + 20], bx mov ebx, [edx + 24] ; IRS mov [eax + sockets + 40], ebx mov [eax + sockets + 56], ebx mov esi, sockets add esi, eax add esi, 56 call inc_inet_esi ; RCV.NXT mov ebx, [eax + sockets + 36] ; ISS mov [eax + sockets + 48], ebx ; SND.NXT ; Now construct the response, and queue for sending by IP mov eax, EMPTY_QUEUE call dequeue cmp ax, NO_BUFFER je stl_exit push eax mov bl, 0x12 ; SYN + ACK mov ecx, 0 mov esi, 0 call buildTCPPacket mov eax, NET1OUT_QUEUE mov edx, [stack_ip] mov ecx, [ sktAddr ] mov ecx, [ ecx + 16 ] cmp edx, ecx jne stl_notlocal mov eax, IPIN_QUEUE stl_notlocal: ; Send it. pop ebx call queue mov ebx, TCB_SYN_RECEIVED mov esi, [sktAddr] mov [esi + 28], ebx ; increament SND.NXT in socket add esi, 48 call inc_inet_esi stl_exit: ret stateTCB_SYN_SENT: ; We are awaiting an ACK to our SYN, with a SYM ; Look at control flags - expecting an ACK mov bl, [edx + 33] and bl, 0x12 cmp bl, 0x12 jnz stss_exit mov ebx, TCB_ESTABLISHED mov esi, [sktAddr] mov [esi + 28], ebx ; Store the recv.nxt field mov eax, [edx + 24] ; Update our recv.nxt field mov esi, [sktAddr] add esi, 56 mov [esi], eax call inc_inet_esi ; Send an ACK ; Now construct the response, and queue for sending by IP mov eax, EMPTY_QUEUE call dequeue cmp ax, NO_BUFFER je stss_exit push eax mov bl, 0x10 ; ACK mov ecx, 0 mov esi, 0 call buildTCPPacket mov eax, NET1OUT_QUEUE mov edx, [stack_ip] mov ecx, [ sktAddr ] mov ecx, [ ecx + 16 ] cmp edx, ecx jne stss_notlocal mov eax, IPIN_QUEUE stss_notlocal: ; Send it. pop ebx call queue stss_exit: ret stateTCB_SYN_RECEIVED: ; In this case, we are expecting an ACK packet ; For now, if the packet is an ACK, process it, ; If not, ignore it ; Look at control flags - expecting an ACK mov bl, [edx + 33] and bl, 0x10 cmp bl, 0x10 jnz stsr_exit mov ebx, TCB_ESTABLISHED mov esi, [sktAddr] mov [esi + 28], ebx stsr_exit: ret stateTCB_ESTABLISHED: ; Here we are expecting data, or a request to close ; OR both... ; Did we receive a FIN or RST? mov bl, [edx + 33] and bl, 0x05 cmp bl, 0 je ste_chkack ; It was a fin or reset. ; Remove resend entries from the queue - I dont want to send any more data pusha mov ebx, [sktAddr] sub ebx, sockets shr ebx, 12 ; get skt # mov esi, resendQ mov ecx, 0 ste001: cmp ecx, NUMRESENDENTRIES je ste003 ; None left cmp [esi], bl je ste002 ; found one inc ecx add esi, 4 jmp ste001 ste002: dec dword [arp_rx_count] ; ************ TEST ONLY! mov [esi], byte 0xFF jmp ste001 ste003: popa ; was it a reset? mov bl, [edx + 33] and bl, 0x04 cmp bl, 0x04 jne ste003a mov esi, [sktAddr] mov ebx, TCB_CLOSED mov [esi + 28], ebx jmp ste_exit ste003a: ; Send an ACK to that fin, and enter closewait state mov esi, [sktAddr] mov ebx, TCB_CLOSE_WAIT mov [esi + 28], ebx add esi, 56 mov eax, [esi] ; save original call inc_inet_esi ;; jmp ste_ack - NO, there may be data ste_chkack: ; Check that we received an ACK mov bl, [edx + 33] and bl, 0x10 cmp bl, 0x10 jnz ste_exit ; TODO - done, I think! ; First, look at the incoming window. If this is less than or equal to 1024, ; Set the socket window timer to 1. This will stop an additional packets being ; queued. ; ** I may need to tweak this value, since I do not know how many packets are already queued mov ch, [edx + 34] mov cl, [edx + 35] cmp cx, 1024 ja ste004 mov ecx, [sktAddr] mov [ecx+72], dword 1 ste004: ; OK, here is the deal ; My recv.nct field holds the seq of the expected next rec byte ; if the recevied sequence number is not equal to this, do not ; increment the recv.nxt field, do not copy data - just send a ; repeat ack. ; recv.nxt is in dword [edx+24], in inext format ; recv seq is in [sktAddr]+56, in inet format ; just do a comparision mov ecx, [sktAddr] add ecx, 56 cmp [ecx - 56 + 28], dword TCB_CLOSE_WAIT mov ecx, [ecx] jne stenofin mov ecx, eax stenofin: cmp ecx, [edx+24] jne ste_ack ; Read the data bytes, store in socket buffer xor ecx, ecx mov ch, [edx + 2] mov cl, [edx + 3] sub ecx, 40 ; Discard 40 bytes of header cmp ecx, 0 jnz ste_data ; Read data, if any ; If we had received a fin, we need to ACK it. mov esi, [sktAddr] mov ebx, [esi + 28] cmp ebx, TCB_CLOSE_WAIT jz ste_ack jnz ste_exit ste_data: push ecx mov esi, [sktAddr] add [esi + 24], ecx ; increment the count of bytes in buffer mov eax, [esi + 4] ; get socket owner PID push eax mov eax, [esi + 24] ; get # of bytes already in buffer ; point to the location to store the data add esi, eax sub esi, ecx add esi, SOCKETHEADERSIZE add edx, 40 ; edx now points to the data mov edi, esi mov esi, edx cld rep movsb ; copy the data across ; flag an event to the application pop eax mov ecx,1 mov esi,0x3020+TASKDATA.pid news: cmp [esi],eax je foundPID1 inc ecx add esi,0x20 cmp ecx,[0x3004] jbe news foundPID1: shl ecx,8 or dword [ecx+0x80000+APPDATA.event_mask],dword 10000000b ; stack event pop ecx ; Update our recv.nxt field mov esi, [sktAddr] add esi, 56 call add_inet_esi ste_ack: ; Send an ACK ; Now construct the response, and queue for sending by IP mov eax, EMPTY_QUEUE call dequeue cmp ax, NO_BUFFER je ste_exit push eax mov bl, 0x10 ; ACK mov ecx, 0 mov esi, 0 call buildTCPPacket mov eax, NET1OUT_QUEUE mov edx, [stack_ip] mov ecx, [ sktAddr ] mov ecx, [ ecx + 16 ] cmp edx, ecx jne ste_notlocal mov eax, IPIN_QUEUE ste_notlocal: ; Send it. pop ebx call queue ste_exit: ret stateTCB_FIN_WAIT_1: ; We can either receive an ACK of a fin, or a fin mov bl, [edx + 33] and bl, 0x10 cmp bl, 0x10 jnz stfw1_001 ; It was an ACK mov esi, [sktAddr] mov ebx, TCB_FIN_WAIT_2 mov [esi + 28], ebx jmp stfw1_exit stfw1_001: ; It must be a fin then mov esi, [sktAddr] mov ebx, TCB_CLOSING mov [esi + 28], ebx add esi, 56 call inc_inet_esi ; Send an ACK mov eax, EMPTY_QUEUE call dequeue cmp ax, NO_BUFFER je stfw1_exit push eax mov bl, 0x10 ; ACK mov ecx, 0 mov esi, 0 call buildTCPPacket mov eax, NET1OUT_QUEUE mov edx, [stack_ip] mov ecx, [ sktAddr ] mov ecx, [ ecx + 16 ] cmp edx, ecx jne stfw1_notlocal mov eax, IPIN_QUEUE stfw1_notlocal: ; Send it. pop ebx call queue stfw1_exit: ret stateTCB_FIN_WAIT_2: mov esi, [sktAddr] ; Get data length xor ecx, ecx mov ch, [edx+2] mov cl, [edx+3] sub ecx, 40 mov bl, [edx + 33] and bl, 0x01 cmp bl, 0x01 jne stfw2001 ; Change state, as we have a fin mov ebx, TCB_TIME_WAIT mov [esi + 28], ebx inc ecx ; FIN is part of the sequence space stfw2001: add esi, 56 call add_inet_esi ; Send an ACK mov eax, EMPTY_QUEUE call dequeue cmp ax, NO_BUFFER je stfw2_exit push eax mov bl, 0x10 ; ACK mov ecx, 0 mov esi, 0 call buildTCPPacket mov eax, NET1OUT_QUEUE mov edx, [stack_ip] mov ecx, [ sktAddr ] mov ecx, [ ecx + 16 ] cmp edx, ecx jne stfw2_notlocal mov eax, IPIN_QUEUE stfw2_notlocal: ; Send it. pop ebx call queue ; Only delete the socket if we received the FIN mov bl, [edx + 33] and bl, 0x01 cmp bl, 0x01 jne stfw2_exit ; mov edi, [sktAddr] ; delete the socket. Should really wait for 2MSL ; xor eax, eax ; mov ecx,SOCKETHEADERSIZE ; cld ; rep stosb stfw2_exit: ret stateTCB_CLOSE_WAIT: ; Intentionally left empty ; socket_close_tcp handles this ret stateTCB_CLOSING: ; We can either receive an ACK of a fin, or a fin mov bl, [edx + 33] and bl, 0x10 cmp bl, 0x10 jnz stc_exit ; It was an ACK mov edi, [sktAddr] ; delete the socket xor eax, eax mov ecx,SOCKETHEADERSIZE cld rep stosb stc_exit: ret stateTCB_LAST_ACK: ; Look at control flags - expecting an ACK mov bl, [edx + 33] and bl, 0x10 cmp bl, 0x10 jnz stla_exit mov edi, [sktAddr] ; delete the socket xor eax, eax mov ecx,SOCKETHEADERSIZE cld rep stosb stla_exit: ret stateTCB_TIME_WAIT: ret stateTCB_CLOSED: ret