77,21 → 77,23 |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 72| Retransmit queue # NOW WINDOW SIZE TIMER INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 76| RX offset from |
; 76| RX Data | |
; 76| RX Data Buffer | |
; +-+-+-.......... -+ |
|
|
; so, define struct |
struc SOCKET |
{ .Status dd ? ;+00 - Status ( of this buffer ) |
{ |
.PrevPtr dd ? |
.NextPtr dd ? |
.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 |
.OrigRemoteIP dd ? |
.OrigRemotePort dw ? |
.rxDataCount dd ? ;+24 - Rx Data Count |
.TCBState dd ? ;+28 - TCB STATE |
.TCBTimer dd ? ;+32 - TCB Timer (seconds) |
113,21 → 115,132 |
end virtual |
|
; simple macro calcing real memory address of SOCKET struct by socket's |
macro Index2RealAddr reg |
{ |
shl reg, 12 |
add reg, sockets |
} |
;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 |
SOCK_EMPTY = 0 ; socket not in use |
SOCK_OPEN = 1 ; open issued, but no data sent |
|
; TCP opening modes |
SOCKET_PASSIVE equ 0 |
SOCKET_ACTIVE equ 1 |
|
proc net_socket_alloc stdcall uses ebx ecx edx edi |
mov ecx, SOCKETBUFFSIZE |
mov edx, PG_SW |
call @mem_alloc@8 |
DEBUGF 1, "K : net_socket_alloc (0x%x)\n", eax |
or eax, eax |
jz .exit |
|
push eax |
mov edi, eax |
mov ecx, SOCKETBUFFSIZE / 4 |
cld |
xor eax, eax |
rep stosd |
pop eax |
|
mov ebx, net_sockets |
push [ebx + SOCKET.NextPtr] |
mov [ebx + SOCKET.NextPtr], eax |
mov [eax + SOCKET.PrevPtr], ebx |
pop ebx |
mov [eax + SOCKET.NextPtr], ebx |
or ebx, ebx |
jz @f |
mov [ebx + SOCKET.PrevPtr], eax |
|
@@: mov ebx, [TASK_BASE] |
mov ebx, [ebx + TASKDATA.pid] |
mov [eax + SOCKET.PID], ebx |
|
.exit: |
ret |
endp |
|
proc net_socket_free stdcall uses ebx ecx edx, sock:DWORD |
mov eax, [sock] |
DEBUGF 1, "K : net_socket_free (0x%x)\n", eax |
or eax, eax |
jz .error |
|
mov ebx, net_sockets |
mov ecx, [TASK_BASE] |
mov ecx, [ecx + TASKDATA.pid] |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .error |
cmp ebx, eax |
jne .next_socket |
;cmp [ebx + SOCKET.PID], ecx |
;jne .next_socket |
|
mov ebx, [eax + SOCKET.NextPtr] |
mov eax, [eax + SOCKET.PrevPtr] |
mov [eax + SOCKET.NextPtr], ebx |
or ebx, ebx |
jz @f |
mov [ebx + SOCKET.PrevPtr], eax |
|
@@: |
mov ecx, [sock] |
call @mem_free@4 |
ret |
|
.error: |
DEBUGF 1, "K : failed\n" |
ret |
endp |
|
proc net_socket_num_to_addr stdcall uses ebx ecx, x:DWORD |
; FIXME: do real transform |
mov eax, [x] |
mov ebx, net_sockets |
mov ecx, [TASK_BASE] |
mov ecx, [ecx + TASKDATA.pid] |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .error |
cmp ebx, eax |
jne .next_socket |
;cmp [ebx + SOCKET.PID], ecx |
;jne .next_socket |
ret |
|
.error: |
xor eax, eax |
ret |
endp |
|
proc net_socket_addr_to_num stdcall uses ebx ecx, x:DWORD |
; FIXME: do real transform |
mov eax, [x] |
mov ebx, net_sockets |
mov ecx, [TASK_BASE] |
mov ecx, [ecx + TASKDATA.pid] |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .error |
cmp ebx, eax |
jne .next_socket |
;cmp [ebx + SOCKET.PID], ecx |
;jne .next_socket |
ret |
|
.error: |
xor eax, eax |
ret |
endp |
|
;*************************************************************************** |
; Function |
; is_localport_unused |
140,51 → 253,26 |
; On return, eax = 1 for free, 0 for in use |
; |
;*************************************************************************** |
is_localport_unused: |
mov al, bh |
mov ah, bl |
mov bx, ax |
proc is_localport_unused stdcall |
|
mov edx, SOCKETBUFFSIZE * NUM_SOCKETS |
mov ecx, NUM_SOCKETS |
mov eax, 0 ; Assume the return value is 'in use' |
xchg bl, bh |
|
ilu1: |
sub edx, SOCKETBUFFSIZE |
cmp [edx + sockets + SOCKET.LocalPort], bx |
loopnz ilu1 ; Return back if the socket is occupied |
xor eax, eax ; Assume the return value is 'free' |
inc al |
mov edx, net_sockets |
|
jz ilu_exit |
inc eax ; return port not in use |
.next_socket: |
mov edx, [edx + SOCKET.NextPtr] |
or edx, edx |
jz .exit |
cmp [edx + SOCKET.LocalPort], bx |
jne .next_socket ; Return back if the port is not occupied |
|
ilu_exit: |
ret |
dec al ; return 'in use' |
|
|
|
;*************************************************************************** |
; 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: |
.exit: |
ret |
endp |
|
|
;*************************************************************************** |
199,18 → 287,16 |
; return socket # in eax, -1 if none available |
; |
;*************************************************************************** |
socket_open: |
call get_free_socket |
proc socket_open stdcall |
call net_socket_alloc |
or eax, eax |
jz .error |
|
cmp eax, 0xFFFFFFFF |
jz so_exit |
DEBUGF 1, "K : socket_open (0x%x)\n", eax |
|
; ax holds the socket number that is free. Get real address |
push eax |
Index2RealAddr eax |
|
mov [eax + SOCKET.Status], dword SOCK_OPEN |
|
mov [eax + SOCKET.Status], SOCK_OPEN |
xchg bh, bl |
mov [eax + SOCKET.LocalPort], bx |
xchg ch, cl |
219,18 → 305,18 |
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, [TASK_BASE] |
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 |
;pop eax ; Get the socket number back, so we can return it |
stdcall net_socket_addr_to_num |
ret |
|
so_exit: |
.error: |
DEBUGF 1, "K : socket_open (fail)\n" |
or eax, -1 |
ret |
endp |
|
|
|
;*************************************************************************** |
; Function |
; socket_open_tcp |
245,94 → 331,111 |
; return socket # in eax, -1 if none available |
; |
;*************************************************************************** |
socket_open_tcp: |
call get_free_socket |
proc socket_open_tcp stdcall |
local sockAddr dd ? |
|
cmp eax, 0xFFFFFFFF |
jz so_exit |
cmp esi, SOCKET_PASSIVE |
jne .skip_port_check |
|
; ax holds the socket number that is free. Get real address |
push eax |
Index2RealAddr eax |
push ebx |
mov eax, ebx |
xchg al, ah |
mov ebx, net_sockets |
|
mov [sktAddr], eax |
mov [eax], dword SOCK_OPEN |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .last_socket |
cmp [ebx + SOCKET.TCBState], TCB_LISTEN |
jne .next_socket |
cmp [ebx + SOCKET.LocalPort], ax |
jne .next_socket |
|
xchg al, ah |
DEBUGF 1, "K : error: port %u is listened by 0x%x\n", ax, ebx |
pop ebx |
jmp .error |
|
.last_socket: |
pop ebx |
|
.skip_port_check: |
call net_socket_alloc |
or eax, eax |
jz .error |
|
DEBUGF 1, "K : socket_open_tcp (0x%x)\n", eax |
|
mov [sockAddr], eax |
|
; TODO - check this works! |
mov [eax + SOCKET.wndsizeTimer], dword 0 ; Reset the window timer. |
;xxx: already 0 (intialized by net_socket_alloc) |
;mov [eax + SOCKET.wndsizeTimer], 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 [eax + SOCKET.OrigRemotePort], cx |
mov ebx, [stack_ip] |
mov [eax + SOCKET.LocalIP], ebx |
mov [eax + SOCKET.RemoteIP], edx |
mov [eax + SOCKET.rxDataCount], dword 0 |
mov [eax + SOCKET.OrigRemoteIP], edx |
|
; Now fill in TCB state |
mov ebx, TCB_LISTEN |
cmp esi, SOCKET_PASSIVE |
jz sot_001 |
je @f |
mov ebx, TCB_SYN_SENT |
@@: mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB |
|
sot_001: |
mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB |
|
mov esi, [TASK_BASE] |
mov ecx, [esi+TASKDATA.pid] |
mov [eax + SOCKET.PID], ecx ; save the process ID |
|
cmp ebx, TCB_LISTEN |
je sot_done |
je .exit |
|
; 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 |
je .exit |
|
push eax |
|
mov bl, 0x02 ; SYN |
mov ecx, 0 |
mov bl, TH_SYN |
xor ecx, ecx |
stdcall build_tcp_packet, [sockAddr] |
|
call buildTCPPacket |
|
mov eax, NET1OUT_QUEUE |
|
mov edx, [stack_ip] |
mov ecx, [sktAddr ] |
mov ecx, [ecx + 16] |
cmp edx, ecx |
jne sot_notlocal |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
|
sot_notlocal: |
.not_local: |
; Send it. |
pop ebx |
call queue |
|
mov esi, [sktAddr] |
mov esi, [sockAddr] |
|
; increment SND.NXT in socket |
add esi, 48 |
add esi, SOCKET.SND_NXT |
call inc_inet_esi |
|
sot_done: |
pop eax ; Get the socket number back, so we can return it |
.exit: |
mov ebx, [sockAddr] |
mov [ebx + SOCKET.Status], SOCK_OPEN |
;pop eax ; Get the socket number back, so we can return it |
stdcall net_socket_addr_to_num, ebx |
ret |
|
sot_exit: |
.error: |
DEBUGF 1, "K : socket_open_tcp (fail)\n" |
or eax, -1 |
ret |
endp |
|
|
|
;*************************************************************************** |
; Function |
; socket_close |
342,26 → 445,33 |
; returns 0 for ok, -1 for socket not open (fail) |
; |
;*************************************************************************** |
socket_close: |
mov eax, 0xFFFFFFFF ; assume this operation will fail.. |
cmp ebx, NUM_SOCKETS |
jae sc_exit |
Index2RealAddr ebx |
cmp [ebx + SOCKET.Status], dword SOCK_EMPTY |
jz sc_exit |
proc socket_close stdcall |
DEBUGF 1, "K : socket_close (0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
|
cmp [eax + SOCKET.Status], dword SOCK_EMPTY |
jz .error |
|
; Clear the socket varaibles |
stdcall net_socket_free, eax |
; mov edi, eax |
; xor eax, eax |
; mov ecx, SOCKETHEADERSIZE |
; cld |
; rep stosb |
|
xor eax, eax |
mov edi, ebx |
mov ecx, SOCKETHEADERSIZE |
cld |
rep stosb |
ret |
|
sc_exit: |
.error: |
DEBUGF 1, "K : socket_close (fail)\n" |
or eax, -1 |
ret |
endp |
|
|
|
;*************************************************************************** |
; Function |
; socket_close_tcp |
371,7 → 481,9 |
; returns 0 for ok, -1 for socket not open (fail) |
; |
;*************************************************************************** |
socket_close_tcp: |
proc socket_close_tcp stdcall |
local sockAddr dd ? |
DEBUGF 1, "K : socket_close_tcp (0x%x)\n", ebx |
; first, remove any resend entries |
pusha |
|
378,105 → 490,113 |
mov esi, resendQ |
mov ecx, 0 |
|
sct001: |
.next_resendq: |
cmp ecx, NUMRESENDENTRIES |
je sct003 ; None left |
cmp [esi], bl |
je sct002 ; found one |
je .last_resendq ; None left |
;cmp [esi], bl ; XTODO: bl -> ebx |
cmp [esi + 4], ebx |
je @f ; found one |
inc ecx |
add esi, 4 |
jmp sct001 |
add esi, 8 |
jmp .next_resendq |
|
sct002: |
;@@: mov byte[esi], 0xff ; XTODO: 0xff -> 0 |
@@: mov dword[esi + 4], 0 |
inc ecx |
add esi, 8 |
jmp .next_resendq |
|
mov [esi], byte 0xFF |
jmp sct001 |
|
sct003: |
.last_resendq: |
popa |
|
Index2RealAddr ebx |
mov [sktAddr], ebx |
mov eax, 0xFFFFFFFF ; assume this operation will fail.. |
cmp [ebx + SOCKET.Status], dword SOCK_EMPTY |
jz sct_exit |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
|
mov ebx, eax |
mov [sockAddr], eax |
cmp [ebx + SOCKET.Status], SOCK_EMPTY |
je .error |
|
cmp [ebx + SOCKET.TCBState], TCB_LISTEN ;xxx |
je .destroy_tcb ;xxx |
cmp [ebx + SOCKET.TCBState], TCB_SYN_SENT ;xxx |
je .destroy_tcb ;xxx |
|
; Now construct the response, and queue for sending by IP |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je stl_exit |
je .error |
|
push eax |
|
mov bl, 0x11 ; FIN + ACK |
mov ecx, 0 |
mov esi, 0 |
;xxx mov bl, TH_FIN + TH_ACK |
mov bl, TH_FIN ;xxx |
xor ecx, ecx |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
|
call buildTCPPacket |
|
mov ebx, [sktAddr] |
|
mov ebx, [sockAddr] |
; increament SND.NXT in socket |
mov esi, 48 |
add esi, ebx |
lea esi, [ebx + SOCKET.SND_NXT] |
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 |
;xxx cmp eax, TCB_LISTEN |
;xxx je .destroy_tcb |
;xxx cmp eax, TCB_SYN_SENT |
;xxx je .destroy_tcb |
cmp eax, TCB_SYN_RECEIVED |
je sct_finwait1 |
je .fin_wait_1 |
cmp eax, TCB_ESTABLISHED |
je sct_finwait1 |
je .fin_wait_1 |
|
; 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 |
; TODO: check if it's really a TCB_CLOSE_WAIT |
mov [ebx + SOCKET.TCBState], TCB_LAST_ACK |
jmp .send |
|
sct_finwait1: |
.fin_wait_1: |
; Send a fin, then enter finwait2 state |
mov eax, TCB_FIN_WAIT_1 |
mov [ebx + SOCKET.TCBState], eax |
xor eax, eax |
mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_1 |
|
sct_send: |
.send: |
mov eax, NET1OUT_QUEUE |
|
mov edx, [stack_ip] |
mov ecx, [sktAddr ] |
mov ecx, [ecx + 16] |
cmp edx, ecx |
jne sct_notlocal |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
|
sct_notlocal: |
.not_local: |
; Send it. |
pop ebx |
call queue |
jmp sct_exit |
jmp .exit |
|
destroyTCB: |
pop eax |
; Clear the socket varaibles |
.destroy_tcb: |
;xxx pop eax |
|
; Clear the socket variables |
;xxx stdcall net_socket_free, [sockAddr] |
stdcall net_socket_free, ebx |
|
.exit: |
xor eax, eax |
mov edi, ebx |
mov ecx, SOCKETHEADERSIZE |
cld |
rep stosb |
ret |
|
sct_exit: |
.error: |
DEBUGF 1, "K : socket_close_tcp (fail)\n" |
or eax, -1 |
ret |
endp |
|
|
|
;*************************************************************************** |
; Function |
; socket_poll |
486,12 → 606,20 |
; returns count in eax. |
; |
;*************************************************************************** |
socket_poll: |
Index2RealAddr ebx |
mov eax, [ebx + SOCKET.rxDataCount] |
proc socket_poll stdcall |
; DEBUGF 1, "socket_poll(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
|
mov eax, [eax + SOCKET.rxDataCount] |
ret |
|
.error: |
;or eax, -1 |
xor eax, eax |
ret |
endp |
|
|
;*************************************************************************** |
503,14 → 631,27 |
; returns TCB state in eax. |
; |
;*************************************************************************** |
socket_status: |
Index2RealAddr ebx |
mov eax, [ebx + SOCKET.TCBState] |
proc socket_status stdcall |
;; DEBUGF 1, "socket_status(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
|
mov eax, [eax + SOCKET.TCBState] |
ret |
|
.error: |
;or eax, -1 |
xor eax, eax |
ret |
endp |
|
; Index2RealAddr ebx |
; mov eax, [ebx + SOCKET.TCBState] |
; |
; ret |
|
|
;*************************************************************************** |
; Function |
; socket_read |
520,12 → 661,16 |
; returns # of bytes remaining in eax, data in bl |
; |
;*************************************************************************** |
socket_read: |
Index2RealAddr ebx |
proc socket_read stdcall |
; DEBUGF 1, "socket_read(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
|
mov ebx, eax |
mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes |
mov ecx, 1 |
test eax, eax |
jz sr2 |
jz .error |
|
dec eax |
mov esi, ebx ; esi is address of socket |
537,18 → 682,19 |
inc esi |
|
mov ecx, (SOCKETBUFFSIZE - SOCKETHEADERSIZE) / 4 |
lea edi, [ebx + SOCKETHEADERSIZE] |
lea esi, [edi + 1] |
cld |
rep movsd |
xor ecx, ecx |
|
sr1: |
jmp sor_exit |
ret |
|
sr2: |
xor bl, bl |
|
sor_exit: |
.error: |
;or eax, -1 |
xor eax, eax |
xor ebx, ebx |
ret |
endp |
|
|
;*************************************************************************** |
562,22 → 708,27 |
; returns # of bytes copied in eax |
; |
;*************************************************************************** |
socket_read_packet: |
Index2RealAddr ebx ; get real socket address |
proc socket_read_packet stdcall |
; DEBUGF 1, "socket_read_packet(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx ; get real socket address |
or eax, eax |
jz .error |
|
mov ebx, eax |
mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes |
test eax, eax ; if count of bytes is zero.. |
jz .exit ; exit function (eax will be zero) |
|
test edx, edx ; if buffer size is zero, copy all data |
jz .copyallbytes |
jz .copy_all_bytes |
cmp edx, eax ; if buffer size is larger then the bytes of data, copy all data |
jge .copyallbytes |
jge .copy_all_bytes |
|
sub eax, edx ; store new count (data bytes in buffer - bytes we're about to copy) |
mov [ebx + SOCKET.rxDataCount], eax ; |
push eax |
mov eax, edx ; number of bytes we want to copy must be in eax |
call .startcopy ; copy to the application |
call .start_copy ; copy to the application |
|
mov esi, ebx ; now we're going to copy the remaining bytes to the beginning |
add esi, SOCKETHEADERSIZE ; we dont need to copy the header |
592,33 → 743,36 |
and ecx, 3 |
rep movsb ; copy remaining bytes |
|
.exit: |
ret ; at last, exit |
|
.copyallbytes: |
.error: |
;or eax, -1 |
xor eax, eax |
ret |
|
.copy_all_bytes: |
xor esi, esi |
mov [ebx + SOCKET.rxDataCount], esi ; store new count (zero) |
call .start_copy |
ret |
|
.startcopy: |
mov edi, ecx ; |
; add edi, std_application_base_address ; get data pointer to buffer in application |
|
mov esi, ebx ; |
.start_copy: |
mov edi, ecx |
mov esi, ebx |
add esi, SOCKETHEADERSIZE ; we dont need to copy the header |
mov ecx, eax ; eax is count of bytes |
push ecx |
shr ecx, 2 ; divide eax by 4 |
cld ; copy all full dwords |
rep movsd ; |
rep movsd |
pop ecx |
and ecx, 3 |
rep movsb ; copy the rest bytes |
retn ; exit, or go back to shift remaining bytes if any |
endp |
|
.exit: |
ret ; exit, or go back to shift remaining bytes if any |
|
|
|
|
;*************************************************************************** |
; Function |
; socket_write |
631,19 → 785,22 |
; could not queue IP packet ) |
; |
;*************************************************************************** |
socket_write: |
Index2RealAddr ebx |
proc socket_write stdcall |
; DEBUGF 1, "socket_write(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx ; get real socket address |
or eax, eax |
jz .error |
|
mov eax, 0xFFFFFFFF |
mov ebx, eax |
|
; If the socket is invalid, return with an error code |
cmp [ebx], dword SOCK_EMPTY |
je sw_exit |
cmp [ebx + SOCKET.Status], SOCK_EMPTY |
je .error |
|
|
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je sw_exit |
je .error |
|
; Save the queue entry number |
push eax |
662,55 → 819,46 |
; 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 eax, [ebx + SOCKET.LocalIP] |
mov [edx + IP_PACKET.SourceAddress], eax |
mov eax, [ebx + SOCKET.RemoteIP] |
mov [edx + IP_PACKET.DestinationAddress], eax |
|
mov al, 0x45 |
mov [edx], al ; Version, IHL |
xor al, al |
mov [edx + 1], al ; Type of service |
mov [edx + IP_PACKET.VersionAndIHL], 0x45 |
mov [edx + IP_PACKET.TypeOfService], 0 |
|
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 |
xchg al, ah |
mov [edx + IP_PACKET.TotalLength], ax |
xor eax, eax |
mov [edx + IP_PACKET.Identification], ax |
mov [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040 |
mov [edx + IP_PACKET.TimeToLive], 0x20 |
mov [edx + IP_PACKET.Protocol], PROTOCOL_UDP |
|
; Checksum left unfilled |
xor ax, ax |
mov [edx + 10], ax |
mov [edx + IP_PACKET.HeaderChecksum], ax |
|
; Fill in the UDP header ( some data is in the socket descriptor) |
mov ax, [ebx + 12] |
mov [edx + 20], ax |
mov ax, [ebx + SOCKET.LocalPort] |
mov [edx + 20 + UDP_PACKET.SourcePort], ax |
|
mov ax, [ebx + 20] |
mov [edx + 20 + 2], ax |
mov ax, [ebx + SOCKET.RemotePort] |
mov [edx + 20 + UDP_PACKET.DestinationPort], ax |
|
pop eax |
push eax |
|
add eax, 8 |
mov [edx + 20 + 4], ah |
mov [edx + 20 + 5], al |
xchg al, ah |
mov [edx + 20 + UDP_PACKET.Length], ax |
|
; Checksum left unfilled |
xor ax, ax |
mov [edx + 20 + 6], ax |
xor eax, eax |
mov [edx + 20 + UDP_PACKET.Checksum], ax |
|
pop ecx ; count of bytes to send |
mov ebx, ecx ; need the length later |
730,16 → 878,15 |
; we have edx as IPbuffer ptr. |
; Fill in the UDP checksum |
; First, fill in pseudoheader |
mov eax, [edx + 12] |
mov eax, [edx + IP_PACKET.SourceAddress] |
mov [pseudoHeader], eax |
mov eax, [edx + 16] |
mov eax, [edx + IP_PACKET.DestinationAddress] |
mov [pseudoHeader+4], eax |
mov ax, 0x1100 ; 0 + protocol |
mov [pseudoHeader+8], ax |
mov word[pseudoHeader + 8], PROTOCOL_UDP shl 8 + 0 ; 0 + protocol |
add ebx, 8 |
mov eax, ebx |
mov [pseudoHeader+10], ah |
mov [pseudoHeader+11], al |
xchg al, ah |
mov [pseudoHeader + 10], ax |
|
mov eax, pseudoHeader |
mov [checkAdd1], eax |
757,44 → 904,43 |
|
; If the UDP checksum computes to 0, we must make it 0xffff |
; (0 is reserved for 'not used') |
cmp ax, 0 |
jne sw_001 |
test ax, ax |
jnz @f |
mov ax, 0xffff |
|
sw_001: |
mov [edx + 20 + 6], ah |
mov [edx + 20 + 7], al |
@@: xchg al, ah |
mov [edx + 20 + UDP_PACKET.Checksum], ax |
|
; Fill in the IP header checksum |
GET_IHL ecx,edx ; get IP-Header length |
stdcall checksum_jb,edx,ecx ; buf_ptr, buf_size |
xchg al, ah |
mov [edx + IP_PACKET.HeaderChecksum], ax |
|
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 ecx, [edx + SOCKET.RemoteIP] |
mov edx, [stack_ip] |
cmp edx, ecx |
jne sw_notlocal |
jne .not_local |
mov eax, IPIN_QUEUE |
|
sw_notlocal: |
.not_local: |
; Send it. |
call queue |
|
xor eax, eax |
ret |
|
sw_exit: |
.error: |
or eax, -1 |
ret |
endp |
|
|
|
;*************************************************************************** |
; Function |
; socket_write_tcp |
807,30 → 953,33 |
; could not queue IP packet ) |
; |
;*************************************************************************** |
socket_write_tcp: |
Index2RealAddr ebx |
proc socket_write_tcp stdcall |
local sockAddr dd ? |
|
mov [sktAddr], ebx |
; DEBUGF 1, "socket_write_tcp(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
|
mov eax, 0xFFFFFFFF |
mov ebx, eax |
mov [sockAddr], ebx |
|
; If the socket is invalid, return with an error code |
cmp [ebx], dword SOCK_EMPTY |
je swt_exit |
cmp [ebx + SOCKET.Status], SOCK_EMPTY |
je .error |
|
; If the sockets window timer is nonzero, do not queue packet |
; TODO - done |
cmp [ebx + SOCKET.wndsizeTimer], dword 0 |
jne swt_exit |
cmp [ebx + SOCKET.wndsizeTimer], 0 |
jne .error |
|
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je swt_exit |
je .error |
|
push eax |
|
mov bl, 0x10 ; ACK |
|
; Get the address of the callers data |
mov edi, [TASK_BASE] |
add edi, TASKDATA.mem_start |
841,7 → 990,8 |
push eax |
|
push ecx |
call buildTCPPacket |
mov bl, TH_ACK |
stdcall build_tcp_packet, [sockAddr] |
pop ecx |
|
; Check destination IP address. |
852,13 → 1002,12 |
mov eax, NET1OUT_QUEUE |
|
mov edx, [stack_ip] |
mov ecx, [sktAddr ] |
mov ecx, [ecx + 16] |
cmp edx, ecx |
jne swt_notlocal |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
|
swt_notlocal: |
.not_local: |
pop ecx |
|
push ebx ; save ipbuffer number |
865,11 → 1014,11 |
|
call queue |
|
mov esi, [sktAddr] |
mov esi, [sockAddr] |
|
; increament SND.NXT in socket |
; Amount to increment by is in ecx |
add esi, 48 |
add esi, SOCKET.SND_NXT |
call add_inet_esi |
|
pop ebx |
879,17 → 1028,17 |
mov esi, resendQ |
mov ecx, 0 |
|
swt003: |
.next_resendq: |
cmp ecx, NUMRESENDENTRIES |
je swt001 ; None found |
cmp [esi], byte 0xFF |
je swt002 ; found one |
je .exit ; None found |
;cmp byte[esi], 0xff ; XTODO: 0xff -> 0 |
cmp dword[esi + 4], 0 |
je @f ; found one |
inc ecx |
add esi, 4 |
jmp swt003 |
add esi, 8 |
jmp .next_resendq |
|
swt002: |
push ebx |
@@: push ebx |
|
; OK, we have a buffer descriptor ptr in esi. |
; resend entry # in ecx |
899,20 → 1048,19 |
; 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 |
stdcall net_socket_addr_to_num, [sockAddr] |
;mov [esi], al ; XTODO: al -> eax |
mov [esi + 4], eax |
mov byte[esi + 1], TCP_RETRIES |
mov word[esi + 2], 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 |
|
@@: add edi, IPBUFFSIZE |
loop @b |
|
; we have dest buffer location in edi |
pop eax |
; convert source buffer pointer eax to the absolute address |
926,9 → 1074,11 |
cld |
rep movsb |
|
swt001: |
.exit: |
xor eax, eax |
ret |
|
swt_exit: |
.error: |
or eax, -1 |
ret |
|
endp |