0,0 → 1,863 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; SOCKET.INC |
;; |
;; Sockets constants, structures and functions |
;; |
;; Last revision: 11.11.2006 |
;; |
;; This file contains the following: |
;; is_localport_unused |
;; get_free_socket |
;; socket_open |
;; socket_open_tcp |
;; socket_close |
;; socket_close_tcp |
;; socket_poll |
;; socket_status |
;; socket_read |
;; socket_write |
;; socket_write_tcp |
;; |
;; |
;; Changes history: |
;; 22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net |
;; 11.11.2006 - [Johnny_B] and [smb] |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
; |
; Socket Descriptor + Buffer |
; |
; 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 |
; |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 0| Status ( of this buffer ) | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 4| Application Process ID | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 8| Local IP Address | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 12| Local IP Port | Unused ( set to 0 ) | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 16| Remote IP Address | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 20| Remote IP Port | Unused ( set to 0 ) | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 24| Rx Data Count INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 28| TCB STATE INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 32| TCB Timer (seconds) INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 36| ISS (Inital Sequence # used by this connection ) INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 40| IRS ( Inital Receive Sequence # ) INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 44| SND.UNA Seq # of unack'ed sent packets INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 48| SND.NXT Next send seq # to use INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 52| SND.WND Send window INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 56| RCV.NXT Next expected receive sequence # INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 60| RCV.WND Receive window INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 64| SEG.LEN Segment length INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 68| SEG.WND Segment window INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 72| Retransmit queue # NOW WINDOW SIZE TIMER INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 76| RX offset from |
; 76| RX Data | |
; +-+-+-.......... -+ |
|
|
; so, define struct |
struc SOCKET |
{ .Status dd ? ;+00 - Status ( of this buffer ) |
.PID dd ? ;+04 - Application Process ID |
.LocalIP dd ? ;+08 - Local IP Address |
.LocalPort dw ? ;+12 - Local Port |
.UnusedL dw ? ;+14 - may be removed in future |
.RemoteIP dd ? ;+16 - Remote IP Address |
.RemotePort dw ? ;+20 - Remote Port |
.UnusedR dw ? ;+22 - may be removed in future |
.rxDataCount dd ? ;+24 - Rx Data Count |
.TCBState dd ? ;+28 - TCB STATE |
.TCBTimer dd ? ;+32 - TCB Timer (seconds) |
.ISS dd ? ;+36 - Initial Send Sequence |
.IRS dd ? ;+40 - Initial Receive Sequence |
.SND_UNA dd ? ;+44 - Sequence number of unack'ed sent packets |
.SND_NXT dd ? ;+48 - Next send sequence number to use |
.SND_WND dd ? ;+52 - Send window |
.RCV_NXT dd ? ;+56 - Next receive sequence number to use |
.RCV_WND dd ? ;+60 - Receive window |
.SEG_LEN dd ? ;+64 - Segment length |
.SEG_WND dd ? ;+68 - Segment window |
.wndsizeTimer dd ? ;+72 - Retransmit queue # NOW WINDOW SIZE TIMER |
.rxData dd ? ;+76 - receive data buffer here |
} |
|
virtual at 0 |
SOCKET SOCKET |
end virtual |
|
; simple macro calcing real memory address of SOCKET struct by socket's |
macro Index2RealAddr reg |
{ |
shl reg, 12 |
add reg, sockets |
} |
|
;Constants |
; current socket statuses |
SOCK_EMPTY equ 0 ; socket not in use |
SOCK_OPEN equ 1 ; open issued, but no data sent |
|
; TCP opening modes |
SOCKET_PASSIVE equ 0 |
SOCKET_ACTIVE equ 1 |
|
;*************************************************************************** |
; Function |
; is_localport_unused |
; |
; Description |
; scans through all the active sockets , looking to see if the |
; port number specified in bx is in use as a localport number. |
; This is useful when you want a to generate a unique local port |
; number. |
; On return, eax = 1 for free, 0 for in use |
; |
;*************************************************************************** |
is_localport_unused: |
mov al, bh |
mov ah, bl |
mov bx, ax |
|
mov edx, SOCKETBUFFSIZE * NUM_SOCKETS |
mov ecx, NUM_SOCKETS |
mov eax, 0 ; Assume the return value is 'in use' |
|
ilu1: |
sub edx, SOCKETBUFFSIZE |
cmp [edx + sockets + SOCKET.LocalPort], bx |
loopnz ilu1 ; Return back if the socket is occupied |
|
jz ilu_exit |
inc eax ; return port not in use |
|
ilu_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; get_free_socket |
; |
; Description |
; |
;*************************************************************************** |
get_free_socket: |
push ecx |
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS |
mov ecx, NUM_SOCKETS |
|
gfs1: |
sub eax, SOCKETBUFFSIZE |
cmp [eax + sockets + SOCKET.Status], dword SOCK_EMPTY |
loopnz gfs1 ; Return back if the socket is occupied |
mov eax, ecx |
pop ecx |
jz gfs_exit |
mov eax, 0xFFFFFFFF |
|
gfs_exit: |
ret |
|
|
;*************************************************************************** |
; Function |
; socket_open |
; |
; Description |
; find a free socket |
; local port in ebx |
; remote port in ecx |
; remote ip in edx |
; return socket # in eax, -1 if none available |
; |
;*************************************************************************** |
socket_open: |
call get_free_socket |
|
cmp eax, 0xFFFFFFFF |
jz so_exit |
|
; ax holds the socket number that is free. Get real address |
push eax |
Index2RealAddr eax |
|
mov [eax + SOCKET.Status], dword SOCK_OPEN |
|
xchg bh, bl |
mov [eax + SOCKET.LocalPort], bx |
; mov [eax + 12], byte bh ; Local port ( LS 16 bits ) |
; mov [eax + 13], byte bl ; Local port ( LS 16 bits ) |
xchg ch, cl |
mov [eax + SOCKET.RemotePort], cx |
; mov [eax + 20], ch ; Remote Port ( LS 16 bits ) |
; mov [eax + 21], cl ; Remote Port ( LS 16 bits ) |
|
mov ebx, [stack_ip] |
mov [eax + SOCKET.LocalIP], ebx |
mov [eax + SOCKET.RemoteIP], edx |
mov [eax + SOCKET.rxDataCount], dword 0 ; recieved data count |
|
mov esi, [0x3010] |
mov ebx, [esi+TASKDATA.pid] |
mov [eax + SOCKET.PID], ebx ; save the process ID |
pop eax ; Get the socket number back, so we can return it |
|
so_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_open_tcp |
; |
; Description |
; Opens a TCP socket in PASSIVE or ACTIVE mode |
; find a free socket |
; local port in ebx ( intel format ) |
; remote port in ecx ( intel format ) |
; remote ip in edx ( in Internet byte order ) |
; Socket open mode in esi ( SOCKET_PASSIVE or SOCKET_ACTIVE ) |
; return socket # in eax, -1 if none available |
; |
;*************************************************************************** |
socket_open_tcp: |
call get_free_socket |
|
cmp eax, 0xFFFFFFFF |
jz so_exit |
|
; ax holds the socket number that is free. Get real address |
push eax |
Index2RealAddr eax |
|
mov [sktAddr], eax |
mov [eax], dword SOCK_OPEN |
|
; TODO - check this works! |
mov [eax + SOCKET.wndsizeTimer], dword 0 ; Reset the window timer. |
|
xchg bh, bl |
mov [eax + SOCKET.LocalPort], bx |
; mov [eax + 12], byte bh ; Local port ( LS 16 bits ) |
; mov [eax + 13], byte bl ; Local port ( LS 16 bits ) |
|
xchg ch, cl |
mov [eax + SOCKET.RemotePort], cx |
; mov [eax + 20], ch ; Remote Port ( LS 16 bits ) |
; mov [eax + 21], cl ; Remote Port ( LS 16 bits ) |
|
mov ebx, [stack_ip] |
mov [eax + SOCKET.LocalIP], ebx |
mov [eax + SOCKET.RemoteIP], edx |
mov [eax + SOCKET.rxDataCount], dword 0 |
|
; Now fill in TCB state |
mov ebx, TCB_LISTEN |
cmp esi, SOCKET_PASSIVE |
jz sot_001 |
mov ebx, TCB_SYN_SENT |
|
sot_001: |
mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB |
|
mov esi, [0x3010] |
mov ecx, [esi+TASKDATA.pid] |
mov [eax + SOCKET.PID], ecx ; save the process ID |
|
cmp ebx, TCB_LISTEN |
je sot_done |
|
; Now, if we are in active mode, then we have to send a SYN to the specified remote port |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je sot_done |
|
push eax |
|
mov bl, 0x02 ; SYN |
mov ecx, 0 |
|
call buildTCPPacket |
|
mov eax, NET1OUT_QUEUE |
|
mov edx, [stack_ip] |
mov ecx, [sktAddr ] |
mov ecx, [ecx + 16] |
cmp edx, ecx |
jne sot_notlocal |
mov eax, IPIN_QUEUE |
|
sot_notlocal: |
; Send it. |
pop ebx |
call queue |
|
mov esi, [sktAddr] |
|
; increment SND.NXT in socket |
add esi, 48 |
call inc_inet_esi |
|
sot_done: |
pop eax ; Get the socket number back, so we can return it |
|
sot_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_close |
; |
; Description |
; socket # in ebx |
; returns 0 for ok, -1 for socket not open (fail) |
; |
;*************************************************************************** |
socket_close: |
Index2RealAddr ebx |
mov eax, 0xFFFFFFFF ; assume this operation will fail.. |
cmp [ebx + SOCKET.Status], dword SOCK_EMPTY |
jz sc_exit |
|
; Clear the socket varaibles |
xor eax, eax |
mov edi, ebx |
mov ecx, SOCKETHEADERSIZE |
cld |
rep stosb |
|
sc_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_close_tcp |
; |
; Description |
; socket # in ebx |
; returns 0 for ok, -1 for socket not open (fail) |
; |
;*************************************************************************** |
socket_close_tcp: |
; first, remove any resend entries |
pusha |
|
mov esi, resendQ |
mov ecx, 0 |
|
sct001: |
cmp ecx, NUMRESENDENTRIES |
je sct003 ; None left |
cmp [esi], bl |
je sct002 ; found one |
inc ecx |
add esi, 4 |
jmp sct001 |
|
sct002: |
|
mov [esi], byte 0xFF |
jmp sct001 |
|
sct003: |
popa |
|
Index2RealAddr ebx |
mov [sktAddr], ebx |
mov eax, 0xFFFFFFFF ; assume this operation will fail.. |
cmp [ebx + SOCKET.Status], dword SOCK_EMPTY |
jz sct_exit |
|
; 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, 0x11 ; FIN + ACK |
mov ecx, 0 |
mov esi, 0 |
|
call buildTCPPacket |
|
mov ebx, [sktAddr] |
|
; increament SND.NXT in socket |
mov esi, 48 |
add esi, ebx |
call inc_inet_esi |
|
|
; Get the socket state |
mov eax, [ebx + SOCKET.TCBState] |
cmp eax, TCB_LISTEN |
je destroyTCB |
cmp eax, TCB_SYN_SENT |
je destroyTCB |
cmp eax, TCB_SYN_RECEIVED |
je sct_finwait1 |
cmp eax, TCB_ESTABLISHED |
je sct_finwait1 |
|
; assume CLOSE WAIT |
; Send a fin, then enter last-ack state |
mov eax, TCB_LAST_ACK |
mov [ebx + SOCKET.TCBState], eax |
xor eax, eax |
jmp sct_send |
|
sct_finwait1: |
; Send a fin, then enter finwait2 state |
mov eax, TCB_FIN_WAIT_1 |
mov [ebx + SOCKET.TCBState], eax |
xor eax, eax |
|
sct_send: |
mov eax, NET1OUT_QUEUE |
|
mov edx, [stack_ip] |
mov ecx, [sktAddr ] |
mov ecx, [ecx + 16] |
cmp edx, ecx |
jne sct_notlocal |
mov eax, IPIN_QUEUE |
|
sct_notlocal: |
; Send it. |
pop ebx |
call queue |
jmp sct_exit |
|
destroyTCB: |
pop eax |
; Clear the socket varaibles |
xor eax, eax |
mov edi, ebx |
mov ecx, SOCKETHEADERSIZE |
cld |
rep stosb |
|
sct_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_poll |
; |
; Description |
; socket # in ebx |
; returns count in eax. |
; |
;*************************************************************************** |
socket_poll: |
Index2RealAddr ebx |
mov eax, [ebx + SOCKET.rxDataCount] |
|
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_status |
; |
; Description |
; socket # in ebx |
; returns TCB state in eax. |
; |
;*************************************************************************** |
socket_status: |
Index2RealAddr ebx |
mov eax, [ebx + SOCKET.TCBState] |
|
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_read |
; |
; Description |
; socket # in ebx |
; returns # of bytes remaining in eax, data in bl |
; |
;*************************************************************************** |
socket_read: |
Index2RealAddr ebx |
mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes |
mov ecx, 1 |
test eax, eax |
jz sr2 |
|
dec eax |
mov esi, ebx ; esi is address of socket |
mov [ebx + SOCKET.rxDataCount], eax ; store new count |
;movzx ebx, byte [ebx + SOCKET.rxData] ; get the byte |
movzx ebx, byte [ebx + SOCKETHEADERSIZE] ; get the byte |
add esi, SOCKETHEADERSIZE |
mov edi, esi |
inc esi |
|
mov ecx, (SOCKETBUFFSIZE - SOCKETHEADERSIZE) / 4 |
cld |
rep movsd |
xor ecx, ecx |
|
sr1: |
jmp sor_exit |
|
sr2: |
xor bl, bl |
|
sor_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_write |
; |
; Description |
; socket in ebx |
; # of bytes to write in ecx |
; pointer to data in edx |
; returns 0 in eax ok, -1 == failed ( invalid socket, or |
; could not queue IP packet ) |
; |
;*************************************************************************** |
socket_write: |
Index2RealAddr ebx |
|
mov eax, 0xFFFFFFFF |
; If the socket is invalid, return with an error code |
cmp [ebx], dword SOCK_EMPTY |
je sw_exit |
|
|
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je sw_exit |
|
; Save the queue entry number |
push eax |
|
; save the pointers to the data buffer & size |
push edx |
push ecx |
|
; convert buffer pointer eax to the absolute address |
mov ecx, IPBUFFSIZE |
mul ecx |
add eax, IPbuffs |
|
mov edx, eax |
|
; 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 UDP data length |
push eax |
|
add eax, 20 + 8 ; add IP header and UDP 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, 17 |
mov [edx + 9], al |
|
; Checksum left unfilled |
xor ax, ax |
mov [edx + 10], ax |
|
; Fill in the UDP header ( some data is in the socket descriptor) |
mov ax, [ebx + 12] |
mov [edx + 20], ax |
|
mov ax, [ebx + 20] |
mov [edx + 20 + 2], ax |
|
pop eax |
push eax |
|
add eax, 8 |
mov [edx + 20 + 4], ah |
mov [edx + 20 + 5], al |
|
; Checksum left unfilled |
xor ax, ax |
mov [edx + 20 + 6], ax |
|
pop ecx ; count of bytes to send |
mov ebx, ecx ; need the length later |
pop eax ; get callers ptr to data to send |
|
; Get the address of the callers data |
mov edi, [0x3010] |
add edi, TASKDATA.mem_start |
add eax, [edi] |
mov esi, eax |
|
mov edi, edx |
add edi, 28 |
cld |
rep movsb ; copy the data across |
|
; we have edx as IPbuffer ptr. |
; Fill in the UDP checksum |
; First, fill in pseudoheader |
mov eax, [edx + 12] |
mov [pseudoHeader], eax |
mov eax, [edx + 16] |
mov [pseudoHeader+4], eax |
mov ax, 0x1100 ; 0 + protocol |
mov [pseudoHeader+8], ax |
add ebx, 8 |
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 ; was eax!! mjh 8/7/02 |
|
call checksum |
|
; store it in the UDP checksum ( in the correct order! ) |
mov ax, [checkResult] |
|
; If the UDP checksum computes to 0, we must make it 0xffff |
; (0 is reserved for 'not used') |
cmp ax, 0 |
jne sw_001 |
mov ax, 0xffff |
|
sw_001: |
mov [edx + 20 + 6], ah |
mov [edx + 20 + 7], al |
|
; Fill in the IP header checksum |
GET_IHL ecx,edx ; get IP-Header length |
stdcall checksum_jb,edx,ecx ; buf_ptr, buf_size |
|
mov [edx + 10], ah |
mov [edx + 11], al |
|
; Check destination IP address. |
; If it is the local host IP, route it back to IP_RX |
|
pop ebx |
mov eax, NET1OUT_QUEUE |
|
mov ecx, [ edx + 16] |
mov edx, [stack_ip] |
cmp edx, ecx |
jne sw_notlocal |
mov eax, IPIN_QUEUE |
|
sw_notlocal: |
; Send it. |
call queue |
|
xor eax, eax |
|
sw_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_write_tcp |
; |
; Description |
; socket in ebx |
; # of bytes to write in ecx |
; pointer to data in edx |
; returns 0 in eax ok, -1 == failed ( invalid socket, or |
; could not queue IP packet ) |
; |
;*************************************************************************** |
socket_write_tcp: |
Index2RealAddr ebx |
|
mov [sktAddr], ebx |
|
mov eax, 0xFFFFFFFF |
; If the socket is invalid, return with an error code |
cmp [ebx], dword SOCK_EMPTY |
je swt_exit |
|
; If the sockets window timer is nonzero, do not queue packet |
; TODO - done |
cmp [ebx + SOCKET.wndsizeTimer], dword 0 |
jne swt_exit |
|
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je swt_exit |
|
push eax |
|
mov bl, 0x10 ; ACK |
|
; Get the address of the callers data |
mov edi, [0x3010] |
add edi, TASKDATA.mem_start |
add edx, [edi] |
mov esi, edx |
|
pop eax |
push eax |
|
push ecx |
call buildTCPPacket |
pop ecx |
|
; Check destination IP address. |
; If it is the local host IP, route it back to IP_RX |
|
pop ebx |
push ecx |
mov eax, NET1OUT_QUEUE |
|
mov edx, [stack_ip] |
mov ecx, [sktAddr ] |
mov ecx, [ecx + 16] |
cmp edx, ecx |
jne swt_notlocal |
mov eax, IPIN_QUEUE |
|
swt_notlocal: |
pop ecx |
|
push ebx ; save ipbuffer number |
|
call queue |
|
mov esi, [sktAddr] |
|
; increament SND.NXT in socket |
; Amount to increment by is in ecx |
add esi, 48 |
call add_inet_esi |
|
pop ebx |
|
; Copy the IP buffer to a resend queue |
; If there isn't one, dont worry about it for now |
mov esi, resendQ |
mov ecx, 0 |
|
swt003: |
cmp ecx, NUMRESENDENTRIES |
je swt001 ; None found |
cmp [esi], byte 0xFF |
je swt002 ; found one |
inc ecx |
add esi, 4 |
jmp swt003 |
|
swt002: |
push ebx |
|
; OK, we have a buffer descriptor ptr in esi. |
; resend entry # in ecx |
; Populate it |
; socket # |
; retries count |
; retry time |
; fill IP buffer associated with this descriptor |
|
mov eax, [sktAddr] |
sub eax, sockets |
shr eax, 12 ; get skt # |
mov [esi], al |
mov [esi + 1], byte TCP_RETRIES |
mov [esi + 2], word TCP_TIMEOUT |
|
inc ecx |
; Now get buffer location, and copy buffer across. argh! more copying,, |
mov edi, resendBuffer - IPBUFFSIZE |
swt002a: |
add edi, IPBUFFSIZE |
loop swt002a |
|
; we have dest buffer location in edi |
pop eax |
; convert source buffer pointer eax to the absolute address |
mov ecx, IPBUFFSIZE |
mul ecx |
add eax, IPbuffs |
mov esi, eax |
|
; do copy |
mov ecx, IPBUFFSIZE |
cld |
rep movsb |
|
swt001: |
xor eax, eax |
|
swt_exit: |
ret |
|